欢迎光临
我们一直在努力

ROS(Robot Operating System)全面深入详解,入门学习ROS和ROS2

在这里插入图片描述

目录

  • 一、ROS 概述与背景
  • 二、ROS 的核心哲学与设计思想
  • 三、ROS 核心概念详解
  • 四、ROS 架构体系
  • 五、ROS 通信机制深度解析
  • 六、ROS 开发环境搭建
  • 七、ROS 核心工具链
  • 八、ROS 常用功能包与生态
  • 九、ROS2 vs ROS1:为什么需要 ROS2
  • 十、ROS2 核心概念与新特性
  • 十一、ROS2 通信机制详解
  • 十二、ROS2 开发环境与工具
  • 十三、SLAM(同时定位与地图构建)
  • 十四、Navigation 导航栈
  • 十五、机械臂控制与 MoveIt
  • 十六、仿真环境
  • 十七、ROS 与传感器
  • 十八、ROS 与视觉/AI
  • 十九、ROS 项目实战开发流程
  • 二十、学习路线图与资源推荐
  • 附录:常见问题与排错

一、ROS 概述与背景

1.1 什么是 ROS

ROS(Robot Operating System)并不是一个传统意义上的操作系统,而是一个机器人软件开发框架。它提供了一套标准的通信机制、开发工具、库函数和约定,使得开发者可以更加高效地构建复杂的机器人应用。

通俗理解:如果说操作系统(如 Windows/Linux)管理的是计算机硬件资源,那么 ROS 管理的就是机器人各组件之间的协作。它就像是机器人的"神经系统",负责连接感知模块(眼睛/耳朵)、决策模块(大脑)和执行模块(手脚)。

1.2 ROS 的诞生与发展

时间节点事件
2007年 Willow Garage 公司开始开发 ROS
2010年 ROS 1.0 正式发布(基于 Ubuntu)
2012年 ROS 成为机器人领域事实上的标准框架
2017年 ROS2 的第一个正式版本发布
2020年 ROS1 Noetic 发布(最后一个 ROS1 版本,2025年 EOL)
2022年 ROS2 Humble 发布(LTS 长期支持版本)
2023年 ROS2 Iron 发布
2024年 ROS2 Jazzy 发布(LTS 长期支持版本)

1.3 为什么选择 ROS

  • 标准化:提供了统一的通信协议和接口标准,不同团队开发的模块可以无缝集成
  • 模块化:采用松耦合架构,每个功能模块可以独立开发、测试和替换
  • 生态丰富:拥有数千个开源功能包,涵盖导航、SLAM、机械臂控制、视觉处理等
  • 社区活跃:全球最大的机器人开发者社区,文档、教程、问答资源丰富
  • 跨平台:ROS2 支持 Linux、Windows、macOS 甚至嵌入式系统
  • 工业级应用:被 NASA、波士顿动力、Fetch Robotics 等广泛采用
  • 1.4 ROS 适用场景

    • 移动机器人(AGV、AMR)导航与避障
    • 机械臂运动规划与控制
    • 无人驾驶(与 Autoware 等结合)
    • 无人机飞控与编队
    • 人形机器人控制
    • 巡检、配送、清洁等服务机器人
    • 工业自动化与智能制造
    • 学术研究与教育

    二、ROS 的核心哲学与设计思想

    2.1 点对点设计(Peer-to-Peer)

    ROS 采用点对点的通信架构。每个功能模块(节点)可以独立运行在不同的计算机上,通过网络直接通信,而不是依赖一个中心服务器。

    ┌──────────────┐ Topic: /camera/image ┌──────────────┐
    │ 相机节点 │ ==========================> │ 视觉处理节点 │
    │ (电脑A) │ │ (电脑B) │
    └──────────────┘ └──────────────┘

    2.2 不重复造轮子(Re-use)

    ROS 鼓励代码复用。已有的功能包可以直接拿来使用,开发者只需要关注自己需要创新的部分。

    2.3 语言无关性

    ROS 的核心通信层是用 C++ 实现的,但它提供了 Python、C++、Java、Lua 等多语言的客户端接口(Client Library)。

    2.4 松耦合架构

    节点之间通过消息(Message)进行通信,而不是直接调用彼此的函数。这意味着:

    • 节点可以随时启动或关闭,不影响其他节点
    • 可以方便地替换任何节点的实现
    • 可以在不同语言编写的节点之间通信

    2.5 工具化思维

    ROS 提供了大量的可视化、调试和分析工具,而不是将这些功能嵌入到框架本身,保持了核心的轻量化。


    三、ROS 核心概念详解

    3.1 节点(Node)

    节点是 ROS 中最基本的执行单元,每个节点负责机器人的一项具体功能。

    一个机器人系统可能包含的节点:
    ├── /base_controller → 底盘运动控制
    ├── /lidar_driver → 激光雷达驱动
    ├── /camera_driver → 相机驱动
    ├── /slam_node → SLAM建图
    ├── /navigation_node → 导航规划
    ├── /obstacle_detector → 障碍物检测
    └── /battery_monitor → 电池监控

    节点的特点:

    • 一个节点是一个进程(Process)
    • 一个节点通常只负责一件事(单一职责原则)
    • 节点可以在同一台机器上运行,也可以分布在不同机器上
    • 每个节点在 ROS 网络中有一个唯一的名称

    节点生命周期:

    创建 → 初始化(注册到Master) → 运行(发布/订阅/服务) → 关闭(注销)

    3.2 消息(Message)

    消息是节点之间通信的数据载体,定义了传输数据的结构。

    消息文件(.msg)定义示例:

    # geometry_msgs/Point.msg
    float64 x
    float64 y
    float64 z

    # sensor_msgs/LaserScan.msg
    std_msgs/Header header
    float32 angle_min
    float32 angle_max
    float32 angle_increment
    float32 time_increment
    float32 scan_time
    float32 range_min
    float32 range_max
    float32[] ranges
    float32[] intensities

    常见消息类型分类:

    包名用途常见消息
    std_msgs 基础数据类型 Int32, Float64, String, Bool
    geometry_msgs 几何信息 Twist, Pose, Point, Quaternion
    sensor_msgs 传感器数据 LaserScan, Image, Imu, PointCloud2
    nav_msgs 导航相关 Odometry, OccupancyGrid, Path
    actionlib_msgs 动作相关 GoalID, GoalStatus

    消息的嵌套与组合:

    # geometry_msgs/Pose.msg (嵌套了Point和Quaternion)
    geometry_msgs/Point position
    geometry_msgs/Quaternion orientation

    # geometry_msgs/Twist.msg (嵌套了Vector3)
    geometry_msgs/Vector3 linear
    geometry_msgs/Vector3 angular

    3.3 话题(Topic)

    话题是 ROS 中最常用的异步通信机制,基于发布-订阅(Publish-Subscribe)模型。

    发布者 订阅者
    ┌─────┐ ┌──────────┐
    │节点A│ ──发布──> [/chatter] ──> │ 节点B │
    └─────┘ │ └──────────┘
    │ ┌──────────┐
    └──────────> │ 节点C │
    └──────────┘

    话题的关键特性:

    • 异步通信:发布者发送消息后不等待订阅者接收
    • 一对多:一个话题可以有多个订阅者
    • 多对一:多个发布者可以向同一个话题发布消息
    • 解耦:发布者和订阅者不需要知道对方的存在
    • 有类型:每个话题只能传输一种类型的消息

    话题 vs 消息的区别:

    • 话题是通信的通道(管道)
    • 消息是通道中传输的数据(水)

    3.4 服务(Service)

    服务是 ROS 中的同步通信机制,基于请求-响应(Request-Response)模型。

    客户端(Client) 服务端(Server)
    ┌─────┐ ┌─────┐
    │节点A│ ──请求(Request)──> │节点B│
    │ │ <──响应(Response)── │ │
    └─────┘ └─────┘

    服务 vs 话题的对比:

    特性话题(Topic)服务(Service)
    通信模式 发布-订阅(异步) 请求-响应(同步)
    实时性 持续发送 一次请求一次响应
    适用场景 传感器数据流、状态广播 查询状态、触发动作
    多对多 支持 一对一
    流量 可能很大(如30Hz图像) 通常很小

    服务文件(.srv)示例:

    # AddTwoInts.srv
    int64 a
    int64 b
    —
    int64 sum

    上面的 — 分隔了请求和响应部分。

    3.5 动作(Action)

    动作是 ROS 中用于长时间任务的通信机制,基于目标-反馈-结果模型。

    客户端 服务端
    ┌─────┐ ┌─────┐
    │ │ ──目标(Goal)──────> │ │
    │ │ <──反馈(Feedback)── ··· │ │ ← 可以持续发送多次反馈
    │ │ <──反馈(Feedback)── ··· │ │
    │ │ <──结果(Result)──── │ │
    └─────┘ └─────┘

    动作的三部分:

  • Goal(目标):客户端发送任务目标
  • Feedback(反馈):服务端周期性反馈执行进度
  • Result(结果):任务完成后返回最终结果
  • 动作 vs 服务的对比:

    特性服务动作
    执行时间 短(毫秒级) 长(秒到分钟)
    反馈 无 有周期性反馈
    取消 不支持 支持取消
    典型应用 查询电池电量 导航到目标点

    动作文件(.action)示例:

    # NavigateToGoal.action
    geometry_msgs/PoseStamped target_pose
    —
    geometry_msgs/PoseStamped final_pose
    —
    float32 distance_remaining
    float32 progress_percent

    三个 — 分隔了目标(Goal)、结果(Result)和反馈(Feedback)。

    3.6 参数(Parameter)

    参数是 ROS 中的全局共享数据存储机制,类似于一个分布式的键值数据库。

    # 设置参数
    rosparam set /robot_name "turtlebot3"

    # 获取参数
    rosparam get /robot_name

    # 列出所有参数
    rosparam list

    # 从 YAML 文件加载参数
    rosparam load params.yaml

    参数的用途:

    • 存储机器人配置(如轮距、最大速度)
    • 存储传感器校准数据
    • 存储算法超参数
    • 存储坐标变换参数

    参数服务器的特性:

    • 全局共享:所有节点都可以读取
    • 可以存储基本类型(int, float, string, bool)以及列表、字典
    • 运行时可以动态修改(不需要重启节点)
    • 由 ROS Master 管理

    3.7 坐标系与 TF 变换

    TF(Transform)是 ROS 中管理多坐标系关系的系统。

    为什么需要 TF? 一个机器人有多个传感器和执行器,每个都有自己的坐标系:

    /map(地图坐标系)
    │
    /odom(里程计坐标系)
    │
    /base_link(机器人本体坐标系)
    ╱ │ ╲
    /arm_base /laser /camera_link

    TF 的核心功能:

    • 实时维护多个坐标系之间的变换关系
    • 查询任意两个坐标系之间的变换(旋转 + 平移)
    • 支持时间回溯(查询历史时刻的变换)

    TF 广播示例(Python):

    import tf2_ros
    import geometry_msgs.msg

    # 广播 TF 变换
    broadcaster = tf2_ros.TransformBroadcaster()
    transform = geometry_msgs.msg.TransformStamped()
    transform.header.stamp = rospy.Time.now()
    transform.header.frame_id = "odom"
    transform.child_frame_id = "base_link"
    transform.transform.translation.x = 1.0
    transform.transform.translation.y = 0.5
    transform.transform.rotation.w = 1.0
    broadcaster.sendTransform(transform)

    TF 监听示例(Python):

    import tf2_ros

    # 监听 TF 变换
    tf_buffer = tf2_ros.Buffer()
    listener = tf2_ros.TransformListener(tf_buffer)

    # 查询 base_link 在 odom 坐标系下的位姿
    transform = tf_buffer.lookup_transform("odom", "base_link", rospy.Time(0))

    3.8 Launch 文件

    Launch 文件用于同时启动多个节点以及配置相关参数。

    XML 格式(ROS1 传统格式):

    <launch>
    <!– 设置参数 –>
    <param name="robot_name" value="my_robot"/>

    <!– 启动节点 –>
    <node pkg="turtlesim" type="turtlesim_node" name="turtle_sim" output="screen"/>
    <node pkg="turtlesim" type="turtle_teleop_key" name="turtle_teleop" output="screen"/>

    <!– 包含其他 launch 文件 –>
    <include file="$(find my_robot)/launch/base.launch"/>

    <!– 条件启动 –>
    <arg name="use_rviz" default="true"/>
    <node pkg="rviz" type="rviz" name="rviz" if="$(arg use_rviz)"/>
    </launch>

    Python 格式(ROS2 推荐):

    from launch import LaunchDescription
    from launch_ros.actions import Node
    from launch.actions import DeclareLaunchArgument
    from launch.substitutions import LaunchConfiguration

    def generate_launch_description():
    return LaunchDescription([
    DeclareLaunchArgument('use_rviz', default_value='true'),
    Node(
    package='turtlesim',
    executable='turtlesim_node',
    name='turtle_sim',
    output='screen'
    ),
    Node(
    package='rviz2',
    executable='rviz2',
    name='rviz',
    condition=IfCondition(LaunchConfiguration('use_rviz'))
    ),
    ])

    3.9 功能包(Package)

    功能包是 ROS 中代码组织的基本单位,类似于项目/模块。

    功能包的目录结构:

    my_robot_package/
    ├── CMakeLists.txt # 编译配置(必须)
    ├── package.xml # 包描述文件(必须)
    ├── launch/ # launch 文件目录
    │ └── bringup.launch.py
    ├── config/ # 配置文件目录
    │ └── params.yaml
    ├── src/ # C++ 源代码
    │ └── my_node.cpp
    ├── scripts/ # Python 脚本
    │ └── my_node.py
    ├── msg/ # 自定义消息
    │ └── MyMessage.msg
    ├── srv/ # 自定义服务
    │ └── MyService.srv
    ├── action/ # 自定义动作
    │ └── MyAction.action
    ├── urdf/ # 机器人模型文件
    │ └── robot.urdf
    └── worlds/ # 仿真世界文件
    └── empty.world

    package.xml 示例:

    <?xml version="1.0"?>
    <package format="2">
    <name>my_robot_package</name>
    <version>0.1.0</version>
    <description>我的机器人功能包</description>
    <maintainer email="me@example.com">myname</maintainer>
    <license>Apache-2.0</license>

    <buildtool_depend>ament_cmake</buildtool_depend>

    <depend>rclcpp</depend>
    <depend>std_msgs</depend>
    <depend>geometry_msgs</depend>
    <exec_depend>robot_state_publisher</exec_depend>
    <test_depend>ament_lint_auto</test_depend>

    <export>
    <build_type>ament_cmake</build_type>
    </export>
    </package>


    四、ROS 架构体系

    4.1 三层架构

    ROS 的架构可以分为三个层次:

    ┌─────────────────────────────────────────────────┐
    │ 社区级 (Community Level) │
    │ ROS Wiki · 软件包仓库 · 邮件列表 · 论坛 │
    ├─────────────────────────────────────────────────┤
    │ 计算图级 (Computation Graph Level) │
    │ Master · Node · Topic · Service · Action │
    │ Parameter Server · TF │
    ├─────────────────────────────────────────────────┤
    │ 文件系统级 (Filesystem Level) │
    │ Workspace · Package · Message · Service File │
    │ Action File · Launch File · URDF │
    └─────────────────────────────────────────────────┘

    4.2 文件系统级

    工作空间(Workspace)结构:

    catkin_ws/ (ROS1 工作空间)
    ├── src/ # 源代码空间
    │ ├── CMakeLists.txt # 由 catkin_init_workspace 生成
    │ ├── package_a/
    │ └── package_b/
    ├── build/ # 编译空间(自动生成)
    ├── devel/ # 开发空间(自动生成)
    └── install/ # 安装空间(可选)

    ros2_ws/ (ROS2 工作空间)
    ├── src/
    │ ├── package_a/
    │ └── package_b/
    ├── build/ # 编译空间
    ├── install/ # 安装空间
    └── log/ # 日志空间

    4.3 计算图级(ROS1)

    ROS1 中有一个重要的角色——ROS Master(主节点):

    ┌──────────────────────────────────────────────────────┐
    │ ROS Master │
    │ (维护节点注册表和话题/服务查找) │
    │ │
    │ 注册信息: │
    │ – /talker 节点 → 发布 /chatter 话题 │
    │ – /listener 节点 → 订阅 /chatter 话题 │
    │ │
    └───────────┬──────────────────────────┬───────────────┘
    │ 注册/查找 │ 注册/查找
    ▼ ▼
    ┌───────────┐ ┌───────────┐
    │ /talker │ ──消息──> │ /listener │
    │ (发布者) │ (P2P通信) │ (订阅者) │
    └───────────┘ └───────────┘

    ROS Master 的作用:

  • 节点注册:每个节点启动时向 Master 注册自己的信息
  • 名称服务:帮助节点找到其他节点的网络地址
  • 参数管理:存储和管理全局参数
  • 重要:Master 只负责"牵线搭桥",实际的数据传输是节点之间直接进行的。

    4.4 ROS2 架构的变化

    ROS2 移除了中心化的 Master,采用了更加分布式的架构:

    ROS1: 节点 → Master → 节点(需要Master中转)
    ROS2: 节点 ←→ 节点(通过DDS直接发现和通信)

    ROS2 使用 DDS(Data Distribution Service) 作为底层通信中间件,实现了:

    • 去中心化的节点自动发现
    • 更好的实时性
    • 跨网络通信
    • 更高的可靠性

    五、ROS 通信机制深度解析

    5.1 话题通信详细流程(ROS1)

    步骤1: Talker 启动,向 Master 注册
    Talker → Master: "我是 /talker,我要发布 /chatter 话题"

    步骤2: Listener 启动,向 Master 注册
    Listener → Master: "我是 /listener,我要订阅 /chatter 话题"

    步骤3: Master 通知 Listener
    Master → Listener: "/talker 有你要的 /chatter 话题,它的地址是 xxx"

    步骤4: Listener 向 Talker 发起连接
    Listener → Talker: "我要订阅 /chatter"

    步骤5: Talker 确认连接,开始发送数据
    Talker → Listener: [消息数据流…]

    步骤6: 之后的数据传输不再经过 Master(P2P通信)

    代码示例 – 发布者(Python):

    #!/usr/bin/env python3
    import rospy
    from std_msgs.msg import String

    def talker():
    rospy.init_node('talker', anonymous=True)
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rate = rospy.Rate(10) # 10Hz

    while not rospy.is_shutdown():
    hello_str = "hello world %s" % rospy.get_time()
    rospy.loginfo(hello_str)
    pub.publish(hello_str)
    rate.sleep()

    if __name__ == '__main__':
    talker()

    代码示例 – 订阅者(Python):

    #!/usr/bin/env python3
    import rospy
    from std_msgs.msg import String

    def callback(data):
    rospy.loginfo("I heard: %s", data.data)

    def listener():
    rospy.init_node('listener', anonymous=True)
    rospy.Subscriber('chatter', String, callback)
    rospy.spin() # 保持节点运行

    if __name__ == '__main__':
    listener()

    ROS2 版本 – 发布者(Python):

    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.1 # 10Hz
    self.timer = self.create_timer(timer_period, self.timer_callback)

    def timer_callback(self):
    msg = String()
    msg.data = f'Hello World: {self.get_clock().now()}'
    self.publisher_.publish(msg)
    self.get_logger().info(f'Publishing: "{msg.data}"')

    def main():
    rclpy.init()
    node = Talker()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

    if __name__ == '__main__':
    main()

    ROS2 版本 – 订阅者(Python):

    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.callback, 10)

    def callback(self, msg):
    self.get_logger().info(f'I heard: "{msg.data}"')

    def main():
    rclpy.init()
    node = Listener()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

    if __name__ == '__main__':
    main()

    5.2 服务通信详细流程

    步骤1: Server 启动,向 Master 注册服务
    步骤2: Client 向 Master 查询服务地址
    步骤3: Client 向 Server 发送请求
    步骤4: Server 处理请求,返回响应
    步骤5: Client 收到响应

    服务端代码示例(ROS2 Python):

    import rclpy
    from rclpy.node import Node
    from example_interfaces.srv import AddTwoInts

    class AddTwoIntsServer(Node):
    def __init__(self):
    super().__init__('add_two_ints_server')
    self.srv = self.create_service(
    AddTwoInts, 'add_two_ints', self.callback)
    self.get_logger().info('Service ready.')

    def callback(self, request, response):
    response.sum = request.a + request.b
    self.get_logger().info(
    f'Request: {request.a} + {request.b} = {response.sum}')
    return response

    def main():
    rclpy.init()
    node = AddTwoIntsServer()
    rclpy.spin(node)
    rclpy.shutdown()

    客户端代码示例(ROS2 Python):

    import rclpy
    from rclpy.node import Node
    from example_interfaces.srv import AddTwoInts

    class AddTwoIntsClient(Node):
    def __init__(self):
    super().__init__('add_two_ints_client')
    self.client = self.create_client(AddTwoInts, 'add_two_ints')
    while not self.client.wait_for_service(timeout_sec=1.0):
    self.get_logger().info('Waiting for service…')
    self.request = AddTwoInts.Request()

    def send_request(self, a, b):
    self.request.a = a
    self.request.b = b
    return self.client.call_async(self.request)

    def main():
    rclpy.init()
    node = AddTwoIntsClient()
    future = node.send_request(3, 5)
    rclpy.spin_until_future_complete(node, future)
    result = future.result()
    node.get_logger().info(f'Result: {result.sum}')
    node.destroy_node()
    rclpy.shutdown()

    5.3 动作通信详细流程

    动作端代码示例(ROS2 Python – Server):

    import rclpy
    from rclpy.node import Node
    from rclpy.action import ActionServer
    from example_interfaces.action import Fibonacci

    class FibonacciServer(Node):
    def __init__(self):
    super().__init__('fibonacci_server')
    self._action_server = ActionServer(
    self, Fibonacci, 'fibonacci', self.execute_callback)

    async def execute_callback(self, goal_handle):
    self.get_logger().info('Executing goal…')
    feedback_msg = Fibonacci.Feedback()
    feedback_msg.sequence = [0, 1]

    for i in range(1, goal_handle.request.order):
    feedback_msg.sequence.append(
    feedback_msg.sequence[–1] + feedback_msg.sequence[–2])
    goal_handle.publish_feedback(feedback_msg)
    self.get_logger().info(f'Feedback: {feedback_msg.sequence}')

    goal_handle.succeed()
    result = Fibonacci.Result()
    result.sequence = feedback_msg.sequence
    return result

    5.4 参数通信

    ROS2 参数使用示例:

    class MyNode(Node):
    def __init__(self):
    super().__init__('param_node')
    # 声明参数(带默认值)
    self.declare_parameter('speed', 1.0)
    self.declare_parameter('robot_name', 'default_robot')

    # 获取参数值
    speed = self.get_parameter('speed').value
    name = self.get_parameter('robot_name').value

    # 动态参数回调
    self.add_on_set_parameters_callback(self.param_callback)

    def param_callback(self, params):
    for param in params:
    if param.name == 'speed':
    self.get_logger().info(f'Speed changed to: {param.value}')
    return SetParametersResult(successful=True)


    六、ROS 开发环境搭建

    6.1 操作系统选择

    操作系统ROS版本推荐度
    Ubuntu 20.04 ROS1 Noetic / ROS2 Foxy ⭐⭐⭐⭐
    Ubuntu 22.04 ROS2 Humble(LTS) ⭐⭐⭐⭐⭐
    Ubuntu 24.04 ROS2 Jazzy(LTS) ⭐⭐⭐⭐⭐
    Windows 10/11 ROS2(部分支持) ⭐⭐⭐
    macOS ROS2(实验性) ⭐⭐

    推荐:新手建议使用 Ubuntu 22.04 + ROS2 Humble 或 Ubuntu 24.04 + ROS2 Jazzy。

    6.2 安装 ROS2 Humble(Ubuntu 22.04)

    # 1. 设置语言环境
    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. 设置环境变量
    echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
    source ~/.bashrc

    # 5. 安装开发工具
    sudo apt install python3-colcon-common-extensions python3-rosdep2

    # 6. 初始化 rosdep
    sudo rosdep init
    rosdep update

    6.3 安装 ROS1 Noetic(Ubuntu 20.04)

    # 1. 添加 ROS 软件源
    sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
    curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add –

    # 2. 安装 ROS
    sudo apt update
    sudo apt install ros-noetic-desktop-full

    # 3. 设置环境变量
    echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
    source ~/.bashrc

    # 4. 安装依赖管理工具
    sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
    sudo rosdep init
    rosdep update

    6.4 使用 Docker 环境(推荐新手尝试)

    # 拉取 ROS2 Humble 镜像
    docker pull ros:humble-desktop

    # 运行容器(带 GUI 支持)
    docker run -it \\
    –env DISPLAY=$DISPLAY \\
    –volume /tmp/.X11-unix:/tmp/.X11-unix \\
    –net=host \\
    ros:humble-desktop

    # 在容器中测试
    ros2 run demo_nodes_cpp talker

    6.5 使用虚拟机

    对于不想更换操作系统的用户:

  • 安装 VirtualBox 或 VMware
  • 下载 Ubuntu 22.04 ISO
  • 创建虚拟机(建议分配 4GB+ 内存,20GB+ 硬盘)
  • 在虚拟机中安装 ROS2
  • 注意:虚拟机中无法使用 GPU 加速,性能会有限制。对于图形化仿真(如 Gazebo)可能体验较差。

    6.6 WSL2 方案(Windows 用户)

    # 在 Windows PowerShell 中执行
    wsl —install –d Ubuntu-22.04

    # 重启后进入 Ubuntu,按上述步骤安装 ROS2 Humble
    # 注意:WSL2 中 GUI 支持需要安装 WSLg(Windows 11 自带)


    七、ROS 核心工具链

    7.1 命令行工具

    ROS1 命令行工具

    # ===== 节点相关 =====
    rosnode list # 列出所有运行中的节点
    rosnode info /node_name # 查看节点信息
    rosnode ping /node_name # 测试节点连接
    rosnode kill /node_name # 杀死节点

    # ===== 话题相关 =====
    rostopic list # 列出所有活跃话题
    rostopic info /topic_name # 查看话题信息(类型、发布者、订阅者)
    rostopic echo /topic_name # 实时打印话题消息
    rostopic hz /topic_name # 查看话题发布频率
    rostopic pub /topic_name msg_type "data: 'hello'" # 手动发布消息
    rostopic type /topic_name # 查看消息类型

    # ===== 服务相关 =====
    rosservice list # 列出所有服务
    rosservice info /service_name # 查看服务信息
    rosservice call /service_name "args" # 调用服务

    # ===== 参数相关 =====
    rosparam list # 列出所有参数
    rosparam get /param_name # 获取参数值
    rosparam set /param_name value # 设置参数值
    rosparam dump params.yaml # 导出参数到文件
    rosparam load params.yaml # 从文件加载参数

    # ===== 消息/服务类型 =====
    rosmsg show msg_type # 查看消息结构
    rossrv show srv_type # 查看服务结构
    rosmsg list # 列出所有消息类型

    # ===== 日志 =====
    roscd log # 进入日志目录
    rqt_console # 图形化日志查看器

    # ===== 系统 =====
    rospack find package_name # 查找功能包路径
    rosls package_name # 列出功能包内容
    roscd package_name # 进入功能包目录

    ROS2 命令行工具

    # ===== 节点相关 =====
    ros2 node list # 列出所有节点
    ros2 node info /node_name # 查看节点信息

    # ===== 话题相关 =====
    ros2 topic list # 列出所有话题
    ros2 topic list -t # 列出话题及其类型
    ros2 topic info /topic_name # 查看话题信息
    ros2 topic echo /topic_name # 打印话题消息
    ros2 topic hz /topic_name # 查看发布频率
    ros2 topic pub /topic_name msg_type "{data: hello}" # 发布消息

    # ===== 服务相关 =====
    ros2 service list # 列出所有服务
    ros2 service list -t # 列出服务及其类型
    ros2 service call /service_name type_name "{args}" # 调用服务

    # ===== 动作相关 =====
    ros2 action list # 列出所有动作
    ros2 action info /action_name # 查看动作信息
    ros2 action send_goal /action_name type_name "{args}" # 发送动作目标

    # ===== 参数相关 =====
    ros2 param list # 列出所有参数
    ros2 param get /node_name param_name # 获取参数
    ros2 param set /node_name param_name value # 设置参数
    ros2 param dump /node_name # 导出节点参数

    # ===== 包管理 =====
    ros2 pkg list # 列出所有已安装的包
    ros2 pkg executables package_name # 列出包的可执行文件
    ros2 pkg create my_package # 创建新功能包

    # ===== 运行节点 =====
    ros2 run package_name executable # 运行节点
    ros2 launch package_name launch_file.py # 运行launch文件

    # ===== 调试工具 =====
    ros2 doctor # 系统诊断
    ros2 bag record /topic_name # 录制话题数据
    ros2 bag play bag_file # 回放数据

    7.2 可视化工具

    RViz(Robot Visualization)

    RViz 是 ROS 中最重要的3D可视化工具,用于显示:

    • 机器人模型(URDF)
    • 激光雷达点云
    • 相机图像
    • 地图
    • 路径规划
    • 坐标系变换
    • 标记(Markers)

    # ROS1
    rviz

    # ROS2
    ros2 run rviz2 rviz2

    RViz 常用显示类型:

    显示类型用途
    RobotModel 显示机器人3D模型
    LaserScan 显示激光雷达数据
    PointCloud2 显示3D点云
    Image 显示相机图像
    Map 显示2D栅格地图
    Path 显示路径
    Pose 显示位姿
    Marker 显示自定义标记
    TF 显示坐标系关系
    Odometry 显示里程计轨迹
    RQt 工具集

    RQt 是基于 Qt 的图形化工具集:

    rqt # 启动 rqt 综合界面
    rqt_graph # 显示节点之间的连接关系图
    rqt_plot # 实时绘制数据曲线
    rqt_console # 日志查看器
    rqt_tf_tree # 查看 TF 坐标树
    rqt_image_view # 查看图像话题
    rqt_reconfigure # 动态参数调节

    Foxglove Studio(ROS2 推荐)

    Foxglove Studio 是一个现代化的 ROS 可视化工具,支持 Web 端使用:

    • 3D 面板
    • 图表面板
    • 图像面板
    • 地图面板
    • 支持 ROS bag 回放
    • 支持远程连接

    7.3 数据录制与回放(rosbag)

    rosbag 是 ROS 的数据录制工具,可以录制话题数据并回放,用于:

    • 记录实验数据
    • 离线调试算法
    • 数据集创建

    # ROS1
    rosbag record -a # 录制所有话题
    rosbag record /camera/image /scan # 录制指定话题
    rosbag play data.bag # 回放数据
    rosbag info data.bag # 查看 bag 文件信息

    # ROS2
    ros2 bag record -a # 录制所有话题
    ros2 bag record /camera/image /scan # 录制指定话题
    ros2 bag play data/ # 回放数据(ROS2 bag 是目录格式)
    ros2 bag info data/ # 查看信息

    7.4 构建工具

    构建工具ROS版本说明
    catkin ROS1 基于 CMake 的构建系统
    colcon ROS2 通用构建工具,支持 CMake/Python
    ament ROS2 ROS2 的构建框架

    # catkin(ROS1)
    mkdir -p catkin_ws/src
    cd catkin_ws/src
    catkin_init_workspace
    cd ..
    catkin_make
    source devel/setup.bash

    # colcon(ROS2)
    mkdir -p ros2_ws/src
    cd ros2_ws/src
    ros2 pkg create my_package –build-type ament_cmake
    cd ..
    colcon build
    source install/setup.bash

    # 只编译特定包
    colcon build –packages-select my_package

    # 编译并开启并行
    colcon build –parallel-workers 4

    # 编译后自动 source
    colcon build && source install/setup.bash


    八、ROS 常用功能包与生态

    8.1 导航相关

    功能包说明
    navigation / nav2 ROS1/ROS2 导航栈(路径规划、避障)
    gmapping 基于激光雷达的 SLAM
    cartographer Google 开源的 SLAM
    slam_toolbox ROS2 推荐的 SLAM 工具
    amcl 自适应蒙特卡洛定位
    robot_localization 多传感器融合定位
    teb_local_planner 局部路径规划器

    8.2 机械臂控制

    功能包说明
    moveit / moveit2 机械臂运动规划框架
    ros_control / ros2_control 硬件抽象和控制框架
    kdl 运动学/动力学求解器
    trac_ik 逆运动学求解器
    ros_industrial 工业机器人接口

    8.3 仿真

    功能包说明
    gazebo / gazebo_classic / ignition 物理仿真器
    turtlebot3_simulations TurtleBot3 仿真
    turtlebot4_simulator TurtleBot4 仿真
    carla 自动驾驶仿真
    air_sim 无人机仿真
    webots Webots 仿真器 ROS 接口

    8.4 感知与视觉

    功能包说明
    cv_bridge OpenCV 与 ROS 图像消息转换
    image_transport 高效图像传输
    vision_opencv 计算机视觉工具
    darknet_ros YOLO 目标检测
    perception_pcl 点云处理
    aruco_ros ArUco 标记检测
    depthai_ros OAK 相机驱动

    8.5 常用机器人平台

    平台说明
    TurtleBot3/4 最流行的 ROS 学习/研究平台
    PR2 Willow Garage 的研究机器人
    Fetch 仓库机器人
    Universal Robots (UR) 工业机械臂
    Franka Emika 协作机械臂
    DJI Robomaster 教育机器人

    8.6 URDF 与机器人建模

    URDF(Unified Robot Description Format) 是 ROS 中描述机器人模型的标准 XML 格式。

    <?xml version="1.0"?>
    <robot name="my_robot">

    <!– 基座连杆 –>
    <link name="base_link">
    <visual>
    <geometry>
    <box size="0.5 0.3 0.1"/>
    </geometry>
    <material name="blue">
    <color rgba="0 0 0.8 1"/>
    </material>
    </visual>
    <collision>
    <geometry>
    <box size="0.5 0.3 0.1"/>
    </geometry>
    </collision>
    <inertial>
    <mass value="10.0"/>
    <inertia ixx="0.1" ixy="0" ixz="0"
    iyy="0.1" iyz="0" izz="0.1"/>

    </inertial>
    </link>

    <!– 左轮连杆 –>
    <link name="left_wheel">
    <visual>
    <geometry>
    <cylinder radius="0.1" length="0.05"/>
    </geometry>
    </visual>
    </link>

    <!– 左轮关节(连续旋转) –>
    <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="0 0.175 0" rpy="-1.5708 0 0"/>
    <axis xyz="0 0 1"/>
    </joint>

    </robot>

    URDF 关节类型:

    类型说明
    fixed 固定关节,不可移动
    revolute 旋转关节,有角度限制
    continuous 连续旋转关节,无角度限制
    prismatic 棱柱形关节(滑动)
    floating 浮动关节(6自由度)
    planar 平面关节

    URDF 查看工具:

    # 可视化 URDF
    ros2 run urdf_tutorial display model.launch.py model:=my_robot.urdf

    # 使用 RViz 查看
    ros2 run robot_state_publisher robot_state_publisher –ros-args -p robot_description:="$(cat my_robot.urdf)"

    Xacro(XML Macro) 是 URDF 的增强版,支持宏定义、变量、条件判断:

    <!– 定义变量 –>
    <xacro:property name="wheel_radius" value="0.1"/>

    <!– 定义宏 –>
    <xacro:macro name="wheel" params="name parent y_offset">
    <link name="${name}">
    <visual>
    <geometry>
    <cylinder radius="${wheel_radius}" length="0.05"/>
    </geometry>
    </visual>
    </link>
    <joint name="${name}_joint" type="continuous">
    <parent link="${parent}"/>
    <child link="${name}"/>
    <origin xyz="0 ${y_offset} 0" rpy="-1.5708 0 0"/>
    <axis xyz="0 0 1"/>
    </joint>
    </xacro:macro>

    <!– 使用宏 –>
    <xacro:wheel name="left_wheel" parent="base_link" y_offset="0.175"/>
    <xacro:wheel name="right_wheel" parent="base_link" y_offset="-0.175"/>


    九、ROS2 vs ROS1:为什么需要 ROS2

    9.1 ROS1 的局限性

    问题详细说明
    依赖 Master 单点故障,Master 挂了整个系统不工作
    实时性差 基于 TCP/UDP,无法保证实时性
    不支持跨网络 同一局域网内通信,难以实现云机器人
    构建系统不规范 catkin 构建系统复杂,新手学习成本高
    不支持多机器人 多机器人系统需要复杂的命名空间配置
    安全性差 没有认证和加密机制
    仅支持 Linux 主要支持 Ubuntu,跨平台困难

    9.2 ROS2 的改进

    改进项详细说明
    去中心化 使用 DDS 实现节点自动发现,无需 Master
    实时支持 支持实时调度,满足工业级实时要求
    跨平台 支持 Linux、Windows、macOS、嵌入式
    安全性 支持 SROS2(安全 ROS2),提供认证和加密
    多机器人 原生支持多机器人系统和命名空间
    构建系统 使用 colcon + ament,更简洁标准
    生命周期管理 节点支持生命周期状态机
    QoS 策略 灵活的服务质量控制
    组件化 支持节点组件(Component),可在同进程组合

    9.3 ROS1 与 ROS2 对照表

    概念ROS1ROS2
    构建工具 catkin_make / catkin_tools colcon
    包格式 package.xml format 1/2 package.xml format 3
    构建系统 catkin ament_cmake / ament_python
    Master roscore 无(DDS自动发现)
    节点 rospy / roscpp rclpy / rclcpp
    参数 rosparam ros2 param
    启动 roslaunch ros2 launch(Python格式)
    包管理 rosdep rosdep
    录制 rosbag ros2 bag
    环境 source devel/setup.bash source install/setup.bash
    通信库 自定义TCP/UDP DDS(中间件)
    命名 /global/topic 可配置命名空间

    9.4 ROS1 到 ROS2 的迁移

    迁移工具:

    • ros1_bridge:ROS1 和 ROS2 之间的消息桥接
    • 逐步迁移策略:核心模块迁移到 ROS2,其余通过 bridge 通信

    # 安装 ros1_bridge
    sudo apt install ros-humble-ros1-bridge

    # 使用 bridge
    ros2 run ros1_bridge dynamic_bridge

    代码迁移对比:

    # ROS1 写法
    import rospy
    from std_msgs.msg import String

    rospy.init_node('my_node')
    pub = rospy.Publisher('topic', String, queue_size=10)
    rospy.loginfo("Hello")

    # ROS2 写法
    import rclpy
    from rclpy.node import Node
    from std_msgs.msg import String

    rclpy.init()
    node = Node('my_node')
    pub = node.create_publisher(String, 'topic', 10)
    node.get_logger().info("Hello")


    十、ROS2 核心概念与新特性

    10.1 节点生命周期(Lifecycle Node)

    ROS2 引入了生命周期管理,节点可以有以下状态:

    ┌──────────┐
    │Unconfigured│
    └─────┬────┘
    configure│
    ▼
    ┌──────────┐
    ┌───>│ Inactive │<───┐
    │ └─────┬────┘ │
    activate│ │ deactivate│
    │ ▼ │
    │ ┌──────────┐ │
    │ │ Active │────┘
    │ └─────┬────┘
    │ cleanup│
    │ ▼
    │ ┌──────────┐
    │ │Finalized │
    │ └──────────┘
    │
    │ error (任何状态)
    └──────────────────

    生命周期状态说明:

    状态说明
    Unconfigured 未配置,初始状态
    Inactive 已配置但未激活,不发布数据
    Active 激活状态,正常工作
    Finalized 已终结,准备销毁

    用途:实现系统启动时序控制,确保传感器先初始化再启动算法。

    10.2 QoS(Quality of Service)策略

    QoS 是 ROS2 的重要特性,允许精细控制通信行为。

    QoS 配置文件:

    策略选项说明
    Reliability RELIABLE / BEST_EFFORT 可靠传输 vs 尽力传输
    Durability TRANSIENT_LOCAL / VOLATILE 保留最后消息 vs 不保留
    History KEEP_LAST(n) / KEEP_ALL 保留最近n条 / 保留全部
    Depth 数值 队列深度
    Deadline 期限 预期消息到达间隔
    Liveliness AUTOMATIC / MANUAL 存活检测方式

    QoS 预设:

    from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy

    # 传感器数据(实时性优先,允许丢帧)
    sensor_qos = QoSProfile(
    reliability=ReliabilityPolicy.BEST_EFFORT,
    durability=DurabilityPolicy.VOLATILE,
    depth=5
    )

    # 控制指令(可靠性优先)
    control_qos = QoSProfile(
    reliability=ReliabilityPolicy.RELIABLE,
    durability=DurabilityPolicy.TRANSIENT_LOCAL,
    depth=10
    )

    # 使用 QoS
    pub = node.create_publisher(String, 'topic', qos_profile=sensor_qos)

    10.3 组件(Component)与进程内通信

    ROS2 支持将多个节点组合到同一个进程中,实现零拷贝的高效通信。

    # 组件节点(继承自 Node,但不调用 rclpy.init)
    import rclpy
    from rclpy.node import Node

    class MyComponent(Node):
    def __init__(self):
    super().__init__('my_component')
    self.pub = self.create_publisher(String, 'output', 10)
    self.sub = self.create_subscription(
    String, 'input', self.callback, 10)

    def callback(self, msg):
    out = String()
    out.data = f"Processed: {msg.data}"
    self.pub.publish(out)

    # 注册为组件
    from rclpy.executors import ExternalShutdownException
    def main():
    rclpy.spin(MyComponent())

    组合的好处:

    • 减少进程间通信开销
    • 共享内存(零拷贝传输)
    • 更好的确定性和实时性

    10.4 Executor 执行器

    ROS2 使用 Executor 来管理回调的执行:

    # 单线程执行器(默认)
    executor = rclpy.executors.SingleThreadedExecutor()
    executor.add_node(node)
    executor.spin()

    # 多线程执行器
    executor = rclpy.executors.MultiThreadedExecutor(num_threads=4)
    executor.add_node(node1)
    executor.add_node(node2)
    executor.spin()

    # 静态单线程执行器(更高性能)
    executor = rclpy.executors.StaticSingleThreadedExecutor()
    executor.add_node(node)
    executor.spin()

    10.5 命名空间与重映射

    # 命名空间
    ros2 run my_package my_node –ros-args -r __ns:=/robot1
    # 效果:节点的所有话题都加上 /robot1/ 前缀

    # 话题重映射
    ros2 run my_package my_node –ros-args -r /input:=/camera/image_raw
    # 效果:节点订阅的 /input 话题被重映射为 /camera/image_raw

    # 节点名称重映射
    ros2 run my_package my_node –ros-args -r __node:=my_renamed_node


    十一、ROS2 通信机制详解

    11.1 DDS(Data Distribution Service)

    DDS 是 ROS2 的底层通信中间件,是一种工业级的实时发布-订阅通信标准。

    DDS 厂商:

    厂商包名许可证
    eProsima Fast DDS rmw_fastrtps_cpp Apache 2.0(默认)
    RTI Connext DDS rmw_connextdds 商业/研究
    Eclipse Cyclone DDS rmw_cyclonedds_cpp EPL 2.0

    # 切换 DDS 实现
    export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp

    DDS 通信流程:

    1. 节点启动 → DDS Participant 创建
    2. 创建 Publisher/Subscriber → DDS DataWriter/DataReader
    3. DDS 自动发现其他 Participant(无需 Master)
    4. 数据通过 DDS 中间件传输
    5. 支持 TCP/UDP/Shared Memory 传输

    11.2 ROS2 消息 IDL

    ROS2 使用 IDL(Interface Description Language)定义接口:

    # msg/MyMessage.idl
    module my_package {
    module msg {
    struct MyMessage {
    string name;
    float64 value;
    sequence<uint8> data;
    };
    };
    };

    同时仍然支持传统的 .msg、.srv、.action 文件格式。

    11.3 ROS2 完整发布订阅示例

    自定义消息定义:

    # msg/RobotStatus.msg
    string robot_name
    float64 battery_level
    geometry_msgs/Pose current_pose
    bool is_moving

    CMakeLists.txt 配置:

    find_package(rosidl_default_generators REQUIRED)
    find_package(geometry_msgs REQUIRED)

    rosidl_generate_interfaces(${PROJECT_NAME}
    "msg/RobotStatus.msg"
    DEPENDENCIES geometry_msgs
    )


    十二、ROS2 开发环境与工具

    12.1 创建 ROS2 工作空间

    # 创建工作空间
    mkdir -p ~/ros2_ws/src
    cd ~/ros2_ws/src

    # 创建功能包(C++)
    ros2 pkg create –build-type ament_cmake my_cpp_package \\
    –dependencies rclcpp std_msgs

    # 创建功能包(Python)
    ros2 pkg create –build-type ament_python my_py_package \\
    –dependencies rclpy std_msgs

    # 编译
    cd ~/ros2_ws
    colcon build

    # 加载环境
    source install/setup.bash

    12.2 Python 功能包结构

    my_py_package/
    ├── package.xml
    ├── setup.py
    ├── setup.cfg
    ├── resource/
    │ └── my_py_package
    ├── my_py_package/
    │ ├── __init__.py
    │ ├── my_publisher.py # 发布者节点
    │ ├── my_subscriber.py # 订阅者节点
    │ └── my_service.py # 服务节点
    └── test/
    ├── test_copyright.py
    ├── test_flake8.py
    └── test_pep257.py

    setup.py:

    from setuptools import setup

    package_name = 'my_py_package'

    setup(
    name=package_name,
    version='0.1.0',
    packages=[package_name],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='yourname',
    maintainer_email='your@email.com',
    description='My ROS2 Python package',
    license='Apache-2.0',
    tests_require=['pytest'],
    entry_points={
    'console_scripts': [
    'my_publisher = my_py_package.my_publisher:main',
    'my_subscriber = my_py_package.my_subscriber:main',
    'my_service = my_py_package.my_service:main',
    ],
    },
    )

    12.3 C++ 功能包结构

    my_cpp_package/
    ├── CMakeLists.txt
    ├── package.xml
    ├── include/
    │ └── my_cpp_package/
    │ └── my_node.hpp
    ├── src/
    │ ├── my_publisher.cpp
    │ ├── my_subscriber.cpp
    │ └── my_service.cpp
    └── test/
    └── test_my_node.cpp

    CMakeLists.txt:

    cmake_minimum_required(VERSION 3.8)
    project(my_cpp_package)

    if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    add_compile_options(-Wall -Wextra -Wpedantic)
    endif()

    find_package(ament_cmake REQUIRED)
    find_package(rclcpp REQUIRED)
    find_package(std_msgs REQUIRED)

    add_executable(my_publisher src/my_publisher.cpp)
    ament_target_dependencies(my_publisher rclcpp std_msgs)

    add_executable(my_subscriber src/my_subscriber.cpp)
    ament_target_dependencies(my_subscriber rclcpp std_msgs)

    install(TARGETS
    my_publisher
    my_subscriber
    DESTINATION lib/${PROJECT_NAME})

    ament_package()

    12.4 Launch 文件详解(ROS2)

    # launch/my_system.launch.py
    from launch import LaunchDescription
    from launch_ros.actions import Node, ComposableNodeContainer
    from launch.actions import (
    DeclareLaunchArgument, IncludeLaunchDescription,
    GroupAction, TimerAction
    )
    from launch.substitutions import LaunchConfiguration, PathJoinSubstitution
    from launch_ros.substitutions import FindPackageShare
    from launch.conditions import IfCondition

    def generate_launch_description():
    # 声明启动参数
    use_sim_time_arg = DeclareLaunchArgument(
    'use_sim_time', default_value='false'
    )
    robot_name_arg = DeclareLaunchArgument(
    'robot_name', default_value='my_robot'
    )

    return LaunchDescription([
    use_sim_time_arg,
    robot_name_arg,

    # 启动节点
    Node(
    package='robot_state_publisher',
    executable='robot_state_publisher',
    name='robot_state_publisher',
    parameters=[{
    'robot_description': open(
    '/path/to/robot.urdf').read(),
    'use_sim_time': LaunchConfiguration('use_sim_time'),
    }],
    output='screen',
    ),

    # 延迟启动
    TimerAction(
    period=3.0,
    actions=[
    Node(
    package='nav2_bringup',
    executable='bringup_launch.py',
    name='navigation',
    ),
    ]
    ),

    # 包含其他 launch 文件
    IncludeLaunchDescription(
    PathJoinSubstitution([
    FindPackageShare('my_package'),
    'launch',
    'sensors.launch.py'
    ])
    ),
    ])

    12.5 ros2_control 硬件抽象框架

    ros2_control 是 ROS2 的硬件抽象和控制框架:

    # config/controllers.yaml
    controller_manager:
    ros__parameters:
    update_rate: 100
    joint_state_broadcaster:
    type: joint_state_broadcaster/JointStateBroadcaster
    diff_drive_controller:
    type: diff_drive_controller/DiffDriveController

    diff_drive_controller:
    ros__parameters:
    left_wheel_names: ["left_wheel_joint"]
    right_wheel_names: ["right_wheel_joint"]
    wheel_separation: 0.35
    wheel_radius: 0.1
    publish_rate: 50.0


    十三、SLAM(同时定位与地图构建)

    13.1 SLAM 基本概念

    SLAM(Simultaneous Localization and Mapping) 是机器人在未知环境中同时完成:

  • 定位(Localization):确定自己在环境中的位置
  • 建图(Mapping):构建环境的地图
  • ┌────────────┐
    传感器数据 ───> │ SLAM 算法 │ ───> 地图 + 机器人位姿
    (激光/相机/IMU) └────────────┘
    ▲
    │
    里程计数据
    (编码器/IMU)

    13.2 地图类型

    地图类型说明适用场景
    栅格地图(Grid Map) 2D 平面网格,每个格子有占用概率 室内导航(最常用)
    点云地图(Point Cloud) 3D 空间中的点集合 3D 环境感知
    拓扑地图(Topological) 节点+边的图结构 大规模导航
    语义地图(Semantic) 带物体标签的地图 高级任务规划

    13.3 常用 SLAM 算法

    13.3.1 Gmapping(2D 激光 SLAM)

    # 安装
    sudo apt install ros-humble-gmapping

    # 运行
    ros2 launch slam_toolbox online_async_launch.py \\
    params_file:=./config/mapper_params_online_async.yaml

    Gmapping 参数配置:

    # mapper_params.yaml
    slam_toolbox:
    ros__parameters:
    resolution: 0.05 # 地图分辨率(米/格)
    max_laser_range: 12.0 # 激光雷达最大范围
    minimum_score: 50 # 匹配最小得分
    use_scan_matching: true
    use_scan_barycenter: true
    maxUrange: 12.0
    sigma: 0.05
    kernelSize: 1
    lstep: 0.05
    astep: 0.05
    iterations: 5
    lsigma: 0.075
    ogain: 3.0
    lskip: 0
    srr: 0.1
    srt: 0.2
    str: 0.1
    stt: 0.2
    linearUpdate: 1.0
    angularUpdate: 0.5
    temporalUpdate: 3.0
    occ_thresh: 0.25

    13.3.2 Cartographer(Google)

    Cartographer 是 Google 开源的跨平台 SLAM 系统:

    # 安装
    sudo apt install ros-humble-cartographer
    sudo apt install ros-humble-cartographer-ros

    # 运行2D SLAM
    ros2 launch cartographer_ros demo_backpack_2d.launch.py

    # 运行3D SLAM
    ros2 launch cartographer_ros demo_backpack_3d.launch.py

    Cartographer 的特点:

    • 支持 2D 和 3D SLAM
    • 累积误差小
    • 支持多传感器融合(激光+IMU+里程计)
    • Google 背书,工程质量高
    13.3.3 SLAM Toolbox(ROS2 推荐)

    SLAM Toolbox 是 ROS2 中最推荐的 2D SLAM 方案:

    # 安装
    sudo apt install ros-humble-slam-toolbox

    # 在线建图
    ros2 launch slam_toolbox online_async_launch.py

    # 离线处理
    ros2 launch slam_toolbox offline.launch.py

    # 继续之前的地图继续建图
    ros2 launch slam_toolbox online_async_launch.py \\
    use_sim_time:=true

    13.3.4 ORB-SLAM3(视觉 SLAM)

    ORB-SLAM3 是目前最先进的视觉 SLAM 系统:

    # 需要从源码编译
    git clone https://github.com/UZ-SLAMLab/ORB_SLAM3.git
    cd ORB_SLAM3
    ./build.sh

    特点:

    • 支持单目、双目、RGB-D 相机
    • 支持视觉+IMU 融合
    • 支持多地图系统
    • 实时性能优秀

    13.4 保存和加载地图

    # 保存地图(nav2_map_server)
    ros2 run nav2_map_server map_saver_cli -f my_map

    # 生成文件:
    # my_map.pgm → 地图图像(灰度图)
    # my_map.yaml → 地图元数据

    # 加载地图
    ros2 run nav2_map_server map_server –ros-args \\
    -p yaml_filename:=my_map.yaml -p use_sim_time:=true

    地图文件(.yaml)示例:

    image: my_map.pgm
    resolution: 0.05 # 米/像素
    origin: [-13.8, -12.6, 0] # 地图原点(x, y, yaw)
    negate: 0
    occupied_thresh: 0.65 # 占用阈值
    free_thresh: 0.196 # 空闲阈值


    十四、Navigation 导航栈

    14.1 Nav2 概述(ROS2)

    Nav2 是 ROS2 的标准导航框架,是 ROS1 Navigation Stack 的升级版。

    ┌────────────────────────────────────────────────────┐
    │ Nav2 架构 │
    │ │
    │ ┌──────────────┐ ┌──────────────────────────┐ │
    │ │ BT Navigator │ │ Controller Server │ │
    │ │(行为树导航) │ │ (控制器/局部规划) │ │
    │ └──────┬───────┘ └────────────┬─────────────┘ │
    │ │ │ │
    │ ┌──────┴───────┐ ┌────────────┴─────────────┐ │
    │ │ Planner Server│ │ Recovery Server │ │
    │ │ (全局规划) │ │ (恢复行为) │ │
    │ └──────────────┘ └──────────────────────────┘ │
    │ │
    │ ┌──────────────┐ ┌──────────────────────────┐ │
    │ │ Map Server │ │ Costmap 2D │ │
    │ │ (地图服务) │ │ (代价地图) │ │
    │ └──────────────┘ └──────────────────────────┘ │
    └────────────────────────────────────────────────────┘

    14.2 Nav2 核心组件

    全局路径规划器(Global Planner)
    规划器说明
    NavFn Planner Dijkstra/A* 算法
    Smac Planner 2D/Hybrid-A*/Lattice 算法
    Theta* Planner 任意角度路径
    局部控制器(Local Controller)
    控制器说明
    DWB Controller 动态窗口法(DWA改进)
    TEB Controller 时间弹性带算法
    MPPI Controller 模型预测路径积分
    RPP Controller 拦截点追踪(Regulated Pure Pursuit)
    Rotation Shim 旋转辅助控制器
    行为树(Behavior Tree)

    Nav2 使用行为树来组织复杂的导航逻辑:

    <!– 导航行为树 –>
    <root main_tree_to_execute="MainTree">
    <BehaviorTree ID="MainTree">
    <Sequence name="NavigateWithRecovery">
    <!– 全局路径规划 –>
    <ComputePathToPose goal="{goal}" path="{path}"/>
    <!– 局部控制跟随路径 –>
    <FollowPath path="{path}"/>
    </Sequence>
    <!– 恢复行为 –>
    <RecoveryNode number_of_retries="3">
    <SequenceStar name="RecoveryActions">
    <ClearEntireCostmap service_name="global_costmap/clear"/>
    <Wait wait_duration="2"/>
    <Spin spin_dist="1.57"/>
    <BackUp backup_dist="0.3" backup_speed="0.1"/>
    </SequenceStar>
    </RecoveryNode>
    </BehaviorTree>
    </root>

    代价地图(Costmap)

    ┌─────────────────────────────┐
    │ 代价地图 │
    │ ┌───────────────────────┐ │
    │ │ 静态层 (Static) │ │ ← 来自地图
    │ │ 障碍物层 (Obstacle) │ │ ← 来自传感器
    │ │ 膨胀层 (Inflation) │ │ ← 障碍物膨胀
    │ │ 安全距离 │ │
    │ └───────────────────────┘ │
    └─────────────────────────────┘

    14.3 Nav2 配置

    典型 Nav2 配置文件:

    # nav2_params.yaml
    bt_navigator:
    ros__parameters:
    default_nav_to_pose_bt_xml: nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml
    plugin_lib_names:
    – nav2_compute_path_to_pose_action_bt_node
    – nav2_follow_path_action_bt_node
    – nav2_rate_controller_bt_node

    controller_server:
    ros__parameters:
    controller_frequency: 20.0
    min_x_velocity_threshold: 0.001
    min_y_velocity_threshold: 0.5
    min_theta_velocity_threshold: 0.001
    progress_checker_plugins: ["progress_checker"]
    goal_checker_plugins: ["goal_checker"]
    controller_plugins: ["FollowPath"]
    progress_checker:
    plugin: "nav2_controller::SimpleProgressChecker"
    required_movement_radius: 0.5
    movement_time_allowance: 10.0
    goal_checker:
    plugin: "nav2_controller::SimpleGoalChecker"
    xy_goal_tolerance: 0.25
    yaw_goal_tolerance: 0.25
    FollowPath:
    plugin: "dwb_core::DWBLocalPlanner"

    planner_server:
    ros__parameters:
    expected_planner_frequency: 20.0
    planner_plugins: ["GridBased"]
    GridBased:
    plugin: "nav2_navfn_planner/NavfnPlanner"
    tolerance: 0.5
    use_astar: false

    local_costmap:
    local_costmap:
    ros__parameters:
    update_frequency: 5.0
    publish_frequency: 2.0
    global_frame: odom
    robot_base_frame: base_link
    rolling_window: true
    width: 3
    height: 3
    resolution: 0.05
    robot_radius: 0.22
    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
    inflation_layer:
    plugin: "nav2_costmap_2d::InflationLayer"
    cost_scaling_factor: 10.0
    inflation_radius: 0.55

    global_costmap:
    global_costmap:
    ros__parameters:
    update_frequency: 1.0
    publish_frequency: 1.0
    global_frame: map
    robot_base_frame: base_link
    robot_radius: 0.22
    plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
    static_layer:
    plugin: "nav2_costmap_2d::StaticLayer"
    map_subscribe_transient_local: True

    14.4 运行 Nav2

    # 启动完整导航栈
    ros2 launch nav2_bringup navigation_launch.py \\
    use_sim_time:=true \\
    map:=/path/to/my_map.yaml

    # 通过 RViz 发送导航目标
    # 或通过代码发送
    ros2 action send_goal /navigate_to_pose nav2_msgs/action/NavigateToPose \\
    "{pose: {header: {frame_id: 'map'}, pose: {position: {x: 2.0, y: 1.0}}}}"

    14.5 自定义导航行为

    # 通过代码发送导航目标
    import rclpy
    from rclpy.node import Node
    from rclpy.action import ActionClient
    from nav2_msgs.action import NavigateToPose
    from geometry_msgs.msg import PoseStamped

    class NavClient(Node):
    def __init__(self):
    super().__init__('nav_client')
    self._action_client = ActionClient(
    self, NavigateToPose, 'navigate_to_pose')

    def send_goal(self, x, y, yaw=0.0):
    goal_msg = NavigateToPose.Goal()
    goal_msg.pose.header.frame_id = 'map'
    goal_msg.pose.pose.position.x = x
    goal_msg.pose.pose.position.y = y

    self._action_client.wait_for_server()
    return self._action_client.send_goal_async(
    goal_msg, feedback_callback=self.feedback_callback)

    def feedback_callback(self, feedback_msg):
    remaining = feedback_msg.feedback.distance_remaining
    self.get_logger().info(f'Distance remaining: {remaining:.2f}m')


    十五、机械臂控制与 MoveIt

    15.1 MoveIt 概述

    MoveIt 是 ROS 中最流行的运动规划框架,支持:

    • 运动学求解(正/逆运动学)
    • 运动规划(RRT、PRM 等算法)
    • 碰撞检测
    • 抓取规划
    • 轨迹执行

    15.2 MoveIt 架构

    ┌──────────────────────────────────────────────┐
    │ MoveIt2 架构 │
    │ │
    │ ┌──────────────┐ ┌──────────────────┐ │
    │ │ Move Group │ │ Planning Scene │ │
    │ │ (运动组) │ │ (规划场景) │ │
    │ └──────┬───────┘ └────────┬─────────┘ │
    │ │ │ │
    │ ┌──────┴───────┐ ┌────────┴─────────┐ │
    │ │Motion Planner│ │ Collision Check │ │
    │ │(运动规划器) │ │ (碰撞检测) │ │
    │ └──────────────┘ └──────────────────┘ │
    │ │
    │ ┌──────────────┐ ┌──────────────────┐ │
    │ │ Kinematics │ │ ros2_control │ │
    │ │ (运动学) │ │ (硬件控制) │ │
    │ └──────────────┘ └──────────────────┘ │
    └──────────────────────────────────────────────┘

    15.3 使用 MoveIt Setup Assistant

    # 启动 MoveIt 配置助手(图形化配置工具)
    ros2 launch moveit_setup_assistant setup_assistant.launch.py

    Setup Assistant 步骤:

  • 加载 URDF 模型
  • 生成自碰撞矩阵
  • 定义虚拟关节
  • 规划组(Planning Group)配置
  • 定义机器人姿态(预设位姿)
  • 配置末端执行器
  • 生成配置文件
  • 15.4 MoveIt 运动规划代码示例

    import rclpy
    from rclpy.node import Node
    from moveit_msgs.action import MoveGroup
    from moveit_msgs.msg import (
    MotionPlanRequest, Constraints, JointConstraint,
    PositionConstraint, OrientationConstraint
    )
    from geometry_msgs.msg import PoseStamped
    import moveit_commander

    class MoveItDemo(Node):
    def __init__(self):
    super().__init__('moveit_demo')
    moveit_commander.roscpp_initialize([])
    self.robot = moveit_commander.RobotCommander()
    self.scene = moveit_commander.PlanningSceneInterface()
    self.group = moveit_commander.MoveGroupCommander("arm")

    def move_to_joint_goal(self):
    """移动到关节目标"""
    joint_goal = self.group.get_current_joint_values()
    joint_goal[0] = 0.0
    joint_goal[1] = –0.5
    joint_goal[2] = 0.5
    joint_goal[3] = –1.0
    joint_goal[4] = 0.0
    joint_goal[5] = 0.5
    self.group.go(joint_goal, wait=True)
    self.group.stop()

    def move_to_pose_goal(self):
    """移动到笛卡尔目标"""
    pose_goal = PoseStamped()
    pose_goal.header.frame_id = "base_link"
    pose_goal.pose.position.x = 0.4
    pose_goal.pose.position.y = 0.0
    pose_goal.pose.position.z = 0.4
    pose_goal.pose.orientation.w = 1.0
    self.group.set_pose_target(pose_goal)
    plan = self.group.go(wait=True)
    self.group.stop()
    self.group.clear_pose_targets()

    def plan_cartesian_path(self):
    """笛卡尔路径规划(直线运动)"""
    waypoints = []
    wpose = self.group.get_current_pose().pose
    wpose.position.z += 0.1
    waypoints.append(wpose)
    wpose.position.x += 0.2
    waypoints.append(wpose)

    (plan, fraction) = self.group.compute_cartesian_path(
    waypoints, 0.01, 0.0) # 步长1cm
    self.group.execute(plan, wait=True)

    15.5 常用运动规划算法

    算法类型特点
    RRT 单查询 快速,但路径可能不优
    RRT* 单查询 RRT 改进,渐近最优
    PRM 多查询 适合静态环境反复查询
    KPIECE 单查询 适合高维空间
    BKPIECE 单查询 双向 KPIECE
    LBKPIECE 单查询 有界的双向 KPIECE
    TRRT 单查询 适合有梯度的环境

    十六、仿真环境

    16.1 Gazebo

    Gazebo 是 ROS 生态中最主流的物理仿真器。

    # Gazebo Classic(ROS1 常用)
    gazebo –verbose worlds/empty.world

    # Gazebo Fortress/Harmonic(ROS2 新版)
    # 安装
    sudo apt install ros-humble-gazebo-ros-pkgs

    # 运行
    ros2 launch gazebo_ros gazebo.launch.py

    Gazebo 能做什么:

    • 物理引擎仿真(重力、摩擦、碰撞)
    • 传感器仿真(激光雷达、相机、IMU、GPS)
    • 机器人模型加载(URDF/SDF)
    • 自定义环境(建筑、地形、物体)
    • 插件系统(自定义行为)

    Gazebo 插件示例:

    <!– 在 URDF/SDF 中添加 Gazebo 插件 –>
    <gazebo>
    <plugin name="differential_drive" filename="libgazebo_ros_diff_drive.so">
    <ros>
    <namespace>/</namespace>
    </ros>
    <update_rate>30</update_rate>
    <left_joint>left_wheel_joint</left_joint>
    <right_joint>right_wheel_joint</right_joint>
    <wheel_separation>0.35</wheel_separation>
    <wheel_diameter>0.2</wheel_diameter>
    <publish_odom>true</publish_odom>
    <publish_odom_tf>true</publish_odom_tf>
    </plugin>
    </gazebo>

    16.2 TurtleBot3 仿真(入门推荐)

    # 安装
    sudo apt install ros-humble-turtlebot3*
    sudo apt install ros-humble-turtlebot3-simulations

    # 设置模型
    export TURTLEBOT3_MODEL=burger

    # 启动 Gazebo 仿真
    ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py

    # 启动导航
    ros2 launch turtlebot3_navigation2 navigation2.launch.py \\
    use_sim_time:=true map:=$HOME/map.yaml

    # 启动 SLAM
    ros2 launch turtlebot3_cartographer cartographer.launch.py \\
    use_sim_time:=true

    16.3 Webots

    Webots 是另一个流行的开源仿真器:

    sudo apt install ros-humble-webots-ros2
    ros2 launch webots_ros2_universal_robot multirobot_launch.py

    16.4 Isaac Sim(NVIDIA)

    NVIDIA Isaac Sim 是基于 Omniverse 的高保真机器人仿真平台:

    • 物理级真实的渲染
    • 域随机化(Domain Randomization)
    • 支持 ROS2 接口
    • GPU 加速
    • 适合深度学习训练

    16.5 仿真与实际机器人的关系

    仿真环境 真实环境
    ┌────────────┐ ┌────────────┐
    │ Gazebo │ │ 真实机器人 │
    │ │ │ │
    │ /cmd_vel ──┤ │ /cmd_vel ──┤
    │ /scan ──┤ ← 接口完全相同 → │ /scan ──┤
    │ /odom ──┤ │ /odom ──┤
    │ /camera ──┤ │ /camera ──┤
    │ │ │ │
    │ use_sim_time:=true │ use_sim_time:=false
    └────────────┘ └────────────┘

    Sim2Real(从仿真到现实)的关键:

    • 使用 use_sim_time 参数区分仿真和真实时间
    • 话题和消息接口保持一致
    • 仿真中测试通过后,只需要更换硬件驱动即可部署到真实机器人

    十七、ROS 与传感器

    17.1 激光雷达(LiDAR)

    # 常用激光雷达驱动
    sudo apt install ros-humble-rplidar-ros # RPLidar A1/A2/A3
    sudo apt install ros-humble-velodyne-driver # Velodyne 3D 雷达
    sudo apt install ros-humble-hls-lfcd-lidar-driver # LDS-01(TurtleBot3)

    # 查看激光数据
    ros2 topic echo /scan
    ros2 run rviz2 rviz2 # 添加 LaserScan 显示

    LaserScan 消息结构:

    Header header
    float32 angle_min # 扫描起始角度
    float32 angle_max # 扫描结束角度
    float32 angle_increment # 角度分辨率
    float32 time_increment # 测量时间间隔
    float32 scan_time # 完整扫描时间
    float32 range_min # 最小测量距离
    float32 range_max # 最大测量距离
    float32[] ranges # 距离数据数组
    float32[] intensities # 强度数据数组

    17.2 相机

    # USB 相机
    sudo apt install ros-humble-usb-cam
    ros2 run usb_cam usb_cam_node_exe –ros-args -p video_device:=/dev/video0

    # Intel RealSense 深度相机
    sudo apt install ros-humble-realsense2-camera
    ros2 launch realsense2_camera rs_launch.py

    # 查看图像
    ros2 run rqt_image_view rqt_image_view

    常用图像话题:

    话题类型说明
    /camera/image_raw sensor_msgs/Image 原始图像
    /camera/image_color sensor_msgs/Image 彩色图像
    /camera/image_depth sensor_msgs/Image 深度图像
    /camera/points sensor_msgs/PointCloud2 点云数据
    /camera/camera_info sensor_msgs/CameraInfo 相机内参

    17.3 IMU(惯性测量单元)

    # 查看 IMU 数据
    ros2 topic echo /imu

    Imu 消息结构:

    Header header
    geometry_msgs/Quaternion orientation
    float64[9] orientation_covariance
    geometry_msgs/Vector3 angular_velocity
    float64[9] angular_velocity_covariance
    geometry_msgs/Vector3 linear_acceleration
    float64[9] linear_acceleration_covariance

    17.4 GPS

    # u-blox GPS
    sudo apt install ros-humble-ublox-gps

    17.5 多传感器融合

    # robot_localization 包 – 扩展卡尔曼滤波融合
    sudo apt install ros-humble-robot-localization

    融合配置示例(ekf.yaml):

    ekf_filter_node:
    ros__parameters:
    frequency: 30.0
    two_d_mode: false
    odom0: /odom
    odom0_config: [true, true, false,
    false, false, true,
    true, true, false,
    false, false, true,
    false, false, false]
    imu0: /imu
    imu0_config: [false, false, false,
    true, true, true,
    false, false, false,
    true, true, true,
    true, true, true]
    odom0_differential: false
    imu0_differential: false


    十八、ROS 与视觉/AI

    18.1 OpenCV 与 ROS 集成

    import rclpy
    from rclpy.node import Node
    from sensor_msgs.msg import Image
    from cv_bridge import CvBridge
    import cv2

    class VisionNode(Node):
    def __init__(self):
    super().__init__('vision_node')
    self.bridge = CvBridge()
    self.sub = self.create_subscription(
    Image, '/camera/image_raw', self.image_callback, 10)
    self.pub = self.create_publisher(Image, '/processed_image', 10)

    def image_callback(self, msg):
    # ROS Image → OpenCV
    cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8")

    # 图像处理
    gray = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)
    edges = cv2.Canny(gray, 50, 150)

    # OpenCV → ROS Image
    ros_image = self.bridge.cv2_to_imgmsg(edges, "mono8")
    self.pub.publish(ros_image)

    18.2 目标检测集成

    # 使用 YOLO + ROS2
    import torch
    from ultralytics import YOLO

    class YOLONode(Node):
    def __init__(self):
    super().__init__('yolo_node')
    self.model = YOLO('yolov8n.pt')
    self.bridge = CvBridge()
    self.sub = self.create_subscription(
    Image, '/camera/image_raw', self.detect, 10)

    def detect(self, msg):
    cv_image = self.bridge.imgmsg_to_cv2(msg, "bgr8")
    results = self.model(cv_image)

    for result in results:
    boxes = result.boxes
    for box in boxes:
    cls = int(box.cls[0])
    conf = float(box.conf[0])
    name = result.names[cls]
    self.get_logger().info(
    f'Detected: {name} ({conf:.2f})')

    18.3 点云处理

    import rclpy
    from sensor_msgs.msg import PointCloud2
    import sensor_msgs_py.point_cloud2 as pc2

    class PointCloudNode(Node):
    def __init__(self):
    super().__init__('pointcloud_node')
    self.sub = self.create_subscription(
    PointCloud2, '/points', self.callback, 10)

    def callback(self, msg):
    # 读取点云数据
    points = list(pc2.read_points(msg,
    field_names=("x", "y", "z"), skip_nans=True))

    self.get_logger().info(
    f'Point cloud: {len(points)} points')

    18.4 Nav2 路径跟随中的视觉应用

    结合视觉和导航的典型场景:

    • 视觉 SLAM(VSLAM)
    • 二维码/ArUco 定位
    • 视觉避障
    • 物体识别后的目标导航

    十九、ROS 项目实战开发流程

    20.1 典型项目流程

    阶段1: 需求分析与系统设计
    ├── 确定机器人类型(移动/机械臂/复合)
    ├── 确定传感器配置
    ├── 确定功能需求(导航/抓取/巡检等)
    └── 系统架构设计

    阶段2: 模型建立
    ├── 创建 URDF/Xacro 模型
    ├── 在 RViz 中验证模型
    ├── 添加物理属性(惯性、碰撞)
    └── 配置 ros2_control 硬件接口

    阶段3: 仿真验证
    ├── 在 Gazebo 中搭建环境
    ├── 加载机器人模型
    ├── 测试传感器数据
    └── 调试基础运动

    阶段4: 功能开发
    ├── 实现传感器驱动
    ├── 实现 SLAM 建图
    ├── 实现导航功能
    ├── 实现任务逻辑
    └── 集成 AI/视觉算法

    阶段5: 测试与优化
    ├── 仿真环境全面测试
    ├── 性能优化
    ├── 异常处理
    └── 参数调优

    阶段6: 部署与调试
    ├── 迁移到真实机器人
    ├── 实机调试
    ├── 参数标定
    └── 现场测试

    20.2 项目目录结构示例

    my_robot_project/
    ├── src/
    │ ├── my_robot_description/ # 机器人描述
    │ │ ├── urdf/
    │ │ │ ├── robot.urdf.xacro
    │ │ │ └── robot.gazebo.xacro
    │ │ ├── meshes/
    │ │ │ ├── base_link.stl
    │ │ │ └── wheel.stl
    │ │ ├── config/
    │ │ │ └── robot_state_publisher.yaml
    │ │ └── launch/
    │ │ └── display.launch.py
    │ │
    │ ├── my_robot_bringup/ # 系统启动
    │ │ ├── launch/
    │ │ │ ├── robot.launch.py # 真实机器人启动
    │ │ │ ├── sim.launch.py # 仿真启动
    │ │ │ └── nav.launch.py # 导航启动
    │ │ └── config/
    │ │ └── nav2_params.yaml
    │ │
    │ ├── my_robot_navigation/ # 导航功能
    │ │ ├── src/
    │ │ ├── config/
    │ │ └── launch/
    │ │
    │ ├── my_robot_perception/ # 感知功能
    │ │ ├── src/
    │ │ │ ├── obstacle_detector.py
    │ │ │ └── object_tracker.py
    │ │ └── launch/
    │ │
    │ └── my_robot_bringup/ # 任务逻辑
    │ ├── src/
    │ │ ├── patrol_node.py # 巡逻节点
    │ │ └── task_manager.py # 任务管理器
    │ └── config/
    │ └── patrol_points.yaml
    │
    └── maps/
    ├── warehouse_map.yaml
    └── warehouse_map.pgm

    20.3 实际项目示例:巡检机器人

    # patrol_node.py
    import rclpy
    from rclpy.node import Node
    from rclpy.action import ActionClient
    from nav2_msgs.action import NavigateToPose
    from geometry_msgs.msg import PoseStamped
    import yaml

    class PatrolNode(Node):
    def __init__(self):
    super().__init__('patrol_node')
    self._nav_client = ActionClient(
    self, NavigateToPose, 'navigate_to_pose')

    # 加载巡检点
    self.patrol_points = self.load_patrol_points()
    self.current_index = 0

    # 定时器:每30秒检查一次
    self.timer = self.create_timer(30.0, self.patrol_callback)

    def load_patrol_points(self):
    with open('/config/patrol_points.yaml', 'r') as f:
    data = yaml.safe_load(f)
    return data['points']

    def patrol_callback(self):
    if not self._nav_client.wait_for_server(timeout_sec=1.0):
    self.get_logger().warn('Navigation server not available')
    return

    point = self.patrol_points[self.current_index]
    goal = NavigateToPose.Goal()
    goal.pose.header.frame_id = 'map'
    goal.pose.pose.position.x = point['x']
    goal.pose.pose.position.y = point['y']
    goal.pose.pose.orientation.w = 1.0

    self.get_logger().info(
    f'Navigating to point {self.current_index}: '
    f'({point["x"]}, {point["y"]})')

    future = self._nav_client.send_goal_async(
    goal, feedback_callback=self.feedback_cb)
    future.add_done_callback(self.goal_response_cb)

    def goal_response_cb(self, future):
    goal_handle = future.result()
    if not goal_handle.accepted:
    self.get_logger().warn('Goal rejected')
    return
    result_future = goal_handle.get_result_async()
    result_future.add_done_callback(self.result_cb)

    def result_cb(self, future):
    self.get_logger().info('Goal reached!')
    self.current_index = (
    self.current_index + 1) % len(self.patrol_points)

    def feedback_cb(self, feedback_msg):
    dist = feedback_msg.feedback.distance_remaining
    self.get_logger().debug(f'Remaining: {dist:.1f}m')


    二十、学习路线图与资源推荐

    20.1 学习路线图

    阶段 0: 基础准备(2-4周)
    ├── Linux 基础命令
    ├── Python 基础(或 C++ 基础)
    ├── 线性代数基础(矩阵、坐标变换)
    └── 软件安装与环境配置

    阶段 1: ROS 基础入门(4-6周)
    ├── ROS 核心概念(节点/话题/服务)
    ├── 命令行工具使用
    ├── 编写简单发布者/订阅者
    ├── 编写简单服务端/客户端
    ├── Launch 文件编写
    ├── 功能包创建与管理
    └── RViz 可视化入门

    阶段 2: ROS 进阶(4-6周)
    ├── TF 坐标变换系统
    ├── URDF 机器人建模
    ├── 自定义消息/服务/动作
    ├── 参数使用与管理
    ├── rosbag 数据录制与回放
    ├── RQt 工具使用
    └── Gazebo 仿真入门

    阶段 3: 机器人功能模块(6-8周)
    ├── SLAM 建图
    ├── Navigation 导航
    ├── MoveIt 机械臂控制
    ├── 传感器集成(激光/相机/IMU)
    ├── 多传感器融合
    └── 视觉处理与目标检测

    阶段 4: 项目实战(8-12周)
    ├── 完整机器人系统集成
    ├── 仿真到实际部署
    ├── 性能优化与调试
    ├── 多机器人系统
    └── 安全与异常处理

    阶段 5: 高级主题(持续学习)
    ├── ROS2 DDS 深入
    ├── 实时系统与 ros2_control
    ├── AI 与 ROS 集成
    ├── 嵌入式 ROS2(micro-ROS)
    ├── 云机器人
    └── 开源贡献

    20.2 推荐学习资源

    官方资源
    资源链接说明
    ROS Wiki wiki.ros.org ROS1 官方文档
    ROS2 文档 docs.ros.org ROS2 官方文档
    ROS Discourse discourse.ros.org 官方论坛
    ROS Answers answers.ros.org 问答社区
    GitHub github.com/ros2 源码仓库
    教程与课程
    资源说明
    ROS2 官方教程 docs.ros.org/en/humble/Tutorials.html
    The Construct(在线课程) 付费/免费 ROS 课程
    古月居(中文社区) 古月居 ROS 教程
    fishros(中文工具) 一键安装脚本和教程
    鱼香ROS fishros.com
    推荐书籍
    书名说明
    《ROS Robot Programming》 ROS 入门经典
    《Programming Robots with ROS》 O’Reilly ROS 实战
    《Learning ROS for Robotics Programming》 ROS 学习指南
    《ROS2 Navigation》 Nav2 导航详解
    《Mastering ROS for Robotics Programming》 ROS 进阶
    推荐硬件平台
    平台价格适合
    TurtleBot3 Burger ~$500 入门学习
    TurtleBot4 ~$2000 进阶学习
    JetBot ~$200 AI + 机器人
    OpenManipulator ~$500 机械臂学习
    自制小车 + RPLidar ~$300-500 动手能力强

    20.3 快速上手练习

    练习 1:Hello ROS

    # 安装 demo 包
    sudo apt install ros-humble-demo-nodes-cpp ros-humble-demo-nodes-py

    # 运行发布者(终端1)
    ros2 run demo_nodes_cpp talker

    # 运行订阅者(终端2)
    ros2 run demo_nodes_py listener

    # 使用 rqt_graph 查看节点关系
    rqt_graph

    练习 2:Turtle 仿真

    # 安装
    sudo apt install ros-humble-turtlesim

    # 启动小乌龟
    ros2 run turtlesim turtlesim_node

    # 键盘控制
    ros2 run turtlesim turtle_teleop_key

    # 查看话题
    ros2 topic list
    ros2 topic echo /turtle1/pose

    练习 3:自己写一个控制乌龟的节点

    import rclpy
    from rclpy.node import Node
    from geometry_msgs.msg import Twist

    class TurtleController(Node):
    def __init__(self):
    super().__init__('turtle_controller')
    self.pub = self.create_publisher(Twist, '/turtle1/cmd_vel', 10)
    self.timer = self.create_timer(0.1, self.move_turtle)
    self.angle = 0.0

    def move_turtle(self):
    msg = Twist()
    msg.linear.x = 1.0
    msg.angular.z = 0.5
    self.pub.publish(msg)

    def main():
    rclpy.init()
    node = TurtleController()
    rclpy.spin(node)
    rclpy.shutdown()

    if __name__ == '__main__':
    main()


    附录:常见问题与排错

    A1. 常见错误及解决方案

    错误原因解决方案
    ros2: command not found 未 source 环境 source /opt/ros/humble/setup.bash
    Package not found 包未安装或未 source sudo apt install ros-humble-<pkg> 或 source workspace
    Could not find the GUI Docker/WSL 中没有显示 设置 DISPLAY 环境变量
    Node already exists 节点名重复 更换节点名或使用 anonymous:=True
    QoS incompatible 发布者和订阅者 QoS 不匹配 确保 reliability/durability 兼容
    Failed to load robot description URDF 文件路径错误 检查文件路径和 launch 参数
    Transform lookup failed TF 树不完整 检查 TF 广播器是否运行
    colcon build 失败 依赖缺失 rosdep install –from-paths src –ignore-src -r -y

    A2. 调试技巧

    # 1. 系统诊断
    ros2 doctor –report

    # 2. 查看节点通信图
    rqt_graph

    # 3. 查看 TF 树
    ros2 run tf2_tools view_frames

    # 4. 查看话题数据流
    ros2 topic info /topic_name -v

    # 5. 检查节点参数
    ros2 param dump /node_name

    # 6. 查看日志
    ros2 log list
    ros2 log /tmp/ros2_latest/my_node.log

    # 7. GDB 调试
    ros2 run –prefix 'gdb -ex run' my_package my_node

    # 8. 性能分析
    ros2 run rqt_top rqt_top

    A3. 性能优化建议

  • 使用组件(Component):将多个节点组合到同一进程,减少进程间通信开销
  • 选择合适的 QoS:传感器数据使用 BEST_EFFORT,控制指令使用 RELIABLE
  • 使用共享内存:ROS2 支持零拷贝的共享内存传输
  • 减少消息频率:只在必要时使用高频话题
  • 使用 Intra-Process Communication:同一进程内的节点可以直接传递指针
  • A4. 环境变量速查

    # ROS1
    export ROS_MASTER_URI=http://localhost:11311
    export ROS_HOSTNAME=localhost
    export ROS_IP=192.168.1.100

    # ROS2
    export ROS_DOMAIN_ID=0 # 域ID(多机器人隔离)
    export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp # DDS实现
    export ROS_LOCALHOST_ONLY=1 # 仅本机通信
    export CYCLONEDDS_URI=file:///path/to/cyclonedds.xml # DDS配置

    # 通用
    export TURTLEBOT3_MODEL=burger # TurtleBot3 模型选择
    export GAZEBO_MODEL_PATH=$GAZEBO_MODEL_PATH:/path/to/models

    A5. 多机器人配置

    # 机器人1
    export ROS_DOMAIN_ID=0
    ros2 run my_package robot_node –ros-args -r __ns:=/robot1

    # 机器人2
    export ROS_DOMAIN_ID=0
    ros2 run my_package robot_node –ros-args -r __ns:=/robot2

    A6. micro-ROS(嵌入式 ROS2)

    micro-ROS 是 ROS2 的嵌入式版本,支持在微控制器上运行:

    • 支持平台:ESP32、STM32、Arduino 等
    • 通信协议:与 ROS2 完全兼容
    • 适用场景:传感器节点、执行器节点

    # 创建 micro-ROS 固件
    ros2 run micro_ros_setup create_firmware_ws.sh host
    ros2 run micro_ros_setup create_agent_ws.sh

    # 构建 micro-ROS agent
    ros2 run micro_ros_setup build_agent.sh
    ros2 run micro_ros_agent micro_ros_agent serial –dev /dev/ttyUSB0


    总结

    本文档从零基础出发,系统梳理了 ROS 和 ROS2 的核心知识体系:

  • 概念层面:理解了 ROS 的节点、话题、服务、动作、参数等核心概念
  • 架构层面:理解了 ROS 的三层架构和 ROS2 去中心化的设计
  • 工具层面:掌握了命令行工具、RViz、Gazebo 等核心工具
  • 应用层面:了解了 SLAM、导航、机械臂控制、视觉处理等应用
  • 实践层面:掌握了从建模到仿真实战的完整开发流程
  • 给新手的建议:

    • 先 ROS2:ROS1 即将 EOL,建议直接学习 ROS2
    • 多动手:每学一个概念就写代码验证
    • 从小项目开始:先用 TurtleBot3 仿真,再尝试真实机器人
    • 善用社区:遇到问题搜索 ROS Answers、GitHub Issues
    • 系统学习:跟着官方教程走一遍基础教程
    赞(0)
    未经允许不得转载:171主机测评 » ROS(Robot Operating System)全面深入详解,入门学习ROS和ROS2
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址