ros topic advanced questions - maohaihua/ros_study GitHub Wiki

Subscribe的第四个参数用法

看别人的代码真的是很好的学习过程啊

之前用Subscribe订阅的时候都是简单的用法形如:

ros::Subscriber sub = node.subscribe<uhf_rfid_api::UhfRfid>("messageepc", 0, rfid_callback) ;

这样只用三个参数。

 然后在实际中,如果想要给回调函数传参数可以用C++ 的boost库中的boost::bind() 函数,如:

image_transport::Subscriber sub = it.subscribe(topic_root + "/camera/image", 0, boost::bind(image_callback, _1, &pub_vt));

这里,boost::bind中的第一个参数是回调函数名,第二个 _1 是一个占位符,因为回调函数image_callback的第一个参数是msg,要给它留位置。第三个,就是传的一个参数。以此扩展,如果想要传两个参数,这样:boost::bind(image_callback, _1, &pub_vt, &pub_odo),不要把_1当做参数个数哈

然后在回调函数里面,这样用:

void image_callback(sensor_msgs::ImageConstPtr image, ros::Publisher * pub_vt)

就可以把参数写在第二个实参的位置了O(∩_∩)O

然后来说今天的重点,我学到的第四个参数的用法,先上示例:

ros::Subscriber mysub = nh.subscribe("/move_cmd", 0, &Robot::moveCallback, &tars);

在API里的原型是这样的: 复制代码

template<class M , class T > Subscriber ros::NodeHandle::subscribe(const std::string & topic, uint32_t queue_size, void(T::*)(M) fp, T * obj, const TransportHints & transport_hints = TransportHints() ) [inline]

复制代码

看上面原型要注意的是回调函数,应该是和第四个参数的在同一个类中,上面的例子是都在类T中,并且fp和obj都是指针类型 * 的。

解释下用法,第四个参数的T* obj是将类T的对象实例的指针传给同类的回调函数,void(T::*)(M) fp。因此在实例类obj中,如果改了一个变量的值,在回调函数中也能体现出来。这样,就相当于类中使用全局变量了。

好了,解释完了,放我实现的栗子:

void Robot::moveCallback(const fsm_robot::rcmd_move msg) { cmd_int = n; n++; }

这里,cmd_int就是类实例中中的全局变量了

ROS多进程回调的实现 ROS Using different ros::CallbackQueue

总体上分为一下步骤:

1 用 ros::CallbackQueue定义需要的回调队列;

ros::CallbackQueue state_callback_queue;

2 将回调队列初始化进subscriber中。例如下面所示:

ros::SubscribeOptions ops=ros::SubscribeOptions::create<bhand_controller::State>( "/bhand_node/state", 1, state_callback, ros::VoidPtr(), &state_callback_queue )

ros::Subscriber listen_state=bhand_state.subscribe(ops);

3 定义ros::AsyncSpinner,并初始化回调队列,第一个参数代表几个进程,但是目前并不知道有什么特殊用处。

ros::AsyncSpinner state_spinner(1,&state_callback_queue);

4 启动调用。

state_spinner.start();

备注:

(1) 注意subscriber的缓存队列的大小,会影响回调结果,这与ROS的回调机制相关,ROS在发生回调是会将所有队列中的消息分别送往回调函数中,因此如果队列未被及时更新,可能出现多次重复响应,因此建议设置为1,或者慎重考虑下运行频率相关。

(2)可通过在回调函数中加标志位的方式实时停止回调。下面在回调函数中使得init_state_flag置1,break跳出while或for的循环.

while(ros::ok())
{
    if(init_state_flag == 1)
    {
        state_spinner.stop();
        break;
    }
    state_spinner.start();

}

(3)不要把初始化的定义语句,诸如ros::Subscriber listen_state=bhand_state.subscribe(ops);放在没有ros.sleep的while(ros::ok()),否则会不能触发消息回调,而且编译不会提示任何问题。

5 该部分完整的实例如下;

ros::CallbackQueue state_callback_queue; void state_callback(const bhand_controller::State::ConstPtr& msg) {

.......

init_state_flag=1;//也可在需要位置置1

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

//monitor the state of the hand.
ros::NodeHandle bhand_state;

ros::SubscribeOptions ops=ros::SubscribeOptions::create<bhand_controller::State>(
            "/bhand_node/state",
            1,
            state_callback,
            ros::VoidPtr(),
            &state_callback_queue
            );
ros::Subscriber listen_state=bhand_state.subscribe(ops);

ros::AsyncSpinner state_spinner(1,&state_callback_queue);

while(ros::ok())
{
    if(init_state_flag == 1)
    {
        state_spinner.stop();
        break;
    }
    state_spinner.start();

}

}

https://blog.csdn.net/hookie1990/article/details/76696180 ROS下实现机器人序列任务的执行控制


作者:信雪神话 来源:CSDN 原文:https://blog.csdn.net/hookie1990/article/details/76696180 版权声明:本文为博主原创文章,转载请附上博文链接!