なお、後日譚も含めたレポートをnoteの方に書きましたので、よろしければご覧くださいませ。
我が家には2歳半の息子と3か月の娘がおり、子育ては日々戦争な状況です。子供と関わっている時間の長短もしんどさの一つの要因ではありますが、むしろ、ちょっと子供が寝ている間にあれをやろうと取り掛かったところ、急に泣き出して中断せざるを得ないといった予測のできなさも一つの要因ではないでしょうか?
夜泣きをセンサーで検出する
最初はセンサー系のbitを組み合わせて、赤ちゃんが泣くタイミングを検出しようとしました。具体的には、i20 sound triggerで赤ちゃんの泣き声らしき大声を検出し、i13 light sensorで一定以上の明るさなら(特に夜泣きの場合、いったん電気をつけておむつをチェックし、おしっこやウンチが確認できたら交換するので)夜泣きと判断する仕組みを実装しました。
夜泣き予測システムの材料
今回の材料は次の通りです。
- p1 power x 1 (またはp3 usb power), 関連するケーブルや電池
- i13 light sensor x 1
- i20 sound trigger x 1
- w6 arduino x 1 (+PCからのスケッチ流し込み用USBケーブル)
- w7 fork x 1
- o9 bargraph x 1
- o21 number x 1
- その他、mounting board x 1, screw driver x 1(センサ調整用)
これらのbitを次の写真に挙げるようにmounting board上に配置していきます。
プログラミング
Arduino bitにはこんなプログラムを流し込みます。
unsigned long SEC = 1000;
unsigned long MIN = SEC * 60;
unsigned long HOUR = MIN * 60;
unsigned long count = 0; // 起きた回数
unsigned long lastDetect1 = 0; // ・泣いたあとで
unsigned long lastDetect2 = 0; // ・部屋の電気をつける→起きた
unsigned long nextDetect = 3 * HOUR; // 次回起きそうなタイミング
unsigned long kizami = nextDetect / 1024; // p9 bargraph用補正値
unsigned long history[5] = {nextDetect, 0, 0, 0, 0};// 起きるまでの間隔履歴
unsigned long hIndex = 1; // 配列インデックス
// o21 numberを数字表示用に使うために渡す値
int numbers [] = {0,3,6,8,10,13,15,18,20,23,26,28,30,33,35,38,40,43,45,48,50,53,55,58,61,
64,66,69,71,74,76,78,81,84,86,89,91,94,96,99,102,104,106,108,111,114,116,
119,121,124,127,129,132,134,136,139,141,143,146,149,151,154,156,159,160,163,
166,169,171,173,176,179,181,184,186,188,190,193,196,199,202,205,208,210,212,
214,217,218,221,224,227,230,232,235,237,239,242,245,247,252,255};
void setup() {
pinMode(5, OUTPUT); // analog設定
pinMode(9, OUTPUT); // analog設定
analogWrite(5, 0);
analogWrite(9, 0);
}
void loop() {
Serial.begin(115200);
unsigned long now = millis();
int sound = analogRead(A0); // i20 sound trigger
int light = analogRead(A1); // i13 light sensor (light mode設定)
if (sound > 1000) { // 子供が泣いた?(設置環境ごとに調整要)
if (lastDetect1 == 0 || (now - lastDetect1) > 1 * HOUR) { // 初回または前回から1時間後以降なら
lastDetect1 = now; // 泣き出した
}
}
if (light > 600) { // 部屋が明るい?(設置環境ごとに調整要)
if ((lastDetect2 == 0 || (now - lastDetect2) > 1 * HOUR) && // 初回または前回から1時間後以降かつ
(now - lastDetect1) < 5 * MIN) { // 泣いてから5分以内なら
history[hIndex++] = now - lastDetect2; // 履歴に追加
if (hIndex >= 5) {
hIndex = 0;
}
lastDetect2 = now;
count++; // カウントアップして
analogWrite(5, numbers[count]); // o21 numberに表示
unsigned long total = 0;
int validCount = 0;
for (int i = 0; i < 5; i++) { // 過去5回の間隔履歴から
if (history[i] > 0) {
total += history[i];
validCount++;
}
}
nextDetect = total / validCount; // 平均を求めて次回の予測値とする
kizami = (nextDetect - now) / 1024;
}
}
unsigned long graph = now - lastDetect2; // 予測値までの時間に応じ
analogWrite(9, graph / kizami); // o9 bargraphで青→黄→赤表示する
/* デバッグ用 */
Serial.print("Sound:");
Serial.print(sound, DEC);
Serial.print("(");
Serial.print((lastDetect1 / SEC), DEC);
Serial.print("), Light:");
Serial.print(light, DEC);
Serial.print("(");
Serial.print((lastDetect2 / SEC), DEC);
Serial.print("), Count:");
Serial.print(count, DEC);
Serial.print(", Time:");
Serial.print((now / SEC), DEC);
Serial.print(", Graph:");
Serial.print(graph / kizami, DEC);
Serial.println();
}
実際に使用できるようにするには、sound triggerやlight sensorのsensitivityの調整やソースコード上の閾値設定が必要です。泣く・泣かない、明るい・暗いのメリハリのある環境であれば、そこそこ調整はつくかと思います。
実際に使ってみて
赤ちゃんの夜泣きはおっぱいが欲しいという空腹のサインだったり、おむつが濡れたという不快のサインだったりするわけですが、空腹サインに関しては、あらかじめ予測がつけば、大泣きする前におっぱいをあげることで、泣き声で起こされる感を減らせる一方、不快サインに関しては、おっぱいと違って、おむつが濡れる前に取り換えても何の意味もないので、結局は泣き出すのを待つしかないという結論に至りました。保育園なんかだと一人一人の赤ちゃんの状況を見るうえでお役に立てないかな、と思いつつも、現状の自動検出の仕組みは適用できないので、シンプルに泣いたらなり、ミルクを上げたらなり、おむつを替えたらボタンを押すくらいの仕組みで十分な気がします。
実際には下の子は生後3か月になり、夜の授乳タイミングも夜寝てから朝起きるまで1回あるかないかになったので、本センサもお役御免かと思いきや、上の子のトイレトレーニングに使えそうな状況になってきました。今度はセンサを使わず、おしっこ出た、うんち出たタイミングで自分でボタンを押してもらう、という入力で、次のトイレを楽しみながらゲーム感覚で促してあげることができそうだと睨んで、次期バージョンの作成にこれから取り掛かるところです。
最後ですが、LEDというか表示系が暗いお部屋ではまぶしいくらいに明るいので、薄い紙で覆う等、赤ちゃんの眠りを妨げない環境づくりも必要です。
それではまたどこかでお会いしましょう。さようなら!