2

This question comes on the heels of this question

In the last question I learned how to use an initializer list to solve my issue, but working with ros::Subscriber is requiring a different solution.

I'm dealing with a callback in this scenario. If I leave the callback as a standalone function then the program runs but I have no access to class members and methods inside the function which defeats the purpose. Here is my standalone callback:

void setPRYCallback( const std_msgs::Empty& toggle_msg) {}

Once I move this into my class is when I encounter the error.

steps to implementing into class

// add member variable for callback
protected:
  void setPRYCallback( const std_msgs::Empty& );

...

// ass method
void ROSController::setPRYCallback( const std_msgs::Empty& toggle_msg) {}

...

// set initializer list
ROSController::ROSController() : sub("setPRY", &setPRYCallback )

How do I thwart this error while keeping my callback as a class method?

Program with Standalone Function Callback (program runs)

#include <ros.h> // https://github.com/ros-drivers/rosserial/blob/jade-devel/rosserial_arduino/src/ros_lib/ros.h
#include <std_msgs/Empty.h>

class ROSController {
  protected:
    ros::Subscriber<std_msgs::Empty> sub;
    ros::NodeHandle _nh;
  public:
    void loop();
    ROSController();
};

void setPRYCallback( const std_msgs::Empty& toggle_msg) {}

ROSController::ROSController()  {
  this->_nh.initNode();
  this->_nh.subscribe(sub);
}

void ROSController::loop() {
  this->_nh.spinOnce();
  delay(1000);
}

Program with Method Callback (program fails)

#include <ros.h> // https://github.com/ros-drivers/rosserial/blob/jade-devel/rosserial_arduino/src/ros_lib/ros.h
#include <std_msgs/Empty.h>

class ROSController {
  protected:
    ros::Subscriber<std_msgs::Empty> sub;
    ros::NodeHandle _nh;
    void setPRYCallback( const std_msgs::Empty& );
  public:
    void loop();
    ROSController();
};

void ROSController::setPRYCallback( const std_msgs::Empty& toggle_msg) {}

ROSController::ROSController() : sub("setPRY", &setPRYCallback )  {
  this->_nh.initNode();
  this->_nh.subscribe(sub);
}

void ROSController::loop() {
  this->_nh.spinOnce();
  delay(1000);
}

arduino mega

3

2 Answers 2

2

When you move the setPRUCallback function into your class you change the prototype (well, C++ changes the prototype) from:

void setPRYCallback( const std_msgs::Empty& toggle_msg) {}

to:

void setPRYCallback( ROSController *this, const std_msgs::Empty& toggle_msg) {}

That is now not what the callback registering function expects, and so it breaks.

By making the method static it removes that *this parameter, but also means that the function can only access static data within your class (variables also marked static) and there is only one copy of the function (and static variables) shared between all instances of the class (maybe not what you want).

2

If you define instance as a global value, how about to set callback with using lambda expression as variable of constructor.

#include <ros.h>
#include <std_msgs/Empty.h>

class ROSController {
  protected:
    ros::Subscriber<std_msgs::Empty> sub;
    ros::NodeHandle nh;
  public:
    ROSController(void (*staticPRYCallback)(const std_msgs::Empty& msg));
    void begin();
    void loop();
    void setPRYCallback( const std_msgs::Empty& );
};

void ROSController::setPRYCallback(const std_msgs::Empty& toggle_msg) {}

ROSController::ROSController(void (*staticPRYCallback)(const std_msgs::Empty& msg))
  : sub("setPRY", staticPRYCallback )  {
}

void ROSController::begin() {
  nh.initNode();
  nh.subscribe(sub);
}

void ROSController::loop() {
  nh.spinOnce();
}

ROSController rosController([](const std_msgs::Empty& msg){
  rosController.setPRYCallback(msg);
});

void setup() {
  rosController.begin();
}

void loop() {
  rosController.loop();
  delay(1000);
}

Reference (A post of my blog in Japanese)
https://asukiaaa.blogspot.com/2020/09/define-cpp-callback-for-class-value-with-using-lambda-as-a-variable.html

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.