工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Arduino、Python、Kerasを使用したDIY雨予測

コンポーネントと消耗品

取り外し可能な蓋付きの小さなプラスチックの箱(私のものにはネジがあります)
× 1
3つのAAAバッテリーホルダー
× 1
3つのAAA充電式バッテリー
× 1
6V小型ソーラーパネル
× 1
SparkFun Arduino Pro Mini 328-5V / 16MHz
× 1
1N4004ダイオード
× 1
汎用トランジスタNPN
× 1
雨センサー
× 1
HC-12シリアル通信モジュール
× 1
HC-12USBシリアルモジュール
× 1
SparkFun大気センサーブレイクアウト-BME280
× 1
BH1750
× 1
PCB、ワイヤー、はんだ、KF301-2Pプラグインスクリューコネクター、オスとメスのPCBコネクタ、接着剤
× 1
3.3Vレギュレーター
× 1

必要なツールとマシン

USB-シリアルFTDIアダプターFT232RL
ドリル
はんだごて(汎用)
ドライバー

このプロジェクトについて

このプロジェクトについての最初のいくつかの言葉は、動機、関連するテクノロジー、そして私たちが構築しようとしている最終製品です。

したがって、ここでの大きな目的は、明らかに将来の雨を予測することです(6時間試してみます)。予測はyesまたはno(プログラミング用語ではブール値)になります。この問題に関するチュートリアルを検索しましたが、すべての点で完全なものは見つかりませんでした。ですから、私はこれをまったく新しいアプローチに取り入れ、あらゆる側面に取り組みます。そのために、次のことを行います:

  • ビルド ウェザーステーション自身。ステーションは、ソーラーパネルと非常に低電力モード(数十マイクロアンペア時)で完全にオフグリッドである必要があります
  • プログラム ステーションはデータを収集し、10分ごとに基地局に送信します
  • 収集 基地局のデータを(データベースに)保存します
  • ニューラルネットワークの使用 (Kerasライブラリ)およびpandasなどの他のPythonライブラリは、データをフィルタリング、クリーンアップ、前処理してから、ニューラルネットワークにフィードして、雨が降るかどうかを予測するための「モデル」をトレーニングします。
  • 最後に予測 次の6時間に雨が降り、メールでユーザーに通知するかどうか

私は個人的にこの気象観測所を使用してデータを収集しました(必要に応じて、次の手順でデータをダウンロードできます)。わずか約600日間の気象データで、システムは、それほど悪くないパラメータに応じて、約80%の精度で、次の6時間に雨が降るかどうかを予測できます。

このチュートリアルでは、降雨量を最初から予測するために必要なすべての手順を説明します。外部の天気や機械学習APIを使用せずに、実用的な仕事をする最終製品を作成します。その過程で、メンテナンスなしで長期間にわたって実際にデータを収集する実用的な気象観測所(低電力でグリッド外)を構築する方法を学びます。その後、ArduinoIDEを使用してプログラムする方法を学びます。基地局(サーバー)上のデータベースにデータを収集する方法。そして、データを処理する方法(Pandas)とニューラルネットワークを適用する方法(Keras)、そして降雨量を予測する方法。

ステップ1:ステーションを構築するための部品とツール

パーツ:

1.取り外し可能な蓋付きの小さなプラスチックの箱(私のものにはネジがあります)。ボックスのサイズは、小さなコンポーネントやバッテリーを収めるのに十分な大きさである必要があります。私の箱は11x 7 x 5cmです

2.3つのAAAバッテリーホルダー

3.3つのAAA充電式バッテリー

4.6V小型ソーラーパネル

5. Arduino Pro Mini 328p

6.ダイオード、1N4004(バッテリーからパネルへの逆電流を防ぐため)

7.小さなNPNトランジスタと1k抵抗(コンポーネントの電源のオンとオフを切り替えるため)

8.レインセンサー

9.HC-12シリアル通信モジュール

10. HC-12 USBシリアルモジュール(ベースステーション用)

11. BME280ボッシュセンサーモジュール(湿度、温度、圧力用)

12.BH1750光検知モジュール

13. PCB、ワイヤー、はんだ、KF301-2Pプラグインスクリューコネクター、オス&メスPCBコネクター、接着剤

14.3.3Vレギュレーター

15.ベースステーション:PC、または常時稼働している開発ボード。データを収集し、雨予測モデルをトレーニングし、予測を行うことが役割です

ツール:

1. Arduino ProMiniをプログラムするためのUSB-シリアルFTDIアダプターFT232RL

2. Arduino IDE

3.ドリル

4.ファインブレードソー

5.ドライバー

6.はんだごて

7.ワイヤーカッター

スキル:

1.はんだ付け、このチュートリアルを確認してください

2.基本的なarduinoプログラミング

3. Linuxサービスの構成、パッケージのインストール

4.いくつかのプログラミングスキル

ステップ2:ウェザーステーションを構築する

気象観測所は、次のコンポーネントのセットで構成されています。

1。 ソーラーパネルが接着された箱

2 。電子機器を内蔵したPCB

3。 バッテリーホルダーも内側にあります

4。 BME280と外側の光と雨のセンサー

1。 ボックスには4つの穴が必要です。1つはソーラーパネルワイヤー用で、他の3つは外側に配置されるセンサー用です。最初に全体をドリルします。オスとメスのワイヤーが突き出てセンサーに到達するのに十分な大きさである必要があります。全体に穴を開けたら、パネルをボックスの片側に接着し、ワイヤーを内側の穴に通します

2。 PCBは、arduino、HC-12、3.3Vレギュレーター、ダイオード、トランジスター、抵抗器、および2つのKF301-2Pを保持します

  • 最初に2つのメスPCBコネクタをarduinoのPCBにはんだ付けし、オスPCBコネクタをarduinoにはんだ付けして、arduinoをPCBに配置します
  • arduino LEDを取り外すか、少なくとも1つのピンを外す必要があります。これは非常に重要です LEDは大量の電力を消費するためです。他のコンポーネントを損傷しないように注意してください
  • トランジスタ、抵抗、3.3Vレギュレータをはんだ付けします
  • 2つのKF301-2Pをはんだ付けします。 1つはソーラーパネル用、もう1つはバッテリーホルダー用です
  • 3つのメスPCBコネクタをはんだ付けします:光センサー、BME280、および雨センサー用
  • すべてのPCBコンポーネントを接続するための小さなワイヤーをはんだ付けします(写真とフリッツのシャマティックを確認してください)

3。 充電済みのAAANiMHバッテリー3個をホルダーの中に入れ、ボックスの中に入れて、ワイヤーをKF301-2Pコネクターに接続します

4。 ボックスの外側からBME280と光センサーを対応するオスコネクタに接続します

レインセンサーの場合は、3本のワイヤー(Gnd、Vcc、信号)をはんだ付けし、反対側には、ボックス内の対応するオスコネクタに接続するオスピンをはんだ付けします

最後に、ステーションを最終的な位置に配置します。雨や雪から守られる場所を選びました。レインセンサーにはもっと長いワイヤーを選び、雨の中でしっかりと支えて別々に配置しました。メインボックスには、接着剤付きの特別な種類のテープを選択しました(写真を確認してください)が、ボックスを保持するものなら何でもかまいません。

Sketch.fzz

ステップ3:Arduinoコード

このステップでは、必要な外部ライブラリについて学習します。コードの概要とその仕組みについて説明します。もちろん、コードをダウンロードするか、Arduino IDEにコピーして貼り付け、気象観測所にアップロードします。

気象観測所の役割は、センサーに関するデータを10分ごとに基地局に送信することです。

まず、ウェザーステーションプログラムの機能について説明しましょう。

1。 センサーデータ(湿度、温度、圧力、雨、光、電圧)を読み取ります

2。 エンコードされたデータを2番目のソフトウェアシリアルラインを介して送信します。

エンコードされたデータは次のようになります:

  H1:78 | T1:12 | PS1:1022 | L1:500 | R1:0 | V1:4010 |  

上記の説明は、ステーション「1」からの湿度が78パーセント、ステーション1からの温度が12度、圧力が1022バール、光レベルが500ルクス、雨が0、電圧が4010ミリボルトであることを意味します。

3。 補助コンポーネントの電源を切ります:センサーと通信デバイス

4。 arduinoを10分間スリープモードにします(これにより、消費するマイクロアンペアが50マイクロアンペア未満になります)

5。 コンポーネントの電源を入れ、手順1〜4を繰り返します

ここでもう少し微調整します。電圧レベルが4.2Vを超える場合、arduinoは通常のスリープ機能「delay(milliseconds)」を使用します。これにより、消費電力が大幅に増加し、電圧が急激に低下します。これにより、ソーラーパネルがバッテリーを過充電するのを効果的に防ぎます。

ここで私のGithubリポジトリからコードを取得できます:https://github.com/danionescu0/home-automation/tre ...

または、下からコピーして貼り付けます。どちらの方法でも、 "transmitSenzorData(" V "、sensors.voltage);" の行を削除するだけです。

  #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、TXAdafruit_BME280 bme; BH1750 lightMeter; const byte rainPin =A0; byte SensorsCode =1; / ***通常のスリープではなくディープスリープでマイクロコントローラーをパンする電圧レベル* / int VoltageDeepSleepThreshold =4200; const byte peripherialsPowerPin =6; char buffer [] ={''、 ''、 ''、 ''、 ''、 ''、 ''}; struct SensorData {バイト湿度; int温度;バイト雨; int圧力;長い電圧; int light; }; ensorDataセンサー; voidsetup(){Serial.begin(9600); serialComm.begin(9600); pinMode(peripherialsPowerPin、OUTPUT); digitalWrite(peripherialsPowerPin、HIGH); delay(500); if(!bme.begin()){Serial.println( "有効なBME280センサーが見つかりませんでした。配線を確認してください!"); while(1){customSleep(100); }} Serial.println( "初期化が正常に終了しました"); delay(50); digitalWrite(peripherialsPowerPin、HIGH);} void loop(){updateSenzors(); transmitData(); customSleep(75); } 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();センサー。電圧=readVcc(); Sensors.rain =readRain();} voidtransmitData(){emptyIncommingSerialBuffer(); Serial.print( "Temp:"); Serial.println(sensors.temperature); Serial.print( "Humid:"); Serial.println(sensors.humidity); Serial.print( "Pressure:"); Serial.println(sensors.pressure); Serial.print( "Light:"); Serial.println(sensors.light); Serial.print( "電圧:"); Serial.println(センサー。電圧); Serial.print( "Rain:"); Serial.println(sensors.rain); 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 emptyIncommingSerialBuffer(){while(serialComm.available()> 0){serialComm.read(); delay(5); }} void TransmitSenzorData(String type、int value){serialComm.print(type); serialComm.print(sensorsCode); serialComm.print( ":"); serialComm.print(value); serialComm.print( "|"); delay(50);} void customSleep(long 8SecondCycles){if(sensors.voltage> VoltageDeepSleepThreshold){delay(eightSecondCycles * 8000);戻る; } digitalWrite(peripherialsPowerPin、LOW); for(int i =0; i

コードをアップロードする前に、次のarduinoライブラリをダウンロードしてインストールします。

* BH1750ライブラリ:https://github.com/claws/BH1750 * LowPowerライブラリ:https://github.com/rocketscream/Low-Power

* Adafruitセンサーライブラリ:https://github.com/adafruit/Adafruit_Sensor

* Adafruit BME280ライブラリ:https://github.com/adafruit/Adafruit_Sensor

その方法がわからない場合は、このチュートリアルを確認してください。

ステップ4:ベースステーションの準備

ベースステーションは、 Linuxコンピューターで構成されます。 (デスクトップ、ラップトップ、または開発ボード) HC-12 USB モジュールが接続されています。ステーションから10分ごとにデータを収集するには、コンピューターを常にオンにしておく必要があります。

ラップトップをUbuntu18で使用しました。

インストール手順:

1。 anacondaをインストールします。 AnacondaはPythonパッケージマネージャーであり、同じ依存関係を簡単に操作できるようになります。 Pythonのバージョンと各パッケージのバージョンを制御できるようになります

インストール方法がわからない場合は、https://www.digitalocean.com/community/tutorials/h ...チュートリアルを確認し、手順1〜8に従ってください

2。 mongoDbをインストールします。 MongoDbは、このプロジェクトのメインデータベースになります。すべてのセンサーの時系列に関するデータが保存されます。それはスキーマレスであり、私たちの目的のためにそれは使いやすいです。

インストール手順については、次のページを確認してください:https://docs.mongodb.com/v3.4/tutorial/install-mon ...

私は古いバージョンのmongoDb3.4.6を使用しましたが、上記のチュートリアルに従うと、まさにそれが得られます。原則として、最新バージョンで動作するはずです。

[オプション]日付フィールドにインデックスを追加します:

  mongouse Weather db.weather_station.createIndex({"date":1}) 

3。 ここからプロジェクトをダウンロードします:https://github.com/danionescu0/home-automation。天気予測フォルダを使用します

  sudo apt-get install gitgit clone https://github.com/danionescu0/home-automation.gi ...  

4。 anaconda環境を作成して構成します:

  cd Weather-predict#Python3.6.2condaを使用して「weather」という名前のanaconda環境を作成しますcreate--name Weather python =3.6.2#environmentcondaをアクティブにしますweatherをアクティブにします#すべてのパッケージをインストールしますpip install -r Requirements.txt  

これにより、新しいanaconda環境が作成され、必要なパッケージがインストールされます。パッケージの一部は次のとおりです。

Keras(高レベルのニューラルネットワークレイヤー。このライブラリを使用して、すべてのニューラルネットワークの予測を行います)

パンダ(データを操作する便利なツールです。頻繁に使用します)

pymongo(python mongoDbドライバー)

sklearn(データマイニングおよびデータ分析ツール)

プロジェクトを構成する

構成ファイルはweather-predictフォルダーにあり、config.py

という名前です。

1. MongoDbをリモートまたは別のポートにインストールする場合は、

の「ホスト」または「ポート」を変更します
  mongodb ={'host': 'localhost'、 'port':27017} ...  

2.次に、HC-12USBシリアルアダプタを接続する必要があります。実行する前に:

  ls -l / dev / tty *  

マウントされたデバイスのリストを取得する必要があります。

次に、HC-12をUSBポートに挿入し、同じコマンドを再度実行します。これは、そのリストの1つの新しいエントリ、シリアルアダプタである必要があります。次に、必要に応じて構成のアダプターポートを変更します

  serial ={'port': '/ dev / ttyUSB0'、 'baud_rate':9600}  

他の構成エントリはいくつかのファイルのデフォルトパスであり、そこで変更する必要はありません。

ステップ5:実際に気象観測所を使用する

ここでは、テストデータのインポート、テストの実行、独自のデータの設定、グラフの表示、今後数時間の予測を含むメールの設定に関する基本的なことについて説明します。

それがどのように機能するかについてもっと知りたい場合は、次のステップ「どのように機能するか」をチェックしてください

すでに収集したデータのインポート

MongoDbには、jsonからデータをインポートするためのcliコマンドが付属しています:

  mongoimport -d Weather -c Weather_station --file sample_data / Weather_station.json  

これにより、サンプルデータから「天気」データベースと「データポイント」コレクションにファイルがインポートされます

警告 ここで、収集したデータを使用して、それを新しいローカルデータと組み合わせると、ハードウェア(センサー)とローカルの気象パターンのわずかな違いにより、精度が低下する可能性があります。

新しいデータの収集

基地局の役割の1つは、気象観測所からの受信データを後で処理するためにデータベースに保存することです。シリアルポートをリッスンしてデータベースに保存するプロセスを開始するには、次のコマンドを実行します。

  conda activate Weatherpython serial_listener.py#10分ごとに、ウェザーステーションからのデータが表示されます:[センサー:type(temperature)、value(14.3)] [Sensor:type(pressure)、value( 1056.0)] ...  

予測モデルの生成

データをインポートしたか、「スクリプトを数年間実行」してパーソナライズされたデータを収集したと想定されるため、このステップでは、データを処理して、将来の雨を予測するために使用されるモデルを作成します。

  conda activate Weatherpython train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 8 --hour-granularity 6  

*最初のパラメーター--days_behindは、スクリプトが処理する必要がある過去のデータ量を意味します。日数で測定されます

* --test-file-percentは、テスト目的で考慮すべきデータの量を意味します。これは、機械学習アルゴリズムの通常のステップです

* --hour-granularityは基本的に、予測が必要になる未来の時間数を意味します

* --datapoints-このパラメータの背後については、次のセクションでさらに説明します

すべての気象観測所センサーでいくつかのデータチャートを表示する

過去10日間としましょう:

  conda activate Weather Python Graphs --days-behind 10  

次の期間に雨が降るかどうかを予測します

雨が降るかどうかを予測し、通知メールを送信します

  conda activate Weather python Forecast.py --datapoints-behind 8 --hour-granularity 6 --from-addr a_gmail_address --from-password gmail_password --to-addr a_email_destination  

テストデータに対してバッチ予測を実行します:

  python Forecast_batch.py​​ -f sample_data / test_data.csv  

上記のtrainスクリプトと同じパラメータを使用することが重要です。

メール通知を機能させるには、Gmailアカウントにログインし、安全性の低いアプリをオンにするをオンにします。これにより、他の人があなたのアカウントにアクセスしやすくなることに注意してください。

2つのメールアドレスが必要です。1つは上記のオプションが有効になっているGmailアドレスで、もう1つは通知を受け取るアドレスです。

1時間ごとに通知を受け取りたい場合は、スクリプトをcrontabに入れてください

これらすべてがどのように可能かを確認するには、次のステップを確認してください

ステップ6:どのように機能するか

この最後のステップでは、このプロジェクトのアーキテクチャのいくつかの側面について説明します。

1。 プロジェクトの概要、関連する一般的なアーキテクチャとテクノロジーについて説明します

2。 機械学習の基本概念

3。 データの準備方法(最も重要なステップ)

4。 実際のニューラルネットワークラッパーAPIの仕組み(Keras)

5。 将来の改善

ここでいくつかのコード例を示しますが、プロジェクトのコードが100%ではないことに注意してください。プロジェクトでは、それ自体がコードであり、クラスと構造が少し複雑になっています

1.プロジェクトの概要、関連する一般的なアーキテクチャとテクノロジーについて説明します

前に話したように、プロジェクトには2つの別々の部分があります。データを収集して送信することだけが機能するのは、ウェザーステーションです。そして、すべての収集トレーニングと予測が行われる基地局。

分離の利点 気象観測所と基地局の概要:

  • 電力要件。気象観測所もデータを処理できる場合は、かなりの電力、おそらく大型のソーラーパネルまたは恒久的な電源が必要になります。
  • 携帯性。サイズが小さいため、気象観測所は数百メートル離れた場所からデータを収集でき、必要に応じて場所を簡単に変更できます。
  • スケーラビリティ。複数の気象観測所を構築し、それらを数百メートルに広げることで、予測精度を高めることができます。
  • 低コスト。安価なデバイスであるため、紛失や盗難に備えて別のデバイスを簡単に構築できます。

データベースの選択 。私はmongoDbを選択しました。それは、スキーマレス、無料、使いやすいAPIなどの優れた機能だからです

センサーデータが受信されるたびに、データはデータベースに保存され、データエントリは次のようになります。

  {"_id": "04_27_2017_06_17"、 "humidity":65、 "date":ISODate( "2017-04-27T06:17:18Z")、 "pressure":1007、 "temperature": 9、「雨」:0、「光」:15}  

データベースはデータをBSON形式(JSONと同様)で保存するため、読みやすく、操作も簡単です。文字列として分にフォーマットされた日付を含む識別子の下でデータを集約したので、ここでの最小のグループ化は分です。

気象ステーション(正常に動作している場合)は、10分ごとにデータポイントを送信します。データポイントは、「日付」、「湿度」、「気圧」、「気温」、「雨」、「光」の値のコレクションです。

データ処理とニューラルネットワーク テクノロジーの選択

ニューラルネットワークの多くの主要な革新がPythonに見られるため、バックエンドにPythonを選択しました。多くのGithubリポジトリ、チュートリアルブログ、書籍を備えた成長中のコミュニティが役に立ちます。

*データ処理部分にはパンダを使用しました ( https://pandas.pydata.org/ 。パンダを使用すると、データの操作が簡単になります。 CSV、Excel、Pythonデータ構造からテーブルを読み込んで並べ替えたり、列を削除したり、列を追加したり、列ごとにインデックスを付けたり、その他多くの変換を行うことができます。

*ニューラルネットワークを操作するために、 Keras を選択しました (https://keras.io/)。 Kerasは、Tensorflowなどのより低レベルのAPIを超える高レベルのニューラルネットワークラッパーであり、数十行程度のコードで多層ニューラルネットワークを構築できます。他の人の素晴らしい仕事に役立つ何かを構築できるので、これは大きな利点です。これはプログラミングの基本的なことであり、他の小さなビルディングブロックに基づいて構築されます。

2.機械学習の基本概念

このチュートリアルの範囲は、機械学習を教えることではなく、考えられるユースケースの1つと、それをこのユースケースに実際に適用する方法を概説することです。

ニューラルネットワークは、ニューロンと呼ばれる脳細胞に似たデータ構造です。科学は、脳が軸索と呼ばれる「線」を介して電気インパルスによって他のニューロンと通信するニューロンと呼ばれる特別な細胞を持っていることを発見しました。 (他の多くのニューロンから)十分に刺激された場合、ニューロンは、他のニューロンを刺激するこの「ネットワーク」でさらに離れた場所で電気インパルスをトリガーします。もちろん、これはプロセスを過度に単純化したものですが、基本的にコンピューターアルゴリズムは、この生物学的プロセスを複製しようとします。

コンピュータニューラルネットでは、各ニューロンに「トリガーポイント」があり、そのポイントで刺激された場合、刺激が前方に伝播しますが、そうでない場合は伝播しません。このため、シミュレートされた各ニューロンにはバイアスがあり、各軸索には重みがあります。これらの値をランダムに初期化した後、「学習」と呼ばれるプロセスが開始されます。これは、ループ内でアルゴリズムが次の手順を実行することを意味します。

  • 入力ニューロンを刺激する
  • 出力ニューロンまでネットワーク層を介して信号を伝播します
  • 出力ニューロンを読み取り、結果を目的の結果と比較します
  • 次回より良い結果を得るために軸索の重みを微調整します
  • ループの数に達するまで再開します

このプロセスの詳細については、https://mattmazur.com/2015/03/17/a-step-by-step-ba ...をご覧ください。そこにチュートリアル。

もう1つ、ここでは教師あり学習方法を使用します。つまり、アルゴリズムに入力と出力も教えるので、新しい入力のセットが与えられると、出力を予測できます。

3.データの準備方法(最も重要なステップ)

多くの機械学習やニューラルネットワークの問題では、データの準備は非常に重要な部分であり、以下をカバーします。

  • 生データを取得する
  • データのクリーンアップ:これは、孤立した値、異常、またはその他の異常を削除することを意味します
  • データのグループ化:多くのデータポイントを取得し、集約されたデータポイントに変換します
  • データの強化:独自のデータまたは外部ソースから派生したデータの他の側面を追加する
  • トレーニングデータとテストデータのデータを分割する
  • 各トレインとテストデータを入力と出力に分割します。通常、問題には多くの入力といくつかの出力があります
  • データを0から1の間に再スケーリングします(これにより、ネットワークが高値/低値のバイアスを取り除くのに役立ちます)

生データの取得

In our case getting data for MongoDb in python is really easy. Given our datapoints collection just this lines of code will do

client =MongoClient(host, port).weather.datapoints cursor =client.find( {'$and' :[ {'date' :{'$gte' :start_date}}, {'date' :{'$lte' :end_date}} ]} )data =list(cursor).. 

Data cleanup

The empty values in the dataframe are dropped

dataframe =dataframe.dropna() 

Data grouping &data enhancing

This is a very important step, the many small datapoins will be grouped into intervals of 6 hours. For each group several metrics will be calculated on each of the sensors (humidity, rain, temperature, light, pressure)

  • min value
  • max value
  • mean
  • 70, 90, 30, 10 percentiles
  • nr of times there has been a rise in a sensor
  • nr of times there has been a fall in a sensor
  • nr of times there has been steady values in a sensor

All of these things will give the network information for a datapoint, so for each of the 6 hours intervals these things will be known.

From a dataframe that looks like this:

_id date humidity light pressure rain temperature 04_27_2017_03_08 2017-04-27 03:08:36 67.0 0.0 1007.0 0.0 11.004_27_2017_03_19 2017-04-27 03:19:05 66.0 0.0 1007.0 0.0 11.004_27_2017_03_29 2017-04-27 03:29:34 66.0 0.0 1007.0 0.0 11.0  

And the transformation will be:"

_id date humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile humidity_avg ... temperature_avg temperature_fall temperature_max temperature_min temperature_rise temperature_steady ... 04_27_2017_0 2017-04-27 03:08:36 59.6 60.8 63.2 66.0 62.294118 ... 10.058824 2 11.0 9.0 1 1404_27_2017_1 2017-04-27 06:06:50 40.3 42.0 60.0 62.0 50.735294 ... 14.647059 3 26.0 9.0 11 2004_27_2017_2 2017-04-27 12:00:59 36.0 37.0 39.8 42.0 38.314286 ... 22.114286 1 24.0 20.0 5 29  

After this a new column named "has_rain" will be added. This will be the output (our predicted variable). Has rain will be 0 or 1 depending if the rain average is above a threshold (0.1). With pandas it's as simple as:

dataframe.insert(loc=1, column='has_rain', value=numpy.where(dataframe['rain_avg']> 0.1, 1, 0)) 

Data cleanup (again)

- we'll drop the date column because it's no use to us, and also remove datapoints where the minimum temperature is below 0 because our weather station it doesn't have a snow sensor, so we won't be able to measure if it snowed

dataframe =dataframe.drop(['date'], axis=1)dataframe =dataframe[dataframe['temperature_min']>=0] 

Data enhancing

Because data in the past might influence our prediction of the rain, we need for each of the dataframe rows to add columns reference to the past rows. This is because each of the row will serve as a training point, and if we want the prediction of the rain to take into account previous datapoints that's exactly what we should do:add more columns for datapoints in the past ex:

_id has_rain humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile ... temperature_steady_4 temperature_steady_5 temperature_steady_6 temperature_steady_7 temperature_steady_8 ... 04_27_2017_3 0 36.0 44.8 61.0 63.0 ... NaN NaN NaN NaN NaN04_28_2017_0 0 68.0 70.0 74.0 75.0 ... 14.0 NaN NaN NaN NaN04_28_2017_1 0 40.0 45.0 63.2 69.0 ... 20.0 14.0 NaN NaN NaN04_28_2017_2 0 34.0 35.9 40.0 41.0 ... 29.0 20.0 14.0 NaN NaN04_28_2017_3 0 36.1 40.6 52.0 54.0 ... 19.0 29.0 20.0 14.0 NaN04_29_2017_0 0 52.0 54.0 56.0 58.0 ... 26.0 19.0 29.0 20.0 14.004_29_2017_1 0 39.4 43.2 54.6 57.0 ... 18.0 26.0 19.0 29.0 20.004_29_2017_2 1 41.0 42.0 44.2 47.0 ... 28.0 18.0 26.0 19.0 29.0  

So you see that for every sensor let's say temperature the following rows will be added:"temperature_1", "temperature_2".. meaning temperature on the previous datapoint, temperature on the previous two datapoints etc. I've experimented with this and I found that a optimum number for our 6 hour groupings in 8. That means 8 datapoints in the past (48 hours). So our network learned the best from datapoins spanning 48 hours in the past.

Data cleanup (again)

As you see, the first few columns has "NaN" values because there is nothing in front of them so they should be removed because they are incomplete.

Also data about current datapoint should be dropped, the only exception is "has_rain". the idea is that the system should be able to predict "has_rain" without knowing anything but previous data.

Splitting the data in train and test data

This is very easy due to Sklearn package:

from sklearn.model_selection import train_test_split ...main_data, test_data =train_test_split(dataframe, test_size=percent_test_data) ... 

This will split the data randomly into two different sets

Split each of the train and test data into inputs and outputs

Presuming that our "has_rain" interest column is located first

X =main_data.iloc[:, 1:].valuesy =main_data.iloc[:, 0].values  

Rescale the data so it's between 0 and 1

Again fairly easy because of sklearn

from sklearn.preprocessing import StandardScalerfrom sklearn.externals import joblib..scaler =StandardScaler()X =scaler.fit_transform(X) ...# of course we should be careful to save the scaled model for later reusejoblib.dump(scaler, 'model_file_name.save')  

4. How the actual neural network wrapper API works (Keras)

Building a multi layer neural network with Keras is very easy:

from keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropout ...input_dimensions =X.shape[1] optimizer ='rmsprop'dropout =0.05model =Sequential()inner_nodes =int(input_dimensions / 2)model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))model.add(Dropout(rate=dropout))model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))model.add(Dropout(rate=dropout))model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) model.fit(X, y, batch_size=1, epochs=50)...# save the model for later useclassifier.save('file_model_name') 

So what does this code mean? Here we're building a sequential model, that means sequentially all the layers will be evaluated.

a) we declare the input layer (Dense), here all the inputs from our dataset will be initializedm so the "input_dim" parameter must be equal to the row length

b) a Dropout layer is added. To understand the Dropout first we must understand what "overfitting" means:it's a state in which the network has learned too much particularities for a specific dataset and will perform badly when confronted to a new dataset. The dropout layer will disconnect randomly neurons at each iteration so the network won't overfit.

c) another layer of Dense is added

d) another Dropout

e) the last layer is added with one output dimension (it will predict only yes/no)

f) the model is "fitted" that means the learning process will begin, and the model will learn

Other parameters here:

  • activation functions (sigmoid, relu). This are functions that dictate when the neuron will transmit it's impulse further in the network. There are many, but sigmoid and relu are the most common. Check out this link for more details:https://towardsdatascience.com/activation-function...
  • kernel_initializer function (uniform). This means that all the weights are initialized with random uniform values
  • loss function (mean_absolute_error). This function measures the error comparing the network predicted result versus the ground truth. There are many alternatives:https://keras.io/losses/
  • metrics function (accuracy). It measures the performance of the model
  • optimiser functions (rmsprop). It optimizes how the model learn through backpropagation.
  • batch_size. Number of datapoints to take once by Keras before applying optimizer function
  • epochs:how many times the process it's started from 0 (to learn better)

There is no best configuration for any network or dataset, all these parameters can an should be tuned for optimal performance and will make a big difference in prediction success.

5. Future improvements

Let's start from the weather station , I can see a lot of improving work to be done here:

  • add a wind speed / direction sensor. This could be a very important sensor that i'm missing in my model
  • experiment with UV rays, gas and particle sensors
  • add at least two stations in the zone for better data (make some better averages)
  • collect a few more years of data, i've experimented with just a year and a half

Some processing improvements:

  • try to incorporate data from other sources into the model. You can start to import wind speed data and combine with the local station data for a better model. This website offers historical data:https://www.wunderground.com/history/
  • optimize the Keras model better by adjusting:layers, nr of neurons in layers, dropout percents, metrics functions, optimiser functions, loss functions, batch size, learning epochs
  • try other model architectures, for example i've experimented with LSTM (long short term memory) but it gived slightly poorer results)

To try different parameters on the learning model you can use

python train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 6 --hour-granularity 6 --grid-search 

This will search through different "batch_size", "epoch", "optimizer" and "dropout" values, evaluate all and print out the best combination for your data.

If you have some feedback on my work please share it, thanks for staying till the end of the tutorial!

Step 7:Bonus:Using an Official Weather Dataset

I was wondering if I can get better results with a more reliable weather station, so i've searched a bit, and i've came across "Darksky AP I" (https://darksky.net/dev), this is a great tool that provides current and historical weather data with many more sensor data:

  • temperature
  • humidity
  • pressure
  • wind speed
  • wind gust
  • ub index
  • visibilitySo this beeing data from an official weather station, and having more parameters I thought it should perform better so i've gave it a try. To replicate my findings:

1.Download the data from darsky or import my MongoDb collection:

a) Download

  • to download your self, first create an account in darsky and get the API key
  • replace the API key in download_import/config.py
  • also in the config replace the geographic coordonates for the location you want to predict the rain
  • in a console activate "weather" anaconda environment and run:
python download_import/darksky.py -d 1000 

- the free version of the API is limited to 1000 requests per day so if you want more data you need to wait for a longer time

b) Import my downloaded data for Bucharest city

- in a console run

mongoimport -d weather -c darksky --file sample_data/darksky.json  

2。 When you train the model specify that it should run on "darksy" dataset

python train.py -d 2000 -p 20 -dp 4 -hg 6 --data-source darksky 

3。 To see the results run predict batch script as before

python predict_batch.py -f sample_data/test_data.csv 

You'll see that the overall prediction percent has gone from about 80% to 90%. Also the prediction accuracy when accounting only rainy days has gone up.

So yes, the dataset really matters.

コード

  • Code snippet #2
  • コードスニペット#5
  • Code snippet #6
  • Code snippet #10
  • Code snippet #15
  • Code snippet #16
  • Code snippet #18
  • Code snippet #22
  • Code snippet #23
  • Code snippet #25
  • Code snippet #26
Code snippet #2Plain text
#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, TXAdafruit_BME280 bme; BH1750 lightMeter;const byte rainPin =A0;byte sensorsCode =1;/** * voltage level that will pun the microcontroller in deep sleep instead of regular sleep */int voltageDeepSleepThreshold =4200; const byte peripherialsPowerPin =6;char buffer[] ={' ',' ',' ',' ',' ',' ',' '};struct sensorData { byte humidity; int temperature; byte rain; int pressure; long voltage; int light; };sensorData 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); digitalWrite(peripherialsPowerPin, HIGH);}void loop() { updateSenzors(); transmitData(); customSleep(75); }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(){ emptyIncommingSerialBuffer(); Serial.print("Temp:");Serial.println(sensors.temperature); Serial.print("Humid:");Serial.println(sensors.humidity); Serial.print("Pressure:");Serial.println(sensors.pressure); Serial.print("Light:");Serial.println(sensors.light); Serial.print("Voltage:");Serial.println(sensors.voltage); Serial.print("Rain:");Serial.println(sensors.rain); 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 emptyIncommingSerialBuffer(){ while (serialComm.available()> 0) { serialComm.read(); delay(5); }}void transmitSenzorData(String type, int value){ serialComm.print(type); serialComm.print(sensorsCode); serialComm.print(":"); serialComm.print(value); serialComm.print("|"); delay(50);}void customSleep(long eightSecondCycles){ if (sensors.voltage> voltageDeepSleepThreshold) { delay(eightSecondCycles * 8000);戻る; } digitalWrite(peripherialsPowerPin, LOW); for (int i =0; i
コードスニペット#5 プレーンテキスト
cd weather-predict # create anaconda environment named "weather" with python 3.6.2conda create --name weather python=3.6.2 # activate environmentconda activate weather# install all packages pip install -r requirements.txt 
Code snippet #6Plain text
mongodb ={ 'host':'localhost', 'port':27017}...
Code snippet #10Plain text
conda activate weatherpython serial_listener.py# every 10 minutes you should see data from the weather station coming in :[Sensor:type(temperature), value(14.3)][Sensor:type(pressure), value(1056.0)]...
Code snippet #15Plain text
{ "_id" :"04_27_2017_06_17", "humidity" :65, "date" :ISODate("2017-04-27T06:17:18Z"), "pressure" :1007, "temperature" :9, "rain" :0, "light" :15}
Code snippet #16Plain text
client =MongoClient(host, port).weather.datapoints cursor =client.find( {'$and' :[ {'date' :{'$gte' :start_date}}, {'date' :{'$lte' :end_date}} ]} )data =list(cursor)..
Code snippet #18Plain text
_id date humidity light pressure rain temperature 04_27_2017_03_08 2017-04-27 03:08:36 67.0 0.0 1007.0 0.0 11.004_27_2017_03_19 2017-04-27 03:19:05 66.0 0.0 1007.0 0.0 11.004_27_2017_03_29 2017-04-27 03:29:34 66.0 0.0 1007.0 0.0 11.0 
Code snippet #22Plain text
_id has_rain humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile ... temperature_steady_4 temperature_steady_5 temperature_steady_6 temperature_steady_7 temperature_steady_8 ... 04_27_2017_3 0 36.0 44.8 61.0 63.0 ... NaN NaN NaN NaN NaN04_28_2017_0 0 68.0 70.0 74.0 75.0 ... 14.0 NaN NaN NaN NaN04_28_2017_1 0 40.0 45.0 63.2 69.0 ... 20.0 14.0 NaN NaN NaN04_28_2017_2 0 34.0 35.9 40.0 41.0 ... 29.0 20.0 14.0 NaN NaN04_28_2017_3 0 36.1 40.6 52.0 54.0 ... 19.0 29.0 20.0 14.0 NaN04_29_2017_0 0 52.0 54.0 56.0 58.0 ... 26.0 19.0 29.0 20.0 14.004_29_2017_1 0 39.4 43.2 54.6 57.0 ... 18.0 26.0 19.0 29.0 20.004_29_2017_2 1 41.0 42.0 44.2 47.0 ... 28.0 18.0 26.0 19.0 29.0 
Code snippet #23Plain text
from sklearn.model_selection import train_test_split ...main_data, test_data =train_test_split(dataframe, test_size=percent_test_data) ...
Code snippet #25Plain text
from sklearn.preprocessing import StandardScalerfrom sklearn.externals import joblib..scaler =StandardScaler()X =scaler.fit_transform(X) ...# of course we should be careful to save the scaled model for later reusejoblib.dump(scaler, 'model_file_name.save') 
Code snippet #26Plain text
from keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropout ...input_dimensions =X.shape[1] optimizer ='rmsprop'dropout =0.05model =Sequential()inner_nodes =int(input_dimensions / 2)model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))model.add(Dropout(rate=dropout))model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))model.add(Dropout(rate=dropout))model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) model.fit(X, y, batch_size=1, epochs=50)...# save the model for later useclassifier.save('file_model_name')
Github
https://github.com/claws/BH1750https://github.com/claws/BH1750
Github
https://github.com/rocketscream/Low-Powerhttps://github.com/rocketscream/Low-Power
Github
https://github.com/adafruit/Adafruit_Sensorhttps://github.com/adafruit/Adafruit_Sensor
Github
https://github.com/adafruit/Adafruit_BME280_Libraryhttps://github.com/adafruit/Adafruit_BME280_Library
Github
https://github.com/danionescu0/home-automationhttps://github.com/danionescu0/home-automation

回路図

sketch_KAtDa2VReF.fzz
Weather station arduino sketch
https://github.com/danionescu0/home-automation/tree/master/arduino-sketches/weatherStation

製造プロセス

  1. PythonとRaspberryPiの温度センサー
  2. Arduino Nano RP2040を使用したDIYPhotoshop編集コンソール
  3. Python で os.rename() を使用してファイルとディレクトリの名前を変更する
  4. PythonでArduinoとRFIDを使用した出席システム
  5. Arduino、1Sheeld、Androidを使用したユニバーサルリモコン
  6. Arduinoとスマートフォンを使用したDIY電圧計
  7. Arduinoを使用したDIY赤外線ハートビートセンサー
  8. Arduinoを使用した周波数とデューティサイクルの測定
  9. ArduinoとNokia5110ディスプレイを備えたDIY電圧計
  10. arduinoを使用したソナーと処理IDEでの表示
  11. BoltとArduinoを使用したLEDの明るさの制御