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

Nodehandle destroyed and shutdown the ros node

asked 2014-03-19 18:13:46 -0500

dalishi gravatar image

updated 2016-07-05 06:30:12 -0500

user23fj239 gravatar image

Hi all

I was wondering what would happen to the previously created subscriptions and publications and services after the nodehandle is destroyed? I have experieced such case: create a nodehandle in the constructor of the class and in my main() I just create a object of the class. The constructor will be called when the object is created and the nodehandle will experience starting the node, subscribe and publish, and shutting down the node as the life of circle of the nodehande is within the constructor and after that the nodehandle (lets assume it is the only one nodehandle in this example) will be destroyed and the shutdown() will be invoked.

Will this work? Will the publish and subcribe work in this way below? Thank you all.

Class A {

A

{ ros::NodeHandle private_nh("~"); pub = private_nh.advertise... sub_ = private_nh.subscribe...

}

}

int main()

{

ros::init(...);

A a;

ros::spin();

}

edit retag flag offensive close merge delete

Comments

The nodehandle declared in the constructor should end its life cycle (destroyed) after the constructor function has been successfully executed, which according to the http://wiki.ros.org/roscpp/Overview/Initialization%20and%20Shutdown, the destroy of last nodehandle instance will kill all open subscriptions, publications, service calls, and service servers. Please correct me if I am wrong.

dalishi gravatar image dalishi  ( 2014-03-19 22:24:44 -0500 )edit

3 Answers

Sort by ยป oldest newest most voted
3

answered 2014-03-20 01:09:37 -0500

demmeln gravatar image

You can always make sure there exists another NodeHandle outside of your class, e.g. in the main function, which is initialized before you create the object and lives as long as you want the node to live. However, as @Wolf points out, I see no benefit in not rather storing a node handle as a (private) member of your class and avoid potential bugs of your class depending on the existance of an external node handle.

edit flag offensive delete link more

Comments

Hi demmeln, thanks for your reply. The reason I raised this problem is I have seen NavfnRos as in navfn_ros.cpp of the navigation stack, it declared temporary NodeHandle in the constructor and no other member NodeHandle nor external NodeHandle in the main(), which confused me. I will take your advice.

dalishi gravatar image dalishi  ( 2014-03-20 01:33:00 -0500 )edit
1

answered 2014-03-19 21:24:25 -0500

Wolf gravatar image

Yes this will work. You can create nodehandles anywhere in your process after ros::init. After ros::spin() has finished, your class instance goes out of scope, thereby its destructor (possibly implicitly created by compiler) is called. It will also destruct your member NodeHandle and thereby shutdown subscribers.

edit flag offensive delete link more

Comments

Hi Thanks for your reply. If the nodehandle is a member variable of my class, that would definitely work as you described. However, I want to know the case what if the nodehandle is not a member variable but a temporary variable in a member function like in the constructor as in my example. Thanks.

dalishi gravatar image dalishi  ( 2014-03-19 22:08:44 -0500 )edit
1

I am afraid that won't work. See http://docs.ros.org/hydro/api/roscpp/html/classros_1_1NodeHandle.html Destructor and advertise doc. Why do you not want to have the NodeHandle as private class member?

Wolf gravatar image Wolf  ( 2014-03-20 00:24:14 -0500 )edit

Hi Thanks. I actually write my class in exactly the same as you suggested that is making the NodeHandle as private class member. The reason I raised this post is I have seen many codes in the ros community that did not do like this. For example, that NavfnRos as in navfn_ros.cpp of the navigation stack.

dalishi gravatar image dalishi  ( 2014-03-20 01:24:04 -0500 )edit

that NavfnRos as in navfn_ros.cpp of the navigation stack declared the NodeHandles in the constructor of the class and in the main() there is no other NodeHandle maintained. The same case is in the sbpl_lattice_planner. So this is actually confusing me of the way that how to use the NodeHandles.

dalishi gravatar image dalishi  ( 2014-03-20 01:26:57 -0500 )edit
0

answered 2016-07-05 06:26:10 -0500

user23fj239 gravatar image

updated 2016-07-05 06:26:51 -0500

The first nodeHandle fully initalizes your node, any other nodeHandles constructed along the way (e.g. for another topic, scoping etc) increases the global refrence count. The first nodeHandle sets the count to 1 and starts the node with ros::start() . More info check this link text

I stumbled into the following message, when my last nodehandle ran out of scope and I checked for ros::ok() returning false and chrasing the node having multiple boost threads.

* Error in `/home/user/Downloads/catkin_ws/devel/lib/foo/foo': free(): invalid pointer: 0x00007ffe036a1280 *

In my case I constructed publisher objects having nodehandles and the ros::publisher . This is handy: once the topic is not needed anymore I did let the object run out of scope (or erase it from the object container like vector < pub_obj >) and the destructor of pub_obj got called.
As a solution. Have one nodeHandle right after ros::init and dont let it go out of scope till the main function finishes. So if one of the pub_obj gets destroyed the refrence count decreases only down to 1 not causing the error.

Check this example with scoping: If you compile it with the nodeHandle after the bracket the second ros::ok returns false thus the node being not connected to the ros system. The way it is below returns ok:

//ros headers (most functions of ROS)
#include "ros/ros.h"
#include "std_msgs/String.h"

//c++ headers
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <sstream>
#include <iostream>

using namespace std;

int main(int argc, char** argv) {
  ros::init(argc, argv, "foo");
  std::cout << "published roso1?" <<ros::ok()<< std::endl;
  ros::NodeHandle nh_;

  {
    ros::Publisher chatter_pub;

    chatter_pub = nh_.advertise  <std_msgs::String>("chatter", 100);
    ROS_INFO("advertised chatter");

    std_msgs::String msg;
    std::stringstream ss;
    ss << "hello world ";
    msg.data = ss.str();
    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);
    usleep(50000000);//5s

  } 

  std::cout << "published rosok2?" <<ros::ok()<< std::endl;
}

now lets check it with $ rosrun foo foo

published roso1?1
[ INFO] [1467717888.162157852]: advertised chatter
[ INFO] [1467717888.162239147]: hello world 
published rosok2?1
edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2014-03-19 18:13:46 -0500

Seen: 3,528 times

Last updated: Jul 05 '16