MyoSuite Tutorial No.2

# はじめに
本記事は以下の人を対象としています．

- 筋骨格シミュレータに興味がある人
- MuJoCoに興味がある人

:::note warn
本記事では[2_Load_policy.ipynb](https://github.com/MyoHub/myosuite/blob/main/docs/source/tutorials/2_Load_policy.ipynb)をGoogle Colabで実行した際の手順と結果に関してまとめる．
:::

# MyoSuiteとは

https://sites.google.com/view/myosuite

MuJoCoを学習モジュールとして組み込んだ筋骨格シミュレータ

:::note info
2024年にICRAにてworkshopを展開
https://sites.google.com/view/myosuite/myosymposium/icra24
:::

# Tutorial Notebook

https://github.com/MyoHub/myosuite/tree/main/docs/source/tutorials

# 実施事項
Tutorialに記載のコードを1つずつ試して, Errorになったところは都度修正版を記載する.

## ライブラリのinstallと環境設定

```bash
!pip install -U myosuite
# mjrlとgym==0.13のinstall
!pip install tabulate matplotlib torch gym==0.13 git+https://github.com/aravindr93/mjrl.git@pvr_beta_1vk
%env MUJOCO_GL=egl
```

:::note warn
環境変数MUJOCO_GL=eglを設定しないとmujoco.FatalError: gladLoadGL errorが出る.
https://github.com/Farama-Foundation/Gymnasium/issues/501#issuecomment-1730755393
:::

## ライブラリのimportと結果表示の関数

```python
from myosuite.utils import gym # importが上手くいくと"MyoSuite:> Registering Myo Envs"と表示される
import skvideo.io
import numpy as np
import os

from IPython.display import HTML
from base64 import b64encode

def show_video(video_path, video_width = 400):

  video_file = open(video_path, "r+b").read()

  video_url = f"data:video/mp4;base64,{b64encode(video_file).decode()}"
  return HTML(f"""<video autoplay width={video_width} controls><source src="{video_url}"></video>""")
```
詳細はこちらを参照

https://qiita.com/Mittag-tech/items/7d1cfb97c58547ccdfbf#%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%81%AEimport%E3%81%A8%E7%B5%90%E6%9E%9C%E8%A1%A8%E7%A4%BA%E3%81%AE%E9%96%A2%E6%95%B0

## policyの読み込み

:::note info
必要となるpickleファイルを用意するために、MyoSuiteのレポジトリを同じディレクトリ階層にclone
:::

```python
pth = 'myosuite/myosuite/agents/baslines_NPG/'

policy = pth+"myoElbowPose1D6MExoRandom-v0/2022-02-26_21-16-27/36_env=myoElbowPose1D6MExoRandom-v0,seed=1/iterations/best_policy.pickle"

import pickle
pi = pickle.load(open(policy, 'rb'))
```

## modelのloadとpolicyの結果確認

```python
env = gym.make('myoElbowPose1D6MExoRandom-v0')
# define a discrete sequence of positions to test
AngleSequence = [60, 30, 30, 60, 80, 80, 60, 30, 80, 30, 80, 60]
env.reset()
frames = []
for ep in range(len(AngleSequence)):
    print("Ep {} of {} testing angle {}".format(ep, len(AngleSequence), AngleSequence[ep]))
    env.unwrapped.target_jnt_value = [np.deg2rad(AngleSequence[int(ep)])]
    env.unwrapped.target_type = 'fixed'
    env.unwrapped.weight_range=(0,0)
    env.unwrapped.update_target()
    for _ in range(40):
        frame = env.sim.renderer.render_offscreen(
                        width=400,
                        height=400,
                        camera_id=0)
        frames.append(frame)
        o = env.get_obs() # observation
        a = pi.get_action(o)[0] # action
        next_o, r, done, *_, ifo = env.step(a) # take an action based on the current observation
env.close()

os.makedirs('videos', exist_ok=True)
# make a local copy
skvideo.io.vwrite('videos/exo_arm.mp4', np.asarray(frames),outputdict={"-pix_fmt": "yuv420p"})
show_video('videos/exo_arm.mp4')
```

出力結果(GIFにしているので連続だが実際は19秒ほど)
![2_load_policy-demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043769/c3d7cd66-d005-b877-f81a-3ef24514abfb.gif)

# 何をやっているのか

- 腕を伸ばした状態から```AngleSequence```で設定した分だけ腕を曲げた状態を目標状態に設定
- 1.6secごとに姿勢を変化、policyに従いactuator側にforceを生成

# 参考資料

https://github.com/MyoHub/myosuite/issues/92

https://note.com/npaka/n/nbbbd07464c85