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

[roscpp] Get package name from argv vector

asked 2020-01-10 06:06:51 -0600

d.fenucci gravatar image

updated 2020-01-10 08:39:26 -0600

Hello everyone,

as per the title of the post, I am looking for a method able to get the package name from the argv vector inside my ROS node implementation, bearing in mind that it is my plan to always use the roslaunch utility to run the executable.

As far as I have seen, roslaunch converts the line of the launch file:

<node pkg="pkg_name" type="exec_name" name="node_name"/>

into the command:

path-to-catkin-ws/devel/lib/pkg_name/exec_name __name:=node_name

which is then used to build the argv parameters vector. Is there any other way to get the package name other than extracting it from the string contained in argv[0]?

EDIT

I'll try to explain briefly the reason why I need this. My working group is in the process of refactoring some code in our system. In particular, we have two packages, say base_pkg and derived_pkg, where the latter depends on the former.

The package base_pkg provides a library containing a class, say MyROSNodeInterface, which defines the interface for the ROS nodes we are developing in our system. The package derived_pkg contains a class, say MyROSNode, which implements an actual ROS node inheriting from the MyROSNodeInterface class.

The MyROSNodeInterface class implements some functionalities that we want all the actual nodes to have in common, so we want to be able to have access to information about the derived class, such as the package name, in the base one.

In the legacy version of the code, these functionalities were implemented in the header file of the class MyROSNodeInterface using ROS defines such as ROS_PACKAGE_NAME. This file was then included in the file MyROSNode.h and compiled when compiling the package derived_pkg. In this case everything worked fine, as the compile-time constants assumed the values specified in the compilation of derived_pkg, e.g. ROS_PACKAGE_NAME=derived_pkg.

Now, we want to refactor the implementation of the class MyROSNodeInterface in header file and implementation file. In this case, the compile-time constants will be used in the MyROSNodeInterface.cpp file, which will only be compiled when the base_pkg is compiled. In this case, the compile-time constants will assume the values given during the compilation of base_pkg, e.g. ROS_PACKAGE_NAME=base_pkg.

The only way that came to my mind to solve this problem is to add the all the additional information about the actual node, such as the package name, in the interface of the MyROSNodeInterface class, but this would require a change in the code of MyROSNode (and all the other actual nodes) to pass an additional parameter to the base class constructor. Since at the moment the interface of the class MyROSNodeInterface is the following:

class MyROSNodeInterface {
    MyROSNodeInterface(int argc, char **argv, const std::string& node_name);

    // Other interface methods
};

I was wondering whether it is possible to retrieve at least the package name from the argv vector.

I hope this helps to understand better the problem.

edit retag flag offensive close merge delete

Comments

There should be no need to parse argv yourself.

The ros::this_node namespace contains a function get_name() which:

Returns the name of the current node.

gvdhoorn gravatar image gvdhoorn  ( 2020-01-10 06:34:57 -0600 )edit

Thank you for replying. That function returns the node name (node_name in the example), not the package name (pkg_name). Am I wrong?

d.fenucci gravatar image d.fenucci  ( 2020-01-10 06:37:28 -0600 )edit
1

Ah, you're right. I misread your question.

In that case, your question is a duplicate of #q254330.

As to your question: I don't believe there is API provided for this.

Relying on the package name to be part of the path to the binary is probably rather brittle, as it doesn't always have to be the case it's present.

gvdhoorn gravatar image gvdhoorn  ( 2020-01-10 06:39:24 -0600 )edit

Thanks, I'll follow it then. I though mine was a bit more specific than that one, that's why I opened a new one. Apologies if I was wrong

d.fenucci gravatar image d.fenucci  ( 2020-01-10 06:42:20 -0600 )edit

Yes, I don't like it either and I understand your concern. In my mind, I would always rely on roslaunch to run the node, and since you always need to provide the package name as a parameter in the launch file, I thought it could always be retrieved somehow. I know it sounds a silly problem, but it is just the last bit in a bigger matter. Maybe I will add this to the question for completeness.

d.fenucci gravatar image d.fenucci  ( 2020-01-10 06:51:57 -0600 )edit

Do you want to do this dynamically btw, or would a compile-time option be acceptable?

And also: please explain why you want the name of the package. We may be discussing an xy-problem.

gvdhoorn gravatar image gvdhoorn  ( 2020-01-10 06:55:34 -0600 )edit

Ok, I'll edit the post now and try to explain what I'm trying to solve

d.fenucci gravatar image d.fenucci  ( 2020-01-10 07:04:02 -0600 )edit

2 Answers

Sort by ยป oldest newest most voted
1

answered 2020-01-10 07:25:19 -0600

gvdhoorn gravatar image

updated 2020-01-11 04:15:28 -0600

With the risk of answering an xy-problem: the package name is for roscpp based nodes is passed as a compile time constant.

An example gcc command line for an arbitrary node:

/usr/lib/ccache/c++ -DROSCONSOLE_BACKEND_LOG4CXX -DROS_BUILD_SHARED_LIBS=1 -DROS_PACKAGE_NAME=\"my_pkg\" ...

Note the ROS_PACKAGE_NAME here, set to my_pkg in this case.

I believe this is the only time roscpp nodes have access to the name of the package they are hosted in.


Edit: after your edit: I'm not entirely sure I completely understand what you are describing, but afaik there is no way to conclusively determine in which package a node is at runtime.

At compile-time this is easier, as we can ask CMake to add definitions to the compilation flags. This is what ROS_PACKAGE_NAME does, and which you already appeared to be using before the refactor you describe.

I would perhaps suggest to generate a .h which gets included in your derived class and which contains a std::string constand which is used to pass the package name to the ctor of your base node class (ie, via the node_name argument). This way, the package name would be set at build time of the derived class, and the super class would still be able to access it.

Even after your edit I don't really understand why the package name is needed specifically, but I'm sure you have valid reasons.

edit flag offensive delete link more

Comments

I couldn't actually find where this is added, other than some old rosbuild CMake infrastructure.

@Dirk Thomas : would you know?

gvdhoorn gravatar image gvdhoorn  ( 2020-01-10 07:48:20 -0600 )edit

Thank you very much for your help, and sorry if I caused waste of time. Try to read my edit, hoping I have been clear enough in explaining the context

d.fenucci gravatar image d.fenucci  ( 2020-01-10 08:41:53 -0600 )edit

I believe that this is the correct approach. But it shouldn't rely on the ROS_PACKAGE_NAME but another custom compile flag that you should use. The package name is a very fragile way to differentiate behavior. And would completely break if you say, merged the two implementations into another package. Or more likely created a 3rd version. If this is something that you're configuring on, it should be setup to be a configuration variable for what you're abstracting.

tfoote gravatar image tfoote  ( 2020-01-10 18:07:59 -0600 )edit
0

answered 2021-12-01 08:28:43 -0600

harshal gravatar image

In the case of using a launch file for the node specifically, could you not just pack the pkg name into an arg for the launch file, plug in the arg in the pkg field, and perhaps set a param with the value of the same arg? Something along the lines of ...

<arg name="pname" default="pkg_name" />
<node pkg="$(arg pname)" type="node" name="my_node output="screen" />
<param name="pname" type="string" value="$(arg pname)" />

And then read the value off of the param server?

I could very well be way off in understanding the question as well!

edit flag offensive delete link more

Question Tools

Stats

Asked: 2020-01-10 06:06:51 -0600

Seen: 1,281 times

Last updated: Dec 01 '21