ROS多传感器数据时间戳同步方案——message_filters::TimeSynchronizer

在ROS开发中,处理多传感器数据融合时需判断时间戳以保证数据同步,常用队列存储数据,但存在需进程锁和条件变量保证内存访问的缺点,影响点云数据处理性能。ROS提供message_filters::TimeSynchronizer等同步类完成此任务,使用时回调函数参数有特定要求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

综述

在ROS开发过程中,有一些时候需要处理来自多个传感器的数据,比如我自己做的一些东西,就需要把不同相机的点云数据进行融合,融合的过程中需要判断传感器数据的时间戳,保证融合的数据尽可能是两个传感器的同步数据,一般的实现是用队列来存储传感器的数据,在不断的出队过程中比较传感器队列的时间戳,如果时间戳之间相差的时间在容忍范围内,就可以认为是同步的。

std::queue buf1;
std::queue buf2;
std::thread process;
//typedef M 传感器数据类型,比如sensor_msg::PointCloud2、sensor_msg::Image等等
void callback1(M& msg){
	//数据入队
	buf1.push(msg);
	//其他代码。。。
}
void callback2(M& msg){
	//数据入队
	buf2.push(msg);
	//其他代码。。。
}
void process_comparation(){
	while(ros::ok()){
		M data1=buf1.front();
		M data2=buf2.front();
		if(data1.header.timestamp.toSec()>data1.header.timestamp.toSec()){
			buf2.pop();
		}
		else 
			buf1.pop();
		//其他操作data1和data2的代码
	}
}
int main(int argc,char** argv){
	//initialization
	
}

这个也是VINS里面处理双目相机和IMU数据的方法,这样的方法一个很大的缺点是需要用一些进程锁和条件变量来保证内存访问,因为有一些全局变量例如传感器数据的队列可能同时会被多个进程访问,这个缺点在处理图片和IMU这类小体量数据的时候体现不出来,并且VINS也确实需要这样的队列来完成算法,在处理点云数据的时候,这个缺点对于程序的性能就有很大的影响。幸好ROS提供了message_filters::TimeSynchronizer等同步类来完成多传感器数据同步融合的任务。

message_filters::TimeSynchronizer

参照官文链接: ROS wiki

#include <message_filters/subscriber.h>
#include <message_filters/time_synchronizer.h>
#include <sensor_msgs/PointCloud2.h>

using namespace sensor_msgs;
using namespace message_filters;

void callback(const PointCloud2ConstPtr& image, const PointCloud2ConstPtr& cam_info)
{
  // Solve all of perception here...
}

int main(int argc, char** argv)
{
  ros::init(argc, argv, "vision_node");

  ros::NodeHandle nh;

  message_filters::Subscriber<PointCloud2> cloud1(nh, "/camera1/depth/color/points", 1);
  message_filters::Subscriber<PointCloud2> cloud2(nh, "/camera2/depth/color/points", 1);
  TimeSynchronizer<PointCloud2, PointCloud2> sync(cloud1, cloud2, 10);
  sync.registerCallback(boost::bind(&callback, _1, _2));//boost::bind的用法可以参考https://www.cnblogs.com/benxintuzi/p/4862129.html

  ros::spin();

  return 0;
}

注意:回调函数里面的参数一定是const MConstPtr& msg,不能是M& msg。比如点云数据一定是const PointCloud2ConstPtr& msg,别的像const PointCloud2Ptr& msg或者const PointCloud2& msg都不行,这个也是困扰了我一个晚上的小小细节。

ROS2中,`message_filters`包提供了一种高级的方式来处理主题(topics)间的同步,特别是在需要时间相关的数据对齐时非常有用。要使用`message_filters`订阅特定的topic,首先你需要安装`message_filters`库(如果还没有的话),然后可以按照以下步骤操作: 1. **导入必要的包**: ```cpp #include <rclcpp.hpp> #include <message_filters/subscriber.hpp> #include <sensor_msgs/msg/image.hpp> ``` 2. **声明Subscriber**: ```cpp class ImageSubscriber : public rclcpp::Node { std::shared_ptr<message_filters::Subscription<std_msgs::msg::Time, sensor_msgs::msg::Image>> image_sub; message_filters::sync_policies::ApproximateTime<sensor_msgs::msg::Image, std_msgs::msg::Time> sync_policy; }; ``` 3. **设置订阅和同步策略**: ```cpp void setup() { // 设置主题名称和同步政策 image_sub = this->create_subscription<std_msgs::msg::Time>("image_topic", 10, [this](const std_msgs::msg::Time::SharedPtr msg) { // 回调函数,处理接收到的时间戳 }); image_sub->registerCallback( [&sync_policy](const sensor_msgs::msg::Image::SharedPtr img_msg) { // 回调函数,处理接收到的图像消息并同步 }); sync_policy.registerCallback([this](const auto& /*time_msg*/, const auto& img_msg) { // 同步回调,处理两个消息的时间对齐 }); } ``` 4. **启动订阅**: ```cpp void spin() { setup(); rclcpp::spin_some(context_); } ``` 5. **运行节点**: ```cpp int main(int argc, char * argv[]) { auto node = std::make_shared<ImageSubscriber>("my_node"); rclcpp::init(argc, argv); node->spin(); rclcpp::shutdown(); return 0; } ``` 在这个例子中,我们订阅了名为`"image_topic"`的主题,并使用`ApproximateTime`同步策略处理时间相关的数据对齐。当主题发布新的`sensor_msgs::msg::Image`和`std_msgs::msg::Time`消息时,它们会在时间上尽可能接近的地方同步
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值