如何通过已创建的ROS节点实现外部C程序向rostopic发布数据?
解决方案
你可以根据现有程序的可修改程度,选择以下三种可行方案实现需求:
方案1:进程间通信适配(无需大幅修改原有C程序)
这种方案适用于不想修改原有ADSB采集C程序核心逻辑的场景,通过进程间传输的方式把数据传递到ROS节点处理:
- 首先在原有C程序中,将输出的ADSB数据按约定好的结构化格式(比如固定字段分隔的字符串、二进制结构体)输出到标准输出,或写入Unix域套接字、命名管道
- 在你已创建的ROS发布节点中,持续读取C程序输出的结构化数据,解析后填充到
mavros/ADSBVehicle消息字段中,调用publish()接口直接发布即可 - 如果用匿名管道实现流程最简单,直接在启动时通过shell管道将两个程序绑定即可,示例启动命令:
./你的ADSB采集程序 | rosrun 你的功能包名 你的ROS发布节点名
附C++ ROS节点读取标准输入的核心代码片段:
#include <ros/ros.h> #include <mavros/ADSBVehicle.h> #include <iostream> int main(int argc, char** argv) { ros::init(argc, argv, "adsb_publisher"); ros::NodeHandle nh; // *注意latch设为false,避免旧消息缓存,对应你之前遇到的3秒延迟问题* ros::Publisher pub = nh.advertise<mavros::ADSBVehicle>("/mavros/adsb/in", 10, false); std::string line; // 持续读取管道输入的ADSB数据 while (ros::ok() && std::getline(std::cin, line)) { mavros::ADSBVehicle msg; // 这里按你约定的格式解析line,填充msg的各个字段,比如ICAO地址、经纬度、高度、速度等 // 示例:msg.header.stamp = ros::Time::now(); // msg.icao_address = ...; pub.publish(msg); ros::spinOnce(); } return 0; }
方案2:C程序功能直接集成进ROS节点(性能最优)
如果可以修改原有C程序的工程结构,推荐直接将C代码集成到ROS节点中,完全省去进程间通信的开销和不稳定因素:
- 将原有C程序的ADSB采集相关函数封装成独立的C语言库,对外暴露初始化、读取单帧ADSB数据的接口
- 在ROS C++节点中链接该C库,调用接口直接获取ADSB数据,填充消息后发布即可
- 注意C代码引用C接口时需要用
extern "C"包裹头文件引用,避免C名称修饰导致链接失败:
extern "C" { #include "你的ADSB采集库头文件.h" }
方案3:共享内存传输(适合高吞吐量场景)
如果你的ADSB数据输出频率很高,前两种方案满足不了延迟要求,可以用共享内存实现跨进程数据传输,在C程序和ROS节点中分别挂载同一块共享内存空间,C程序写入数据后通过信号量通知ROS节点读取即可。
额外注意事项
- 消息的时间戳尽量用数据采集的实际时间,如果拿不到采集时间再用ROS节点读取数据的当前时间填充
内容的提问来源于stack exchange,提问作者Francisco Zacarias
相关产品推荐
相关产品推荐

