フィジカルAI研究室を作る Log#20 | ゲームパッドで動いた mechArm 270、遅さは pymycobot の版

この記事の素材(コード・ログ・データ 20ファイル・まとめてダウンロードあり)
AIで読む ChatGPT・Claude などで、この記事に質問できます

市販のゲームパッドで小型ロボットアーム mechArm 270 を実機で動かしたところ、1回の指令ごとに約1.6秒待たされていた原因は、アームの中の Raspberry Pi で動く制御の受け口(daemon)が、使うはずの制御ライブラリ pymycobot 2.9.6 ではなく 4.0.4 を読んでいたことでした。pymycobot 4.0.4 は、指令を送るたびにアームからの返事を0.5秒ずつ3回待ち、同じ指令を3回書いてから −1 を返していました。 2.9.6 に戻すと1回の送信は約0.02秒になり、十字キーを押し続ければ関節が毎秒約8°で動き続けるようになりました。

この回でやったことで、次のことが変わります。

  • 良くなること:十字キーを押し続けると、関節が止まらずに動き続ける。長押しの速さは、直す前の毎秒1.0°から、毎秒約8°(中央の値。実機の記録 14 回の長押しから)になった。1回押して1.6秒待つことはなくなった
  • もたらされること:10月30日の夜に daemon を自動で起動する形にしてから、このアームを使うスクリプトはすべて、1回の送信に約1.6秒かかっていた。AI(Physical Intelligence の π0.5)の推論も同じ daemon を通るので、次の推論から送る待ちが短くなる見込み。推論で実際にどれだけ縮むかは、次の実機の推論で測る
  • 時間・費用:遅さに気づいてから daemon を直すまで約6分(7:51 に長押しが動かないと気づき、7:57 に直った daemon で動いた)。直したのは起動スクリプトの1行。GPU は使っていないので費用は0円

前の回(LOG419)では、ゲームパッドで関節を動かすスクリプトを、アームに指令を送らない試しまで作りました。同じシリーズの Log#18(LOG422)では、AI の推論の途中で手首の関節が垂れたまま戻らなくなり、実機を止めていました。今回は手首の点検から始め、ゲームパッドで初めて実物のアームを動かしました。動かしてみると、決めた範囲が狭すぎる、0.5°の押しでは関節が動かない、押すたびに長く待たされる、長押しがぎこちない、と困りごとが順に出てきて、その場で1つずつ直しています。

段階やったこと結果
手首を点検する
6つのサーボの力・角度・電圧・温度を、アームを動かさずに読んだ
手首 j4 にも力が入っていた。あとでゲームパッドで動かすと、0°から −10°まで指令どおりに動いた
ゲームパッドで初めて実機を動かす
根元・肩・ひじ・手首・爪・停止・HOME を一通り押した
動いた。ただ、起動した姿勢から各関節 ±10° の枠では、HOME からブロックの上まで運べなかった
範囲を広げ、長押しを足す
枠をやめてアーム本体の可動域にし、十字キーの長押しで送り続ける形にした
別の Claude にコードを読んでもらい、直すべき点1つと推奨5つのうち4つを直した
長押しが動かない理由を調べる
記録を見ると、1回送るたびに約1.6秒かかっていた
Pi の daemon が pymycobot 4.0.4 を読んでいた。起動スクリプトで 2.9.6 を読むように直した
刻みと送り直し
0.5°の押しは半分以上で関節が動かなかった。無視された指令で8秒止まった
1押しを1°にし、動いていなければ同じ指令を送り直す形にした
長押しをなめらかにする
刻みごとに着いて止まっていたので、読んだ角度から3°先を0.1秒おきに送る形にした
止まらずには動くが、なめらかにはならなかった。角度の読み取りが続けて失敗し、13秒止まった場面もあった
限界を測る準備
今の形をタグで残し、jog(押している間だけ動き続けるアームの命令)を測る試しを作った
実機では、次の回で測る

ゲームパッドで直す練習を重ねる前に、mechArm 270 でどこまでなめらかに動かせるのかを数字で知りたい、というのが次の課題です。

GPU を買うか借りるかの判断は、Runpod で実際に借りて学習させた費用をもとに、別のページにまとめています。

導入比較ガイドロボットAIの学習用GPU、買うか借りるか実際に借りて学習させた費用と、損益分岐の計算機で決められます

作業ログ ― 手首の点検から、ゲームパッドの実機と daemon の pymycobot の版まで

この回の数字は、すべて実機の記録(KIOXIA の runs/experiments/gamepad_teleop/ の log.jsonl 5本と、diag/servo_check_20261103_071326/)から数えたものです。見込みの数字は、見込みと書いています。

この回で使う言葉

言葉意味
daemon(デーモン)
アームの中の Raspberry Pi で、ずっと動いている受け口のプログラム(mecharm_daemon.py)。Mac から送られた指令を受け取り、シリアルでアームへ流す。ゲームパッドのスクリプトも AI の推論も、ここを通ってアームを動かす
systemd
Raspberry Pi の電源を入れたときに、決めたプログラムを自動で起動する仕組み。10月30日の夜から daemon はこれで起動している
fresh_mode
アームの設定の1つ。1にすると、前の動きが終わるのを待たずに、新しい指令で上書きできる
jog
アームの命令の1つ。関節と向きと速さを渡すと、止める命令が来るまで、一定の速さで動き続ける

pymycobot は、mechArm を Python から動かすためのライブラリ

pymycobot は、mechArm 270 を作っている Elephant Robotics が出している Python のライブラリです。関節の角度を送る send_angles、角度を読む get_angles、爪を動かす命令などが入っています。PyPI で版ごとに配られていて、同じ名前の命令でも、版によって中の動きが違います。

この回で出てくる版
置き場所(Raspberry Pi)
送る命令の返り方
2.9.6
/usr/local/lib/python2.7/dist-packages(対話のシェルの ~/.bashrc で PYTHONPATH に入る)
書いたらすぐ返る
4.0.4
Python 3 の標準の置き場所(何も付けずに起動すると読まれる)
アームの返事を0.5秒ずつ3回待ち、来なければ −1 を返す

このプロジェクトでは、daemon も、点検のスクリプトも、2.9.6 を前提に作ってきました。2.9.6 が対話のシェルでしか読まれず、何も付けずに起動すると 4.0.4 が読まれることは、10月19日のレビュー(docs/review_request_20261019_record_teach_demo.md)で分かっていました。

11/3 7:05:前回までの状態を確かめた

ゲームパッドのスクリプトの残りを頼んだ依頼69は、前の晩に終わっていました(ドライランは記録しない・起動時の SDL の警告を消す。テスト53件。commit f061d54)。

依頼箱の報告 20261102_69_ゲームパッドのドライランは記録しない・SDLの重複を直す_20261102_1939.md

# 結果:20261102_69_ゲームパッドのドライランは記録しない・SDLの重複を直す

- 状態:完了
- 始めた時刻:2026-11-02 19:39
- 終わった時刻:2026-11-02 20:09(30分)
- 作業フォルダ:/Users/shimazueiichi/r2r2r-scripts
- この続きを Claude Code で話すとき:作業フォルダで `claude --resume e3ba2c9d-9a7a-49a7-82b0-e461abd73097`

## Claude Code の報告

**やったこと**
- ドライラン(`--execute` なし)は、KIOXIA に何も書かないようにしました。フォルダも作らず、KIOXIA がつながっているかも確かめないので、つながっていなくても動きます。`--execute` のときは今までどおり記録します。
- 変わる表示は2行だけです。始めの行は「[記録] ドライランなので記録しません」、終わりの行は「記録なし(ドライラン)」になります。ほかのターミナルの表示と画面は前と同じです。
- スクリプトの先頭の説明に「L2+R2 は新しい指令を送らないだけで、送った1回分(HOME を含む)は最後まで動く」を書きました。
- SDL が2つ読み込まれる原因が分かりました。
  - 2つ目は opencv(cv2)に入っている `site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib` です。
  - gamepad_teleop.py が先頭で読む `pi05/run_policy_client.py` が `import cv2` をしていました(camera_resolver から cv2_enumerate_cameras も読む)。`j0_sweep_scan.py`・`visual_servo_pick.py`・`pi05/policy_recorder.py` も先頭で cv2 を読みます。
- 直し方:
  - この3つ(run_policy_client・j0_sweep_scan・visual_servo_pick)は、`--execute` のときだけ読むようにしました。
  - ドライランでも要る値(HOME・J4_SAFE・GRIPPER_SLEEP、waypoint_replay.py の可動域)は、元のファイルの書いてある値をそのまま読みます。同じ値を二重に書いてはいません。
  - `--execute` では、読み込んだあとに値が同じかを確かめます。違えば、記録も daemon も触らずに止めます。
  - ほかのスクリプトと Python の環境は変えていません。
- 操作・刻み・守りの値・送り方・停止の作り・十字キー左右の向きは変えていません。実機には流していません。
- codex のレビューは2回通しました。必須の指摘は2回ともなしでした。推奨は1回目に3件、2回目に1件あり、すべて直しました。

**結果**
- テストは53件すべて通りました(前からの46件と、新しく足した7件)。
  - ドライランのテストは「KIOXIA に何も作らない・書かない」を確かめる形に変えました。
  - 新しいテストは、`--execute` では今までどおり書くこと、別のプロセスで起動したドライランに cv2 が入らず警告も出ないこと、値の読み取りと一致を確かめます。
- PS4 コントローラーをつないだ状態で本物のドライランを起動し、objc の警告は0行でした(前は十数行)。
- 画面の描画を前の版と比べたところ、止まっていないときも止まっているときも同じでした。
- KIOXIA の `gamepad_teleop/` の中は `teleop_20261102_192657_dry` だけのままです。消していませんし、動かしてもいません。
- pygame 自身が出す「pkg_resources is deprecated」の警告は残ります。SDL とは別のもので、pygame だけを読む `gamepad_check.py` でも出ます。

**変えたファイル**
- `tools/gamepad_teleop.py`
- `tools/test_gamepad_teleop.py`
- `logs/20261102_2009.md`(作業の記録)
- commit:f061d54(この3つを個別に指定して add しました)

**決めてほしいこと**
- `--execute` のときは cv2 を読むので、SDL の警告は今までどおり出ます(動きには影響ありません)。消すには、Python の環境を変える(opencv か pygame を入れ替える)か、`visual_servo_pick.py` などで cv2 を読むところを変える必要があります。このままにするか、決めてください。

手首の点検のスクリプトを頼んだ依頼58は、codex の2回目のレビューを待つ間に時間切れになっていました。Mac の ~/r2r2r-scripts を見ると、tools/servo_check.sh・tools/pi/servo_check_pi.py とテストはでき上がっていて、コミットされていないだけでした。2回目のレビューの結果はありません。テストを流すと、シェルの52件と Python の15件はどちらも通りました。

tools/test_servo_check.sh の出力

[1] systemd で動いている・読むだけ
  ok   終了コード 0
  ok   console.txt がある
  ok   result.json を持ち帰った
  ok   result.json の move は null (読むだけ)
  ok   6 つのサーボを読んだ
  ok   Pi へ写してから流した
  ok   止めてから流した
  ok   流したあとに戻した
  ok   --read-only を渡した
  ok   PYTHONPATH に 2.9.6 の置き場所
  ok   画面に j4 の力が入っていない
  ok   画面にデーモンが戻った
  ok   2.9.6 で戻れば PYTHONPATH の注意は出ない
  ok   デーモンは動いている
  ok   手で起動していない
[2] 手で起動されている・動かす側で q
  ok   終了コード 0
  ok   pkill で止めた
  ok   対話シェルで戻した
  ok   systemctl は使っていない
  ok   --read-only を渡していない
  ok   支える 1 行が出た
  ok   q で何も送らずに止めた
  ok   result.json に止めた印
[3] デーモンが動いていない
  ok   終了コード 0
  ok   止めていない・起動していない
  ok   動いていないと出した
  ok   デーモンは動いていないまま
[4] Pi のスクリプトが失敗しても戻す
  ok   終了コード 3 を返す
  ok   戻した
  ok   持ち帰れないと出した
[5] デーモンが止まらない
  ok   終了コード 1
  ok   止まらないと出した
  ok   Pi のスクリプトは流していない
[6] 止めたあとも 5555 が開いている・シリアルを別のプロセスが開いている・確かめられない
  ok   listen_stays: 終了コード 1
  ok   listen_stays: 止めた理由を出した
  ok   listen_stays: Pi のスクリプトは流していない
  ok   serial=777: 終了コード 1
  ok   serial=777: 止めた理由を出した
  ok   serial=777: Pi のスクリプトは流していない
  ok   serial=不明: 終了コード 1
  ok   serial=不明: 止めた理由を出した
  ok   serial=不明: Pi のスクリプトは流していない
[7] 戻す前に点検の残りを止める・戻したデーモンが 4.0.4 かもしれない・戻らない
  ok   点検の残りを止めてから戻した
  ok   JSON を持ち帰ってから戻した
  ok   PYTHONPATH の注意を出した
  ok   戻らないと注意を出した
  ok   戻らなくても終了コードは Pi のもの (0)
[8] KIOXIA がない・同じ名前がある・引数が違う
  ok   KIOXIA がないと 1
  ok   KIOXIA がないと Pi に触らない
  ok   同じ名前があると 1
  ok   同じ名前があると Pi に触らない
  ok   知らない引数は 2
OK 52 / NG 0

test_servo_check_pi.py の出力

test_main_read_only_writes_json (test_servo_check_pi.TestMain) ... ok
test_already_zero_goes_home (test_servo_check_pi.TestMove) ... ok
test_focus_missing_stops (test_servo_check_pi.TestMove) ... ok
test_negative_start (test_servo_check_pi.TestMove) ... ok
test_partial_moves_follow_measured (test_servo_check_pi.TestMove) ... ok
test_q_at_prompt_sends_nothing (test_servo_check_pi.TestMove) ... ok
test_q_during_angle_retries (test_servo_check_pi.TestMove) ... ok
test_q_during_steps_stops_sending (test_servo_check_pi.TestMove) ... ok
test_send_failure_stops (test_servo_check_pi.TestMove) ... ok
test_steps_to_zero_then_home (test_servo_check_pi.TestMove) ... ok
test_stuck_does_not_run_ahead (test_servo_check_pi.TestMove) ... ok
test_exception_is_not_fatal (test_servo_check_pi.TestRead) ... ok
test_legacy_fallback_and_missing (test_servo_check_pi.TestRead) ... ok
test_no_reply_servo (test_servo_check_pi.TestRead) ... ok
test_read_only_sends_nothing (test_servo_check_pi.TestRead) ... ok

----------------------------------------------------------------------
Ran 15 tests in 2.280s

OK

アームを動かす部分(手首に力を入れ直して5°ずつ0°へ戻す)はレビューが終わっていないので、まず読むだけの点検(--read-only)を流すことにしました。

7:13:手首 j4 のサーボを読むだけで点検すると、力が入っていた

1回目は Pi へスクリプトを送る所で接続が切れ、2回目で通りました。

KIOXIA の diag/servo_check_20261103_071236/console.txt

servo_check 20261103_071236 (結果: /Volumes/KIOXIA/r2r2r-data/diag/servo_check_20261103_071236)
scp: Connection closed
ABORT: Pi へ送れなかった

servo_check.sh —read-only を流したターミナルの出力(1〜64行目)

Last login: Mon Nov  2 15:44:30 on ttys003
(base) shimazueiichi@shimadzueiichinoMacBook-Pro ~ % cd ~/r2r2r-scripts
tools/servo_check.sh --read-only
servo_check 20261103_071236 (結果: /Volumes/KIOXIA/r2r2r-data/diag/servo_check_20261103_071236)
scp: Connection closed
ABORT: Pi へ送れなかった
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
tools/servo_check.sh --read-only
servo_check 20261103_071326 (結果: /Volumes/KIOXIA/r2r2r-data/diag/servo_check_20261103_071326)
--- デーモンの状態 (止める前)
mode=systemd
pid=540
listen=yes
daemon_pythonpath=(なし)
serial_users=540
checker=no
--- デーモンの状態 (止めたあと)
mode=none
pid=なし
listen=no
serial_users=(なし)
checker=no
pymycobot 2.9.6 (/usr/local/lib/python2.7/dist-packages/pymycobot/__init__.py)
========================================================================
1. 読むだけの点検 (アームは動かさない)
========================================================================
  get_angles                 [+23.29, +109.77, -62.40, +0.79, -49.30, -30.93]
  get_encoders               [1783, 3297, 1338, 2039, 1487, 2400]
  get_error_information      取れない  (この版に get_error_information がない)
  get_servo_status           [0, 0, 0]
  get_servo_temps            [6425, 5654, 6421]
  get_servo_voltages         [+1901.60, +1901.80, +1876.10]
  get_system_version         [11]
  is_all_servo_enable        1
  is_controller_connected    1
  is_power_on                1
  read_next_error            [0, 0, 0, 0, 0, 0, 0]

  サーボごと (力 1=入っている 0=入っていない -1=エラー / 番地 62・63・65 は Feetech STS 想定・未確認)
      id    力       角度    エンコ     エンコ→°   電圧62   温度63   状態65     電圧     温度     応答
  j0   1    1   +23.29   1783    -23.29     74     25      0 +1901.60   6425     あり
  j1   2    1  +109.77   3297   +109.78     72     26      0 +1901.80   5654     あり
  j2   3    1   -62.40   1338    -62.40     74     22      0 +1876.10   6421     あり
  j3   4    1    +0.79   2039     -0.79     74     22      0   応答なし   応答なし     あり
  j4   5    1   -49.30   1487    -49.31     73     25      0   応答なし   応答なし     あり
  j5   6    1   -30.93   2400    +30.94     73     21      0   応答なし   応答なし     あり

  目安:
    j4 の電圧62 73 / ほかの関節の中央 74
    j4 の温度63 25 / ほかの関節の中央 22
    j4 の角度 -49.30 / エンコーダからの角度 -49.31 (差 0.0°。2048=0°・向きは仮定。同じセンサーの読みどうし)
結果: /tmp/servo_check_20261103_071326.json
Connection to 192.168.2.1 closed.
--- servo_check_pi.py の終了コード: 0
結果の JSON: /Volumes/KIOXIA/r2r2r-data/diag/servo_check_20261103_071326/result.json
--- デーモンを戻す (systemctl start)
mode=systemd
pid=31095
listen=yes
daemon_pythonpath=(なし)
serial_users=31095
checker=no
デーモンは戻った (5555 LISTEN)
注意: デーモンの PYTHONPATH に python2.7 がない (pymycobot 4.0.4 を読んでいるかもしれない)

KIOXIA の diag/servo_check_20261103_071326/result.json

{
 "read": {
  "global": {
   "is_power_on": 1,
   "is_controller_connected": 1,
   "is_all_servo_enable": 1,
   "read_next_error": [
    0,
    0,
    0,
    0,
    0,
    0,
    0
   ],
   "get_error_information": {
    "error": "この版に get_error_information がない"
   },
   "get_system_version": [
    11
   ],
   "get_servo_voltages": [
    1901.6,
    1901.8,
    1876.1
   ],
   "get_servo_temps": [
    6425,
    5654,
    6421
   ],
   "get_servo_status": [
    0,
    0,
    0
   ],
   "get_encoders": [
    1783,
    3297,
    1338,
    2039,
    1487,
    2400
   ],
   "get_angles": [
    23.29,
    109.77,
    -62.4,
    0.79,
    -49.3,
    -30.93
   ]
  },
  "servos": [
   {
    "joint": "j0",
    "servo_id": 1,
    "enable": 1,
    "encoder": 1783,
    "voltage_raw": 74,
    "temp_raw": 25,
    "status_raw": 0,
    "angle": 23.29,
    "angle_from_encoder": -23.291015625,
    "responded": true,
    "voltage_list": 1901.6,
    "temp_list": 6425,
    "status_list": 0
   },
   {
    "joint": "j1",
    "servo_id": 2,
    "enable": 1,
    "encoder": 3297,
    "voltage_raw": 72,
    "temp_raw": 26,
    "status_raw": 0,
    "angle": 109.77,
    "angle_from_encoder": 109.775390625,
    "responded": true,
    "voltage_list": 1901.8,
    "temp_list": 5654,
    "status_list": 0
   },
   {
    "joint": "j2",
    "servo_id": 3,
    "enable": 1,
    "encoder": 1338,
    "voltage_raw": 74,
    "temp_raw": 22,
    "status_raw": 0,
    "angle": -62.4,
    "angle_from_encoder": -62.40234375,
    "responded": true,
    "voltage_list": 1876.1,
    "temp_list": 6421,
    "status_list": 0
   },
   {
    "joint": "j3",
    "servo_id": 4,
    "enable": 1,
    "encoder": 2039,
    "voltage_raw": 74,
    "temp_raw": 22,
    "status_raw": 0,
    "angle": 0.79,
    "angle_from_encoder": -0.791015625,
    "responded": true,
    "voltage_list": null,
    "temp_list": null,
    "status_list": null
   },
   {
    "joint": "j4",
    "servo_id": 5,
    "enable": 1,
    "encoder": 1487,
    "voltage_raw": 73,
    "temp_raw": 25,
    "status_raw": 0,
    "angle": -49.3,
    "angle_from_encoder": -49.306640625,
    "responded": true,
    "voltage_list": null,
    "temp_list": null,
    "status_list": null
   },
   {
    "joint": "j5",
    "servo_id": 6,
    "enable": 1,
    "encoder": 2400,
    "voltage_raw": 73,
    "temp_raw": 21,
    "status_raw": 0,
    "angle": -30.93,
    "angle_from_encoder": 30.9375,
    "responded": true,
    "voltage_list": null,
    "temp_list": null,
    "status_list": null
   }
  ],
  "notes": [
   "j4 の電圧62 73 / ほかの関節の中央 74",
   "j4 の温度63 25 / ほかの関節の中央 22",
   "j4 の角度 -49.30 / エンコーダからの角度 -49.31 (差 0.0°。2048=0°・向きは仮定。同じセンサーの読みどうし)"
  ]
 },
 "move": null,
 "pymycobot": {
  "version": "2.9.6",
  "file": "/usr/local/lib/python2.7/dist-packages/pymycobot/__init__.py"
 },
 "started": "2022-10-13 14:44:59",
 "finished": "2022-10-13 14:45:02"
}

6つのサーボすべてに力が入っていて(is_all_servo_enable 1)、エラーの読み(read_next_error)も全部0でした。手首 j4 の電圧の読み(番地62)は73で、ほかの関節の中央の74とほぼ同じ、温度の読み(番地63)は25で、ほかの中央22より少し高いだけでした。LOG422 では手首が +54.49° のまま指令に応えなくなっていましたが、この朝は −49.30° にいて、力も入っていました。電源を入れ直したあと、どこかで戻ったと見ています。何が戻したのかは、この記録からは分かりません。

点検の終わりに、デーモンの PYTHONPATH に python2.7 がない、という注意が出ています。止める前から同じ状態だったので、この時点では点検で変わったものではないと判断しました。この注意が、あとで遅さの原因につながります。

7:14:ゲームパッドで初めて実物の mechArm 270 を動かした

この記事のコード・ログ・データは、1ファイルずつ下に置いています。全文はリンク先にあります。

ファイルの一覧(20本)

01_sec04.txt ― gamepad_teleop.py --execute を動かしたターミナルの出力(65〜217行目)・16,539字

02_Claude_docs_review_request_20261103_gamepad_hold.md ― 別の Claude に、長押しのコードを読んでもらった / レビュー依頼 docs/review_request_20261103_gamepad_hold.md(差分を含む全文)・33,120字

03_Claude.md ― 別の Claude に、長押しのコードを読んでもらった / 別の Claude のレビューの全文・4,627字

04_sec06.txt ― 7:49:長押しが動かない。0.5°では関節が動かず、1回の送信に約1.6秒かかっていた・12,777字

05_sec07.py.txt ― pymycobot 4.0.4 と 2.9.6 の該当箇所(PyPI の配布物から)・4,786字

06_sec07.txt ― daemon.log の確かめと、起動スクリプトの入れ替え・daemon の起動し直し(300〜350行目)・8,824字

07_sec08.txt ― 7:57 からのターミナルの出力と、2.9.6 の起動・1°の刻みのコミット(351〜760行目)・47,550字

08_sec09.txt ― 3°先の形で動かしたターミナルの出力(761〜822行目)・10,669字

09_sec09.txt ― 目標を戻さない形をコミットしたあとのターミナルの出力(823〜917行目)・13,051字

10_sec10.py.txt ― 5本の記録から数えた、送る間隔と長押しの速さ・4,695字

11_tools_jog_probe.sh.txt ― tools/jog_probe.sh・5,614字

12_tools_pi_jog_probe_pi.py.txt ― tools/pi/jog_probe_pi.py・10,591字

13_gamepad_teleop.py.txt ― gamepad_teleop.py(commit 413f7e1)・58,364字

14_test_gamepad_teleop.py.txt ― test_gamepad_teleop.py(テスト73件・commit 413f7e1)・54,393字

15_eop.py_73_commit_413f7e1.txt ― test_gamepad_teleop.py(テスト73件・commit 413f7e1) / test_gamepad_teleop.py の出力(73件)・6,311字

16_sec14.json ― 7:14 の記録 runs/experiments/gamepad_teleop/teleop_20261103_071424/log.jsonl(121行)・70,626字

17_sec14.json ― 7:49 の記録 runs/experiments/gamepad_teleop/teleop_20261103_074936/log.jsonl(50行)・32,442字

18_sec14.json ― 7:57 の記録 runs/experiments/gamepad_teleop/teleop_20261103_075657/log.jsonl(437行)・338,321字

19_sec14.json ― 8:06 の記録 runs/experiments/gamepad_teleop/teleop_20261103_080648/log.jsonl(228行)・147,025字

20_sec14.json ― 8:09 の記録 runs/experiments/gamepad_teleop/teleop_20261103_080930/log.jsonl(307行)・196,904字

アームは起動したとき j1(肩)が +109.77° で、PICK の高さ(90.87°)より下にいました。スクリプトは守りの外と判断し、HOME の長押しだけを受け付けました。HOME で戻してから、根元・肩・ひじ・手首・爪・停止を一通り押しています。

gamepad_teleop.py —execute を動かしたターミナルの出力(65〜217行目)

01_sec04.txt16,539字・153行・text
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % python3 tools/gamepad_teleop.py --execute
/opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/pkgdata.py:25: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  from pkg_resources import resource_stream, resource_exists
objc[7091]: Class SDLApplication is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x1063912c8) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x1278b0890). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[7091]: Class SDLAppDelegate is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x106391318) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x1278b08e0). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[7091]: Class SDLTranslatorResponder is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x106391390) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x1278b0958). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[7091]: Class SDLMessageBoxPresenter is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x1063913b8) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x1278b0980). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[7091]: Class SDL_cocoametalview is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x106391408) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x1278b09d0). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
別のタブで開く保存

根元(j0)も肩(j1)も手首(j4)も動き、L2+R2 の停止と OPTIONS の再開、HOME の長押しも決めたとおりに動きました。爪の行に出る result= -1 は、LOG175 のころから出ている返り値で、動いたかどうかとは関係ありません(arm_kinematics.md の「LOG175 既知の問題」)。

止まったのは、j1 の +10°、j2 の +10°、j4 の −10° でした。どれも、起動した姿勢(HOME を押したあとは HOME)から各関節 ±10° の枠です。決めたとおりに効いていました。

関節のリミットあってる?

決めたとおりではあるけれど、この枠では HOME から始めると、各関節 ±10° の中しか動けず、PICK の高さまで下ろせません。AI が止めた姿勢の近くで直すだけなら足りますが、HOME から手でブロックの上まで運ぶ使い方には合いません。

HOME から手でブロックの上まで運ぶ使い方もするのでアーム本体の可動域まで広げてください。 それと方向キーの長押しでずっと関節が動くように修正してください。

7:23:範囲をアーム本体の可動域に広げ、十字キーの長押しで送り続ける形にした

最初は依頼箱に依頼77として置きましたが、依頼箱では ServiceSim の依頼75が作業中、76が待ちで、始まるまでに時間がかかる状態でした。

依頼じゃなく、すぐに進めてください。

依頼77は依頼箱から外し(依頼箱/_to_delete_77.md に移した)、Claude が Mac の ~/r2r2r-scripts を直接直しました。外した依頼文は、何を頼もうとしたかの記録として残します。

依頼箱から外した依頼文 20261103_77_ゲームパッドの範囲を物理可動域にし長押しで動き続けるようにする.md

---
作業フォルダ: /Users/shimazueiichi/r2r2r-scripts
上限時間: 120
---
# 依頼77:tools/gamepad_teleop.py の範囲を物理可動域まで広げ、十字キーの長押しで関節が動き続けるようにする。実機には流さない(2026-11-03)

2026-11-03 朝の実機の試し(runs/experiments/gamepad_teleop/teleop_20261103_071424、120行)を受けて、エイイチが決めた。
ゲームパッドは、AI の動きを近くで直すだけでなく、HOME から手でブロックの上まで運ぶ使い方もする。

## 1. 範囲:基準の姿勢から ±15°・±10° の枠をなくし、物理可動域にする

- 今の枠(J0_RANGE_DEG 15・JOINT_RANGE_DEG 10、基準の姿勢から測る BASE)では、HOME から始めると各関節 ±10° の中しか動けず、PICK の高さまで下ろせない(今朝、j1・j2 は +10°、j4 は −10° で切られた)
- BASE の枠を外す。残す守りは次の3つ(狭い方が勝つ形は今のまま)
  - 物理可動域(wr.JOINT_LIMITS。今の読み方のまま)
  - j1 は 90.87 を超えない(PICK_J1_FIXED。床に当てないため。エイイチと決めた値のまま)
  - j4 は J4_SAFE(−90〜+60)
- 起動したときの姿勢が守りの外なら HOME しか送らない、の扱いは今のまま(今朝は j1 +109.77 で起動して、そのとおりに動いた)
- 基準の姿勢(base_pose)は範囲には使わなくなる。記録の項目として残すか消すかは任せる

## 2. 十字キーの長押しで、押している間ずっと動く

- 短く押したら今までどおり 1 刻み(0.5°、R1 を押しながらなら 2°)
- 押し続けたら、離すまで同じ向きに刻みを送り続ける。十字キーの左右(j0)・上下(選んでいる関節)の両方
- 注意:今の届いたかの判定(REACH_TOL_DEG 3°)は刻み(0.5°・2°)より大きいので、送った直後に「届いた」になる(今朝の elapsed_sec は 0.01〜0.04 秒)。この判定を頼りに次を送ると、アームより指令が先へ走る。次のように歩調を決める
  - 長押しとみなすのは、押してから約 0.4 秒たっても押しているとき(短い押しで 2 刻み出ないように)
  - 送る間隔は一定(目安 0.15〜0.2 秒。下の速さを見て決める)
  - 送る前に読んだ角度と、直前に送った指令の差が 3° を超えていたら、その回は送らずに待つ(離したときに、アームが指令から大きく遅れて動き続けないように)
  - 速さの目安:0.5° 刻みで 2〜3°/秒、R1 で 8〜10°/秒くらい。daemon と speed 20 で実際に出る速さを、ログ(今朝の分を含む)や送り口の待ち時間から見て決め、報告に書く
- 長押しを止めるもの:ボタンを離す・L2+R2 の停止・範囲の端に着いた(端では 1 回だけ「送らない」を出して、同じ行を繰り返さない)・コントローラーの接続が切れた・読み取りの失敗
- 長押しの途中で R1 を押す/離すと刻みが変わってよい
- 長押しの途中で別の関節に △ で切り替えたら、その長押しは止める
- 記録:送った 1 刻みごとに log.jsonl へ 1 行(今までと同じ項目)。長押しの何回目か・同じ長押しの通し番号を足す
- 停止の作りは変えない(L2+R2 は新しい指令を送らないだけ。送った 1 刻み分は最後まで動く)

## 変えないもの

- ボタンの割り当て・刻み(0.5° / 2°)・HOME の長押し・爪・停止と OPTIONS の再開
- 十字キー左右の向き(J0_LEFT_SIGN)。エイイチの確認待ち
- send_angles だけ・speed 20・daemon の送り方と読み方
- daemon、run_policy_client.py・visual_servo_pick.py などの既存のスクリプト、tools/gamepad_check.py
- 既存のデータ(runs/experiments/gamepad_teleop/ の2つのフォルダ)

## 確かめ(実機なし)

- 今のテスト53件が通ること(枠を外したことで意味が変わるテストは直し、直した理由を書く)
- 足すテスト:HOME から j1 を 90.87 まで下ろせる・90.87 で止まる、j4 が J4_SAFE で止まる、物理可動域で止まる/長押しで刻みが続く・短い押しは 1 刻み・離すと止まる・L2+R2 で止まる・指令が読んだ角度より 3° 先なら送らない・端で止まって同じ行を繰り返さない・△ で長押しが止まる
- ドライランで、長押しがひととおり動くこと

## 終わったら

- 関節を動かすコードで、守りの枠を外すので、codex のレビューを通してから報告する(code_review_request_template.md の形)。指摘は直すか、直さない理由を書く
- 実機には流さない。報告に、エイイチが最初に試す手順を書く(HOME から j0 の長押し → j1 の長押しで少し下ろす → 離して止まるか → L2+R2 で止まるか)
- 個別のファイルを指定して add・commit する(`git add .` は使わない)

直したのは2つです。

直した所前後
範囲
起動した姿勢から j0 ±15°・j1〜j5 ±10°、物理可動域、j1 ≤ 90.87、j4 は J4_SAFE(−90〜+60)
物理可動域、j1 ≤ 90.87、j4 は J4_SAFE。基準の姿勢からの枠はやめた
十字キーの長押しなし(1回押すと1刻み)
0.4秒押し続けたら、0.2秒おきに同じ向きの刻みを送る。直前の指令と読んだ角度の差が3°を超えている間は送らずに待つ

j1 の 90.87(PICK の高さ。床に当てないため)と、手首の J4_SAFE は残しました。HOME からブロックの上まで運んで PICK の高さまで下ろすなら、どちらにも当たりません。

長押しを足すときに、記録で気づいたことがあります。届いたかを見る幅(3°)が刻み(0.5°・2°)より大きいので、送った直後に届いたと判定されていました(7:14 の記録の elapsed_sec は 0.01〜0.04秒)。この判定を合図に次を送ると、指令がアームより先へ走り、離したあとも動き続けます。そのため、読んだ角度と指令の差で待つ形にしました。

別の Claude に、長押しのコードを読んでもらった

codex は Mac の外からは呼べなかったので、書いた Claude とは別の Claude のエージェントに、差分と全体を読んでもらいました(読み取りだけ・ファイルは変えない)。

レビュー依頼 docs/review_request_20261103_gamepad_hold.md(差分を含む全文)

# レビュー依頼:gamepad_teleop.py の範囲を物理可動域にし、十字キーの長押しで動き続けるようにした(2026-11-03)

前提: 2026-11-03 朝の実機の試し(runs/experiments/gamepad_teleop/teleop_20261103_071424)で、基準の姿勢から ±10° の枠により HOME から PICK の高さへ下ろせなかった。エイイチが「HOME から手でブロックの上まで運ぶ使い方もするので、アーム本体の可動域まで広げる」「方向キーの長押しでずっと関節が動くように」と決めた。
実装は Claude(依頼箱を通さず、エイイチの指示ですぐ直した)。まだ実機では流していない。

## 変えたこと
1. 範囲: 基準の姿勢 ±15°/±10° の枠(BASE)をやめた。残る守りは 物理可動域(wr.JOINT_LIMITS)・j1 ≤ 90.87(PICK_J1_FIXED)・j4 は J4_SAFE(−90〜+60)。起動時の姿勢が守りの外なら HOME しか送らない扱いは今のまま
2. 長押し: 十字キーを押して 0.4 秒たっても押していれば、0.2 秒おきに同じ向きの刻みを送る。2 回目からは送る前に、直前の指令と読んだ角度の差(6 関節の最大)が 3° を超えている間は送らずに待つ。3 秒待っても追いつかなければ、その長押しを止める。離す・L2+R2・△・ほかのボタン(R1 以外)・接続が切れる・範囲の端・送れなかった で長押しは止まる
別のタブで開く保存

別の Claude のレビューの全文

03_Claude.md4,627字・32行・markdown
# gamepad_teleop.py 長押しと範囲変更のレビュー(2026-11-03)

**確かめた範囲:** 依頼文・`gamepad_teleop.py` 全体・`test_gamepad_teleop.py` を読みました。ここには pygame と、定数を読む元のファイル(`run_policy_client.py`・`waypoint_replay.py`)がないので、64 件のテストは流せていません。代わりに、`gamepad_teleop.py` をスクラッチに写し、定数と pygame を仮のものに差し替えて、下の A・B・C の道を実際に起こして確かめました。元のファイルは何も変えていません。

## 必須

| 項目 | 判定 | 確認結果・修正案 |
|---|---|---|
別のタブで開く保存

直すべき点は1つでした。動いている間に押した十字キーは受付なしと出るのに、押し続けるとあとから長押しとして動き出していました。HOME の長押しには、押し始めに受け付けられなければ押し続けても送らない、という決まりがあり、それと食い違っています。押し始めに受け付けられなかった押しは長押しにしない形に直しました。

推奨5つのうち、離したあとに1刻み出る道(B)、先へ出る量の説明(C)、離した合図の取りこぼし(D)、当たったときの表示(F)を直しました。机に当たる道(E)は、範囲を広げたのが決めたことなので、止めは足していません。

docs/review_result_20261103_gamepad_hold.md

# レビュー結果:gamepad_teleop.py の範囲を物理可動域にし、十字キーの長押しで動き続けるようにした(2026-11-03)

依頼文: docs/review_request_20261103_gamepad_hold.md。レビューは、実装した Claude とは別の Claude のエージェント(読み取りのみ。codex は Mac の外から呼べなかったので使っていない)。

| 指摘 | 分類 | 対応 |
|---|---|---|
| A. 動いている間・停止中に押した十字キーが、受付なしと出たあと押し続けると長押しとして動き出す | 必須 | 直した。押し始めに受け付けられなければ長押しにしない(HOME の長押しと同じ)。テスト 2 件 |
| B. 離したあとに 1 刻み送られることがある | 推奨 | 直した。離したとき、長押しの 2 回目からの刻みをまだ送ると決めていなければ SendGate で取り消す。1 回目(短い押し)は取り消さない。テスト 2 件 |
| C. 先へ出る量は 3° ではなく 3° + 1 刻み | 推奨 | 説明と定数の注記を直した |
| D. 離した合図を取りこぼすと物理可動域の端まで動き続ける | 推奨 | 直した。長押しの最中は毎コマ js.get_button を見て、押されていなければ離したことにする。読めなければ停止。テスト 1 件 |
| E. 物理可動域まで広げたので、j2・j4 を下げる向きで机に当たる道がある | 推奨 | 据え置き。範囲はエイイチの決定。初回は R1 なし(0.5°)の短い長押しで試す |
| F. 当たって追いつかないとき最後の指令が残る | 推奨 | 表示に「逆向きを1回押すか HOME で戻してください」を足した |
| 送れたときにも hold_lead_deg を残す | 小さな改善 | 足した |

テスト: 69 件すべて通過(前からの 53 件・長押し 11 件・レビュー対応 5 件)。実機ではまだ流していない。
  • ねらい:離した合図を取りこぼしても、長押しが範囲の端まで走り続けないようにする
  • 変わったこと:長押しの間は、毎コマ(60回/秒)コントローラーのボタンの状態も見て、押されていなければ離したことにする。読めなければ停止
  • 見込める効果:Bluetooth の乱れで離した合図が届かなくても止まる見込み。実機で合図を取りこぼした場面は、この回の記録にはまだない

テストは69件すべて通り、Mac で36def3cとしてコミットしました。

7:49:長押しが動かない。0.5°では関節が動かず、1回の送信に約1.6秒かかっていた

04_sec06.txt12,777字・82行・text
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
git add tools/gamepad_teleop.py tools/test_gamepad_teleop.py docs/review_request_20261103_gamepad_hold.md docs/review_result_20261103_gamepad_hold.md
git commit -m "gamepad_teleop: 範囲を物理可動域に (j1 90.87・J4_SAFE は残す), 十字キーの長押しで送り続ける (0.4 秒から 0.2 秒おき・指令と読んだ角度の差 3° 超は 待つ・3 秒追いつかなければ止める・離したら未送信の刻みを取り消す・毎コマ ボタン の状態も見る). テスト 69 件

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LevEXRnwfWWxYdvM8WRMgs"
python3 tools/gamepad_teleop.py --execute
[main 36def3c] gamepad_teleop: 範囲を物理可動域に (j1 90.87・J4_SAFE は残す), 十字キーの長押しで送り続ける (0.4 秒から 0.2 秒おき・指令と読んだ角度の差 3° 超は待つ・3 秒追いつかなければ止める・離したら未送信の刻みを取り消す・毎コマ ボタンの状態も見る). テスト 69 件
別のタブで開く保存

ちゃんと動いてなくない?

記録を見ると、2つのことが重なっていました。

1つ目は、0.5°の押しではサーボが反応しないことです。0.5°の送信のうち、読んだ角度が0.2°以上動いたのは、7:14 の記録で7回中3回、7:49 の記録で18回中8回でした。2°の送信は毎回動いています。始めの1押しを左右に交互に押すと、指令だけが行ったり来たりして、アームは止まったままでした。

2つ目は、1回の仕事に約1.6秒かかっていたことです。長押しの2回目以降を送った間隔は、中央1.630秒でした。送る前の読み取りは約0.04秒、送ったあと届いたかの確かめは0.02秒前後で、残りは daemon_send_angles の返事を待つ時間です。長押しの速さは毎秒1.0°でした。

ゲームパッドの1押しは、次のように決めました。

決めたこと選んだもの
ふつうの1押し
1°(R1 を押しながらは2°のまま)。7:14 の記録で、1°の差は動いていた
1.6秒の遅さ
daemon の遅さを調べて直す

7:53:daemon の pymycobot 4.0.4 が、送るたびに返事を0.5秒×3回待っていた

daemon(mecharm_daemon.py)は、send_angles の前後の時間を daemon.log に書いています。daemon は from pymycobot.mycobot import MyCobot で読み込み、_mc.send_angles(angles, speed) を呼ぶだけです。daemon のコードは変えていないので、変わったのはライブラリの側だと考え、pymycobot の 4.0.4 と 2.9.6 の中身を PyPI から取ってきて比べました。

pymycobot 4.0.4 と 2.9.6 の該当箇所(PyPI の配布物から)

05_sec07.py.txt4,786字・133行・python
=== pymycobot 4.0.4 generate.py (send_angles)
    def send_angles(self, angles, speed, _async=False):
        """Send the angles of all joints to robot arm.

        Args:
            angles: a list of angle values(List[float]). len 6.
            speed : (int) 1 ~ 100
        """
別のタブで開く保存

4.0.4 は send_angles を has_reply=True(返事を受け取る)で送ります。古い MyCobot のクラスは、返事が来るまで、指令を書いて0.5秒待つことを3回まで繰り返し、来なければ −1 を返します。mechArm 270-Pi のファームウェア(get_system_version は11)は、この命令に返事を返さないので、毎回 0.5秒×3回 = 1.5秒待ち、同じ指令を3回書いていました。爪の命令も同じで、ずっと出ていた result= -1 はこれでした。2.9.6 は返事を待たずに、書いたらすぐ返ります。

10月30日の夜(依頼36。コミットは10月31日の 3fa44b5)に、daemon を systemd で自動で起動する形にしました。起動スクリプト mecharm_daemon_start.sh は /usr/bin/python3 を何も付けずに起動するので、~/.bashrc の PYTHONPATH が入らず、4.0.4 が読まれます。それより前は、対話のシェルで手で起動していて 2.9.6 でした。10月31日(LOG417)と11月1日(LOG422)の実機の推論も、この daemon を通っていました。11月1日の推論の作業の記録(依頼57)にも 送ってから rpc が返るまで(約 1.6 秒。daemon が着いたと判定するまで) とあり、推論も同じ待ちを通っていたことになります。

起動スクリプトで 2.9.6 を読むように、export PYTHONPATH=/usr/local/lib/python2.7/dist-packages を足し、起動の行に読んだ pymycobot の版を書くようにしました。

tools/pi/mecharm_daemon_start.sh(直したあとの全文)

#!/bin/bash
# mecharm_daemon_start.sh (Pi 側, systemd mecharm-daemon.service から呼ぶ)
# - シリアルの準備を待ってから mecharm_daemon.py を起動する
# - すでに 5555 を受け付けている / デーモンのプロセスがいるときは起動しない (二重起動防止)
# - ログは今までどおり /home/ubuntu/daemon.log に足していく
# このファイルのコマンド行は「mecharm_daemon_start.sh」なので
# 下の pgrep -f '[m]echarm_daemon\.py' は自分に当たらない。

LOG=/home/ubuntu/daemon.log
DAEMON=/home/ubuntu/mecharm_daemon.py
SERIAL=/dev/ttyAMA0
BOOT_WAIT_SEC=5

stamp() { echo "[START $(date '+%H:%M:%S')] $*" >> "$LOG"; }

# シリアルの準備を待つ (最大 30 秒, その後さらに BOOT_WAIT_SEC 秒)
for i in $(seq 1 30); do
    [ -e "$SERIAL" ] && break
    sleep 1
done
sleep "$BOOT_WAIT_SEC"

if ss -ltn | grep -q ':5555 '; then
    stamp "5555 はすでに LISTEN 中。起動しない"
    exit 0
fi
if pgrep -f '[m]echarm_daemon\.py' > /dev/null; then
    stamp "mecharm_daemon.py のプロセスがすでにいる。起動しない"
    exit 0
fi

# pymycobot は対話シェル (~/.bashrc) と同じ 2.9.6 を読む (2026-11-03).
# 何も付けずに起動すると 4.0.4 を読み, send_angles・爪のたびに返事を 0.5 秒 × 3 回待って
# 同じ指令を 3 回書き, -1 を返す (1 回の送信が約 1.6 秒. 10-31 に systemd で起動するようにしてから)
export PYTHONPATH=/usr/local/lib/python2.7/dist-packages
stamp "mecharm_daemon.py を起動する ($(/usr/bin/python3 -c 'import pymycobot; print("pymycobot", pymycobot.__version__, pymycobot.__file__)' 2>&1))"
cd /home/ubuntu
exec /usr/bin/python3 -u "$DAEMON" >> "$LOG" 2>&1

ゲームパッドの1押しは 0.5° から 1° にしました(テストは0.5°の刻みで書いてあるので、テストの中だけ0.5°にし、実際の値が1°であることを別のテストで確かめる形にした)。

Pi のログで裏付けを取ってから、起動スクリプトを入れ替えて daemon を起動し直しました。

daemon.log の確かめと、起動スクリプトの入れ替え・daemon の起動し直し(300〜350行目)

06_sec07.txt8,824字・51行・text
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
ssh -i ~/.ssh/id_rsa_pi ubuntu@192.168.2.1 'grep "send_angles 呼び出し後" /home/ubuntu/daemon.log | tail -5'
tools/daemon_ctl.sh install
tools/daemon_ctl.sh restart
tools/daemon_ctl.sh log 5
python3 tools/gamepad_teleop.py --execute
[DAEMON 15:55:21] send_angles 呼び出し後: result=-1, elapsed_ms=1552.6
[DAEMON 15:55:27] send_angles 呼び出し後: result=-1, elapsed_ms=1564.2
別のタブで開く保存

直す前の送信はどれも result=-1, elapsed_ms=1500 前後でした。起動し直した daemon の行には pymycobot 2.9.6 と出ています(Pi の時計は日本の時刻からずれていて、15:28 と出ている)。

  • ねらい:アームに送る1回の指令を、返事を待たない 2.9.6 の形に戻す
  • 変わったこと:daemon の send_angles が約1.5秒から、すぐ返るようになった。ゲームパッドで押してから送り終わるまでの時間は、中央0.042秒から0.024秒、長押しの送る間隔は中央1.630秒から0.216秒(同じ刻みの形の長押しで比べた)
  • 見込める効果:daemon を使う推論・お手本の再生・点検も、1回の送信の待ちが短くなる見込み。推論での効き方は次の実機の推論で測る

7:57:2.9.6 に戻すと長押しが続いたが、無視された指令で8秒止まった

7:57 からの記録(teleop_20261103_075657)では、長押しの送る間隔は中央0.216秒、長押しの速さは中央毎秒5.9°になりました。

途中で3回、8秒止まりました。3回とも、指令は送れているのに、どの関節も送る前の角度のままでした。指令がアームにまるごと無視されています。ゲームパッドは送り直さない作りだったので、届くまでの待ちの上限の8秒、次の押しが受付なしになっていました。

時刻(記録の始めから)関節指令送る前8秒後
48.94秒j2+6.02+9.58+9.49
81.09秒j4−4.43−0.43−0.43
94.32秒j5−21.88−26.19−26.10

LOG422 にも [RETRY] 1回目送信が無視された(pre→last max|Δ| 0.00°) と出ていて、お手本の再生のスクリプト(waypoint_replay.py)のコメントにも 単発は無視されるが、0.1s 周期で打てば通る とあります。4.0.4 が同じ指令を3回書いていたことで、無視が目立たなかった面もあるかもしれません。ゲームパッドにも送り直しを入れました。送ってから0.5秒たっても届いておらず、どの関節も0.3°動いていなければ、同じ目標を送り直します(3回まで)。送り直しも停止の鍵(SendGate)の中で送るので、L2+R2 のあとや長押しを離したあとは送りません。

7:57 からのターミナルの出力と、2.9.6 の起動・1°の刻みのコミット(351〜760行目)

07_sec08.txt47,550字・410行・text
[記録] /Volumes/KIOXIA/r2r2r-data/runs/experiments/gamepad_teleop/teleop_20261103_075657
[実機] daemon に送ります。起動したときの姿勢: -0.26 +1.31 +2.02 +0.08 -0.08 -29.88
コントローラーを待っています(つないでいなければ、今つないでください)
[接続] PS4 Controller  GUID=03008fe54c050000cc09000000016800  軸=6  ボタン=16
[送信] j0 -1.0° → -1.26 +1.31 +2.02 +0.08 -0.08 -29.88  届いた(ずれ 1.0°)  届いた角度 -0.26 +1.31 +2.02 +0.08 -0.08 -29.88
[送信] j0 -1.0°(長押し 1) → -2.26 +1.31 +2.02 +0.08 -0.08 -29.88  届いた(ずれ 1.21°)  届いた角度 -1.05 +2.19 +2.81 +0.08 -0.08 -29.88
[送信] j0 -1.0°(長押し 2) → -3.26 +1.31 +2.02 +0.08 -0.08 -29.88  届いた(ずれ 0.88°)  届いた角度 -2.54 +2.19 +2.81 +0.08 -0.08 -29.88
[送信] j0 -1.0°(長押し 3) → -4.26 +1.31 +2.02 +0.08 -0.08 -29.88  届いた(ずれ 0.88°)  届いた角度 -3.95 +2.19 +2.81 +0.08 -0.08 -29.88
別のタブで開く保存

動きがぎこちないけどよく動くようにはなった

8:03:長押しは、読んだ角度から3°先を0.1秒おきに送る形にした

ぎこちない理由は、1刻み(1〜2°)ごとにアームが目標に着いて止まり、次の指令(0.2〜0.4秒後)でまた動き出していたことです。記録では、送る前の読んだ角度と直前の指令の差は、毎回1°前後まで詰まっていました。

長押しの間だけ、読んだ角度から3°先を0.1秒おきに送り直す形を提案し、speed 20 のまま止めずに動かすと決めました。

長押しの作り前(刻み)後(3°先)
送る目標直前の指令 + 1刻み
動かす関節は、いま読んだ角度 + 3°。ほかの関節は直前の指令のまま
送る間隔
0.2秒(差が3°を超えたら待つ)
0.1秒。届くのを待たない
目標が戻るとき―
前の目標より後ろへは戻さない(読んだ角度が古いと引き戻すため)
止まる条件3秒追いつかない
1秒進まない(当たっているなど)
ターミナル1刻みごとに1行
離したときに [長押し] j0 を ○° → ○° まで の1行
R1長押しの刻みも2°になる
短い押しの刻み(2°)にだけ効く。長押しの速さは speed で決まる

ほかの関節を直前の指令のまま送るのは、読んだ角度で送り直すと、j1 が重さで沈んだ分(記録では1°前後)を毎回なぞって、ずり下がっていくからです。テストは73件すべて通り、15ca6a4・413f7e1 としてコミットしました。

3°先の形で動かしたターミナルの出力(761〜822行目)

08_sec09.txt10,669字・62行・text
 3 files changed, 278 insertions(+), 154 deletions(-)
/opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/pkgdata.py:25: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
  from pkg_resources import resource_stream, resource_exists
objc[8239]: Class SDLApplication is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x106f152c8) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x12106c890). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[8239]: Class SDLAppDelegate is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x106f15318) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x12106c8e0). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[8239]: Class SDLTranslatorResponder is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x106f15390) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x12106c958). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[8239]: Class SDLMessageBoxPresenter is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x106f153b8) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x12106c980). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
objc[8239]: Class SDL_cocoametalview is implemented in both /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/pygame/.dylibs/libSDL2-2.0.0.dylib (0x106f15408) and /opt/homebrew/Caskroom/miniforge/base/lib/python3.12/site-packages/cv2/.dylibs/libSDL2-2.0.0.dylib (0x12106c9d0). This may cause spurious casting failures and mysterious crashes. One of the duplicates must be removed or renamed.
別のタブで開く保存

目標を戻さない形をコミットしたあとのターミナルの出力(823〜917行目)

09_sec09.txt13,051字・95行・text
(base) shimazueiichi@shimadzueiichinoMacBook-Pro r2r2r-scripts % cd ~/r2r2r-scripts
git add tools/gamepad_teleop.py tools/test_gamepad_teleop.py tools/pi/mecharm_daemon_start.sh
git commit -m "gamepad_teleop: 長押しは 0.1 秒おきに読んだ角度 + 3° 先を送り, 届くのを待たずに止めずに動かす (ほかの関節は指令のまま・目標は戻さない・1 秒進まなければ止める). 無視された指令は送り直す. 1 押し 1°. daemon を pymycobot 2.9.6 で起動. テスト 73 件

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LevEXRnwfWWxYdvM8WRMgs"
python3 tools/gamepad_teleop.py --execute
[main 413f7e1] gamepad_teleop: 長押しは 0.1 秒おきに読んだ角度 + 3° 先を送り, 届くのを待たずに止めずに動かす (ほかの関節は指令のまま・目標は戻さない・1 秒進まなければ止める). 無視された指令は送り直す. 1 押し 1°. daemon を pymycobot 2.9.6 で起動. テスト 73 件
別のタブで開く保存
  • ねらい:長押しの間、アームを目標に着かせずに動かし続け、刻みごとに止まらないようにする
  • 変わったこと:長押しの送る間隔は中央0.216秒から0.119〜0.126秒、長押しの速さは中央毎秒5.9°から8.3°・7.7°(記録2本)
  • 見込める効果:ブロックの上まで運ぶ時間が縮む見込み。止まらずに動くかは、下の通りまだ足りない

8:13:3°先の形でも、なめらかにはならなかった

動きの滑らかさはないね。R1押しても押さなくても動く角度変わらなくない?

R1 はその通りで、長押しの速さは R1 があってもなくても同じにしていました。R1 が効くのは短い押しの刻み(1°と2°)だけで、0.4秒以上押すと長押しに切り替わるので、R1 の差はほとんど感じられません。

なめらかにならない理由は、記録から2つ見えています。

  1. speed 20 のアームは、3°先の目標に0.15秒ほどで着いて止まる。0.1秒おきに送っても、ときどき1回の仕事が0.4秒かかり(長押しの送る間隔の90%の値は0.406〜0.417秒)、そのたびに止まる
  2. 角度の読み取りが続けて失敗し、13秒止まった場面があった。8.57秒に押した右が、送れたのは21.45秒。ターミナルにも daemon_get_angles failed: daemon error: get_angles returned empty/invalid after 12 retries が3回出ている。指令を細かく送り続けると、アームからの返事が混ざって読み取りに失敗しやすくなると見ている(確かめてはいない)

5本の記録から数えた、送る間隔と長押しの速さ

10_sec10.py.txt4,695字・108行・python
#!/usr/bin/env python3
"""analyze_gamepad_runs.py — 2026-11-03 のゲームパッドの実機の記録 (log.jsonl) 5 本を読み, 送る間隔・長押しの速さ・止まった所を数える (LOG436)

  python3 analyze_gamepad_runs.py <gamepad_teleop のフォルダ>
"""
import json
import os
import statistics as st
別のタブで開く保存

analyze_gamepad_runs.py の出力

## 1. 記録ごとのまとめ
| 記録 | コミット | 1押しの刻み | 行 | 送った | 受付なし(busy) | 長押しの送る間隔 中央/90% (秒) | 届くまで1秒超 | 押してから送るまで 中央/最大 (秒) |
|---|---|---|---|---|---|---|---|---|
| teleop_20261103_071424 | f061d54  | 0.5° | 121 | 46 | 13 | - | 0 | 0.040 / 0.31 |
| teleop_20261103_074936 | 36def3c  | 0.5° | 50 | 32 | 5 | 1.630 / 1.658 | 0 | 0.042 / 0.08 |
| teleop_20261103_075657 | 36def3c (変更あり) | 1.0° | 437 | 370 | 10 | 0.216 / 0.443 | 5 | 0.042 / 0.08 |
| teleop_20261103_080648 | 15ca6a4  | 1.0° | 228 | 209 | 0 | 0.126 / 0.406 | 0 | 0.024 / 0.44 |
| teleop_20261103_080930 | 413f7e1  | 1.0° | 307 | 274 | 8 | 0.119 / 0.417 | 0 | 0.024 / 12.89 |

## 2. 長押し (5 回以上送ったもの) の速さ = 動かした関節の進んだ角度 ÷ かかった時間
- teleop_20261103_074936: 長押し 2 回・中央 1.0°/秒・最小 0.7・最大 1.3
- teleop_20261103_075657: 長押し 23 回・中央 5.9°/秒・最小 2.6・最大 9.4
- teleop_20261103_080648: 長押し 13 回・中央 8.3°/秒・最小 4.7・最大 12.6
- teleop_20261103_080930: 長押し 14 回・中央 7.7°/秒・最小 3.8・最大 10.3

## 3. 届くまで 1 秒を超えた送信 (指令が無視されたもの)
- teleop_20261103_075657   48.94秒 j2 -2.0° 長押し 8/3 届くまで 8.08 秒 ずれ 3.47°
    送る前     +7.82  +15.29   +9.58   +0.17   -0.96  -29.88
    指令       +7.74  +14.31   +6.02   +0.08   -0.08  -29.88
    届いた     +7.82  +15.29   +9.49   +0.17   -0.52  -29.88
- teleop_20261103_075657   81.09秒 j4 -2.0° 長押し 19/1 届くまで 8.09 秒 ずれ 4.0°
    送る前     -6.41  +16.08  +10.19   -1.23   -0.43  -29.88
    指令       -6.18  +15.29   +9.49   -0.83   -4.43  -29.88
    届いた     -6.41  +16.08  +10.19   -1.05   -0.43  -29.88
- teleop_20261103_075657   94.32秒 j5 +2.0° 長押し 23/3 届くまで 8.12 秒 ずれ 4.22°
    送る前     +1.49  +16.96  +10.89   -0.87   -0.43  -26.19
    指令       +1.59  +16.08  +10.19   -1.05   -0.43  -21.88
    届いた     +1.49  +16.96  +10.89   -0.87   -0.43  -26.10
- teleop_20261103_075657  286.46秒 j4 +2.0° 長押し 36/2 届くまで 1.66 秒 ずれ 2.9°
    送る前     +7.47  +17.84  +11.51   -0.96  -35.77  -25.75
    指令       +7.49  +16.96  +10.89   -0.87  -32.43  -26.10
    届いた     +7.47  +17.84  +11.51   -0.96  -35.33  -25.75
- teleop_20261103_075657  343.03秒 j5 -2.0° 長押し 53/1 届くまで 1.36 秒 ずれ 2.95°
    送る前    +12.39  +20.03  +11.60   +0.43  -16.96  -26.89
    指令      +12.49  +18.96  +10.89   +0.13  -16.43  -30.10
    届いた    +12.39  +20.03  +11.60   +0.43  -16.87  -27.15

## 4. 押してから送るまで 1 秒を超えたもの (角度の読み取りが続けて失敗した)
- teleop_20261103_080930    8.57秒に押した j0 → 送ったのは 21.45秒 (12.89 秒あと)

## 5. 0.5° の押しで, 送る前と届いた角度が変わったか (1 押し 0.5° の 2 本)
- teleop_20261103_071424: 0.5° の送信 7 回のうち, 読んだ角度が 0.2° 以上動いたのは 3 回
- teleop_20261103_074936: 0.5° の送信 18 回のうち, 読んだ角度が 0.2° 以上動いたのは 8 回
記録
daemon の pymycobot
長押しの形長押しの送る間隔(中央)長押しの速さ(中央)
7:49(074936)4.0.4刻み(0.5°・2°)1.630秒毎秒1.0°
7:57(075657)2.9.6刻み(1°・2°)0.216秒毎秒5.9°
8:06(080648)2.9.63°先を0.1秒おき0.126秒毎秒8.3°
8:09(080930)2.9.6
3°先を0.1秒おき(目標を戻さない)
0.119秒毎秒7.7°

8:20:今の長押しをタグで残し、jog と fresh_mode を測る試しを用意した

指令を何度も送り直すやり方では、mechArm でなめらかに動かすのは難しいと見ています。アームには jog という、押している間だけ一定の速さで動き続ける命令があり、Pi の pymycobot 2.9.6 にも jog_angle と jog_stop が入っています。jog に変えるなら、押したら動かし始め、離したら止め、R1 で jog の速さを変え、L2+R2 で本当に動きを止められます。ただし daemon に jog と停止の命令と、通信が切れたら止める見張りを足す必要があり、mechArm のファームウェアが jog に応えるかもまだ分かりません。

今の仕様を暫定で保管(今の動きでも大方の問題は解決はできている)しつつ、jogの修正も進めてください。 どこまでmecharmの動きを改善できるのか限界もまた知りたいです。

今の長押しは commit 413f7e1 にあり、gamepad-stream-v1 のタグで残します。jog 版は別に作り、今の gamepad_teleop.py はそのまま使えるようにします。

前のシリーズ(mechArm 270 Pi 動的追従の限界を探る Log#1〜#2、LOG182・LOG183)では、fresh_mode を有効にすると Pi 上で毎秒91回まで指令を送れることと、アームの物理応答は振幅10°で約0.5秒かかることを測っています。その続きとして、同じ根元 j0 で4つの動かし方を並べて測る試し jog_probe を作りました。daemon を一時止めて Pi で直接 pymycobot を使う形で、手首の点検(servo_check.sh)と同じ流れです。

テスト動かし方見るもの
0
読むだけ(get_angles を40回)
1回の読み取りの時間と、空で返る割合
A
1回だけ send_angles(+10°、speed 20)
着くまでの時間と最高速度(アームそのものの速さ)
B
0.1秒おきに、読んだ角度 + 3° を send_angles(1秒)
今の長押しのなめらかさ
C
B と同じに fresh_mode(1) を足す
上書きでなめらかになるか
D
jog_angle を speed 10 と 30 で1秒ずつ → jog_stop
jog に応えるか・速さ・止める命令のあとの行きすぎ

どのテストも、始めの角度から25°離れたら止め、終わるたびに始めの角度へ戻します。0.1秒ごとの速さを並べて出すので、数字がそろっていればなめらか、0が混ざっていれば止まりながら動いている、と読めます。

tools/jog_probe.sh

11_tools_jog_probe.sh.txt5,614字・157行・bash
#!/bin/bash
# jog_probe.sh — Mac から, Pi の mechArm で根元 j0 を 4 つの動かし方で動かし, なめらかさと限界を測る (2026-11-03)
#
#   tools/jog_probe.sh     A 1 回の send_angles / B 送り直し (今の長押し) / C 送り直し + fresh_mode / D jog (speed 10・30)
#                          テストごとに Enter で進む。q と Enter で止める
#
# 流れ (tools/servo_check.sh と同じ):
#   0. KIOXIA のマウントを確かめ, diag/jog_probe_{日時}/ を作る
別のタブで開く保存

tools/pi/jog_probe_pi.py

12_tools_pi_jog_probe_pi.py.txt10,591字・300行・python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""jog_probe_pi.py — 根元 j0 で 4 つの動かし方を測り, mechArm がどこまでなめらかに動くかを見る (2026-11-03)

Mac の tools/jog_probe.sh から呼ぶ (デーモンを止めてから, シリアルに直接つなぐ)。
Pi の python3 は 3.6, pymycobot 2.9.6 (PYTHONPATH=/usr/local/lib/python2.7/dist-packages)。

測るもの (どれも j0 だけを動かす. 始める前に HOME 近くにいること. 各テストのあと始めの角度へ戻す):
別のタブで開く保存

実機の代わりに、0.1秒で目標へ寄る偽の MyCobot(毎秒25°で動き、jog は speed の0.6倍の速さ)で一通り流し、テストの流れと数え方が動くことを確かめました。偽物の数字なので、mechArm の値ではありません。

偽の pymycobot.mycobot(確かめ用)

import time
class MyCobot:
    def __init__(s,*a):
        s.q=[0.3,0,0,0,0,-30.0]; s.t=time.time(); s.tgt=None; s.v=0; s.calls=[]
    def _upd(s):
        t=time.time(); dt=t-s.t; s.t=t
        if s.v: s.q[0]+=s.v*dt
        elif s.tgt is not None:
            d=s.tgt-s.q[0]; step=25*dt
            s.q[0]+= max(-step,min(step,d))
    def get_angles(s):
        time.sleep(0.01); s._upd(); return list(s.q)
    def send_angles(s,a,sp): s._upd(); s.tgt=a[0]; s.v=0; s.calls.append(("send",a[0]))
    def jog_angle(s,j,d,sp): s._upd(); s.v=(sp*0.6)*(1 if d==1 else -1); s.calls.append(("jog",j,d,sp))
    def jog_stop(s): s._upd(); s.v=0; s.tgt=s.q[0]
    def set_fresh_mode(s,v): pass

偽の MyCobot で jog_probe_pi.py を流した出力

pymycobot fake (/sessions/rcw-01levexrnwfwwxydvm8wrmgs/work/fakepmc/pymycobot/__init__.py)
始めの角度: [0.3, 0.0, 0.0, 0.0, 0.0, -30.0]
根元 j0 だけを、始めの角度から 25° 以内で動かします。毎回始めの角度へ戻します。

0. 読み取りの速さ (動かさない)
  読み取り 1 回: 中央 12.4 ms / 最大 15.4 ms / 空で返った割合 0.0

A_step_10deg を始めます  (Enter で進む / q と Enter で終わる)
  [A_step_10deg] travel_deg=9.7  mean_speed=4.87  median_speed=0.0  max_speed=29.42  speed_cv=None  stall_ratio=None  arrive_sec=0.36
        0.1 秒ごとの速さ (°/秒): 25.0 29.4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
  始めの角度へ戻した: 着いた j0=1.1

B_stream を始めます  (Enter で進む / q と Enter で終わる)
  守り: j0 が始めから 25.2° 離れたので止めます
  [B_stream] travel_deg=24.93  mean_speed=24.99  median_speed=24.99  max_speed=25.01  speed_cv=0.0  stall_ratio=0.0  overshoot_deg=0.31  stop_latency_sec=0.0  n_sends=10
        0.1 秒ごとの速さ (°/秒): 25.0 25.0 25.0 24.9 25.0 25.0 25.0
  始めの角度へ戻した: 着いた j0=2.18

C_stream_fresh を始めます  (Enter で進む / q と Enter で終わる)
  守り: j0 が始めから -25.3° 離れたので止めます
  [C_stream_fresh] travel_deg=24.65  mean_speed=24.99  median_speed=25.0  max_speed=25.03  speed_cv=0.0  stall_ratio=0.0  overshoot_deg=0.61  stop_latency_sec=0.01  n_sends=10
        0.1 秒ごとの速さ (°/秒): 25.0 25.0 25.0 25.0 25.0 25.0 25.0
  始めの角度へ戻した: 着いた j0=0.3

D_jog_speed10 を始めます  (Enter で進む / q と Enter で終わる)
  [D_jog_speed10] travel_deg=5.97  mean_speed=6.0  median_speed=6.0  max_speed=6.0  speed_cv=0.0  stall_ratio=0.0  overshoot_deg=0.01  stop_latency_sec=0.0  jog_moved=True
        0.1 秒ごとの速さ (°/秒): 6.0 6.0 6.0 6.0 6.0 6.0 6.0
  始めの角度へ戻した: 着いた j0=0.3

D_jog_speed30 を始めます  (Enter で進む / q と Enter で終わる)
  [D_jog_speed30] travel_deg=17.77  mean_speed=18.0  median_speed=18.0  max_speed=18.05  speed_cv=0.01  stall_ratio=0.0  overshoot_deg=0.05  stop_latency_sec=0.0  jog_moved=True
        0.1 秒ごとの速さ (°/秒): 17.7 18.0 18.0 18.0 18.0 18.0 18.0
  始めの角度へ戻した: 着いた j0=-0.45
結果: /tmp/jp.json

実機の jog_probe は、アームを止めたので次の回で流します。

次に実機で確かめること

順番確かめること見る数字
1
git tag gamepad-stream-v1 413f7e1 で今の長押しを残し、tools/jog_probe.sh を流す
テストごとの0.1秒ごとの速さ・止まった区間の割合・jog の行きすぎ
2
jog に応えれば、jog 版のゲームパッドを作る(daemon に jog と停止と見張り)
長押しの速さのばらつき・離してから止まるまでの角度
3
十字キーの右で根元がどちらに回るかを決める(今は右 = +)
―
4
AI(π0.5)の動きを、ゲームパッドで直す
1回の直しにかかる時間・2.9.6 に戻した daemon での推論の送る待ち
5
手首の点検のスクリプト(servo_check.sh)の2回目のレビューを通してコミットする
―

この回のコード(全文)

gamepad_teleop.py(commit 413f7e1)

13_gamepad_teleop.py.txt58,364字・1,316行・python
#!/usr/bin/env python3
"""gamepad_teleop.py — ゲームパッドで mechArm 270 を手で動かす (依頼 68. 2026-11-02)

PICK で爪の位置がずれたときに, エイイチがゲームパッドで左右・上げ下げ・爪の開閉を直す.
押した分だけそのまま動く. 自動で動く要素は入れない (自動の握り直し・失敗時の自動 HOME などはない).
押した操作と, 送った角度・届いた角度をすべて log.jsonl に残す (あとで「人が直した記録」として使う).

操作 (エイイチが決めた. 変えない):
別のタブで開く保存

test_gamepad_teleop.py(テスト73件・commit 413f7e1)

14_test_gamepad_teleop.py.txt54,393字・1,277行・python
#!/usr/bin/env python3
"""test_gamepad_teleop.py — gamepad_teleop.py の確かめ (アームなし・コントローラーなし. 依頼 68).

  python3 tools/test_gamepad_teleop.py -v

中身:
  - ボタン番号と操作の対応 (依頼 68 の表) / 十字キー上下の向き / △ で j1 → j5 → j1
  - 守り: j1 は 90.87 を超えない / 物理可動域まで (基準の姿勢からの枠はない. 2026-11-03) / J4_SAFE
別のタブで開く保存

test_gamepad_teleop.py の出力(73件)

15_eop.py_73_commit_413f7e1.txt6,311字・91行・text
test_presses_while_moving_are_dropped (test_gamepad_teleop.TestBusy) ... ok
test_dpad_left_right_always_j0 (test_gamepad_teleop.TestButtonMap) ... ok
test_gripper (test_gamepad_teleop.TestButtonMap) ... ok
test_numbers (test_gamepad_teleop.TestButtonMap) ... ok
test_r1_coarse_step (test_gamepad_teleop.TestButtonMap) ... ok
test_triangle_cycles (test_gamepad_teleop.TestButtonMap) ... ok
test_unassigned_do_nothing (test_gamepad_teleop.TestButtonMap) ... ok
test_up_minus_down_plus_starts_j1 (test_gamepad_teleop.TestButtonMap) ... ok
別のタブで開く保存

この回の実機の記録(全量)

7:14 の記録 runs/experiments/gamepad_teleop/teleop_20261103_071424/meta.json

{
  "run_stem": "teleop_20261103_071424",
  "started_at": "2026-11-03T07:14:26",
  "execute": true,
  "argv": [
    "tools/gamepad_teleop.py",
    "--execute"
  ],
  "controllers": [
    {
      "name": "PS4 Controller",
      "guid": "03008fe54c050000cc09000000016800",
      "instance_id": 0,
      "axes": 6,
      "buttons": 16,
      "hats": 0,
      "connected_at": "2026-11-03T07:14:31"
    }
  ],
  "python": "3.12.12 | packaged by conda-forge | (main, Oct 22 2025, 23:34:53) [Clang 19.1.7 ]",
  "pygame": "2.6.1",
  "sdl": "2.28.4",
  "platform": "macOS-26.6.2-arm64-arm-64bit",
  "start_pose": [
    23.29,
    109.77,
    -62.4,
    0.79,
    -49.3,
    -30.93
  ],
  "guards": {
    "J1_MAX_DEG": 90.87,
    "J0_RANGE_DEG": 15.0,
    "JOINT_RANGE_DEG": 10.0,
    "J4_SAFE": [
      -90.0,
      60.0
    ],
    "JOINT_LIMITS": [
      [
        -156.0,
        161.0
      ],
      [
        -79.0,
        123.0
      ],
      [
        -177.0,
        177.0
      ],
      [
        -156.0,
        162.0
      ],
      [
        -118.0,
        118.0
      ],
      [
        -177.0,
        178.0
      ]
    ],
    "window_at_start": {
      "lo": [
        8.29,
        99.77,
        -72.4,
        -9.21,
        -59.3,
        -40.93
      ],
      "hi": [
        38.29,
        90.87,
        -52.4,
        10.79,
        -39.3,
        -20.93
      ]
    },
    "home_bypasses_range_check": true
  },
  "motion": {
    "speed": 20,
    "step_fine_deg": 0.5,
    "step_coarse_deg": 2.0,
    "reach_tol_deg": 3.0,
    "reach_timeout_min_sec": 8.0,
    "poll_sec": 0.3,
    "gripper_sleep_sec": 0.8,
    "grip_close_value": 20,
    "send_wait": 0.0,
    "home": [
      0.0,
      0.0,
      0.0,
      0.0,
      0.0,
      -30.0
    ],
    "home_hold_sec": 1.0,
    "trigger_stop_above": 0.0,
    "j0_left_sign": -1.0,
    "up_sign": -1.0,
    "select_order": [
      1,
      2,
      3,
      4,
      5
    ]
  },
  "button_map": {
    "0": "cross",
    "1": "circle",
    "2": "square",
    "3": "triangle",
    "4": "share",
    "5": "home",
    "6": "options",
    "7": "l3",
    "8": "r3",
    "9": "l1",
    "10": "r1",
    "11": "dpad_up",
    "12": "dpad_down",
    "13": "dpad_left",
    "14": "dpad_right",
    "15": "touchpad"
  },
  "git": {
    "commit": "f061d54a87d17ff5dd027bf928addc0dee59f212",
    "script_status": "clean"
  },
  "script_copy": "gamepad_teleop.py",
  "script_sha256": "ad49623b481286a962e8d05da2525022fa5fb49d11bc75f4e62170db73f9e70d",
  "ended_at": "2026-11-03T07:49:31",
  "end_reason": "ctrl_c",
  "n_sent": 48
}

7:14 の記録 runs/experiments/gamepad_teleop/teleop_20261103_071424/log.jsonl(121行)

16_sec14.json70,626字・121行・json
{"seq": 1, "t": "2026-11-03T07:14:37.221", "t_unix": 1793657677.222, "button": 5, "button_name": "home", "kind": "home", "selected_joint": 1, "step_deg": 0.5, "execute": true, "held_sec": 1.007, "accepted": true, "measured_before": [23.29, 109.77, -62.4, 0.79, -49.3, -30.93], "command": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0], "range_check": "skipped_for_home", "sent": true, "timeout_sec": 18.47, "t_send": 1793657677.26519, "measured_before_send": [23.29, 109.77, -62.4, 0.79, -49.3, -30.93], "reached": true, "reached_angles": [-0.17, 1.4, 0.43, 0.35, 1.05, -30.58], "reach_err": 1.4, "elapsed_sec": 1.15, "grip_state": "unknown", "stopped": false, "stop_reason": null, "base_pose": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]}
{"seq": 2, "t": "2026-11-03T07:14:44.061", "t_unix": 1793657684.062, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 0, "delta": -0.5, "accepted": true, "measured_before": [0.0, 1.31, 0.87, 0.26, 1.23, -30.41], "start_source": "command", "cmd_gap_deg": 1.31, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-0.5, 0.0, 0.0, 0.0, 0.0, -30.0], "sent": true, "timeout_sec": 8.0, "t_send": 1793657684.113447, "measured_before_send": [0.0, 1.31, 0.87, 0.26, 1.23, -30.41], "reached": true, "reached_angles": [0.0, 1.31, 0.87, 0.26, 1.23, -30.32], "reach_err": 1.31, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null, "base_pose": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]}
{"seq": 3, "t": "2026-11-03T07:14:46.378", "t_unix": 1793657686.379, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 0, "delta": -0.5, "accepted": true, "measured_before": [0.0, 1.31, 0.87, 0.26, 1.23, -30.32], "start_source": "command", "cmd_gap_deg": 1.31, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-1.0, 0.0, 0.0, 0.0, 0.0, -30.0], "sent": true, "timeout_sec": 8.0, "t_send": 1793657686.4208698, "measured_before_send": [0.0, 1.31, 0.87, 0.26, 1.23, -30.32], "reached": true, "reached_angles": [-0.96, 1.31, 0.87, 0.26, 0.61, -30.23], "reach_err": 1.31, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null, "base_pose": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]}
{"seq": 4, "t": "2026-11-03T07:14:50.080", "t_unix": 1793657690.081, "button": 3, "button_name": "triangle", "kind": "select_joint", "selected_joint": 2, "step_deg": 0.5, "execute": true, "accepted": true, "grip_state": "unknown", "stopped": false, "stop_reason": null, "base_pose": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]}
{"seq": 5, "t": "2026-11-03T07:14:51.636", "t_unix": 1793657691.636, "button": 3, "button_name": "triangle", "kind": "select_joint", "selected_joint": 3, "step_deg": 0.5, "execute": true, "accepted": true, "grip_state": "unknown", "stopped": false, "stop_reason": null, "base_pose": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]}
{"seq": 6, "t": "2026-11-03T07:14:52.069", "t_unix": 1793657692.07, "button": 3, "button_name": "triangle", "kind": "select_joint", "selected_joint": 4, "step_deg": 0.5, "execute": true, "accepted": true, "grip_state": "unknown", "stopped": false, "stop_reason": null, "base_pose": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]}
{"seq": 7, "t": "2026-11-03T07:14:52.740", "t_unix": 1793657692.74, "button": 3, "button_name": "triangle", "kind": "select_joint", "selected_joint": 5, "step_deg": 0.5, "execute": true, "accepted": true, "grip_state": "unknown", "stopped": false, "stop_reason": null, "base_pose": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]}
{"seq": 8, "t": "2026-11-03T07:14:53.174", "t_unix": 1793657693.175, "button": 3, "button_name": "triangle", "kind": "select_joint", "selected_joint": 1, "step_deg": 0.5, "execute": true, "accepted": true, "grip_state": "unknown", "stopped": false, "stop_reason": null, "base_pose": [0.0, 0.0, 0.0, 0.0, 0.0, -30.0]}
別のタブで開く保存

7:49 の記録 runs/experiments/gamepad_teleop/teleop_20261103_074936/meta.json

{
  "run_stem": "teleop_20261103_074936",
  "started_at": "2026-11-03T07:49:37",
  "execute": true,
  "argv": [
    "tools/gamepad_teleop.py",
    "--execute"
  ],
  "controllers": [
    {
      "name": "PS4 Controller",
      "guid": "03008fe54c050000cc09000000016800",
      "instance_id": 0,
      "axes": 6,
      "buttons": 16,
      "hats": 0,
      "connected_at": "2026-11-03T07:50:02"
    }
  ],
  "python": "3.12.12 | packaged by conda-forge | (main, Oct 22 2025, 23:34:53) [Clang 19.1.7 ]",
  "pygame": "2.6.1",
  "sdl": "2.28.4",
  "platform": "macOS-26.6.2-arm64-arm-64bit",
  "start_pose": [
    -0.43,
    1.23,
    1.31,
    -0.26,
    -0.17,
    -29.7
  ],
  "guards": {
    "J1_MAX_DEG": 90.87,
    "range": "physical_limits (no base window. 2026-11-03)",
    "J4_SAFE": [
      -90.0,
      60.0
    ],
    "JOINT_LIMITS": [
      [
        -156.0,
        161.0
      ],
      [
        -79.0,
        123.0
      ],
      [
        -177.0,
        177.0
      ],
      [
        -156.0,
        162.0
      ],
      [
        -118.0,
        118.0
      ],
      [
        -177.0,
        178.0
      ]
    ],
    "window": {
      "lo": [
        -156.0,
        -79.0,
        -177.0,
        -156.0,
        -90.0,
        -177.0
      ],
      "hi": [
        161.0,
        90.87,
        177.0,
        162.0,
        60.0,
        178.0
      ]
    },
    "home_bypasses_range_check": true
  },
  "motion": {
    "speed": 20,
    "step_fine_deg": 0.5,
    "step_coarse_deg": 2.0,
    "reach_tol_deg": 3.0,
    "reach_timeout_min_sec": 8.0,
    "poll_sec": 0.3,
    "gripper_sleep_sec": 0.8,
    "grip_close_value": 20,
    "send_wait": 0.0,
    "home": [
      0.0,
      0.0,
      0.0,
      0.0,
      0.0,
      -30.0
    ],
    "home_hold_sec": 1.0,
    "trigger_stop_above": 0.0,
    "hold_start_sec": 0.4,
    "hold_interval_sec": 0.2,
    "hold_lead_max_deg": 3.0,
    "hold_wait_max_sec": 3.0,
    "j0_left_sign": -1.0,
    "up_sign": -1.0,
    "select_order": [
      1,
      2,
      3,
      4,
      5
    ]
  },
  "button_map": {
    "0": "cross",
    "1": "circle",
    "2": "square",
    "3": "triangle",
    "4": "share",
    "5": "home",
    "6": "options",
    "7": "l3",
    "8": "r3",
    "9": "l1",
    "10": "r1",
    "11": "dpad_up",
    "12": "dpad_down",
    "13": "dpad_left",
    "14": "dpad_right",
    "15": "touchpad"
  },
  "git": {
    "commit": "36def3cc1216f2bcaa937994a99968e38366009c",
    "script_status": "clean"
  },
  "script_copy": "gamepad_teleop.py",
  "script_sha256": "87c4c644aea9f43d8b891b95adf9bb603f62f47e9b59165a999f863f02e54918",
  "ended_at": "2026-11-03T07:56:27",
  "end_reason": "ctrl_c",
  "n_sent": 33
}

7:49 の記録 runs/experiments/gamepad_teleop/teleop_20261103_074936/log.jsonl(50行)

17_sec14.json32,442字・50行・json
{"seq": 1, "t": "2026-11-03T07:50:06.353", "t_unix": 1793659806.353, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 0, "delta": -0.5, "hold_id": 1, "hold_n": 0, "accepted": true, "measured_before": [-0.43, 1.23, 1.31, -0.26, -0.17, -29.7], "start_source": "command", "cmd_gap_deg": 0.0, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-0.93, 1.23, 1.31, -0.26, -0.17, -29.7], "sent": true, "timeout_sec": 8.0, "t_send": 1793659806.430069, "measured_before_send": [-0.43, 1.23, 1.31, -0.26, -0.17, -29.7], "reached": true, "reached_angles": [-0.43, 2.02, 2.02, -0.26, -0.17, -29.7], "reach_err": 0.79, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 2, "t": "2026-11-03T07:50:10.543", "t_unix": 1793659810.544, "button": 11, "button_name": "dpad_up", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 1, "delta": -0.5, "hold_id": 2, "hold_n": 0, "accepted": true, "measured_before": [-0.43, 2.02, 2.02, -0.17, -0.17, -29.7], "start_source": "command", "cmd_gap_deg": 0.79, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-0.93, 0.73, 1.31, -0.26, -0.17, -29.7], "sent": true, "timeout_sec": 8.0, "t_send": 1793659810.589694, "measured_before_send": [-0.43, 2.02, 2.02, -0.17, -0.17, -29.7], "reached": true, "reached_angles": [-0.43, 2.02, 2.02, -0.17, -0.17, -29.7], "reach_err": 1.29, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 4, "t": "2026-11-03T07:50:13.833", "t_unix": 1793659813.833, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 0, "delta": -0.5, "hold_id": 4, "hold_n": 0, "accepted": false, "reason": "busy", "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 3, "t": "2026-11-03T07:50:12.427", "t_unix": 1793659812.427, "button": 12, "button_name": "dpad_down", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 1, "delta": 0.5, "hold_id": 3, "hold_n": 0, "accepted": true, "measured_before": [-0.43, 2.02, 2.02, -0.17, -0.17, -29.7], "start_source": "command", "cmd_gap_deg": 1.29, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-0.93, 1.23, 1.31, -0.26, -0.17, -29.7], "sent": true, "timeout_sec": 8.0, "t_send": 1793659812.458703, "measured_before_send": [-0.43, 2.02, 2.02, -0.17, -0.17, -29.7], "reached": true, "reached_angles": [-0.43, 2.02, 2.02, -0.17, -0.17, -29.7], "reach_err": 0.79, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 5, "t": "2026-11-03T07:50:18.426", "t_unix": 1793659818.427, "button": 14, "button_name": "dpad_right", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 0, "delta": 0.5, "hold_id": 5, "hold_n": 0, "accepted": true, "measured_before": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "start_source": "command", "cmd_gap_deg": 0.79, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-0.43, 1.23, 1.31, -0.26, -0.17, -29.7], "sent": true, "timeout_sec": 8.0, "t_send": 1793659818.474234, "measured_before_send": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "reached": true, "reached_angles": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "reach_err": 0.79, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 6, "t": "2026-11-03T07:50:20.072", "t_unix": 1793659820.072, "button": 14, "button_name": "dpad_right", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 0, "delta": 0.5, "hold_id": 5, "hold_n": 1, "held_sec": 1.646, "accepted": true, "measured_before": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "hold_wait_sec": 0.0, "hold_lead_deg": 0.79, "start_source": "command", "cmd_gap_deg": 0.79, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [0.07, 1.23, 1.31, -0.26, -0.17, -29.7], "sent": true, "timeout_sec": 8.0, "t_send": 1793659820.1020741, "measured_before_send": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "reached": true, "reached_angles": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "reach_err": 0.79, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 7, "t": "2026-11-03T07:50:21.709", "t_unix": 1793659821.709, "button": 14, "button_name": "dpad_right", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 0, "delta": 0.5, "hold_id": 5, "hold_n": 2, "held_sec": 3.283, "accepted": true, "released_during_job": true, "measured_before": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "hold_wait_sec": 0.0, "hold_lead_deg": 0.79, "start_source": "command", "cmd_gap_deg": 0.79, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [0.57, 1.23, 1.31, -0.26, -0.17, -29.7], "sent": false, "why": "halted_before_send", "measured_before_send": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "reached": null, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 8, "t": "2026-11-03T07:50:22.232", "t_unix": 1793659822.232, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 0.5, "execute": true, "joint": 0, "delta": -0.5, "hold_id": 6, "hold_n": 0, "accepted": true, "measured_before": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "start_source": "command", "cmd_gap_deg": 0.79, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-0.43, 1.23, 1.31, -0.26, -0.17, -29.7], "sent": true, "timeout_sec": 8.0, "t_send": 1793659822.2657962, "measured_before_send": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "reached": true, "reached_angles": [-0.43, 2.02, 2.1, -0.17, -0.17, -29.7], "reach_err": 0.79, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
別のタブで開く保存

7:57 の記録 runs/experiments/gamepad_teleop/teleop_20261103_075657/meta.json

{
  "run_stem": "teleop_20261103_075657",
  "started_at": "2026-11-03T07:56:58",
  "execute": true,
  "argv": [
    "tools/gamepad_teleop.py",
    "--execute"
  ],
  "controllers": [
    {
      "name": "PS4 Controller",
      "guid": "03008fe54c050000cc09000000016800",
      "instance_id": 0,
      "axes": 6,
      "buttons": 16,
      "hats": 0,
      "connected_at": "2026-11-03T07:57:03"
    }
  ],
  "python": "3.12.12 | packaged by conda-forge | (main, Oct 22 2025, 23:34:53) [Clang 19.1.7 ]",
  "pygame": "2.6.1",
  "sdl": "2.28.4",
  "platform": "macOS-26.6.2-arm64-arm-64bit",
  "start_pose": [
    -0.26,
    1.31,
    2.02,
    0.08,
    -0.08,
    -29.88
  ],
  "guards": {
    "J1_MAX_DEG": 90.87,
    "range": "physical_limits (no base window. 2026-11-03)",
    "J4_SAFE": [
      -90.0,
      60.0
    ],
    "JOINT_LIMITS": [
      [
        -156.0,
        161.0
      ],
      [
        -79.0,
        123.0
      ],
      [
        -177.0,
        177.0
      ],
      [
        -156.0,
        162.0
      ],
      [
        -118.0,
        118.0
      ],
      [
        -177.0,
        178.0
      ]
    ],
    "window": {
      "lo": [
        -156.0,
        -79.0,
        -177.0,
        -156.0,
        -90.0,
        -177.0
      ],
      "hi": [
        161.0,
        90.87,
        177.0,
        162.0,
        60.0,
        178.0
      ]
    },
    "home_bypasses_range_check": true
  },
  "motion": {
    "speed": 20,
    "step_fine_deg": 1.0,
    "step_coarse_deg": 2.0,
    "reach_tol_deg": 3.0,
    "reach_timeout_min_sec": 8.0,
    "poll_sec": 0.3,
    "gripper_sleep_sec": 0.8,
    "grip_close_value": 20,
    "send_wait": 0.0,
    "home": [
      0.0,
      0.0,
      0.0,
      0.0,
      0.0,
      -30.0
    ],
    "home_hold_sec": 1.0,
    "trigger_stop_above": 0.0,
    "hold_start_sec": 0.4,
    "hold_interval_sec": 0.2,
    "hold_lead_max_deg": 3.0,
    "hold_wait_max_sec": 3.0,
    "j0_left_sign": -1.0,
    "up_sign": -1.0,
    "select_order": [
      1,
      2,
      3,
      4,
      5
    ]
  },
  "button_map": {
    "0": "cross",
    "1": "circle",
    "2": "square",
    "3": "triangle",
    "4": "share",
    "5": "home",
    "6": "options",
    "7": "l3",
    "8": "r3",
    "9": "l1",
    "10": "r1",
    "11": "dpad_up",
    "12": "dpad_down",
    "13": "dpad_left",
    "14": "dpad_right",
    "15": "touchpad"
  },
  "git": {
    "commit": "36def3cc1216f2bcaa937994a99968e38366009c",
    "script_status": "M tools/gamepad_teleop.py"
  },
  "script_copy": "gamepad_teleop.py",
  "script_sha256": "cfa6f4108c9658c7a7d770d36a9c15261a9f057a8307eabd832883bff1bb090c",
  "ended_at": "2026-11-03T08:06:44",
  "end_reason": "ctrl_c",
  "n_sent": 371
}

7:57 の記録 runs/experiments/gamepad_teleop/teleop_20261103_075657/log.jsonl(437行)

18_sec14.json338,321字・437行・json
{"seq": 1, "t": "2026-11-03T07:57:15.566", "t_unix": 1793660235.567, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 0, "accepted": true, "measured_before": [-0.26, 1.31, 2.02, 0.08, -0.08, -29.88], "start_source": "command", "cmd_gap_deg": 0.0, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-1.26, 1.31, 2.02, 0.08, -0.08, -29.88], "sent": true, "timeout_sec": 8.0, "t_send": 1793660235.644908, "measured_before_send": [-0.26, 1.31, 2.02, 0.08, -0.08, -29.88], "reached": true, "reached_angles": [-0.26, 1.31, 2.02, 0.08, -0.08, -29.88], "reach_err": 1.0, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 2, "t": "2026-11-03T07:57:15.977", "t_unix": 1793660235.977, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 1, "held_sec": 0.412, "accepted": true, "measured_before": [-1.05, 2.19, 2.81, 0.08, -0.08, -29.88], "hold_wait_sec": 0.0, "hold_lead_deg": 0.88, "start_source": "command", "cmd_gap_deg": 0.88, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-2.26, 1.31, 2.02, 0.08, -0.08, -29.88], "sent": true, "timeout_sec": 8.0, "t_send": 1793660236.023721, "measured_before_send": [-0.96, 2.19, 2.81, 0.08, -0.08, -29.88], "reached": true, "reached_angles": [-1.05, 2.19, 2.81, 0.08, -0.08, -29.88], "reach_err": 1.21, "elapsed_sec": 0.03, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 3, "t": "2026-11-03T07:57:16.178", "t_unix": 1793660236.179, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 2, "held_sec": 0.613, "accepted": true, "measured_before": [-1.66, 2.19, 2.81, 0.08, -0.08, -29.88], "hold_wait_sec": 0.001, "hold_lead_deg": 0.88, "start_source": "command", "cmd_gap_deg": 0.88, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-3.26, 1.31, 2.02, 0.08, -0.08, -29.88], "sent": true, "timeout_sec": 8.0, "t_send": 1793660236.2086022, "measured_before_send": [-1.75, 2.19, 2.81, 0.08, -0.08, -29.88], "reached": true, "reached_angles": [-2.54, 2.19, 2.81, 0.08, -0.08, -29.88], "reach_err": 0.88, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 4, "t": "2026-11-03T07:57:16.382", "t_unix": 1793660236.383, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 3, "held_sec": 0.817, "accepted": true, "measured_before": [-2.1, 2.19, 2.81, 0.08, -0.08, -29.88], "hold_wait_sec": 0.0, "hold_lead_deg": 1.16, "start_source": "command", "cmd_gap_deg": 1.16, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-4.26, 1.31, 2.02, 0.08, -0.08, -29.88], "sent": true, "timeout_sec": 8.0, "t_send": 1793660236.414411, "measured_before_send": [-2.02, 2.19, 2.81, 0.08, -0.08, -29.88], "reached": true, "reached_angles": [-3.95, 2.19, 2.81, 0.08, -0.08, -29.88], "reach_err": 0.88, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 5, "t": "2026-11-03T07:57:16.786", "t_unix": 1793660236.787, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 4, "held_sec": 1.221, "accepted": true, "measured_before": [-4.57, 2.19, 2.81, 0.08, -0.08, -29.88], "hold_wait_sec": 0.0, "hold_lead_deg": 0.88, "start_source": "command", "cmd_gap_deg": 0.88, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-5.26, 1.31, 2.02, 0.08, -0.08, -29.88], "sent": true, "timeout_sec": 8.0, "t_send": 1793660236.839932, "measured_before_send": [-4.65, 2.19, 2.81, 0.08, -0.08, -29.88], "reached": true, "reached_angles": [-4.57, 2.19, 2.81, 0.08, -0.08, -29.88], "reach_err": 0.88, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 6, "t": "2026-11-03T07:57:16.987", "t_unix": 1793660236.988, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 5, "held_sec": 1.422, "accepted": true, "measured_before": [-4.65, 2.19, 2.81, 0.08, -0.08, -29.88], "hold_wait_sec": 0.0, "hold_lead_deg": 0.88, "start_source": "command", "cmd_gap_deg": 0.88, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-6.26, 1.31, 2.02, 0.08, -0.08, -29.88], "sent": true, "timeout_sec": 8.0, "t_send": 1793660237.027798, "measured_before_send": [-4.92, 2.19, 2.81, 0.08, -0.08, -29.88], "reached": true, "reached_angles": [-5.53, 2.19, 2.81, 0.08, -0.08, -29.88], "reach_err": 0.88, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 7, "t": "2026-11-03T07:57:17.189", "t_unix": 1793660237.19, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 6, "held_sec": 1.624, "accepted": true, "measured_before": [-5.88, 2.19, 2.81, 0.08, -0.08, -29.88], "hold_wait_sec": 0.0, "hold_lead_deg": 0.88, "start_source": "command", "cmd_gap_deg": 0.88, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-7.26, 1.31, 2.02, 0.08, -0.08, -29.88], "sent": true, "timeout_sec": 8.0, "t_send": 1793660237.23727, "measured_before_send": [-6.5, 2.19, 2.81, 0.08, -0.08, -29.88], "reached": true, "reached_angles": [-6.24, 2.19, 2.81, 0.08, -0.08, -29.88], "reach_err": 1.02, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 8, "t": "2026-11-03T07:57:17.391", "t_unix": 1793660237.392, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 7, "held_sec": 1.826, "accepted": true, "measured_before": [-5.97, 2.19, 2.81, 0.08, -0.08, -29.88], "hold_wait_sec": 0.0, "hold_lead_deg": 1.29, "start_source": "command", "cmd_gap_deg": 1.29, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-8.26, 1.31, 2.02, 0.08, -0.08, -29.88], "sent": true, "timeout_sec": 8.0, "t_send": 1793660237.437109, "measured_before_send": [-6.06, 2.19, 2.81, 0.08, -0.08, -29.88], "reached": true, "reached_angles": [-7.91, 2.19, 2.81, 0.08, -0.08, -29.88], "reach_err": 0.88, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
別のタブで開く保存

8:06 の記録 runs/experiments/gamepad_teleop/teleop_20261103_080648/meta.json

{
  "run_stem": "teleop_20261103_080648",
  "started_at": "2026-11-03T08:06:49",
  "execute": true,
  "argv": [
    "tools/gamepad_teleop.py",
    "--execute"
  ],
  "controllers": [
    {
      "name": "PS4 Controller",
      "guid": "03008fe54c050000cc09000000016800",
      "instance_id": 0,
      "axes": 6,
      "buttons": 16,
      "hats": 0,
      "connected_at": "2026-11-03T08:06:54"
    }
  ],
  "python": "3.12.12 | packaged by conda-forge | (main, Oct 22 2025, 23:34:53) [Clang 19.1.7 ]",
  "pygame": "2.6.1",
  "sdl": "2.28.4",
  "platform": "macOS-26.6.2-arm64-arm-64bit",
  "start_pose": [
    -0.26,
    1.14,
    1.4,
    0.0,
    0.17,
    -29.7
  ],
  "guards": {
    "J1_MAX_DEG": 90.87,
    "range": "physical_limits (no base window. 2026-11-03)",
    "J4_SAFE": [
      -90.0,
      60.0
    ],
    "JOINT_LIMITS": [
      [
        -156.0,
        161.0
      ],
      [
        -79.0,
        123.0
      ],
      [
        -177.0,
        177.0
      ],
      [
        -156.0,
        162.0
      ],
      [
        -118.0,
        118.0
      ],
      [
        -177.0,
        178.0
      ]
    ],
    "window": {
      "lo": [
        -156.0,
        -79.0,
        -177.0,
        -156.0,
        -90.0,
        -177.0
      ],
      "hi": [
        161.0,
        90.87,
        177.0,
        162.0,
        60.0,
        178.0
      ]
    },
    "home_bypasses_range_check": true
  },
  "motion": {
    "speed": 20,
    "step_fine_deg": 1.0,
    "step_coarse_deg": 2.0,
    "reach_tol_deg": 3.0,
    "reach_timeout_min_sec": 8.0,
    "poll_sec": 0.3,
    "gripper_sleep_sec": 0.8,
    "grip_close_value": 20,
    "send_wait": 0.0,
    "home": [
      0.0,
      0.0,
      0.0,
      0.0,
      0.0,
      -30.0
    ],
    "home_hold_sec": 1.0,
    "trigger_stop_above": 0.0,
    "hold_start_sec": 0.4,
    "hold_interval_sec": 0.1,
    "hold_ahead_deg": 3.0,
    "hold_stall_sec": 1.0,
    "ignored_check_sec": 0.5,
    "ignored_max_resends": 3,
    "j0_left_sign": -1.0,
    "up_sign": -1.0,
    "select_order": [
      1,
      2,
      3,
      4,
      5
    ]
  },
  "button_map": {
    "0": "cross",
    "1": "circle",
    "2": "square",
    "3": "triangle",
    "4": "share",
    "5": "home",
    "6": "options",
    "7": "l3",
    "8": "r3",
    "9": "l1",
    "10": "r1",
    "11": "dpad_up",
    "12": "dpad_down",
    "13": "dpad_left",
    "14": "dpad_right",
    "15": "touchpad"
  },
  "git": {
    "commit": "15ca6a4ce359b5770531bc9e43f709a15ad12910",
    "script_status": "clean"
  },
  "script_copy": "gamepad_teleop.py",
  "script_sha256": "b8662a3ecfb2f20243c25c9819b325ab86ddfd3f1f3a446cc821cd9c4aeb41f3",
  "ended_at": "2026-11-03T08:09:26",
  "end_reason": "ctrl_c",
  "n_sent": 210
}

8:06 の記録 runs/experiments/gamepad_teleop/teleop_20261103_080648/log.jsonl(228行)

19_sec14.json147,025字・228行・json
{"seq": 1, "t": "2026-11-03T08:07:10.868", "t_unix": 1793660830.868, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 0, "accepted": true, "measured_before": [-0.26, 1.14, 1.4, 0.0, 0.17, -29.7], "start_source": "command", "cmd_gap_deg": 0.0, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-1.26, 1.14, 1.4, 0.0, 0.17, -29.7], "sent": true, "timeout_sec": 8.0, "t_send": 1793660830.910841, "measured_before_send": [-0.26, 1.14, 1.4, 0.0, 0.17, -29.7], "resends": [], "reached": true, "reached_angles": [-0.26, 1.14, 1.4, 0.0, 0.17, -29.7], "reach_err": 1.0, "elapsed_sec": 0.02, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 2, "t": "2026-11-03T08:07:11.281", "t_unix": 1793660831.281, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 1, "held_sec": 0.414, "accepted": true, "measured_before": [-0.96, 1.93, 2.1, 0.0, 0.17, -29.7], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 0.3, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-3.96, 1.14, 1.4, 0.0, 0.17, -29.7], "sent": true, "reached": null, "no_check": true, "t_send": 1793660831.302738, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 3, "t": "2026-11-03T08:07:11.679", "t_unix": 1793660831.679, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 2, "held_sec": 0.812, "accepted": true, "measured_before": [-3.95, 1.93, 2.1, 0.0, 0.17, -29.7], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 0.01, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-6.95, 1.14, 1.4, 0.0, 0.17, -29.7], "sent": true, "reached": null, "no_check": true, "t_send": 1793660831.698498, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 4, "t": "2026-11-03T08:07:11.794", "t_unix": 1793660831.794, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 3, "held_sec": 0.927, "accepted": true, "measured_before": [-4.39, 1.93, 2.1, 0.0, 0.17, -29.7], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 2.56, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-7.39, 1.14, 1.4, 0.0, 0.17, -29.7], "sent": true, "reached": null, "no_check": true, "t_send": 1793660831.825438, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 5, "t": "2026-11-03T08:07:11.894", "t_unix": 1793660831.894, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 4, "held_sec": 1.027, "accepted": true, "measured_before": [-5.36, 1.93, 2.1, -0.08, 0.17, -29.7], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 2.03, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-8.36, 1.14, 1.4, 0.0, 0.17, -29.7], "sent": true, "reached": null, "no_check": true, "t_send": 1793660831.9236102, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 6, "t": "2026-11-03T08:07:12.275", "t_unix": 1793660832.276, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 5, "held_sec": 1.408, "accepted": true, "measured_before": [-7.38, 1.93, 2.1, -0.08, 0.17, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 0.98, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-10.38, 1.14, 1.4, 0.0, 0.17, -29.7], "sent": true, "reached": null, "no_check": true, "t_send": 1793660832.294986, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 7, "t": "2026-11-03T08:07:12.393", "t_unix": 1793660832.393, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 6, "held_sec": 1.526, "accepted": true, "measured_before": [-7.29, 1.93, 2.1, -0.08, 0.17, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 3.09, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-10.29, 1.14, 1.4, 0.0, 0.17, -29.7], "sent": true, "reached": null, "no_check": true, "t_send": 1793660832.4133902, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 8, "t": "2026-11-03T08:07:12.779", "t_unix": 1793660832.779, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 7, "held_sec": 1.912, "accepted": true, "measured_before": [-10.19, 1.93, 2.1, -0.17, 0.17, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 0.1, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-13.19, 1.14, 1.4, 0.0, 0.17, -29.7], "sent": true, "reached": null, "no_check": true, "t_send": 1793660832.798008, "grip_state": "unknown", "stopped": false, "stop_reason": null}
別のタブで開く保存

8:09 の記録 runs/experiments/gamepad_teleop/teleop_20261103_080930/meta.json

{
  "run_stem": "teleop_20261103_080930",
  "started_at": "2026-11-03T08:09:31",
  "execute": true,
  "argv": [
    "tools/gamepad_teleop.py",
    "--execute"
  ],
  "controllers": [
    {
      "name": "PS4 Controller",
      "guid": "03008fe54c050000cc09000000016800",
      "instance_id": 0,
      "axes": 6,
      "buttons": 16,
      "hats": 0,
      "connected_at": "2026-11-03T08:09:36"
    }
  ],
  "python": "3.12.12 | packaged by conda-forge | (main, Oct 22 2025, 23:34:53) [Clang 19.1.7 ]",
  "pygame": "2.6.1",
  "sdl": "2.28.4",
  "platform": "macOS-26.6.2-arm64-arm-64bit",
  "start_pose": [
    -0.26,
    1.49,
    2.1,
    0.26,
    -0.26,
    -29.79
  ],
  "guards": {
    "J1_MAX_DEG": 90.87,
    "range": "physical_limits (no base window. 2026-11-03)",
    "J4_SAFE": [
      -90.0,
      60.0
    ],
    "JOINT_LIMITS": [
      [
        -156.0,
        161.0
      ],
      [
        -79.0,
        123.0
      ],
      [
        -177.0,
        177.0
      ],
      [
        -156.0,
        162.0
      ],
      [
        -118.0,
        118.0
      ],
      [
        -177.0,
        178.0
      ]
    ],
    "window": {
      "lo": [
        -156.0,
        -79.0,
        -177.0,
        -156.0,
        -90.0,
        -177.0
      ],
      "hi": [
        161.0,
        90.87,
        177.0,
        162.0,
        60.0,
        178.0
      ]
    },
    "home_bypasses_range_check": true
  },
  "motion": {
    "speed": 20,
    "step_fine_deg": 1.0,
    "step_coarse_deg": 2.0,
    "reach_tol_deg": 3.0,
    "reach_timeout_min_sec": 8.0,
    "poll_sec": 0.3,
    "gripper_sleep_sec": 0.8,
    "grip_close_value": 20,
    "send_wait": 0.0,
    "home": [
      0.0,
      0.0,
      0.0,
      0.0,
      0.0,
      -30.0
    ],
    "home_hold_sec": 1.0,
    "trigger_stop_above": 0.0,
    "hold_start_sec": 0.4,
    "hold_interval_sec": 0.1,
    "hold_ahead_deg": 3.0,
    "hold_stall_sec": 1.0,
    "ignored_check_sec": 0.5,
    "ignored_max_resends": 3,
    "j0_left_sign": -1.0,
    "up_sign": -1.0,
    "select_order": [
      1,
      2,
      3,
      4,
      5
    ]
  },
  "button_map": {
    "0": "cross",
    "1": "circle",
    "2": "square",
    "3": "triangle",
    "4": "share",
    "5": "home",
    "6": "options",
    "7": "l3",
    "8": "r3",
    "9": "l1",
    "10": "r1",
    "11": "dpad_up",
    "12": "dpad_down",
    "13": "dpad_left",
    "14": "dpad_right",
    "15": "touchpad"
  },
  "git": {
    "commit": "413f7e111fcd58b991b790ddd6bb3a220d1c3479",
    "script_status": "clean"
  },
  "script_copy": "gamepad_teleop.py",
  "script_sha256": "6d14e322e4560c6aa66d8172776874b204d1c28867cb73c5805527255d2ac29f",
  "ended_at": "2026-11-03T08:11:33",
  "end_reason": "ctrl_c",
  "n_sent": 275
}

8:09 の記録 runs/experiments/gamepad_teleop/teleop_20261103_080930/log.jsonl(307行)

20_sec14.json196,904字・307行・json
{"seq": 1, "t": "2026-11-03T08:09:45.936", "t_unix": 1793660985.937, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -1.0, "hold_id": 1, "hold_n": 0, "accepted": true, "measured_before": [-0.26, 1.49, 2.1, 0.26, -0.26, -29.79], "start_source": "command", "cmd_gap_deg": 0.0, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-1.26, 1.49, 2.1, 0.26, -0.26, -29.79], "sent": true, "timeout_sec": 8.0, "t_send": 1793660986.018062, "measured_before_send": [-0.26, 1.49, 2.1, 0.26, -0.26, -29.79], "resends": [], "reached": true, "reached_angles": [-0.26, 1.49, 2.1, 0.26, -0.26, -29.79], "reach_err": 1.0, "elapsed_sec": 0.01, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 2, "t": "2026-11-03T08:09:46.336", "t_unix": 1793660986.337, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 1, "held_sec": 0.401, "accepted": true, "measured_before": [-1.05, 2.28, 2.81, 0.26, -0.26, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 0.21, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-4.05, 1.49, 2.1, 0.26, -0.26, -29.79], "sent": true, "reached": null, "no_check": true, "t_send": 1793660986.363437, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 3, "t": "2026-11-03T08:09:46.437", "t_unix": 1793660986.437, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 2, "held_sec": 0.501, "accepted": true, "measured_before": [-1.05, 2.28, 2.81, 0.26, -0.26, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 3.0, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-4.05, 1.49, 2.1, 0.26, -0.26, -29.79], "sent": true, "reached": null, "no_check": true, "t_send": 1793660986.465986, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 4, "t": "2026-11-03T08:09:46.537", "t_unix": 1793660986.538, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 3, "held_sec": 0.602, "accepted": true, "measured_before": [-2.37, 2.28, 2.81, 0.26, -0.26, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 1.68, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-5.37, 1.49, 2.1, 0.26, -0.26, -29.79], "sent": true, "reached": null, "no_check": true, "t_send": 1793660986.565394, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 5, "t": "2026-11-03T08:09:46.646", "t_unix": 1793660986.647, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 4, "held_sec": 0.711, "accepted": true, "measured_before": [-4.74, 2.28, 2.81, 0.26, -0.26, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 0.63, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-7.74, 1.49, 2.1, 0.26, -0.26, -29.79], "sent": true, "reached": null, "no_check": true, "t_send": 1793660986.666309, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 6, "t": "2026-11-03T08:09:46.763", "t_unix": 1793660986.763, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 5, "held_sec": 0.827, "accepted": true, "measured_before": [-7.64, 2.28, 2.81, 0.17, -0.26, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 0.1, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-10.64, 1.49, 2.1, 0.26, -0.26, -29.79], "sent": true, "reached": null, "no_check": true, "t_send": 1793660987.151343, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 7, "t": "2026-11-03T08:09:47.213", "t_unix": 1793660987.213, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 6, "held_sec": 1.277, "accepted": true, "measured_before": [-7.82, 2.28, 2.81, 0.17, -0.26, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 2.82, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-10.82, 1.49, 2.1, 0.26, -0.26, -29.79], "sent": true, "reached": null, "no_check": true, "t_send": 1793660987.2410161, "grip_state": "unknown", "stopped": false, "stop_reason": null}
{"seq": 8, "t": "2026-11-03T08:09:47.664", "t_unix": 1793660987.665, "button": 13, "button_name": "dpad_left", "kind": "move", "selected_joint": 1, "step_deg": 1.0, "execute": true, "joint": 0, "delta": -3.0, "hold_id": 1, "hold_n": 7, "held_sec": 1.729, "accepted": true, "measured_before": [-10.98, 2.28, 2.81, 0.08, -0.26, -29.79], "start_source": "hold", "cmd_gap_deg": 0.79, "hold_lead_deg": 0.16, "clip": [], "refused": [], "limit_ja": "", "limit_ascii": "", "command": [-13.98, 1.49, 2.1, 0.26, -0.26, -29.79], "sent": true, "reached": null, "no_check": true, "t_send": 1793660987.6829162, "grip_state": "unknown", "stopped": false, "stop_reason": null}
別のタブで開く保存