diff --git a/tools/roslaunch/src/roslaunch/loader.py b/tools/roslaunch/src/roslaunch/loader.py
index 21d11a8a38..025aeba624 100644
--- a/tools/roslaunch/src/roslaunch/loader.py
+++ b/tools/roslaunch/src/roslaunch/loader.py
@@ -365,7 +365,7 @@ def add_param(self, ros_config, param_name, param_value, verbose=True):
else:
ros_config.add_param(Param(param_name, param_value), verbose=verbose)
- def load_rosparam(self, context, ros_config, cmd, param, file_, text, verbose=True):
+ def load_rosparam(self, context, ros_config, cmd, param, file_, text, verbose=True, subst_function=None):
"""
Load rosparam setting
@@ -401,6 +401,8 @@ def load_rosparam(self, context, ros_config, cmd, param, file_, text, verbose=Tr
with open(file_, 'r') as f:
text = f.read()
+ if subst_function is not None:
+ text = subst_function(text)
# parse YAML text
# - lazy import: we have to import rosparam in oder to to configure the YAML constructors
global rosparam
diff --git a/tools/roslaunch/src/roslaunch/xmlloader.py b/tools/roslaunch/src/roslaunch/xmlloader.py
index 5feb0c4155..78a9775542 100644
--- a/tools/roslaunch/src/roslaunch/xmlloader.py
+++ b/tools/roslaunch/src/roslaunch/xmlloader.py
@@ -235,9 +235,10 @@ def _rosparam_tag(self, tag, context, ros_config, verbose=True):
# load is the default command
cmd = cmd or 'load'
value = _get_text(tag)
+ subst_function = None
if subst_value:
- value = self.resolve_args(value, context)
- self.load_rosparam(context, ros_config, cmd, param, file, value, verbose=verbose)
+ subst_function = lambda x: self.resolve_args(x, context)
+ self.load_rosparam(context, ros_config, cmd, param, file, value, verbose=verbose, subst_function=subst_function)
except ValueError as e:
raise loader.LoadException("error loading tag: \n\t"+str(e)+"\nXML is %s"%tag.toxml())
diff --git a/tools/roslaunch/test/params_subst.yaml b/tools/roslaunch/test/params_subst.yaml
new file mode 100644
index 0000000000..a34c327dd2
--- /dev/null
+++ b/tools/roslaunch/test/params_subst.yaml
@@ -0,0 +1 @@
+string1: $(anon foo)
diff --git a/tools/roslaunch/test/unit/test_xmlloader.py b/tools/roslaunch/test/unit/test_xmlloader.py
index 3986815608..ac30189d00 100644
--- a/tools/roslaunch/test/unit/test_xmlloader.py
+++ b/tools/roslaunch/test/unit/test_xmlloader.py
@@ -242,6 +242,10 @@ def test_rosparam_valid(self):
self.assertEquals('bar', p.value)
p = [p for p in mock.params if p.key == '/node_rosparam/robots/childparam'][0]
self.assertEquals('a child namespace parameter', p.value)
+
+ # test substitution in yaml files
+ p = [p for p in mock.params if p.key == '/rosparam_subst/string1'][0]
+ self.assertTrue('$(anon foo)' not in p.value)
exes = [e for e in mock.executables if e.command == 'rosparam']
self.assertEquals(len(exes), 2, "expected 2 rosparam exes, got %s"%len(exes))
@@ -274,6 +278,10 @@ def test_rosparam_valid(self):
p = [p for p in mock.params if p.key == '/inline_dict2/key4'][0]
self.assertEquals('value4', p.value)
+ # test substitution in inline yaml
+ p = [p for p in mock.params if p.key == '/inline_subst'][0]
+ self.assertTrue('$(anon foo)' not in p.value)
+
# verify that later tags override
# - key2 is overriden
self.assertEquals(1, len([p for p in mock.params if p.key == '/override/key1']))
diff --git a/tools/roslaunch/test/xml/test-rosparam-valid.xml b/tools/roslaunch/test/xml/test-rosparam-valid.xml
index c5d521db3d..2d00435ed7 100644
--- a/tools/roslaunch/test/xml/test-rosparam-valid.xml
+++ b/tools/roslaunch/test/xml/test-rosparam-valid.xml
@@ -12,6 +12,10 @@
+
+
+
+
value1
[1, 2, 3, 4]
{key1: value1, key2: value2}
@@ -19,6 +23,8 @@
key3: value3
key4: value4
+
+ $(anon foo)
{key1: value1, key2: value2}
{key1: override1}