Loading

【ROS】-- 自定义回调队列

在 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;
}
posted @ 2024-05-27 20:20  深夜好梦  阅读(163)  评论(0)    收藏  举报