记录一次在 ROS 学习过程中遇到的问题
message_filter 的使用方法 问题背景 现有一节点需要获取两不同传感器的数据,需要同时订阅两个话题,并将数据整合为一个 JSON 格式的数据帧发送至指定地址的指定端口;要求两帧数据时间戳尽量接近,socket 发送频率不低于 5Hz。
问题剖析 由于数据包不大,且发送频率无上限,故使用 UDP 即可,通过 socket 实现很容易。 JSON 的处理也有第三方库可用。问题关键是:
怎么保证 JSON 包数据的来源话题尽可能时间上接近 什么时候调用 socket 把数据发出去 解决方法一:ros::MultiThreadedSpin() + pthread::rwlock 定义 JSON 数据包为全局变量,分别订阅两个话题,使用两个回调函数,在其中一个回调函数结束写入消息数据时,为全局变量设置读写锁;而另一个回调函数先解锁,再写入消息,再加锁,依次类推。
定义套接字为全局变量,在其中一个回调函数中调用 sendto() 方法发送 JSON 包。
使用ros::MultiThreadedSpin() 来分别调用两话题的回调函数。
解决方法二:message_filter::Subscriber + message_filters::sync_policies::ApproximateTime 使用 message_filter::Subscriber 同时订阅两个话题,使用 ApproximateTime 作为消息订阅的策略,实现两话题的消息时间尽可能接近。
使用 registerCallback 来定义一个总的回调函数来处理两个话题的数据。
实操问题单: boost::bind() 方法的问题 按照教程订阅完话题,设置完消息过滤策略后,设置回调函数时,按照教程写下以下代码:
// 回调函数声明 void ROSHandler::callbackSocket(const glosa::qt_GUIConstPtr& qtSource, const msgs_record::glosaConstPtr& msgSource); ... // 绑定回调函数 sync....
个人学习过程中的笔记,如有不足敬请指正。
1. ROS 的基本概念 ROS (机器人操作系统) 简单来说就是提供了通讯框架,工具和现成功能的平台,我们最主要用的是通讯功能和工具套件。通讯功能主要包括同步通讯 (Service) 和异步通讯 (Topic);工具包括 rviz, Gazebo 等。ROS 的分布式框架设计方便智能驾驶和机器人这种多机通讯,数据流分散的场合。
1.1 计算图级 其实就是 ROS 通讯的拓扑网络,是一种点对点的通讯形式。
1. Node 节点,进程,或者说功能单元,是代码模块的最小单位,或者说是最小的单个可执行文件。
ROS 的通讯其实就是节点和节点之间 (不一定直接)的通信。
一个节点既可以实现订阅,也可以实现发布,也能同时实现。
2. Master 主人? 节点管理器,所有的节点都要找它进行注册才能被其他节点发现。因此要先启动节点管理器 (roscore)再启动节点 (rosrun)。
3. Message 消息,节点之间通讯的内容或媒介,可以自定义格式,就和 C 语言里的结构体一样,只不过 Message 更像是具体的对象,抽象的 *.msg 定义在对应 Topic 的文件夹中,或是单独作为一个程序包并被其他程序包所包括。
4. Topic 话题,或者叫主题,可以看成是一个频道,或者说是一个广场,单个或多个节点可以向一个话题发送消息,单个或多个节点也可以去订阅这个话题来获取消息。因此,话题的存在实现了消息发布者和消息订阅者之间的解耦,两者无需直接通信,无需知道对方的存在。
一个话题对应一种格式类型的 Message。
Topic 的内容在代码层面是字符串。
5. Service 服务,相对于话题的通讯模式是像 UDP 的广播式,它更像是TCP,是一端到另一端的直接通讯,并针对一次请求给予一次回应。因此没有频繁的消息传递,也就没有高系统资源占用。
Service通信是一对一通信,信息流是双向的,而且客户端与服务端之间的执行是同步的 (有一定顺序的)。
6. Bag 包 (为了区别下文中的程序包package一般口头叫它rosbag),用于保存并回放 ROS 运行中所有消息数据的特殊格式,在 debug 和数据后处理阶段非常有用。
回放 bag 时,Master 会创建一个临时节点来发送 bag 中记录的数据,其他所有话题直接订阅这个临时节点,消息是不经过我们自定义的节点的。因此,使用 bag 录制的数据来验证后修改的代码是不可行的。...