ROS2开发
ROS2开发
ROS 2(Robot Operating System 2)是用于机器人开发的灵活框架,相较于 ROS 1,它在实时性、安全性、跨平台支持和分布式通信等方面有显著提升。以下是一个 ROS 2 开发的快速入门指南,适用于初学者或希望系统化学习的人。
🧰 一、环境准备
1. 操作系统支持
- 推荐:Ubuntu 22.04(对应 ROS 2 Humble)
- 其他支持:Ubuntu 20.04(Foxy)、Ubuntu 24.04(Jazzy,较新)
官方推荐使用 Ubuntu + 官方二进制安装方式。
2. 安装 ROS 2(以 Humble 为例)
# 设置 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
# 添加 ROS 2 软件源
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt install curl
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
# 安装 ROS 2 Desktop 版本
sudo apt update
sudo apt install ros-humble-desktop
3. 设置环境变量
source /opt/ros/humble/setup.bash
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
4. 安装开发工具
sudo apt install python3-colcon-common-extensions \
python3-rosdep \
python3-rosinstall-generator \
build-essential
📦 二、创建第一个 ROS 2 包
1. 创建工作空间
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
colcon build
2. 创建功能包(Python 示例)
cd src
ros2 pkg create --build-type ament_python --node-name my_node my_package
3. 编写简单 Publisher(发布者)
编辑 my_package/my_package/my_node.py:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MyPublisher(Node):
def __init__(self):
super().__init__('my_publisher')
self.publisher_ = self.create_publisher(String, 'chatter', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
def timer_callback(self):
msg = String()
msg.data = f'Hello ROS 2! #{self.i}'
self.publisher_.publish(msg)
self.get_logger().info(f'Publishing: "{msg.data}"')
self.i += 1
def main(args=None):
rclpy.init(args=args)
node = MyPublisher()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
4. 修改 setup.py
确保入口点注册:
entry_points={
'console_scripts': [
'my_node = my_package.my_node:main',
],
},
5. 编译并运行
cd ~/ros2_ws
colcon build --packages-select my_package
source install/setup.bash
ros2 run my_package my_node
🛠️ 三、常用命令
| 功能 | 命令 |
|---|---|
| 查看话题 | ros2 topic list |
| 监听话题 | ros2 topic echo /chatter |
| 查看节点 | ros2 node list |
| 查看服务 | ros2 service list |
| 启动 launch 文件 | ros2 launch <package> <file.launch.py> |
| 查看参数 | ros2 param list |
📚 四、进阶主题
- 自定义消息/服务:在
msg/和srv/目录中定义.msg/.srv文件,并在CMakeLists.txt或setup.py中配置。 - Launch 文件:使用 Python 编写
.launch.py实现多节点启动。 - 参数管理:通过 YAML 文件或命令行传参。
- QoS 配置:控制通信可靠性(如传感器数据 vs 控制指令)。
- DDS 配置:可更换底层通信中间件(Fast DDS、Cyclone DDS 等)。
- ROS 2 与 Gazebo/Ignition 集成:用于仿真。
- 安全机制:启用 SROS2(安全 ROS 2)进行身份认证和加密。
📘 五、学习资源
- 官方文档:https://docs.ros.org/en/humble/
- 教程:https://docs.ros.org/en/humble/Tutorials.html
- ROS 2 设计文章:https://design.ros2.org/
- 社区论坛:https://answers.ros.org/
2.ROS2详解
ROS 2(Robot Operating System 2)是专为机器人软件开发设计的分布式、模块化、实时通信框架,并非传统意义上的“操作系统”,而是一个中间件 + 工具链 + 生态系统。以下是对 ROS 2 的全面、结构化详解,涵盖其本质、核心机制、架构演进、工程实践与技术边界。
一、ROS 2 是什么?
定义
ROS 2 = 分布式机器人软件框架 + DDS 中间件 + 组件化开发模型 + 丰富工具链
它提供:
- 硬件抽象:屏蔽传感器/执行器差异
- 进程间通信(IPC):节点通过话题、服务、动作交互
- 开发工具:调试、可视化(RViz2)、日志、仿真(Gazebo)
- 算法库:SLAM、导航、运动规划等参考实现
二、ROS 2 vs ROS 1:关键演进
| 特性 | ROS 1 | ROS 2 |
|---|---|---|
| 通信机制 | 自研 TCPROS/UDPROS + Master | 标准 DDS(Data Distribution Service) |
| 实时性 | 不支持硬实时 | 支持 确定性调度(配合 RTOS) |
| 跨平台 | 主要 Linux | Linux / Windows / macOS / 嵌入式 |
| 语言支持 | C++03, Python 2 | C++17, Python 3.6+, Rust/C# 实验性 |
| 安全性 | 无 | SROS2:TLS 加密、权限控制、证书认证 |
| 启动方式 | 需 roscore |
去中心化,无需 Master |
| API 稳定性 | 频繁变动 | 向后兼容承诺(LTS 版本 5 年支持) |
| 生命周期管理 | 无 | Managed Nodes(Unconfigured → Active → Finalized) |
✅ ROS 2 已成为工业界主流(如 Boston Dynamics、宇树科技、NVIDIA Isaac)
三、ROS 2 核心概念(通信层)
1. 节点(Node)
- 最小计算单元,通常一个可执行文件
- 负责单一功能(如激光处理、电机控制)
- 可用 C++、Python 编写
- 示例:
camera_node,nav2_bringup
2. 话题(Topic)— 异步发布/订阅
- 单向、多对多、异步通信
- 数据流:
Publisher → Topic ← Subscriber - 消息类型由
.msg文件定义(如sensor_msgs/Image) - QoS 策略决定传输行为(见下文)
3. 服务(Service)— 同步请求/响应
- 阻塞式、一对一通信
- 用于需立即反馈的操作(如“获取电池电量”)
- 接口由
.srv文件定义(请求/响应用---分隔)
4. 动作(Action)— 长时任务
- 适用于耗时操作(如导航到目标点)
- 包含三部分:
Goal(目标)、Feedback(进度)、Result(结果) - 支持中途取消
5. 参数(Parameter)
- 全局或节点级配置项(如 PID 增益、采样频率)
- 支持动态重配置(运行时修改)
6. QoS(Quality of Service)
DDS 提供的通信策略,关键参数:
| QoS 策略 | 取值 | 适用场景 |
|---|---|---|
| 可靠性 | RELIABLE / BEST_EFFORT |
控制指令用 reliable,摄像头数据可用 best_effort |
| 持久性 | VOLATILE / TRANSIENT_LOCAL |
TRANSIENT_LOCAL 可缓存最后一条消息(新订阅者也能收到) |
| 历史深度 | KEEP_LAST(N) / KEEP_ALL |
限制队列长度,防内存溢出 |
⚠️ 常见问题:Publisher 和 Subscriber 的 QoS 不匹配 → 消息收不到!
四、系统架构(三层模型)
1. 通信层(Communication Layer)
- 节点、话题、服务、动作、QoS
- 底层由 DDS 实现(Fast DDS、Cyclone DDS 等)
2. 系统层(System Layer)
- 工作空间(Workspace):
src/,build/,install/ - 构建系统:
colcon(替代 catkin) - Launch 系统:
.launch.py启动多节点 - TF2:坐标变换系统(
map → odom → base_link) - Bag:记录/回放消息流(调试利器)
3. 应用层(Application Layer)
- 感知:点云处理、目标检测
- SLAM:
slam_toolbox,cartographer - 导航:
Nav2(含 AMCL、Planner、Controller、行为树) - 控制:实时运动控制、关节轨迹跟踪
- 部署:Docker 容器化、CI/CD、安全加固(SROS2)
五、典型工作流程
graph LR
A[创建工作空间] --> B[创建功能包]
B --> C[编写节点代码]
C --> D[colcon build]
D --> E[source install/setup.bash]
E --> F[ros2 run ...]
F --> G[用 ros2 topic/service/action 调试]
G --> H[用 RViz2 可视化]
H --> I[用 ros2 bag 记录复现问题]
六、工程化最佳实践
✅ 项目组织
- 使用
.repos文件管理多仓库依赖 - 分层工作区:
dev_ws(开发)、overlay_ws(集成)、release_ws(交付)
✅ 编程规范
- 所有接口通过
.msg/.srv/.action定义 - 关键参数从 YAML 注入(非硬编码)
- 回调函数中禁止阻塞操作
✅ 通信优化
- 传感器数据:
best_effort + KEEP_LAST(5) - 控制指令:
reliable + transient_local - 启用 Intra-process 通信(零拷贝,提升性能)
✅ 调试策略
- 先用
ros2 bag record录制现场 - 在仿真环境回放(
--clock + use_sim_time:=true) - 用 RViz2 查看 TF、点云、路径是否异常
七、学习路线建议
| 阶段 | 目标 | 内容 |
|---|---|---|
| 入门 | 能写简单节点 | Publisher/Subscriber、Service、Action、QoS |
| 进阶 | 构建完整系统 | Launch、TF2、Bag、参数管理、多线程 Executor |
| 应用 | 实现机器人功能 | SLAM、Nav2、MoveIt、Gazebo 仿真 |
| 工程化 | 交付可靠产品 | SROS2、Docker、CI/CD、性能调优 |
八、官方资源推荐
- 📚 ROS 2 官方文档
- 🧪 ROS 2 教程
- 🗺️ Nav2 导航栈文档
- 🐢 TurtleBot3 示例
- 🎥 The Construct 仿真课程
总结
ROS 2 的本质是“让机器人软件像搭积木一样开发”
- 通过标准化通信解耦模块
- 通过工具链降低调试成本
- 通过生态组件(Nav2/SLAM/MoveIt)加速产品落地
如果你正在开发移动机器人、机械臂、无人机或自动驾驶小车,ROS 2 是当前最成熟、最活跃的开源选择。
3.如何从零搭建 Nav2 导航系统?
从零搭建 ROS 2 的 Nav2(Navigation2)导航系统 是实现移动机器人自主导航的关键一步。Nav2 是 ROS 2 官方推荐的、模块化、可扩展的导航栈,支持 SLAM、定位、路径规划、避障、恢复行为等完整功能。
下面以 Ubuntu 22.04 + ROS 2 Humble 为例,提供一套完整、可复现、面向真实或仿真机器人的搭建流程。
🧰 一、前提条件
1. 系统环境
- Ubuntu 22.04 LTS
- 已安装 ROS 2 Humble Desktop(含
rviz2,gazebo) - 已配置
colcon构建工具
若未安装,请先参考官方安装指南:
https://docs.ros.org/en/humble/Installation.html
2. 依赖安装
sudo apt update
sudo apt install -y \
ros-humble-navigation2 \
ros-humble-nav2-bringup \
ros-humble-turtlebot3-gazebo \
ros-humble-turtlebot3-cartographer \
ros-humble-turtlebot3-navigation2 \
ros-humble-robot-localization \
ros-humble-slam-toolbox
💡 即使你不用 TurtleBot3,这些包也提供了标准的演示和配置模板。
🤖 二、选择机器人平台(以 TurtleBot3 为例)
TurtleBot3 是 Nav2 官方推荐的入门平台,模型轻量、文档齐全。
1. 设置环境变量(必须!)
export TURTLEBOT3_MODEL=burger
export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/opt/ros/humble/share/turtlebot3_gazebo/models
建议写入
~/.bashrc:echo 'export TURTLEBOT3_MODEL=burger' >> ~/.bashrc
2. 启动 Gazebo 仿真环境
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
- 将出现一个带障碍物的室内环境,机器人在原点。
🗺️ 三、方式一:使用 Nav2 预置 Bringup(快速启动)
1. 启动 Nav2 导航栈
ros2 launch nav2_bringup tb3_simulation_launch.py headless:=False
参数说明:
headless:=False:自动启动 RViz2 可视化界面- 默认加载
turtlebot3_world地图(位于nav2_bringup包中)
2. 在 RViz2 中操作
- 点击 2D Pose Estimate 给机器人初始位姿(AMCL 定位需要)
- 点击 Navigation2 Goal 设置目标点
- 机器人将自动规划路径并导航!
✅ 此时你已成功运行 Nav2!
🛠️ 四、方式二:从零构建自己的 Nav2 系统(推荐学习)
步骤 1:创建你的机器人描述包(URDF + TF)
确保你的机器人有:
- 正确的 URDF 模型
- 发布
/tf和/tf_static - 发布
/scan(激光雷达)或/point_cloud(深度相机) - 发布
/odom(里程计)
示例:TurtleBot3 的 URDF 在
turtlebot3_description包中。
步骤 2:准备地图(两种方式)
A. 使用已有地图(.pgm + .yaml)
- 地图文件示例:
map.pgm map.yaml map.yaml内容:image: map.pgm resolution: 0.05 origin: [-10.0, -10.0, 0.0] negate: 0 occupied_thresh: 0.65 free_thresh: 0.196
B. 实时建图(SLAM)
# 使用 SLAM Toolbox
ros2 launch slam_toolbox online_async_launch.py
# 或使用 Cartographer
ros2 launch turtlebot3_cartographer cartographer.launch.py
- 用键盘控制机器人建图:
ros2 run teleop_twist_keyboard teleop_twist_keyboard - 保存地图:
ros2 run nav2_map_server map_saver_cli -f ~/my_map
步骤 3:编写 Nav2 配置文件
创建你的配置目录,例如 ~/my_nav2_config/,包含:
1. nav2_params.yaml
amcl:
ros__parameters:
use_sim_time: True
alpha1: 0.2
alpha2: 0.2
alpha3: 0.2
alpha4: 0.2
base_frame_id: "base_footprint"
beam_skip_distance: 0.5
beam_skip_error_threshold: 0.9
beam_skip_threshold: 0.3
do_beamskip: false
global_frame_id: "map"
lambda_short: 0.1
laser_likelihood_max_dist: 2.0
laser_max_range: 3.5
laser_min_range: 0.12
laser_model_type: "likelihood_field"
max_beams: 60
max_particles: 2000
min_particles: 500
odom_frame_id: "odom"
pf_err: 0.05
pf_z: 0.99
recovery_alpha_fast: 0.0
recovery_alpha_slow: 0.0
resample_interval: 1
robot_model_type: "differential"
save_pose_rate: 0.5
sigma_hit: 0.2
tf_broadcast: true
transform_tolerance: 1.0
update_min_a: 0.2
update_min_d: 0.25
z_hit: 0.5
z_max: 0.05
z_rand: 0.5
z_short: 0.05
bt_navigator:
ros__parameters:
use_sim_time: True
global_frame: map
robot_base_frame: base_link
odom_topic: /odom
default_bt_xml_filename: "navigate_w_replanning_and_recovery.xml"
plugin_lib_names:
- nav2_compute_path_to_pose_action_bt_node
- nav2_follow_path_action_bt_node
- nav2_back_up_action_bt_node
- nav2_spin_action_bt_node
- nav2_wait_action_bt_node
- nav2_clear_costmap_service_bt_node
- nav2_is_stuck_condition_bt_node
- nav2_goal_reached_condition_bt_node
- nav2_initial_pose_received_condition_bt_node
- nav2_reinitialize_global_localization_service_bt_node
- nav2_rate_controller_bt_node
- nav2_distance_controller_bt_node
- nav2_speed_controller_bt_node
- nav2_truncate_path_action_bt_node
- nav2_change_goal_node_bt_node
- nav2_recovery_node_bt_node
- nav2_pipeline_sequence_bt_node
- nav2_round_robin_node_bt_node
- nav2_transform_available_condition_bt_node
- nav2_time_expired_condition_bt_node
- nav2_distance_traveled_condition_bt_node
controller_server:
ros__parameters:
use_sim_time: True
controller_frequency: 20.0
min_x_velocity_threshold: 0.001
min_y_velocity_threshold: 0.5
min_theta_velocity_threshold: 0.001
progress_checker_plugin: "progress_checker"
goal_checker_plugins: ["goal_checker"]
controller_plugins: ["FollowPath"]
# Progress Checker
progress_checker:
plugin: "nav2_controller::SimpleProgressChecker"
required_movement_radius: 0.5
movement_time_allowance: 10.0
# Goal Checker
goal_checker:
plugin: "nav2_controller::SimpleGoalChecker"
xy_tolerance: 0.25
yaw_tolerance: 0.25
# Controller
FollowPath:
plugin: "nav2_regulated_pure_pursuit_controller::RegulatedPurePursuitController"
desired_linear_vel: 0.5
lookahead_dist: 0.6
min_lookahead_dist: 0.3
max_lookahead_dist: 0.9
planner_server:
ros__parameters:
use_sim_time: True
planner_plugins: ["GridBased"]
GridBased:
plugin: "nav2_navfn_planner/NavfnPlanner"
tolerance: 0.5
use_astar: false
allow_unknown: true
behavior_server:
ros__parameters:
costmap_topic: local_costmap/costmap_raw
footprint_topic: local_costmap/published_footprint
cycle_frequency: 10.0
behavior_plugins: ["spin", "backup", "wait"]
spin:
plugin: "nav2_behaviors/Spin"
backup:
plugin: "nav2_behaviors/BackUp"
wait:
plugin: "nav2_behaviors/Wait"
local_costmap:
local_costmap:
ros__parameters:
update_frequency: 5.0
publish_frequency: 2.0
global_frame: odom
robot_base_frame: base_link
use_sim_time: True
rolling_window: true
width: 3
height: 3
resolution: 0.05
plugins: ["obstacle_layer", "inflation_layer"]
obstacle_layer:
plugin: "nav2_costmap_2d::ObstacleLayer"
enabled: True
observation_sources: scan
scan:
topic: /scan
max_obstacle_height: 2.0
clearing: True
marking: True
data_type: "LaserScan"
inflation_layer:
plugin: "nav2_costmap_2d::InflationLayer"
cost_scaling_factor: 3.0
inflation_radius: 0.55
always_send_full_costmap: True
global_costmap:
global_costmap:
ros__parameters:
update_frequency: 1.0
publish_frequency: 1.0
global_frame: map
robot_base_frame: base_link
use_sim_time: True
resolution: 0.05
track_unknown_space: true
plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
static_layer:
plugin: "nav2_costmap_2d::StaticLayer"
map_subscribe_transient_local: True
obstacle_layer:
plugin: "nav2_costmap_2d::ObstacleLayer"
enabled: True
observation_sources: scan
scan:
topic: /scan
max_obstacle_height: 2.0
clearing: True
marking: True
data_type: "LaserScan"
inflation_layer:
plugin: "nav2_costmap_2d::InflationLayer"
cost_scaling_factor: 3.0
inflation_radius: 0.55
2. bt.xml(行为树)
通常使用默认:navigate_w_replanning_and_recovery.xml(位于 nav2_bt_navigator 包中)
步骤 4:编写 Launch 文件
创建 bringup_launch.py:
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription
from launch.substitutions import PathJoinSubstitution
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
pkg_share = FindPackageShare('my_robot_nav2').find('my_robot_nav2')
return LaunchDescription([
# 启动 Nav2
IncludeLaunchDescription(
PathJoinSubstitution([FindPackageShare('nav2_bringup'), 'launch', 'bringup_launch.py']),
launch_arguments={
'use_sim_time': 'True',
'map': PathJoinSubstitution([pkg_share, 'maps', 'my_map.yaml']),
'params_file': PathJoinSubstitution([pkg_share, 'config', 'nav2_params.yaml']),
'default_bt_xml_filename': PathJoinSubstitution([
FindPackageShare('nav2_bt_navigator'),
'behavior_trees',
'navigate_w_replanning_and_recovery.xml'
])
}.items()
),
# 启动 RViz2(可选)
Node(
package='rviz2',
executable='rviz2',
name='rviz2',
arguments=['-d', PathJoinSubstitution([pkg_share, 'rviz', 'nav2.rviz'])],
parameters=[{'use_sim_time': True}],
output='screen'
)
])
步骤 5:启动你的系统
ros2 launch my_robot_nav2 bringup_launch.py
🔍 五、调试与验证
| 问题 | 检查方法 |
|---|---|
| 机器人不动 | ros2 node list 看 controller_server 是否运行;ros2 topic echo /cmd_vel |
| 定位漂移 | 检查 AMCL 参数、激光是否正常、初始位姿是否准确 |
| 路径规划失败 | 查看 global_costmap 是否有未知区域阻挡(allow_unknown: true) |
| 避障失效 | 检查 local_costmap 是否收到 /scan 数据 |
使用 RViz2 添加以下显示:
- Map(全局地图)
- Global Plan / Local Plan
- Costmap(全局 & 局部)
- TF(确保
map → odom → base_link链完整)
📦 六、迁移到真实机器人
- 关闭
use_sim_time(设为false) - 确保真实传感器发布
/scan、/odom - 校准 TF(特别是激光雷达到 base_link 的偏移)
- 调整控制器参数(如最大速度、加速度)
- 考虑使用 robot_localization 融合 IMU + 轮速计
📚 七、学习资源
更多推荐
所有评论(0)