1. 概要 |
WebIO は、MIDI通信を用いてブラウザからIO制御する仕組みです。
上図左は、温湿度センサをつないだマイコン(図ではXIAO samd21)とパソコンをUSB接続でMIDI通信し、パソコンのWebブラウザの画面にセンサの値を表示する様子を表しています。
上図右は、赤外線送信機をつないだマイコン(図ではATOM lite)とスマホをBluetooth接続でMIDI通信し、スマホでテレビのリモコン操作をする様子を表しています。
どちらも、マイコンにはArduinoプログラム(webio2.ino)を書き込んでおき、パソコンやスマホからは見かけ上MIDIデバイスとなります。温湿度計やリモコンのWebアプリはJavascriptライブラリ(webio2.js)と一緒にサーバに置きます。また、MIDI通信の際にMIDIプロトコルの一部を入出力のために転用しています(付録1)。
パソコンやスマホに特別なアプリは必要ありません。また、操作対象は「ブラウザが動作しているパソコンやスマホに接続したデバイス」で、遠隔地のデバイスを操作できるわけではありません。
以下はWebIOを用いた制作例で、それぞれリンク先に詳しい説明があります。
□ ブラウザ画面に表示する温湿度計[リンク] | |
大きなモニタに表示すれば、体育館やイベント会場などで熱中症対策に利用できます。 | |
□ ブラウザ画面に表示するCO2モニタ[リンク] | |
大きなモニタを使えば、イベント会場や飲食店の店頭などで換気の目安を表示できます(新型コロナ対策)。 | |
□ ブラウザで操作する赤外線リモコン[リンク] | |
通常のリモコンボタンを押せない重度障害者も、パソコンが操作できればリモコンを操作できます。 | |
□ ブラウザと連動して自動演奏するミニドラム[リンク] | |
ブラウザのメロディーと連動して、ミニドラムのスティックをモータで制御します。 | |
□ 電子工作の導入教材[リンク] | |
ブラウザの操作でLEDをオンオフ、スイッチでブラウザ画面を操作、センサの値をブラウザ画面に表示などの簡単なWebアプリを作りながら、電子工作の導入教材として利用できます。 |
以下のブラウザおよびマイコンで動作します。どのブラウザが Web MIDI API やWebBluetoothに対応しているかは「Can I Use」で確認できます。
USB接続の場合(パソコン) | Bluetooth接続の場合(パソコン・スマホ) | |
---|---|---|
ブラウザ | Windows版Chrome, Edge など (Web MIDI API 対応ブラウザ) |
Windows版Chrome, Edge, Android版Chrome など (Web MIDI APIおよび Web Bluetooth 対応ブラウザ) |
マイコン | Leonardo, ProMicro, Wio, XIAO samd21, XIAO RP2040 など (webio2.inoを書き込んでおく) |
XIAO ESP32, XIAO ESP32S3, ATOM lite, ATOM S3 lite など (webio2.inoを書き込んでおく) |
webio2.zipをダウンロードし、解凍すると、以下のファイルが復元されます。
この章はWebアプリ(HTMLファイル)を作成する際にご覧ください。
パソコンやスマホとマイコンの間の情報交換はMIDI通信で、ブラウザの Web MIDI API を介して行われます(付録1)。Webアプリから利用しやすいように、以下のようにArduino風のJavascriptの関数や定数をJavascriptライブラリ(webio2.js)で定義しています。
定数名 | 内容 |
---|---|
HIGH, LOW | デジタル出力またはデジタル入力されたピンの状態 (HIGHは1、LOWは0) |
OUTPUT, INPUT, INPUT_PULLUP INPUT_ANALOG, OUTPUT_TONE, OUTPUT_NEOPIXEL, OUTPUT_IR, INPUT_IR |
pinMode()で設定する入出力のモード(値はマイコンにより異なる) (INPUT, OUTPUT, INPUT_PULLUP以外は独自の名称) |
D0~, A0~, G0~ | デジタル入出力ピンおよびアナログ入力ピン (値はマイコンにより異なる: 付録2参照) |
TEMP, HUMI, CO2 | I2C接続した温湿度センサSHT30/SHT31または CO2センサSCD30の測定値を入力する仮想ピン |
関数名 | 内容 |
---|---|
pinMode(pin, mode) | pinをmodeにする(modeは(1)の表参照) |
digitalRead(pin) | pinの値を読んでHIGH(1)またはLOW(0)の値を返す |
digitalWrite(pin, HIGH) digitalWrite(pin, HIGH, t) |
pinにHIGH(1)を出力する...値はHIGH(1)またはLOW(0) pinをt(ms) HIGH(1)にする |
analogRead(a) | aピンのアナログ値を読み、0~1023の値を返す。 TEMP(60), HUMI(61), CO2(62)は仮想ピン。 |
analogWrite(pin, value) | pinにvalue(0~255)を出力する |
sendNote(key, t) | ピン6にkeyのブザー音をt[ms]出力する keyの指定はmidiのノート番号(21~108)または文字列("A0"~"C8") |
playNote(key, t) | ブラウザからkeyの合成音をt[ms]出力する keyの指定はmidiのノート番号(21~108)または文字列("A0"~"C8") ただし 0 または "R" は休符 |
drumKick(key, t) drumSnare(key, t) drumHihat(key, t) |
ブラウザからドラムの合成音を出力する ブラウザからスネアの合成音を出力する ブラウザからハイハットの合成音を出力する |
talk(s) talk(s,voice) talk(s,voice,pitch) talk(s,voice,pitch,speed) |
ブラウザの合成音声でsを読み上げる(声はHaruka) 声を指定 日本語: 10 Google 日本語, 19 Ayumi, 20 Haruka, 21 Ichiro, 22 Sayaka 英語: 1 US, 2 UK Female, 3 UK Male 声と音程(0.1~2)を指定 声と音程と速さ(0.1~10)を指定 |
servo(pin, pos) | pinに接続したサーボの角度をpos(0~180)にする(pinは9と10を推奨) |
motor(lspeed, rspeed) | I2C接続した左右のモーターの速度をlspeed, rspeed(それぞれ-255~255)にする |
pixel(i, r,g,b) pixel(i, hue, brightness) |
NeoPixelのi番目のLEDをr,g,bにする(それぞれ0~255)。 NeoPixelのi番目のLEDを色相hue(0~255), 明るさbrightness(0~255 省略時255)にする。 NeoPixelはピン4に接続 |
IRsend(protocol, command, address) | IRリモート信号を出力する |
$(id) | document.getElementById(id)の短縮表現 |
上記とは別に、以下の関数をプログラム中に定義すると特別な役割を果たします。
関数名 | 内容 |
---|---|
setup() | ページが表示され、MIDIデバイスが認識された時にこの関数が呼び出される |
loop() | 20ms毎にこの関数が呼び出される |
irreceive(protocol, address, command) | IRリモコン信号を受信した時に呼び出される |
ここでは、マイコンにXIAO samd21を使い、LEDとスイッチを接続した場合の動作を中心に説明します。
MIDIデバイス(マイコン)をパソコンにUSB接続し、webio2.jsを使ったページ(このページもそうです)を表示すると、ページ冒頭にのような表示が現れます。これはSeeed XIAO M0という名前のMIDIデバイス(マイコン)が認識されていることを表しています。 | |
本物のMIDIデバイス(ここではnsx-39)を接続した場合は、ページ冒頭の表示がのようになり、ブラウザ画面の楽譜をMIDI音源(nsx-39)で演奏させるようなページを作ることができます。 WebIOは、「さまざまな独自のMIDIデバイスを作って演奏(?)するページを作る」ということに他なりません。 | |
USB接続のMIDIデバイスが無い場合は、のような表示になります。ボタンを押すと、以下のような画面が現れます。 |
以下では、MIDIデバイス(マイコン)として XIAO samd21 をUSB接続することを想定して説明しています。 XIAO ESP32C3 をBluetooth接続しても同じように動作します。
画面上のボタンが押されるとプログラムが実行される例(led1.html)です。
| ||
led1.html が表示され、MIDIデバイス(マイコン)が認識されると、setup関数が呼び出されます。
setupの関数定義の中の
pinMode(D9,OUTPUT);
はD9ピンをOUTPUTモード(出力)にする指示です。
pinMode関数はwebio2.jsの中で定義されています。また、D9はピン番号、OUTPUTは入出力モードで、その値もwebio2.jsの中で定義されています。値は使用するマイコンによって異なり、MIDIデバイス(マイコン)が認識された時点で自動的に値が決まります。XIAO samd21の場合、D9の値は9、OUTPUTの値は1です。
pinMode(9,1)が呼び出されると、 [0xE8,0x09, 0x0F] の3バイトのMIDIデータがMIDIデバイス(マイコン)に送信されます(MIDIデータの詳細は付録1)。
MIDIデバイス(マイコン)は3バイトのMIDIデータを受け取り、内容を解読し、9ピンを出力モードにします。
ボタンが押されると、
digitalWrite(D9,1)
が呼び出され、これはD9ピンに1を出力する指示です。digitalWrite関数はwebio2.jsの中で定義されていて、digitalWrite(9,1)が呼び出されると、 [0xE8, 0x09, 0x0F] の3バイトのMIDIデータがMIDIデバイスに送信されます(MIDIデータの詳細は付録1)。
MIDIデバイス(マイコン)は3バイトのMIDIデータを受け取ると、内容を解読し、9ピンに1(高い電圧)を出力し、LEDが点灯します。
同様に、ボタンが押されると、
digitalWrite(D9,0)
が呼び出され、 [0xE8, 0x09, 0x0F] の3バイトのMIDIデータがMIDIデバイスに送信されます。MIDIデバイス(マイコン)は3バイトのMIDIデータを受け取ると、9ピンに0(低い電圧)を出力し、LEDが消灯します。
スイッチの状態(オフで1, オンで0)をブラウザ画面に表示する例(button2.html)です。LEDも連動して点灯・消灯します。
| ||
button2.html が表示され、MIDIデバイス(マイコン)が認識されると、setup関数が呼び出されます。
setupの関数定義の中に記載されている
pinMode(D2,INPUT_PULLUP);
はD2ピンをINPUT_PULLUPモードにする指示で
pinMode(D9,OUTPUT);
はD9ピンをOUTPUTモードにする指示です。D2はピン番号、INPUT_PULLUPは入出力モードで、XIAO samd21の場合、D2の値は2、INPUT_PULLUPの値は2になっています。
pinMode(9,1)が呼び出されると、 [0xE8,0x09, 0x01] の3バイトのMIDIデータがMIDIデバイス(マイコン)に送信され、MIDIデバイス(マイコン)はこれを受け取り、内容を解読し、9ピンを出力モードにします。
pinMode(2,2)が呼び出されると、 [0xE8,0x02, 0x02] の3バイトのMIDIデータがMIDIデバイス(マイコン)に送信され、MIDIデバイス(マイコン)はこれを受け取り、内容を解読し、2ピンをプルアップ入力モードにします。2ピンにはスイッチがつながっていて、スイッチがオフの時に1(高い電圧)、オンの時に0(低い電圧)になります。マイコンは定期的(20ms毎)にこの値を読み取り、「初回および変化があった時」に、[0xE8,0x09, 0x0E](ピンが0の時)または[0xE8,0x09, 0x0F](ピンが1の時)の3バイトのMIDIデータをパソコンに送信します。
Javascriptプログラムでは、20ms毎に実行されるloop関数の中の
val=digitalRead(D2);
で、D2ピンの値(0または1)がvalに代入されます。続く
digitalWrite(D9,val);
で、[0xE8, 0x09, 0x0E](valが0の時)または[0xE8, 0x09, 0x0F](valが1の時)の3バイトのMIDIデータがMIDIデバイス(マイコン)に送信されます。
MIDIデバイス(マイコン)は3バイトのMIDIデータを受け取ると、内容を解読し、9ピンに0(低い電圧)または1(高い電圧)を出力します。
loop関数の中では引き続き、
$("VAL").innerHTML=val;
で「VAL」の箇所(<span id=VAL ...></span>)にvalの値(0または1)を表示します。
機能 | send(PC → I/O) | receive(I/O → PC) | JavaScript関数 | 備考 | |||||
---|---|---|---|---|---|---|---|---|---|
byte1 | byte2 | byte3 | byte1 | byte2 | byte3 | ||||
8x | [midi] NoteOff | 1000nnnn | 0kkkkkkk | 0vvvvvvv | 1000nnnn | 0kkkkkkk | 0vvvvvvv | 音を停止 | |
9x | [midi] NoteOn | 1001nnnn | 0kkkkkkk | 0vvvvvvv | 1001nnnn | 0kkkkkkk | 0vvvvvvv | sendNote(key, t) sendNote(key, t, ch) | key0-125のブザー音をt[ms]出力 ch0-15を指定できる |
Ax | [midi] Pressure | 1010nnnn | 0kkkkkkk | 0vvvvvvv | |||||
Bx | [midi] Control Change | 1011nnnn | 0ccccccc | 0vvvvvvv | |||||
Reset | 1011nnnn | 01111001 | 00000000 | reset() | Reset All Control | ||||
AllNoteOff | 1011nnnn | 01111011 | 00000000 | All Note Off | |||||
Cx | [midi] Program Change | 1100nnnn | 0ppppppp | setVoice(ch, voice) | ch0-15を音源0-127に | ||||
Dx | [midi] Pressure | 1101nnnn | 0vvvvvvv | ||||||
Ex | [midi] Pitch Bend | 1110nnnn | 0lllllll | 0mmmmmmm | |||||
(Reserved) 512Byte | 11100xxx (E0-E7) | 0xxxxxxx | 0xxxxxxx | 11100xxx (E0-E7) | 0xxxxxxx | 0xxxxxxx | |||
PinMode DigitalOut |
11101000 (E8) | 00pppppp | 0000mmmm 0000111v | pinMode(pin, mode) digitalWrite(pin,val) digitalWrite(pin,1,t) |
pin0-63のpinModeをmode0-13に pin0-63を0/1に tを指定した場合は t[ms] 1に | ||||
DigitalIn | 11101000 (E8) | 00pppppp | 0000111v | digitalRead(pin) | pin0-63の値0/1 (20ms毎に更新) | ||||
AnalogOut | 11101000 (E8) | 01vppppp | 0vvvvvvv | analogWrite(pin, val) | pin0~31を0-255に | ||||
ServoMotor Motor |
11101001 (E9) | 00vppppp 00v1111p |
0vvvvvvv 0vvvvvvv | servo(pin, val) servo(pin, val, t) motor(lspeed, rspeed) |
pin0~29のサーボモーターを0-180に tを指定した場合はt[ms]後に停止 L(30) R(31)モーターのスピードを -128~127に | ||||
(Reserved) 32Byte | 11101001 (E9) | 01xxxxxx | 0xxxxxxx | ||||||
AnalogIn | 11101001 (E9) | 0vvvvvpp | 0vvvvvvv | analogRead(pin) | TEMP(0:60),HUMI(1:61),CO2(2:62)の値0-4095 | ||||
AnalogIn | 1110101v (EA-EB) | 0vvppppp | 0vvvvvvv | analogRead(pin) | pin0~31の値0-1023(20ms毎に更新) | ||||
NeoPixel | 11101010 (EA) | 0rgbllll | 0rrrrrrr | Pixel(LED, R,G,B) | LED0-15の色をR(0-255)G(0-255)B(0-255)に | ||||
11101011 (EB) | 0ggggggg | 0bbbbbbb | |||||||
IRsend | 11101100 (EC) | 0ppppppp | 0000aacc | IRsend(&IRDATA) | IRリモート信号を送信 IRDATA内に protocol, address, command | ||||
11101101 (ED) | 0aaaaaaa | 0aaaaaaa | |||||||
11101110 (EE) | 0ccccccc | 0ccccccc | |||||||
IRreceive | 11101100 (EC) | 0ppppppp | 0000aacc | IRreceive(&IRDATA) | IRリモート信号を受信 IRDATA内に protocol, address, command | ||||
11101101 (ED) | 0aaaaaaa | 0aaaaaaa | |||||||
11101110 (EE) | 0ccccccc | 0ccccccc | |||||||
(Reserved) 64Byte | 11101111 (EF) | 0xxxxxxx | 0xxxxxxx | 11101111 (EF) | 0xxxxxxx | 0xxxxxxx | |||
Fx | [midi] SysEx | 1111xxxx | 1111xxxx |
|
|
|
|
|