前回まで/次回以降の取り組みはこちらから。
Raspberry Pi側のアプリを作りこんでいきます。
もくじ
今回の完成図
こんな感じ。
LED照明に関して、時刻と照度で自動制御できるようになりました。
「時刻設定1」「時刻設定2」「照度設定」のチェックが入っていればそれぞれ有効になり、ロジックは「(時刻設定1 or 時刻設定2) and 照度設定」にしました。
例えば、
LEDは常に点灯する。 | |
0:00~6:00の間点灯する。 | |
18:00~23:59の間点灯する。 | |
照度が40以下なら点灯する。 | |
0:00~6:00の間と、18:00~23:59の間に点灯する。 | |
0:00~6:00の間、照度が40以下なら点灯する。 | |
18:00~23:59の間、照度が40以下なら点灯する。 | |
0:00~6:00の間と18:00~23:59の間、照度が40以下なら点灯する。 |
こんな風に設定できます。
Arduinoスケッチ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | // あさがおIoT観察日記 Arduino側プログラム // 2020.05.21 V0.0.1 DHT11による温度・湿度取得(DHT11サンプルスケッチより作成) // V0.0.2 BME280気圧取得(BME280サンプルスケッチより作成) // 2020.05.23 V0.0.3 TEMT6000による照度取得 // 2020.05.24 V0.0.4 KeyStudio製センサで土の水分量取得 // 2020.06.02 V0.0.5 RaspberryPi側通信制御開発のため、一度シリアル送信するのを照度データだけに変更 // 今後の準備としてLED照明、ポンプ、水切れセンサ、ボタンSWに関する制御パートを追加 // 2020.06.06 V0.0.6 センサの数値をすべてシリアル送信するように変更 // データ「d」をシリアルで受信したらセンサデータを送信する // 2020.06.08 V0.0.7 LEDガーデンライトの制御に対応 boolean l = false; #define LED_pin 13 #define pump_pin 12 #define SW_B_pin 11 #define SW_R_pin 10 #define sensor_tank 2 #define sensor_water 1 #define sensor_bright 0 #include <Adafruit_Sensor.h> #include <DHT.h> #include <DHT_U.h> #define DHTPIN 2 // Digital pin connected to the DHT sensor #define DHTTYPE DHT11 // DHT 11 DHT_Unified dht(DHTPIN, DHTTYPE); #include <Wire.h> #include <SPI.h> #include <Adafruit_BME280.h> #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME280 bme; // I2C uint32_t delayMS; int Alt = 120; void serial_send(double temp,double humid,double pres_0,int bright,int water,int tank){ Serial.println(temp); Serial.println(humid); Serial.println(pres_0); Serial.println(bright); Serial.println(water); Serial.println(tank); } void setup() { Serial.begin(9600); pinMode(LED_pin, OUTPUT); pinMode(pump_pin,OUTPUT); pinMode(SW_B_pin,INPUT_PULLUP); pinMode(SW_R_pin,INPUT_PULLUP); dht.begin(); delayMS = 100; bme.begin(0x76); } void loop() { double temp; double temp_0; double humid; double pres; double pres_0; int bright; int water; int tank; static boolean LED_Flag = false; static int LED_Th = 999; sensors_event_t event; //温度取得 dht.temperature().getEvent(&event); if (!isnan(event.temperature)) { temp = event.temperature; } //湿度取得 dht.humidity().getEvent(&event); if (!isnan(event.relative_humidity)) { humid = event.relative_humidity; } //気圧取得 pres = bme.readPressure() / 100; pres_0 = pres/(pow((1-((0.0065*Alt)/(bme.readTemperature()+0.0065*Alt+273.15))),5.257)); //海面更生 //照度取得 bright = analogRead(sensor_bright); //LED照明制御 if(LED_Flag==true && bright<LED_Th){ digitalWrite(LED_pin,HIGH); }else{ digitalWrite(LED_pin,LOW); } //水分量取得 water = analogRead(sensor_water); //水やり判断 tank = analogRead(sensor_tank); //シリアル送信 if(Serial.available()>=4){ //しきい値受信用行列 char th[] = {0,0,0}; char val = Serial.read(); th[0]= int(Serial.read())-48; th[1]= int(Serial.read())-48; th[2]= int(Serial.read())-48; //しきい値計算 int th_lebel = 100*th[0] + 10*th[1] + 1*th[2]; if(val=='L'){ if(th_lebel==999){ LED_Flag = false; }else if(th_lebel==0){ LED_Th = 1024; LED_Flag = true; }else{ LED_Th = th_lebel; LED_Flag = true; } serial_send(temp,humid,pres_0,bright,water,tank); }else if(val=='d'){ serial_send(temp,humid,pres_0,bright,water,tank); } Serial.println(LED_Th); } } |
前々回、センサデータの先頭に「d」という1文字を送ることで、Arduinoがデータの先頭を判断できるようにしました。
pythonプログラム
main_0_0_7.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | from PyQt5.QtWidgets import QApplication from ui.mainwindow_0_0_7 import MainWindow from PyQt5.QtCore import * import time import datetime import serial serialport = "/dev/ttyACM0" LED_TH = 999 LED_TH_P = 999 class SerialCom: def __init__(self, serialport): self.sc = serial.Serial(serialport,9600) time.sleep(3) def data_read(self): rc_data = self.sc.readline() return rc_data def start_com(self): self.sc.write(b'd') self.sc.write(b'0') self.sc.write(b'0') self.sc.write(b'0') def light_set(self, th): self.sc.write(b'L') light1 = th//100+48 light2 = (th%100)//10+48 light3 = (th%100%10)+48 self.sc.write(chr(light1).encode()) self.sc.write(chr(light2).encode()) self.sc.write(chr(light3).encode()) def close(self): self.sc.close() def refresh_time(): #時刻更新 now = datetime.datetime.now() ct = "現在時刻:" + now.strftime('%Y/%m/%d %H:%M:%S') ui.labeltime.setText(ct) #LED制御 n = now.time() global LED_TH #時刻制御1 cb_t1 = ui.checkBoxLightTime1.checkState() t = ui.timeEditLedStart1.time() LedStartTime1 = datetime.time(t.hour(), t.minute(), 0) t = ui.timeEditLedEnd1.time() LedEndTime1 = datetime.time(t.hour(), t.minute(), 0) #時刻制御2 cb_t2 = ui.checkBoxLightTime2.checkState() t = ui.timeEditLedStart2.time() LedStartTime2 = datetime.time(t.hour(), t.minute(), 0) t = ui.timeEditLedEnd2.time() LedEndTime2 = datetime.time(t.hour(), t.minute(), 0) #時刻制御有効の場合 if((cb_t1>0 and LedStartTime1<=n<LedEndTime1) or (cb_t2>0 and LedStartTime2<=n<LedEndTime2)): ui.progressBarLight.setValue(100) if(ui.checkBoxLightTh.checkState()): LED_TH = ui.spinBoxLed.value() else: LED_TH = 0 else: ui.progressBarLight.setValue(0) LED_TH = 999 #時刻制御無効の場合、センサーレベルだけ見る #すべてのチェックが入っていなければ、常時ON if(cb_t1==0 and cb_t2==0): if(ui.checkBoxLightTh.checkState()): LED_TH = ui.spinBoxLed.value() else: LED_TH = 0 def refresh_sensor(): myserial.start_com() global LED_TH global LED_TH_P #温度更新 temp = myserial.data_read() ui.labeltemp.setText("気温:\t" + str("{0:.2f}".format(float(temp))) + " [℃]") #湿度更新 humid = myserial.data_read() ui.labelhumid.setText("湿度:\t" + str("{0:.2f}".format(float(humid)))+ " [%]") #気圧更新 press = myserial.data_read() ui.labelpress.setText("大気圧:" + str("{0:.2f}".format(float(press))) + " [hPa]" ) #照度更新 bright = myserial.data_read() ui.labelbright.setText("照度:\t" + str("{0:4}".format(int(bright))) + "[Lx]") #水分量更新 water= myserial.data_read() ui.labelwater.setText( "水分量:\t" + str("{0:4}".format(int(water)))) #水タンク満水検知 tank= myserial.data_read() ui.labeltank.setText("タンク内水検知:" + str("{0:4}".format(int(tank)))) #LEDライトしきい値送信 light = myserial.data_read() ui.labelLight.setText(str("{000:}".format(int(light)))) if(LED_TH != LED_TH_P): myserial.light_set(LED_TH) LED_TH_P = LED_TH if __name__=="__main__": import sys app = QApplication(sys.argv) ui = MainWindow() #ui.showFullScreen() myserial = SerialCom(serialport) refresh_sensor() timer1 = QTimer() timer1.timeout.connect(refresh_time) timer1.start(200) timer2 = QTimer() timer2.timeout.connect(refresh_sensor) timer2.start(1000) ui.show() sys.exit(app.exec_()) |
mainwondow_0_0_7.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # -*- coding: utf-8 -*- """ Module implementing MainWindow. """ from PyQt5.QtCore import pyqtSlot from PyQt5.QtWidgets import QMainWindow from .Ui_mainwindow_0_0_7 import Ui_MainWindow class MainWindow(QMainWindow, Ui_MainWindow): """ Class documentation goes here. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(MainWindow, self).__init__(parent) self.setupUi(self) |
Raspberry PiとArduinoでLEDを連携制御する
前回まで
これまでは、Raspberry PiがArduinoからセンサの値を受け取るためにこんな風に動いていました。
Raspberry PiはArduinoにシリアル通信で「d」という文字を送り、データを受信する体制に入ります。
Arduinoは「d」という文字を受け取ったら、決められた順番に沿ってセンサのデータを返事していきます。
今回は
LEDの制御をするために、こんな風なやり取りをしています。
Raspberry Piから受け取ったデータ文字列によってON/OFFのしきい値とフラグを変えます。
フラグが「true」ならLEDをON、「false」ならLEDをOFFにします。
照度センサの値がしきい値以下であり、フラグがtrueならLEDをONします。
それ以外の状態、照度センサの値がしきい値より大きいとか、照度センサの値がしきい値以下でもフラグがfalseならばLEDをOFFします。
A:点灯させるとき(照度しきい値なし)
Raspberry Piのアプリで「照度設定」のチェックが入っていなくて、設定時間になった場合です。
または、「照度設定」にも「時刻設定1/2」にもチェックが入っていない場合です。
Raspberry Piから「L000」という文字列を送信します。
Arduinoはしきい値を「1024」、フラグを「true」にします。
照度センサの値は0~1023の範囲しかとらないので常にしきい値以下です。
照度に関係なくLEDが点灯するというわけです。
B:点灯させるとき(照度しきい値あり)
Raspberry Piのアプリで「照度設定」のチェックが入っていて、設定時間になった場合です。
または、「照度設定」にだけチェックが入っていない場合です。
Raspberry Piから「Lxxx」という文字列を送信します。
「xxx」にはしきい値が入ります。0~998の範囲で指定します。
(999が入らない理由は別のことに使ってるからです。次のセクションで出てきます)
Arduinoはしきい値を「xxx」、フラグを「true」にします。
LEDフラグはtrueなので照度センサの値がしきい値以下になればそれでLEDが点灯します。
C:消灯させるとき
Raspberry Piのアプリで「時刻設定」がされていて、設定時間外になった場合です。
Raspberry Piから「L999」という文字列を送信します。
この場合はArduinoはフラグを「false」にします。
照度センサの値とかしきい値とか、問答無用でLEDはOFFになります。
センサデータのやり取り
センサデータのやり取りについてもちょっと変更しました。
これまでは文字データ「d」でしたが、照明制御の時とデータの長さを合わせるために文字列「d000」に変更しました。
今回は照明用LEDの制御が完成しました。
この方法をほとんどそっくりそのまま使えば水やりの制御もできてしまいそうです。
また、クリスマスのイルミネーションや玄関灯にもこのまま応用できそうですね。
まだまだ続きます。
コメント