【Unity】アプリ実行後センサが見つかるまで探し続ける

背景と今回やること

シリアル通信を使用して外部センサの値を読み込むアプリケーションをUnityで製作した際に,アプリ実行直後のタイミングでセンサがつながらなかった場合,アプリを再起動する必要がありました.

それが面倒くさかったため,アプリ実行後センサが接続するまで待機し続けるというプログラムを作成しました.

使用するのは以下と同じプログラムです.

challenge-think.hatenablog.com

コード

github.com

説明なんてどうでもいいという方は以下のコードを参考にして自分なりに改変してください.

// シリアルポート
private SerialPort serialPort_;
private Thread thread_, thread2_;
private bool isRunning_ = false;
// スレッド監視
public int serialStatus = 0;  // 0 : waiting, 1 : success, 2 : failure
private bool thread2_status = false;

void Start()
{
    Debug.Log("Start");
    StartCoroutine("Open");
}

void SerialOpen(){
    thread2_status = true;
    serialStatus = 0;
    serialPort_ = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
    try{
        serialPort_.Open();
    }
    catch (Exception e){
        serialStatus = 2;
    }
    if (serialStatus == 0) serialStatus = 1;
    thread2_status = false;
}

private IEnumerator Open()
{
    serialStatus = 2;
    while (serialStatus != 1){
            Debug.Log("センサ接続トライ中");
        if (serialStatus == 2){
            thread2_ = new Thread(SerialOpen);
            thread2_.Start();
            yield return null;
        }
        while (thread2_status) { yield return null; }
        thread2_.Join();
        yield return null;
    }
    serialPort_.ReadTimeout = 50;
    isRunning_ = true;
    thread_ = new Thread(Read);
    thread_.Start();

    // オフセット角も更新する
    rotate Rotate;
    GameObject obj = GameObject.Find("Main Camera");
    Rotate = obj.GetComponent();
    Rotate.offsetFlag = true;

    // check
    Debug.Log("OPEN!");
}

コードの説明

それでは解説をしていきます.

Step1

まずOpenメソッドの中にあるシリアル通信を確立する部分で接続が確認できなかった場合に処理を止めて最初から戻るという動作ができるようにコルーチンを使用します.


void Start()
{
    Debug.Log("Start");
    StartCoroutine("Open");
}
private IEnumerator Open()
{
    ....
}

Step2

ここで,シリアルポートをつなぐ部分(serialPort.Open())は何度もループする場所なので,わかりやすいように別関数として定義しておきます.

後で使いますが,接続が確立されたのかどうかを判断するために,変数を二つ定義しています.

thread2_statusは,プログラムがこの関数を処理している最中なのか,全て処理が完了しているのかどうかを判断するために使用します.

serialStatusは,今接続がどのような状態かを判断するために使用します.

void SerialOpen(){ // 0 : waiting, 1 : success, 2 : failure
  thread2_status = true; serialStatus = 0; serialPort_ = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One); try{ serialPort_.Open(); } catch (Exception e){ serialStatus = 2; } if (serialStatus == 0) serialStatus = 1; thread2_status = false; }

Step3

次は,センサを見つけてシリアル通信を確立するまでの間,他のメインスレッドの処理を待たせてしまうことを防ぐために別スレッドとして使用していきます.

以下のwhileループ中の処理としては,シリアル通信が確立できなかった場合は,(1)スレッドを初期化し,(2)初期化した状態で再度接続確立を試みる.(3)1フレーム待機.(4)定義した接続を確立するための関数の処理をすべて実行するまで待つ.(5)一通り終了したらスレッドを消す.という順でループし,接続が確立した場合(serialStatus != 1)ループを抜け出すという形になっています.

 

serialStatus = 2;
while (serialStatus != 1){
        Debug.Log("センサ接続トライ中");
    if (serialStatus == 2){
        thread2_ = new Thread(SerialOpen);(1)
        thread2_.Start();(2)
        yield return null;(3)
    }
    while (thread2_status) { yield return null; }(4)
    thread2_.Join();(5)
    yield return null;
}
最後にコルーチンを使用しているので,Start()の部分をStartCoroutine("Open")
と書き換えることも忘れずに.
以上で終了です.