# ポリシーデプロイ（lerobot-rollout）

`lerobot-rollout` は、学習済みポリシーを実際のロボットにデプロイするための単一の CLI です。クイックな評価から、連続的な記録、ヒューマン・イン・ザ・ループによるデータ収集まで、複数の実行戦略と推論バックエンドをサポートしています。

## クイックスタート

ロボットとポリシーの追加機能以外に、追加の依存関係は必要ありません。

```bash
lerobot-rollout \
    --strategy.type=base \
    --policy.path=lerobot/act_koch_real \
    --robot.type=koch_follower \
    --robot.port=/dev/ttyACM0 \
    --task="pick up cube" \
    --duration=30
```

これは、録画なしでポリシーを30秒間実行します。

### デバイスの選択

ホスト上で利用可能なデバイスでチェックポイントのデバイスを上書きするには、`--device=cpu` または `--device=cuda` を渡します。解決されたデバイスは、ポリシーの読み込みとプロセッサの構築の前に、ポリシー設定に適用されます。例えば、ポリシーが CPU での実行をサポートしている場合、上記のコマンドに `--device=cpu` を追加することで、CPU のみのホスト上で CUDA で学習されたチェックポイントを実行できます。ロボットにデプロイする前に、CPU 推論が要求される制御レートを満たせることを確認してください。

`--device` が省略された場合、rollout は設定されているポリシー設定のデバイスを使用し、設定されていない場合は利用可能なデバイスを自動的に選択します。`RolloutConfig(device=...)` と `build_rollout_context` にも同じ動作が適用されます。

---

## 戦略

`--strategy.type=<name>` を使用して戦略を選択します。各戦略は、独自の記録およびインタラクションのセマンティクスを持つ異なる制御ループを定義します。

### Base (`--strategy.type=base`)

データの記録なしで自律的にポリシーを実行します。クイックな評価、デモ、またはロボットを観察するだけの場合に使用してください。

```bash
lerobot-rollout \
    --strategy.type=base \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --task="Put lego brick into the box" \
    --duration=60
```

| フラグ             | 説明                                            | デフォルト |
| ---------------- | ------------------------------------------------------ | ------- |
| `--duration`     | 実行時間（秒）（0 = 無限）                     | 0       |
| `--task`         | ポリシーに渡されるタスクの説明                  | --      |
| `--display_data` | Rerun に observations/actions をストリーミングして可視化 | false   |

### Sentry (`--strategy.type=sentry`)

Hugging Face Hub への定期的なアップロードを伴う、継続的な自律録画。エピソードの境界はカメラの解像度と FPS から自動計算されるため、保存される各エピソードが完全な動画ファイルとして生成され、アップロードの効率性が保たれます。

Policy state (hidden state, RTC queue) persists across episode boundaries: the robot does not reset between episodes.

```bash
lerobot-rollout \
    --strategy.type=sentry \
    --strategy.upload_every_n_episodes=5 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --dataset.repo_id=${HF_USER}/rollout_eval_data \
    --dataset.single_task="Put lego brick into the box" \
    --duration=3600
```

| フラグ                                   | 説明                                           | デフォルト |
| -------------------------------------- | ----------------------------------------------------- | ------- |
| `--strategy.upload_every_n_episodes`   | NエピソードごとにHubにプッシュ                          | 5       |
| `--strategy.target_video_file_size_mb` | エピソードローテーション用のターゲット動画ファイルサイズ           | auto    |
| `--dataset.repo_id`                    | **必須。**記録されたデータセットのHubリポジトリ | --      |
| `--dataset.push_to_hub`                | 破棄時に Hub にプッシュするかどうか                    | true    |

### Highlight (`--strategy.type=highlight`)

メモリ有界リングバッファによるオンデマンド録画付きの自律ロールアウト。バッファは直近 N 秒のテレメトリをキャプチャします。保存キーを押すとバッファがフラッシュされライブ録画が開始され、もう一度押すとエピソードが保存されます。非同期バックエンドを使用する場合、各トグルは推論を一時停止し、キューイング中または補間されたモーションを無効化し、ブロッキングのドレインまたは保存の前にサポートされているローカルホールドを要求します。正常な実行は、その後、新しいキャプチャから再開されます。

```bash
lerobot-rollout \
    --strategy.type=highlight \
    --strategy.ring_buffer_seconds=30 \
    --strategy.save_key=s \
    --strategy.push_key=h \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=koch_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_highlight_data \
    --dataset.single_task="Pick up the red cube"
```

**キーボード操作:**

| キー                | アクション                                                   |
| ------------------ | -------------------------------------------------------- |
| `s`（設定可能） | 録画を開始（バッファをフラッシュ）/ 停止してエピソードを保存 |
| `h`（設定可能） | Push dataset to Hub                                      |
| `ESC`              | セッションを停止する                                         |

| フラグ                                   | 説明                                    |
| -------------------------------------- | ---------------------------------------------- |
| `--strategy.ring_buffer_seconds`       | バッファリングされたテレメトリの期間（デフォルト: 10）   |
| `--strategy.ring_buffer_max_memory_mb` | リングバッファのメモリ上限（デフォルト: 1024） |
| `--strategy.save_key`                  | 録画の切り替えキー（デフォルト: `s`）         |
| `--strategy.push_key`                  | Hubにプッシュするキー（デフォルト: `h`）              |

### DAgger (`--strategy.type=dagger`)

Human-in-the-loopデータ収集。自律的なポリシー実行と、テレオペレーターによる人間介入を交互に行います。介入フレームには`intervention=True`がタグ付けされます。テレオペレーター（`--teleop.type`）が必要です。

詳細な手順については、[ヒューマン・イン・ザ・ループ データ収集](./hil_data_collection)ガイドを参照してください。

**修正のみモード**（デフォルト）：人間の修正ウィンドウのみが記録されます。各修正が1つのエピソードになります。

```bash
lerobot-rollout \
    --strategy.type=dagger \
    --strategy.num_episodes=20 \
    --policy.path=outputs/pretrain/checkpoints/last/pretrained_model \
    --robot.type=bi_openarm_follower \
    --teleop.type=bi_openarm_mini \
    --dataset.repo_id=${HF_USER}/rollout_hil_data \
    --dataset.single_task="Fold the T-shirt"
```

**連続録画モード**（`--strategy.record_autonomous=true`）: 自律フレームと補正フレームの両方が、時間ベースのエピソードローテーション（Sentry と同じ）で録画されます。

```bash
lerobot-rollout \
    --strategy.type=dagger \
    --strategy.record_autonomous=true \
    --strategy.num_episodes=50 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM1 \
    --dataset.repo_id=${HF_USER}/rollout_dagger_data \
    --dataset.single_task="Grasp the block"
```

**キーボード操作**（デフォルトの入力デバイス）：

| キー     | アクション                                      |
| ------- | ------------------------------------------- |
| `Space` | ポリシーの実行を一時停止/再開             |
| `Tab`   | 人間の修正を開始/停止               |
| `Enter` | Push dataset to Hub (corrections-only mode) |
| `ESC`   | セッションを停止する                            |

`--strategy.input_device=pedal` を使用して、フットペダル入力もサポートされています。`--strategy.pedal.*` フラグでペダルコードを設定します。

ロボットがロールアウト時の位置ホールドをサポートする場合、ポーズすると、ドライバーが実際に適用した最後の位置ターゲット（クリッピングおよびグリップターゲットを含む）が更新されます。最初のコマンドの前に、検証済みの測定姿勢がターゲットとして提供されます。これにより、ターゲットを測定姿勢に変更するのではなく、コマンドされた位置誤差が保持されます。ポリシーの軌道進行が停止している間、ロボットはそのターゲットに向かって定常状態に落ち着き終えることができます。実際のロボット上でアームおよびグリップの動作を検証してください。このソフトウェアによるホールドは、グリップの保持や物理的な不動を保証するものではありません。

| フラグ                                 | 説明                                                                                                                                                    |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--strategy.num_episodes`            | 記録する修正エピソードの数（デフォルト: `--dataset.num_episodes`）                                                                                    |
| `--strategy.record_autonomous`       | 自律フレームも記録する（デフォルト: false）                                                                                                                  |
| `--strategy.upload_every_n_episodes` | NエピソードごとにHubにプッシュする（デフォルト: 5）                                                                                                                      |
| `--strategy.input_device`            | 入力デバイス: `keyboard` または `pedal` (デフォルト: keyboard)                                                                                                        |
| `--strategy.smooth_handover`         | ポーズ/修正開始時に制御をスムーズに引き継ぎます（デフォルト: true）。エンゲージ時に現在のロボットの姿勢を基準として再参照するクラッチ式のテレオペレーションでは、これを無効にしてください。 |
| `--teleop.type`                      | **必須。**テレオペレータータイプ                                                                                                                                |

### Episodic (`--strategy.type=episodic`)

`lerobot-record` の動作を模したエピソード単位の録画です。各エピソードではポリシーがロボットを駆動し、エピソード間のリセットフェーズでは、任意でテレオペレーターがロボットを駆動できます。

```bash
lerobot-rollout \
    --strategy.type=episodic \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --teleop.type=so100_leader \
    --teleop.port=/dev/ttyACM1 \
    --dataset.repo_id=${HF_USER}/rollout_eval_data \
    --dataset.num_episodes=20 \
    --dataset.episode_time_s=30 \
    --dataset.reset_time_s=10 \
    --dataset.single_task="Pick up the red cube"
```

Teleopはオプションです。省略した場合、リセットフェーズの間ロボットは位置を保持します。

**キーボード操作:**

| キー         | アクション                           |
| ----------- | -------------------------------- |
| `→`（右） | 現在のエピソードを早期に終了する    |
| `←`（左）  | エピソードを破棄して再録音する |
| `ESC`       | 録音セッションを停止します       |

| フラグ                                            | 説明                                                                                                                                                |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--dataset.num_episodes`                        | 記録するエピソード数                                                                                                                               |
| `--dataset.episode_time_s`                      | 各録音エピソードの長さ（秒）。`--duration`が設定されており、このオプションが設定されていない場合は、`--duration`の値がデフォルトとして使用されます。                                               |
| `--dataset.reset_time_s`                        | エピソード間のリセットフェーズの持続時間（秒）                                                                                                    |
| `--teleop.type`                                 | オプション。リセット中にロボットを操作するためのテレオペレーター                                                                                                    |
| `--strategy.reset_to_initial_position`          | エピソード間でロボットを初期位置にリセットするかどうか                                                                                        |
| `--strategy.smooth_leader_to_follower_handover` | リーダーからフォロワーへのスムーズなハンドオーバー動作をオンにするかオフにするかを指定します。                                                                                 |
| `--strategy.smooth_handover`                    | リセット開始時に、テレオペレーションへ制御をスムーズに引き継ぎます（デフォルト: true）。エンゲージ時に現在のロボットの姿勢を基準として再参照するクラッチ式のテレオペレーションでは、これを無効にしてください。 |

### 独自の戦略を持ち込む

`--strategy.type` は、上記の組み込み戦略だけでなく、環境に登録されている任意の戦略を受け入れます。戦略は、pip でインストール可能なパッケージ内の 2 つのクラスで構成されます。`RolloutStrategyConfig` に登録される設定クラスと、`Config` サフィックスを除いた同名の `RolloutStrategy` サブクラスです。これは [カスタムハードウェア](./integrate_hardware#the-4-core-conventions) と同じ `SomethingConfig`/`Something` の規約に従い、設定のモジュールまたはパッケージから解決されます。

```python
from dataclasses import dataclass
from typing import ClassVar

from lerobot.rollout import RolloutContext, RolloutStrategy, RolloutStrategyConfig

@RolloutStrategyConfig.register_subclass("patrol")
@dataclass
class PatrolStrategyConfig(RolloutStrategyConfig):
    dataset_mode: ClassVar[str] = "required"  # the engine creates the dataset for you
    legs: int = 2  # becomes --strategy.legs

class PatrolStrategy(RolloutStrategy):
    def run(self, ctx: RolloutContext) -> None:
        ...  # the paced control loop: see the contract on RolloutStrategy.run

    def teardown(self, ctx: RolloutContext) -> None:
        ctx.data.dataset.finalize()
        self._teardown_hardware(ctx.hardware, ctx.runtime.cfg.return_to_initial_position)
```

config は、エンジンが strategy の代わりに何を配置するかを宣言するため、LeRobot 内のどこもその型を知る必要はありません:

| 宣言                     | 効果                                                                                                                                     |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `dataset_mode`                  | `"none"`（デフォルト）は`--dataset.*`フラグを拒否し、`"optional"`は指定された場合に記録し、`"required"`は`--dataset.repo_id`を必須にします |
| `requires_teleop`               | `--teleop.type` を必須にします                                                                                                            |
| `supports_interactive`          | `--interactive=true`を許可します。`run()`は、`RolloutStrategy`にドキュメント化されている再起動可能な契約を遵守する必要があります。                             |
| `supports_sim_robot`            | `--robot.type=sim`を許可します。`run()`は、エピソードが終了するたびに新しいエピソードを開始する必要があります（`lerobot.robots.sim_robot`を参照）。                        |
| `requires_streaming_encoding()` | 制御ループ内でフレームが書き込まれた場合、`True`を返します: `--dataset.streaming_encoding`が強制オンになります                            |
| `extra_dataset_features()`      | Strategyが所有するデータセットの列（例えば、DAggerの`intervention`）。記録された各フレームにはこれらが含まれている必要があります                               |

ディストリビューションを`lerobot_strategy_<name>`と命名し、`lerobot-rollout`は CLI を解析する前にパッケージをインポートします。実行されるのは`__init__.py`のみなので、設定はそこでインポートしてください。他の名前のパッケージは、`--strategy.discover_packages_path=<package>` を使用して、サブモジュールを含む形で読み込まれます。ストラテジーの dataclass フィールドは`--strategy.*`フラグになります。

```bash
lerobot-rollout \
    --strategy.type=patrol \
    --strategy.legs=3 \
    --policy.path=${HF_USER}/my_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_patrol \
    --dataset.single_task="patrol the aisle"
```

`SentryStrategy`（録画、インタラクティブ安全）と`BaseStrategy`（録画なし）は、コピーするための参照実装です。`lerobot.rollout.strategies` の`send_next_action`、`safe_push_to_hub`、`estimate_max_episode_seconds` は、それらが基盤として利用するヘルパーです。

非同期バックエンドでは、ディスパッチ契約は必須です。各キャプチャされた観測値を`engine.notify_observation(obs_processed)`で公開し、**すべての自律モーターティック**（補間ティックおよびホールドティックを含む）で`send_next_action(...)`を呼び出し、その後`engine.pump_query(obs_processed)`を呼び出します。`engine.get_action()`のみを呼び出すと、パーミッションおよびホールドのハンドシェイクがバイパスされます。これにより、計画されたテキストクエリが無限に待機する可能性があり、ターミナルフォールトがシャットダウンをシグナルしない可能性があります。

サードパーティ製戦略では、`_init_engine(ctx)` の後に周期的なヘルスレポートを含めるために、`timer.tick(...)` の代わりに `self._tick(timer, new_cycle=interpolator.needs_new_action())` を呼び出すことができます。

`send_next_action` は `lerobot.inference.dispatch_tick` とその構成要素（`next_interpolated_action`、`commit_action`、`dispatch_permitted`）の上に構築されており、これらの順序を一度だけエンコードしています。アクションの取得前後および送信前に `dispatch_allowed()` を呼び出し、拒否された場合は補間の無効化とサポートされているローカルホールド、および `acknowledge_hold()` を実行し、送信後に `record_dispatch()` を呼び出します。失敗したホールドは決して確認されません。このシーケンスを再実装するのではなく、これらのヘルパーを使用してください。`send_next_action` が追加するのは、データセットフレーム、ロボット側のアクションプロセッサ、およびキャデンスの集計のみです。リモートコンテキストでは、`ctx.policy.policy`、`preprocessor`、`postprocessor` は `None` に設定されています。`ctx.policy.inference` と `ctx.processors` 内のロボット側のパイプラインを使用してください。

実行中の既知のブロッキング録画処理（リングバッファのドレインやエピソードの確定を含む）を`self._pause_for_recording(ctx)`でラップしてください。これにより、録画のストール前に非同期モーションが無効化され、実行が依然として健全かつアクティブな場合のみ再開されます。オペレーター制御フェーズを持つ戦略は、現在のモーション許可を`resume_allowed`として渡す必要があります。次のアクションは新しい観測から取得する必要があります。保存された作業によって、一時停止中、停止中、または障害が発生した実行を復活させてはいけません。

---

## ポリシーの予測の可視化

`--display_data` を使用すると、ビューアはアクションの他に、ポリシーが予測する内容も表示します。例えば、ワールドモデルが想像したカメラフレーム、予測されたサブタスク、カメラ上に描画されたバウンディングボックスなどです。各ポリシーは、予測する内容を決定し、独自の設定でそれを有効にします。例えば、LingBot-VA の場合は `--policy.return_predicted_video=true` です。予測は、予測対象の名前に基づいて命名されます。Rerun では、予測された `observation.images.top` は `prediction.images.top` として、予測されたサブタスクは `prediction.subtask` として、ボックスは対応するカメラの下（`<camera>/prediction`）に表示されます。Foxglove では、これらは `/prediction/...` トピックおよび `<camera topic>/prediction` 画像アノテーションとして公開されます。RTC を使用する場合、予測はチャンクごとに1回更新されます。ポリシーから予測を返す方法については、[Bring your own policy](./bring_your_own_policies) を参照してください。

## 推論バックエンド

`--inference.type=<name>` を使用してバックエンドを選択します。ローカル同期推論および RTC 推論は、以下で設定されたポリシーを使用します。[リモートバックエンド](./remote_inference) はサーバーからポリシー契約を取得し、ロボットコンピュータ上で重みをロードしません。

### Sync (デフォルト)

制御ティックごとに1回のポリシー呼び出し。メインループはアクションが計算されるまでブロックします。

すべてのポリシーと互換性があります。追加のフラグは不要です。

### リアルタイムチャンク分割（`--inference.type=rtc`）

バックグラウンドスレッドが非同期にアクションチャンクを生成します。メインの制御ループは次の実行可能なアクションをポーリングする一方で、ポリシーは並行して次のチャンクを計算します。

互換性のあるVLAモデル（Pi0、Pi0.5、SmolVLA）とRTCを使用することで、推論とモーションをオーバーラップできます。継続的な実行には、推論のレイテンシーとその変動をカバーするのに十分な量の利用可能なアクション再生が必要です。

```bash
lerobot-rollout \
    --strategy.type=base \
    --inference.type=rtc \
    --inference.rtc.execution_horizon=10 \
    --inference.rtc.max_guidance_weight=10.0 \
    --policy.path=${HF_USER}/pi0_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --task="Pick up the cube" \
    --duration=60 \
    --device=cuda
```

| フラグ                                        | 説明                                                                                         |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------- |
| `--inference.rtc.execution_horizon`         | 前のチャンクとブレンドする手順（デフォルト: ポリシーによって異なります）                                      |
| `--inference.rtc.mode`                      | `guided`（デフォルト）または、互換性のある Pi05 チェックポイント用の学習済みプレフィックス `trained`                      |
| `--inference.rtc.max_guidance_weight`       | 整合性強制の強度（デフォルト: ポリシーによって異なります）                                        |
| `--inference.rtc.prefix_attention_schedule` | ブレンドスケジュール: `LINEAR`、`EXP`、`ONES`、`ZEROS`                                                    |
| `--inference.queue_threshold`               | Backpressure threshold; 学習済みRTCは、その最大遅延時間以上を必要とします                             |
| `--inference.action_starvation_grace_s`     | サポート対象のロボット上で、飢餓状態後の新しいモーションを待機します（デフォルトは`1.0`。`0`の場合は即座に障害が発生します） |

RTCパラメータのチューニングの詳細については、[リアルタイムチャンキング](./rtc)ガイドを参照してください。

ローカル RTC は、トランスポートなしで、ロールアウトプロセス内のバックグラウンドスレッドで実行されます。同じコンピュータ上のサーバーとクライアントは、代わりに`--inference.type=remote`を使用します。チャンクの整列/ブレンドおよび非同期バックエンドで共有される[待機動作](./remote_inference#what-the-robot-does-while-waiting-or-stopping)については、[リモートガイド](./remote_inference)を参照してください。

**Waiting には対応ロボットが必要です。** 通常のローカル RTC はこの機能なしでも利用可能ですが、計画されたテキスト / 指示変更の一時停止や回復可能な starvation には必要です。位置制御の SO、OMX、Koch、HopeJr、Rebot フォローアはこれに対応しています。OpenArm、Reachy2、両手操作ラッパーには、[ロボットサポート表](./integrate_hardware#waiting-between-predictions)に記載されている設定制約があります。対応する場合、空のバッファは、古い推論の排出と新しいキャプチャからの予測に必要な時間を含め、`action_starvation_grace_s`（デフォルト 1 秒）の間、最後に適用されたターゲットを保持できます。モーションが開始された後、grace がゼロまたは非対応のロボットの場合、枯渇時に即座にフォールトします。起動には独自の期限があります。従来のローカル RTC パスとは異なり、枯渇はもう無期限にスキップされるティックではありません。grace は、期限切れのリクエストや鮮度制限を延長しません。

Local RTC は、`--inference.` を通じてこれらの追加の予算を公開します:

| パラメータ               | デフォルト | 意味                                      |
| ----------------------- | ------- | -------------------------------------------- |
| `max_observation_age_s` | `5 s`   | アクション実行によるソースの最大経過時間  |
| `action_timeout_s`      | `10 s`  | 未処理のアクションリクエスト                   |
| `startup_timeout_s`     | `120 s` | 初期準備とフレッシュアクションの起動 |
| `language_timeout_s`    | `120 s` | 計画されている言語操作                   |

これらは初期値であり、測定されたハードウェアの保証ではありません。RTCは、次の推論とタイミングの余裕分だけ、**トリム後の再生**を保持する必要があります。推論が利用可能な予測ホライズンを常時消費してしまう場合、`queue_threshold`を上げても効果はありません。レイテンシを削減するか、より長いホライズンや異なるアクション周波数を検証してください。

ターミナルフォールトでは、ポリシーの動作が自動的に再開されることはありません。利用可能な観測の取得とアクチュエータの制御がある場合、シャットダウンは`--return_to_initial_position`（デフォルトは true）を尊重し、切断を行います。リターン処理では完全な観測を読み取るため、カメラの永続的な故障がこれを妨げる可能性があります。コマンド適用の失敗は、sync を含むすべてのバックエンドにおいて、さらなるシャットダウン時の動きを抑制します。これにより、同期予測が変更されることも、カメラ固有の復旧が導入されることもありません。

コンパイルと命令の変更

RTC コンパイルでは、モーションの前に、初期呼び出しとプレフィックス付き呼び出しの両方をウォームアップします。これには、代表例としての非ゼロの遅延が含まれます。`--compile_warmup_inferences` のデフォルト値は 2 ですが、RTC を有効にするには少なくとも 3 が必要です。実際の回数は起動ログに報告されます。ウォームアップは `startup_timeout_s` の範囲内に収まる必要があります。テンソルの形状を変更する後続の指示は、再コンパイルをトリガーし、再生や操作の期限超過を引き起こす可能性があります。

推論中のタスク変更により、不要になった結果は破棄されます。対応するロボットは一時停止し、新しいアクションを要求します。この待機機能がなければ、残りのアクションが尽きてしまう可能性があります。これらのロボットでは、実行の間にタスクを変更することを推奨します。

---

## インタラクティブセッション

`--interactive=true` を追加すると、即座に開始するのではなく、ターミナルからロールアウトを操作できます。ハードウェアの接続とポリシーの読み込みは通常どおり行われますが、**`/start` を入力するまでロボットは静止したままです**。まずシーンを配置したい場合、試行の間にポリシーに再指示を出したい場合、または読み込み時間を再発生させずに複数回の撮影を行いたい場合に便利です。

```bash
lerobot-rollout \
    --strategy.type=base \
    --policy.path=${HF_USER}/my_smolvla_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}}" \
    --task="pick up the cube" \
    --interactive=true
```

| コマンド             | アクション                                                                                                                                                                                                                                                                                                                  |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/start`            | ポリシー制御ループを開始(または再起動)します                                                                                                                                                                                                                                                                              |
| `/subtask <text>`   | 現在のラン内の指示を変更します。非同期推論が計画されたホールド状態に入る可能性があります。引数なしで現在のタスクを表示します。言語に条件付けされるポリシー（SmolVLA、π0/π0.5、および類似のもの）にのみ影響します。[外部プランナー](#external-planner)を使用している場合、`/subtask`はautosteerから制御を返却します。 |
| `/vqa <text>`       | ロボットが現在見ているものに関する質問を行います。実行が進行中の場合のみ、かつポリシーのテキストヘッドまたは[外部プランナー](#external-planner)を使用している場合のみ可能です。                                                                                                                                                       |
| `/autosteer <goal>` | 高レベルの目標を渡して、ポリシーのテキストヘッドまたは[外部プランナー](#external-planner)にサブタスクを選択させます。`/autosteer off`で制御を返却します。引数なしで現在の目標を報告します                                                                                                                  |
| `/reset`            | 動きを停止し、ロボットを起動位置に戻し、`--task` 指示を復元します                                                                                                                                                                                                                           |
| `/stop`             | セッションを終了し、通常のシャットダウンルーチンを実行します                                                                                                                                                                                                                                                                    |
| `/help`             | コマンドをリスト表示する                                                                                                                                                                                                                                                                                                       |

```text
> /start
Rollout running — task 'pick up the cube'. /subtask <text> to change it, ...
> /subtask put the cube in the box
Task: 'pick up the cube' → 'put the cube in the box' (applies from the next policy inference)
> /vqa is the cube inside the box?
Asked: 'is the cube inside the box?' — answering from the next observation...
Q: is the cube inside the box?
A: No — the cube is on the table to the left of the box.
> /reset
Task restored to 'pick up the cube'
Resetting — returning the robot to its initial position...
Robot reset — holding at initial position. /start to run.
> /stop
```

`>` で始まる行は、ユーザーが入力する内容です。セッション自体はプロンプトを表示しません。

`Ctrl-C` は通常どおりシャットダウンを実行し、stdin のクローズ（`Ctrl-D`、またはパイプされたスクリプトの終了）でセッションが終了します。そのため、パイプされたスクリプトは、意図した期間にわたって stdin をオープン状態に保つ必要があります。

```bash
(printf '/start\n'; sleep 60; printf '/stop\n') | lerobot-rollout ... --interactive=true
```

**`/subtask`** は、その後の推論におけるタスクを更新します。`--inference.type=sync` を使用する場合、事前計算されたチャンクアクションは破棄されます。ローカル RTC またはリモート推論の場合、アクション要求中にタスクが変更されると、古い結果は破棄されます。ローカルホールドをサポートするロボットでは、エンジンはキューイング中または補間中のモーションを無効化し、制御ループがホールドを確認するのを待ってから、新しいタスクのもとで新しいモーションを要求します。この遷移中に停止が発生しますが、保証された連続的なブレンドではありません。要求間のタスク変更では、連続性を保つために、すでに受け入れられたアクションを保持できます。ホールドをサポートしないロボットでのローカル RTC は、古い結果を破棄しますが、残りのアクションを使い切って終了する可能性があります。そのロボットが適切にホールドできない場合は、実行間で指示を変更してください。

ローカルで`--use_torch_compile=true`を使用すると、処理されたテンソルの形状を変更する指示が再コンパイルをトリガーする可能性があります。パディングにより、一部のタスク変更で形状が同一に保たれる場合がありますが、後続のコンパイルが残りの再生や指示変更の期限に適合することが保証されるわけではありません。ターミナルフォールトを引き起こす可能性があります。指示を探索している間は、それらの遷移が検証されていない限り、コンパイルをオフにしてください。初期コンパイルのウォームアップ中の変更は、ポリシーのモーションがまだ開始されていないため、モーションホールドを要求しません。

`/vqa` と `/autosteer` には、テキスト生成のサポートを宣言し、`PreTrainedPolicy.generate_text()` を実装したポリシーが必要です。例えば、適切に訓練された EO1 チェックポイントや、[外部プランナー](#external-planner) などです。クエリを受け入れる前に機能がチェックされますが、チェックポイント固有の動作については、引き続き検証が必要です。

**`/vqa`** は次の観測結果に対する回答を返す準備ができると出力するため、その間も入力を続けることができます。同時に進行中の質問は1つだけです（autosteer 自身のクエリもそのスロットを共有します）。外部プランナーを使用する場合、質問への回答はワーカースレッドで処理され、ロボットはアクションを継続します。この場合、以下の説明は適用されません。非同期バックエンドは、まず確認済みのローカルホールドに入り、キューイング中または補間されたモーションを無効化してから、新しい観測結果をテキストパスに送信します。正常なアクティブな実行は、回答後に新しいアクションチャンクから再開します。一時停止中または停止した実行は非アクティブなままです。同期テキスト生成は制御スレッド上でインラインで実行され、ポリシーの事前計算されたアクションを破棄するため、次のティックは新しい推論から再開します。クエリ時間は `--duration` にカウントされます。質問は実行が進行中の場合のみ受け付けられます。アイドル状態のエンジンには現在のビューがありません。指示または実行コンテキストによって非同期の回答が無効化された場合、質問には陳腐化した回答の代わりに1つのキャンセル通知が送信されます。セグメントの終了時にも、未回答の質問（生成が進行中のものを含む）が報告されます。キャンセルの報告は、実行中のモデル呼び出しを中断したり、そのクエリスロットを早期に解放したりしません。

**`/autosteer`** は、ポリシーにゴールを渡し、`--autosteer_interval_s` 秒（デフォルトは 10 秒）ごとに次のサブタスクを要求します。各サブタスクは `/subtask` と同じ経路で適用され、チャットでアナウンスされます。各クエリは完全なテキスト生成であるため、この間隔はコスト調整の役割を果たします。値を下げるとより早く再計画されますが、アクションを実行する代わりにテキスト生成にループの大部分を費やすことになります。計画の進捗はロールアウトではなくポリシーに保持されるため、セグメントが終了すると計画も失われます。シーケンサーは、`/reset`、`/subtask`、`/autosteer off`、および最初の計画失敗でも停止します。

**ERROR 未満のログはセッション実行中にミュートされます**。これにより、ルーティン出力が入力中のテキストと混在しません。エラーや致命的な推論の失敗は引き続き表示され、セッション終了時に通常のログ出力が再開されます。[cadence サマリー](#cadence-reporting)はチャット内で表示されます。`--interactive`なしで実行すると、ライブログが出力されます。

セッションは SSH 経由およびヘッドレスマシンで動作し、ディスプレイサーバーは不要です。

**対話しながら記録する。** `--strategy.type=sentry` は `--interactive=true` も受け入れ、操作しながら継続的に記録します。各 `/start`…`/reset` セグメントは完全なエピソードと最終的な部分エピソードを保存し、データセットはシャットダウンまで開いたままになります。フレームには実際に送信されたアクションのタスク由来情報が付与されるため、旧タスクの下でキューに積まれた、または補間されたアクションは旧ラベルを保持します。

実行中のエピソード保存がブロックされると、非同期推論が一時停止し、キューイング中または補間されたアクションが無効化され、サポートされているローカルホールドが要求されます。実行がアクティブかつ健全な状態を維持している場合のみ、新しいキャプチャから再開されます。同じ保護がDAggerの保存およびHighlightのリングバッファの排出/保存にも適用されます。録画の一時停止と通常の飢餓状態は物理的な待機動作を共有しますが、期限と再開の理由はそれぞれ独立しています。

```bash
lerobot-rollout \
    --strategy.type=sentry \
    --policy.path=${HF_USER}/my_smolvla_policy \
    --robot.type=so100_follower \
    --robot.port=/dev/ttyACM0 \
    --dataset.repo_id=${HF_USER}/rollout_cube_sessions \
    --task="pick up the cube" \
    --interactive=true
```

その他の記録戦略（episodic、DAgger、highlight）はサポートされていません。これらは独自のキーボード操作をバインドし、`run()`が終了した時点でデータセットを確定するため、セグメントごとに再開することができません。

### 外部プランナー

`--planner.model_id=<name>` を指定すると、`/vqa` および `/autosteer` は、ポリシーのテキストヘッドではなく、アノテーションパイプラインの VLM クライアント（`annotations` 追加機能）を介してルーティングされます。これらの呼び出しは、ロボットが動作を継続している間、ワーカースレッド上で実行され、言語ホールドは要求されません。ただし、意図的な例外が 1 つあります。`/autosteer` が開始されると、ゴールはポリシーへの指示ではなくプランナーへのコンテキストであるため、プランナーの最初の応答が返るまで推論バックエンドが一時停止します。非同期バックエンド（`rtc`、`remote`）は、前の指示用にキューイング済みまたは計算中のアクションを破棄します。一方、同期バックエンドはロボットをホールドします。最初のサブタスクが適用されると、バックエンドは新しい観測から再開します。`/subtask` は引き続き指示を直接適用し、自動プランニングをキャンセルします。遅れて届くプランナーの応答ではこれを上書きできません。

planner はすべての推論バックエンドで動作します。ローカル推論の場合、ロードされたプロセッサにサブタスクのレシピが存在する場合はそれを再利用し、存在しない場合は短い指示を要求します。ただし、これによりチェックポイントがその指示に従えることが保証されるわけではありません。`--planner.instructions='["pick up the cup","open the drawer"]'` は planner の出力を制限します。VLM はこれらの文字列のいずれかを選択するように求められ、リスト外の次のサブタスクの応答はエラーとなります。大文字・小文字、余分なスペース、末尾のピリオドは無視され、リスト自体の文言がポリシーに送信されます。このフラグを指定しない場合、リストはチェックポイントの学習データセットのタスクラベルから読み込まれます（`train_config.json` を介して）。すべてのラベルがプロンプトに含まれるため、タスクが多いデータセットでは、より短いリストを指定してフラグを渡してください。データセットを読み取れない場合、警告がログに記録され、planner の出力はフリーフォームのままになります。リモート推論ではポリシーがリモート側に存在するため、レシピも学習語彙もローカルでは利用できません。`--planner.instructions` を明示的に渡すか、応答はフリーフォームのままになります。planner はローカル推論のみのハードウェアで検証されています。

外部プランナーは、直前の`--planner.history`個の観測/コマンドペア（デフォルトは4個）と、現在の画像を受け取ります。各ペアには、指示の要求に使用された観測と、その後エンジンによって受理された指示が含まれます。受理は、実行の成功を意味しません。繰り返された指示は履歴に残されるため、VLMは進捗の欠如を評価できます。履歴は、手動の引き継ぎ、リセット、停止、セグメントの終了、または新しいautosteer目標の設定時にクリアされます。`--planner.history=0`を設定すると、これを無効化できます。`/vqa`はこの履歴を検査できますが、エントリを追加しません。次のサブタスクの要求に対しては、VLMはまずシーンを記述し、前回のコマンドが完了、進行中、または失敗したかを述べてから、初めて次の指示を指定する必要があります。`done`という応答は、目標が完了したことを意味します。autosteerは停止し、実行は終了し、ロボットは`/reset`または`/start`が実行されるまで姿勢を保持します。`/subtask`、`/reset`、または新しい目標の前に送信された遅延した`done`は破棄されます。適用された各サブタスクは、モデルによるシーン評価と要求のレイテンシとともに出力されます。

OpenAI互換のVLMサーバーを別途起動し、その後接続します:

```bash
transformers serve Qwen/Qwen3-VL-8B-Instruct --port 8000
# Alternatively: vllm serve Qwen/Qwen3-VL-8B-Instruct --port 8000
lerobot-rollout ... --task="pick up the cup" --interactive=true \
    --planner.model_id=Qwen/Qwen3-VL-8B-Instruct \
    --planner.api_base=http://localhost:8000/v1
> /start
> /vqa What is the next short instruction to clear the table?
> /subtask put the cup in the sink
> /autosteer clear the table
```

ホストされたモデルも同じように動作します。この例では、Hugging Face Inference Providers を使用し、"Make calls to Inference Providers" 権限を持つトークンを使用しています:

```bash
export HF_TOKEN=hf_...
lerobot-rollout ... --task="put all colored cubes in the green bin" --interactive=true \
    --planner.model_id=Qwen/Qwen3.8-27B:novita \
    --planner.api_base=/static-proxy?url=https%3A%2F%2Frouter.huggingface.co%2Fv1 \
    --planner.api_key_env=HF_TOKEN
```

`/vqa` は回答のみを報告しますが、`/autosteer` は指示を適用します。エンドポイントは `--planner.api_base` で、キーは `--planner.api_key_env=<variable>`（推奨。コマンドやログにキーが現れないため）または `--planner.api_key` で設定します。`--planner.request_timeout_s`（デフォルト 600）と `--planner.request_max_retries`（デフォルト 2）で各リクエストの上限を定め、`--planner.camera_key` でカメラを 1 つ選択し、`--planner.log_path` ですべてのやり取りを 1 行の JSON として追記します。モデルサービングの依存関係はサーバー環境に属します。`--autosteer_interval_s` は、応答が適用された後のロボットの動作時間を、リクエストのレイテンシに加えて測定します。マルチレベルのステアリングと自動シーンインベントリは、このアダプターの範囲外です。

### プログラマティックな制御

`RolloutController` は、ライブラリ API と同じ操作を公開します。スレッドセーフな `start()` / `reset()` / `stop()` / `set_task()` と `RolloutEvent` コールバックが提供され、stdin、出力、ログのミュートは付随しません。

```python
from threading import Event, Thread

from lerobot.rollout import (
    LinkedEvent,
    RolloutController,
    RolloutEvent,
    build_rollout_context,
    create_strategy,
)

parent = Event()  # your application's shutdown signal
ctx = build_rollout_context(cfg, LinkedEvent(parent))  # loads policy, connects robot
strategy = create_strategy(cfg.strategy)
strategy.setup(ctx)

controller = RolloutController(strategy, ctx, on_event=print)  # or your own observer
serve_thread = Thread(target=controller.serve)  # serve() blocks; run it where you like
serve_thread.start()

controller.start()                        # robot starts executing the policy
controller.set_task("grab the red cube")  # re-instruct mid-run
controller.reset()                        # stop movement, return home, stay warm
controller.stop()                         # end serve()

serve_thread.join()
strategy.teardown(ctx)  # teardown stays with the caller
```

`RolloutController` は、コンテキストのシャットダウンイベントが上記のように構築された `LinkedEvent` であることを要求します。コントローラーはローカルフラグを通じて実行セグメントを終了しますが、`parent` イベントは引き続き完全なシャットダウンを強制します。音声アナウンスを希望しない場合は、`play_sounds=False` を設定してください。

---

## 共通フラグ

| フラグ                              | 説明                                                       | デフォルト |
| --------------------------------- | ----------------------------------------------------------------- | ------- |
| `--policy.path`                   | **必須。** HF Hub のモデル ID またはローカルチェックポイントのパス            | --      |
| `--robot.type`                    | **必須。** ロボットのタイプ（例: `so100_follower`、`koch_follower`） | --      |
| `--robot.port`                    | ロボットのシリアルポート                                         | --      |
| `--robot.cameras`                 | カメラ設定（JSON辞書）                                  | --      |
| `--fps`                           | ポリシー推論とデータセット記録の頻度                  | 30      |
| `--status_interval_s`             | ヘルスログ間の秒数（0で無効化、非対話モードのみ）    | 5       |
| `--duration`                      | 実行時間（秒）（0 = 無限；対話モードの場合はセグメントごと）    | 0       |
| `--device`                        | Torch デバイス (`cpu`、`cuda`、`mps`)                               | auto    |
| `--task`                          | タスクの説明（データセットが提供されていない場合に使用）               | --      |
| `--display_data`                  | Rerunの可視化にテレメトリをストリーミング                           | false   |
| `--display_ip` / `--display_port` | リモートRerunサーバーのアドレス                                       | --      |
| `--interpolation_multiplier`      | ポリシーアクションごとのロボットコマンド（`fps × N` Hzでの制御）        | 1       |
| `--interactive`                   | stdinでのチャットセッション; ロボットは`/start`（base, sentry）まで待機します  | false   |
| `--use_torch_compile`             | 推論で`torch.compile`を有効にする                              | false   |
| `--resume`                        | 以前の録画セッションを再開する                               | false   |
| `--play_sounds`                   | イベント向けの音声合成                                        | true    |

---

## Cadenceレポート

Non-interactive rollout は5秒ごとにステータスをログに記録します。`--status_interval_s=10` で間隔を変更するか、`--status_interval_s=0` で無効にできます。

```text
Rollout: loop 29.7/30 Hz · over budget 2/149 · starved 0 · infer 18.7 ms (worst 40.1) · process 2.41 GiB · GPU 5.12/79.6 GiB
```

レイテンシは区間内の中央値/最悪値です（RTC/リモートの場合は`turnaround`）。利用できないフィールドは省略されます。GPU メモリはデバイス全体のもので、リモートメモリはローカルのものでした。ループがブロックされている間はレポートが一時停止されます。

すべての戦略は、その制御ループが実際に達成した内容を報告します。`lerobot-record`、`lerobot-teleoperate`、`lerobot-replay` も同様で、これらはすべて同じタイマーで進行します。保存された各エピソードには1行のサマリーが付与され、ループが終了したとき（`Ctrl-C` による中断を含む）には、実行全体をカバーするブロックが表示されます:

```
Cadence (episode 1): 29.84 Hz policy vs 30 Hz target · 1200 ticks, 20.1 s measured · 6/598 cycles over the 33.3 ms budget (work mean 18.7 ms, worst 48.1 ms)
Cadence (episode 2): 29.84 Hz policy vs 30 Hz target · 1200 ticks, 20.1 s measured · 6/599 cycles over the 33.3 ms budget (work mean 18.7 ms, worst 48.1 ms)
Cadence summary — whole run, 2 episodes · target 30 Hz × 2 (16.7 ms tick slot, 33.3 ms cycle budget): 2400 ticks, 1197 cycles judged
  effective cadence: 29.84 Hz policy / 59.67 Hz commands over 40.2 s measured
  cycles over the 33.3 ms work budget: 12/1197 (1.0%) — work mean 18.7 ms, worst 48.1 ms
  ticks over their 16.7 ms slot: 40/2400 (costs interpolation smoothness only)
  loop-body steps (share of measured work):
    observe      mean   3.13 ms · worst   9.00 ms ·  31.7% of work · 2400 calls
    process_obs  mean   0.50 ms · worst   1.00 ms ·   5.1% of work · 2400 calls
    infer        mean   5.18 ms · worst  40.00 ms ·  52.4% of work · 2400 calls
    send         mean   0.40 ms · worst   0.40 ms ·   4.1% of work · 2400 calls
    record       mean   0.67 ms · worst 620.00 ms ·   6.8% of work · 2402 calls
  pacing headroom: 7.4 ms slept per tick on average (max 13.0 ms) — near zero means the loop is saturated
```

上から順に読み解きます。**effective cadence** は `--fps` に対する実際の達成値であり、**cycles over budget** はループがその速度を維持できなかった頻度を示します。**step breakdown** は時間の内訳を、**pacing headroom** がほぼゼロであることは、遅いティックを吸収する余裕がもうないことを意味します。`infer` の割合が高い場合はポリシーまたはデバイスに、`observe` の割合が高い場合はカメラに問題があることを示唆します。あるステップの `worst` がその `mean` を大きく上回っている場合は一時的なものです。上記の例では、`record` はフレームあたり 0.67 ms であり、620 ms の外れ値はエピソードを閉じる際にブロッキングとなった `save_episode` です。

ここでは、_サイクル_とは1回のポリシーアクション分のティック（`--interpolation_multiplier` 回）を指します。`1/fps` の予算に対して、サイクル全体が超過した場合のみフレームの損失につながります。単一のティックがそのスロットを超過しても、補間されたモーションが滑らかさを失うだけであるため、両者は別々にカウントされます。補間がない場合、サイクルは単一のティックとなるため、レポートはこの区別を省略し、一貫してティックとしてカウントします。

[対話型セッション](#interactive-sessions)では、各 `/start` セグメントが独自のタイマーを保持するため、レポートはプロセスごとではなく、セグメントごと（`/reset`、`/stop`、または `--duration`）に1回ずつチャットに送信されます。

---

## プログラマティックな使用

拡張機能では、`lerobot.inference` がバックエンド設定、ローカルエンジン、共有スケジューリング契約の公開パッケージです。`lerobot.remote_inference` はリモートエンジン、プロトコル、デプロイ、セッション実装を管理し、`lerobot.rollout` はロボットループ、戦略、補間、記録を管理します。実装ファイルではなく、各パッケージから公開シンボルをインポートしてください。オプションのリモート依存関係は、リモートバックエンドまたはサーバーを使用する場合にのみ必要です。

カスタムデプロイメント（運動学プロセッサなどを使用する場合）では、rolloutモジュールのAPIを直接使用します：

```python
from lerobot.rollout import BaseStrategyConfig, RolloutConfig, build_rollout_context
from lerobot.inference import SyncInferenceConfig
from lerobot.rollout.strategies import BaseStrategy
from lerobot.utils.process import ProcessSignalHandler

cfg = RolloutConfig(
    robot=my_robot_config,
    policy=my_policy_config,
    strategy=BaseStrategyConfig(),
    inference=SyncInferenceConfig(),
    fps=30,
    duration=60,
    task="my task",
)

signal_handler = ProcessSignalHandler(use_threads=True)
ctx = build_rollout_context(
    cfg,
    signal_handler.shutdown_event,
    robot_action_processor=my_custom_action_processor,       # optional
    robot_observation_processor=my_custom_obs_processor,     # optional
)

strategy = BaseStrategy(cfg.strategy)
try:
    strategy.setup(ctx)
    strategy.run(ctx)
finally:
    strategy.teardown(ctx)
```

運動学プロセッサを含む完全な例については、`examples/so100_to_so100_EE/rollout.py`および`examples/phone_to_so100/rollout.py`を参照してください。

