0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

PIRセンサを使えるようにする話

Last updated at Posted at 2021-09-29

1. はじめに

お仕事で 「人が居ない事を検知して下さい、カメラはダメよ!」とか言う
いつもの無茶振りで話は突然はじまった

むむむ?
人が居る事ぢゃなくって人が居ない事を検知?
なんだ?何に使うんだ?
って事で一旦なんとなく形になって来たのでというお話

2. PIRセンサを真面目に考える

部品箱に入っている PIRセンサを取り出して

適当に繋いでみると実に不安定....に見える
これでは評価も低くなるなぁ

test.ino

# define PIN (26)
void setup() {
  Serial.begin( 115200 );
  pinMode(PIN, INPUT_PULLUP);
}

void loop() {
  int val;
  val = digitalRead(PIN);
  Serial.printf("val=%d\n", val);
}

データシートを読んでみると何やら BLOCK_TIME と言うものがあり
この間は 反応をしないらしい
ははぁ それで不安定に見えるのか...

3. 改造?

WEBを検索しまくると

とか、ICの5PIN/6PIN直結の記事が目立つ
別にそれが良いとか悪いとかの話ではなくて
改造しちゃうと量産に耐えられなくなってしまうので
ここはソフトでカバーしまくることにした

  • 量産の掟風なものがあり 買ってきたものは改造してはいけない
  • っていうかだいたい内製してねとのお話

4. 仕組み

下記のように BLOCK TIME と呼ばれる部分は 仮想的にONを出力しセンサからの値を出力しないようにする

//
//         +---+............
//         |   | BLOCK     :
//         |   |     TIME  :
// --------+   +----------------------------
// Status ON   OFF
//
//
//         +---+............
//         |   | VirtualON :
//         |   |      TIME :
// --------+   +----------------------------
// Status ON               OFF
//
//

さらに ON/OFF の状態が変わった時点から n分間の傾向を算出してみる
これが 0であれば過去n分間 そこに人が居なかった事がわかる

     +-+     +-+                  +-+
     | |     | |                  | |
     | |     | |                  | |
-----+ +-----+ +------....--------+ +----
     1回目   2回目                 n回目
<-------------- 過去n分間 --------------->

5. 全ソース

PIR.ino
# include "myPIR.h"
const uint16_t LEDPIN = (10);
const uint16_t PIRPIN = (26);
const uint32_t ONE_SEC_MSEC = (1 * 1000);
const uint32_t FIVE_SEC_MSEC = (5 * 1000);
const uint32_t ONE_MIN_MSEC = (60 * ONE_SEC_MSEC);

//========================
// 初期化
//========================
void setup(void)
{
  Serial.begin( 115200 );
  pinMode(LEDPIN, OUTPUT);
  digitalWrite(LEDPIN, !LOW);
  setupPIR(PIRPIN, FIVE_SEC_MSEC);
}

//========================
// LOOP
//========================
void loop(void)
{
  int16_t val, cnt;
  val = getPIR();
  cnt = getAnyMinTrand(ONE_MIN_MSEC);
  digitalWrite(LEDPIN, !val);
  Serial.printf("val=%d cnt=%d\n", val, cnt);
  delay(1);
}
myPIR.h
//===============================================================> myPIR.h
//  HC-SR501
//  Author/date   : @chrmLinux 2021/09/29
//  Author/update : @chrmLinux 2021/09/29
//  https://datasheetspdf.com/pdf-file/775434/ETC/HC-SR501/1
//
//  +--------------------------+
//  |          . . .           |
//  |          G O V           |
//  |          N U C           |
//  |          D T C           |
//  || Repeat                  |
//  |. Single ==   ==          |
//  +--------------------------+
//    Sensitivity  TimeDelay
//             VR         VR
//    min <-> max  min <-> max
//
// 1)1分くらい待たないと安定しない
// 2)OFF直後に BLOCK TIME がある
//
//         +---+............
//         |   | BLOCK     :
//         |   |     TIME  :
// --------+   +----------------------------
// Status ON   OFF
//
//
// 3)ぢゃ、仮想的にONするって感じで
//
//         +---+............
//         |   | VirtualON :
//         |   |      TIME :
// --------+   +----------------------------
// Status ON               OFF
//
//

const uint32_t BLOCK_TM = (5 * 1000);
static uint16_t _pirPin = 0;
static uint32_t _blockTime = 0L;

//========================
// BLOCKING TIME秒数 待つ
//========================
bool waitBlockTime()
{
  static uint32_t tm = millis();
  bool rtn = false;
  if ((millis() - tm) > _blockTime) {
    tm = millis();
    rtn = true;
//    Serial.printf("[wait]\n");
  }
  return rtn;
}

//========================
// PIR初期化
//========================
void setupPIR(uint16_t pin, uint32_t blocktime)
{
  _pirPin = pin;
  _blockTime = (blocktime < BLOCK_TM) ? BLOCK_TM : blocktime;
  pinMode(_pirPin, INPUT_PULLUP);
}

//========================
// 設定したBlockTImeを得る
//========================
uint32_t getBlockTime(void)
{
  return _blockTime;
}

//========================
// PIRから実際に値を得る
//========================
int16_t getRealPIR(void)
{
  int16_t val = digitalRead(_pirPin);
  return val;
}

//========================
// PIRから仮想の値を得る
//========================
int16_t getPIR(void)
{
  static int16_t preVal = -1;

  if (preVal == HIGH) {
    if (!waitBlockTime()) {
      return HIGH;
    }
  }

  int16_t val = getRealPIR();
  if (preVal != val) {
//    Serial.printf("[getPIR] preVal:%d val:%d\n", preVal, val);
    preVal = val;
  }
  return val;
}

//========================
// センサ検知からn分間の傾向
//========================
uint32_t getAnyMinTrand(uint32_t any_sec_msec)
{
  static uint32_t tm = millis();
  static uint32_t cnt = 0L;
  static int16_t preVal = 0;
  int16_t val;

  if ((millis() - tm) > any_sec_msec) {
    tm = millis();
    cnt = 0L;
  }

  val = getPIR();
  if (preVal != val) {
    tm = millis();
    preVal = val;
    if (val == HIGH) {
      cnt++;
    }
  }

  return cnt;
}
//<=============================================================== myPIR.h

6. おわりに

何かと癖がある PIRセンサですが
うまい具合に使うと色々な可能性が見えてきました
さて、クライアントはこれを何に使うのでしょうか...
私には見当もつきません(コロナ対策かな?)

  • この処理が皆さんに広がって中途半端な故障の多いPIRセンサとか言われているこれが見直される事を祈ります
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?