树莓派 ROS 2 入门:从 Python 小练习到机器人节点
本文目录
树莓派项目很容易卡在两个极端:只装好系统就收工,或者一开始就把相机、模型、导航和底盘全堆上去。更稳的路线是先让一块板子成为可维护的 Linux 主机,再用两个 ROS 2 节点跑通消息流,最后逐项接入传感器和执行器。
先说明这份学习记录的边界
本系列的本地记录包含 Python 字典、条件分支、循环和函数练习;ROS 2 的节点、Topic、Service、Action、TF2、相机和导航仍是学习路线,并非已经在树莓派上验收的项目。下面的通信示例用于建立概念和练习,不能当作已在真实硬件上运行的日志。真实设备、ROS 发行版和外设组合尚未完成验证。
这次对照了原始练习目录:lesson5.py、lesson6.py 有 Python 答案和批注,lesson7.py 仍只有函数练习题;这些文件没有实现 ROS 节点。学习 README 将新增课程文件指向 work/plugin/ros,而当前这组练习位于 work/other/ros,目录约定尚未统一。继续添加课程前先选定一个权威目录,并同步 README 与索引,避免换机后找错文件。原始目录中的个人纠错记录没有复制到公开文章。
先选对系统与发行版
先记录树莓派具体型号、系统版本和 CPU 架构:
cat /etc/os-release
uname -m
free -h
df -h /
ROS 2 的二进制包与 Ubuntu 版本、架构和 ROS 发行版绑定。截至 2026-10-19,最新 LTS 是 ROS 2 Lyrical Luth,支持到 2031 年 5 月;官方将 Ubuntu 26.04(Resolute)的 ARM64 列为 Tier 1。新建 64 位树莓派环境时,可优先评估 Ubuntu 26.04 + ROS 2 Lyrical,但先按具体板型确认镜像和启动固件。Ubuntu 的型号支持矩阵与 ROS 的平台等级是两张不同的表:前者不代表第三方驱动、摄像头、GPIO 外设或整套机器人项目已经验证。
Ubuntu 26.04 树莓派型号矩阵
下表整理自 Ubuntu 官方 Raspberry Pi 支持表。S 表示 Server,D 表示 Desktop,C 表示 Certified;它描述的是 Ubuntu 镜像/认证范围,不是 ROS 2 的 Tier 等级。
| Raspberry Pi 型号 | 26.04 支持项 |
|---|---|
| 3B、3B+、3A+ | S |
| 4B | S、D、C |
| 400 | S、D |
| 5 | S、D、C |
| 500 | S、D |
| Zero 2W | S |
| CM4 | S、D、C |
| CM5 | S、D |
刷写前还要核对 EEPROM 版本:Pi 4B、400、CM4 至少需要 2022-11-25 的启动 EEPROM;Pi 5、500、CM5 至少需要 2025-02-11。先运行 sudo rpi-eeprom-update 查看状态,不要在不清楚设备型号、启动介质或恢复方案时盲目更新。官方给出的旧版升级路径是先启动 Ubuntu 24.04,再执行 sudo rpi-eeprom-update -a、重启并复查,确认满足要求后再切换到 26.04。
Ubuntu 26.04 Desktop 镜像的官方最低内存要求是 4 GB;不要把旧版 Ubuntu 的 2 GB 门槛套用到 26.04,也不要仅凭板型名称推断某个具体内存规格受支持。先核对 Ubuntu 官方 Raspberry Pi 支持表,再确认所选镜像对应的板型、内存和启动固件。这个最低门槛只说明镜像安装条件,不代表运行 ROS、视觉模型或多个传感器时性能足够;实际项目还要测内存、温度、供电和存储空间。
| Ubuntu | 对应 ROS 2 发行版 | 适用情况 |
|---|---|---|
| 26.04 Resolute | Lyrical Luth | 新建 ARM64 环境的当前 LTS 组合;核心平台为 Tier 1。 |
| 24.04 Noble | Jazzy Jalisco | 已有稳定设备或驱动依赖 Jazzy 时的成熟选择;Jazzy 支持至 2029 年 5 月。 |
| 22.04 Jammy | Humble Hawksbill | 维护既有 Humble 项目时使用;官方支持至 2027 年 5 月。 |
不要把 Lyrical 与旧 Ubuntu 组合想当然地当作官方二进制支持:Lyrical 对 Ubuntu 24.04 标为 Tier 3,需要按官方说明从源码构建。不同发行版的节点也不保证跨发行版互通。刷机前核对树莓派型号、Ubuntu 镜像架构、ROS 发行版、驱动支持和项目现有依赖;不要把旧教程里的发行版命令直接套到新系统。
首次部署优先使用 Raspberry Pi Imager 和可信系统镜像。无显示器安装时,为设备设独立主机名和用户,启用 SSH 公钥,先在可信局域网验证连接;不要把 SSH、数据库或 Docker 管理端口直接映射到公网。保留原始存储卡镜像或可恢复备份,避免把唯一系统盘当实验盘。
如果只是想先学 ROS 2 概念,可以在电脑或虚拟机中跑官方示例,再迁移到树莓派。Docker 有助于固定依赖,但容器默认并不能自动访问 GPIO、摄像头、串口或图形桌面;设备映射、用户组、网络发现和升级策略都要单独设计。原学习 README 中的旧图形容器示例包含 xhost +local:docker,它会修改 X Server 的访问控制列表;不要未经核对就在日常桌面执行。先用无界面示例学习;确实需要 RViz 时,优先在隔离虚拟机中配置图形通道,并在实验结束后确认访问授权已恢复。xhost 手册说明该工具用于增删 X Server 的允许连接项。
用两个终端验证安装
完成官方安装并加载对应发行版环境后,在两个终端分别运行官方 Python 示例:
# 终端 A
source /opt/ros/lyrical/setup.bash # 按实际安装替换为 jazzy 或 humble
ros2 run demo_nodes_py talker
# 终端 B
source /opt/ros/lyrical/setup.bash # 与终端 A 使用同一个发行版
ros2 run demo_nodes_py listener
如果提示找不到 demo_nodes_py,先确认发行版环境已加载,再按当前发行版安装对应的 ros-<发行版>-demo-nodes-py 示例包。
另开终端检查图:
ros2 node list
ros2 topic list
ros2 topic echo /chatter
ros2 topic info /chatter
看到消息只证明这台机器上的基础通信链可用,不代表跨机器发现、Wi-Fi 稳定性或传感器驱动已经正常。多机调试还要逐项核对网络互通、ROS 发行版、ROS_DOMAIN_ID、RMW 实现和 QoS 兼容;先在同一局域网用有线连接缩小变量,再引入无线网络和防火墙规则。
ROS 2 的通信方式怎么选
| 机制 | 适合的问题 | 前端/服务端类比 | 需要留意 |
|---|---|---|---|
| Topic | 连续传感器数据、状态和事件流 | 发布订阅、WebSocket 推送 | 发布者和订阅者解耦;消息频率、队列深度和 QoS 会影响实时性与丢包行为 |
| Service | 快速、有限的一问一答 | HTTP 请求/响应 | 适合查询或短操作,不应拿它承载长时间任务 |
| Action | 可能持续较久、需要反馈或取消的任务 | 带进度和取消的异步任务 | 需要定义目标、反馈、结果及取消语义 |
| Parameter | 运行时可配置的节点参数 | 服务配置 | 参数也需要范围校验、默认值和变更后的安全策略 |
它们不是把 HTTP、WebSocket 换个名字:ROS 2 还需要处理消息类型、发现、QoS、时间戳和机器人坐标系。消息传输成功,也不能自动证明数据单位、坐标方向或采样时钟正确。
Lyrical 为 rclpy 增加了 AsyncNode,可在 ROS 回调中结合 asyncio;这是进阶能力,不是第一条消息的前置条件。先掌握普通 Node、executor、回调和关闭清理,再判断是否需要并发 I/O,避免仅为“用了 async”而增加状态和取消复杂度。
从 Python 练习走向节点
补全本地 lesson7 函数练习
本机 lesson7.py 目前保存的是题目,没有可执行答案。下面是按题意整理的参考解法,不代表原练习文件已被修改。阈值判断要先检查更高的 danger,否则 7.4 会先命中普通 warning;电量示例假定输入已在 0–100 范围内,真实接口还要做范围校验。
def check_sensor_reading(reading: float) -> str:
if reading > 7.0:
return "danger"
if reading > 3.0:
return "warning"
return "safe"
readings = [3.2, 5.1, 2.8, 7.4, 0.5, 6.0]
for reading in readings:
status = check_sensor_reading(reading)
print(f"{reading}: {status}")
def battery_status(battery_level: int, min_level: int = 20) -> bool:
return battery_level >= min_level
print(battery_status(15))
print(battery_status(50))
print(battery_status(15, min_level=10))
to_celsius = lambda fahrenheit: (fahrenheit - 32) * 5 / 9
print(f"{to_celsius(98.6):.1f}")
预期输出:
3.2: warning
5.1: warning
2.8: safe
7.4: danger
0.5: safe
6.0: warning
False
True
True
37.0
lambda 适合这个单表达式换算;一旦需要输入校验、单位对象或复用测试,改成有名字的函数通常更清楚。
先创建一个 Python 包。命令会按所安装的 ROS 发行版选择工具链;若命令缺包,应回到该发行版的官方安装说明检查依赖,而不是随手混装其他发行版的包:
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_python sensor_demo --dependencies rclpy std_msgs
在包的 sensor_demo/ Python 模块中创建 talker.py,并在生成的 setup.py 中注册命令入口:
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class SensorTalker(Node):
def __init__(self):
super().__init__('sensor_talker')
self.publisher = self.create_publisher(String, 'sensor/status', 10)
self.timer = self.create_timer(1.0, self.publish_status)
self.sequence = 0
def publish_status(self):
message = String()
message.data = f'reading-{self.sequence}'
self.publisher.publish(message)
self.get_logger().info(f'published: {message.data}')
self.sequence += 1
def main(args=None):
rclpy.init(args=args)
node = SensorTalker()
try:
rclpy.spin(node)
except KeyboardInterrupt:
pass
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
entry_points={
'console_scripts': [
'talker = sensor_demo.talker:main',
],
},
构建并加载工作区:
cd ~/ros2_ws
colcon build --symlink-install --packages-select sensor_demo
source install/setup.bash
ros2 run sensor_demo talker
这是教学用状态字符串,不是传感器驱动。真正的测量数据应优先使用语义合适的标准消息(例如 sensor_msgs),明确单位、坐标系、采集时间和无效值表达;订阅端还要做范围检查、超时与断连处理。硬件电机指令应有速度/范围限制、急停和失联后的安全行为,不能直接把网络输入映射成无限制执行器输出。
建议的渐进路线
- Python:函数、类、异常、文件读写、类型标注和单元测试;本地练习已有字典、循环与条件判断,函数练习源文件仍是题目,本页附有参考解答但没有回写学习目录。
- ROS 基础:节点生命周期、Topic、标准消息、Service、Action、参数、命名空间和 launch;先用官方模拟示例建立观察和调试习惯。
- 传感器:一次只接一个摄像头、IMU 或距离传感器;先确认驱动、设备权限、消息频率、时间戳和坐标系,再考虑融合。
- 机器人几何:理解 TF2、坐标变换、URDF 与 RViz;先对照已知姿态验证方向和单位,避免错误变换被可视化掩盖。
- 进阶项目:再研究 OpenCV、预训练模型、Nav2 和 SLAM;先在仿真中测资源占用与失败恢复,再接实体底盘。树莓派算力、散热、供电和存储卡写入寿命都可能成为瓶颈。
每一步留一份可复现记录:板型/架构、OS 与 ROS 发行版、依赖版本、接线图、启动命令、Topic 类型与频率、预期输出、错误恢复方法。不要把 Wi-Fi 密码、私钥、设备公网地址或默认账号放进仓库。
本地练习的可复现边界
- README 当前把 lesson5、lesson6 标记为完成;lesson7 文件仍是题目,而不是 ROS 2 节点实现。本文给出的函数答案只是参考,不会回写本机练习文件。
- README 中 Docker 命令固定使用 ROS 2 Humble 桌面镜像,但这只是学习方案记录;没有从该文件推断出本机已构建镜像、启动容器或安装 Humble。
- 真实项目开始前,先补齐一条可复现记录:树莓派型号与架构、Ubuntu/系统镜像、ROS 发行版、依赖安装来源、构建命令、测试输出和传感器型号。没有这些证据时,把内容标为计划或示例,不要写成硬件实测。
从入门走向真实项目
如果你已经跑通发布者和订阅者,下一步可以看这个分阶段案例:从相机到轨迹预测:羽毛球机器人视觉链路的 ROS 2 工程拆解。它重点讨论图像检测、轨迹估计、消息契约和执行器安全,并把本机项目记录中的设备状态限定为历史快照;不会公开网络地址、账号或机器路径,也不把尚未复验的硬件状态写成已完成。
官方参考
- ROS 2 发行版列表与支持周期
- ROS 2 Lyrical 官方平台支持表:Ubuntu 与 ARM64 的支持等级是平台组合信息,不等于任意树莓派型号、GPIO 驱动或外设都已验证。
- ROS 2 Lyrical Ubuntu 二进制安装说明
- ROS 2 Lyrical Python 发布者与订阅者教程
- Ubuntu Raspberry Pi 支持型号、镜像与 EEPROM 要求
- ROS 2 Lyrical 发布说明(含
rclpy.AsyncNode)
本文还参考了作者工作区内的 Python 学习记录;这些练习文件目前不是公开 Git 仓库,因此不提供源码下载链接。
官方文档会随发行版和硬件支持变化。开始安装前再次核对目标板型、Ubuntu 架构、ROS 发行版和驱动支持;本文章节中的示例代码没有在真实树莓派或 ROS 运行环境中执行验证。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。