LoginSignup
3
0

More than 3 years have passed since last update.

在宅ウェブ会議用LEDライト作ってみた

Last updated at Posted at 2020-04-06

背景

昨今は、在宅勤務を余儀なくされている方々が多いと思います。
嫁さんが「ウェブ会議で映る自分の顔が暗い」と言ってたので
たまたま家にあったLEDリングライトとArduino互換ボードで
小型照明を作ってみました。

LEDコントローラ01.jpg

ハードウエアなど詳細については、別のブログ記事に書いています。
こちらでは、電気回路とコード内容について書きました。

部品構成

アイテム 数量 備考
Arduino互換ボード 1個 わずか80円!謎のArduino互換機を動かしてみた
LEDリングライト24灯 1個
ジョイスティック 1個
タクトスイッチ 3個 お好きなだけ
LEDカバー 1個 3Dプリンタ品

SAMさん情報で買っていた謎の激安ボードを採用しました。
使い方はコチラ、ともさんのQiita記事
LGT8f328P Arduino互換ボードを使ってみる
を参考にしました。この情報が無ければ使えなかったでしょう、感謝!

電気回路図

次のブレッドボード図を参考お願いします。

LED-controler01.jpg

図は本家のArduino MINIで描いていますので、読み替えお願いします。
MINIと同様にUSBシリアル変換を使って、ArduinoIDEでスケッチ書き込みできました。

スケッチ

Arduino IDE 1.8.11 を使用しました。

以下、コードを少し区切って説明します。
順番に全てを繋げれば動くはずですが、必要に応じて適時修正お願いします。

#include <FastLED.h>

#define NUM_LEDS 24
#define DATA_PIN 8           // Neopixel data pin
CRGB leds[NUM_LEDS];

const int xAxis = A0;         // joystick X axis
const int yAxis = A1;         // joystick Y axis
const int posButton = 13;     // input pin for position mode
const int clrButton = 12;     // input pin for color mode
const int briButton = 11;     // input pin for bright mode
int threshold = 1000000;        // resting threshold

int modeState = 0;            // effective mode state
int modeStated = 0;           // previous mode state
int resetModes = 3;           // countdown to reset
int resetMode = resetModes;
int freetimes = 100;          // countdown to mode cancel
int freetime = freetimes;

int posLed = 0;               // LED ON position
int posLeds[24] = {};
int hueLed = 64;              // LED color type, yellow
int satLed = 128;             // 255 = pure color, 0 = plain white
int valLed = 128;             // LED brightness

void setup() {
  Serial.begin(9600);
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
}

冒頭は、I/Oピン定義、各変数の定義です。
全ての変数の意味は、すみませんが説明省略します。
setupにて、neopixelのライブラリ定義。以降は、並んでいるLEDの番号ごとに
色や明るさを指定してから FastLED.show(); の命令で点灯。とても楽ちん。

void loop() {
  pinMode(posButton, INPUT_PULLUP);
  pinMode(clrButton, INPUT_PULLUP);
  pinMode(briButton, INPUT_PULLUP);
  long xReading = (long)readAxis(xAxis) * -1;
  long yReading = (long)readAxis(yAxis);
  long rReading = (xReading * xReading) + (yReading * yReading);
  long degReading = _atan2(yReading , xReading);

  // mode select
  int posMode = digitalRead(posButton);
  int clrMode = digitalRead(clrButton);
  int briMode = digitalRead(briButton);
  if (posMode + clrMode + briMode == 0) modeState = 1;
  else if (posMode + clrMode + briMode == 2 and posMode == 0){
    modeState = 2;
    for(int j = 2; j < 8; j += 2){
      for(int i = 0; i < NUM_LEDS; i += 1) {    // mode effect & reset position
        if(i % j == 0) leds[i] = CHSV(0, 0, 128);
        else          leds[i] = CHSV(0, 0, 0);
        posLeds[i] = 0;
      }
      FastLED.show();
      delay(200);
    }
    if(modeState == modeStated) resetMode -= 1;
  }else if (posMode + clrMode + briMode == 2 and clrMode == 0){
    modeState = 3;
    for(int j = 0; j < 256; j += 32){
      for(int i = 0; i < NUM_LEDS; i += 1) {      // mode effect
        if(i > 15 and i < 21) leds[i] = CHSV(0, 0, 0);
        else          leds[i] = CHSV(j, 128, 128);
      }
      FastLED.show();
      delay(100);
    }
    satLed = 128;             // reset saturation
    if(modeState == modeStated) resetMode -= 1;
  }else if (posMode + clrMode + briMode == 2 and briMode == 0){
    modeState = 4;
    for(int j = 0; j < 256; j += 32){
      for(int i = 0; i < NUM_LEDS; i += 1) {      // mode effect
        leds[i] = CHSV(0, 0, j);
      }
      FastLED.show();
      delay(100);
    }
    if(modeState == modeStated) resetMode -= 1;
  }else{
    if(resetMode < 0){
      switch (modeStated){
        case 2:       //long press posB = all turn on
        for(int i = 0; i < NUM_LEDS; i += 1) {
          posLeds[i] = 1;
        }
        break;
        case 3:       //long press clrB = plain white
        satLed = 0;
        break;
        case 4:       //long press briB = half lit
        valLed = 128;
        break;
      }
    }
    resetMode = resetModes;
    // long time hands-free = mode cancel
    if(rReading < threshold) freetime -= 1;
    if(freetime < 0) modeState = 0;
  }
  if(modeState != modeStated) freetime = freetimes;

ブレッドボード図の各種ボタンを押してモード切り替えします。
私は3ボタンにしたので、モードは3パターン。さらに長押しにも意味を持たせています。

ボタン モード 長押し
光る場所を指定 全周点灯
中央 色を設定 無色(白)に設定
明るさと彩度を変更 彩度を50%に設定

ボタン押している間は、役割に応じてアニメーション点灯する事で
何のモードに入ったか分かるようにしています。
例えば中央「色を設定」ならば、リングライトが「C」の文字に光ります。

  // reset & all black
  switch (modeState){
    case 1:
    for(int i = 0; i < NUM_LEDS; i += 1){
      leds[i] = CHSV(0, 0, 0);
    }
    modeStated = 1;
    delay(1000);
    break;

  // change position mode
    case 2:
    if(rReading > threshold){
      posLed = map(degReading, 0, 36000, 0, 24);
      if(posLeds[posLed] == 0) posLeds[posLed] = 1;
    }
    modeStated = 2;
    break;

  // change color mode
    case 3:
    if(rReading > threshold){
      hueLed = map(degReading, 0, 36000, 0, 256);
    }
    modeStated = 3;
    break;

  // change bright mode
    case 4:
    if (xReading > threshold/100) satLed -= 4;
    else if(xReading < -threshold/100) satLed += 4;
    if (yReading > threshold/100) valLed -= 4;
    else if(yReading < -threshold/100) valLed += 4;
    if(satLed > 255) satLed = 255;
    else if(satLed < 0) satLed = 0;
    if(valLed > 255) valLed = 255;
    else if(valLed < 0) valLed = 0;    
    modeStated = 4;
    break;
  }

  // LED set & turn on
    for(int i = 0; i < NUM_LEDS; i += 1) {
      if(posLeds[i] == 1) leds[i] = CHSV(hueLed, satLed, valLed);
      else                leds[i] = CHSV(0, 0, 0);
    }
  FastLED.show();
  delay(100);
}

各種モードに入った後、ジョイスティックを動かした時の挙動を定義しています。
LEDの色や明るさを変数で設定してから、その通りに点灯させる、を繰り返してます。

// read the analog input
int readAxis(int thisAxis) {
  int reading = analogRead(thisAxis);
  int distance = reading - 2000;       //adjusted center
  return distance;
}

// convert xy => degree(0 to 36000)
long _atan2(long _y, long _x) {
  long x = abs(_x);
  long y = abs(_y);
  float   z;
  bool    c;

  c = y < x;
  if (c)z = (float)y / x;
  else  z = (float)x / y;

  long a;
  //a = z * (-1556 * z + 6072);                     //2次曲線近似
  //a = z * (z * (-448 * z - 954) + 5894);          //3次曲線近似
  a = z * (z * (z * (829 * z - 2011) - 58) + 5741); //4次曲線近似

  if (c) {
    if (_x > 0) {
      if (_y < 0)a = 36000 - a;
    }
    if (_x < 0) {
      if (_y > 0)a = 18000 - a;
      if (_y < 0)a = 18000 + a;
    }
  }
  if (!c) {
    if (_x > 0) {
      if (_y > 0) a = 9000 - a;
      if (_y < 0) a = 27000 + a;
    }
    if (_x < 0) {
      if (_y > 0) a = a + 9000;
      if (_y < 0) a = 27000 - a;
    }
  }
  return a;
}

ジョイスティックのXY軸入力から、ベクトル角度に換算します。
次の記事を参考させていただきました。
近似式でatan2の処理を高速化してみる

まとめ

今回も先人の方々の知恵や情報がなければ完成できませんでした。感謝感謝です。
この記事が少しでも参考になれば幸いです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0