ROS / ROS2 是什么?做 ESP32 小机器人要不要学
- 搞懂 ROS 是"机器人中间件",而不是装在板子上的操作系统
- 用人话掌握节点、话题、消息、服务、tf、包六个核心概念
- 能判断自己手上的项目到底要不要上 ROS,避免为学而学
- 知道 ESP32 通过 micro-ROS 接入的路子在哪
你写过的第一个机器人程序,大概是一个 loop():读超声波、判断距离、转电机,一气呵成。简单,痛快。
然后你给它加了个激光雷达,加了个 IMU,加了个想跑路径规划的念头,还想顺手接个摄像头做识别。某天打开主程序,你发现一个文件里塞了七八百行:雷达解析、电机控制、状态机、串口收发、一堆全局变量互相牵扯。改一个避障参数,担心碰坏电机时序;想单独测一下雷达数据对不对,却得把整套跑起来才能看。代码乱成一团毛线,这就是该认识 ROS 的时刻了。
这篇假设你已经会用 ESP32 跑过电机和传感器,懂一点 MQTT 那种"发布订阅"的通信模型——后面会发现,ROS 的核心思路和它是亲戚。
ROS 到底是什么:一个被名字坑了的"中间件"
先把最大的误会拆掉:ROS 不是操作系统。
它的全称是 Robot Operating System,但这个名字纯属历史遗留的浪漫主义。你不会把 ROS"装到"ESP32 上替代 Arduino,也不会拿它替代 Linux。ROS 跑在一台已经装好 Linux(通常是 Ubuntu)的电脑上——可能是树莓派、Jetson,或者你的开发笔记本。
那它是什么?ROS 是机器人中间件。说人话:它是一套规矩 + 一套工具,让你机器人里那一堆互相不认识的程序模块,能用统一的方式互相通信、各管各的。
回到上面那团毛线。ROS 的核心主张就一句话:把那个七八百行的大循环,拆成一堆各自独立运行的小程序,让它们通过消息互相喊话,而不是共享一堆全局变量。
- 雷达驱动是一个独立程序,只负责把雷达数据广播出去。
- 避障逻辑是另一个独立程序,只负责听雷达、算出该怎么转,广播速度指令。
- 电机控制又是一个独立程序,只负责听速度指令、驱动轮子。
这三个程序谁也不调用谁,谁也不知道对方的内部代码长什么样。它们只认"消息"。这就是解耦。
六个核心概念,用人话讲透
ROS 的术语听着唬人,本质就六个,理解了这六个,文档你就能自己读了。
节点(Node):一个独立运行的小程序,就是上面说的"雷达驱动""避障逻辑"。一个机器人通常由几个到几十个节点组成。把节点想成"一个只干一件事的进程",八九不离十。
话题(Topic)+ 发布订阅:节点之间最主要的通信方式。这和 MQTT 一模一样——有节点往一个"话题"上**发布(publish)消息,有节点订阅(subscribe)**这个话题来收。比如雷达节点往 /scan 话题发布数据,避障节点订阅 /scan 收数据。发布方根本不知道谁在听,听的人可以有零个、一个、十个。这种"一对多、互不认识"的解耦,正是 ROS 的精髓。
消息(Message):话题上传的数据,有固定的结构(类似你定义的 struct)。比如激光雷达数据是 sensor_msgs/LaserScan 类型,里面规定好了角度范围、每个角度的距离值这些字段。速度指令是 geometry_msgs/Twist,里面有线速度和角速度。ROS 预定义了一大堆标准消息类型,大家都用标准的,生态才能互通。
服务(Service):话题是"广播 + 不要回执",适合源源不断的数据流(雷达每秒发几十帧)。服务是"打电话"——发一个请求,等一个回复,一来一回。适合"调一次就好"的动作,比如"把地图存一下""重置里程计"。数据流用话题,一次性指令用服务,这个分界记住就行。
tf(坐标变换):机器人身上传感器位置各不相同——雷达在车头,摄像头在车顶,轮子在底盘。同一个障碍物,雷达坐标系里和底盘坐标系里的坐标是不一样的。tf 这套系统专门管"各个坐标系之间怎么换算",让你能随时问"这个点在底盘坐标系里是哪"。做导航绕不开它,现在不懂细节没关系,知道它管坐标这件事就够。
包(Package):代码的组织单位。一个包就是一个文件夹,装着相关的几个节点、消息定义、配置。别人写好的功能(比如某款雷达的驱动、某个导航算法)都是以包的形式发布的,你 apt install 或者下载下来就能用。
一个最小避障的样子(示意)
讲一万句不如看一眼结构。下面是"雷达节点 + 避障节点"最精简的示意,重点看通信结构,不是让你照抄能跑:
# ===== 节点 A:雷达驱动(示意)=====
# 真实场景里这是雷达厂商写好的包,你直接用,不用自己写
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import LaserScan
class LidarNode(Node):
def __init__(self):
super().__init__('lidar_node')
# 往 /scan 话题发布雷达数据
self.pub = self.create_publisher(LaserScan, '/scan', 10)
self.create_timer(0.1, self.tick) # 每 0.1 秒发一帧
def tick(self):
msg = LaserScan()
# ... 这里填充从硬件读到的真实距离数据 ...
self.pub.publish(msg)
# ===== 节点 B:避障逻辑(示意)=====
from geometry_msgs.msg import Twist
class AvoidNode(Node):
def __init__(self):
super().__init__('avoid_node')
# 订阅 /scan 收雷达数据
self.sub = self.create_subscription(LaserScan, '/scan', self.on_scan, 10)
# 往 /cmd_vel 发布速度指令
self.cmd = self.create_publisher(Twist, '/cmd_vel', 10)
def on_scan(self, msg):
front = min(msg.ranges) # 最近的障碍物距离(示意)
twist = Twist()
if front < 0.4: # 太近了
twist.angular.z = 0.5 # 原地转向避开
else:
twist.linear.x = 0.2 # 没障碍,往前走
self.cmd.publish(twist) # 发出去,电机节点会收
看清楚这个链条没有:雷达节点 → /scan 话题 → 避障节点 → /cmd_vel 话题 → 电机节点。三方各写各的,靠两个话题串起来。你想单独测避障逻辑?往 /scan 灌一段假数据就行,根本不用接真雷达。你想换一款雷达?只要新驱动也往 /scan 发标准格式,避障节点一行都不用改。这就是中间件给你买到的东西。
ROS1 还是 ROS2:新学的别犹豫
你搜资料一定会撞见 ROS1 和 ROS2 两套,先说结论:2026 年从零开始学,直接上 ROS2,别碰 ROS1。
区别讲清楚:
- ROS1 有个中心节点叫
roscore,所有通信都得先到它那登记。这个中心一挂全盘崩,而且天生不适合多机器人、对实时性也不友好。ROS1 最后一个版本 Noetic 已经停止维护了。 - ROS2 底层换成了 DDS(一套工业级的分布式通信标准),去掉了中心节点,节点之间能直接发现彼此。这让它天然适合多机协同、对实时和可靠性更友好,也更适合上真产品。
新学的选 ROS2 Humble(长期支持版,跑在 Ubuntu 22.04 上),资料最全、坑最少。网上很多老教程是 ROS1 的,概念相通但命令和 API 有差异,照着 ROS1 教程在 ROS2 上敲会处处报错,认准版本号能省你大半天。
为什么做复杂机器人绕不开它:生态
如果 ROS 只是个发布订阅框架,那它没什么稀奇,自己拿 MQTT 也能搭。ROS 真正的护城河是生态——一堆现成的、能直接用的重型轮子:
- Nav2(导航栈):给它一张地图和目标点,它帮你算路径、绕开障碍、控制底盘开过去。这套东西自己从头写是几个月的活。
- SLAM:边走边建图 + 定位(机器人怎么知道自己在哪、地图长啥样)。有现成的包,喂雷达数据进去就出地图。
- Rviz(可视化):一个 3D 窗口,雷达点云、机器人模型、规划路径、坐标系,全都能实时画出来看。调试机器人没有它基本等于盲人摸象。
- Gazebo(仿真):在电脑里建一个带物理引擎的虚拟世界,机器人没造出来就能先跑算法。撞墙了不心疼,省钱省时间。
这些东西全都按 ROS 的话题/消息标准来通信。你只要把自己的传感器数据按标准格式发出去,就能白嫖整套生态。这才是大家忍着学习曲线也要用 ROS 的真正原因——不是 ROS 多优雅,是它身后那片现成的森林。
你应该理解了什么
- ROS 不是操作系统,是机器人中间件:跑在 Linux 上,让一堆程序模块解耦通信。
- 核心就是把大循环拆成节点,节点之间靠话题(发布订阅)+ 消息通信,思路和 MQTT 同源。
- 数据流用话题,一次性指令用服务,坐标换算交给 tf,代码以包为单位组织。
- 新学直接 ROS2 Humble,别碰已停维护的 ROS1。
- 它真正值钱的是 Nav2 / SLAM / Rviz / Gazebo 这片生态,做复杂机器人因此绕不开。
常见误区
| 误区 | 真相 |
|---|---|
| ROS 是操作系统,要装到板子上 | 它是中间件,跑在已装好 Linux 的电脑上,不替代任何系统 |
| 装好 ROS 机器人就能动了 | 装的只是框架,节点逻辑、传感器接入、参数调试都得你自己干 |
| 学 ROS1 还是 ROS2 都行 | 新学只学 ROS2 Humble,ROS1 已停维护,老教程命令会处处报错 |
| ESP32 能直接装 ROS | 不能。ESP32 算力跑不动完整 ROS,得用 micro-ROS 这个精简版接入 |
| ROS 很简单几天就会 | 学习曲线确实陡,光环境和概念就劝退一批。但项目逼到位了,学起来才不痛苦 |
延伸一下
ESP32 怎么接进 ROS 世界? 答案是 micro-ROS——专门给单片机设计的 ROS2 精简版。你的 ESP32 不跑完整 ROS,而是跑一个 micro-ROS 客户端,把传感器数据当成一个 ROS2 节点发出去,电脑那头的完整 ROS2 系统就能直接收。这等于让你的小板子无缝插进整套生态。这块我们后面单开一篇细讲。
Nav2 + SLAM 是导航的终极形态。 等你真做到"扫地机器人那种自己建图、自己规划路线、自己绕开沙发腿"的程度,就是这两套东西在背后干活。它们也正是 ROS 生态里最值钱、最难自己复刻的部分。
动手挑战
不写代码,做一次拆解练习。拿出你现在手上最复杂的那个机器人项目(或者你脑子里想做的那个),把它按节点拆一遍:
- 列出它里面所有"在干活的模块"——读雷达?控电机?跑状态机?连 WiFi 收指令?做识别?
- 给每个模块画成一个节点,想想它该听什么话题、该发什么话题。
- 数数你拆出来几个节点。如果只有两三个、彼此关系也清楚,那你现在不需要 ROS,老老实实写循环更省事。如果拆出来七八个、还互相缠着说不清谁调谁,恭喜,你的项目已经长到该上 ROS 的体量了。
这个练习本身就是答案:要不要学 ROS,不取决于它多火,取决于你的代码乱到什么程度。
小结·下一步
ROS 是机器人中间件,靠"节点 + 话题发布订阅 + 标准消息"把一堆程序解耦,新学直接 ROS2 Humble,真正的价值在 Nav2/SLAM/Rviz/Gazebo 这片现成生态。要不要学?别为学而学。 做 ESP32 点灯小车、两三个模块的循迹车,纯属杀鸡用牛刀,老实写循环。等你做的项目模块多到手忙脚乱、自己都理不清谁调谁的时候,你会自然而然地需要它——那时候学,每个概念都对应着你正被折磨的真实痛点,学得又快又扎实。
机器人有了能听会动的"身体"和能跑导航的"框架"之后,下一个问题就是给它装个会思考的"脑子"——这正是当下最热的方向。下一篇我们聊聊把大模型接进机器人的具身智能(Embodied AI)到底是怎么回事。