ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ROS2从零入门:安装配置、三大通信机制与实战详解

ROS2从零入门:安装配置、三大通信机制与实战详解 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 年开始逐步成熟底层通信改用了 DDSData 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 的 LTSLong 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 -yros-humble-desktop是桌面完整版包含了 Rviz2、turtlesim 小海龟、demo 示例、常用消息库等适合开发和可视化调试。如果你做的是非常精简的嵌入式部署可以只安装sudo apt install ros-humble-ros-base -y第四步安装开发工具sudo apt install ros-dev-tools -yros-dev-tools包含colcon、rosdep、ros2命令行等常用工具后面创建功能包和编译项目都离不开它们。1.3 安装验证与常用环境变量安装完成后需要把 ROS2 的环境脚本加载到当前终端source /opt/ros/humble/setup.bash为了以后每次打开终端都自动加载可以把这行写入.bashrcecho 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目录存放你自己写的功能包build、install、log目录是执行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(argsNone): rclpy.init(argsargs) 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)让节点持续运行处理回调直到被 CtrlC 中断。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(argsNone): rclpy.init(argsargs) node ListenerNode() rclpy.spin(node) node.destroy_node() rclpy.shutdown() if __name__ __main__: main()注意一个进程里如果创建了多个节点rclpy.spin默认只会处理全局 executor 中的节点。上面的写法保持一个进程一个节点是最稳妥的入门方式。3.4 运行与验证修改完setup.py和两个 Python 文件后重新编译并 sourcecd ~/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 --verbose3.5 QoS 策略与话题通信排错QoSQuality 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_interfacesexample_interfaces中提供了AddTwoInts.srv包含两个整型请求字段a和b以及一个整型响应字段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(argsNone): rclpy.init(argsargs) 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_sec1.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(argsNone): rclpy.init(argsargs) 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.py的entry_pointsentry_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(argsNone): rclpy.init(argsargs) 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_callbackself.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(argsNone): rclpy.init(argsargs) node FibonacciClient() node.send_goal(10) rclpy.spin(node) if __name__ __main__: main()客户端发送目标后通过回调分别处理“服务端是否接受目标”“执行过程中的实时反馈”“最终结果”三个阶段。这种异步模型非常适合导航和机械臂控制。修改setup.py的entry_pointsentry_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父坐标系名称例如world或map。child_frame_id子坐标系名称例如base_link、laser_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坐标系下 x1.0、y0.0、z0.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(argsNone): rclpy.init(argsargs) 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 模型添加LaserScan、PointCloud2可以显示雷达和点云数据。在具身智能相关项目中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.pyGazebo 和 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并写入~/.bashrccolcon: command not found没有安装ros-dev-tools执行sudo apt install ros-dev-toolsros2 run提示找不到入口点setup.py中entry_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检查服务名程序运行时卡住CtrlC 无法退出回调中写了阻塞逻辑或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、
返回列表