ROS编程实战:从零构建虚拟温度传感器与监控系统 1. 项目缘起为什么从“鱼香ROS”开始聊ROS编程如果你最近在B站、知乎或者一些机器人技术社区里逛大概率会刷到“鱼香ROS”或者“小鱼ROS一键安装”这些词。这其实反映了一个非常真实的现状很多对机器人操作系统ROS感兴趣的朋友尤其是学生和刚入行的开发者在第一步“安装ROS”上就卡住了。官方的安装文档虽然详尽但步骤繁琐对网络环境、系统版本依赖性强一个依赖包没装好就可能前功尽弃。于是像“鱼香ROS一键安装脚本”这样的社区工具应运而生它通过一个脚本自动化解决环境配置问题极大地降低了入门门槛。但安装成功只是万里长征的第一步。当你兴奋地输入roscore看到那个熟悉的日志输出后下一个问题立刻摆在了面前“然后呢我该怎么开始写我的第一个ROS程序” 网上能找到的教程要么是过于理论通篇讲节点、话题、服务、动作这些概念要么是过于零散只给一个“Hello World”的发布订阅例子离实际项目相去甚远。你需要的是一份能串联起核心概念、提供完整项目上下文、并且附上每一步可运行代码的实战指南。这就是我写这篇教程的初衷。我不打算重复那些枯燥的概念定义而是想通过构建一个完整的、有实际意义的微型项目带你走一遍ROS编程的全流程。我们将从零开始创建一个能模拟传感器数据发布、并进行简单处理的机器人应用。在这个过程中你会自然而然地理解节点、话题、消息、服务这些核心组件是如何协同工作的并掌握编写、编译、调试ROS程序的标准方法。所有代码都是可运行的你可以一边看一边在自己的环境里复现。2. 环境准备不仅仅是安装ROS在开始敲代码之前一个稳定、干净的开发环境至关重要。虽然“一键安装”很方便但了解背后的原理能让你在遇到问题时更有底气。2.1 ROS发行版与系统选择目前ROS主要有两个活跃版本系列ROS 1 (Noetic) 和 ROS 2 (Humble, Iron, Jazzy)。对于纯粹的新手我仍然推荐从ROS 1 Noetic开始。原因很简单其生态成熟资料尤其是中文资料极其丰富社区遇到的大部分问题都能找到现成的解决方案。ROS 2虽然代表未来设计更优秀但其学习曲线更陡峭且在某些中间件配置上容易让新手困惑。本教程基于Ubuntu 20.04 ROS Noetic进行这也是目前最稳定、最通用的新手组合。如果你使用的是Ubuntu 22.04或24.04官方推荐搭配ROS 2 Humble或Jazzy。虽然核心编程思想相通但具体的命令行工具ros2vsros、构建系统colconvscatkin和部分API有差异。如果你想用ROS 2跟随本教程需要自行转换部分命令和代码这本身也是一个很好的学习过程。2.2 超越“一键安装”理解Catkin工作空间使用“鱼香ROS”等脚本安装后你的系统里已经有了ROS的核心库和工具。但我们的代码不会直接放在系统路径下而是需要一个独立的工作空间。在ROS 1中这个构建系统叫做Catkin。你可以把Catkin工作空间理解为你个人的机器人项目“车间”。所有你自己写的包PackageROS软件的基本组织单元都放在这个车间里进行编译、管理。系统自带的ROS包相当于“标准件库”放在另一个地方。这种隔离保证了你的项目不会污染系统也便于管理和迁移。创建一个标准工作空间的步骤如下# 1. 创建并进入工作空间目录 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src # 2. 初始化工作空间。这会在src目录下生成一个CMakeLists.txt的链接文件。 catkin_init_workspace # 3. 回到工作空间根目录进行第一次编译。这主要是构建工作空间本身的基础结构。 cd ~/catkin_ws catkin_make # 4. 配置环境变量。这一步非常关键它让你当前的终端能“找到”你工作空间里编译好的程序。 source devel/setup.bash为了不用每次开新终端都手动source可以把这行命令加到你的~/.bashrc文件末尾echo source ~/catkin_ws/devel/setup.bash ~/.bashrc source ~/.bashrc现在你的个人“车间”就搭建好了。后续我们创建的所有包都会放在~/catkin_ws/src/目录下。3. 第一个ROS包定义我们的微型项目我们不写孤立的“Hello World”而是设计一个简单的模拟项目一个虚拟温度传感器节点和一个温度监控节点。传感器节点周期性地发布当前的温度读数模拟数据监控节点订阅这些读数并在温度超过阈值时在终端发出警告。3.1 创建功能包Package在ROS中所有代码都必须归属于一个“包”。包是ROS中组织软件的基本单元它包含了实现特定功能的节点、库、配置文件等。进入你的工作空间src目录使用catkin_create_pkg命令创建我们的第一个包cd ~/catkin_ws/src catkin_create_pkg my_first_robot rospy std_msgs解释一下这个命令my_first_robot: 这是我们包的名字。rospy: 这表示我们的包依赖ROS的Python客户端库rospy。我们将主要使用Python进行编程因为它上手快原型开发效率高。std_msgs: 这表示我们依赖ROS的标准消息库。我们需要使用里面定义的基本数据类型比如Float32来构建我们自己的消息。命令执行后会在src目录下生成一个名为my_first_robot的文件夹其结构如下my_first_robot/ ├── CMakeLists.txt # 包的编译规则由catkin管理 ├── package.xml # 包的元信息如名称、版本、依赖 └── src/ # 未来存放C源码的目录本例用不到对于Python项目我们通常需要手动创建两个目录cd my_first_robot mkdir scripts msgscripts/: 用于存放所有Python可执行脚本我们的节点。msg/: 用于存放自定义的消息定义文件.msg。3.2 设计消息接口温度读数节点之间通过消息Message在话题Topic上进行通信。消息是一种严格定义的数据结构。虽然我们可以直接使用std_msgs/Float32来发送一个浮点数温度值但实际项目中消息往往携带更多信息。我们来定义一个自定义消息。在msg/目录下创建文件Temperature.msg# my_first_robot/msg/Temperature.msg Header header # 标准消息头包含时间戳、坐标系等信息 float32 value # 温度值 string unit # 温度单位如 “Celsius”Header是一个非常有用的标准结构它包含seq序列号、stamp时间戳和frame_id坐标系ID。加上它我们的温度读数就有了时空上下文这在多传感器融合、数据记录rosbag时至关重要。value和unit则承载了业务数据。定义好消息后我们需要让编译系统知道它。修改package.xml文件确保包含以下两行通常catkin_create_pkg已自动添加但需检查build_dependmessage_generation/build_depend exec_dependmessage_runtime/exec_depend然后修改CMakeLists.txt文件在find_package(...)部分确保包含message_generation。取消注释或添加add_message_files(...)部分add_message_files( FILES Temperature.msg )取消注释或添加generate_messages(...)部分。在catkin_package(...)中确保CATKIN_DEPENDS包含message_runtime。完成以上修改后回到工作空间根目录编译cd ~/catkin_ws catkin_make编译成功后你就可以在Python代码中通过from my_first_robot.msg import Temperature来使用这个消息了。ROS会自动在devel/lib/python3/dist-packages/下生成对应的Python模块。注意每次修改.msg文件或CMakeLists.txt中关于消息/服务的配置后都必须重新执行catkin_make才能使更改生效。4. 编写节点从发布者到订阅者现在进入核心的编程环节。我们将创建两个Python节点。4.1 虚拟温度传感器节点发布者在scripts/目录下创建文件virtual_temp_sensor.py并赋予可执行权限cd ~/catkin_ws/src/my_first_robot/scripts touch virtual_temp_sensor.py chmod x virtual_temp_sensor.py编辑其内容#!/usr/bin/env python3 # -*- coding: utf-8 -*- import rospy import random from my_first_robot.msg import Temperature from std_msgs.msg import Header def sensor_node(): # 初始化节点节点名称必须唯一 rospy.init_node(virtual_temperature_sensor, anonymousTrue) # 创建一个Publisher发布到名为“/temperature”的话题消息类型为Temperature队列大小10 pub rospy.Publisher(/temperature, Temperature, queue_size10) # 设置发布频率1Hz (每秒1次) rate rospy.Rate(1) # 模拟一个初始温度和环境参数 current_temp 25.0 # 初始温度25度 rospy.loginfo(虚拟温度传感器节点已启动开始发布数据...) seq 0 while not rospy.is_shutdown(): # 模拟温度变化在基础值上增加一个随机波动 # 使用随机游走模型使变化更连续 delta random.uniform(-0.5, 0.5) current_temp delta # 简单限制一下范围避免过于离谱 current_temp max(15.0, min(35.0, current_temp)) # 构造消息 temp_msg Temperature() # 填充Header temp_msg.header Header() temp_msg.header.seq seq temp_msg.header.stamp rospy.Time.now() # 当前ROS时间 temp_msg.header.frame_id sensor_frame # 填充数据 temp_msg.value current_temp temp_msg.unit Celsius # 发布消息 pub.publish(temp_msg) # 打印日志便于调试 rospy.loginfo(发布温度: %.2f %s [seq:%d], temp_msg.value, temp_msg.unit, seq) seq 1 rate.sleep() # 按照设定的频率休眠 if __name__ __main__: try: sensor_node() except rospy.ROSInterruptException: pass代码解读与注意事项#!/usr/bin/env python3 首行shebang让系统知道用Python3解释器执行此脚本。rospy.init_node() 每个ROS节点都必须初始化。anonymousTrue参数会在节点名后附加一个随机数防止多次启动同一节点时名称冲突。rospy.Publisher() 创建发布者。queue_size是一个重要参数它定义了发布者的缓存队列大小。如果发布消息的速度快于网络发送的速度旧消息会被丢弃。对于实时性要求不高的传感器10是一个常用值。rospy.Rate() 方便地控制循环频率。rate.sleep()会计算并休眠足够的时间以满足设定的频率。rospy.Time.now() 获取当前ROS时间这比使用系统时间更好因为它与ROS的仿真时间/clock兼容。rospy.loginfo() 使用ROS的日志系统输出信息比print更规范可以分级info, warn, error, debug并重定向。rospy.is_shutdown() 检查ROS是否被关闭如按CtrlC这是循环退出的标准条件。异常处理 捕获ROSInterruptException是良好习惯确保节点被CtrlC终止时能安静退出。4.2 温度监控节点订阅者在同一个scripts/目录下创建文件temperature_monitor.py并赋予可执行权限touch temperature_monitor.py chmod x temperature_monitor.py编辑其内容#!/usr/bin/env python3 # -*- coding: utf-8 -*- import rospy from my_first_robot.msg import Temperature # 这是一个回调函数当收到新消息时会被自动调用 def temperature_callback(msg): 处理接收到的温度消息。 :param msg: 接收到的Temperature消息对象 # 从Header中获取时间戳并转换为易读格式可选 recv_time msg.header.stamp.to_sec() # 获取温度值 temp_value msg.value # 业务逻辑判断是否超过阈值 HIGH_TEMP_THRESHOLD 30.0 LOW_TEMP_THRESHOLD 18.0 if temp_value HIGH_TEMP_THRESHOLD: rospy.logwarn([警报] 温度过高当前温度: %.2f %s (时间: %.2f), temp_value, msg.unit, recv_time) elif temp_value LOW_TEMP_THRESHOLD: rospy.logwarn([警报] 温度过低当前温度: %.2f %s (时间: %.2f), temp_value, msg.unit, recv_time) else: rospy.loginfo([正常] 当前温度: %.2f %s, temp_value, msg.unit) def monitor_node(): # 初始化节点 rospy.init_node(temperature_monitor, anonymousTrue) # 创建一个Subscriber订阅名为“/temperature”的话题消息类型为Temperature # 收到新消息时调用temperature_callback函数进行处理 sub rospy.Subscriber(/temperature, Temperature, temperature_callback) rospy.loginfo(温度监控节点已启动开始监听 /temperature 话题...) # rospy.spin() 会让程序保持运行直到节点被关闭。 # 它会持续监听订阅的话题一旦有消息到来就自动调用注册的回调函数。 rospy.spin() if __name__ __main__: try: monitor_node() except rospy.ROSInterruptException: pass代码解读与注意事项回调函数Callback 这是ROS订阅者编程的核心模式。你不需要主动去“轮询”或“读取”消息而是定义一个函数temperature_callback告诉ROS“当有新消息到达时请调用这个函数并把消息作为参数传给它”。这种事件驱动模型非常高效。rospy.Subscriber() 创建订阅者。三个关键参数话题名、消息类型、回调函数。注意话题名必须与发布者发布的话题名完全一致包括前面的斜杠/。rospy.spin() 这个调用会阻塞当前线程让程序进入一个循环等待并处理到来的消息。对于只做订阅的简单节点在初始化后直接调用rospy.spin()即可。如果节点还需要做其他周期性工作比如同时也是一个发布者则通常使用while not rospy.is_shutdown():循环并在循环内调用rate.sleep()和rospy.spinOnce()在C中常见Python的rospy在后台自动处理了spinOnce。日志分级 我们使用了rospy.logwarn()来输出警告信息这在终端中会以黄色显示更容易引起注意。合理使用日志分级debug, info, warn, error, fatal是调试和监控程序状态的好习惯。5. 运行与调试让整个系统动起来代码写好了现在是见证成果的时刻。ROS程序的运行有一套标准的流程。5.1 启动ROS核心roscore在任何ROS 1程序运行前必须先启动一个roscore。它是ROS系统的“大脑”提供了名称注册、参数服务器等核心服务。打开一个新的终端我们称之为终端1roscore你会看到一系列启动日志最后保持运行状态。不要关闭这个终端。5.2 运行传感器节点打开第二个终端终端2务必先激活工作空间的环境变量然后运行我们的传感器节点# 激活环境如果你已将source命令加入.bashrc则新终端会自动激活 source ~/catkin_ws/devel/setup.bash # 运行节点 rosrun my_first_robot virtual_temp_sensor.py你应该会看到类似以下的输出每秒一条[INFO] [1712345678.910123]: 虚拟温度传感器节点已启动开始发布数据... [INFO] [1712345678.910456]: 发布温度: 25.00 Celsius [seq:0] [INFO] [1712345679.911222]: 发布温度: 24.73 Celsius [seq:1] ...节点已经运行起来了正在向/temperature话题发布消息。5.3 运行监控节点打开第三个终端终端3同样先激活环境然后运行监控节点source ~/catkin_ws/devel/setup.bash rosrun my_first_robot temperature_monitor.py你会看到监控节点启动的日志然后开始打印接收到的温度信息。当温度超过30度或低于18度时会打印警告黄色字体[INFO] [1712345678.920123]: 温度监控节点已启动开始监听 /temperature 话题... [INFO] [1712345678.930456]: [正常] 当前温度: 25.00 Celsius [INFO] [1712345679.931222]: [正常] 当前温度: 24.73 Celsius ... [WARN] [1712345685.941234]: [警报] 温度过高当前温度: 30.15 Celsius (时间: 1712345685.94)5.4 使用命令行工具进行调试与观察ROS提供了强大的命令行工具让你可以在不修改代码的情况下洞察系统状态。这些工具是调试的利器。查看活跃节点与话题 打开第四个终端输入rosnode list你会看到类似/virtual_temperature_sensor_12345和/temperature_monitor_67890的节点名后面的数字是anonymousTrue产生的随机数。 输入rostopic list你会看到/temperature这个话题以及ROS系统默认的一些话题如/rosout,/rosout_agg。实时查看话题上的消息内容rostopic echo /temperature这个命令会持续打印/temperature话题上流动的原始消息数据包括header和value等所有字段。这是验证消息是否正确发布的最直接方法。查看话题的详细信息rostopic info /temperature这会显示该话题的类型my_first_robot/Temperature、发布者节点和订阅者节点。非常有用可以确认通信链路是否建立。手动发布一条消息测试用 如果你想测试监控节点而不启动传感器节点可以手动发布消息rostopic pub -r 1 /temperature my_first_robot/Temperature header: seq: 0 stamp: {secs: 0, nsecs: 0} frame_id: manual_test value: 32.5 unit: Celsius这个命令会以1Hz的频率发布一条温度为32.5度的消息。监控节点会立刻产生高温警报。5.5 使用rqt_graph可视化节点与话题连接对于更复杂的系统图形化工具能帮你理清脉络。ROS提供了rqt_graph。rqt_graph一个GUI窗口会弹出你可以看到两个椭圆代表节点/virtual_temperature_sensor...和/temperature_monitor...以及一个方框代表话题/temperature并用箭头连接起来清晰地展示了“发布-订阅”的关系。如果图形没有正确显示可以点击左上角的刷新按钮。6. 项目进阶引入服务与参数服务器话题Topic是一种单向、异步的通信方式发布者“只管说”订阅者“只管听”双方不需要知道对方是否存在。但有时我们需要一种双向、同步的交互比如请求一个计算并等待结果。这时就需要服务Service。让我们为监控节点增加一个功能允许动态修改温度阈值。我们将创建一个服务当调用这个服务时可以设置新的高温和低温阈值。6.1 定义服务Service服务需要定义请求Request和响应Response的数据结构。在包目录下创建srv/文件夹并在其中创建SetThreshold.srv文件cd ~/catkin_ws/src/my_first_robot mkdir srv编辑srv/SetThreshold.srv# 请求部分客户端发送给服务器的数据 float32 high_threshold float32 low_threshold --- # 响应部分服务器返回给客户端的数据 bool success string messagesrv文件用三个短横线---分隔请求和响应。这里客户端发送两个浮点数作为新的阈值服务器返回一个布尔值表示是否设置成功以及一个字符串消息。同样需要修改package.xml和CMakeLists.txt来包含服务定义。package.xml的依赖部分已经包含了message_generation和message_runtime服务也依赖它们。在CMakeLists.txt中修改add_service_files部分add_service_files( FILES SetThreshold.srv )然后重新编译cd ~/catkin_ws catkin_make6.2 在监控节点中实现服务端我们需要修改temperature_monitor.py使其既能订阅话题又能提供修改阈值的服务。更新后的temperature_monitor.py核心部分#!/usr/bin/env python3 # -*- coding: utf-8 -*- import rospy from my_first_robot.msg import Temperature from my_first_robot.srv import SetThreshold, SetThresholdResponse class TemperatureMonitor: def __init__(self): # 初始化节点 rospy.init_node(temperature_monitor, anonymousTrue) # 从参数服务器读取初始阈值如果不存在则使用默认值 # 这提供了另一种灵活的配置方式 self.high_threshold rospy.get_param(~high_threshold, 30.0) self.low_threshold rospy.get_param(~low_threshold, 18.0) rospy.loginfo(初始温度阈值 - 高: %.1f, 低: %.1f, self.high_threshold, self.low_threshold) # 创建订阅者 self.sub rospy.Subscriber(/temperature, Temperature, self.temperature_callback) # 创建服务端服务名为“set_threshold”使用自定义的SetThreshold服务类型 # 当有请求到来时调用 self.handle_set_threshold 方法 self.srv rospy.Service(set_threshold, SetThreshold, self.handle_set_threshold) rospy.loginfo(温度监控节点已启动。服务 ‘set_threshold’ 已就绪。) def temperature_callback(self, msg): 处理温度消息的回调函数 temp_value msg.value if temp_value self.high_threshold: rospy.logwarn([警报] 温度过高当前: %.2f %s (阈值: %.1f), temp_value, msg.unit, self.high_threshold) elif temp_value self.low_threshold: rospy.logwarn([警报] 温度过低当前: %.2f %s (阈值: %.1f), temp_value, msg.unit, self.low_threshold) else: rospy.loginfo([正常] 当前温度: %.2f %s, temp_value, msg.unit) def handle_set_threshold(self, req): 处理设置阈值服务的请求。 :param req: SetThresholdRequest 对象包含 high_threshold 和 low_threshold 字段 :return: SetThresholdResponse 对象 # 简单的业务逻辑验证高温阈值必须大于低温阈值 if req.high_threshold req.low_threshold: response SetThresholdResponse() response.success False response.message 设置失败高温阈值必须大于低温阈值。 rospy.logerr(尝试设置无效阈值: 高%.1f, 低%.1f, req.high_threshold, req.low_threshold) return response # 验证通过更新内部阈值 old_high, old_low self.high_threshold, self.low_threshold self.high_threshold req.high_threshold self.low_threshold req.low_threshold response SetThresholdResponse() response.success True response.message 阈值更新成功。 rospy.loginfo(阈值已更新: 高 %.1f - %.1f, 低 %.1f - %.1f, old_high, self.high_threshold, old_low, self.low_threshold) return response def run(self): 保持节点运行 rospy.spin() if __name__ __main__: try: monitor TemperatureMonitor() monitor.run() except rospy.ROSInterruptException: pass主要改动类封装 将节点逻辑封装进TemperatureMonitor类使代码结构更清晰便于管理多个回调函数和共享数据如阈值。参数服务器 使用rospy.get_param(~high_threshold, 30.0)从ROS参数服务器读取参数。~表示私有参数其完整名称是/temperature_monitor_xxxxx/high_threshold。这允许我们通过启动文件或命令行动态配置节点。服务端创建rospy.Service(set_threshold, SetThreshold, self.handle_set_threshold)创建了一个名为set_threshold的服务。当有客户端调用该服务时handle_set_threshold方法会被调用并传入一个包含请求数据的req对象。该方法必须返回一个响应对象。6.3 测试服务功能重新编译并运行节点因为srv文件改变了需要重新catkin_makecd ~/catkin_ws catkin_make source devel/setup.bash # 在终端2重新运行传感器节点如果已关闭 rosrun my_first_robot virtual_temp_sensor.py # 在终端3重新运行监控节点 rosrun my_first_robot temperature_monitor.py使用命令行调用服务 打开一个新终端使用rosservice call命令来测试我们的服务# 调用 set_threshold 服务设置高温阈值为28低温阈值为20 rosservice call /set_threshold high_threshold: 28.0 low_threshold: 20.0如果成功你会看到类似输出success: True message: 阈值更新成功。同时监控节点的终端里会打印日志信息。现在如果传感器发布的温度超过28度或低于20度就会触发警报。测试错误情况# 尝试设置非法阈值高温不大于低温 rosservice call /set_threshold high_threshold: 25.0 low_threshold: 26.0你会收到失败的响应并在监控节点看到错误日志。6.4 使用rqt_reconfigure动态调整参数除了服务ROS还提供了另一种更“轻量”的动态配置方式动态参数服务器dynamic_reconfigure。它特别适合需要频繁调整的调试参数。由于设置稍复杂这里不展开代码但你可以通过rqt_reconfigureGUI工具直观地修改那些通过rospy.get_param读取的参数需要节点支持dynamic_reconfigure我们的简单节点暂不支持。了解这个工具的存在是很有用的rosrun rqt_reconfigure rqt_reconfigure7. 工程化与最佳实践思考通过上面的例子你已经完成了一个微型但完整的ROS应用。但在实际项目中还需要考虑更多工程化的问题。7.1 包的结构与管理一个规范的ROS包其目录结构可能如下my_first_robot/ ├── CMakeLists.txt ├── package.xml ├── scripts/ # Python可执行脚本 │ ├── virtual_temp_sensor.py │ └── temperature_monitor.py ├── src/ # C源代码本例未使用 ├── msg/ # 自定义消息定义 │ └── Temperature.msg ├── srv/ # 自定义服务定义 │ └── SetThreshold.srv ├── launch/ # 启动文件.launch ├── config/ # 配置文件.yaml └── README.md # 项目说明文档launch文件 当你的系统有多个需要同时启动的节点时手动在每个终端运行rosrun非常低效。ROS Launch文件.launch允许你用一个命令启动一组节点并可以设置参数、重映射话题名等。这是管理复杂ROS系统的标准方式。config文件 将参数存储在YAML配置文件中通过launch文件加载比在代码中硬编码或通过命令行设置更清晰、更易维护。7.2 日志与调试技巧合理使用日志级别rospy.logdebug()信息只在日志级别为DEBUG时输出适合输出详细的内部状态rospy.loginfo()用于常规信息rospy.logwarn()和rospy.logerr()用于警告和错误。可以通过rospy.set_param(/rosout/logger_level, DEBUG)或在启动节点时使用ROS_LOGLEVELdebug rosrun ...来调整日志级别。使用rqt_console 这是一个强大的日志查看和管理工具可以收集、过滤、高亮显示所有节点的日志消息比在终端里看滚动日志方便得多。rosrun rqt_console rqt_console7.3 性能与可靠性考量队列大小queue_size Publisher的queue_size需要根据数据频率和消费速度谨慎设置。太小会导致消息在繁忙时被丢弃太大会占用大量内存并在网络延迟时导致数据“过时”。回调函数的执行时间 订阅者的回调函数应该尽快执行完毕。如果回调函数耗时很长会阻塞其他回调函数甚至整个节点的消息处理。对于耗时操作应考虑使用线程或异步处理。时间处理 尽量使用rospy.Time和rospy.Duration而不是Python的time模块以保证与ROS仿真时间同步。7.4 从ROS 1到ROS 2的思维转变如果你未来要转向ROS 2需要提前了解一些关键区别中间件 ROS 1基于自定义的TCPROS/UDPROS而ROS 2基于DDS数据分发服务这是一个工业级的通信标准提供了更好的实时性、可靠性和网络发现机制。命令行工具rosrun-ros2 run,rostopic-ros2 topic,rosservice-ros2 service。构建系统catkin_make-colcon build。colcon更现代支持并行编译和更好的包隔离。编程接口 Python接口从rospy变为rclpyAPI有较大变化但核心概念节点、话题、服务、动作一脉相承。启动系统 Launch文件格式完全不同ROS 2使用基于Python的XML格式.launch.py功能更强大。我个人的体会是先扎实掌握ROS 1的核心概念和编程模式再学习ROS 2会顺畅很多。很多底层思想是相通的只是工具和API换了。你可以把本篇教程中的项目用ROS 2的API重写一遍这将是一个极好的进阶练习。