2. ROS2基础与环境搭建

说实话,每次带新人入门ROS2,我都会想起自己当年被ROS1的“环境变量地狱”支配的恐惧。ROS2的出现,确实让很多坑被填平了。但话说回来,该踩的坑一个都不会少,只是换了个地方踩而已。

这一章,咱们就一起把ROS2的开发环境搭起来。我保证,跟着我的节奏走,你至少能少走一半弯路。

2.1 ROS2的安装与配置

ROS2的版本选择,我个人建议直接用Humble Hawksbill。为什么?因为它是LTS版本,支持到2027年。我在项目里吃过非LTS版本的亏——项目还没做完,官方就停止维护了,那叫一个尴尬。

安装前的准备

先确认你的Ubuntu版本。ROS2 Humble对应的是Ubuntu 22.04。如果你用的是20.04,那就选Galactic版本。别搞混了,否则依赖关系会让你怀疑人生。

⚠️ 我曾经犯过的错: 直接在Ubuntu 20.04上装Humble,结果编译时各种依赖缺失。折腾了两天,最后发现是版本不匹配。嗯,从那以后我学乖了,装之前先查兼容性表格。

安装步骤(以Humble为例)

# 1. 设置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
export LANG=en_US.UTF-8

# 2. 添加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

# 3. 安装ROS2
sudo apt update
sudo apt upgrade
sudo apt install ros-humble-desktop

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

安装完成后,记得配置环境变量。我个人习惯把它写到 ~/.bashrc 里,这样每次打开终端就不用重新source了。

echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc
💡 小技巧: 如果你同时装了ROS1和ROS2,可以在.bashrc里写个别名切换。比如 alias ros1='source /opt/ros/noetic/setup.bash',alias ros2='source /opt/ros/humble/setup.bash'。这样想用哪个就切哪个,互不干扰。

2.2 工作空间创建

工作空间,说白了就是你放代码的地方。ROS2用的是colcon来编译,跟ROS1的catkin_make有点像,但更现代一些。

创建工作空间

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

第一次编译会生成几个文件夹:build、install、log。其中install里放着编译好的可执行文件和库文件。每次编译完,记得source一下:

source install/setup.bash

你想想看,如果你忘了source,那系统就找不到你新写的节点。我刚开始用ROS2时,经常编译完发现节点跑不起来,debug了半天才发现是忘了source。嗯,这种低级错误,犯过一次就记住了。

2.3 发布-订阅模型

发布-订阅模型,是ROS2最核心的通信机制。说白了,就是一个节点发消息,另一个节点收消息,中间通过话题(Topic)来传递。

我画了一张图,帮你理解这个模型:

发布者节点 (Publisher) /joint_states 话题 (Topic) 消息类型: JointState 订阅者节点 (Subscriber) 发布消息 订阅消息 发布-订阅模型:一对多、异步、解耦 一个话题可以有多个发布者和多个订阅者

你看这张图,发布者只管往话题里发消息,订阅者只管从话题里收消息。两者完全解耦,互不知道对方的存在。这就是ROS2通信的优雅之处。

写一个简单的发布者

# talker.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class Talker(Node):
    def __init__(self):
        super().__init__('talker')
        self.publisher = self.create_publisher(String, 'chatter', 10)
        timer_period = 0.5  # 0.5秒发一次
        self.timer = self.create_timer(timer_period, self.timer_callback)
        self.count = 0

    def timer_callback(self):
        msg = String()
        msg.data = f'Hello, ROS2! 第 {self.count} 次'
        self.publisher.publish(msg)
        self.get_logger().info(f'发布了: {msg.data}')
        self.count += 1

def main(args=None):
    rclpy.init(args=args)
    talker = Talker()
    rclpy.spin(talker)
    talker.destroy_node()
    rclpy.shutdown()

写一个对应的订阅者

# listener.py
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class Listener(Node):
    def __init__(self):
        super().__init__('listener')
        self.subscription = self.create_subscription(
            String, 'chatter', self.listener_callback, 10)
        self.subscription  # 防止被垃圾回收

    def listener_callback(self, msg):
        self.get_logger().info(f'收到了: {msg.data}')

def main(args=None):
    rclpy.init(args=args)
    listener = Listener()
    rclpy.spin(listener)
    listener.destroy_node()
    rclpy.shutdown()
🔑 关键点:
  • create_publisher 的第三个参数是队列长度。10表示最多缓存10条消息。如果订阅者处理不过来,旧消息会被丢弃。
  • rclpy.spin() 会让节点一直运行,直到你按 Ctrl+C 停止。
  • 话题名称是字符串,可以任意命名。但建议用有意义的名称,比如 /joint_states、/cmd_vel。

2.4 话题与服务的基本使用

话题是“发布-订阅”模式,适合持续性的数据流。比如传感器数据、机器人状态。但有些场景需要“请求-响应”模式,比如让机器人抓个东西、查询当前位姿。这时候就该服务(Service)上场了。

话题 vs 服务

特性 话题 (Topic) 服务 (Service)
通信模式 发布-订阅(异步) 请求-响应(同步)
数据流向 单向 双向
适用场景 传感器数据、状态信息 指令下发、参数查询
是否阻塞 不阻塞 客户端会阻塞等待响应
典型例子 /camera/image_raw /gripper/close

服务的定义

服务需要定义请求和响应的数据结构。比如我们定义一个加法服务:

# AddTwoInts.srv
int64 a
int64 b
---
int64 sum

三个横线上面是请求,下面是响应。这个文件放在 srv/ 目录下。

服务端实现

# server.py
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class Server(Node):
    def __init__(self):
        super().__init__('server')
        self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_callback)

    def add_callback(self, request, response):
        response.sum = request.a + request.b
        self.get_logger().info(f'收到请求: {request.a} + {request.b} = {response.sum}')
        return response

def main(args=None):
    rclpy.init(args=args)
    server = Server()
    rclpy.spin(server)
    server.destroy_node()
    rclpy.shutdown()

客户端实现

# client.py
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class Client(Node):
    def __init__(self):
        super().__init__('client')
        self.cli = self.create_client(AddTwoInts, 'add_two_ints')
        while not self.cli.wait_for_service(timeout_sec=1.0):
            self.get_logger().info('等待服务上线...')
        self.req = AddTwoInts.Request()

    def send_request(self, a, b):
        self.req.a = a
        self.req.b = b
        self.future = self.cli.call_async(self.req)
        rclpy.spin_until_future_complete(self, self.future)
        return self.future.result()

def main(args=None):
    rclpy.init(args=args)
    client = Client()
    response = client.send_request(3, 5)
    client.get_logger().info(f'结果: 3 + 5 = {response.sum}')
    client.destroy_node()
    rclpy.shutdown()
💡 实战经验: 我在做机械臂避障时,话题用来传激光雷达的点云数据(持续流),服务用来下发“开始避障”或“停止避障”的指令(一次性请求)。两种模式配合使用,效果很好。

2.5 编译与运行

代码写好了,怎么跑起来?用colcon编译,然后用ros2 run运行。

# 编译
cd ~/ros2_ws
colcon build --packages-select your_package_name

# 运行发布者
source install/setup.bash
ros2 run your_package_name talker

# 另一个终端运行订阅者
source install/setup.bash
ros2 run your_package_name listener

你可以在终端里看到发布者每隔0.5秒发一条消息,订阅者实时收到。这就是ROS2最基本的通信流程。

⚠️ 注意: 每次打开新终端,都要记得 source install/setup.bash。我建议你把这个命令写到 ~/.bashrc 里,省得每次都手动敲。但如果你有多个工作空间,要注意source的顺序,后面的会覆盖前面的。

好了,ROS2的基础环境搭建和通信机制就讲到这里。这些内容看起来简单,但它们是后续所有复杂功能的基础。你想想看,如果连消息都发不出去,那避障、路径规划什么的就都无从谈起了。

下一章,我们会开始搭建机械臂的仿真环境。到时候,这些话题和服务就会真正派上用场了。


可可精品资料库