12
3

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.

[M5StickC] 子どもの歯磨き応援ツール

Last updated at Posted at 2019-12-08

タイトルなし.png

TL;DR(まとめ)

  • M5StickC, Raspberry Pi Zero W, Google Home Mini を用いて歯磨き応援ツールを開発しました。
  • M5StickCは加速度センサー、内蔵バッテリー、Wi-Fi、モニタ、スピーカーHAT(後付け)ありでPoCに最適なデバイスでした。
  • PoCによって作り手がこだわった機能と、ユーザーに刺さる機能は必ずしも一致しないことを学びました。

きっかけ

  • M5StickC × 加速度センサーで何か面白いものを作る、というお題が出た。
  • 最近子供が歯磨きを面倒くさがっている。

システム構成

タイトルなし.png

  1. 歯ブラシを 1 往復したら( M5StickC の加速度センサーで Y 軸方向に一定以上の差分が出たら) 1 回カウントする。
  2. カウントごとに SPK HAT から音を鳴らす。(プッ!プッ!)
  3. 10 回ごとに少し高めの音を鳴らす。(ピッ!)
  4. 一定回数ごとに LCD モニターに "Over XX times!" と表示させる。
  5. 規定回数を超えたら Google Home に激励(あるいはお疲れ様)のメッセージを喋ってもらう。

構築手順(ブラッシュアップのアドバイス大募集中です!)

M5StickC スケッチ

(2019/12/12追記)HTTP / POST した後に http.end(); する1行を追加

cheer_brushing.ino
#include <M5StickC.h>
#include <WiFiClientSecure.h>
#include <ArduinoJson.h>
#include "config.h"
#include <HTTPClient.h>

// Speaker用
const int servo_pin = 26;
int freq = 50;
int ledChannel = 0;
int resolution = 10;

// getAccelData用
float accX = 0;
float accY = 0;
float accZ = 0;
float previous_accY = 0;
float current_accY = 0;

// ブラッシングカウント用
int brushing_count = 0;
// カウントフラグ
int count_flag = 0;
// Google Homeが喋るセリフ
char *nodered_json = "";
// HTTP Response
int status_code = 0;

WiFiClientSecure wifiClient;
HTTPClient http;

void setup_wifi() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("connecting to ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, password);

    if (WiFi.waitForConnectResult() != WL_CONNECTED) {
      // Wi-Fiアクスポイントへの接続に失敗したら5秒間待ってリトライ
      Serial.println("failed to connect");
      delay(5000);
      return;
    } else {
      Serial.print("WiFi connected: ");
      Serial.println(WiFi.localIP());
      //M5.Lcd.setTextSize(1);
      //M5.Lcd.println(WiFi.localIP());
    }

    //wifiClient.setCACert(test_ca_cert);
    randomSeed(micros());
  }
}

// 初期設定
void setup() {
  M5.begin();
  M5.Axp.ScreenBreath(8);     // 画面の輝度(MIN:7~MAX:15)
  M5.Lcd.setRotation(3);      // 左を上にする
  M5.Lcd.setTextSize(2);      // 文字サイズを2にする
  M5.Lcd.fillScreen(BLACK);   // 背景を黒にする

  //シリアル接続速度指定
  Serial.begin(9600);

  //Wi-Fi接続
  setup_wifi();

  // 6軸センサー
  M5.MPU6886.Init();

  // Speaker用
  ledcSetup(ledChannel, freq, resolution);
  ledcAttachPin(servo_pin, ledChannel);
}

// Node-REDにWebhooks
void nodered_post(int counts) {
  Serial.println(counts);
  //const char *nodered_json = "{\"message\":\"" + msg + "\"}";
  if ( counts == 50) {
    nodered_json = "{\"message\":\"まだまだがんばれ\"}";
  } else if ( counts == 100) {
    nodered_json = "{\"message\":\"もう少しだよ\"}";
  } else if ( counts == 150) {
    nodered_json = "{\"message\":\"はい、お疲れ様でした\"}";
  }
  Serial.println(nodered_json);
  http.begin( nodered_server, 1880, "/hamigakimsg");
  http.addHeader("Content-Type", "application/json" );
  status_code = http.POST((uint8_t*)nodered_json, strlen(nodered_json));
  Serial.println(status_code);
  http.end();
}

// ループ処理
void loop() {
  
  // 加速度取得(変化前)
  M5.MPU6886.getAccelData(&accX,&accY,&accZ);
  previous_accY = accY * 1000;

  // 加速度表示
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.println(previous_accY);

  // 100ミリ秒待つ
  delay(100);

  // 加速度取得(変化後)
  M5.MPU6886.getAccelData(&accX,&accY,&accZ);
  current_accY = accY * 1000;

  // Y軸加速度の差分が400以上の場合
  if ( current_accY - previous_accY > 400) {
    // Beep音発行(10階ごとにちょい高めの音鳴らす)
    if ( brushing_count % 10 == 0) {
      ledcWriteTone(ledChannel, 1500);
    } else {
      ledcWriteTone(ledChannel, 1000);
    }
    delay(10);
    ledcWriteTone(ledChannel, 0);

    // ブラッシング回数インクリメント
    brushing_count++;
  }

  // ブラッシング回数表示
  M5.Lcd.setCursor(0, 16);
  M5.Lcd.println(brushing_count);
  
  // ToDo 一定回数超えたらWebhooksしてGoogle Homeしゃべらす。
  if ( brushing_count % 50 == 0 && brushing_count !=0 && count_flag == 0) {
    // 一定回数超えたことを表示する。
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setCursor(0, 32);
    M5.Lcd.println("over " + String(brushing_count) + " times!!");

    // Google Home しゃべらす。
    nodered_post(brushing_count);

    // ループ抑止フラグを立てる
    count_flag = 1;
  }

  // 51,101,151回目の時にフラグを初期化する。
  if ( brushing_count % 50 == 1) {
    count_flag = 0;
  }

  // ボタン全体の状態更新
  M5.update();
  // ボタンA(M5)が押されたらカウンタリセット&画面リセット
  if ( M5.BtnA.wasPressed() ) {
    brushing_count = 0;
    M5.Lcd.fillScreen(BLACK);
  }
}
config.h
// Wi-Fiアクセスポイント
const char *ssid = "XXX";
const char *password = "XXX";

// Raspberry pi Node-RED
const char *nodered_server = "192.168.XXX.XXX";

Google Home周り(技術要素:Node-RED, google-home-notifier)

Raspberry Pi Zero W にNode-RED, google-home-notifier をインストールし、
Node-REDを以下の通り設定します。

image.png

  1. M5StickCからのHTTPリクエストを受け付ける http in ノードを作成する。
  2. Function ノードにて、 google-home-notifier を呼びだす。
  3. http request ノードで状態コード 200 を返す。

function ノードで google-home-notifier を呼べるよう、メインの settings.js 内で、 functionGlobalContext を定義します。

~/.node-red/settings.js
functionGlobalContext: {
    googlehomenotifier:require('[google-home-notifierパス]/google-home-notifier'),
},

function ノードは以下の記述だけで msg.payload.message に渡されたメッセージを Google Home が喋ってくれます。

functionノード
const googlehome = context.global.googlehomenotifier;
const language = 'ja';

googlehome.device("GoogleHome", language);
googlehome.ip("XXX.XXX.XXX.XXX");
googlehome.notify(msg.payload.message, function(res) {
  console.log(res);
});

return msg;

所感

  • 子どもに使ってもらったところ、想像以上に楽しそうに歯磨きしてくれてます。
  • 作った本人としては、歯磨きの回数に応じて Google Home が喋るところがポイントでした。
  • 使う側としては、音が出たり、歯磨き回数が表示される方が気に入ったようです。
12
3
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
12
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?