ArticulationBodyのパラメータにアクセスする


<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/a41cd967-f549-8677-1efa-2e99bf69518d.png" align="top" /> UnityとC#の基本がわかっていなかった...

Unityのバージョン2020.1以降、ArticulationBodyというメカ好きには嬉しい機能が実装されました。
ArticulationBodyはコンポーネントの一つで、多関節のロボットのジョイントを崩壊することなく表現することができます。また、URDFファイルをURDF-Importerでインポートした場合にもこのコンポーネントが自動的に付与されます。

基本的な機能については以下のnoteが大変参考になります。

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

今回はこのArticulationBodyのパラメータにスクリプトからアクセスする際のコツを自分用にまとめてみました。


# ArticulationBodyのパラメータへのアクセス
自分はそもそもプログラミング全般の知識が浅いので、クラスや構造体へのアクセスが苦手です。
インスタンス名にドットで区切ってアクセスできるものならなんとかなるのですが、それ以上の使い方となるとよくわからなくなります。

いくつか実際に試すことでパターンを理解していきます。

## Targetへのアクセス(xDrive)
ArticulationBodyの移動目標の値はxDriveのTargetというパラメータに格納されています。
まずここにアクセスしてコードから値を書き換えてみます。

ArticulationBodyに値を直接代入しようとしてもうまくいかないそうです。
値を代入するにはArticulationBodyの要素の一つであるArticulationDriveクラスのインスタンスを一度立て、そこに値を代入した上でArticulationBodyに代入するという手順が必要なようです。
具体的には下記のようにします。
Unity用のC#スクリプトについて、void Start(){} 前後のコードを抜き出しています。

```c#:例1
    private ArticulationBody[] bodies;//コンポーネントを入れておく配列
    public GameObject target_urdf;//ターゲットとなるオブジェクトを格納する変数

    void Start()    {
        //起動時にターゲットオブジェクトの全ArticulationBodyコンポーネントを取得
        bodies = target_urdf.GetComponentsInChildren<ArticulationBody>(true);
        //各ArticulationBodyのxDriveターゲット値に30度を代入する
        foreach (var body in bodies)
        {
            // 回転関節のみ対象とする
            if ((body.jointType == ArticulationJointType.RevoluteJoint))
            {
                ArticulationDrive tmpDrive = body.xDrive; //変数格納用のインスタンスを準備
                tmpDrive.target = 30 * Mathf.Deg2Rad; //インスタンスにラジアン換算した30度を代入
                body.xDrive = tmpDrive; //上記をArticulationBodyのパラメータとして設定
            }
        }
    }
```



上記の例では、ArticulationDriveの型を宣言する際、取得したArticulationBodyインスタンスのデータごとコピーして作成しています。こうすることで、パラメータを変更してArticulationBodyに代入するときに、該当のデータ以外を元の状態にキープしておくことができます。

## jointPositionへのアクセス(ArticulationReducedSpace)
さきほどのxDrive.targetは、関節のトルクやスピードなどを加味した状態で、アクチュエーターにその目標位置まで移動してもらうという命令でした。
目標位置にただ移動させたい、位置を取得したいという場合には、.jointPositionというパラメータにアクセスします。
ただし、このパラメータはArticulationBodyの中にあるArticulationReducedSpaceに入っています。
xDriveの時と同じく、型となる変数を別途作成し、そこに数値を代入したのちに、型ごとArticulationBodyに代入する必要があるようです。


```c#:例2
    private ArticulationBody[] bodies;//コンポーネントを入れておく配列
    public GameObject target_urdf;//ターゲットとなるオブジェクトを格納する変数

    void Start()    {
        //起動時にターゲットオブジェクトの全ArticulationBodyコンポーネントを取得
        bodies = target_urdf.GetComponentsInChildren<ArticulationBody>(true);
        //各ArticulationBodyのxDriveターゲット値に30度を代入する
        foreach (var body in bodies)
        {
            // 回転関節のみ対象とする
            if ((body.jointType == ArticulationJointType.RevoluteJoint))
            {
                // 関節角度（jointPosition）を直接指定するテスト
                ArticulationReducedSpace tmpBody = body.jointPosition; // 変数用のインスタンス
                tmpBody[0] = 30 * Mathf.Deg2Rad; //インスタンスにラジアン換算した30度を代入
                body.jointPosition = tmpBody;//上記をArticulationBodyのパラメータとして設定
            }
        }
    }
```

## パラメータ変更のパターンがわかってきた

ArticulationBodyの内容を変更するには、パラメータを適切な型に入れてから代入する、というのがパターンになります。

そもそもUnityでパラメータを扱う時の基本中の基本のような気がしますが、これまではせいぜいVector3に入れて代入するとかだけだったのでこのパターンに気づきませんでした...

このパターンでいけばコンポーネントのいろいろな値にアクセスできるようになると思います。

## 書き換えたいパラメータが型のどの場所にあるかを調べるには？

公式サイトのマニュアルでコンポーネントについての型の内容を確認できます。
ArticulationBodyについても、一覧表が掲載されています。

https://docs.unity3d.com/ja/2020.2/ScriptReference/ArticulationBody.html

例えば、上記サイトで「anchorPosition」をクリックすると、遷移後のページの上部に
> **ArticulationBody.anchorPosition**　  
> public Vector3 anchorPosition ;

と表示されます。
これはVector3の型を作ってデータを代入すれば、そのVector3をanchorPositionに代入できるということを示しているようです。

これでUnityのパラメータを扱いやすくなったはず...です。

### 謝辞

https://github.com/kirurobo/Roid1_Simple

いろいろと教えていただきました！ありがとうございました。

### 参考
https://docs.unity3d.com/ja/2020.3/Manual/class-ArticulationBody.html

### 関連記事

https://qiita.com/Ninagawa_Izumi/items/b24ceee29755e09b4d73