在 ros 中,我们常用的回调处理是 ros::spin() 或者 ros::spinOnce(),但是,这两个是阻塞式单线程处理的, 即当不做其他处理的情况下,某一个回调函数堵塞,其他topic或者service的回调函数就无法进入。
使用ros多线程的方式可以解决该问题,但引入多线程会导致线程安全的问题。针对某些场景,可以手动将回调函数分到不同的回调队列中去,不同回调队列内部仍是单线程。
【ROS】在类中实现自定义多线程回调 文中给出了类内自定义topic 订阅回调函数的解决思路,简单总结如下:
1、先在类的声明中提供自定义的回调队列:
/**
ros::SubscribeOptions ops=ros::SubscribeOptions::create<bhand_controller::State>(
"/bhand_node/state",
1,
state_callback,
ros::VoidPtr(),
&state_callback_queue
)
*/
// SubscribeOptions 不支持将类成员函数设置为回调函数, 需要单独声明模板目标
template <class M, class T>
ros::SubscribeOptions getSubscribeOptions(
const std::string &topic, uint32_t queue_size,
void (T::*fp)(const boost::shared_ptr<M const> &),
T* obj,
ros::CallbackQueueInterface* queue,
const ros::TransportHints &transport_hints = ros::TransportHints()) {
ros::SubscribeOptions ops;
ops.template init<M>(topic, queue_size, boost::bind(fp, obj, _1));
ops.callback_queue = queue;
ops.transport_hints = transport_hints;
return ops;
}
2、利用 ros::AsyncSpinner 异步多线程处理特定回调队列:
ros::CallbackQueue string_queue;
ros::SubscribeOptions ops = getSubscribeOptions(image_topic,1,
&Rotation::image_callback,this, &m_image_queue);//image_topic为订阅的图像话题名称
m_img_subscriber = nh_.subscribe(ops);
// 队列长度为1保证该回调队列内部仍为单线程
ros::AsyncSpinner spinner_(1, &string_queue);
// start the spinner
spinner_.start();
参考上面的实现,给出ros service的自定义回调队列的实现方式
template <class Service, class T>
ros::AdvertiseServiceOptions getAdvertiseServiceOptions(
const std::string& service,
bool (T::*fp)(typename Service::Request&, typename Service::Response&),
T* obj,
ros::CallbackQueueInterface* queue) {
ros::AdvertiseServiceOptions ops;
ops.init<typename Service::Request, typename Service::Response>(service, boost::bind(fp, obj, _1, _2));
ops.callback_queue = queue;
return ops;
}
标签:ros,自定义,ops,--,回调,queue,队列,ROS
From: https://www.cnblogs.com/Maybera/p/18216454