モノづくりコミュニティのために居心地の良い素敵な空間を提供してくれている「工作室もくもくはりねずみ」の移転・新装開店を記念する文化祭でちょいとお話しようとしておもしろい体験をした。
実は毎年何回か,近隣の子供たちに電子工作を楽しんでもらうための簡単な玩具を作っているのだけど,来年の新年会では最近発見しておもしろいなぁとはまっているぐにゃぐにゃLEDを3Dプリンターで作った玩具に巻き付けて光らせて遊ぼうと現在大量生産中。
これを工作室モクハリの文化祭でみんなに見せようと思ったんだけど,さすがに工作オタクが集まる会で光るだけの玩具じゃみんなスルーだよね,とひと工夫することにした。
いろいろ変化するLチカを作る
手元にあったM5ATOM Liteを電池抱き合わせにした「ATOM Motion」を使ってピカピカ光らせてやろうともくろんだ。
ATOM Motionならある程度余裕のある電池が付属している。これだけでLEDオーナメントを光らせられるので,ハンディで便利だと選定した。
光らせるのも,ただ光らせるLチカだけじゃ今どきおもしろくない,少し変化のある光らせ方をしてやろうと思ったわけ。
ぐにゃぐにゃ曲がるLEDは3Vで光ってくれるので,ATOM LITEに付いているGROVE端子のグランドと信号端子の3番目か4番目のピンに刺してやればいろいろ光り方をコントロールできるはず。
さて,プログラムを書こう,と思ったらここしばらく(1年くらい)こういうプログラムを書いてない。どうするんだっけ?
そうだ,AIに聞いてみよう
ということで、MicrosoftのAI, Copilotにコードの書き方ヒントを教えてもらうことにした。
まず,こう切り出してみた。
[私]Arduinoのプログラムの話です。
digitalWrite(LED_PIN, HIGH);
でLEDが点灯しますが,この後,ランダムに光ったり,ゆっくりフェイドアウトしたりさせたい。この部分のコードを書いてください。
ものの数秒後,こんなふうに答えてくれた。
もちろん、ArduinoでLEDがランダムに光ったり、ゆっくりフェイドアウトしたりするコードを提供します。以下のコードを使用すると、LEDがランダムに点灯し、フェイドアウトします:
#define LED_PIN 9 // LEDのピン番号
void setup() {
pinMode(LED_PIN, OUTPUT);
randomSeed(analogRead(0)); // ランダムシードを設定
}
void loop() {
// LEDをランダムに点滅させる
int delayTime = random(100, 1000); // 100msから1000msの間でランダムな時間
digitalWrite(LED_PIN, HIGH);
delay(delayTime);
digitalWrite(LED_PIN, LOW);
delay(delayTime);
// LEDをゆっくりフェイドアウトさせる
for (int brightness = 255; brightness >= 0; brightness--) {
analogWrite(LED_PIN, brightness);
delay(10); // フェイドアウトの速度を調整
}
}
このコードは以下の機能を持ちます:
- randomSeed(analogRead(0))でランダムシードを設定し、ランダムな点滅を実現します。
- random(100, 1000)で100ミリ秒から1000ミリ秒のランダムな時間でLEDを点滅させます。
- analogWrite(LED_PIN, brightness)でLEDの明るさを制御し、delay(10)を使ってゆっくりとフェイドアウトします。
このコードをArduinoにアップロードして実行すると、LEDがランダムに点灯し、その後ゆっくりとフェイドアウトする動作を確認できるはずです。お試しください!
何か他に質問があれば教えてくださいね。
お〜〜〜! すごい!
これでモクハリに行ける、と早速Arduino IDEを通じてM5 ATOM Liteにプログラムを流し込んだ。
ところが,全然動かないじゃないか。
コードを見直してみたら、LEDのPIN番号指定が「9」になっている。今回LEDを刺したGROVE端子の4番目は実際のところ何番なのか? こういうときは原典に当たる必要がある。M5 Stack社のATOM Liteの仕様を調べてみた。
すると,以下の通り,GROVEの4番ピンはGPIOの32がつながっていることが分かる。
Copilotにはそこの詳細情報は教えていないので,Arduinoの標準的なLED番号を回答してきたのだろう。
そこで,
#define LED_PIN 9
の部分を
#define LED_PIN 32
と書き換えて実行してみた。
それでもまだ動かない
う〜む、それでもまだ動かない。どこが悪いんだ? ともう一度コードを見直してみたら
LEDを点灯させるコードに
analogWrite(LED_PIN, brightness);
と書かれている。
実はATOM Liteに入っているマイコンはESP32をベースにしており、analogWrite
というコマンドは用意されておらず,動かないのだ。
はは〜ん、ここだな。ここを修正すればいいんだな。
でも、なんと書直せばいいのか? すぐに思い出せないな〜と。
またまた困ったときのAI頼みだ。
[私]ターゲットマシンはESP32です。
analogWrite()
はESP32では動かないと思います。analogWrite()
の部分を修正してください。
すると,一瞬でこう答えてきた。
ESP32はArduinoのanalogWrite()関数をサポートしていません。ただし、同様の機能を実現するためにPWM(パルス幅変調)を使うことができます。ESP32では、ledcWrite()関数を使ってPWMを制御します。
以下は、ESP32でLEDをランダムに点灯し、フェイドアウトさせるためのコードの例です:
#define LED_PIN 9 // LEDのピン番号
void setup() {
ledcSetup(0, 5000, 8); // チャネル0、5kHz、8ビットの解像度を設定
ledcAttachPin(LED_PIN, 0); // LED_PINをチャネル0にアタッチ
randomSeed(analogRead(0)); // ランダムシードを設定
}
void loop() {
// LEDをランダムに点滅させる
int delayTime = random(100, 1000); // 100msから1000msの間でランダムな時間
ledcWrite(0, 255); // LEDを点灯(最大輝度)
delay(delayTime);
ledcWrite(0, 0); // LEDを消灯
delay(delayTime);
// LEDをゆっくりフェイドアウトさせる
for (int brightness = 255; brightness >= 0; brightness--) {
ledcWrite(0, brightness);
delay(10); // フェイドアウトの速度を調整
}
}
このコードでは、ledcSetup()関数を使ってPWMを設定し、ledcWrite()関数でLEDの明るさを制御しています。これにより、ESP32でもLEDの点灯やフェイドアウトを行うことができます。
これを試して、ESP32でのLED制御を楽しんでください!他に質問があれば教えてくださいね。
オ〜〜動いた!
LEDピン番号は指示し直していないので,相変わらずピン番号9と書いてくるが,マイコンに流し込むときに32と書直して実行する。
すると、見事。
ゆっくりと点いたり消えたり。さすが,AIだ。
でも,何だか単調だな,芸が無さすぎ。これじゃ,モクハリの参加者は見向きもしてくれないだろう。
そこで,またAIにお願い。
[私]ハイ,なかなかいいですね。もっと複雑な変化は出来ますか? パパパ,っと点灯したかと思うとしばらくしたらゆっくり点灯,また数秒間ついたり消えたりしたあとゆっくり点灯して,また早めの点滅する,といった動作です。
もちろん、複雑なLEDの動作を実現するためのコードを提供します。以下のコードでは、LEDが素早く点灯した後、ゆっくりと点灯し、数秒間ついたり消えたりした後、再びゆっくり点灯し、最後に早めの点滅を行います。
#define LED_PIN 9 // LEDのピン番号
void setup() {
ledcSetup(0, 5000, 8); // チャネル0、5kHz、8ビットの解像度を設定
ledcAttachPin(LED_PIN, 0); // LED_PINをチャネル0にアタッチ
randomSeed(analogRead(0)); // ランダムシードを設定
}
void loop() {
// パパパッと点灯
for (int i = 0; i < 5; i++) {
ledcWrite(0, 255);
delay(100);
ledcWrite(0, 0);
delay(100);
}
// ゆっくり点灯
for (int brightness = 0; brightness <= 255; brightness++) {
ledcWrite(0, brightness);
delay(20);
}
delay(1000); // しばらく点灯したまま
// 数秒間ついたり消えたり
for (int i = 0; i < 10; i++) {
ledcWrite(0, 255);
delay(500);
ledcWrite(0, 0);
delay(500);
}
// 再びゆっくり点灯
for (int brightness = 0; brightness <= 255; brightness++) {
ledcWrite(0, brightness);
delay(20);
}
delay(1000); // しばらく点灯したまま
// 早めの点滅
for (int i = 0; i < 20; i++) {
ledcWrite(0, 255);
delay(100);
ledcWrite(0, 0);
delay(100);
}
}
このコードでは、以下の順序でLEDの動作を制御しています:
- パパパッと点灯:100ミリ秒間隔で5回素早く点滅。
- ゆっくり点灯:20ミリ秒の間隔で徐々に明るくなり、1000ミリ秒間点灯。
- 数秒間ついたり消えたり:500ミリ秒間隔で10回点滅。
- 再びゆっくり点灯:再び20ミリ秒の間隔で徐々に明るくなり、1000ミリ秒間点灯。
- 早めの点滅:100ミリ秒間隔で20回点滅。
これを試して、LEDの複雑な動作をお楽しみください。他にもご質問があれば教えてくださいね。
いやあ,素晴らしい、ゆっくり点灯したり,ぱぱっと点いたり消えたり。
でもまだ味気ない。もっと遊んでほしいな
しばらく見ていると毎回同じパターンだと飽きてくる感じだ。
そこで,またまたAIに注文した。
[私]いいですね! このパターンをランダムな順番で実行させるにはどうすればいいですか?
ランダムな順番でLEDのパターンを実行させるには、パターンごとに関数を作成し、ランダムに関数を呼び出す方法が効果的です。以下のコードでは、各パターンを関数化し、ランダムに実行させるようにしています。
#include <Arduino.h>
#define LED_PIN 9 // LEDのピン番号
void setup() {
ledcSetup(0, 5000, 8); // チャネル0、5kHz、8ビットの解像度を設定
ledcAttachPin(LED_PIN, 0); // LED_PINをチャネル0にアタッチ
randomSeed(analogRead(0)); // ランダムシードを設定
}
void loop() {
int pattern = random(0, 4);
switch (pattern) {
case 0:
rapidBlink();
break;
case 1:
slowFadeIn();
break;
case 2:
blinkOnOff();
break;
case 3:
quickBlink();
break;
}
}
// パパパッと点灯
void rapidBlink() {
for (int i = 0; i < 5; i++) {
ledcWrite(0, 255);
delay(100);
ledcWrite(0, 0);
delay(100);
}
}
// ゆっくり点灯
void slowFadeIn() {
for (int brightness = 0; brightness <= 255; brightness++) {
ledcWrite(0, brightness);
delay(20);
}
delay(1000); // しばらく点灯したまま
}
// 数秒間ついたり消えたり
void blinkOnOff() {
for (int i = 0; i < 10; i++) {
ledcWrite(0, 255);
delay(500);
ledcWrite(0, 0);
delay(500);
}
}
// 早めの点滅
void quickBlink() {
for (int i = 0; i < 20; i++) {
ledcWrite(0, 255);
delay(100);
ledcWrite(0, 0);
delay(100);
}
}
このコードでは、以下のことを実現しています:
- 各パターン(「パパパッと点灯」「ゆっくり点灯」「数秒間ついたり消えたり」「早めの点滅」)を関数に分けました。
- loop()関数内で、ランダムにパターンを選び、選ばれた関数を実行するようにしました。
これを実行すると、LEDはランダムな順番で異なるパターンの点灯を繰り返します。ぜひ試してみてください!
他にも質問があれば教えてくださいね。
うん,なかなかいい。
でも、ゆっくり点灯する動作はあるけど,ゆっくり消灯する動作がないなぁ。
[私]ゆっくり消灯する関数も追加してください。
もちろんです。ゆっくり消灯する関数を追加して、LEDの動作をさらに複雑にするコードを提供します。以下に、消灯の関数を追加した完全なコードを示します:
#include <Arduino.h>
#define LED_PIN 9 // LEDのピン番号
void setup() {
ledcSetup(0, 5000, 8); // チャネル0、5kHz、8ビットの解像度を設定
ledcAttachPin(LED_PIN, 0); // LED_PINをチャネル0にアタッチ
randomSeed(analogRead(0)); // ランダムシードを設定
}
void loop() {
int pattern = random(0, 5);
switch (pattern) {
case 0:
rapidBlink();
break;
case 1:
slowFadeIn();
break;
case 2:
blinkOnOff();
break;
case 3:
quickBlink();
break;
case 4:
slowFadeOut();
break;
}
}
// パパパッと点灯
void rapidBlink() {
for (int i = 0; i < 5; i++) {
ledcWrite(0, 255);
delay(100);
ledcWrite(0, 0);
delay(100);
}
}
// ゆっくり点灯
void slowFadeIn() {
for (int brightness = 0; brightness <= 255; brightness++) {
ledcWrite(0, brightness);
delay(20);
}
delay(1000); // しばらく点灯したまま
}
// 数秒間ついたり消えたり
void blinkOnOff() {
for (int i = 0; i < 10; i++) {
ledcWrite(0, 255);
delay(500);
ledcWrite(0, 0);
delay(500);
}
}
// 早めの点滅
void quickBlink() {
for (int i = 0; i < 20; i++) {
ledcWrite(0, 255);
delay(100);
ledcWrite(0, 0);
delay(100);
}
}
// ゆっくり消灯
void slowFadeOut() {
for (int brightness = 255; brightness >= 0; brightness--) {
ledcWrite(0, brightness);
delay(20);
}
}
このコードにより、ランダムに以下のパターンが実行されます:
- パパパッと点灯
- ゆっくり点灯
- 数秒間ついたり消えたり
- 早めの点滅
- ゆっくり消灯(新しく追加)
これを試して、さらに複雑なLEDの動作を楽しんでください!他にも質問があれば教えてくださいね。
このコードをM5ATOM Liteに流し込んだら、
ランダムに以下のパターンが実行された!!!
1. パパパッと点灯
2. ゆっくり点灯
3. 数秒間ついたり消えたり
4. 早めの点滅
5. ゆっくり消灯(新しく追加)
いやあ! AI君,大したもんじゃないか。
これで工作室モクハリの文化祭、LT大会に持って行ける。ランチのあと、たった1時間でおもしろいものができた。
AIに聞けばいろんなことが瞬時に解決できるし,何回無理難題を言っても文句を言わずに答えてくれる。素晴らしい。
しかし,最初の回答で動かなかった問題は,ある程度のハード・ソフトの基礎知識を身に付けておかなければクリアできなかっただろう。やはり,その分野の全体像を理解する知識を身に付けた上でAIシステムと付き合うことが必要,ということですね。