The value of knowledge lies not in possession, but in share.

0%

C++与ROS 回调函数解析

C++中的回调函数:

A “callback” is any function that is called by another function which takes the first function as a parameter.

直白点说,就是“函数#”的参数是另一个函数,通过“函数#”调用另一个函数,这个“函数#”就是回调函数。以数学形式来看(虽然不太恰当):Function(y)和Function(g(x))。Function(y)是一个函数,g(x)也是一个函数,那么Function(g(x))就可以看成是一个回调过程,g(x)就是回调函数。

更直接地说,我们一般都是调用OpenCV里面的库函数,现在关系反过来了,我们要让OpenCV调用一个我们自己写的函数,这个过程就是回调。那个被OpenCV调用的(我们自己写的)函数就是回调函数。接下來举例规范地说一下:

不带参数的回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//回调函数  
void wordsCallback()
{
std::cout<<"Hello World!"<<std::endl;
}

//实现回调函数的"调用函数"
void wods(void (*callfuction)())
{
callfuction();
}

int main(int argc,char* argv[])
{
words(wodsCallback);
return 0;
}

程序的正确输出结果是:Hello World!

带参数的回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//回调函数  
void wordsCallback(char* s)
{
std::cout<<s<<std::endl;
}

//实现带参回调函数的"调用函数"
void words(void (*callfuction)(char*),char* s)
{
callfuction(s);
}

int main(int argc,char* argv[])
{
words(wordsCallback,"Hello World!");
return 0;
}

程序的正确输出结果:Hello World!

ROS中的回调函数

一般来说这个回调函数会用一些比较显著且比较统一的名字:**Callback(如ScanCallback/CameraCallback),它是在订阅话题的时候使用的。所以在使用时,我们需要声明订阅话题的名称,然后选择话题,最后调用Callback函数。)

举个栗子:

1
2
3
4
5
6
7
8
9
10
11
void imageCallback(const sensor_msgs::ImageConstPtr& msg)
{
try
{
cv::imshow("view", cv_bridge::toCvShare(msg, "bgr8")->image);
}
catch (cv_bridge::Exception& e)
{
ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
}
}
1
image_transport::Subscriber sub_raw_image = it.subscribe("camera/rgb/image_raw", 1, imageCallback);

先声明订阅的话题的名称:

1
sub_raw_image

然后,选择我们需要订阅的话题。

1
"camera/rgb/image_raw"

题外话,ROS中有很多话题,有的是自己写的,有的来自其他节点发布的。

1代表我们一次性可以缓存多少消息,最后那个就是回调函数了。

1
imageCallback

ROS中,imageCallback的参数是与话题息息相关的,要跟据订阅的话题来确定参数。

一般来说,程序的主要功能也都是在回调函数中实现的。

或者说,将来自【订阅话题】中的数据,传递给【目标函数】进行处理。

需要的数据,都是要通过话题订阅的,而订阅了就肯定有回调函数。可以把一个个回调函数看成是一个个单独的线程。

只要订阅的消息一更新(当有消息到达topic时),回调函数就会被调用(ROS就会调用imageCallback ()函数),对新的(到达的)数据进行处理,程序就这么不断的进行下去了。

这里我们仍旧举例:

1
2
3
void forwardCallback(const nav_msgs::Odometry::ConstPtr &forward_msg){}  

void imageCallback(const sensor_msgs::ImageConstPtr &image_msg){}

需要确定的就是这个sensor_msgs::ImageConstPtrnav_msgs::Odometry::ConstPtr.

使用类作为回调函数:

举个栗子:

1
2
3
4
5
class Listener
{
public:
void callback(const std_msgs::String::ConstPtr& msg);
};
1
2
Listener listen;
ros::Subscriber sub = n.subscribe("chatter", 1000, &Listener::callback, &listen);

如果订阅在Listener内部,你替换最后的参数为关键词this,它意味着订阅会引用类的一部分。

以上!

附:

& 有 “引用” 和 “ 取地址”的含义

int a; int &b = a;上述两行语句执行完之后,a、b表示同一个变量,对其中一个的操作相当于对另一个的操作。

int a; int *b = &a;则b中储存的是a的地址。对*b的任何操作相当于对a的操作。

🍭支持一根棒棒糖吧!