赤外線リモコン

投稿日:

 もうひとつ。赤外線リモコンの送信部を求めようと思って秋月電子へ行ったら、逆の、リモコンと受信機が売られていた。800円。

IMG_3101

 メーカーのサイトに行くとサンプルスケッチがあるが、なかなかこれは大きさがある。

 IDEにメーカーサイトのスケッチをコピペし、モジュールをArduinoにつなぐ。赤黒はそれぞれ+5VとGND、緑はデジタルの2番ピンにつなぐ。

IMG_3103

 そうやっておいて、付属のリモコンを操作すると、シリアルモニタに操作したキーがモニターされる。

IRRemoconTest

 何か動かすときには、サンプルスケッチの一番下のほうにある、switch~caseの中を書き換えればいいわけだ。

焦電センサで遊ぶ

投稿日:

 秋月電子に行ったら、「焦電センサ」が売られていた。付加回路のついたモジュールで、800円。秋月電子のサイトを見ると、他にも安いものはあるが、店頭にあるものではこれが一番安かった。

IMG_3096

 「焦電センサ」という言い方は随分通ぶった言い方で、一般的には「赤外線人感センサ」と言った方が通りがよかろう。

 買ったものは5V・TTLの負ロジックで、35度くらいのものがセンサ前面の角度120°の範囲2メートル以内で動くと、出力が「負」になる。ロジック端子にプルアップ抵抗をつけて、5Vくらいをくれておいてやるとよいわけだ。

 そこで、早速こんなふうにする。ブレッドボードシールド上にはプルアップ抵抗と、リード線を伸ばして3色LEDを取り付けるだけでいい。

IMG_3097
IMG_3098

 スケッチをこんなふうに書けば、即席人感ランプの出来上がりである。

//
//  Pir2Led.ino
//  焦電センサで遊ぶ。
//    秋月電子焦電センサモジュール「SE-10」使用
//    https://satotoshio.net/blog/?p=1471
//    27.7.11 1100~
//    佐藤俊夫
//
const int PIR = 8, LEDR = 9, LEDG = 10, LEDB = 11, LIGHTTIME = 5000, DULL = 100;
//  DULL  過敏さを抑えるため、100回くらい人感しないと点灯させない。
//  LEDはアノードコモン、焦電センサは負論理なので、どっちも「負 LOW」で点灯
void setup() {
  pinMode(PIR, INPUT);
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);
  digitalWrite(LEDR, HIGH);
  digitalWrite(LEDG, HIGH);
  digitalWrite(LEDB, HIGH);
}

void loop() {
  static int pcount = 0;
  boolean p = HIGH;
  delay(20);
  p = digitalRead(PIR);
  if(p == LOW){
    pcount++;
  }
  if(pcount >= DULL){
    digitalWrite(LEDR, LOW);
    digitalWrite(LEDG, LOW);
    digitalWrite(LEDB, LOW);
    pcount = 0;
    delay(LIGHTTIME);
  }else{
    digitalWrite(LEDR, HIGH);
    digitalWrite(LEDG, HIGH);
    digitalWrite(LEDB, HIGH);
  }
}

お互いを蔑む

投稿日:

 知能の高い人は、存外にバカの扱い方をわきまえているもので、バカが絶叫したり暴れたりすることには冷静だ。

 反面、バカは知能の高い人の扱いをわきまえていなさそうで、その実、意外にわきまえている。

 バカと優秀の懸隔は、実に、一にかかって、ここにあるように感じられる。

 どちらも対手の扱いをわきまえていると信じていることだ。それが、パーセプション・ギャップとなり、悲劇を生む。

 知能の高い人は「所詮バカだ」とバカを蔑み、バカはバカで「わけのわからん変なスケベ野郎」と知能の高い人を蔑んでいる。

 混沌とした特殊な職場にいると、それがとてもよくわかる。

アクリル安物

投稿日:

 今日作ったブツ、生のままだとガチャガチャして見苦しいので、100円ショップのアクリル製仕切り具に取り付けてみたところ、なんだかカラフルで面白い。

IMG_3093

ウェブ扇風機

投稿日:

 昨日試した扇風機遊びを少し進め、温度制御を付けてみたい。

 おあつらえ向きに、最初に買った「Seeedstudio SIDEKICK BASIC KIT」には、サーミスタが入っている。これで温度を検知して、温度ごとに扇風機の回転を制御するわけだ。値の変更などはETHERNET SHIELD 2をつなぎ、ウェブインターフェイスで行うと面白いだろう。

 以前にも試したが、しかし、このキット付属のサーミスタは情報が少なくて困る。そこで、ちゃんと計算してそれなりの温度測定をしてみたい。以前は測りたい温度近傍の特性値をテーブルから拾って2次式で近似しただけであった。

 スペックシートによれば、-55℃で10583.3Ω、+125℃で1.277Ωになる、とある。常温付近では0℃で190.07Ω、40℃で24.87Ωだ。もしサーミスタ直付けでArduinoから5V給電すれば、-55℃のときは0.47mAだが、0℃で26.3mA、40℃で201mAと、Arduinoに流せる電流の20mAを大きく逸脱してしまう。

 40度付近でも大丈夫なように、抵抗を付加しなければならない。40℃の時に流したい電流を5mAと仮定すれば、

IMG_3075

……というような計算で975Ωくらいつなげておけばよいということになる。

 しかし、手持ちの抵抗は、キットに入っていた330Ω・1kΩ・10kΩの3種類しかないから、これで賄うしかない。

 一番大きい抵抗は10kΩだから、これで計算しなおすと、40℃の時で

5V / (24.87Ω + 10kΩ) = 0.5mA

2番目は1kΩ、同じく40℃の時で

5V / (24.87Ω + 1kΩ) = 4.88mA

同様に3番目の330Ωだと

5V / (24.87Ω + 330Ω) = 14mA

…ということになる。間をとって、1kΩで回路を作ってみよう。

 次に、サーミスタは抵抗から温度を知る。一方、Arduinoは電圧からデジタル値を知る。したがって、電圧からまず抵抗値を知らなければその先の温度測定に進めない。

 先の電流調整用の1kΩ抵抗をR0として含め、現在のサーミスタの抵抗値を知るには、一般に式は次のようになろう。

IMG_3079

 これをソースコードに表せば、次のようになる。

  const float v0 = 5.0, r0 = 1000.0;  //  Arduino +5Vと電流調整抵抗1kΩ
  const int resolution = 1024;  //  アナログ入力の分解能
  int srcVal = 0;
  float vt = 0.0, rt = 0.0;
  
  srcVal = analogRead(THERMISTOR);
  vt = srcVal * (v0 / (resolution - 1));
  rt = (v0 * r0 - vt * r0) / vt;

 次に、知った抵抗値から温度を知る計算である。

 サーミスタの抵抗は対数特性を持っているので、関数は対数モデルになる。また、サーミスタの特性を表す重要な値は「B値」と呼ばれるものと、Ta(温度)、R0(抵抗)の3つで、それらはスペックシートに書いてある。

 TaとR0については、「温度がTaのとき、抵抗はR0になる」というものだ。私の手元のサーミスタは、スペックシートによると、

Ta = 25℃
R0 = 50kΩ

……とある。

 B値は「抵抗の対数と、温度の比」である。これもスペックシートに関係式が書いてある。

 これらのスペックシートの値と、知った抵抗値から温度を求める式は、次のようになる。

IMG_3080

 これを、先の抵抗値を知る部分と併せて、Arduinoで使える関数にすれば、このようになろうか。

float tempMesure(){
  const float B = 4350.0, Ta = 25.0, Rt0 = 50000.0;  //  MF11-503Kスペックシート記載
  const float K = 273.15;  //  熱力学温度の定数
  const float v0 = 5.0, r0 = 1000.0;  //  Arduino +5Vと電流調整抵抗1kΩ
  const int resolution = 1024;  //  アナログ入力の分解能
  int srcVal = 0;
  float vt = 0.0, rt = 0.0;
  
  srcVal = analogRead(THERMISTOR);
  vt = srcVal * (v0 / (resolution - 1));
  rt = (v0 * r0 - vt * r0) / vt;
  return(1.0 / (log(rt / Rt0) / B + 1.0 / (Ta + K)) - K);
}

 これを用いて、少し真面目っぽい温度測定スケッチを書けば、次のようになる。

//
//  thermistor2temp.ino
//    サーミスタでわりと真面目に温度を測る。
//    27.7.5(日)
//    佐藤俊夫
//
const int THERMISTOR = 1;

void setup() 
{ 
  Serial.begin(9600);
} 
 
void loop() 
{ 
  float t = 0.0;
  
  t = tempMesure();
  Serial.print("Temp = ");
  Serial.print(t);
  Serial.println("C");
  delay(500);
}

float tempMesure(){
  const float B = 4350.0, Ta = 25.0, Rt0 = 50000.0;  //  MF11-503Kスペックシート記載
  const float K = 273.15;  //  熱力学温度の定数
  const float v0 = 5.0, r0 = 1000.0;  //  Arduino +5Vと電流調整抵抗1kΩ
  const int resolution = 1024;  //  アナログ入力の分解能
  int srcVal = 0;
  float vt = 0.0, rt = 0.0;
  
  srcVal = analogRead(THERMISTOR);
  vt = srcVal * (v0 / (resolution - 1));
  rt = (v0 * r0 - vt * r0) / vt;
  return(1.0 / (log(rt / Rt0) / B + 1.0 / (Ta + K)) - K);
}

 次に、温度に応じて扇風機の回転数が変わるようにしよう。先日作った「ソリッドステート・リレーモジュール」を遺憾なく使用する。

ソリッドステート・リレーモジュール
IMG_3081

 このモジュールの内部には、秋月電子の「ソリッド・ステート・リレー(SSR)キット 25A(20A)タイプ」が組み付けてある。

 27℃で1/fゆらぎエフェクト、28℃で弱風、29℃で強風、とでもしてみようか。1/fゆらぎエフェクトには、先週書いた関数をそのままコピペする。

IMG_3083

//
//  thermistor2windFan.ino
//    サーミスタで温度を測り、扇風機を制御する。
//    27.7.5(日)
//    佐藤俊夫
//
const int THERMISTOR = 1, WINDFAN = 9;
void setup() 
{ 
  Serial.begin(9600);
  pinMode(WINDFAN, OUTPUT);
} 
 
void loop() 
{ 
  const int half = 128, full = 255;
  const float lowTemp = 27.0, midTemp = 28.0, highTemp = 29.0; 
  float t = 0.0, f = 0.0;
  
  t = tempMesure();
  Serial.print("temp=");
  Serial.println(t);
  if(t > highTemp){
    analogWrite(WINDFAN, full);
  }else
  if(t > midTemp){
    analogWrite(WINDFAN, half);
  }else
  if(t > lowTemp){
    f = f1Fluctuation();
    analogWrite(WINDFAN, f);
  }else{
    analogWrite(WINDFAN, 0);
  }
  delay(20);
}

float tempMesure(){
  const float B = 4350.0, Ta = 25.0, Rt0 = 50000.0;  //  MF11-503Kスペックシート記載
  const float K = 273.15;  //  熱力学温度の定数
  const float v0 = 5.0, r0 = 1000.0;  //  Arduino +5Vと電流調整抵抗1kΩ
  const int resolution = 1024;  //  アナログ入力の分解能
  int srcVal = 0;
  float vt = 0.0, rt = 0.0;
  
  srcVal = analogRead(THERMISTOR);
  vt = srcVal * (v0 / (resolution - 1));
  rt = (v0 * r0 - vt * r0) / vt;
  return(1.0 / (log(rt / Rt0) / B + 1.0 / (Ta + K)) - K);
}

int f1Fluctuation(){
  static float x = 0.1;
  if(x < 0.5){
    x = x + 2 * x * x;
  } 
  else {
    x = x - 2 * (1.0 - x) * (1.0 - x);
  }
  if(x < 0.05 || x > 0.995){
    x = random(10, 90) / 100.0;
  }
  return((int)(x * 255));
}

 回路図など、描くも愚かというか、こんな簡単なものである。

IMG_3084

 さて次に、ETHERNET SHIELD 2をつなぎ、この扇風機をWeb化する。昨日買っておいた「クリアランス確保用ピンソケット」が役に立つ。

IMG_3067

 組み付けるとこんな感じである。回路はネットにつながない場合と同じでよい。

IMG_3087

 こんなインターフェイスで動かす。

ネット扇風機インターフェイス

 設定した温度になると扇風機が回る。

IMG_3088

 スケッチはこのようになる。

//
//  web2thermistor_windFan.ino
//    サーミスタで温度を測り、扇風機を制御する。
//    27.7.5(日)
//    佐藤俊夫
//
#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;
const int THERMISTOR = 1, WINDFAN = 9;
//
void setup() 
{ 
  Ethernet.begin(mac, ip);
  SERVER.begin();
  Serial.begin(9600);
  pinMode(WINDFAN, OUTPUT);
} 
 
void loop() 
{ 
  const int half = 128, full = 255;
  static float lowTemp = 27.0, midTemp = 28.0, highTemp = 29.0; 
  float t = 0.0, f = 0.0;
  //  Webサーバの動作
  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("low=") >= 0){
      lowTemp = rstr.substring(rstr.indexOf("low=") + 4, rstr.indexOf("&green=")).toInt();
      midTemp = rstr.substring(rstr.indexOf("mid=") + 4, rstr.indexOf("&blue=")).toInt();
      highTemp = rstr.substring(rstr.indexOf("high=") + 5, rstr.indexOf("&end")).toInt();
    }
    rstr = "";
    sendform(lowTemp, midTemp, highTemp);
    delay(1);
    // close the connection:
    CLIENT.stop();
  }
  // 温度測定
  t = tempMesure();
  Serial.print("temp=");
  Serial.println(t);
  if(t > highTemp){
    analogWrite(WINDFAN, full);
    Serial.println("high");
  }else
  if(t > midTemp){
    analogWrite(WINDFAN, half);
  }else
  if(t > lowTemp){
    f = f1Fluctuation();
    analogWrite(WINDFAN, f);
  }else{
    analogWrite(WINDFAN, 0);
  }
  delay(20);
}

float tempMesure(){
  //  Seeedstudio SIDEKICK BASIC KIT付属のサーミスタ「MF11-503K」で
  //  温度を測る。
  const float B = 4350.0, Ta = 25.0, Rt0 = 50000.0;  //  MF11-503Kスペックシート記載
  const float K = 273.15;  //  熱力学温度の定数
  const float v0 = 5.0, r0 = 1000.0;  //  Arduino +5Vと電流調整抵抗1kΩ
  const int resolution = 1024;  //  アナログ入力の分解能
  int srcVal = 0;
  float vt = 0.0, rt = 0.0;
  
  srcVal = analogRead(THERMISTOR);
  vt = srcVal * (v0 / (resolution - 1));
  rt = (v0 * r0 - vt * r0) / vt;
  return(1.0 / (log(rt / Rt0) / B + 1.0 / (Ta + K)) - K);
}

int f1Fluctuation(){
  //  間欠カオス法により0~255の間で1/fゆらぎを生成して返す。
  static float x = 0.1;
  if(x < 0.5){
    x = x + 2 * x * x;
  } 
  else {
    x = x - 2 * (1.0 - x) * (1.0 - x);
  }
  if(x < 0.05 || x > 0.995){
    x = random(10, 90) / 100.0;
  }
  return((int)(x * 255));
}

void sendform(float lowTemp, float midTemp, float highTemp){
  //  フォームを送る。
  char* formFirstHalf[] = {
    "<html>",
    "  <head>",
    "    <meta charset=\"utf-8\">",
    "  </head>",
    "  <body bgcolor='#ddddff'>",
    "    <center>",
    "      <h1>Arduino ネット扇風機</h1>",
    "      <form method='GET'>",
    "        <table>",
    "          <tr>",
    "  	    <th>ゆらぎ送風温度</th>",
    "  	    <th>弱風温度</th>",
    "  	    <th>強風温度</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("           <input type='text' name='low' size='6em' value =");
  CLIENT.print(lowTemp);
  CLIENT.println(">");
  CLIENT.println("            </td>");
  CLIENT.println("            <td>");
  CLIENT.println("           <input type='text' name='mid' size='6em' value =");
  CLIENT.print(midTemp);
  CLIENT.println(">");
  CLIENT.println("            </td>");
  CLIENT.println("            <td>");
  CLIENT.println("           <input type='text' name='high' size='6em' value =");
  CLIENT.print(highTemp);
  CLIENT.println(">");
  CLIENT.println("            </td>");
  CLIENT.println("          </tr>");
  for(i = 0; i < 7; i++){
    CLIENT.println(formSecondHalf[i]);
  }

}






飲んだくれていて深夜になる

投稿日:

 酒を飲み、ここ最近には珍しく夜更かしをしている。

IMG_3071

 4~5年前まで私は宵ッぱりであった。朝は今と同じ5時起き、5時半から6時までピアノの稽古をして通勤、7時半ごろ職場の席に着いて、カフェインを大量に摂っては仕事、午後に腕立て伏せ300回・腹筋300回・ランニング最低12km、更に仕事をして、その頃は17時半で定時だったので、家に帰って勉強して酒を飲み、寝るのはだいたい1時頃で、4時間ほど眠ってまた朝5時に起きる。それが10年以上の習慣だった。

 ところが、4~5年ほど前から、以前までの夜更かしがウソだったかのように早く寝るようになった。3年ほど前には、21時半には寝ていた。まるで小学生みたいだが、その頃は故あって1日20kmほどランニングしなければならず、筋トレは腕立て伏せ500回、腹筋500回にも達していたので、それぐらい早く寝なければ、なんとしても体がついていかなかった。そのために晩飯はうどん用のどんぶりに山盛りに食い、酒はウィスキーを生のままコップに指五本分注いで飲んでいた。

 今は仕事が定時ではなくなってしまったのだが、家に帰って風呂に入って晩飯を食い、妻子と喋ったらすぐに寝てしまうようにしている。テレビは見ないので、まったく問題がない。節電・省エネにもなってよい。

 テレビを見ないようにすると、非常に電気代が安く済む。新聞も読まないようにすると、森林資源や二酸化炭素などに関してまことに筋道が通る……などとうそぶきつつ、ネットやPCをバリバリ使いまくっているのだからシャレにならないが。

Raspberry Piの入門は

投稿日:

 今はArduinoが面白いのでこればかりいじっているが、ひと段落ついたら世間で人気のRaspberry Piも買ってみようと思っている。

 Raspberry Piは本体だけ買ってもどうにもならないだろうということはだいたい想像がつくので、今日千石電商へ寄った時になにかいいものはないかと店内のポップなど見てみると、「入門用に全部入ってポッキリこのお値段!」というパッケージは、だいたい8千円ぐらいである。

 どうやら、このあたりのものが店頭にあったようだ。


 覚えておきたい。

秋葉原路上

投稿日:

 今日、知人から聞いた秋葉原の人気ラーメン店「野郎ラーメン」というところへ行った。

 私がラーメン屋に行くのは、実は最近では珍しい。北海道で暮らした頃に食べたラーメンがうまかったので、その後、他のラーメンがあまりうまいと感じられなくなったということも一因である。また、妻が作る具入りのインスタントラーメンのほうがうまいと感じてしまうので、ラーメン店から遠ざかる、ということもある。

 さておき、ラーメン好きの人に言わせると、その「野郎ラーメン」という店は、「二郎インスパイア系ラーメン店」という系列に分類されるそうで、いやはや、ラーメン好きの人たちの旺盛な探求欲には恐れ入るばかりである。

 野郎ラーメンでは、その名も「豚野郎ラーメン」というファッキンなネーミングのメニューが人気だそうだが、今日は味付卵入りの「野郎ラーメン」というのを選んだ。

 小柄な白人の女の子が片言でフロアを切り盛りしており、後れ毛がなにやらムフフと可愛らしい。

 ラーメンを食って満腹し、店の前でSwarmでも入れておこうかい、とスマホをいじっていたら、

「すいません、フジテレビです。取材なんですが」

と、お兄さんがアンケート用紙と鉛筆を持って近寄ってきた。

「はいはい、なんでしょう?」

「今、秋葉原は『カレー激戦区』ということで世間の噂が盛り上がっているんです。」

「へっ?……はあ、そうなんですか?」という私のスットボケた返事に、お兄さんは(あれっ、これはインタビュー相手を間違ったな)という顔をしたが、あきらめず、

「で、もし、おすすめのカレー店や噂のカレー店などをご存知でしたら教えていただけませんか?」

「えっ……。す、すみません、ごめんなさい。カレー、あんまり食べないもので……」

「……失礼しました、ハハッ、最初の反応で、そうだろうなあ、と思いました、いや、すみません。……今日はラーメンで?」

「ええ、それがね、ラーメンもめったに食わないんですがね。今日は噂をきいて入ってみたんですよ。」

「へえ、めったに召し上がらない?」

「秋葉原へ来ると、万世橋の向う、連雀町のほうの、じじむさい界隈のじじむさいものを食う方が性に合ってましてね」

「ははあ、それはなるほど、粋向きですねえ。……いやどうも、お時間をお取らせしました。よい一日で」

……などと、お兄さん、なかなか軽妙に人を喋らせるのであった。

 本郷通りを南へ横切って、メイドさんの並んでいるカルチャーズ・ゾーンの前を通り過ぎ、千石電商へ行ってネジ、ケース、ニッパー、蛇の目基盤、ピンコネクタなどを買い込む。

 今日の買い物の大ヒットは、このピンコネクタである。180円。

IMG_3067

 こんなものの何が大ヒットなのかと言うと、これは実はArduino用のセットなのである。本来はArduino製作用のユニバーサル基盤に半田付けして使うものだ。しかし、私がこれを購入したのは別の理由だ。

 これは、先日買ったArduino用のブレッドボードシールドである。

IMG_3063

 まことに便利なのだが、難点がある。ETHERNET SHIELD 2 とともに使おうとすると、ピンの長さが短く、ETHERNET SHIELD 2 の RJ45コネクタのシールドと干渉してしまい、下の写真のように斜めになってきちんと挿さらないのである。

IMG_3065

 そこで、買ってきたこのピンコネクタを、ETHERNET SHIELD 2 に挿す。

IMG_3068

 こうすることによりめでたくArduino UNO R3 + ETHERNET SHIELD 2 + ブレッドボードシールドの3階建てがまっすぐに挿さって、使えるようになるのであった。

IMG_3069

 めでたし、めでたし。