lekiwi のキャリブレーションとテレオペ
はじめに
以下を参考にさせていただきました。貴重な情報のご提供に感謝いたします。
やってみると、エラーがたくさん出ました。
エラー対応で初めてわかったこともあり、忘れないように記録します。
LerobotでLekiwiを使用する方法
LeRobot LeKiwi 入門 (3) - キャリブレーションとテレオペレーション
前提は conda で 仮想環境を構築済みであり、作業ディレクトリが ~/lerobot です。バージョンは、lerobot 0.4.x です。
念のために、Ubuntu 22.04 での手順例をしめします。
conda create -y -n lerobot python=3.10
conda activate lerobot
git clone https://github.com/huggingface/lerobot.git ~/lerobot
conda install ffmpeg -c conda-forge
cd ~/lerobot
pip install -e ".[lekiwi,feetech,zeromq]"
なぜか、zeromq がインストールできませんでしたが、あらためて以下を実行したらインストールできました。
pip install -e ".[zeromq]"
もし、pytorch のバージョン不整合関係でトラブルが起きたら、以下を試してもいいかもしれません(私の場合は、これでトラブルが解消しました)。
pip install torch==2.7.1 torchvision==0.22.1 torchaudio==2.7.1
その後、以下を実行。
python - << 'EOF' import torch, torchvision, torchaudio print(torch.__version__) print(torchvision.__version__) print(torchaudio.__version__) EOF
無事に以下が表示されました。
2.7.1+cpu 0.22.1 2.7.1
サーボモータにID書き込み
まず、以下のコマンドで、サーボモータドライバの USBポートを調べます。
USBケーブルをPCまたはラズパイにつなぎ、以下を実行します。メッセージにしたがって、ケーブルを外して ENTER を押すと、/dev/ttyACM0 のような表示がでます。
lerobot-find-port
表示が出たら、USBケーブルを接続します。
アクセス権付与のため、以下を実行します。 ttyACM0 の部分は表示された値に置き換えてください。
sudo chmod 666 /dev/ttyACM0
サーボモータを必ず1つずつ接続します。最初は 6 番です。以下を実行します。メッセージにしたがい ENTER を押したら、6番を外して 5番をつなぎ ENTER を押します。同様に、4番、3番、2番、1番、9番、8番、7番 の順に繰り返します。この順番を間違えたら、最初からやり直します。
lerobot-setup-motors \
--robot.type=lekiwi \
--robot.port=/dev/ttyACM0
キャリブレーション(ラズパイ)
USBカメラ2台を接続してから、キャリブレーションを開始します。
以下で、キャリブレーションを実施しました。このプログラムは、
/home/###/lerobot/src/lerobot/scripts の中にあります。以下にあります。### はユーザー名です。
lerobot-calibrate \
--robot.type=lekiwi \
--robot.id=my_awesome_kiwi
結果は以下の通り。キャリブレーションだけでカメラ使わないのに、何故かカメラの認識をやっています。
つまり、カメラ2台の USBをつないでおかないと実行時にエラーが出ます。
...
INFO 2026-01-22 17:12:00 a_opencv.py:180 OpenCVCamera(/dev/video0) connected.
INFO 2026-01-22 17:12:01 a_opencv.py:180 OpenCVCamera(/dev/video2) connected.
INFO 2026-01-22 17:12:01 i/lekiwi.py:125 my_awesome_kiwi LeKiwi connected.
続きの画面で、ENTER を押します。
Press ENTER to use provided calibration file associated with the id my_awesome_kiwi, or type 'c' and press ENTER to run calibration: c
INFO 2026-01-22 17:13:53 i/lekiwi.py:141
Running calibration of my_awesome_kiwi LeKiwi
ここで、アームを初期位置に支え持ち、ENTER を押すと、キャリブレーションが開始されます。各サーボの動かせる限界まで手で動かします。動かしている間、サーボの角度の変化が表示されます。
Move robot to the middle of its range of motion and press ENTER....
Move all arm joints except '['arm_wrist_roll', 'base_left_wheel', 'base_back_wheel', 'base_right_wheel']' sequentially through their entire ranges of motion.
Recording positions. Press ENTER to stop...
-------------------------------------------
-------------------------------------------
NAME | MIN | POS | MAX4
arm_shoulder_pan | 738 | 2179 | 33649
arm_shoulder_lift | 874 | 1842 | 3299
arm_elbow_flex | 847 | 2215 | 3039
arm_wrist_flex | 905 | 2040 | 3203
arm_gripper | 2037 | 2038 | 3480
ENTER で止めると、以下のようにキャリブレーションの結果が保存され、終了処理が実施されます。
Calibration saved to /home/pi/.cache/huggingface/lerobot/calibration/robots/lekiwi/my_awesome_kiwi.json
INFO 2026-01-22 17:16:22 i/lekiwi.py:408 Base motors stopped
INFO 2026-01-22 17:16:22 a_opencv.py:541 OpenCVCamera(/dev/video0) disconnected.
INFO 2026-01-22 17:16:22 a_opencv.py:541 OpenCVCamera(/dev/video2) disconnected.
INFO 2026-01-22 17:16:22 i/lekiwi.py:417 my_awesome_kiwi LeKiwi disconnected.
よく見ると、さっきの一番上の arm_shoulder_pan の MAX が 33649 と表示されています。ENTER の前までは、3364 だったのが、ひと桁増えています。
NAME | MIN | POS | MAX4
arm_shoulder_pan | 738 | 2179 | 33649
キャリブレート結果が正常かどうか不安だったので、cat で確認しました。### はユーザー名です。
cat /home/###/.cache/huggingface/lerobot/calibration/robots/lekiwi/my_awesome_kiwi.json
保存されていた .json ファイルの中身は以下で、特に問題ありませんでした。
{
"arm_shoulder_pan": {
"id": 1,
"drive_mode": 0,
"homing_offset": -2002,
"range_min": 738,
"range_max": 3364
},
"arm_shoulder_lift": {
"id": 2,
"drive_mode": 0,
"homing_offset": -1014,
"range_min": 874,
"range_max": 3299
},
"arm_elbow_flex": {
"id": 3,
"drive_mode": 0,
"homing_offset": 1168,
"range_min": 847,
"range_max": 3039
},
"arm_wrist_flex": {
"id": 4,
"drive_mode": 0,
"homing_offset": -2044,
"range_min": 905,
"range_max": 3203
},
"arm_wrist_roll": {
"id": 5,
"drive_mode": 0,
"homing_offset": -2002,
"range_min": 0,
"range_max": 4095
},
"arm_gripper": {
"id": 6,
"drive_mode": 0,
"homing_offset": 925,
"range_min": 2037,
"range_max": 3480
},
"base_left_wheel": {
"id": 7,
"drive_mode": 0,
"homing_offset": 0,
"range_min": 0,
"range_max": 4095
},
"base_back_wheel": {
"id": 8,
"drive_mode": 0,
"homing_offset": 0,
"range_min": 0,
"range_max": 4095
},
"base_right_wheel": {
"id": 9,
"drive_mode": 0,
"homing_offset": 0,
"range_min": 0,
"range_max": 4095
}
}
キャリブレーション(PC)
こちらは、USBカメラ不要なこともあり、スムーズにできました。
python -m lerobot.calibrate \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyACM0 \
--teleop.id=my_awesome_leader_arm
ラズパイをホストにして、PCからリモートでテレオペ
まず、ラズパイで以下を実行し、ラズパイの IP (192.168.###.### みたいな4種類の数字列)を調べます。
hostname -I
次に、PC側の準備です。以下で、PCにつないだサーボコントローラの情報を確認します。今回は、/dev/ttyACM0 でした。
lerobot-find-port
PCの examples/lekiwi/teleoperate.py を書き換えます。
変更するのは、remote_ip の行と port の行です。それぞれ、調べた内容で書き換えます
robot_config = LeKiwiClientConfig(
remote_ip="192.168.###.###",
id="my_awesome_kiwi"
)
teleop_arm_config = SO100LeaderConfig(
port="/dev/ttyACM0",
id="my_awesome_leader_arm"
)
なお、この examples/lekiwi/teleoperate.py は以下のように実行します。
python examples/lekiwi/teleoperate.py
ホストにうまくつながらない場合、以下を試してみます。
python examples/lekiwi/teleoperate.py --robot.address=192.168.###.###
実行時にエラーがでる場合があります。
ModuleNotFoundError: No module named 'zmq'
この場合、以下を実行しました。
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py
...
Successfully installed packaging-26.0 pip-25.3 wheel-0.46.2
ただし、以下のエラーが出る可能性があります。
ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
lerobot 0.4.3 requires packaging<26.0,>=24.2, but you have packaging 26.0 which is incompatible.
その場合は、以下でなんとかなるはずです(私はなんとかなりました)
python -m pip install "packaging<26.0,>=24.2"
...
Successfully installed packaging-25.0
ここまでくれば、以下をすれば、pyzmqのインストールも大丈夫です。
python -m pip install pyzmq
...
Successfully installed pyzmq-27.1.0
ラズパイのホストプログラムはカメラをチェックするので、認識するか以下で事前に確認しました。
python3 - << 'EOF'
import cv2, time
cap = cv2.VideoCapture("/dev/video2")
time.sleep(2)
ret, frame = cap.read()
print("ret:", ret)
cap.release()
結果は、以下で False でした。
[ WARN:0@12.243] global cap_v4l.cpp:1049 tryIoctl VIDEOIO(V4L2:/dev/video0): select() timeout.
ret: False
USBを指し直して、もう一回実行すると、今度は True で大丈夫そうです。
video0 ret: True
満を持して、ラズパイのホストプログラムを起動します。
python -m lerobot.robots.lekiwi.lekiwi_host --robot.id=my_awesome_kiwi --robot.port=/dev/ttyACM0
ところが、こんなエラーが。id=6 のグリッパーの接続の問題のようです。
ConnectionError: Failed to write 'Lock' on id_=6 with '1' after 1 tries. [TxRxResult] Incorrect status packet!
しかし、コネクタを指し直すと、エラーがでなくなったので、気を取り直してラズパイのホストプログラムを実行しました。ところが、USBカメラの認識問題でエラーです。
[ WARN:0@10.374] global cap_v4l.cpp:1049 tryIoctl VIDEOIO(V4L2:/dev/video0): select() timeout.
...
RuntimeError: OpenCVCamera(/dev/video0) read failed (status=False).
USBを指し直すとエラーが出ない場合もあるのですが、不安定だったので、カメラを探さないオプション --robot.cameras={} をつけて、ラズパイで実行しました。
python -m lerobot.robots.lekiwi.lekiwi_host --robot.id=my_awesome_kiwi --robot.port=/dev/ttyACM0 --robot.cameras={}
実行時の画面表示は以下で、カメラ関係のエラーはでなくなりました。ただし、タイムアウト設定が 0.5秒(500mS)と短く、その間にPCのプログラム examples/lekiwi/teleoperate.py を起動できませんでした。その結果、このホストプログラムは、PCからのコマンドを受け付けることができず、終了しました。
WARNING:root:No command available
...
WARNING:root:No command available
WARNING:root:Command not received for more than 500 milliseconds. Stopping the base.
Cycle time reached.
Shutting down Lekiwi Host.
ラズパイのホストプログラム実行後に、PC側を実行しましたが、ホストのタイムアウトに間に合いませんでした。
PCのプログラムにもタイムアウト時間が設定されており、PCのプログラムを先に立ち上げると、ラズパイ(ホスト)が立ち上がる前にPC側が先にタイムアウトします。
仕方がないので、ホストプログラムのタイムアウト設定を変更します。ホストプログラムは、同じホルダー内にある config_lekiwi.py を参照しており、その中の以下の部分を書き換えて、タイムアウトを5秒(5000ms)にしました。
# Watchdog: stop the robot if no command is received for over 0.5 seconds.
# watchdog_timeout_ms: int = 500
watchdog_timeout_ms: int = 5000
ラズパイで、再び以下を実行し、いそいでPC側のプログラムも実行しました。
python -m lerobot.robots.lekiwi.lekiwi_host --robot.id=my_awesome_kiwi --robot.port=/dev/ttyACM0 --robot.cameras={}
つながりました!!!
実行時の画面表示は以下で、タイムアウトが5秒(5000ms)になり、接続できました。ただし、30秒で Cycle time に到達し、プログラムは自動的に終了しました。
WARNING:root:No command available
...
...
WARNING:root:Command not received for more than 5000 milliseconds. Stopping the base.
WARNING:root:No command available
...
...WARNING:root:No command available
Cycle time reached.
Shutting down Lekiwi Host.
60秒つなぎたい場合は、 config_lekiwi.py の以下の部分の 30 を 60 書き換えます。
# Duration of the application
connection_time_s: int = 30
車両を動かす場合は、キーボードを使います。
w: 前進、s:後退、a:左進、d:右進、z:左回転、x:右回転
r:速度up、f:速度down
速度は以下の3種類です。
| 速度モード | 直線速度 (m/s) | 回転速度 (deg/s) |
|---|---|---|
| 高速 | 0.4 | 90 |
| 中速 | 0.25 | 60 |
| 低速 | 0.1 | 30 |
なお、実行時に rerun が自動的に起動していますので、確認ください。
終わりに
やる前は簡単に動くと思っていましたが、やり始めると色々トラブルが発生して、結構苦しみました。
最後のタイムアウト問題が一番の難関でした。最終的には、無事に動いたのでよかったです。
追記
その後、古いノートPCに入れ替えました。PC接続のリーダーアームでラズパイ接続のフォロワーアームをテレオペできたのですが、キーボードで車両を動かすことができませんでした。
色々調べて試行錯誤したところ、マウスの動きを画面に反映させたり、ウィンドウを描画したりする「ディスプレイサーバー」の問題であることがわかりました。
ログイン画面の右下にある「歯車アイコン」でWayland から X11(X.Org)へ切り替えることで、キーボードでの車両コントロールができるようになりました。古いPCでうまく動作しない場合は、試してみるとよいかもしれません。