ROS 2 速查手册(进阶)

4802 字
24 分钟
ROS 2 速查手册(进阶)

配套:ROS 2 Jazzy / Ubuntu 24.04

重点:C++ 工程结构、Composable Node、intra-process communication、QoS 实战、自定义 msg、Launch 阅读、TF2 编程、RViz2/Foxglove、Marker、rosbag 离线调试、ROS 环境变量与 systemd 部署。


1. 这份手册和基础版有什么区别?#

基础版主要解决:

ROS 2 是什么?
怎么创建 Node?
怎么发布 Topic?
怎么订阅 Topic?
怎么编译?
怎么 launch?
怎么查 TF?

这一份进一步解决:

为什么视觉项目要用 Composable Node?
为什么图像传来传去会很慢?
intra-process 到底是什么?
怎么自己定义 msg?
怎么看懂一个陌生的 launch?
怎么在代码里真正使用 TF2?
怎么把算法结果画到 RViz2?
Foxglove 和 RViz2 怎么选?
怎么用 rosbag 做离线算法开发?
机器人开机后如何自动启动 ROS?

2. ROS 2 C++ 工程结构#

一个比较正规的 C++ ROS 2 Package 通常长这样:

my_package/
├── CMakeLists.txt
├── package.xml
├── include/
│ └── my_package/
│ └── detector.hpp
├── src/
│ ├── detector.cpp
│ └── detector_node.cpp
├── config/
│ └── detector.yaml
├── launch/
│ └── detector.launch.py
└── rviz/
└── detector.rviz

可以把它理解成:

package.xml
“我是谁?依赖谁?”
CMakeLists.txt
“我要怎么编译?”
include/
“头文件”
src/
“真正代码”
config/
“参数”
launch/
“怎么启动整个系统”
rviz/
“怎么可视化”

3. package.xmlCMakeLists.txt 的区别#

package.xml#

它更像:

项目的身份证 + 依赖清单

<package format="3">
<name>my_detector</name>
<version>0.0.1</version>
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>rclcpp</depend>
<depend>sensor_msgs</depend>
<depend>geometry_msgs</depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>

CMakeLists.txt#

它更像:

告诉编译器“代码怎么变成程序”

cmake_minimum_required(VERSION 3.8)
project(my_detector)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(geometry_msgs REQUIRED)
add_executable(detector_node
src/detector_node.cpp
)
ament_target_dependencies(
detector_node
rclcpp
sensor_msgs
geometry_msgs
)
install(
TARGETS detector_node
DESTINATION lib/${PROJECT_NAME}
)
install(
DIRECTORY config launch
DESTINATION share/${PROJECT_NAME}
)
ament_package()

记忆:

package.xml
= “我需要谁”
CMakeLists.txt
= “我怎么用这些东西编译”

4. ROS 2 依赖为什么经常报错?#

例如代码:

##include <sensor_msgs/msg/image.hpp>

但编译报:

fatal error:
sensor_msgs/msg/image.hpp: No such file or directory

检查两层。

第一层:package.xml#

<depend>sensor_msgs</depend>

第二层:CMakeLists.txt#

find_package(sensor_msgs REQUIRED)

并且:

ament_target_dependencies(
detector_node
rclcpp
sensor_msgs
)

所以:

package.xml
声明依赖
CMakeLists.txt
找到依赖 + 链接依赖

普通:

Terminal window
colcon build

开发时推荐:

Terminal window
colcon build --symlink-install

普通安装可以理解为:

源码
复制
install/

symlink:

源码
软链接
install/

对于 Python、配置文件等开发内容特别方便。


6. CMake Generator 改了为什么要删 build?#

例如:

Terminal window
colcon build --cmake-args -G Ninja

之前可能使用:

Unix Makefiles

CMake 会把 generator 信息缓存到 build/

所以切换:

Makefiles
Ninja

建议:

Terminal window
rm -rf build install log
colcon build

记忆:

CMake 构建系统发生根本变化 → 清理旧缓存。


7. 自定义 Message#

标准消息:

sensor_msgs/Image
geometry_msgs/Pose
geometry_msgs/Point

解决的是通用问题。

视觉项目可能需要:

装甲板:
位置
置信度
类型
四角点
ID

于是定义:

ArmorDetection.msg

例如:

geometry_msgs/Point position
float32 confidence
uint8 armor_type
string text

它相当于:

自己设计一种“数据包格式”。


8. msg 文件语法#

最基本:

类型 名字

例如:

float32 confidence
int32 id
bool valid
string name

数组:

float32[] scores
geometry_msgs/Point[] corners

固定长度数组:

float32[4] values

引用其他消息:

geometry_msgs/Point position
sensor_msgs/Image image

9. 自定义 Message 的构建流程#

假设:

autoaim_interfaces/
└── msg/
└── ArmorDetection.msg

CMake:

find_package(rosidl_default_generators REQUIRED)
find_package(geometry_msgs REQUIRED)
rosidl_generate_interfaces(
${PROJECT_NAME}
"msg/ArmorDetection.msg"
DEPENDENCIES geometry_msgs
)

package.xml 中需要对应的接口生成和运行依赖,例如:

<buildtool_depend>ament_cmake</buildtool_depend>
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<depend>geometry_msgs</depend>
<member_of_group>
rosidl_interface_packages
</member_of_group>

然后:

Terminal window
colcon build --packages-select autoaim_interfaces
source install/setup.bash

查看:

Terminal window
ros2 interface show autoaim_interfaces/msg/ArmorDetection

10. 修改 msg 后为什么必须重新 build?#

例如原来:

Point position
float confidence

后来增加:

uint8 armor_type

如果不重新构建:

代码
仍然使用旧生成接口

所以:

Terminal window
colcon build --packages-select autoaim_interfaces
source install/setup.bash

如果依赖它的包也需要重新构建:

Terminal window
colcon build

经验:

.msg → 先想到重新 build 接口包。


11. QoS:从“知道”进入“会排查”#

QoS 可以理解成:

消息传输规则。

重要概念:

History
Depth
Reliability
Durability

12. History / Depth#

例如:

Depth = 1

可以简单理解为:

只保留最新的一条消息

实时视觉:

Frame 1
Frame 2
Frame 3
Frame 4

如果算法处理很慢,不希望:

处理 Frame 1
→ Frame 2
→ Frame 3
→ Frame 4

最后虽然“每帧都处理了”,但处理的其实都是过去很久的数据。

实时视觉往往更关心:

“现在这一帧是什么?”

而不是:

“历史帧一帧都不能丢。”


13. Reliability#

主要模式:

RELIABLE
BEST_EFFORT

RELIABLE#

“尽量保证你收到”

适合:

重要控制命令
关键状态
不能轻易丢的消息

BEST_EFFORT#

“能及时收到最好,丢一帧没关系”

视觉图像通常更能接受这种思路。

例如:

30 FPS
Frame 100
Frame 101
Frame 102
Frame 103
Frame 104

偶尔:

Frame 102 丢了

通常仍然可以:

103
104
105

继续处理。


14. QoS 不匹配是视觉项目经典问题#

例如:

Camera Publisher
Reliability = BEST_EFFORT

而:

Detector Subscriber
Reliability = RELIABLE

两边 QoS 不兼容时:

Topic 明明存在
Node 也存在
但是收不到消息

遇到:

“Topic 有,节点也有,但 callback 不触发。”

先检查:

Terminal window
ros2 topic info /camera/image_raw --verbose

不要第一时间怀疑 OpenCV。


15. Composable Node:为什么视觉项目特别喜欢它?#

普通 ROS 2:

camera_node
一个进程
detector_node
一个进程
locator_node
一个进程

也就是:

Process A
Process B
Process C
Process D
...

每个进程都有:

自己的内存
自己的运行环境
自己的进程开销

16. 图像为什么尤其怕进程间复制?#

假设:

1280 × 1024 × 3

约:

4 MB / frame

如果:

Camera
Detector
Locator
Tracker

每经过一个进程,可能涉及:

序列化
复制
反序列化
下一进程

如果:

30 FPS

数据复制量很快就非常大。

所以视觉项目会特别关心:

不要无意义地复制图像。


17. Composable Node 是什么?#

普通 Node:

Node
可执行文件
独立进程

Composable Node:

Node
可动态加载的类
Container

多个 Node:

Container Process
┌──────────────────────────┐
│ │
│ CameraNode │
│ DetectorNode │
│ LocatorNode │
│ TrackerNode │
│ │
└──────────────────────────┘

类比:

普通模式:
每个功能 = 一个 App
组件模式:
一个 App = 一个容器
功能 = App 里的插件

18. 普通 Node 和组件 Node 的区别#

普通:

int main(int argc, char** argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(
std::make_shared<CameraNode>()
);
rclcpp::shutdown();
}

组件:

class CameraNode : public rclcpp::Node
{
public:
explicit CameraNode(
const rclcpp::NodeOptions& options)
: Node("camera", options)
{
}
};

然后:

RCLCPP_COMPONENTS_REGISTER_NODE(
CameraNode
)

重点:

组件通常没有自己的 main()


19. CMake 如何注册组件?#

普通:

add_executable(camera_node
src/camera_node.cpp
)

组件:

find_package(rclcpp_components REQUIRED)
add_library(
camera_node_component
SHARED
src/camera_node.cpp
)
ament_target_dependencies(
camera_node_component
rclcpp
rclcpp_components
)
rclcpp_components_register_nodes(
camera_node_component
"autoaim_camera::CameraNode"
)

本质:

.cpp
Shared Library
注册插件
Container 动态加载

20. Container#

常见:

component_container
component_container_mt

区别:

component_container
单线程
component_container_mt
多线程

视觉项目通常更关注:

Terminal window
component_container_mt

21. 为什么多线程 Container 对视觉有帮助?#

假设:

Camera callback
Detector callback
Locator callback

如果单线程:

Detector 推理 20ms
其他 callback
全部排队

可能造成:

Camera
等待
Detector
等待
Locator

多线程:

Thread 1 → Camera
Thread 2 → Detector
Thread 3 → Locator

可以更充分地并行执行。

注意:

多线程不等于自动变快。共享资源仍然需要考虑线程安全、锁和执行器行为。


22. intra-process communication#

仅仅:

多个 Node
同一个进程

并不意味着所有数据都完全不复制。

可以开启:

extra_arguments=[
{
'use_intra_process_comms': True
}
]

核心思想:

普通通信:
Node A
序列化
复制
Node B
intra-process:
Node A
进程内部通信
减少序列化/复制
Node B

对于:

4 MB 图像 × 高频率

尤其有意义。


23. Composable Node + intra-process#

可以记成:

Composable Node
解决“进程太多”
intra-process communication
减少同进程 Node 之间的数据复制

组合起来:

Camera
│ image
Detector
│ detection
Locator
Tracker
全部在同一个 Container

24. Component CLI#

查看组件:

Terminal window
ros2 component list

查看系统支持的组件类型:

Terminal window
ros2 component types

手动加载:

Terminal window
ros2 component load /autoaim_container autoaim_camera autoaim_camera::CameraNode

适合:

启动 Container
不重启整个系统
临时加载某个 Node
测试

25. 如何阅读一个陌生 Launch?#

拿到:

autoaim_launcher.py

推荐顺序:

① 找 Node / ComposableNode
② 看 package
③ 看 executable / plugin
④ 看 name
⑤ 看 parameters
⑥ 看 remappings
⑦ 看 namespace
⑧ 看 container
⑨ 画出 Topic 数据流

最终把代码脑补成:

Camera
├── image_raw ──→ Detector
Detector
└── detections ──→ Locator
Tracker

26. ComposableNode Launch 结构#

典型:

ComposableNode(
package='autoaim_camera',
plugin='autoaim_camera::CameraNode',
name='autoaim_camera',
parameters=[
camera_params_yaml
],
extra_arguments=[
{
'use_intra_process_comms': True
}
],
)

重点看:

package
来自哪个 ROS Package
plugin
加载哪个 C++ 组件类
name
运行时 Node 名字
parameters
加载什么配置
extra_arguments
额外运行选项

27. TF2:进入代码层#

TF2 最核心的四个类:

用途
tf2_ros::Buffer保存 / 查询 TF
tf2_ros::TransformListener接收 TF
tf2_ros::TransformBroadcaster发布动态 TF
tf2_ros::StaticTransformBroadcaster发布静态 TF

常见初始化:

tf_buffer_ =
std::make_shared<tf2_ros::Buffer>(
get_clock()
);
tf_listener_ =
std::make_unique<tf2_ros::TransformListener>(
*tf_buffer_
);

28. lookupTransform#

例如:

auto transform =
tf_buffer_->lookupTransform(
"gimbal_link",
"camera_link",
tf2::TimePointZero
);

最重要的是理解:

lookupTransform(
target_frame,
source_frame,
time
)

也就是:

“我要把 source_frame 中的东西转换到 target_frame。”


29. TimePointZero#

tf2::TimePointZero

可以简单理解成:

使用最近可用的 TF。

视觉程序里经常:

lookupTransform(
"gimbal_link",
"camera_link",
tf2::TimePointZero
);

如果任务严格依赖某一时刻的传感器数据,则应该认真处理时间戳,而不是永远使用最新 TF。


30. 查询前先 canTransform#

直接:

lookupTransform(...)

如果 TF 不存在可能抛异常。

更安全:

if (tf_buffer_->canTransform(
"gimbal_link",
"camera_link",
tf2::TimePointZero))
{
auto t =
tf_buffer_->lookupTransform(
"gimbal_link",
"camera_link",
tf2::TimePointZero
);
}

实际工程还应考虑:

TF 是否刚刚启动
TF 是否暂时还没收到
时间戳是否匹配

31. 直接变换一个 Point#

例如相机检测到了:

camera_link:
x = 1.0
y = 0.0
z = 2.0

建立:

geometry_msgs::msg::PointStamped camera_point;
camera_point.header.frame_id =
"camera_link";
camera_point.point.x = 1.0;
camera_point.point.y = 0.0;
camera_point.point.z = 2.0;

然后:

auto gimbal_point =
tf_buffer_->transform(
camera_point,
"gimbal_link"
);

现在:

camera_point
TF2
gimbal_point

这就是视觉项目中“相机系位置 → 云台系位置”的核心操作。


32. 广播动态 TF#

如果两个坐标系的关系会变化:

云台旋转
camera 相对于 gimbal 的姿态变化

可以:

tf2_ros::TransformBroadcaster broadcaster(this);
geometry_msgs::msg::TransformStamped t;
t.header.stamp = now();
t.header.frame_id =
"gimbal_link";
t.child_frame_id =
"camera_link";
t.transform.translation.x = 0.05;
t.transform.rotation.w = 1.0;
broadcaster.sendTransform(t);

核心关系:

parent
child

33. 广播静态 TF#

例如相机牢牢安装在云台上:

gimbal
│ 固定
camera

命令:

Terminal window
ros2 run tf2_ros static_transform_publisher 0.05 0 0.1 0 0 0 gimbal_link camera_link

可以理解为:

x y z
+
yaw pitch roll
+
parent
+
child

34. TF2 排错#

Unknown frame#

Unknown frame "camera_link"

检查:

Terminal window
ros2 run tf2_ros tf2_echo camera_link gimbal_link

如果都找不到:

frame 名字可能写错
或者
没人发布这个 frame

刚启动就 TF 报错#

可能只是:

Node 启动
TF broadcaster 还没启动完成
查询过早

解决思路:

canTransform
+
重试

TF Tree 断了#

查看:

Terminal window
ros2 run tf2_tools view_frames

寻找断开的 frame:

谁应该发布它?
那个 Node 启动了吗?
静态 TF 发布了吗?

35. RViz2:把抽象数据变成可观察对象#

启动:

Terminal window
rviz2

核心价值:

把 ROS 中的坐标、图像、点云、轨迹、算法结果直接画出来。


36. Fixed Frame#

RViz2:

Global Options
Fixed Frame

例如:

gimbal_link

可以理解成:

“我要站在哪个坐标系里观察整个机器人世界?”

如果 Fixed Frame 错了:

TF
Point
Marker
Robot

可能:

不显示
乱飞
报 TF 错误

37. RViz2 常用 Display#

Display用途
Image查看相机图像
TF查看所有坐标系
Marker查看单个 Marker
MarkerArray查看多个调试对象
PointCloud2查看点云
LaserScan查看激光雷达
RobotModel查看机器人模型
Path查看轨迹
Axes查看坐标轴
Grid查看参考网格

视觉开发最常用:

Image
TF
MarkerArray
PointCloud2

38. Marker:给算法结果“画出来”#

假设算法算出来:

目标位置:
x = 2.0
y = 0.3
z = 0.1

单纯:

std::cout << x << y << z;

很难直观看出:

到底算对没有?

如果画成 Marker:

机器人
│ ● ← 算法认为的目标
└────────────

一眼就知道。


39. Marker 最重要的字段#

visualization_msgs::msg::Marker m;

Frame:

m.header.frame_id =
"gimbal_link";

命名空间:

m.ns = "locator";

ID:

m.id = 0;

类型:

m.type =
visualization_msgs::msg::Marker::SPHERE;

位置:

m.pose.position.x = 1.0;
m.pose.position.y = 0.2;
m.pose.position.z = 0.1;

大小:

m.scale.x = 0.1;
m.scale.y = 0.1;
m.scale.z = 0.1;

40. 常用 Marker 类型#

ARROW
CUBE
SPHERE
CYLINDER
LINE_STRIP
LINE_LIST
TEXT_VIEW_FACING

例如:

SPHERE
画一个目标点
ARROW
画方向
LINE_STRIP
画轨迹
TEXT_VIEW_FACING
显示文字

41. Marker 生命周期#

如果不断 ADD:

Marker 1
Marker 2
Marker 3
Marker 4
...

可能留下大量历史残影。

可以设置:

m.lifetime =
rclcpp::Duration(
0,
100 * 1000000
);

类似:

100 ms 后自动消失

实时视觉中很实用。


42. MarkerArray#

如果一次要画:

20 个目标
100 个轨迹点
多个坐标轴

可以:

visualization_msgs::msg::MarkerArray arr;
arr.markers.push_back(marker);
marker_pub_->publish(arr);

适合批量发布调试信息。


43. 推荐的视觉调试习惯#

不要只画:

算法最终结果

最好同时画:

原始检测
解算结果
滤波结果
预测结果

例如:

检测位置
另一个点
滤波位置
箭头
速度方向
线
预测轨迹

这样可以快速定位:

Detector 错?
Locator 错?
TF 错?
Filter 错?

44. Foxglove:现代化 ROS 可视化#

Foxglove 可以理解成:

一个更现代、更适合数据分析的 ROS 可视化工具。

架构:

ROS 2
│ Topics
foxglove_bridge
│ WebSocket
浏览器 / Foxglove App

所以:

机器人上
bridge
你的电脑
Foxglove

45. Foxglove Bridge#

Ubuntu 24.04 + Jazzy:

Terminal window
sudo apt install -y ros-jazzy-foxglove-bridge

启动:

Terminal window
ros2 launch foxglove_bridge foxglove_bridge_launch.xml port:=8765

常用端口:

8765

46. Foxglove 常用面板#

3D#

看:

TF
Marker
PointCloud
机器人空间数据

Image#

看:

相机
检测图像
视觉处理结果

Raw Messages#

适合:

“这个 msg 到底发了什么?”

直接查看完整字段。

Topic Metrics#

适合查:

频率
延迟
数据流

47. RViz2 vs Foxglove#

RViz2Foxglove
安装ROS 环境常自带独立客户端/网页
3D
TF
Image
Raw Message一般很方便
Topic Metrics基础很方便
布局本地配置更适合保存/分享
远程观察不够方便很方便
适合ROS 本机调试综合数据分析

简单记:

本机快速调 ROS
→ RViz2
远程 / 数据分析 / 布局
→ Foxglove

48. rosbag:机器人开发的“录像机”#

现场测试:

机器人
相机
Detector
真实数据

如果每次改算法都重新跑机器人:

非常慢

所以录制:

Terminal window
ros2 bag record -o bag/test01 /camera/image_raw /camera/camera_info /detections

保存下来。


49. rosbag 回放#

Terminal window
ros2 bag play bag/test01

循环:

Terminal window
ros2 bag play bag/test01 --loop

于是:

真实机器人
一次录制
rosbag
无限回放
你的算法

这意味着:

可以在没有机器人、没有相机的情况下反复调算法。


50. 推荐的视觉开发模式#

第一阶段:

实车
录制 rosbag
保存测试数据

之后:

修改 Detector
rosbag play
测试

再:

修改 Locator
rosbag play
测试

再:

修改 Tracker
rosbag play
测试

最终:

全部通过
上真实机器人

51. ROS_DOMAIN_ID#

如果多台机器人同时运行:

Robot A
Robot B
Robot C

不同机器人可以使用不同 Domain:

Terminal window
export ROS_DOMAIN_ID=10

另一台:

Terminal window
export ROS_DOMAIN_ID=11

理解为:

Domain 10
Robot A
Domain 11
Robot B

达到网络隔离效果。


52. RMW_IMPLEMENTATION#

ROS 2 通过 RMW 层连接底层通信实现。

查看:

Terminal window
echo $RMW_IMPLEMENTATION

例如可能看到:

rmw_fastrtps_cpp

不要为了“优化”就随意切换。

真实机器人系统通常应该:

团队统一
RMW
统一部署

53. 日志环境变量#

例如:

Terminal window
echo $RCUTILS_CONSOLE_OUTPUT_FORMAT

可以控制 ROS 日志输出格式。

部署时可能统一:

时间
节点
日志级别
消息

方便分析机器人运行日志。


54. systemd:让机器人开机自动运行#

开发阶段:

Terminal window
ros2 launch ...

每次手动运行。

真正部署机器人:

机器人上电
Linux 启动
systemd
ROS 2 launch
整套机器人程序自动启动

55. systemd 服务的核心思想#

典型:

[Unit]
Description=AutoAim ROS2
[Service]
User=robot
Group=dialout
EnvironmentFile=/path/to/robot.env
ExecStart=/path/to/start.sh
Restart=always
[Install]
WantedBy=multi-user.target

理解:

User
用谁运行
Group
例如串口权限
EnvironmentFile
读取机器人配置
ExecStart
启动命令
Restart=always
程序崩了自动重启

56. systemd 常用命令#

查看:

Terminal window
systemctl status autoaim.service

启动:

Terminal window
sudo systemctl start autoaim.service

停止:

Terminal window
sudo systemctl stop autoaim.service

开机启动:

Terminal window
sudo systemctl enable autoaim.service

取消:

Terminal window
sudo systemctl disable autoaim.service

查看日志:

Terminal window
journalctl -u autoaim.service

实时:

Terminal window
journalctl -u autoaim.service -f

57. 一个完整的机器人系统#

成熟 ROS 2 视觉系统可以理解为:

systemd
ROS 2 launch
┌─────────┴─────────┐
│ │
Component Container Other Node
┌──────┼─────────┐
│ │ │
Camera Detector Locator
│ │ │
└──────┴─────────┘
TF2
Tracker
Controller
Hardware

同时:

Topics
rosbag
离线回放

以及:

Topics
RViz2 / Foxglove
可视化调试

58. 一张“工程化 ROS 2”心智地图#

ROS 2 项目
├── Workspace
│ ├── src
│ ├── build
│ ├── install
│ └── log
├── Package
│ ├── package.xml
│ ├── CMakeLists.txt
│ ├── src
│ ├── include
│ ├── config
│ └── launch
├── Communication
│ ├── Topic
│ ├── Service
│ └── Action
├── Configuration
│ └── Parameter / YAML
├── Interface
│ ├── msg
│ ├── srv
│ └── action
├── Performance
│ ├── QoS
│ ├── Component
│ ├── Multi-thread
│ └── Intra-process
├── Coordinate
│ └── TF2
├── Visualization
│ ├── RViz2
│ ├── Foxglove
│ └── Marker
├── Data
│ └── rosbag
└── Deployment
├── Environment
├── ROS_DOMAIN_ID
├── RMW
└── systemd

59. 视觉项目排错顺序#

没有图像#

Terminal window
ros2 node list
ros2 topic list
ros2 topic type /camera/image_raw
ros2 topic info /camera/image_raw --verbose
ros2 topic hz /camera/image_raw

顺序:

Node
Topic
Type
Publisher
QoS
Frequency

检测结果没有#

检查:

Camera
image_raw
Detector
detections

分别:

Terminal window
ros2 topic hz /image_raw
ros2 topic hz /detections

如果:

image_raw 正常
detections 没有

重点查:

Detector
QoS
callback
算法

坐标位置不对#

检查:

1. frame_id
2. TF tree
3. parent / child
4. 相机外参
5. 时间戳
6. 坐标轴定义

先:

Terminal window
ros2 run tf2_tools view_frames

再:

Terminal window
ros2 run tf2_ros tf2_echo gimbal_link camera_link

最后用 Marker 在 RViz2 里画出来。


60. 最重要的进阶命令#

Terminal window
## Component
ros2 component list
ros2 component types
## TF
ros2 run tf2_ros tf2_echo base_link camera_link
ros2 run tf2_tools view_frames
ros2 run tf2_ros tf2_monitor
## Visualization
rviz2
rqt_graph
## Bag
ros2 bag record -a
ros2 bag info <bag>
ros2 bag play <bag>
## Parameter
ros2 param list
ros2 param get <node> <param>
ros2 param dump <node>
## QoS
ros2 topic info /topic --verbose
## System
systemctl status <service>
journalctl -u <service> -f

61. 必须真正理解的 8 个关键词#

① Composable Node#

把 Node 变成可加载组件

② Container#

加载多个组件的进程

③ Intra-process#

减少同进程 Node 之间的数据复制

④ QoS#

规定消息怎么传

⑤ Custom Message#

定义属于自己项目的数据格式

⑥ TF2#

管理并转换坐标系

⑦ Marker#

把算法结果画出来

⑧ rosbag#

把机器人现场录下来,之后离线反复播放

62. 最终把整个知识体系串起来#

一个真实视觉项目可以是:

相机
│ Image
Camera Node
│ /image_raw
Detector
│ Custom Message
Locator
│ camera frame
TF2
│ gimbal frame
Tracker
│ prediction
Controller

与此同时:

所有 Topic
├────────→ rosbag
├────────→ RViz2
└────────→ Foxglove

性能方面:

Camera
Detector
Locator
Tracker
Composable Container
Multi-thread
Intra-process communication

部署方面:

Linux
systemd
launch
ROS 2 system

63. 一句话总结#

基础 ROS 2 是“让节点通信起来”;进阶 ROS 2 是“让整个机器人系统跑得快、看得见、调得动、部署稳”。

对于机器人视觉,最重要的一条链是:

Topic
Custom Message
Composable Node
Intra-process
TF2
Marker / RViz2 / Foxglove
rosbag
systemd

这条链基本覆盖了从“写出一个 ROS 节点”到“把视觉算法部署到真实机器人”的关键工程能力。


参考资料#

本手册根据浙江大学 RoboMaster Vision 的 ROS 2 基础培训页面整理,并刻意避开上一份基础速查手册已经详细介绍的内容:

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或投喂支持!

投喂
ROS 2 速查手册(进阶)
https://www.infvar.com/posts/ros2-advanced/
作者
Dignite
发布于
2026-09-11
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
Dignite
技术,学习,生活,旅行。
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
站点统计
文章
158
分类
5
标签
282
总字数
338,254
运行时长
0
最后活动
0 天前

目录