赤外線モーションセンサモジュール(HC-SR501)を試してみる(その4)


前回は赤外線モーションセンサモジュール(HC-SR501)を使って USBライトを点灯させる方法を紹介しました。
しかし前回の状態だと、人の動きがあれば部屋の明るさに関係なくライトが点灯してしまいます。
そこで、ライトセンサーを加えて、暗いときだけライトを点灯するようにしました。




使用したライトセンサーは上の写真のように3ピンが出ているモジュールです。
受光部(CDS)にはGL55 シリーズが使われいるようです。
基板上にはLM393(Comparator) が載っていて、これでCDSの出力を判定しています。
VCCに3.3Vを加えてやると、明るいときは0V、暗くなると3.3Vが出力されることが分かりました。




回路図は以下のとおりです。
今までの回路にライトセンサーを加えただけです。

回路図

全体はこんな感じです。




ソースコードは以下のとおりです。
USBの電源をONにする前にライトセンサーの値を判定し、暗いときだけUSBの電源をONにします。
動作中を示すLEDを加えています。

以下の部分は環境に合わせて変更してください。
// Define Hub Control Command
#define PROG    "/home/pi/hub-ctrl/hub-ctrl" → hub-ctrlのフルパス

// Define Hub Control Chip
#define CHIP    "Texas" → USB-HUBに使われているチップメーカ

// Define Hub Port
#define PORT    4 → 使用するUSB-HUBのポート番号

USB-HUBに使われているチップメーカは以下で確認することができます。
$ sudo lsusb -v | grep Bus
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 006: ID 0451:1446 Texas Instruments, Inc. TUSB2040/2070 Hub 
→ USB-HUBに使われているチップメー カ

/*
cc -o test7 test7.c -lwiringPi
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <wiringPi.h>

// Define Motion Sensor Pin
#define MOTION  4    // rsp board pin:7

// Define Light Sensor Pin
#define LIGHT    18      // rsp board pin:12

// Define Button Pin
#define BUTTON    23      // rsp board pin:16

// Define LED Pin
#define LED    25      // rsp board pin:22

// Define Timeout
#define WAITSEC    60      // タイムアウト時間

// Define Hub Control Command
#define PROG    "/home/pi/hub-ctrl/hub-ctrl"

// Define Hub Control Chip
#define CHIP    "Texas"

// Define Hub Port
#define PORT    4

int semid;
int gpioid=0;

//USB-HUBの情報取得
int GetHubInfo (char *cmdline, char *bus, char *device)
{
    FILE *fp;
    char buf[256];
    char *tok;
    int flag=0;

    if ( (fp=popen(cmdline,"r")) ==NULL) return(1);

    while(fgets(buf, sizeof(buf), fp) != NULL) {
      if (strncmp(buf,"Bus ",4) == 0) {
        tok=strtok( buf, " :" );
        while( tok != NULL ){
          if (flag == 1) {
            strcpy(bus,tok);
            flag=0;
          }
          if (flag == 2) {
            strcpy(device,tok);
            flag=0;
          }
          if (strcmp(tok,"Bus") == 0) flag=1;
          if (strcmp(tok,"Device") == 0) flag=2;
          tok = strtok( NULL, " :" );  /* 2回目以降 */
        }
      }
    }
    pclose(fp);

    return(0);
}

//USB-HUBの電源ON
int HubOn (char *bus, char *device, int port)
{
    char buf[256];
    struct stat st;

    if (stat(PROG,&st) != 0) return(1);
    sprintf(buf,"sudo %s -b %s -d %s -P %d -p 1",PROG,bus,device,port);
    return(system(buf));
}

//USB-HUBの電源OFF
int HubOff (char *bus, char *device, int port)
{
    char buf[256];
    struct stat st;

    if (stat(PROG,&st) != 0) return(1);
    sprintf(buf,"sudo %s -b %s -d %s -P %d -p 0",PROG,bus,device,port);
    return(system(buf));
}

//排他処理開始(ロック開始)
//自分よりも先にロックされていた場合にはロック解除されるまでスリープします
void lock(int semid){
    struct sembuf sb[1];
    sb[0].sem_num=0;
    sb[0].sem_op=-1;
    sb[0].sem_flg=0;
    if(EOF==semop(semid,sb,1)){
        printf("%s\n","lock ERR");
        exit(1);
    }
}

//排他処理終了(ロック解除)
void unlock(int semid){
    struct sembuf sb[1];
    sb[0].sem_num=0;
    sb[0].sem_op=1;
    sb[0].sem_flg=0;
    if(EOF==semop(semid,sb,1)){
        printf("%s\n","unlock ERR");
        exit(1);
    }
}

//セマフォ値のセット
void SemSetValue(int semid, int semnum, int semval) {
    union semun {
        int              val;     /* SETVAL の値 */
        struct semid_ds  *buf;    /* IPC_STAT, IPC_SET 用のバッファ */
        unsigned short   *array;  /* GETALL, SETALL 用の配列 */
    } ctl_arg;

    ctl_arg.val = semval;
    if((semctl(semid,semnum,SETVAL,ctl_arg))==EOF){
        printf("%s\n","semctl ERR");
        exit(1);
    }
}

//センサーが反応したときの対応
void signal1(void){
     gpioid=1;
     unlock(semid);
}

//ボタンが押されたときの対応
void signal9(void){
     gpioid=9;
     unlock(semid);
}

int main(int argc, char **argv) {
    int endFlag=1;
    pid_t result_pid;
    int status;
    int process_count=0;
    char cmdline[50];
    char bus[10];
    char device[10];
    int ret;
    int ldata;

    sprintf(cmdline,"sudo lsusb -v | grep ^Bus | grep %s",CHIP);
    ret=GetHubInfo (cmdline, bus, device);

    //セマフォを割り付けます
    semid=semget(IPC_PRIVATE,1,0666);
    if(semid==EOF){
        printf("%s\n","semget ERR");
        exit(1);
    }

    //セマフォに初期値を書き込みます
    SemSetValue(semid,0,0);

    if (wiringPiSetupGpio() == -1){
        printf("wiringPiSetup init error\n");
        exit(1);
    }
    pinMode(MOTION, INPUT);
    pinMode(BUTTON, INPUT);
    pinMode(LED, OUTPUT);
    pinMode(LIGHT, INPUT);
    digitalWrite(LED, 1);
    HubOff (bus, device, PORT);

    //割り込みを設定します
    wiringPiISR( MOTION, INT_EDGE_FALLING, signal1 );
    wiringPiISR( BUTTON, INT_EDGE_FALLING, signal9 );

    while(endFlag){
        lock(semid); // Wait Unlock
        switch (gpioid) {
            case 0: // 子プロセス終了
                process_count--;
                if (process_count == 0) HubOff (bus, device, PORT);
                break;
            case 1: // センサからの入力あり
                ldata=digitalRead(LIGHT);
                if (ldata == 0) break;
                if (process_count == 0) HubOn (bus, device, PORT);
                process_count++;
                result_pid = fork();
                if (result_pid == 0) { // 子プロセス開始
                    sleep(WAITSEC);
                    unlock(semid);
                    exit(0);
                }
                break;
            case 9: // ボタンが押された
                endFlag=0;
                break;
            default: //
                break;
        }
        gpioid=0;
    }

    if (process_count != 0) { // 子プロセス終了待ち
        waitpid( result_pid,&status,0);
    }
    HubOff (bus, device, PORT);

    //セマフォの削除
    if((semctl(semid,0,IPC_RMID,0))==EOF){
        printf("%s\n","semctl ERR");
        exit(1);
    }
    digitalWrite(LED, 0);

    exit(0);
}

続く...