Arduino×Python×Kerasで実現する高精度雨予報システムの構築
必要な部品と材料
| 部品 | 数量 |
|---|---|
| 小型プラスチックケース(蓋着脱式、ネジ止め推奨)11×7×5cm程度 | 1 |
| 単3電池ホルダー(3本用) | 1 |
| 単3ニッケル水素充電池 | 3 |
| 6V小型ソーラーパネル | 1 |
| Arduino Pro Mini 328 - 5V/16MHz | 1 |
| ダイオード 1N4004(逆流防止用) | 1 |
| 汎用NPNトランジスタ + 1kΩ抵抗(周辺機器電源スイッチ用) | 1 |
| 雨センサー | 1 |
| HC-12 シリアル通信モジュール | 1 |
| HC-12 USBシリアルモジュール(基地局側) | 1 |
| BME280 大気センサー(温湿度・気圧) | 1 |
| BH1750 照度センサー | 1 |
| PCB、配線、ハンダ、コネクタ類、接着剤 | 1式 |
| 3.3Vレギュレータ | 1 |
必要な工具
- USB-シリアル変換アダプタ(FT232RL) - Pro Mini書き込み用
- Arduino IDE
- ドリル、細工用ノコギリ、ドライバー、ハンダゴテ、ニッパー
プロジェクト概要
このプロジェクトの最終目標は、6時間先の雨の有無(Yes/No)を予測することです。既存のチュートリアルで完結したものが見つからなかったため、気象観測装置の自作からデータ収集、蓄積、機械学習によるモデル構築、予測・通知まで全工程をカバーします。
- 気象観測装置を自作:ソーラーパネルで完全オフグリッド、極低消費電力(数十μA/h)
- 装置をプログラミング:10分ごとにデータ取得・送信
- 基地局でデータ収集・蓄積:データベースに保存
- ニューラルネットワーク(Keras)で学習:Pandasでデータ前処理後、雨予測モデルを訓練
- 予測・通知:今後6時間の雨予測をメール通知


約600日分の気象データで学習させたモデルでは、パラメータによりますが約80%の精度で6時間先の雨予測が可能です。外部の気象APIや機械学習APIを使わず、実用的なエンドツーエンドのシステムをゼロから構築します。
ステップ1:部品と工具の準備
上記の部品リストと工具を用意します。必要なスキル:半田付け、基本的なArduinoプログラミング、Linuxサービス設定、一般的なプログラミングスキル。
ステップ2:気象観測装置の組み立て
装置は以下の4要素で構成:
- ソーラーパネル貼り付け済みケース
- 電子部品実装済みPCB
- 電池ホルダー(内蔵)
- BME280、照度センサー、雨センサー(外部配置)
ケースに4つの穴を開け(ソーラー配線用1つ、センサー用3つ)、パネルを接着して配線を内部に通します。PCBにはArduino、HC-12、3.3Vレギュレータ、ダイオード、トランジスタ、抵抗、コネクタ類を実装します。重要:ArduinoのオンボードLEDは除去するか片足をカットしてください。LEDが大量の電力を消費します。
センサー類を外部からコネクタ接続し、雨センサーは長めの配線で別置きします。設置場所は雨雪を避けられる場所を選び、強力な両面テープ等で固定します。
ステップ3:Arduinoコード
観測装置の役割:10分ごとにセンサーデータを基地局へ送信すること。
プログラムの流れ:
- センサー読み取り(湿度、温度、気圧、雨、照度、電圧)
- 第2ソフトウェアシリアルでエンコード送信(形式:
H1:78|T1:12|PS1:1022|L1:500|R1:0|V1:4010|) - 周辺機器(センサー、通信モジュール)の電源OFF
- Arduinoをスリープモード(10分、50μA以下)
- 電源ONして1〜4を繰り返し
電圧が4.2V以上なら通常のdelay()でスリープし、過充電を防ぎます。
主要ライブラリ(事前インストール必須)
スケッチ(抜粋)
#include "LowPower.h"
#include "SoftwareSerial.h"
#include "Wire.h"
#include "Adafruit_Sensor.h"
#include "Adafruit_BME280.h"
#include "BH1750.h"
SoftwareSerial serialComm(4, 5); // RX, TX
Adafruit_BME280 bme;
BH1750 lightMeter;
const byte rainPin = A0;
byte sensorsCode = 1;
int voltageDeepSleepThreshold = 4200;
const byte peripherialsPowerPin = 6;
struct sensorData {
byte humidity;
int temperature;
byte rain;
int pressure;
long voltage;
int light;
} sensors;
void setup() {
Serial.begin(9600);
serialComm.begin(9600);
pinMode(peripherialsPowerPin, OUTPUT);
digitalWrite(peripherialsPowerPin, HIGH);
delay(500);
if (!bme.begin()) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1) { customSleep(100); }
}
Serial.println("Initialization finished succesfully");
delay(50);
}
void loop() {
updateSenzors();
transmitData();
customSleep(75); // 75×8秒 = 600秒 = 10分
}
void updateSenzors() {
bme.begin();
lightMeter.begin();
delay(300);
sensors.temperature = bme.readTemperature();
sensors.pressure = bme.readPressure() / 100.0F;
sensors.humidity = bme.readHumidity();
sensors.light = lightMeter.readLightLevel();
sensors.voltage = readVcc();
sensors.rain = readRain();
}
void transmitData() {
// シリアルバッファクリア後、各センサー値を送信
transmitSenzorData("T", sensors.temperature);
transmitSenzorData("H", sensors.humidity);
transmitSenzorData("PS", sensors.pressure);
transmitSenzorData("L", sensors.light);
transmitSenzorData("V", sensors.voltage);
transmitSenzorData("R", sensors.rain);
}
void customSleep(long eightSecondCycles) {
if (sensors.voltage > voltageDeepSleepThreshold) {
delay(eightSecondCycles * 8000);
return;
}
digitalWrite(peripherialsPowerPin, LOW);
for (int i = 0; i < eightSecondCycles; i++) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
}
digitalWrite(peripherialsPowerPin, HIGH);
delay(500);
}
long readVcc() {
// 内部1.1V基準電圧でVccを測定
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
delay(2);
ADCSRA |= _BV(ADSC);
while (bit_is_set(ADCSRA, ADSC));
uint8_t low = ADCL;
uint8_t high = ADCH;
long result = (high << 8) | low;
result = 1125300L / result; // 1.1*1023*1000
return result; // mV単位
}
完全なコード:GitHubリポジトリ
ステップ4:基地局(サーバー)の準備
Linuxマシン(PC、ラップトップ、開発ボード等)にHC-12 USBモジュールを接続し、常時稼働させて10分ごとのデータを受信します。私はUbuntu 18.04のラップトップを使用しました。
- Anacondaインストール:Python環境管理用
- MongoDBインストール:時系列データ保存用(スキーマレスで扱いやすい)
- プロジェクトクローン:
git clone https://github.com/danionescu0/home-automation.git - Conda環境構築:
主なパッケージ:Keras、Pandas、PyMongo、scikit-learncd weather-predict conda create --name weather python=3.6.2 conda activate weather pip install -r requirements.txt - 設定ファイル(config.py)調整:MongoDBホスト/ポート、シリアルポート(
/dev/ttyUSB0等)
ステップ5:実運用
テストデータのインポート
mongoimport -d weather -c weather_station --file sample_data/weather_station.json
※ 自分のデータと混ぜるとハードウェア差異で精度が下がる可能性があります。
新規データ収集
conda activate weather
python serial_listener.py
# 10分ごとにデータ受信を確認
予測モデルの訓練
python train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 8 --hour-granularity 6
--days_behind:過去何日分のデータを使用するか--test-file-percent:テストデータの割合--hour-granularity:何時間先を予測するか(6時間)--datapoints-behind:過去何データポイントを参照するか
グラフ表示
python graphs --days-behind 10
雨予測とメール通知
python predict.py --datapoints-behind 8 --hour-granularity 6 \
--from-addr gmail_address --from-password gmail_password --to-addr destination_email
Gmailで「安全性の低いアプリの許可」をONにする必要があります。cronに登録すれば定期実行可能です。
ステップ6:仕組みの解説
1. プロジェクト全体像
観測装置(データ収集・送信のみ)と基地局(蓄積・学習・予測)を分離する利点:
- 観測装置の低消費電力化・小型化・携帯性確保
- 複数装置の配置による精度向上・スケーラビリティ
- 低コストで冗長化可能
データベースはMongoDBを採用。10分ごとのデータポイントをBSON形式で保存。
2. 機械学習の基本概念
ニューラルネットワークは生物のニューロンを模倣。入力層→隠れ層→出力層で信号を伝播し、バックプロパゲーションで重みを調整して学習します。教師あり学習(入力と正解ラベルのペアで学習)を採用。
3. データ準備(最重要ステップ)
- 生データ取得(MongoDBからPandas DataFrameへ)
- データクリーニング(欠損値除去)
- データグループ化:10分データを6時間区間で集約し、各センサーの最小/最大/平均/パーセンタイル/上昇/下降/一定回数を算出
- データ拡張:過去8データポイント(48時間分)の特徴量を追加(時系列の文脈を与える)
- 目的変数
has_rain作成:6時間区間の雨量平均>0.1mmなら1、 else 0 - 現在のデータポイント情報を除外(過去情報のみで予測させる)
- 訓練/テスト分割(scikit-learn)、入力/出力分離、標準化(StandardScaler)
4. Kerasによるニューラルネットワーク構築
from keras.models import Sequential
from keras.layers import Dense, Dropout
input_dim = X.shape[1]
model = Sequential()
model.add(Dense(input_dim//2, activation='relu', input_dim=input_dim))
model.add(Dropout(0.05))
model.add(Dense(input_dim//2, activation='relu'))
model.add(Dropout(0.05))
model.add(Dense(1, activation='sigmoid')) # 二値分類
model.compile(optimizer='rmsprop', loss='mean_absolute_error', metrics=['accuracy'])
model.fit(X, y, batch_size=1, epochs=50)
model.save('model_file_name')
活性化関数(ReLU, Sigmoid)、損失関数、オプティマイザ、バッチサイズ、エポック数等はデータセットに合わせてチューニングすべきです。--grid-searchオプションで自動探索も可能。
5. 今後の改善点
- 風速/風向センサー追加(重要な気象要素)
- UV、ガス、粒子センサーの実験
- 複数観測点の設置で空間平均化
- 数年分のデータ蓄積
- 外部気象データ(Weather Underground等)との融合
- LSTM等の時系列特化モデルの試行
ステップ7:ボーナス - 公式気象データセットの活用
より信頼性の高いデータで精度向上を図るため、Dark Sky API(現Apple WeatherKit)の過去データを試しました。風速、突風、UV指数、視程等の豊富なパラメータを含みます。
- APIキー取得後、
python download_import/darksky.py -d 1000でデータ取得(無料枠は1日1000リクエスト) - または私の収集済みデータ(ブカレスト)をインポート:
mongoimport -d weather -c darksky --file sample_data/darksky.json python train.py -d 2000 -p 20 -dp 4 -hg 6 --data-source darkskyで学習
結果:全体精度が約80%→約90%に向上。雨の日の予測精度も改善。データセットの質がモデル性能を大きく左右することが確認できました。
回路図

Arduinoスケッチ完全版:GitHub
製造プロセス
- Raspberry PiとPythonでリモート温度センサーを構築 – ステップバイステップガイド
- Arduino Nano RP2040で作るDIY Photoshopコントロールコンソール
- Python連携で信頼性向上: Arduino RFID勤怠管理システム
- Arduinoと1Sheeldで作る万能Androidリモコン──IR制御で家電を一括操作
- Arduinoとスマホで作るスマート電圧計 – 簡単DIYプロジェクト
- Arduinoで作る赤外線心拍センサー:低コスト・リアルタイム波形表示のステップバイステップガイド
- Arduino UNOで周波数とデューティサイクルを高精度測定
- ArduinoとNokia 5110ディスプレイで自作電圧計:ステップバイステップガイド
- Arduino超音波センサーとProcessingで作るリアルタイム距離測定ソナー
- Bolt IoTとArduino UNOでLED輝度をシームレス制御
- Python os.rename()でファイル・ディレクトリをリネーム:ステップバイステップガイド