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

Arduinoを搭載したウォーターボトル

コンポーネントと消耗品

>
SparkFun Arduino Pro Mini 328-5V / 16MHz
× 1
防水超音波センサー
× 1
リアルタイムクロック(RTC)
× 1
SparkFun Common-cathode4桁7セグメントディスプレイ
× 1
ブザー
× 1
SparkFunプッシュボタンスイッチ12mm
× 1
汎用トランジスタNPN
× 1
リチウムイオン電池1000mAh
× 1
AdafruitUSBリチウムイオンバッテリー充電器
× 1
抵抗221オーム
× 8
抵抗1kオーム
× 4
抵抗4.75kオーム
× 2

必要なツールとマシン

>
はんだごて(汎用)
ホットグルーガン(汎用)

アプリとオンラインサービス

>
Arduino IDE

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

はじめに:

十分な水を飲むことは私たちの健康にとって非常に重要です。より多くの水を飲むと、肌がよりきれいになり、全体的な健康状態が改善され、生産性と脳機能が改善され、エネルギーレベルが上昇し、さらには体重が減少する可能性があります。

私たちの忙しい生活の中で、十分な水を飲むことを覚えておくのは本当に難しいです。そして、ほとんどの場合、家でも、オフィスでも、外出先でも、十分な水を飲むのを忘れています。アメリカ人の約75%は常に慢性的に脱水状態になっています。

したがって、健康的な水を飲む習慣を身に付けるには、毎日の水分摂取量を追跡することが重要です。

水の摂取量を追跡するために、Arduinoを使用してウォーターボトルをスマートにしました。次のことができます:

1.毎日の水分摂取量を追跡します

2.毎週の平均水分摂取量を追跡します

3.水を取るように私に思い出させてください

4.最後の摂取時間を追跡する

5.1回の充電で1か月以上実行します。

RTCモジュールの作成

取水情報を記録または追跡するには、現在の日時情報を蓄積されたデータと一緒に保存する必要があります。適切なバックアップバッテリを備えたDS1307などのリアルタイムクロック(RTC)チップを使用して、必要な情報を提供できます。 RTCチップ(ソフトウェア)のプログラミングプロセスも非常にシンプルで、ほとんどのプログラミング環境でサポートされています。

<図> <図> <図>

これは、日常のマイクロコントローラープロジェクト向けの、人気のあるRTC ICDS1307に基づくコンパクトなRTCモジュールの設計です。 DS1307シリアルリアルタイムクロック(RTC)は、低電力の完全な2進化10進数(BCD)クロック/カレンダーに56バイトのNVSRAMを加えたものです。アドレスとデータは、I2C双方向バスを介してシリアルに転送されます。 24時間/ 12時間形式の時計/カレンダーは、うるう年の修正を含む、秒、分、時間、日、日付、月、および年の情報を提供します。

添付の回路図に従ってリアルタイムクロックモジュールを作成しましょう。 DS1307 RTCを正しく動作させるには、外部水晶振動子が必要です。 ICのSCL&SDAピンには2つのプルアップ抵抗が必要です。抵抗の値は約2kから10kかもしれません。 4.7kを使用しました。はんだ付け中は、回路のスペースが限られているため、モジュールをできるだけ小さくするようにしました。 DS1307の代わりにDS3231を使用でき、ICには水晶発振器が内蔵されています。したがって、外部クリスタルを追加する必要はありません。自分で作りたくない場合は、既製の小さなRTCモジュールを購入することもできます。システム全体がバッテリーで動作するため、コイン電池を使用せずにRTCのVBATピンをアースに接続しました。

DS1307の重要なピン:

  • 5Vピン :このピンがハイの場合、ds1307はデータを送信し、ローの場合、バックアップボタン電池で実行されます。
  • GND :これはモジュールのアースピンです。バッテリーのアースと電源の両方が相互に接続されています。
  • SCL :マイクロコントローラと通信するのはI2Cクロックピンです。 ArduinoSCLピンに接続する必要があります。
  • SDA :マイクロコントローラと通信するのはI2Cデータピンです。 ArduinoSDAピンに接続する必要があります。
  • VBAT :標準の3Vリチウム電池またはその他のエネルギー源用のバッテリー入力。使用しない場合は接地する必要があります。

7セグメントディスプレイボードの作成

ここでの表示モジュールには、いくつかの単純な文字で数値データを表示するのに適した4つの7セグメントLED数値ディスプレイを含む自己完結型のコンパクトなコモンカソードモジュールを使用しました。

ディスプレイモジュールの各セグメントは多重化されています。つまり、同じアノード接続ポイントを共有しています。また、モジュールの4桁のそれぞれに、独自の共通カソード接続ポイントがあります。これにより、各桁を個別にオンまたはオフにすることができます。また、この多重化技術は、ディスプレイを制御するために必要な大量のマイクロコントローラーピンを(32ではなく)わずか11または12に変えます!

<図> <図> <図>

ディスプレイのLEDセグメントには、5Vロジックピンから電力を供給する場合に電流制限抵抗が必要です。抵抗の値は、通常、5 Vで330〜470オームです。リチウムイオン電池の動作では、220オームになる場合があります。また、マイクロコントローラの各ピンは40 mA近くの電流しかソースまたはシンクできないため、LEDセグメントに追加の駆動電流を供給するためにドライバトランジスタをお勧めします。ディスプレイのすべて(7)セグメントが同時にオンになると(数字の8)、電流需要はこの40mAの制限を超えます。下の画像は、電流制限抵抗とドライバトランジスタの基本的な配線図を示しています。

この4桁の7セグメントディスプレイセクションは、4つのコモンカソード7セグメントLEDディスプレイと4つの2N2222NPNトランジスタの周りに配線されています。 1K抵抗はベース電流制限に使用され、220R抵抗はLEDディスプレイセグメントの動作電流を制限します。

Arduinoボードでは、D10からD17までのデジタル出力がセグメント(aからg&dp)を駆動するために使用され、デジタル出力D6からD9が4×7 LEDディスプレイの桁(D0からD3)に使用されます。

さまざまなオプションにアクセスするためのボタンスイッチがディスプレイモジュールに追加されています。また、外部ハードウェア割り込みを使用して、Arduinoをスリープモードからウェイクアップするためにも使用されます。そのため、ボタンはArduinoデジタルピン#2(INT0)に接続されています。

ディスプレイボードとArduinoMiniProの接続

前に提供された回路図によると、すべてのセグメントピンをArduinoミニピンにはんだ付けします。次に、4つの共通ピンをトランジスタのコレクタピンにはんだ付けします。トランジスタのベースはArduinoピンに接続されています。ディスプレイを接続した後、ボタンスイッチをArduinoデジタルピン2(INT 0)に接続します。このボタンを使用してArduinoをスリープモードからウェイクアップするための外部ハードウェア割り込みを実装するため、ボタンをArduinoピン2に接続していることを確認してください。

<図> <図> <図> <図> <図>

RTCモジュールとブザーの接続

次に、前に作成したRTCモジュールをArduinoボードに接続します。モジュールのSDAピンはArduinoピンのSDA(A4)ピンに接続する必要があり、モジュールのSCLピンはArduinoのSCL(A5)ピンに接続する必要があります。次に、ブザーをArduinoボードに接続します。

<図> <図>

接続:

RTC ------> Arduino Mini Pro

  • SDA ------> A4
  • SCL ------> A5
  • ブザー------> D3

ボトルキャップ付き超音波センサーの取り付け

画像のようにボトルキャップに穴を開けます。超音波センサーの4本のワイヤーを穴から引き出し、ボトルキャップの中央に超音波センサーを固定しました。センサーはボトルキャップの内側に取​​り付け、中央の位置に配置する必要があります。

<図> <図> <図>

接続:

超音波センサー------> Arduino Mini Pro

  • VCC ------> VCC
  • GND ------> GND
  • トリガー------> D4
  • エコー------> D5

プログラムのアップロードとテスト

すべての接続が完了したら、Arduinoボードにプログラムをアップロードして機能をテストするのに適切なタイミングです。プログラムが正しく動作するには、いくつかのライブラリが必要になります。ボタンインターフェースの場合、OneButtonライブラリを追加する必要があります。デバイスはバッテリーで動作するため、消費電力は重要な問題です。 Arduinoスケッチにスリープモードを実装しました。ウォッチドッグタイマーと外部ハードウェア割り込みを使用して、Arduinoをスリープモードからウェイクアップしました。 Arduinoはセンサーの読み取りを3回行い、平均して必要な情報を計算し、情報を10秒間表示してから、1分間スリープモードに移行します。 INT0(デジタルピン2)に接続されたボタンを押すといつでもウェイクアップします。したがって、水分摂取量に関する情報を確認したい場合は、いつでもオプションボタンを押してください。それはあなたのために目覚めます。ボタンを押さなくても、1分ごとに読み取りが必要になります。スリープモードを実装するために、Arduino低電力ライブラリを使用しました。 DS1307 RTCモジュールからの読み取り時間には、DS1307RTCライブラリを使用しました。したがって、添付のプログラムをコンパイルするには、すべてのライブラリを環境に追加します。

<図>

ここでは、計算アルゴリズムについてのみ簡単に説明します。完全なスケッチについては、添付の塗りつぶしを参照してください。計算は、5つのセンサー読み取り値の平均から行われ、十分に正確になります。毎日の読書は24時間でリセットされ、新しい日の新しい読書の準備が整います。

平均水分摂取量は、過去7日間の1日の摂取量の平均から作成されます。水をまったく摂取せずに2時間経過すると、15分ごとに2回のビープ音が鳴り、水を摂取した後2時間停止します。

添付のコードをダウンロードして、Arduino MiniProにアップロードします。すべてのモジュールを接続して電源を入れ、すべてのコンポーネントが正しく機能しているかどうかをテストします。ディスプレイに結果が表示されたら、おめでとうございます。あなたはすでに難しいことをしました。

ボトルキャップでArduinoを修正する

ホットグルーを使用して、ボトルキャップの上側にArduinominiを取り付けます。すべてのコンポーネントをボトルキャップに固定する必要があることに注意してください。ボトルキャップにしっかりと接着するように、十分な接着剤を追加します。

<図>

バッテリーと充電器モジュールの取り付け

次に、Arduinoの上部にあるLi-ionバッテリーを固定します。開いているピンでバッテリーを短絡する場合は注意してください。次に、充電器モジュールをキャップに接続します。 USBポートは、充電器に簡単に接続できるように、外側から簡単にアクセスできるようにしてください。

<図> <図> <図>

すべての回路を防水にする

すべてのコンポーネントとモジュールを接続したら、デバイスを完全に防水にするのに適切なタイミングです。それはウォーターボトルであり、いつでも水が回路に落下して回路を損傷する可能性があるため、これは非常に重要です。完全防水にするには、USBポートのない回路のすべての外側部分に十分な接着剤を追加します。接着剤を使ってキャップを元のキャップに丸くすることができます。

<図> <図> <図> <図>

ボトルキャップを水に沈めないでください。

楽しんでください

<図>

コード

  • Arduinoスケッチ
Arduino Sketch Arduino
 // I2CとWireを介して接続されたDS1307RTCを使用した日付と時刻の関数lib#include  #include  #include  #include  #include " LowPower.h "#include" OneButton.h "OneButton button(2、true); const byte InterruptPin =2; volatile int state =0; const int trigPin =4; const int echoPin =5; int piezoPin =3; const int Digit [4] ={9,6,7,8}; int Digit_value [4]; int Digit_value1 [4]; int button_press_count =1; const int segment [8] ={16,10,12,14,15、 17,11,13}; const byte number [10] [8] ={{1,1,1,1,1,1,0,0}、// 0 {0,1,1,0,0、 0,0,0}、// 1 {1,1,0,1,1,0,1,0}、// 2 {1,1,1,1,0,0,1,0}、/ / 3 {0,1,1,0,0,1,1,0}、// 4 {1,0,1,1,0,1,1,0}、// 5 {1,0,1 、1,1,1,1,0}、// 6 {1,1,1,0,0,0,0,0}、// 7 {1,1,1,1,1,1,1 、0}、// 8 {1,1,1,1,0,1,1,0}}; // 9constバイトd [8] ={0,1,1,1,1,0,1,1}; constバイトa [8] ={1,1,1,0,1,1,1,1 }; const byte r [8] ={0,0,0,0,1,0,1,1}; const byte t [8] ={0,0,0,1,1,1,1,1 }; int秒、分、時間; int water_in_ounch [15]; int water_intake_ounch [15]; int water_intake_days [7]; int water_intake_times =0; int previous_water_amount =0; int total_water_intake_today =0; int average_intake_last_week =0; int inatke_day =1; float average_water_level =0; //複数の読み取り値の平均を保存intwater_amount_in_ounce =0; //計算されたwaterintidle_time =0; intintake_day =1; int previous_value =0; void setup(){Serial.begin(9600);を保存します。 pinMode(interruptPin、INPUT_PULLUP); //セットアップコードをここに配置して、1回実行します:for(int i =6; i <=17; i ++)pinMode(i、OUTPUT); pinMode(trigPin、OUTPUT); pinMode(echoPin、INPUT); button.attachClick(押された); button.attachDoubleClick(doubleclick); button.attachLongPressStart(longPressStart); button.attachDuringLongPress(longPress);} long previous_state =millis(); int count =1; int daily_intake =0; int weekly_intake =0; long sleep_time =millis(); void loop(){read_time(); button.tick(); //プッシュボタンを監視し続けます:calculation(); daily_intake =total_water_intake_in_day(); weekly_intake =average_water_intake_last_week(); if(button_press_count ==1){display_d(); display_number(daily_intake); } else if(button_press_count ==2){display_a(); display_number(weekly_intake); } else if(button_press_count ==3){display_r(); display_number(water_amount_in_ounce); } else if(button_press_count ==4){display_first_2(hours); display_last_2(minutes); } if(idle_time> =120){alert(); alert(); } if((millis()-sleep_time)> =15000){display_off(); attachInterrupt(digitalPinToInterrupt(interruptPin)、空白、FALLING); LowPower.powerDown(SLEEP_8S、ADC_OFF、BOD_OFF); LowPower.powerDown(SLEEP_8S、ADC_OFF、BOD_OFF); LowPower.powerDown(SLEEP_8S、ADC_OFF、BOD_OFF); LowPower.powerDown(SLEEP_8S、ADC_OFF、BOD_OFF); LowPower.powerDown(SLEEP_8S、ADC_OFF、BOD_OFF); LowPower.powerDown(SLEEP_8S、ADC_OFF、BOD_OFF); detachInterrupt(digitalPinToInterrupt(interruptPin)); sleep_time =millis(); }} void display_digit(int digit){for(int i =0; i <8; i ++){digitalWrite(segment [i]、number [digit] [i]); }} void display_number(int number){int i =0; while(number> 0){digit_value [2-i] =number%10;数=数/ 10; i ++; } digitalWrite(digit [1]、HIGH); digitalWrite(digit [2]、LOW); digitalWrite(digit [3]、LOW); display_digit(digit_value [0]); delay(5); digitalWrite(digit [1]、LOW); digitalWrite(digit [2]、HIGH); digitalWrite(digit [3]、LOW); display_digit(digit_value [1]); delay(5); digitalWrite(digit [1]、LOW); digitalWrite(digit [2]、LOW); digitalWrite(digit [3]、HIGH); display_digit(digit_value [2]); delay(5); digitalWrite(digit [3]、LOW); Digit_value [0] =0; Digit_value [1] =0; Digit_value [2] =0; } void display_first_2(int number){digitalWrite(digit [2]、LOW); digitalWrite(digit [3]、LOW); int i =0; while(number> 0){digit_value [1-i] =number%10;数=数/ 10; i ++; } digitalWrite(digit [0]、HIGH); digitalWrite(digit [1]、LOW); display_digit(digit_value [0]); delay(3); digitalWrite(digit [0]、LOW); digitalWrite(digit [1]、HIGH); display_digit(digit_value [1]); delay(3); } void display_last_2(int number){digitalWrite(digit [0]、LOW); digitalWrite(digit [1]、LOW); int i =0; while(number> 0){digit_value1 [1-i] =number%10;数=数/ 10; i ++; } digitalWrite(digit [2]、HIGH); digitalWrite(digit [3]、LOW); display_digit(digit_value1 [0]); delay(3); digitalWrite(digit [2]、LOW); digitalWrite(digit [3]、HIGH); display_digit(digit_value1 [1]); delay(3); } void display_d(){digitalWrite(digit [0]、HIGH); for(int i =0; i <8; i ++){digitalWrite(segment [i]、d [i]); } delay(5); digitalWrite(digit [0]、LOW); } void display_a(){digitalWrite(digit [0]、HIGH); for(int i =0; i <8; i ++){digitalWrite(segment [i]、a [i]); } delay(5); digitalWrite(digit [0]、LOW); } void display_r(){digitalWrite(digit [0]、HIGH); for(int i =0; i <8; i ++){digitalWrite(segment [i]、r [i]); } delay(5); digitalWrite(digit [0]、LOW); } void display_t(){digitalWrite(digit [0]、HIGH); for(int i =0; i <8; i ++){digitalWrite(segment [i]、t [i]); } delay(5); digitalWrite(digit [0]、LOW); } void display_off(){digitalWrite(digit [0]、LOW); digitalWrite(digit [1]、LOW); digitalWrite(digit [2]、LOW); digitalWrite(digit [3]、LOW); for(int i =0; i <8; i ++){digitalWrite(segment [i]、LOW); } delay(5); } void read_time(){tmElements_t tm; if(RTC.read(tm)){秒=tm.Second;分=tm.Minute;時間=tm.Hour; }} int distance_in_cm(){long duration、cm; //センサーは10マイクロ秒以上のHIGHパルスによってトリガーされます。 //クリーンなHIGHパルスを確保するために、事前に短いLOWパルスを与えます。digitalWrite(trigPin、LOW); delayMicroseconds(2); digitalWrite(trigPin、HIGH); delayMicroseconds(10); digitalWrite(trigPin、LOW); //センサーからの信号を読み取ります。//持続時間がpingの送信から//オブジェクトからのエコーの受信までの時間(マイクロ秒単位)であるHIGHパルス。期間=pulseIn(echoPin、HIGH); //時間を距離に変換しますcm =microsecondsToCentimeters(duration);リターンcm; } long microsecondsToCentimeters(long microseconds){//音速は340 m / sまたは29マイクロ秒/センチメートルです。 // pingは前後に移動するため、//オブジェクトの距離を見つけるために、移動した距離の半分を取ります。マイクロ秒を返す/ 29/2; } void alert(){tone(piezoPin、2000、50);トーン(piezoPin、2000、200); // delay(10); } void blank(){// tone(piezoPin、2000、100); // state ++;} //この関数は、button1が1回押されたときに呼び出されます(2.ボタンが押された後はありません)。voidpressed(){// Serial.println( "Button 1 click。"); button_press_count ++; alert(); if(button_press_count ==5){button_press_count =1; }} // click //この関数は、button1が短い時間枠で2回押されたときに呼び出されます。voiddoubleclick(){Serial.println( "Button 1 doubleclick。");} // doubleclick //この関数はbutton1が長時間押されたときに一度呼び出されます。voidlongPressStart(){Serial.println( "Button 1 longPress start");} // longPressStart //この関数は、button1が押されている間に頻繁に呼び出されます。 a long time.void longPress(){Serial.println( "Button 1 longPress ..."); water_intake_ounch [water_intake_times --1] =0; //最後の値を無視します} // longPressvoid Calculation(){float water_level =0; //すべてのステップでレベルを保存しますintread_value =0; //センサーの読み取り値をcm単位で読み取りますfor(int i =0; i <5; i ++){// 5つの読み取り値を取得read_value =distance_in_cm(); if(read_value> 16 || read_value <3){//不安定な読み取り値return; //読み取りが不安定なため、呼び出し元の関数に戻ります} else if(read_value <=16 &&read_value> =3){//有効な値water_level =water_level + read_value; } delay(10); } average_water_level =17-water_level / 5; // 5つの読み取り値から平均を求めます。17=ボトールの高さwater_amount_in_ounce =int(average_water_level * 1.87); // 16cmの水位=30 ounch if(water_intake_times ==0){previous_water_amount =water_amount_in_ounce; water_intake_times =1; } if((water_amount_in_ounce  previous_water_amount){//水が補充されます//ここで水が補充されますprevious_water_amount =water_amount_in_ounce; } else if(water_amount_in_ounce ==previous_water_amount){//水を消費しないか、idle_time + =1を補充します。 } if(hours ==23 &&minutes ==59){// 1日が終わり、すべての値は新しい日のゼロから始まりますfor(int i =0; i <15; i ++){water_intake_ounch [i] =0; } water_intake_times =0;摂取日++; if(intake_day ==8){intake_day =1; }}} int total_water_intake_in_day(){// 1日の総水分摂取量を計算するtotal_water_intake_today =0; for(int i =0; i  

回路図


製造プロセス

  1. 芝生のスプリンクラー
  2. 食器洗い機
  3. 水鉄砲
  4. トイレ
  5. 消火栓
  6. 断熱ボトル
  7. シャンプー
  8. 乾式壁
  9. 集積回路
  10. MOSMusic