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

Handle model:// path in URI #20

Closed
wants to merge 9 commits into from
Closed

Conversation

oKermorgant
Copy link

Hi,

This PR is to convert URI's starting with model:// to absolute paths, by using classical Gazebo environment variables.

While it does not answer all cases (http link / relative path), many models just rely on model:// meshes which are resolved here.

I am not sure on the order the environment variables should be processed (see here).

@quarkytale
Copy link
Contributor

@oKermorgant Thanks for your contribution! Do you mind refactoring the header a bit based on the suggestions by the workflow run, like one here, it's mostly reformatting, missing spaces, etc.

Copy link
Contributor

@quarkytale quarkytale left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it's efficient. Added suggestions based on CI and some improvements to make it more readable and preferring C++ methods.

sdformat_urdf/src/uri_resolve.hpp Outdated Show resolved Hide resolved
sdformat_urdf/src/uri_resolve.hpp Outdated Show resolved Hide resolved
sdformat_urdf/src/uri_resolve.hpp Outdated Show resolved Hide resolved
@@ -32,6 +32,7 @@
#include <sdf/Visual.hh>

#include "sdformat_urdf/sdformat_urdf.hpp"
#include "uri_resolve.hpp"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be renamed to resolve_model_uri for clarity?

sdformat_urdf/src/uri_resolve.hpp Outdated Show resolved Hide resolved
sdformat_urdf/src/uri_resolve.hpp Outdated Show resolved Hide resolved
char* path = strtok_r(paths, ":", save_ptr);
while(path)
{
fs::path root(path);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could root be renamed to something more descriptive like modelDirectory?

sdformat_urdf/src/uri_resolve.hpp Outdated Show resolved Hide resolved
sdformat_urdf/src/uri_resolve.hpp Outdated Show resolved Hide resolved
continue;

char** save_ptr{};
char* path = strtok_r(paths, ":", save_ptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be defined as const?

@quarkytale
Copy link
Contributor

quarkytale commented Aug 16, 2023

@oKermorgant regarding the environment variables, Gazebo will look for URIs (path / URL) in the following order:

  1. All paths on the GZ_SIM_RESOURCE_PATH
  2. Current directory
  3. Cache ($HOME/.gz)

The SDF_PATH environment variable is not recommended. More details here: https://gazebosim.org/api/sim/7/resources.html

@sloretz
Copy link
Contributor

sloretz commented Aug 28, 2023

This is an interesting one. On the ROS side resource_retriever can handle package:// URIs, but by default SDFormat only supports model://.

libsdformat is able to parse URDF, and during that it converts package:// to model://, and as long as someone makes their package add its installed model directory to gazebo related paths (like an ament environment hook with a dsv file containing prepend-non-duplicate;IGN_GAZEBO_RESOURCE_PATH;@CMAKE_INSTALL_PREFIX@/share/@PROJECT_NAME@/models) then gazebo can load models from a ROS package using the model:// URI. libsdformat also has anAPI for adding paths to look at per URI scheme.

I think my favorite solution would be one or both of these instead of resolving the URI here:

  1. Add an API to libsdformat that registered a callback for a URI scheme. Then we could add a plugin to ros_gz that said "if given a package:// URI, resolve it using resource_retriever". All models in ROS packages could use package:// URIs.
  2. Add the ability to resource_retriever to load plugins. Then we could make a plugin that resolved model:// URIs in ros_gz according to gazebo conventions.

@oKermorgant
Copy link
Author

Hi,

Indeed the whole thing is about ROS and Gazebo coupling through having to parse possibly the same URDF and SDF files.

To my experience, URIs starting with package:// (e.g. classical URDF) may not be resolved by Gazebo, which does not understand pure ROS packages. On the opposite, ROS has no idea what a model:// is.
I tend to use file://$(find pkg) with xacro but then problems arise when sharing a robot description among several computers, as the absolute path may not be valid on another computer.

I came into this issue when playing with pure Gazebo models I wanted to run a robot_state_publisher for, hence resolving model:// URIs. If any broader approach seems useful I'll be happy to help.

@Yadunund
Copy link
Member

Recently ran into this problem and opened #25 without noticing this PR.

I think @sloretz's suggestions make sense. I could work on 1) if it is still unimplemented?

@oKermorgant
Copy link
Author

Hi, I am not familiar enough with libsdformat and ros_gz plugins to deal with the suggestions, so feel free to tackle this one.

For my use cases resolving URI based on Gazebo environment variables is fine, though dealing with nested models would be a bit better.

@quarkytale quarkytale linked an issue Feb 13, 2024 that may be closed by this pull request
@azeey
Copy link
Contributor

azeey commented Feb 14, 2024

The problem with (1) is that we have a chicken and egg problem. Gazebo plugins are currently read from SDF files, which requires loading the model or world SDF that also contains the paths we need to resolve. The plugin would not have a chance to configure libsdformat to know about package://.

Another solution might be to add the share directories (actually the parent of that) of all the dependencies of a package to GZ_SIM_RESOURCE_PATH before starting Gazebo. Then, Gazebo should be able to resolve paths like package://<package_name>/models/foo. For example, if we have the following files installed

<prefix>/turtlebot3_gazebo/share/turtlebot3_gazebo/models/turtlebot3_waffle
<prefix>/turtlebot3_gazebo/share/turtlebot3_gazebo/models/turtlebot3_waffle/model-1_4.sdf
<prefix>/turtlebot3_gazebo/share/turtlebot3_gazebo/models/turtlebot3_waffle/model.config
<prefix>/turtlebot3_gazebo/share/turtlebot3_gazebo/models/turtlebot3_waffle/model.sdf

We can add <prefix>/turtlebot3_gazebo/share/ to GZ_SIM_RESOURCE_PATH , which is the output of os.path.join(get_package_prefix('turtlebot3_gazebo'), 'share') or "$(ros2 pkg prefix turtlebot3_gazebo)/share" (not ros2 pkg prefix --share turtlebot3_gazebo since that includes an extra package name at the end). Gazebo should then be able to resolve package://turtlebot3_gazebo/models/turtlebot3_waffle.

We would provide a launch helper python module to do this. gazebosim/ros_gz#492 is doing something similar on a more global scale to replicate what we had in Gazebo Classic. Maybe adding all available packages instead of just dependencies to the path might work too.

@Yadunund
Copy link
Member

Yadunund commented Feb 17, 2024

@azeey the approach you shared worked like a charm! ✨
I added the <prefix>/ros_pkg/share to my gazebo_paths.dsv.in file such that GZ_SIM_RESOURCE_PATH is set as recommended when I source the workspace.

This commit could serve as a useful reference for others.

Further, I've opened #26 to add information from your comment to the README. I guess we could close this PR and my ticket with that?

@azeey
Copy link
Contributor

azeey commented Feb 17, 2024

@Yadunund Glad it worked! I've also created gazebosim/ros_gz#497 that would eventually allow us to do (1) from #20 (comment)

@ahcorde ahcorde deleted the branch ros:ros2 April 23, 2024 10:17
@ahcorde ahcorde closed this Apr 23, 2024
@asherikov
Copy link

Hi, it looks like the proposed solution is incomplete.

Apparently, path resolution happens twice when rviz loads model description provided by robot_state_publisher:

  • first time to expand SDF tags
  • second time to resolve resources such as mesh files

The first step does not seem to work with either package:// or model://, e.g.,
[ros2-1] [ERROR] [...] [sdformat_urdf]: Unable to find uri[package://<path_to_included_sdf>].
robot_state_publisher, however, works fine with package:// -- there must be some differences in logic.

It is possible to workaround this issue by launching rviz in <install_prefix>/share, which allows resolution to fallback to relative paths. Setting SDF_PATH (same as GZ_SIM_RESOURCE_PATH) also works.

@Yadunund
Copy link
Member

Yadunund commented Dec 9, 2024

The first step does not seem to work with either package:// or model://, e.g.,

@asherikov could you share a link to a minimal repo that allows one to reproduce the issue?

@asherikov
Copy link

Hi, it may take some time, rough idea:

  • SDF file that references mesh files and includes other SDF files with tags (the latter seems to be the source of the problem);
  • robot state publisher reads this SDF file and publishes description;
  • model is visualized in rviz with the corresponding robot description topic.

rviz would spit errors to the console, observed with ROS2 Humble, havent tried anything else.

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

Successfully merging this pull request may close these issues.

Issues resolving mesh uri with model://
7 participants