
1. 名词都会,语义仍用错
配置用 latched topic「谁最后发谁赢」、长任务忙等 service、控制环里同步 call——演示能通,产品期变成卡死与不可观测。选原语前先问三句:失败是否对调用方可见?是否可取消?背压打在谁身上?答不清就先别开接口评审。
底盘曾用 service 做模式切换:实验室快,导航与遥控并发后切换卡在服务队列,轮速环出毛刺。改成短 topic 设定点 + 带状态反馈后,毛刺消失。问题不在「service 坏」,而在把同步阻塞放进了硬实时路径。
2. Topic:扇出便宜,不保证处理完
发布-订阅适合传感器流、高频设定点、状态广播。扇出成本低,但不保证对端算完——压力表现为丢样或延迟,不是抛异常给发布者。
cmd_pub_ = create_publisher<geometry_msgs::msg::Twist>("cmd_vel", 10);调用方看不到「对方收到没有」,必须用看门狗或状态话题补闭环。把配置当 latched topic 时,要写清仲裁:谁有权最后写入,冲突如何可见。三个节点各发一次「最大速度」,谁赢全靠启动顺序,是配置灾难。
传感器侧常用 SensorDataQoS()(Best Effort + KeepLast 小 depth);订阅者若用 Reliable,可能根本收不到——这是 QoS 合约问题,不是 topic 「坏了」。
3. Service:短、幂等、可超时
适合「问一次得一次答案」:查参数快照、触发单次标定、切换布尔模式。同步 call 在 100 Hz 环里死等,等于把对端抖动写进力矩。
auto future = client_->async_send_request(request);
if (future.wait_for(200ms) != std::future_status::ready) {
RCLCPP_WARN(get_logger(), "service timeout");
return;
}超时后的重试必须幂等——「再调一次启动扫描」可能开两个冲突任务。需要进度与取消的长任务,别硬塞 service。
4. Action:长任务的标准契约
导航、抓取、长标定、轨迹执行——需要 goal、feedback、cancel 语义,用 Action:
ros2 action send_goal /follow_path nav2_msgs/action/FollowPath "{...}"用 topic 模拟 action(发 goal topic、听 result topic、另发 cancel topic),最后仍要自建状态机,还少了标准取消语义。Action 服务器的 cancel 回调必须落到执行器安全态,否则面板上显示已取消,轮子还在转。
5. 画同步边界:跨进程要显式失败
跨进程、跨机、跨责任边界:用 service/action 把失败显式化(超时、拒绝、abort)。边界内高频交换:用 topic 流式推。同一能力不要同时提供「阻塞 service」和「无超时 topic」两套入口,除非写清优先级——双入口是现场「到底听谁的」的根源。
lifecycle 与原语正交:节点 inactive 时,service 应拒绝或 unavailable;action 应 abort 在途目标。把「图还在」当成「契约还在」会误导上层重试风暴。
6. 节点图与 executor 的隐性代价
单节点内 topic 回调共享 executor;一个回调阻塞,同节点其他订阅也饿死。service 回调里做巨型计算,会拖死同进程 topic——这不是原语问题,是调度问题,但选型时要把「谁同进程」算进去。
Composable 容器里多组件共享进程:topic 快、service 慢可以共存,但要在架构上隔离硬实时组件(独立 executor 或独立进程)。
7. 迁移与故障注入验收
注入对端崩溃:topic 侧看门狗应响;service 应超时/失败返回;action 应 aborted/canceled 且执行器停。迁移期:长任务先加超时与取消,再迁 Action——不要同一周既改原语又改算法。
- 新接口设计文档写明:原语选择、超时、幂等、取消语义。
- CI 冒烟:关键 service 带超时调用;action cancel 后执行器归零。
- 配置类能力禁止无仲裁的多 publisher topic。
流用 topic,短契约用 service,长且可取消用 action。例外写进设计说明,而不是口口相传。原语选错的成本,在并发与故障注入时才爆炸——演示路径永远偏乐观。
8. 案例:导航目标的三条错误路径
曾见过同一「去目标点」能力提供:同步 service(阻塞 30 s)、无 ACK 的 topic goal、以及后来才加的 Action。现场三套客户端并存,取消语义互不兼容,录包显示 goal 已 cancel 但 base 仍在滑。收敛到单一 Action 后,故障单数量降了一个量级——不是 Action 魔法,是契约统一。
相关
也可以看看
johan's blog