照度センサを使ってみた

今回は照度センサを使ってみます。

明るさを測る方法のひとつにフォトレジスタを使うものがあります。フォトレジスタは光を入射すると電気抵抗が変化する素子です。フォトレジスタには様々な種類がありますが、以前はCdS(硫化カドミウムセル)といわれるものがよく使われていました。CdSは「抵抗値の変化の幅が大きい」、「反応する周波数が広い」などの利点がありましたが、カドミウムがRoHS指令の規制対象元素になったため、あまり使われなくなりました。

現在フォトダイオードやフォトICなどの代替品が各社から販売されていますが、今回はCdSの代わりとして使いやすいパナソニック製NaPiCa AMS302を使いました。千石電商で入手できます。
NaPiCaはフォトダイオードのパッケージに増幅回路を内蔵しており、人間の視感度に近い特性を持っているのが特徴です。印加電圧は1.5~6V、ピーク波長は580nmです。周囲の明るさに比例した光電流がリニアに出力されます。

DSC01510s
回路を組んでみました。写真のブレッドボード上の透明なLEDのような形をした素子がAMS302です。AMS302は上がアノード、下の切り欠きのある側がカソードです。アノードのほうが足が長くなっています。抵抗をアノードとGNDの間につなぐことにより抵抗とアノードの間から出力(電圧)が得られます。今回は330Ωの抵抗をつなぎました。RaspberryHabuBasic側はアナログ入力0ピンを使っています。

 // napica.c sample program for RaspberryHabu
 // Licence CC 0 ( Public Domain )
 
 #include "stdio.h"
 #include "stdlib.h"
 #include "wiringPiSPI.h"
 #include "unistd.h"
 #define SPIBUFFSIZE 256
 unsigned char spidata[SPIBUFFSIZE];
 int MCP3008Read( int channel ){
   int spireturn,data;
   spidata[0]= 1; 
   spidata[1]= ( 0x80 | channel << 4 )  ;
   spidata[2]= 0;
   spireturn = wiringPiSPIDataRW( 0, spidata , SPIBUFFSIZE );
   data = ((spidata[1]&3) << 8) + spidata[2];
 return(data);
 }

int main()
{
  int spiresult;
  if (-1 == wiringPiSPISetup(0,1000000))
    {
      printf("SPI setup error!");
      exit(1);
    }
  while(1){
    spiresult=MCP3008Read(0);
    printf("channnel 0 : %d\n", spiresult);
    sleep (1);
  }
}

AD変換された10bitデータがそのまま表示されるコードです。1から1024の数字が出ます。暗いと小さくて明るいと大きい数字になります。

DSC01511通常時です。すこし暗めですが、数値は110付近ですね。

DSC01512センサを手で覆ってみました。数値は15付近。だいぶ暗いです。

DSC01514白いLEDで照らしてみました。数値は250付近でした。

このセンサを使えば明るさの変化に対応したシステムが組めます。
今後、いろいろ使って紹介していきたいと思います。

温度計作ってみた

今回は熱電対を使って温度計を作ってみます。

異なる2種類の金属線をつないで、二つの接した部分に温度差を与えると電圧が発生します。この現象をゼーベック効果といいます。熱電対とはこの現象を利用したセンサで、一端の温度が分かれば発生する電圧と既知の金属の特性からもう一方の接点の温度を求めることができます。

絶対的な温度を計る場合は熱電対の測定に使う接点を温接点、端子側を基準接点とし、その温度(基準接点温度)を測り測定点の温度を求める必要があります。基準接点温度を測定するときはサーミスタや測温抵抗体などを使います。

試作には秋月電子で購入したK型熱電対ステンレス管タイプを使いました。この熱電対は-200℃~+600℃の広範囲の温度を測定することができます。温度差1℃当たり約40.7μVの起電力が発生します。

RaspberryHabuのアナログポートに入力するには電圧変化が小さすぎるのでオペアンプで増幅します。一般的に信号を増幅するためによく使われるLM358では誤差が大きすぎるので今回は精度の高いオペアンプNJM2119Dの1回路分を使い、1kΩと100kΩの抵抗で100倍に増幅し、RaspberryHabuのアナログ1番ピンに入力しました。NJM2119Dは秋月電子で手に入ります。

2V2A6612

熱電対の端子は商品では樹脂の端子がついていますが、ブレッドボードに指すために分解してあります。ケーブルは単芯なので被膜を取るだけでブレッドボードにさせます。
写真は2か所の温度を計るため熱電対を2つ使い、2チャンネル分の回路を作っています。

熱電対の出力はアナログなのでRaspberryHabuBasicのアナログ入力ピンからMCP3008を通してSPIでRaspberryPiに入力します。
以下のコードはサーミスタも使い室温を出したうえで熱電対で測定した結果の温度差を足して計測対象の温度を出しています。

 // thermocouple.c sample program for RaspberryHABU
 // Licence CC 0 ( Public Domain )
 
 
 #include "stdio.h"
 #include "stdlib.h"
 #include "wiringPi.h"
 #include "unistd.h"
 #define SPIBUFFSIZE 256
 #define THERMISTORCHANNEL 7
 #define THERMISTOR 10000 // 10k ohm
 #define B 3380 // 
 #define DIVR 10000 // 10k ohm
 
 unsigned char spidata[SPIBUFFSIZE];
 int MCP3008Read( int channel ){
   int spireturn,data;
   spidata[0]= 1; 
   spidata[1]= ( 0x80 | channel << 4 )  ;
   spidata[2]= 0;
   spireturn = wiringPiSPIDataRW( 0, spidata , SPIBUFFSIZE );
   data = ((spidata[1]&3) << 8) + spidata[2];
 return(data);
 }
 
 int main()
 {
   int spiresult,spiresult7;
   double thermistor_r,baseTemp,TCTemp,t1;
   if ( -1 ==  wiringPiSPISetup(0,1000000) )
   {
     printf("SPI setup error!");
     exit(1);
   }
   while (1){
     spiresult7=MCP3008Read(THERMISTORCHANNEL);
     thermistor_r = ( DIVR * spiresult7 )/ (1024 -spiresult7 );  // thermistor is lower
     t1 =   log( thermistor_r / THERMISTOR ) ;
     baseTemp = ((298*B) / ( B + ( 298 * t1 ))) - 273;
   
     spiresult=MCP3008Read(0);
     TCTemp = (3.3/1024.0*(double)spiresult*1.010)/0.00407;
 
     printf("temp: %3.f c  (room temp: %3.f c : A0 value0 %d)\n",TCTemp+baseTemp,baseTemp,spiresult);
     sleep(10);
   }
 
 }

入力した値はAD変換され10bitのデータとしてRaspberryPiに入力されます。その値は3.3Vを10bit(1024)分割された値なので1Vあたりの数値を出し、それを40.7μVで割ることで温度差を出しています。NJM2119Dは5V電源を試用していますが、出力は4V程度までしか出ないため、1.01をかけて補正してあります。

上記のプログラムとは出力が違いますが、別の実験で熱電対と基準接点温度を測定するためにサーミスタを使ったときの出力結果は以下のようになりました。この実験ではコップのお湯の温度を測ってみました。

IMG_20140326_141717

今回使ったK型熱電対は対温度性が1250℃(樹脂の端子カバーを残して使う場合は600℃)と高いのでオーブン作ったりリフロー機作ったりできそうですね。

キャラクタ液晶使ってみた

Arduinoでも良く使われるキャラクタ液晶モジュールをRaspberryPiで使ってみました。
今回使ったのは台湾サンライク社(SUNLIKE)液晶モジュールSD1602HULB-XA-G-Gです。若松通商でGR-SAKURA用として販売されています。秋月電子でも販売されています。
16文字x2行の液晶でLEDバックライトも内蔵しています。

この液晶モジュールに内蔵されているインターフェースICはHD44780互換になっています。HD44780は、80年代前半に日立製作所(現ルネサス エレクトロニクス)から発売されたキャラクタ液晶用のコントローラICです。現在、ほとんどのキャラクタ液晶モジュールでHD44780またはその互換ICが使用されています。HD44780は「MPUにバス接続してコマンドによる制御が可能」「80文字(40桁×2行)分の表示データ・バッファを内蔵」「キャラクタ・ジェネレータを内蔵」「LCDドライバを内蔵しLCDパネルを直結駆動可能」などの特徴があり、カナや外字の表示も可能です。

この液晶インターフェースを動かすにはシンク電流が流れるようにしておく必要がありますが、RaspberryHabuのTD62783AGPを通すとシンク電流が流れないため、基板上のRaspberryPiのピンから直結されているポートにコネクタをつけます。
DSC01441s
この液晶にデータを書き込む方法は4bitモードと8bitモードがありますが、今回はピン数を節約するため4bitモードで使います。4bitモードでは8bitの信号を上位4bit下位4bitの2回に分けて書き込みます。
ピンを液晶にはんだづけしてブレッドボードに差し、以下のように繋ぎます。
DSC01446s

左下の半固定抵抗は10kΩでコントラスト調整用です。だいたい3kΩくらいが見やすい値でした。液晶側15、16ピンはバックライト用で15ピンはVcc、16ピンは330Ωの抵抗を通してGNDにつなぎます。

/*
lcdout.c
Lisence CC0.
*/
#include "stdio.h"
#include "stdlib.h"
#include "unistd.h"
#include "wiringPi.h"

#define RS 4
#define E 6
#define ESETUPTIME 10
#define NEXTTIME 50
#define EPULSETIME 60

int WriteLCDLCommand( int command ){
  int i,pair=0x80;
  usleep(NEXTTIME);
  digitalWrite(RS,LOW);
  for ( i = 3; i >= 0 ; i--){
    if ( 0 < ( pair & command ) )
    {
      digitalWrite(i,HIGH);
    } else {
      digitalWrite(i,LOW);
      }
    pair = pair / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);
  for ( i = 3; i >= 0 ; i--){
    if ( 0 < ( pair & command ) )
    {
  digitalWrite(i,HIGH);
    } else {
      digitalWrite(i,LOW);
      }
    pair = pair / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);
  }

int WriteLCDLData( int data ){
  int i,pair=0x80;
  usleep(NEXTTIME);
  digitalWrite(RS,HIGH);
  for ( i = 3; i >= 0 ; i--){
    printf("%d %d %d:",data,pair,i);
    if ( 0 < ( pair & data ) )
      {
      digitalWrite(i,HIGH);
      printf("1\n");
      } else {
        digitalWrite(i,LOW);
        printf("0\n");
        }
    pair = pair / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);
  for ( i = 3; i >= 0 ; i--){
    printf("%d %d %d:",data,pair,i);
    if ( 0 < ( pair & data ) )
      {
      digitalWrite(i,HIGH);
      printf("1\n");
      } else {
      digitalWrite(i,LOW);
      printf("0\n");
      }
    pair = pair / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);

  }

  int WriteLCDCommand( int command ){
  int i;
  digitalWrite(RS,LOW);
  for ( i = 0; i < 4 ; i++){
    if ( 0 > command % 2 )
      {
      digitalWrite(i,HIGH);
      } else {
      digitalWrite(i,LOW);
      }
    command = command / 2;
    }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);

  }

  int WriteLCDData( int data ){
  int i;
  digitalWrite(RS,HIGH);
  for ( i = 0; i < 4 ; i++){
  if ( 0 > data % 2 )
    {
    digitalWrite(i,HIGH);
    } else {
    digitalWrite(i,LOW);
    }
  data = data / 2;
  }
  usleep(ESETUPTIME);
  digitalWrite(E,HIGH);
  usleep(EPULSETIME);
  digitalWrite(E,LOW);
  usleep(ESETUPTIME);

  }

int main()
  {
  wiringPiSetup();
  pinMode(0,OUTPUT);
  pinMode(1,OUTPUT);
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  /*
  WriteLCDCommand( 0x02 );
  WriteLCDCommand( 0x02 );

  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x08 );

  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x01 );

  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x04 );

  WriteLCDCommand( 0x07 );
  WriteLCDCommand( 0x00 );

  WriteLCDData( 0x08 );
  WriteLCDData( 0x00 );

  WriteLCDData( 0x03 );
  WriteLCDData( 0x03 );

  usleep(NEXTTIME);

  WriteLCDCommand( 0x03 );
  WriteLCDCommand( 0x03 );

  usleep(NEXTTIME);

  WriteLCDCommand( 0x03 );
  WriteLCDCommand( 0x02 );

  usleep(NEXTTIME);

  WriteLCDCommand( 0x02 );
  WriteLCDCommand( 0x08 );

  usleep(NEXTTIME);
  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x0C );

  usleep(NEXTTIME);
  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x06 );

  usleep(NEXTTIME);
  WriteLCDCommand( 0x00 );
  WriteLCDCommand( 0x01 );

  usleep(NEXTTIME);
  usleep(2000);

  WriteLCDCommand( 0x08 );
  WriteLCDCommand( 0x00 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x03 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x04 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x05 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x06 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x07 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x08 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x09 );

  usleep(NEXTTIME);
  WriteLCDData( 0x03 );
  WriteLCDData( 0x0A );

  WriteLCDLCommand( 0x33 );
  WriteLCDLCommand( 0x32 );
  WriteLCDLCommand( 0x28 );
  WriteLCDLCommand( 0x0C );
  WriteLCDLCommand( 0x06 );
  WriteLCDLCommand( 0x01 );
  WriteLCDLCommand( 0x80 );

  WriteLCDLData( 0x32 );
  WriteLCDLData( 0x33 );
  WriteLCDLData( 0x34 );
  WriteLCDLData( 0x35 );
  WriteLCDLData( 0x33 );
}

WriteLCDLCommandでLCDの初期設定やモードなどを書き込み、WriteLCDLDataで表示する文字のデータを2回に分けて書き込みます。

DSC01437ss
出力結果です。WriteLCDLDataで書き込まれた数字が表示されています。

LCD表示ができるとセンサで計測した数値をリアルタイムで確認したり本体の動作の確認に使えたりいろいろ便利そうですね。

表面実装!リフロー機を使ってみた

1リフロー機

某所のリフロー機(INFRARED IC HEATER T-962A)を使ってみました。中華製で設定がややめんどくさい(時間の表示は信じてはいけない)とかボタンの認識が悪いとかいろいろありますが、ちゃんと使えたよという報告。

2かめお3かめお2

カッティングプロッター(silhouette CAMEO)ではんだペーストを基板にのせるためのステンシルを作ります。

4ステンシル

ちょっとはんだペーストついてるけど、透明なシートでステンシルを作ってみました。片面がちょっと粘着します。

5はんだペースト

はんだペーストはdigikeyで買いました。

6はんだペースト載せた1

ステンシル使ってはんだペーストを載せました。位置合わせが大変!

7ちっこい抵抗

そして、ちっさい部品を

8置いてる

載せていく……

9置いた

載りました。(基板かわってるけど。)

10リフロー機開けた

リフロー機を開けます。

11焼く前

まんなかへんに置いて焼きます。

12焼いた後

きれいに焼けました!

ちょろちょろ部品が傾いたりずれたりはんだペーストの量がまちまちですが、なんとか使えそうです。課題はいっぱいだけど……

BreadBoardAdapter4RaspberryPi + BOX

以前紹介したRaspberryPiにBreadBoardをつなげるアダプタ(以下BBA)ですが専用のケースを作ってみました。
アクリルをレーザーカッターで加工して組み立てています。

BBA4RPBOX1

BBA4RPBOX2

ケースの中にすべてが入ります。試作なのでまだ固定しきれていません…

1段目にRapberryPi本体、2段目にBreadBoardが入っていてBBAでつながっています。BBA基板上のポートにUSBシリアルアダプタを刺し、PCとつなぐことでRaspberryPi本体への給電もできます。ブレッドボードにいろいろさしたままケースのふたが閉まるのでどこでもそのまま持ち歩けます!便利!使うときは蓋を下面にしまえるので失くさない!かも。

各種穴の位置合わせとできる限りの小型化が今後の課題です…

IR測距モジュールをRaspberryPiで使おう

今回は赤外線測距モジュールでは有名なSHARP製GP2Y0A21YKをRaspberryPiにつないでみます。

GP2Y0A21YK-front

GP2Y0A21YK-front

GP2Y0A21YK-back

GP2Y0A21YK-back

赤い線が4.5V-5.5Vの電源(vcc)、黒い線がアース(Ground)、黄色い線がアナログ出力(Vo)です。
RaspberryHabuにつなぐときは黄色い線をアナログ入力に繋ぎます。今回はアナログ入力7番ピンを使いました。

GP2Y0A21YK+Habu

GP2Y0A21YK+Habu

そしてデータシートのグラフを見ながら適当にコードを書きます。今回は距離に応じて0から7まで数字を出します。単位は特にないです。

IR

試しに実行してみます。
IR-test1

IR-test2

画面にAD変換された数値(spiresult)と適当に変換した結果(distance)が出ています。障害物の距離に応じて数値(0から7)が出ています。

これでデジタル測距器の完成です。出てくる数値は適当ですが。(ほんとに使う場合はif文の部分をもっと細かく正しい数値で作りましょう)

RaspberryHabu + PIRセンサモジュール(その2)

前回の続きでPIRセンサをいじっていきます。

まずはWiringPiをRaspberryPiに入れましょう。RaspberryHabuの組み立てTogetterにて動作確認のために入れていれば問題ないです。
そして簡単なデジタルINのプログラムを書いてみます。ピンは1番です。

pirtest-c

特に目立ったことはしてないです。digitalRead(pin番号)という関数がWiringPiでデジタル入力信号を取ってくる関数ですね。1秒ごとにHighで1、LOWで0が返ってきます。

cc -o プログラム名 ファイル名 -lwiringPi
でコンパイルして実行すると

pirtest-offpirtest-on

こうなります。人が止まっているときやいないときはセンサからLOWが返ってくるのでOFFと表示されます。動いたらセンサからHIGHが返ってきてONと表示されています。写真ではわかりにくいですが、僕はOFFになるまでじっと待っていました。センサの調整ねじを回せば同じ信号を出し続ける時間が長くなります。

このプログラムはHIGHやLOWだけを出すようなほかのセンサでも応用できるので便利です。
スイッチにも使えますね。すでに実装されてますが。

RaspberryHabu + PIRセンサモジュール(その1)

皆様、はじめまして。ヤマモトと申します。これからFabLibの製品であるRaspberryHabuの作例を紹介して行きたいと思います。

今回の作例はPIRセンサをRaspberryPiで使ってみよう!です。

PIRセンサのはaitendoさんのA500Pです。4.5V-20Vで駆動し、人体が近づくとON信号(Highレベル電圧)が出力されるセンサーモジュールです。今回は5VをRaspberryHabuから給電しました。

A500P-frontA500P-back

デジタル入力を使うので使用したHabuはBasicです。

A500P+Pi

写真のようにつなぐと、人体を感知したときにセンサがON信号を流してチェック用のLEDが光ります。

ON信号が流れる時間はPIRセンサモジュールの可変抵抗をいじると変更できるようです。

A500P+Pi-up

下準備だけですが、今回はここまで。次回はRaspberryPi上でいろいろいじりたいと思います。

writer: ヤマモト