UnityとmBotを連携させたい!
ゲーム開発を中心とした統合開発環境であるUnity
プログラミング言語だけでなくマウス操作だけでも制作ができるため、初心者でも比較的扱いやすいのが特徴です。
そんな仮想空間を簡単に作ることができるUnityとプログラミング教育ロボットキットのmBotを組み合わせて、現実空間でロボットに加えた変化をUnityで反映、可視化させてみました。
macOSでの説明になります
OSやツール、エディタ、ガジェットの種類によって以下の手法では実現できない場合もあります。
今回のゴール
- macOS上で、MegaPi(Arduino)から送信される角度データをUnityで受信し、3Dオブジェクトを連動して回転させる
- UnityからもPWM信号をシリアル経由で送信し、モーター速度を制御できるようにする
実現方法
macOS側の準備
Arduino(MegaPi Pro)の準備
Arduino IDEの設定
- Arduino IDE を開く
- MegaPi Proに合わせてボードを設定
→ [ツール] > [ボード] > [Arduino Mega or Mega 2560] - シリアルポートも /dev/cu.usbserial-xxxx を選択
このときシリアルポートはBluetooth以外のものを選択すること - ライブラリのインポートをを行う
→ [スケッチ] → [ライブラリをインクルード] → [ライブラリマネージャ]
ライブラリマネージャで「MeMegaPiPro」または「Makeblock」を検索
該当するライブラリ(例:Makeblock、MegaPi Proなど)をインストール
Unityの準備
▼Unityのディレクトリ構成
Assets/
├── Scripts/
│ ├── Serial/
│ │ ├── SerialPortReader.cs
│ │ └── SerialAngleReceiver.cs
├── Prefabs/
│ └── RollObject.prefab
- 空の GameObject に
SerialAngleReceiver
をアタッチ -
RollObject
には回転させたいオブジェクトをInspectorでドラッグ
macOS+Unityでシリアル通信を行う準備
Unity は Windows では System.IO.Ports.SerialPort を使って簡単に Arduino や M5Stack などと通信できますが、macOS ではそのままでは動きません。Unity は Mono ランタイムをベースにしており、System.IO.Ports.SerialPort は macOS 向けには完全に対応していません。
解決策
UniSerialPort は、macOS/Linux/Windows の クロスプラットフォームで動作する Unity 専用のシリアル通信ライブラリです。macOS のポート /dev/cu.usbserial-xxxx にも対応し、C# スクリプトから直接 Arduino などと通信が可能になります。
1.GitHubからライブラリをダウンロード
https://github.com/prossel/UnitySerialPort
ZIPファイルを解凍すると、UnitySerialPort-main/
というフォルダができます
2.Unityプロジェクトにコピー
YourUnityProject/
├── Assets/
│ ├── Scripts/
│ └── UnitySerialPort/ ← ここに入れる
- あなたの Unity プロジェクトの
Assets/
フォルダを開く - 解凍した中の
UnitySerialPort-main/UnitySerialPort/
フォルダをそのままAssets/
フォルダにコピーします
Unityスクリプトの実装
シリアル通信スクリプト SerialPortReader.cs
Unity側でmacOSのシリアルポート(/dev/cu.usbserial-xxxx)を直接開いて読み書きするためのクラス
- Windows のように System.IO.Ports.SerialPort は使えません
- macOSでは /dev/cu.usbserial-xxxx のようなパスを FileStream を使って開きます
- ポートは Arduino IDE などと競合するため、Unity実行前に必ず閉じること
▼例のコード
using System.IO;
using System.Text;
using UnityEngine;
public class SerialPortReader
{
private FileStream stream;
private StreamReader reader;
private StreamWriter writer;
public bool IsOpened { get; private set; }
public void Open(string portName, int baudRate)
{
try
{
stream = new FileStream(portName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
reader = new StreamReader(stream, Encoding.ASCII);
writer = new StreamWriter(stream, Encoding.ASCII) { AutoFlush = true };
IsOpened = true;
}
catch (System.Exception e)
{
Debug.LogError("Serial open failed: " + e.Message);
IsOpened = false;
}
}
public bool ReadLine(out string line)
{
line = null;
if (!IsOpened || reader == null) return false;
try
{
line = reader.ReadLine();
return !string.IsNullOrEmpty(line);
}
catch { return false; }
}
public void WriteLine(string message)
{
if (IsOpened && writer != null) writer.WriteLine(message);
}
public void Close()
{
reader?.Close();
writer?.Close();
stream?.Close();
IsOpened = false;
}
}
オブジェクトを回転させる SerialAngleReceiver.cs
Arduinoから送られてきた角度を読み取り、Unity内のオブジェクトを回転させるスクリプト
-
Start()メゾットでシリアルを初期化
SerialPortReader のインスタンスを作成
指定したポートで通信開始
Arduinoと同じボーレートを必ず指定すること
-
Updata()メゾットでシリアルから受信
毎フレーム Arduino から角度を受信
-
回転の実装
Inspector上で RollObject に対象のオブジェクトをドラッグ&ドロップして割り当てることが必要
-
エラーハンドリングとクローズ処理
OnDestroy() でシリアルを確実に閉じる
RollObject が未設定だと UnassignedReferenceException が出るので、Inspector確認必須
モーターとUnityの同期テスト
1. macとmBotをケーブルで接続
- 通信用のケーブルを使用し必ずアクセサリ接続許可を行う
- mbotは電源を入れておく
2. Arduino側でスクリプトを実行
- これはコードを編集しない限り実行したままでOK
- SerialMonitorを一度表示しておく
3. Arduinoとmbotの接続を確認する
- Monitorをオンにしておくとmbotの接続がうまくいっていればMonitorにmBot側からの出力が送られる
- 出力がしっかり送られていた場合はMonitorを切ってください
通信ポートを占領してしまい、Unity側でエラーが出て実行できなくなります
4. Unityを実行
- Unityを実行
- Arduinoでもう一度Monitorを表示
Unity側に通信を受け取った時の処理(consoleに角度などのテキスト出力を設定している場合)がUnity側に出力される - mBotを操作してUnity内のオブジェクトが回転するか確かめる
まとめ(注意点)
- Arduino IDEをUnityと合わせて使えるセットアップを行う
-
macOSだとUnityがベースにしているものはmacOS向けには完全に対応していない
ちゃんとUniSerialPortのようなUnity専用のライブラリを使うのがおすすめ - オブジェクトに位相を与えるスクリプトは動かしたいスクリプトに直接貼るのではなく空のゲームオブジェクトに貼り付ける
- 実行の際にはポートの競合を起こすので注意