見出し画像

# 子守りロボット ピコちゃん制作日記(3)ー Open Duck Mini v2の制作記録〜強化学習による新モーションの開発〜

前回補足

前回の記事では組み立てが終わり、いざ動かしたらコケて破損までいってしまいました。
その後、OpenDuck Miniが無事に動いて歩けるようになったので、制作にあたっての注意点をまとめようと思います。

前回の転倒・大破の反省を活かし、今回はケチるのをやめて、BOM(部品リスト)通りに Raspberry Pi Zero 2W を買い直して実装しました。

いろいろ代用品でケチりながらやろうと試みましたが、なんだかんだで公式ドキュメントに書いてある通りにそのまま作るのが、一番うまくいくということを(当たり前ですが)身をもって理解しました。
特に二足歩行ロボットは、シミュレーション上のAIを現実に移植する「Sim2Real」の塊です。勝手な代用パーツを使って重さや重心が少しでも変わってしまうと、学習済みのポリシー(歩行制御プログラム)がシミュレーション通りに動かなくなって即コケてしまうので、厳密なパーツ選定が非常に重要でした。

組み立ての詳細について、公式のGitHubリポジトリのドキュメントで説明が足りない部分は、以下のWikiサイトに手順が詳細かつ順を追って記載されています。これから作る方は、この通りに進めていくのが絶対におすすめです。必要なことはすべて網羅されています。

※ちなみに中国語のサイトです。Google Chromeの標準機能ではなぜか翻訳できないページ構造になっているため、知りたい情報がある場合はブラウザのAIアシスタント等に聞きながら翻訳するとスムーズです。このWikiはOpenDuckMiniの公式リポジトリからも公式にリンクされている信頼できるサイトです。


さて、これで実際に歩行できるロボットが完成しました。ここからが本番、何をするかというフェーズに入ります。
現時点では、付属のコントローラーを使って前後・左右・旋回ができるのみです。
しかし、このロボットにはマイク・スピーカー・カメラの搭載スペースが最初から用意されており、追加で実装を進めれば、LLM(大規模言語モデル)を介してロボットと会話するような拡張も可能です。

そして、「フィジカルAI」としてさらに一歩踏み込むなら、自分で「新しいモーション」を作成し、強化学習をさせて動かすことに挑戦したくなります。 ロボットの形状や重量バランスを少しでもカスタムした際には再度の強化学習が必須になるため、このやり方を学ぶことには非常に大きな価値があります。

そこで今回は、強化学習に焦点を当て、「OpenDuckMiniがどのようにして歩行を学習したのか」の仕組みを紐解きます。さらに、その手順を応用して「新しいモーション(うさぎ跳び)」の強化学習にもチャレンジしてみたいと思います!


OpenDuckMiniのプロジェクト全体構成

強化学習を始める前に、OpenDuckMiniのプロジェクトを構成する4つのGithubリポジトリの役割を整理しておきましょう。
このうち、今回のシミュレーションと強化学習に主に関わるのは Open_Duck_PlaygroundOpen_Duck_reference_motion_generator の2つです。

以下は各リポジトリの簡単な説明。
①Open_Duck_Mini・・・ハブリポジトリ。CADデータ、3Dプリント用STL、設計書、シミュレーション用モデル定義(URDF/MJCF)、標準の歩行エンジン、学習済みのONNXモデル(`BEST_WALK_ONNX.onnx`)を格納。
②Open_Duck_Mini_Runtime・・・Raspberry Pi Zero 2W上で動く実行コード。`scripts/v2_rl_walk_mujoco.py` が学習済みONNXを読み込み、50Hzでサーボを直接駆動する。実機を実際に歩かせる時(組み立て後の最終段階)で必要となる。
③Open_Duck_Playground・・・Google DeepMindの `mujoco_playground` をベースにした強化学習フレームワーク。ロボットの歩行ポリシー(脳にあたる部分)を学習させる。自分でオリジナルの歩行ポリシーを学習したい時に必要となる(既存のモデルでよければ不要)。
④Open_Duck_reference_motion_generator・・・逆運動学(IK)エンジン「Placo」を使用し、理想的な歩行軌道(`polynomial_coefficients.pkl`)を生成する。強化学習時の「お手本」となる。学習用のお手本モーションを作り直したい時に必要となる(既存のデータでよければ不要)。
(補足) bam ・・・Better Actuator Models。Feetechサーボ等の物理特性を特定したパラメータ群。シミュレーションの精度向上に使われているため参照のみ(再測定などは不要)


OpenDuckMiniの歩行強化学習の仕組み

それでは、OpenDuckMiniがどのように強化学習で歩行をマスターしているのか、その裏側の仕組みを見ていきましょう。

1. シミュレータから実機へ!「Sim2Real」の全体像

強化学習を実機(リアルなロボット)で直接行うのは非常に困難です。なぜなら、学習初期のロボットはメチャクチャに暴れてコケるため、数万回も繰り返せばロボットが物理的に壊れてしまうからです。
そこで、現代のロボット強化学習では「Sim2Real(シミュレーションから現実へ)」というアプローチを取ります。

OpenDuckMiniの学習パイプラインは、大きく以下の3つのステップで構成されています。

  1. 理想のモーション生成 (オフライン計算)
    「理想的な歩行パターン」を、ロボット工学の逆運動学(IK)エンジンを用いて計算し、多項式の係数データとして保存しておきます。

  2. シミュレータでの超並列学習 (強化学習フェーズ)
    物理シミュレータ「MuJoCo」の中で、数千台のロボットをGPU上で並列に動かし、保存しておいた理想モーションを「お手本」としながら、PPO(Proximal Policy Optimization)というアルゴリズムで学習します。

  3. 実機へのデプロイ (推論フェーズ)
    学習したニューラルネットワークを軽量なONNX形式に変換し、ロボットの実機(Raspberry Pi)に転送します。実機では、センサー情報から1秒間に50回(50Hz)のペースで次の関節の角度を計算し、モーターを駆動します。

2. ディズニーの「BDXドロイド」論文を参考にした「模倣報酬(Imitation Reward)」

このプロジェクトは、ディズニーの「BDXドロイド」に関する研究論文(Disney Research)を参考に設計されたとのこと。強化学習では参照モーションを事前に作り、模倣させるように報酬を設計するのが定石となっているらしいです。

ディズニーのBDXドロイドとは?
スター・ウォーズのテーマパークなどで活躍する、アニメーションのように愛らしく感情豊かに歩く二足歩行ドロイド。ディズニーは、アニメーターが作った魅力的な動き(リファレンスモーション)をシミュレータ上でロボットに「模倣」させる強化学習を用いて、実機での安定歩行を実現しました。

純粋な強化学習(ゼロから報酬の最大化を目指すもの)で二足歩行を学習させようとすると、AIはしばしば人間には理解できない奇妙な動き(床を這いずり回ったり、不自然に飛び跳ねたり)を「最も効率よく移動できる方法」として学習してしまいます。

そこで、OpenDuckMiniでもディズニーの手法を参考にし、「あらかじめ計算した理想の歩行スタイルをお手本として真似しなさい」というインセンティブを報酬関数に組み込みました。
具体的には、歩行サイクルの時間(位相)に合わせて、「理想のポーズ(関節角度)と、現在の実際の関節角度の差」を計算し、その差が小さければ小さいほど高い報酬がもらえるように設計されています。

これにより、ロボットは「転ばずに移動する」という大目的に加え、「きれいに可愛く歩く」というスタイルを効率よく、かつ素早く身につけることができるのです。

3. 「まず立て、話はそれからだ」── 絶妙な報酬設計

強化学習の成否は、ロボットに与える「アメとムチ(報酬とペナルティ)」のバランス設計にかかっています。OpenDuckMiniでは、複数の報酬とペナルティを掛け合わせて学習を誘導しています。

💡 生存報酬 `alive` が「最強」に設定されている理由

表を見ると、生存報酬が `+20.0` とずば抜けて高く設定されています。
実はこれが「カリキュラム効果」を生み出します。学習を始めたばかりのAIは、最初はどう歩けばいいか全くわかりません。しかし、「立っているだけで大量のポイントがもらえる」ため、「コケずに立ち続けること」を最優先で学習します。
立ち上がれるようになった後で、AIは「あれ?少し前進コマンドに合わせて体を揺らすと、もっとポイントがもらえるぞ!」と気づき始め、段階的に「歩行」のステップへと移行していくのです。

4. シミュレータと実機のギャップを埋める「Sim2Real」の泥臭い工夫

「シミュレータの中では完璧に歩いたのに、実機にプログラムを書き込んだら1歩目でコケた」
これはロボット強化学習における「最大の壁」であり、Sim2Realギャップと呼ばれます。
シミュレータは摩擦や重力が完璧に計算された「理想郷」ですが、現実のロボットにはサーボのギアのガタ(遊び)があり、床の滑りやすさは場所によって異なり、バッテリー残量でモーターの出力も変わり、センサーにはノイズが乗り、通信の遅延(タイムラグ)が存在します。

このギャップを埋めるため、学習プロセスに以下のような非常に実践的で「泥臭い」工夫を盛り込んでいます。

  • ドメインランダム化(Domain Randomization): 並列で走る数千台のロボット環境ごとに、床の摩擦(0.5〜1.0)、各パーツの質量(±10%)、重心の位置、サーボモーターのパワーなどをあえてランダムに変えることで、どんな環境でも頑健に歩けるようにします。

  • バックラッシュの物理モデリング: サーボモーターにあるわずかなギアの「遊び(バックラッシュ)」を物理エンジン上で再現し、ガタがある体での歩き方をあらかじめ体験させておきます。

  • 観測ノイズと遅延の注入: センサー値にノイズを混ぜ、さらに0〜3ステップのランダムな通信遅延を意図的に発生させ、通信ラグに強いタフな制御を身につけさせます。

5. GPUの暴力で学習する「超並列シミュレーション」

これらの大量の試行錯誤とランダム化を支えているのが、Google DeepMindが開発するJAX/MJX(MuJoCo JAX版)を利用した超高速シミュレーションです。
従来のシミュレータでは、1台のロボットの物理計算をCPUでコツコツ行うのが限界でしたが、MJXを使うことで、
「GPU上で8192台のロボットを同時に並列シミュレーションする」という力技が可能になります。

  • 1回の学習(1.5億〜3億ステップ)で、ロボットが経験する累積エピソード数は約100万回以上。

  • もし実機で100万回歩かせようとしたら何ヶ月もかかりますが、GPU(例えばRTX 4090)を使えばわずか1.5〜3時間で学習が完了します。


では実際このフローを元に新しいモーションを試しましょう!

新しいモーションとして、OpenDuckMiniに「うさぎ跳び(bunny_hop)」をさせてみます。
はたして、アヒルロボットにジャンプさせることができるのか、チャレンジです!

まず、うさぎ跳びのモーションを作成します。片足が接地していない状態を作るのは難しく、数式に基づく逆運動学(IK)エンジンではなかなか綺麗に飛び跳ねる軌道を計算できませんでした。

モーションを作成したら、いよいよ強化学習です。
初期の実験では、ロボットは「立ち上がるし前進もするけれど、全く跳び上がらずに足をズリズリ引きずるだけ」という問題に直面しました。

この「跳ばない局所解」を解決するために、問題の切り分けを行い、強化学習における報酬・アルゴリズムの見直しを行いました。

1. 物理的な限界の検証

まず、「そもそもこのモーターと重量で跳べるのか?」を単発キックテストで検証しました。
ロボットの重量2.1kg、サーボ(STS3215)の実効限界速度約7 rad/sに対して測定したところ、「0.10秒〜0.15秒の全力伸展(キック)」を行えば物理的に3cm以上浮き上がって跳べることが判明しました。
しかし、最初のお手本モーションはキック時間が0.3秒と長すぎたため、物理的に跳び上がれないお手本を真似しようとした結果、AIは妥協して「足ズリ歩行」を学習していたのです。

2. 報酬設計の見直しとバグ修正

うさぎ跳び用のタスク(`bunny_hop.py`)を開発するにあたり、以下の報酬設計の見直しを行いました。

  • 参照データの修正: 以前の参照データは「contacts(接地判定)が常に1.0(常時接地)」かつ「上方向の速度(vz)が0固定」となっており、実は「跳び上がると参照とズレて罰せられる」という本末転倒な設定になっていました。これを、空中期間は contacts=0 になるように修正しました。

  • `flight_match` 報酬(空中ボーナス)の導入: 参照データとお手本がともに「両足が浮いている(contacts=0)」状態のときに、大きなボーナス(+2.0)を与えるようにしました。これにより、足を引きずるよりも、しっかり跳ねた方が圧倒的に得点が高くなるように誘導しました。

  • 不要なペナルティの緩和: 通常の歩行で使われる「足の滑り(slip)ペナルティ」などは、ジャンプ・着地時の激しい摩擦変化によって学習を阻害するため、うさぎ跳び用に調整・オフにするなどの見直しを行いました。

3. RSI (Reference State Initialization) の導入(DeepMimic論文の技術)

うさぎ跳び学習の最大のブレイクスルーが、2018年に発表された有名な強化学習論文「DeepMimic」で提案されたRSI(Reference State Initialization)という技術の導入です。

うさぎ跳びを学習させる際、「立ち姿勢」からしかエピソードを開始しない場合、跳ぶ方法を知らないAIは「空中での正しい姿勢制御や着地」を経験することができません(=探索の鶏と卵問題)。
そこで、エピソードの開始時に、80%の確率で「空中を含めた、ジャンプ動作のランダムな瞬間(位相)からロボットを配置してスタートする」ようにしました。

【RSI(参照状態初期化)のイメージ】

 通常の学習:  [立位スタート] ──(跳べない)──> [コケる] (空中や着地を経験できない)
 RSI導入後:   [空中に浮いた状態からスタート] ──> [着地を学習] (後半の動きから逆向きにマスター)

これにより、AIは「空中にいる状態からの着地方法」を先に学び、その後で「どうすればその空中状態に移行できるか(キック)」を組み立てることで、見事に連続した跳躍動作を学習することに成功しました。


シミュレーション上はうまくいったので、実機でトライ!

Sim2Realの圧倒的な壁

シミュレータの中では1〜3cm可愛らしく跳ねていたOpenDuckMiniですが、実機に書き込むと全く跳び上がらず、その場でガタガタと揺れているだけでした……。

原因として考えられるのは:

  • サーボモーターの瞬間トルク不足: シミュレータ上のモーターモデルよりも、実機のサーボは急激な電圧降下や個体差によって「瞬発的なキック力」が足りなかった。

  • 実機の機体剛性: 3Dプリントされたボディのしなりや関節の物理的なガタがシミュレータ以上に大きく、キックのエネルギーが吸収されてしまった。

  • 床の弾性と摩擦の不一致: 現実の床がシミュレータより柔らかく(あるいは硬く)、反発力を得られなかった。

シミュレーションでどれほど完璧でも、ダイナミックな高出力モーションを実機に転移させる(Sim2Real)ことの難しさを痛感する結果となりました。やはり物理は甘くないですね。
ですが、この「思い通りにいかないハードウェアとAIのチューニング」こそが、ロボティクス開発の何よりの醍醐味です。

いつか本気でうさぎ跳びできるようになるまで、諦めずにデバッグと改変を続けていこうと思います!

いいなと思ったら応援しよう!