1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RobStride RS02でMuJoCoモデルのモータパラメータ同定

1
Last updated at Posted at 2026-04-29

はじめに

最近Twitterで話題のモータの物理シミュレータモデルのパラメータ同定をやってみました.
モータにはRobStride社のRS02を,物理シミュレータにはMuJoCoを用います.

手順はこちらのツイートを参考にさせていただきました.ありがたや...

モータのパラメータ同定とは?

シミュレータ(MuJoCo)の動力学モデルに含まれる物理パラメータ(armature=慣性,frictionloss=クーロン摩擦,damping=粘性減衰)を実機の入出力データに当てはめて推定する作業.これにより sim2real ギャップを縮めてRL 学習結果が実機で動くようにする作業や手法のことです.

ワークフロー:

  1. recorder/ — Linux + SocketCAN 上で 1 kHz RT ループを回しマルチサイン純トルク(kp=0, kd=0, torque_ff=multi_sine(t))で関節を励振して位置・速度を CSV 記録する.
  2. optimizer_mujoco/sysid/optimize.py — シミュレーションリプレイ法で scipy.optimize.least_squares(TRF、数値ヤコビアン)により 3 パラメータ θ を最小二乗推定する.
  3. optimizer_mujoco/sysid/validate.py — PD クローズドループで初期値 vs 同定値 vs 実機の追従誤差を比較.
  4. optimizer_isaac/ — 同じ枠組みを Isaac Sim バックエンドへ移植中(feat ブランチで作業中)
    要は「実機トルク→関節応答」のデータから MuJoCo/Isaac の摩擦・慣性パラメータを逆算し、RL 用シミュレータの忠実度を上げるための一連のツール群.

実験用コード

https://github.com/kim-xps12/bsl_droid_control/tree/main/sysid_ws に全て上がっています.気になる方は参照ください.

環境

  • Jetson Orin Nano Super
  • USB-CANアダプタ: DSD TECH SH-C31G
  • RobStride RS02

こんな感じで実施しました.

実機実験の流れ

データの記録

青舶の本体に組み付け済みの左腰ヨーモータ(ID 11)でデータ収集を行います.
励振は次式を用いました.

torque(t) = amp × (sin(2π·f·t) + 0.6·sin(2π·3.4f·t) + 0.3·sin(2π·7.4f·t))

以下のコマンドを実行します.

cd sysid_ws/recorder
sudo build/sysid_recorder \
 --interface can1_rs  \
 --motor-id 11 \
 --freq 4.5 \
 --amp 2.5 \
 --duration 30.0 \
 --output ../optimizer/data/recording_sysid_id11.csv

実行結果.30sec分,問題なく取れていそうですね.

=== sysid_recorder ===
  Mode:      SYSID (multi-sine)
  Interface: can1_rs
  Motor ID:  11
  Freq:        4.5 Hz
  Amp:         2.5 Nm
  Gains:       kp=0.0  kd=0.0 (pure torque)
  Drift guard: +/- 2pi rad / +/- 30 rad/s
  Duration:    30 s
  Torque lim:  12 Nm
  Output:      ../optimizer/data/recording_sysid_id11.csv

Connected to can1_rs
Motor probe OK: pos=0.171044 rad, vel=0.0496841 rad/s

Recording... (Ctrl+C to stop early)
[ 30.0s] tick=30000  missed=0    pos=  3.829 rad  
Recording done: 30100 samples, 0 missed (0.0%)
Saved: ../optimizer/data/recording_sysid_id11.csv

パラメータ最適化

30sec分のデータからモデルパラメータをフィッティングします.

cd sysid_ws/optimizer
uv run python sysid/optimize.py \
  --csv data/recording_sysid_id11.csv \
  --model ../models/rs02_joint.xml \
  --output results/identified_params.json

以下のように計算が完了すればOKです.

Loading CSV: data/recording_sysid_id11.csv
  30100 valid samples, duration=30.10 s

Optimizing (least_squares / TRF, x0=[0.01 0.1  0.05]) ...
  iter=   1  armature=0.010000  frictionloss=0.100000  damping=0.050000  cost=2.14351924
  iter=   6  armature=0.013489  frictionloss=0.050194  damping=0.025634  cost=0.09181274
  iter=  11  armature=0.014997  frictionloss=0.044270  damping=0.022955  cost=0.02418515
  iter=  16  armature=0.015309  frictionloss=0.039236  damping=0.023216  cost=0.02345425
  iter=  21  armature=0.015360  frictionloss=0.001153  damping=0.027921  cost=0.02220637
  iter=  26  armature=0.015363  frictionloss=0.001002  damping=0.027940  cost=0.02220158
  iter=  31  armature=0.015364  frictionloss=0.001000  damping=0.027940  cost=0.02220150
  iter=  36  armature=0.015364  frictionloss=0.001000  damping=0.027940  cost=0.02220150
  iter=  41  armature=0.015364  frictionloss=0.001000  damping=0.027940  cost=0.02220150
  iter=  46  armature=0.015364  frictionloss=0.001000  damping=0.027940  cost=0.02220150

=== Identified Parameters ===
  armature: 0.015364
  frictionloss: 0.001000
  damping: 0.027940
  Final cost:  0.0222015033
  Converged:   True
  Iterations:  13

Saved: results/identified_params.json

得られたモデルパラメータがこちら.

{
  "armature": 0.01536404780450517,
  "frictionloss": 0.0010000000000000002,
  "damping": 0.027939873183805693
}

これを使って評価していきましょう.

評価用データの記録

次節の評価で使う「モータ実機側の挙動」のデータ収集をします.まずは最適化の材料を取るのに使ったモータで実施.

cd sysid_ws/recorder
sudo build/sysid_recorder \
  --interface can1_rs \
  --motor-id 11 \
  --validate --kp 8 \
  --kd 0.5 \
  --duration 30.0 \
  --output ../optimizer/data/validation_id11.csv

保存できました.

=== sysid_recorder ===
  Mode:      VALIDATE (PD)
  Interface: can1_rs
  Motor ID:  11
  kp=8  kd=0.5  ramp=200 ms
  Duration:    30 s
  Torque lim:  12 Nm
  Output:      ../optimizer/data/validation_id11.csv

Connected to can1_rs
Motor probe OK: pos=-0.992132 rad, vel=0.0174566 rad/s

Recording... (Ctrl+C to stop early)
[ 30.0s] tick=30000  missed=0    pos=  1.877 rad  
Recording done: 30100 samples, 0 missed (0.0%)
Saved: ../optimizer/data/validation_id11.csv

材料収集に使ったモータとは別の個体(右脚の腰ヨーモータ)でも評価用のサンプルを取っておきます.

sudo build/sysid_recorder \
  --interface can2_rs \
  --motor-id 21 \
  --validate \
  --kp 8 \
  --kd 0.5 \
  --duration 30.0 \
  --output ../optimizer/data/validation_id21.csv

取れました.

=== sysid_recorder ===
  Mode:      VALIDATE (PD)
  Interface: can2_rs
  Motor ID:  21
  kp=8  kd=0.5  ramp=200 ms
  Duration:    30 s
  Torque lim:  12 Nm
  Output:      ../optimizer/data/validation_id21.csv

Connected to can2_rs
Motor probe OK: pos=-2.80497 rad, vel=-0.0349132 rad/s

Recording... (Ctrl+C to stop early)
[ 30.0s] tick=30000  missed=0    pos=  1.857 rad  
Recording done: 30100 samples, 0 missed (0.0%)
Saved: ../optimizer/data/validation_id21.csv

評価

先ほど実機に与えた指令値をシミュレータにも与えて,その振る舞いを比較します.
パラメータ同定で得られた物理特性の反映の有無で,実機に振る舞いが近づいたら成功です.

まずはID 11のモータから.

cd sysid_ws/optimizer
uv run python sysid/validate.py \
  --csv data/validation_id11.csv \
  --model ../models/rs02_joint.xml \
  --params results/identified_params.json \
  --output-png results/validation_id11.png
Loading CSV: data/validation_id11.csv
  30100 valid samples, duration=30.10 s
  Detected torque_limit: 12.00 Nm (used to match sim clamp to real motor)

Simulating with initial parameters ...
Loading identified params: results/identified_params.json
  armature=0.015364  frictionloss=0.001000  damping=0.027940

Simulating with identified parameters ...

=== Validation Results ===
  Position RMSE:  initial=0.0788 rad  →  identified=0.0363 rad  (improvement: 53.9%)
  Velocity RMSE:  initial=1.8113 rad/s  →  identified=0.7499 rad/s  (improvement: 58.6%)
Saved: results/validation_id11.png

image.png

下段の同定されたモデルパラメータを用いた場合の方が,実機の振る舞いに近づいていますね.良い感じ.

ID 21のモータでもやってみます.

cd sysid_ws/optimizer
uv run python sysid/validate.py \
  --csv data/validation_id21.csv \
  --model ../models/rs02_joint.xml \
  --params results/identified_params.json \
  --output-png results/validation_id21.png
Loading CSV: data/validation_id21.csv
  30100 valid samples, duration=30.10 s
  Detected torque_limit: 12.00 Nm (used to match sim clamp to real motor)

Simulating with initial parameters ...
Loading identified params: results/identified_params.json
  armature=0.015364  frictionloss=0.001000  damping=0.027940

Simulating with identified parameters ...

=== Validation Results ===
  Position RMSE:  initial=0.0781 rad  →  identified=0.0380 rad  (improvement: 51.4%)
  Velocity RMSE:  initial=1.7809 rad/s  →  identified=0.7419 rad/s  (improvement: 58.3%)
Saved: results/validation_id21.png

image.png

こちらでも同様の結果になりました.モデルパラメータを異なる個体間で使い回しも大丈夫そうな雰囲気で一安心です.



再実験

ここで,Claude Codeくんが「"frictionloss": 0.001000...は同定処理の下限に張り付いてるから微妙かも??」と提言してくれたので修正してもらいます.良い時代になりました.

torque(t) = amp × (0.4·cos(2π·0.3f·t) + sin(2π·f·t)
                 + 0.6·sin(2π·3.4f·t) + 0.3·sin(2π·7.4f·t))

0.4·cos(2π·0.3f·t)の低周波成分が増えました.これで再実験です.

データの記録

cd sysid_ws/recorder
sudo build/sysid_recorder \
  --interface can1_rs \
  --motor-id 11 \
  --freq 4.5 \
  --amp 1.5 \
  --duration 30 \
  --output ../optimizer/data/recording_sysid_id11_v2.csv

--ampを先ほどと同じ2.5にしておいたところ,可動域を超えて回りすぎるのか動作が途中で止まったので1.5に下げています.これで30sec分ちゃんと取れました.

=== sysid_recorder ===
  Mode:      SYSID (multi-sine)
  Interface: can1_rs
  Motor ID:  11
  Freq:        4.5 Hz
  Amp:         1.5 Nm
  Gains:       kp=0.0  kd=0.0 (pure torque)
  Drift guard: +/- 2pi rad / +/- 30 rad/s
  Duration:    30 s
  Torque lim:  12 Nm
  Output:      ../optimizer/data/recording_sysid_id11_v2.csv

Connected to can1_rs
Motor probe OK: pos=-6.09239 rad, vel=-0.100711 rad/s

Recording... (Ctrl+C to stop early)
[ 30.0s] tick=30000  missed=0    pos= -4.156 rad  
Recording done: 30100 samples, 0 missed (0.0%)
Saved: ../optimizer/data/recording_sysid_id11_v2.csv

パラメータ最適化

cd sysid_ws/optimizer
uv run python sysid/optimize.py \
    --csv data/recording_sysid_id11_v2.csv \
    --model ../models/rs02_joint.xml \
    --output results/identified_params_v2.json

実行結果

Loading CSV: data/recording_sysid_id11_v2.csv
  30100 valid samples, duration=30.10 s

Optimizing (least_squares / TRF, x0=[0.01 0.1  0.05]) ...
  iter=   1  armature=0.010000  frictionloss=0.100000  damping=0.050000  cost=0.84936673
  iter=   6  armature=0.014158  frictionloss=0.054734  damping=0.030671  cost=0.13219040
  iter=  11  armature=0.015488  frictionloss=0.047875  damping=0.026856  cost=0.03318613
  iter=  16  armature=0.015406  frictionloss=0.045297  damping=0.025956  cost=0.02627268
  iter=  21  armature=0.015352  frictionloss=0.027550  damping=0.029456  cost=0.02590879
  iter=  26  armature=0.015365  frictionloss=0.029607  damping=0.029041  cost=0.02589557
  iter=  31  armature=0.015349  frictionloss=0.030662  damping=0.028836  cost=0.02589141
  iter=  36  armature=0.015350  frictionloss=0.030512  damping=0.028867  cost=0.02589139
  iter=  41  armature=0.015350  frictionloss=0.030514  damping=0.028867  cost=0.02589140
  iter=  46  armature=0.015350  frictionloss=0.030513  damping=0.028867  cost=0.02589139
  iter=  51  armature=0.015350  frictionloss=0.030513  damping=0.028867  cost=0.02589139
  iter=  56  armature=0.015350  frictionloss=0.030513  damping=0.028867  cost=0.02589139
  iter=  61  armature=0.015350  frictionloss=0.030513  damping=0.028867  cost=0.02589139
  iter=  66  armature=0.015350  frictionloss=0.030513  damping=0.028867  cost=0.02589139
  iter=  71  armature=0.015350  frictionloss=0.030513  damping=0.028867  cost=0.02589139
  iter=  76  armature=0.015350  frictionloss=0.030513  damping=0.028867  cost=0.02589139

=== Identified Parameters ===
  armature: 0.015350
  frictionloss: 0.030513
  damping: 0.028867
  Final cost:  0.0258913919
  Converged:   True
  Iterations:  29

Saved: results/identified_params_v2.json

以下のパラメータが得られました.

{
  "armature": 0.015349920579792717,
  "frictionloss": 0.030512575816449027,
  "damping": 0.028866991695064865
}

"frictionloss": 0.030と下限の0.001から上がりましたね.

再評価

まずはID 11で実施.

cd sysid_ws/optimizer
uv run python sysid/validate.py \
    --csv data/validation_id11.csv \
    --model ../models/rs02_joint.xml \
    --params results/identified_params_v2.json \
    --kp 8 --kd 0.5 \
    --output-png results/validation_id11_v2.png
Loading CSV: data/validation_id11.csv
  30100 valid samples, duration=30.10 s
  Detected torque_limit: 12.00 Nm (used to match sim clamp to real motor)

Simulating with initial parameters ...
Loading identified params: results/identified_params_v2.json
  armature=0.015350  frictionloss=0.030513  damping=0.028867

Simulating with identified parameters ...

=== Validation Results ===
  Position RMSE:  initial=0.0788 rad  →  identified=0.0352 rad  (improvement: 55.3%)
  Velocity RMSE:  initial=1.8113 rad/s  →  identified=0.7477 rad/s  (improvement: 58.7%)
Saved: results/validation_id11_v2.png

image.png

デグレもなさそうです.

次にID 21で実施.

cd sysid_ws/optimizer
uv run python sysid/validate.py \
    --csv data/validation_id21.csv \
    --model ../models/rs02_joint.xml \
    --params results/identified_params_v2.json \
    --kp 8 --kd 0.5 \
    --output-png results/validation_id21_v2.png
Loading CSV: data/validation_id21.csv
  30100 valid samples, duration=30.10 s
  Detected torque_limit: 12.00 Nm (used to match sim clamp to real motor)

Simulating with initial parameters ...
Loading identified params: results/identified_params_v2.json
  armature=0.015350  frictionloss=0.030513  damping=0.028867

Simulating with identified parameters ...

=== Validation Results ===
  Position RMSE:  initial=0.0781 rad  →  identified=0.0369 rad  (improvement: 52.8%)
  Velocity RMSE:  initial=1.7809 rad/s  →  identified=0.7392 rad/s  (improvement: 58.5%)
Saved: results/validation_id21_v2.png

image.png

こちらも問題なさそう.細かい数字で見るとpos RMSEが0.0363→0.0352と3%程度改善しているようです.誤差な気もしますね...まあ悪化していないので修正版を採用することにします.

詳細が気になる方はリポジトリ内の修正レポートをご覧ください.

おわりに

本稿ではRobStride RS02のモデル同定を実施しました.今後はこれを使ってシミュレータで歩容獲得→実機適用に挑戦する予定です.

それでは.

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?