ROS2基础:核心概念与开发环境搭建
核心原理:从“进程孤岛”到“分布式协作”
ROS2 的本质是一套分布式通信中间件,它让多个独立运行的进程(即可执行程序)能够以松耦合的方式协同完成复杂任务。在机器人路径规划项目中,我们通常需要同时运行传感器驱动、定位模块、全局规划器、局部规划器、底盘控制等多个程序。如果这些程序各自为政,数据交换将变得极其困难。ROS2 通过四种核心通信原语解决了这一问题:节点(Node)、话题(Topic)、服务(Service)和动作(Action)。
节点是 ROS2 中最基本的计算单元,一个节点通常负责一个单一职责,例如“激光雷达驱动节点”或“路径规划节点”。节点之间不直接调用代码,而是通过“话题”进行异步数据流传输(如传感器数据流),或通过“服务”进行同步请求-应答(如查询地图信息)。当任务需要长时间执行且可能被取消时(如导航到目标点),则使用“动作”接口,它提供了反馈和取消机制。理解这四种原语的区别与适用场景,是后续编写路径规划代码的基石。
方法流程:搭建开发环境与验证通信
在 Ubuntu 22.04 系统上,我们推荐使用 ROS2 Humble 发行版。环境搭建的核心步骤包括:设置软件源、安装 ROS2 基础包、配置环境变量、安装开发工具(如 colcon 和 turtlesim 用于验证)。以下是关键命令序列:
# 1. 设置编码与软件源
sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo add-apt-repository universe
# 2. 添加 ROS2 GPG 密钥与仓库
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 Humble 桌面版(包含可视化工具)
sudo apt update
sudo apt install ros-humble-desktop python3-colcon-common-extensions
# 4. 环境变量配置(写入 ~/.bashrc)
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc
安装完成后,务必使用 ROS2 自带的“小乌龟”模拟器进行通信验证。打开两个终端,一个运行 ros2 run turtlesim turtlesim_node,另一个运行 ros2 run turtlesim turtle_teleop_key。如果能够通过键盘控制小乌龟移动,说明节点发现、话题通信机制已正常工作。此时可以运行 ros2 node list 和 ros2 topic list 查看当前活跃的节点与话题。
| 工具/命令 | 作用 | 路径规划中的典型用途 |
|---|---|---|
ros2 node list |
列出所有活跃节点 | 确认规划节点与底盘节点是否正常注册 |
ros2 topic echo /scan |
打印话题数据流 | 检查激光雷达数据是否发布 |
ros2 service list |
列出所有服务 | 查看地图服务是否可用 |
ros2 action list |
列出所有动作 | 确认导航动作服务器已启动 |
colcon build |
编译工作空间 | 编译自定义的规划器与控制器包 |
案例/场景:用“话题”驱动一个简单的路径跟踪
假设我们已有一个发布机器人位姿的节点(/pose),现在要编写一个“直线跟踪节点”,它订阅 /pose 并发布速度指令 /cmd_vel。这个场景直接体现了节点与话题的配合。以下是一个极简的 Python 节点骨架:
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from nav_msgs.msg import Odometry
class StraightLineController(Node):
def __init__(self):
super().__init__('straight_line_controller')
self.publisher = self.create_publisher(Twist, '/cmd_vel', 10)
self.subscription = self.create_subscription(
Odometry, '/odom', self.odom_callback, 10)
def odom_callback(self, msg):
# 简单逻辑:如果 x 坐标小于 2.0 则前进,否则停止
if msg.pose.pose.position.x < 2.0:
vel = Twist()
vel.linear.x = 0.2
self.publisher.publish(vel)
else:
self.publisher.publish(Twist()) # 发布空速度
def main(args=None):
rclpy.init(args=args)
node = StraightLineController()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
在这个案例中,create_subscription 让节点订阅 /odom 话题,每当有新的里程计数据到达时,回调函数就会被触发。节点内部计算后通过 create_publisher 向 /cmd_vel 发布速度指令。这种“订阅-处理-发布”的模式是 ROS2 中绝大多数算法节点的基本骨架。
误区/复盘:新手最容易踩的四个“坑”
- 混淆“话题”与“服务”的适用场景。 新手常试图用服务来传输高频传感器数据,这会导致严重的阻塞。传感器流必须使用话题;只有偶尔一次的请求(如“保存当前地图”)才适合用服务。
- 忘记 source 环境变量。 新开终端后直接运行
ros2 run会报“找不到包”的错误。务必先执行source /opt/ros/humble/setup.bash,或确保它已写入~/.bashrc。 - 节点名与话题名不匹配。 发布者与订阅者必须使用完全相同的话题名(包括命名空间)。例如发布到
/cmd_vel,而订阅者监听/robot/cmd_vel,则永远无法通信。使用ros2 topic info /cmd_vel可以快速排查。 - 忽视“动作”与“服务”的差异。 如果导航任务需要 10 秒才能完成,使用服务会导致客户端一直阻塞等待。此时必须使用动作,以便在任务执行过程中持续接收反馈,并允许用户取消任务。
Node('global_planner')。