做自动驾驶和机器人控制联调的工程师,基本都会在某一天走到这一步:把Simulink里调好的控制算法,跟ROS2生态里的节点和数据打通。模型里放一个订阅模块接收上游感知信息,再放一个发布模块把控制指令发出去,结构很简单,但也正是这种“看起来简单”,让我前前后后栽了不少跟头。
我最早做这个的时候,以为就是用Simulink里的ROS2 Subscribe和ROS2 Publish两个模块一拖一连就完事。实际跑起来才发现,真正卡人的地方全在模块外面:MATLAB版本和ROS2发行版对不对得上、底层的DDS中间件是不是同一套、ROS_DOMAIN_ID是否一致、消息类型有没有同步到Bus对象里、QoS策略到底匹不匹配。最典型的一个场景就是:Simulink里信号刷得飞快,所有波形都很正常,但旁边终端敲ros2 topic echo /cmd_vel却迟迟看不到一条数据。遇到这种情况,很多人第一反应是查网络、查防火墙,但实际排查下来,问题往往出在配置层而不是链路层。
这篇文章我就把Simulink与ROS2做订阅/发布通信时需要注意的事情,以及从仿真走到独立部署时的固化事项,完整梳理一遍。适合那些正准备把Simulink控制模型接入ROS2系统,或者已经在联调但被各种“玄学”问题卡住的工程师。文中提到的思路大多来自我实际调试中的反复验证,有些细节可能官方文档里写了但不够醒目,这里帮你集中划出来。
1. 先把环境对齐:版本、中间件、域ID里还藏着多少“看不见”的差异
1.1 MATLAB与ROS2发行版的版本绑定关系
很多人忽略的第一件事:Simulink对ROS2的支持并不是“只要装个工具箱,任何ROS2版本都能随便连”。MathWorks对ROS2的支持是跟随MATLAB版本走的,每个版本官方支持的ROS2发行版范围不同,而且模块内部使用的消息类型定义也是按对应发行版生成的。
我印象很深刻的一次:一台机器上装的是较早的MATLAB版本,目标工控机上是比较新的ROS2发行版。模型里能正常创建节点,但一订阅对方的话题就报“消息类型不匹配”,查了半天,问题根源是MATLAB自带的ros2消息定义和对方发行版的消息定义不完全一样,甚至连基础消息集都有差异。
所以在你开始做任何事之前,第一件事永远是去查你当前MATLAB版本对应的ROS2支持情况。注意这里要区分两个维度:
- 你本机仿真时连接的ROS2环境的发行版;
- 你部署目标机上跑的ROS2发行版。
这两个可以不一样,但不建议差太远。比如你在R2021a上开发模型,目标却是一台Humble环境的设备,生成和移植过程中通常会有额外的坑。根据个人经验,做Humble相关项目时优先选择较新的MATLAB版本,各版本具体差异以MathWorks官方版本说明为准,我这里不写死表格,因为官方支持矩阵会随补丁版本更新而变化。
1.2 RMW实现不一致,节点即使在同一网段也无法发现彼此
ROS2和ROS1最大的区别,就是把底层通信从自研的TCPROS换成了DDS。而DDS并不是只有一个实现,ROS2里通过RMW(ROS Middleware Interface)层来切换不同的DDS供应商,比如Fast DDS、Cyclone DDS、RTI Connext。
如果在你的场景里,Simulink和外部ROS2节点跑在同一台机器上,一般不会遇到问题,因为默认的RMW实现通常是能自洽的。但如果你是在一台Linux工控机上部署,或者Simulink跑在Windows、外部ROS2设备跑在Linux,中间就很容易出现RMW实现不一致的情况。
我遇到过一种情况:外部节点是用Cyclone DDS作为中间件的,而Simulink这边默认走的是Fast DDS。两边都正常跑着,ros2 node list里甚至能看到对方,但订阅和发布就是不通,数据完全不流动。这个现象会把人带偏到网络配置上,但本质是中间件不匹配。
处理方式也很直接:确保两侧使用相同的RMW实现。常见做法是在启动任何节点之前,在终端或环境变量里显式指定:
bash复制export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
如果Simulink是在Windows上运行的,那就在系统环境变量里加上同样的配置;如果是Linux下启动MATLAB,则在启动MATLAB前设置好这个环境变量。
1.3 ROS_DOMAIN_ID:最容易被忽略的“隔离墙”
ROS2用域ID来隔离不同的逻辑通信组。默认情况下所有节点都在域0,但如果你在不同的终端里分别设置了不同的`ROS_DOMA
