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

Two nodes with common base class declaring a namespaced service path

asked 2015-04-28 19:51:17 -0500

j12y gravatar image

I want to be able to use a base class for declaring a service that separate nodes can utilize. I thought I might be able to remap this in a launch file, but I must be doing something wrong.

To illustrate, imagine this class hierarchy:

class Base(object):
   def __init__(self):
      service = rospy.Service('get_state', ...) 

class Node1(Base):
  def __init__(self):
      super(Node1, self).__init__()

class Node2(Base):
  def __init__(self):
      super(Node2, self).__init__()

My hope would be that I could call:

$ rosservice my_pkg /node1/get_state
$ rosservice my_pkg /node2/get_state

Instead I have a service named "/get_state" and a collision.

I have tried a few things:

  1. re-order so init_node is called before super of the base class
  2. use ~get_state but this results in '/unnamed/get_state' which is still a collision
  3. Use a launch file to remap the namespace

This last attempt included a launch file like this:

<node pkg="my_pkg" name="node1" type="node1">
   <remap from="get_state" to="node1/get_state"/>

The result still seems to be a name collision and only a /get_state for the first node and not the second.

Is there a simpler/better way to go about something like this?

edit retag flag offensive close merge delete

2 Answers

Sort by ยป oldest newest most voted

answered 2015-04-28 22:04:01 -0500

j12y gravatar image

updated 2015-04-30 21:00:49 -0500

The answer is simply to include a tilde (~) when creating the service. A good practice would be to call init_node from the main block to prevent the mistake of including more than one node in a single process. There isn't much benefit in calling the init_node from within the class __init__.

# src/
class Base(object):
   def __init__(self):
      service = rospy.Service('set_state', ...)    # results in /set_state
      service = rospy.Service('~get_state', ...)   # results in /node1/get_state (as desired)

# nodes/
import foo
class Node1(foo.Base):
  def __init__(self):
      super(Node1, self).__init__()

if __name__ == '__main__':
    rospy.init_node('node1')  # moved out of Node1.__init__
    node = Node1()

That seems consistent with the docs to keep the Service private to the node's namespace...

edit flag offensive delete link more



rospy.init_node() is global; you should not call it more than once in your program.

ahendrix gravatar image ahendrix  ( 2015-04-28 22:55:38 -0500 )edit

Sure, but to be clear that is not the point of my question. For illustration and brevity I omitted that Node1 and Node2 are two separate nodes / processes / sub-components -- not a single program. That's why having a library with some common functionality seems valuable for consistency between.

j12y gravatar image j12y  ( 2015-04-28 23:15:17 -0500 )edit

For clarity and to avoid calling rospy.init_node more than once, I usually call it from main().

ahendrix gravatar image ahendrix  ( 2015-04-30 16:21:00 -0500 )edit

That's a great point, there probably is no need to have the init_node call in the __init__ at all. I guess I've gotten into the habit of keeping the main block simple in other projects. Thanks.

j12y gravatar image j12y  ( 2015-04-30 20:45:50 -0500 )edit

answered 2015-04-28 21:45:37 -0500

ahendrix gravatar image

rospy.init_node() is global; you should not call it more than once in your program.

Instead, you could pass your node's namespace into the superclass constructor:

class Base(object):
   def __init__(self, name=""):
      service_name = 'get_state'
      if name:
         service_name = name + '/' + service_name
      service = rospy.Service(service_name, ...) 

class Node1(Base):
  def __init__(self):
      super(Node1, self).__init__('node1')
edit flag offensive delete link more

Question Tools

1 follower


Asked: 2015-04-28 19:51:17 -0500

Seen: 439 times

Last updated: Apr 30 '15