Sim Env Builder は何をしますか?
目標: 1つの説明文から、物理的に正確で見た目も良い、動作するシミュレーション環境を、最小限のユーザーターン数(理想的には: リクエスト -> 1回の確認 -> 完了)で提供すること。 品質基準: すべてのスモークテストが合格し、レンダリング画像を実際に確認し、それがリクエストと一致していること。
SKILL_DIR 以下 = このファイルのディレクトリ。Pythonヘルパーは SKILL_DIR/scripts/simkit にあります。
フェーズ0 - セットアップ (1分)
PY=$(bash SKILL_DIR/scripts/setup_env.sh) # mujoco, trimesh, usd-core, gymnasium がインストールされたPython
$PY SKILL_DIR/scripts/check_platform.py # OS, GPU, Isaac の利用可否を確認
環境フォルダを選択: ユーザーが指定しない限り、カレントディレクトリに ./<short_snake_name>/ を作成します。
フェーズ1 - バックエンドの選択 (reference/backend_choice.md を参照)
Isaac Sim を使用するには、Linux/Windows 上で NVIDIA RTX GPU が必要です。MuJoCo はどこでも動作します。
- MuJoCo: デフォルト。接触の多い操作や移動、高速なイテレーション、CPU/ラップトップ/macOS、小~中規模のシーン、モデルベース制御、再現可能な研究、GPU RL 向け MJX/Warp。
- Isaac Sim: フォトリアルな RTX レンダリングまたは合成データ(Replicator)、RTX LiDAR/カメラセンサーのリアリズム、Isaac Lab での数千の並列環境、大規模な USD/Omniverse シーン、ユーザーが既に Isaac を使用している場合。
- Isaac の方が適しているが
isaac_runnable_hereが false の場合、確認時にその旨を伝え、代替案を提示: ここで MuJoCo でビルドして完全テスト + USD ステージと Isaac 用のスモークスクリプトを GPU マシン向けにエクスポート (reference/isaac.md)。実行していない Isaac の結果を主張してはいけません。
フェーズ2 - ビルド前にユーザーに確認 (reference/confirmation.md)
- まず、簡単なアセットスキャンを実行して概要を具体化します:
find_assetsを1回呼び出し (polypizza MCP)、各オブジェクトの役割ごとに1~3個のクエリをリストアップします。 - 1つの短い概要を送信 (テンプレートは reference/confirmation.md): バックエンドとその理由、シーンに含まれるもの、ロボット/エージェントとその制御インターフェース、Poly Pizza から調達するアセットと手続き型生成のアセット、主要な物理パラメータ(重力、摩擦、タイムステップ)、成果物、そして各項目に推奨されるデフォルト値を含む2~4個の質問。
- AskUserQuestion ツールが存在する場合はそれを使用して質問します。存在しない場合は、概要をメッセージとして送り、ユーザーの応答を待ちます。ユーザーが答える前にビルドを開始しないでください。 例外: ユーザーが「質問しないで / そのままビルドして」と言った場合 -> 仮定を SPEC.md に書き込み、処理を進めます。
- 確認された決定事項を
<env>/SPEC.mdに記録します (テンプレートは reference/confirmation.md)。
フェーズ3 - アセット: Poly Pizza を優先し、手続き型で補完 (reference/assets.md)
各オブジェクトの役割ごとに:
find_assets/search_models-> 結果を読み取ります (found / weak / not_found)。- found または weak ->
preview_models([...ids])でプレビューし、確認: 適切なオブジェクトか、スタイルは一貫しているか、現実的なシーンに不適切な玩具や漫画っぽいもの、複数オブジェクトのバンドル、スケールクラスの誤りを却下します。 - 承認 ->
download_model(id, "<abs env path>/assets/polypizza", "<role>")(クレジットは自動的にassets/polypizza/CREDITS.mdに記録されます)。 - not_found、却下、またはダウンロードエラー -> 手続き型:
simkit.proceduralのレシピ(木、建物、家具、街路備品、門、食器、地形...)を使用するか、プリミティブ /lathe/extrude/rockから自分で作成します。リクエストされたオブジェクトを絶対に省略しないでください。 <env>/assets/ASSETS.mdを作成: 役割 | ソース (Poly Pizza ID + タイトル + ライセンス、または手続き型レシピ) | 実寸 | 理由。モデルのタイトルが役割と異なる場合(「パークベンチ」をピクニックテーブルとして使用するなど)、その旨と、それでも適合する理由を記述するか、再検索するか、手続き型にします。 また、却下された候補もリストアップします (ID + 理由: 「漫画スタイル」「12オブジェクトのバンドル」)。たとえすべてが手続き型になったとしても、検索の過程を追跡可能にするためです。 Poly Pizza のモデルは静的メッシュです。関節を持つロボットや車両はsimkit.robotsから提供されます (Poly Pizza のメッシュをビジュアルジオメトリとして適用することも可能です)。
フェーズ4 - ビルド (reference/robots.md, templates/)
mkdir -p <env> && cp -r SKILL_DIR/scripts/simkit <env>/simkit # vendored: 環境は自己完結型
cp SKILL_DIR/templates/build_env.py SKILL_DIR/templates/env.py SKILL_DIR/templates/view.py <env>/ # 最初の2つを編集
build_env.pyはすべてを決定論的に(シード指定で)再生成し ->scene.xmlを出力します。simkit.scene.Scene(空、地面、ライト、注視カメラ、raw MJCF 用のセクション)、simkit.assets.glb_to_mujoco(glb, env, name, target={"height": m}, yaw_deg=..)(実世界サイズ、Z-up、色ごとのパーツ、box/hull/parts 衝突判定)、 フォールバックと地形にはsimkit.procedural、テスト済みロボット(クアッドローター、車、差動駆動、アーム+グリッパー、四足歩行)とそのコントローラーにはsimkit.robotsを使用します。- 実世界スケールは必須です (reference/assets.md のサイズ表)。オブジェクトは支持面の上に置かれます。
- ユーザーが指定したすべてのオブジェクトクラスが、概要で読み取り可能なサイズで明確に見える必要があります(「岩の多い道」には見える岩が必要で、7cmの点ではありません。「起伏のある地形」にはロボットスケールで見える起伏が必要です)。スモークテストでは、
hintsの下に点のようなオブジェクトがリストされます。 - 少なくとも2つの名前付きカメラ: 1つは概要用、もう1つは被写体(ロボット/タスクオブジェクトがフレームの約30~50%を占める)にフォーカスしたもの。ロボット搭載カメラがある場合はそれも含みます。固定センサーカメラは、ロボットのホームポーズによって遮蔽されてはいけません(スモークが15%以上のカバレッジをフラグします)。
world.py(シーンが独自の動的挙動を持つ場合):make_world(model)->world(model, data)を定義します。これはスモーク、試験官、ショーケース、env.py、view.py、ダッシュボードによってすべての物理ステップの前に呼び出されます。浮力/抗力、風、コンベア、信号機サイクル、スクリプト化された歩行者やNPC車両はここに記述し、決して controller.py 内には記述しないでください(パッシブテストやRLポリシーが、ボートが沈み、信号が変わらない世界を実行することになります)。タスクチェックでシミュレーションをステップ実行する場合も、これを呼び出す必要があります。controller.py: スクリプト化されたデモポリシー (make_controller(model)->ctrl(model, data)) で、環境がその役割を果たしていることを示します(ドローンがゲートを通過する、車がルートを走行する、アームがオブジェクトに到達する...)。 モジュールレベルでDEMO_SECONDS = <デモ全体の長さ>を設定します。スモークテストはこれを基に、デモ全体(ピック、リフト、プレイス / すべてのゲート)を撮影しチェックします。最初の4秒だけではありません。task_checks.py: 関数check_<name>(model, data) -> {"status", "value", "expect", "details"}をタスクレベルの物理検証用に定義します。ユーザーが述べた、または確認した各成功基準に対して1つのチェックを作成し(ユーザーの言葉にちなんで名前を付けます: 「足が接触している」->check_feet_in_contact)、さらにスポawnの健全性チェック(ロボットが支持面上で開始する)を追加します。少なくとも2つ。最初の実行前に、閾値と各メトリクスの正確な定義(基準点、単位: 「ローバー底面中心から着陸機中心までの距離、メートル」)を SPEC.md に書き込み、それを維持します。僅差で失敗した場合は、閾値を緩めるのではなく、コントローラ/シーンを修正します(閾値の変更は「確定計画からの変更」として明記する必要があります)。制限値の15%以内で合格したチェックは、そのマージンとともに報告されます(「傾き25.8度、制限30度」)。主張する動作(障害物での減速、信号サイクル、浮力、グリッパー保持)には、それを実際にテストするチェックが必要です。例えば、経路上に障害物を置き、ロボットが停止することをアサートします。シーンの主要な物理特性はすべて、物理的な目標値を用いた測定可能なチェックが必要です。ボールの転がり減速率、ボートの喫水線、ローバーの斜面登坂、低重力での落下時間、グリッパー保持力など。必要なセンサーもチェックします。デモ中にロボットカメラをレンダリングし、タスクを示す非ブランクの画像(例: 前方の並木)をアサートします。LiDARの場合は、妥当な範囲をアサートします。各タスクチェックは、スクリプト化されたロールアウトに加え、2~3の摂動ロールアウト(別のシード、開始姿勢、初速度、ライトフェーズ)でも実行します。たった1つの正確なロールアウトでのみ有効なチェックはほとんど意味がありません。把持チェックには、リフトとキャリー中に両方のフィンガーパッドとオブジェクトの接触が必要です (data.contactを読み取る)。単に「オブジェクトが上がった」だけでは不十分です。- 衝突判定: シンプルかつ正直に。木: 幹に衝突判定、樹冠は視覚のみ(ユーザーが樹冠への衝突を希望する場合を除く)。マルチローター: アームはカプセルまたはハル、プロペラを飲み込む1つのボックスではありません。非凸形状の小道具(顕微鏡、椅子、アーチ、棚)は
collision="parts"またはいくつかのプリミティブを使用します。1つの凸ハルでそれらを囲むと、視覚的に空であるスペースをブロックしてしまいます (collision_sheet.png で確認)。 env.py: Gymnasium スタイルのreset/step/renderを備え、タスク観測、報酬スタブ、終了条件を含みます。その__main__セルフテストは、デモコントローラ(または参照ポリシー)を使用して env API を通じて環境を駆動し、タスク目標に到達したかどうかを出力します。これは目標に到達可能であることの証明です。- デバッグ/カメラリグ用のボディとマーカー: geom グループ 4-5(レンダリングされない)、data.cameras には含めない。
- 吊り下げられたもの(天井灯、吊り看板、壁棚):
mounted_*またはhanging_*と名付け、浮遊オブジェクトチェックがそれらをスキップするようにします。 - 照明: ニュートラルホワイト(色付きライトなし)。追加ライトは最大2~3個。レンダリングで白い壁が白~グレーのままであることを確認します。
- シーンを正しく読み取るために必要なもの以上の、リクエストされていないドレッシングは追加しません。オプションの追加項目は概要にリストし、ユーザーが選択できるようにします。
- タイムボックス: ビルド開始時刻を記録します (
date)。ボーナス/ストレッチ項目(「折りたたみはボーナス」)は、すべての必須項目が合格した後にのみ追加し、最初に削除されます。ビルド開始から約60分経過したら、残りの調整を停止します。REPORT.md と README の結果を最終版として確定し、報告します(削除された項目をリスト)。報告がないビルドは、既知のギャップがあるビルドよりも悪いです。 - 予算: すべての必須項目が存在し、すべてのチェックが合格したら、追加項目の追加を停止します。ビジュアルチェック、README、レポートを完了します。追加項目は README にアイデアとして記載します。
- 変更のたびに
$PY build_env.pyを実行します。コンパイルエラーには行番号が含まれます。
フェーズ5 - スモークテスト (reference/smoke_tests.md)。3つすべて必須です。
cd <env> && $PY -m simkit.smoke scene.xml --out smoke --controller controller.py --task-checks task_checks.py
- レンダリングテスト - すべての名前付きカメラ + 自動ビューが、非ブランクで、照明が適切で、詳細なフレームをレンダリングすること。セグメンテーションにより、どのオブジェクトが表示されているかが示されます(表示されていないオブジェクトはフラグされます)。
- 物理試験官 - ソルバー/接触/摩擦/重力プローブ(シーン自身の設定を使用)、ロールアウトの安定性、貫通、落下、セトリング、アクチュエータステップ応答、決定論、タイムステップ感度、リアルタイム係数、レイアウト(浮遊/埋没/相互貫通する小道具)、さらにタスクチェック。
- ビジュアルチェック - あなたは
smoke/contact_sheet.png、smoke/filmstrip.png、smoke/collision_sheet.pngおよびsmoke/renders/内のクローズアップ画像を開いて確認し(Read ツールを使用)、チェックリストを具体的な観察結果とともにsmoke/visual_check.mdに記入する必要があります。
すべての FAIL を修正します。すべての WARN を調査します(修正するか、README でなぜ予想されるのかを説明します)。判定が PASS / PASS_WITH_WARNINGS-explained になり、ビジュアルチェックが正直にすべて「はい」になるまで、再ビルドと再実行を繰り返します。通常2~3回のイテレーションが必要です。最初のレンダリングが正しいことはめったにありません。
また、$PY env.py (ランダムアクション、有限な観測) を実行します。
フェーズ6 - Isaac Sim 成果物 (Isaac が選択された場合のみ; reference/isaac.md)
$PY -m simkit.usd_export scene.xml isaac/scene.usda (エクスポート + ローカル検証)、SKILL_DIR/templates/isaac_smoke.py を isaac/ にコピー、GPU マシンで実行する方法をドキュメント化します。何が実行され、何が実行されなかったかを明確に述べます。
フェーズ7 - 納品
<env>/README.md: シーンに含まれるもの、実行方法(ビルド、スモーク、env、ビューア: $PY view.py はデモコントローラをライブ実行します。通常の mujoco.viewer はパッシブ物理のみを表示します)、カメラ、アクチュエータ、コントローラ、タスクチェック、アセットクレジット、既知の制限事項。
ユーザーへの最終メッセージ: 判定行、構築されたもの、Poly Pizza と手続き型のどちらのアセットを使用したか、スモーク結果、smoke/showcase.mp4(視聴者が見るビデオ)、コンタクトシートとフィルムストリップへのパス、未完了または未検証の項目、および「確定計画からの変更」リスト(アセットやライセンスの変更、サイズ/数の変更、追加項目の削除) - 変更がない場合は空でも常に存在します。smoke/smoke_report.json と physics_report.json からすべての数値(合格したチェック、スコア、エラー)をコピーし、その summary_line をそのまま貼り付けます(「スモーク PASS: examiner 19 pass / 0 warn / 0 fail; task checks 9/9 pass; render ok」)。カウントを記憶から書かないでください。
最初のスモーク実行が完了したらすぐに <env>/REPORT.md を開始し、修正のたびに更新します。これにより、セッションが中断されてもレポートが残ります。最終メッセージはその最新バージョンです。
成果物レイアウト (厳密に維持すること。ツールとダッシュボードがこれに依存します)
<env>/
SPEC.md README.md REPORT.md build_env.py scene.xml env.py view.py controller.py task_checks.py
world.py (シーンが独自の動的挙動を持つ場合のみ)
simkit/ ベンダー化されたヘルパー
assets/polypizza/*.glb assets/polypizza/CREDITS.md assets/polypizza/polypizza_assets.json
assets/meshes/ assets/procedural/ assets/ASSETS.md
smoke/ (showcase.mp4 contact_sheet.png filmstrip.png collision_sheet.png renders/ rollout.mp4
physics_report.json render_report.json smoke_report.json env_manifest.json
SMOKE.md visual_check.md)
isaac/ (Isaac の場合のみ: scene.usda, isaac_smoke.py, README セクション)
苦労して得られたルール (それぞれが実際のビルドを壊した経験に基づく)
-
確認されたスコープ内に留まること。デモはユーザーが同意したことを示す(例:「立っていれば十分」は安定した立ち姿勢を意味し、新しい移動コントローラではない)。時間をシーン、アセット、チェック、ビジュアルレビューに費やし、ストレッチアイデアはREADMEにリストすること。
-
<visual>設定:sc.set_visual("map", znear=.., zfar=..)など。各要素は1度だけ出現できます。 -
カメラの
xyaxesを手計算しないこと: 代わりにScene.camera(name, pos, target)/simkit.scene.lookatを使用すること。 -
キーフレームの qpos リストを手書きしないこと:
scene.home[joint] = valueを設定します(ロボットが自動的に行います)。Scene.writeはジョイント名でhomeキーフレームを構築し、それに一致するように位置アクチュエータのctrlを設定します。 -
薄い/平らなメッシュは
inertia="shell"が必要です (glb_to_mujoco が行います)。ビジュアルジオム:contype=0 conaffinity=0 group=2 mass=0。衝突プロキシはグループ3に配置します。 -
ワールドに溶接されたロボットは、自身のベースと衝突します: ベース/最初のリンク用に
<exclude>を追加します。