Arduinoをブラウザから動かす

前回、Node.jsでLチカを実現しました。

Node.js→Arduinoがうまくいけば、ブラウザ(HTML)→Node.jsは、何とかなるような気がします。

Node.js+Express+socket.io

Node.jsを使うとき、無理せずフレームワークのExpressをセットで使います。

そして、サーバーとクライアントの双方向リアルタイム通信を実現したいときは、socket.ioモジュールを使わせて頂きます。

いきなりArduinoでNode.jsを導入より、定番のリアルタイムチャット開発を通じてNode.jsを学んだ方が、理解しやすかもしれません。

ディレクトリ構成

前回からの続きで、Cドライブ直下の「node-arduino」というディレクトリ内で開発を進めます。

「htdocs」というディレクトリを新たに作り、index.htmlを作ります。

ブラウザ側のスイッチを作る

index.htmlは、ブラウザでLEDの点灯を制御する画面です。

ブラウザに表示されるスイッチを押すと、ArduinoにつながれたLEDが光ります。

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Arduinoをブラウザ操作</title>
<script src="/socket.io/socket.io.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<style>
 body {
  padding-top: 500px;
  background: #000;
  text-align: center;
 }
 button {
  padding: 20px 40px;
  border-bottom: #999 solid 20px;
  border-radius: 15px;
  background: #EEE;
  font-size: 100px;
 }
 button.on {
  margin-top: 15px;
  border-bottom: #095E13 solid 5px;
  background: #3C9053;
  color: #FFF;
 }
</style>
</head>
<body>
<button id="ledBtn">LED点灯</button>
<script type="text/javascript">
 var socket = io(),
 $ledBtn = $("#ledBtn"),
 ledSwitch = false,
 SWITCH_CLASS = "on";
 
 $ledBtn.on("click", function(){
  if(ledSwitch === false){
   ledSwitch = true;
   $(this).addClass(SWITCH_CLASS);
  }else{
   ledSwitch = false;
   $(this).removeClass(SWITCH_CLASS);
  }
  socket.emit('led', ledSwitch);
 });
</script>
</body>
</html>

LEDが点灯中は、ブラウザ上のスイッチも緑色になります。

サーバー側のスクリプトを書く

サーバ―側のapp.jsでは、サーバーの起動および、ブラウザからの命令を受け取り、Arduinoに命令を出すためのコードを書きます。

var express = require('express'),
 app = express(),
 http = require('http').Server(app),
 port = 3000,
 io = require('socket.io')(http),
 five = require("johnny-five"),
 board = new five.Board(),
 led,
 
server = function(){
 app.use(express.static('htdocs'));
 http.listen(port,function(){
  console.log("Expressサーバーがポート%dで起動しました。モード:%s",port,app.settings.env);
 });
};

board.on("ready", function() {
 server();
 led = new five.Led(13),
 io.on('connection', function(socket) {
  socket.on('led', function(data) {
   if (data === true) {
    led.on();   
   } else {
    led.off();
   }
  });
 });
});

前回の再掲載となりますが、回路は13番にLEDがつながっている単純な構成です。

LEDをブラウザから点灯!

準備が整いました。

コマンドプロントの「node app.js」で、サーバーを起動します。

ブラウザのアドレスバーに「http://localhost:3000/」と打ち、index.htmlを表示させます。

LED点灯ボタンが出てきます。

ボタンをクリック!

ブラウザのボタンも緑、LEDも緑に点灯しました。

すばらしい連動性です。

GIFアニメも掲載します。

これくらいのことだと、socket.ioが必要なかった気がしますが・・・次回はもっと双方向な構築で、socket.ioも活躍します。

ArduinoをJavaScriptで動かす

これまでIoT実現のため、組み込み系プログラムを試行錯誤し、なんとかWebまでつなげてきましたが・・・無理のある構築になっている気がします。

勉強のため、今度は逆にWeb系の技術を起点に開発を進めてみようと思います。

JavaScriptで開発するための環境準備

Web系の技術、主にJavaScriptを使って、Arduinoをブラウザから制御できるようにします。

開発環境の準備は、ICS MEDIAさんの「JavaScriptでArduinoをコントロール ― 第1回 Lチカ(LEDチカチカ)させてみよう!」を、参考とさせて頂きました。

やることは・・・

  • StandardFirmataをArduinoに書き込む
  • Node.jsをPCにインストール(私はインストール済みでした)
  • johnny-fiveをPCにインストール

私の場合、Windows環境で、Cドライブ直下に「node-arduino」というフォルダを作り、「app.js」という名前のJavaScriptを用意しています。

Arduinoを制御するJavaScript

実際にLEDをチカチカさせるJavaScriptを作ります。

先ほどの「app.js」に下記コードを書きます。

var five = require("johnny-five");
var board = new five.Board();

board.on("ready", function() {
 var led = new five.Led(13);
 led.blink(1000); //1秒ごとに点滅
});

johnny-fiveのサイトに掲載されているサンプルコードを使ってみます。
(試しに点滅は1秒ごに変えています)

Lチカ回路を作り Node.js実行

あとは、最小構成のLチカ回路を作ります。

Windowsの場合、コマンドプロントを立ち上げます。

cd C:\node-arduino

と、コマンドを打ち込み、先ほど用意したディレクトリに移動します。

最後に「app.js」をNode.jsで動かします。

node app.js

これでLEDがチカチカします。

ブラウザ側の制御は楽になりそう

Node.jsを使えれば、ブラウザでの非同期処理は、ハードルが一気に下がります。

次回はブラウザからLEDを操作してみようと思います。

ボッチャ普及員を目指す

ボッチャ普及指導員になることを目指しています。

指導者講習会を2日間受講する必要があるようですが、日本ボッチャ協会のサイトでは、講習会情報が全く掲載されていません。(2017年5月10日現在)

ただ、他を探してみると、葛飾区のサイトにボッチャ普及指導員講習会の参加申し込み情報が掲載されていたので、そちらに申し込もうと思います。

・・・葛飾区の住民でないので、ダメかもしれませんが。

ボッチャ教室にも通うことに

それと同時に、週1でボッチャ教室に通い始めました。

平日ということもあり、開始時間になっても私1人しかいなく、なかなか不安もありましたが、最終的には10人くらい集まり、和やかにボッチャ練習をすることができました。

いろんな投球練習がある

最初はコートに置かれた輪の中に、ボールを入れる練習です。

距離があると、なかなか輪の中でボールが止まりません。

すると今度はA4用紙をコートに敷き、その上に止める練習に移ります。

もっと精度の高い投球が求められます。

・・・A4用紙に乗らない。

 

それにしても、いろんな練習方法があるものです。

正式ルールではないレクリエーション・ボッチャなら、自由にルールを決められるので、まだまだ楽しい練習方法や遊び方が考えられそうです。

試合形式で練習

そして、試合形式での練習が始まりました。

先ほどと違い、他のボールを押して優勢にしたり、相手チームの投球進路を邪魔したり、戦略が加わります。

ジャックボールを投げる時に気づいたのですが、自分が一番端にいる時は、自分側のコートの端に投げると、反対側の端にいる人が投げにくくなります。

でも、それをやったら、少し心が痛みました。

 

ゆるい勝負

驚いたのは、勝負のゆるさです。とてもゆるい。

審判は計測器具を一切使わず、すべて目測。

最終的に同じくらいのボール距離に見える場合、引き分け。

・・・思わず笑ってしまいました。

 

雪降るウォッチ

第16回 IoT×プログラミング教育

ウェアラブル端末を作ります。16回目にしてようやくIoTです。

手を振るとブラウザ上で雪が降る仕組みを作ります。

ウォッチを作る

足立区のイベントでもらったパラスポーツ応援リングに、前回作ったブレッドボードを巻きつけます。

もっと小さくして、ただのリングにしたかったのですが、大きくなって時計のようになってしまいました。

バッテリーも邪魔です。

・・・まあ、最初のIoT体験としてはこれで良いでしょう。

1回振ると、1つ雪が降る

腕を1回振ると、ブラウザ上で1回雪が振る仕組みを作ります。

「ESPr Developer」をサーバーとし、腕を振った回数を取得できるようにします。

雪を降らすまでの大まかな流れは、

傾斜センサーが傾き取得

LEDが光ると同時に、傾いた回数をカウント

傾いた回数を0.5秒ごとにサーバーがJSONP出力

ブラウザからAjaxでJSONP取得

傾いた回数が増えていたら、増えた数だけ雪を降らす

「ESPr Developer」側のプログラム

世の中に出して良いプログラムなのか迷うほど、正攻法とは思えないやり方ですが、「ESPr Developer」に書き込んだプログラムを掲載します。

/*
ESPr Developerを使ったWi-Fi接続コードは、下記をサイトのものを使わせて頂きました。
ESPr Developer ( ESP-WROOM-02 開発ボード )の使い方をザッと紹介
*/ #include <ESP8266WiFi.h> #define PIN 13 const char* ssid = "※自分のWi-FiのID※"; const char* password = "※自分のWi-Fiパスワード※"; WiFiServer server(80); WiFiClient client; int val = 0; //アナログ入力値 int count = 0; //振った回数 int interval = 0; boolean shake = false; void setup(){ pinMode(PIN, OUTPUT); #ifndef __AVR_ATtiny85__ #endif Serial.begin(115200); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); server.begin(); // Print the IP address Serial.println(WiFi.localIP()); } void loop(){ val = analogRead(0); if(val > 800){ //傾き無し digitalWrite(PIN,LOW); shake = false; }else if(shake == false){ //傾き初回 digitalWrite(PIN,HIGH); count++; shake = true; }else{ //傾き中 digitalWrite(PIN,LOW); } delay(50); interval++; if(interval > 10){ //50m秒×10(=500m秒)ごとに Ini_HTTP_Response(); //HTTPレスポンス実行 interval = 0; } } void Ini_HTTP_Response() { client = server.available(); delay(1); String req; while(client){ if(client.available()){ req = client.readStringUntil('\n'); Serial.println(req); if (req.indexOf("GET / HTTP") >= 0 || req.indexOf("GET /?callback") >= 0 || req.indexOf("GET /favicon") >= 0){ Serial.println(req); while(req.indexOf("\r") != 0){ req = client.readStringUntil('\n'); Serial.println(req); } req = ""; delay(10); //JSONP書き出し client.print("callback({\"Shake\":"); client.print(count); client.print("});"); delay(1); client.stop(); Serial.println("\nGET HTTP client stop--------------------"); req = ""; } } } }

これで、「ESPr Developer」と同一ネットワーク上にあるPCやスマホのブラウザで、JSONPを取得できるようになります。

Serial.println(ssid);により、シリアルモニタにIPアドレスが書き出されるので、それをブラウザ側でも使います。

ブラウザ側のプログラム

次にブラウザで表示するHTMLを作ります。

ローカルサーバーでもレンタルサーバーでも良いので、やりやすいところにHTMLを置きます。

HTML(CSSとJS込)は以下です。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>距離計測結果</title>

<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<style type="text/css">
body {
 background: #000;
 color: #FFF;
 overflow:hidden;
}
#output {
 font-size: 100px;
}
.snow {
 position: absolute;
 border-radius: 50%;
}
 
.snow.layer0 {
 width: 50px;
 height: 50px;
 background-color: hsla(0,0%,100%,0.8);
 animation: fall 2s linear;
}
 
.snow.layer1 {
 width: 40px;
 height: 40px;
 background-color: hsla(0,0%,100%,0.6);
 animation: fall 3s linear
}
 
.snow.layer2 {
 width: 30px;
 height: 30px;
 background-color: hsla(0,0%,100%,0.4);
 animation: fall 4s linear;
}

@keyframes fall {
 0% {
  margin-top: 0;
 }
 100% {
  margin-top: 1200px;
 }
}
</style>
</head>
<body>
<div id="wrap">
 <div id="output"></div>
</div>
<script type="text/javascript">
 var count = 0,
 oldCount = 0,
 snowCount = 0,
 
 init = function(){
  setInterval(function(){
   $.ajax({
    type: 'GET',
    url: 'http://192.168.179.2',
    dataType: 'jsonp',
    jsonpCallback: 'callback',
    success: function(json){
    oldCount = count;
    count = json.Shake;
    if(count > oldCount){
     $("#output").text(count);
     snowCount = count - oldCount;
     for(var i = 0; i < snowCount; i++){
      $("#wrap").append('<div class="snow layer' + Math.floor( Math.random() * 3 ) + '" style="left:' + Math.floor( Math.random() * 101 ) + '%; top:-' + (Math.floor( Math.random() * 101 ) + 50) + 'px"></div>');
     }
    }
   }
  });
 },1000);
}

init();


</script>
</body>
</html>

Ajaxで取得するURLは、Arduinoシリアルモニタで確認したIPアドレスを指定します。

JSONPで、クロスドメインの壁を超えていますが、こんなやり方でよいのでしょうか・・・。

雪を降らそう

ブラウザをフルスクリーンにして、雪降るウォッチを振ってみます。
左上の数字は降った(振った)回数です。

たまに動作が安定しないので、そういう時は「ESPr Developer」のリセットボタンを押してやり直します。

子供の食いつきはなかなか

IoT体験として、子供の食いつきは良かったです。

有り余る子供のエネルギーに、パソコンが連動するのが良いです。

今回は深い理由もなく、雪を降らせましたが、別途IoT観戦で使えないか研究中です。

多分「ESPr Developer」をサーバーとするやり方は限界があるので、別の方法も考えていきます。

傾くと光る 傾斜センサー

第15回 IoT×プログラミング教育

単純で簡単そうな部品「傾斜センサー」を使ってみます。

傾斜センサーとは?

Arduino拡張キットにコンデンサーみたいな形のセンサーが入っていました。

降ると音がして、中に球が入っているようです。

説明書には「傾斜センサー」と書かれていたので、傾きを取得してくれるのでしょう。

「ESPr Developer」を使う

傾斜センサーに反応して光る仕組みを作りますが、最終的には無線接続をしたかったので、今回は「Arduino」ではなく、Wi-Fi搭載の「ESPr Developer」をArduino互換機として使います。

以前「ESPr Developer」について予習した知識では

  • アナログ入力は1つしかなく、TOUTピンを使う
  • TOUTは1Vまでの入力なので分圧回路を組む

・・・ここら辺は、子供に説明できるレベルを超えているような気がして、傾斜センサーを中心に見ていきます。

傾斜センサーの回路を組む

「ESPr Developer」の下にジャンパーワイヤーを差し込んでいます。

傾斜センサーは足が2本しかないので、今まで使ったセンサーの中で最も簡単な部類に入るかと思います。片方の足に電圧をかけ、アナログ入力(TOUT)につなぐだけです。

傾きに応じて、電圧が変化すると思いきや・・・ON、OFF、スパッと切り替わります。

これは、センサーというよりスイッチでは?

傾くとスイッチが切れるようです。

アナログ入力を使う必要があるのか分かりませんが、分圧回路で510Ωと200Ωの抵抗器を使い、TOUTへ入力を1V以下に抑えています。

あとは、傾きに反応して光るよう、13ピンにLEDをつないでいます。

傾けて光らせよう

 

計算では・・・常時942くらいのアナログ入力値を受け取ることになると思いますが、余裕をみて800より大きい時を通常時とし、800以下を傾いたと判断します。

#define PIN 13
int val = 0; //アナログ入力値

void setup(){
 pinMode(PIN, OUTPUT);
}

void loop(){
 val = analogRead(0);
 if(val > 800){ //傾き無し
  digitalWrite(PIN,LOW);
 }else{ //傾き中
  digitalWrite(PIN,HIGH);
 }
 delay(50);
} 

傾けている間、光ります。

やってみます。

傾けると・・・

光ります。

・・・これだけです。

しかし、次回は「ESPr Developer」を使ったIoTを体験できるようにします。

引き戸と押し戸を間違える

小学校の授業参観に行ったとき、玄関のドアが開けられず困りました。

鍵がかかっているのかな?と、思って、別の入り口を探してキョロキョロしていると、先生が「引き戸なんですよ、分かりにくいですよね。」と、開けてくれました。

・・・恥ずかしい。

デザインが悪い

自己嫌悪に陥いりそうですが、これはデザインが悪い。

先生の話では、他にも間違えた人がいるようです。

有名な認知心理学者ノーマン博士の著書『誰のためのデザイン?』に、ドアのデザインの問題と、それを作ったデザイナーの問題について、書かれていた記憶があります。

たしか・・・悪いのは使う人ではなく、間違いを起こすデザインだと。

少なくともユーザー(私)の経験では、押し戸(開き戸)だと認知してしまいました。

なぜ間違えたか?

側面と正面からみた、ドアの形です。

大部分がガラス張りで、金属の取っ手がついています。

なぜ私が横にスライドさせる引き戸だと思わず、押してしまったのか・・・理由は分かりました。

普段使うデパートの入口の押し戸に、とても近いデザインだったからです。

今までの経験が、押し戸と引き戸を間違えさせたようです。

バリアフリー配慮か

では、なぜ学校の玄関を、引き戸にしたかを考えました。
確か私の小学校は押し戸だったような・・・。

息子の通う学校は比較的新しく、校内には車いす用トイレや、エレベーターが設置されています。

なるほど・・・車いす用トイレのドアと同じ設計思想なのでしょう。

前後移動がなく、車いすでも開けやすいのが引き戸です。

バリアフリーへの配慮で、玄関が引き戸になったと考えられます。

 

ただ、間違える人が多いなら、ユニバーサルデザインとは言えません。

開けてくれた先生が「横矢印でもつけようかな・・・」と言っていました。

確かに、それなら横に引くと、すぐ認識できそうです。