【Arduino】観葉植物の自動水やり装置を作ってみた

この記事はブログとプログラミングで生計をたてている海外在住ウェブディベロッパーがわかりやすさにこだわって作成しました

はじめに

 

みずやり装置とかでググってみると、すでに大勢の方がいろんな方法で自動水やり装置を作っています。Arduinoとネットで中国から取り寄せたいろいろな部品を使って、観葉植物に水をやる装置を試作してみました。

 

 

 

使ったもの  

  • Arduino Nano
  • USB電源
  • AMS1117-3.3 DC-DC ステップダウン パワーモジュール
  • 土壌水分センサーモジュール
  • リレーモジュール、LCDモジュール、LEDライト他
    ※下記の記事『【Arduino】ダイソー5LEDライトスタンドを改造してみた』の「今回使用したもの」を参照
  • 水中ポンプ
  • DFPlayer Mini(MP3再生モジュール)
  • タクトSW
  • ブレッドボード他

 

【Arduino】ダイソー5LEDライトスタンドを改造してみた | diy.smart-agri.info

 

実現したいこと

 

  • 通常モードで、スイッチが押されると土壌のかわき具合をLCDに表示する
  • 通常モードで、土壌が乾燥してくると水やりモードに移行し、次の動作をする(以下水やりモードでの動作)
    • LCDに常に土壌のかわき具合を常時表示する(バックライトON)
    • 水やりモードでは、土壌の乾き具合によって「水がほしい」とか「もう少し」とか言う
    • 十分土壌が潤ったら、通常モードに移行し、「もう大丈夫」と言う
    • スイッチが押されると水中ポンプを回して、「ありがとう」とお礼を言う
    • 水やりモードのまましばらく放置されると 、サイレントモードに移行する(以下サイレントモードでの動作)
        ※夜間は常にサイレントモードになる 
      • LCDは常時OFFでたまに表示する
      • スイッチが押されると、水やりモードに復帰する
      • サイレントモードでしばらく放置すると、たまに水やりモードに復帰する
      • たまに「水がほしい」と言う
  • パラメータ値は設定可能にする。

 

 

ハードウェア設計とパーツ設定

 

Arduino

これがないとはじまりません。ArduinoはC++に似た言語でプログラミングをすることができます。学習用途からメディアアート作品、プロトタイプまで幅広く使われているマイコンボードです。CPUやメモリなどが組み込まれたマイクロ・コントローラとそれらを動作させるための最小限の回路が組み込まれています。

USB電源

  • ARDUINO VCC、GNDに接続する。

土壌水分センサーモジュール

  • Arduino NanoのVCC、GND、A0を土壌水分センサーに接続する

水中ポンプ

AMS1117-3.3 DC-DC ステップダウン パワーモジュール

  • USB電源5V、GNDを接続する。
    ※DFPlayer Miniは電源電圧が3.3Vのためこの降圧モジュールを使用する

DFPlayer Mini(MP3再生モジュール)

  • VCC、GNDをAMS1117-3.3 DC-DC ステップダウン パワーモジュール の3.3VとGNDに接続する。
  • TX、RXをARDUINOのRX、TXにそれぞれ接続する。

タクトSW

  • DIO4をタクトSW(DIO側)に接続する。
  • SW(DIO側)とGNDを抵抗(10KΩ)を挟んで接続する。
  • SW(VCC側)とArduinoVccを接続する

 

 

ソフトウェア設計

ソフトウェアで実現したいことは次のようなことです

 

動作モードとして、通常モード(土壌が乾いていないとき)、水やりモード(土壌が乾いて水やりが必要な場合)、サイレントモード(水やりモードで一定時間経過した場合)があり、それぞれ異なる動きをする。どのモードの場合でも、共通の処理は必ず行われる。 また、パラメータの設定などの設定モードがあり、こちらは特定のキー操作で移行または復帰する。

  • 通常モード⇔水やりモード⇔サイレントモード
  • 通常モード/水やりモード⇔設定モード

1.共通の処理

  • 土壌水分センサーの値を読み、パーセンテージに置き換える

2.通常モードの処理

  • 土壌のかわき具合がr%を超えている場合は、水やりモードに移行する ※このとき催促開始時間を現在時間(millis()で取得)に設定する
  • スイッチが押されている場合は、土壌のかわき具合を3秒間LCDに表示する

3.水やりモードの処理

  • LCDに土壌のかわき具合を常に表示する
  • スイッチON経験フラグがOFFの場合、m分経過判定を行い、「水がほしい」と言う
  • スイッチON経験フラグがONかつかわき具合s%超過であれば、m分経過判定を行い、「まだ、たりない」と言う
  • スイッチON経験フラグがONかつ土壌のかわき具合t%超過であれば、m分経過判定を行い、「あともう少し」と言う
  • スイッチON経験フラグがONかつ土壌のかわき具合t%以下になれば、通常モードに移行し、「もう大丈夫」と言う ※このときスイッチON経験フラグをOFFにする
  • スイッチが押されるとx秒間水中ポンプを回して、「ありがとう」とお礼を言う ※このときスイッチON経験フラグをONにする ※このとき催促開始時間を現在時間(millis()で取得)に設定する
  • n分経過すれば、サイレントモードに移行する

4.サイレントモードの処理

  • LCDのバックライトを点滅(ON/OFF)する
  • スイッチが押されると、水やりモードに復帰する
  • p分経過すると、水やりモードに復帰する
  • q分おきに「水がほしい」と言う

5.設定モードの処理

  • 通常モードまたは水やりモードから特定のキー操作により設定モードに移行する
  • 特定のキー操作により設定モード移行前のモードに復帰する
  • 設定モードでは、パラメータ等の設定処理を行う

6.ファンクション

n分経過判定

  • 催促実施フラグがOFFかつ((現在時間(millis()で取得)-催促開始時間)% (60000×n)) > ((60000×n) – 50)の場合、 n分経過と判断する。それ以外の場合、n分未経過と判断する
  • ((現在時間(millis()で取得)-催促開始時間)% (60000×n)) < 50の場合、 催促実施フラグをOFFにする
  • n分経過と判断すると、催促実施フラグをONにする

 

 

作成したスクリプト

こちらがそのスクリプトです。Arduinoに書き込んで動作します。

簡易動作バージョン
[code lang=”c”]
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>

//Digital I/O
#define DIO_RELAY_OUTPUT  3
#define DIO_TACTSW_INPUT  4
#define DIO_STATUSLED_INPUT  13
//Analog input
#define ANG_WATER_SENSOR 0

//Relay mode
#define RELAY_ACT_MODE_ON  0
#define RELAY_ACT_MODE_OFF 1

//tactSW status
#define TACT_SW_STATUS_ON  1
#define TACT_SW_STATUS_OFF 0


//LCD I2C
//int I2CADR = 0x3F;  
int I2CADR = 0x3E;  
//int I2CADR = 0x27;  

LiquidCrystal_I2C lcd(I2CADR, 16, 2);




String strBuf = "";
int msec;
char s[32];
  int i;
  int stat;
  int relay_act_mode;  
int act_mode = 0;	//0:通常モード、1:水やりモード


void flashLed(int pin, int times, int wait) {
    
    for (int i = 0; i < times; i++) {
      digitalWrite(pin, HIGH);
      delay(wait);
      digitalWrite(pin, LOW);
      
      if (i + 1 < times) {
        delay(wait);
      }
    }
}

void setup() {
  pinMode(DIO_TACTSW_INPUT, INPUT);			//タクトSW
  pinMode(DIO_STATUSLED_INPUT, OUTPUT);	//ARDUINO LED
  pinMode(DIO_RELAY_OUTPUT, OUTPUT);			//リレー出力
  digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_OFF);	//リレー出力(OFF)
  relay_act_mode=RELAY_ACT_MODE_OFF;					//実際のリレー出力の状態と一致させる
  
  //LCD初期化
  lcd.setBacklight(0);
  lcd.init();
  //LCD初期表示
  lcd.setCursor(0, 0);
  lcd.print(" A HINT OF");
  lcd.setCursor(0, 1);
  lcd.print("  SMART AGRI!!");
  lcd.setBacklight(1);
  delay(2000);  //wait 1ms for mp3 module to set volume
  lcd.setBacklight(0);
  //SERIAL I/F初期化
  Serial1.begin (9600);  //Serial1 for DFPlayer-mini mp3 module 
  Serial.begin (9600);   //Serial for standard serial I/F
  while (!Serial);
  //MP3初期化
  mp3_set_serial (Serial1);  //set Serial for DFPlayer-mini mp3 module 
  mp3_set_volume (20);
  delay(100);  //wait 1ms for mp3 module to set volume
  mp3_play (1); //Startup sound
  delay (3000);
  mp3_stop ();  //Stop after played for XXsec.
  
}

void loop() {

/*
  digitalWrite(DIO_RELAY_OUTPUT, HIGH);
  digitalWrite(DIO_STATUSLED_INPUT, LOW);
  delay(2000);
  digitalWrite(DIO_RELAY_OUTPUT, LOW);
  digitalWrite(DIO_STATUSLED_INPUT, HIGH);
  delay(2000);
*/
/*
  if(millis() % 3600000L == 0) {
    lcd.setBacklight(1);
    lcd.setCursor(0, 0);
    lcd.print(" A HINT OF");
    lcd.setCursor(0, 1);
    lcd.print("  SMART AGRI!!");
    digitalWrite(DIO_RELAY_OUTPUT, 0);
  }
  else if(millis() % 3600000L == 5000)  {
    lcd.setBacklight(0);
    lcd.clear();
    digitalWrite(DIO_RELAY_OUTPUT, 1);
  }
*/
  //リレー停止中かつタクトSW ON検出時は、リレー停止⇒リレー駆動
  if(relay_act_mode==RELAY_ACT_MODE_OFF && digitalRead(DIO_TACTSW_INPUT)==TACT_SW_STATUS_ON) {
    digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_ON);
    relay_act_mode=RELAY_ACT_MODE_ON;

  mp3_set_volume (20);
  delay (500);
  mp3_next ();
    
    sprintf(s, " %5d  %5d", analogRead(ANG_WATER_SENSOR), (int)((analogRead(ANG_WATER_SENSOR)-523.0)/500.0*100));
    //sprintf(s, "%5d  %5d", analogRead(ANG_WATER_SENSOR), analogRead(1));
    lcd.setBacklight(1);
    lcd.setCursor(0, 0);
    lcd.print("Raw    Percentage");
    lcd.setCursor(0, 1);
    lcd.print(s);
    
  //リレー駆動中かつタクトSW OFF検出時は、リレー駆動⇒リレー停止
  } else if(relay_act_mode==RELAY_ACT_MODE_ON && digitalRead(DIO_TACTSW_INPUT)==TACT_SW_STATUS_OFF) {
    digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_OFF);
    relay_act_mode=RELAY_ACT_MODE_OFF;
    lcd.setBacklight(0);
    lcd.clear();
  }else{
  }
 /* 
  //if(digitalRead(DIO_TACTSW_INPUT)){
    lcd.setBacklight(1);
      mp3_set_volume (20);
      delay (100);
     // mp3_random_play ();
     mp3_single_play (5);
    for(i=0;i<5;i++){
      digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_ON);
      delay(1000); //10sec
      digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_OFF);
      delay(1000); //10sec
    }
    delay (8000);
      //mp3_get_state ();
      //delay (10);
      //stat = mp3_wait_state();
      //  sprintf(s, "stat:%5d.", stat);
      //  lcd.setCursor(0, 0);
  //lcd.print(s);

      mp3_stop ();
    delay (2000);
    lcd.setBacklight(0);
    
  }else{
    digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_ON);
  }
  delay(500);
  */
}
[/code]
いろいろ詰め込んだフル機能バージョン
[code lang=”c”]
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>

//Digital I/O
#define DIO_RELAY_OUTPUT  3
#define DIO_TACTSW_INPUT  4
#define DIO_STATUSLED_INPUT  13
//Analog input
#define ANG_WATER_SENSOR 0

//Relay mode
#define RELAY_ACT_MODE_ON  0
#define RELAY_ACT_MODE_OFF 1

//tactSW status
#define TACT_SW_STATUS_ON  1
#define TACT_SW_STATUS_OFF 0

#define EXEC_MODE_NORMAL 0
#define EXEC_MODE_WATERPLANTS 1
#define EXEC_MODE_SILENT 2

#define ONE_MINUTE 60000

#define ON 1
#define OFF 0
#define MAX_UL 4294967295

#define INTERVAL_MAIN_LOOP 100

//LCD I2C
//int I2CADR = 0x3F;  
int I2CADR = 0x3E;  
//int I2CADR = 0x27;  

LiquidCrystal_I2C lcd(I2CADR, 16, 2);




String strBuf = "";
int msec;
char s[32];
  int i;
  int stat;
  int relay_act_mode;  
  int tact_sw_status;
  int last_tact_sw_status=-1;
int exec_mode = EXEC_MODE_NORMAL;  //0:通常モード、1:水やりモード、2:サイレントモード
int last_exec_mode = -1;  //動作モードの前回値
int setting_mode = 0; //0:OFF(非設定モード)、1:ON(設定モード)
int soilanalog = 0; //土壌水分センサー生データ(0~1023)
int soilhumid = 0; //土壌水分センサー相対値(0~100%)


unsigned long count_watermode_reminder1 = 0;  //暫定10回

unsigned long startedtime_allmode_sensing = 0;
unsigned long startedtime_normalmode_lcd_display=0;
unsigned long startedtime_watermode_reminder1=0;
unsigned long startedtime_watermode_reminder2=0;
//unsigned long startedtime_watermode_pump=0; //モータ駆動はDELAYを使用する(安全のため)
unsigned long startedtime_watermode=0;
unsigned long startedtime_silentmode=0;
unsigned long startedtime_silentmode_lcd_flash_on=0;
unsigned long startedtime_silentmode_lcd_flash_off=0;


unsigned long maxcount_watermode_reminder1 = 10;  //暫定10回
unsigned long maxcount_watermode_reminder2 = MAX_UL;  //暫定制限なし

unsigned long intervaltime_allmode_sensing = 1000; //暫定1秒
unsigned long intervaltime_normalmode_lcd_display = 3000; //暫定3秒
unsigned long intervaltime_watermode_reminder1 = 10000;  //暫定10sec
unsigned long intervaltime_watermode_reminder2 = 600000;  //暫定10min
unsigned long intervaltime_watermode_pump=2000;     //暫定2秒
unsigned long intervaltime_watermode = 1800000;      //暫定30min
unsigned long intervaltime_silentmode = 7200000;      //暫定2h
unsigned long intervaltime_silentmode_lcd_flash_on = 60000; //暫定1min
unsigned long intervaltime_silentmode_lcd_flash_off = 2000; //暫定2秒

int thr_soil_himid_level_A = 70;
int thr_soil_himid_level_B = 50;
int thr_soil_himid_level_C = 30;

/****************************************************
 * タイトル:n分経過判定                           *
 * 概要:startedtimeからn分経過判定処理をする      *
 * 内容:startedtimeからn分が経過したかどうか      *
 *       判定する。経過時はstartedtimeを初期化する  *
 *                                                  *
 ***************************************************/
int check_overtime(unsigned long n, unsigned long &startedtime) {
    if(startedtime != MAX_UL && (millis() - startedtime) > n){
        startedtime= millis();
        return ON;
    }else{
        return OFF;
    }
}

/****************************************************
 * タイトル:LEDフラッシング                        *
 * 概要:LEDを指定の間隔でフラッシングする          *
 * 内容:                                           *
 *                                                  *
 *                                                  *
 ***************************************************/
void flashLed(int pin, int times, int wait) {
    
    for (int i = 0; i < times; i++) {
      digitalWrite(pin, HIGH);
      delay(wait);
      digitalWrite(pin, LOW);
      
      if (i + 1 < times) { delay(wait); } } } /**************************************************** * タイトル:LCDに土壌水分データを表示 * * 概要:LCDに土壌水分データを表示する * * 内容: * * * * * ***************************************************/ void lcd_display(){ lcd.setBacklight(1); //LCD表示用メッセージを作成する lcd.setCursor(0, 0); if(exec_mode == EXEC_MODE_NORMAL) { lcd.print("Raw Ratio (^^)"); }else if(exec_mode == EXEC_MODE_WATERPLANTS) { lcd.print("Raw Ratio T_T"); }else if(exec_mode == EXEC_MODE_SILENT) { lcd.print("Raw Ratio .zzZ"); }else{ lcd.print("Raw Ratio ????"); } //LCDに土壌水分量情報を出力する lcd.setCursor(0, 1); sprintf(s, "%5d %5d",soilanalog, soilhumid); lcd.print(s); } /**************************************************** * タイトル:セットアップ関数 * * 概要:ARDUINO起動直後の初期処理実行関数 * * 内容: * * * * * ***************************************************/ void setup() { pinMode(DIO_TACTSW_INPUT, INPUT); //タクトSW pinMode(DIO_STATUSLED_INPUT, OUTPUT); //ARDUINO LED pinMode(DIO_RELAY_OUTPUT, OUTPUT); //リレー出力 digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_OFF); //リレー出力(OFF) relay_act_mode=RELAY_ACT_MODE_OFF; //実際のリレー出力の状態と一致させる //LCD初期化 lcd.setBacklight(0); lcd.init(); //LCD初期表示 lcd.setCursor(0, 0); lcd.print(" A HINT OF"); lcd.setCursor(0, 1); lcd.print(" SMART AGRI!!"); lcd.setBacklight(1); delay(2000); //wait 1ms for mp3 module to set volume lcd.setBacklight(0); //SERIAL I/F初期化 //Serial1.begin (9600); //Serial1 for DFPlayer-mini mp3 module Serial.begin (9600); //Serial for standard serial I/F //while (!Serial); //MP3初期化 mp3_set_serial (Serial); //set Serial for DFPlayer-mini mp3 module mp3_set_volume (20); delay(100); //wait 1ms for mp3 module to set volume mp3_play (9); //Startup sound delay (12000); mp3_stop (); //Stop after played for XXsec. } /**************************************************** * タイトル:メイン処理関数 * * 概要:メイン処理関数 * * 内容: * * * * * ***************************************************/ void loop() { //1s間隔でセンサーデータを取得 if(check_overtime(intervaltime_allmode_sensing, startedtime_allmode_sensing)) { //土壌水分センサー取得値を変数に保存する soilanalog = analogRead(ANG_WATER_SENSOR); //土壌水分センサー取得値を0~100%の相対値に変換して変数に保存する soilhumid = (int)((soilanalog-523.0)/500.0*100); } tact_sw_status = digitalRead(DIO_TACTSW_INPUT); /* digitalWrite(DIO_RELAY_OUTPUT, HIGH); digitalWrite(DIO_STATUSLED_INPUT, LOW); delay(2000); digitalWrite(DIO_RELAY_OUTPUT, LOW); digitalWrite(DIO_STATUSLED_INPUT, HIGH); delay(2000); */ /* if(millis() % 3600000L == 0) { lcd.setBacklight(1); lcd.setCursor(0, 0); lcd.print(" A HINT OF"); lcd.setCursor(0, 1); lcd.print(" SMART AGRI!!"); digitalWrite(DIO_RELAY_OUTPUT, 0); } else if(millis() % 3600000L == 5000) { lcd.setBacklight(0); lcd.clear(); digitalWrite(DIO_RELAY_OUTPUT, 1); } */ //通常モード時の処理 if(exec_mode == EXEC_MODE_NORMAL) { //起動直後または通常モードに移行してはじめての場合 if(last_exec_mode != exec_mode) { last_exec_mode = exec_mode; startedtime_normalmode_lcd_display = millis(); } //土壌のかわきがLEVELAを超過すれば水やりモードに移行する if(soilhumid > thr_soil_himid_level_A) {
            //水やりモード移行する
            last_exec_mode = exec_mode;
            exec_mode = EXEC_MODE_WATERPLANTS;
        } 

        //タクトスイッチの立ち上がり検出時
        if(last_tact_sw_status != tact_sw_status && tact_sw_status==TACT_SW_STATUS_ON) {

            //LCDに土壌水分量を表示する
            lcd_display();
            //LCD表示直後の時間を保存する
            startedtime_normalmode_lcd_display = millis();

        } 
        //タクトスイッチの立ち下がり検出時
        else if(check_overtime(intervaltime_normalmode_lcd_display, startedtime_normalmode_lcd_display) && tact_sw_status==TACT_SW_STATUS_OFF) {

            //LCDを消灯する
            lcd.setBacklight(0);
            lcd.clear();
        }else{
        }
        
        
    }
    //水やりモード時の処理
    else if(exec_mode == EXEC_MODE_WATERPLANTS) {

          //LCDに土壌水分量を表示する(常時表示)
          lcd_display();
        
        //起動直後または水やりモードに移行してはじめての場合
        if(last_exec_mode != exec_mode) {

            last_exec_mode = exec_mode;

            //水をくださいの音声メッセージ
            mp3_play (1);
            
            //水やりモード移行直後の時間を保存する
            startedtime_watermode = millis();
            startedtime_watermode_reminder1 = millis();
            startedtime_watermode_reminder2 = MAX_UL;
            count_watermode_reminder1 = 0;

            //SWがOFFになるまで待機
            while((tact_sw_status = digitalRead(DIO_TACTSW_INPUT)) == ON);
            delay(100);
        }

        //前回水をください出力後、一定時間経過した場合
        if(check_overtime(intervaltime_watermode_reminder1, startedtime_watermode_reminder1)) {
            count_watermode_reminder1++;
            if(count_watermode_reminder1 > maxcount_watermode_reminder1){
                startedtime_watermode_reminder1 = MAX_UL;
                startedtime_watermode_reminder2 = millis();
            }

            //土壌のかわきがLEVELAを超過すれば水やりモードに移行する
            if(soilhumid > thr_soil_himid_level_A) {
                //水をくださいの音声メッセージ
                mp3_play (1);
            }             
            else if(soilhumid > thr_soil_himid_level_B) {
                //たりないの音声メッセージ
                mp3_play (2);
            }             
            else if(soilhumid > thr_soil_himid_level_C) {
                //あとすこしの音声メッセージ
                mp3_play (3);
            }             
        }


        //前回水をください出力後、一定時間経過した場合
        if(check_overtime(intervaltime_watermode_reminder2, startedtime_watermode_reminder2)) {

            //土壌のかわきがLEVELAを超過すれば水やりモードに移行する
            if(soilhumid > thr_soil_himid_level_A) {
                //水をくださいの音声メッセージ
                mp3_play (1);
            }             
            else if(soilhumid > thr_soil_himid_level_B) {
                //たりないの音声メッセージ
                mp3_play (2);
            }             
            else if(soilhumid > thr_soil_himid_level_C) {
                //あとすこしの音声メッセージ
                mp3_play (3);
            }             
       
            
        }


        //水やりモードで一定時間経過した場合
        if(check_overtime(intervaltime_watermode, startedtime_watermode)) {
            //サイレントモードへ移行する
            last_exec_mode = exec_mode;
            exec_mode = EXEC_MODE_SILENT;
            //LCDを消灯する
            lcd.setBacklight(0);
            lcd.clear();
        }

        //リレー停止中かつタクトSW ON検出時は、リレー停止⇒リレー駆動⇒リレー停止
        if(relay_act_mode==RELAY_ACT_MODE_OFF && tact_sw_status==TACT_SW_STATUS_ON) {
            //リレー停止⇒リレー駆動
            relay_act_mode=RELAY_ACT_MODE_ON;
            //リレー動作モードを出力する(DIO出力の誤動作を防止するため常時出力する)
            digitalWrite(DIO_RELAY_OUTPUT, relay_act_mode);
            delay (intervaltime_watermode_pump);   //駆動時間2秒
            //リレー駆動⇒リレー停止
            relay_act_mode=RELAY_ACT_MODE_OFF;
            //リレー動作モードを出力する(DIO出力の誤動作を防止するため常時出力する)
            digitalWrite(DIO_RELAY_OUTPUT, relay_act_mode);

            //ありがとうの音声メッセージ
            mp3_play (5);
            startedtime_watermode_reminder1 = millis();
            startedtime_watermode_reminder2 = MAX_UL;
            startedtime_watermode =  millis();

        } 
        //安全措置:ポンプ駆動開始から一定時間経過時は、リレー駆動⇒リレー停止
        else if(relay_act_mode==RELAY_ACT_MODE_ON) {
            //リレー駆動⇒リレー停止
            relay_act_mode=RELAY_ACT_MODE_OFF;
            //リレー動作モードを出力する(DIO出力の誤動作を防止するため常時出力する)
            digitalWrite(DIO_RELAY_OUTPUT, relay_act_mode);
        }

        if(soilhumid <= thr_soil_himid_level_C) {
            //通常モードへ移行する
            last_exec_mode = exec_mode;
            exec_mode = EXEC_MODE_NORMAL;
            //LCDを消灯する
            lcd.setBacklight(0);
            lcd.clear();
            //ARIGATOの音声メッセージ
            mp3_play(4);
        }   

    }
    //サイレントモード時の処理
    else if(exec_mode == EXEC_MODE_SILENT) {

        //起動直後またはsilentモードに移行してはじめての場合
        if(last_exec_mode != exec_mode) {
            last_exec_mode = exec_mode;

            //LCDに土壌水分量を表示する(常時表示)
            lcd_display();
            //水をくださいの音声メッセージ
            mp3_stop ();

            startedtime_silentmode = millis();
        }

        //一定時間経過した場合
        if(check_overtime(intervaltime_silentmode_lcd_flash_on, startedtime_silentmode_lcd_flash_on)) {
            //LCDに土壌水分量を表示する(インターバル表示)
            lcd_display();
            startedtime_silentmode_lcd_flash_off = millis();
        }
        //一定時間経過した場合
        if(check_overtime(intervaltime_silentmode_lcd_flash_off, startedtime_silentmode_lcd_flash_off)) {
            //LCDを消灯する
            lcd.setBacklight(0);
            lcd.clear();
            startedtime_silentmode_lcd_flash_off = MAX_UL;
            startedtime_silentmode_lcd_flash_on = millis();
        }
        //SW立ち上がり検出
        if((last_tact_sw_status != TACT_SW_STATUS_ON && tact_sw_status == TACT_SW_STATUS_ON)
            || check_overtime(intervaltime_silentmode, startedtime_silentmode)) {
            //サイレントモードへ移行する
            last_exec_mode = exec_mode;
            exec_mode = EXEC_MODE_WATERPLANTS;
            //LCDを消灯する
            lcd.setBacklight(0);
            lcd.clear();
        } 
    }else{

    }
    
    last_tact_sw_status = tact_sw_status;


 /* 
  //if(digitalRead(DIO_TACTSW_INPUT)){
    lcd.setBacklight(1);
      mp3_set_volume (20);
      delay (100);
     // mp3_random_play ();
     mp3_single_play (5);
    for(i=0;i<5;i++){
      digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_ON);
      delay(1000); //10sec
      digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_OFF);
      delay(1000); //10sec
    }
    delay (8000);
      //mp3_get_state ();
      //delay (10);
      //stat = mp3_wait_state();
      //  sprintf(s, "stat:%5d.", stat);
      //  lcd.setCursor(0, 0);
  //lcd.print(s);

      mp3_stop ();
    delay (2000);
    lcd.setBacklight(0);
    
  }else{
    digitalWrite(DIO_RELAY_OUTPUT, RELAY_ACT_MODE_ON);
  }
  delay(500);
  */
}


[/code]

 

MP3音声ファイル作成

 

7/22 下記のサイトは好きな文言を一発でMP3変換してファイルに落としてくれるサービスです。これがあれば変換ソフトをインストールする必要がありません。

  • Google翻訳で生成した音声をダウンロードできる『Sound of Text』を利用する
    http://soundoftext.com/

 

 

 

課題

 

  • モータノイズにより、ポンプを連続で動かしているとたまにシリアル通信のLCDのデータがでたらめの文字を表示したり、最悪Arduinoが固まったりする。
    ⇒ おそらく、ノイズ対策せずにDCモータを使っているため。
    【対策】 0.1μfのコンデンサをつけてみる(http://monoist.atmarkit.co.jp/mn/articles/1602/19/news010_2.html)
    ※なぜかモータを水中で動作させない場合はどれだけ連続で動かしても誤動作しない。

 

マブチモーターのノイズ対策
「マブチモーター」に代表される直流ブラシ付きモーターは安価で入手性も良好ですが、Arduinoなどと組み合わせる際には発生するノイズが問題となることがあります。そこで今回は、「直流ブラシ付きモーターのノイズ対策」について解説します。

 

 

 

 

 

まとめ

 

いろいろ課題はありますが、まずはArduinoで自動水やり装置の完成とします。中国製モジュールがネットで簡単に購入することができるようになって、思ったよりかなり安く仕上がりました。しばらくリビングにおいて家族に使ってもらって様子を見てみます。また気が向いたら第二弾バージョンアップの製作に取り掛かりたいと思います!

 

 

2017/8/15 評価用プロトタイプ製作

ブレッドボードとジャンパー線を卒業してユニバーサル基板で配線してみました。

 

 

 

 

動画

 

 

 

 

参考

 

PHP/Javascript/WORDPRESS案件全般承ります

オーストラリアで主に日系企業や個人のお客様からのご依頼でお仕事をしております。この記事についてのご質問またはお困りのことがございましたら、お気軽にお問い合わせください。

タイトルとURLをコピーしました