UnityでArduinoの接続にユニークIDを使う (Windows)


**注意！ Leonardo系はポートによってインスタンスIDが替わるので使用できない**


Arduinoを複数接続する場合や、PCを変えた際にCOMPortが入れ替わったりした場合に誤接続を防ぐため、COMPortの番号ではなくArduino個体のIDで接続したかった

`pnputil` というコマンドで接続されているデバイスの情報を読み取れるのでこれを使ってみる
**Windows10 バージョン2004以降でのみ有効**

## pnputiコマンドで接続されているArduinoを確認

`/enum-devices /connected /class "Ports"` でクラス名Ports(COMPort)のデバイスを取得できる

	pnputil /enum-devices /connected /class "Ports"

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45348/162eb9f8-7730-f86d-0db9-17ded67766e4.png)

インスタンスIDがArduinoのユニークIDになるので、UnityではこのIDを指定して接続できるようにする

## Unityでpnputiコマンド叩くスクリプト

- インスタンスID指定してデバイスを検索する

``` COMPort.cs
namespace COMPortUtil
{
    using System.Diagnostics;

    public class COMPort
    {
        public static void Find(
            string findDveiceInstanceId,
            DataReceivedEventHandler outputHandler = null,
            DataReceivedEventHandler errorOutputHanlder = null,
            System.EventHandler processExit = null)
        {
            Process process = new Process();

            process.StartInfo.FileName = "pnputil";
            process.StartInfo.UseShellExecute = false;

            process.StartInfo.RedirectStandardOutput = true;
            process.OutputDataReceived += new DataReceivedEventHandler(outputHandler);

            process.StartInfo.RedirectStandardError = true;
            process.ErrorDataReceived += new DataReceivedEventHandler(errorOutputHanlder);

            process.StartInfo.RedirectStandardInput = false;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.LoadUserProfile = true;

            process.StartInfo.Arguments = "/enum-devices /connected /instanceid " + findDveiceInstanceId;

            process.EnableRaisingEvents = true;

            process.Exited += new System.EventHandler(processExit);
            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
        }
    }
}

```

- 検索結果からCOMPortの番号を取得する

```FindComPort.cs
using COMPortUtil;
using System.Text.RegularExpressions;

public class FindComPort: MonoBehaviour
{

	string comPortName;

	void Start()
	{
	  COMPortUtil.COMPort.Find(
	    " FTDIBUS\\VID_0403+PID_6001+AU013KJPA\\0000",  // Dveice Instance Id
	    this.COMUtileOutputHandler,
	    this.COMUtileErrorOutputHanlder,
	    this.COMUtileProcess_Exit);
	}

	private void COMUtileOutputHandler(object sender, System.Diagnostics.DataReceivedEventArgs args)
	{
	    if (!string.IsNullOrEmpty(args.Data))
	    {
	        // Debug.Log("output : " + args.Data);
	        string result = args.Data;
	        Match matchedObject = Regex.Match(result, @"COM\d+");

	        if (matchedObject.Value.Length >= 4)
	        {
	            string comPort = matchedObject.Value;
	            try
	            {
	                comPortName = comPort;
	            }
	            catch (System.IO.IOException ex)
	            {
	                Debug.Log(ex.Message);
	            }
	        }
	    }
	}
	private void COMUtileErrorOutputHanlder(object sender, System.Diagnostics.DataReceivedEventArgs args)
	{
	    if (!string.IsNullOrEmpty(args.Data))
	    {
	        Debug.Log("error : " + args.Data);
	    }
	}

	private void COMUtileProcess_Exit(object sender, EventArgs e)
	{
	    System.Diagnostics.Process proc = (System.Diagnostics.Process)sender;
	    proc.Kill();
	}
}
```


あとはcomPortNameを使ってシリアルポートをオープンするだけ