おもちゃラボ

Unityで遊びを作ってます

【Unity】UniRxを使ってArduinoとシリアル通信

前回の記事では、シリアル通信のためのPluginを作ることで、Arduino⇔Unityのシリアル通信を実現しました。

nn-hokuson.hatenablog.com

今回はUniRxを使うことで、前回よりも簡単にArduinoとシリアル通信をする方法を紹介します。今回の記事の内容は次のとおりです。

UniRxとは

UniRxとはUnity Reactive Extensionsの略で、名前の通り(?)Unityで非同期通信をしたいときに使うと便利なツールになります。UniRxはAsset Storeから無料で手に入れることができます。

f:id:nn_hokuson:20170912190532j:plain

今回の記事では、UniRxはスレッドを作るためだけに使います(贅沢)UniRxの詳しい説明はしませんが、非常に便利なライブラリなのでいつか解説を書く・・・かも。

Arduino側のプログラムを作る

こちらはシリアル通信でデータを一方的に送りつけるだけのプログラムです。次のプログラムをスケッチに書いて下さい。

byte a = 0;

void setup() {
 Serial.begin(9600);
}

void loop() {
 a++;
 Serial.println(a);
}

プログラムの内容は・・・setupメソッドの中でシリアル通信を開始しています。loopメソッドの中では、変数aの値をインクリメントしながらシリアルにどんどん流し込んでいるだけのプログラムになります。

プログラムができたら、書き込みボタンでArduinoに書き込んでおきましょう。

f:id:nn_hokuson:20170912191350p:plain:w350

Unity側のプログラムを作る

続いてUnity側のシリアル通信プログラムを作ります。こちらはシリアル通信で送られてくるデータを受け取るプログラムです。

UniRxを使うため、Asset Storeからダウンロードしてインポートしておいてください。

f:id:nn_hokuson:20170912190532j:plain:w400

また、Unityでは標準で.NET 2.0のサブセットを使うように設定されていますが、サブセットにはSerialクラスが含まれていないため、.NET 2.0 Subsetから.NET 2.0に変更する必要があります。

メニューバーからEdit -> Project Settings -> Playerを選択し、API Compatibility Levelを.NET 2.0に変更してください。

f:id:nn_hokuson:20170912190634p:plain:w400

続いて、シリアル通信用のスクリプトを作成します。プロジェクトビューで右クリックし、「Create」→「Script」→「C# Script」を選択し、SerialController.csという名前で保存し、作成したファイルに次のスクリプトを入力してください。

using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System;
using System.IO.Ports;
using UnityEngine;
using UniRx;

public class Serial : MonoBehaviour {

    public string portName;
    public int baurate;

    SerialPort serial;
    bool isLoop = true;

    void Start () 
    {
        this.serial = new SerialPort (portName, baurate, Parity.None, 8, StopBits.One);

        try
        {
            this.serial.Open();
            Scheduler.ThreadPool.Schedule (() => ReadData ()).AddTo(this);
        } 
        catch(Exception e)
        {
            Debug.Log ("can not open serial port");
        }
    }
	
    public void ReadData()
    {
        while (this.isLoop)
        {
            string message = this.serial.ReadLine();
            Debug.Log( message );
        }
    }

    void OnDestroy()
    {
        this.isLoop = false;
        this.serial.Close ();
    }
}

ここでは、UniRxを使うため、using UniRX;を追加しています。Startメソッドの中でSerialクラスのインスタンスを作成した後、Scheduleメソッドを使ってReadDataスレッドを立ちあげています。

ReadDataメソッドの中ではSerialクラスのReadLineメソッドを使って、シリアルで送られてくるデータを読んで表示しています。

ゲームを終了する場合はOnDestroyメソッドが実行されます。その中で、スレッドを抜けて、シリアルポートを閉じています。

実行してみる

スクリプトが作成できたら、空のゲームオブジェクトを作って、それにスクリプトをアタッチしておきましょう。アタッチしたゲームオブジェクトのインスペクタから、ボーレートとポート名を設定してください。ボーレートはArduino側で指定した9600に設定します。

ポート名はArduinoを起動し、メニューバーからツール -> ポートで確認することができます。

f:id:nn_hokuson:20170912190808p:plain:w300

これで準備完了です。ArduinoをPCに接続し、Unityを実行してみてください。コンソールビューの数字が増加して1〜255を繰り返せば成功です。

f:id:nn_hokuson:20170912190819g:plain

まとめ

Unityで非同期通信やスレッドなどを使いたい場合はUniRxを使うことで、非常にスッキリとしたプログラムを書くことができます。