Repository: ros/ros_comm

Issue:
roslaunch: ignores ROS_NAMESPACE for parameters
Migrated from https://code.ros.org/trac/ros/ticket/2380
Attachment available in code.ros.org?: No

---

It makes working with multiple robots under one master less convenient. 



Discussion:
Are there any news regarding this issue?

This bug breaks multiple robot support in Gazebo, at least without the need to modify the launch files used for a single robot:

```
<launch>
   <!-- send the robot XML to param server -->
   <param name="robot_description" command="$(find xacro)/xacro.py $(find hector_quadrotor_urdf)/urdf/quadrotor.gazebo.xacro" />

   <!-- push robot_description to factory and spawn robot in gazebo -->
   <node name="spawn_robot" pkg="gazebo_ros" type="spawn_model"
   args="-param robot_description
   -urdf
   -z 0.5
   -model quadrotor"
     respawn="false" output="screen"/>
</launch>

$ ROS_NAMESPACE=quadrotor1 roslaunch hector_quadrotor_gazebo spawn_quadrotor.launch
$ ROS_NAMESPACE=quadrotor2 roslaunch hector_quadrotor_gazebo spawn_quadrotor.launch
```

roslaunch sets the robot_description in the root namespace and ignores the ROS_NAMESPACE environment variable. The nodes itself are respecting ROS_NAMESPACE and therefore cannot find parameters set by roslaunch:

```
[INFO] [WallTime: 1373482991.569527] [0.000000] Loading model xml from ros parameter
Traceback (most recent call last):
  File "/home/meyer/ros/hydro/gazebo/src/gazebo_ros_pkgs/gazebo_ros/scripts/spawn_model", line 292, in <module>
    sm.callSpawnService()
  File "/home/meyer/ros/hydro/gazebo/src/gazebo_ros_pkgs/gazebo_ros/scripts/spawn_model", line 229, in callSpawnService
    model_xml = rospy.get_param(self.param_name)
  File "/opt/ros/hydro/lib/python2.7/dist-packages/rospy/client.py", line 452, in get_param
    return _param_server[param_name] #MasterProxy does all the magic for us
  File "/opt/ros/hydro/lib/python2.7/dist-packages/rospy/msproxy.py", line 117, in __getitem__
    raise KeyError(key)
KeyError: 'robot_description'
```

In the case of the `robot_description` parameters one could simply use `/robot_description` instead if all robots are the same, but in general there might be parameters that are different for each robot.

As a workaround, I am currently adding an enclosing `<group ns="$(optenv ROS_NAMESPACE)">...</group>` tag in all relevant launch files. This solution works fine and should IMHO reflect the builtin roslaunch semantics.

I have updated the issue title to mention that _roslaunch_ ignores the `ROS_NAMESPACE` environment variable when evaluating _param_ tags.

It currently also pushes nodes into a namespace even if the specify an absolute namespace themselves (since it does not reset the environment when invoking the node).

Last but not least ROS_NAMESPACE currently pushes the parameters and nodes from roscore.xml into a sub namespace which is also unintended.


Resolving patch:
diff --git a/tools/roslaunch/src/roslaunch/core.py b/tools/roslaunch/src/roslaunch/core.py
--- a/tools/roslaunch/src/roslaunch/core.py
+++ b/tools/roslaunch/src/roslaunch/core.py
@@ -196,6 +196,8 @@ def setup_env(node, machine, master_uri, env=None):
 
     # add node-specific env args last as they have highest precedence
     if node:
+        if rosgraph.ROS_NAMESPACE in d:
+            del d[rosgraph.ROS_NAMESPACE]
         ns = node.namespace 
         if ns[-1] == '/':
             ns = ns[:-1]
diff --git a/tools/roslaunch/src/roslaunch/xmlloader.py b/tools/roslaunch/src/roslaunch/xmlloader.py
--- a/tools/roslaunch/src/roslaunch/xmlloader.py
+++ b/tools/roslaunch/src/roslaunch/xmlloader.py
@@ -46,7 +46,7 @@
 from xml.dom.minidom import parse, parseString
 from xml.dom import Node as DomNode #avoid aliasing
 
-from rosgraph.names import make_global_ns, ns_join, is_private, is_legal_name
+from rosgraph.names import make_global_ns, ns_join, is_private, is_legal_name, get_ros_namespace
 
 from .core import Param, Node, Test, Machine, RLException
 from . import loader
@@ -662,7 +662,7 @@ def _load_launch(self, launch, ros_config, is_core=False, filename=None, argv=No
             argv = sys.argv
 
         self._launch_tag(launch, ros_config, filename)
-        self.root_context = loader.LoaderContext('', filename)
+        self.root_context = loader.LoaderContext(get_ros_namespace(), filename)
         loader.load_sysargs_into_context(self.root_context, argv)
 
         if len(launch.getElementsByTagName('master')) > 0:


Test patch: