关于ROS在一个回调函数中处理两个订阅话题消息(多话题回调、多参数回调问题)

最近遇到需要在一个回调函数中处理多话题消息的问题,特此记录下在一个回调函数中处理多话题、多参数的方法。

举例:

#include <iostream>
#include <boost/bind.hpp>

#include <ros/ros.h>

#include <sensor_msgs/Image.h>
#include "detectmsg/SpatialDetection.h"
#include "detectmsg/SpatialDetectionArray.h"
#include "detectmsg/pose2D.h"
#include "detectmsg/multi_pedestrian_pose.h"
 
ros::Publisher obj_pub_;
ros::Subscriber  obj_sub_;
ros::Subscriber  image_sub_;

int Class_ID;

std::string pub_topic;
std::string sub_topic;

void Callback(const detectmsg::SpatialDetectionArray::ConstPtr& detect, const sensor_msgs::Image::ConstPtr& image)
{
  ROS_INFO("ok!");
}
 
int main(int argc, char **argv)
{
    ros::init(argc, argv, "obj_publish_node");
    ros::NodeHandle nh;

    int ErrorParam=0;

    ErrorParam += !nh.getParam("objdetectnode/Class_ID_", Class_ID);

    ErrorParam += !nh.getParam("objdetectnode/pub_topic_", pub_topic);
    ErrorParam += !nh.getParam("objdetectnode/sub_topic_", sub_topic);


    if(ErrorParam>0){
      ROS_INFO("Error Param Load! Error Number:%d",ErrorParam);
      return 1;
    }

    ROS_INFO("SUCCESSFULLY STARTED");

    obj_pub_ = nh.advertise<detectmsg::multi_pedestrian_pose>(pub_topic, 1);
    obj_sub_ = nh.subscribe<detectmsg::SpatialDetectionArray>(sub_topic, 1, boost::bind(&Callback, _1 , sensor_msgs::Image::ConstPtr()));
    image_sub_ = nh.subscribe<sensor_msgs::Image>("/yolov4_publisher/color/image", 1, boost::bind(&Callback, detectmsg::SpatialDetectionArray::ConstPtr(), _1));
   
    ros::spin();
    return 0;
}

这是一段没写完的代码,主要用来测试一下多参数回调问题,最关键的部分在订阅话题的两端代码上,其他的代码不用看,需要注意到地方会在下文提到。

1、要实现多话题回调需要包含头文件,对应代码:#include <boost/bind.hpp>

2、要实现两个话题传向一个回调函数,首先先分别写出两个订阅话题的代码,最常用的订阅话题的代码段格式为:

obj_sub_ = nh.subscribe<detectmsg::SpatialDetectionArray>(sub_topic, 1, &Callback);

要实现多话题回调需要使用到函数boost::bind(),这里可以参考上文的代码(以obj_sub_为例),将原来回调函数的位置替换为该函数,函数内有三个参数,第一个是这两个话题进行绑定后共同传入的回调函数名称,第二个参数是一个占位符,为下面的话题订阅占位,最后一位为传入当前语句订阅的话题,注意结尾的::ConstPtr()。

image_sub_的语句是类似的,唯一的区别是占位的时候需要注意占位符位置的变化以及消息格式已经变成了上一个话题的消息格式。这里我特意选择了两个不同的消息格式防止混淆,相信各位一对比就能很清楚的明白其中的规律。

最后就是注意下一下在回调函数的参数部分,两个参数的顺序不能颠倒,同时注意const。

---------------------------------------------------------------------------------------------------------------------------------

上面代码经过测试是正常运行的,但是我尝试进行三个话题的同步回调时遇到了问题,按照上述写法,在回调函数中每次只能读取到一个话题的消息,不知道是因为时间同步问题导致还是代码里逻辑有问题,总之运行是不正确的,运行有问题的代码如下:

    // obj_sub_ = nh.subscribe<yolov5_ros_msgs::BoundingBoxes>("/yolov5/BoundingBoxes", 1, 
    //     boost::bind(&Callback, _1 , sensor_msgs::Image::ConstPtr(),sensor_msgs::CameraInfo::ConstPtr()));
    // image_sub_ = nh.subscribe<sensor_msgs::Image>("/stereo_publisher/stereo/depth", 1, 
    //     boost::bind(&Callback, yolov5_ros_msgs::BoundingBoxes::ConstPtr(), _1,sensor_msgs::CameraInfo::ConstPtr()));
    // caminfo_sub_ = nh.subscribe<sensor_msgs::CameraInfo>("/stereo_publisher/stereo/camera_info", 1, 
    //     boost::bind(&Callback, yolov5_ros_msgs::BoundingBoxes::ConstPtr(), sensor_msgs::Image::ConstPtr(),_1));

这段代码语法上是没有问题的,是可以编译通过的,我因为该代码的不正确运行,报的段错误,找到错误花了些时间,有一定迷惑性。

找到错误后更换了订阅话题方法,新方法用到了message_filters这个库,没有安装的话用下面的代码安装即可:

 sudo apt-get install ros-melodic-message-filters
//中间部分换成自己的版本

使用时包含头文件并并在cmakelists文件中find package部分进行添加

//头文件
#include<message_filters/subscriber.h>
#include<message_filters/time_synchronizer.h>

----------------------------------------------------
//CMakelists.txt

find_package(catkin REQUIRED COMPONENTS
  ...
  message_filters
)

...

target_link_libraries(your_executable_name
  ...
  ${catkin_LIBRARIES}
)

cpp中使用方法,还是上面的例子:

    message_filters::Subscriber<yolov5_ros_msgs::BoundingBoxes> detect_sub(nh, "/yolov5/BoundingBoxes", 1);
    message_filters::Subscriber<sensor_msgs::Image> image_sub(nh, "/stereo_publisher/stereo/depth", 1);
    message_filters::Subscriber<sensor_msgs::CameraInfo> caminfo_sub(nh, "/stereo_publisher/stereo/camera_info", 1);

    message_filters::TimeSynchronizer<yolov5_ros_msgs::BoundingBoxes, sensor_msgs::Image, sensor_msgs::CameraInfo> sync(detect_sub, image_sub, caminfo_sub, 10);
    sync.registerCallback(boost::bind(&Callback, _1, _2, _3));
  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
ROS处理两个不同类型的话题消息时,可以使用回调函数消息过滤器来实现。以下是一个示例代码,展示了如何处理两个不同类型的话题消息: ```cpp #include <ros/ros.h> #include <message_filters/subscriber.h> #include <message_filters/time_synchronizer.h> #include <asv_msgs/StateArray.h> #include <nav_msgs/Odometry.h> void callback(const asv_msgs::StateArray::ConstPtr& state_msg, const nav_msgs::Odometry::ConstPtr& odometry_msg) { // 在这里处理两个不同类型的消息 } int main(int argc, char** argv) { ros::init(argc, argv, "message_sync_node"); ros::NodeHandle nh; // 创建两个订阅者,分别用于接收asv_msgs::StateArray和nav_msgs::Odometry类型的消息 message_filters::Subscriber<asv_msgs::StateArray> state_sub(nh, "obstacle_states", 1); message_filters::Subscriber<nav_msgs::Odometry> odometry_sub(nh, "/asv/state", 1); // 创建时间同步器,用于同步两个话题消息 typedef message_filters::sync_policies::ApproximateTime<asv_msgs::StateArray, nav_msgs::Odometry> SyncPolicy; message_filters::Synchronizer<SyncPolicy> sync(SyncPolicy(10), state_sub, odometry_sub); // 设置回调函数 sync.registerCallback(boost::bind(&callback, _1, _2)); ros::spin(); return 0; } ``` 在这个示例,我们使用了`message_filters`库来创建订阅者和时间同步器。首先,我们创建了两个订阅者,分别用于接收`asv_msgs::StateArray`和`nav_msgs::Odometry`类型的消息。然后,我们创建了一个时间同步器,并将两个订阅者传递给它。最后,我们设置了回调函数,将其绑定到时间同步器的回调函数。 在`callback`函数,你可以处理两个不同类型的消息。根据你的需求,你可以使用消息的字段和方法来获取所需的信息进行处理。 这是一个基本示例,你可以根据需要进行修改和扩展。希望对你有所帮助!如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值