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

tea が 2022年09月05日20時49分16秒 に編集

初版

タイトルの変更

+

サイバードラレコ方向指示器

タグの変更

+

自転車

+

spresense

+

サーボモーター

+

LEDテープ

+

GPS

+

Arduino

+

ドラレコ

+

速度計

メイン画像の変更

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

記事種類の変更

+

製作品

本文の変更

+

# 動画 @[youtube](https://www.youtube.com/watch?v=Wp3bPdnoegE) # 概要 **自転車で有るといいもの乗っけました** ドラレコ機能、方向指示器、ブレーキランプ、フロントライト、そして*変形*! 夜間自転車に乗ることが多いのですが、手信号は見えないため 方向指示器があれば安全に乗ることができます 万が一のためにドラレコ機能も搭載 # 構成図 ![キャプションを入力できます](https://camo.elchika.com/d5ddcb3c643cef83d9fc3b9957db8939232ca3ea/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f38373531373662632d626564622d343565322d623731322d306564356264336637386361/) Spresense カメラボードでドラレコ機能を実装します 自動ブレーキランプ機能ありのテールランプと連携させます 方向指示の連携はシリアル通信で行うことで、自転車の前後をスッキリと繋ぐことが出来ます Spresense のGPSにて速度計測を行う予定でしたが、未実装 ボディは3Dプリンタで作成。 自転車用ですが、メインユニットは取り外し可能で、車でもつかえるようにします 路面にレーザ表示し、車幅を車に知らせます 加速度センサーでブレーキを感知し、ブレーキランプを明滅 そして、変形機能!起動時にサーボで左右に展開します 機能テンコ盛り~ # 使用しているパーツ - メインユニット Spresenseメインボード Spresenseカメラボード Spresense拡張ボード 4000円 WINGONEER 1.8インチフルカラー128×160 SPIフルカラーTFT LCDディスプレイモジュールST7735S 3.3V 899円 ALITOVE WS2812B LEDテープ1m 144連 NeoPixel RGB TAPE LED 5050 SMD LEDテープライトピクセル 1,839円 SDカード IIC I2C シリアルOLED液晶ディスプレイモジュール I2C SSD1306 白色I2C OLEDスクリーンドライバ0.91" Arduino用DC 128x32 3.3V〜5V 1400円 - 電源ユニット モバイルバッテリー 100均 スイッチ - ハンドル スイッチ×3 コネクタ - 後部ユニット 中華製ArduinoNano 1000円 サーボ×2 ブザー ## メインユニット カメラは可動出来るようにしています。また車でも使えるように取り外し可能にしておきます 他のユニットとの接続はコネクタを利用します ![キャプションを入力できます](https://camo.elchika.com/5768c6d0bfb9b532cf762de24aecb29a565a789f/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f35646235353264652d336235302d343034322d626361302d326633373863383663626630/) ## 方向指示器(フラッシャー) LEDテープで方向を表示します Arduino用のライブラリで制御しようとして四苦八苦していたのですが Spresense 用の物が必要みたいです [こちら](https://github.com/hideakitai/SpresenseNeoPixel) 前方向指示器はナイトライダーのセンサーライトをイメージして作っています ナイトライダーっておじさんしか知らないかも あのヒュンヒュンいいながらライトが光るの萌える! 常時動作させたいため、サブコア側でプログラムは走らせます しかし、どうにも別の色になったりノイズが入ります。 原因はTFTディスプレイドライバのAdafruit_ST7735とLEDテープの相性が悪い模様 TFTをやめ、OELDディスプレイに変更したところ改善しました。 ![キャプションを入力できます](https://camo.elchika.com/cc9dbb4a14956b7e7c2f6b42c3f7453b471205cc/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f65356163623662372d616531372d346466332d623862652d653837656631386532396235/) ## 後部ユニット ![キャプションを入力できます](https://camo.elchika.com/641ca785da0fa6c52d72f12079c6395505576401/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f32393634653931652d333663622d346330642d616439342d636561613931306130623135/) 以前に作成した[テールランプ](https://elchika.com/article/afe8925e-36ea-4398-a017-85da7cc01296/)をサイバーチックに改造しています 起動するとライトが左右にサーボで展開します カッコイイ・・・かな?変形はロマン! 幅が広い方が方向指示器が見やすいので、ムダではない! ![キャプションを入力できます](https://camo.elchika.com/893d476fee3f2c7039805af961766f1b38849988/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f36623931613231312d343866392d346562642d626562372d336134313866363966363766/) しかし、中身ごちゃごちゃ。上手い配線の仕方を覚えないと ## 後部ユニットとのシリアル通信 シリアル通信で後部ユニットのArduinoと通信を行います しかし、ここからが苦闘の歴史・・・ メインボードからTXを繋いでArduinoのRXに送ってみます が、送信されている気配はあるのに文字が送れない、数値もダメ・・・なぜ~ ==原因はメインボードのTXでは1.8Vのため、電圧が足りなく信号が送れない模様== レベルシフタ無いといかんらしい。まじか Spresense拡張ボードが必須でした。無いとメインボードだけだと何もできない! 最初からモニター応募しておけばよかった・・・ 泣く泣くぽちりました4000円なり 購入したSpresense拡張ボードで通信してみるも文字が送れない 5Vではなくどうやら3.3Vでないとだめらしい(ArduinoNanoの動作電圧5Vじゃ?) その後、うまくいったのでマルチコア化をして再試験・・・動かない マルチコアにするとSerial2が使えなくなるようです。Spresenseのバグ? 結局ソフトウエアシリアルを使用することで回避しました ## ドラレコ カメラサンプルをちょちょっと変更して、画像を永続的にファイル保存すれば終わり! となるはずでしたが、欲をかいてプレビュー機能を付けようと安いディスプレイを購入 一応表示できるところまで出来ましたが、表示があまりに遅くてプレビューには使えませんでした ディスプレイは早いものを選びましょう ## 速度表示 GPSのサンプルをちょちょっと変更して、速度を取得してディスプレイに表示すれば終わり! となるはずでしたが、何分たっても時速が取得できない・・・ 時間などは取得できているので壊れているわけではなさそう。今回は諦めました ## フロントライト 普通の自転車のライトをモバイルバッテリーで点灯します 本当はSpresenseで制御したかったのですが、 ==デジタル入出力端子は 6mA== ということなので 100mAのフロントライトは直では制御できません モータードライバとかFETで電流を流す方法は、色々手はあるのですが、 モバイルバッテリーから直で供給することとしました ## ハンドル方向指示スイッチ ![キャプションを入力できます](https://camo.elchika.com/f96378cd59246d8471cd821077f8222f2c6cd3bc/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f38616539643763622d353935322d346434642d613065652d303563386434343466363137/) 3Dプリンタで作成します。意外と設計が難しくて5,6回試作してしまいました。 ちなみに私は初心者でも簡単に扱えるTinkercad](https://www.tinkercad.com/)使っています STLのモデルが欲しい方はコメントして頂いたらアップします 4端子のコネクタにスイッチはつなげておきます ![キャプションを入力できます](https://camo.elchika.com/f707cfda210ebcaa41ecd9a8b55c4e5e16fa08f3/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f31633232356533372d373336642d346233392d393633612d633936666432623633663439/) ## 電源ユニット ![キャプションを入力できます](https://camo.elchika.com/eb4e2ad84c49e9af60fa84a7fe398b732b544a12/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f66353432393036622d633234352d343339612d393036372d386634616533363664663737/) 100均のモバイルバッテリーを電源にします 拡張ボードの方には電源スイッチが無いため、電源ユニット側にスイッチを付けます USBケーブルを切断し、途中にスイッチを付けるのですが、ここで注意しないといけないのが 電源用として使用する場合、信号線を短絡する必要があるらしいです 短絡しないとデータ通信用と認識され、拡張ボードに供給できませんでした。 # 今後のやりたいこと - スイッチで操作ではなくSpresenseでフロントライトや後部ユニットの電源制御がしたい - オートパワーOFF - 盗難防止機能で移動されるとブザーがなるのですが、GPSで位置も送るとか - 電磁加速装置を追加したい - 防水?雨の日は自転車乗らないので問題なし! # Spresense落とし穴ポイントまとめ - メインボードは1.8V。arduinoと連携できない - デジタル入出力端子は 6mA - サブコアでSerial.begin(115200);を入れると固まる - マルチコアにするとSerial2が使えなくなる - Adafruit_ST7735とサブコアでLEDテープの相性が悪い - SDカードへのアクセスするとLEDテープにノイズが乗る マニュアルをよく読め!ということですかね こういった情報、皆さんの役に立つかな? Spresenseの情報がやっぱり少ないので コンテストバンバンやって使ってもらうのが普及に繋がりそう # メインコアコード メインユニットで同時に複数の処理を行う必要があるので、 折角のマルチコアですので、コアごとに処理を分けてみました ただ、分けるとLEDテープにノイズが乗るようです 何故?原因はSDカードへのアクセスのようです 拡張ボードのSDカードを引っこ抜くと改善する・・・ 一応抵抗を咬ますと軽減されるようですがノイズなのかなあ ```arduino:メインコア(カメラ・GPS) #ifdef SUBCORE #error "Core selection is wrong!!" #endif #include <MP.h> /* include the GNSS library */ #include <GNSS.h> #include <Adafruit_GFX.h> // Core graphics library #if TFT #include <Adafruit_ST7735.h> // Hardware-specific library for ST7735 #endif #include <Adafruit_SSD1306.h> #include <SPI.h> #include <SDHCI.h> #include <stdio.h> /* for sprintf */ #include <Camera.h> #define STRING_BUFFER_SIZE 128 /**< %Buffer size */ #define RESTART_CYCLE (60 * 5) /**< positioning test term */ static SpGnss Gnss; /**< SpGnss object */ #define BAUDRATE (115200) #define TOTAL_PICTURE_COUNT (5000) SDClass theSD; int take_picture_count = 0; #if TFT #define TFT_CS 10 #define TFT_RST 9 // Or set to -1 and connect to Arduino RESET pin #define TFT_DC 8 #define TFT_MOSI 11 // Data out #define TFT_SCLK 13 // Clock out // For ST7735-based displays, we will use this call Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST); #endif #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); /** * @enum ParamSat * @brief Satellite system */ enum ParamSat { eSatGps, /**< GPS World wide coverage */ eSatGlonass, /**< GLONASS World wide coverage */ eSatGpsSbas, /**< GPS+SBAS North America */ eSatGpsGlonass, /**< GPS+Glonass World wide coverage */ eSatGpsBeidou, /**< GPS+BeiDou World wide coverage */ eSatGpsGalileo, /**< GPS+Galileo World wide coverage */ eSatGpsQz1c, /**< GPS+QZSS_L1CA East Asia & Oceania */ eSatGpsGlonassQz1c, /**< GPS+Glonass+QZSS_L1CA East Asia & Oceania */ eSatGpsBeidouQz1c, /**< GPS+BeiDou+QZSS_L1CA East Asia & Oceania */ eSatGpsGalileoQz1c, /**< GPS+Galileo+QZSS_L1CA East Asia & Oceania */ eSatGpsQz1cQz1S, /**< GPS+QZSS_L1CA+QZSS_L1S Japan */ }; /* Set this parameter depending on your current region. */ static enum ParamSat satType = eSatGps; unsigned long timeCamera; unsigned long timeLed; unsigned long timeGnss; int mode = 1; /** * @brief Turn on / off the LED0 for CPU active notification. */ static void Led_isActive(void) { static int state = 1; if (state == 1) { ledOn(PIN_LED0); state = 0; } else { ledOff(PIN_LED0); state = 1; } } /** * @brief Turn on / off the LED1 for positioning state notification. * * @param [in] state Positioning state */ static void Led_isPosfix(bool state) { if (state) { ledOn(PIN_LED1); } else { ledOff(PIN_LED1); } } /** * @brief Turn on / off the LED3 for error notification. * * @param [in] state Error state */ static void Led_isError(bool state) { if (state) { ledOn(PIN_LED3); } else { ledOff(PIN_LED3); } } void CoreSetup() { int ret = 0; int subid; //Serial.begin(115200); while (!Serial); /* Boot SubCore */ for (subid = 1; subid <= 1; subid++) { ret = MP.begin(subid); if (ret < 0) { MPLog("MP.begin(%d) error = %d\n", subid, ret); } } } /** * @brief Activate GNSS device and start positioning. */ void setup() { /* Set serial baudrate. */ Serial.begin(115200); //Serial2.begin(9600); CoreSetup(); #if TFT //tft.initR(INITR_GREENTAB); // Init ST7735S chip, green tab tft.initR(INITR_BLACKTAB); // タブが緑なのにブラック? /* ライブラリの245行目に下記を追加 _colstart = 2; _rowstart = 1;*/ tft.setTextWrap(false); tft.fillScreen(ST77XX_BLACK); tft.setCursor(0, 30); tft.setTextColor(ST77XX_RED); tft.setTextSize(1); tft.println("Hello World!"); tft.setTextColor(ST77XX_YELLOW); tft.setTextSize(2); #endif if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } display.clearDisplay(); display.setTextSize(3); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); display.print("START"); display.display(); if(mode == 1){ /* Set serial baudrate. */ CameraSetup(); } if(mode == 2){ GnssSetup(); } } void GnssSetup() { int error_flag = 0; /* Wait HW initialization done. */ sleep(3); /* Turn on all LED:Setup start. */ ledOn(PIN_LED0); ledOn(PIN_LED1); ledOn(PIN_LED2); ledOn(PIN_LED3); /* Set Debug mode to Info */ Gnss.setDebugMode(PrintInfo); int result; /* Activate GNSS device */ result = Gnss.begin(); if (result != 0) { Serial.println("Gnss begin error!!"); error_flag = 1; } else { /* Setup GNSS * It is possible to setup up to two GNSS satellites systems. * Depending on your location you can improve your accuracy by selecting different GNSS system than the GPS system. * See: https://developer.sony.com/develop/spresense/developer-tools/get-started-using-nuttx/nuttx-developer-guide#_gnss * for detailed information. */ switch (satType) { case eSatGps: Gnss.select(GPS); break; case eSatGpsSbas: Gnss.select(GPS); Gnss.select(SBAS); break; case eSatGlonass: Gnss.select(GLONASS); break; case eSatGpsGlonass: Gnss.select(GPS); Gnss.select(GLONASS); break; case eSatGpsBeidou: Gnss.select(GPS); Gnss.select(BEIDOU); break; case eSatGpsGalileo: Gnss.select(GPS); Gnss.select(GALILEO); break; case eSatGpsQz1c: Gnss.select(GPS); Gnss.select(QZ_L1CA); break; case eSatGpsQz1cQz1S: Gnss.select(GPS); Gnss.select(QZ_L1CA); Gnss.select(QZ_L1S); break; case eSatGpsBeidouQz1c: Gnss.select(GPS); Gnss.select(BEIDOU); Gnss.select(QZ_L1CA); break; case eSatGpsGalileoQz1c: Gnss.select(GPS); Gnss.select(GALILEO); Gnss.select(QZ_L1CA); break; case eSatGpsGlonassQz1c: default: Gnss.select(GPS); Gnss.select(GLONASS); Gnss.select(QZ_L1CA); break; } /* Start positioning */ result = Gnss.start(COLD_START); if (result != 0) { Serial.println("Gnss start error!!"); error_flag = 1; } else { Serial.println("Gnss setup OK"); } } /* Start 1PSS output to PIN_D02 */ //Gnss.start1PPS(); /* Turn off all LED:Setup done. */ ledOff(PIN_LED0); ledOff(PIN_LED1); ledOff(PIN_LED2); ledOff(PIN_LED3); /* Set error LED. */ if (error_flag == 1) { Led_isError(true); exit(0); } } /** * @brief %Print position information. */ static void print_pos(SpNavData *pNavData) { char StringBuffer[STRING_BUFFER_SIZE]; display.clearDisplay(); display.setTextSize(1); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); #if TFT tft.fillRect(0, 40, tft.width(), 16, ST77XX_BLUE); tft.setCursor(0, 40); tft.setTextSize(1); #endif /* print time */ snprintf(StringBuffer, STRING_BUFFER_SIZE, "%04d/%02d/%02d ", pNavData->time.year, pNavData->time.month, pNavData->time.day); Serial.print(StringBuffer); snprintf(StringBuffer, STRING_BUFFER_SIZE, "%02d:%02d:%02d ", pNavData->time.hour, pNavData->time.minute, pNavData->time.sec); Serial.print(StringBuffer); #if TFT tft.println(StringBuffer); #endif display.println(StringBuffer); /* print satellites count */ snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSat:%2d, ", pNavData->numSatellites); Serial.print(StringBuffer); #if TFT tft.print(StringBuffer); #endif display.print(StringBuffer); display.display(); /* print position data */ if (pNavData->posFixMode == FixInvalid) { #if TFT tft.println("N"); #endif Serial.print("No-Fix, "); } else { #if TFT tft.println("F"); #endif Serial.print("Fix, "); } if (pNavData->posDataExist == 0) { Serial.print("No Position"); } else { Serial.print("Lat="); Serial.print(pNavData->latitude, 6); Serial.print(", Lon="); Serial.print(pNavData->longitude, 6); } Serial.println(""); } /** * @brief %Print satellite condition. */ static void print_condition(SpNavData *pNavData) { char StringBuffer[STRING_BUFFER_SIZE]; unsigned long cnt; /* Print satellite count. */ snprintf(StringBuffer, STRING_BUFFER_SIZE, "numSatellites:%2d\n", pNavData->numSatellites); Serial.print(StringBuffer); #if TFT tft.setCursor(0, 60); tft.setTextSize(1); #endif display.setCursor(0,16); // Start at top-left corner display.println(StringBuffer); for (cnt = 0; cnt < pNavData->numSatellites; cnt++) { const char *pType = "---"; SpSatelliteType sattype = pNavData->getSatelliteType(cnt); /* Get satellite type. */ /* Keep it to three letters. */ switch (sattype) { case GPS: pType = "GPS"; break; case GLONASS: pType = "GLN"; break; case QZ_L1CA: pType = "QCA"; break; case SBAS: pType = "SBA"; break; case QZ_L1S: pType = "Q1S"; break; case BEIDOU: pType = "BDS"; break; case GALILEO: pType = "GAL"; break; default: pType = "UKN"; break; } /* Get print conditions. */ unsigned long Id = pNavData->getSatelliteId(cnt); unsigned long Elv = pNavData->getSatelliteElevation(cnt); unsigned long Azm = pNavData->getSatelliteAzimuth(cnt); float sigLevel = pNavData->getSatelliteSignalLevel(cnt); /* Print satellite condition. */ //snprintf(StringBuffer, STRING_BUFFER_SIZE, "[%2ld] Type:%s, Elv:%2ld, Azm:%3ld, CN0:", cnt, pType, Elv, Azm ); snprintf(StringBuffer, STRING_BUFFER_SIZE, "El:%2ld,Az:%3ld,CN:%2ld", Elv, Azm, sigLevel ); Serial.print(StringBuffer); #if TFT tft.fillRect(0, 60 +cnt*16, tft.width(), 16, ST77XX_BLUE); tft.println(StringBuffer); #endif display.println(StringBuffer); Serial.println(sigLevel, 6); } display.display(); } /** * @brief %Print position information and satellite condition. * * @details When the loop count reaches the RESTART_CYCLE value, GNSS device is * restarted. */ void loop() { if(mode == 1 && micros() -timeCamera > 2000) { timeCamera = micros(); CameraLoop(); //Serial2.println("L"); //Serial2.write(2); } if(mode == 2 && micros() -timeGnss > 10000) { timeGnss = micros(); LoopGnss(); } } void LoopGnss() { char StringBuffer[STRING_BUFFER_SIZE]; static int LoopCount = 0; static int LastPrintMin = 0; /* Blink LED. */ Led_isActive(); /* Check update. */ if (Gnss.waitUpdate(-1)) { /* Get NaviData. */ SpNavData NavData; Gnss.getNavData(&NavData); #if TFT //tft.fillScreen(ST77XX_BLACK); tft.fillRect(0, 0, tft.width(), 40, ST77XX_BLUE); tft.setCursor(0, 0); tft.setTextColor(ST77XX_GREEN); tft.setTextSize(2); snprintf(StringBuffer, STRING_BUFFER_SIZE, "Sp:%.2f", NavData.velocity/60/60); tft.println(StringBuffer); snprintf(StringBuffer, STRING_BUFFER_SIZE, "Gg:%ld", NavData.direction ); tft.println(StringBuffer); Serial.print(StringBuffer); #endif /* Set posfix LED. */ bool LedSet = (NavData.posDataExist && (NavData.posFixMode != FixInvalid)); Led_isPosfix(LedSet); /* Print satellite information every minute. */ if (NavData.time.minute != LastPrintMin) { print_condition(&NavData); LastPrintMin = NavData.time.minute; } /* Print position information. */ print_pos(&NavData); } else { /* Not update. */ Serial.println("data not update"); } /* Check loop count. */ //LoopCount++;//リスタートしない if (LoopCount >= RESTART_CYCLE) { int error_flag = 0; /* Turn off LED0 */ ledOff(PIN_LED0); /* Set posfix LED. */ Led_isPosfix(false); /* Restart GNSS. */ if (Gnss.stop() != 0) { Serial.println("Gnss stop error!!"); error_flag = 1; } else if (Gnss.end() != 0) { Serial.println("Gnss end error!!"); error_flag = 1; } else { Serial.println("Gnss stop OK."); } if (Gnss.begin() != 0) { Serial.println("Gnss begin error!!"); error_flag = 1; } else if (Gnss.start(HOT_START) != 0) { Serial.println("Gnss start error!!"); error_flag = 1; } else { Serial.println("Gnss restart OK."); } LoopCount = 0; /* Set error LED. */ if (error_flag == 1) { Led_isError(true); exit(0); } } } //ここからカメラ関連 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); //img.convertPixFormat(CAM_IMAGE_PIX_FMT_GRAY); //tft.drawRGBBitmap(0, 0, (uint16_t *)img.getImgBuff(), 128, 160);// img.getWidth(), img.getHeight()); // #if TFT tft.drawRGBBitmap(0, 38, (uint16_t *)img.getImgBuff(), 160, 120);// img.getWidth(), img.getHeight()); // #endif /* 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(""); /*char filename[16] = {0}; sprintf(filename, "PICT_MINI%03d.JPG", take_picture_count); theSD.remove(filename); File myFile = theSD.open(filename, FILE_WRITE); myFile.write(img.getImgBuff(), img.getImgSize()); myFile.close();*/ } else { Serial.println("Failed to get video stream image"); } } /** * @brief Initialize camera */ void CameraSetup() { CamErr err; /* Open serial communications and wait for port to open */ Serial.begin(BAUDRATE); 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(1, CAM_VIDEO_FPS_5, CAM_IMGSIZE_QQVGA_H, CAM_IMGSIZE_QQVGA_V, CAM_IMAGE_PIX_FMT_YUV422);//CAM_IMAGE_PIX_FMT_RGB565);// 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_3M_H,// CAM_IMGSIZE_HD_H,// CAM_IMGSIZE_QUADVGA_H, CAM_IMGSIZE_3M_V/2,// CAM_IMGSIZE_HD_V,// CAM_IMGSIZE_QUADVGA_V, CAM_IMAGE_PIX_FMT_JPG); if (err != CAM_ERR_SUCCESS) { printError(err); } } /** * @brief Take picture with format JPEG per second */ void CameraLoop() { //sleep(1); /* wait for one second to take still picture. */ /* You can change the format of still picture at here also, if you want. */ /* theCamera.setStillPictureImageFormat( * CAM_IMGSIZE_HD_H, * CAM_IMGSIZE_HD_V, * CAM_IMAGE_PIX_FMT_JPG); */ /* This sample code can take pictures in every one second from starting. */ /* Take still picture. * Unlike video stream(startStreaming) , this API wait to receive image data * from camera device. */ //tft.fillRect(0, 0, tft.width(), 16, ST77XX_BLUE); Serial.println("call takePicture()"); CamImage img = theCamera.takePicture(); /* Check availability of the img instance. */ /* If any errors occur, the img is not available. */ if (img.isAvailable()) { /* Create file name */ char filename[16] = {0}; sprintf(filename, "PICT%03d.JPG", take_picture_count); Serial.print("Save taken picture as "); Serial.print(filename); Serial.println(""); theSD.remove(filename); File myFile = theSD.open(filename, FILE_WRITE); myFile.write(img.getImgBuff(), img.getImgSize()); myFile.close(); display.clearDisplay(); display.setTextSize(1); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); sprintf(filename, "%03d", take_picture_count); display.print(filename); display.display(); } else { /* The size of a picture may exceed the allocated memory size. * Then, allocate the larger memory size and/or decrease the size of a picture. * [How to allocate the larger memory] * - Decrease jpgbufsize_divisor specified by setStillPictureImageFormat() * - Increase the Memory size from Arduino IDE tools Menu * [How to decrease the size of a picture] * - Decrease the JPEG quality by setJPEGQuality() */ Serial.println("Failed to take picture"); } if (take_picture_count >= TOTAL_PICTURE_COUNT) { take_picture_count=0; } /* else if (take_picture_count == TOTAL_PICTURE_COUNT) { Serial.println("End."); theCamera.end(); } */ take_picture_count++; } ``` # サブコアコード(LEDテープ・シリアル通信) ```arduino:サブコアコード(LEDテープ・シリアル通信) #if (SUBCORE != 1) #error "Core selection is wrong!!" #endif #include <MP.h> #include <SpresenseNeoPixel.h> #include <SoftwareSerial.h> #define PIN 2 // On Trinket or Gemma, suggest changing this to 1 #define NUMPIXELS 28// 10 // Popular NeoPixel ring size #define PIN_L 26 #define PIN_R 25 #define PIN_C 16 SpresenseNeoPixel<PIN, NUMPIXELS> neopixel; unsigned long timeLed; int knightCount[4]; int arrow[4]; int winCount; SoftwareSerial mySerial(4, 7); // RX, TX void setup() { MP.begin(); //Serial2.begin(9600); mySerial.begin(9600); pinMode(PIN_L, INPUT_PULLUP); pinMode(PIN_R, INPUT_PULLUP); pinMode(PIN_C, INPUT_PULLUP); //テープLED neopixel.clear(); neopixel.framerate(40); // default framerate is 40[fps] for(int i=0; i<4; i++) { arrow[i] = 1; knightCount[i] = i; } } void loop() { //if(micros() -timeLed > 1800) { timeLed = micros(); led(); } /*ledOn(LED0); delay(1000); ledOff(LED0); delay(1000);*/ } void led() { neopixel.clear(); //レフト if (digitalRead(PIN_L) == LOW ){ for(int i=10; i<NUMPIXELS; i++) { neopixel.set(i, 0, 0, 20); } if(winCount/6%2 == 0){ for(int i=0; i<10; i++) { int a = 255; neopixel.set(i, a, a/2, 0); } } winCount++; //mySerial.print("L"); //Serial2.print("L"); mySerial.write(2); MPLog("left\n"); } // ライト else if (digitalRead(PIN_R) == LOW ){ for(int i=0; i<NUMPIXELS -10; i++) { neopixel.set(i, 0, 0, 20); } if(winCount/6%2 == 0){ for(int i=0; i<10; i++) { int a = 255; neopixel.set(NUMPIXELS -i -1, a, a/2, 0); } } winCount++; //Serial2.print("R"); mySerial.write(1); MPLog("right\n"); } else{ winCount = 0; for(int i=0; i<NUMPIXELS; i++) { int a = 2; neopixel.set(i, 0, a/2, a); } for(int i=0; i<4; i++) { int a = (i*80 +10)%255; neopixel.set(knightCount[i], 0, a/2, a); } for(int i=0; i<4; i++) { knightCount[i] += arrow[i]; if(knightCount[i] < 0){ knightCount[i] = 0; arrow[i] = 1; } if(knightCount[i] > NUMPIXELS-1){ knightCount[i] = NUMPIXELS -1; arrow[i] = -1; } } } //センター if (digitalRead(PIN_C) == LOW ){ //Serial2.print("C"); mySerial.write(3); MPLog("center\n"); delay(1000);//連続送信しない } neopixel.show(); // Send the updated pixel colors to the hardware. delay(20); } ``` サブコアのsetupにSerial.begin(115200);を入れると何故かフリーズ 気を付けましょう # 後部ユニットコード ```arduino:サブコアコード(LEDテープ・シリアル通信) #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <avr/sleep.h> #include <Adafruit_NeoPixel.h> #ifdef __AVR__ #include <avr/power.h> // Required for 16 MHz Adafruit Trinket #endif #include <SoftwareSerial.h> #include "ServoEasing.hpp" #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 32 // OLED display height, in pixels int FRONT_PIN = 11; SoftwareSerial mySerial(FRONT_PIN, 1); // RX, TX #define PIN 9 // On Trinket or Gemma, suggest changing this to 1 #define PIN_L 7 // On Trinket or Gemma, suggest changing this to 1 #define NUMPIXELS 28// 10 // Popular NeoPixel ring size Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel pixelsL(NUMPIXELS, PIN_L, NEO_GRB + NEO_KHZ800); // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) // The pins for I2C are defined by the Wire-library. // On an arduino UNO: A4(SDA), A5(SCL) // On an arduino MEGA 2560: 20(SDA), 21(SCL) // On an arduino LEONARDO: 2(SDA), 3(SCL), ... #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // MPU-6050のアドレス、レジスタ設定値 #define MPU6050_WHO_AM_I 0x75 // Read Only #define MPU6050_PWR_MGMT_1 0x6B // Read and Write #define MPU_ADDRESS 0x68 #define SERVO1_PIN1 4 #define SERVO1_PIN2 8 int LASER_PIN = 10; int BEEP_PIN = 12; // 変数に7を割り当てる(デジタルピン7番) int DISP_PIN = 3; // 変数に7を割り当てる(デジタルピン7番) int wakePin = 5; //割り込み用のピン番号 int wakePin2 = 6; //割り込み用のピン番号 bool active; float acc_old_z; float acc_old_y; int keyCount; bool keyFlag; int keyWait; ServoEasing Servo1; ServoEasing Servo2; float old1; float old2; float old3; float old4; float blinkTime; int count; int blinkCount; int knightCount[4]; int arrow[4]; int sindouCount; int sindouSinpuku; int sleepCount; int renCount; int mode; bool ledCloseFlag; // デバイス初期化時に実行される void setup() { mySerial.begin(9600); pinMode(13, OUTPUT); // デジタルピン7番を出力モードに設定 Serial.begin(115200); //115200bps //シリアル通信テスト /*for(;;){ digitalWrite(13, LOW); // turn the LED off by making the voltage LOW Serial.println("x"); //while(mySerial.available()>0){ digitalWrite(13, HIGH); // turn the LED off by making the voltage LOW Serial.print(mySerial.read());//String //mode //} }*/ Serial.println("Start"); pinMode(wakePin, INPUT_PULLUP); pinMode(wakePin2, INPUT_PULLUP); pinMode(A0, INPUT); Wire.begin(); // PCとの通信を開始 //Serial.begin(115200); //115200bps // 初回の読み出し Wire.beginTransmission(MPU_ADDRESS); Wire.write(MPU6050_WHO_AM_I); //MPU6050_PWR_MGMT_1 Wire.write(0x00); Wire.endTransmission(); // 動作モードの読み出し Wire.beginTransmission(MPU_ADDRESS); Wire.write(MPU6050_PWR_MGMT_1); //MPU6050_PWR_MGMT_1レジスタの設定 Wire.write(0x00); Wire.endTransmission(); //ここから文字表示 if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); for(;;); // Don't proceed, loop forever } Serial.println("Start"); //BLINK pinMode(LED_BUILTIN, OUTPUT); pinMode(LASER_PIN, OUTPUT); // デジタルピン7番を出力モードに設定 pinMode(BEEP_PIN, OUTPUT); // デジタルピン7番を出力モードに設定 pinMode(DISP_PIN, OUTPUT); // デジタルピン7番を出力モードに設定 digitalWrite(DISP_PIN, HIGH); // turn the LED off by making the voltage LOW digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW active = true; keyFlag = true; pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixelsL.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) boot(); } void boot() { delay(80); int i, j; display.clearDisplay(); display.setTextSize(3); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); display.print("START"); display.display(); pixels.clear(); // Set all pixel colors to 'off' for(i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.clear(); // Set all pixel colors to 'off' for(i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixelsL.Color(0, 0, 0)); } pixelsL.show(); // Send the updated pixel colors to the hardware. delay(80); //サーボ Servo1.attach(SERVO1_PIN1, 90); Servo1.setEasingType(EASE_QUADRATIC_IN_OUT); delay(80); Servo1.easeTo(180, 80); delay(80); Servo1.detach(); Servo2.attach(SERVO1_PIN2, 90); Servo2.setEasingType(EASE_QUADRATIC_IN_OUT); Servo2.easeTo(0, 80); delay(80); Servo2.detach(); //ここからTEST用 /* for(int i=0; i<4; i++) { arrow[i] = 1; knightCount[i] = i; } for(;;){ pixels.clear(); pixelsL.clear(); for(int i=0; i<NUMPIXELS; i++) { int a = 2; pixels.setPixelColor(i, pixels.Color(a, a/2, 0)); pixelsL.setPixelColor(i, pixels.Color(a, a/2, 0)); } for(int i=0; i<4; i++) { int a = (i*80 +10)%255; pixels.setPixelColor(knightCount[i], pixels.Color(a, a/2, 0)); pixelsL.setPixelColor(knightCount[i], pixels.Color(a, a/2, 0)); } for(int i=0; i<4; i++) { knightCount[i] += arrow[i]; if(knightCount[i] < 0){ knightCount[i] = 0; arrow[i] = 1; } if(knightCount[i] > NUMPIXELS-1){ knightCount[i] = NUMPIXELS -1; arrow[i] = -1; } } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.show(); // Send the updated pixel colors to the hardware. delay(40); } //end */ for(j=0; j<256; j++) { pixels.clear(); // Set all pixel colors to 'off' for(i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, (255-j)/2, 255-j)); } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.clear(); // Set all pixel colors to 'off' for(i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixelsL.Color(0, (255-j)/2, 255-j)); } pixelsL.show(); // Send the updated pixel colors to the hardware. delay(2); } } void LedClose() { for(int j=0; j<256; j++) { pixels.clear(); // Set all pixel colors to 'off' for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(255-j, (255-j)/2, 0)); } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.clear(); // Set all pixel colors to 'off' for(int i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixelsL.Color(255-j, (255-j)/2, 0)); } pixelsL.show(); // Send the updated pixel colors to the hardware. delay(2); } //サーボ Servo1.attach(SERVO1_PIN1, 90); Servo2.attach(SERVO1_PIN2, 90); Servo1.easeTo(90, 80); Servo2.easeTo(90, 80); delay(80); Servo1.detach(); Servo2.detach(); } void loop() { pixels.clear(); // Set all pixel colors to 'off' pixelsL.clear(); // Set all pixel colors to 'off' if(!active){ //set_sleep_mode(SLEEP_MODE_PWR_DOWN); //スリープモードの設定 //interrupt(); delayWDT2(70); } Wire.beginTransmission(0x68); Wire.write(0x3B); Wire.endTransmission(false); Wire.requestFrom(0x68, 14, true); while (Wire.available() < 14); int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, Temperature; axRaw = Wire.read() << 8 | Wire.read(); ayRaw = Wire.read() << 8 | Wire.read(); azRaw = Wire.read() << 8 | Wire.read(); Temperature = Wire.read() << 8 | Wire.read(); gxRaw = Wire.read() << 8 | Wire.read(); gyRaw = Wire.read() << 8 | Wire.read(); gzRaw = Wire.read() << 8 | Wire.read(); // 加速度値を分解能で割って加速度(G)に変換する float acc_x = axRaw / 16384.0; //FS_SEL_0 16,384 LSB / g float acc_y = ayRaw / 16384.0; float acc_z = azRaw / 16384.0; // 角速度値を分解能で割って角速度(degrees per sec)に変換する float gyro_x = gxRaw / 131.0;//FS_SEL_0 131 LSB / (°/s) float gyro_y = gyRaw / 131.0; float gyro_z = gzRaw / 131.0; bool flag = false; //動きありか if(acc_z >= acc_old_z -0.02 && acc_z <= acc_old_z +0.02 && acc_y >= acc_old_y -0.02 && acc_y <= acc_old_y +0.02){ flag = true; } if(!keyFlag){ //キー無し if(!digitalRead(wakePin)){ Serial.print("Key "); active = true; sleepCount = 0; if(keyCount == 1){ keyFlag = true; boot(); } keyCount = 0; } if(!digitalRead(wakePin2)){ Serial.print("Key2 "); active = true; sleepCount = 0; if(keyCount == 0){ keyCount = 1; } } } else{ //遠隔収納 if(mode == 3){ if(ledCloseFlag){ boot(); } else{ LedClose(); } ledCloseFlag = !ledCloseFlag; } //収納 if(!digitalRead(wakePin)){ LedClose(); //スリープへ sleepCount = 500; flag = true; } //スリープからの復帰 if(!active && !digitalRead(wakePin2)) { boot(); } } if(flag){ //動いていない場合 //Serial.print("no active "); //Serial.print(sleepCount); //Serial.print(" "); //Serial.print(acc_y); Serial.println(""); if(sleepCount > 600){ //全消灯 display.clearDisplay(); display.setCursor(0,0); // Start at top-left corner display.print("SLEEP"); display.display(); for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 0)); pixelsL.setPixelColor(i, pixels.Color(0, 0, 0)); } pixels.show(); pixelsL.show(); digitalWrite(LASER_PIN, LOW); digitalWrite(DISP_PIN, LOW); active = false; acc_old_z = acc_z; acc_old_y = acc_y; keyFlag = false; keyWait = 0; return; } sleepCount++; } else{ digitalWrite(DISP_PIN, HIGH); //Serial.print("active "); active = true; sleepCount = 0; } acc_old_z = acc_z; acc_old_y = acc_y; //キーが入っていない場合ブザー if(!keyFlag && keyWait > 500){ digitalWrite(BEEP_PIN, HIGH); for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(255, 0, 0)); pixelsL.setPixelColor(i, pixels.Color(0, 0, 255)); } pixels.show(); pixelsL.show(); //digitalWrite(FRONT_PIN, HIGH); delay(120); digitalWrite(BEEP_PIN, LOW); for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 255)); pixelsL.setPixelColor(i, pixels.Color(255, 0, 0)); } pixels.show(); pixelsL.show(); //digitalWrite(FRONT_PIN, LOW); delay(120); sleepCount+=10; } keyWait++; // Serial.print((Temperature+521)/340+35); Serial.print(","); //Serial.print(acc_x); Serial.println("");//上下 //Serial.print(acc_z); Serial.println("");//傾き //Serial.print(acc_y); Serial.println("");//前後 //Serial.print(gyro_x); Serial.print(","); //Serial.print(gyro_y); Serial.print(","); //Serial.print(gyro_z); Serial.println(""); float sa = 0.12; float heikinOld = (old4*0.5 +old3*0.3 +old2*0.2); float heikinNew = (acc_x +old1)/2; //振動 if(heikinOld < heikinNew -sa && sindouSinpuku != 1){ sindouCount+=4; sindouSinpuku = 1; } if(heikinOld > heikinNew +sa && sindouSinpuku != -1){ sindouCount+=4; sindouSinpuku = -1; } //振動以外で減速したとき if(heikinOld < heikinNew -sa && sindouCount < 2){ blinkTime = 28; } sindouCount--; if(sindouCount < 0){ sindouCount = 0; sindouSinpuku = 0; } if(sindouCount > 10){ sindouCount = 10; } old4 = old3; old3 = old2; old2 = old1; old1 = acc_x; digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW display.clearDisplay(); display.setTextSize(2); // Draw 2X-scale text display.setCursor(0,0); // Start at top-left corner display.setTextColor(SSD1306_WHITE); display.print((Temperature+521)/340+35); display.print("C "); display.print(cpuVcc()); // 電源電圧測定 http://radiopench.blog96.fc2.com/blog-entry-490.html //display.print(analogRead(A0)); display.println("V"); if(keyFlag){ display.print("KEY "); } else{ display.print("INPUT "); display.print((500 -keyWait)/10); } display.drawLine(display.width()/2, display.height() -2, display.width()/2 +heikinNew*100, display.height() -2, SSD1306_WHITE); display.drawLine(display.width()/2, display.height() -4, display.width()/2 +(heikinNew-heikinOld)*200, display.height() -4, SSD1306_WHITE); display.drawLine(display.width()/2, display.height() -6, display.width()/2 +sa*200, display.height() -6, SSD1306_WHITE); if(blinkTime > 0){ //display.println(heikinNew*100); display.println("brake"); //digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) if(count%2 == 0){ digitalWrite(LASER_PIN, HIGH); } else{ digitalWrite(LASER_PIN, LOW); } if(mode == 1){//ライトブリンク if(blinkCount/4%2 == 0){ for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(255, 100, 0)); } } blinkCount++; } else{ if(count%2 == 0){ for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(255, 50, 50)); } } else{ for(int i=0; i<NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(0, 0, 50)); } } } if(mode == 2){//レフトブリンク if(blinkCount/4%2 == 0){ for(int i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixels.Color(255, 100, 0)); } } blinkCount++; } else{ if(count%2 == 0){ for(int i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixels.Color(0, 0, 50)); } } else{ for(int i=0; i<NUMPIXELS; i++) { pixelsL.setPixelColor(i, pixels.Color(255, 50, 50)); } } } blinkTime--; } else{ //digitalWrite(BEEP_PIN, LOW); for(int i=0; i<NUMPIXELS; i++) { if(mode == 2){//ライトブリンク if(blinkCount/4%2 == 0){ pixels.setPixelColor(i, pixels.Color(255, 100, 0)); } } else{ pixels.setPixelColor((blinkCount+i)%NUMPIXELS, pixels.Color((i*25)%255, 0, 0)); } if(mode == 1){//レフトブリンク if(blinkCount/4%2 == 0){ //digitalWrite(BEEP_PIN, HIGH); pixelsL.setPixelColor(i, pixels.Color(255, 100, 0)); } } else{ pixelsL.setPixelColor((blinkCount+i)%NUMPIXELS, pixels.Color((i*25)%255, 0, 0)); } } blinkCount++; if(count%4 == 0){ digitalWrite(LASER_PIN, HIGH); } else{ digitalWrite(LASER_PIN, LOW); } } pixels.show(); // Send the updated pixel colors to the hardware. pixelsL.show(); // Send the updated pixel colors to the hardware. count++; display.display(); //シリアル通信受信 mode = 0; while(mySerial.available()>0){ mode = mySerial.read(); } Serial.print("mode:"); Serial.println(mode); delay(20); } //割込み関数 void interrupt(){ //attachInterrupt(0,wakeUp, LOW); //割り込み処理の設定、2番ピンがLowで復帰 PRR = PRR | 0b00100000; //8bitタイマーdisable sleep_mode(); //スリープモードを有効にする //detachInterrupt(0); //割り込み処理を解除する } void wakeUp(){ //Serial.println("Wake up from standby."); //復帰時にシリアルモニターに表示 PRR = PRR & 0b00000000; //8bitタイマーenable //delay(30000); //時間調整 } void delayWDT2(unsigned long t) { // パワーダウンモードでdelayを実行 Serial.flush(); // シリアルバッファが空になるまで待つ delayWDT_setup(t); // ウォッチドッグタイマー割り込み条件設定 // ADCを停止(消費電流 147→27μA) ADCSRA &= ~(1 << ADEN); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // パワーダウンモード指定 sleep_enable(); // BODを停止(消費電流 27→6.5μA) MCUCR |= (1 << BODSE) | (1 << BODS); // MCUCRのBODSとBODSEに1をセット MCUCR = (MCUCR & ~(1 << BODSE)) | (1 << BODS); // すぐに(4クロック以内)BODSSEを0, BODSを1に設定 asm("sleep"); // 3クロック以内にスリープ sleep_mode();では間に合わなかった sleep_disable(); // WDTがタイムアップでここから動作再開 ADCSRA |= (1 << ADEN); // ADCの電源をON(BODはハードウエアで自動再開される) } void delayWDT_setup(unsigned int ii) { // ウォッチドッグタイマーをセット。 // 引数はWDTCSRにセットするWDP0-WDP3の値。設定値と動作時間は概略下記 // 0=16ms, 1=32ms, 2=64ms, 3=128ms, 4=250ms, 5=500ms // 6=1sec, 7=2sec, 8=4sec, 9=8sec byte bb; if (ii > 9 ) { // 変な値を排除 ii = 9; } bb = ii & 7; // 下位3ビットをbbに if (ii > 7) { // 7以上(7.8,9)なら bb |= (1 << 5); // bbの5ビット目(WDP3)を1にする } bb |= ( 1 << WDCE ); MCUSR &= ~(1 << WDRF); // MCU Status Reg. Watchdog Reset Flag ->0 // start timed sequence WDTCSR |= (1 << WDCE) | (1 << WDE); // ウォッチドッグ変更許可(WDCEは4サイクルで自動リセット) // set new watchdog timeout value WDTCSR = bb; // 制御レジスタを設定 WDTCSR |= _BV(WDIE); } ISR(WDT_vect) { // WDTがタイムアップした時に実行される処理 // wdt_cycle++; // 必要ならコメントアウトを外す } float cpuVcc(){ // 電源電圧(AVCC)測定関数 long sum=0; adcSetup(0x4E); // Vref=AVcc, input=internal1.1V for(int n=0; n < 10; n++){ sum = sum + adc(); // adcの値を読んで積分 } return (1.1 * 10240.0)/ sum; // 電圧を計算して戻り値にする } void adcSetup(byte data){ // ADコンバーターの設定 ADMUX = data; // ADC Multiplexer Select Reg. ADCSRA |= ( 1 << ADEN); // ADC イネーブル ADCSRA |= 0x07; // AD変換クロック CK/128 delay(10); // 安定するまで待つ } unsigned int adc(){ // ADCの値を読む unsigned int dL, dH; ADCSRA |= ( 1 << ADSC); // AD変換開始 while(ADCSRA & ( 1 << ADSC) ){ // 変換完了待ち } dL = ADCL; // LSB側読み出し dH = ADCH; // MSB側 return dL | (dH << 8); // 10ビットに合成した値を返す } void testfillcircle(void) { for(int16_t i=max(display.width(),display.height())/2; i>0; i-=3) { // The INVERSE color is used so circles alternate white/black display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE); } } ``` # 余談 Spresenseを使ってみて、遊びで使うにはちょっと使いづらい面も メインボードと拡張ボードが一体化した6000円ぐらいの物があれば使いやすそう メインボードは省電力設計となっているので電圧1.8Vなのかもしれないですが、arduinoと同一だと使いやすそう カメラは高機能だなあ。そこら辺はSONYらしいというか ![キャプションを入力できます](https://camo.elchika.com/8418f267d852372d84bee4b544a47b576e31287d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f62653166393733652d306530312d346431322d613230662d6330343966663838643031302f39313162636666622d376233302d346137322d613036372d353366343531623536353037/) こんな高画質で連続で撮影できます