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.txtsetup.py 中配置。
  • Launch 文件:使用 Python 编写 .launch.py 实现多节点启动。
  • 参数管理:通过 YAML 文件或命令行传参。
  • QoS 配置:控制通信可靠性(如传感器数据 vs 控制指令)。
  • DDS 配置:可更换底层通信中间件(Fast DDS、Cyclone DDS 等)。
  • ROS 2 与 Gazebo/Ignition 集成:用于仿真。
  • 安全机制:启用 SROS2(安全 ROS 2)进行身份认证和加密。

📘 五、学习资源


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)

  • 感知:点云处理、目标检测
  • SLAMslam_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 通信(零拷贝,提升性能)

✅ 调试策略

  1. 先用 ros2 bag record 录制现场
  2. 在仿真环境回放(--clock + use_sim_time:=true
  3. 用 RViz2 查看 TF、点云、路径是否异常

七、学习路线建议

阶段 目标 内容
入门 能写简单节点 Publisher/Subscriber、Service、Action、QoS
进阶 构建完整系统 Launch、TF2、Bag、参数管理、多线程 Executor
应用 实现机器人功能 SLAM、Nav2、MoveIt、Gazebo 仿真
工程化 交付可靠产品 SROS2、Docker、CI/CD、性能调优

八、官方资源推荐


总结

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 listcontroller_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 链完整)

📦 六、迁移到真实机器人

  1. 关闭 use_sim_time(设为 false
  2. 确保真实传感器发布 /scan/odom
  3. 校准 TF(特别是激光雷达到 base_link 的偏移)
  4. 调整控制器参数(如最大速度、加速度)
  5. 考虑使用 robot_localization 融合 IMU + 轮速计

📚 七、学习资源


Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐