こんにちは、16の山本です。
皆さん年度末いかがお過ごしでしょうか、僕は講義のない毎日を満喫しつつ来る春休みの終了を嘆いています。
基本的に機械分野をメインの住処としている僕ですが、最近訳あってUnityを触ることになりました。
Unityはゲーム制作をするために使用される有名なソフトウェアですが、ハード屋の僕としてはオリジナルの自作コントローラーを作って遊びたくなります。
そこでマイコンボードとPCでシリアル通信をしてそれをUnity内で読み書きしようと思ったわけです。
最近Twitterにて自分と同様のことをしようとして悩んでいた方がいらっしゃったので、そのような方たちに対してせめてもの手助けになれればと思いこの記事を書いています。
注意:この記事はプログラム弱者が書いています。私はUnityで初めてC#に触れました。とりあえず自分の環境では動いたのでご了承ください。
自分の環境
OS: Windows 10 Education
Unityのバージョン: Unity 5.6.1f1 (64-bit)
マイコンボード: STM32 NUCLEO-F411RE (mbedでプログラミングした)
参考になる記事がないか早速ググると、このページが出てきました☟
「SerialPort または Uniduino を使った Unity と Arduino を連携させる方法調べてみた」
この記事の中の「SerialPort から自前で読み取る(無料)」の項目を参考にして、マイコンから
pc.printf("NI+CORA\n");
wait_ms(1);
で1ms毎に文字列を送り付け(mbedからの送信について詳しくはこっち)、記事にあった”SerialHandler.cs”を実行してみたもののうまく動かず。
Unityのツールバーにある”Window”→”Console”からエラーメッセージを見てみると
Object reference not set to an instance of an object
UnityEngine.Debug:LogWarning(Object)
と出た。
色々やってるとどうやら67行目の
serialPort_.BytesToRead
がよくないようだった。
この人も似たようなことを言っている☟
「unityのSystem.IO.PortsクラスのBytesToReadが正常に動かない」
ということでBytesToReadを含むif文を取っ払ってみた。
すると今度はUnityで実行したらフリーズしてしまった。仕方なくタスクマネージャーで終了。
色々やっているとどうやら68行目の
serialPort_.ReadLine()
が終了しないようだ。
そこでOpen()の中に
serialPort_.ReadTimeout = 20;
を追加。要するに20msでタイムアウトさせる。
すると今度はフリーズしなくなりエラーメッセージに
The operation has timed-out.
UnityEngine.Debug:LogWarning(Object)
と出た。ずっとタイムアウトしっぱなしらしい。
そこでOpen()の中に今度は
serialPort_.NewLine = "\n";
を追加。こうすることで改行コード\nでその行が終了したと判断できるようになった。
すると今度はエラーメッセージに
NullReferenceException: Object reference not set to an instance of an object
と出た。調べてみると内容としてはOnDataReceivedがNullということらしい。
そこで9行目の
public event SerialDataReceivedEventHandler OnDataReceived;
を
public event SerialDataReceivedEventHandler OnDataReceived = delegate { };
に修正。するとエラーメッセージが出なくなった!
早速Update()内に
Debug.Log(message_);
を追加して受信した内容を読んでみると…
やったぜ
見事マイコンから送信した文字列を受信することができました(๑˃̵ᴗ˂̵)و
前述のブログではこの”SerialHandler.cs”を使ってUnityからマイコンに文字を送信し、マイコンのLEDを光らせていました。
そのためのコードとして”LedController.cs”が用意されていましたが、これも僕の環境では動きませんでした。
送信するキーとして割り当てられているAキーとSキーを押すと
NullReferenceException: Object reference not set to an instance of an object
とエラーを吐かれてしまいます。またNullになってるらしいですね。
そこでStart()を新たに作り
void Start()
{
serialHandler = GetComponent();
}
とすると、今度はしっかりとキーを押したときに文字を送信してくれました。
前述のブログにはLEDの点灯の他にジャイロセンサーを読み取り、Unity内のオブジェクトの回転へ反映させるプログラムもありましたが、そちらは試していません。
しかし、代わりに可変抵抗の値を読み取りそれをUnity内のオブジェクトの回転へ反映させることはできました。
こちらも同様にStart()の中にserialHandler = GetComponent();を追加すれば大丈夫だと思います。
最後に僕が加筆したプログラム達
SerialHandler.cs
LedController.cs
mbedprogram.cpp (STM32 NUCLEO-F411REに書き込んだもの)