urdfeus
URDF ⇄ EusLisp を相互変換するPythonライブラリ
eus2urdfで変換したjskeusの全モデル(ロボット・物体・シーン)をブラウザで閲覧・操作・ダウンロードできます → https://iory.github.io/urdfeus/
ブラウザで変換する(インストール不要)
手元のモデルをその場で相互変換できます → https://iory.github.io/urdfeus/convert/
urdfeusがWebAssembly(Pyodide)として動くため、Pythonの環境構築が要りません。変換はすべてブラウザ内で完結するので、ファイルはどこにもアップロードされません。
URDF → EusLisp
URDFをドラッグ&ドロップすると必要なメッシュが一覧表示されるので、「Select files」か「Select directory」でメッシュを渡してください。ファイル名を手がかりにpackage://のパスへ自動で突き合わせるので、メッシュの入ったフォルダごと指定して構いません。URDFとメッシュが同じフォルダにあるなら、フォルダごとドロップするだけで済みます。
EusLisp → URDF
.lをドロップすると、その場でURDFパッケージに変換し3Dで表示します。関節はスライダで動かせ、package.xml + urdf/ + meshes/一式をzipでダウンロードできます。生成モデル(euscollada/urdfeusのロボット、jskeusの物体モデル)は幾何情報をファイル内に持っているので、メッシュを別途渡す必要はありません。
GitHubのURLを貼るだけでも変換できます。 ファイルページのURL(https://github.com/<owner>/<repo>/blob/<ref>/<path>.l)を貼るとraw.githubusercontent.comに読み替えて取得します。リンクをドロップしても同じです。
?url=を付ければ、開いた時点で取得と変換まで走ります(URLはパーセントエンコードしてください)。モデルをそのまま共有できます:
https://iory.github.io/urdfeus/convert/?url=https%3A%2F%2Fgithub.com%2Fowner%2Frepo%2Fblob%2Fmain%2Frobot.l
取得はブラウザからの直接アクセスなので、CORSを許可しているホストに限られます(GitHubのrawは許可しています)。それ以外のURLは失敗するので、ファイルを落としてドロップしてください。
irteusglはネイティブプログラムなのでブラウザでは動きません。代わりに.lを直接読む静的パーサを使います。コードでリンクを組み立てるモデルや、他ファイルをloadするシーンはこの経路では読めないので、インストールしたeus2urdf(irteusgl経由)を使ってください。
初回のみPython実行環境(約33MB)を取得するため数秒かかります。2回目以降はブラウザのキャッシュが効きます。
--voxel-sizeによるメッシュ簡素化はopen3dに依存するため、ブラウザでは使えません。
概要
urdfeusは、ロボット記述ファイル(URDF)をEusLispのロボットモデル定義に変換するツールです。ROS環境で使用されるURDFファイルを、EusLispプログラミング環境で利用できる形式に変換できます。
インストール
Python 3.10以降が必要です。
uvを使う場合(推奨)
uvは高速なPythonパッケージマネージャです。コマンドとして使うだけならuv toolが最も確実です:
uv tool install urdfeus
uv tool upgrade urdfeus
隔離された環境に入り、~/.local/binのshimが絶対パスのインタプリタを指すので、カレントディレクトリにあるチェックアウトに影響されません。
ライブラリとして使う場合は仮想環境に:
uv venv
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows
uv pip install urdfeus
オプションの依存関係も含める場合:
uv pip install "urdfeus[all]"
[all]が入れるopen3dはPython 3.12以下でのみインストールされます(open3dがcp313以降のホイールを配布していないため)。3.13以降ではurdfeus本体だけが入り、メッシュ簡素化(--voxel-size)が使えません。
uvxを使う場合(PATHや環境を汚したくない場合)
インストールせずに一度だけ変換したい、~/.local/binにshimを置きたくない、という場合はuvxが使えます。実行のたびに一時的な隔離環境が作られ、終わったらキャッシュ以外は残りません。
コマンド名がパッケージ名と違うので--from urdfeusが必要です:
uvx --from urdfeus urdf2eus robot.urdf robot.l
uvx --from urdfeus eus2urdf robot.l output_package_dir
uvx --from urdfeus urdf2eus --doctor
オプションの依存関係が要る場合(--voxel-sizeなど):
uvx --from "urdfeus[all]" urdf2eus robot.urdf robot.l --voxel-size 0.01
バージョンを固定したいときは--from "urdfeus==1.2.1"のように書けます。ROS_PACKAGE_PATHなどの環境変数はそのまま引き継がれるので、package://の解決も通常どおり動きます。
毎回パッケージの解決が走るので、常用するならuv tool installのほうが向いています。
pipを使う場合
pip install urdfeus
pip install --userは避けてください。~/.localに残った古いコピーが、あとから入れた環境を隠すことがあります。
開発版
git clone https://github.com/iory/urdfeus.git
cd urdfeus
uv pip install -e . # または pip install -e .
ROS環境との関係
urdf2eusはROSのPythonインタプリタを必要としません。URDFのpackage://を解決するためにROS_PACKAGE_PATHが通っていれば、隔離された仮想環境から実行できます:
export ROS_PACKAGE_PATH=/path/to/your/ros/workspace
urdf2eus robot.urdf robot.l
不具合の報告
環境の取り違えが原因の不具合が多いため、報告には実行環境を添えてください:
urdf2eus --doctor
どのPython・どのurdfeus・どのscikit-robotが実際に読み込まれたかを、バージョンだけでなくパスまで表示します。変換が成功して結果だけがおかしい場合は、生成された.lの先頭20行でも同じ情報が得られます。
使用方法
コマンドライン
# 基本的な変換
urdf2eus robot.urdf robot.l
# YAMLファイルと一緒に変換
urdf2eus robot.urdf robot.l --yaml-path robot.yaml
# カスタムロボット名を指定
urdf2eus robot.urdf robot.l --name my_robot
# メッシュ簡素化オプション付き
urdf2eus robot.urdf robot.l --voxel-size 0.01
Pythonスクリプト
from urdfeus.urdf2eus import urdf2eus
# URDFファイルをEusLispに変換
with open('robot.l', 'w') as f:
urdf2eus('robot.urdf', fp=f)
# YAMLファイルと一緒に変換
with open('robot.l', 'w') as f:
urdf2eus('robot.urdf', 'robot.yaml', fp=f)
# カスタムロボット名を指定
with open('robot.l', 'w') as f:
urdf2eus('robot.urdf', robot_name='my_robot', fp=f)
EusLisp → URDF 変換 (eus2urdf)
eus2urdfは、EusLispのロボットモデルをURDF(ROSパッケージ形式)へ変換する逆方向のツールです。
モデルはirteusglで実体化してから抽出するため、:init内で手続き的に追加されるリンク・関節(脚や吸盤など)も取りこぼさず変換できます。メッシュはglverticesからtrimesh経由で書き出します(デフォルトは色を保持できる.glb)。変換結果はギャラリーで確認できます。
前提
irteusgl(jskeus)がインストールされていること(無い場合は後述の静的パーサが使われます)- メッシュ書き出しに
trimesh/pycollada(依存に含まれます)
コマンドライン
# EusLispモデル -> ROSパッケージ一式 (package.xml + urdf/ + meshes/)
eus2urdf robot.l output_package_dir
# package:// で使うパッケージ名を指定
eus2urdf robot.l output_package_dir --package-name my_robot_description
# ロボット名・コンストラクタ・メッシュ形式を指定
eus2urdf robot.l out --name my_robot --constructor my-robot --mesh-format obj
生成物のレイアウト:
output_package_dir/
package.xml
CMakeLists.txt # 最小のcatkin定義(catkin build/catkin_makeで通る)
urdf/<robot>.urdf # package://<pkg>/meshes/<link>.glb を参照
meshes/<link>.glb
Pythonスクリプト
from urdfeus.eus2urdf import eus2urdf
urdf_path = eus2urdf('robot.l', 'output_package_dir',
package_name='my_robot_description')
オプション
--package-name:package://で参照するROSパッケージ名(既定は出力ディレクトリ名)--name:<robot name>とURDFファイル名(既定はモデルが返すロボット名)--constructor: EusLispのコンストラクタ関数名(既定はファイル名のstem)--mesh-format:trimesh.exportが扱う拡張子(既定glb)。glb/ply/objは面ごとの色を保持。daeはtrimeshのColladaエクスポータが色をtextureに潰すため多色メッシュがグレーになる(単色メッシュは保持)。stlは色なし--draco: glbメッシュをDraco圧縮(KHR_draco_mesh_compression)。頂点色を保ったまま密なメッシュを概ね1桁小さくする。glb固定でDracoPyが必要(pip install urdfeus[draco])。読み込み側のglTFローダにはDracoデコーダが要る--irteusgl: 使用するirteusgl実行ファイル--backend: モデルの読み方(後述)
eus2urdfのバックエンド
モデルを読む経路は2つあります。
--backend |
読み方 | 対応範囲 |
|---|---|---|
irteusgl |
irteusglでモデルを実体化してダンプ |
どんなモデルでも読める。EusLispのインストールが必要 |
static |
.lファイルを直接パースする(urdfeus.eus_parse) |
生成モデル限定。EusLispは不要 |
auto(既定) |
irteusglがPATHにあればそちら、無ければstatic |
staticが読めるのは生成されたモデルです。euscollada/urdfeusがURDF・colladaから吐いたロボット(gl::glverticesで幾何を持つもの)と、jskeusの物体モデル(facesetで幾何を持つもの)が該当します。手書きでリンクを計算するモデルや、他ファイルをloadするシーン(*-scene.l)は読めず、その旨のエラーになります(黙って一部だけ変換することはありません)。
staticは:assocや:newcoordsといったEusLispの座標系の意味論を再現しており、jskeusの全モデル651個でirteusglのダンプと突き合わせて検証しています(641個が完全一致、2個は下限が正のジョイントに関する差でURDFとしては等価、8個はシーンで対象外)。
# EusLispが入っていない環境でも変換できる
eus2urdf robot.l out --backend static
from urdfeus.eus_parse import parse_eus_model
data = parse_eus_model('robot.l') # irteusgl不要。dumpと同じ辞書が返る
ジオメトリの扱い
- colladaボディは
glverticesから、make-cube等で生成されたプレーンなbody(例::initで追加される可視化用の脚キューブや吸盤)は各faceを三角形分割してメッシュ化します。いずれもメッシュとして書き出されます。 - プレーンbodyのface三角形分割は凸面を仮定します(プリミティブ形状では成立)。
生成されたEusLispファイルの使用
;; EusLisp環境での使用例
(load "robot.l")
(setq *robot* (robot)) ; URDFのロボット名または--nameで指定した名前
(send *robot* :angle-vector)
;; カスタム名を指定した場合
(load "robot.l")
(setq *robot* (my_robot)) ; --name my_robot で生成した場合
(send *robot* :angle-vector)
ロボット名の制約
--nameオプションで指定するロボット名は、EusLispの識別子として有効である必要があります:
- 文字または
_で始まる - 文字、数字、
_、-のみ使用可能 - EusLispの予約語(
if,defun,nilなど)は使用不可 - 空文字列やスペースを含む名前は使用不可
有効な例: my_robot, robot-v1, MyRobot, _robot, robot123
無効な例: 123robot, robot name, robot.name, if, defun
YAMLファイル
ロボットの関節グループ、エンドエフェクタ、初期ポーズを設定できます。
PR2ロボットの設定例
実際のPR2設定ファイルを参考にした例:
# 関節グループの定義
torso:
- torso_lift_joint : torso-waist-z
larm:
- l_shoulder_pan_joint : larm-collar-y
- l_shoulder_lift_joint : larm-shoulder-p
- l_upper_arm_roll_joint : larm-shoulder-r
- l_elbow_flex_joint : larm-elbow-p
- l_forearm_roll_joint : larm-elbow-r
- l_wrist_flex_joint : larm-wrist-p
- l_wrist_roll_joint : larm-wrist-r
rarm:
- r_shoulder_pan_joint : rarm-collar-y
- r_shoulder_lift_joint : rarm-shoulder-p
- r_upper_arm_roll_joint : rarm-shoulder-r
- r_elbow_flex_joint : rarm-elbow-p
- r_forearm_roll_joint : rarm-elbow-r
- r_wrist_flex_joint : rarm-wrist-p
- r_wrist_roll_joint : rarm-wrist-r
head:
- head_pan_joint : head-neck-y
- head_tilt_joint : head-neck-p
# エンドエフェクタ座標系
larm-end-coords:
parent : l_gripper_tool_frame
rotate : [0, 1, 0, 0]
rarm-end-coords:
parent : r_gripper_tool_frame
rotate : [0, 1, 0, 0]
head-end-coords:
translate : [0.08, 0, 0.13]
rotate : [0, 1, 0, 90]
# 事前定義ポーズ
angle-vector:
reset-manip-pose : [300.0, 75.0, 50.0, 110.0, -110.0, -20.0, -10.0, -10.0, -75.0, 50.0, -110.0, -110.0, 20.0, -10.0, -10.0, 0.0, 50.0]
reset-pose : [50.0, 60.0, 74.0, 70.0, -120.0, 20.0, -30.0, 180.0, -60.0, 74.0, -70.0, -120.0, -20.0, -30.0, 180.0, 0.0, 0.0]
グループ定義の効果
YAMLファイルでグループを定義すると、EusLispで以下のようなメソッドが使用できるようになります:
;; PR2ロボットの例
(setq *robot* (pr2))
;; 右腕の現在の関節角度を取得
(send *robot* :rarm :angle-vector)
;; => #f(-60.0 74.0 -70.0 -120.0 -20.0 -30.0 180.0)
;; 右腕の関節リストを取得
(send *robot* :rarm :joint-list)
;; => (#<rotational-joint r_shoulder_pan_joint>
;; #<rotational-joint r_shoulder_lift_joint> ...)
;; 関節名を取得
(send-all (send *robot* :rarm :joint-list) :name)
;; => ("r_shoulder_pan_joint" "r_shoulder_lift_joint"
;; "r_upper_arm_roll_joint" "r_elbow_flex_joint" ...)
;; 右腕の関節角度を設定
(send *robot* :rarm :angle-vector #f(0 0 0 -90 0 0 0))
;; 事前定義ポーズの使用
(send *robot* :reset-pose)
設定項目の詳細
関節グループ
グループ名: ロボットの部位名(rarm, larm, head など)関節名 : EusLisp関節名: URDFの関節名とEusLispでの関節名のマッピング
エンドエフェクタ座標系
parent: 座標系を取り付ける親リンク名translate: [x, y, z] 平行移動(メートル単位)rotate: [x, y, z, angle] 回転軸ベクトルと角度(度単位)
事前定義ポーズ
angle-vector: ポーズ名と対応する関節角度リスト- 関節角度は度単位で指定
- 関節の順序はYAMLファイル内の関節グループの定義順序に従う
依存関係
- Python 3.6+
- scikit-robot
- trimesh
- numpy
ライセンス
MIT License
貢献
プルリクエストやイシューの報告を歓迎します。
関連プロジェクト
- scikit-robot - Pythonロボットモデリングライブラリ
- EusLisp - Lispベースのロボットプログラミング言語
Release files for urdfeus 1.2.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| urdfeus-1.2.3.tar.gz | 97.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| urdfeus-1.2.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 193.4 kB
Release files / urdfeus-1.2.3.tar.gz
| Download URL | urdfeus-1.2.3.tar.gz |
|---|---|
| Size | 97.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc131fa7891843218a1ada5a114a665146257266c3bb9273bceb60d6a8e65345
|
|
BLAKE2b-256 checksum How to use checksums |
b326bdf23e6f114078e809d0613d51e1650ab53742f9490e34ac9a9f4a3c6e0e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.25
|
Release files / urdfeus-1.2.3-py3-none-any.whl
| Download URL | urdfeus-1.2.3-py3-none-any.whl |
|---|---|
| Size | 95.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9f4a607cb6b49d775ea3363174a6b0da8365418f9ec4a1d8085ef9df93dadcd0
|
|
BLAKE2b-256 checksum How to use checksums |
938f36697a12dc4749c8437127851b2f0f1f4f8166f04a1271008573c9773039
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.9.25
|