如何解析 URDF 文件路径中的“package://”?

hex*_*ing 5 python robotics path urdf

我有一个机器人 URDF,它使用“package://”指向网格文件。

  <geometry>
    <mesh filename="package://a1_rw/meshes/hip.dae" scale="1 1 1"/>
  </geometry>
Run Code Online (Sandbox Code Playgroud)

我想使用 urdfpy 来解析这个 URDF。但是,它无法解释“package://”的含义。

import os
from urdfpy import URDF

a1_rw = {
    "model": "a1",
    "csvpath": "a1_rw/urdf/a1_rw.csv",
    "urdfpath": "a1_rw/urdf/a1_rw.urdf"
}

model = a1_rw
curdir = os.getcwd()
path_parent = os.path.dirname(curdir)
print("path parent = ", path_parent)
model_path = model["urdfpath"]
robot = URDF.load(os.path.join(path_parent, model_path))
Run Code Online (Sandbox Code Playgroud)

这是错误消息:

$ python3.8 calc_parallax.py
path parent =  /home/ben/Documents/git_workspace/a1_test
Traceback (most recent call last):
  File "calc_parallax.py", line 18, in <module>
    robot = URDF.load(os.path.join(path_parent, model_path))
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 3729, in load
    return URDF._from_xml(node, path)
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 3926, in _from_xml
    kwargs = cls._parse(node, path)
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 161, in _parse
    kwargs.update(cls._parse_simple_elements(node, path))
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 137, in _parse_simple_elements
    v = [t._from_xml(n, path) for n in vs]
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 137, in <listcomp>
    v = [t._from_xml(n, path) for n in vs]
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 181, in _from_xml
    return cls(**cls._parse(node, path))
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 161, in _parse
    kwargs.update(cls._parse_simple_elements(node, path))
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 137, in _parse_simple_elements
    v = [t._from_xml(n, path) for n in vs]
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 137, in <listcomp>
    v = [t._from_xml(n, path) for n in vs]
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 1146, in _from_xml
    kwargs = cls._parse(node, path)
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 161, in _parse
    kwargs.update(cls._parse_simple_elements(node, path))
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 127, in _parse_simple_elements
    v = t._from_xml(v, path)
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 181, in _from_xml
    return cls(**cls._parse(node, path))
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 161, in _parse
    kwargs.update(cls._parse_simple_elements(node, path))
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 127, in _parse_simple_elements
    v = t._from_xml(v, path)
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/urdf.py", line 581, in _from_xml
    meshes = load_meshes(fn)
  File "/home/ben/.local/lib/python3.8/site-packages/urdfpy/utils.py", line 225, in load_meshes
    meshes = trimesh.load(filename)
  File "/home/ben/.local/lib/python3.8/site-packages/trimesh/exchange/load.py", line 111, in load
    ) = parse_file_args(file_obj=file_obj,
  File "/home/ben/.local/lib/python3.8/site-packages/trimesh/exchange/load.py", line 623, in parse_file_args
    raise ValueError('string is not a file: {}'.format(file_obj))
ValueError: string is not a file: /home/ben/Documents/git_workspace/a1_test/a1_rw/urdf/package://a1_rw/meshes/trunk.dae
Run Code Online (Sandbox Code Playgroud)

有没有办法让 urdfpy (或另一个 urdf 解析器)正确解析它?

LNi*_*rha 1

您观察到的行为是预期的。该文档urdfpy.URDF.load()具体指出:

URDF 中的任何路径都应指定为文件的相对路径,.urdf而不是 ROS 资源。

如果您想继续使用相同的库,解决此问题的唯一方法是替换文件中的字符串.urdf。为此,我建议使用临时文件,以便在加载 URDF 后自动丢弃该文件,并且实际上不会影响原始 urdf。

from pathlib import Path
from urdfpy import URDF
import tempfile

# URDF file (pathlib is a little nicer but not mandatory)
urdf_file_path = Path("path/to/my/file.urdf")

# Define how you replace your string. Adjust it so it fits your file organization
ros_url_prefix = "package://"
abs_path_prefix = "/path/to/my/meshes/folder"

# Start with openning a temp dir (context manger makes it easy to handle)
with tempfile.TemporaryDirectory() as tmpdirname:
  
    # Where your tmpfile will be
    tmp_file_path = Path(tmpdirname)/urdf_file_path.name

    # Write each line in fout replacing the ros url prefix with abs path
    with open(urdf_file_path, 'r') as fin:
        with open(tmp_file_path, 'w') as fout:
            for line in fin:
                fout.write(line.replace(ros_url_prefix, abs_path_prefix))

    # Load the urdf from the corrected tmp file
    robot_urdf = load(tmp_file_path)

# Here we get out of tmpfile context manager, so the tmpdir and all its content is erased
robot_urdf.show() # The robot urdf is still accessible
Run Code Online (Sandbox Code Playgroud)