Skip to content

Static Remapping [Meta] #450

@sloretz

Description

@sloretz

Feature request

This ticket is meant to track the implementation of static remapping.

Feature description

Static remapping is the ability to remap one name (topic, service, parameter) to another. See the design doc for more info.

Implementation considerations

ROS 2 implementation proposal (work in progress, Feedback is welcome)

TODO

  • PR to ros2/design to update grammar to support URL scheme

Unresolved questions:

  • Can parameters be remapped? If so, what is needed to be compatible with the parameter design? Parameters use . as a separator?

Resolved questions:

  • Does dynamic composition by a roslaunch equivalent need a way to pass rules to RCL after rcl_init(...) has been called?
    • Yes
    • A tool like roslaunch launching dynamically composed nodes needs to have them ignore global arguments
  • Topic name design doc Mentions URL form of names, but the remapping grammar does not consider them.
    • PR to ros2/design updating grammar to support URL form of names
  • Does remapping need to be able to remap a topic but not a service of the same name?
    • Yes
    • Use URL form for this case. If url form not given then assume rule applies to both.
  • How should the ros1 bridge deal with remapping?
    • It should bypass remap rules.

Library Responsibilities

  • rcl responsible for command line parsing and name remapping
  • rmw libraries are completely ignorant of remapping
  • clients like rclcpp and rclpy rely on rcl to do remapping transparently, but have options to bypass it for special cases (ros1 bridge)

High level rcl implementation

  • rcl offers an API for parsing command line arguments
    • rcl_init() parses command line arguments and stores the results globally
    • A node can be given its own arguments and told to either override or ignore the global rules completely
  • Remapping is applied to names transparently in most rcl_* functions
  • Names used in graph.h functions are not remapped, since those functions are used for introspection of the system.

Low level rcl implementation

rcl type changes

  • rcl_node_options_t
    • Add field bool use_global_arguments;. True means global remapping rules (parsed by rcl_init() are applied. False means only FQN expansion/substitution and node specific remap rules are applied.
  • Add rcl_arguments_t
    • Output of parsing CLI arguments
    • Includes a list of remap rules

New rcl functions

  • rcl_arguments_t * rcl_parse_arguments(int argc, char ** argv, rcl_allocator_t * alloc)
    • Parses arguments and returns a structure that includes a list of remap rules
  • char * rcl_remap_node_name(rcl_node_t * node, char * name, rcl_allocator_t * alloc)
    • Remaps from one node name to another (__node:=new_nodename)
  • char * rcl_remap_namespace(rcl_node_t * node, char * namespace, rcl_allocator_t * alloc)
    • Remaps from one namespace to another (__ns:=/new/namespace)
  • char * rcl_remap_name(rcl_node_t * node, char * name, rcl_allocator_t * alloc)
    • Given an expanded name (rcl_expand_topic_name(...) must be called first), return what it would be remapped to
    • node argument necessary because rules can be node specific.
    • Remapping rules are tested in the order they were given on the command line, and stops at the first matching rule.

Behavior of existing rcl functions

  • rcl_init()
    • Parses remapping rules from command line arguments
    • stores the result of parsing in a global instance of rcl_arguments_t
  • rcl_node_get_default_options()
    • returns options with use_global_arguments = true.
  • rcl_expand_topic_name(...)
    • Unchanged. This function is responsible for substitutions and FQN expansion. Remapping takes place afterwards.
  • rcl_node_init(...)
    • Implementation uses rcl_get_remap_node_name() and rcl_get_remap_namespace() on supplied node name and namespace
  • rcl_client_init(...), rcl_publisher_init(...), rcl_service_init(...), rcl_subscription_init(...)
    • Implementation uses rcl_remap_name(...) on the supplied service/topic name
  • rcl_client_get_service_name(...), rcl_publisher_get_topic_name(...), rcl_service_get_service_name(...), rcl_subscription_get_topic_name(...)
    • Returns the remapped name. The documentation on these functions already says as much
  • rcl_get_topic_names_and_types(...)
    • This is a graph function used for introspection. The returned names are not remapped before being returned.
  • rcl_count_publishers(...), rcl_count_subscribers(...)
    • This is a graph function used for introspection. The supplied name is not remapped internally.

Low level rclcpp implementation

  • rclcpp::expand_topic_or_service_name()
    • Logic unchanged. Add to documentation that returned name does not include any remapping.
  • rclcpp::Node::Node(...) and rclcpp::NodeBase::NodeBase(...)
    • Add another new constructor with rclcpp::Arguments. Node passes this through to NodeBase which sets options.use_global_arguments and rcl_arguments_t when calling rcl_node_init().
  • rclcpp::NodeGraph::get_topic_names_and_types(), rclcpp::NodeGraph::get_topic_names_and_types()
    • Document that these are the actual names used, and attempts to create pubs/subs using these names may not work depending on whether those names match any remapping rules.
  • rclcpp::NodeGraph::count_publishers(...), rclcpp::NodeGraph::count_publishers(...)
    • Document that the topic name passed in is not automatically remapped, and users must remap them prior to passing them in if that is what they want info on.
  • rclcpp::NodeBase::remap_name(const std::string & name)
    • Remaps a name, doing expansion internally

Low level rclpy implementation

  • rclpy_create_node(...)
    • Add argument for cli_args, use_global_arguments
  • Node.__init__(...)
    • Add keyword arugments cli_args=None, use_global_arguments=True

Additional Info

Ros 1 bridge handling of remapping

Currently dynamic_bridge passes all command line arguments to both ros::init and rclcpp::init. Say the bridge is supplied a command line argument /foo/bar:=/fiz/buz. There is a ros1 node with a publisher on /foo/bar, and a ros2 subscriber on /foo/bar. The bridge will attempt to create a ros1 subscriber and a ros2 publisher, but the names will be remapped so the bridge is subscribed to the ros1 topic /fiz/buz and publishing to the ros2 topic /fiz/buz.

To solve this the dynamic_bridge executable will explicitly asks for names to not be remapped

  • Disables remapping of names when creating publishers, subscribers, clients and services
    • ROS 1 by using NodeHandle specific remappings by creating a node handle with a remap rule to remap a topic to itself. This will prevent any rules passed on the command line from applying to it
    • ROS2 by setting remap = false in rcl_*_options_t to disable automatic name remapping
How was remapping implemented in ROS 1?

roscpp stores global remapping rules (from command line arguments or passed via ros::init()) in two global variables. These variables are written to only once; it happens during library initialization. One variable stores the remappings before expanding relative names to fully qualified names (unresolved), while the other stores the same remappings after expansion (resolved).

The unresolved remappings are only used to implement searchParam. Since it is not known what namespace the param should be found in, relative name remapping will change the relative parameter name being searched for (TODO if there is a rule from a relative name to a fully qualified name that matches the parameter being searched for, what will the master do when told to search with a fully qualified parameter)?

Remapping rules can also be passed into a ros::NodeHandle via its constructor. Any name created via this node handle is first checked against the remappings given to the constructor. If none match then the global rules are checked.

The name remappings are evaluated when:

rospy also stores global remappings into two global variables with the same meaning as in roscpp. All remappings in rospy are global. It does not have an equivalent to NodeHandle. Remappings either must come from the command line, or they must be given as if they were command line arguments to the argv argument of rospy.init_node. (TODO verify name remappings being evaluated at places equivalently to roscpp)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions