c++回调函数/ROS回调函数

本文详细介绍了C++中的回调函数概念,并给出了具体的代码示例。进一步地,文章讲解了ROS环境中回调函数的应用,包括如何定义和使用带参数及不带参数的回调函数,以及在订阅话题时回调函数的作用。

以下均是个人在实际耕码的过程中遇到的问题和整理的结果,可能会有不对的地方,望各位指正与交流

-------------------------------------------------我会有喵的---------------------------------------------------

 

c++中的回调函数:

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

 

 

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

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

不带参数的回调函数:

//回调函数
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!

  带参数的回调函数:

//回调函数
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函数。废话不多说,举个例子(突然想吃举个栗子了啊-------):

ros::Subscriber sub_raw_image = n.subscribe(IMAGE_TOPIC, 2000, imageCallback);

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

sub_raw_image 

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

IMAGE_TOPIC

题外话,ROS中有很多话题,你可以自己写,上面这个IMAGE_TOIC就是我自己写的。当然你也可以使用一些系统提供的。比如你启动了激光雷达,不论是仿真Gazebo中的还是真的激光雷达(如rplidar),那你就可以订阅“/scan”这个话题。

 

2000代表我们一次性可以缓存多少消息(暂时没发现这个数字对我的程序会带来很大的影响,我经常写成1),最后那个就是回调函数了。

 

imageCallback

对于imageCallback的实现需要说一下。ROS中,imageCallback的参数是与你的话题息息相关的,你要跟据订阅的话题来确定参数。一般来说,程序的主要功能也都是在回调函数中实现的。你需要的数据,都是要通过话题订阅的,而订阅了就肯定有回调函数。你可以把一个个回调函数看成是一个个单独的线程。只要你订阅的消息一更新,回调函数就会被调用,对新的数据进行处理,程序就这么不断的进行下去了。这里我们仍旧举例:

 

 

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

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

需要确定的就是这个sensor_msgs::ImageConstPtr和nav_msgs::Odometry::ConstPtr啦!

嗯啊,今天到此结束啦,白白!

          

 

### ROS C++ 回调函数使用方法 在ROS中,回调函数主要用于处理订阅的消息。当节点接收到消息时,会触发相应的回调函数执行特定的操作。为了使回调函数外也能访问到这些数据,通常采用类的方式封装回调逻辑。 #### 类封装回调函数的方法 下面展示了一个基于类的实现方式,在此类内部维护成员变量存储所需的数据: ```cpp class SimpleSubscriber { public: SimpleSubscriber() : nh_(), sub_(nh_.subscribe("chatter", 1000, &SimpleSubscriber::callback, this)) {} private: void callback(const std_msgs::StringConstPtr& msg) { // 更新成员变量以供其他地方使用 received_message_ = *msg; // 可在此处打印接收的信息验证功能正常工作 ROS_INFO_STREAM("I heard: [" << msg->data.c_str() << "]"); } ros::NodeHandle nh_; ros::Subscriber sub_; // 成员变量保存从话题接收到的内容 std_msgs::String received_message_; }; ``` 此代码片段展示了如何利用类结构将回调函数获取的数据赋值给对象属性以便后续使用[^1]。 #### 主循环与 `spinOnce` 方法 为了让程序持续运行并响应新到来的消息,需在一个无限循环里周期性地调用 `ros::spinOnce()` 函数来检查是否有新的消息到达,并相应地调用对应的回调函数: ```cpp int main(int argc, char **argv){ ros::init(argc, argv, "listener"); SimpleSubscriber ss; ros::Rate loop_rate(10); while (ros::ok()){ ros::spinOnce(); loop_rate.sleep(); } } ``` 上述例子中,`while` 循环不断重复直到节点停止(`ros::ok()==false`)为止;每次迭代都会先尝试处理所有等待中的回调请求再休眠一段时间维持固定的更新速率[^2]。 #### 使用 Boost.Bind 进行参数传递 有时希望向回调函数传递额外参数而不仅仅是默认的主题消息本身。这时可以通过Boost库提供的 `boost::bind` 工具完成这一需求。它允许把某些固定值绑定至目标函数签名的一部分位置上从而形成一个新的可调用实体。 例如,如果想要让多个不同的实例监听同一个主题但是各自携带独立的状态信息,则可以在创建订阅器的时候指定带有自定义上下文环境的回调处理器: ```cpp void chatterCallback(const std_msgs::String::ConstPtr& msg, const std::string& prefix){ ROS_INFO("%s I heard: [%s]", prefix.c_str(), msg->data.c_str()); } // 创建带参数的订阅者 sub = n.subscribe("chatter", 1000, boost::bind(chatterCallback, _1, "Custom Prefix")); ``` 这段代码通过 `boost::bind` 将字符串 `"Custom Prefix"` 绑定到了实际调用时第二个参数的位置上去,使得每当有新消息传来时都能带上这个前缀一起输出[^3]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值