UnityでROS2用スマホコントローラを作る

※今回の記事はほとんど下の記事の再現です。偉大な先人に感謝。
https://qiita.com/Kotakku/items/cdc3eca89dd8aec4ee86


　今回はAndroidとROS2を通信させてスマホコントローラーを作成する。なお，UnityはUbuntu22.04に対応していないため，大人しくWindowsにインストールすること。
　それぞれのバージョンは以下の通り。
 - Windows11
 - Unity 2021.3.25f1
 - Ubuntu22.04
 - ROS2 Humble

　それぞれの導入については簡単なので省略する。

# 大まかな解説
　最近はTelloなどの市販品に限らず，ロボコンなどでもスマホでロボットを操作する事例をよく見かける。遅延はどうなってるの？とか，コントローラーで良くね？とか，色々消極的な意見はあるだろうが，やはりスマホからロボットを操作しているとなんとなくカッコよく見えるのは確かだ。
　そんなわけでスマホをコントローラーとして用いようと思った時に，最も簡単と思われるのがUnityとROS２を用いるやり方だ。この方法では[ros2-for-unity](https://github.com/RobotecAI/ros2-for-unity)という，ネイティブでUnityとROS2を通信させるライブラリを利用する。[こちらの記事](https://zenn.dev/hakuturu583/articles/ros2_for_unity)によるとこのライブラリは他のものと比べて高速で通信できるらしい。
>ros2-for-unityは[Robotec.ai](https://robotec.ai/)によって開発されたUnityとROS2間の通信を行うライブラリです。  
ROS2 C#クライアントライブラリをネイティブライブラリとしてUnity Projectに取り込み、DDSのプロトコルで他のROS2アプリケーションと通信します。  
OSはWindowsとUbuntuをサポートしています。  
無駄な変換が一切挟まっていないため、これより早いプロセス間通信の方法は存在しないと言えます。

　`OSはWindowsとUbuntuをサポートしています`という部分を読んで「ならAndroidでは使えないじゃん！」と思った人がいるかもしれないが，Androidに対応するためのパッケージを有志が公開しているので問題ない。
　また，Unityを利用する事でUI開発が容易になるなどのメリットもある。便利なツールはどんどん使って開発を効率化していこう。
# 準備
Unityで開発を始めるための準備を行う。
### パッケージのダウンロード
[こちら](https://github.com/RobotecAI/ros2-for-unity/releases)からros2-for-unityのビルド済みソースコードをダウンロードする。
<img width="675.75" alt="image.png (60.9 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/1e43f7fe-018d-4aa5-84e8-0d0be7ab4697.png">

今回の例ではROS2がインストールされていないWindows上での利用が想定されるので，`Ros2ForUnity_humble_standalone_windows11.zip`をダウンロードする。
次に[こちら](https://github.com/Kotakku/ros2-for-unity-android-package)からros2-for-unity-android-packageをダウンロードする。これはros2-for-unityをAndroidでも使えるようにしたパッケージだ。
<img width="624.75" alt="image.png (62.5 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/cf582236-c1db-445a-b476-baa541e37be7.png">

ダウンロードした２つのファイルを適当に解凍しておく。
### プロジェクトの作成
Unity Hubを開く。
日本語の方が良いという人は左上の歯車マークをクリックして`Appearance`>`Language`>`日本語`とする。
右上の`新しいプロジェクト`を選択してテンプレートとして`2D Mobile`を選択する（恐らく初回はテンプレートのダウンロードが求めらられる）。
<img width="1440" alt="image.png (113.3 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/3d0b3cc8-07ed-4982-868f-d658987b0ec4.png">

プロジェクト名と保存場所を指定し，`プロジェクト作成`をクリックする。
なお，今回はプロジェクト名を`Android Controller`とした。
### パッケージの導入
Unityのウィンドウが開く。日本語にしたい人は左上から`Edit`>`Preferences...`>`Languages`>`Editor language`>`日本語(Experimental)`とすれば良い。

先ほどダウンロードしたパッケージを導入する。
プロジェクトウィンドウ上で右クリックをすると以下の画像のように表示が出てくるので，`パッケージをインポート`>`カスタムパッケージ...`をクリックする。
<img width="956.25" alt="image.png (62.8 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/fe297c70-f648-4cc9-8f47-aa5a097969b9.png">

先ほど解凍した`ros2-for-unity-android-package`の中にある`Ros2ForUnityAndroid.unitypackage`を選択し，開く。
すると下の画像のようなポップアップが出てくるので，そのまま`インポート`を選択する。
<img width="263.25" alt="image.png (30.0 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/63a78d1a-299b-427f-abb7-a4d30c677a1e.png">

プロジェクトウィンドウに`Ros2ForUnity`というフォルダが追加されているのが確認できると思う。
<img width="435" alt="image.png (9.0 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/d0fe8c50-0e79-403d-bc14-6c756115ae5c.png">

`Ros2ForUnity`>`Plugins`と開くと`Android`というフォルダがあるので，その上で右クリックをして`エクスプローラーで表示`をクリックする。
<img width="765" alt="image.png (65.5 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/e03f543c-2755-41f0-ae3d-0343b181ba1f.png">

エクスプローラーをもう一つ開いて先ほど解凍したもう一つのフォルダ(Ros2ForUnity)を開く。`Ros2ForUnity`>`Plugins`と開くと，中に`Windows`というフォルダがあるので，それを先ほど開いた別のエクスプローラーのウィンドウにコピペする。
<img width="807.75" alt="image.png (155.8 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/d8cc42d3-7a56-4cd6-b35f-d357f9586c0c.png">

Unityの画面をクリックすると自動的にインポートが行われる。
### 諸々の設定
次のステップで`Input System Package`というパッケージを利用したいのでその設定を行う。
`ウィンドウ`>`パッケージマネージャー`を開く。
<img width="807" alt="image.png (42.2 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/919b0bac-aea1-4343-b773-7caa093b7d4d.png">

出てきたウィンドウの左上の`パッケージ:プロジェクト内`となっている部分をクリックし，`Unityレジストリ`に変更する。
<img width="604.5" alt="image.png (62.9 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/f9108cf6-2f78-434c-8657-85b9b6a89efb.png">

右上の検索欄に`Input`と入力すると`Input System`というパッケージが表示されるので，それをインストールする。
<img width="598.5" alt="image.png (41.3 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/658e2fac-9664-4100-be23-eba9bd721d18.png">

画像のような表示が出てくるので`Yes`を選択してUnityを再起動する。
<img width="293.25" alt="image.png (9.3 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/178c7f7b-dd8a-499a-9e53-d79d99c4f387.png">

次にInput System Packageをアクティブにする。
左上のメニューから`編集`>`プロジェクト設定...`と開き，`プレイヤー`>`Windows, Mac, Linuxの設定`>`その他の設定`を開く。
<img width="657" alt="image.png (71.6 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/fcf03c4f-d0de-40cd-b1ec-173919fdaa76.png">

`その他の設定`>`設定`>`アクティブな入力処理*`>`入力システムパッケージ(新)`とする。
<img width="457.5" alt="image.png (25.9 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/abde69a2-b113-447a-b138-2d2ba9bc00bd.png">

ポップアップが出てくるので`Apply`を選択してUnityを再起動する。
<img width="292.5" alt="image.png (6.2 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/1705e468-453e-41a1-b820-820ac3e4ffe3.png">

# Unityでの作業
### Buttonを作成する
コントローラーのボタンの代替となるようなものを作る。
ヒエラルキーウィンドウ上で右クリックし，`UI`>`ボタン-TextMeshPro`と選択。
<img width="505.5" alt="image.png (65.6 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/cd562df9-a692-4ab1-891c-057cc26329be.png">

このような表示が出てきたら`Import TMP Essentials`を選択しておく。
<img width="484.5" alt="image.png (27.4 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/7aaf2010-4e6f-4ce0-b0f3-a605297a7784.png">

必要であればヒエラルキーウィンドウから`Button`>`Text(TMP)`の不可視マークを外しておく。
<img width="367.5" alt="image.png (13.4 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/74d793f4-5024-42c8-b288-33279d7a0a4e.png">

同じくヒエラルキーウィンドウの`Canvas`をダブルクリックすると，シーンビューがUIサイズに調整されるので，Buttonのオブジェクトをいい感じのサイズに調整しておく。
<img width="1104.75" alt="image.png (24.1 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/4cb0d225-7855-4ff8-b54f-8ff32e751665.png">

ヒエラルキーウィンドウで`Text(TMP)`を選択すると，右側のインスペクターウィンドウに`Text(TMP)`の情報が表示される。
`TextMeshPro-Text(UI)`>`Text Input`にある文字列を変更しておく。
<img width="451.5" alt="image.png (37.5 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/2d854bd3-acae-48f5-bf57-15cc83779eac.png">

今回は`Say Hello`とした。その下の`Main Setting`では文字の色やサイズが変更できるので気になる人は触ってみるといいだろう。

次に`Button`にアタッチするC#スクリプトを作成する。
プロジェクトウィンドウ上で右クリックし，`作成`>`C#スクリプト`とする。
<img width="697.5" alt="image.png (76.2 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/26/142382/b4a4c2f7-d441-4ad8-baac-26e5702cc2fe.png">

今回はファイル名を`HelloButton`とした。作成したC#ファイルをダブルクリックすると，VisualStudioが開くのでそこに以下のコードを貼り付ける。
```cs
using UnityEngine;
using ROS2;
using UnityEngine.UI;

public class HelloButton : MonoBehaviour
{
    private ROS2UnityComponent ros2Unity;
    private ROS2Node ros2Node;
    private IPublisher<std_msgs.msg.String> chatter_pub;
    private int i = 0;
    // ボタンの参照
    [SerializeField] private Button button;
    // シーン読み込み時に呼び出される関数
    void Start()
    {
        TryGetComponent(out ros2Unity);
        // onClickに関数を登録
        button.onClick.AddListener(OnButton);
    }

    // フレーム更新時に呼び出される関数
    void Update()
    {
        if (ros2Unity.Ok())
        {
            if (ros2Node == null)
            {
                // Nodeの名前を指定する
                ros2Node = ros2Unity.CreateNode("ROS2UnityTalkerNode");
                //トピックの名前と型を指定する
                chatter_pub = ros2Node.CreatePublisher<std_msgs.msg.String>("hello_from_Unity");
            }
        }
    }

    // ボタンが押されたときに呼び出される関数
    void OnButton()
    {
        i++;
        std_msgs.msg.String msg = new std_msgs.msg.String();
        msg.Data = "Hello world from Unity" + i;
        chatter_pub.Publish(msg);
    }
}
```
ちなみにUnityではファイル名とclass名が同じでないとエラーが出るのでコピペする際には注意する事。

今作成したHelloButton.csと/Ros2ForUnity/Scripts/ROS2UnityComponent.csをヒエラルキーウィンドウの`Button`にドラッグ＆ドロップしてアタッチする。
インスペクターウィンドウで画像のように表示されていればアタッチできている。
<img width="450.75" alt="image.png (88.8 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/95e26af4-e7a6-44de-a8d1-aa4ca8c92116.png">

インスペクターの`Hello Button(スクリプト)`>`ボタン`の⦿をクリックしてButtonオブジェクトを割り当てる。
<img width="447.75" alt="image.png (19.9 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/b94c49ea-40ee-4641-a3a7-ab0c2b59e4ec.png">
これをしないとボタンを押しても何も起こらないので注意。

### JoyStickを作成する
コントローラーのJoyStickの代替となるようなものを作る。
先ほどと同様にヒエラルキーウィンドウ上で右クリックし，`UI`>`画像`と選択。Imageでは分かりにくいので名前をJoyStickに変更しておく。
インスペクターウィンドウから`Image`>`ソース画像`の右側の⦿をクリックし，出てきたポップアップから好きな画像を選ぶ。今回は`Knob`という白い円の画像を選んだ。
<img width="454.5" alt="image.png (54.2 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/de67b0bc-a4af-4968-bfe8-7377f0a10416.png">

さらにインスペクターの下部にある`コンポーネントを追加`から`On-Screen Stick`を追加する。
<img width="456.75" alt="image.png (20.8 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/a5d86afa-ecec-437c-9b12-eb1b9a5e4c89.png">

追加された`On-Screen Stick`の設定を以下の画像のように変更する。
<img width="454.5" alt="image.png (12.4 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/37f2a92f-8079-4be0-b2bc-ad33568a7218.png">
`Movement Range`はジョイスティックの動き回る範囲であり，小さすぎると操作しずらいので値を増やしておく。

シーンビューからJoyStickのサイズや位置を調整しておく。
<img width="679.5" alt="image.png (12.2 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/116619d7-5a5a-4c1b-bd6f-862fa2366ab8.png">

次に`JoyStick`にアタッチするC#スクリプトを先ほどと同様の手順で作成する。今回はファイル名を`JoyController`とした。
ファイルを開いて以下のコードをコピペする。
```cs
using UnityEngine;
using UnityEngine.InputSystem;
using ROS2;

public class JoyController : MonoBehaviour
{
    private ROS2UnityComponent ros2Unity;
    private ROS2Node ros2Node;
    private IPublisher<geometry_msgs.msg.Twist> twist_pub;
    // シーン読み込み時に呼び出される関数
    void Start()
    {
        TryGetComponent(out ros2Unity);
    }

    // フレーム更新時に呼び出される関数
    void Update()
    {
        if (ros2Unity.Ok())
        {
            if (ros2Node == null)
            {
                // Nodeの名前を指定する
                ros2Node = ros2Unity.CreateNode("UnityJoyNode");
                // トピックの名前と型を指定する
                twist_pub = ros2Node.CreatePublisher<geometry_msgs.msg.Twist>("/turtle1/cmd_vel");
            }
            geometry_msgs.msg.Twist msg = new geometry_msgs.msg.Twist();
            var current = Gamepad.current;
            var input_vec = current.leftStick.ReadValue();
            msg.Linear.X = input_vec.x;
            msg.Linear.Y = input_vec.y;
            twist_pub.Publish(msg);
        }
    }
}
```  
turtlesimを動かしたいのでこのようなコードになっている。

先ほどと同様に，今作成したJoyController.csと/Ros2ForUnity/Scripts/ROS2UnityComponent.csをヒエラルキーウィンドウの`JoyStick`にドラッグ＆ドロップしてアタッチする。

### その他必要な作業
 - ROS_DOMAIN_IDの設定
　これまでの実装では特にROS_DOMAIN_IDを設定してこなかったが，実際に使う場合は必ずIDを設定する必要がある。また，ROS_DOMAIN_IDはROS2UnityComponent.csの実行よりも先に設定される必要があるため，その設定を行う。
※ROS_DOMAIN_IDは例として`123`としているが，適宜自分の環境のものに置き換えること。

先ずは，プロジェクトウィンドウ上で右クリックをして`SetID`という名前のC#スクリプトを作成し，そこに以下のコードをコピペする。
```cs
using System;
using UnityEngine;

public class SetID : MonoBehaviour
{
    void Start()
    {
        // 現在設定されているIDを調べる
        string value = Environment.GetEnvironmentVariable("ROS_DOMAIN_ID");
        Debug.Log("current ROS_DOMAIN_ID:" + value + "\n");
        // ROS_DOMAIN_IDに123を設定する
        Environment.SetEnvironmentVariable("ROS_DOMAIN_ID", "123");
        Debug.Log("DOMAIN_ID set OK\n");
        // 上手く設定できているか確認する
        value = Environment.GetEnvironmentVariable("ROS_DOMAIN_ID");
        Debug.Log("current ROS_DOMAIN_ID:" + value + "\n");
    }
}
```
作成したスクリプトを適当な空のオブジェクトに貼り付けて実行されるようにする。
ヒエラルキーウィンドウ上で右クリックをして`空のオブジェクトを作成`を選択し，分かりやすくするためオブジェクトに`SetID_Object`という名前を付けた。
<img width="366" alt="image.png (41.3 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/31/142382/8be0e507-0796-4dfb-a061-96538fcbda62.png">

先ほど作成した`SetID.cs`をプロジェクトウィンドウからヒエラルキーウィンドウ上の`SetID_Object`へドラッグ＆ドロップしてスクリプトをアタッチする。
上手くいっていれば`SetID_Object`のインスペクターが画像のようになる。
<img width="453" alt="image.png (22.3 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/31/142382/80bcddaf-93b3-48cd-b96b-362ae16d085c.png">



次にメニューから`編集`>` プロジェクト設定...`>`スクリプト実行順序`と開き，右下の`+`から`SetID`を追加する。
<img width="639.75" alt="image.png (55.9 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/31/142382/fa991922-7e80-481d-bf8b-1372a223e0a9.png">

`SetID`の右側の欄に`-1`と入力し，`Apply`をクリックすれば`SetID`は通常のスクリプトよりも早く実行されるようになる。
<img width="486" alt="image.png (41.1 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/31/142382/272cb00f-f62a-4af1-b226-a7b8a78237a9.png">


 - Input System Packageの準備の続き
ヒエラルキーウィンドウから`EventSystem`を選択し，インスペクターウィンドウで`Standalone Input Module`の`Replace with InputSystemUIInputModule`をクリックする。
<img width="452.25" alt="image.png (64.0 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/afa53445-2cb5-4331-8952-57c5c14f8fcb.png">

以上で`Input System Package`を使う準備ができた。

# ビルド＆インストール
### ビルドの実行
今作ったゲーム？を実際にアプリとしてビルドしていく。
`ファイル`>`ビルド設定`を開く。
<img width="430.5" alt="image.png (33.4 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/02885737-4953-44ed-80b6-e6665d79ecdf.png">

下の画像のようなウィンドウが出てくるので，プラットフォームにAndoridを選択して`プレイヤー設定...`を開く。
<img width="483" alt="image.png (69.0 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/bf2625fe-7ffb-4747-99f3-4924b10683d1.png">
※Androidが選択できない人はUnity HubからAndroid Bulid Supportをインストールすること。

`解像度と表示`>`自動回転を許可する向き`を`横向き(右)`と`横向き(左)`だけにする。
<img width="463.5" alt="image.png (48.5 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/44be7679-4d64-4c6a-9e22-e76f11103747.png">

`その他の設定`>`設定`>`スクリプティングバックエンド`をMonoからIL2CPPに変更し，その下の`ターゲットアーキテクチャ`のARM64にチェックを入れる。さらに`インターネットアクセス`を`必須`に変更する。
<img width="455.25" alt="image.png (40.1 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/c7a24c58-d3f5-48f4-b3dc-67524d2bb677.png">

Project Settingsを閉じてBuild Settingに戻り，ウィンドウ右下の`ターゲット切り替え`をクリックする。
すると下の画像のような画面になるので`ビルド`を選択する。
<img width="482.25" alt="image.png (68.4 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/ddb939c8-e2da-4924-b60d-f7b00fd8532f.png">

ファイル名と保存場所を聞かれるので適当に決める。しばらく時間がかかるので気長に待つこと。

### Androidへのインストール
先ほど作成したapkファイルをAndroidにインストールする。以下の操作はスマホによって微妙に異なると思われるのであくまでも一例。

Androidの設定アプリを開き，`デバイス情報`>`ビルド番号`を連打して開発者向けオプションを有効化する。
`システム`>`開発者オプション`>`デバッグ`からUSBデバッグを有効にする。
<img width="540" alt="image.png (157.4 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/38cc40e3-12fb-47e2-9e9a-3c7d831e770b.png">

スマホをPCにUSB接続し，先ほど作成したapkファイルをスマホの適当なフォルダにコピペする。
スマホ側で適当なファイルアプリでapkファイルを探してタップすると画像のような表示が出てくるので，そのままインストールする。いろいろ警告が出てくるかもしれないが全て無視すれば良い。
<img width="540" alt="image.png (71.8 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/1a87cc6a-7124-4aee-8bb9-5e40db15ee77.png">

インストールできた。
<img width="1080" alt="image.png (514.2 kB)" src="https://img.esa.io/uploads/production/attachments/19744/2023/05/27/142382/6c1c0969-1617-43bf-8176-9b00cc2afacf.png">

# テスト
スマホ側で先ほどインストールしたアプリを起動する。
Ubuntu22.04を起動し，スマホと同じWiFi(テザリングでも良い)に接続していることを確認してから，ターミナルに以下のコマンドを打ち込む。
```
$ ros2 topic list
```
このように表示されていればうまくいっている。
```
/hello_from_Unity
/parameter_events
/rosout
/turtle1/cmd_vel
```
次に以下のコマンドをそれぞれ別のターミナルで実行する。
```
$ ros2 run turtlesim turtlesim_node
$ ros2 topic echo /hello_from_Unity
```
スマホ側のボタンを押すとメッセージが，joystickを操作すると亀が動くはずだ。
[![ros2 Android controller](https://img.youtube.com/vi/hqI5gseNL6U/0.jpg)](https://www.youtube.com/watch?v=hqI5gseNL6U)
※動画に飛びます

# 終わり
ROS_DOMAIN_IDの設定にかなり手こずってしまったが，なにはともあれ憧れのスマホコントローラーができた。今回はボタンとjoystickというコントローラーの基礎的な要素のみの実装だったが，これを応用すれば素晴らしいオリジナルUIを作成できるのではないだろうか。

### 参考文献
[入力システムパッケージ (Input System Package) を導入する](https://sorceryforce.net/ja/tips/unity-input-input-system-package)
[ros2-for-unity-android-package](https://github.com/Kotakku/ros2-for-unity-android-package)
[AndroidをROS2ノードにしてロボットのコントローラを作る](https://qiita.com/Kotakku/items/cdc3eca89dd8aec4ee86)
[ROS2 for Unityで始めるUnityとROS2間の高速データ通信](https://zenn.dev/hakuturu583/articles/ros2_for_unity)