# シミュレーション: ローカルまたはサーブ

シミュレートされた環境は、2つの方法で駆動できます：

- **バッチ化された環境**として（`--env.*`）: 1つのタスクに対して複数の環境を、各 `step()` 呼び出しでまとめてステップを進めます。`lerobot-eval` と学習中の評価で使用されます。
- **シミュレーションロボット**（`--robot.type=sim`）として：`Robot` インターフェースの背後に1つの環境があり、実ハードウェアと交換可能です。`lerobot-rollout`、`lerobot-record`、`lerobot-teleoperate`、`lerobot-replay` がこれを使用します。

**ローカル**で実行するか、環境 API を介して実行するか、`lerobot-env-server` によって**サーブ**されるかのいずれかです。通常、シミュレーターの依存関係がポリシーの依存関係と衝突しないよう、専用の Docker イメージ内で動作します。`endpoint` を設定するとサーブ実行が選択されます。どちらのパスも、同じ正規化された観測（HWC の uint8 画像、フラットな float32 状態）、エピソードの終了、および制御規約を公開します。

このコードは3つのレイヤーを分離しています:

- **env**（`lerobot.envs`、`--env.type`）は、LeRobot コマンドが実行する対象であり、`EnvConfig` によって設定されます。すべての env がシミュレーターであるとは限りません。`gym_manipulator` は実物のロボットを制御します。
- **sim**（`lerobot.sim`）は、シミュレートされた環境の背後にあるシミュレーターです。その統合を指定する`SimConfig`を持ち、`LocalVectorEnv`によってステップが進められ、torch は使用しません。
- **env server**（`lerobot.env_server`）はシミュレーションを提供し、`RemoteVectorEnv` は `LocalVectorEnv` と同じ API を使用してそれを制御します。

## チェックポイントの評価

ローカルでは、LeRobotの隣にシミュレーターをインストールします([LIBERO](./libero)を参照):

```bash
lerobot-eval \
  --policy.path=lerobot/smolvla_libero \
  --policy.pretrained_revision=a24f1f380461b665158d52acd140152c79e8b36d \
  --policy.device=cuda \
  --env.type=libero --env.task=libero_spatial --env.task_ids='[0]' \
  --rename_map='{"observation.images.image": "observation.images.camera1", "observation.images.image2": "observation.images.camera2"}' \
  --eval.n_episodes=1 --eval.batch_size=1 \
  --output_dir=outputs/eval_libero
```

Served: 同じ環境でサーバーを起動し（[環境のサービング](#serve-an-environment)を参照）、そのエンドポイントを追加します:

```bash
lerobot-env-server --config_path=docker/sim/configs/libero.yaml --docker=true
lerobot-eval ... --env.server.endpoint=tcp/127.0.0.1:7448
```

サーバーのすべてのオプションは`--env.server.*`の下にあり、ローカル実行には適用されません。クライアントは、サーバー設定で指定されている`--env.type`に由来するデプロイメント名を要求します。別のデプロイメントを使用するには`--env.server.deployment`を渡します。エンドポイントまたはデプロイメントが誤っている場合、`--env.server.handshake_timeout_s`（10秒）以内に失敗し、そのエンドポイントが提供しているものを示します。TLSで保護されたサーバーに対しては、リモート推論と同様に、そのZenoh JSON5ファイルを`--env.server.zenoh_config_path`で渡します。サーバーは、コマンドが記述する環境を実行する必要があります。つまり、同じtype、task、制御規約、シミュレートされた本体（`robot_type`）です。そうでない場合、評価は開始を拒否し、差分を列挙します。その他の異なるオプション（解像度、エピソード長など）は警告としてログに記録されます。

Observation の名前は環境から取得されます（`observation.images.<camera>`、`observation.state`）。チェックポイントが他のカメラ名で学習された場合は、他のロボットと同様に `--rename_map` でそれらをマッピングし、複数のカメラが同じ形状を持つ場合でも、各カメラのアイデンティティを保持してください。プレースホルダーカメラ（`empty_cameras`）はチェックポイントに保存されるポリシー設定であり、必要に応じて `--policy.empty_cameras` で上書きしてください。

最初のステップの前に、リネーム後のすべてのチェックポイント入力が環境内に存在し、状態とアクションの次元数およびRGBチャネル数が一致している必要があります。画像の高さと幅は異なっていても構いません。リサイズはポリシーの事前処理が担当します。コントローラーの規約（デルタアクションと絶対アクション、回転形式）はチェックされません。環境の規約で学習されたチェックポイントを使用してください。

各 `step()` は、バッチ内の未完了のすべての環境を1回ずつ進めます。終了した環境は、次のリセットまでターミナル観測を保持し、他の環境をステップしても再開されません。`--eval.use_async_envs=true` (デフォルト) を使用すると、各環境はローカルまたはサーバー上で独自のワーカープロセスとして実行され、バッチは並列でステップされます。サーバーはバッチあたり最大 `max_envs` 個の環境 (デフォルトは32) を受け入れます。`--env.server.encoding=jpeg` (または `--robot.env.server.encoding=jpeg`、`--env.server.jpeg_quality` を併用、デフォルトは90) を指定すると、配信されるカメラフレームをJPEGとして送信します。これにより、リモートサーバーでは応答が小さくなりバッチサイズを大きくできますが、エンコード時間と有圧縮フレームというコストが発生します。localhost では、生フレームの方が高速です。応答にはバッチ内のすべての環境のフレームが含まれ、両端で `max_payload_bytes` (デフォルトは32 MiB) に収まる必要があります。収まらない場合、サーバーはバッチの開始時に拒否します。大規模なバッチや高解像度カメラを使用する場合は、サーバー側 (YAML の `zenoh` セクションの `max_payload_bytes`、`listen_endpoints` の隣) とクライアント側 (`--env.server.max_payload_bytes`、または `--robot.env.server.max_payload_bytes`) で値を引き上げてください。

## シミュレーションロボットを実行する

バッチ化された環境やシミュレーションロボットとして使用する場合と同じ環境:

```bash
lerobot-eval    --env.type=libero --env.task=libero_spatial --env.task_ids='[0]' ...
lerobot-rollout --robot.type=sim --robot.env.type=libero --robot.env.task=libero_spatial --robot.task_id=0 ...
```

例えば:

```bash
lerobot-rollout \
  --robot.type=sim --robot.env.type=libero --robot.env.task=libero_spatial --robot.task_id=0 \
  --task="pick up the black bowl between the plate and the ramekin and place it on the plate" \
  --policy.path=lerobot/smolvla_libero \
  --policy.pretrained_revision=a24f1f380461b665158d52acd140152c79e8b36d \
  --rename_map='{"observation.images.image": "observation.images.camera1", "observation.images.image2": "observation.images.camera2"}' \
  --device=cuda --fps=20 --inference.type=sync \
  --display_data=true --display_mode=rerun \
  --return_to_initial_position=false --play_sounds=false
```

- `--robot.env.*` は、評価における `--env.*` と同じオプションを受け取ります。`--robot.task_id` はロボットが実行する 1 つのタスクを選択しますが、評価ではスイートのすべてのタスク、または `--env.task_ids` に指定されたタスクが実行されます。EnvHub の環境は `--robot.env.type=envhub --robot.env.hub_path=<user/repo> --robot.env.trust_remote_code=true` です。
- 一部のポリシーは、環境のプロセッサ（LIBERO上のXVLAとCosmos3、Isaac Lab Arena）が必要です。`lerobot-eval` はこれらを適用します。`--inference.type=sync` を使用したシミュレーションロボットも同様です。リモート推論では適用されないため、起動時にそのようなチェックポイントを拒否します。
- `--robot.env.server.endpoint=tcp/...` は、バッチ化された環境に対して `--env.server.endpoint` が行うのと同様に、環境を env サーバー上で駆動します。ロボットは、そのサーバーがその環境を実行していることを確認します。
- 各 `send_action()` は環境をちょうど1ステップだけ進めます。観測の読み取り、ポリシーの推論、および待機はシミュレーションを進めません。既存の制御ループがリアルタイムのペース配分を管理します。
- `--fps` は、環境の制御レートに等しくなければなりません。補間を行う場合は、`--interpolation_multiplier` で割った値に等しくなければなりません。これは、すべてのコマンドが環境を1回進めるためです。録画を行う場合、`--dataset.fps` は `--fps` に等しくなければなりません。そうでない場合、ロールアウトは開始を拒否します。

シムロボットはロボットです: `--robot.type=sim --robot.env.*` を実際のフォロワーの `--robot.*` に置き換えるだけで、それ以外はすべてそのままです。テレオペレーターは、フォロワーを操作するようにシムロボットを操作します (SO-101のツインの場合は `--teleop.type=so101_leader`)。これは、環境がフォロワーのアクション名と単位を宣言している場合に有効で、不一致がある場合は最初のアクションで報告されます。 `lerobot-record` は、環境が宣言したボディをデータセットの `robot_type` として保存します (LIBEROの場合は `panda`)。宣言がない場合は `sim_robot` になります。

記録されたエピソードは環境のそれに従います。`lerobot-record` とエピソード単位のロールアウト戦略は、各エピソードの開始時にシミュレーション環境を再起動し、環境のエピソードが終了したとき（成功、終了、またはステップ数の上限に達したとき）またはその期間が満了したとき、いずれか先に起きた時点で終了します。したがって、各記録されたエピソードは、その初期状態からの 1 つのシミュレーションエピソードになります。手動でのリセットは不要なため、エピソード間のリセットフェーズは `--dataset.reset_time_s=0` でスキップし、エピソード単位のロールアウト戦略を使用する場合は `--strategy.reset_to_initial_position=false` も渡してください。エピソードが終了すると、ロボットは停止します。アクションを無視して最終状態を保持し、`latest` は最終報酬、終了、成功を保持します。その後、テレオペレーションとベースのロールアウト戦略が新しいエピソードを開始します（戦略はポリシーもリセットします）、そしてリプレイは停止します。センチネル、ハイライト、DAgger 戦略は、エピソード単位ではなく時間またはオンデマンドで記録するため、まだシミュレーションロボットをサポートしていません。記録にはエピソード単位の戦略を使用してください。実ロボットには影響ありません。そのエピソードは時間ベースであり、シーンは手動でリセットされます。成功率については、`lerobot-eval` とバッチ化された環境で評価してください。

ロボットのカメラ機能は、実ハードウェアでの録画と同じ`observation.images.<camera>`という名前を使用します。無名の単一カメラは`observation.images.image`です。バッチ評価では、単一カメラの場合`observation.image`など、環境自身のキーが保持されます。その名前のチェックポイントを`SimRobot`を通じてデプロイする場合は、`--rename_map='{"observation.images.image": "observation.image"}'`を使用してください。

リモート推論では、`--robot.*` オプションをそのまま維持し、ローカルポリシーおよび推論オプションを以下に置き換えてください。

```bash
--inference.type=remote \
--inference.endpoint=tcp/127.0.0.1:7447 \
--inference.deployment=libero \
--inference.semantics=libero-delta-v1
```

[リモート推論セットアップ](./remote_inference)を使用して、ポリシーサーバーを別途起動します。そのスキーマは、`--rename_map`適用後のロボットの観測値と一致する必要があります。ポリシーサーバーがチェックポイントをロードするため、ロールアウトコマンドから`--policy.path`を省略してください。ローカルRTCでは、ポリシーのRTC設定とともに`--inference.type=rtc`を使用します。

ポリシーが遅延している場合、シミュレーションロボットを保持しても物理シミュレーションは進行しません。シミュレータの障害は、ロールアウトのシャットダウンに伝播します。

## 環境をサーブする

LeRobotのソースチェックアウト（イメージはこれからビルドされます）から、リポジトリのルートで実行します:

```bash
lerobot-env-server --config_path=docker/sim/configs/libero.yaml --docker=true
```

`--docker=true` は `docker/sim/compose.server.yaml` を使用し、`sim.type` からイメージを選択して、有効な YAML をマウントし、ホストネットワーク上でコンテナを実行します。これにより、`--zenoh.listen_endpoints` で指定がない限り、サーバーは `localhost:7448` でリッスンします。別のシミュレーターを選択するには、YAML を差し替えてください。各シミュレーターの制御レート、アクションの規約、コンポーネント名、ロボットタイプは、その統合の `conventions()` から取得されるため、YAML にはタスク名とシミュレーターのオプションのみを指定します。

`lerobot-policy-server` については、すべての YAML フィールドがネストされたコマンドライン上書きを受け付け、ファイル自体は変更されません。`sim.kwargs` のような辞書値は、YAML のものにマージされます:

```bash
lerobot-env-server --config_path=docker/sim/configs/libero.yaml --docker=true \
  --sim.task=libero_goal \
  --sim.kwargs='{gym_kwargs: {observation_height: 256, observation_width: 256}}'
```

有効な設定は`$HF_LEROBOT_HOME/sim`以下に保存されるため、コンテナを再起動しても検出されます。設定を切り替えるとサーバーが再作成され、アクティブなセッションは終了します。イメージが存在しない場合はビルドされます。シミュレーターやLeRobotのソースを変更した後に再ビルドするには`--build=true`を追加し、サーバーを停止するには`--stop=true`を追加します。コンテナはEGLレンダリングのためにDockerのGPUアクセスを必要とします。[EnvHub](./envhub)リポジトリは`--envhub=<user/repo>`で提供されます。[EnvHubとシミュレーターサーバー](./envhub#envhub-and-the-simulator-server)を参照してください。

> [!TIP]
> Vulkan でレンダリングするシミュレーター（Isaac Sim、または RoboMME のように独自の Vulkan ファイルをイメージに同梱している ManiSkill/SAPIEN など）が、Docker 外では動作するのにコンテナ内で `vkCreateInstance failed` または `ERROR_INCOMPATIBLE_DRIVER` で失敗する場合、コンテナには NVIDIA ドライバーのライブラリは存在しますが、それらを指すローダーファイル（`/usr/share/vulkan/icd.d/nvidia_icd.json`、`/usr/share/glvnd/egl_vendor.d/10_nvidia.json`）が不足しています。`gpus: all` で使用される NVIDIA Container Toolkit のデフォルトモードではこれらがマウントされない場合がありますが、[CDI モード](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/cdi-support.html)ではマウントされます。CDI 経由で GPU を要求してください（`docker run` では `--device nvidia.com/gpu=all`、`docker/sim/compose.server.yaml` では `gpus: all` の代わりに `devices: [nvidia.com/gpu=all]` を指定）、またはこれらの 2 つのファイルをイメージに追加してください。

`--docker=true` を指定しない場合、同じコマンドは現在の環境でサーバーを実行します。シミュレーターのネイティブ依存関係を隔離された環境にインストールし、`--no-deps` を付けて LeRobot をインストールし、`docker/sim/requirements.txt` をインストールします。いずれの場合も localhost でリッスンします。他のマシンからの接続を受け入れるには、それらのマシンが到達できるネットワークインターフェースのアドレスを渡します。例えば `--zenoh.listen_endpoints='[tcp/192.168.1.20:7448]'` のように指定し、YAML の `zenoh.config_file` で TLS とアクセス制御を追加します。

LIBERO のランタイムイメージは、変換済みの NumPy 初期状態ファイルを使用します。イメージのビルドでは、`scripts/ci/convert_libero_init_states.py` によって信頼できるアップストリームのアセットを変換し、サーバーは変換済みのファイルが欠落している場合は拒否します。RoboTwin と RoboMME は、それぞれネイティブなプランニングと ManiSkill のために独自の torch を必要とし、それらの torch のインストールはポリシー環境から分離されています。

Serverへのリクエストは再試行されません。曖昧なタイムアウトが発生した場合、クライアントは失敗します。その場合は、クライアントを閉じて新しいセッションを開いてください。

## ベンチマークを追加する

シミュレーターモジュール、規約、イメージ、CI統合については、[ベンチマークの追加](./adding_benchmarks)を参照してください。

