在MATLAB命令行执行ros2node 和 ros2subscriber后,执行ros2 topic list,MATLAB卡死

发布于:2025-06-13 ⋅ 阅读:(28) ⋅ 点赞:(0)

提问

setenv(‘ROS_DOMAIN_ID’,‘5’)
node = ros2node(“test_node”);
sub = ros2subscriber(node, “/topic_state”, “pid_interfaces/Command”);

我执行上面的命令,都是正常的,直到紧接着执行下面的命令:

ros2 topic list

然后MATLAB就一直处于busy。 无法完成。 这是为什么?

回答

你现在遇到的是一个MATLAB 在调用 ROS 2 相关 API 时陷入卡死(busy 状态)的问题,这类问题通常与 DDS 通信层阻塞或冲突 有关,下面是针对你情况的深度分析:


🧠 现象分析:

你成功执行了:

setenv('ROS_DOMAIN_ID','5');
node = ros2node("test_node");
sub = ros2subscriber(node, "/topic_state", "pid_interfaces/Command");

然后一旦执行:

ros2 topic list

MATLAB 卡住,进入 busy,甚至必须强制终止。


✅ 初步结论:

这是一个 DDS 节点/发现层阻塞死锁或资源竞争 问题。

✔ 为什么会这样?
  • ros2noderos2subscriber 都会初始化 ROS 2 runtime 和底层 DDS 实例(Fast DDS)

  • ros2 topic list 调用又试图初始化 另一个节点或访问 ROS graph

  • 如果:

    • DDS participant 互相冲突(共享资源)
    • 底层 DDS 实现(如 FastDDS)有线程死锁风险
    • 自定义消息未正确定义或未注册(特别是 pid_interfaces/Command
    • 端口/资源(如 multicast 地址)已被占用或绑定异常
      那么在调用 ros2 topic list 时,DDS discovery 阶段就会阻塞,造成 MATLAB 卡死

✅ 对策建议:

✅ 一:避免混用 ros2subscriberros2 topic list

你已经创建了一个 ros2noderos2subscriber,这些已经启动了一个 DDS 会话。
此时不要再用 ros2 topic list 命令去触发另一个 DDS Graph API 操作,建议调试过程只使用一类 API,否则会出现 DDS 死锁。

❗️推荐做法是:先用 ros2 topic list,再构建 ros2subscriber


✅ 二:换一种方式验证话题是否收到

比如你已经建立了 subscriber,那就直接:

msg = receive(sub, 5);
  • 如果 5 秒内能收到消息,说明连接一切正常
  • 如果 5 秒后报超时(Timeout while receiving),说明订阅建立但没有实际收到消息(要么发太慢,要么消息类型不匹配)

✅ 三:建议你执行以下测试脚本

把下面的操作流程当作“黄金验证路径”,只使用一次 DDS 初始化,避免混用 MATLAB API 和 CLI 命令:

% 确保环境变量设置正确
setenv('ROS_DOMAIN_ID','5');

% 创建节点
node = ros2node("sim_debug");

% 列出话题(推荐先做这个)
disp(ros2topic("list"));  % 如果这里不卡死,说明 DDS OK

% 创建订阅者
sub = ros2subscriber(node, "/topic_state", "pid_interfaces/Command");

% 接收消息
msg = receive(sub, 5);
disp(msg);

✅ 四:防止卡死建议

如果你已经卡死过,建议你执行以下清理动作后重试:

  1. 重启 MATLAB

  2. 关闭所有后台的 ros2 daemon(Linux 端执行 ros2 daemon stop

  3. 删除 DDS 缓存:

    • Windows: %LocalAppData%\Temp\fastrtps* 等缓存文件
    • Linux: ~/.ros~/.dds 相关缓存
  4. 确保 Linux 和 Windows 使用相同的 RMW 实现(如都是 rmw_fastrtps_cpp

  5. 确保 Windows 防火墙彻底关闭,或者明确放通 UDP 多播端口(7400/7410)


✅ 五:参考已知问题

  • MathWorks 已知问题报告
  • 官方建议在某些版本中避免在 node active 时使用 ros2 CLI 命令
  • 或者通过 clear all 清除所有 ROS 节点,再执行 ros2 topic list 也可避免冲突

✅ 总结

结论 说明
不建议在已有 ros2noderos2subscriber 的会话中使用 ros2 topic list 会触发 DDS 层冲突或阻塞
建议先使用 ros2 topic list,再初始化节点/订阅者 避免 DDS 冲突
你当前问题极可能是 DDS participant 重复或线程资源死锁 并非 Simulink 问题,而是底层通信资源未正确释放

是否需要我帮你写个自动化测试脚本(自动初始化节点、订阅、接收并打印消息),方便你以后排查这类问题?

继续提问

为什么使用了
setenv(‘ROS_DOMAIN_ID’,‘5’)
node = ros2node(“test_node”);
sub = ros2subscriber(node, “/topic_state”, “pid_interfaces/Command”);

以后,连打开simulink都变得很慢?如何取消节点?

回答

你发现 使用了 ros2noderos2subscriber 后,连打开 Simulink 都变得很慢,这个现象确实存在,并且是可以解释的:


🧠 问题根源:ROS 2 节点阻塞 DDS 网络线程资源

执行:

setenv('ROS_DOMAIN_ID','5')
node = ros2node("test_node");
sub = ros2subscriber(node, "/topic_state", "pid_interfaces/Command");

实际上会常驻启动一个 ROS 2 节点,这个节点:

  • 会开启底层 DDS participant(Fast DDS)
  • 会占用线程、UDP端口、多播资源
  • 会持续尝试“发现”远程参与者,尤其如果远端不回应,就会不断重试,消耗 CPU + 网络堆栈资源

于是就导致:

现象 原因
Simulink 打开慢 Simulink 在启动时也会尝试初始化 ROS 2 子系统,结果被当前 DDS participant 阻塞
MATLAB 运行慢 ROS2 节点内部有 I/O 线程和 discovery loop,持续占资源
多次运行 ros2node 后卡死 participant 没有及时释放,堆积成“幽灵节点”

✅ 如何释放和取消节点

你可以使用下面命令立即释放所有 ROS 2 资源

clear node sub

如果你还用了多个变量:

clear all

然后再执行:

ros2 reset

这将彻底清除 MATLAB 当前会话中的所有 ROS 2 DDS participant 和缓存。


✅ 补充推荐操作

如果你已经执行过 ros2node 等命令,建议在打开 Simulink 前先做这两件事:

clear all
ros2 reset

然后再打开 Simulink,速度会明显恢复。


✅ 持久优化建议

1. 养成习惯:测试完 ROS2 后清理资源

clear node sub
ros2 reset

2. 避免在 MATLAB 启动后立即执行多个 ROS2 节点(会拖慢初始化)

3. 如果你调试频繁,可写个“清理小脚本”:

function cleanup_ros2()
    try
        clear all;
        ros2 reset;
        disp("✅ 已清理 ROS2 节点和 DDS participant");
    catch
        disp("⚠️ 无 ROS2 节点正在运行");
    end
end

✅ 总结

你做了什么? 发生了什么?
执行 ros2noderos2subscriber 启动 ROS 2 DDS 节点,抢占资源
之后打开 Simulink Simulink 内部初始化 ROS 2,发生阻塞冲突
MATLAB 很慢 DDS participant 没释放,持续发现网络节点
如何解决 clear node sub,然后 ros2 reset 即可

需要我帮你写一个一键测试 + 自动清理的 ROS2 脚本模板吗?这样你每次调试完就不会拖慢 MATLAB 或 Simulink。