重新系统学习 ROS 过程中的笔记整理,涵盖通信机制、参数系统、时间管理和常用编程模式。
通信机制
话题(Topic)vs 服务(Service)
| Topic(话题) | Service(服务) | |
|---|---|---|
| 通信模式 | 发布/订阅 | 请求/响应 |
| 同步性 | 异步 | 同步 |
| 缓冲区 | 有 | 无 |
| 实时性 | 弱 | 强 |
| 结点关系 | 多对多 | 一对多(一个Server) |
| 数据类型 | msg | srv |
| 适用场景 | 连续高频数据(雷达、里程计) | 偶发性逻辑处理(拍照、语音识别) |
服务通信适用于对实时性有要求、并有一定逻辑处理的应用场景。话题通信虽实时性不高,但传输效率明显高于服务通信。
服务通信流程
服务通信涉及三个角色:
- master(管理者):保管 server 和 client 注册信息,匹配并帮助建立连接
- server(服务端):接收请求并响应
- client(客户端):发送请求
通信建立在请求响应模式之上,一个节点发送数据后能接收到另一个节点返回的数据。
NodeHandle 与命名空间
NodeHandle 是 ROS 中与节点交互的核心句柄。它不是一个简单的指针,而是系统管理的引用标识——有一个固定的地址指向固定位置,而该位置中的值可以动态变化。
全局 vs 局部命名空间
1 | ros::NodeHandle n; // 全局命名空间 |
命名规则:
| 类型 | 示例 | 说明 |
|---|---|---|
| 全局名称 | /global/name |
以 / 开头,全局可访问 |
| 相对名称 | relative/name |
基于默认命名空间 |
| 私有名称 | ~private/name |
基于节点全局名称 |
实际示例:
1 | // 用例1:无默认命名空间 |
私有名称不使用当前默认命名空间,而是用节点的全局名称作为命名空间。
参数系统
参数本质是一个中央注册表,支持增删改查。代码和 launch 文件中都可以设置,launch 文件的参数会覆盖代码中的参数。
roscpp 中的两套参数 API
推荐使用 ros::param 方式——它给人的感觉是参数操作是静态的、实例无关的,更符合”参数”的本质。
ros::param 方式:
1 |
|
ros::NodeHandle 方式:
1 | ros::NodeHandle nh; |
launch 文件中加载参数
1 | <launch> |
读取全局与局部参数:
1 | ros::NodeHandle nh_global; |
arg 传参
arg 的优势在于不修改 launch 文件就能改变参数值:
1 | <arg name="a" default="1" /> |
命令行覆盖:
1 | roslaunch my_pkg launch_file.launch a:=10 b:=20 |
YAML 参数文件
当系统复杂时,用 YAML 文件集中管理参数:
1 | <rosparam file="$(find pkg)/config/params.yaml" command="load" ns="namespace" /> |
等价于终端命令:rosparam load params.yaml
时间管理
ros::Time 与仿真时间
1 | ros::Time now = ros::Time::now(); // 系统时间或仿真时间,取决于 use_sim_time |
use_sim_time=true→ 输出仿真时间(如 rosbag 回放的时间)use_sim_time=false→ 输出系统时间
设置 use_sim_time:
1 | <!-- launch 文件 --> |
1 | # 终端 |
如果使用模拟时钟,
ros::Time::now()在收到第一条/clock消息前返回 0。需要真实时间时,使用ros::WallTime::now()。
ros::Duration
1 | ros::Time begin = ros::Time::now(); |
定时器 ros::Timer
定时器每隔一段时间调用一次回调函数:
1 | // 创建定时器 |
period:回调间隔,如ros::Duration(0.1)即每 0.1 秒oneshot:是否只执行一次
定时器可通过 stop()、setPeriod()、start() 重置:
1 | void timerCallback(const ros::TimerEvent& e); // 必须带参数 |
ros::TimerEvent 提供时间诊断信息:last_expected、last_real、current_expected、current_real。
调试技巧
日志打印
1 | ROS_INFO_STREAM_ONCE("只打印一次"); // 确认数据接收但不刷屏 |
查看日志:rqt_console
过滤日志等级:rosrun rqt_logger_level rqt_logger_level
Debug 信息默认不显示,需要先启动
rqt_logger_level手动开启。