LEDをネットにつないでコントロール

投稿日:

 先週少しやりかけて途中だった、Arduino UNO に ETHERNET SHIELD 2 をとりつけ、ウェブインターフェイスを作ってこれでLEDをコントロールするという遊びの続きをやる。

 こんなふうなインターフェイスでコントロールすることにする。

名称未設定 1

 で、ブレッドボードとArduinoはこんな感じ。「SeeedStudio SIDEKICK BASIC KIT」に入っていた3色LEDを使う。

IMG_3004

 スケッチはこんな感じで。ウェブ上で同じようなことを公開している方々は、ブラウザの出力を受けるのに、たいてい普通のポインタ文字列を使っておられるのだが、せっかくStringクラスがあるので、それを活用することにした。Stringクラスを使う欠点は多少メモリを浪費することだが、反面、余裕は十分あり、今回は別にメモリが足りないというわけでもないので、そうした。

//
//  Web2TriColorLED.ino
//    27.06.07(日) 1800~
//    佐藤俊夫
//    3色LEDをウェブインターフェイスで制御
//    ETHERNET SHIELD 2 使用
//
#include <SPI.h>
#include <Ethernet2.h>
//
byte mac[] = {
  0x90, 0xA2, 0xDA, 0x0F, 0xF6, 0x74
};
IPAddress ip(192, 168, 1, 129);
EthernetServer SERVER(80);
EthernetClient CLIENT;
int R = 0, G = 0, B = 0;
const int LEDR = 3, LEDG = 5, LEDB = 6;
//
void setup() {
  Ethernet.begin(mac, ip);
  SERVER.begin();
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);
}


void loop() {
  char c;
  String rstr = "";
  CLIENT = SERVER.available();
  if (CLIENT) {
    while (CLIENT.connected()) {
      if (CLIENT.available()) {
        c = CLIENT.read();
        rstr += c;
        if(rstr.endsWith("\r\n")){
          break;
        }
      }
    }
    if(rstr.indexOf("red=") >= 0){
      R = rstr.substring(rstr.indexOf("red=") + 4, rstr.indexOf("&green=")).toInt();
      G = rstr.substring(rstr.indexOf("green=") + 6, rstr.indexOf("&blue=")).toInt();
      B = rstr.substring(rstr.indexOf("blue=") + 5, rstr.indexOf("&end")).toInt();
    }
    analogWrite(LEDR, R);
    analogWrite(LEDG, G);
    analogWrite(LEDB, B);
    delay(10);
    rstr = "";
    sendform();
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    CLIENT.stop();
  }
}
//
void sendform(){
  char* formFirstHalf[] = {
    "<html>",
    "  <head>",
    "    <meta charset=\"utf-8\">",
    "  </head>",
    "  <body>",
    "    <center>",
    "      <h1>Arduino 3色LEDをウェブインターフェイスで</h1>",
    "      <form method='GET'>",
    "        <table>",
    "          <tr>",
    "  	    <th style='background-color:red;  color:white;'>赤</th>",
    "  	    <th style='background-color:green;color:white;'>緑</th>",
    "  	    <th style='background-color:blue; color:white;'>青</th>",
    "	  </tr>"
  };  //  14 num.
  char* formSecondHalf[] = {
    "        </table>",
    "        <input type='hidden' name='end'>",
    "        <input type='submit' value='セット'>",
    "      </form>",
    "    </center>",
    "  </body>",
    "</html>"
  };  // 7 num.
  int i = 0;

  CLIENT.println("HTTP/1.1 200 OK");
  CLIENT.println("Content-Type: text/html");
  CLIENT.println("Connection: close");
  CLIENT.println();
  CLIENT.println("<!DOCTYPE HTML>");
  for(i = 0; i < 14; i++){
    CLIENT.println(formFirstHalf[i]);
  }
  CLIENT.println("          <tr>");
  CLIENT.println("            <td>");
  CLIENT.println("              <select name='red'>");
  for(i = 0; i <= 255; i++){
    CLIENT.print("                <option value='");
    CLIENT.print(i, DEC);
    if(i == R){
      CLIENT.print("' selected>");
    }else{
      CLIENT.print("'>");
    }
    CLIENT.print(255 - i, DEC);
    CLIENT.println("</option>");
  }
  CLIENT.println("              </select>");
  CLIENT.println("            </td>");
  CLIENT.println("            <td>");
  CLIENT.println("              <select name='green'>");
  for(i = 0; i <= 255; i++){
    CLIENT.print("                <option value='");
    CLIENT.print(i, DEC);
    if(i == G){
      CLIENT.print("' selected>");
    }else{
      CLIENT.print("'>");
    }
    CLIENT.print(255 - i, DEC);
    CLIENT.println("</option>");
  }
  CLIENT.println("              </select>");
  CLIENT.println("            </td>");
  CLIENT.println("            <td>");
  CLIENT.println("              <select name='blue'>");
  for(i = 0; i <= 255; i++){
    CLIENT.print("                <option value='");
    CLIENT.print(i, DEC);
    if(i == B){
      CLIENT.print("' selected>");
    }else{
      CLIENT.print("'>");
    }
    CLIENT.print(255 - i, DEC);
    CLIENT.println("</option>");
  }
  CLIENT.println("              </select>");
  CLIENT.println("            </td>");
  CLIENT.println("          </tr>");
  for(i = 0; i < 7; i++){
    CLIENT.println(formSecondHalf[i]);
  }

}

 気を付けるところは、私が買った「SeeedStudio SIDEKICK BASIC KIT」というキットに入っている3色LEDは「アノードコモン(共通陽極)」というタイプで、プラスに5V、各色のコントロールはマイナスになる、という点だ。ここを間違えると思ったように動作しない。一番長い脚が共通陽極だ。封入の切り欠きを左にして、左から赤、アノード、緑、青の順に脚が並ぶ。

 また、フォームから与える値も、アノードコモンであるゆえに、「0」が最も明るくなり、「255」が最も暗くなるので、インターフェイスを逆にするなど、多少工夫が必要だ。

 それから、PWM(パルス幅変調)の機能を大いに活用し、いろいろな色が出せるようにした。この場合の注意点は、ETHERNET SHIELD 2を取り付けると、10番・11番・12番のピンが使えなくなるので、他のピンで出力しなければならないことだ。今回は3番・5番・6番を使った。

 で、ウェブインターフェイスをタブレットにロードする。

IMG_3005

 動かしてみるとこんな感じで、いろんな色になって面白い。


3色入りLED

投稿日:

 あ、そうだ、最初に買ったキットの中に3色入りのLEDがある。アレを、Webインターフェイスでコントロールするのも面白そうだな……。イーサネットシールド2もあるし。

カメラのシャッターをネット経由で切る

投稿日:

 先週、Arduinoを使ってデジカメのシャッターを切る遊びがやりたくて、ソレノイドでやろうとしたら、ソレノイドの力不足でうまくいかなかった。

 よく考えてみたら、最初に買った入門キットの中に小さいサーボがあり、これは力があるからシャッターぐらい押せるだろう、と思って工夫した。

 そうしたら、うまくいった。こんな具合である。



 ネットワーク経由で動くようになっており、そのプログラムは次の通りである。

//
//  WebServerでサーボを動かし、カメラのシャッターを切る。
//    佐藤俊夫
//    27.5.30(土)1300~
//

#include <SPI.h>
#include <Ethernet2.h>
#include <Servo.h>

byte mac[] = {
  0x90, 0xA2, 0xDA, 0x0F, 0xF6, 0x74
};
IPAddress ip(192, 168, 1, 129);
EthernetServer server(80);
Servo shutter;
const int SERVO = 9;

void setup() {
  Ethernet.begin(mac, ip);
  server.begin();
  shutter.attach(SERVO);
  shutter.write(90);
}

void loop() {
  String recvbuf;
  EthernetClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        recvbuf += c;
        if (c == '\n' && currentLineIsBlank) {
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("<head></head>");
          client.println("<body>");
          client.println("<center><h3>Drive solenoid.</h3>");
          client.println("<hr>");
          client.println("<form method=\"POST\">");
          client.println("<input type=\"submit\" value=\"Do!\">");
          client.println("</form>");
          client.println("</center>");
          client.println("</body>");
          client.println("</html>");
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
          if(recvbuf.indexOf("POST") == 0){
            shutter.write(50);
            delay(5000);
            shutter.write(90);            
          } 
          recvbuf = "";
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    client.stop();
  }
}

次に、ETHERNET SHIELD 2というやつを…

投稿日:

 次に、昨日FETやソレノイドと一緒に買っておいた「イーサネットシールド」というやつを試す。

 これを買ったのは、簡単なウェブインターフェイスで、例えばフォームのボタンをクリックするとデジカメのシャッターが落ちる、みたいなのをやりたかったからだ。千石電商で3240円だったが、多分、もっと安い互換品などもあるのだろう。

 ともかく、こんな箱に入っている、こういう形のブツである。

IMG_2880

 この方のサイトなどを勝手に参考にさせていただきつつ、いじくってみる。

 Arduinoに取り付けるとこのようになる。

IMG_2881

 で、ArduinoのIDEにサンプルプログラムが入っているから、それをタッチアップして目的を達する。

 注意しなければならないのは、私の買ったのは「ETHERNET SHIELD 2」という最新のもので、ネットで多く紹介されている「ETHERNET SHIELD R3」というものとは違うということだ。

 私の買った「ETHERNET SHIELD 2」は、最新のArduino IDE 1.7.3でないと、サンプルコードなども違い、扱えない。私が使っているIDEは1.6.4なので、アップグレードしなければならない。

 アップグレードしたIDEで、次のように「ファイル」→「スケッチの例」→「Ethernet2」とメニューを操作していくとサンプルコードが出てくる。

webServerSketchExample2

  • AdvancedChatServer
  • BarometricPressureWebServer
  • ChatServer
  • DhcpAddressPrinter
  • DhcpChatServer
  • TelnetClient
  • UdpNtpClient
  • UDPSendReceiveString
  • WebClient
  • WebClientRepeating
  • WebServer

……このように、けっこういろいろなものが入っている。今日は一番下の「WebServer」を選ぶ。

 このソースのMACアドレスとIPアドレスを、先達サイトを参考に現況に合わせて書き換える。MACアドレスはシールドの基板の裏にシールで貼ってある。
 
 出来上がったらそのへんにのたくっているカテ5のモジュラーをえいっとつっこみ、ブラウザにIPアドレスを入れれば、すぐにミニWebサーバとして動き出す。

ArduinoWebServerScreen

 これは、各アナログピンの現在の値を5秒毎にモニタしている。何かセンサをピンにつなげば、即、ネット温度計やネット照度計の出来上がりである。

 さて、次に、コイツで「POST」を受け取る段取りだ。コイツにアクセスして、フォームのボタンを押すと、ソレノイドが動く、という機構を作るためである。

 本当ならクライアントから来る文字列を標準入力で受ける段取りが必要だが、今日は簡略化して、ブラウザがPOSTを投げたら、内容はなんでもいいから、とりあえずソレノイドを動かす、というふうにする。

 そのソースコードはこんな感じだ。

//
//  WebServerでソレノイドを動かす。
//    佐藤俊夫
//    27.5.24(日)1352~
//

#include <SPI.h>
#include <Ethernet2.h>

const int FET = 9;
byte mac[] = {
  0x90, 0xA2, 0xDA, 0x0F, 0xF6, 0x74
};
IPAddress ip(192, 168, 1, 129);
EthernetServer server(80);

void setup() {
  Ethernet.begin(mac, ip);
  server.begin();
  pinMode(FET, OUTPUT);
}

void loop() {
  String recvbuf;
  EthernetClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        recvbuf += c;
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");
          client.println("<head></head>");
          client.println("<body>");
          client.println("<center><h3>Drive solenoid.</h3>");
          client.println("<hr>");
          client.println("<form method=\"POST\">");
          client.println("<input type=\"submit\" value=\"Do!\">");
          client.println("</form>");
          client.println("</center>");
          client.println("</body>");
          client.println("</html>");
        if (c == '\n' && currentLineIsBlank) {
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
          if(recvbuf.indexOf("POST") == 0){
            digitalWrite(FET, HIGH);
            delay(2000);
            digitalWrite(FET, LOW);            
          } 
          recvbuf = "";
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    delay(1);
    client.stop();
  }
}

 次に、ちょっと仕掛けを作る。本当はカメラのシャッターを切りたいのだが、買ってきたソレノイドの力があんまりなくて、シャッターが切れない。それで、ガラスのコップをソレノイドで叩いて音を出す。

 ソレノイドは、午前中やったように、電流がちょいとばかり多く流れるので、FETでリレーしてやる。

 こんな仕掛けにする。

IMG_2885

 こんなフォームを作り、携帯電話にロードする。「Do!」というボタンをクリックすると、ソレノイドが動く。

form

 で、ガラスのコップにソレノイドの軸を近づけて……。

IMG_2886

 操作するとこんな風になる。


 

インターネットの商用利用のことを書こうとして

投稿日:

 ちょっと今後のWebに関して思うところでも書き留めておこうとして、ひょいと「LINE」、SNS、なんて書いたら、ブログ、Web掲示板、田代祭り、ネットニュースのエロ画像、メーリングリスト、メール……と遡ってしまい、そうするととめどもなくパソコン通信のBBS、草の根ネット、ニフティ、テレホーダイ、電電公社からNTTへ、ペンティアム、486、386、286、8086、エプソンの互換機、MS-DOSが5、4、3、3.30bが一番よくつかった、2.11、PC-DOS、8ビットのBASIC、シャープの電卓に4004の互換の石が乗っててこれはたしかPC-1211って型番、緑っぽい液晶で、そう、嶋正利氏、嶋氏といえば8086の一方ではザイログでZ80AからB、そんでZ800にZ8000、いやそれはもっと後の話、シャープのワンボードのマイコン博士、TK-80、80にはあとに「BS」てのがあってさ、その頃だったら電電公社の「DEMOS」とかまだ動いてたでしょプッシュホンでアクセスするアレ……などと、際限なく収拾のつかない回顧文字列に脱線していくから、もう、ダメだ。

WordPressでFacebookにクロスポスト

投稿日:

 WordPress+Jetpackのパブリサイズ共有。WordPressもJetpackも着々とバージョンは上がっていくのだが、Facebookへのクロスポストがさっぱり効かない。

 どうも困ったな、と思っていたのだが、今プラグインの更新案内が来たので、また今度もどうせダメだろ、ぐらいの気持ちで更新してみたら、できている。

 やった。

 これで、Webへの文字列書きなぐり環境が一応完成したぞ。

ともかく

投稿日:

 去年、OCNのブログサービス「ブログ人」が廃止されてしまった。MovableTypeベースの機能豊富なブログで、10年も書いたのだが、なくなってしまったのはどうにもならず仕方がない。ウェブ世紀の日常としてあきらめなければならない。

 だが、そこへ加えてホームページサービスの「PageOn」も廃止の案内が来るようでは、もうこれはどうしようもない。

 そこでともかく、こうしてレンタルサーバを借り、そこにWebスペースを設けた。ひところとは違って数百円で借りることができ、自宅のPC Linuxでサービスするのなんぞとはちがって、そこそこセキュリティも安心だから、これでよかろう。

WordPress入門

投稿日:

 WordPressの情報サイトにある「はじめてのWordPress」、更にその中の「計画を立ててみよう」という項目は、非常に良い。けだし名文である。

「なぜこのサイトを始めたのか?」という質問を思い出してほしい。というのも、君が共有するに値する有益でタイムリーな情報をもっているからであり、君が自分に興味のある主題について語りたがっているからであり、もしかしたら、ただ語ると面白いと思っているからだ。なぜ? みんなそうしているじゃないか!

 いいね。ぐっとくる。

心霊ソースコード

投稿日:

 デジタルと霊魂とのシームレスな融合、ということを考えてみた。

 かつて写真は、画期的な技術的ブレイクスルー、人類の文明を劇的に前進させるハイパーメディアであったはずである。

 しかし、当時の科学技術の粋を集めた写真技術にすら、いにしえの神秘主義は待て(しば)しというものがなく、「心霊写真」という一大ジャンルがいまだ絶えることなく人々を惑わせている。

 写真に霊魂が写るのならば、デジタルデータにも霊魂の作用があってしかるべきである。

 すなわち、「心霊mp3」「心霊csv」「心霊プレゼン」「心霊ソースコード」「心霊web」「心霊html」「心霊パケット」「心霊名前解決」などがそれである。

 写真に霊が写るというのならば、通るはずのないコンパイルに心霊の作用したソースコードが通るとか、解決されるはずのないfqdnがなぜかIPアドレスになる、などということもあってよい。

twitter

投稿日:

 「twitter」というのが流行っているようである。何がいいんだか悪いんだかサッパリわからないのだが、とにかく登録してみた。

 とにかく、Webがらみのことなら、何でも味見をしてみなくてはならない。