M5Stack 赤外線利用で遮光物体の有無検知

2024.5.24 Coskx Lab  

1 はじめに

赤外線発光装置と受光装置の間の光路に赤外線を遮る物体が存在するかどうかを検知することを目的とします。



図のように赤外線の発光受光を行い,赤外光路を遮断されているかどうかを検出して,対象物の有無を検知します。
使用するのは赤外LED(light emitting diode)と赤外線受光モジュールです。

2 使用環境

3 赤外線受光モジュール

赤外線受光モジュールのデータシート
赤外線受光モジュールは,家庭電化製品(テレビなど)の赤外線リモコンに使用されているセンサです。
赤外線発光器以外からの赤外線を含む光に反応しないように,赤外線受光モジュールは38kHzで強度変化(ON-OFFでよい)のある赤外線(38kHz変調赤外線)に対して反応するようになっています。
(テレビなどのリモコンではリモコンボタンを押すと,38kHz変調赤外線の有無のパターンの一連の信号が送られます。)

データシート(赤外線受光モジュール OSRB38C9AA)の動作図を見ると,赤外線LED側は38kHz変調赤外線を発したり休止したりしています。38kHz変調赤外線を発している期間も,休止している期間もそれぞれ600μsになっています。
それに対応して,赤外線受光モジュールは38kHz変調赤外線を受光しているときはLを,38kHz変調赤外線を受光していないときはHを,モジュール出力にしています。(負論理)
しかも,100msecが1ブロックとなっていて,ブロックの最後はある長さの休止期間が必要となっています。
この休止区間(長めの非受光期間)はリモコンボタンの一連の信号パターンの区切りを表すと同時に,受光モジュールのAGC(Automatic Gain Control)に無信号レベルをセットするのに使われているようです。


   データシート(赤外線受光モジュール OSRB38C9AA)にある動作図

赤外線受光モジュールのテスト
赤外線受光モジュール OSRB38C9AAで次のテストをしました。
(1) 赤外線LEDから600μsの38kHz変調赤外線発光と600μsの休止区間を連続して与え続けたところ,最初の0.1秒程度は赤外線受光モジュールが受光検知の信号を見せますが,その後,受光しているはずなのに非受光状態を示す信号を発するようになりました。
長めの休止区間(非受光期間)がないため,AGCのレベルセットが出来ず誤動作に至ったものと考えられます。
(2) 次の図に示すように,600μsの休止区間を挟んで,600μsの38kHz変調赤外線を2回与える動作を25msec周期で与える動作をしたところ,(約23msecの非受光区間を与えたことになります)光路に遮蔽物があるか無しかを正しくとらえることが出来るようになりました。



     テストした25msec周期の駆動パターン(1周期に2回の受光区間)


テスト結果からの指針
(2)の方式では,連続して正常な動作を行いますが,25msec毎の遮光物検査しかできません。遮光物検査の時間分解能は25msecになります。

(1)で起動直後の短かな時間では正しく動作することを利用して,遮光物検査の度に赤外線受光モジュールに通電し,検査が終わったら通電をやめる方式では,5msec毎の遮光物検査が出来ることがわかりました。
この方式では,遮光物検査の度に赤外線受光モジュールに通電し,1500μs待ってから,600μsの短い休止区間を挟んで,赤外線LEDから600μsの38kHz変調赤外線を2回与える動作になります。(2回の検査で信頼性を上げます。)また,遮光物検査の時間分解能は5msecになります。
こちらの方式を採用することにしました。



4 M5stackピン割り当てと回路

M5stackピン割り当て
M5Stackは,
(1)赤外LEDの点滅のために38kHz変調赤外線生成
(2)赤外線受光モジュールへ通電コントロール
(3)赤外線受光モジュールからの信号を受け取り
を行います。

赤外LEDの点滅のためにPWM出力できる出力ピンとして,デジタル出力ピンGPIO2を割り当てます。

赤外線受光モジュールの仕様は電源供給は3.3V,Max1.5mAになっています。
そのため赤外線受光モジュールの電源コントロールにはGPIO16の出力をそのまま使ってコントロールします。
赤外線受光モジュールからの信号は論理信号なので,デジタル入力ピンでよいのですが,動作確認も出来るようにADCピンGPIO35を割り当てます。

赤外LED
赤外LEDの電流は100mAまで可能ですが,M5Stack側のデジタル出力に無理をしないように,20mAで駆動するように制限抵抗を使います。
 M5Stackのデジタルピン出力;3.3V
 LED順電圧:1.35V
 駆動電流:20mA
 3.3V-1.35V=1.95V
 R=V/I=1.95V/0.02A=97.5Ω
ということで,電流制限抵抗は100Ω程度を使います。

赤外線受光モジュール
赤外線受光モジュールの安定動作のため,1μFのバイパスコンデンサを付けます。
またM5Stack出力ピンの電流制限のため,100Ω程度の抵抗を使います。

次のような回路となります。


5 赤外線利用で遮光物体有無検知のプログラム

赤外LED38kHz変調駆動には38kHzのPWM動作を使用します。
PWM信号のデューティ比は,32/256,64/256,96/256,128/256を使用し,デフォルトは32/258です。
ボタンCでPWM信号のデューティ比を変更します。
起動直後のM5Stackの画面2行目に使用中のデューティ比が表示されます。
デューティ比が大きいほど,赤外LEDの強度は大きくなりますが,場合によっては乱反射による赤外線の回り込みが生じ,常に受光モジュールが反応してしまうことがあります。

loop関数シーケンス内で5msecの周期で受光モジュールの状態を検査します。
検査動作では,600μsecの赤外LED38kHz変調駆動を行います。
赤外LED38kHz変調駆動開始後300μsec経過後に受光モジュールの信号をチェックし,遮光物がないとき(受光時)にLを,遮光物があるとき(非受光時)にHをデジタル値で受け取ります。



//infraredsensor0A.ino

#include <M5Stack.h>

const uint8_t nBits_forPWM = 8; // PWMに使用するビット数 n=1~16[bit]
const uint8_t PWM_Values[] = {32, 64, 96, 128}; //デューティ
                         //MaxDuty=2^n  DutyRatio = Duty/MaxDuty
const int nValues = sizeof(PWM_Values)/sizeof(uint8_t);
int ValueIndex = 0;

uint8_t PWM_Value = PWM_Values[ValueIndex]; //duty ratio = 32/256 に設定
const double PWM_Frequency = 38000.0;   // PWM周波数 Maxfreq=80000000.0/2^n[Hz] 38kHz

const uint8_t PWM_CH = 2;  // PWMチャンネル
const uint8_t PWM_PIN = 2; // PWM出力に使用するGPIO PIN番号
const uint8_t IRRecModuleOUT_PIN = 35; // 赤外線センサの出力に使用するGPIO PIN番号
const uint8_t IRRecModuleVCC_PIN = 16; // 赤外線センサ電源に使用するGPIO PIN番号

long msecperiod = 5;  // 赤外線光路チェック周期 msec
long usecWaitingtime = 1500;  // 赤外線モジュール通電後の待機時間 μsec
long msectimetocheck = msecperiod*2;

void setup() {
  M5.begin();
  M5.Power.begin();
  M5.Lcd.setTextSize(2);
  M5.Lcd.print("Infrared Receiver check\n");
  M5.Lcd.printf("PWM FRQ:%.0lfk dutyR:%d/256 \n", PWM_Frequency/1000, PWM_Value);
  M5.Lcd.printf("R: Received    b: Blocked");

  //PWM信号発生ピンを出力モードにする
  pinMode(PWM_PIN, OUTPUT); 
  // チャンネルと周波数の分解能を設定
  ledcSetup(PWM_CH, PWM_Frequency, nBits_forPWM);
  // PWM出力ピンとチャンネルの設定
  ledcAttachPin(PWM_PIN, PWM_CH);

  //PWM出力ピンと周波数,分解能,チャンネルの設定 (これはESP32用の新しい関数なので,まだ使えない)
  //ledcAttachChannel(PWM_PIN, PWM_Frequency, nBits_forPWM, PWM_CH);

  //IRRecModuleOUT_PINを単純入力モードにする
  pinMode(IRRecModuleOUT_PIN, INPUT); 
  pinMode(IRRecModuleVCC_PIN, OUTPUT);
  digitalWrite(IRRecModuleVCC_PIN, LOW);
}

// 2回の受光モジュールチェックを行う
// 1: 遮光状態
// 0: 受光状態
// -1: 判定不能
int checkIRRecModule() {
  digitalWrite(IRRecModuleVCC_PIN, HIGH);
  delayMicroseconds(usecWaitingtime);

  //PWM信号発生開始
  ledcWrite(PWM_CH, PWM_Value);
  delayMicroseconds(300);
  int result1 = digitalRead(IRRecModuleOUT_PIN);
  delayMicroseconds(300);
  //PWM信号発生停止
  ledcWrite(PWM_CH, 0);

  delayMicroseconds(600);

  //PWM信号発生開始
  ledcWrite(PWM_CH, PWM_Value);
  delayMicroseconds(300);
  int result2 = digitalRead(IRRecModuleOUT_PIN);
  //delayMicroseconds(300);
  //PWM信号発生停止
  ledcWrite(PWM_CH, 0);

  digitalWrite(IRRecModuleVCC_PIN, LOW);

  //確認用表示 これを有効にすると時間がかかって5msec周期で動かない
  //M5.Lcd.setTextSize(2);
  //M5.Lcd.setCursor(0,3*16);
  //M5.Lcd.printf("%4d %4d", result1, result2);

  if (result1==0 && result2==0) return 0;
  if (result1==1 && result2==1) return 1;
  return -1;
}

void loop() {
  static int loopcount=0;
  M5.update();
  if(M5.BtnC.wasPressed()){
    ValueIndex++;
    if (ValueIndex == nValues) ValueIndex = 0;
    PWM_Value = PWM_Values[ValueIndex];
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(0,1*16);
    M5.Lcd.printf("PWM FRQ:%.0lfk dutyR:%d/256 ", PWM_Frequency/1000, PWM_Value);
    M5.Lcd.setCursor(0,4*16);
  }

  if (msectimetocheck <= millis()) {
    msectimetocheck += msecperiod;
    int IRRecModulestatus = checkIRRecModule();
    M5.Lcd.setCursor((loopcount%25)*12, (loopcount/25+6)*16);
    M5.Lcd.printf("%c ", " Rb"[IRRecModulestatus+1]); //確認用表示
    if (++loopcount == 100) loopcount = 0;
  }
}

/*
発行側の設定
LEDの制限抵抗は220Ω並列で110Ωとしている
LED駆動は38kHz デューティ比32/256 = 12.5%
これくらいの設定が良いようだ
*/

6 実行の様子

実際のテスト装置は次のようになります。
右側のブレッドボード上に赤外LEDがあり,左側のブレッドボード上に赤外線受光モジュールがあります。



また,テスト時のM5Stack画面の様子は次のようになりました。
100回分の検知結果を繰り返し表示しています。
R:受光中  b:非受光中

受光時非受光時

7 動作中の信号観察

非受光時(遮蔽物が赤外線光路上にある時)
38kHz変調の赤外光が遮蔽されているため,2回ある検出ポイントでの赤外線受光モジュールの出力はHです。
検出周期は5msecです。


受光時(遮蔽物が赤外線光路上にない時)
38kHz変調の赤外光が透過しているため,2回ある検出ポイントでの赤外線受光モジュールの出力はLです。

8 使用デューティ比と,センサペア間の距離

デューティ比によって利用可能な赤外発光アセンブリと赤外受光アセンブリ間の距離は次のようになっています。(実測)

デューティ比 発光と受光間の最大距離
32/256 150cm
64/256 230cm

9 まとめ

M5Stackで赤外線を使った遮光物体の有無検知ができました。
50cmの赤外線光路でうまく動作しています。

製作・テストにおいて誤動作がありました。対処は次の通りでした。
(1)赤外線受光モジュールにはノイズの少ない電源を与える必要がある。セラミックコンデンサ1μFを赤外線受光モジュール直近に付加することで対処出来ました。
(2)赤外線受光モジュールのAGC(Automatic Gain Control)が働かないようにして動作しているため,外乱光にかく乱されることがありました。外乱光を防ぐためのカバーを使うことで対処しました。

感想

2000年頃にRS232C通信の途中に赤外線通信で中継してロボコンのロボットの遠隔操作機能を作ったときには,単純に38kHz変調・復調しただけで通信ができたと記憶しています。そのころの受光モジュールは単純に38kHz変調された赤外線を復調しているだけのものが入手出来たのではないかと思います。現在入手できる赤外線受光モジュールは用途が家電製品のリモコンに特化され,耐ノイズ性能は向上したものの,特定のバーストパターンしか受け入れないようにできていて,受光状態か非受光状態かを常時監視するにはプログラムの工夫が必要となっています。
いろいろ調べていくと,OSRB38C9AA を含む最近の赤外線受光モジュールはリモコン用と書かれていて,ある長さの非受光状態をAGCが必要としているようで,Net検索してみると困っている人も多いようです。今は廃版になってしまった赤外線受光素子 NJL21V380A や PL-IRM1261-C438 はある長さの非受光状態を必要としていないようです。(入手できない)

赤外線受光モジュール OSRB38C9AAの最初のテストでは,赤外LEDから連続して38kHz変調した赤外線を発光し,赤外線受光モジュール出力を見ていました。赤外線光路の遮断を繰り返してみたのですが,非受光状態から受光状態になったときに,赤外線受光モジュールは赤外線の受光状態を示し,すぐに非受光状態に遷移してしまいました。動作が思ったものと違ったため,わかりにくいデータシートのバーストパターンをいろいろ解釈して,ようやく目的の機能を実現することが出来ました。