RobotLocomotion / drake

Model-based design and verification for robotics.
https://drake.mit.edu
Other
3.35k stars 1.27k forks source link

C++ URDF parser should send global filename for meshes #1636

Closed gizatt closed 8 years ago

gizatt commented 8 years ago

e.g. In carSimLCM, when run from the directory of the prius URDF and mesh, sends ./prius.stl as the mesh path.

patmarion commented 8 years ago

I have also encountered this. It seems the mesh filenames listed in DRAKE_VIEWER_LOAD_ROBOT are based on the dirname of the urdf filename passed to addRobotFromURDF(). So, if you specify the urdf as:

./examples/Cars/prius/prius.urdf

Then the mesh filename will be ./examples/Cars/prius/prius.dae But if you specify the urdf using an aboslute path, such as:

/path/to/examples/Cars/prius/prius.urdf

Then the mesh will be absolute too, i.e., /path/to/examples/Cars/prius/prius.dae

When mesh filenames are relative, then drake-visualizer must be launched from the same working dir as the publishing program (the one reading the urdf) for things to work out. When mesh filenames are aboslute, then drake-visualizer can be launched from anywhere (on mac I like to use the drake-visualizer.app in my dock :)

Absolute paths would allow the visualization to work regardless of the cwd of the launched programs. This would be ok except that log files would not be transferable between computers. One alternative is to use the package:// notation, or specify paths relative to the drake root, and then teach drake-visualizer to resolve these paths itself. Thoughts?

rdeits commented 8 years ago

I think that relative to drake root makes a lot of sense. On the python side, you can already do import pydrake; pydrake.getDrakePath() to get the path to the drake folder.

patmarion commented 8 years ago

Ok. Confirmed that pydrake.getDrakePath() works in drake-visualizer. Then we just need to filename manipulation routines to be available inside the drake C++. I guess drake uses spruce, but looking at spruce.hh it looks a bit limited in its api. Previously drake used boost filesystem. We'd need something like these python functions for converting filenames to absolute paths and relative to drake root paths:

>>> import os
>>> import pydrake
>>> urdf = '../examples/Cars/prius/prius.urdf'
>>> os.path.abspath(urdf)
'/Users/pat/source/drake/drake/drake/examples/Cars/prius/prius.urdf'
>>> os.path.relpath(urdf, pydrake.getDrakePath())
'examples/Cars/prius/prius.urdf'
RussTedrake commented 8 years ago

does this mean that we will always send the path relative to drake, or indicate it with a package:// or even drake:// symbol, and also support absolute file paths?

patmarion commented 8 years ago

Relative paths in a urdf file should be interpreted as being relative to the urdf file, but DRAKE_VIEWER_LOAD_ROBOT publishes information that does not necessarily have to come from a urdf at all, so I'd say we're free to choose a different convention. On the DRAKE_VIEWER_LOAD_ROBOT channel (or any future DRAKEVIEWER* channel we invent), we could say relative paths should be interpreted relative to the drake resource root (and right now lets define that to be the drake root, i.e. the top level source directory)

Or, we could say relative paths on this channel are interpreted relative to the receiver's current working directory, which is difficult to predict, and use drake:// to indicate the drake root.

And that defines how to interpret relative paths (or drake:// paths if we choose) on the DRAKEVIEWER* channels. We can support absolute paths too, but we'll be more flexible by not using absolute paths in most places.

RussTedrake commented 8 years ago

Just trying to think out possible limitations / failure modes of using the drake root everywhere…  some files might live outside of the drake root (e.g. if someone has drake as an external for their personal project).  would we want drakeroot/../../myotherpath/file.urdfas the syntax? there?  isn’t that just as bad as an absolute path for the log files?  

I’ve actually already added the drake root path to the package path search list in the c++ parser (even if it does not appear in the environment variable).  the viewer should do the same?  we can use package:// and just have the viewer know that drakeroot is always one of the package paths?

patmarion commented 8 years ago

Agreed. Sounds like you are suggesting we adopt a convention that mirrors ROS_PACKAGE_PATH. Here's my understanding of the ROS_PACKAGE_PATH implementation:

-recursively search each path in the ROS_PACKAGE_PATH environment variable for packages -when a package is found (a directory with a package.xml file), add an entry to map the package name to that path

This basic implementation is used in director for locating urdf resources for Atlas and Val. The director has some preferred paths baked in, and then it appends whatever is specified in ROS_PACKAGE_PATH.

I think it works well enough, we could do that. You need some way to identify which directories are packages. ROS uses a package.xml. Would you adopt something that? Here is documentation of ROS's package.xml specification: http://www.ros.org/reps/rep-0127.html

patmarion commented 8 years ago

Oh, but again, many urdfs specify filenames using paths relative to the urdf file itself. When director loads a urdf, it knows the urdf path, so it is able to resolve relative filenames inside the urdf.

For DRAKE_VIEWER_LOAD_ROBOT, would it only support filenames using the package:// format? Seems like you still need to support relative paths somehow. The message could broadcast a root directory which should be used by the viewer to resolve relative paths. And package:// is preferred for generality, but then relative paths still work.

RussTedrake commented 8 years ago

That’s what I’m thinking.  Our own simple version of this algorithm is implemented in c++ (using spruce) here: https://github.com/RobotLocomotion/drake/blob/master/drake/systems/plants/RigidBodyTreeURDF.cpp#L41

drakeroot does have a trivial package.xml file in it (https://github.com/RobotLocomotion/drake/blob/master/drake/package.xml), so gets added to the DB.

On January 23, 2016 at 12:55:22 PM, Pat Marion (notifications@github.com) wrote:

Agreed. Sounds like you are suggesting we adopt a convention that mirrors ROS_PACKAGE_PATH. Here's my understanding of the ROS_PACKAGE_PATH implementation:

-recursively search each path in the ROS_PACKAGE_PATH environment variable for packages -when a package is found (a directory with a package.xml file), add an entry to map the package name to that path

This basic implementation is used in director for locating urdf resources for Atlas and Val. The director has some preferred paths baked in, and then it appends whatever is specified in ROS_PACKAGE_PATH.

I think it works well enough, we could do that. You need some way to identify which directories are packages. ROS uses a package.xml. Would you adopt something that? Here is documentation of ROS's package.xml specification: http://www.ros.org/reps/rep-0127.html

— Reply to this email directly or view it on GitHub.

patmarion commented 8 years ago

Ok so we have:

options to support urdf files that use relative paths for meshes:

RussTedrake commented 8 years ago

agreed.  so the drake c++ parser will simply keep the package:// string when it exists, and add a package:// + relative path from drake root when the path is relative to the current url.

i guess the director side probably has to happen first?