toio を Web Bluetooth API で制御した際の応答を得る（目標指定付きモーター制御）

## はじめに
ロボットトイ「[toio](https://toio.io/)」を [Web Bluetooth API](https://webbluetoothcg.github.io/web-bluetooth/) で制御した際、制御の応答を得る方法を試した内容のメモです。
具体的には、以下の「目標指定付きモーター制御」を使った際の「目標指定付きモーター制御の応答」を得ようとしてやった内容です。
　[●モーター · toio™コア キューブ 技術仕様](https://toio.github.io/toio-spec/docs/ble_motor#%E7%9B%AE%E6%A8%99%E6%8C%87%E5%AE%9A%E4%BB%98%E3%81%8D%E3%83%A2%E3%83%BC%E3%82%BF%E3%83%BC%E5%88%B6%E5%BE%A1)

以下の記事を書いた際にモーター制御を行いましたが、連続したモーター制御をやろうとした場合に、モーター制御が完了したかどうかを取得したくなり、今回の記事の内容を試しました。
　[●toio を音で制御してみた（Audio用の Teachable Machine でベルやタンバリンの音を機械学習） - Qiita](https://qiita.com/youtoy/items/37f70bb4ce630e6cbd92)
　[●#toio の目標指定付きモーター制御の仕様を確認して使ってみる（ #GWアドベントカレンダー 5/3 ） #おうちでロボット開発 - Qiita](https://qiita.com/youtoy/items/6620385a0f77e22ac6fd)

## 目標指定付きモーター制御の応答の仕様
まず、toio のモーター制御の応答の仕様について調べてみます。

toio のモーター制御の仕様を見ると、目標指定付きモーター制御を行った場合、以下の応答を得られるようです。
<img width="610" alt="目標指定付きモーター制御の応答.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/464db2c8-3aab-38c1-6dc8-e5e41d6a4b1f.jpeg">
制御の種類の部分は固定で、2番目の制御識別子は「目標指定付きモーター制御を行った場合に指定した値（以下の画像の赤矢印で示した部分）」となるようです。
<img width="655" alt="目標指定付きモーター制御.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/eb599e3f-f04c-3133-76f6-ac0408e62daf.jpeg">
そして、応答内容は以下のいずれかが返ってくるようです。
<img width="616" alt="目標指定付きモーター制御の応答の応答内容.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/53c1ce0b-6eaa-c6c7-5b34-07c3bd761c9c.jpeg">
おおよそ、応答の仕様は分かったところで、プログラムでの処理について見ていきます。

## Web Bluetooth API での Notifications
応答の受け取り方について、軽く調べて見ると以下の仕組みを利用する形になりそうでした。
　●Web Bluetooth / Notifications Sample
　　https://googlechrome.github.io/samples/web-bluetooth/notifications.html

上記の中で、自分が過去の記事で作ったプログラムに組み込むと良さそうな部分を抜粋してみます。

まず、`characteristic` を取得した後に `startNotifications` の部分を加えつつ、`addEventListener` で `characteristicvaluechanged` と通知を受けたときに処理を行うための関数（以下では「`handleNotifications`」）を加えれば良さそうです。

```JavaScript
  .then(characteristic => {
    myCharacteristic = characteristic;
    return myCharacteristic.startNotifications().then(_ => {
      log('> Notifications started');
      myCharacteristic.addEventListener('characteristicvaluechanged',
          handleNotifications);
    });
  })
```

また、通知を受け取った場合の処理として、以下の `event.target.value` の部分に応答が返ってきそうです。

```JavaScript
function handleNotifications(event) {
  let value = event.target.value;
  let a = [];
  // Convert raw data bytes to hex values just for the sake of showing something.
  // In the "real" world, you'd use data.getUint8, data.getUint16 or even
  // TextDecoder to process raw data bytes.
  for (let i = 0; i < value.byteLength; i++) {
    a.push('0x' + ('00' + value.getUint8(i).toString(16)).slice(-2));
  }
  log('> ' + a.join(' '));
}
```

これをプログラムに組み込んでみます。

## 上記を toio の制御に組み込んでみる
[以前の記事](https://qiita.com/youtoy/items/37f70bb4ce630e6cbd92)に[掲載していたプログラム](https://github.com/yo-to/API_Test/blob/master/WebAPI/test10_test09_and_AudioRecognition/test02_c.html)に対して まず以下の 2行の処理を加えてみました。

```JavaScript
  .then(characteristic => {
    cube.motorChar = characteristic;
    console.log("characteristic", characteristic);
    cube.motorChar.startNotifications(); //追加1
    cube.motorChar.addEventListener('characteristicvaluechanged',handleNotifications); //追加2
  })
```

さらに、上記の処理の追加に合わせて `handleNotifications` もプログラムに追加します。
処理はひとまず以下としてみました。

```JavaScript
// 以下の4行を追加
function handleNotifications(event){
  console.log(event);
  console.log(event.target.value);
}
```

その後、プログラムを実行して toio のペアリングと BLE 経由でのモーター制御を実行してみました。
その際、ブラウザのコンソールの出力を見てみると、'event.target.value' のほうで 3バイトのバイナリデータが受け取れていそうでした。
<img width="625" alt="コンソールの出力1.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/71cec57d-963e-0bc0-07ae-9fb093d22204.jpeg">

そして、プログラムを以下のとおり書きかえて、再度試してみました。

```JavaScript
function handleNotifications(event){
  console.log(event.target.value.getUint8(0));
  console.log(event.target.value.getUint8(1));
  console.log(event.target.value.getUint8(2));
}
```

そうすると、モーター制御の処理をして完了するまで待った場合と、モーター制御の処理中に次の制御を行った場合で、それぞれ以下の出力を得られました。

モーターの制御が終わるまで待った場合は、以下となりました。
1つ目は、toio の仕様通り `0x81`（10進数で 131）が出力されており、2番目はモーター制御を行う際に指定した 0 が出力されています。また、3つ目についてはモーター制御が正常に終了した場合の値 0 が出力されており、意図通りの応答か得られたことが分かります。
<img width="242" alt="コンソールの出力2.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/fdaf4624-6dfa-6f5a-bbf5-9a4d7228f519.jpeg">

また、モーター制御の処理中に次のモーター制御を行った場合は、以下と上記の内容とが出力されました。
以下は、上記と比べて 3つ目の値が違っており、5 の値となっています。上記の toio の仕様では、この値は「他の書き込み受付」を示すもので、2度のモーター制御の中で 1つ目が終了する前に 2つ目を実行した結果を反映したものになっています。2度目のモーター制御は正常に終了したため、上記と同じ結果が以下に続いて出力された形です。
<img width="179" alt="コンソールの出力3.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/95328997-3f23-ffce-de7c-7c493d357d08.jpeg">

## まとめ
toio の目標指定付きモーター制御を行った際、その制御が正常に行われたか等を判別するための応答の取得を試し、応答が得られることを確認できました。

今後は、この応答を上手く使って連続したモーター制御をやってみたいと思います。