M5Stick-CとNeoPixelリングでさまざまなエフェクトを選べるランプを作ってみよう
こんにちは、遠藤です。
前回の私の記事「ESP32とフルカラーLEDで色が変化する和紙製ランプを作ってみよう」と同じ様にLチカネタですが、今回はM5Stack-CでNeoPixelリングを制御して、さまざまなエフェクトをボタンで切り替えられるランプを作ってみます。
また、M5Stackシリーズ用の光センサーLIGHT UNITを利用して、暗くなったら自動で点灯、明るくなったら消灯するようにしてみます。
前回の記事では4つのフルカラーLEDをつなげて制御しましたが、この記事で使用するNeoPixelリングは16個のLEDをリング状につなげたパーツとなっています。プログラムの書き方は単体のLEDと同じです。
LIGHT UNITは、Cdsセルという明るさによって抵抗値が変わるパーツが組み込まれていて、光の強さをアナログの電圧またはデジタルな値として読み取ることができます。今回は、M5Stick-Cでデジタル入力から値を読み取り暗くなったら点灯するようにします。
マイコンもESPr Developer 32からM5Stick-Cに変更しています。
その理由は、電池ではやはり長時間の利用に耐えられないため(1000mAhの電池で10から12時間程度)、実用性を考えるとUSB給電で動作させる方が確実といったところです。
また、ESPr Developer 32からの給電ではフルカラーLED PL9823を正常に動作させるにはパワー不足でした。NeoPixelリングでも同様のことが考えられます(未検証です)。
PL9823は、M5Stick-Cからの給電で正常に動作したたためM5Stick-Cを使ってみることにしました。
パーツリスト
以下、このチュートリアルで使用するパーツのリストです。
パーツのECサイトのリンクは、NeoPixelリングが秋月電子通商では扱ってなかったためマルツでまとめています。
QIコネクタ オスのみ、マルツでは扱いがなかったので秋月電子通商のリンクも記載していますが、代用可能なパーツへのリンクを貼ってありますので送料を抑えたい場合はマルツのみでまとめられるようにしてあります。
USB Type-Cケーブルは、M5Stick-Cに付属していますが、付属しているものは短いので設置場所に応じて長いものを用意してください。
ランプシェードは、「ランプシェード 四角錐」というキーワードでググるとアマゾンや楽天の ショップがヒットしますので好きなショップで購入してください。
使用する工具リスト
この記事では、以下の工具を使用します。
ワイヤーの加工に使用する精密圧着ペンチ(写真左)とワイヤーストリッパー(写真中央)は持っていない方がほとんどだと思いますので、なくてもラジオペンチがあればなんとかなります。
とはいえ、あると作業がはかどりますし2000円程度のものなので手元に置いておきたい工具です。
上記の写真に写っている工具はこちら、どちらも電子工作でよく使うサイズのコネクタやワイヤーに対応しています。
ヒートガンは、熱圧縮チューブを収縮させるときに使いますが、こちらについては私も特に困っていないのでライターを代用するで問題ないと思います。
NeoPixelリングにジャンパワイヤーを取り付ける
NeoPixelリングは基盤にピンホールがあるのみなので、GNDとV+、INにワイヤーをはんだ付けし、M5Stack-Cに接続する反対側にはコネクタピンを取り付けます。
まず、ワイヤーを選び適当な長さ、今回は30cmほどにカットします。
色は、GND用は黒、V+用は赤、IN用は黄色を選択すると接続するときにわかりやすいです。
それぞれのワイヤーの皮膜を5から7mm程度剥がして、NeoPixelリングにはんだ付けします。以下ように黒をGNDに、赤をV+、黄色をINに取り付けます。
皮膜はを剥がす作業は、ワイヤーストリッパーがあると楽ですが、無い場合は中の線を切らないようにカッターなどで切り込みをいれて引っ張ると外せます。
裏からみるとこんな感じになります。
LEDとLEDの間が狭くてはんだ付けが難しいですがマスキングテーブなどでうまく固定してがんばってください。
3つのワイヤーを束ねて長さを揃う箇所でカットしておきます。
続いて、M5Stick-Cのコネクタに刺す方は QI コネクタを取り付けます。
ワイヤーの被膜を 1cm 弱ほどはがし、以下の位置に合わせて精密圧着ペンチでかしめます。精密圧着ペンチがない場合は、ラジオペンチでもなんとかなります。
以下の様にしっかりと圧着します。
このままでも使えますが、熱圧縮チューブで圧着箇所を保護します。
熱圧縮チューブを1cmほどに切って、コネクタの圧着箇所に通してヒートガンやライターなどで温めます。
以上で、NeoPixelリングの準備は完了です。
パーツの配線
NeoPixelリング、LIGHT UNITとM5Stick-Cを以下の通りに接続します。
LITHG UNITはGrove端子をつなぐだけです。
プログラム開発環境 Arduino IDE のセットアップ
プログラムの開発はArduino IDEで行います。
Arduino IDEのインストール
以下のArduinoのダウンロードページを開き、お使いのプラットフォームのものをダウンロードしてください。
https://www.arduino.cc/en/software
Windowsの場合は「Windows Win 7 and newer」を、Macの場合は「Mac OS X 10.10 or newer」を選択します。
ダウンロードの際に寄付を求められますが、寄付をしない場合は[JUST DOWNLOAD]をクリックすればダウンロードが始まります。
ダウンロードできたら、WindowsとMacそれぞれ以下の手順でArduino IDEをセットアップします。
Windowsの場合
1. ダウンロードしたファイル「arduino-x.x.x-windows.exe」を開きます。
2. ユーザーアカウント制御のポップアップで[はい]を選択すると、インストーラが起動します。
3. 「Arduino Setup: License Agreement」のページで[I Agree]ボタンをクリックして次に進みます。
4. 「Arduino Setup: Installation Options」のページではデフォルトのまま[Next]をクリックして次に進みます。
5. 「Arduino Setup: Installation Folder」でインストール先のフォルダを確認し、変更したい場合はフォルダを選択して、[Install]ボタンをクリックします。
6. 「Arduino Setup: Installing」が表示されインストールの完了を待ちます。途中、Windows セキュリティのポップアップが表示されるので[インストール]を選択します。完了したら[Close]ボタンをクリックしてインストールウィザードを閉じます。
Arduino IDEの起動は、Windowsメニューからできます。
Macの場合
Macの場合はダウンロードしたファイルがアプリケーションのファイルなので、Finderで「アプリケーション」フォルダに移動しておきます。
Arduino IDEの起動は、Launchpadから選択するか、またはダウンロードしたファイルを直接開きます。
ESP32用のArudiono IDE ボードマネージャをインストール
次に、ESP32用のArudiono IDEボードマネージャをインストールします。
1. Arduino IDEのメニューから[ファイル] > [環境設定] (Macの場合は[Arduino] > [Preferences...])を選択して設定画面を開きます。
2. [追加のボードマネージャのURL]にURL「https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json」を入力して[OK]をクリックします。
次に[ツール] > [ボード "ArduinoUno"] > [ボードマネージャ...]を開きます。
右上のフィルターに「esp32」と入力して、「esp32 by Espressif Systems」の[インストール]ボタンをクリックしてインストールします。
インストールは、数分かかります。完了したらボードマネージャを閉じます。
M5Stick-C用のライブラリをインストール
M5Stick-CのボタンやLCDを制御するためにM5Stick-C用のライブラリをインストールします。
Arduino IDEのメニューの[ツール] > [ライブラリを管理...]を選択して、「ライブラリマネージャ」を開きます。
右上のフィルターに「M5StickC」と入力するといくつかの候補に絞られます。
その中から「M5StickC」の[インストール]ボタンをクリックしてインストールします。
完了したらライブラリマネージャを閉じます。
NeoPixel Ring制御用のライブラリをインストール
Arduino IDEのメニューの[ツール] > [ライブラリを管理...]を選択して、「ライブラリマネージャ」を開きます。
右上のフィルターに「NeoPixel」と入力するといくつかの候補に絞られます。
その中から「Adafuit NeoPixel」の[インストール]ボタンをクリックしてインストールします。
完了したらライブラリマネージャを閉じます。
以上でArduino IDEのセットアップは完了です。
プログラムの作成と書き込み
Arduino IDEを開き、以下のコードを入力します。
#include <M5StickC.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
#endif
// Digital IO pin connected to the button.
#define BUTTON_PIN 37
#define PIXEL_PIN 26 // Digital IO pin connected to the NeoPixels.
#define PIXEL_COUNT 16 // Number of NeoPixels
#define EFFECT_WIPE 1
#define EFFECT_THEATER_CHASE 2
#define EFFECT_RAINBOW 3
#define EFFECT_THEATER_CHASE_RAINBOW 4
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
struct effect {
int type;
uint32_t color;
int wait;
};
struct effect effects[] = {
{EFFECT_WIPE, strip.Color( 0, 0, 0), 100},
{EFFECT_WIPE, strip.Color(255, 0, 0), 100}, // Red
{EFFECT_WIPE, strip.Color( 0, 255, 0), 100}, // Green
{EFFECT_WIPE, strip.Color( 0, 0, 255), 100}, // Blue
{EFFECT_THEATER_CHASE, strip.Color(127, 127, 127), 100}, // White
{EFFECT_THEATER_CHASE, strip.Color(255, 0, 0), 100}, // Red
{EFFECT_THEATER_CHASE, strip.Color( 0, 0, 255), 100}, // Blue
{EFFECT_RAINBOW, strip.Color( 0, 0, 0), 10},
{EFFECT_THEATER_CHASE_RAINBOW, strip.Color( 0, 0, 0), 10}
};
boolean oldState = HIGH;
uint16_t brightness = 1;
int mode = 0; // Currently-active animation mode, 0-9
int effect_type;
uint32_t color;
int wait;
int step_num;
void setup() {
M5.begin();
M5.Axp.ScreenBreath(10);
M5.Lcd.setRotation(1);
M5.Lcd.setCursor(10, 10);
M5.Lcd.printf("Brightness:");
M5.Lcd.setCursor(10, 30);
M5.Lcd.print("Mode:");
// LIGHT UNITデジタル入力用
pinMode(32, INPUT);
// pinMode(GPIO_NUM_10, OUTPUT);
// digitalWrite(GPIO_NUM_10, LOW);
// ボタンのピンにプルアップを指定
pinMode(BUTTON_PIN, INPUT_PULLUP);
strip.begin(); // Initialize NeoPixel strip object (REQUIRED)
strip.show(); // Initialize all pixels to 'off'
}
void loop() {
// Get current button state.
boolean newState = digitalRead(BUTTON_PIN);
// Check if state changed from high to low (button press).
if((newState == LOW) && (oldState == HIGH)) {
// Short delay to debounce button.
delay(20);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.setCursor(78, 30);
M5.Lcd.printf("%d\n", mode);
// Check if button is still low after debounce.
newState = digitalRead(BUTTON_PIN);
if(newState == LOW) { // Yes, still low
if(++mode > 8) mode = 0; // Advance to next mode, wrap around after #8
}
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.setCursor(78, 30);
M5.Lcd.printf("%d\n", mode);
effect_type = effects[mode].type;
color = effects[mode].color;
wait = effects[mode].wait;
step_num = 0;
}
// Set the last-read button state to the old state.
oldState = newState;
// 明るさを読み取る
M5.Lcd.setTextColor(BLACK);
M5.Lcd.setCursor(78, 10);
M5.Lcd.printf("%d\n", brightness);
brightness = digitalRead(32);
M5.Lcd.setTextColor(YELLOW);
M5.Lcd.setCursor(78, 10);
M5.Lcd.printf("%d\n", brightness);
if (brightness == LOW) {
// 明るかったらなら消灯
strip.clear();
strip.show();
delay(1000);
return;
}
switch(effect_type) {
case EFFECT_WIPE:
if (step_num < strip.numPixels()) {
strip.setPixelColor(step_num, color);
} else {
strip.setPixelColor(step_num - strip.numPixels(), strip.Color( 0, 0, 0));
}
strip.show();
if (++step_num > strip.numPixels() * 2) {
step_num = 0;
}
break;
case EFFECT_THEATER_CHASE:
strip.clear();
for(int c=step_num; c<strip.numPixels(); c += 3) {
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show();
if (++step_num == 3) {
step_num = 0;
}
break;
case EFFECT_RAINBOW:
for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
// Offset pixel hue by an amount to make one full revolution of the
// color wheel (range of 65536) along the length of the strip
// (strip.numPixels() steps):
int pixelHue = step_num + (i * 65536L / strip.numPixels());
// strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
// optionally add saturation and value (brightness) (each 0 to 255).
// Here we're using just the single-argument hue variant. The result
// is passed through strip.gamma32() to provide 'truer' colors
// before assigning to each pixel:
strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
}
strip.show(); // Update strip with new contents
step_num += 256;
if (step_num == 3*65536) {
step_num = 0;
}
break;
case EFFECT_THEATER_CHASE_RAINBOW:
strip.clear();
int b = step_num % 3;
for(int c=b; c<strip.numPixels(); c += 3) {
// hue of pixel 'c' is offset by an amount to make one full
// revolution of the color wheel (range 65536) along the length
// of the strip (strip.numPixels() steps):
int hue = step_num + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
}
strip.show();
step_num += 65536 / 90;
if (step_num == 65536) {
step_num = 0;
}
break;
}
delay(wait);
}
こちらのコードは、Adafruit_NeoPixelのサンプルbuttoncyclerを基に機能を追加しました。
続いてプログラムをESP32開発ボードに書き込んでいきます。
ESP32開発ボードをUSBケーブルで繋ぎます。
Arduino IDEでボードを「ESP32 Dev Module」に切り替えます。
[ボード: "Arduino Uno"] > [ESP32 Arduino] > [M5Stick-C]を選択します。
次にシリアルポートを切り替えます。
Windowsの場合は、まずポート名をデバイスマネージャで確認します。
この場合は、「COM3」を選択します。
Macの場合は、[ツール] > [シリアルポート]で「/dev/cu.usbserial-695225E845」を選択します。
「書込装置を使って書き込む」ボタンをクリックして、コンパイルと転送を開始しいます。
ランプシェードをつけて完成
あとは給電用のUSBアダプタに繋いで、ランプシェードをのせれば完成です。
NeoPixelRingの上にランプシェードをのせます。
あとは部屋を暗くして、ボタンを押してエフェクトを選ぶと記事冒頭の動画のようにランプを光らせることができます。
また、設置場所の照明の明るさなどに依ってランプをOn/Offする明るさを調整する必要があります。その場合はLIGHT UNITの青いネジを回し、Brightnessの値が主照明の明るさでは「0」で、ランプのLEDの明るさだと「1」となるポイントを探して設定してみてください。
この記事が気に入ったらサポートをしてみませんか?