電子工作 記事一覧

赤外線学習リモコン―赤外線信号送信・受信(改)

公開日時:2016/07/23 18:06

当サイトの『赤外線リモコン信号受信・送信』の記事は、他の記事から群を抜いて沢山アクセされており、今現在(2016/07/23)で 25,383 件のアクセスがあります。

みなさんが Raspberry Pi を使って何をするか考えた時、赤外線学習リモコンというのはとても良い選択肢であるということだと思います。

上記記事は実は、私が Raspberry Pi を使い始めて初めて書いた記事なので、当たり記事である反面、大分おかしなところもあります。つい先日も、一番最初に出てくる回路図が特に、かなりおかしいことを指摘していただきました。

そこで、今回は1年の時を経て、もっとまともな赤外線学習リモコンの記事を書いてみたいと思います。

このコーナーの最終目標

実際の回路

実際の回路

このくらいの簡単な回路になります。

受光部分

まず、受光部分です。

受光部分

使用部品は

  • PL-IRM2161-XD1(赤外線リモコン受光モジュール)
  • 1.0μF セラミックコンデンサ

PL-IRM2161-XD1 については 秋月電子通商ではもう取り扱いが行われていないようなので、他の受光モジュールをご利用いただければと思います。

青いのがセラミックコンデンサです。

回路図

受光回路

GPIO 7番ピンを信号受信用のピンにしました。これは自由に変えていただいて構いません。この受光モジュールは Vcc が 2.4V から 5.0V で動作するので、分圧とか変なことを考えなくても良いように 3.3V に接続しました。

回路の挙動を安定させるため、Vcc と GND の間に 1.0μF のセラミックコンデンサを挟みました。これはこの受光モジュールの仕様書の以下を参考にしています。

仕様書

送信部分

次は送信部分です。

送信回路

使用部品は

  • 2SC2120Y (NPN型トランジスタ)
  • 240Ω 抵抗 ? 2
  • 10Ω 抵抗
  • OSI5LA5113A(赤外線LED)

参考にしたのはBit Trade Oneの Raspberry Pi 用拡張ボードApple Piの赤外線信号送信部分の回路です。Raspberry Piにつなげることで、いろいろと便利な実験回路として動作するようです。

回路図は以下です。

送信回路

OSI5LA5113A(赤外線LED)の半減角度は30℃しかないため、『赤外線リモコン信号受信・送信』では 3 連 LED みたいなことをしていましたが、そういうのは信号が乱れてかえって不安定になるそうですのでシングル LED にしました。

また、『赤外線リモコン信号受信・送信』の場合はトランジスタの増幅を使って電流量をコントロールしていましたが、こちらも増幅度のバラ付きがあって電流値が定まらず好ましくないとのご指摘を受け、ちゃんと LED の前に抵抗を挟んで安定化に努めています。

前の回路は LED の前に抵抗がないので大電流が流れる可能性があったため、コンデンサに電気を溜めておいてそれをつかって発光を行い、想定以上の電気が流れるのを阻止していましたが、そんな事をしなくても、LED の前に抵抗を挟むだけで LED の破損を十分防げるでしょう。

Apple Piの回路ではトランジスタベース前の抵抗 240Ωのみでしたが、一応、エミッタからベース側にも 240Ωの抵抗を挟んで、コレクタ遮断電流で予期せずスイッチが ON になってしまうのを避けてみました。

2SC2120 ですが、足の位置に注意が必要です。どうも、データシートの図は、足の順番が逆なのではないかと思います。

2SC1815と同じように平で型番が書いてある方を上にして、左から エミッタ - コレクタ - ベースです。

エミッタに GND、コレクタに 5V から LED に繋がる部分、ベースに GPIO17 (11番ピン)、が接続されます。

リモコン信号受信プログラム

赤外線信号受信プログラムは、赤外線リモコン信号受信・送信のソースコードをそのまま使って下さい。

赤外線信号送信プログラム

赤外線送信プログラムは、赤外線リモコン信号受信・送信のソースコードをそのまま使って下さい。

まとめ。

このくらい簡単な回路で、前の回路よりもずっと安定した赤外線学習リモコンが作れます。

皆さんも是非、学習リモコンを作ってみてくださいね。今後は、ソケットサーバー「HAL」にこの学習リモコンを組み込んだ、より便利な活用記事を書きます。ご期待ください。

赤外線信号送信・受信

公開日時:2016/07/14 22:00

はじめに

(2016/07/23追記 この記事を全面的に改定した新記事『赤外線学習リモコン―赤外線信号送信・受信(改)』を、新たに作成しました。お急ぎの方はそちらをお読み下さい。このページは、初めて私が Raspberry Pi と 電子回路に触れた時に何を考えて何を試したのかの軌跡として残してあります。余裕のある方のみ、御覧ください)

Raspberry Pi を使って、学習可能な汎用赤外線リモコンを制作してみました。

「raspberrypi 赤外線リモコン」で検索すると、とても沢山のページがヒットします。当初は簡単に実装できるものと高をくくっていたのですが、これがかなり難航しました。

結論から言うと、弊社では発売間もない時期にRaspberry Pi 2 Model B を初めて購入したのですが、これらのページで紹介されていた赤外線リモコン信号送受信用のアプリケーション「lirc」は、Raspberry Pi 2 Model B では動作しないようです。(送信のみ。受信は可能)

『Raspberry Piで遊ぼう! 改訂第3版』最新情報お知らせページ

(※2015/05/25 追記 tech4u blogさんの『Raspberry Pi 2 で LIRC(赤外線リモコン)』の記事で紹介されたとおり、Raspberry Pi のファームウェアアップデートのためか、Raspberry Pi 2でのlircについての不具合の記事は削除されていました)

初めての Raspberry Pi であったためにどこに問題があるのかわからず1週間くらい悩み、あきらめて仕方なく大宮技研さんの『irMagician』を購入して、到着を待っている時に上記ページを見つけた次第です。

同時に、うしこlog さんの『ラズパイでエアコンを動かす』を発見し、すぐにサンプルコードをダウンロードしてコンパイルし、実行してみました。1週間、お腹が痛くなるくらい悩んだのが馬鹿みたいな話で、すんなり動作してくれました。

Raspberry Pi 2 を買って、赤外線リモコン送信が出来ずに悩んでいる方、lirc はあきらめましょう。

2015/05/19

このページをリンクしてくださった方のブログで、Raspberry Pi のファームウェアをアップデートするとLircが利用できるようになるといった記事を見つけました。tech4u blogさんのRaspberry Pi 2 で LIRC(赤外線リモコン)(Google Analytics はこういう用途にも使えて便利ですね)

これについては弊社ではテストしていませんので詳細は分かりませんが、lircを利用されたい方は参考になさってください。

配線

さて、配線ですが、こちらはネットで検索して出てくるどの配線でも大抵動きます。弊社ではブレッドボードで次のような配線をしました。(2016/07/14 下図の、特に受光部分について作図ミスであるというご指摘を受けて後ろに追記を行いました。)

ブレッドボードと回路図

※赤外線受光モジュールは、ブレッドボード図とは別のものを利用しています。脚の位置が違いますのでご注意ください。

使用部品
  • 赤外線リモコン受光モジュール(PL-IRM2161-XD1) 1個
  • 赤外線LED (OSI5LA5113A) 3個
  • 抵抗 (1K?) 2個(※リンクは100本入りなので注意)
  • トランジスタ (2SC1815C GR) 1個

赤外線LEDを3個も使っている理由ですが、この赤外線LEDの半減角度は15°とのことで、有効な照射範囲がかなり狭めです。ですから、数を増やしてできるだけ有効範囲を広げようとしています。

トランジスタのベース前の抵抗が1K?ですが、コレクタ→エミッタ間には実測値で134mAの電流が流れました。赤外線LED OSI5LA5113Aの最大定格電流は100mAなのでかなりオーバーしているのですが、当初80mA程度流す予定で3.9K?の抵抗を使ったところ、有効な照射距離が2m程度しか出ませんでしたので、購入してあった1K?の抵抗に差し替えました。

赤外線リモコン信号の場合はパルス信号を送信しており、極めて短時間の明滅を繰り返します。点灯時間は400μsec程度なので電流オーバーでもそれほど負担にはならないと考えています。今後継続的に動作検証を行います。

ただ、実験途中で誤って電流を流しっぱなしにしてしまい(回路をショートさせてしまったようです)LEDを一つ破裂させてしまいました。ですので、最初は3.9K?の抵抗と可視光LEDでテストをされることをお勧めします。

そういったこともあり、確実にトランジスタのON/OFFを切り替えて意図しない電流をコレクタ-エミッタ間に流さないよう、エミッタ-ベース間に1K?の抵抗を挟んで漏れ電流(遮断電流)を逃がしています。

(参考)コレクタ遮断電流とは?

(※サイトが閉鎖されたようです)

トランジスタのしくみ

(参考)トランジスタをマイコン出力のスイッチとして使う方法(1/2)

プログラム

赤外線受信・送信プログラムは、基本的には うしこlog さんの『ラズパイでエアコンを動かす』を踏襲しています。まず、こちらのページを一読されることをお勧めします。

ただし、ダウンロードできるコードにいくらかのバグがあるのと、個人的に少し分かりずらいネーミングやコーディングであったこともあって、拡張を施しながらコードを1から書き直しました。

前準備(WiringPi のインストール)

WiringPiは、Raspberry PiのGPIOを制御するためのC言語ライブラリです。赤外線の送受信ではGPIOを制御するため、このライブラリを利用します。

インストールの仕方は比較的簡単なので、以下のコマンドをターミナル等で順番通りに実行するだけでインストールできます。

git clone git://git.drogon.net/wiringPi
cd wiringPi
./build

正しくインストールされたか、gpioのバージョンを表示して確認してみましょう。

gpio -v

下記のような情報が表示されれば正しくインストールされています。(下記はRaspberry Pi Model B+での動作)

gpio version: 2.26
Copyright (c) 2012-2015 Gordon Henderson
This is free software with ABSOLUTELY NO WARRANTY.
For details type: gpio -warranty

Raspberry Pi Details:
  Type: Model B+, Revision: 1.2, Memory: 512MB, Maker: Sony

赤外線信号受信プログラム

受信プログラムは以下の様になっています。

/*
 * scanir.c
 * 
 * copyright c 2016 Katsuhiko Miki All rights reserved.
 */

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>

int readable = 1;       // 非同期でイベントが発生した場合、コールバックにより0に設定される
int read_pin = 7;       // 入力ピン番号(wiringpiの番号)
int interval = 10;      // 継続時間判定の間隔(us)
int max_wait = 40000;   // 最大継続時間(us)

void signalCallBackHandler(int sig)
{
    readable = 0;
}

double getMoment()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return ((double)(tv.tv_sec) * 1000000 + (double)(tv.tv_usec));
}

int main(int argc, char *argv[])
{
    int result;

    // スキャンデータを書きだすファイルのポインタを取得
    FILE *fp;
    char *fileName = "irdata.txt";
    if(argc >= 2){ fileName = argv[1]; }
    if((fp = fopen(fileName, "w")) == NULL){
        printf("can't open file : %s\n", fileName);
        exit(1);
    }
    printf("write file: %s\n", fileName);

    // signal関数は、シグナル(非同期イベント)が発生したときに、
    // そのシグナルを受信して、シグナル特有の処理を行うシグナル処理関数(シグナルハンドラ)を登録します。
    if(signal(SIGINT, signalCallBackHandler) == SIG_ERR){
        printf("can't set signal\n");
        exit(1);
    }

    // wiringpiのセットアップ
    if(wiringPiSetup() == -1){
        printf("error wiringPi setup\n");
        exit(1);
    }

    // 読み取りピン番号
    if(argc >= 3){
        read_pin = atoi(argv[2]);
    }
    pinMode(read_pin, INPUT);
    printf("scaning pin: %d (wiringpi)\n", read_pin);

    // 最大継続時間
    if(argc >= 4){
        max_wait = atoi(argv[3]) * 1000;
    }
    printf("max keep time: %d(ms)\n", max_wait/1000);

    // 準備完了
    printf("Infrared LED scanning start.\n");
    printf("Pressed Ctrl+C, this program will exit.\n");

    // スキャン開始
    result = scan(fp);

    fclose(fp);

    if(result || !readable){
        printf("\n\n!!! could not scanning. quit.\n\n");
    } else {
        printf("\nScanning has been done.\n\n");
    }

    return 0;
}

int scan(FILE *fp)
{
    // 受光モジュールは受光するとLOWになる
    if(!digitalRead(read_pin)){ return 1; }

    int on, off;

    // 送信が開始されるまで待機
    while( readable && digitalRead(read_pin) ){}

    // 解析開始
    while( readable ){
        on = getTime(0);
        off = getTime(1);
        fprintf(fp, "%6d %6d\n", on, off);

        //最大継続時間同じ状態が続いたら送信は終了していると判断
        if(off > max_wait){ break; }
    }

    return 0;
}

int getTime(int status)
{
    int count = 0;
    int max = max_wait / interval;
    double start, end;

    start = getMoment();
    while( digitalRead(read_pin) == status )
    {
        delayMicroseconds(interval);
        count++;
        //最大継続時間同じ状態が続いたら送信は終了していると判断
        if(count > max){ break; }
    }
    end = getMoment();

    return getInterval(start, end);
}

int getInterval(double t1, double t2)
{
    return (int)(t2-t1);
}

これを、以下のようにしてコンパイルします。

sudo gcc scanir.c -o scanir -lwiringPi

コンパイルが完了すると、scanirという実行ファイルが生成されているはずです。

このscanirの仕様は、第一引数が書きだすファイル名、第二引数が読み取りピン、第三引数が最大継続時間です。最大継続時間は、この時間以上赤外線が点灯しなかった場合、リモコンからの送信は終了しているとみなし、読み取りを終了してファイルを書き出します。

第二引数の読み取りピン番号ですが、このピン番号はRaspberry Pi のピン番号でもGPIO番号でもなく、WiringPiのピン番号です。WiringPiのピン番号とこれらの対照表は、

gpio readall

で確認できます。デフォルトは7番ピン(Raspberry Pi でも7番ピン)に設定しています。他のピンで動作させたい場合は、

sudo ./scanir ir.data 3

のように引数を与えてください。上記の場合、3番ピン(Raspberry Piの15番ピン)で読み取りが行われます。

受信のコツですが、0.5秒から1秒程度リモコンボタンを押し続けるようにしてください。

なお、スキャンしたデータを確認するとわかるのですが、リモコンによって、ボタンを押し続けている間断続的に信号が送信されるものと、1度だけ送信されるものがあるようです。断続的に送信されるものは立ち上がりが不安定な場合があるので、スキャンしたデータをエディタなどで、良質な部分だけ切り出すなどすると良いでしょう。弊社では読み取ったデータを自動で整形するプログラムを書いていますが、PHPなため、ここでの説明は割愛します。

赤外線送信プログラム

送信プログラムは以下のようになっています。

/*
 * sendir.c
 *
 * copyright c 2016 Katsuhiko Miki All rights reserved.
 */

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <math.h>
#include <unistd.h>
#define BUF_LEN   256

int write_pin = 0;

int Hz = 38;            // 周波数(KHz)
int duty_num = 1;       // duty比(分子)
int duty_denomi = 3;    // duty比(分母)
int unit = 26;          // ユニット長us
int duty_high = 9;      // HIGH時間
int duty_low = 17;      // LOW時間
int repeat = 1;         // 送信回数

void high(int on_time)
{
    // パルス信号に変換して送信
    int i;
    int count = on_time/unit;
    for(i=0; i<count; i++)
    {
        digitalWrite(write_pin, 1); //high
        delayMicroseconds(duty_high);

        digitalWrite(write_pin, 0); //low
        delayMicroseconds(duty_low);
    }
}

void output(int on_time, int off_time)
{
    // 赤外線点灯
    high(on_time);

    // 赤外線消灯
    digitalWrite(write_pin, 0);
    delayMicroseconds(off_time);
}

void readAndSend(FILE *fp)
{
    char buf[BUF_LEN];
    int i, j, length = 0;
    int *on, *off;

    while( fgets(buf, BUF_LEN, fp) != NULL){ length++; }
    on = (int *)calloc(length, sizeof(int));
    off = (int *)calloc(length, sizeof(int));

    rewind(fp);
    for(i=0; i<length; i++)
    {
        fscanf(fp,"%d %d", &on[i], &off[i]);
    }

    // 送信(同じ情報をrepeat回送信する)
    for(j=0; j<repeat; j++)
    {
        printf("send data.\n");
        for(i=0; i<length; i++)
        {
            output(on[i], off[i]);
        }
        usleep(50000);
    }

    // アロケートしたメモリを解放
    free(on);
    free(off);
}

int main(int argc, char *argv[])
{
    // 送信データファイル
    FILE *fp;
    char *fileName = "irdata.txt";
    if(argc >= 2){ fileName = argv[1]; }
    if((fp = fopen(fileName, "r")) == NULL){
        printf("can't open file: %s\n", fileName);
        exit(1);
    }
    printf("read file: %s\n", fileName);

    // wiringpiのセットアップ
    if(wiringPiSetup() == -1){
        printf("error wiringPi setup\n");
        exit(1);
    }

    // 送信繰り返し回数
    if(argc >= 3){
        repeat = atoi(argv[2]);
    }

    // 送信ピン番号
    if(argc >= 4){
        write_pin = atoi(argv[3]);
    }
    pinMode(write_pin, OUTPUT);
    printf("output pin: %d (wiringpi)\n", write_pin);

    // 周波数の設定
    if(argc >= 5){ Hz = atoi(argv[4]); }

    // duty比の分子
    if(argc >= 6){ duty_num = atoi(argv[5]); }

    // duty比の分母
    if(argc >= 7){ duty_denomi = atoi(argv[6]); }

    // unit長
    unit = (1.0f / (Hz * 1000)) * 1000000;
    duty_high = roundf(((float)unit / duty_denomi) * duty_num);
    unit = (int)unit;     //us
    duty_low = unit - duty_high;

    printf("unit: %dms duty:%d-%d\n", unit, duty_high, duty_low);

    // 準備完了
    printf("send infrared signal.\n");

    // データ読み込みと赤外線の送信
    readAndSend(fp);

    printf("\ndone\n");
    fclose(fp);

    return 0;
}

こちらも同様にコンパイルするのですが、数学関数を利用しているため、コンパイルオプションに-lmを追加します。

sudo gcc sendir.c -lm -o sendir -lwiringPi

sendirの仕様は、第一引数が読み取りファイル名、第二引数が送信繰り返し回数、第三引数が出力ピン番号、第四引数が送信信号の周波数、第五引数がduty比の分子、第六引数がduty比の分母です。

周波数、duty比については、『放課後マイコンクラブさんのブログ』が参考になりました。この記事の周辺に赤外線リモコンのフォーマットについての記述がありますので、そちらも併せて読まれると良いでしょう。

基本的に赤外線リモコンのduty比は1/3で良さそうなので、これをデフォルトにしています。弊社の蛍光灯がNationalなので、デフォルトの周波数は38KHzを設定してあります。一応、33KHzでも40KHzでも蛍光灯のON/OFFができましたので、重要なのはduty比と信号のON/OFFのタイミングであり、周波数(送信時間)にはかなり柔軟なようです。(2015/05/07 単位が間違っていたので修正しました)

送信コードは以下のようになります。

sudo ./sendir ir.data 3

上記は、ir.dataに記録されている信号パターンを連続で3回送信します。

冒頭で述べた lirc ではプログラムのバッファ容量の問題からか、エアコンのような信号長の長いリモコンには対応できなかったようですが、この送受信プログラムはエアコンなどにも対応できます。

問題点としては、134mAまで電流量を増やしても、3m程度しか赤外線が届かないことですね。市販の赤外線リモコンは10mくらい離れていても赤外線が届くので、かなりの出力を行っているのだと思います。また、有効角度もかなり広く、明後日の方を向いていても機器が反応するので、赤外線LED自体が全く違う物なのかもしれません。

a配線結果

2015/05/04

上記回路についていろいろと抵抗値を変えたりコンデンサを挟んでみたりしたのですが、どうもうまくいきませんでした。出力が130mA程度しか出ません。そこでもう少し検索してみたところ、

(参考)トランジスタのスイッチ

にたどり着きました。どうやら、Raspberry Piの3.3Vの電圧下での2SC1815は厳しいようです。

2SC1815のデータシートより抜粋

2SC1815データシート抜粋

グラフを見ると分かるのですが、コレクタ電流が60mAを越えたあたりから急激にhFE値が下がっていて、電圧が低いほど急激な下がり方をしています。弊社の回路では

(3.3V - エミッタ・ベース間飽和電圧1.0V) ÷ 1000? = 2.3mA

がベース電流で、GRをhFE200倍とすると、460mA程流れることが予測されるのですが、実際には134mAでしたので、58倍にしかなっていません。グラフからも、大体そのあたりに落ち着くことが読み取れます。2SC1815 GRでは、あまり高出力の赤外線LED発光は望めそうにありません。

そこで、似たようなトランジスタで3.3Vでももっと大量の電流を流せるトランジスタが無いか少し検索してみたところ、

2SC3419-Y

こちらのトランジスタが良さそうな感じです。

2SC3419のデータシートより抜粋

2SC3419データシート抜粋

300mA付近までhFEの低下はほとんどなくVCE 2VでもhFE 150程度が得られそうです。(2.3×150=345mA程流せるかと思います)

電脳伝説 Vintagechipsさんのトランジスタのスイッチの記述の通り、130mAでは3m程しか赤外線信号が届かなかったので、このトランジスタを購入して出力を上げてみたいと思います。

2015/05/18

2SC3419が届いたので、テストしてみました。

2SC1815と2SC3419

2SC3419は中電力増幅用のためか、2SC1815よりも大き目です。テストした回路は次のような簡単なものです。

2SC3419のテスト回路

A点での実測値は330mA、hFE値は140で、データシート通りの結果が得られました。

2SC3419データシート

実は、2SC3419購入に合わせてもう一つ電界効果トランジスタ(FET)を購入しました。

2SJ496

2SJ496-TZ-E

これで何がしたいかなのですが、前述のように赤外線LED (OSI5LA5113A)の定格電流は100mAですから、330mAを流せばLEDは壊れ、悪くすれば破裂します(事故でショートさせて1つ破裂させました)。

赤外線リモコンではパルス信号を送信するため常に330mAが流れるわけではないのですが、万が一流れ続けてしまうことが無いよう、安全装置を付ける必要があります。

2SJ496はPchのMOS FETで、ゲートがLOWの時にソース→ドレインに電気が流れ、HIGHの時には流れません。これを利用し、次のような回路を組みました。

MOS FETを使ったNOT回路

Raspberry Pi からの信号がLOWの時は、5VからLED側に向かって電気が流れますが、2SC3419のベースに電流が流れないためコレクタ→エミッタに電気が流れることが出来ず、LEDは光りません。ただし、LEDの前にあるキャパシタ(コンデンサ)はグランド接地されているため電気が流れ、ここに必要な電気が溜まります。

Raspberry Pi からの信号がHIGHになると2SJ496のゲートに電圧がかかるため、ソース→ドレイン間に電気が流れなくなって5VからのLED側への電気の流れは止まります。同時に2SC3419のベースに電気が流れるため、コレクタ→エミッタに電気が流れる事ができるようになります。キャパシタにはLOW時に電気が溜まっているため、この電気がなくなるまでLEDに電気が供給される、という回路です。

R3、R4はそれぞれのトランジスタの漏れ電流により意図せずにスイッチが入って電気が流れてしまわないようにしています。R5は万が一 Raspberry Pi からの信号線がオープンになってしまった時2SC3419のスイッチが入ってしまい、キャパシタに溜まっている電気がLEDに向かって流れ続けてしまうのを防いでいます。

電解コンデンサ(キャパシタ)の容量を200μFにしたのは100μFの電解コンデンサで防爆弁がついているものが見当たらなかったからです。あまり大きな容量の電解コンデンサは接続し間違えて万が一破裂したりすると怖いので動作に問題ない範囲で小さなものにしようと思い、電子回路シミュレータCircuitViewerで実験したところ、100μFでもLEDの点灯には十分そうな電流が流れました。それで近くの電子部品販売店でキャパシタを探したところ、一番近い200μFが防爆弁があったのでこちらにしたという理由です。Raspberry Pi は最大でも5Vですからそうそう爆発するようなこともないと思うのですが、より安全そうな方を選びました。

実験結果はこちらです。

これで赤外線リモコンも完成か…と思いきや、どうもまだ出力が足りないようです。2SC1815の時よりは若干出力が強くなったようですが、もう少し出力を上げたいところです。

そこで、赤外線LED (OSI5LA5113A)のデータシートをよく確認してみました。

OSI5LA5113Aデータシート

なんと、パルス信号の定格電流は1000mAです。(パルス幅100μs以下、duty比1/100以下)

この送信プログラムでは、38KHzで送信した時の信号の1ユニットは26μsで、duty比1/3なのでLED発光時間は9μsです。これを考えると、定格電流とまではいかなくとも、750mAくらい流してもLEDは大丈夫そうに思えます。

そこで、もう一度2SC3419のデータシートを確認。

2SC3419データシート3

750mA流す時のhFEは 60倍程度なので、ベースに流す電流は12.5mAとなります。ただ、今度は2SC3419の定格が問題で、2SC3419のコレクタ定格電流は800mAでした。安全性を考慮して今回は600mAほど流す事を考えると、hFE 80倍なのでベースに流す電流は7.5mA程度が良さそうです。

Raspberry Pi のGPIOは3.3Vで、2SC3419のベース・エミッタ間飽和電圧は標準で0.9Vなので、

(3.3V-0.9V) ÷ 0.0075A = 320Ω

ですね。320Ωの抵抗は無いので、330オームで良さそうです。と、弊社には330?の抵抗が2つしかないので、また仕入れる必要がありますね… 後日、再実験します。

2015/05/20

330Ωの抵抗でテストしてみましたが、どうもまだ若干弱い感じです。Raspberry Pi の5Vのリミッターは600mAらしいので、デフォルトのままではこれ以上は出力できないでしょう。(2015/05/22 リミッターがあるのはUSBだけの様にも… 詳しいスペックシートないか探してみます)

抵抗を変えてテスト

しかし、実際の回路ではキャパシタ(コンデンサ)に蓄えられた電気を流すため、キャパシタに溜まっている電気分は流れるはずです。パルス信号ですから多少定格を越えても流せるだけ流してしまいましょう、ということで、

160Ω抵抗回路

こんな回路になりました。

(3.3 - 1.1) ÷ 160 = 13.75mA

hFE値は定格一杯の60倍以下でしょうから、精一杯流れたとして

13.75 × 60 = 825mA

このくらいなら大丈夫な気がします。ということで、実験。大分出力は強くなりました。ただ、やはり半減角は狭めで、LEDがちゃんと蛍光灯の方を向いていないと拾ってくれません。やっぱりLED自体が広角のような気がするんですが…

今のところ発熱など問題は無いので、もう少しテストを繰り返してみます。問題なさそうなら、これで赤外線リモコン送信回路は終了にしたいと思います。

2016/07/14 追記

一年の時を経て、最初の回路に大間違いが合った事がわかりました。赤外線受光モジュールの Vcc について、赤外線 LED のカソード側に接続するように記述していましたが、実際に私が試したのは

訂正

こうでした。

当時はとにかく送信部分について苦慮していて、受光についてはあまり深く考えておらずずっと気づきませんでした。

気づくきっかけになったのは、当サイトのサーバーフレームワーク製品の「HAL」の利用例として、私の拙い回路ではなく、安心して利用できる既成品をご存知の方がいないかと思い Facebook の「ラズベリー・パイ ジャパン」グループに投稿した事でした。

先程述べたとおり私は送信部分にばかり気が行っていたのでみなさんが指摘してくれている事がよくわからなかったのですが、根気よく説明してくださったS.Nさん、K.Wさん、S.Yさん始め、他のみなさんに深く感謝します。

なお、上記の訂正部分についても適切ではありません。というのも赤外線受光モジュールに 5V の電圧をかけてそれをそのまま GPIO に流しているのですが、Raspberry Pi の GPIO は 3.3V 耐圧だからです。この記事で使用している PL-IRM2161-XD1 は

データシート

によると 2.4V ~ 5V で動作するようですので、Raspberry Pi の 3.3V に繋ぐのが正解で、上図のように 5V に繋ぐのであれば分圧を行って電圧を下げる必要があります。

何しろ1年前の事ですし、この記事が最初にかいた Raspberry Pi の記事なので、本当に 5V に繋いでいたのか、3.3V に繋いでいたのを 5V と間違えたのかは今となっては定かではありませんが、いずれにせよ、赤外線 LED のカソード側に受光モジュールの Vcc を繋いでいるのは明らかに間違いです。訂正してお詫びします。

上記データシートの参考回路をみてみると、Vcc と GND の間に 10μF 1.0μF のコンデンサを挟んでいます。

データシートのサンプル

Facebook のグループで教えていただいたのですが、Raspberry Pi はノイズが入りやすいため、このようにコンデンサを挟むことで動作を安定させた方がよいそうです。

送信部分もそうですが、受光部分についても、本当に適切な回路にするにはまだまだ修正が必要であることを追記します。

最後にご教示頂いた方々に謝意を表して今回の追記を終わります。

室内温度の測定

公開日時:2016/07/12 04:32

室内温度の測定(ADT7410使用モジュールとPHP)

今回は温度センサモジュールを使って、Raspberry Pi で室内温度を測定してみようと思います。

温度センサモジュールはADT7410キットを使用しました。16bit の温度センサで -55℃~+150℃まで計測できるようです。殆どの部品は既にハンダ付け済みですが、接続用の端子について4箇所のハンダ付けが必要になります。

ADT7410使用 高精度・高分解能 I2C・16Bit 温度センサモジュール(秋月電子通商)

ADT7410使用 高精度・高分解能 I2C・16Bit 温度センサモジュール

I2C の有効化

Raspbian Jessie の場合は、X window で I2C の有効化が出来るようです。(恐らく今までどおり、raspi-config でも出来るでしょう)

sudo startx

Raspberry Pi の設定

Menu > 設定 > Raspberry Pi の設定 で設定画面が開くので、そこのインターフェイスタブで I2C を「有効」にしてください。OK をクリックすると再起動を促されます。

インターフェイス設定画面

再起動すると、I2C 通信が行えるようになっていると思います。

I2C ライブラリの導入

I2C 通信を簡単に行うには i2c-dev を有効にして下さい。(これは既に有効になっているかもしれません。また Raspbian のバージョンにより他のモジュールも必要かもしれません)

sudo vi /etc/modules

以下の行があるか確認し、なければ追加して下さい。(行頭に#がある場合はコメントになっていますので、#を削除してください)

i2c-dev

また、/boot/config.txt についても、「dtparam=i2c_arm=on」をアンコメントまたは追記して下さい。

sudo vi /boot/config.txt
# Uncomment some or all of these to enable the optional hardware interfaces
dtparam=i2c_arm=on
#dtparam=i2s=on
#dtparam=spi=on

変更があった場合は、再起動するとこれらが有効になります。

あとは、i2c-tools をインストールします。

sudo apt-get install i2c-tools

温度センサモジュールの接続

温度センサモジュールには4つの端子があり、それぞれ VDD、SCL、SDA、GND となっています。どの端子がどれかは基盤に書いてありますが、かなり細かい文字です。老眼が始まっている私には結構きついので、ヘッドマウントルーペを利用しています。

ヘッドルーペ

デザインがあんまりよくありませんので、目が悪い人でもっとカッコいいものが良い人は Amazon などで購入するのも良いでしょう。倍率もさまざまなものがあります。

なお、温度センサモジュールには当然仕様書もついていて、端子の順番はそれではっきりと分かります。

温度センサモジュール仕様書

ADT7410 は 2.7V~5.5V の電圧で動作するそうですので、VDD には 3.3V でも 5V でも良さそうです。であれば、Raspberry Pi の GPIO の耐圧である 3.3V を繋いだほうが良さそうですね。私は 1 番ピンに繋ぎました。

SDA は Raspberry Pi では 3 番ピン、SCL は 5 番ピンです。GND は沢山ありますが、他のピンに一番近い 6 番ピンが良さそうです。

デバイスが利用できるか確認

温度センサモジュールを接続したら、Raspberry Pi で認識できるかテストしてみましょう。

sudo i2cdetect -y 1

正常に利用できれば、次のようなレスポンスが返るはずです。

pi@raspberrypi:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

i2cdetect -y 1 の最後の 1 ですが、『Raspberry Pi でI2C: 温度センサーを使う|猫ぱーんち!』さんのところによると、Raspberry Pi のリビジョンによって 0 や 1 になるようです。ここのところは私にはちょっと良くわかりませんでしたが、私の Pi3 では 1 でした。(0 と 1 両方試してエラーが出ない方が正解、といった内容のページは見つかりましたが、さらっと探しただけでは対応表は見つかりませんでした。すみません)

ADT 7410キットの仕様書を見るとわかりますが、デフォルトでは I2C バスアドレスとして 0x48 を利用します。

※なお、これはハンダ付けで回路をショートさせる事により、0x49、0x4A、0x4Bに変更することが可能のようです。

さて、上記のように 0x48 で認識していることを確認したら

sudo i2cget -y 1 0x48 0x00 w

で、温度が取得できます。

上記コマンドの i2cget の説明ですが、『Rasberry PIのI2Cコマンド詳解|かないノート』さんの記事によると、0x48 にまず、0x00 を書き込み、その後で 0x48 から読み出しを行うということのようです。w は恐らく word モードということだと思うのですが、I2C 通信についてはよく知らないので、『Raspberry Pi でI2C: 温度センサーを使う|猫ぱーんち!』さんのところをそのまま参考にしました。

とにかく、上記を実行すると

0x780c

こんな感じの 2 バイトのデータが返されます。これが温度なのですが少々ややこしく、まず 16 進数な事はお分かりになると思います。冒頭で述べたとおり、ADT7410 は-55℃~+150℃まで計測 可能なので、温度は signed(符号付き)です。

そして、この値はリトルエンディアンとなっており、上記の場合2バイトの前後を入れ替えて、計測温度は 0x0c78 を 10 進数にした値から得られます。

参考)エンディアン

この ADT7410 キットは 16 bit モードで動作しているようで、こうして得られた値を 128 で割ると測定した温度が分かる、ということのようです。

参考)I2C温度センサADT7410を使う(2)|wsnakのブログ

上記では負数の場合、65536を減算した値を 128 で除算 していますが、PHP では hexdec() というメソッドがあり、16 進数を表す文字列をそのまま渡すだけで符号付きの整数が得られます。

つまり、こうなります。

<?php

$read = system("sudo i2cget -y 1 0x48 0x00 w");
$r1 = substr($read, 2, 2);
$r2 = substr($read, 4, 2);
$swap =  "0x{$r2}{$r1}";
echo hexdec($swap) / 128;

system() メソッドでは、OS コマンドを実行して得られた標準出力を取得できます。

substr() は第 1 引数で与えた文字列の第 2 引数の位置から第 3 引数文字分切り出します。これは ASCII 文字として扱われるので、日本語のような多バイト文字列を利用する時は mb_substr() を使う必要がありますが、今回は16進数文字列ですので substr() で構いません。開始位置は 0 オリジン(0から始まる)ですので、2 文字目からと 4 文字目からそれぞれ 2 文字を取得してひっくり返しています。

このようにすると、先ほどの計測で得られた 0x780c は、24.9375℃であった事がわかります。

なお、小数点以下4桁も精度があってもあまり意味ない場合が多いので、

echo number_format(hexdec($swap) / 128, 1);

とすると、四捨五入された小数点以下1桁の数値にフォーマットできます。(戻り値は string 型なので注意しましょう)

まとめ

以上のように、ADT7410使用 高精度・高分解能 I2C・16Bit 温度センサモジュール(秋月電子通商)さえあれば、とても簡単に室温の計測が出来ることがわかります。

ちなみに、system() コマンドは比較的遅いのでどの程度の時間がかかるのか調べようと思い、以下の様な呪文を唱えてみました。(2016/08/02 コードの中盤が欠落していたので修正しました)

sudo php -r '$time_start = microtime(true);$read = system("sudo i2cget -y 1 0x48 0x00 w");$r1 = substr($read, 2, 2);$r2 = substr($read, 4, 2);$swap = "0x0x{$r2}{$r1}";$temp = (float)number_format(intval(hexdec($swap)) / 128, 1);echo "\n";echo microtime(true) - $time_start;'

php に -r オプションを付けると PHP コマンドを直接実行できるので、マイクロ秒単位で実行時間を計測しています。結果、

0.036367893218994(単位は秒)

全然気にしなくて良さそうな速度ですね。

記事を書き終わってネット検索していたら wiringPi を使った通信を紹介しているサイトもありました。

参考)Raspberry Piで湿度を測ってみる |ず

I2C ライブラリが使えなかった場合は、こういう方法もありそうです。

人感センサー(焦電型赤外線センサー)

公開日時:2016/05/22 07:55

Raspberry Pi を取り扱ったページで比較的多いのはやはり赤外線リモコンのページなのですが、併せて多いのが人感センサー(焦電型赤外線センサー)のページです。焦電型赤外線センサーの原理は、分極されバランスがとれているセンサーの表面に赤外線が当たることで、温度上昇・下降に伴って電荷が移動することを利用しているそうです。

参考)人体検知器の製作

この焦電型赤外線センサーを使うことで、人体から発生する赤外線を計測し、人が動いたことを感知しようというのが一般的な人感センサーの仕組みのようです。

ただ、人体から発生する赤外線によって得られる電荷はとても僅かなので、それをそのまま測定するのではなく、オペアンプ等によって電圧の変化を増幅することで、その変化を検出しやすくする方法がとられています。

オペアンプについてはいろいろと原理紹介のページがあるのでそちらを見ていただくと良いと思いますが、2つの抵抗の比率で増幅率が決まる増幅回路、という、とても計算お手軽な回路です。

参考)オペアンプ(wikipedia)

回路図

焦電型赤外線センサーには、AKE-1(RE-210)を利用しました。これに併せて、人体検知器の製作のPDFにあるように赤外線の集光率を上げるためのフレネルレンズとしてS9013を使いました。

オペアンプはLM358Nです。オペアンプ2回路入りの汎用品で、オペアンプについて記述されているWEBページでは頻繁に目にする定番中の定番のようです。秋月電子では5個入りで100円となっています。

センサーの増幅回路ですが、これはRE-210のデータシートにある応用回路例を参考に、手元にある電子部品をできるだけ使って組みました。また、がた老AVR研究所さんのブログ記事やYouTubeの秋月焦電センサのテスト回路なども参考にさせていただいています。

データシートの応用回路例

データシートの応用回路例

弊社で実験した回路

実験回路

ブレッドボード

オペアンプ左側が非反転増幅回路で100倍、右側が反転増幅回路で100倍、合計約1万倍の増幅です。増幅率を変えていろいろやってみましたが、結局、データシートの応用例が一番検出が楽なようでした。センサーとしては電荷の移動が十分検知できればいいので結構アバウトでも大丈夫なようです。

回路図ではオペアンプが離れて記述してあるのでゆったり目に見えますが、LM358Nは2回路入りで、ICの左側1,2,3番ピンが回路図の左側のオペアンプ、5,6,7番ピンが回路図の右側のオペアンプとなり、ブレッドボードで組むとかなりごちゃごちゃします。ですので、短めのオス-オスのジャンパワイヤーがあると便利でしょう。

なお、4番はGND、8番はVccなのでRaspberry Pi の5Vに繋ぐことになります。LM358Nの最大定格電圧は±16Vのようで、3Vでも動作するという事ですから3.3Vでも5Vでも問題ないでしょうが、焦電型赤外線センサーを5Vで駆動させているためそれをそのまま利用しました。

参考)マイコン回路での入力信号増幅をオペアンプで行う方法

回路を組む上で、あと注意しなければいけないのは電解コンデンサを使っているので極性を間違えないことぐらいでしょうか。無極性のキャパシタ(コンデンサ)が使えればその方が初心者には安心かもしれませんね。

動作確認

実際の動作確認には、ブルーバックス社の「Raspberry Pi で学ぶ電子工作 超小型コンピュータで電子回路を制御する」のサンプルコード 06-01-print.py を移植したPHPコードを利用しています。動作確認だけであれば 06-01-print.py をそのまま使うだけで十分です。

因みに、この本はとても親切な編集になっているので初心者向けとしてとてもお勧めです。A/DコンバータのMCP3208についての紹介もあります。A/Dコンバータはいろいろな場面で利用できるので、ぜひとも常備したい部品の1つです。

上記回路の OUT をMCP3208の検査用のピンに繋ぐと、オペアンプで増幅された焦電型赤外線センサーの電位の変化が数値となってコンソールに出力されます。

がた老AVR研究所』さんのブログ記事にもあるのですが、この焦電型赤外線センサーは、通電してから電荷が安定して赤外線を正常に検知できるようなるまでに40秒ほどかかります。

弊社の回路で06-01-print.py を使った場合、電荷が安定すると2500~3200程度の値を推移しますが、傍で人が動くと10程度まで突然数値が下がった後、12bit A/D コンバータであるMCP3208の最大値4095が検出されます。人感センサーとしては、この電圧の変化を測定することになります(ブログ記事にオシロスコープ画面があるのでそれを見ていただければ理解しやすいとおもいます)。

検出距離は意外に広く、10m位離れていても人が動くのをしっかりと感知してくれます。フレネルレンズの効果でしょうね。なお、赤外線を検知するので昼間と夜間では多少動作が変わります。ですから実際の運用ではCdSセルを併用して周りの明るさを検知し、昼と夜で検出のしきい値を変更したりするのも良いかもしれません。

余談ですが、傍でコーヒーを飲むとその湯気に反応したりもするようです。もっと面白いのは、ため息に反応することです。本当に疲れた時自然に出るため息には反応するのですが、それをまねしてワザとため息を吐いてみてもほとんど反応しません。自然に出るため息というのはかなりの赤外線を発するようです。

弊社ではセンサーからの数値のプログラムでの取り扱いを容易にするため、A/Dコンバータから読み取ったデジタル値を%に変換しています。人感センサーでは95%と60%にしきい値を設け、これよりも上あるいは下になる値に短時間(1秒以内)で連続して切り変った場合に、人が動いたとしています。

((float)value / 4095) × 100 = %

本当はニュートラルな値を50%付近に持ってきたかったのですが、オペアンプの調整が上手くいかず、増幅率を変えても大体70%半ばになってしまいました。何分、独学で電子回路の勉強を始めてまだ日が浅いため、既存回路に少しずつ手を加えて回路の意味を把握している状態ですので暖かい目で見ていただければと思います。人感センサーとしては上記回路でも十分な結果が得られましたので人感センサー回路の実験はこれで終わりにして連続運転で経過観察に移りますが、もう少しオペアンプの勉強をしたら50%に平常時を持ってこれるようになるかもしれません。

(2016/05/22 追記)

余談になりますが、この人感センサーの回路、ブレッドボードやジャンパワイヤ―まで含めると軽く1,000円を超えてしまいます。一方、Raspberry Piに対応した既成品は数百円で販売されています。例えばこれなどです。

当サイトで購入してテストした製品は ¥520 で(Amazonでは売り切れになってしまっていました)検出性能もとても良くできています。単純に人感センサーを導入したいだけであれば、こういった既成品を購入して Raspberry Piに接続するほうが、ずっと安くてお手軽です。

そういう身も蓋もない話ではなく、自分で回路を組み上げるのが楽しいんだ! という方は、ぜひあなたの人感センサーを作ってみてください。それこそが、Raspberry Piを使う最大の楽しみでもあるのではないでしょうか。

トランジスタ

公開日時:2015/06/11 03:17

トランジスタの動作検証です。

検証に使用したのは2SC1815のGRランクと、2SC3419のYランクです。

altテキスト

2SC1815 GR

トランジスタ回路1

エミッタ側A点電流実測値 2.57mA

ベースに流した電流はデータシートによるとベース・エミッタ間飽和電圧最大1.0Vで

(3.3V-1.0V) ÷ 986 = 0.00233A = 2.33mA

2SC1815 GRのhFE値を200とすると、エミッタ側Aには

2.33mA × 200 = 466mA 程度流れる予定。そのままGNDに流しても大きなは問題なさそうなので、エミッタ側をショートさせてA点を観測。

トランジスタ回路

実測

ベース電流実測値 2.36mA

A点実測値 146mA(時間経過とともに低下)

146 ÷ 2.36 = hFE 61.9倍

2SC1815のデータシートより抜粋

2SC1815データシート

Raspberry PiのGPIOは3.3Vで、2SC1815のベース・エミッタ間飽和電圧は最大1.0Vな事を考慮すると大体データシート通り。2SC1815は60mAを越えたあたりから急激にhFE値が下がる。

2SC3419 Y

2SC3419回路1

エミッタ側A点電流実測値 2.62mA

1815と同様にエミッタ側をショートさせる。

2SC3419回路2

ベース電流実測値 2.36mA

A点実測値 330mA

330 ÷ 2.36 = hFE 140倍

トランジスタ回路

こちらもデータシート通りの結果になった。

2SJ496 (Pch MOS FET)

2SJ496TZ-E

PchのMOS FET (電界効果トランジスタ) を使った実験。

MOS FETによるNOTスイッチ回路

Raspberry Pi からの信号がLOWの時は5VからB側に電気を流し、HIGHになった時はA側に電気を流す。R3、R4は漏れ電流によりトランジスタのスイッチが入ってしまうのを防止するために配置している。R5はRaspberry Piからの信号線がオープンになった場合に2SC3419のコレクタ・エミッタ間に電気を流してしまわないためのもの。

(参考)トランジスタをマイコン出力のスイッチとして使う方法(1/2)

LOW時

LOW時

HIGH時

HIGH時

R6をキャパシタ(コンデンサ)に変更し、2SC3419のコレクタ側にLEDを設置した。Raspberry Piからの信号がLOWの時はキャパシタに電気を蓄え、HIGHになったらキャパシタへの電気供給を断ちつつ、キャパシタからLEDに電気を供給して光らせる。

MOS FETによるNOTスイッチ回路2

記事リンク