第1章:ROS2基础与环境搭建

各位同学好,我是你们这门课的老朋友。今天咱们从最基础的东西开始——把ROS2 Humble装好,把开发环境搭起来。

说实话,我见过太多同学一上来就急着写代码,结果编译报错、通信不通,折腾半天发现是环境没配好。嗯,咱们先把地基打牢,后面才能跑得快。

1.1 ROS2 Humble安装——别踩我踩过的坑

ROS2的版本很多,为什么我选Humble?因为它是个长期支持版(LTS),到2027年都有人维护。我在项目里吃过非LTS版本的亏——升级后一堆包不兼容,那叫一个酸爽。

安装前,先确认你的Ubuntu版本。Humble对应的是Ubuntu 22.04。如果你用20.04,那就装Galactic;用24.04就装Jazzy。别搞混了,否则依赖会出问题。

⚠️ 避坑指南: 我曾经在Ubuntu 20.04上强行装Humble,结果rosdep死活过不去。后来老老实实重装了系统。记住:版本匹配是第一步。

安装步骤其实很简单,我习惯用脚本一键搞定:

# 设置locale
sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8

# 添加ROS2源
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

# 安装ROS2 Humble桌面版(推荐)
sudo apt update
sudo apt install ros-humble-desktop

# 安装开发工具
sudo apt install ros-dev-tools

装完后,别忘了配置环境变量。我个人习惯把它写到.bashrc里:

echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc

验证一下是否装好了:

ros2 run demo_nodes_cpp talker

再开一个终端,运行:

ros2 run demo_nodes_py listener

如果你看到两个节点在互相发消息,恭喜你,环境搭好了。

💡 我的小技巧: 我习惯在~/.bashrc里加一行别名:alias ros2='source /opt/ros/humble/setup.bash && ros2'。这样每次打开终端不用手动source,省事。

1.2 工作空间创建——你的代码仓库

ROS2里,所有代码都放在工作空间里。说白了,就是一个有特定结构的文件夹。我建议你建一个专门的目录来放所有ROS2项目:

mkdir -p ~/ros2_ws/src
cd ~/ros2_ws

这个src文件夹放你的代码包,build和install是编译后自动生成的,不用手动管。

你想想看,如果你把所有代码都堆在桌面上,找起来多费劲。工作空间就是帮你把项目组织得井井有条。

1.3 Colcon编译工具——从catkin到colcon的进化

用过ROS1的同学可能记得catkin。ROS2换成了colcon,速度更快,功能更强。我个人觉得colcon最大的好处是——它不会把编译中间文件搞得乱七八糟。

安装colcon:

sudo apt install python3-colcon-common-extensions

编译工作空间:

cd ~/ros2_ws
colcon build

常用的编译选项:

命令 作用 我什么时候用
colcon build 完整编译 第一次编译,或改了多个包
colcon build --packages-select 包名 只编译指定包 只改了一个包时,省时间
colcon build --symlink-install 符号链接安装 开发Python节点时,改代码不用重新编译
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release Release模式编译 性能测试时用

重点: 每次编译后,记得source一下:source install/setup.bash。我刚开始经常忘了这步,然后发现找不到自己写的节点,急得团团转。

1.4 话题通信——ROS2的血管

话题(Topic)是ROS2里最常用的通信方式。一个节点发布消息,另一个节点订阅,就这么简单。

我举个例子。在Nav2导航里,机器人会发布/odom话题(里程计数据),机械臂会订阅这个数据来调整自己的位置。这就是典型的话题通信。

创建一个发布者:

import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class MinimalPublisher(Node):
    def __init__(self):
        super().__init__('minimal_publisher')
        self.publisher_ = self.create_publisher(String, 'topic', 10)
        timer_period = 0.5  # 每秒发两次
        self.timer = self.create_timer(timer_period, self.timer_callback)

    def timer_callback(self):
        msg = String()
        msg.data = 'Hello, Nav2!'
        self.publisher_.publish(msg)
        self.get_logger().info('Publishing: "%s"' % msg.data)

创建一个订阅者:

class MinimalSubscriber(Node):
    def __init__(self):
        super().__init__('minimal_subscriber')
        self.subscription = self.create_subscription(
            String, 'topic', self.listener_callback, 10)

    def listener_callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data)

为什么用话题?因为它是一对多、异步的。一个传感器数据可以被导航模块、机械臂、可视化工具同时使用,互不干扰。

1.5 服务通信——有来有往

话题是单向的,服务(Service)是双向的。客户端发请求,服务端回响应。我在做机械臂抓取时,经常用服务来查询当前关节角度——问一次,答一次,干净利落。

定义服务接口(srv文件):

# GetJointAngle.srv
string joint_name
---
float64 angle

服务端实现:

class JointAngleServer(Node):
    def __init__(self):
        super().__init__('joint_angle_server')
        self.srv = self.create_service(
            GetJointAngle, 'get_joint_angle', self.get_angle_callback)

    def get_angle_callback(self, request, response):
        # 假设从硬件读取角度
        response.angle = 45.0
        return response

客户端调用:

client = self.create_client(GetJointAngle, 'get_joint_angle')
while not client.wait_for_service(timeout_sec=1.0):
    self.get_logger().info('service not available, waiting...')
req = GetJointAngle.Request()
req.joint_name = 'shoulder'
future = client.call_async(req)
⚠️ 注意: 服务调用是阻塞的,如果你在控制循环里调用服务,记得用异步方式(call_async),否则整个节点会卡住。我吃过这个亏,机械臂差点撞到人。

1.6 动作通信——干大事的

动作(Action)是ROS2里最复杂的通信方式,但也是最强大的。它适合长时间的任务,比如让机械臂从A点移动到B点——你可以随时查询进度,也可以中途取消。

动作有三个要素:目标(Goal)、反馈(Feedback)、结果(Result)。

定义动作接口:

# MoveArm.action
# 目标
geometry_msgs/Pose target_pose
---
# 结果
bool success
string message
---
# 反馈
float32 progress

动作服务端:

class MoveArmServer(Node):
    def __init__(self):
        super().__init__('move_arm_server')
        self.action_server = ActionServer(
            self, MoveArm, 'move_arm', self.execute_callback)

    def execute_callback(self, goal_handle):
        feedback_msg = MoveArm.Feedback()
        # 模拟移动过程
        for i in range(10):
            feedback_msg.progress = (i + 1) * 10.0
            goal_handle.publish_feedback(feedback_msg)
            time.sleep(0.5)
        goal_handle.succeed()
        result = MoveArm.Result()
        result.success = True
        return result

动作客户端:

class MoveArmClient(Node):
    def __init__(self):
        super().__init__('move_arm_client')
        self.action_client = ActionClient(self, MoveArm, 'move_arm')

    def send_goal(self, pose):
        goal_msg = MoveArm.Goal()
        goal_msg.target_pose = pose
        self.action_client.send_goal_async(goal_msg)

1.7 本章知识体系

下面这张图是我自己画的,把本章的核心内容串起来了。你保存好,后面学Nav2和机械臂时经常要回来翻。

ROS2基础与环境搭建 - 知识体系 环境搭建层 Ubuntu 22.04 + ROS2 Humble + Colcon + 工作空间 通信机制层 话题 (Topic) 发布/订阅模式 一对多、异步 服务 (Service) 请求/响应模式 一对一、同步/异步 动作 (Action) 目标/反馈/结果 可取消、可查询进度 应用场景层 Nav2导航(里程计/激光雷达话题) + 机械臂控制(关节角度服务/移动动作) 第1章:ROS2基础与环境搭建 - 知识体系总览

这张图你看懂了吗?从上到下,先搭环境,再学通信,最后应用到Nav2和机械臂上。每一步都是下一步的基础。

💡 我的建议: 学ROS2别贪快。我当年花了一周时间专门练话题和服务,把各种数据类型都试了一遍。后面做项目时,通信部分从来没出过问题。基础打牢了,后面就是水到渠成的事。

好了,这一章的内容就到这里。环境搭好了,通信机制也回顾了,后面咱们就可以开始玩真的了——让机器人动起来!

可可精品资料库