本文面向有嵌入式 C/RTOS 背景、首次接触 ROS2 的工程师,系统讲解 ROS2 的版本、架构、源码获取与构建、开发模型。
写作时已核实版本信息 :截至 2026-08,最新 LTS 为 Lyrical Luth(2026-05 发布)。
一、ROS2 是什么
ROS2(Robot Operating System 2) 不是操作系统,而是一套构建机器人应用的中间件 + 工具链 + 生态:
- 中间件层:基于 DDS(Data Distribution Service)或 Zenoh 的发布/订阅消息总线,提供跨进程、跨机器的节点通信
- 工具链:构建系统(colcon/ament)、包管理(rosdep)、可视化(rviz2)、录制(ros2 bag)、launch 编排
- 生态:数千个功能包(导航 Nav2、感知、运动规划、SLAM、驱动...)
与 ROS1 的核心区别:
| 维度 | ROS1 | ROS2 |
|---|---|---|
| 中间件 | 自研 TCPROS/UDPROS,中心化 master | DDS/Zenoh,去中心化,无 master |
| 实时性 | 无保证 | 支持 RTOS、实时调度、QoS 策略 |
| 多机 | 需配置 | 天然支持(DDS 发现) |
| 安全 | 无 | 支持 DDS Security(SLS/TLS) |
| 平台 | Linux 为主 | Linux/Windows/macOS/嵌入式 |
| 生命周期 | 无 | 受控生命周期节点 |
对嵌入式背景的你要点:ROS2 节点跑在 Linux/POSIX 上(不是 MCU),用 C++(rclcpp)或 Python(rclpy)。MCU 上跑的是 micro-ROS(ROS2 的精简分支,通过 DDS-XRCE 桥接)。GNSS 驱动这类"跑在主机/树莓派/工控机上、读串口、发消息"的场景,正是 ROS2 的典型用法。
📖 动手实操:ROS2 本质、colcon 编译、从零开发一个包、工具链使用见 \[ROS2实操指南-是什么怎么编译开发使用]。
二、版本全景(已核实至 2026-08)
ROS2 版本按字母顺序命名(考古字母表),每年 5 月发布一个新版,LTS 版本支持 5 年。
2.1 活跃版本
| 版本 | 代号 | 发布 | 类型 | EOL | 主要平台 |
|---|---|---|---|---|---|
| Lyrical | Lyrical Luth(lyrical) |
2026-05 | LTS | 2031-05 | Ubuntu 26.04 / RHEL 10 / Windows |
| Kilted | Kilted Kaiju(kilted) |
2025-05 | 普通 | 2026-11 | Ubuntu 24.04 / RHEL 9 / Windows |
| Jazzy | Jazzy Jalisco(jazzy) |
2024-05 | LTS | 2029-05 | Ubuntu 24.04 / RHEL 9 / Windows |
| Humble | Humble Hawksbill(humble) |
2022-05 | LTS | 2027-05 | Ubuntu 22.04 / RHEL 8 / Windows |
| Rolling | Rolling Ridley(rolling) |
滚动 | 开发分支 | --- | 永远最新(不稳定) |
2.2 已 EOL 版本
| 版本 | 代号 | 发布 | 类型 | EOL | 平台 |
|---|---|---|---|---|---|
| Foxy | Foxy Fitzroy(foxy) |
2020-06 | LTS | 2023-06(已 EOL) | Ubuntu 20.04 |
| Iron | Iron Irwini(iron) |
2023-05 | 普通 | 2024-11 | Ubuntu 22.04 |
| Galactic | Galactic Geochelone | 2021-05 | 普通 | 2022-12 | Ubuntu 20.04 |
| 更早 | Eloquent/Dashing/Crystal/Bouncy/Ardent | 2017-2019 | --- | 已 EOL | --- |
⚠️ 关于 Foxy :Foxy 已于 2023-06 停止官方维护,不再收到安全/bug 修复 ,Ubuntu 20.04 也已于 2025-04 EOL。除非客户目标机是已有 Ubuntu 20.04 旧系统、无法升级 且不关心长期维护,否则不建议新项目选 Foxy。若被迫用 Foxy,需在方案中明确标注 EOL 风险,并争取迁移到 Humble+。
2.3 开发中
- Makoa Mata-mata (
makoa):计划 2027-05 发布,当前在 Rolling 上开发
2.4 选版建议
现状 :方案待定,版本候选包括 Foxy / Humble / Jazzy / Lyrical。下面给出各候选的取舍,供调研评估。
| 候选 | Ubuntu | 维护至 | 评估意见 |
|---|---|---|---|
| Foxy | 20.04 | ❌ 已 EOL(2023-06) | 不推荐新选。仅当客户旧机无法升级时考虑,须标注 EOL 风险 |
| Humble | 22.04 | 2027-05 | 短期可接受,生态最成熟;但 Ubuntu 22.04 已 EOL(2025-04),剩约 1 年支持,有过渡压力 |
| Jazzy(LTS) | 24.04 | 2029-05 | 推荐。长期支持,生态齐全,UM982 社区驱动已验证可跑 |
| Lyrical(LTS) | 26.04 | 2031-05 | 最新 LTS,长期最优;但要求 Ubuntu 26.04,需确认目标机能装 |
关键约束 :ROS2 版本与 Ubuntu 版本强绑定(Foxy→20.04,Humble→22.04,Jazzy→24.04,Lyrical→26.04)。调研第一步:摸清客户/目标机的 Ubuntu 版本------这直接决定 ROS2 distro 可选范围。GNSS 驱动作为功能包发布时,也要注明支持哪个 distro。
三、整体架构
text
┌───────────────────────────────────────────────────────────┐
│ 应用层:你的节点(GNSS 驱动节点、导航、感知...) │
├───────────────────────────────────────────────────────────┤
│ 客户端库: rclcpp(C++) rclpy(Python) rclrs(Rust) │
├───────────────────────────────────────────────────────────┤
│ rcl(Ros Client Library,C 接口,与语言无关的核心逻辑) │
├───────────────────────────────────────────────────────────┤
│ rmw(RMW,中间件抽象接口 ------ 切换 DDS 实现的统一抽象) │
├───────────────────────────────────────────────────────────┤
│ DDS 实现: Fast DDS / Cyclone DDS / Zenoh / Connext │
│ (rmw_fastrtps / rmw_cyclonedds / rmw_zenoh ...) │
├───────────────────────────────────────────────────────────┤
│ OS: Linux / Windows / macOS │
└───────────────────────────────────────────────────────────┘
3.1 分层职责
- DDS / Zenoh(底层通信):负责序列化、传输、服务发现、QoS。ROS2 不自己造轮子,直接用工业级 DDS。
- rmw(RMW Interface):中间件抽象层。屏蔽不同 DDS 实现差异,代码可跨 DDS 移植。切换 DDS 只需改环境变量,无需重编译(大部分情况)。
- rcl:C 语言写的核心库,封装 rmw,提供节点、话题、服务、执行器等原语。所有语言客户端都基于 rcl。
- rclcpp / rclpy:面向 C++/Python 的客户端库,你日常用它们写节点。
3.2 三种 RMW 实现
| RMW | 实现 | 特点 |
|---|---|---|
rmw_fastrtps_cpp |
eProsima Fast DDS | 历史默认,功能全,配置项多 |
rmw_cyclonedds_cpp |
Eclipse Cyclone DDS | 性能稳定,配置简单,社区活跃 |
rmw_zenoh |
Eclipse Zenoh | 轻量、低开销、跨网络友好,新版重点方向 |
切换方式(无需重编译):
bash
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp # 或 rmw_fastrtps_cpp / rmw_zenoh
对嵌入式背景:rmw 抽象相当于 HAL 层------你换 DDS 实现就像换底层驱动,上层 rclcpp 代码不动。GNSS 驱动开发通常用默认 DDS 即可,默认配置足够。
四、核心概念
4.1 节点(Node)
节点是 ROS2 的基本执行单元,一个进程可含多个节点。每个节点:
- 有名字和命名空间(
/gnss_driver) - 可发布/订阅话题、提供/调用服务、提供动作
- 可有参数(运行时可改的配置)
cpp
#include "rclcpp/rclcpp.hpp"
class GnssNode : public rclcpp::Node {
public:
GnssNode() : Node("gnss_driver") {
// 声明参数、创建发布者、定时器...
}
};
4.2 三种通信原语
| 原语 | 模式 | 典型用途 | GNSS 场景 |
|---|---|---|---|
| Topic(话题) | 发布/订阅,异步,多对多 | 持续数据流 | 发布位置/原始观测量(高频) |
| Service(服务) | 请求/响应,同步,一对一 | 触发式查询/命令 | 查询固件版本、触发冷启动 |
| Action(动作) | 请求/响应 + 反馈 + 可取消,长时间任务 | 导航到点、机械臂运动 | GNSS 较少用,可选:RTK 基站对齐 |
4.3 消息(Message)接口
消息用 .msg 文件定义,跨语言。ROS2 内置丰富消息类型,位于 sensor_msgs、std_msgs、geometry_msgs 等包:
text
# sensor_msgs/msg/NavSatFix ------ 位置信息标准消息
std_msgs/Header header
uint8 status # 状态(无定位/单点/RTK...)
float64 latitude # 纬度
float64 longitude # 经度
float64 altitude # 高度
| 客户需求 | 对应 ROS2 标准消息 | 所在包 |
|---|---|---|
| 位置信息 | sensor_msgs/msg/NavSatFix |
sensor_msgs |
| 定向信息(航向) | geometry_msgs/msg/Quaternion(姿态)或自定义 |
geometry_msgs |
| 原始观测量 | 无标准 ,通常自定义 .msg(RINEX/RTCM 片段) |
自定义 |
| debug 信息 | std_msgs/msg/String(文本)或自定义结构 |
std_msgs |
| 速度 | geometry_msgs/msg/TwistStamped |
geometry_msgs |
| 卫星状态 | sensor_msgs/msg/NavSatStatus |
sensor_msgs |
重要 :能用标准消息就别自定义,这样你的 GNSS 驱动能直接被 Nav2、robot_localization 等下游消费。位置信息务必用
NavSatFix,这是 ROS2 生态约定。
4.4 QoS(服务质量)
ROS2 的 QoS 是相比 ROS1 的重大升级,决定消息传递的可靠性、历史、 deadline:
| QoS 策略 | 选项 | GNSS 建议值 |
|---|---|---|
| Reliability | RELIABLE / BEST_EFFORT | 位置:RELIABLE;原始观测量高频可用 BEST_EFFORT |
| History | KEEP_LAST(N) / KEEP_ALL | KEEP_LAST(1~10),丢旧保新 |
| Durability | VOLATILE / TRANSIENT_LOCAL | 一般 VOLATILE;配置参数用 TRANSIENT_LOCAL |
| Deadline | 时间 | 按定位频率(如 100ms for 10Hz) |
对传感器数据,BEST_EFFORT + KEEP_LAST(1) 很常见------丢几帧无所谓,要最新值。这与 ROS1 默认 RELIABLE 不同,是 ROS2 新手常踩坑点(订阅者 QoS 与发布者不匹配会收不到数据)。
📖 深入:QoS 的七大策略、匹配规则、事件回调、GNSS 选型见 \[ROS2-QoS详解]。
4.5 参数(Parameter)
节点运行时可配置的变量,类型化(int/double/string/bool/array)。可从 launch 文件、YAML、命令行 ros2 param set 设置。
cpp
// 声明参数(带默认值)
this->declare_parameter<std::string>("serial_port", "/dev/ttyUSB0");
this->declare_parameter<int>("baudrate", 115200);
std::string port = this->get_parameter("serial_port").as_string();
4.6 生命周期节点(Lifecycle Node)
受控启动的节点,有明确状态机:
text
unconfigured → inactive → active → inactive → finalized
↑________↓
(configure/activate/deactivate/cleanup)
- 适合需要有序启停的硬件驱动:配置阶段打开串口,activate 开始发数据,deactivate 停止,cleanup 关串口
4.7 执行器(Executor)
执行器把回调(订阅、定时器、服务)分发到线程。ROS2 提供:
- SingleThreadedExecutor:单线程,简单
- MultiThreadedExecutor:多线程,回调可并发(注意线程安全)
- StaticSingleThreadedExecutor:实体固定时更高效
cpp
rclcpp::executors::MultiThreadedExecutor exec;
exec.add_node(node);
exec.spin();
4.8 TF 坐标变换
tf2 维护一棵坐标系树,广播坐标变换(如 base_link → gps),下游用它把 GPS 位置转到车体坐标。
- GNSS 驱动通常需广播一个静态 TF:
gps_link(天线位置)相对base_link(车体原点) - 用
tf2_ros::StaticTransformBroadcaster
4.9 Launch 系统
用 Python/XML/YAML 描述多节点启动、参数加载、命名空间、重映射。一个 GNSS + robot_localization 的 launch 例子:
python
# launch/gnss_bringup.launch.py
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_gnss_driver',
executable='gnss_node',
name='gnss_driver',
parameters=[{
'serial_port': '/dev/ttyUSB0',
'baudrate': 460800,
'frame_id': 'gps_link',
'publish_rate': 10.0,
}],
remappings=[('fix', '/gnss/fix')],
),
])
五、源码获取与构建
5.1 方式一:apt 二进制安装(推荐入门)
最快上手,无需编译 ROS2 本体。
bash
# 1. 添加 ROS2 apt 源(Lyrical / Ubuntu 26.04)
sudo apt update && sudo apt install software-properties-common curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
-o /usr/share/keyrings/ros-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] \
http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" \
| sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
# 2. 安装桌面完整版(含 rviz2、demo)
sudo apt update
sudo apt install ros-lyrical-desktop
# 3. Jazzy 用户把上面的 lyrical 换成 jazzy、desktop 同理
# 4. source 环境(写入 ~/.bashrc)
source /opt/ros/lyrical/setup.bash
Jazzy:
ros-jazzy-desktop,Ubuntu 24.04。Humble:ros-humble-desktop,Ubuntu 22.04。
5.2 方式二:源码编译(定制/贡献/学习)
当你需要改 ROS2 本体、或想学习源码时用此方式。
官方一键脚本(ros2/ros2 仓库):
bash
# 1. 准备目录
mkdir -p ~/ros2_rolling/src
cd ~/ros2_rolling
# 2. 下载 ros2.repos 清单(描述所有子仓库地址)
vcs import --input https://raw.githubusercontent.com/ros2/ros2/rolling/ros2.repos src
# 3. 安装依赖
sudo rosdep init
rosdep update
rosdep install --from-paths src --ignore-src -y --rosdistro rolling
# 4. 编译(colcon)
colcon build --symlink-install
关键仓库:
| 仓库 | 内容 |
|---|---|
ros2/ros2 |
顶层清单仓库,ros2.repos 汇总所有子模块 |
ros2/rclcpp |
C++ 客户端库源码 |
ros2/rcl |
C 核心库源码 |
ros2/rmw |
RMW 接口定义 |
ament/ament_cmake |
构建系统 |
ros2/demos |
示例节点 |
ros2/sensor_msgs 等 |
标准消息定义 |
vcs(vcstool)是 ROS2 用来管理多仓库的工具,类似 git submodule 但更灵活。ros2.repos是个 YAML,列出每个子仓库的 url 和 version。
5.3 方式三:rosdep 包依赖管理
bash
# 安装功能包的所有依赖(读 package.xml)
rosdep install --from-paths src --ignore-src -y --rosdistro lyrical
5.4 colcon 构建系统
colcon 是 ROS2 的构建工具(替代 ROS1 的 catkin),底层调 CMake/ament。
bash
colcon build # 编译整个工作区
colcon build --packages-select my_gnss_driver # 只编某个包
colcon build --symlink-install # 软链接安装,改 Python/launch 不用重编
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release # Release 模式
source install/setup.bash # source 工作区(在编译后)
工作区结构:
text
~/ros2_ws/
├── src/ ← 你的源码包(功能包)
│ └── my_gnss_driver/
│ ├── package.xml
│ ├── CMakeLists.txt
│ ├── src/
│ ├── include/
│ ├── msg/ ← 自定义消息
│ └── launch/
├── build/ ← 编译中间产物(可删)
├── install/ ← 安装产物(source 它)
└── log/
六、开发模型(C++ 为主)
GNSS 驱动建议用 C++(rclcpp),因为:性能好、串口/二进制解析方便、嵌入式背景熟悉、可与其他 C++ 定位融合包无缝集成。
6.1 一个功能包的最小结构
text
my_gnss_driver/
├── package.xml # 包元数据(依赖、作者、license)
├── CMakeLists.txt # 构建配置
├── src/
│ ├── gnss_node.cpp # 节点 main
│ └── nmea_parser.cpp # 协议解析
├── include/my_gnss_driver/
│ └── nmea_parser.hpp
├── msg/
│ └── RawObservation.msg # 自定义原始观测量消息
└── launch/
└── gnss_bringup.launch.py
6.2 package.xml(关键依赖)
xml
<package format="3">
<name>my_gnss_driver</name>
<version>0.1.0</version>
<description>GNSS 模组 ROS2 驱动</description>
<maintainer email="you@example.com">赵宇涵</maintainer>
<license>Apache-2.0</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>rclcpp</depend>
<depend>sensor_msgs</depend>
<depend>geometry_msgs</depend>
<depend>std_msgs</depend>
<depend>tf2_ros</depend>
<test_depend>ament_lint_auto</test_depend>
<export><build_type>ament_cmake</build_type></export>
</package>
6.3 CMakeLists.txt(关键片段)
cmake
cmake_minimum_required(VERSION 3.8)
project(my_gnss_driver)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(tf2_ros REQUIRED)
find_package(rosidl_default_generators REQUIRED)
# 自定义消息
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/RawObservation.msg"
)
add_executable(gnss_node src/gnss_node.cpp src/nmea_parser.cpp)
ament_target_dependencies(gnss_node
rclcpp sensor_msgs geometry_msgs std_msgs tf2_ros)
install(TARGETS gnss_node DESTINATION lib/${PROJECT_NAME})
install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})
ament_package()
6.4 节点骨架(生命周期节点 + 串口 + 多话题)
cpp
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/lifecycle_node.hpp"
#include "sensor_msgs/msg/nav_sat_fix.hpp"
#include "sensor_msgs/msg/nav_sat_status.hpp"
#include "std_msgs/msg/string.hpp"
#include "my_gnss_driver/msg/raw_observation.hpp"
class GnssDriver : public rclcpp_lifecycle::LifecycleNode {
public:
GnssDriver() : rclcpp_lifecycle::LifecycleNode("gnss_driver") {
declare_parameter<std::string>("serial_port", "/dev/ttyUSB0");
declare_parameter<int>("baudrate", 460800);
declare_parameter<std::string>("frame_id", "gps_link");
}
// 配置回调:打开串口、创建发布者
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_configure(const rclcpp_lifecycle::State &) {
port_ = get_parameter("serial_port").as_string();
// serial_.open(port_, baudrate) ...
fix_pub_ = create_publisher<sensor_msgs::msg::NavSatFix>("/gnss/fix", 10);
obs_pub_ = create_publisher<my_gnss_driver::msg::RawObservation>("/gnss/raw_obs", 10);
debug_pub_ = create_publisher<std_msgs::msg::String>("/gnss/debug", 10);
RCLCPP_INFO(get_logger(), "configured, port=%s", port_.c_str());
return rclcpp_lifecycle::CallbackReturn::SUCCESS;
}
// 激活回调:启动定时读串口
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_activate(const rclcpp_lifecycle::State &) {
timer_ = create_wall_timer(std::chrono::milliseconds(10),
std::bind(&GnssDriver::read_loop, this));
fix_pub_->on_activate(); obs_pub_->on_activate(); debug_pub_->on_activate();
return rclcpp_lifecycle::CallbackReturn::SUCCESS;
}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_deactivate(const rclcpp_lifecycle::State &) {
timer_.reset();
return rclcpp_lifecycle::CallbackReturn::SUCCESS;
}
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
on_cleanup(const rclcpp_lifecycle::State &) {
// serial_.close() ...
fix_pub_.reset(); obs_pub_.reset(); debug_pub_.reset();
return rclcpp_lifecycle::CallbackReturn::SUCCESS;
}
private:
void read_loop() {
// 1. 从串口读一行/一帧
// 2. 解析(NMEA/二进制)
// 3. 按类型发布
sensor_msgs::msg::NavSatFix fix;
fix.header.stamp = now();
fix.header.frame_id = frame_id_;
fix.latitude = lat; fix.longitude = lon; fix.altitude = alt;
fix_pub_->publish(fix);
}
std::string port_, frame_id_;
rclcpp::TimerBase::SharedPtr timer_;
rclcpp_lifecycle::Publisher<sensor_msgs::msg::NavSatFix>::SharedPtr fix_pub_;
rclcpp_lifecycle::Publisher<my_gnss_driver::msg::RawObservation>::SharedPtr obs_pub_;
rclcpp_lifecycle::Publisher<std_msgs::msg::String>::SharedPtr debug_pub_;
};
int main(int argc, char **argv) {
rclcpp::init(argc, argv);
rclcpp::executors::SingleThreadedExecutor exec;
auto node = std::make_shared<GnssDriver>();
exec.add_node(node->get_node_base_interface());
exec.spin();
rclcpp::shutdown();
return 0;
}
七、常用 CLI 命令
bash
# 节点/话题
ros2 node list # 列节点
ros2 topic list # 列话题
ros2 topic echo /gnss/fix # 看消息
ros2 topic hz /gnss/fix # 看频率
ros2 topic info /gnss/fix # 看发布者/订阅者
# 服务/动作
ros2 service list
ros2 service call /gnss/cold_start std_srvs/srv/Trigger
# 参数
ros2 param list /gnss_driver
ros2 param set /gnss_driver baudrate 921600
# 录制回放
ros2 bag record -a # 录全部
ros2 bag record /gnss/fix /gnss/raw_obs
ros2 bag play rosbag2_2026xxx # 回放
# 包
ros2 pkg create --build-type ament_cmake --node-name gnss_node my_gnss_driver
ros2 run my_gnss_driver gnss_node # 运行节点
ros2 launch my_gnss_driver gnss_bringup.launch.py
ros2 bag是调试利器:现场录制 GNSS 原始数据,回实验室反复回放调试解析逻辑,不用反复跑现场。
八、官方资料
| 资料 | 链接 |
|---|---|
| 官方文档(主入口) | https://docs.ros.org/en/rolling/ |
| 教程(Tutorials) | https://docs.ros.org/en/rolling/Tutorials.html |
| Lyrical 版本文档 | https://docs.ros.org/en/lyrical/ |
| ros2/ros2 源码仓库 | https://github.com/ros2/ros2 |
| 包索引(找包) | https://index.ros.org/ |
| Answers(问答) | https://answers.ros.org/ |
| Discourse(讨论) | https://discourse.ros.org/ |
九、常见坑(嵌入式背景易踩)
- QoS 不匹配收不到数据:订阅者与发布者 QoS 不兼容(尤其 Reliability),消息静默丢弃。传感器常用 BEST_EFFORT,调试时先确认双方 QoS。
- 忘了 source 环境 :每开新终端要
source /opt/ros/lyrical/setup.bash和工作区install/setup.bash,否则ros2命令找不到。建议写进~/.bashrc。 - 节点名/话题名/命名空间混淆:launch 里可重映射,别在代码里写死话题名,用参数或 remapping。
- 阻塞回调:串口读写在回调里阻塞会拖死整个执行器(单线程时)。用单独线程读串口 + 无锁队列传递,或用异步 IO。
- 时间戳 :NavSatFix 的
header.stamp要用 GNSS 时间(若可得)或node->now(),别用 0,否则 robot_localization 等下游会拒收。 - frame_id 漏设 :所有消息要带
frame_id(如gps_link),否则 TF 查找失败。 - C++ 版本 :ROS2 Lyrical 用 C++17/20,注意编译标准对齐(
CMAKE_CXX_STANDARD 17)。
十、速记卡
- 最新 LTS:Lyrical Luth(2026-05,Ubuntu 26.04);Jazzy(2024 LTS,Ubuntu 24.04)仍活跃
- 版本与 Ubuntu 强绑定:先定 Ubuntu,再定 ROS2 distro
- 分层:应用 → rclcpp/rclpy → rcl → rmw → DDS/Zenoh → OS
- rmw:切换 DDS 实现的抽象层,改环境变量即可,不动代码
- 三种通信:Topic(流)/ Service(查询)/ Action(长任务)
- QoS:传感器常用 BEST_EFFORT + KEEP_LAST(1),与 ROS1 默认不同
- 生命周期节点:GNSS 驱动推荐,有序管理串口开关
- 构建:colcon + ament_cmake;源码用 vcstool 按 ros2.repos 拉取
- 调试三件套:ros2 bag(录回放)、rviz2(可视化)、plotjuggler(画曲线)
- Foxy 已 EOL(2023-06):除非旧机无法升级,否则新项目排除