Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling arguments in included xacro files #204

Open
jarvisschultz opened this issue Feb 18, 2019 · 24 comments
Open

Handling arguments in included xacro files #204

jarvisschultz opened this issue Feb 18, 2019 · 24 comments

Comments

@jarvisschultz
Copy link

jarvisschultz commented Feb 18, 2019

Consider the following two xacro files:

parent.xacro

<?xml version="1.0" ?>
<robot name="example" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <xacro:arg name="gazebo" default="false"/>

  <xacro:include filename="child.xacro">
    <xacro:arg name="gazebo" value="False" />
  </xacro:include>
  
  <xacro:if value="$(arg gazebo)">
    <link name="test" />
  </xacro:if>
  
</robot>

child.xacro

<?xml version="1.0" ?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">

  <xacro:arg name="gazebo" default="false"/>

  <xacro:if value="$(arg gazebo)">
    <link name="test" />
  </xacro:if>
  
</robot>

Running xacro --inorder parent.xacro gazebo:=true results in

<?xml version="1.0" ?>
<!-- =================================================================================== -->
<!-- |    This document was autogenerated by xacro from parent.xacro                   | -->
<!-- |    EDITING THIS FILE BY HAND IS NOT RECOMMENDED                                 | -->
<!-- =================================================================================== -->
<robot name="example" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <link name="test"/>
  <link name="test"/>
</robot>

I'd expect there to be only one <link>, but it seems that I cannot set the value of the argument in an included xacro file. I've seen a few xacro files out there trying to set arguments in includes so I thought this was possible (ex1, ex2), but I can't make it work. Is this a regression or a bug? Am I missing something?

@rhaschke
Copy link
Contributor

I don't think that any content in tags is considered at all. It's just silently ignored.
But it could be indeed interesting to set scoped args and properties for an include.
However, I will not have time for this in the next few weeks.

@jarvisschultz
Copy link
Author

Thanks for the quick response. I think perhaps users assume that xacro files will behave like launch files (a reasonable assumption), and I do agree that it would be a useful feature. I'll let you know if I get any time to look at this as well.

@tandronescu
Copy link

Did you ever figure this out @jarvisschultz ? Running into the same issue, seems like a bug since like you said I have seen this work in some scenarios. Looking at the same sawyer example and I don't see the magic they did to make it work

@jarvisschultz
Copy link
Author

I have never spent any time into digging into this feature. In my particular example, it was pretty easy to work around by using macros with args instead of xacro files with args. I.e. parent.xacro would read an <arg> tag and pass the value into a macro defined in child.xacro.

@rickstaa
Copy link

I think this issue in 2020 still contains a relevant feature request. I think having the xacro:include take child tags would result in cleaner code. I, however, currently also don't have time to take it on. Nevertheless, I will consider it in the future.

@rickstaa

This comment has been minimized.

@rhaschke
Copy link
Contributor

Isn't that documented here already? Both args and properties are forwarded to included files.

@rickstaa

This comment has been minimized.

@rhaschke
Copy link
Contributor

rhaschke commented Jun 1, 2021

The key point is that args is a global dictionary, which is accessible from within any file or macro. If you feel that the docs should be improved, go ahead and do so ;-)

@rickstaa

This comment has been minimized.

@jarvisschultz
Copy link
Author

To me it seems like you worked around this in exactly same way I described in my comment above. Basically since you can't pass values for <arg> tags into included xacro files, you are using the rospack-like substitution argument, $(arg), to forward the value of an argument to a macro. While this is different than what I had originally envisioned in this issue, I do think it is how this need should be accomplished with the current capabilities of xacro.

Perhaps @rhaschke is correct that documentation improvements are really what is needed to illustrate to users the "proper" way of accomplishing this.

@rhaschke
Copy link
Contributor

rhaschke commented Jun 1, 2021

<xacro:arg> tags are considered everywhere - except within the scope of an <include> tag. Actually, all content of an include tag is neglected. Sorry that you ran into this trap.
I still think it might be useful to define file-local properties there. However, this doesn't work for args, because those are global anyway.

@rickstaa

This comment has been minimized.

@jarvisschultz
Copy link
Author

@rhaschke This is definitely correct and an important thing for people to understand. I agree that file-local properties could still be useful, and is very much along the lines of what I was thinking when I created this issue.

@rickstaa Looks like a good improvement to me. Maybe could also add a sentence explicitly helping users avoid this trap. Maybe something like:

If you want to pass custom <xacro:arg> values to the included other_file.xacro it is instead recommended to use a <xacro:macro>.

@rhaschke
Copy link
Contributor

rhaschke commented Jun 1, 2021

There is no need to pass arguments via the macro (of course that's possible too). But, you could declare your <xacro:args> just outside the <xacro:include> tag and it should work as expected.

@rickstaa

This comment has been minimized.

@rickstaa

This comment has been minimized.

@rhaschke
Copy link
Contributor

rhaschke commented Jun 2, 2021

I like your second proposal and added it to the docs.

@rickstaa
Copy link

rickstaa commented Jun 2, 2021

@rhaschke Amazing thanks a lot. I will hide my comments to clean up this feature request.

@rcywongaa
Copy link

Unfortunately, this means that the user of a child.xacro relies on the provider to properly wrap it in a macro.
An alternative (though likely even more involved) would be to somehow allow wrapping a file in a macro on the user side. Would be cool to have something like the following

child.macro.xacro

<xacro:macro name="child" params="gazebo:=false">
  <xacro:include filename="child.xacro"/>
</xacro:macro>

@rhaschke
Copy link
Contributor

@rcywongaa, including a file within a macro, should be possible already. Also using the property ${gazebo} shouldn't be an issue.
Please open a new issue, if you actually experience problems with that.

@rcywongaa
Copy link

@rhaschke But included files inside the macro don't get the macro's parameters so it's still not possible to pass arguments to the included file from another xacro file. Using property also doesn't solve that.

Note this is all assuming that child.xacro is provided externally and that it's not possible / undesirable to modify it.

The following variants of parent.xacro all fail to overwrite the gazebo argument resulting in the same output as OP posted

parent1.xacro

<?xml version="1.0" ?>
<robot name="example" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <xacro:macro name="child" params="gazebo:=false">
    <xacro:include filename="child.xacro"/>
  </xacro:macro>
  
  <xacro:child gazebo="false"/>
                 
  <xacro:arg name="gazebo" default="false"/>
  <xacro:if value="$(arg gazebo)">
    <link name="test" />
  </xacro:if>
</robot>

parent2.xacro

<?xml version="1.0" ?>
<robot name="example" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <xacro:property name="gazebo" value="false"/>
  <xacro:include filename="child.xacro"/>

  <xacro:arg name="gazebo" default="false"/>
  <xacro:if value="$(arg gazebo)">
    <link name="test" />
  </xacro:if>
</robot>

parent3.xacro

<?xml version="1.0" ?>
<robot name="example" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <xacro:macro name="child">
    <xacro:property name="gazebo" value="false"/>
    <xacro:include filename="child.xacro"/>
  </xacro:macro>
  
  <xacro:child/>
                 
  <xacro:arg name="gazebo" default="false"/>
  <xacro:if value="$(arg gazebo)">
    <link name="test" />
  </xacro:if>
</robot>

parent4.xacro

<?xml version="1.0" ?>
<robot name="example" xmlns:xacro="http://www.ros.org/wiki/xacro">
  <xacro:arg name="child.gazebo" default="false"/>
  <xacro:include filename="child.xacro" ns="child"/>
  
  <xacro:arg name="gazebo" default="false"/>
  <xacro:if value="$(arg gazebo)">
    <link name="test" />
  </xacro:if>
</robot>

Basically it's the same problem as the initial post. I'm merely suggesting how it would be useful and potential approaches to implementing it.

@rhaschke
Copy link
Contributor

You need to understand that xacro distinguishes two types of parameters: properties and (cmdline) arguments.
The former ones a much more flexible.
If your included file just uses the latter ones, you are stuck to a global argument namespace.

@rhaschke
Copy link
Contributor

I managed to achieve your task as follows:
parent.xacro:

<?xml version="1.0"?>
<robot name="example" xmlns:xacro="http://www.ros.org/wiki/xacro">
	<xacro:macro name="child" params="gazebo:=false">
		<xacro:arg name="gazebo" default="${str(gazebo)}" />
		<xacro:include filename="child.xacro" />
	</xacro:macro>

	<xacro:child gazebo="true" />
</robot>

child.xacro:

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
	<xacro:if value="${gazebo}">
		<link name="prop" />
	</xacro:if>
	<xacro:if value="$(arg gazebo)">
		<link name="arg" />
	</xacro:if>
</robot>

However, note that you can set the (default) argument only once. The best way to go is to use properties.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants