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

How to keep a class "alive" (...and passing the same NodeHandle) ?

asked 2014-12-06 08:43:21 -0600

Andromeda gravatar image

updated 2014-12-06 08:43:47 -0600

Hi, here the minimal example I could create to explain a problem with my program which is splitted into 2 classes. One class creates an istance of the second one:

Let's start with the main file:

#include <ros/ros.h>
#include "include/foo.h"
#include "include/bar.h"
int main ( int argc, char **argv ) {
   ros::init( argc, argv, "main_node" );
   ros::NodeHandle nh;
   ros::NodeHandle nh_private( "~" );

    boost::scoped_ptr<Foo> trajectory( new Foo( nh, nh_private ) );
    ROS_INFO( "Waiting some seconds..." ); // Just for fun
    ros::Duration(3.0).sleep();

    return 0;
}

The class Foo has a constructor which initialize the class and later, thtough an internal function, create an istance of the second class.

class Foo {
    private:
     /* private variables here */

    private:
    void initParam();
    /* of course here there are much more functions already implemented.... */

}

in initParam() I have the following creation of the last class:

void initParam()  // A method defined in Foo
{
 /* code code code...*/
  boost::scoped_ptr<Bar> way( new Bar( nh_ ) ); // <- !!!! Here is the same NodeHdandle of the master class pased by VALUE
  way->amIAlive(); // <- Yes it is....the call is working
  ROS_INFO( "Getting a random value: %6.4f", way->generateValues() ) // <-working perfectly here too
  /*...*/
}

and lately the class Bar in which I have defined a timer to publish some data regularly:

class Bar {
   Bar::Bar( ros::NodeHandle nh ): nh_(nh) {

    marker_pub_ = nh_.advertise<visualization_msgs::MarkerArray>( "visualization_marker_array", 10 ); // To publish data on RViz

  ros::Timer timeloop_ = nh_.createTimer( ros::Duration( set_duration_time_ ), &Bar::publishPoints, this ); // Nothing...here doesn't publish anything... Why!?!?

void Bar::publishPoints( const ros::TimerEvent& event ) const {
    /* publish the markers */
    marker_pub_.publish( marker_array_ );
}
}

So guys...the problem. The problem is the second class (Bar) gets the node passed by value but doesn't publish anything. Doing:

$ rostopic echo /visualization_marker_array

stucks all the time. Other functions implemented in the class are working correctly and I get the calculation for the points in the right way. What could be the reason?

I put some comments in the constrctors and destructors of both classes to see where could be the problem and here is the output:

me@YE-166:~/workspace_ros$ rosrun my_pkg my_prog
[ INFO] [1417875069.502609530]: Constructor of the Foo class has been called
[ INFO] [1417875069.505375417]: Constructor of the Bar class has been called
[ INFO] [1417875069.505837985]: Valid number of requested waypoints
[ INFO] [1417875072.506157010]: Number of points: 7
[ WARN] [1417875072.506273683]: Calling Destructor of the Bar's class...
[ INFO] [1417875072.508900594]: Waiting some seconds...
[ WARN] [1417875075.509383455]: Calling Destructor of the Foo's Class...
me@YE-166:~/workspace_ros$

Seems to working correctly but I suppose (and it is my opinion) that the class Bar doesn't have the time to publish data on the topic. Fpor that reasons I put a waiting function inside of it to give it time. But it doesn't help. The class runs the function Bar::publishPoints() which is time event function and it is suppose to run all the time. But get destroy with the class

2 things I have:

  • I want to be able to publish data ...
(more)
edit retag flag offensive close merge delete

Comments

1

Is there a spin or spinOnce anywhere in your code?

kramer gravatar image kramer  ( 2014-12-06 10:12:06 -0600 )edit

1 Answer

Sort by ยป oldest newest most voted
3

answered 2014-12-06 10:48:38 -0600

paulbovbel gravatar image

As @kramer has pointed out, you have no ros::spin() function in your main, meaning that a) no callbacks get processed and b) main returns immediately, destroying Foo.

Even after adding ros::spin(), Bar will still die earlier than you expect, because it will be destroyed when the initParam function returns.

Please read about lifetime, scope, and blocking on stackoverflow.

edit flag offensive delete link more

Comments

1

For clarity: a Timer uses ROS's callback mechanism for its operation; without a spin, the publishPoints method will never be called.

I totally overlooked Bar's scope and destruction...nice catch, @paulbovbel.

kramer gravatar image kramer  ( 2014-12-06 16:39:08 -0600 )edit

Ok, guys. Thanks. a lot. A didn't know, that a timer has the same callback like messages and topics. About the scope of a class I agree with you, but I was sure that the running timer doesn't let the function to return. The visibility is right, but I misunderstood how a timer is currently working.

Andromeda gravatar image Andromeda  ( 2014-12-07 11:55:57 -0600 )edit

createTimer does return immediately. And then the timer object goes out of scope, so it won't be running anymore. Just like with pub/sub, you need the object to be in scope (i.e. be a member of the class and not just temporary on the heap), and you need ros::spin to process callbacks.

paulbovbel gravatar image paulbovbel  ( 2014-12-07 13:42:52 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2014-12-06 08:43:21 -0600

Seen: 2,145 times

Last updated: Dec 06 '14