ROS2从零入门:安装配置、三大通信机制与实战详解
2026/9/3 10:33:09 网站建设 项目流程

H2 1. 为什么具身智能开发者绕不开 ROS2H3 1.1 具身智能需要什么样的机器人软件框架H3 1.2 ROS2 与 ROS1 的核心差异H3 1.3 本文的适合人群与学习目标

进入 2026 年,具身智能(Embodied AI)已经从学术热词变成了机器人行业真实的研发方向。无论是人形机器人、机械臂抓取,还是移动底盘导航,背后都需要一套能把感知、决策、控制、通信串起来的软件框架。而目前综合生态最完整、社区最活跃、资料最多的框架,仍然是 ROS2。

很多读者第一次接触 ROS2 时会有一个困惑:我到底是直接学具身智能算法,还是先学 ROS2?答案是,如果你做的是真实机器人,哪怕只是仿真环境中的机器人,ROS2 都会成为你和硬件、传感器、算法模块之间的“中间层”。它本身不解决具体的视觉模型怎么做、路径规划怎么算,但它负责让这些模块能够互相通信、协同运行、可视化调试。可以把 ROS2 理解为机器人领域的“操作系统级软件底座”。

本文不是泛泛介绍,而是一份从零开始的 ROS2 上手教程。我们会在 Ubuntu 环境下完成 ROS2 安装,创建工作空间和功能包,再通过完整的 Python 示例跑通三种最核心的通信机制:话题(Topic)、服务(Service)、动作(Action)。最后补充坐标变换 tf2 和 Rviz2、Gazebo 等常用工具的使用思路。看完之后,你会具备独立搭建一个 ROS2 工程、编写节点并完成基础联调的能力。

在正式动手前,先简单区分一下 ROS1 和 ROS2。ROS1 最早诞生于 2007 年左右,设计上偏向单机、学术研究,通信依赖一个中心节点(roscore)。ROS2 则从 2017 年开始逐步成熟,底层通信改用了 DDS(Data Distribution Service),不再需要中心节点,支持多机通信、实时性要求更高的场景,也更适合现代机器人架构。2022 年发布的 ROS1 Noetic 是最后一个 ROS1 版本,ROS1 已经停止维护。所以现在新入门,不需要纠结,直接学 ROS2 就好。

本文的示例以 Ubuntu 22.04 + ROS2 Humble 为主,也会说明 Ubuntu 24.04 + ROS2 Jazzy 的对应关系。如果你之前没有任何 ROS 基础,也不用担心,下一章我们从环境安装开始,每一步都可以照着操作。


1. ROS2 环境搭建:版本选型与安装验证

1.1 Ubuntu 与 ROS2 版本对应关系

ROS2 的 LTS(Long Term Support,长期支持)版本与 Ubuntu 系统的 LTS 版本有严格对应关系。版本不匹配虽然可以通过源码编译强行安装,但对初学者来说,强烈建议直接选择官方支持的组合。

Ubuntu 版本推荐 ROS2 版本说明
Ubuntu 22.04 LTSROS2 Humble Hawksbill当前教程资料最多的版本,使用稳定
Ubuntu 24.04 LTSROS2 Jazzy Jalisco2024 年发布的新 LTS,适合新项目
Ubuntu 20.04 LTSROS2 Foxy Fitzroy较老版本,不建议新入门使用

本文命令以 Humble 为例,如果你使用的是 Ubuntu 24.04,把命令里的humble全部替换成jazzy即可,核心章节的 Python 代码在两个版本下基本通用。

需要注意的是,不要在公司内部生产机器上直接做破坏性实验,安装 ROS2 属于系统环境变更,建议先在虚拟机、Docker 容器或专用测试机上进行。

1.2 以 Humble 为例的完整安装步骤

打开终端,按顺序执行以下命令。

第一步,更新系统软件源并安装基础工具:

sudo apt update sudo apt install software-properties-common -y

第二步,添加 ROS2 官方软件源。这里先把 ROS2 的 GPG 密钥下载到系统 keyring 目录:

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

然后配置 apt 使用 ROS2 软件源:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

如果你的网络访问packages.ros.org不稳定,可以把这个源地址换成国内镜像源,一般常见的是清华 TUNA 镜像:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] https://mirrors.tuna.tsinghua.edu.cn/ros2/ubuntu $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null

注意,镜像源的完整配置方式要以镜像站自己的说明为准,这里仅提供思路。

第三步,更新软件索引并安装 ROS2 桌面版:

sudo apt update sudo apt upgrade -y sudo apt install ros-humble-desktop -y

ros-humble-desktop是桌面完整版,包含了 Rviz2、turtlesim 小海龟、demo 示例、常用消息库等,适合开发和可视化调试。如果你做的是非常精简的嵌入式部署,可以只安装:

sudo apt install ros-humble-ros-base -y

第四步,安装开发工具:

sudo apt install ros-dev-tools -y

ros-dev-tools包含colconrosdepros2命令行等常用工具,后面创建功能包和编译项目都离不开它们。

1.3 安装验证与常用环境变量

安装完成后,需要把 ROS2 的环境脚本加载到当前终端:

source /opt/ros/humble/setup.bash

为了以后每次打开终端都自动加载,可以把这行写入.bashrc

echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc source ~/.bashrc

验证安装是否成功:

ros2 --help

如果能看到 ROS2 命令行帮助信息,说明安装成功。接着跑一个最简单的小海龟测试:

ros2 run turtlesim turtlesim_node

另开一个终端:

ros2 run turtlesim turtle_teleop_key

这时会出现一只小海龟,用方向键控制它移动,就说明 ROS2 的核心通信链路已经正常工作了。

另外,很多教程会建议设置ROS_DOMAIN_ID环境变量。同一台机器或同一局域网内多个 ROS2 系统通信时,不同ROS_DOMAIN_ID可以隔离消息,避免互相干扰。单机学习时默认值足够。


2. 工作空间与功能包:ROS2 项目的组织方式

2.1 工作空间结构

ROS2 的项目组织方式和 ROS1 类似,核心单位是“功能包(Package)”,多个功能包放在同一个工作空间(Workspace)下统一编译。典型结构如下:

ros2_ws/ ├── src/ │ ├── pkg_a/ │ ├── pkg_b/ │ └── ... ├── build/ ├── install/ └── log/

src目录存放你自己写的功能包,buildinstalllog目录是执行colcon build后自动生成的。install目录下会有setup.bash,编译完成后需要 source 它,才能让新功能包被当前终端识别。

创建工作空间的命令:

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

此时src目录为空,直接colcon build也能成功,但没有任何包被编译。

2.2 创建第一个功能包

进入src目录,使用ros2 pkg create创建一个 Python 类型的功能包:

cd ~/ros2_ws/src ros2 pkg create py_talker_listener --build-type ament_python --dependencies rclpy std_msgs

这个命令会生成如下结构:

py_talker_listener/ ├── package.xml ├── py_talker_listener/ │ └── __init__.py ├── resource/ ├── setup.cfg ├── setup.py └── test/

参数解释:

  • --build-type ament_python:指定包类型为 Python 包。如果你更熟悉 C++,可以换成ament_cmake
  • --dependencies rclpy std_msgs:声明依赖,rclpy是 ROS2 的 Python 客户端库,std_msgs提供标准消息类型。

2.3 使用 colcon 构建

回到工作空间根目录,编译刚才创建的功能包:

cd ~/ros2_ws colcon build --packages-select py_talker_listener

--packages-select只编译指定的包,在包多的时候可以节省时间。编译完成后:

source install/setup.bash

之后用ros2 pkg list可以查看到该包。

2.4 功能包中的关键配置文件

Python 功能包中最重要的配置是setup.py里的entry_points。这个字段决定了ros2 run命令能否找到你的可执行程序。修改setup.py,添加如下内容:

entry_points={ 'console_scripts': [ 'talker = py_talker_listener.talker:main', 'listener = py_talker_listener.listener:main', ], },

其中talker是命令别名,后面这部分是“模块名:函数名”。比如py_talker_listener.talker:main,表示从py_talker_listener/talker.py模块中执行main函数。写错路径会导致运行时提示找不到入口点。

另外,setup.py中的packages字段需要保证 ROS2 的 Python 源码目录被正确打包。默认模板通常已经处理好了,如果改动目录结构,需要同步检查。


3. 节点与话题:ROS2 最核心的通信机制

3.1 节点与话题的概念

节点(Node)是 ROS2 中的最小执行单元。一个功能包可以包含多个节点,每个节点负责一个独立任务。节点之间通过话题(Topic)进行异步通信。

话题是一种发布/订阅模型。一个节点在话题上发布数据,其他节点订阅该话题接收数据。发布方和订阅方互不知道对方的存在,这种解耦设计让机器人系统可以灵活扩展。类似地,你把一个传感器节点接入系统,其他模块只需要订阅对应的话题,不需要修改。

消息类型(Message)决定了话题数据的结构。例如std_msgs/msg/String是一个非常基础的消息类型,只包含一个字符串字段data

3.2 用 Python 实现一个话题发布者

py_talker_listener/py_talker_listener/目录下新建talker.py

#!/usr/bin/env python3 import rclpy from rclpy.node import Node from std_msgs.msg import String class TalkerNode(Node): def __init__(self): super().__init__('talker') self.publisher_ = self.create_publisher(String, 'chatter', 10) self.timer = self.create_timer(0.5, self.timer_callback) self.count = 0 def timer_callback(self): msg = String() msg.data = 'Hello ROS2: %d' % self.count self.publisher_.publish(msg) self.get_logger().info('Publishing: "%s"' % msg.data) self.count += 1 def main(args=None): rclpy.init(args=args) node = TalkerNode() try: rclpy.spin(node) except KeyboardInterrupt: pass finally: node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()

代码要点:

  • create_publisher(String, 'chatter', 10)创建一个话题发布者,第一个参数是消息类型,第二个是话题名,第三个是消息队列长度。
  • create_timer(0.5, self.timer_callback)每 0.5 秒调用一次回调函数。
  • rclpy.spin(node)让节点持续运行,处理回调,直到被 Ctrl+C 中断。

3.3 用 Python 实现一个话题订阅者

在相同目录下新建listener.py

#!/usr/bin/env python3 import rclpy from rclpy.node import Node from std_msgs.msg import String class ListenerNode(Node): def __init__(self): super().__init__('listener') self.subscription = self.create_subscription( String, 'chatter', self.listener_callback, 10 ) def listener_callback(self, msg): self.get_logger().info('I heard: "%s"' % msg.data) def main(args=None): rclpy.init(args=args) node = ListenerNode() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()

注意,一个进程里如果创建了多个节点,rclpy.spin默认只会处理全局 executor 中的节点。上面的写法保持一个进程一个节点,是最稳妥的入门方式。

3.4 运行与验证

修改完setup.py和两个 Python 文件后,重新编译并 source:

cd ~/ros2_ws colcon build --packages-select py_talker_listener --symlink-install source install/setup.bash

--symlink-install对 Python 包非常有用,后续修改.py文件不用重新 build,直接生效。

先运行发布者:

ros2 run py_talker_listener talker

再开一个终端,source 环境后运行订阅者:

source /opt/ros/humble/setup.bash source ~/ros2_ws/install/setup.bash ros2 run py_talker_listener listener

预期输出中,订阅者终端会不断打印:

[INFO] I heard: "Hello ROS2: 0" [INFO] I heard: "Hello ROS2: 1"

此时可以用第三终端查看话题状态:

ros2 topic list ros2 topic echo /chatter ros2 topic info /chatter --verbose

3.5 QoS 策略与话题通信排错

QoS(Quality of Service,服务质量)是 ROS2 中非常重要的概念。它定义了消息传输的可靠性、历史数据保留策略等。

常见参数:

  • reliabilityRELIABLE(可靠传输,保证送达,适合控制指令)或BEST_EFFORT(尽力传输,延迟更低,适合图像、点云等大流量传感器数据)。
  • durabilityVOLATILE(不保存历史数据)或TRANSIENT_LOCAL(保存最近数据,晚加入的订阅者也能收到)。

如果发布者的 QoS 和订阅者不兼容,会出现“双方都能启动,但订阅者收不到数据”的情况。排查时用这个命令:

ros2 topic info /chatter --verbose

它会显示各端声明的 QoS 策略,能帮你快速定位问题。在实际项目中,图像传输常用BEST_EFFORT,导航指令用RELIABLE


4. 服务机制:同步请求与应答

4.1 服务机制解决的问题

话题是异步单向通信,机器人里很多场景需要“请求-应答”模式,例如:调用一个服务让机械臂运动到某个位置,运动完成后返回结果;或者查询机器人当前的电池电量。

ROS2 的服务(Service)提供的就是这种同步 RPC 式通信。客户端(Client)发送请求,服务端(Server)处理请求并返回响应。一个服务端可以同时服务多个客户端,但同一个请求只对应一个响应。

4.2 服务端与客户端代码实战

这里用一个加法服务作为示例。创建服务功能包:

cd ~/ros2_ws/src ros2 pkg create py_service_demo --build-type ament_python --dependencies rclpy example_interfaces

example_interfaces中提供了AddTwoInts.srv,包含两个整型请求字段ab,以及一个整型响应字段sum

py_service_demo/py_service_demo/下新建server.py

#!/usr/bin/env python3 import rclpy from rclpy.node import Node from example_interfaces.srv import AddTwoInts class AdderServer(Node): def __init__(self): super().__init__('adder_server') self.srv = self.create_service(AddTwoInts, 'add_two_ints', self.add_callback) def add_callback(self, request, response): response.sum = request.a + request.b self.get_logger().info('Incoming request: a=%d, b=%d' % (request.a, request.b)) return response def main(args=None): rclpy.init(args=args) node = AdderServer() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()

新建client.py

#!/usr/bin/env python3 import rclpy from rclpy.node import Node from example_interfaces.srv import AddTwoInts class AdderClient(Node): def __init__(self): super().__init__('adder_client') self.cli = self.create_client(AddTwoInts, 'add_two_ints') while not self.cli.wait_for_service(timeout_sec=1.0): self.get_logger().info('service not available, waiting...') def send_request(self, a, b): request = AddTwoInts.Request() request.a = a request.b = b future = self.cli.call_async(request) rclpy.spin_until_future_complete(self, future) return future.result() def main(args=None): rclpy.init(args=args) client = AdderClient() response = client.send_request(3, 5) client.get_logger().info('Result: %d + %d = %d' % (3, 5, response.sum)) client.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()

与话题回调不同的是,客户端的call_async返回的是一个 Future 对象,需要用spin_until_future_complete阻塞等待服务端返回。

4.3 配置与运行

修改setup.pyentry_points

entry_points={ 'console_scripts': [ 'server = py_service_demo.server:main', 'client = py_service_demo.client:main', ], },

然后编译:

cd ~/ros2_ws colcon build --packages-select py_service_demo --symlink-install source install/setup.bash

先启动服务端:

ros2 run py_service_demo server

再启动客户端:

ros2 run py_service_demo client

客户端会打印Result: 3 + 5 = 8。也可以直接用命令行工具测试服务:

ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 10, b: 20}"

这种方式在调试时很有用,不需要写任何代码就能验证服务端是否正常。


5. 动作机制:长时间任务的通信方案

5.1 动作机制的三段式结构

话题适合高频单向数据,服务适合短时同步调用。但如果是一个需要执行几十秒甚至更久的任务,比如“把机械臂移动到目标点”“导航到二楼会议室”,使用服务会有问题:调用方需要一直阻塞等待,中途无法取消,也无法获得过程反馈。

ROS2 的动作(Action)机制就是为了解决长任务控制而设计的。它由三部分组成:

  • 目标(Goal):客户端告诉服务端要做什么。
  • 反馈(Feedback):服务端在执行过程中持续返回当前进度。
  • 结果(Result):任务完成后返回最终结果。

动作的底层仍然借助了话题和服务,但对上层用户来说,你只需要关心目标、反馈、结果这三个阶段。

5.2 动作服务端实现

ROS2 中常见的动作接口是example_interfaces/action/Fibonacci。它接收一个整数order,表示要计算的斐波那契数列项数,执行过程中不断发布当前已经算出的序列,最终返回完整序列。

继续在py_service_demo包中演示,先新建action_server.py

#!/usr/bin/env python3 import rclpy from rclpy.action import ActionServer from rclpy.node import Node 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 ) self.get_logger().info('Action server is running.') def execute_callback(self, goal_handle): self.get_logger().info('Executing goal: order=%d' % goal_handle.request.order) 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[i - 1] + feedback_msg.sequence[i] ) goal_handle.publish_feedback(feedback_msg) self.get_logger().info('Feedback: {0}'.format(feedback_msg.sequence)) goal_handle.succeed() result = Fibonacci.Result() result.sequence = feedback_msg.sequence return result def main(args=None): rclpy.init(args=args) node = FibonacciServer() try: rclpy.spin(node) except KeyboardInterrupt: pass finally: node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()

这里的execute_callback是动作服务端核心,它会在收到目标后执行任务循环,并通过goal_handle.publish_feedback发布反馈。

5.3 动作客户端实现

新建action_client.py

#!/usr/bin/env python3 import rclpy from rclpy.action import ActionClient from rclpy.node import Node from example_interfaces.action import Fibonacci class FibonacciClient(Node): def __init__(self): super().__init__('fibonacci_client') self._action_client = ActionClient(self, Fibonacci, 'fibonacci') def send_goal(self, order): goal_msg = Fibonacci.Goal() goal_msg.order = order self._action_client.wait_for_server() self._send_goal_future = self._action_client.send_goal_async( goal_msg, feedback_callback=self.feedback_callback ) self._send_goal_future.add_done_callback(self.goal_response_callback) def goal_response_callback(self, future): goal_handle = future.result() if not goal_handle.accepted: self.get_logger().info('Goal rejected :(') return self.get_logger().info('Goal accepted :)') self._get_result_future = goal_handle.get_result_async() self._get_result_future.add_done_callback(self.get_result_callback) def get_result_callback(self, future): result = future.result().result self.get_logger().info('Result: {0}'.format(result.sequence)) rclpy.shutdown() def feedback_callback(self, feedback_msg): feedback = feedback_msg.feedback self.get_logger().info('Received feedback: {0}'.format(feedback.sequence)) def main(args=None): rclpy.init(args=args) node = FibonacciClient() node.send_goal(10) rclpy.spin(node) if __name__ == '__main__': main()

客户端发送目标后,通过回调分别处理“服务端是否接受目标”“执行过程中的实时反馈”“最终结果”三个阶段。这种异步模型非常适合导航和机械臂控制。

修改setup.pyentry_points

entry_points={ 'console_scripts': [ 'server = py_service_demo.server:main', 'client = py_service_demo.client:main', 'action_server = py_service_demo.action_server:main', 'action_client = py_service_demo.action_client:main', ], },

编译并运行:

cd ~/ros2_ws colcon build --packages-select py_service_demo --symlink-install source install/setup.bash ros2 run py_service_demo action_server

另一个终端:

source /opt/ros/humble/setup.bash source ~/ros2_ws/install/setup.bash ros2 run py_service_demo action_client

客户端会持续收到斐波那契数列的中间结果,最后打印完整序列。


6. 坐标变换与常用工具:tf2、Rviz2、Gazebo、小海龟

6.1 tf2 坐标变换基础

在机器人系统中,不同传感器、关节、部件都有自己的坐标系。例如激光雷达在车顶,摄像头在车头,机械臂末端在手臂末端,要融合这些数据,必须知道每个坐标系之间的相对位置和姿态。

ROS2 中负责这件事的库是 tf2。它维护了一棵坐标变换树,每个变换关系都带时间戳,机器人实时查询“激光点云在 base_link 坐标系下的位置”这类问题时,tf2 会自动完成坐标转换。

tf2 中的两个关键概念:

  • frame_id:父坐标系名称,例如worldmap
  • child_frame_id:子坐标系名称,例如base_linklaser_frame

坐标变换分为静态变换(两个坐标系相对关系固定)和动态变换(关系随时间变化),例如底盘到激光雷达之间是静态,而机械臂关节之间的变换是动态。

6.2 发布静态与动态坐标变换

最简单的静态变换可以通过命令行发布。在终端中执行:

ros2 run tf2_ros static_transform_publisher 1.0 0.0 0.5 0 0 0 world robot_base

这条命令表示把robot_base坐标系固定在world坐标系下 x=1.0、y=0.0、z=0.5 的位置,旋转角为 0。不同 ROS2 版本中 static_transform_publisher 的参数顺序可能略有差异,建议先用ros2 run tf2_ros static_transform_publisher --help确认。

如果需要在代码中动态发布坐标变换,可以新建一个节点:

#!/usr/bin/env python3 import rclpy from rclpy.node import Node from geometry_msgs.msg import TransformStamped from tf2_ros import TransformBroadcaster class DynamicTFBroadcaster(Node): def __init__(self): super().__init__('dynamic_tf_broadcaster') self.tf_broadcaster = TransformBroadcaster(self) self.timer = self.create_timer(0.1, self.broadcast_timer_callback) def broadcast_timer_callback(self): t = TransformStamped() t.header.stamp = self.get_clock().now().to_msg() t.header.frame_id = 'world' t.child_frame_id = 'robot_base' t.transform.translation.x = 1.0 t.transform.translation.y = 0.0 t.transform.translation.z = 0.5 # 四元数表示姿态,这里为单位四元数 t.transform.rotation.x = 0.0 t.transform.rotation.y = 0.0 t.transform.rotation.z = 0.0 t.transform.rotation.w = 1.0 self.tf_broadcaster.sendTransform(t) def main(args=None): rclpy.init(args=args) node = DynamicTFBroadcaster() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()

这里特别注意,tf2 中的旋转使用的是四元数,不是欧拉角。如果你习惯用 Roll-Pitch-Yaw 欧拉角,需要先做转换。ROS2 的tf_transformations库提供了quaternion_from_euler方法。

6.3 Rviz2 可视化

Rviz2 是 ROS2 官方的 3D 可视化工具。它最大的价值在于,你可以直观看到机器人的模型、传感器数据、坐标变换关系,而不需要把每个数据打印到终端。

运行:

ros2 run rviz2 rviz2

在 Rviz2 界面左侧的Displays面板点击Add,添加TF显示,就能看到世界坐标和各个 frame 之间的坐标轴关系。添加RobotModel可以加载机器人 URDF 模型,添加LaserScanPointCloud2可以显示雷达和点云数据。

在具身智能相关项目中,Rviz2 几乎是必用的调试工具。很多看似复杂的传感器对齐问题,打开 Rviz2 看一眼 TF 树就明白了。

6.4 Gazebo 仿真与小海龟示例

Gazebo 是目前 ROS2 生态中最常用的机器人仿真环境之一,可以模拟物理碰撞、重力、传感器噪声。安装 Gazebo 相关插件:

sudo apt install ros-humble-gazebo-ros-pkgs -y

启动一个空的 Gazebo 世界:

ros2 launch gazebo_ros gazebo.launch.py

Gazebo 和 Rviz2 配合使用时,通常还需要 camera、laser 等传感器插件,这部分会涉及 URDF 和 xacro 建模,属于进阶内容。入门阶段,推荐先用小海龟把 ROS2 基础通信彻底跑熟,再进入仿真环境。

小海龟虽然简单,却是理解 ROS2 通信机制最好的教材:

ros2 run turtlesim turtlesim_node

另外终端执行:

ros2 run turtlesim turtle_teleop_key

然后在新终端查看:

ros2 node list ros2 topic list ros2 topic echo /turtle1/pose

通过ros2 topic echo /turtle1/pose,你能看到小海龟每一帧的位置和角度数据,这其实就是移动机器人里程计信息的最简化版本。


7. 常见问题与排查思路

7.1 安装与构建类问题

问题现象常见原因解决思路
sudo apt update时 ROS2 源报错软件源地址不可达或 key 路径不对检查/etc/apt/sources.list.d/ros2.list,切换国内镜像源
ros2: command not found没有 source ROS2 环境执行source /opt/ros/humble/setup.bash,并写入~/.bashrc
colcon: command not found没有安装ros-dev-tools执行sudo apt install ros-dev-tools
ros2 run提示找不到入口点setup.pyentry_points路径写错检查入口点 = 模块路径:函数名是否与文件实际路径一致
不同 ROS2 LTS 混用导致编译报错系统存在多版本 ROS2 环境变量冲突一个终端只 source 一个 ROS2 版本,工作空间内包保持一致

7.2 通信与运行类问题

问题现象常见原因解决思路
发布者和订阅者都启动,但订阅不到数据QoS 不兼容,或话题名拼写不一致使用ros2 topic info /话题名 --verbose检查 QoS
多机通信时节点互相看不见ROS_DOMAIN_ID不同,或 DDS 发现机制受阻把多台机器设置为相同ROS_DOMAIN_ID,确保在同一网段
服务客户端一直打印 waiting服务端未启动,或服务名不一致先启动服务端,用ros2 service list检查服务名
程序运行时卡住,Ctrl+C 无法退出回调中写了阻塞逻辑,或spin使用不当保持spin在主线,避免在回调中做耗时操作

7.3 仿真与可视化类问题

问题现象常见原因解决思路
Rviz2 中看不到机器人模型未添加 RobotModel,或模型描述话题未发布确认/robot_description话题存在,并在 Rviz2 中正确添加显示
Gazebo 启动后机器人掉落或穿模模型缺少碰撞属性,或物理参数配置错误检查 URDF 中<collision><inertial>配置
tf2 查询不到坐标变换变换发布方未启动,或 parent/child 关系写反ros2 run tf2_ros tf2_echo 父坐标系 子坐标系调试

另外,在 Windows 系统中安装 ROS2 桌面相关工具时,有读者遇到过“此应用包不支持通过应用安装程序安装,因为它使用了某些受限制的功能”的提示。这类问题通常是系统缺少开发人员模式或应用安装权限受限导致的。如果你不是在 Windows 下编译源码,我更推荐直接用 WSL2 + Docker 或 Linux 虚拟机作为初学环境,可以避开大量系统兼容问题。


8. 最佳实践与学习路线建议

8.1 工程化开发建议

在学习阶段就能养成的 ROS2 开发习惯,会直接影响后续做项目的效率。

第一,包名、节点名、话题名使用蛇形命名法,例如py_talker_listener、`

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询