Unity × ROS 2連携完全ガイド-試行錯誤の全記録
LOG28R2R2R2026/1/6

Unity × ROS 2連携完全ガイド-試行錯誤の全記録

Unity 6上のデジタルツイン(mechArm 270 M5)を、Mac上のROS 2(Humble)から遠隔操作するシステムの構築に成功しました。

※本プロジェクトの目的:実機「mechArm 270 M5」の制御を通じて、AIの判断をいかに物理的な動きへ変換するか。そのロボット制御の仕組みを理解するプロセスを記録・検証するものです。

Unity側の通信基盤:ROS TCP Connectorの導入

Unity画面-ROS Setting

まず、UnityとROSの橋渡し役となる公式パッケージを導入しました。

  • 手順: Package Managerから ROS TCP Connector をインストール。

  • 設定: Robotics ➔ ROS Settings を開き、通信ルールを決定。

最初の失敗:Protocolの不一致

  • 初期設定が「ROS1」になっていたため、ROS 2との通信が成立しませんでした。

  • 解決策: 明示的に「ROS2」へ切り替えることで解決。

Mac側のエンドポイント構築:ワークスペースの迷路

ROS 2側でUnityからのデータを受け取る窓口を作るプロセスです。

  • 手順: 専用ワークスペース unity_ws を作成し、ROS-TCP-Endpoint をビルド。

ビルドの壁:コマンド未検出

  • colcon build を実行した際、command not found: colcon エラーが発生。

  • 解決策: Conda環境(ros_env)に colcon をインストールし、環境をアクティベートすることで解決。

IPアドレスの疑問

サーバーが 0.0.0.0 で立ち上がり、Unityの設定 127.0.0.1 と食い違って見えた。

学び: 0.0.0.0 は「すべての接続を待つ」状態であり、自分自身の 127.0.0.1 からのアクセスも包含されるため問題ないという知見を得ました。

ロボットに「耳」を付ける:Subscriberの実装

通信がつながっても(HUDが青くなっても)、ロボットが命令を理解できなければ動きません。

課題: ROS 2のトピック /arm_joints を購読するスクリプトが必要。

スクリプト作成の三重苦

  • 名称エラー: クラス名にスペース(Joint State Subscriber)を入れてしまい、作成ボタンが押せない。

  • iCloudの罠: プロジェクトがiCloud同期フォルダにあったため、DirectoryNotFoundException で保存に失敗。

  • UIの変化: Unity 6ではC# ScriptがMonoBehaviour Scriptという名前に変わっていた。

  • 解決策: スペースを抜き、iCloudを避け、新しいメニューから JointStateSubscriber を作成。

6つの関節の「配線」

Unity画面-link1 〜 link6をElementに紐付け

プログラム(脳)と3Dモデル(体)を物理的に紐付ける作業です。

  • 設定: JointStateSubscriber の Joint Bodies 配列を「Size: 6」に設定。

  • 手順: Hierarchyから link1 〜 link6 を、InspectorのElement 0 〜 5 へ順番にドラッグ&ドロップ。

  • これにより、ROSからの1番目の角度がlink1に伝わる仕組みが完成しました。

成功の瞬間:Hello, Robot!

Unity画面-ROS 2との接続完了

ターミナルから以下のコマンドを打ち込んだ瞬間、Unity内のロボットが生命を宿したように回転しました。

ros2 topic pub --once /arm_joints sensor_msgs/msg/JointState "{name: ['link1', ...], position: [1.0, 0.0, ...]}"

結果: ターミナルに publishing #1 と表示され、Unity内のアームが正確に約57度(1.0ラジアン)傾きました。

さらに、複雑なポーズの実現

ターミナルから複数関節の角度指定コマンドを送信しました。

ros2 topic pub --once /arm_joints sensor_msgs/msg/JointState "{name: ['link1', ...], position: [-1.0, 0.5, 0.8, -0.5, 1.0, 0.5]}"

結果: ターミナルに publishing #1 と表示され、Unity内のロボットが指定通りの複雑なポーズをピタリと再現。Unity HUDも青く輝き、完全な同期を確認しました。

本日の教訓

  • HUDの色は正直: 青ければ通信はOK。動かないならスクリプトを疑う。

  • 環境のsourceは絶対: 新しいターミナルを開くたびに conda activate と source setup.zsh を忘れないこと。

  • iCloudは開発の敵: パスエラーが出る場合は、ローカルフォルダへ移動するのが鉄則。

ターミナルのエラーについて

ターミナル画面-エラー

[ERROR] Exception: No more data available

このエラーは、通信が突然途切れたことを示しています。

  • 原因: 主にUnityの再生ボタン(▶︎)を停止したときに発生します。

  • 仕組み: ROS側のサーバー(Mac)はUnityからデータが送られてくるのをずっと待っていますが、Unityを止めると通信用の「管(ソケット)」が急に閉じられます。ROS側が「次のデータを読もうとしたら、もうデータが空っぽ(No more data)だった!」と驚いて出しているエラーです。

  • 結論: Unityの再生を止めたときに出るものであれば、完全に無視して大丈夫です。

 [INFO] Disconnected from 127.0.0.1

これはエラーではなく、接続が切れましたというただの通知です。

  • 意味: 上記のエラーに伴い、Unity(127.0.0.1)との通信が終了したことを記録しています。これも、Unityを停止すれば必ず出るメッセージです。

[WARN] Publisher already registered...

これが一番長く、難しそうに見える警告(黄色い文字)ですね。

  • 意味: 同じ名前の送信役(Publisher)が、すでにROSの世界に登録されていますよという警告です。

  • 原因: ROS 2では、通信の参加者リストがMacの中で管理されています。Unityを停止➔再生と素早く繰り返すと、ROS側で前のUnityの登録情報が消える前に新しいUnityの登録が来てしまい、名前が重複するために発生します。

  • 解決策: 数秒待ってから再生するか、気になる場合はMac側のサーバー(ターミナル)を一度 Ctrl + C で止めてから起動し直すと消えます。基本的には無視しても動作に支障はありません。