”テレビから離れて!” 子供に注意して聞かないとテレビを消すBOX
初めに
子供はテレビにかじりつくように見る事が多い。ママは目が悪くなることを心配して”テレビから離れて”といつも注意。忙しいママに代わって注意してくれるBOX。注意しても聞かないとテレビOFFしてしまう。(離れればまたON)。その他⓵在室の時だけテレビONにするEco機能 ➁暗闇でも体温で侵入者を検知する防犯機能 がある。一台3役の優れもの。
仕組み
① 子供の接近を検知する方法として、超音波距離計があるがテレビの近くに物があったり部屋で反響したりして誤動作が多い。シャープ赤外距離計は1mくらいまでが限度で視野角も狭い。サーモグラフが安定していた。ただし距離を測るデバイスでなく体温の占める面積でおよその距離とした。(面積多い=近距離)
テレビの前にBOXを置き子供が傍に来ると(視野角60度 2~3m)警告音を鳴らし同時に親の声を録音していた音声ボードで”テレビから離れて”を再生。更に1mくらいまで接近すると、長い警告音のあとリモコンで電源OFFする。その後テレビを離れるとリモコンで電源ONする。
② Ecoモードでは、テレビの部屋に人がいる(60度~4m)ことを検知するとテレビONし退出すると一定時間後テレビOFFする。従来のエコテレビに比べ、体温検知により安定したON OFF検出が行える。
③ 防犯モードでは、暗闇でジッとしている不審者でも体温で検出(60度 ~7m)し、一般の焦電型の防犯センサでは動きのない物には反応しないため防犯効果は大きい。
その他
テレビのリモコンは電源コードがON・OFFトグル動作で、BOXはテレビの電源状態がわからないので電源コードを送るとON OFFを逆転させてしまう恐れがある。これを防ぐ為リモコンコードで強制ONコード 強制OFFコードによりテレビの電源のコントロールを行う。リモコンコードは公開されていないので自力で調べるしかない(>_<)。今回ソニーのテレビでリモコンコードを調べ強制ON 強制OFFにより ON OFFの間違えを防いでいる。
主な部品
マイコン arduino NANO
サーモグラフ AMG8833基板(IIC pullupがされている)
音声ボード ISD1820 (録音/再生機能 アンプがついている)
小型SP
圧電Buzzer (*圧電SPではない)
赤外線LED 2個
3positionスライドSW 1回路3接点
電源PushSW
006Pスナップ
ケース 100均
結果
5才くらいまでの孫で”実験”したところ、意外にも皆きちんとBOXの言うとうりテレビに近ずくときちんと戻りましたヽ(^o^)丿 小学生低学年でも”くだらない”とも言わず音声をたのしんでいました。予想外だったのはBOXの音声ボードはマイクが付いていて録音も出来るので自分の声を録音して弟たちに注意していました。みんなで楽しめた工作でした。またサーモグラフは値段も下がりホビーでも使えるようになり、今後いろいろ応用が楽しみです。
参考文献
Conta サーモグラフィー AMG8833搭載
赤外線アレーセンサAMG8833をWebSocketで見てみる
M5stickCで赤外線リモコン・・・
M5stickCでちゃんと動く赤外線リモコンを作る
ソースコード
テレビから離れて
#include <Wire.h>
#define PCTL 0x00
#define RST 0x01
#define FPSC 0x02
#define INTC 0x03
#define STAT 0x04
#define SCLR 0x05
#define AVE 0x07
#define INTHL 0x08
#define TTHL 0x0E
#define INT0 0x10
#define T01L 0x80
#define AMG88_ADDR 0x69 // in 7bit gyroMPU6050 IIC68h
//temporaryData to buffer sumtotal IIC ADlow68h ADhigh69h
int TMPDAT0[64], TMPDAT1[64], TMPDAT2[64], TMPDAT3[64], TMPDATS[64];
int TMPHISairdata=0;
//**object scan **
int INITSTcnt = 0; //初期設定から打ち4LOOP
int TMPmax = 0, TMPmin = 400, TMPair = 0;
int lmax = 0, lmin = 0, imax = 0, imin = 0;
int TMPHIS[350], TMPHISmax; //int TMPHIS[150];TMPHISmax; //TMPHIS[150]NG
int MANflg, WASHflg;
int TMPHISmanS=0;
int TMPmaxmin=500; //minをセット「するためinitは高め:300~350
//int cdsON,cdsOFF;
//**system**
int POWflg = 1; //flg=0 だとSWONで一旦PIPIと鳴る
//**IR Remote**
#include <IRremote.h>
IRsend irsend;
void setup()
{
Serial.begin(115200);
Wire.begin(); //A4:SDA A5:SCL
pinMode(3, OUTPUT); pinMode(2,OUTPUT);digitalWrite(2,LOW); //赤外LED 2:GND 3:OUT
pinMode(12,OUTPUT);pinMode(13,OUTPUT);pinMode(11,OUTPUT);digitalWrite(11,LOW);pinMode(10,OUTPUT); //12,13:BUZZER 11:FT MIC 10:音声Trigger
pinMode(4,OUTPUT);digitalWrite(4,HIGH); //D4:Keyscan 出力:keyscanの時だけLOWにしてD5 D6 D7 のpullup lossを防ぐ
pinMode(5,INPUT_PULLUP);pinMode(6,INPUT_PULLUP);pinMode(7,INPUT_PULLUP); //Keyscan入力 D5:childLock D6;alarm D7:eco enegy savimg
int fpsc = B00000000;// 1fps
datasend(AMG88_ADDR, FPSC, &fpsc, 1);
int intc = 0x00; // diff interrpt mode, INT output reactive
datasend(AMG88_ADDR, INTC, &intc, 1);
// moving average output mode active
int tmp = 0x50;
datasend(AMG88_ADDR, 0x1F, &tmp, 1);
tmp = 0x45;
datasend(AMG88_ADDR, 0x1F, &tmp, 1);
tmp = 0x57;
datasend(AMG88_ADDR, 0x1F, &tmp, 1);
tmp = 0x20;
datasend(AMG88_ADDR, AVE, &tmp, 1);
tmp = 0x00;
datasend(AMG88_ADDR, 0x1F, &tmp, 1);
int sensorTemp[2];
dataread(AMG88_ADDR, TTHL, sensorTemp, 2);
// Serial.print("sensor temperature:");
// Serial.println( (sensorTemp[1]*256 + sensorTemp[0])*0.0625);
} //setup END
void loop()
{
INITSTcnt++; if (INITSTcnt >=50) INITSTcnt = 50; //初期設定から打ち5回以上
TMPmax = 0; TMPmin = 400; TMPHISmax = 0; //max min RESET
Serial.println("[");
// Wire library cannnot contain more than 32 bytes in bufffer
// 2byte per one data
// 2 byte * 16 data * 4 times = 2byte*64point
int sensorData[32];
//TMPHISCLR(); //histgram clear initで設定する場合
for (int i = 0; i < 4; i++)
{
// read each 32 bytes
dataread(AMG88_ADDR, T01L + i * 0x20, sensorData, 32);
for (int l = 0 ; l < 16 ; l++)
{
int16_t temporaryData = (sensorData[l * 2 + 1] * 256 ) + sensorData[l * 2];
//TMPHIS[temporaryData] += 1; //温度ヒストグラム+1 初期設定する場合
//*** TMPDATSUM();*** 温度Data sum3回で安定化
TMPDATS[i * 16 + l] = 0; //TMPDATS[i*16+1]=0;
TMPDAT0[i * 16 + l] = temporaryData;
TMPDAT1[i * 16 + l] = TMPDAT0[i * 16 + l]; //TMPDAT1[i*16+l]=TMPDAT0[i*16+l];
TMPDATS[i * 16 + l] = TMPDATS[i * 16 + l] + TMPDAT1[i * 16 + l]; //TMPDATS[i*16+l]=TMPDATS[i*16+1]+TMPDAT1[i*16+1];
TMPDAT2[i * 16 + l] = TMPDAT1[i * 16 + l]; //TMPDAT2[i*16+1]=TMPDAT1[i*16+l];
TMPDATS[i * 16 + l] = TMPDATS[i * 16 + l] + TMPDAT2[i * 16 + l]; //TMPDATS[i*16+l]=TMPDATS[i*16+1]+TMPDAT2[i*16+1];
TMPDAT3[i * 16 + l] = TMPDAT2[i * 16 + l]; //TMPDAT3[i*16+1]=TMPDAT2[i*16+l];
TMPDATS[i * 16 + l] = TMPDATS[i * 16 + l] + TMPDAT3[i * 16 + l]; //TMPDATS[i*16+l]=TMPDATS[i*16+1]+TMPDAT3[i*16+1];
//*TMPDATSUMmaxmin*
if (TMPmax < TMPDATS[i * 16 + l]) {
TMPmax = TMPDATS[i * 16 + l];
imax = i;
lmax = l;
} //if (TMPmax<TMPDATS[i*16+1]) {TMPmax=TMPDATS[i*6+1];imax=i;lmax=l;}
if (TMPmin > TMPDATS[i * 16 + l]) {
TMPmin = TMPDATS[i * 16 + l]; //(TMPDATS[i * 16 + l]); //Serial.print(temporaryData);//Serial.print(temperature);
imin = i;
lmin = l;
}
Serial.print(TMPDATS[i * 16 + l]); //Serial.print(temporaryData);//Serial.print(temperature);
if ( (l + i * 16) < 63 ) Serial.print(",");
if (l == 7) Serial.println();
} //for:I16 END
Serial.println(); //every 16data
} //for:i4 END
Serial.println("]"); //every 64data
//****************************************1frame Data complete 3回から打ちしてからmain loop********
if (INITSTcnt >=5 ) //3回から打ちしてからMain loop
{
airtemperature(); //air temperature histgraghmaxで決定
objectscan() ; //object Scanで探す
}
//**********************************************************************
Serial.print(TMPmax);Serial.print(" maxads"); Serial.print(imax * 16 + lmax + 1);Serial.print(" maxmin"); Serial.println(TMPmaxmin);
Serial.println(TMPmin);
Serial.print(TMPair);Serial.print(" aircells");Serial.println(TMPHISmax);//Serial.println(INITSTcnt);
Serial.print(POWflg);Serial.print(" mancells"); Serial.println(TMPHISmanS);//
// Serial.print(cdsON);Serial.println(cdsOFF);
delay(1000);
} //loop END
//*********loop END*************
void datasend(int id, int reg, int *data, int datasize)
{
Wire.beginTransmission(id);
Wire.write(reg);
for (int i = 0; i < datasize; i++)
{
Wire.write(data[i]);
}
Wire.endTransmission();
}
void dataread(int id, int reg, int *data, int datasize)
{
Wire.beginTransmission(id);
Wire.write(reg);
Wire.endTransmission(false);
Wire.requestFrom(id, datasize, false);
for (int i = 0; i < datasize; i++)
{
data[i] = Wire.read();
}
Wire.endTransmission(true);
}
void airtemperature() //温度別ヒストグラム:最大sample数=Air温度
{ TMPHISmax=0; TMPHISCLR(); //時間をかけてrefresh 安定基準
for (int air=63;air>=0;air--)
{ TMPHISairdata=TMPDATS[air]; //TMP[350]にすると相対温度修正不要 TMPDATS[air]-250;NG
TMPHIS[TMPHISairdata]++; //0=<TMP<350 TEMP<400 配列確保NG 150<TEMP<400 0<配列<250
if (TMPHIS[TMPHISairdata]>TMPHISmax) {TMPHISmax=TMPHIS[TMPHISairdata]; TMPair=TMPHISairdata; //=TMPHISairdata+150;//
}
}
//**人の面積 TMPmax値のmin値(人のいないところのmax値)を探し それ以上の個数をHISTGRMで合計=人の面積
if (TMPmaxmin>TMPmax) TMPmaxmin=TMPmax;
TMPHISmanS=0; //init reset //maxmin+8以上の温度の個数を合計 air温度以上のhistgramの個数を合計:manが近ずくと増加
for ( int TMPHISman=349;TMPHISman > TMPmaxmin + 8;TMPHISman--) //温度:349からmaxmin+8まで:人温度スレシホールド設定まで個数を合計 TMPmaxminは温度データー配列温度計算はー150 +(スレシホールド)
{ TMPHISmanS=TMPHISmanS+TMPHIS[TMPHISman];
}
//Serial.println(TMPHISmanS);
}
// for (int tmp = 149; tmp > 50; tmp--)
// { if (TMPHIS[tmp] > TMPHISmax) {
// TMPHISmax = TMPHIS[tmp];
// TMPair = tmp;
// }
// }
//}
void TMPHISCLR() {
for ( int m = 349; m >= 0; m--) { //TMPHIS[350]で相対温度補正なし [150]NG [250] 150<TEMP<150+250=400
TMPHIS[m] = 0;
}
} //END
void objectscan()
{
digitalWrite(4,LOW); //digitalWrite(4,LOW); //SW checkの時だけkeyscan 4pin出力Lowにして D5 D6 D7 Pullupのlossを防ぐ
int sensorValchlk = digitalRead(5); //0:child lock
int sensorValalm = digitalRead(6); //0:alarm
int sensorValeco = digitalRead(7); //0:eco enegy saving
digitalWrite(4,HIGH);
if (sensorValeco == 0) eco(); //eco?
else if (sensorValchlk == 0) childlock(); //child lock?
else if (sensorValalm == 1) alarm(); //alarm?
} //END
void childlock() //IR POWERON
{ //TVOFFのとき2コマ以下ON 3コマ以上PiなしのSPEECH******************************
if (POWflg<=0) { // if (POWflg==0) { //off していて人がちいさくなったらon case POWlg
if (TMPHISmanS <= 2) { //2コマ以下だとON領域判断 chatter防止2~9 no action TMPmaxmin-140(温度で+10:2=4m)
//cdsOFF = analogRead(A0); //ONする前のcdsValue
for (int i = 0; i < 3; i++) {
irsend.sendSony(0xa90, 12); //0xa90,12= 22 POWON/OFF
delay(40);
}
POWflg=1; // POWflg=1;
pi(); //ピッ ON sound //delay(1000);
//cdsON = analogRead(A0); //ONした後のcdsValue
} //2コマ以下ON判断END
else {
speech(); //TVOFF & 3コマ以上なので speechで警告 PIはなし TVONで接近と区別
}
} //POWflg OFF END
else //TVONで11コマ以上=OFF 3~10コマ警告領域 2コマ以下TVONのまま ***************************************
{ if (POWflg>=1) { //onしていて人がきたらoff case POWflg
if (TMPHISmanS >= 11) { //11コマ以上あるとOFF領域に入った判断 /chatter防止2~9 no action TMPmaxmin-140(温度で+10:10=1m)
//cdsON = analogRead(A0); //OFFする前の cdsValue
for (int i = 0; i < 3; i++) {
irsend.sendSony(0xa90, 12); //0xa90,12= 22 POWON/OFF
delay(40);// delay(40);
}
POWflg=0;
pii();
speech(); //ピー― OFF sound
//cdsOFF = analogRead(A0); //OFFした後のcdsValue
//if (cdsOFF<cdsON) irsend.sendSony(0xa90,12); //ON OFF 逆だったので再度
}
else //**************************ALARM**************************************
{ if (TMPHISmanS>=3 ) { pi(); speech(); delay(500);} //pi(); //3コマ~10コマまでは警告領域判断
}//Object scan END
} //offcase POWflg END
} // POWflg else END
} //END
void pf()
{
}
void speech() {
digitalWrite(10,HIGH);
delay(500);
digitalWrite(10,LOW);
}
void pii() {
digitalWrite(11,HIGH); //FT:H
for (int s=600;s>0;s--) {
digitalWrite(13,HIGH);
digitalWrite(12,LOW);
delayMicroseconds(400);
digitalWrite(13,LOW);
digitalWrite(12,HIGH);
delayMicroseconds(400);
}
digitalWrite(11,LOW); //FT:L
}
void pi() {
digitalWrite(11,HIGH); //FT:H
for (int s=80;s>0;s--) {
digitalWrite(13,HIGH);
digitalWrite(12,LOW);
delayMicroseconds(200);
digitalWrite(13,LOW);
digitalWrite(12,HIGH);
delayMicroseconds(200);
}
digitalWrite(11,LOW); //FT:L
}
void pipi()
{ digitalWrite(11,HIGH); //FT:H
pi();
delay(100);
pi();
digitalWrite(11,LOW); //FT:L
}
void iron()
{
for (int i = 0; i < 3; i++) {
irsend.sendSony(0xa90, 12); //0xa90,12= 22 POWON/OFF
delay(40);
}
}
void iroff()
{
for (int i = 0; i < 3; i++) {
irsend.sendSony(0xa90, 12); //0xa90,12= 22 POWON/OFF
delay(40);
}
}
void eco() //void eco()
{
if ((POWflg<=0)&&(TMPHISmanS>=2)) { //POWOFFで人がいるのでIRON
pi();
iron() ;
POWflg=4; //POWflg=10; //人がいなくなってOFFするまでのWAIT時間設定 4秒
} //if END
if ((POWflg==1)&&(TMPHISmanS<2)) { //POWONで人がいないのでIROFF
pipi();
iroff(); //
POWflg=0;
} //if END
if ((POWflg>1)&&(TMPHISmanS<2)) { //人がいなくなってOFFするまでWait時間
POWflg--; //IROFFまでのWAIT時間
} //if END
} //END
void alarm()
{
if (TMPHISmanS>=2) {pi(); delay(100); pi(); delay(100); pi();delay(100); pi(); delay(1000);} //>=1 誤動作
}
投稿者の人気記事
-
syouwa-taro
さんが
2021/02/18
に
編集
をしました。
(メッセージ: 初版)
-
syouwa-taro
さんが
2021/02/18
に
編集
をしました。
(メッセージ: コンテスト応募TAG追加)
ログインしてコメントを投稿する