title: ROS class method callback error
body: <p>I am banging my head on this 1 error. I have made 3 files out of which 1 is a main.cpp, 2nd is a .cpp file and the 3rd is a .hpp code file.
  For some reason the subscriber callback function is giving me an error when I am trying to call it from a class method. The code is as follows:</p>
  
  <p>File 1: main.cpp</p>
  
  <pre><code>#include "ControlTurtlebot.hpp"
  
  int main(int argc, char **argv){
  
  //initialize the ROS node
  ros::init(argc, argv, "free_space_navigation_node");
  ros::NodeHandle n;
  
  ControlTurtlebot obj;
  
  //subscribe to the odometry topic to get the position of the robot
  obj.pose_subscriber = n.subscribe("/odom", 10, &amp;ControlTurtlebot::poseCallback, &amp;obj);
  //register the velocity publisher
  obj.pub =n.advertise&lt;geometry_msgs::Twist&gt;("mobile_base/commands/velocity", 1000);
  
  ros::spinOnce();
  ros::Rate loop(1);
  loop.sleep();loop.sleep();loop.sleep();//loop.sleep();loop.sleep();
  ros::spinOnce();
  
  while (ros::ok()){
      ros::spinOnce();loop.sleep();
      printf("robot initial pose: (%.2f, %.2f, %.2f)\n", obj.turtlebot_odom_pose.pose.pose.position.x, obj.turtlebot_odom_pose.pose.pose.position.y, obj.radian2degree(tf::getYaw(obj.turtlebot_odom_pose.pose.pose.orientation)));
  
      double velocity = 0.3;
  
      obj.moveShape(1.0, 3, 120, velocity);
  
      //exercise: try to remove the ros::SpinOnce() and observe and comment the result
      ros::spinOnce();loop.sleep();ros::spinOnce();
      printf("robot final pose: (%.2f, %.2f, %.2f)\n", obj.turtlebot_odom_pose.pose.pose.position.x, obj.turtlebot_odom_pose.pose.pose.position.y, obj.radian2degree(tf::getYaw(obj.turtlebot_odom_pose.pose.pose.orientation)));
      return 0;
  }
  
  return 0;
  </code></pre>
  
  <p>}</p>
  
  <p>And the other file is:</p>
  
  <p>File 2: ControlTurtlebot.hpp</p>
  
  <pre><code>#pragma once
  
  #ifndef INCLUDE_CONTROLTURTLEBOT_HPP_
  #define INCLUDE_CONTROLTURTLEBOT_HPP_
  
  #include "ros/ros.h"
  #include "geometry_msgs/Twist.h"
  #include "sensor_msgs/LaserScan.h"
  #include "nav_msgs/Odometry.h"
  #include "tf/tf.h"
  #include &lt;tf/transform_listener.h&gt;
  #include &lt;fstream&gt;
  
  class ControlTurtlebot {
  
  
    public:
  
    #define ANGULAR_VELOCITY_MINIMUM_THRESHOLD 0.4
    #define pi 22/7
  
    //declare publishers
    ros::Publisher pub;
    //declare subscribers
    ros::Subscriber pose_subscriber;
    //global variable to update the position of the robot
    nav_msgs::Odometry turtlebot_odom_pose;
  
    ros::NodeHandle n;
  
  
    //callback function for the /odom topic to update the pose
    void poseCallback(const nav_msgs::Odometry::ConstPtr&amp; pose_message);
  
  
  
    //the function that makes the robot moves forward and backward
    void move_linear(double speed, double distance, bool isForward);
  
    //the function that makes the robot rotates left and right
    double rotate(double ang_vel, double angle_radian, bool isClockwise);
  
    double degree2radian(double degreeAngle);
    double radian2degree(double radianAngle);
  
    void moveShape(double sideLength, double totalSides, double angle, double velocity);
  
  };
  
  #endif
  </code></pre>
  
  <p>`
  And the last file is:</p>
  
  <p>File 3: ControlTurtlebot.cpp </p>
  
  <pre><code>#include "ControlTurtlebot.hpp"
  
  
  
  void ControlTurtlebot::poseCallback(const nav_msgs::Odometry::ConstPtr&amp; pose_message){
  
  turtlebot_odom_pose.pose.pose.position.x=pose_message-&gt;pose.pose.position.x;
  turtlebot_odom_pose.pose.pose.position.y=pose_message-&gt;pose.pose.position.y;
  turtlebot_odom_pose.pose.pose.position.z=pose_message-&gt;pose.pose.position.z;
  
  turtlebot_odom_pose.pose.pose.orientation.w=pose_message-&gt;pose.pose.orientation.w;
  turtlebot_odom_pose.pose.pose.orientation.x=pose_message-&gt;pose.pose.orientation.x;
  turtlebot_odom_pose.pose.pose.orientation.y=pose_message-&gt;pose.pose.orientation.y;
  turtlebot_odom_pose.pose.pose.orientation.z=pose_message-&gt;pose.pose.orientation.z;
  
  }
  
  
  
  void ControlTurtlebot::moveShape(double sideLength, double totalSides, double angle, double velocity){
      for (int i=0;i&lt;totalSides;i++){
          move_linear(velocity, sideLength, true);
          rotate (velocity, degree2radian(angle), true);
      }   
  }
  
  
  void ControlTurtlebot::move_linear(double speed, double distance, bool isForward){
      //delcare a Twist message to send velocity commands
      geometry_msgs::Twist VelocityMessage;
      //initial pose of the turtlebot before start moving
      nav_msgs::Odometry initial_turtlebot_odom_pose;
  
      //set the linear velocity to a positive value if isFoward is true
      if (isForward)
          VelocityMessage.linear.x =abs(speed);
      //all velocities of other axes must be zero.
      VelocityMessage.linear.y = VelocityMessage.linear.z =VelocityMessage.angular.x =VelocityMessage.angular.y =VelocityMessage.angular.z =0;
  
      double distance_moved = 0.0;
      ros::Rate loop_rate(10); // we publish the velocity at 10 Hz (10 times a second)
  
      //we update the initial_turtlebot_odom_pose using the turtlebot_odom_pose global variable updated in the callback function poseCallback
      initial_turtlebot_odom_pose = turtlebot_odom_pose;
  
      do{
          pub.publish(VelocityMessage);
          ros::spinOnce();
          loop_rate.sleep();
          distance_moved = sqrt(pow((turtlebot_odom_pose.pose.pose.position.x-initial_turtlebot_odom_pose.pose.pose.position.x), 2) +
              pow((turtlebot_odom_pose.pose.pose.position.y-initial_turtlebot_odom_pose.pose.pose.position.y), 2));
  
      }while((distance_moved&lt;distance)&amp;&amp;(ros::ok()));
  //finally, stop the robot when the distance is moved
      VelocityMessage.linear.x =0;
      pub.publish(VelocityMessage);
  }
  
  
  
  double ControlTurtlebot::rotate(double angular_velocity, double radians,  bool clockwise)
  {
  
  //delcare a Twist message to send velocity commands
  geometry_msgs::Twist VelocityMessage;
  //declare tf transform listener: this transform listener will be used to listen and capture the transformation between
  // the odom frame (that represent the reference frame) and the base_footprint frame the represent moving frame
  tf::TransformListener TFListener;
  //declare tf transform
  //init_transform: is the transformation before starting the motion
  tf::StampedTransform init_transform;
  //current_transformation: is the transformation while the robot is moving
  tf::StampedTransform current_transform;
  //initial coordinates (for method 3)
  nav_msgs::Odometry initial_turtlebot_odom_pose;
  
  double angle_turned =0.0;
  
  //validate angular velocity; ANGULAR_VELOCITY_MINIMUM_THRESHOLD is the minimum allowed
  angular_velocity=((angular_velocity&gt;ANGULAR_VELOCITY_MINIMUM_THRESHOLD)?angular_velocity:ANGULAR_VELOCITY_MINIMUM_THRESHOLD);
  
  while(radians &lt; 0) radians += 2*pi;
  while(radians &gt; 2*pi) radians -= 2*pi;
  
  //wait for the listener to get the first message
  TFListener.waitForTransform("base_footprint", "odom", ros::Time(0), ros::Duration(1.0));
  
  //record the starting transform from the odometry to the base frame
  TFListener.lookupTransform("base_footprint", "odom", ros::Time(0), init_transform);
  
  //the command will be to turn at 0.75 rad/s
  VelocityMessage.linear.x = VelocityMessage.linear.y = 0.0;
  VelocityMessage.angular.z = angular_velocity;
  if (clockwise) VelocityMessage.angular.z = -VelocityMessage.angular.z;
  
  //the axis we want to be rotating by
  tf::Vector3 desired_turn_axis(0,0,1);
  if (!clockwise) desired_turn_axis = -desired_turn_axis;
  
  ros::Rate rate(10.0);
  bool done = false;
  while (!done )
  {
      //send the drive command
      pub.publish(VelocityMessage);
      rate.sleep();
      //get the current transform
      try
      {
          TFListener.waitForTransform("base_footprint", "odom", ros::Time(0), ros::Duration(1.0));
          TFListener.lookupTransform("base_footprint", "odom", ros::Time(0), current_transform);
      }
      catch (tf::TransformException ex)
      {
          ROS_ERROR("%s",ex.what());
          break;
      }
      tf::Transform relative_transform = init_transform.inverse() * current_transform;
      tf::Vector3 actual_turn_axis = relative_transform.getRotation().getAxis();
      angle_turned = relative_transform.getRotation().getAngle();
  
      if (fabs(angle_turned) &lt; 1.0e-2) continue;
      if (actual_turn_axis.dot(desired_turn_axis ) &lt; 0 )
          angle_turned = 2 * pi - angle_turned;
  
      if (!clockwise)
          VelocityMessage.angular.z = (angular_velocity-ANGULAR_VELOCITY_MINIMUM_THRESHOLD) * (fabs(radian2degree(radians-angle_turned)/radian2degree(radians)))+ANGULAR_VELOCITY_MINIMUM_THRESHOLD;
      else
          if (clockwise)
              VelocityMessage.angular.z = (-angular_velocity+ANGULAR_VELOCITY_MINIMUM_THRESHOLD) * (fabs(radian2degree(radians-angle_turned)/radian2degree(radians)))-ANGULAR_VELOCITY_MINIMUM_THRESHOLD;
  
      if (angle_turned &gt; radians) {
          done = true;
          VelocityMessage.linear.x = VelocityMessage.linear.y = VelocityMessage.angular.z = 0;
          pub.publish(VelocityMessage);
      }
  
  }
  if (done) return angle_turned;
  return angle_turned;
  }
  
  /* makes conversion from radian to degree */
  double ControlTurtlebot::radian2degree(double radianAngle){
  return (radianAngle*57.2957795);
  }
  
  
  /* makes conversion from degree to radian */
  double ControlTurtlebot::degree2radian(double degreeAngle){
      return (degreeAngle/57.2957795);
  }
  </code></pre>
  
  <p>And the error that I get on using the above mentioned subscriber callback in main.cpp file is:</p>
  
  <blockquote>
    <p>CMakeFiles/free_space_navigation_node.dir/src/main.cpp.o: In function
    <code>main': main.cpp:(.text+0x400): undefined reference to
    </code>ControlTurtlebot::poseCallback(boost::shared_ptr</p>
    
    <blockquote>
      <p>const> const&amp;)' main.cpp:(.text+0x5f0): undefined reference to <code>ControlTurtlebot::radian2degree(double)' main.cpp:(.text+0x674):
      undefined reference to</code>ControlTurtlebot::moveShape(double, double,
      double, double)' main.cpp:(.text+0x6b1): undefined reference to
      `ControlTurtlebot::radian2degree(double)' collect2: error: ld returned
      1 exit status
      toy_robot/CMakeFiles/free_space_navigation_node.dir/build.make:118:
      recipe for target
      '/home/viki/catkin_ws/devel/lib/toy_robot/free_space_navigation_node'
      failed make[2]: <strong>*
      [/home/viki/catkin_ws/devel/lib/toy_robot/free_space_navigation_node]
      Error 1 CMakeFiles/Makefile2:2938: recipe for target
      'toy_robot/CMakeFiles/free_space_navigation_node.dir/all' failed
      make[1]: *</strong> [toy_robot/CMakeFiles/free_space_navigation_node.dir/all]
      Error 2 Makefile:138: recipe for target 'all' failed make: *** [all]
      Error 2</p>
    </blockquote>
  </blockquote>
  
  <p>And if I change the subscribe callback line in main.cpp from:</p>
  
  <pre><code>    obj.pose_subscriber = n.subscribe("/odom", 10, &amp;ControlTurtlebot::poseCallback, &amp;obj);
  </code></pre>
  
  <p>to</p>
  
  <pre><code>    obj.pose_subscriber = n.subscribe("/odom", 10, ControlTurtlebot::poseCallback);
  </code></pre>
  
  <p>So I get an error as follows:</p>
  
  <blockquote>
    <p>error: invalid use of non-static member function ‘void
    ControlTurtlebot::poseCallback(const ConstPtr&amp;)’
        obj.pose_subscriber = n.subscribe("/odom", 10, ControlTurtlebot::poseCallbac
                                                                         ^ toy_robot/CMakeFiles/free_space_navigation_node.dir/build.make:62:
    recipe for target
    'toy_robot/CMakeFiles/free_space_navigation_node.dir/src/main.cpp.o'
    failed make[2]: <strong>*
    [toy_robot/CMakeFiles/free_space_navigation_node.dir/src/main.cpp.o]
    Error 1 CMakeFiles/Makefile2:2938: recipe for target
    'toy_robot/CMakeFiles/free_space_navigation_node.dir/all' failed
    make[1]: *</strong> [toy_robot/CMakeFiles/free_space_navigation_node.dir/all]
    Error 2 Makefile:138: recipe for target 'all' failed make: *** [all]
    Error 2</p>
  </blockquote>
  
  <p>I don't understand what is the problem. I have also tried changing the callfunction definition from void to static void callback(), but it again reverts to the 1st error, similar to when I am using the above-mentioned subscriber method.</p>
  
  <p>Any help would be really appreciated!</p>
  
  <p>Thanks!</p>