はじめに結論
Unity側でSeralPort
に対してReadLine()
するとき、Arduino側はSerial
に対してSerial.println("Hello")
だけしか呼んでいな場合、Unity側で取得できるはずのHelloというデータがやって来ないという問題に遭遇しました。
そこで対策として、次のようにArduinoスケッチ側でデータ本体と改行コードの送出を2つに分けてみたところ、意図した通りにReadLine()
の戻り値でデータが取得できる事がわかりました。
Serial.print("Hello");
Serial.println("");
Unityからシリアルポートを使うための準備
UnityでSerialPortクラスを使ってArduinoとの連携する方法については凹みさんの記事 が大変参考になりました。いつもありがとうございます!
僭越ながら1つ処理を加えさせて頂くと、
serialPort_ = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
の直後に下記の1行を入れておくとより安心かと思います。
serialPort_.ReadTimeout = 1000; // 1000は適当な値です
こうすることでデータが来ないときでもserialPort_.ReadLine();
の呼び出しから抜けられるようになるので、終了処理で固まる事を防げるはずです。
本題の不具合発生状況と対策について
Unity側は諸々の設定が済んでいて、Arduino側もスケッチを書き込んであって、ReadLine()
したらデータがやってくるはず!と思って実験してみると、予想に反して何も出ない!Arduinoのシリアルコンソールにはちゃんと出力されていたのに!という事態が起こりました。
Arduioにはこんなスケッチが書かれているとします。
※参考にした凹みさんの記事にあるスケッチはうまく動くと思います(念のため)
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println("Hello");
delay(1000);
}
当然、シリアルコンソールには1秒おきに Hello が出力され、何も問題が無いように見えます。
しかしUnity側では何も取得出来ません。
そしてなぜか、ReadLine()
を改行コードとは無関係に逐次読み出し出来るはずのReadBuffer()
に変更しても何も取得出来ません。
試行錯誤の結果、Arduinoのスケッチを見直して、以下のようにprint
とprintln
を分けて見た所うまく行った、というわけです。
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.print("Hello");
// Serial.println("");
Serial.println(); // Unity 2019.2.0f1 で確認したら、引数無しでないと動かなかった
delay(1000);
}
MSDNのSerialPort.ReadLine メソッド ()やmonoのSystem.IO.Ports.SerialPort.ReadLine Methodのドキュメントを読んで、SerialPort
クラスのReadLine()
メソッドは改行コードがやってきたらその時点までに取得した値を返してくれるはずだと思っていましたが、どうやらUnityの実装に対してはこの理解は一部誤りだったようです。
ここからは推測ですが、UnityのSerialPortクラスの実装では、改行を表すバイト列(つまりSystem.Environment.NewLine
)が単独で送られて来るまで、バッファの内容を返さない実装になっているのではないでしょうか。
検証環境
今回、不具合が発生してかつ対策が有効だった環境は以下の通りです。
- Windows 10 および Mac OS X El Capitan
- Unity 5.4.1
- Arduino IDE 1.6.10