fujiwara が 2022年09月25日21時22分07秒 に編集
修正
本文の変更
# 概要 SPRESENSEはパワフルかつ、低消費電力で駆動する優秀なマイコンです カメラや音声を使ったAIが動作するため、カメラの調整やFFT解析の描画などの用途で液晶を使用します 「[SPRESENSEではじめるローパワーエッジAI](https://www.amazon.co.jp/dp/4873119677/ref=cm_sw_r_tw_dp_XAT982ZDQZVW6DZZ7RME)」より 第9章のセマンティックセグメーションを使った認識と組み合わせて、対象となる物体がカメラで撮影できる範囲に入ると、画面が起動する仕組みを作ります 普段消灯させるのは液晶を使用していると消費電力が大きくなるからです ディープスリープやコールドスリープもありますが、AIを使用しながらだとそれは使えません # 現状確認 まずはどのくらいの消費電力か、現状を確認します 液晶のバックライトで確認していきます バックライトが点灯しているときの電流値 0.17A ![キャプションを入力できます](https://camo.elchika.com/4194c9f49062c3c8c525f17db50066892438504d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666236363161632d303337392d346466392d613234642d3864376634383439613839332f31313239306161392d376464372d343036622d623364372d373434343536643135663263/) バックライトが消灯しているときの電流値 0.11A ![キャプションを入力できます](https://camo.elchika.com/5b75ad9a1616a0d8b3654389b4465807fe36de75/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666236363161632d303337392d346466392d613234642d3864376634383439613839332f36633765316665642d396566612d343461302d393939392d616630316237643035663339/)
### **液晶を消灯すると、65%くらい消費電力が減るようです**
**液晶を消灯すると、65%くらい消費電力が減るようです**
これは効果がありそうですね! # 回路図 そこで以下のような回路を作ることにしました ![キャプションを入力できます](https://camo.elchika.com/01b7a76b35dc0de67841837daff42ca5e8f498a4/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666236363161632d303337392d346466392d613234642d3864376634383439613839332f62636164393634622d653931662d343132322d623232372d366538346538656535373561/) # 部品表 | 購入部品| 数量| |:---:|:---:| | [抵抗220Ω](https://akizukidenshi.com/catalog/g/gR-25221/) | 1個 | | [フォトリレーTCP241B](https://akizukidenshi.com/catalog/g/gI-16705/) | 1個| | [液晶 ili9341 2.2TFT](https://amzn.asia/d/5xeqVNE) | 1個| これを実装してみます # 結果 対象物が現れると液晶が点灯 ![キャプションを入力できます](https://camo.elchika.com/692e636f3fb43af21bd3e084fd5e3a720e8a5b64/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666236363161632d303337392d346466392d613234642d3864376634383439613839332f33613863356162642d366261382d346364662d393062392d306533613633623062363031/) 対象物がないと液晶が消灯 ![キャプションを入力できます](https://camo.elchika.com/f3e0560a545e44efb2118c088f71b4f1e1a2c86e/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38666236363161632d303337392d346466392d613234642d3864376634383439613839332f33613730643336332d353835392d346539302d613636362d343733313430616263306466/) 簡単なif文の分岐ですが結構スピーディです [こちら](https://youtu.be/o5hz6488DAs)で動画をご覧ください # ソースコード ソースコードは以下の通りです semaseg_camera.inoを以下の様に書き換えます ぜひ試してみてください!! ``` * semaseg_camera.ino - Binary Sematic Segmentation sample * Copyright 2022 Sony Semiconductor Solutions Corporation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <Camera.h> #include "Adafruit_ILI9341.h" #include <SDHCI.h> #include <DNNRT.h> #define TFT_DC 9 #define TFT_CS 10 Adafruit_ILI9341 display = Adafruit_ILI9341(TFT_CS, TFT_DC); #define OFFSET_X (48) #define OFFSET_Y (6) #define CLIP_WIDTH (224) #define CLIP_HEIGHT (224) #define DNN_WIDTH (28) #define DNN_HEIGHT (28) DNNRT dnnrt; SDClass SD; // RGBの画像を入力 DNNVariable input(DNN_WIDTH*DNN_HEIGHT*3); void CamCB(CamImage img) { if (!img.isAvailable()) return; // 画像の切り出しと縮小 CamImage small; CamErr camErr = img.clipAndResizeImageByHW(small ,OFFSET_X ,OFFSET_Y ,OFFSET_X+CLIP_WIDTH-1 ,OFFSET_Y+CLIP_HEIGHT-1 ,DNN_WIDTH ,DNN_HEIGHT); if (!small.isAvailable()) return; // 画像をYUVからRGB565に変換 small.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565); uint16_t* sbuf = (uint16_t*)small.getImgBuff(); // RGBのピクセルをフレームに分割 float* fbuf_r = input.data(); float* fbuf_g = fbuf_r + DNN_WIDTH*DNN_HEIGHT; float* fbuf_b = fbuf_g + DNN_WIDTH*DNN_HEIGHT; for (int i = 0; i < DNN_WIDTH*DNN_HEIGHT; ++i) { fbuf_r[i] = (float)((sbuf[i] >> 11) & 0x1F)/31.0; // 0x1F = 31 fbuf_g[i] = (float)((sbuf[i] >> 5) & 0x3F)/63.0; // 0x3F = 64 fbuf_b[i] = (float)((sbuf[i]) & 0x1F)/31.0; // 0x1F = 31 } // 推論を実行 dnnrt.inputVariable(input, 0); dnnrt.forward(); DNNVariable output = dnnrt.outputVariable(0); // DNNRTの結果をLCDに出力するために画像化 static uint16_t result_buf[DNN_WIDTH*DNN_HEIGHT]; for (int i = 0; i < DNN_WIDTH * DNN_HEIGHT; ++i) { uint16_t value = output[i] * 0x3F; // 6bit if (value > 0x3F) value = 0x3F; result_buf[i] = (value << 5); // Only Green } // 認識対象の横幅と横方向座標を取得 bool err; int16_t s_sx, s_width; err = get_sx_and_width_of_region(output, DNN_WIDTH, DNN_HEIGHT, &s_sx, &s_width); // 認識対象の縦幅と縦方向座標を取得 int16_t s_sy, s_height; int sx, width, sy, height; sx = width = sy = height = 0; err = get_sy_and_height_of_region(output, DNN_WIDTH, DNN_HEIGHT, &s_sy, &s_height); if (!err) { Serial.println("detection error"); goto disp; } // 何も検出できなかった if (s_width == 0 || s_height == 0) { digitalWrite(0, LOW); Serial.println("no detection"); goto disp; } // 認証対象のボックスと座標をカメラ画像にあわせて拡大 sx = s_sx * (CLIP_WIDTH/DNN_WIDTH) + OFFSET_X; width = s_width * (CLIP_WIDTH/DNN_WIDTH); sy = s_sy * (CLIP_HEIGHT/DNN_HEIGHT) + OFFSET_Y; height = s_height * (CLIP_HEIGHT/DNN_HEIGHT); disp: img.convertPixFormat(CAM_IMAGE_PIX_FMT_RGB565); uint16_t* buf = (uint16_t*)img.getImgBuff(); // 認識対象のボックスをカメラ画像に描画 draw_box(buf, sx, sy, width, height); if (sx >1) { digitalWrite(0,HIGH); } // サイドバンドをフレームバッファに描画 draw_sideband(buf, OFFSET_X, ILI9341_BLACK); // DNNRTへの入力画像をLCDの左上に表示 display.drawRGBBitmap(0, 0, (uint16_t*)sbuf, DNN_HEIGHT, DNN_WIDTH); // DNNRTの出力画像をLCDの右上に表示 display.drawRGBBitmap(320-DNN_WIDTH, 0, result_buf, DNN_WIDTH, DNN_HEIGHT); // ボックス描画されたカメラ画像を表示 display.drawRGBBitmap(0, DNN_HEIGHT, buf, 320, 240-DNN_HEIGHT); } void setup() { pinMode(0, OUTPUT); digitalWrite(0, LOW); Serial.begin(115200); display.begin(); display.setRotation(3); display.fillRect(0, 0, 320, 240, ILI9341_BLUE); File nnbfile = SD.open("model.nnb"); if (!nnbfile) { Serial.print("nnb not found"); return; } Serial.println("DNN initialize"); int ret = dnnrt.begin(nnbfile); if (ret < 0) { Serial.print("Runtime initialization failure. "); Serial.println(ret); return; } theCamera.begin(); theCamera.startStreaming(true, CamCB); } void loop() { // put your main code here, to run repeatedly: } ```