ROS Resources: Documentation | Support | Discussion Forum | Index | Service Status | ros @ Robotics Stack Exchange
Ask Your Question
9

How to pass arguments to/from subscriber callback functions

asked 2011-11-05 07:31:00 -0500

Paul0nc gravatar image

updated 2022-02-23 17:41:26 -0500

130s gravatar image

I'm currently subscribing to the depth image of a Kinect with the following code:

ros::Subscriber sub = nh.subscribe("/camera/depth/image", 3, myDepthViewer);

The callback function, myDepthViewer receives a sensor_msgs image:

void myDepthViewer( const sensor_msgs::ImageConstPtr& image )

So, my question is: how is myDepthViewer being passed the message if it does not appear in the call, and, how would I pass other arguments to it. I'd like to do some processing on the image and pass a result back to main.

Thanks for any advice. Paul.

edit retag flag offensive close merge delete

3 Answers

Sort by ยป oldest newest most voted
10

answered 2011-11-05 16:20:04 -0500

joq gravatar image

A boost shared pointer to the message does appear in the call. That is how you access the message. You can't pass other parameters, because this callback is invoked by ROS whenever a message arrives.

The best way to pass information back to main() is defining a C++ class in your program with the callback as a member function. It can then update class data as messages arrive.

Alternatively, you could update some global data structure. That is not generally a good practice unless your node is small and simple.

edit flag offensive delete link more

Comments

Thanks joq. This was helpful.
Paul0nc gravatar image Paul0nc  ( 2011-11-06 09:31:59 -0500 )edit
joq or anyone: (pardon the basic nature of this question): is it possible to update a global variable in a callback function. When I try this, I get compilation errors that the variable is not defined in the scope of the function. Thanks.
Paul0nc gravatar image Paul0nc  ( 2011-11-06 22:56:15 -0500 )edit
That is a basic C++ language question, not appropriate for this forum. There are good C++ resources on-line: http://www.cplusplus.com/doc/tutorial/variables/
joq gravatar image joq  ( 2011-11-07 01:42:36 -0500 )edit
To repeat, I recommend using class variables rather than global variables.
joq gravatar image joq  ( 2011-11-07 01:43:51 -0500 )edit
3

Nice question. I'm having the same problems/questions. There should be some tutorial for this.

End-Effector gravatar image End-Effector  ( 2015-03-23 09:59:28 -0500 )edit
10

answered 2015-10-22 03:31:16 -0500

NickHock gravatar image

updated 2015-10-22 10:15:07 -0500

There are probably a fair number of ROS users who are learning C++, so the following links may be useful.

For why things are done this way: https://isocpp.org/wiki/faq/pointers-to-members

For the standard library way to solve the problem (note the differences between C++98 and C++11): http://www.cplusplus.com/reference/functional/bind/?kw=bind .

This code works, using boost::bind , though others may suggest better ways:

#include <string>  
#include <iomanip> 
#include <sstream> 
#include <fstream>
#include <functional>

// image subscriber
#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <opencv2/highgui/highgui.hpp>
#include <cv_bridge/cv_bridge.h>
#include <camera_info_manager/camera_info_manager.h>
#include <boost/assign/list_of.hpp>

// opencv2.4
#include <opencv2/core/core.hpp>
#include <opencv2/video/tracking.hpp>
#include <opencv2/imgproc/imgproc.hpp> 

using namespace cv;
using namespace std;
typedef const boost::function< void(const sensor_msgs::ImageConstPtr &)>  callback;

class myImages {
  public:
    cv::Mat myMatImage1;
    sensor_msgs::ImagePtr myMessagePtr;
    void imageCallback(const sensor_msgs::ImageConstPtr& msg );
};

static void wrapper_imageCallback(void* pt2Object, const sensor_msgs::ImageConstPtr& msg);

void myImages::imageCallback(const sensor_msgs::ImageConstPtr& msg )
{
  try
  {
    this->myMatImage1 = cv_bridge::toCvShare(msg, "bgr8")->image;
    cv::imshow("view", this->myMatImage1);
    cv::waitKey(30);
    this->myMessagePtr = cv_bridge::CvImage(std_msgs::Header(), "bgr8", this->myMatImage1).toImageMsg();  
  }
  catch (cv_bridge::Exception& e)
  {
    ROS_ERROR("Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str());
  }
}

static void wrapper_imageCallback(void* pt2Object, const sensor_msgs::ImageConstPtr& msg)
   {
       myImages* mySelf = (myImages*) pt2Object; // explicitly cast to a pointer to class myImages
       mySelf->imageCallback(msg );          // call member
   }

int main(int argc, char **argv)
{
  ros::init(argc, argv, "flow_vision");
  ros::NodeHandle nh;
  cv::namedWindow("view");
  cv::startWindowThread();
  image_transport::ImageTransport it(nh);
  myImages MyImagesObj;
  callback boundImageCallback = boost::bind(&myImages::imageCallback, &MyImagesObj/*&images*/, _1); 
  // "_1" is a place holder for the first (and only) parameter of myImages::imageCallback(const sensor_msgs::ImageConstPtr& msg )
  /*subscribe (
   * const std::string &base_topic,
   * uint32_t queue_size,
   * const boost::function< void(const sensor_msgs::ImageConstPtr &)>       &callback,
   * const ros::VoidPtr &tracked_object=ros::VoidPtr(),
   * const TransportHints &transport_hints=TransportHints()) 
   */
  image_transport::Subscriber sub = it.subscribe("camera/image_raw", 1, boundImageCallback);
  image_transport::Publisher pub = it.advertise("out_flow_vision_image_base_topic", 1);
  ros::Rate loop_rate(15);  //need to increase for video
  while (nh.ok()) {
    pub.publish(MyImagesObj.myMessagePtr);
    ros::spinOnce();
    loop_rate.sleep();
  }
  cv::destroyWindow("view");
}
edit flag offensive delete link more
2

answered 2018-09-23 10:40:20 -0500

shivaang12 gravatar image

I was looking for the same thing and found this link,

http://wiki.ros.org/roscpp_tutorials/...

Hope it helps!

edit flag offensive delete link more

Question Tools

4 followers

Stats

Asked: 2011-11-05 07:31:00 -0500

Seen: 31,284 times

Last updated: Feb 23 '22