【问题标题】:Pass non-static class member callback function to ros::subscriber [duplicate]将非静态类成员回调函数传递给 ros::subscriber [重复]
【发布时间】:2021-07-27 19:23:37
【问题描述】:

我正在尝试编写一个类来处理基于 ROS 的机器人(特别是使用 Arduino IDE 的 ESP32 芯片)的电机控制。

为此,我想实现一个 ROS 串行订阅者,它在收到新消息时调用回调函数。回调函数将消息数据存储在类的实例变量中,因此我可以轻松地与类的其他函数一起使用它。

这使得回调函数非静态,因此我使用std::bind 将其绑定到我的类的特定实例,同时保留消息的占位符。

一个简化的代码示例:

#include <ros.h>
#include <geometry_msgs/Twist.h>

ros::NodeHandle nh;

const char cmd_vel_topic[] = "/cmd_vel"

class MotorControlInterface {

  public:
    // FreeRTOS task to call from main
    void TaskMotorControl(void *pvParameters)
    {    
      ros::Subscriber<geometry_msgs::Twist> twist_sub
      ( 
          // The topic to subscribe to
          cmd_vel_topic,
          // Reference to callback function that is bound to this instance of the class
          &std::bind(&MotorControlInterface::twistCallback, this, std::placeholders::_1),             
      );
      nh.subscribe(twist_sub);
      
      for(;;)
      {
        // Do some stuff with velocity commands
        handleMotorSpeeds();
        vTaskDelay( 10 );
      }
    };

  private:
    // Instance variable I want to store message data in
    double vel_cmd_x;

    // Callback function 
    void twistCallback(const geometry_msgs::Twist& twist_msg)
    {
      // Save velocity command
      vel_cmd_x = twist_msg.linear.x;
    };

};

我得到的错误信息:

Arduino: 1.8.15 (Linux), Board: "ESP32 Dev Module, Disabled, Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS), 240MHz (WiFi/BT), QIO, 80MHz, 4MB (32Mb), 921600, None"


/home/ubuntu/Arduino/***/*****.ino: In member function 'void MotorControlInterface::TaskMotorControl(void*)':
*****:83:87: error: taking address of temporary [-fpermissive]
         &std::bind( &MotorControlInterface::twistCallback, this, std::placeholders::_1)
                                                                                       ^
*****:84:7: error: no matching function for call to 'ros::Subscriber<geometry_msgs::Twist>::Subscriber(const char [9], std::_Bind_helper<false, void (MotorControlInterface::*)(const geometry_msgs::Twist&), MotorControlInterface*, const std::_Placeholder<1>&>::type*)'
       );
       ^
In file included from /home/ubuntu/Arduino/libraries/ros_lib/ros/node_handle.h:60:0,
                 from /home/ubuntu/Arduino/libraries/ros_lib/ros.h:38,
                 from /home/ubuntu/Arduino/*****/*****.ino:28:
/home/ubuntu/Arduino/libraries/ros_lib/ros/subscriber.h:107:3: note: candidate: ros::Subscriber<MsgT, void>::Subscriber(const char*, ros::Subscriber<MsgT, void>::CallbackT, int) [with MsgT = geometry_msgs::Twist; ros::Subscriber<MsgT, void>::CallbackT = void (*)(const geometry_msgs::Twist&)]
   Subscriber(const char * topic_name, CallbackT cb, int endpoint = rosserial_msgs::TopicInfo::ID_SUBSCRIBER) :
   ^
/home/ubuntu/Arduino/libraries/ros_lib/ros/subscriber.h:107:3: note:   no known conversion for argument 2 from 'std::_Bind_helper<false, void (MotorControlInterface::*)(const geometry_msgs::Twist&), MotorControlInterface*, const std::_Placeholder<1>&>::type* {aka std::_Bind<std::_Mem_fn<void (MotorControlInterface::*)(const geometry_msgs::Twist&)>(MotorControlInterface*, std::_Placeholder<1>)>*}' to 'ros::Subscriber<geometry_msgs::Twist>::CallbackT {aka void (*)(const geometry_msgs::Twist&)}'
/home/ubuntu/Arduino/libraries/ros_lib/ros/subscriber.h:101:7: note: candidate: constexpr ros::Subscriber<geometry_msgs::Twist>::Subscriber(const ros::Subscriber<geometry_msgs::Twist>&)
 class Subscriber<MsgT, void>: public Subscriber_
       ^
/home/ubuntu/Arduino/libraries/ros_lib/ros/subscriber.h:101:7: note:   candidate expects 1 argument, 2 provided
/home/ubuntu/Arduino/libraries/ros_lib/ros/subscriber.h:101:7: note: candidate: constexpr ros::Subscriber<geometry_msgs::Twist>::Subscriber(ros::Subscriber<geometry_msgs::Twist>&&)
/home/ubuntu/Arduino/libraries/ros_lib/ros/subscriber.h:101:7: note:   candidate expects 1 argument, 2 provided

exit status 1
taking address of temporary [-fpermissive]

在我看来,回调函数的std::bind 没有返回我期望的结果,因此引用失败。不过根据this,返回值是一个函数对象。

由于这是我一段时间以来的第一个 C/C++ 项目,我很感谢任何有关如何使其工作的建议。我已经为此花费了好几个小时,并且不确定如何继续,因为错误消息并没有真正帮助我。

解决方案: This solution 作品:

#include <ros.h>
#include <geometry_msgs/Twist.h>

ros::NodeHandle nh;

const char cmd_vel_topic[] = "/cmd_vel"

class MotorControlInterface {

  public:
    MotorControlInterface() 
    : twistSubscriber(cmd_vel_topic, &MotorControlInterface::twistCallback, this)
    {
      ; // Stuff to do in the constructor
    };

    // FreeRTOS task to call from main
    void TaskMotorControl(void *pvParameters)
    {    
      nh.subscribe(twist_sub);

      for(;;)
      {
        // Do some stuff with velocity commands
        handleMotorSpeeds();
        vTaskDelay( 10 );
      }
    };

  private:
    // Instance variable I want to store message data in
    double vel_cmd_x;
    ros::Subscriber<geometry_msgs::Twist, MotorControlInterface> twistSubscriber;

    // Callback function 
    void twistCallback(const geometry_msgs::Twist& twist_msg)
    {
      // Save velocity command
      vel_cmd_x = twist_msg.linear.x;
    };

};

【问题讨论】:

  • 返回错误与其说是错误,不如说是生命周期。如果您不将对象存储在某个地方,该对象几乎会立即超出范围,一旦超出范围,指向它的指针就没有用了。
  • 我尝试将std::bind 的返回值存储到这样的类变量中:std::function&lt;void(geometry_msgs::Twist)&gt; selfTwistCB = std::bind( &amp;MotorControlInterface::twistCallback, this, std::placeholders::_1 );。当我使用对此类变量的引用时,我会遇到以下错误:pastebin。显然我没有为变量选择正确的数据类型?
  • 我有同样的问题,你的解决方案在 Arduino 上对我不起作用,因为编译器不理解语法 ros::Subscriber&lt;geometry_msgs::Twist, MotorControlInterface&gt; twistSubscriber; - 错误:类模板“ros::Subscriber”的参数太多。你是怎么做到的?

标签: c++ arduino callback ros non-static


【解决方案1】:
  • ROS不需要std::bindros::Subscriber构造函数结合使用:对于非静态成员函数ros::NodeHandle::subscribe其实有对应的重载(nh 是您的节点句柄)

    ros::Subscriber<geometry_msgs::Twist> twist_sub = nh.subscribe(cmd_vel_topic, 1, &MotorControlInterface::twistCallback, this);
    
  • rosserial 的语法略有不同(请参阅here

    ros::Subscriber<geometry_msgs::Twist> twist_sub {cmd_vel_topic, &MotorControlInterface::twistCallback, this};
    nh.subscribe(twist_sub);
    

    进一步 - 与 ROS 不同 - boost::function 没有重载,这意味着您根本无法将语法与 boost::bindstd::bind 一起使用。

【讨论】:

  • 感谢您的回复。当我尝试您的解决方案时,我收到此错误:pastebin 检查ros_lib/ros/node_handle.h 时,编译器确实是正确的,并且它不包含重载的构造函数。我在this tutorial 之后创建了ros_lib,并再次完成了这个过程。在创建库期间是否可能需要设置一个标志?
  • @Finn2708 哦,你在使用rosserial 的 Arduino。我手头没有 Arduino,但您应该可以将ros::Subscriber&lt;geometry_msgs::Twist&gt; twist_sub {cmd_vel_topic, &amp;MotorControlInterface::twistCallback, this};nh.subscribe(twist_sub); 结合使用。让我知道这是否有效!
  • 我让它同时工作。我已经链接了我在原始问题中使用的资源。遗憾的是,您建议的解决方案对我不起作用(Error message。对我来说,&amp;MotorControlInterface::twistCallback 的类型似乎与预期的类型不匹配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-18
  • 2011-01-07
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
  • 2019-03-14
  • 1970-01-01
相关资源
最近更新 更多