LeRobot documentation
ロボットおよびテレオペレーター向けのプロセッサ
ロボットおよびテレオペレーター向けのプロセッサ
このガイドでは、テレオペレーター(例:電話)とロボットおよびデータセットを接続する処理パイプラインの構築と変更方法を示します。パイプラインは異なるアクション/観測空間間の変換を標準化するため、テレオペとロボットを交換しても、グルーコードを書き直す必要はありません。
具体的にするため、Phone to SO‑100 follower の例を使用しますが、同じパターンは他のロボットにも適用できます。
学べる内容
- 絶対EE制御と相対EE制御:それぞれの意味、トレードオフ、タスクに応じた選択方法
- 3つのパイプラインのパターン: テレオペレーションのアクションからデータセットのアクション、そしてロボットのコマンドへのマッピング方法、およびロボットの観測からデータセットの観測へのマッピング方法。
- アダプター(
to_transition/to_output): 生データである辞書からEnvTransitionへの変換、およびその逆変換をどのように行い、ボイラープレートコードを削減しているか。 - Dataset feature contracts:
transform_features(...)によってステップが特徴を宣言する方法、および記録のためにそれらを集約・マージする方法。 - 表現の選択:関節、絶対EE姿勢、相対EEデルタのいずれを保存すべきか、そしてそれが学習にどのように影響するか。
- パイプラインのカスタマイズのガイドライン: ロボット/URDFを安全に交換し、境界値、ステップサイズ、IK初期化などのオプションを調整する方法。
絶対EE制御と相対EE制御
このガイドの例では、推論が容易なため、絶対的なエンドエフェクタ(EE)の姿勢を使用しています。実際の運用では、学習特徴として相対的なEEのデルタや関節位置が好まれることがよくあります。
プロセッサでは、ポリシーで使用したい学習用の特徴量を選択します。これは、関節の位置/速度、絶対的なEE、または相対的なEE位置などが該当します。また、関節トルクやモーター電流などの他の特徴量を保存することも選択できます。
3つのパイプライン
3つのパイプラインを組み合わせることがよくあります。セットアップによっては、アクション空間と観測空間がすでに一致している場合、一部のパイプラインは空になることがあります。 これらのパイプラインはそれぞれ、異なるアクション空間と観測空間間の異なる変換を処理します。以下に、各パイプラインの簡単な説明を示します。
- Pipeline 1: Teleop action space → dataset action space (phone pose → EE targets)
- Pipeline 2: データセットのアクション空間 → ロボットコマンド空間(EEターゲット → 関節)
- Pipeline 3: ロボットの観測空間 → データセットの観測空間(関節 → EE ポーズ)
以下は、phone to SO-100 follower の例で使用している3つのパイプラインの例です:
phone_to_robot_ee_pose_processor = RobotProcessorPipeline[tuple[RobotAction, RobotObservation], RobotAction]( # teleop -> dataset action
steps=[
MapPhoneActionToRobotAction(platform=teleop_config.phone_os),
EEReferenceAndDelta(
kinematics=kinematics_solver, end_effector_step_sizes={"x": 0.5, "y": 0.5, "z": 0.5}, motor_names=list(robot.bus.motors.keys()),
),
EEBoundsAndSafety(
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]}, max_ee_step_m=0.20,
),
GripperVelocityToJoint(),
],
to_transition=robot_action_observation_to_transition,
to_output=transition_to_robot_action,
)
robot_ee_to_joints_processor = RobotProcessorPipeline[tuple[RobotAction, RobotObservation], RobotAction]( # dataset action -> robot
steps=[
InverseKinematicsEEToJoints(
kinematics=kinematics_solver, motor_names=list(robot.bus.motors.keys()), initial_guess_current_joints=True,
),
],
to_transition=robot_action_observation_to_transition,
to_output=transition_to_robot_action,
)
robot_joints_to_ee_pose = RobotProcessorPipeline[RobotObservation, RobotObservation]( # robot obs -> dataset obs
steps=[
ForwardKinematicsJointsToEE(kinematics=kinematics_solver, motor_names=list(robot.bus.motors.keys()))
],
to_transition=observation_to_transition,
to_output=transition_to_observation,
)to_transition / to_output を使用すべき理由
ロボット/テレオペレーターからパイプラインへの変換、およびその逆変換には、to_transition と to_output のパイプラインアダプターを使用します。
これらは変換を標準化してボイラープレートコードを削減し、ロボットおよびテレオペレーターの生の辞書とパイプラインの EnvTransition 形式の間の橋渡しを行います。
電話機から SO-100 フォローラーへの例では、以下のアダプターを使用します。
robot_action_observation_to_transition:(action, robot observation)のペアをパイプラインの遷移に変換します(EEステップとIKステップには、ロボットの現在の関節位置が必要です)。transition_to_robot_action: パイプラインの遷移をロボットアクションの辞書に変換します。observation_to_transition: ロボットの観測辞書をパイプラインの遷移に変換します。transition_to_observation: パイプラインの遷移を observation dict に変換します。
詳細については、src/lerobot/processor/converters.pyを参照してください。
Dataset feature contracts
Dataset の features は、dataset に保存されるキーによって決定されます。各ステップは、transform_features(...) という契約で、自分が変更する features を宣言できます。processor を構築すると、processor は aggregate_pipeline_dataset_features() を使用してこれらの features をすべて集約し、combine_feature_dicts(...) を使用して複数の feature dict をマージできます。
以下は、phone to SO-100 follower の例において、transform_features メソッドで特徴を宣言する方法の例です。
def transform_features(
self, features: dict[PipelineFeatureType, dict[str, PolicyFeature]]
) -> dict[PipelineFeatureType, dict[str, PolicyFeature]]:
# We only use the ee pose in the dataset, so we don't need the joint positions
for n in self.motor_names:
features[PipelineFeatureType.ACTION].pop(f"{n}.pos", None)
# We specify the dataset features of this step that we want to be stored in the dataset
for k in ["x", "y", "z", "wx", "wy", "wz", "gripper_pos"]:
features[PipelineFeatureType.ACTION][f"ee.{k}"] = PolicyFeature(
type=FeatureType.STATE, shape=(1,)
)
return featuresここでは、このステップで変更するPolicyFeaturesを宣言します。これにより、プロセッサを実行した際に期待できる特徴量が明確になります。これらの特徴量は集約され、データセットの特徴量を作成するために使用されます。
以下は、電話からSO-100レコードへの例において、特徴をアグリゲーションおよびマージする方法の例です:
features=combine_feature_dicts(
# Run the feature contract of the pipelines
# This tells you how the features would look like after the pipeline steps
aggregate_pipeline_dataset_features(
pipeline=phone_to_robot_ee_pose_processor,
initial_features=create_initial_features(action=phone.action_features), # <- Action features we can expect, these come from our teleop device (phone) and action processor
use_videos=True,
),
aggregate_pipeline_dataset_features(
pipeline=robot_joints_to_ee_pose,
initial_features=create_initial_features(observation=robot.observation_features), # <- Observation features we can expect, these come from our robot and observation processor
use_videos=True,
patterns=["observation.state.ee"], # <- Here you could optionally filter the features we want to store in the dataset, with a specific pattern
),
),仕組み:
aggregate_pipeline_dataset_features(...): パイプライン全体にtransform_featuresを適用し、パターンでフィルタリングします(use_videos=Trueの場合には画像が含まれ、patternsが指定されている場合には状態特徴が含まれます)。combine_feature_dicts(...): 複数のフィーチャー辞書を結合します。record_loop(...)による記録では、add_frame(...)を呼び出してフレームをデータセットに追加する前に、build_dataset_frame(...)を使用してdataset.featuresと整合性のあるフレームを構築します。
ロボットパイプラインのカスタマイズに関するガイダンス
次のいずれかの機能をアクション/観測空間として保存できます:
- 関節の位置
- 絶対EE姿勢
- 相対的なEEの差分
- その他の機能: 関節速度、トルクなど
のアクションと観測空間に使用したいものを選択し、パイプラインとステップをそれに応じて設定/変更してください。
異なるロボット
- パイプラインは簡単に再利用できます。例えば、別のロボットでPhone teleopを使用する場合、サンプルを修正して、ご自身のロボットでPhone teleopを使用するために
RobotKinematics(URDF)とmotor_namesを差し替えます。また、target_frame_nameがグリップ/リストを指していることを確認してください。
安全第一
- パイプラインを変更する際は、まず狭い範囲の制約から始め、実物のロボットを扱う際には安全対策を実装してください。
- シミュレーションから始め、その後で実際のロボットに移行することをお勧めします。
以上です! このガイドが、ロボットのパイプラインのカスタマイズの第一歩となることを願っています。何か問題に遭遇した場合は、サポートのためにDiscordコミュニティに参加してください。
Update on GitHub