WebIO2: ブラウザ ものづくり(XIAO SAMD21版)[WebIOtest][WebIOtest2]

小山智史

コンピュータの仕組み ATtiny2313版 - - - - -
Arduinoでものづくり ATtiny4313版 ATmega328P版 NANO版 - ESP8266版 XIAOSAMD21
tinyBasicでものづくり - - NANO版 ProMicro版 ESP8266版 XIAOSAMD21
Pythonでものづくり - - - - - XIAOSAMD21
ブラウザでものづくり - - - ProMicro版 - XIAOSAMD21

目次


0. 準備
1. コマンド操作
2. デジタル出力(1): LEDの点滅
3. デジタル入力: スイッチ操作でLEDのオンオフ
4. アナログ出力: LEDの明るさを変える
5. アナログ入力
6. デジタル出力(2): 数字表示LED
7. デジタル出力(3): 液晶ディスプレイ
8. センサーの利用
9. ブザー音で演奏
10. 合成音声でおしゃべり
11. イルミネーション
12. 赤外線リモコン
13. 動くものを作る
14. 押しボタン信号機
(付録1) 入出力モジュール
(付録2) 使用する主な部品
(付録3) WebIOの主な仕様
(付録4) Midiコマンドとの対応


 WebIOは、ブラウザに搭載されているWeb Midi APIの機能を使って、IO制御を行っています。FirmataのWeb版のような感じですが、Midiコマンドと入出力の対応はFirmataとは異なります(付録4)。

 システムの概要は下図のようになっています。Arduinoにはあらかじめプログラム(webio2.ino)を書き込んでおきます。

 プログラム(HTML+JavaScript)はパソコンまたはサーバ上に置き、パソコンのブラウザで表示し、ブラウザ画面で操作します。ブラウザから制御できるのは「自身のパソコンに接続されているデバイス」であり、遠隔操作できるというわけではありません。動作の確認はWeb Midi API に対応しているChromeを使い、Windows10で行っています(EdgeやFirefoxでも動作すると思います)。

 ブラウザ画面で操作するさまざまなWebコンテンツを作ることができます。小中学校等でのICT/IoT学習にも利用できますし、必要ならパソコンに接続した温湿度センサのデータをブラウザから遠方のサーバに送るようなこともできるので、さまざまな応用が可能です。

0. 準備

0.1 ブレッドボードの使い方

 ここでは下図左のブレッドボード(EIC-301)を使います。ボードの内部は下図右のように接続されています。

(外観) (内部の接続)

 ブレッドボードにXIAOを差し込み、GNDと3V3の端子を図のように接続します。USBケーブルをパソコンに接続すると、電源(3.3V)がパソコンから供給されます。XIAOに見やすいラベルを貼っておくことをお勧めします(テプラファイル)。

(回路図) (実体配線図)

 初めてブレッドボードを使う場合は、練習としてLEDと抵抗を下図左のように接続して点灯を確認しましょう。電源はパソコンからUSB端子を通じて供給され、電流の流れは下図右のようになります。ブレッドボードの内部の結線も含めて「電流が流れる経路」を意識することが重要です。

(回路図) (実体配線図) (電流の流れ)

(練習) ブレッドボードで下記の回路を組み立て、スイッチを押すとLEDが点灯することを確認しなさい。

0.2 ソフトウェアの準備[webio2_20230303.zip]

 上のzipファイルをダウンロードして解凍してください。

(1) Arduino用プログラム: webio2.ino
Seeeduino XIAOにwebio2.ino(スケッチ)を書き込んでおきます。2章以降で、LEDを接続して実際にIO制御を行う時に必要になります。Arduino UNOやnanoは利用できないので注意してください。Arduinoの準備ができれば、このページを使ってすぐに動作を確かめることができます。また、15.2の動作テスト用のページでさまざまな動作を確かめることができます。
(2) JavaScriptライブラリ: webio2.js
2章以降で、LEDの制御など実際にIO制御を行うWebページの中で「<script src=webio2.js></script>」のように使います。このページもそのようになっているので、フォーム入力で実際に試すことができます。

1. コマンド操作(JavaScript命令の実行)

コマンド:

 上のコマンド入力欄にJavaScriptの命令文を入力し、実行ボタンを押すかEnterキーを押すと、その命令が実行されます。次のように入力してみてください。

alert(100)

これは、「100をアラート表示しなさい」というJavaScriptの「命令」を表しています。

 以下のふたつめの例では文字列と数値((100+200)の演算結果)の連接演算(+)になっていて、数値(演算結果)が文字列に変換されて文字列の連接演算が行われます。

alert(100+200) alert("答えは"+(100+200))

2. デジタル出力(1): LEDの点滅

 ここから以降は、WebIOのプログラムを書き込んだSeeeduino XIAOを接続し、ブラウザはChromeまたはEdgeを使って行ってください。

2.1 LEDを点灯・消灯する

 以下の回路を組み立ててください。

(回路図) (実体配線図)
コマンド:

 LEDはD9ピンに接続します。「digitalWrite」というコマンドでD9ピンに高い電圧を出力したり低い電圧を出力したりすることができます。上のコマンド入力欄に

digitalWrite(D9,1) または digitalWrite(D9,HIGH)
のように入力し、実行ボタンを押すかEnterキーを押すと、D9ピンに高い電圧(3.3V)が出力され、接続したLEDが点灯します。

digitalWrite(D9,0) または digitalWrite(D9,LOW)
と操作すると、D9ピンに低い電圧(0V)が出力され、LEDは消灯します。「digitalWrite(D9,1)」または「digitalWrite(D9,HIGH)」は「D9ピンに1(高い電圧)を出力しなさい」という意味です。

 LEDが点灯する時の電流の流れは下図のようになります。下図中のスイッチをJavaScriptの命令で切り替えていると考えるといいでしょう。

 なお、「digitalWrite()」や「D9」や「HIGH」「LOW」はwebio2.jsの中で定義されています。「D9」は単に「9」としても構いません。

(練習)「digitalWrite(D9,1)」および「digitalWrite(D9,0)」を実行した時のD9ピンの電圧を、テスターで測りなさい。

(練習)LEDを他のピンにつなぎ替えて、点灯・消灯してみなさい。

2.2 プログラムによるLEDの点滅

 プログラムのはじめの一歩は「Lチカ」です。以下のWebページを作成し、ブラウザで表示してください。冒頭の5行はWebページの常套句で、その先がWebページの本体とプログラムになります。

 Webページは単に「LEDの点滅」と表示するだけです。「<script>」と「</script>」の間がJavaScriptプログラムになります。

 プログラムは、はじめに広域変数としてledの値を0にしています。ledはLEDの点灯状態(0で消灯状態、1で点灯状態)を表しています。次にsetup()とtoggle()の2つの関数を定義しています。

 ここで、「setup()」は特別な関数の名前になっていて、ページが表示された時にこの関数が実行されます。そこでは、まずpinModeでLEDが接続されているD9を出力(OUTPUT)にしています。OUTPUTは予め定義された組み込み変数です。次の「setInterval("toggle()",1000)」で、1000ms(1秒)毎に「toggle()」が呼び出されるよう指示しています。toggle()が呼び出されると、LEDの点灯状態ledを0なら1に、1なら0にし、その値をそのままdigitalWrite()で出力します。

 JavaScriptプログラムでは「delay」や「wait」などの関数は利用できず、setInterval()やsetTimeout()を使ってプログラムを作ります。

blink.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // ledを出力に setInterval("toggle()",1000); // 1秒毎にtoggle()を実行 } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に digitalWrite(D9,led);// D9ピンにledを出力 } </script> <!-- ここまで --> </body></html>

2.3 LEDの点灯・消灯

 画面上のボタンが押されるとプログラムが実行される例です。「<button>点灯</button>」でのようにボタンが表示されます。このボタンを押した時にプログラムが実行されるようにするには「<button onclick=プログラム>点灯</button>」のように書きます。

 以下の例では「点灯」ボタンが押されると「digitalWrite(D9,1)」が呼び出されます。

button0.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <button onclick=digitalWrite(D9,1)>点灯</button> <button onclick=digitalWrite(D9,0)>消灯</button> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9ピンを出力に } </script> <!-- ここまで --> </body></html>


3. デジタル入力: スイッチ操作でLEDのオンオフ

3.1 スイッチが押されているかどうか調べる

 下図左のようにD2ピンにスイッチを接続し、「pinMode(D2, INPUT_PULLUP)」とすると、下図右のようにマイコンに内蔵された抵抗が有効になります。すると、D2ピンはスイッチをオンにすると低い電圧(0V)になり、スイッチをオフにすると高い電圧(3.3V)になります。この抵抗を「プルアップ抵抗」といいます。「高い電圧に引っ張り上げる抵抗」というような意味です。

回路図
スイッチを接続
回路図
プルアップ抵抗

 コマンド入力欄を使い、D2ピンをプルアップ入力に設定した後、D2ピンが高い電圧(1)か低い電圧(0)かをアラート表示してみましょう。

コマンド:
pinMode(D2,INPUT_PULLUP) alert(digitalRead(D2))
回路図

(練習) D2ピンに接続したスイッチを押した時と放した時のスイッチ両端の電圧を、テスターで測りなさい。

(練習) スイッチを押した時と放した時の「alert(digitalRead(D2))」の結果を確かめなさい。

3.2 スイッチの状態をデジタル値としてブラウザ画面に表示する

 以下のプログラムはスイッチの状態をデジタル値としてブラウザ画面に数字で表示します。スイッチを押すと表示が変わります。

button1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>デジタル値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <center><span id=VAL style='font-size:80pt'></span></center> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2ピンをプルアップ入力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(D2); // D2ピンの値を読み取りvalに代入 $("VAL").innerHTML=val; // valをブラウザ画面に表示 } </script> <!-- ここまで --> </body></html>

3.3 スイッチ操作でLEDを点灯・消灯する

 以下は、ブラウザ画面への表示に加え、LEDの点灯・消灯も行うようにしたプログラムです。

button2.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>デジタル値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2ピンをプルアップ入力に pinMode(D9,OUTPUT); // D9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=digitalRead(D2); // D2ピンの値を読み取りvalに代入 digitalWrite(D9,val); // valの値をD9ピンに出力 $("VAL").innerHTML=val; // valをブラウザ画面に表示 } </script> <!-- ここまで --> </body></html>

(練習) スイッチを押した時にLEDが点灯しブラウザ画面に「ON」が表示され、スイッチを放した時にLEDが消灯しブラウザ画面に「OFF」が表示されるようにしなさい。

3.4 スイッチ操作で交互に点灯・消灯する

 以下のプログラムは、スイッチを押すと交互にLEDが点灯・消灯します。考え方は、「スイッチが押された瞬間に(つまりさっき押されていなくて今押されたら)LED表示を反転する」というものです。buttonには「今のスイッチの状態(0または1)」、lastbuttonには「さっきのスイッチの状態(0または1)」、変数ledには「今のLEDの点灯状態(1が点灯、0が消灯)」を保存します。

 まず現在のD2ピンの状態(1または0)を読み取り、buttonに入れます。そして、スイッチがさっきまで押されていなくて今押されているならledの値を0なら1、1なら0にします。その後、D9ピン(LED)にledの値を出力し、今のスイッチの状態を記憶します。

button3.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) var button=1; // 現在のbuttonの状態 var lastbutton=1; // 直前のbuttonの状態 function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2ピンをプルアップ入力に pinMode(D9,OUTPUT); // D9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- button=digitalRead(D2); // D2ピンを読みbuttonに代入 if(button!=lastbutton && button==0)// buttonが前と違いかつ0なら led=(led==0?1:0); // ledが0なら1に、1なら0に digitalWrite(D9,led); // D9ピンにledを出力 lastbutton=button; // lastbuttonを更新 } </script> <!-- ここまで --> </body></html>

(練習) 緑色LEDを増設し、スイッチを押すと赤色LEDと緑色LEDが交互に点灯するようにしなさい。

3.5 スイッチを4回押すと点灯する

 以下のプログラムは、スイッチ操作4回に一度LEDが点灯します。

 スイッチが押されると、Cにスイッチが押された回数を記憶します。つまり、スイッチがさっきまで押されていなくて今押されたならCの値に1を加えます。その後、「C%4==0」つまりCの値を4で割った余りが0であればLEDを点灯し、そうでなければLEDを消灯します。最後に、今のスイッチの状態を記憶します。

button4.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var C=0; // カウントCを0にする var button; // 現在のbuttonの状態 var lastbutton; // 直前のbuttonの状態 function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2ピンをプルアップ入力に pinMode(D9,OUTPUT); // D9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- button=digitalRead(D2); // D2ピンを読みbuttonSに代入 // buttonが直前が1で現在が0ならCをカウントアップ if(lastbutton==1 && button==0) C++; if(C%4==0) digitalWrite(D9,1); // Cが4の倍数なら点灯 else digitalWrite(D9,0); // そうでなければ消灯 lastbutton=button; // lastbuttonを更新 } </script> <!-- ここまで --> </body></html>

(練習) 「C%4==0」の箇所を「C%7==0」や「C%4!=0」などに変えて、どのような動作になるか調べなさい。

(練習) 2個の押しボタンスイッチを使い、一方のスイッチを押すとLEDが点灯し、もう一方のスイッチを押すと消灯するようにしなさい。


4. アナログ出力: LEDの明るさを変える

4.1 アナログ出力する

 はじめに、コマンド入力でLEDの明るさを変えてみます。analogWrite(ピン,値)は、指定したピンに0~255のアナログ値を出力します。0~255の値に応じて電圧(0~3.3V)ピンの電圧は0~3.3Vになります。

コマンド:
pinMode(D9,OUTPUT) analogWrite(D9,0) analogWrite(D9,255) analogWrite(D9,100) analogWrite(D9,10)
回路図

 以下の例ではWeb画面上のスライダーでLEDの明るさをコントロールします。「<input type=range ...>」の箇所でスライダーの表示を指示していて、「value=0」は初期値を0、「min=0 max=255 step=1」はスライダーの返す値を0~255で1きざみにする指示です。また、「onchange=...」の箇所にスライダーの値が変化した時に呼び出すプログラムを書いています。

slider.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <input type=range style="width:300px" onchange=analogWrite(D9,this.value) value=0 min=0 max=255 step=1> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9ピンを出力に } </script> <!-- ここまで --> </body></html>


5. アナログ入力

5.1 アナログ入力値を調べる

 下図左のようにA1ピンにボリュームを接続すると、ボリュームの操作に応じてA1ピンの電圧は0~3.3Vに変化します。analogRead(A1)は、A1ピンの電圧(0~3.3V)に応じて0~1023の値を返します。

 コマンド入力欄を使い、をanalogRead(A1)でA1ピンの値を読み取り、アラート表示してみましょう。

コマンド:
pinMode(A1,INPUT_ANALOG) alert(analogRead(A1))
回路図

(練習) ボリュームを操作し、A1ピンの電圧がどの範囲で変化するか、テスターで測りなさい。

(練習) ボリュームを操作し、「alert(analogRead(3))」の結果を確かめなさい。

5.2 アナログ値をブラウザ画面に表示する

 以下のプログラムはA1ピンの電圧値を0~1023の値としてブラウザ画面に表示します。

analog.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A1); } </script> <!-- ここまで --> </body></html>

 以下のプログラムは読み取ったアナログ値をブラウザにバーグラフで表示します。

bargraph.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> A1: <meter id=A1 style="width:260px;height:60px" max=1023></meter> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("A1").value=analogRead(A1); } </script> <!-- ここまで --> </body></html>

5.3 アナログ値に応じてLEDの点滅時間を変える

 analogRead(A1)は、A1ピンの電圧(0~3.3V)に応じて0~1023の値をとります。以下のプログラムはこれを利用し、ボリュームの値に応じてLEDの点滅時間が変化します。

analogblink.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG);// A1ピンをアナログ入力に pinMode(D9,OUTPUT); // D9ピンを出力に toggle(); } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に digitalWrite(D9,led); // D9ピンにledを出力 setTimeout("toggle()",analogRead(A1)); // 指定の時間後にtoggle() } </script> <!-- ここまで --> </body></html>

5.4 アナログ値に応じてLEDを点灯・消灯する

 以下のプログラムは、ボリュームのアナログ値(0~1023)が400未満の時にLEDを点灯します。

autolight.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に pinMode(D9,OUTPUT); // D9ピンを出力にする } function loop(){ // --- 20ms毎に自動実行 --- var val=analogRead(A1); // A1ピンの値を読取りvalに代入 if(val<400) digitalWrite(D9,1);// ledを点灯 else digitalWrite(D9,0);// ledを消灯 } </script> <!-- ここまで --> </body></html>


6. デジタル出力(2): 数字表示LED

 この章はありません。


7. デジタル出力(3): 液晶ディスプレイ

 この章はありません。


8. センサーの利用

8.1 スイッチをセンサーとして使う

 押しボタンスイッチやスライドスイッチは、操作用のスイッチですが、センサーとしても活躍しています。例えば、CD/DVDデッキやコピー機やプリンタなど動きを伴う機器には、所定の位置に来たがどうかを検知するために、マイクロスイッチが必ずといっていいほど使われています。このような使われ方をするスイッチを「リミットスイッチ」と呼ぶこともあります。

 ふたつの金属片を接触させるだけでスイッチ(センサー)となるので、オリジナルのスイッチを作ることも難しくはありません。所定の水位になったかどうかを検知するピンポン球を使った浮力スイッチ、傾けると金属ボールが移動する傾斜スイッチなど、用途に応じて工夫するのも楽しいでしょう。

8.2 明るさをブラウザ画面に表示する(明るさの計測)

 5.2のボリュームの代わりに明るさセンサー(CDS)をつないでみましょう。明るくなるほどCDSの抵抗値が低くなり、A1ピンの電圧は高くなります。プログラムは5.2と同様です。

analog.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A1); } </script> <!-- ここまで --> </body></html>

 以下のプログラムは読み取ったアナログ値をブラウザにバーグラフで表示します。

bargraph.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> A1: <meter id=A1 style="width:260px;height:60px" max=1023></meter> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("A1").value=analogRead(A1); } </script> <!-- ここまで --> </body></html>

8.3 暗くなるとLEDを点灯する

 街路灯は、暗くなると点灯します。以下のプログラムは、明るさの値が400未満の時にLEDを点灯します。プログラムは5.4と同じです。ただし、明るさの閾値「400」の値は適切な値に変更する必要があります。

autolight.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に pinMode(D9,OUTPUT); // D9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=analogRead(A1); // A1ピンの値を読取りvalに代入 if(val<400) digitalWrite(D9,1);// ledを点灯 else digitalWrite(D9,0);// ledを消灯 } </script> <!-- ここまで --> </body></html>

 街路灯では、境界値付近でledが点灯したり消灯したり不安定になるのを避けるために、下図のような「ヒステリシス特性」を持たせます。

ledが消灯している時(ledSが0)に400以下の明るさになったらledを点灯状態にし(ledSを1)、ledが点灯している時(ledSが1)に500以上の明るさになったらledを消灯状態にします(ledSを0)。

hysteresis.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に pinMode(D9,OUTPUT); // D9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- var val=analogRead(A1); // 明るさを読み取りvalに代入 if(led==0 && val<400) led=1; else if(led==1 && val>=500) led=0; digitalWrite(D9,led); // D9ピンにledを出力 } </script> <!-- ここまで --> </body></html>

(練習) ヒステリシス特性の効果を確かめなさい。また、400と500の値を変えて、適切な値をみつけなさい。

8.4 音を検知する: 音量センサー

 以下のプログラムは音量をバーグラフで表示します。5.3と同じプログラムです。

bargraph.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> A1: <meter id=A1 style="width:260px;height:60px" max=1023></meter> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("A").value=analogRead(A1); } </script> <!-- ここまで --> </body></html>

 以下のプログラムは、音を検知したらLEDを3秒点灯するものです。

sound3.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>LEDの点灯・消灯</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>LEDの点灯・消灯</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) var val; // 現在の音量 var lastval=0; // 直前の音量 function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に pinMode(D9,OUTPUT); // D9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- val=analogRead(A1); // 音量を読み取りvalに代入 if(led==0 && val>=400){// 消灯状態で音量が400を超えたら led=1; // 点灯状態にし setTimeout("led=0",3000);// 3秒後に消灯 } digitalWrite(D9,led); // D9ピンにledを出力 lastval=val; // lastvalを更新 } </script> <!-- ここまで --> </body></html>

(練習) 手をたたくとカウントアップしブラウザに回数を表示するプログラムを作りなさい。

8.5 赤外線反射センサーを使う

 赤外線の反射光で数mm程度の距離に反射物を検知するセンサーです。モーターカーと組み合わせると、ライントレースや衝突回避などが可能になります。以下のプログラムは5.2と同じものです。センサを接続して、analogRead(A1)でどの程度の値が返されるかがわかります。

analog.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>アナログ値の表示</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <span id=VAL style='font-size:80pt'></span> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- $("VAL").innerHTML=analogRead(A1); } </script> <!-- ここまで --> </body></html>


9. ブザー音で演奏

9.1 コマンド操作で音を出す

コマンド:

 初めに「pinMode(D9,OUTPUT_TONE)」のように、ブザーを接続するピンを指定します。その後、「sendNote(key,長さ)」で指定したkeyの音を出すことができます。D9ピンにブザーを接続し、以下の操作で確認してください。

pinMode(D9,OUTPUT_TONE); sendNote(67,200) sendNote(67,200) sendNote(67,200) sendNote(72,2000) sendNote("G4",200) sendNote("G4",200) sendNote("G4",200) sendNote("C5",2000)
回路図

keyはmidiのノート番号(21~108)または文字列("A0"~"C8")で指定します。また、長さは[ms]で指定します。長さを省略すると300[ms]となります。

 sendNote()ではなくplayNote()を使うと、ブラウザから音を出すことができます。以下の操作で確認してください。

playNote(67,200) playNote(67,200) playNote(67,200) playNote(72,2000) playNote("G4",200) playNote("G4",200) playNote("G4",200) playNote("C5",2000)

 ブラウザからドラム音を出すこともできます。

drumKick() drumSnare() drumHihat()

9.2 プログラムで演奏する

 以下は、簡単な演奏プログラムで、D9ピンに接続したブザーから音が出ます。midi音源を接続しても動作します。Javascriptにはdelay()という関数がないため、setTimeout()で次の音に進みます。

sendnotes.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>ブザーで演奏</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>ブザーで演奏</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT_TONE); // D9ピンにブザーを接続 setTimeout("sendNote1()",1000); // 1秒後に演奏開始 } function sendNote1(){ // 1音目 sendNote("G4",200); // 演奏 setTimeout("sendNote2()", 1000);// 1秒後に2音目 } function sendNote2(){ // 2音目 sendNote("G4",200); // 演奏 setTimeout("sendNote3()", 1000);// 1秒後に3音目 } function sendNote3(){ // 3音目 sendNote("G4",200); // 演奏 setTimeout("sendNote4()", 1000);// 1秒後に4音目 } function sendNote4(){ // 4音目 sendNote("C5",2000); // 演奏 } </script> <!-- ここまで --> </body></html>

 以下は、ブラウザで演奏するプログラムです。

playnotes.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>ブラウザで演奏</title> <script src=webio2.js></script> </head><body> <!-- ここからWebページの本体とプログラム --> <h2 align=center>ブラウザで演奏</h2> <script> function setup(){ // --- はじめに自動実行 --- setTimeout("playNote1()",1000); // 1秒後に演奏開始 } function playNote1(){ // 1音目 playNote("G4",200); // 演奏 setTimeout("playNote2()", 1000);// 1秒後に2音目 } function playNote2(){ // 2音目 playNote("G4",200); // 演奏 setTimeout("playNote3()", 1000);// 1秒後に3音目 } function playNote3(){ // 3音目 playNote("G4",200); // 演奏 setTimeout("playNote4()", 1000);// 1秒後に4音目 } function playNote4(){ // 4音目 playNote("C5",2000); // 演奏 } </script> <!-- ここまで --> </body></html>

9.3 楽譜を演奏する

 以下は、楽譜データを参照しながら演奏するプログラムです。楽譜データがプログラムと分離されているので、長い曲も表しやすくなっています。midi音源を接続しても動作します。

midimelody.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>ブザーで楽譜を演奏</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>ブザーで楽譜を演奏</h2> <!-- ここからプログラム --> <script> // ------------------------------------------------------------- var notes=[ // 楽譜データ[音符, Note] [4,"C5"], [8,"G4"],[8,"G4"],[4,"A4"],[4,"G4"], [4,""], [4,"B4"], [4,"C5"] ]; // ------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var p=0; function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT_TONE); // D9ピンにブザーを接続 playNotes(); } function playNotes(){ var T=60000/TEMPO*4/notes[p][0]; // 4分音符 0.5秒, 8分音符 0.25秒 var u=notes[p][1]; sendNote(midiPitch[u], T*.9); if(++p<notes.length) setTimeout("playNotes()", T); } </script> <!-- ここまで --> </body></html>

 楽譜はさまざまな方法で表現することができます。以下は、少し長い曲を演奏するプログラムです。

playmidi.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>ブザーで電子オルゴール</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>ブザーで電子オルゴール</h2> <!-- ここからプログラム --> <script> // ------------------------------------------------------------- var notes="RDDBAGDR RDDBAGER REEcBAFR RdddcABR RDDBAGDR RDDBAGER REEcBAdd ddedcAGR dR BBBR BBBR BdGABRRR cccccBBB BAABAR dR BBBR BBBR BdGABRRR cccccBBB ddcAGR gR"; // ------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var p=0; function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT_TONE); // D9ピンにブザーを接続 playNotes(); } function playNotes(){ for(;p<notes.length&&notes.charAt(p)==" ";p++); // スペースは無視 var T=60000/TEMPO*4/8; // 8分音符 0.25秒 固定 var c=notes.charAt(p); if(c.toUpperCase()!="R"){ // 休符でなければ if(c==c.toLowerCase()) c=c.toUpperCase()+"5"; // 小文字ならC5-B5 else c=c+"4"; // 大文字ならC4-B4 sendNote(midiPitch[c], T*.9); } if(++p<notes.length) setTimeout("playNotes()", T); } </script> <!-- ここまで --> </body></html>

 以下は、「私だけの電子オルゴール」のように「ドドソソララソー」のように楽譜を入力できるようにした例です。


9.4 オモチャのドラムの自動演奏(詳しくはこちら)

 オモチャのドラムを左右2つのスティックで叩きます。左のスティックはセンタードラム(L)とサイドドラム(S)、右のスティックはセンタードラム(R)とハイハット(H)を担当し、サーボモータでそれぞれのドラム位置にスティックを移動します。

drum1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>ドラムの自動演奏</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>ドラムの自動演奏</h2> <button onclick=playNotes()>演奏開始</button> <!-- ここからプログラム --> <script> // ------------------------------------------------------------------------- var notes=[ // 楽譜データ[音符, ドラム] [4,"L"],[8,"L"],[8,"R"],[4,"L"],[4,"R"], [4,""], [4,"S"], [4,"H"] ]; // ------------------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var Td=100; // ドラムを打つ時間(100ms)...バチによって調整 var Ts=500; // サーボモーターの移動時間 var Lmotor=5, Rmotor=4, Lservo=9, Rservo=8; // モータとサーボモータのpin var Lstick={L:150, S:80}; // ドラムの左サーボの角度(個別に調整) var Rstick={R:0, H:60}; // ドラムの右サーボの角度(個別に調整) var p=-1; function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT_TONE); // D9ピンにブザーを接続 } function playNotes(){ var T, u; if(p<0) T=Ts; // 初回は準備 else{ // 1音目からは T=60000/TEMPO*4/notes[p][0]; // 4分音符 0.5秒, 8分音符 0.25秒 u=notes[p][1]; // L R S H if(u.match(/L/) || u.match(/S/)) digitalWrite(Lmotor, 1, Td); // 左を叩く if(u.match(/R/) || u.match(/H/)) digitalWrite(Rmotor, 1, Td); // 右を叩く } if(++p<notes.length){ // 次音の準備 u=notes[p][1]; if(u.match(/L/)) setTimeout("servo(Lservo,"+Lstick["L"]+",Ts)", T/2); else if(u.match(/S/)) setTimeout("servo(Lservo,"+Lstick["S"]+",Ts)", T/2); if(u.match(/R/)) setTimeout("servo(Rservo,"+Rstick["R"]+",Ts)", T/2); else if(u.match(/H/)) setTimeout("servo(Rservo,"+Rstick["H"]+",Ts)", T/2); setTimeout("playNotes()", T); }else p=-1; // 演奏終了 } </script> <!-- ここまで --> </body></html>



9.5 オモチャの鉄琴の自動演奏(詳しくはこちら)

 オモチャの鉄琴を左右2つのスティックで叩きます。左のスティックはドレミファ(C4 D4 E4 F4)、右のスティックはソラシド(G4 A4 B4 C5)を担当し、サーボモータでそれぞれの位置にスティックを移動します。

tekkin1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>鉄琴の自動演奏</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>鉄琴の自動演奏</h2> <button onclick=playNotes()>演奏開始</button> <!-- ここからプログラム --> <script> // ------------------------------------------------------------------------- var notes=[ // 楽譜データ[音符, Note] [4,"C5"], [8,"G4"],[8,"G4"],[4,"A4"],[4,"G4"], [4,""], [4,"B4"], [4,"C5"] ]; // ------------------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var Td=80; // 鉄琴を打つ時間(80ms)...バチによって調整 var Ts=500; // サーボモーターの移動時間 var Lmotor=5, Rmotor=4, Lservo=9, Rservo=8; // モータとサーボモータのpin var Langle={C4:10, D4:35, E4:60, F4:80}; // 鉄琴の左サーボの角度(個別に調整) var Rangle={G4:75, A4:95, B4:120,C5:155} // 鉄琴の右サーボの角度(個別に調整) var p=-1; function setup(){ // --- はじめに自動実行 --- } function playNotes(){ var T, u; if(p<0) T=Ts; // 初回は準備 else{ // 1音目からは T=60000/TEMPO*4/notes[p][0]; // 4分音符 0.5秒, 8分音符 0.25秒 u=notes[p][1]; // C4 D4 ... A4 B4 C5 if(u in Langle) digitalWrite(Lmotor, 1, Td); // 左を叩く if(u in Rangle) digitalWrite(Rmotor, 1, Td); // 右を叩く } if(++p<notes.length){ // 次音の準備 u=notes[p][1]; if(u in Langle) setTimeout("servo(Lservo,"+Langle[u]+",Ts)", T/2); if(u in Rangle) setTimeout("servo(Rservo,"+Rangle[u]+",Ts)", T/2); setTimeout("playNotes()", T); }else p=-1; // 演奏終了 } </script> <!-- ここまで --> </body></html>


9.6 みんなでセッション(詳しくはこちら)

 複数の楽器で「セッション」も楽しめます。グループ学習でやってみると面白いと思います。ブラウザ画面から音が出ますので、楽器が1台でも十分楽しめます。

 それぞれのパソコンのブラウザ画面でを押すと、「正10秒」まで待って演奏を開始します。ボタンを押すタイミングが少しずれても大丈夫です。パソコンの時刻同期の設定をきちんとしておくと時刻のズレを少なくできます(NICTのページで確認できます)。ここではパソコン毎に多少時刻がずれていてもいいように、±1秒の範囲で調整できるようにしてあります。

session1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>みんなでセッション</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>みんなでセッション</h2> <button onclick=playNotes()>演奏開始</button> <!-- ここからプログラム --> <script> // ----------------------------------------------------------------------------- var notes=[ // 楽譜データ[音符, Note, ドラム] [4,"C5","LH"], [8,"G4","SH"],[8,"G4","SH"], [4,"A4","LH"], [4,"G4","SH"], [4,"",""], [4,"B4","LR"], [4,"C5","SH"] ]; // ----------------------------------------------------------------------------- var TEMPO=120; // 1分間に4分音符を120回 var Td=80; // ドラムを打つ時間(100ms)...バチによって調整 var Ts=500; // サーボモーターの移動時間 var Lmotor=5, Rmotor=4, Lservo=9, Rservo=8; // モータとサーボモータのpin var Lstick={L:150, S:80}; // ドラムの左サーボの角度(個別に調整) var Rstick={R:0, H:60}; // ドラムの右サーボの角度(個別に調整) var Langle={C4:10, D4:35, E4:60, F4:80}; // 鉄琴の左サーボの角度(個別に調整) var Rangle={G4:75, A4:95, B4:120, C5:150} // 鉄琴の右サーボの角度(個別に調整) var p=-1; function setup(){ // --- はじめに自動実行 --- pinMode(5, INPUT_PULLUP); // 鉄琴はpin5をGNDに接続する } function playNotes(){ var T, u; if(p<0) T=Ts; // 初回は準備 else{ // 1音目からは u=notes[p][1]; // C3 D3 ... C4 T=60000/TEMPO*4/notes[p][0]; // 4分音符 0.5秒, 8分音符 0.25秒 if(u){ playNote(midiPitch[u], T*.9); // ブラウザから合成音 if(digitalRead(0)==0){ // 鉄琴(pin0をGNDに接続)ならば if(u in Langle) digitalWrite(Lmotor, 1, Td); // 左を叩く if(u in Rangle) digitalWrite(Rmotor, 1, Td); // 右を叩く } } u=notes[p][2]; // S(sidedrum) L R(centerdrum) H(hihat) if(u.match(/L/) || u.match(/R/)) drumKick(); // ブラウザからcenterdrum音 if(u.match(/S/)) drumSnare(); // ブラウザからsidedrum音 if(u.match(/H/)) drumHihat(); // ブラウザからhihat音 if(digitalRead(0)==1){ // ドラム(pin0を解放)ならば if(u.match(/L/) || u.match(/S/)) digitalWrite(Lmotor, 1, Td); // 左を叩く if(u.match(/R/) || u.match(/H/)) digitalWrite(Rmotor, 1, Td); // 右を叩く } } if(++p<notes.length){ // 次音の準備 if(digitalRead(0)==0){ // 鉄琴(pin0をGNDに接続)ならば u=notes[p][1]; if(u in Langle) setTimeout("servo(Lservo,"+Langle[u]+",Ts)",T/2); if(u in Rangle) setTimeout("servo(Rservo,"+Rangle[u]+",Ts)",T/2); }else{ // ドラム(pin0を解放)ならば u=notes[p][2]; if(u.match(/L/)) setTimeout("servo(Lservo,"+Lstick["L"]+",Ts)", T/2); else if(u.match(/S/)) setTimeout("servo(Lservo,"+Lstick["S"]+",Ts)", T/2); if(u.match(/R/)) setTimeout("servo(Rservo,"+Rstick["R"]+",Ts)", T/2); else if(u.match(/H/)) setTimeout("servo(Rservo,"+Rstick["H"]+",Ts)", T/2); } setTimeout("playNotes()", T); }else p=-1; // 演奏終了 } </script> <!-- ここまで --> </body></html>


 以下は楽譜データを分けて(sample.js, akahana.js, ...)、曲を選択できるようにした例です。NeoPixelをつなぐと演奏に連動してカラフルに光ります。イルミネーションのオブジェはngo-tecさんのページを見て作りました。「正10秒」で同期演奏できますし、「正時」に演奏させれば「からくり時計」となります。ブラウザ画面上で楽譜を入力して演奏させることもできます。詳しくは「ミニドラム・ミニ鉄琴」のページをご覧ください。




10. 合成音声でおしゃべり

コマンド:

10.1 コマンド操作でおしゃべり(外部デバイスの接続不要)

 ブラウザの音声合成機能を用いて、おしゃべりするページを作ることができます。

talk("あいうえお") talk("あいうえお",12) talk("Hello, world.",1) talk("あいうえお",0,0.1) talk("あいうえお",0,0.1,0.5) talk(123) talk("準備OK") talk(4+"かける"+5+"は"+(4*5)+"です")
デフォルトは日本語 Windows10版Chromeでは 日本語は話者番号 10, 19, 20, 21, 22 英語は話者番号 1, 2, 3 音程 0.1~2 速さ 0.1~10

10.2 プログラムでおしゃべり(外部デバイスの接続不要)

 以下は、「九九」を合成音声で読み上げるプログラムです。

kuku.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>九九</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>九九</h2> <!-- ここからプログラム --> <script> var a=1, b=1; function setup(){ // --- はじめに自動実行 --- kuku(); } function kuku(){ $("VAL").innerHTML=a+"×"+b+"="+(a*b);// 画面表示 talk(a+"かける"+b+"は"+(a*b)+"です");// 合成音声で読み上げ if(++b==10){ a++; b=1; } if(a<10) kuku(); } </script> <!-- ここまで --> </body></html>

10.3 プログラムでおしゃべり(VOCA)

 以下は、外部スイッチが押されると「九九」をランダムに読み上げるプログラムです。

kukubutton.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>九九</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>九九</h2> <!-- ここからプログラム --> <script> var button; // 現在のbuttonの状態 var lastbutton; // 直前のbuttonの状態 function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP);// D2ピンをプルアップ入力に } function loop(){ // --- 20ms毎に自動実行 --- button=digitalRead(D2); // D2ピンを読みbuttonに代入 if(button!=lastbutton && button==0){// buttonが前と違いかつ0なら var a=Math.floor(1+Math.random()*9);// aは1~9の乱数 var b=Math.floor(1+Math.random()*9);// bは1~9の乱数 $("VAL").innerHTML=a+"×"+b+"="+(a*b);// 画面表示 talk(a+"かける"+b+"は"+(a*b)+"です");// 合成音声で読み上げ } lastbutton=button; // lastbuttonを更新 } </script> <!-- ここまで --> </body></html>

 利用者に適したスイッチを使い、合成音声の読み上げで支援するさまざまなツール(VOCA)をWebで作ることができます。

(練習) 2個のスイッチを接続し、それぞれ「はい」「いいえ」の合成音声が出るようなVOCAを作りなさい。


11. イルミネーション

11.1 NeoPixelの利用

 NeoPixelはフルカラーLEDがシリアルに連結されていて(ここでは10連LEDを使用)、1本の信号線で任意のLEDの発光をコントロールできるのが特徴です。

 初めに「pinMode(D10,OUTPUT_NEOPIXEL)」のように、NeoPixelを接続するピンを指定します。その後、「pixel(...)」でLEDの点灯をコントロールできます。パラメータは、順にLEDの番号(0~11)、Redの明るさ(0~255)、Greenの明るさ(0~255)、Blueの明るさ(0~255)を指定します。D10ピンにNeoPixelを接続し、以下の操作で確認してください。

 LEDの番号(0~11)と色相(0~255)と明るさ(0~255)を指定することもできます。明るさの指定を省略すると255として扱われます。

 まず、コマンド操作で試してみてください。

コマンド:
pinMode(D10,OUTPUT_NEOPIXEL) pixel(0,50,0,0) pixel(0,0,0,0) pixel(0,50,0,0) pixel(1,0,50,0) pixel(2,0,0,50) pixel(3,50,50,0) pixel(4,0,50,50) pixel(5,50,50,50) pixel(0,0,50) pixel(0,128,50) pixel(0,128)

11.2 プログラムによる点滅とフラッシュ

 以下のプログラムは、ひとつ目のLEDを赤で点滅させます。1秒点灯・1秒消灯をくりかえします。下図右は点滅の時間的な変化をタイムチャートで示したものです。

pixelblink1.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: 点滅</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: 点滅</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel setInterval("toggle()",1000); // 1秒毎にtoggle()を実行 } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に if(led==1) pixel(0,50,0,0); // ledが1なら点灯 else pixel(0, 0,0,0); // 0なら消灯 } </script> <!-- ここまで --> </body></html>

 次のようにすると10個のLEDが緑で点滅します。

pixelblink10.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: 点滅</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: 点滅</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel setInterval("toggle()",1000); // 1秒毎にtoggle()を実行 } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に for(var i=0;i<10;i++){ // iを0から9まで if(led==1) pixel(i, 0,50,0);// ledが1なら点灯 else pixel(i, 0,0,0); // 0なら消灯 } } </script> <!-- ここまで --> </body></html>

 次のようにすると明るく短時間点灯する「フラッシュ」になります。

pixelflash10.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: フラッシュ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: フラッシュ</h2> <!-- ここからプログラム --> <script> var led=0; // 現在の点灯状態(0で消灯 1で点灯) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL):// D10ピンにNeoPixel setTimeout("toggle()",1000); // 1秒毎にtoggle()を実行 } function toggle(){ led=(led==0?1:0); // ledが0なら1に、1なら0に for(var i=0;i<10;i++){ // iを0から9まで if(led==1) pixel(i, 0,50,0);// ledが1なら点灯 else pixel(i, 0,0,0); // 0なら消灯 } if(led==1) setTimeout("toggle()",100); else setTimeout("toggle()",900); } </script> <!-- ここまで --> </body></html>

(練習) 10個のLEDが1秒毎に「青→黄→赤」を繰り返すプログラムを作りなさい。

11.3 ワイプ

 以下のプログラムは、10個のLEDを順に点灯させます。このようなイルミネーション効果は「ワイプ」と呼ばれます。

pixelwipe.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: ワイプ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: ワイプ</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel setInterval("nextled()",1000); // 1秒毎にnextled() } function nextled(){ if(L==10){ // Lが10なら for(var i=0;i<10;i++) pixel(i,0,0,0); //全消灯 L=0; // Lを0に }else{ pixel(L,50,0,0); // LのLEDを点灯 L++; // Lを次に } } </script> <!-- ここまで --> </body></html>

(練習) 「赤のワイプ→緑のワイプ→青のワイプ」を繰り返すプログラムを作りなさい。

11.4 スイープ

 以下のプログラムは、10個のLEDを順に点灯・消灯させます。

pixelsweep.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: スイープ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: スイープ</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL):// D10ピンにNeoPixel pixel(L, 50,0,0); // 0番目のLEDを点灯 setInterval("sweep()",1000); // 1秒毎にsweep()を実行 } function sweep(){ pixel(L, 0,0,0); // L番目のLEDを消灯 if(++L==10) L=0; // Lを次に pixel(L, 50,0,0); // L番目のLEDを点灯 } </script> <!-- ここまで --> </body></html>

(練習) 100ms毎にスイープするようにしてみなさい。

11.5 ウェーブ

 以下のプログラムは、4個に1個の点灯がスイープし、波(ウェーブ)のように(あるいは追いかけているように)見えます。「P=3」にすると3個に1個の点灯になります。

pixelwave.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: ウェーブ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: ウェーブ</h2> <!-- ここからプログラム --> <script> var P=4; var j=P; function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL):// D10ピンにNeoPixel setInterval("chase()",100); // 100ms毎にchase()を実行 } function chase(){ for(var i=0;i<10;i++){ // iを0から9まで if((i+j)%P==0) pixel(i, 50,0,0); else pixel(i, 0,0,0); } if(--j==0) j=P; } </script> <!-- ここまで --> </body></html>

(練習) 「1個おき」「3個おき」のウェーブにしてみなさい。

11.6 フェードイン・フェードアウト

 以下のプログラムは、ひとつ目のLEDをだんだん明るくし(赤を0→50)、だんだん暗くし(赤を50→0)、これを繰り返します。

pixelfade.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: フェード</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: フェード</h2> <!-- ここからプログラム --> <script> var R=0; // R(赤)の明るさ var r=1; // Rの変化分 function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL):// D10ピンにNeoPixel setInterval("fade()",20); // 20ms毎にfade()を実行 } function fade(){ pixel(0, R,0,0); // 0番のLEDを明るさRに R+=r; if(R==50) r=-1; else if(R==0) r=1; } </script> <!-- ここまで --> </body></html>

(練習) 色を変えてみなさい。また速さを変えてみなさい。

(練習) 10個のLEDを同時にフェードイン・フェードアウトさせなさい。

11.7 クロスフェード

 ひとつ目のLEDをフェードアウトしながら、ふたつ目のLEDをフェードインすると滑らかに変化させることができます。これを「クロスフェード」といいます。

pixelxfade.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: クロスフェード</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: クロスフェード</h2> <!-- ここからプログラム --> <script> var R=0; // R(赤)の明るさ function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel xfade(); } function xfade(){ pixel(0, 50-R,0,0); pixel(1, R,0,0); R++; if(R<50) setTimeout("xfade()",20); } </script> <!-- ここまで --> </body></html>

 以下は、クロスフェードをスイープに応用した例で、LEDの点灯が滑らかに移動します。

pixelxsweep.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: スイープ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: スイープ</h2> <!-- ここからプログラム --> <script> var L=0; // 点灯するLED(0~9) var R=0; // R(赤)の明るさ function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel setInterval("xsweep()",10); } function xsweep(){ pixel(L, 50-R,0,0); pixel((L+1)%10, R,0,0); R=(R+1)%50; if(R==0) L=(L+1)%10; } </script> <!-- ここまで --> </body></html>

11.8 フルカラー表示

 クロスフェードを用いると色を滑らかに変化させることができます。以下のプログラムは、ひとつ目のLEDの色が赤→緑に滑らかに変化します。

pixelxrg.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: 赤から緑</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: 赤から緑</h2> <!-- ここからプログラム --> <script> var G=0; // G(緑)の明るさ function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel xrg(); } function xrg(){ pixel(0, 50-G,G,0); G++; if(G<50) setTimeout("xrg()",50); } </script> <!-- ここまで --> </body></html>

 RGBの値と表示色の関係は下図のようになっています。


 以下のプログラムは、すべてのLEDの色をフルカラーで連続的に変化させます(明るさ最大85)。

pixelxrgb.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: フルカラー</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: フルカラー</h2> <!-- ここからプログラム --> <script> var W=0; // 0~255 function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel setInterval("xrgb()",20); } function xrgb(){ for(var i=0;i<10;i++) pixel(i,W,50); W=(W+1)%256; } </script> <!-- ここまで --> </body></html>

 以下のプログラムは、すべてのLEDの色を場所を変えながらフルカラーで連続的に変化させます(明るさ最大85)。rgb()は0~255の色相Wを与えると、R,G,Bの変数に値(各々0~85)がセットされます。

pixelrgb.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: フルカラー</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: フルカラー</h2> <!-- ここからプログラム --> <script> var j=0; function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel setInterval("rgb()",10); } function rgb(){ for(var i=0;i<10;i++) pixel(i,(i*256/10+j)%256,50); j=(j+8)%256; } </script> <!-- ここまで --> </body></html>

11.9 イルミネーションの例

(1) ドロップ

 以下は、「ドロップ」のイルミネーションの作例です。水滴が滴り落ちるイメージで、最後にキラッと光ります。

pixeldrop.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: ドロップ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: ドロップ</h2> <!-- ここからプログラム --> <script> var S=0; // 0:休止 var N; // ドロップの長さ var led; // LEDの番号 var b=0; // 明るさ var u; // 最大の明るさ function loop(){ if(S==0){ // 休止 N=6+Math.floor(Math.random()*5);//ドロップ長(ランダムに6~10) led=0; // ledは0から b=0; // 明るさbは0から u=(led+1)*10 // uは最大の明るさ S=1; setTimeout("S=2",Math.random()*2000); }else if(S==2){ // ドロップ pixel(led, u-b,u-b,u-b);// ledをu-bの明るさ(だんだん暗く) pixel((led+1)%10,b,b,b);// led+1をbの明るさ(だんだん明るく) b=(b+1)%u; if(b==0){ led++; if(led==N-1){ S=3; b=u;} } }else if(S==3){ // 明るさbを最大までだんだん明るく(キラリ) if((b+=4)>255){S=4; b=255;} pixel(N-1,b,b,b); }else if(S==4){ // 明るさbを0までだんだん暗く if((b-=4)<0){ S=0; b=0;} pixel(N-1,b,b,b); } } </script> <!-- ここまで --> </body></html>

(2) イルミネーションオブジェ

 以下は、NeoPixelリング(12個)を使い、ランダムに点灯させるようにした例です。オブジェの作り方はngo-tecさんのページを参考にしました(クッキングシートを使ってみました)。点灯位置と点灯色と点灯時間間隔をランダムにし、点灯後はだんだん暗くしています。

pixelfire.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>イルミネーション: オブジェ</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>イルミネーション: オブジェ</h2> <!-- ここからプログラム --> <script> var brightness=[], color=[]; // NeoPixelの明るさと色 function setup(){ // --- はじめに自動実行 --- pinMode(D10,OUTPUT_NEOPIXEL): // D10ピンにNeoPixel for(var i=0;i<NUM_PIXELS;i++){ // すべて消す brightness[i]=0; pixel(i, 0,0); } setInterval("decayPixel()", 50); // NeoPixelを50ms毎に減衰 fire(); } function decayPixel(){ // 明るさを減衰 for(i=0;i<NUM_PIXELS;i++)if(brightness[i]>0){ brightness[i]=Math.floor(brightness[i]*.95); pixel(i, color[i], brightness[i]); } } function fire(){ var p=Math.floor(Math.random()*NUM_PIXELS); // 場所はランダムに brightness[p]=255; // 明るさ最大で color[p]=Math.random()*256; // 色はランダムに setTimeout("fire()",(Math.random()+Math.random())*1000); // 0~2秒後にfire() } </script> <!-- ここまで --> </body></html>

(練習) オリジナルのイルミネーションを考え、作ってみなさい。


12. 赤外線リモコン

コマンド:
pinMode(D10,INPUT_PULLUP) alert(digitalRead(D10))

13. 動くものを作る

13.1 サーボモータを動かす

 ラジコン用のサーボモーターは、右図のようなPWM波形で角度(0~180°)を制御するように作られています。

 以下の例は、サーボモーターが車のワイパーのように動きます。

sweep.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>サーボモーター</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>サーボモーター</h2> <!-- ここからプログラム --> <script> var angle=0; // 角度(0~180) var d=1; // angleの変化分 function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- servo(D9, angle); angle=angle+d; if(angle>=180) d=-1; else if(angle==0) d=1; } </script> <!-- ここまで --> </body></html>

 以下のプログラムは、ボリュームの値によってサーボモーターの位置(角度)が変わります。

knob.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>サーボモーター</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>サーボモーター</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(D9,OUTPUT); // D9ピンを出力に } function loop(){ // --- 20ms毎に自動実行 --- var angle=analogRead(A1)*180/1024; // 角度(0~180) servo(D9, angle); } </script> <!-- ここまで --> </body></html>

(練習) 上記のknob.htmlでボリュームの代わりに明るさセンサーを使い、明るさで位置が変わるようにしなさい。

13.2 モーターを動かす

 下図のようにモーターを接続します。まず、motorコマンドでモーターを動かしてみてください。左右のモーターの速度は-256~255で指定します。電源への負荷を軽減するために、早さを変える場合は一旦停止させてください。

コマンド:
motor(100,100) motor(0,0) motor(100,50) motor(0,0) motor(-100,-100) motor(0,0)

13.3 ブラウザ画面からモーターを制御する

 以下はブラウザに表示されたスライダを操作することによってモーターの回転速度が変わります。

motorslider.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示とプログラム --> <h2 align=center>モーターの制御</h2> <input type=range style="width:300px" onchange=motor(this.value, this.value) value=0 min=0 max=255 step=1> <!-- ここまで --> </body></html>

 以下は、ブラウザ画面のボタン操作で前後左右に動かします。

motorbutton.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示とプログラム --> <h2 align=center>モーターの制御</h2> <center><table> <tr><td></td> <td><button onclick=motor(255,255)>前進</button></td> <td></td></tr> <tr><td><button onclick=motor(50,255)>左回転</button></td> <td><button onclick=motor(0,0)>停止</button></td> <td><button onclick=motor(255,50)>右回転</button></td></tr> <tr><td></td> <td><button onclick=motor(-255,-255)>後退</button></td> <td></td></tr> </table></center> <!-- ここまで --> </body></html>

13.4 ボリュームでモーターを制御する

 以下はボリュームの値によってモーターの回転速度が変わります。

motorvr.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>モーターの制御</h2> <!-- ここからプログラム --> <script> function loop(){ // --- 20ms毎に自動実行 --- var speed=analogRead(A1)*180/1024; // 角度(0~180) motor(speed,speed); } </script> <!-- ここまで --> </body></html>

 以下は音センサモジュールと組み合わせた例で、手を叩く(7ピンに接続した音センサーが400以上)と1秒間前進します。

motorsound.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>モーターの制御</h2> <!-- ここからプログラム --> <script> var S=0; // モーターの状態(0:停止 1:回転) function setup(){ // --- はじめに自動実行 --- pinMode(A1,INPUT_ANALOG); // A1ピンをアナログ入力に } function loop(){ // --- 20ms毎に自動実行 --- if(S==0 && analogRead(A1)>=400){ motor(255,255); S=1; setTimeout("motor(0,0);S=0",1000); } } </script> <!-- ここまで --> </body></html>

 以下の例は、車の先端がテーブルから落ちそう(7ピンに接続した赤外線反射センサーが30以上)になると、少し後退し、右回転して、再び前進します。

motorir.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>モーターの制御</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <h2 align=center>モーターの制御</h2> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- } function loop(){ // --- 20ms毎に自動実行 --- var angle=analogRead(7)*180/1024; // 角度(0~180) servo(D9, angle); } </script> <!-- ここまで --> </body></html>


14. 押しボタン信号機

とします。LEDと連動して、ブラウザ画面も変化するようにしました。また、押しボタンの操作は画面上のでも同じように動作します。


signal.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>押しボタン信号機</title> <script src=webio2.js></script> <style>td{font-size:32pt}</style> </head><body> <!-- ここから画面表示 --> <center><table> <tr><th>自動車</th><th>歩行者</th></tr> <tr><td align=center width=60> <span id=R>●</span><br><span id=Y>●</span><br><span id=B>●</span> </td><td align=center valign=bottom width=60> <span id=RR>■</span><br><span id=BB>■</span> </th></tr> <tr><th></th> <th><button onclick="S=1;timer(4000);">押す</button></th></tr> </table></center> <!-- ここからプログラム --> <script> var S; // 現在の状態 var TOUT; // タイムアウトフラグ var C; // 歩青点滅用カウンタ function signal(c1, c2){ if(c1=="赤"){ pixel(0,50,0,0); $("R").style.color="orangered"; pixel(1,0,0,0); $("Y").style.color="darkgoldenrod"; pixel(2,0,0,0); $("B").style.color="darkblue"; }else if(c1=="黄"){ pixel(0,0,0,0); $("R").style.color="darkred"; pixel(1,50,50,0);$("Y").style.color="gold"; pixel(2,0,0,0); $("B").style.color="darkblue"; }else if(c1=="青"){ pixel(0,0,0,0); $("R").style.color="darkred"; pixel(1,0,0,0); $("Y").style.color="darkgoldenrod"; pixel(2,0,0,50); $("B").style.color="aqua"; } if(c2=="赤"){ pixel(8,50,0,0); $("RR").style.color="orangered"; pixel(9,0,0,0); $("BB").style.color="darkblue"; }else if(c2=="青"){ pixel(8,0,0,0); $("RR").style.color="darkred"; pixel(9,0,0,50); $("BB").style.color="aqua"; }else if(c2=="消"){ pixel(8,0,0,0); $("RR").style.color="darkred"; pixel(9,0,0,0); $("BB").style.color="darkblue"; } } function setup(){ // --- はじめに自動実行 --- pinMode(D2,INPUT_PULLUP); // D2ピンはプルアップ入力 for(var i=0;i<10;i++) pixel(i, 0,0,0); // はじめに全消灯 signal("青", "赤"); // 車青・歩赤 S=0; } function timer(t){TOUT=false; setTimeout("TOUT=true",t);} function loop(){ // --- 20ms毎に自動実行 --- if(S==0 && digitalRead(1)==0){ // ボタンが押されたら S=1; timer(4000); // S=1 }else if(S==1 && TOUT){ // 4秒後に S=2; signal("黄","赤"); timer(4000); // S=2 車黄・歩赤 }else if(S==2 && TOUT){ // 4秒後に S=3; signal("赤","赤"); timer(2000); // S=3 車赤・歩赤 }else if(S==3 && TOUT){ // 2秒後に S=4; signal("赤","青"); timer(16000); // S=4 車赤・歩青 }else if(S==4 && TOUT){ // 16秒後に S=5; signal("赤","青"); timer(500);C=0;// S=5 車赤・歩青 }else if(S==5 && TOUT){ // 0.5秒後に if(C%2==0) signal("赤","青"); // 車赤・歩青点滅 else signal("赤","消"); C++; if(C>=16){ // S=6 車赤・歩赤 S=6; signal("赤","赤"); timer(4000); }else timer(500); }else if(S==6 && TOUT){ // 4秒後に S=0; signal("青","赤"); // S0 車青・歩赤 } } </script> <!-- ここまで --> </body></html>

 また、以下は小学校などで利用されている「交通安全教室用信号機」ですが、上記と組み合わせればWebページと連動した指導ができるようになるかもしれません。


15. さまざまな例

15.1 温湿度計

 以下は、デジタル温湿度センサSHT31を使った温湿度計です。TEMPとHUMIは特別なアナログ入力ピンです。

thermometer.html:

<!DOCTYPE html><html lang="ja"><head> <meta charset="utf-8"> <title>温湿度計</title> <script src=webio2.js></script> </head><body> <!-- ここから画面表示 --> <div id=TEMP style='font-size:80pt'></div> <div id=HUMI style='font-size:80pt'></div> <!-- ここからプログラム --> <script> function setup(){ // --- はじめに自動実行 --- pinMode(TEMPpin,INPUT_ANALOG); // TEMPをアナログ入力に pinMode(HUMIpin,INPUT_ANALOG); // HUMIをアナログ入力に setInterval("measure()",1000); } function measure(){ $("TEMP").innerHTML=analogRead(TEMP)+"<small>℃</small>"; $("HUMI").innerHTML=analogRead(HUMI)+"<small>%RH</small>"; } </script> <!-- ここまで --> </body></html>

 以下は、グラフ表示など多目的に使えるようにした例です。データは使用するパソコンのブラウザに保存され、そのデータをネットワーク経由で見ることはできません。理科や保健の授業などで利用できるかもしれません。ネットワークを利用した気温・湿度・熱中症指数(WBGT)・CO2モニタリングシステムはこちらをご覧ください。


以下はCO2センサも利用できるようにした例です。

15.2 WebIOの動作テスト

 下図のように、WebIOの動作を確かめるページを作りました。プログラムをクッキーに保存することもできます。


(付録1) 入出力モジュール

 ブレッドボードで利用できる入出力モジュールの製作例です。

モジュール回路図製作例
可変抵抗モジュール
明るさセンサーモジュール
赤外線反射モジュール
音量センサーモジュール
10連LEDモジュール
NeoPixel(Dinはpin10に接続)
モーターモジュール
右モーターはA0とA1をGNDに接続

(付録2) 使用する主な部品

部品表
名称 外観 備考
Seeeduino XIAO 秋月 580円
ブレッドボード EIC-301 EIC-301 秋月 190円
ブレッドボード ジャンパーワイヤ 15cm   秋月 10本 300円
ブレッドボード ジャンパーワイヤ EIC-J-S   秋月 250円
LED 秋月 10個 120円
フルカラーシリアルLEDテープ SwitchScience 756円
圧電スピーカー 秋月 2個 100円
プッシュスイッチ DS-660R-C 千石 84円
抵抗 1/4W 4.7Ω, 100Ω, 220Ω, 470Ω, 1kΩ, 10kΩ 秋月 100本 100円
CDS(光センサ)秋月 30円
温湿度センサ SHT31秋月 950円
赤外線反射センサ LBR-127HLD   秋月 50円
サーボモーター SG-90   秋月 400円
モータードライバ DRV8830   秋月 170円

(付録3) WebIOの主な仕様

(1) XIAOで使用できるピン

ピン 定義した変数名 備考
デジタル入出力
アナログ出力(PWM)#
アナログ入力
0 D0-
1 D1A1
2 D2 #A2
3 D3 #A3
4 D4 #A4I2C SDA
5 D5 #A5I2C SCL
6 D6 #A6TX(midi Out)
7 D7 #A7RX(midi In), Bzz(sendNote()に対応)
8 D8 #-SCK
9 D9 #-MISO
10 D10 #-MOSI, NeoPixel
22(仮想ピン)-TEMPSHT31/SCD30 温度
23(仮想ピン)-HUMISHT31/SCD30 湿度
24(仮想ピン)-CO2SCD30 CO2濃度
設定値または取得値0 / 1
# 0 - 255
0 - 1023

(2) 組み込み定数(拡張分)

定数名内容
HIGH, LOWデジタル出力またはデジタル入力されたピンの状態(HIGHは1、LOWは0)
OUTPUT, INPUT, INPUT_PULLUP
INPUT_ANALOG, OUTPUT_TONE,
OUTPUT_NEOPIXEL, OUTPUT_IR, INPUT_IR
pinMode()で設定する入出力のモード
D0~D10, A1~A7デジタル入出力ピンおよびアナログ入力ピン
TEMP, HUMI, CO2I2C接続したSHT31またはSCD30の測定値を入力する仮想ピン

(3) 組み込み関数(拡張分)

関数名内容
pinMode(pin, mode) pinをmodeにする(modeはOUTPUT, INPUT, INPUT_PULLUP, INPUT_ANALOG)
digitalRead(pin) pinの値を読んでHIGHまたはLOWの値を返す
digitalWrite(pin, HIGH)
digitalWrite(pin, 1, t)
pinにHIGHを出力する(値はHIGHまたはLOW)
pinをt(ms) 1にする
analogRead(a) aピンのアナログ値を読み、0~1023の値を返す。
TEMP(22), HUMI(23), CO2(24)は仮想ピン。
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() ページが表示された時にこの関数が呼び出される
loop() 20ms毎にこの関数が呼び出される
irreceive(protocol, address, command) IRリモコン信号を受信した時に呼び出される


(付録4) Midiコマンドとの対応

機能 send(PC → I/O) receive(I/O → PC)JavaScript関数備考
byte1byte2byte3 byte1byte2byte3
8x [midi] NoteOff 1000nnnn0kkkkkkk0vvvvvvv 1000nnnn0kkkkkkk0vvvvvvv pin6の音を停止
9x[midi] NoteOn 1001nnnn0kkkkkkk0vvvvvvv 1001nnnn0kkkkkkk0vvvvvvv sendNote(key, t)pin6にkey0-125のブザー音をt[ms]出力
Ax[midi] Pressure 1010nnnn0kkkkkkk0vvvvvvv
Bx[midi] Control Change 1011nnnn0ccccccc0vvvvvvv
([midi] Program Change) 1011nnnn011111110ppppppp setVoice(ch, voice) ch0-15を音源0-127に
Reset 1011nnnn0111100100000000 reset() Reset All Control
AllNoteOff 1011nnnn0111101100000000 All Note Off
Cx[midi] Program Change 1100nnnn0ppppppp
Dx[midi] Pressure 1101nnnn0vvvvvvv
Ex[midi] Pitch Bend 1110nnnn0lllllll0mmmmmmm
(Reserved) 512Byte 11100xxx
(E0-E7)
0xxxxxxx0xxxxxxx 11100xxx
(E0-E7)
0xxxxxxx0xxxxxxx
PinMode
DigitalOut
11101000
(E8)
000000pp0pppmmmm
0ppp111v
pinMode(pin, mode)
digitalWrite(pin,val)
digitalWrite(pin,1,t)
pin0-31のpinModeをmode0-13に*
pin0-31を0/1に
tを指定した場合は t[ms] 1に
DigitalIn 11101000
(E8)
000000pp0ppp111v digitalRead(pin) pin0-31の値0/1 (20ms毎に更新)
(Reserved) 30Byte 11101000
(E8)
000001xx

001111xx
0xxxxxxx
 
0xxxxxxx
11101000
(E8)
000001xx

001111xx
0xxxxxxx
 
0xxxxxxx
AnalogOut 11101000
(E8)
01vppppp0vvvvvvv analogWrite(pin, val) pin0~31を0-255に
AnalogIn 11101000
(E8)
01vvvaaa0vvvvvvv analogRead(pin) pin0~7の値0-1023(20ms毎に更新)
AnalogIn 11101001
(E9)
0vvvvvaa0vvvvvvv analogRead(pin) TEMP(22),HUMI(23),CO2(24)の値0-4095
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)
01xxxxxx0xxxxxxx
NeoPixel 11101010
(EA)
0rgbllll0rrrrrrr Pixel(LED, R,G,B) LED0-15の色をR(0-255)G(0-255)B(0-255)に
11101011
(EB)
0ggggggg0bbbbbbb
(Reserved) 128Byte 1110101x
(EA-EB)
0xxxxxxx0xxxxxxx
IRsend 11101100
(EC)
0ppppppp0000aacc IRsend(&IRDATA) IRリモート信号を送信
IRDATA内に protocol, address, command
11101101
(ED)
0aaaaaaa0aaaaaaa
11101110
(EE)
0ccccccc0ccccccc
IRreceive 11101100
(EC)
0ppppppp0000aacc IRreceive(&IRDATA) IRリモート信号を受信
IRDATA内に protocol, address, command
11101101
(ED)
0aaaaaaa0aaaaaaa
11101110
(EE)
0ccccccc0ccccccc
(Reserved) 64Byte 11101111
(EF)
0xxxxxxx0xxxxxxx 11101111
(EF)
0xxxxxxx0xxxxxxx
Fx[midi] SysEx 1111xxxx 1111xxxx
* 0:INPUT 1:OUTPUT 2:INPUT_PULLUP 3:INPUT_ANALOG 12:INPUT_IR 13:OUTPUT_IR

(以下はメモ)

Arduino NANO / Pro Micro / Leonardo / Davinci / XIAO のピン接続

Arduino
NANO
備考
D0/TX MidiOut
D1/RX MidiIn / SW
D2
D3#
D4
D5#
D6#
D7
D8
D9# Servo / LED / Tone
D10# Servo / NeoPixel
D11#/MOSI
D12/MISO
D13/SCK
D14/A0 AnalogIn
D15/A1
D16/A2
D17/A3
D18/A4/SDA I2C
D19/A5/SCL I2C
A6
A7
Pro micro Leonardo
/ Davinci
備考
D0/TX D0/TX MidiOut
D1/RX D1/RX MidiIn / SW
D2/SDA D2/SDA I2C
D3#/SCL D3#/SCL I2C
D4 D4
D5# D5#
D6#/A7 D6#/A7
D7 D7
D8/A8 D8/A8
D9#/A9 D9#/A9 Servo / LED / Tone
D10# D10# Servo / NeoPixel
- D11#/A11
- D12
- D13#
D14/MISO -
D15/SCK D15/SCK
D16/MOSI D16/MOSI
- D17/SS
D18/A0 D18/A0 AnalogIn
D19/A1 D19/A1
D20/A2 D20/A2
D21/A3 D21/A3
- D22/A4 TEMP(仮想ピン)
- D23/A5 HUMI(仮想ピン)
Seeeduino
XIAO
備考
D0/DAC0/A0 AnalogIn
D1#/A1 SW
D2#/A2
D3#/A3
D4#/A4/SDA I2C
D5#/A5/SCL I2C
D6#/A6/TX MidiOut (Pythonは#不可)
D7#/A7/RX MidiIn
D8#/A8/SCK
D9#/A9/MISO Servo / LED / Tone
D10#/A10/MOSI Servo / NeoPixel

koyama88@cameo.plala.or.jp