ASRでATOMS3 LITE経由にしてFlashLightを点灯する

以前は、Unit ASRをシリアル経由でTHINKLETに接続して、音声コマンドを実行するデモをやった。録画の開始と終了をstart/stopで指示できるやつなのだけど、モックなので実際に録画はしていないやつ。

 今回は、ASRを直接THINKLETに接続するのではなく、制御用のマイコンを間にはさんで、ASRからの音声コマンドで、Unit FlashLightを制御しつつ、THINKLETにも動作したコマンド履歴を送りたい。

 GroveはFlashLightを接続するので、ASRは底面ピン側に接続。縦4ピンなので簡単かな。

 配線はこんな感じ。ASRはGroveに、ATOMS3 liteのピンから取ってGroveに変換してFlashLightに配線している。

 とりあえず、ASRの動作確認用のスケッチを書く。

#include <Arduino.h>
#include <HardwareSerial.h>

HardwareSerial ASR(1);

 // 受信のみ(ASR TX→ATOM RX)

 constexpr int PIN_RX = 39; // ATOM側RX

 constexpr int PIN_TX = 38; // 未使用でもbeginで指定

constexpr uint32_t BAUD = 115200;

// AA 55 <CMD> 55 AA
enum State : uint8_t { WAIT_AA, WAIT_55A, GOT_CMD, WAIT_55B, WAIT_AA2 };
static State st = WAIT_AA;
static uint8_t cmd = 0;

void setup() {
Serial.begin(115200);
ASR.begin(BAUD, SERIAL_8N1, PIN_RX, PIN_TX);

 }

void loop() {
while (ASR.available()) {
uint8_t b = ASR.read();
switch (st) {

 case WAIT_AA:

st = (b == 0xAA) ? WAIT_55A : WAIT_AA; break;

 case WAIT_55A:

if (b == 0x55) st = GOT_CMD;
else st = (b == 0xAA) ? WAIT_55A : WAIT_AA;
break;

 case GOT_CMD:

cmd = b; st = WAIT_55B; break;

 case WAIT_55B:

st = (b == 0x55) ? WAIT_AA2 : WAIT_AA; break;

 case WAIT_AA2:

if (b == 0xAA) {

 // 16進(0xNN)で出力

Serial.printf("0x%02X\n", cmd);

 }

st = WAIT_AA; break;

 }

 }

 }

 うまく動いている。今回はHEXで出すようにした。

 ASRのプリセット音声コマンドで、照明の操作に使えそうなのはこの4つ。

 0x18 = turn on the lights(点灯)

 0x19 = turn off the lights(消灯)

0x14 = turn on
0x15 = turn off

 前に作ったFlashLightの制御スケッチとマージする。

FlashLight Unit買ってみた|kinneko|pixivFANBOX
https://kinneko.fanbox.cc/posts/10232381

 FlashLight Unit買ってみた 2025年9月3日 08:00  ただのLEDではなく、フラッシュまたは照明アプリケーションとして使えるユニット。あんまり、こんなユニット使ってみている人はいなさそう。用途は、なんかあったとき用に高輝度でチカチカさせるとか?  とりあえず、照明用に明るいのがほしかっただけ。パーツでいろいろ揃えたり、百均に行ってみたりしたけど、これ... 全体公開 kinneko

 いずれかのコマンドが来たらオンオフする。USBシリアルにはTHINKLETで受信できるように、ASRのコマンドと、ライトのON/OFF/AUTOOFFを送信する。

#include <Arduino.h>
#include <HardwareSerial.h>

 // ----- FlashLight配線/設定 -----

 constexpr int PIN_SIG = 2; // HY2.0-4P 黄(G2) → Unit FlashLight SIG

 constexpr int PIN_BTN = 41; // 反応しなければ 39 に変更

constexpr int PWM_FREQ = 5000; // 5 kHz
constexpr int PWM_RES  = 10;   // 10-bit (0..1023)

 constexpr int BRIGHTNESS_PERCENT = 100; // 必要に応じて下げる

 constexpr uint32_t TORCH_TIMEOUT_MS = 15000; // 自動消灯 15秒

 // ----- ASR(UART) 配線/設定 -----

HardwareSerial ASR(1);

 constexpr int PIN_ASR_RX = 39; // ATOM側RX (ASRのTXへ)

 constexpr int PIN_ASR_TX = 38; // 未使用でもbeginで指定

constexpr uint32_t ASR_BAUD = 115200;   // 115200 8N1

 // ----- デバウンス -----

constexpr uint32_t DEBOUNCE_MS = 50;
bool stable = HIGH, lastRaw = HIGH;
uint32_t lastChange = 0;

 // ----- 状態 -----

bool torch = false;
uint32_t torchOnSince = 0;

inline int dutyPct(int p) {
p = constrain(p, 0, 100);
const int maxDuty = (1 << PWM_RES) - 1;

 return (p * maxDuty + 50) / 100; // 四捨五入

 }

enum OffReason : uint8_t { OFF_MANUAL = 0, OFF_AUTO = 1 };

inline void setTorch(bool on, OffReason reason = OFF_MANUAL) {

 if (torch == on) return; // 変化なし

analogWrite(PIN_SIG, on ? dutyPct(BRIGHTNESS_PERCENT) : 0);
torch = on;
if (on) {
torchOnSince = millis();
Serial.println("ON");
} else {
if (reason == OFF_AUTO) Serial.println("AUTOOFF");
else                    Serial.println("OFF");

 }

 }

 // ----- ASRフレーム: AA 55 55 AA -----

enum State : uint8_t { WAIT_AA, WAIT_55A, GOT_CMD, WAIT_55B, WAIT_AA2 };
State st = WAIT_AA;
uint8_t cmd = 0;

void setup() {
Serial.begin(115200);

pinMode(PIN_BTN, INPUT_PULLUP);

 analogWriteFrequency(PIN_SIG, PWM_FREQ); // ピン指定あり

 analogWriteResolution(PIN_SIG, PWM_RES); // ピン+分解能

analogWrite(PIN_SIG, 0);

stable = lastRaw = digitalRead(PIN_BTN);

ASR.begin(ASR_BAUD, SERIAL_8N1, PIN_ASR_RX, PIN_ASR_TX);

 }

void loop() {

 // ----- ASR受信処理 -----

while (ASR.available()) {
uint8_t b = ASR.read();
switch (st) {

 case WAIT_AA:

st = (b == 0xAA) ? WAIT_55A : WAIT_AA; break;

 case WAIT_55A:

if (b == 0x55) st = GOT_CMD;
else st = (b == 0xAA) ? WAIT_55A : WAIT_AA;
break;

 case GOT_CMD:

cmd = b; st = WAIT_55B; break;

 case WAIT_55B:

st = (b == 0x55) ? WAIT_AA2 : WAIT_AA; break;

 case WAIT_AA2:

if (b == 0xAA) {

 // 受信CMDをHEXで出力

Serial.printf("0x%02X\n", cmd);

 // ライト制御

if (cmd == 0x18 || cmd == 0x14) {       // lights on / turn on
setTorch(true, OFF_MANUAL);
} else if (cmd == 0x19 || cmd == 0x15) { // lights off / turn off
setTorch(false, OFF_MANUAL);

 }

 }

st = WAIT_AA; break;

 }

 }

 // ----- ボタン処理(立下りでトグル)-----

 bool raw = digitalRead(PIN_BTN); // 押下でLOW

if (raw != lastRaw) lastChange = millis();
if (millis() - lastChange > DEBOUNCE_MS) {
if (raw != stable) {
stable = raw;
if (stable == LOW) setTorch(!torch, OFF_MANUAL);

 }

 }

lastRaw = raw;

 // ----- 自動消灯 -----

if (torch && (millis() - torchOnSince >= TORCH_TIMEOUT_MS)) {

 setTorch(false, OFF_AUTO); // ★自動消灯メッセージ

 }

 }

 まぁ、普通に動くよね。しかし、あいかわらず英語で反応が不安定なところは残るな。自分の発音が悪いのだろうけど。テンション高くしゃべらないとダメだな...

 THINKLETに仮付けするとこんな感じ。普通に使える。

 100円投げ銭  https://kinneko.booth.pm/items/1963720


オリジナル投稿:
ASRでATOMS3 LITE経由にしてFlashLightを点灯する|kinneko|pixivFANBOX
https://kinneko.fanbox.cc/posts/10466657