toio をブラウザ上から簡単制御！ p5.js用ライブラリの p5.toio の始め方（p5.js Web Editor上からの利用）

いろいろ前置きや説明を書いているため、「早速試していきたい！」という方は [「p5.js Web Editor で p5.toio を使う」の部分](https://qiita.com/youtoy/private/0544183ed0f0dba65f51#p5js-web-editor-%E3%81%A7-p5toio-%E3%82%92%E4%BD%BF%E3%81%86)までは飛ばしてしまって、読んでいただけると良いかもしれません。

## はじめに

この記事は、ブラウザ上から [toio](https://toio.io/) を制御する際に、プログラミングの手間をかなり削減してくれる [p5.toio](https://tetunori.github.io/p5.toio/) に関する記事です。
[p5.js Web Editor](https://editor.p5js.org/) というオンライン上の環境を使って使う方法を、簡単に紹介します（※ さらに今回の内容の続きの記事も、別途書ければと思ってます）。

自分はこれまで Web Bluetooth　API を使った toio用のプログラムを作ってきたのですが、最近ツイートした以下の内容は p5.toio を使って作ってみました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/tetunori_lego?ref_src=twsrc%5Etfw">@tetunori_lego</a> さんが公開されている p5.toio を活用して、1台の円状に動く <a href="https://twitter.com/hashtag/toio?src=hash&amp;ref_src=twsrc%5Etfw">#toio</a> を残り 5台が追いかけるプログラムを作った！<br>2台バージョンは、ずいぶん前に Web Bluetooth API で自力で実装してたけど、p5.toio を使ったら toio の台数は増えたのにソースコードがめちゃくちゃ短くなった！<a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> <a href="https://t.co/J6SqTkSzLO">pic.twitter.com/J6SqTkSzLO</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1399721115065503755?ref_src=twsrc%5Etfw">June 1, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

この時、以前の Web Bluetooth　API を使ったプログラム（例えば、2台での追跡を含むプログラムを作っていました）より格段に短い行数のプログラムになりました。この便利さを、ぜひ p5.js Web Editor の使い方と合わせて紹介したいと思い、この記事を書きました。

余談ですが、↓こちらが 2台で追跡を行う処理を含む Web Bluetooth API を使ったものです。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">さらにもう1作品、機械学習 Teachable Machine と開発者向けマット（仮）の組み合わせです。<br><br>音や声で 2台の <a href="https://twitter.com/hashtag/toio?src=hash&amp;ref_src=twsrc%5Etfw">#toio</a> を操作します。<br>卓上ベル、「追跡開始」の人声、ハンドベルの音、そして、踏切の音で<br>toio が動き出したり、追跡が始まったり、止まったりします。<a href="https://twitter.com/hashtag/%E3%81%8A%E3%81%86%E3%81%A1%E3%81%A7%E3%83%AD%E3%83%9C%E3%83%83%E3%83%88%E9%96%8B%E7%99%BA?src=hash&amp;ref_src=twsrc%5Etfw">#おうちでロボット開発</a> <a href="https://twitter.com/hashtag/toiotomo?src=hash&amp;ref_src=twsrc%5Etfw">#toiotomo</a> <a href="https://t.co/rTWwueY9ZN">pic.twitter.com/rTWwueY9ZN</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1262026960508608514?ref_src=twsrc%5Etfw">May 17, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 今回のゴール
この記事では、toio 1台だけがあれば試せるプログラムを p5.js Web Editor で作成し、動作確認をするところまで行います。
また、toio用のプログラムだけでなく p5.js Web Editor の使い方も補足しながら進めていきます。

## 今回の話に出てくるものの補足（toio以外）
今回の記事の内容から考えると、おそらくはこの記事を見る方は「toio とは？」という説明は不要だと思われるため、「p5.toio」と「p5.js」・「p5.js Web Editor」についてだけ補足をしようと思います。

### p5.toio とは？
p5.toio に関する説明は、作者である @tetunori_lego さんの以下の記事を見ていただくのが良いです。p5.toio を作られた経緯なども書かれています。
　●p5.toioのα版リリースについて - Qiita
　　https://qiita.com/tetunori_lego/items/23642e50129d934876e5

上記の記事にも書かれている、公式ページはこちらです。
　●toio lib for p5.js | p5.toio
　　https://tetunori.github.io/p5.toio/

#### PC環境・ブラウザの制限
p5.toio は Web Bluetooth API が使われており、それが実装されたブラウザが特定のものになるため注意が必要です。
[@tetunori_lego さんの Qiitaの記事の「PC環境」の項目](https://qiita.com/tetunori_lego/items/23642e50129d934876e5#pc%E7%92%B0%E5%A2%83)では、以下のように記載があります。
![PC環境について.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/9659ed46-c40b-8b4a-00c6-d9c19d5ddd94.jpeg)

なお、 https://caniuse.com/ を使い [Web Bluetooth API の実装状況を検索した結果](https://caniuse.com/?search=web%20bluetooth)は、2021/6/7時点では以下の通りです。
![caniuse_WebBluetooth.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/7ff5fbb1-6f86-eb9a-d4e6-c02617ddc95e.jpeg)

### p5.js とは？
[p5.js](https://p5js.org/) は、電子アートとビジュアルデザインのためのプログラミング言語と言われている [Processing](https://processing.org/) を JavaScript で扱えるようにしたライブラリです。2D・3D の描画を簡単に行うための処理がいろいろ準備されています。

他の説明として、 https://p5js.jp/ に書かれた説明も掲載しておきます。
![p5js.jp](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3116064c-eb56-4aa5-d518-9e05b566e2fe.jpeg)

### p5.js Web Editor とは？
p5.js Web Editor は、上記の p5.js を使ったプログラムをオンライン上で書くことができ、さらに作ったプログラムをオンラインに保存しておくこともできたりする環境です（保存のためにはアカウントの作成が必要なのですが、プログラムを書いて動かすだけならアカウントは不要）。

ちなみに、[p5.js Web Editor の URL](https://editor.p5js.org/) にアクセスすると、以下のような画面が表示されます。
![p5_js_Web_Editorのデフォルトの画面.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/bc698b4b-1ad0-e27e-cc9b-164d268bbc39.jpeg)

デフォルトで以下のようなプログラムが書かれていて、ここに JavaScript のプログラムを書いていきます。

```JavaScript
function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}
```

## p5.js Web Editor で p5.toio を使う
それでは、p5.js Web Editor で p5.toio を使ったプログラミングを行っていきます。

### p5.toio のライブラリを読み込ませる
JavaScript のプログラムを書いていく前に、 p5.js Web Editor で p5.toio を使えるようにするための準備をしておきましょう。

まずは以下の部分をクリックしてください。
![HTMLを表示させる手順1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/fa088c9d-1056-85ad-7013-25adaf930f1d.jpeg)

そうすると、左に「index.html」・「sketch.js」・「style.css」の 3つのファイルのリストが表示されます。デフォルトでは sketch.js が選ばれているので、index.html をクリックしてください。
![HTMLを表示させる手順2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/8a5304c8-593f-0f5f-2ebf-3128829c1102.jpeg)

index.html をクリックすると、JavaScript のプログラムが書かれていた部分（sketch.js の内容が書かれていた部分）が index.html の内容に変わります。
そこで
`<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>`
という `p5.sound.min.js` を含む行があるので、その後に
`<script src="https://tetunori.github.io/p5.toio/dist/0.5.0/p5.toio.min.js"></script>`
という行を追加してください。以下は、記事執筆時点で上記の行追加の対応を行った後の index.html  です。

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/addons/p5.sound.min.js"></script>
    <script src="https://tetunori.github.io/p5.toio/dist/0.5.0/p5.toio.min.js"></script>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <meta charset="utf-8" />
  </head>
  <body>
    <script src="sketch.js"></script>
  </body>
</html>
```

行の追加が終わったら、以下の ①⇒② を順番にクリックして最初の状態に戻してしまってください。
![JavaScriptのプログラムの表示に切り替える.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/8e7c23e0-3f5e-1bf2-0def-b64502b7c61e.jpeg)

### toio を動かすプログラムを書く
上にリンクを書いた [@tetunori_lego さんの Qiita の記事](https://qiita.com/tetunori_lego/items/23642e50129d934876e5)や p5.toio の公式ページの説明を見つつ、以下の処理を行うプログラムを書いてみます。

- toio との接続
- toio で音を鳴らす
- toio をその場で回転させる（モーターの制御）
- 上記の回転動作を停止させる

以下が JavaScript のプログラムです。

```javascript
const gCubes = [];

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
}

function mouseClicked() {
  P5tCube.connectNewP5tCube().then((cube) => {
    gCubes.push(cube);
    cube.turnLightOn("white");
  });
}

function keyPressed() {
  switch (keyCode) {
    case LEFT_ARROW:
      gCubes[0]?.playMelody([
        { note: 0x3c, duration: 0x1e },
        { note: 0x3e, duration: 0x1e },
        { note: 0x40, duration: 0x1e },
      ]);
      break;
    case RIGHT_ARROW:
      gCubes[0]?.move(70, -70, 0);
      break;
    case DOWN_ARROW:
      gCubes[0]?.stop();
      break;      
    default:
      break;
  }
}
```

それでは、まずはこのプログラムを動かしてみましょう。
ここで上記を実行する手順を記載してから、その後にプログラムに関する補足を書いていきます。

### 書いたプログラムを実行する
プログラムを実行するには、画面左上の「▶︎ 再生ボタン」を押してください。
![プログラムの実行.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/7bcdfadd-97ae-8913-6ff4-3cce7e11b65f.jpeg)

その後は、JavaScript のプログラムで書いた「toio との接続」・「音を鳴らす」・「モーターを動かす・止める」といった処理を、マウスのクリック操作・矢印キーの押下で行っていきます。

#### toio との接続
toio とブラウザの接続に使われる Web Bluetooth API は、プログラムが勝手にデバイスとの接続を行うことができず、ユーザのアクションが必ず必要になります。
その部分について、今回の実装では @tetunori_lego さんのサンプルと同じように、マウスクリックをトリガーにして toio のスキャンを行う仕組みにしました。

以下の枠で囲まれている部分、「プレビュー」のエリアをマウスでクリックしてください（ちなみに、色がついていない部分でも OK です）。
![プレビューエリア.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/ac76e93b-986a-748b-ea48-9b2e2296cde8.jpeg)

そうすると、以下のような表示が出てくるので、以下の画像の ①⇒② という順番でクリックをしてください。
この操作を行うと toio とのペアリングは完了です。
![toioとのペアリング.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/495c4d27-4527-a102-d3bf-5f5eacab1a01.jpeg)
プログラムで「toio との接続時に、裏のランプを白色で点灯させる」という処理を入れているので、ランプを見ることで処理が完了したことを確認できます。

#### toio で音を鳴らす・toio のモーターを動かす
上記の toio との接続を終えた後、キーボードの矢印キーを押すことで、以下の動作をさせる処理を実行できます。

- 左矢印キーを押す
   - toio から音を鳴らす
- 右矢印キーを押す
   - toio がその場でずっと回転し続ける（モーター制御）
- 下矢印キーを押す
   - 上記の「右矢印キー押下」で実行したモーター制御を止める

実際に動作をさせた時の様子を、以下に掲載してみます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">p5.toio に関する記事に掲載した <a href="https://twitter.com/hashtag/toio?src=hash&amp;ref_src=twsrc%5Etfw">#toio</a> 用のプログラムを動作させた時の様子。 <a href="https://t.co/6e9vLCtvYg">pic.twitter.com/6e9vLCtvYg</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1401473582799065094?ref_src=twsrc%5Etfw">June 6, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

動画のとおり、うまく動作させられました。

### プログラムに関する補足
プログラムを実行して動作を試していただく手順を書き終えたところで、次にプログラムの補足を書いていきます（上に掲載した Qiita の記事を参照していただく部分もあります）。

#### toio との接続・ランプの点灯
この部分は、 @tetunori_lego さんが以下に掲載されていたプログラムを使って書きました。

- [1. Cubeと接続しよう](https://qiita.com/tetunori_lego/items/23642e50129d934876e5#1-cube%E3%81%A8%E6%8E%A5%E7%B6%9A%E3%81%97%E3%82%88%E3%81%86)
- [使用例 1: ランプを点灯する](https://qiita.com/tetunori_lego/items/23642e50129d934876e5#%E4%BD%BF%E7%94%A8%E4%BE%8B-1-%E3%83%A9%E3%83%B3%E3%83%97%E3%82%92%E7%82%B9%E7%81%AF%E3%81%99%E3%82%8B)

#### 音を鳴らす
音を鳴らす指示の部分は、 @tetunori_lego さんが以下に掲載されていたプログラムを使っています。

- [使用例 2: MIDI メロディーを再生する](https://qiita.com/tetunori_lego/items/23642e50129d934876e5#%E4%BD%BF%E7%94%A8%E4%BE%8B-2-midi-%E3%83%A1%E3%83%AD%E3%83%87%E3%82%A3%E3%83%BC%E3%82%92%E5%86%8D%E7%94%9F%E3%81%99%E3%82%8B)

その音を鳴らし始めるトリガーになる処理は、p5.js のキー押下を取得する仕組みを用いました。
以下の p5.js の公式ドキュメントに書かれているもので、押下されたキーの判定には `keyCode === LEFT_ARROW)` という、左矢印キーに対応する値を指定しています。
　●reference | keyPressed()
　　https://p5js.org/reference/#/p5/keyPressed

#### その場で回転させる・動きを止める
回転（モーターの制御）と動きの停止について、toio の制御に関しては p5.toio の公式リファレンスで以下に該当するものを用いています。
`stop()` のほうは、処理を実行するとモーター制御を停止するというもので、パラメーター指定等はありません。
`move()` のほうは、パラメータとして「左側のモーターのスピード指定」・「右側のモーターのスピード指定」・「モーターを動かす時間の長さ（単位はミリ秒）」の 3つがあり、今回はそれぞれ「70、 -70、 0（※ずっと動き続ける）」という値を使いました。

- [【公式リファレンス】 move](https://tetunori.github.io/p5.toio/docs/cube/classes/p5tcube#move)

![move.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a0a47e06-8ae0-a049-edd5-875d3d15f22b.jpeg)
![moveのパラメータ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a9a1f6c7-43e2-59ad-a1fd-be012bb28db9.jpeg)

- [【公式リファレンス】 stop](https://tetunori.github.io/p5.toio/docs/cube/classes/p5tcube#stop)

![stop.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a010cf2f-7aae-7f38-8f54-b09d9b85cd81.jpeg)

#### さらに補足
プログラムの中の「gCubes[0]?.【move等】」という部分の「?.」について、詳細には触れませんが少しだけ補足します（自分用のメモも兼ねて）。
これは「オプショナルチェイニング演算子」 というもので、今回のプログラムでの動作的には「toio との接続がない状態で、toio を制御するための move 等の処理を実行しても、エラーは発生させない（処理としては `undefined` を返す）」というものです。

詳しく知りたい方は以下のページなどをご覧ください。
　●Optional chaining (?.) - JavaScript | MDN
　　https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Optional_chaining

## p5.js Web Editor で便利な操作
最後に、p5.js Web Editor の操作の中で、プログラムを書くときに便利と思われる機能を 1つだけ紹介して説明は終わりにします。

## コードの整形
画面上部のメニューから「編集 ⇒　コード整形」を選んでいくか、ショートカットキー（※ 以下の画像で書かれているのは Mac用のものになっています）を押すと、ソースコードのインデント等を自動的に整えてくれる機能があります。
![コードの整形.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/3373f23a-8141-c28d-37fc-2c44acb27116.jpeg)

## おわりに
今回は p5.toio を使って、p5.js Web Editorの上に書いた toio用のプログラムに関する話を書きました。そして、そのプログラムは、toio 1台だけを使って実行できるものでした。

冒頭に掲載したような複数台を制御するプログラムについては、今回の記事の中で触れられてないので、それについて別途記事を書ければと思っています。

## 【追記】 こんな話も（2021年7月ごろ）

:::note info
【追記2】 一記事、以下のように p5.js Web Editor で使えなくなった時があったのですが、その後、また利用可能になりました。
この追記をした 2024年2月現在でも、利用可能です。
:::

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">つい最近の改変だと思うのですが、p5.js Web EditorでWebBluetoothが使えなくなっていました(p5.ble.js, p5.toioなどなど)。<br>接続時に出るエラーの内容はかなり明確なのでIssueをあげたけど、アーキテクチャ思想的に対応できないです、となるとキツいな。<a href="https://t.co/aqvLwQADg2">https://t.co/aqvLwQADg2</a></p>&mdash; Tetsunori NAKAYAMA | 中山 哲法 (@tetunori_lego) <a href="https://twitter.com/tetunori_lego/status/1415654203117084679?ref_src=twsrc%5Etfw">July 15, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>