編集履歴一覧に戻る
nao_IoTのアイコン画像

nao_IoT が 2022年09月24日09時46分10秒 に編集

初版

タイトルの変更

+

Light Recorder

タグの変更

+

電子工作

+

spresense

+

時計

+

お部屋工作

+

IoT

+

部屋

+

3Dプリンタ

メイン画像の変更

メイン画像が設定されました

記事種類の変更

+

製作品

本文の変更

+

**概要** Spreasenseを使って、部屋の照明の点灯状態を記録するデバイスを作成しました!※IoT化したかったもののWi-Fi接続用のボードを用意していなかったため、現状ネットワークには接続していません。 **デモ動画** 設定編(時間設定・ISO感度設定) https://youtu.be/VxTleF7dsXE レコード編 https://youtu.be/o8DajndhJwE **使用部品** Spreasenseメインボード x1 Spreasense拡張ボード x1 Spreasenseカメラモジュール x1 LCD I2Cシリアル接続 2x16キャラクタ x1 2連タクトスイッチ(古い掃除機から取り出したもの) x1 10kΩ炭素皮膜抵抗 x2 青色LED x12 x1 200Ω炭素皮膜抵抗 x12 ユニバーサル基板 x1 ※ケース・レンズフード等は3Dプリンタで自作しました。 **仕組み** カメラモジュールを照明機器に向けて使用します。ISO感度自動設定機能を用い、照明を点けた場合、消した場合の設定値を比較することで点灯状態を検知しています。1時間に12回計測し、照明が点いている時間が長ければ時計型LEDをONに、消えている時間の方が短ければLEDをOFFにするという形で記録内容を表現をしました。 **特徴** カメラモジュールを用いることで外光に強くなりました。カメラが照明機器を向いていれば、強い西日が入る部屋でも時間帯に関わらず正しく動作することを確認しています。 **感想** 今回初めてSpreasenseを使ってみました!ArduinoやRaspberry Piは比較的使ったことがあったのでとても使いやすかったです。折角なので次回は強みのエッジAI実装に挑戦してみたいです!! **回路図** ![キャプションを入力できます](https://camo.elchika.com/5c8295b0f426fe9e873de3f96d907f8b3387c3d6/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f37303832353565622d303962322d346237352d396264332d3437353238353330333736352f64353939626165612d303139352d343332392d623039652d353132663565633538653334/) **ソースコード** ```main.ino //アドレス0x27 16文字2行の液晶 #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27, 16, 2); //カメラモジュール #include <SDHCI.h> #include <stdio.h> /* for sprintf */ #include <Camera.h> #define BAUDRATE (115200) SDClass theSD; int iso_on = 0; /** * Print error message */ void printError(enum CamErr err) { Serial.print("Error: "); switch (err) { case CAM_ERR_NO_DEVICE: Serial.println("No Device"); break; case CAM_ERR_ILLEGAL_DEVERR: Serial.println("Illegal device error"); break; case CAM_ERR_ALREADY_INITIALIZED: Serial.println("Already initialized"); break; case CAM_ERR_NOT_INITIALIZED: Serial.println("Not initialized"); break; case CAM_ERR_NOT_STILL_INITIALIZED: Serial.println("Still picture not initialized"); break; case CAM_ERR_CANT_CREATE_THREAD: Serial.println("Failed to create thread"); break; case CAM_ERR_INVALID_PARAM: Serial.println("Invalid parameter"); break; case CAM_ERR_NO_MEMORY: Serial.println("No memory"); break; case CAM_ERR_USR_INUSED: Serial.println("Buffer already in use"); break; case CAM_ERR_NOT_PERMITTED: Serial.println("Operation not permitted"); break; default: break; } } /** * Callback from Camera library when video frame is captured. */ void CamCB(CamImage img) { /* Check the img instance is available or not. */ if (img.isAvailable()) { /* If you want RGB565 data, convert image data format to RGB565 */ img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565); /* You can use image data directly by using getImgSize() and getImgBuff(). * for displaying image to a display, etc. */ /* Serial.print("Image data size = "); Serial.print(img.getImgSize(), DEC); Serial.print(" , "); Serial.print("buff addr = "); Serial.print((unsigned long)img.getImgBuff(), HEX); Serial.println(""); */ } else { Serial.println("Failed to get video stream image"); } } //時計型LEDへの出力 void clock_write(bool *state){ for (int i=0;i<12;i++){ if (state[i]==1){ digitalWrite(i, HIGH); } else{ digitalWrite(i, LOW); } } } void led_control(bool val){ if (val==true){ digitalWrite(LED0, HIGH); digitalWrite(LED1, HIGH); digitalWrite(LED2, HIGH); digitalWrite(LED3, HIGH); } else{ digitalWrite(LED0, LOW); digitalWrite(LED1, LOW); digitalWrite(LED2, LOW); digitalWrite(LED3, LOW); } } bool check_light(){ /*ISO感度を取得*/ led_control(true); int iso = theCamera.getISOSensitivity(); //ISO感度取得 char sendPacket_left[24] = ""; // 値を右詰3桁に変換 sprintf(sendPacket_left, "%03d", iso); /*LCDに表示*/ lcd.clear(); lcd.setCursor(0, 0); lcd.print(sendPacket_left); lcd.setCursor(0, 1); bool result = (iso <= iso_on); if (result){ lcd.print("Light ON"); } else{ lcd.print("Light OFF"); } led_control(false); return result; } int time_set = 0; //時間の設定(0~12) bool state[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; //時計の状態を保存 void setup() { Serial.begin(BAUDRATE); /*LCDのセットアップ*/ lcd.init(); lcd.backlight(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Setup..."); //LED pinMode(LED0, OUTPUT); pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(LED3, OUTPUT); //時計型LEDのセットアップ for (int i=0;i<12;i++){ pinMode(i, OUTPUT); } clock_write(state); //全てオフに //INPUT IOの設定 int change = 13; int select = 12; pinMode(change, INPUT); pinMode(select, INPUT); //時間設定 lcd.clear(); lcd.print("Time setting"); digitalWrite(time_set, HIGH); Serial.println("時間設定スタート"); while(digitalRead(select)){ //決定ボタンが押されたら次へ進む(LOW) if (!digitalRead(change)){ digitalWrite(time_set, LOW); //チェンジボタンが押されたら、次のLEDを点灯させる time_set = (time_set+1)%12; Serial.print("設定中: "); Serial.println(time_set); digitalWrite(time_set, HIGH); delay(400); } } Serial.print("設定時間: "); Serial.println(time_set); /*カメラのセットアップ*/ { CamErr err; /* Open serial communications and wait for port to open */ while (!Serial) { ; /* wait for serial port to connect. Needed for native USB port only */ } /* Initialize SD */ while (!theSD.begin()) { /* wait until SD card is mounted. */ Serial.println("Insert SD card."); } /* begin() without parameters means that * number of buffers = 1, 30FPS, QVGA, YUV 4:2:2 format */ Serial.println("Prepare camera"); err = theCamera.begin(); if (err != CAM_ERR_SUCCESS) { printError(err); } /* Start video stream. * If received video stream data from camera device, * camera library call CamCB. */ Serial.println("Start streaming"); err = theCamera.startStreaming(true, CamCB); if (err != CAM_ERR_SUCCESS) { printError(err); } /* Auto white balance configuration */ Serial.println("Set Auto white balance parameter"); err = theCamera.setAutoWhiteBalanceMode(CAM_WHITE_BALANCE_DAYLIGHT); if (err != CAM_ERR_SUCCESS) { printError(err); } /* Set parameters about still picture. * In the following case, QUADVGA and JPEG. */ Serial.println("Set still picture format"); err = theCamera.setStillPictureImageFormat( //CAM_IMGSIZE_QUADVGA_H, //CAM_IMGSIZE_QUADVGA_V, CAM_IMGSIZE_QVGA_H, CAM_IMGSIZE_QVGA_V, CAM_IMAGE_PIX_FMT_JPG); if (err != CAM_ERR_SUCCESS) { printError(err); } /*照明の設定*/ lcd.clear(); delay(10); lcd.print("Turn OFF light"); lcd.setCursor(0, 1); lcd.print("and push Select"); while(digitalRead(select)){} //ボタンが押されるまで待機 int initial_iso = theCamera.getISOSensitivity(); Serial.print("Initial ISO: "); Serial.println(initial_iso); lcd.clear(); lcd.print("turn ON light"); while(theCamera.getISOSensitivity() >= initial_iso){ lcd.clear(); lcd.print("turn ON light"); lcd.setCursor(0, 1); lcd.print(theCamera.getISOSensitivity()); delay(500); } delay(2000); iso_on = theCamera.getISOSensitivity(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Ready"); lcd.setCursor(0, 1); lcd.print("ISO="); lcd.setCursor(5, 1); lcd.print(iso_on,DEC); Serial.print("ISO_on: "); Serial.println(iso_on, DEC); delay(500); } } void loop() { int hour_data = 0; //1時間で何回ついていたかを取得(1時間で12回計測) Serial.print("check: "); for (int i=0;i<12;i++){ bool result = check_light(); Serial.print(result); hour_data = hour_data + result; unsigned long start_time = millis(); while (millis()-start_time<6000) { //300000 check_light(); digitalWrite(time_set, HIGH); delay(700); check_light(); digitalWrite(time_set, LOW); delay(700); } } Serial.println(""); //1時間分のデータを計算 bool hour_result = (float(hour_data)/12.0 >= 0.5); if (hour_result){ state[time_set] = true; }else{ state[time_set] = false; } clock_write(state); Serial.print("Hour check: "); Serial.println(hour_result); time_set = (time_set+1)%12; //theCamera.end(); } ```