完全に機能するArduinoウェザーステーションの作り方

公開: 2022-03-11

更新:この記事が公開された後も、Arduinoウェザーステーションでの作業が続けられ、Open Weather Station(OWS)のリリースに至りました。 コードや新しいチュートリアルとともに、追加のアップデート、リソースをチェックしてください。

これはどういうことですか?

カイトサーフィンは、世界で最も中毒性の高いスポーツの1つです。 必要なのはカイトボード、水域、そしていくつかのアクセサリーだけです。 自然と触れ合い、心を解放し、運動するのに最適な方法です。 さらに、あなたは本当にそれに夢中になることができます。

だから問題は何ですか?

ああ、私は1つの重要な要件を忘れました:風。 そして、それが私たちの問題です。お気に入りのカイトサーフィンスポットのすぐそばに住んでいない限り、風が吹くかどうかはわかりません。

私はアルゼンチンのコルドバに住んでおり、カイトサーフィンをしている湖から約130 km(〜80マイル)離れています。 それは私が対処できるおよそ2時間のドライブです。 しかし、天気予報が不正確であるという事実に対処することはできません。 そして私が住んでいる場所では、良い風の状態はほんの数時間続きます。 あなたがしたい最後のことは、月曜日のスケジュールをクリアしてカイトサーフィンに行き、2時間の運転の後に風のない湖で神々を罵倒していることに気付くことです。

お気に入りのカイトサーフィンスポットの風の状態をリアルタイムで知る必要がありました。 そこで、自分で気象台を作ることにしました。

敵対的な環境でリアルタイムに天気を測定する

目標は、自宅のブラウザにリアルタイムの気象データを配信することでした。

arduinoウェザーステーションの全体的なプロセス

詳細に入る前に、次のようなプロジェクトに関連する重要な質問と警告について考えてみましょう。

  • 泥棒にとって価値も魅力的でもない気象観測所を作成するにはどうすればよいですか?
  • ハードウェアのコストと開発時間を最小限に抑えるにはどうすればよいですか?
  • 気象データをリアルタイムで測定してアクセスし、便利な方法で表示するにはどうすればよいですか?
    • 必要な測定値:風と突風、風向、雨、大気圧、温度、湿度
    • ステーションをインターネットに接続する
    • 地域の気象データを保存および取得する
    • 気象台とサーバー間の通信
  • どうすればメンテナンスを(ほぼ)ゼロに減らすことができますか?
    • ソフトウェアの吊り下げを管理する
    • 接続の喪失を管理する
    • エネルギー供給の損失を管理する

私の小さな友達に挨拶してください!

ファイル

駅をより親しみやすくするために手袋があると思うかもしれません。 ただし、実際には気圧センサーのテストに使用されます(手袋の圧力は膨張した手袋の内部で増加します)。 右側には、近くの塔の上にある駅が最終的な場所にあります。

また、カイトサーフィンに関するWebサイトを設計およびプログラムしました。これには、カイトサーフィンコミュニティを支援するためのステーションの測定値のリアルタイムプロットが含まれています。 最後に、Facebookでカイトサーフィングループを作成しました。

ファイル

すごい! それで、どうやってそれをしましたか?

さて、私は順番に各ポイントに対処します:

「泥棒にとって価値も魅力的でもない気象観測所を作成するにはどうすればよいですか?」

これは重要な要素であり、多くの点で、残りの設計プロセスを推進しました。 2000ドル未満のほとんどの既成のステーションでは、コンピューターへのUSB接続が必要でした。 泥棒がステーションの隣にPCがあることを認識した場合、コンピューターとステーションの交換費用は私の個人的な予算を超えるため、これで終わりです。 そのため、ステーションをゼロから実装するために、いくつかのハードウェアプラットフォームを低コストでテストすることにしました。

「ハードウェアのコストと開発時間を最小限に抑えるにはどうすればよいですか?」

私だけがこのサイドプロジェクトの費用を支え、余暇にすべての仕事をしていたので、もちろんこれは大きな懸念事項でした。 私は人気のあるPIC32といくつかの組み立て済みのマイクロチップイーサネットモジュールから始めましたが、コストは思ったほど低くはなく、ハードウェアの組み立てと拡張に伴うオーバーヘッドが多すぎました。 それから、私はArduinoを調べ始めました。C言語を使用した電子機器のプロトタイピング用のオープンソースハードウェアとソフトウェアです。 これはまさに私が望んでいたことであり、DealeXtremeでモジュールを購入することができました。 たった15ドルの支出と2日間の時間で遊び始めることができました。

もちろん、Arduinoにも制限があります。コンパイルされたソフトウェアには2KバイトのRAMと32Kバイトしかありません。これは、派手な文字列や役に立たない変数のための余地をあまり残していません1

「気象データをリアルタイムで測定してアクセスし、便利な方法で表示するにはどうすればよいですか?」

現在、私のステーションでは、風速、突風、風向、気温、湿度、雨、気圧を測定できます。 温度、湿度、および圧力は、いくつかのライブラリによって処理されます。これにより、生活がはるかに楽になりました。

風速と雨の測定は少し面倒でした。 センサーはスイッチ(リードスイッチ)を開閉することで作動します。 したがって、入力をトリガーするとすぐにセンサーをキャッチするために、ハードウェア割り込みを実装する必要がありました。 つまり、いくつかのメソッドを呼び出す必要がありました。

 attachInterrupt(RAINGAUGE_PIN, countRainCycles, FALLING);

この割り込みは、通常のコード実行を中断し、回路の開閉によってスイッチが立ち下がりエッジを経験するとすぐに、countAnemometerCyclesまたはcountRainCycles関数を呼び出します。 スイッチのトリガーごとに、いくつかの変数が増分されます。 (後で、単位変換を考慮してこれらの変数を比較検討します。)

 void countRainCycles() { rainCyclesCounter++; // This is easy! And it actually works. }

しかし、それほど速くはありません! このプロセスは、ハードウェアスイッチに固有のスイッチバウンス効果の結果として、何百もの誤ったトリガーを生成します。 幸い、この問題にはハードウェアとソフトウェアの両方のソリューションがあります。

バウンス効果について

バウンス効果は、スイッチが回路の残りの部分との接触を確立する「接点」を物理的に開閉した結果として発生します。 接点が分離(スイッチを開く)または結合(スイッチを閉じる)し始めると、いくつかの小さな電気アークが発生する可能性があります。また、回路に機械的弾性が発生し、回路のオンとオフが数ミリ秒トリガーされます。 照明スイッチを切り替えると、この効果は明ら​​かではありません。 ただし、信号の立ち下がりエッジに割り込みを付加すると、このバウンス効果によって大量の割り込みがトリガーされます。 詳細はこちら。

回路のデバウンス

ハードウェアデバウンス回路と同様のバージョンの両方をソフトウェアに実装しました。 しかし、ソフトウェアのデバウンスをどの程度正確に実装しますか? 簡単! 最初に予想されるトリガーが発生した後、新しい割り込みのリッスンを開始する前に、バウンスが落ち着くまで十分な時間を「待機」します。 これは、Cの数行で実行できます。

 void countRainCycles() { if (nextTimeRainIterrupt == 0 || nextTimeRainIterrupt < millis()) { rainCyclesCounter++; // The interrupts counter nextTimeRainIterrupt = millis() + 100; // Wait 100msecs before next trigger } }

millis()関数は、Arduinoがオンになってからの現在の実行時間をミリ秒単位で返します。 また、これらの変数は、実行を最適化しないようにコンパイラーに指示し、ハードウェア割り込み中の不正確な値を回避するために、揮発性として定義する必要があることにも注意してください。

どういうわけか、蓄積されたデータを保存し、これらの測定値をMySQLデータベースに定期的に送信するステーションが必要でした。 そこで、SDスロットを備えたイーサネットモジュールを追加して、値をログに記録し、ユーザー(サーバー)がステーションに接続するたびに値を取得しました。 自宅でADSL接続を使用してテストしている間、これは驚くほどうまく機能しましたが、3Gインターネット(3Gモデムを使用)でこれを「フィールド」でテストすると、ステーションを取得しようとするとランダムにリセットされるため、ほとんど髪を失いました。測定! 重要なテストの結果、接続されたクライアントへのデータの「提供」を説明するインターネット全体で提供された例では、接続が非常に貧弱で、パケット送信の途中でクライアントへの接続が失われる可能性があるとは考えられていなかったことがわかりました。出力バッファがオーバーフローします。 しかし、接続が切断されるとバッファオーバーフローが発生するのはなぜですか? さて、送信セッションが開始され、ステーションが出力バッファをデータでいっぱいにし始めたとしましょう。 理想的には、クライアントはこのバッファがいっぱいになるよりも早くこのバッファを消費します。 ただし、3Gモデムで接続する場合は、そうではありませんでした。 クライアントへの接続が非常に貧弱だったため、バッファが消費されるよりも早くいっぱいになり、バッファオーバーフローとステーションの突然の再起動の両方が発生しました。

この問題に対処するには、Arduinoに付属のイーサネットライブラリに次のような関数を追加する必要がありました。

 int EthernetClient::free() { if (_sock != MAX_SOCK_NUM) return W5100.getTXFreeSize(_sock); return 0; }

次に、クライアントがバッファに空き容量があるかどうかを確認してから、さらにデータを入力することができました。

 while (file.available() > 0) { if (client.free() > 0) { // This was key to solving the issue c = file.read(); client.print((char)c); } else { // No free buffer? Ok, I'll wait a couple of millis... delay(50); } } file.close();

ちなみに、Arduinoのプログラミングに興味があるなら、ここに素晴らしいガイドがあります。

もう1つの興味深いタスクは、LIFOログの実装でした。 なぜこれが必要だったのですか? 通常、測定値を特定のファイルに保存する場合、アプローチは単純です。ファイルを開き、新しいサンプルを最後に追加して、ファイルを閉じます。 しかし、時系列でソートされた最新の1000個の測定値を取得したいとします。 これらの測定値はファイルの最後にあります。 したがって、ファイルを開き、カーソルを最後に移動し、最新の測定値を出力してから、ファイルカーソルを前の測定値に戻し、サンプルの区切り文字を探して、開始位置と停止位置を検出して出力する必要があります。 Arduinoにはこのプロセスをすばやく実行するのに十分なRAMもプロセッサパワーもないので、別のアプローチが必要でした。 代わりに、ファイルを逆の順序でサーバーに出力してから、文字列リテラルをサーバー側に戻すことにしました。

 unsigned long filePosition = file.size(); file.seek(filePosition); while (filePosition >= 0) { if (client.free() > 0){ file.seek(filePosition); c = file.peek(); if (c != -1) { client.print((char)c); } if (filePosition <= 0) { break; } filePosition--; } }

PHP開発者としての経験があれば、文字を正しい順序で含む最新のサンプルを簡単に入手できます。

 // $output has the reversed string measures, each sample is delimited by ; $rows = split(";", trim($output)); array_walk_recursive($rows, 'reverseString'); if (strlen($rows[0]) == 0) { array_shift($rows); // Remove the first line if empty } function reverseString(&$row, $key) { $row = trim(strrev($row)); } // $rows is now the array of the latest samples :)

次に、サーバー側でcronプロセスを設定して、2分ごとに最新の測定値を取得し、データをMySQLエンジンに挿入します。 データを表示するために、www.kitesurfcordoba.com.arを作成し、jQueryを使用してグラフを自動更新しました(グラフ自体は、優れたオープンソースライブラリであるpChart v2.0を使用して生成されます)。

ソフトウェアとハ​​ードウェアの両方のエンジニアリングに関連して、物事を機能させるために必要な他のトリックがたくさんありましたが、私は十分長い間引きずっていました。それでは、メンテナンスの最小化について話しましょう。

「どうすればメンテナンスを(ほぼ)ゼロに減らすことができますか?」

駅にたどり着くのは確かに簡単ではないので、これは大きな懸念事項でした。小さな不具合を修正するためだけに2時間運転しても構わないと思っていれば、そもそも彼女を連れて行く必要はなかったでしょう(私はこれについては前に触れませんでしたが、結局のところ、駅は実際には「彼女」であり、彼女の名前はドロシーです)。

では、ここでどのようなエラーについて話しているのでしょうか。 たとえば、ソフトウェアがハングしたり、ネットワークが接続を失ったり、エネルギー供給が失敗したりする可能性があります(実際に失敗する可能性があります)。

基本的に、ステーションは可能な限り多くの自己回復を実行する必要があります。 そのため、ソフトウォッチドッグとハードウォッチドッグの両方を使用しました。 なじみのない人にとって、ウォッチドッグは、システムが正しく動作しているかどうかをチェックし、正しく動作していない場合は、システムを復活させようとするソフトウェアまたはハードウェアです。 Arduinoには、使用できるウォッチドッグが組み込まれています。 8秒間待機するように設定しました。通話にその制限時間より長くかかると、ソフトウェアウォッチドッグがボードをリセットします。

 wdt_enable(WDTO_8S); // "wdt" stands for "watchdog timer"

私はこの機能が大好きです。 ただし、ボードがリセットされ、イーサネットモジュールがリセットされない場合があります。 なんで? まあ、これは比較的手頃なプロトタイピングボードであり、非常に高価でフェイルプルーフのデバイスではありません(確かにそれを使ってペースメーカーを構築するべきではありません)。 この欠点を克服するために、ハードウェアリセット入力をボード自体のデジタル出力にクロスワイヤリングしてArduinoをハックする必要がありました。 リセットループを回避するには、数行のコードも追加する必要があります。

 void setup() { digitalWrite(RESET_ARDUINO_PIN, HIGH); // Set it to HIGH immediately on boot pinMode(RESET_ARDUINO_PIN, OUTPUT); // We declare it an output ONLY AFTER it's HIGH digitalWrite(RESET_ARDUINO_PIN, HIGH); // Default to HIGH, set to LOW to HARD RESET ...

その後、 digitalWrite(RESET_ARDUINO_PIN, LOW)を呼び出すだけで、Arduinoとその上のすべてのモジュール(イーサネットモジュールを含む)にハードウェアリセットを発行できました。これにより、ドロシーは数秒後に復活しました。

さらに、ボードはエネルギー損失後に自動再起動します。 また、インターネット接続に障害が発生した場合、SDカードのストレージ機能を利用します(データはカードに1週間以上保存でき、サーバーは古いデータを取得して不足しているサンプルを回復できます)。 これらすべての機能を組み合わせることで、監視用に構築された敵対的な状況に耐えることができる非常に堅牢な気象観測所が得られます。 合計で、これは私にちょうど約300ドルの費用がかかりました。

円グラフのグラフィック

そして最後に

ステーションは2012年12月から稼働しています。現在まで、故障していません(または、故障した場合、ステーションはカイトサーフィンコミュニティと私が気付かなかったほど速く回復しました)。 スポットに行く前に定期的にウェザーステーションをチェックするカイトサーファーは約500人います。 ですから、いくつかの難しい技術的課題を解決するという報酬の他に、私はたくさんの人々にもっと楽しいカイトサーフィン体験を提供する機会もありました。

1当初、私はArduinoUnoを使用していました。 その後、RAMとフラッシュメモリを増やす必要があるため、ArduinoMegaに切り替えました。

関連: ESP32オーディオサンプリングの操作