UnityのロボットシミュレーションをOpenShiftで管理

## 概要
- 最適化され続ける分散制御の構想をシミュレーションで実験できる環境をつくりたかった
- 3DシミュレーションをUnity、ロボット制御をROS、コンテナオーケストレーションをOpenShift localで出来そうだったので、とりあえず全部組み合わせてデモが動くところまでやってみた
- 全体の構成は下図のイメージ
    - GithubからUnity公式のROS連携するロボットシミュレーションのリポジトリをとってくる
    - pick and placeのデモで使うDockerfileを少しアレンジして、コンテナイメージをビルド後、Docker Hubにpush
    - OpenShift local上でそのイメージを使ってROSを動かす
    - Unityでpick and placeのデモProjectを実行し、Port forwardingでOpenShiftで動くROSへアクセスできるようにした
![Overview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/5c0124a6-a148-708b-14ff-00113ed9e6dd.png)

## 実行環境
- Ubuntu 20.04
- Unity
    - Unity Hub 3.6.1
- RED HAT OPENSHIFT LOCAL 2.29

## 前提
- dockerをインストール済み
- Docker hubにログイン可能

## 構築手順
### OpenShift Local準備
1. RedHat Developer登録
    - [こちら](https://developers.redhat.com/login)から
    - すでに登録している場合はスキップ
1. インストーラー(crc-linux-amd64.tar.xz)ダウンロード
    - Red Hat Hybrid Cloud Consoleにアクセスし、[Clusters > Cluster Type > Local](https://console.redhat.com/openshift/create/local)とたどる
    - Download OpenShift Localをクリック
    - Pull secretは後で使う
    ![Screenshot from 2023-12-01 08-40-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/a398132d-41a8-aa3e-9905-5f5c2953d4db.png)


1. 解凍・インストール
    ```console
    $ cd ~/Downloads
    $ tar xvf crc-linux-amd64.tar.xz
    $ mkdir -p ~/bin
    $ cp ~/Downloads/crc-linux-*-amd64/crc ~/bin
    export PATH=$PATH:$HOME/bin
    echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc
    ```
1. crcコマンドの動作確認
    ```console
    $ crc version
    CRC version: 2.29.0+da5f55
    OpenShift version: 4.14.1
    Podman version: 4.4.4
    ```

1. OpenShift Localを起動
    - 下記のコマンドを実行
        ```console
        $ crc setup
        $ crc start
        ```
    - 下記のコマンドを実行し、2. のpull secretを貼り付ける
        ```console
        $ crc start -c 6 -m 14000

        ...
        略
        ...
        INFO Adding crc-admin and crc-developer contexts to kubeconfig... 
        Started the OpenShift cluster.
        
        The server is accessible via web console at:
          https://console-openshift-console.apps-crc.testing
        
        Log in as administrator:
          Username: kubeadmin
          Password: <password>
        
        Log in as user:
          Username: developer
          Password: developer
        
        Use the 'oc' command line interface:
          $ eval $(crc oc-env)
          $ oc login -u developer https://api.crc.testing:6443

        ```        
        - `-c`は使用するCPUコア数
        - `-m`は使用するMemory量 [MB]
1. [Webコンソール](https://oauth-openshift.apps-crc.testing)をブラウザで確認

### ROS2 Docker image準備
1. Unity-Robotics-Hubのリポジトリをclone
    ```console
    $ git clone https://github.com/Unity-Technologies/Unity-Robotics-Hub.git
    ```
1. ROSのイメージをビルド
    - pick_and_placeのディレクトリまで移動
        ```console
        $ cd Unity-Robotics-Hub/tutorials/pick_and_place
        ```
    - Unity-Robotics-Hub/tutorials/pick_and_place/docker/Dockerfileを下記のように修正
        ```Dockerfile
        FROM ros:melodic-ros-base
        
        RUN sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F42ED6FBAB17C654
        
        RUN sudo apt-get update && sudo apt-get install -y vim iputils-ping net-tools python-pip ros-melodic-robot-state-publisher ros-melodic-moveit ros-melodic-rosbridge-suite ros-melodic-joy ros-melodic-ros-control ros-melodic-ros-controllers ros-melodic-tf2-web-republisher dos2unix
        
        RUN sudo -H pip install rospkg jsonpickle
        
        ENV ROS_WORKSPACE=/catkin_ws
        
        # Copy each directory explicitly to avoid workspace cruft
        COPY ./ROS/src/moveit_msgs $ROS_WORKSPACE/src/moveit_msgs
        COPY ./ROS/src/niryo_moveit $ROS_WORKSPACE/src/niryo_moveit
        COPY ./ROS/src/niryo_one_ros $ROS_WORKSPACE/src/niryo_one_ros
        COPY ./ROS/src/niryo_one_urdf $ROS_WORKSPACE/src/niryo_one_urdf
        COPY ./ROS/src/ros_tcp_endpoint $ROS_WORKSPACE/src/ros_tcp_endpoint
        
        COPY ./docker/set-up-workspace /setup.sh
        COPY docker/tutorial /
        
        RUN /bin/bash -c "find $ROS_WORKSPACE -type f -print0 | xargs -0 dos2unix"
        
        RUN dos2unix /tutorial && dos2unix /setup.sh && chmod +x /setup.sh && /setup.sh && rm /setup.sh 
        
        WORKDIR $ROS_WORKSPACE
        
        # making sure the file modes are executable
        RUN chmod +x src/niryo_moveit/scripts/*.py
        
        CMD exec /bin/bash -c "roslaunch niryo_moveit part_3.launch" # 追記
        ENTRYPOINT ["/tutorial"]
        ```
    - Dockerイメージをビルド
        - `<docker-user>`の部分はDocker ID
            ```console
            $ docker build -t <docker-user>/pick-and-place:latest -f docker/Dockerfile .
            ```
        - ビルドされたことを確認
            ```console
            $ docker images | head -1 && docker images| grep pick
            REPOSITORY                   TAG    IMAGE ID    CREATED     SIZE
            <docker-user>/pick-and-place latest 95daa64a51b 12 mins ago 2.36GB
            ```
    - Docker hubにイメージをpush
        ```console
        $ docker login
        $ docker push <docker-user>/pick-and-place:latest
        ```
        
### ROSアプリ起動
1. OpenShiftのProjectを作成
    - [Webコンソール](https://oauth-openshift.apps-crc.testing)にアクセスし、ログイン
        - Username: developer
        - Password: developer
        ![Screenshot from 2023-12-21 12-33-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/17539775-84e5-c027-c6fe-2140880c20c4.png)
    - Create a new projectをクリックし、NameにProject名を設定してCreateをクリック
        ![Screenshot from 2023-12-01 12-37-23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/1e577359-a673-f8f1-127b-b1b667af0ff5.png)
1. Application、DeploymentをProjectに追加する
    - 左上のハンバーガーメニューをクリックし、Add+をクリック
    ![Screenshot from 2023-12-21 12-03-15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/de9cb103-82c4-7bf9-6d51-2f8b77105240.png)
    - Container imagesをクリック
    ![Screenshot from 2023-12-21 12-06-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/8d29cb0a-4e36-6207-4ec7-4d743ad0a69c.png)
    - ImageのImage name from external registryを選択した状態で、Docker hubにpushしたコンテナイメージを指定
        - Docker hubにイメージを上げた場合、`docker.io/<docker-user>/pick-and-place`という形式でイメージを指定する
        ![Screenshot from 2023-12-21 12-07-55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/daa44922-6ed4-131a-a2a0-0e79dd26607d.png)
        - その下のApplication（Application名）、Name（Deployment名）を入力（自動で入力されるので、問題なければそのままでよい）
        - Resource typeはDeploymentを選択
    - Advanced optionsのTarget portに10000を入力し、最下部のCreateをクリック
1. DeploymentのYAMLを修正
    - 左上のハンバーガーメニューをクリックし、Topologyをクリック
    - PodがErrorになっていることを確認
        - Container Creatingになっているときは待機
    ![Screenshot from 2023-12-21 12-37-25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/cc8ff63e-5bb2-a50f-d416-e25435b6accf.png)
    - TopologyからDeploymentを選択して（下図１）、Deployment名をクリック（下図２）
    ![Screenshot from 2023-12-21 12-38-11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/5471939c-bf98-c5ca-e36f-26cbeb08f65c.png)
    - YAMLタブをクリック
    ![Screenshot from 2023-12-21 12-42-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/68bce103-6e86-2ad3-7769-a4984d630c74.png)

    - 148行目のsecurityContextオプションを下記のように変更
        ```yaml:変更前
        ...
        securityContext: {}
        ...
        ```
        
        ```yaml:変更後
        ...
        securityContext: 
            runAsUser: 0
        ...
        ```
    - Updateをクリック
        - エラーが出る場合は、Reloadをした後、再度securityオプションを変更してUpdateをクリックする
1. defaultユーザーにprivileged権限を与える
    - ocコマンドを実行できるようにする
        ```bash
        $ eval $(crc oc-env)
        ```
    - 管理者でログインする
        ```bash
        $ oc login -u kubeadmin -p <password>
        ```
        - <password>は「OpenShift Local準備」の5.の後にコンソールに出力される（`Log in as administrator`の部分）
    - privilegedを与える
        ```bash
        $ oc adm policy add-scc-to-user privileged -z default
        clusterrole.rbac.authorization.k8s.io/system:openshift:scc:privileged added: "default"
        ```

1. TopologyからPodが正常にRunning状態になっていることを確認
![Screenshot from 2023-12-21 14-01-41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/54376f8b-8b5f-d391-8a00-1a2572bf4d49.png)


:::note warn
　4. はセキュリティ的に非常に危険な設定なため、本番運用のときどうするか考える必要あり
:::


### Portforwarding
1. ocコマンドを実行できるようにする
    ```bash
    $ eval $(crc oc-env)
    ```
1. Podの名前を確認
    ```bash
    $ oc get pod
    NAME                              READY   STATUS    RESTARTS   AGE
    pick-and-place-75f69d7b59-n276n   1/1     Running   0          13m
    ```
1. Portforwardingを設定
    - pod名は2.で確認したもの
    ```bash
    $ oc port-forward pick-and-place-75f69d7b59-n276n 10000:10000
    Forwarding from 127.0.0.1:10000 -> 10000
    Forwarding from [::1]:10000 -> 10000
    ```

### Unity準備
1. Unity Hubインストール
    - 下記のコマンドを実行
    ```bash
    $ wget -qO - https://hub.unity3d.com/linux/keys/public | gpg --dearmor | sudo tee /usr/share/keyrings/Unity_Technologies_ApS.gpg > /dev/null
    $ sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/Unity_Technologies_ApS.gpg] https://hub.unity3d.com/linux/repos/deb stable main" > /etc/apt/sources.list.d/unityhub.list'
    $ sudo apt update
    $ sudo apt-get install unityhub
    ```
1. Unityセットアップ
    - Unity Hubを開く
![Screenshot from 2023-11-25 08-18-35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/1292593d-71f0-3b51-7743-c8250bd8e064.png)
    - （アカウントがない場合は新規作成してから）ログイン
    - Unity Editorをインストール
    ![Screenshot from 2023-11-25 09-16-09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/ccc63f86-e154-27d1-e61f-d3ecfc322e47.png)
    - 左側メニューのProjectをクリックし、右上のManage licenseをクリック
    ![Screenshot from 2023-11-25 09-53-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/333bcc72-0572-6bdf-4856-95d60209bc9f.png)
    - Add Licenseをクリック、Add a new LicenseのモーダルでGet a free personal licenseをクリック
    ![Screenshot from 2023-11-25 09-57-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/143d5fe3-291c-e110-762d-bf27fc505710.png)
    - Agree and get ...をクリック
    ![Screenshot from 2023-11-25 09-57-26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/a1cf2d0b-1af1-e5f1-f228-248406f5ed39.png)
    - LicenseにPersonalのLicenseが追加されたことを確認
    ![Screenshot from 2023-11-25 09-58-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/21bf1737-85b8-9ddd-8c6d-37e25e3d4acc.png)

1. Projectを開く
    - 左のメニューでProjectを選択している状態で、上部Addボタンの右の▼をクリックし、Add project from diskをクリック
    ![Screenshot from 2023-12-21 13-15-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/09a83037-2f64-7601-c42f-7c198b5f4482.png)
    - 「ROS2 Docker image準備」の1.でcloneしてきたプロジェクトの、Unity-Robotics-Hub/tutorials/pick_and_place/PickAndPlaceProjectを指定する
    - 必要なUnityのバージョンをインストールするか聞かれたら、インストールする

1. Demo Sceneの実行
    - Demo Sceneを開き、上部の▶ボタンをクリック
    ![Screenshot from 2023-12-21 14-08-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/b4f7a18c-57e3-5398-d408-94e2d8c1a923.png)
    - 左上のTCP/IP通信の状態が青色になり、ロボットアームが動いたら成功！
    ![Screenshot from 2023-12-21 14-09-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109639/f039e75e-52e7-10a0-8a93-8c93e435ce72.png)


## 所感・気になること
- OpenShift勉強中のためとりあえず感がかなりありますが共有します
- トラブル集を[こちら](https://qiita.com/yoshi1006/items/dbec41097f87ae33f9a3)にまとめました
- すぐ思いつく改善点
    - Port forwardingを使わずに、NodeportとかをOpenShiftにDeployしたほうがいい
    - コンテナをroot権限で無理やり動かしているのでセキュリティ的よくない


## 参考
https://note.com/npaka/n/n61a86284039a

https://access.redhat.com/documentation/ja-jp/red_hat_openshift_local/2.2/html/getting_started_guide/introducing_gsg