
1. はじめに
ここまでロボットの組み立てから学習データの収集と学習、学習結果の実行について解説しました。 学習結果の実行ではLeRobotのcontrol_robotスクリプトを使いましたが。この方法では学習したモデルを使いロボットを動かすことができますが、独自のアプリケーションに組み込んで利用することができません。
そこで今回はLeRobotをライブラリとして利用することでオリジナルのアプリケーションを実装する方法について紹介します。
2. LeRobotのアプリケーション実装の全体像
学習させたPolicyを用いてロボットを動かすためには大きく次の処理が必要です。
- ロボットへの接続
ロボットのコンフィグファイルを元にロボットのインスタンスを取得し接続します。
- ロボットの内部状態、外部センサの状態取得
カメラの画像やロボットの現在の関節値を取得します。
- Policyによる推論
2で取得した観測情報を元に学習済みPolicyを使ってロボットの指令値を決定します。
- ロボットへの指令値の送信
3で決定した指令値をロボットへ送り、実際にロボットを動かします。
それぞれの処理の実装方法について説明し、最後に全体をまとめたコードを紹介します。
3. ロボットとの接続
LeRobotからロボットへ接続する場合はRobotConfigとManipulatorRobotオブジェクトを使用します。SO-ARM100を接続する場合はSo100RobotConfigを使い、設定を読み込みManipulatoroRobotオブジェクトを作成します。以下のコードはロボットオブジェクトを作成してロボットに接続するコードです。この状態でロボットに対して指示を送ることがあります。
from lerobot.common.robot_devices.robots.configs import So100RobotConfig from lerobot.common.robot_devices.robots.manipulator import ManipulatorRobot config = So100RobotConfig() config.calibration_dir= <スクリプト実行パスからみたキャリブレーションファイルのパス> robot = ManipulatorRobot(config) robot.connect() ## ロボットが急な動きや無理な姿勢、障害物への衝突が発生する可能性があるので ## まだロボットに対して指令値を送らない。
SO100RobotConfigでロボットのコンフィグを読み出します。このconfigは変更可能です。例えば、通常、leaderとfollower両方のアームが読み込まれ接続が行われます。しかし以下のようにSO100RobotConfignのコンストラクタ引数に値を設定することで、leaderアームの設定を無効にし、followerのみ接続するよう変更できます。またcalibration_dirのパスも設定できます。
config = SO100RobotConfig(leader_arms={}, calibration_dir='lerobot/.cache/calibration/so100')
robot = ManipulatorRobot(config)
4. 観測情報の取得
ロボットの関節情報やカメラの画像はManipulatorRobot.capture_observationメソッドからdict型の戻り値として取得できます。カメラはconfigsの設定で指定した値がキー値として設定されます。複数カメラを接続している場合はfor文を使い取り出すことができます。下の例ではリスト内包表記を使用しています。
observation = robot.capture_observation() state = observation['observation.state'] images = [] image_keys = [key for key in observation if "image" in key] # カメラのキー値はConfigファイルに設定した値 #画像はnumpy.arrayで格納されている。 for key in image_keys: cv2.imshow(key, cv2.cvtColor(observation[key].numpy(), cv2.COLOR_RGB2BGR)) cv2.waitKey(1)
5. ロボットへの指令値の送信
ロボットに対するアクションはrobot.send_actionメソッドを使います。このメソッドは要素0が1軸目の台座の回転に対応している要素数6のリスト(numpy.nbarray or tensor)を引数にとり、そのまま各関節の指令値として与えます。そのため不用意に指令値を与えるとロボットの思わぬ動作を引き起こすことになります。順運動や逆運動学を解き、指令値を決める。もしくは現在の関節角をベースに動作を指定するなど対策をしましょう。
今回はダミーデータとして現在の観測値を取得し、それをそのまま指令値として与えてみます。
if robot.is_connected: observation = robot.capture_observation() action = observation['observation.state'] print(action) ## 指令値を変更する場合は無理な姿勢にならないか、急な動作を引き起こさないかを確認する。 ## 警告:適当な値を指令値として与えないこと。 robot.send_action(action)
5. モデルの読み込みと推論
学習ずみモデルを用いて推論を行う場合はモデルクラスのfrom_pretrained()メソッドに学習したモデルファイルを指定して読み込ませます。ACTを使う場合は次のようにします。
推論結果の戻り値はバッチに従って2次元配列になっています。1次元目の要素は1なので、次元を一つ落として利用します。
from lerobot.common.policies.act.modeling_act import ACTPolicy policy = ACTPolicy.from_pretrained('モデルファイルまでのパス') action = policy.select_action(observation) # robot.capture_observationの戻り値 action = action.squeeze(0)#2次元配列から1次元配列へ変換 action = action.to("cpu") if robot.is_connected: robot.send_action(action)
6. 全体のコード
実際にFollowerアームと学習済モデルを使ってロボットを動かす場合は次のようにコードを記述します。以下参考に、ロボットが動き出すトリガーの実装やWEBアプリケーションとの連携などにより、デモの見栄えを良くすることができます。
""" This is sample code for running the robot controller. """ import time import cv2 import torch from lerobot.common.policies.act.modeling_act import ACTPolicy from lerobot.common.robot_devices.robots.configs import So100RobotConfig from lerobot.common.robot_devices.robots.manipulator import ManipulatorRobot from lerobot.common.robot_devices.utils import busy_wait inference_time_s = 60 fps = 30 device = "mps" # TODO: On Mac, use "mps" or "cpu" ckpt_path = "masato-ka/act_so100_cls_block_color" policy = ACTPolicy.from_pretrained(ckpt_path) policy.to(device) config = So100RobotConfig(leader_arms={}) config.calibration_dir='lerobot/.cache/calibration/so100' robot = ManipulatorRobot(config) if __name__ == '__main__': robot.connect() try: for _ in range(inference_time_s * fps): start_time = time.perf_counter() # Read the follower state and access the frames from the cameras observation = robot.capture_observation() image_keys = [key for key in observation if "image" in key] for key in image_keys: cv2.imshow(key, cv2.cvtColor(observation[key].numpy(), cv2.COLOR_RGB2BGR)) cv2.waitKey(1) # Convert to pytorch format: channel first and float32 in [0,1] # with batch dimension for name in observation: if "image" in name: observation[name] = observation[name].type(torch.float32) / 255 observation[name] = observation[name].permute(2, 0, 1).contiguous() observation[name] = observation[name].unsqueeze(0) observation[name] = observation[name].to(device) # Compute the next action with the policy # based on the current observation action = policy.select_action(observation) # Remove batch dimension action = action.squeeze(0) # Move to cpu, if not already the case action = action.to("cpu") # Order the robot to move robot.send_action(action) dt_s = time.perf_counter() - start_time busy_wait(1 / fps - dt_s) finally: robot.disconnect()
7. まとめ
上記コードをベースに、外部イベントによる動作の開始やGUIでの制御といったアプリケーションの構築ができます。LeRobotの付属スクリプの実行だけでなく、WEBブラウザからの入力や他のシステムと連携した動作などインタラクティブなデモアプリケーションを組み上げてください。
次回はより、LeRobotを使いこなすため、Action Chunking Transformerにコンディション(条件)を加えた学習にチャレンジします。例えば、画像上で指定したオブジェクトを取らせたり、言語による作業指示に従って動作させることができるようになります。
▫️画像座標によるコンディショニングの例
x.comACT(Action Chunking Transformer)で画像上でクリックしたブロックを掴むデモ。クリックした座標をObservationにしてACTの入力に突っ込んでる。海外の人の真似。後半失敗してるけどターゲットに追従してる。長い動画だけど最後まで見るとわかる。#LeRobot #AI #SO100 #ロボット pic.twitter.com/cyX1B6ZLxQ
— masato_ka (@masato_ka) 2025年5月6日
▫️言語によるコンディショニング(VLA)の例
x.com言語の指示に従う模倣学習、NL-ACTをLeRobotコードベースで実装した。ACTを埋め込み表現でコンディション付けをしている。お皿にブロックを乗せるか、お皿からブロックを取るかを言語で指定できる。M2 macで推論できる軽量VLA(?)うまく指示に従うようにするデータ収集がすごい難しい。#SO100 #LeRobot pic.twitter.com/4EKBIR9fzN
— masato_ka (@masato_ka) 2025年5月23日