Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remapping private topics of anonymous nodes works differently in rospy and roscpp #2324

Open
peci1 opened this issue Apr 7, 2023 · 1 comment · May be fixed by #2325
Open

Remapping private topics of anonymous nodes works differently in rospy and roscpp #2324

peci1 opened this issue Apr 7, 2023 · 1 comment · May be fixed by #2325

Comments

@peci1
Copy link
Contributor

peci1 commented Apr 7, 2023

When I launch a node from CLI via rosrun and do not set any name, the nodes with anonymous flag generate a random name.

If I pass a local topic remap (~input:=test), rospy correctly remaps this topic, while roscpp does not.

The problem seems to be in this part of this_node code:

name_ = name;
bool disable_anon = false;
M_string::const_iterator it = remappings.find("__name");
if (it != remappings.end())
{
name_ = it->second;
disable_anon = true;
}
it = remappings.find("__ns");
if (it != remappings.end())
{
namespace_ = it->second;
}
namespace_ = names::clean(namespace_);
if (namespace_.empty() || (namespace_[0] != '/'))
{
namespace_ = "/" + namespace_;
}
std::string error;
if (!names::validate(namespace_, error))
{
std::stringstream ss;
ss << "Namespace [" << namespace_ << "] is invalid: " << error;
throw InvalidNameException(ss.str());
}
// names must be initialized here, because it requires the namespace to already be known so that it can properly resolve names.
// It must be done before we resolve g_name, because otherwise the name will not get remapped.
names::init(remappings);
if (name_.find("/") != std::string::npos)
{
throw InvalidNodeNameException(name_, "node names cannot contain /");
}
if (name_.find("~") != std::string::npos)
{
throw InvalidNodeNameException(name_, "node names cannot contain ~");
}
name_ = names::resolve(namespace_, name_);
if (options & init_options::AnonymousName && !disable_anon)
{
char buf[200];
std::snprintf(buf, sizeof(buf), "_%llu", (unsigned long long)WallTime::now().toNSec());
name_ += buf;
}

It first sets name_ to the init_node() argument, possibly replaces it with __name remap, and then it calls names::init().

However, names::init() calls names::resolve(), which in turn calls this_node::getName():

if (copy[0] == '~')
{
copy = append(this_node::getName(), copy.substr(1));
}

But the name in this_node is only the non-anonymous one - the anonymizing part is appended only after names::init() finishes.

Minimal code showing the problem is this:

#include <ros/ros.h>

int main(int argc, char** argv)
{
  ros::init(argc, argv, "node", ros::init_options::AnonymousName);
  
  ros::NodeHandle nh ("~");
  ROS_ERROR("%s", nh.resolveName("test").c_str());
}

run as node ~test:=a to see the problem. Running with node ~test:=a __name:=t works as expected, because explicit name setting disables the anonymous node behavior.

Please note that running the node via roslaunch and name="$(anon node)" would not trigger this issue as it does not actually trigger the anonymous init option of the node (it directly generates a random name which is passed to the node in __name:= remap).

For comparison, here is the Python code that works correctly:

import rospy

rospy.init_node("node", anonymous=True)
rospy.logerr(rospy.names.resolve_name("~test"))

The solution would be calling names::init() once more after the name mangling is finished. Would that be okay?

@peci1
Copy link
Contributor Author

peci1 commented Apr 9, 2023

Fix provided in #2325.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant