# アクションの表現

このガイドでは、LeRobotにおけるロボットアクションの異なる表現方法、それらの相互関係、および各表現の適用タイミングについて説明します。

## ジョイント空間とエンドエフェクタ空間

アクションの表現について議論する前に、アクションが存在し得る2つの座標空間を理解しておくことが役立ちます。

### ジョイントスペース

Joint-space actionsは各モーターの目標位置を直接指定します。6自由度のロボットアームとグripperを持つ場合、joint-space actionは次のようになります。

```
action = [shoulder_pan: 45.0, shoulder_lift: -20.0, elbow: -30.0, wrist_pitch: 10.0, wrist_roll: 0.0, wrist_yaw: 5.0, gripper: 0.8]
```

Joint spaceはLeRobotのデフォルトです。シンプルで、運動学モデルを必要とせず、モーターコマンドに直接マッピングできます。初心者のセットアップ（SO-100、Koch）の多くは、joint-space actionsを使用しています。

### エンドエフェクタ（EE）空間

エンドエフェクタ空間のアクションは、ロボットのツールチップ（グリップ）の所望の位置と姿勢をデカルト座標で指定します：

```
action = [x: 0.25, y: -0.10, z: 0.15, wx: 0.0, wy: 0.0, wz: 0.1, gripper: 0.8]
```

EE空間は、ピッキング&プレースングのようなタスクにおいて、グリップがどこに移動すべきかを直接記述するため、より直感的です。ただし、EEの姿勢と関節角度の間の変換には、運動学モデル（URDF）が必要です。

### スペース間の変換

LeRobotは、`RobotKinematics`を基盤として、ロボットのURDFモデルを読み込み、フォワードキネマティクスとインバースキネマティクスを用いて関節空間とEE空間の変換を行うプロセッサステップを提供します。

```python
from lerobot.model.kinematics import RobotKinematics
from lerobot.robots.so_follower.robot_kinematic_processor import (
    ForwardKinematicsJointsToEE,
    InverseKinematicsEEToJoints,
)

kinematics = RobotKinematics(
    urdf_path="./SO101/so101_new_calib.urdf",
    target_frame_name="gripper_frame_link",
    joint_names=["shoulder", "elbow", "wrist_pitch", "wrist_roll", "wrist_yaw"],
)

# Joints → EE (for observations: "where is my gripper?")
fk_step = ForwardKinematicsJointsToEE(kinematics=kinematics, motor_names=[...])

# EE → Joints (for actions: "move my gripper here")
ik_step = InverseKinematicsEEToJoints(kinematics=kinematics, motor_names=[...])
```

SO-100アームでEE空間のアクションを用いた記録、再生、評価の完全な動作例については、[`examples/so100_to_so100_EE/`](https://github.com/huggingface/lerobot/tree/main/examples/so100_to_so100_EE)を参照してください。

## 絶対、相対、およびデルタアクション

ジョイント空間でもEE空間でも、アクション値は3つの異なる方法で表現できます。用語は[UMI (Chi et al., 2024)](https://arxiv.org/abs/2402.10329)に従います。

### 絶対アクション（LeRobotのデフォルト）

各アクションは、ターゲットの位置を直接指定します。

**例**（ジョイントスペース、チャンク4）：

```
current_state = [45.0, -30.0, 10.0]

action_chunk = [
    [46.0, -29.0, 11.0],   # go to 46, -29, 11
    [47.5, -27.0, 12.0],   # go to 47.5, -27, 12
    [49.0, -25.0, 13.5],   # go to 49, -25, 13.5
    [50.0, -24.0, 15.0],   # go to 50, -24, 15
]
```

各値は、ロボットの座標系におけるターゲット位置です。シンプルで直接的ですが、一貫性のあるグローバル座標系が必要です。これはLeRobotのデフォルトです。

### 相対アクション（OpenPI / pi0で使用）

チャンク内の各アクションは、**予測時点の現在の状態**からのオフセットです。チャンク内のすべてのアクションは同じ基準点を共有します:

```
current_state = [45.0, -30.0, 10.0]

relative_chunk = [
    [1.0,  1.0, 1.0],   # +1 from current → target 46, -29, 11
    [2.5,  3.0, 2.0],   # +2.5 from current → target 47.5, -27, 12
    [4.0,  5.0, 3.5],   # +4 from current → target 49, -25, 13.5
    [5.0,  6.0, 5.0],   # +5 from current → target 50, -24, 15
]
```

変換は単純です: `relative = absolute - current_state`。絶対値を復元するには: `absolute = relative + current_state`。

**なぜ相対アクションを使用するのか？** モデルはゼロを中心に予測するオフセットを学習します。これにより正規化が容易になり、より安定した学習につながります。また、すべてのチャンクが同じ現在の状態を参照するため、チャンク間の誤差蓄積が発生しません。

### Delta Actions（逐次的差分）

各アクションは、**直前のアクション**からのオフセットです（最初のステップの場合は現在の状態からのオフセットです）：

```
current_state = [45.0, -30.0, 10.0]

delta_chunk = [
    [1.0,  1.0, 1.0],   # current → 46, -29, 11
    [1.5,  2.0, 1.0],   # previous action → 47.5, -27, 12
    [1.5,  2.0, 1.5],   # previous action → 49, -25, 13.5
    [1.0,  1.0, 1.5],   # previous action → 50, -24, 15
]
```

ここでは、各ステップは直前のステップに対する相対的なものです。絶対的な位置を復元するには、それまでのすべての差分を合計する必要がありますが、これは時間とともに誤差が蓄積することを意味します。UMIは、この理由からこの表現方式に明確に反対しています。

### 視覚的な比較

下の図（[UMI, Chi et al., 2024](https://arxiv.org/abs/2402.10329)の図に基づく）は、その重要な違いを示しています。**相対軌道**では、チャンク内のすべてのアクションが同じ原点（現在の状態）を指すため、新しい推論ステップで参照がクリーンにリセットされます。一方、**デルタ**では、各アクションが前のアクションに依存するため、誤差が蓄積します。**絶対**アクションには、一貫したグローバルな座標系が必要です。

<img
  src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/action_representations_umi.png"
  alt="Relative Trajectory as Action Representation (UMI, Chi et al., 2024)"
  width="85%"
/>

## LeRobotでの相対アクションの使用

LeRobotは、プロセッサパイプライン内で絶対アクションと相対アクションの変換を行うために`RelativeActionsProcessorStep`を提供しています。pi0、pi0.5、およびpi0_fastが相対アクションをサポートしているのは、この仕組みによるものです。

> **注:** すべての pi モデル (pi0, pi0.5, pi0*fast) は、正規化 (`relative → normalize`) の前に相対変換 \_を適用するため、正規化器は常に delta (相対) 値を確認します。これは、`use_relative_actions=true` で学習を行う場合、これらすべてのモデルに対して**相対アクションの統計情報が必須**であることを意味します。pi0_fast では、`RelativeActionsProcessorStep` はアクションのみを変更し、状態の観測値は変更されないため、`NormalizerProcessorStep` は依然として状態トークナイザーの前に実行され、トークナイザーは期待通りに正規化された状態を受け取ります。

### 仕組み

**学習**（前処理）中では、モデルがアクションを見る前に、絶対座標から相対座標へ変換されます：

```
raw absolute action → RelativeActionsProcessorStep → normalize → model
```

**推論**（後処理）中、モデルの予測値はロボットに送信される前に絶対値へ変換されます：

```
model output → unnormalize → AbsoluteActionsProcessorStep → robot
```

`AbsoluteActionsProcessorStep` は、ペアとなる `RelativeActionsProcessorStep` からキャッシュされた現在の状態を読み取るため、両者は接続されていなければなりません（これはポリシーファクトリによって自動的に処理されます）。

### piファミリー（pi0、pi0.5、pi0_fast）での相対アクションの有効化

**ステップ 1**: データセットの相対アクション統計を事前計算します:

```bash
lerobot-edit-dataset \
    --repo_id your_dataset \
    --new_repo_id your_dataset \
    --operation.type recompute_stats \
    --operation.overwrite true \
    --operation.relative_action true \
    --operation.chunk_size 50 \
    --operation.relative_exclude_joints "['gripper']"
```

**ステップ 2**: 相対アクションを有効にして学習します:

```bash
lerobot-train \
    --dataset.repo_id=your_dataset \
    --policy.type=pi0 \
    --policy.use_relative_actions=true \
    --policy.relative_exclude_joints='["gripper"]'
```

`relative_exclude_joints` パラメータは、絶対空間のままにしておくべき関節を指定します。例えば、グリップのコマンドは通常、二値（開/閉）であり、相対エンコーディングの恩恵を受けません。

`action_feature_names` を定義するポリシー設定の場合、`make_policy` は、データセットのアクション特徴量の `names` メタデータからこのリストを埋めます。names はフラットなシーケンスでも、値がすべてリストまたはタプルである辞書でも構いません。例えば、`{"arm": ["shoulder", "elbow"], "hand": ["gripper"]}` は、グループのキーではなく `["shoulder", "elbow", "gripper"]` になります。グループの挿入順序とグループ内の順序は保持されるため、アクションベクトルと同じ順序で名前を宣言してください。レガシーの名前とインデックスの対応関係は、キーの順序の動作を維持します。

### 相対アクションとRTCの組み合わせ

[RTC](https://arxiv.org/abs/2506.07339)は高頻度でポリシー推論を実行し、完全なチャンクを待たずに、アクションが予測された時点でロボットに送信します。相対アクションとRTCは完全に互換性があります。相対モードでは、すべてのチャンクが**同じ**現在の状態（推論の開始時にキャプチャされたもの）を参照するため、ロボットがすでに移動していても、チャンク内の各予測アクションは有効なオフセットのままです。特別な処理は不要です。`RelativeActionsProcessorStep`は推論呼び出しごとに1回だけ状態をキャッシュし、`AbsoluteActionsProcessorStep`はストリーミング出力のすべてのアクションにそれを適用します。

### 相対アクションとEE空間の組み合わせ

相対アクションは、関節空間とEE空間の両方で機能します。例えば、データセットにEEアクションが保存されている場合、相対エンコーディングはそれらを現在のEEポーズからのオフセットに変換します:

```
current_ee_state = [x: 0.25, y: -0.10, z: 0.15, gripper: 0.8]

absolute_ee_chunk = [
    [0.26, -0.09, 0.16, 0.8],
    [0.28, -0.07, 0.18, 0.8],
]

relative_ee_chunk = [
    [0.01,  0.01, 0.01, 0.0],   # offset from current EE pose
    [0.03,  0.03, 0.03, 0.0],   # offset from current EE pose
]
```

## 処理パイプラインの概要

以下は、異なるプロセッサがどのように構成されるかを示しています。各矢印はプロセッサのステップを表し、`RobotProcessorPipeline`または`PolicyProcessorPipeline`内でチェーン化できます。

```
                    ┌─────────────────────────────────────────┐
   Action Space     │   Joint Space  ←──IK──→  EE Space      │
                    │   ForwardKinematicsJointsToEE           │
                    │   InverseKinematicsEEToJoints           │
                    └─────────────────────────────────────────┘

                    ┌─────────────────────────────────────────┐
   Representation   │   Absolute  ←────→  Relative            │
                    │   RelativeActionsProcessorStep (pre)    │
                    │   AbsoluteActionsProcessorStep (post)   │
                    └─────────────────────────────────────────┘

                    ┌─────────────────────────────────────────┐
   Normalization    │   Raw  ←────→  Normalized               │
                    │   NormalizerProcessorStep (pre)         │
                    │   UnnormalizerProcessorStep (post)      │
                    └─────────────────────────────────────────┘
```

典型的な学習用プリプロセッサでは、`raw absolute joint actions → relative → normalize`のように処理を連鎖させます。典型的な推論用ポストプロセッサでは、`unnormalize → absolute → (optionally IK to joints)`のように処理します。

## 参考文献

- [Universal Manipulation Interface (UMI)](https://arxiv.org/abs/2402.10329) - Chi et al., 2024。相対軌道アクション表現を定義し、絶対アクションおよびデルタアクションと比較しています。
- [プロセッサの紹介](./introduction_processors) - LeRobotにおけるプロセッサパイプラインの動作方法。
- [`examples/so100_to_so100_EE/`](https://github.com/huggingface/lerobot/tree/main/examples/so100_to_so100_EE) - EE空間のアクションを用いた記録と評価の完全な例。

