Skip to content
This repository was archived by the owner on May 31, 2025. It is now read-only.
This repository was archived by the owner on May 31, 2025. It is now read-only.

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

@peci1

Description

@peci1

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions