Arduinoで作るサプリメント飲み忘れ防止システム：重量センサとRTCを活用した実用例

こんにちは、記事をご覧いただきありがとうございます！
エンジニアのまるさんかく（@Marusankaku_E）と申します。

今回は、**Arduino Nano**を使用してサプリメントの飲み忘れを防止するシステムを作成しました。

## きっかけ

毎朝欠かさず飲んでいるサプリメントがあるんですが、ついつい飲み忘れてしまうことがあります。
慌ただしく朝を過ごしていると、ついサプリを飲まなきゃという意識がなくなり、そのまま職場へ...ということが結構な頻度で発生します。
こうした飲み忘れをなくすために、**一目で飲んだかどうかが分かる仕組み**が欲しいと思い立ち、このシステムを開発しました。

## 実現したいこと

- **サプリを飲んでいない状態を通知する**
- **サプリを飲んだら完了を表示する**
- **日付が変わると通知をリセットする**

これらの要件を満たすシステムを目指しました。

## システムの概要

実現したい内容を踏まえ、下記システムを構築しました：

1. **重量センサ**：サプリメントのボトルを計量
    - サプリが取り出されると重さの変化を検知し、飲んだ判定を実施
2. **RTCモジュール**：時刻管理
    - 日付が変わると飲み忘れ判定をリセット
3. **LED表示**：状態を可視化
    - サプリを飲んでいない間は点灯し、飲むことで消灯

### 動作の流れ
- サプリのボトルが規定の重さを下回ると「飲んだ」と判定し、LEDを消灯
- 日が変わると飲み忘れ判定が自動リセットされ、LEDが点灯


## 必要な部品とツール

### ハードウェア

- **Arduino Nano**
  - システム全体の表示
- **HX711 重量センサモジュール**
  - サプリの取り出しを検知
::: note warn
重量センサでは両端のひずみを使用して重量を量ります。
そのため、センサのみのものでなく、下記のようなテーブル付きのものがおすすめです。
:::

https://www.amazon.co.jp/HX711%E3%83%AD%E3%83%BC%E3%83%89%E3%82%BB%E3%83%AB%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-24%E4%BD%8D%E7%B2%BE%E5%BA%A6AD%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-%E5%9C%A7%E5%8A%9B%E3%82%BB%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-Arduino-%E9%87%8D%E9%87%8F%E3%82%BB%E3%83%B3%E3%82%B55KG/dp/B07JL7NP3F/ref=sr_1_1_sspa?dib=eyJ2IjoiMSJ9.Rjdjej0letLkSz_0Qgmuxi06o6USBBl4gyAznpqYczY3PCxhMsvlciQtheNNG-1Odd9Fd_dWiUEIC03KvT4ir-acHAsxPVWBatPG-W1IVDiHlXzpXpgNxhfm00o1nxjgk2RTQGqXbZgNku84K_X5yad7ppWHSy3KD1kynqOwTyFDeY_q9drnK4gL4CWwNlIVF49jdKHG2iaX-38nSvbX3Gx7yixd1hwmTq8jJRmAyMa2X7RD23RoFV0ZljL6c2tteTr3H_CB9rXFknpnwX8B78Wy1s9LlY_Zo9IOA7xidew.b4P6NZ_c2esF074UjAVV3SdVqQwaaMcMj6WZGpxJ5Yc&dib_tag=se&keywords=hx711&qid=1737849721&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&psc=1

- **DS3231 RTCモジュール**
  - 時刻・日付の管理

https://www.amazon.co.jp/VKLSVAN-AT24C32-RTC%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-%E3%83%AA%E3%82%A2%E3%83%AB%E3%82%AF%E3%83%AD%E3%83%83%E3%82%AF%E3%82%BF%E3%82%A4%E3%83%9E%E3%83%BC%E3%83%A1%E3%83%A2%E3%83%AA%E3%83%9C%E3%83%BC%E3%83%89%E3%83%93%E3%83%BC%E3%83%88DS1307-Arduino%E3%81%AB%E5%AF%BE%E5%BF%9C/dp/B081GXLB4H/ref=sr_1_7?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=2GHX7THZLHEFN&dib=eyJ2IjoiMSJ9.zEhi2LatTcbUWkTcy9PA_nYpWEJeugo19tqc1figlky4CBGiob-nT-9uHq2fD-BXcq2XLDUBjPBRGcV7K2F8hQ12DOhFPceFFIi5cuUZlGVKdfLld33YbC68BGn8nDvufiuKm6PuInlP1UVDvQ3etC2eRvFrKXzHHUHomqE7U2Nx7f6QxioQTVIAibvizXQB-UcoLSOCzaLFlz17FeGM_6fr2KNRrUWu1Q5G1f4wSjq_pTs3-I5YspbG2basSZEu6WRByXeMYaExkjNv4YmcMDR93mZrd6sWjdbPytOhbfeKVG0hf2tSOvdu5sLXg_YaoQRjBXnyJlIEMoJDAUWmgwUVS0a6dpV-_veXpxKi4OpysaV8SCODszT1wJliy4IWbSs2LMCab5vnzigkxg4Cdn1ovW5xCJ8AZ7uUD9PJWjL01XTSKS5nwnhrtgH-aqAP.PHzvYSXAnFl6u0ztlwLzx_aiwXI7gtp2uI3f5PZQnbs&dib_tag=se&keywords=ds3231&qid=1737849820&sprefix=ds3231%2Caps%2C183&sr=8-7
  
- **LED（飲み忘れ通知用）**
  - 飲んだかどうかの状態を表示
- **ケース**
  - 上記マイコンやモジュールを格納
  ※今回はケースをモデリングし、3Dプリンタで印刷しました
::: note warn
ケースは無くても別に問題ないです。
:::

### ソフトウェア

- **Arduino IDE**
  - 開発・プログラム書き込みに使用
- **Fusion360**
  - ケースのモデリングに使用

## 配線図

以下にFritzingで作成した配線図を記載します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692990/f9674315-ee9e-95e2-e4c0-758225f7ad29.png" height=50>

##  ソースコード
``` Arduino:SupplementReminderSystem.ino
/*
 * サプリメント飲み忘れ防止システム (Arduino Nano用)
 * 
 * 概要:
 * - HX711重量センサでボトルの動きを検知。
 * - DS3231 RTCモジュールで正確な時刻を管理。
 * - 飲み忘れ時にLEDを点灯し、飲んだ場合に消灯。
 * 
 * 必要な部品:
 * - HX711重量センサモジュール
 * - RTCモジュール（DS3231）
 * - LED
 * - Arduino Nano
 */

#include <HX711.h>
#include <RTClib.h>  // RTC用ライブラリ

// ピン定義（Arduino Nano用に調整）
#define HX711_DT 3     // デジタルピン3 (HX711データ)
#define HX711_SCK 2    // デジタルピン2 (HX711クロック)
#define LED_PIN 4      // デジタルピン4 (LED出力)

// インスタンス作成
HX711 scale;        // 重量センサモジュール
RTC_DS3231 rtc;     // RTCモジュール

float threshold = 50.0;          // 重量しきい値 (適宜調整)
bool isWeightDetected = false;  // 飲用動作判定フラグ
float calibration_factor = -250; // 校正値 (適宜調整)

unsigned long lastStableTime = 0;    // 最後に安定した時間を記録
const unsigned long debounceDelay = 3000; // 5秒間安定しているか確認

void setup() {
  Serial.begin(9600);

  // HX711の初期化
  scale.begin(HX711_DT, HX711_SCK);
  scale.set_scale(calibration_factor);  // キャリブレーション値を調整
  scale.tare();                         // 初期のゼロ点校正

  // RTCモジュールの初期化
  if (!rtc.begin()) {
    Serial.println("RTCモジュールが見つかりません。");
    while (1);  // 無限ループで停止
  }

  // RTCの正確な動作を確認（必要ならば以下のコードを利用して時刻を設定）
  // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // 現在のPC時刻を設定

  // LEDの初期化
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  // 現在時刻を取得
  DateTime now = rtc.now();

  // RTCの時刻をシリアルモニタに出力
  Serial.print("Current Time: ");
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.day(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.println(now.second(), DEC);

  // 指定時刻になったらLEDを点灯（飲み忘れ通知）
  if (now.hour() == 0 && now.minute() == 0 && !isWeightDetected) {
    digitalWrite(LED_PIN, HIGH);
  }

  // 重量を取得してシリアルモニタに出力
  float weight = scale.get_units(10);
  Serial.print("Weight: ");
  Serial.println(weight);

  // 重量がしきい値を下回った場合のチェック（安定性確認を含む）
  if (weight < threshold) {
    // 安定した期間が経過したか確認
    if (millis() - lastStableTime > debounceDelay) {
      if (digitalRead(LED_PIN) == HIGH) {
        digitalWrite(LED_PIN, LOW);   // LEDを消灯（飲用済み）
        isWeightDetected = true;     // 飲用済みとしてフラグ更新
      }
    }
  } else {
    // 安定性判定をリセット
    lastStableTime = millis();
  }

  // 深夜 23:59 にリセットして次の日の判定を準備
  if (now.hour() == 23 && now.minute() == 59) {
    isWeightDetected = false;  // 飲用判定をリセット
  }

  delay(1000);  // 定期的な更新（1秒ごと）
}

```

## 実際の動作

### 通常時の挙動
- 日付変更後、LEDが点灯し、「サプリ未飲」の状態を通知

    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692990/191b2e80-a73a-be0e-b8cc-f3d0ba2050dc.jpeg" height=50>


### サプリ摂取時の挙動
- サプリのボトルが持ち上げられると、重量センサが値を検出し、LEDが消灯
    
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3692990/cb2e9b12-2c7a-e8e3-a95e-49c0c5be2a13.jpeg" height=50>


## まとめ

今回はArduino Nanoを使用して、**サプリメント飲み忘れ防止システム**を作成しました。
見た目はアレですが、普通に使いやすくサプリの飲み忘れが減りました。
なにより、LEDの主張が激しくボトルを下ろさない状態のままだとすごい気になります。
Wi-Fiモジュールを追加して、PCやスマホに飲んだことを通知するように変更するのも面白いかもしれません。

## 参考

https://zenn.dev/suzuky/articles/7e338f8368cc3e

https://randomnerdtutorials.com/arduino-load-cell-hx711/