Arduino MKR IoT CarrierとGrove SCD30搭載CO2センサを使って、長期間の環境測定をしてみる。
人間と共生するロボットは、24時間365日電源を切らないで稼働しなければならないと思うけれど、メンテナンスや省エネのために人間の睡眠に相当するような休息は必要で、ロボットはいつ寝るべきかを調べたいので、お手軽に環境測定と記録が可能なデバイスを用意してみました。
ハードウェアもクラウド連携のソフトウェアも、とても良くできているので、ほとんど買ってくるだけで完了しますが、備忘録のためのソースコードを残します。
購入したもの
ソースコード
// WiFiNINA - Version: 1.8.13 #include <WiFiNINA.h> #include <RTCZero.h> int day; int month; int year; int hours; int minutes; int seconds; int millisCount; #include "thingProperties.h" #include <Arduino_MKRIoTCarrier.h> MKRIoTCarrier carrier; #include "SCD30.h" #if defined(ARDUINO_ARCH_AVR) #pragma message("Defined architecture for ARDUINO_ARCH_AVR.") #define SERIAL Serial #elif defined(ARDUINO_ARCH_SAM) #pragma message("Defined architecture for ARDUINO_ARCH_SAM.") #define SERIAL SerialUSB #elif defined(ARDUINO_ARCH_SAMD) #pragma message("Defined architecture for ARDUINO_ARCH_SAMD.") #define SERIAL SerialUSB #elif defined(ARDUINO_ARCH_STM32F4) #pragma message("Defined architecture for ARDUINO_ARCH_STM32F4.") #define SERIAL SerialUSB #else #pragma message("Not found any architecture.") #define SERIAL Serial #endif File myFile; String filename; /* Create an rtc object */ RTCZero rtcz; void loopRTC() { static int lastSeconds = -1; day = rtcz.getDay(); month = rtcz.getMonth(); year = rtcz.getYear(); hours = rtcz.getHours(); minutes = rtcz.getMinutes(); seconds = rtcz.getSeconds(); // Print date... print2digits(day); Serial.print("/"); print2digits(month); Serial.print("/"); print2digits(year); Serial.print(" "); // ...and time print2digits(hours); Serial.print(":"); print2digits(minutes); Serial.print(":"); print2digits(seconds); Serial.print(":"); if (lastSeconds != seconds) { millisCount = 0; } else { millisCount += 1; } lastSeconds = seconds; print2digits(millisCount); Serial.println(); } void print2digits(int number) { if (number < 10) { Serial.print("0"); // print a 0 before if the number is < than 10 } Serial.print(number); } void loopSCD() { float result[3] = {0}; if (scd30.isAvailable()) { scd30.getCarbonDioxideConcentration(result); CO2Grove = result[0]; temperatureGrove = result[1]; humidityGrove = result[2]; } } void setup() { // Initialize serial and wait for port to open: Serial.begin(115200); // This delay gives the chance to wait for a Serial Monitor without blocking if none is found delay(1500); Serial.println("SCD30 Raw Data"); scd30.initialize(); //connect to WiFi Serial.print("Connecting to "); Serial.println(SSID); WiFi.begin(SSID, PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(" CONNECTED"); rtcz.begin(); //+ unsigned long epoch; int numberOfTries = 0, maxTries = 16; do { epoch = WiFi.getTime(); numberOfTries++; } while ((epoch == 0) && (numberOfTries < maxTries)); Serial.println(epoch); Serial.println(numberOfTries); if (numberOfTries == maxTries) { Serial.print("NTP unreachable!!"); //while (1); } else { Serial.print("Epoch received: "); rtcz.setEpoch(epoch); Serial.println(); } //disconnect WiFi as it's no longer needed WiFi.end(); // Defined in thingProperties.h initProperties(); // Connect to Arduino IoT Cloud ArduinoCloud.begin(ArduinoIoTPreferredConnection); //Get Cloud Info/errors , 0 (only errors) up to 4 setDebugMessageLevel(2); ArduinoCloud.printDebugInfo(); //Wait to get cloud connection to init the carrier while (ArduinoCloud.connected() != 1) { ArduinoCloud.update(); delay(500); } delay(500); CARRIER_CASE = false; carrier.begin(); carrier.display.setRotation(0); delay(1500); // open the file. note that only one file can be open at a time, // so you have to close this one before opening another. SDwritable = false; loopRTC(); String dates = String(month) + String(day); String times = String(hours) + String(minutes); // within 8 characters + 3 charcters filename = dates + times + String(".txt"); myFile = SD.open(filename); if (myFile) { Serial.print("Opening "); Serial.println(filename.c_str()); myFile.println("Year, Month, Day, Hours, Minutes, Seconds, MillisCount, temperature, humidity, pressure, light, r, g, b, Gx, Gy, Gz, Ax, Ay, Az, CO2Grove, temperatureGrove, humidityGrove, batteryVoltage"); myFile.close(); SDwritable = true; } } void loop() { ArduinoCloud.update(); carrier.Buttons.update(); loopRTC(); loopSCD(); temperature = carrier.Env.readTemperature(); humidity = carrier.Env.readHumidity(); pressure = carrier.Pressure.readPressure(); carrier.IMUmodule.readGyroscope(Gx, Gy, Gz); carrier.IMUmodule.readAcceleration(Ax, Ay, Az); batteryVoltage = analogRead(ADC_BATTERY) * 3.3f / 1023.0f / 1.2f * (1.2f + 0.33f); // https://mag.switch-science.com/2021/10/07/arduino-mkr-wifi-1010/ battery = (batteryVoltage - 2.8f) / (4.208f - 2.8f) * 100; //for battery available in % while (!carrier.Light.colorAvailable()) { delay(5); } carrier.Light.readColor(r, g, b, light); if (carrier.Buttons.onTouchDown(TOUCH0)) { carrier.display.fillScreen(ST77XX_WHITE); carrier.display.setTextColor(ST77XX_RED); carrier.display.setTextSize(2); carrier.display.setCursor(20, 80); carrier.display.print("Temp: "); carrier.display.print(temperature); carrier.display.print(" C"); carrier.display.setCursor(20, 120); carrier.display.print("TempGrove: "); carrier.display.print(temperatureGrove); carrier.display.print(" C"); } if (carrier.Buttons.onTouchDown(TOUCH1)) { carrier.display.fillScreen(ST77XX_WHITE); carrier.display.setTextColor(ST77XX_RED); carrier.display.setTextSize(2); carrier.display.setCursor(20, 80); carrier.display.print("Humi: "); carrier.display.print(humidity); carrier.display.print(" %"); carrier.display.setCursor(20, 120); carrier.display.print("HumiGrove: "); carrier.display.print(humidityGrove); carrier.display.print(" %"); } if (carrier.Buttons.onTouchDown(TOUCH2)) { carrier.display.fillScreen(ST77XX_WHITE); carrier.display.setTextColor(ST77XX_RED); carrier.display.setTextSize(2); carrier.display.setCursor(30, 80); carrier.display.print("Light: "); carrier.display.print(light); carrier.display.setCursor(30, 110); carrier.display.print("RGB: "); carrier.display.setCursor(30, 125); carrier.display.print(r); carrier.display.setCursor(30, 140); carrier.display.print(g); carrier.display.setCursor(30, 155); carrier.display.print(b); } if (carrier.Buttons.onTouchDown(TOUCH3)) { carrier.display.fillScreen(ST77XX_WHITE); carrier.display.setTextColor(ST77XX_RED); carrier.display.setTextSize(2); carrier.display.setCursor(30, 80); carrier.display.print("Pressure: "); carrier.display.print(pressure); carrier.display.setCursor(30, 110); carrier.display.print("CO2Grove: "); carrier.display.print(CO2Grove); } if (carrier.Buttons.onTouchDown(TOUCH4)) { carrier.display.fillScreen(ST77XX_WHITE); carrier.display.setTextColor(ST77XX_RED); carrier.display.setCursor(70, 30); carrier.display.print("Gyroscope: "); carrier.display.setCursor(50, 45); carrier.display.print(Gx); carrier.display.setCursor(50, 60); carrier.display.print(Gy); carrier.display.setCursor(50, 75); carrier.display.print(Gz); carrier.display.setCursor(50, 120); carrier.display.print("Accelerometer: "); carrier.display.setCursor(50, 135); carrier.display.print(Ax); carrier.display.setCursor(50, 150); carrier.display.print(Ay); carrier.display.setCursor(50, 165); carrier.display.print(Az); } // if the file opened okay, write to it: myFile = SD.open(filename, FILE_WRITE); if (myFile) { myFile.print(year); myFile.print(","); myFile.print(month); myFile.print(","); myFile.print(day); myFile.print(","); myFile.print(hours); myFile.print(","); myFile.print(minutes); myFile.print(","); myFile.print(seconds); myFile.print(","); myFile.print(millisCount); myFile.print(", "); myFile.print(temperature); myFile.print(","); myFile.print(humidity); myFile.print(","); myFile.print(pressure); myFile.print(","); myFile.print(light); myFile.print(","); myFile.print(r); myFile.print(","); myFile.print(g); myFile.print(","); myFile.print(b); myFile.print(","); myFile.print(Gx); myFile.print(","); myFile.print(Gy); myFile.print(","); myFile.print(Gz); myFile.print(","); myFile.print(Ax); myFile.print(","); myFile.print(Ay); myFile.print(","); myFile.print(Az); myFile.print(","); myFile.print(CO2Grove); myFile.print(","); myFile.print(temperatureGrove); myFile.print(","); myFile.print(humidityGrove); myFile.print(","); myFile.println(batteryVoltage); // close the file: myFile.close(); SDwritable = true; } else { // if the file didn't open, print an error: Serial.print("error opening "); Serial.println(filename.c_str()); SDwritable = false; } if (humidity >= 60 && temperature >= 15) { weather_report = "It is very humid outside"; } else if (temperature >= 15 && light >= 700) { weather_report = "Warm and sunny outside"; } else if (temperature <= 16 && light >= 700) { weather_report = "A little cold, but sunny outside"; } else { weather_report = "Weather is normal"; } } /* Since TemperatureGrove is READ_WRITE variable, onTemperatureGroveChange() is executed every time a new value is received from IoT Cloud. */ void onTemperatureGroveChange() { // Add your code here to act upon TemperatureGrove change }
12月2日追記
Groveセンサーを付けていると、2時間ぐらいでハングアップしてしまいます。まだ、原因不明。
参考文献
[1] 2021年10月7日 スイッチサイエンス "Arduino MKR WiFi 1010 + MKR IoT CarrierでIoTをする" -> バッテリーの電源電圧
[2] GitHub - Seeed-Studio/Seeed_SCD30: carbon dioxide sensor -> SCD30.h, SCD30.cphttps://www.amazon.co.jp/gp/product/B086MN53FX/ref=ppx_yo_dt_b_asin_title_o07_s00?ie=UTF8&psc=1
[3] Grove - CO2 & Temperature & Humidity Sensor (SCD30) - Seeed Wiki
[4] Arduino_MKRIoTCarrier - Arduino Reference
[5] RTCZero - Arduino Reference
[6] はじめてのMKR ZERO (5) RTC - Arduinoクックブック
[7] MKR 1010 WiFi.getTime() returns always zero · Issue #34 · arduino-libraries/WiFiNINA · GitHub -> NTPから時間を拾って調整
[8] ArduinoでIoTにチャレンジ<その4>日付時刻を表示する - Arduinoクックブック
[9] ArduinoでSDメモリカードを読み書きする - なんでも作っちゃう、かも。 -> ArduinoのSDカードのファイルのファイル名の長さは、最大8+3文字まで。FILE_WRITEオプションを付けてopenすると、追記になる。
[10] C言語入門:うるう年判定プログラム:Geekなぺーじ