Unitree Mujoco上でジョイスティックで Unitree Go2 を動かそうとした話

# 1. はじめに
前回の記事では[四足歩行ロボットのUnitree Go2をシミュレーション環境（Mujoco)で動かしてみて分かったこと](https://qiita.com/bebebefu/items/483fe541f20b2855c94c)unitree_mujocoというシミュレーション環境を利用して、サンプルプログラムではありますが、Unitree Go2が立ちあがるところをシミュレーションしつつ以下のことが分かりました。

- 現在のシミュレーション環境のバージョンでは高レベル制御（SportModeなど）は未実装で、低レベル制御のみ対応
- 低レベル制御のみで歩行を実装するには、調整が難しく、振動が発生しやすい
- 「立ち⇔伏せ」の動作は比較的簡単に実装可能

そして今回は、ジョイスティックで Unitree Go2 をMujoco上で動かそうと取り組んだのがこの記事になります。

unitree_mujoco（以下のリンク）のREADME を読む限り、設定を変更すればジョイスティックで Unitree Go2 を操作できるように思えます。  

https://github.com/unitreerobotics/unitree_mujoco

しかし、実際に試してみると… ロボットが動きませんでした。  

「自分の設定ミスか、コードの理解が足りていないのかもしれない」と思い、デバッグを進めたのですが、結局動きませんでした。

この記事では、どのようにデバックし、何が分かったのかを記載しておきます。  
私と同じようにunitree_mujoco上でジョイスティックで Unitree Go2 を動かしたいと考えている方の参考になれば幸いです。

# 2. README の記述と実際の動作
unitree_mujoco の README には、`simulate_python/config.py` の `USE_JOYSTICK` を `1` に設定すれば、**ジョイスティックで Unitree Go2 を制御できる** かのような記述があります。

**README の該当部分（抜粋）：**
```python
USE_JOYSTICK = 1  # Simulate Unitree WirelessController using a gamepad
JOYSTICK_TYPE = "xbox"  # support "xbox" and "switch" gamepad layout
```

## 3．検証手順
手順としては、色々と試しましたが、最終的には以下のように進めました。

1. `simulate_python/config.py` にて `USE_JOYSTICK = 1` を設定
2. デバックのため `unitree_sdk2py_bridge.py` に 以下のprint文を追加
`unitree_sdk2py_bridge.py` の `PublishWirelessController()` に以下の `print()` を追加しました。

```python:unitree_sdk2py_bridge.pyの一部
def PublishWirelessController(self):
    if self.joystick is not None:
        pygame.event.get()
        
        self.wireless_controller.lx = self.joystick.get_axis(self.axis_id["LX"])
        self.wireless_controller.ly = -self.joystick.get_axis(self.axis_id["LY"])
        self.wireless_controller.rx = self.joystick.get_axis(self.axis_id["RX"])
        self.wireless_controller.ry = -self.joystick.get_axis(self.axis_id["RY"])

        # ここでジョイスティックの値を出力
        print(f"Joystick State:")
        print(f"  LX: {self.wireless_controller.lx:.2f}, LY: {self.wireless_controller.ly:.2f}")
        print(f"  RX: {self.wireless_controller.rx:.2f}, RY: {self.wireless_controller.ry:.2f}")
```
3.　ジョイスティック(xbox)を操作する。
ジョイスティック(純正品のxboxのコントローラー)を操作するとログは以下のようになり、ジョイスティックの入力は正しく取得できていることが分かりました。

```terminal:操作したとき
Joystick State:
  LX: 0.00, LY: 1.00
  RX: 0.00, RY: 0.00
  Keys: 0b0
```

```terminal:操作をしないとき
Joystick State:
  LX: 0.00, LY: 0.00
  RX: 0.00, RY: 0.00
  Keys: 0b0
```

**しかしながら、Unitree go2は動きませんでした**


## 4. まとめ
### 何が問題だったのか？
コードを調べたところ、ジョイスティックの入力は `PublishWirelessController()` で **`rt/wireless_controller`** に送信されるだけであり、実際のロボットの制御に必要な **`LowCmd` には適用されていないようである** ということが分かりました。

### **つまり、現在の実装では、以下のようになっていると考えられます。**
- ✅ **ジョイスティックの入力は取得できる**
- ❌ **ロボットを動かす命令には適用されていない**

また、このリポジトリの[Issue #10](https://github.com/unitreerobotics/unitree_mujoco/issues/10) でも、同じような問題を指摘する報告がありました。  
また「ジョイスティックでUnitree Mujoco上でUnitree Go2を動かせた」という事例も私は見つけられませんでした。

### README の記述を誤解していた？
ここで改めて README を見直してみると、  「Mujoco上でジョイスティックで Unitree Go2 を動かせる」 とは **明確には書かれていない** ことに気づきました。

### 学んだこと
- 現状のunitree_mujocoではジョイスティックの入力は取得できるが、Unitree Go2 はデフォルトの設定では動かない
- README の記述は、直接 Mujoco上のUnitree Go2 を動かせるとは書かれていない
- 「設定を変えれば動くはず」と思い込んでいたが、実際の仕様をよく理解する必要があった

### 今後の対応  
もし「ジョイスティックで Unitree Go2 を操作したい」場合は、**独自に `LowCmd` を送る処理を追加するプログラム**を作成する 必要がありそうです。

今後のアップデートで公式対応されるのかどうかは分かりませんが、  引き続き情報を追いながら、何か進展があればまた報告したいと思います。