ジュールシーフ × ATtiny-85 × フルカラーLED (2)

前回の続き。

一般的な機器類で使い古した1V程度の電池切れ、の乾電池(単3か単4あたりを想定。今回は単3)の電圧を昇圧してもう少し使いたい、そしてその昇圧回路もできれば多少安く組みたい、という流れです。いくつか試して、とりあえずHT77XAシリーズにしました、が前回までの内容で。

haseharu.hatenablog.com

一般的な電気機器で利用していて電池切れとなった単3電池(ここでは1.0V程度とする)では、低電力LEDでも光らないと思います。実際に1Vを切った電池をつなげてみてもやはりダメそうです。

f:id:haseharu:20211222212440j:plain

というか、そもそもここで使っている赤色LEDは順電圧2.0Vなので新品のアルカリ単3電池1本でも発光に必要な電流は流れません。

akizukidenshi.com

ATtiny-85も動きません。

akizukidenshi.com

前回までで手元にあったHT77XA昇圧後、低電力LEDやら順電圧3.1Vの青色LEDなんかも光るところまで確認しています。この使い古し電池を昇圧した電源を使って、クリスマスのイルミネーション用にフルカラーLEDが少しずつ色が変わっていくプログラムをATtiny-85で動かしたいと思います。

akizukidenshi.com

プログラム自体は、こちらの書籍*1の「第1章 4 カラーLED」のプログラムをほぼそのまま使わせてもらっています。

www.rutles.net

  #define LED_R 0
  #define LED_G 1
  #define LED_B 2

void setup() {
}

void loop() {
  uint8_t r, g, b;
  uint8_t i;

  for(i=0;;i++){
    
    r = (sin(2 * 3.14 / 256 * i) + 1) * 128;
    g = (sin(2 * 3.14 / 256 * (i + 85)) + 1) * 128;
    b = (sin(2 * 3.14 / 256 * (i + 170)) + 1) * 128;

    analogWrite(LED_R,r);
    analogWrite(LED_G,g);
    analogWrite(LED_B,b);
    delay(20);    
    }
}

Arduino Unoあたりで一度試して動作確認ができたらATtiny-85をArduino化しプログラムを書き込みます。

haseharu.hatenablog.com

書き込み終わったら、ATtiny-85とフルカラーLED等をつないで、LEDが光ればOKです。上記エントリでも書いていますが、ATtiny-85自体のピン番号とGPIOの番号は違うので注意が必要。以下、データシート含めて再掲。今回はGPIOの「0,1,2」を使っています。

https://akizukidenshi.com/download/ds/atmel/attiny25_attiny45_attiny85.pdf

ATtiny-85 Pinout
1 5
2 3
3 4
4 GND
5 0
6 1
7 2
8 VCC

どんな機器類で使い古した電池なのかやフルカラーLEDにつなぐ抵抗などの条件にもよりますが、使い古しの電池でも十数時間程度は光るのではないかと思います。

www.youtube.com

これで、クリスマスのイルミネーションやら5歳の息子がよくやっている「部屋を暗くしていろいろなものを光らせる光の世界」遊びごっこで十分使えるのでこれ以上作り込みませんでしたが、アクセサリーっぽくするのも選択肢としてありかと。

ただ、その場合は、ATtiny-85での実装はサイズも大きくなるのでフルカラーLEDを適宜色を変えて光らせ続けたい、という今回のプログラム例とほぼ同じニーズであれば、ATtiny-85などは使わず、イルミネーションタイプのフルカラーLEDを利用する、という選択肢もあるかと思います。それだけであれば実装がとても簡単になります。

akizukidenshi.com

今回利用したHT7733AとHT7750Aはどちらも0.7V入力をそれぞれ3.3V or 5.0Vへ昇圧してくれます。モーターやらをがんがん回す用途でなければ、簡単な電子工作系は電池1本昇圧、でいけそうな気がしていて、最近はもっぱら3.3Vや5Vを作るときは単3電池をこのHT77XAシリーズを使うかXCL102をDIP化したDCDC昇圧コンバータで昇圧して、で間に合っています。

9V電源をレギュレータで5Vに降圧して使うこともありますが、特にこどもが触るものであれば、使い古しの電池を使って動かしている回路は、もしものショートのときなども考えると少し安心な気がしています。

そして何より使い古しの電池1本でATtiny-85が動くので、LEDを光らせる以外にもまだまだ活用することができるのかな、ということを実感できたのが一番の収穫でした*2

*1:改訂版ではない方

*2:今回もATtiny-85から結局LEDを光らせてますが、確認したかったのはATtiny-85の動作の方です。

ジュールシーフ × ATtiny-85 × フルカラーLED (1)

www.youtube.com

使い古し電池1本を使ってATtiny-85からフルカラーLEDを光らせる、です。

ATtiny-85は電源電圧2.7~5.5V必要ですので、普通に新品のアルカリ単3電池1.5Vのものをつないでも動きません。ましてや使い古した乾電池一本では通常はATtiny-85もフルカラーLEDも動かない/光らないのですが、電圧を昇圧させることで動かしています。

eneloopユーザではあるものの、充電池(二次電池)を使うのはもっぱら電力使用量が多く交換頻度の高いアイテムで、それ以外のリモコンやら時計など用途によっては充電池ではない方の一次電池も使っています。自治体によるのでしょうが、捨て方も面倒なのであまり定期的に捨てられず、気がつくと家には使い古した一次電池が溜まっていきます。

デジタルテスターを入手して使い古したアルカリ単3電池の電圧を測ったとき、1V切っていない数字が表示されて見間違いかと思いましたが、1V前後では動かなくなる機器が多いようです。この使い古しの電池をもう少し使えないの、ということと、よく使っていたXCL102をDIP化したDCDC昇圧コンバータを基板にはんだ付けする時に金額面から躊躇することが多い、という2つの理由で昇圧回路をいくつか試してました。

akizukidenshi.com

akizukidenshi.com

2021/12/15現在、3.3V、5V昇圧用どちらも300円。

よく参考にさせてもらっている武蔵野電波のプロトタイパーズ(ブレッドボーダーズも)のこの辺の回路も試してみましたが、トロイダルコアの巻線はやらずにマイクロインダクターに置き換えてます。巻線は巻ける気がしません。

あと、「ジュールシーフ」という単語についてもこちらの記事に説明があります。

pc.watch.impress.co.jp

TL499Aはデータシートに忠実に作ってみたもののうまく再現できず。ブレッドボードだと再現難しい、というウェブ記事もちらほらみるので、試してはみたものの。

https://www.ti.com/lit/ds/symlink/tl499a.pdf?ts=1639488959713

TL499Aは樫木総業で購入。

www.kashinoki.shop

NJM2360ADでもデータシートと最近改訂版が出たこの本での作例を参考にしてみましたが、出力電圧が安定しないときがあり。どこかおかしい部分があるのでしょうが、突き止めきれず。

gihyo.jp

akizukidenshi.com

どんな波形がでているのやら、そろそろオシロスコープが、というところで一旦中断。

結局、今のところ電圧も可変というよりは3.3Vやら5V固定で良いので、であれば使いやすくて安定してそうなのはHT77XAシリーズでの昇圧回路かな、というところで落ち着きました。一つ40〜50円で値段も安いし、使う部品もマイクロインダクタ(100μH)、ダイオード(データシートだと1N5817だが、手元にあった11EQS04で)、コンデンサ(電解コンデンサ22μF,47μF)と少なめ。

akizukidenshi.com

akizukidenshi.com

HT7750A or HT7733A 40-50円
マイクロインダクタ 100μH 10円
ダイオード 11EQS04 15円
電解コンデンサ 22μF,47μF 20円

上記部品代だけで85-95円で金額面では助かる感じに。ただ、秋月電子通商で入手しましたが、バラ買いしているわけではないので、上記の表通り100円以下で作れるかというと厳密ではないのですが。

部品が集まったら、データシートを参考に3.3V出力可能なHT7733Aの方で組んでみます。

https://akizukidenshi.com/download/ds/holtek/HT77XXA.pdf

f:id:haseharu:20211117174827j:plain

この順電圧3.1Vの青色LEDを光らせていて、デジタルテスターで3.3V測れているのも確認できます。

akizukidenshi.com

こうやって実際に光ると使い古しの電池もまだまだ使えるなあ、ということが実感できます。

他にもなにか使い古しの電池の再利用的なものを考えましたが、7セグLEDとかを光らせてみたりはもちろんできます。

f:id:haseharu:20211117204722j:plain

7セグ、DIPスイッチはこちら。

akizukidenshi.com

akizukidenshi.com

5Vにしたければ、HT7733Aを抜いてHT7750Aを挿せばOK。

とりあえずはここまでで次回、ATtiny-85の方を。

Arduino Uno Rev3からATtiny-85へ書き込む

f:id:haseharu:20211101070145j:plain

Arduino Uno R3を書込装置にしてATtiny-85へ書き込む際の自分用メモ(2度目の書き込み時にはまってしまったので)。

初期設定

Arduino IDEの「File」->「Preferences」を開き、「Settings」タブの「Additional Boards Manager URLs」へ以下を追加し「OK」をクリック。

http://drazzy.com/package_drazzy.com_index.json

「Tools」->「Board」->「Boards Manager」をクリックするとBoards Managerが開くので「attinycore」と入力し検索結果から「ATTinyCore by Spance Konde」を選択しインストール。

これで、「Tools」->「Board」->「ATTinyCore」を選べるようになる。ここまでは一度、Arduino IDEで設定しておけばOK。

書き込み

2回目以降の書き込みはここから。Arduino Uno R3、ブレッドボード(小さいやつで良い)、ジャンパワイヤー6本、電解コンデンサ10μF×1個を準備。

  • Arduino Uno R3を書き込み装置にする
  • 書き込み装置にしたArduino Uno R3からATtiny-85へ書き込む

の順となる。なお、後者はジャンパワイヤ等でのArduino Uno R3とATtiny-85の接続が必要となるが、前者の作業時に後者の接続を行わず順に行う。

Arduino Uno R3を書き込み装置にする

Arduino Unoに何かをつないでいるようであれば、抜く。後述するATtiny-85への書き込み装置の準備もこの段階ではせずにArduino IDEを起動したマシンとのみ接続する。

f:id:haseharu:20211101071940j:plain

「File」->「Examples」->「11.ArduinoISP」->「ArduinoISP」のスケッチを呼び出し、Arduino Uno R3へ書き込む。「Done uploading」となったらArduino Uno R3の書き込み装置化は終了。

書き込み装置にしたArduino Uno R3からATtiny-85へ書き込む

Arduino Uno R3をArduino IDEを起動したマシンから一旦外し、以下の通りATtiny-85と接続する。
GPIOなどはデータシートのPDF2ページ目を参照。ATtiny-85自体のピン番号とGPIOの番号は違うので注意が必要。

https://akizukidenshi.com/download/ds/atmel/attiny25_attiny45_attiny85.pdf

Arduino Uno ATtiny-85
D10 1
GND 4
D11 5
D12 6
D13 7
5V 8
Reset(+)とGNDを電解コンデンサ10μFで接続


f:id:haseharu:20211101073134j:plain

あとはArduino IDEを起動したマシンとArduino Uno R3を接続し、「Tools」->「Board」->「ATTinyCore」->「ATtiny25/45/85」を選択。「Chip」->「ATtiny85」、「Clock Source」->「16Mhz」、など。

一度、「Tools」->「Burn Bootloader」を書き込み、その後、ATtiny-85へ書き込みたいソースコードを「Verify」->「Upload」->「Done Uploading」で終了。

なお、ATtiny-85のピン6番がGPIO 1となる。

ATtiny-85 Pinout
1 5
2 3
3 4
4 GND
5 0
6 1
7 2
8 VCC

ピン6番(GPIO 1)をチカチカさせるLチカコードを書き込んでHelloworld。

void setup() {
  pinMode(1, OUTPUT);
}

void loop() {
  digitalWrite(1, HIGH);
  delay(500);
  digitalWrite(1, LOW);
  delay(500);
}

f:id:haseharu:20211101075317j:plain

ATtiny-85のTinyJoyPadをLEGOにおさめる

 f:id:haseharu:20211017100416j:plain 

 前回、Arduino Unoで試してみたTinyJoyPadをATtiny-85で作ったことの記録です。作例はたくさんあるので、実装例の一つと、LEGOでのケースの記録として。ケースといっても周りをえいえいと固めただけなので「おさめる」とはほど遠いですが。

 ATtiny-85、10月19日現在売り切れ。ずいぶん前に買っておいたものを使っています。クロック20MHz、メモリ8kB、電源電圧2.7-5.5V、GPIO 6ピンです。

akizukidenshi.com

 主要な部品はこちらで、全部秋月電子通商で購入したものです。前回使ったものをほぼ流用。タクトスイッチは色を揃えようと思っていたのですが、こどもにどの色にしたいか聞いたら、全部別の色を選んだので、この組み合わせです。

 写真に写っていない部品としては、抵抗、電池ボックス、コネクタ、です。抵抗は今回は公式HPの数値にあわせましたが、88kΩは手元になかったので、33kΩ+51kΩ=84kΩとしました。なので今回はプログラムを変にいじる必要はなしです。

 f:id:haseharu:20211012055815j:plain

 ボタン電池で実装例が多いですが、小さい子供も使えるようボタン電池をさけ、単3,4電池を想定しています。電池ボックス側にスイッチがあれば電源オンオフ可能になるので、その点でも便利です。

akizukidenshi.com

 逆に写真に写っていますが使っていない部品は3.3V出力昇圧DCDCコンバータです。写真のものは単3電池2個のケースでやや大きいですし、持った感触も電池が重いです。なので単4電池1本を3.3Vに昇圧して使う、がサイズ的にいいのだろうと手元にあったXCL102シリーズを使ったDCDCコンバータを使おうかと思っていたのですがちょっと高いので、今回の用途ではまずは不要かなと、ハンダ付けしませんでした。じゃあ、もうボタン電池でいいじゃん、という気がします。こどもも誤飲する年齢ではないのですが、まだボタン電池むき出しは避けたいな、という感じです。とりあえず昇圧せず単3,4電池2本コースで。
 ディスプレイもピンヘッダとかで抜き差しできるようにしようかと考えましたが、浮いた感じになるのと少しぐらぐらするのでもうこれははんだ付けしないと、とすぐに諦めました。

akizukidenshi.com

 f:id:haseharu:20211017100226j:plain

 特に何も考えずにこのユニバーサル基板で実装したのですが、ぴたっとLEGOのサイズにはまってびっくりしました。

akizukidenshi.com

 ハンダは各部品の足とすずめっきでがんばれるところまで頑張って、あとはポリウレタン銅線でまとめました。スペーサーで少し浮かせています。

 f:id:haseharu:20211017100251j:plain

 箱型にしようかと思っていましたが、あまりに基板がぴったりはまってしまったので、下と脇を固めただけでまとまりました。スペーサーが少し邪魔なので、少し工夫して、もう少しおさめる感じにして、電池も単4電池にすればもう少し携帯感が出てくると思いますが、家でカチカチやる分にはこれで十分です。
 あとは、ATtiny-85の抜き差し部分は丸ピンのソケットを使いましたが、ちょっと硬いなあ、という感じで、ATtiny-85の抜き差しは少し慎重にやる感じです。

 ATtiny-85への書き込みは、Arduino Unoを書込装置にしてATtiny-85へ書き込んでいます。

f:id:haseharu:20211017100331j:plain

 5歳のこどもの手だと、タクトスイッチでの十字キーは操作しづらいかな、という感じでした。そもそも十字キー的なあれを操作したことがあるから4つ上下左右に並べたタクトスイッチもあまり苦労せず動かせるのかもしれません。

Arduino UnoでTinyJoypad

f:id:haseharu:20211005222627j:plain

ATtiny-85で動かせるゲームを配布しているtinyjoypad.comというサイトがある。

www.tinyjoypad.com

ATtiny-85でやってもいいんだけど、とりあえず動きを試したくて、Arduino Unoで試してみた。

TinyJoypadで使っているSSD1306用ライブラリを落として、

github.com

いくつかあるゲームのソースのうち「Tiny Invaders」を落として、Arduino Unoに書き込んで、

www.tinyjoypad.com

ちょうど手元にあったSSD1306の有機EL 128✕64グラフィックディスプレイへつなげてみると映るようだったので、

akizukidenshi.com

タクトスイッチのボタンの方もつなげてみる。Arduino Unoでの接続時はこちらを参照。

https://doc-10-1k-docs.googleusercontent.com/docs/securesc/pojmq4ree4t67t7fnfp41lsnpef54ouq/gb2c2mhgc5pegei5modurqut6of5fcft/1633444050000/01770547387352383734/03720646434477843549/11rv1jlYhM76hwfIRVyPU7DIqp-NmjuP0?e=view&authuser=0&nonce=a0k3glmaemqe2&user=03720646434477843549&hash=5loi2bd2ij93u0afsv6audt822bjpslp

SCLとSDAの接続箇所に注意が必要。最初接続したときははまらなかったのに、2回目に接続したときは、何も考えずに普通にArduino Uno側のSCLとSDAに接続してしまって「何か急にディスプレイ映らなくなったぞ。なんだろう」と2-3時間はまってしまった。

f:id:haseharu:20211005222547j:plain

ATtiny-85での実装を想定しているので、ピン数が少なくても良いようにボタンを抵抗分圧で処理している。自分は抵抗値を適当に変えてしまったが、プログラム内で以下のように設定しているため、数字を変えてやれば良い。

#define TINYJOYPAD_LEFT  (analogRead(A0)>=750)&&(analogRead(A0)<950)
#define TINYJOYPAD_RIGHT (analogRead(A0)>500)&&(analogRead(A0)<750)
#define TINYJOYPAD_DOWN (analogRead(A3)>=750)&&(analogRead(A3)<950)
#define TINYJOYPAD_UP  (analogRead(A3)>500)&&(analogRead(A3)<750)

抵抗値から抵抗の分圧を計算してもよいが、ボタン押下時にanalogRead(A0)とanalogRead(A3)の値を取得して、シリアルモニターで確認してそれにあわせて値を変えてあげても良いと思う。

if (TINYJOYPAD_RIGHT) 
if (TINYJOYPAD_LEFT)

とかでif文で場合分けをしていた(自分はインベーダー的なものとテトリス的なものしかみていないが)。それぞれのif文でserial.printが簡単かもしれない。インベーター的なそれは右と左しかコントールしないため、上の2つしか場合分けがない。テトリス的なあれには下がある感じ(たしか)でたぶんゲームごとに必要ないボタンは最初からプログラムの方では制御していない感じ。

タクトスイッチはカチカチ感が良くて、持っていない色があるとつい買ってしまうパーツの一つかもしれない。ブレッドボードやArduinoやらラズパイのシールド用基盤、あとディスプレイもつい買ってしまうパーツの一つ。

今回使ったSSD1306のやつも小さくて安くて良さそう、と買っておいたもの(確か)。

LEGOとATOM LiteでDIYリモコンカー 6 (IOTなサーボモータ編)

 IOT的にサーボモータを動かします。IOT的なLチカで使った「SimpleWiFiServer」に以下の記事で作ったコードを埋め込んでいく感じです。

haseharu.hatenablog.com

#include <M5Atom.h>
#include <ESP32Servo.h>

Servo myservo1;
Servo myservo2;

void setup() {
  M5.begin(true, false, false);

  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  
  myservo1.setPeriodHertz(50);
  myservo1.attach(22, 500, 2500);

  myservo2.setPeriodHertz(50);
  myservo2.attach(33 500, 2500);
}

 ここまではまるっと入れていく感じだと思います。
 リモートカーの動作は「前進」「後進」「右向く」「左向く」「停止」の5つとし、クライアントからATOM Liteへ送信するデータは「F」「B」「R」「L」「S」とします。ここは何でもよいです。「client.print」でATOM Liteから出力するhtmlを書いていきます。

client.print("<html lang=\"ja\"><head><meta charset=\"UTF-8\"></head><body>");
client.print("<a href=\"/F\">↑ すすめ</a><br>");
client.print("<a href=\"/R\">→ みぎ</a><br>");
client.print("<a href=\"/L\">← ひだり</a><br>");
client.print("<a href=\"/B\">↓ うしろ</a><br>");
client.print("<a href=\"/S\">■ とまれ</a><br>");
client.print("</body></html>");

 クライアントへのデータ出力部分と受け取る部分はaタグのhref属性に書いていきます。エスケープシーケンスでダブルクォーテーション(")のところにバックスラッシュ(or ¥もある?)が入っています。
 loop関数部分は「myservo1.write()」「myservo2.write()」をそれぞれの動作にあわせて追記していきます。

if (currentLine.endsWith("GET /F")) {
 servo1.write(150); 
 servo2.write(40);
}
if (currentLine.endsWith("GET /B")) {
 servo1.write(40); 
 servo2.write(150);
}
if (currentLine.endsWith("GET /R")) {
 servo1.write(110); 
 servo2.write(110);
}
if (currentLine.endsWith("GET /L")) {
 servo1.write(70); 
 servo2.write(70);
}
if (currentLine.endsWith("GET /s")) {
 servo1.write(90); 
 servo2.write(90);
}

 サーボモータの出力値は調整が必要です。右回り、左周りもこの例だと逆転させていますが、他にもやり方があると思います。あと、モータの右左の付け方によっては、前進と後進、右向き、左向きが想定していた向きと逆になると思います。その場合GPIO部分を差し替えればコードの修正は不要だと思います(雑ですみません)。
 というところまでで以下のようなコードになると思います。

#include <M5Atom.h>
#include <ESP32Servo.h>
#include <WiFi.h>

Servo myservo1;
Servo myservo2;

const char* ssid     = "yourssid";
const char* password = "yourpasswd";

IPAddress ip(XXX,XXX,XX,XX);
IPAddress subnet(255,255,255,0);

WiFiServer server();

void setup()
{
    Serial.begin(115200);
    
    M5.begin(true, false, true);
    delay(50);
    M5.dis.drawpix(0, 0x0ff000);

    //servo motor
    ESP32PWM::allocateTimer(0);
    ESP32PWM::allocateTimer(1);
    ESP32PWM::allocateTimer(2);
    ESP32PWM::allocateTimer(3);

    myservo1.setPeriodHertz(50); // standard 50 hz servo
    myservo1.attach(22, 600, 2400);
    myservo2.setPeriodHertz(50); // standard 50 hz servo
    myservo2.attach(33, 600, 2400);
    delay(1000);

    // wifi
    WiFi.config(ip,ip,subnet);
    delay(10);

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();
}

int value = 0;

void loop(){
 WiFiClient client = server.available();

  if (client) {
    Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n') {

          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            client.print("<html lang=\"ja\"><head><meta charset=\"UTF-8\"></head><body>");
            client.print("<a href=\"/F\">↑ すすめ</a><br>");
            client.print("<a href=\"/R\">→ みぎ</a><br>");
            client.print("<a href=\"/L\">← ひだり</a><br>");
            client.print("<a href=\"/B\">↓ うしろ</a><br>");
            client.print("<a href=\"/S\">■ とまれ</a><br>");
            client.print("</body></html>");
            
            client.println();
            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }

        if (currentLine.endsWith("GET /F")) {
           myservo1.write(150); 
           myservo2.write(40);
        }
        if (currentLine.endsWith("GET /B")) {
          myservo1.write(40);
          myservo2.write(150);
        }
        if (currentLine.endsWith("GET /R")) {
          myservo1.write(110);
          myservo2.write(110);
        }
        if (currentLine.endsWith("GET /L")) {
          myservo1.write(70);
          myservo2.write(70);
        }
        if (currentLine.endsWith("GET /S")) {
          myservo1.write(90);
          myservo2.write(90);
        }
        
      }
    }
    client.stop();
    Serial.println("Client Disconnected.");
  }
}

 
 まっすぐ走らない、回るスピードが早すぎる遅すぎるなどは調整いただければある程度は解消されると思います。ATOM TailBATフル充電で10分くらい走りますので「電池が切れたらおしまい」という点でこどもと少し遊ぶにはよいおもちゃだと思います。

 もう少し作り込もうかと、Raspberry Pi Zeroにカメラモジュールを付けて、それをリモコンカーにのせて、ライブ映像を受信できるようやろうとやってみましたが、そのときはLEGOにガチガチに作り込んだラズパイ+カメラが重くて、リモコンカーの馬力が足りず動作が少し残念でした。

www.switch-science.com

akizukidenshi.com

 あと、ブレッドボードと乾電池利用での例を記録しておしまいにしようと思います。

 f:id:haseharu:20210804220735j:plain

 ATOM Liteは仕様上は5Vでの動作となります。

docs.m5stack.com

 5V出力昇圧DCDCコンバータを使います。注意としてはあくまでも昇圧なので、今回であれば5V以上の電源をつながない、でしょうか。9V電池を三端子レギュレータで5Vに降圧させて動作させる、などでも良いかなと思います。

akizukidenshi.com

 データシート上は入力は「0.9-5V」で出力が「5V」になります、とのことです。

akizukidenshi.com

 とりあえず単4電池を2本、

f:id:haseharu:20210804223622j:plain

 およそ3Vあるものをコンバータにつなげてみると、

f:id:haseharu:20210804223519j:plain

 「4.97V」です、いいですね。「3V」から「5V」へきちんと昇圧されています*1。仕事してくれてます。この5VをATOM Liteとサーボモータへつなげます。本当はモータとATOM Liteの電源を別にして上げたほうがいいんでしょうがとりあえず動くのができれば良しとします。想定していたよりもジャンパワイヤが結構必要でやはりぴょんぴょんしてつながりがわかりにくいですね。手軽でいいのですが、見づらくなるのが難点。

f:id:haseharu:20210804223056j:plain

 この部品とケーブル類を処理してあげれば完成です。単4電池2本を5V昇圧で何分位動作するかは試していないのでご注意ください。

 ということでここでおしまいとなります。

 この記事は7月中に終わらせる予定だったのが想定外に長引きました。というか1年に1本書くか書かないかのテンポで書いてきたブログだったので、これで6年分程度は先に書ききりました。

*1:テスターのリード線、逆についてます。電圧も影になっていて見にくいですがマイナスですね。後で見直して気が付いたので追記。 20211005

LEGOとATOM LiteでDIYリモコンカー 5 (IOTなLチカ編)

 IOTでLチカしてみます。コード例があるのでそちらを使います。
 Arduino IDEの「File」->「Example」->[Examples for ESP32 Pico Kit]内->「WiFi」->「SimpleWiFiServer」です。選ぶとコード例が出てきます。以下、コメントを削除したものを載せます。

#include <WiFi.h>

const char* ssid     = "yourssid";
const char* password = "yourpasswd";

WiFiServer server(80);

void setup()
{
    Serial.begin(115200);
    pinMode(5, OUTPUT);

    delay(10);

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();

}

int value = 0;

void loop(){
 WiFiClient client = server.available();

  if (client) {
    Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n') {

          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            client.print("Click <a href=\"/H\">here</a> to turn the LED on pin 5 on.<br>");
            client.print("Click <a href=\"/L\">here</a> to turn the LED on pin 5 off.<br>");

            client.println();

            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }

        if (currentLine.endsWith("GET /H")) {
          digitalWrite(5, HIGH);
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(5, LOW);
        }
      }
    }
    // close the connection:
    client.stop();
    Serial.println("Client Disconnected.");
  }
}

 「WiFi.h」をincludeしています。setup関数は少し長めですが、機能的な部分で役割を果たしているのは、以下の2行です。

WiFi.begin(ssid, password);
server.begin();

WiFi.begin」でWiFi接続し、「server.begin」でクライアントからの接続待ちとなります。

const char* ssid     = "yourssid";
const char* password = "yourpasswd";

 それぞれの環境のWiFiへの接続情報はここに入れておきます。

 loop関数ではクライアントからのアクセスを処理しています。あれこれ書いてありますが、なるべく構造部分を取り出すと以下のような感じです。

String currentLine = "";  
char c = client.read();
Serial.write(c);
if (c == '\n') {
 if (currentLine.length() == 0) {
  client.println("HTTP/1.1 200 OK");
  client.println("Content-type:text/html");
 }
 if (currentLine.endsWith("GET /H")) {
  digitalWrite(5, HIGH);
 }
 if (currentLine.endsWith("GET /L")) {
  digitalWrite(5, LOW);
 }
}

client.stop();

 client.readでクライアントからのデータ取得します。そのデータを元に場合分けしてclient.printlnでクライアントへ応答を返しています。抜き出した部分には入れていませんが、コード例だと、

client.print("Click <a href=\"/H\">here</a> to turn the LED on pin 5 on.<br>");
client.print("Click <a href=\"/L\">here</a> to turn the LED on pin 5 off.<br>");

 がhttpで返ってきてクライアントの手元のブラウザ的なものに表示されます。「the LED on pin 5 on」の方をブラウザ的なものでクリックすると、ATOM Liteへ「H」がデータとして送付されます。

if (currentLine.endsWith("GET /H")) {
 digitalWrite(5, HIGH);
}

 「H」がATOM Liteへ送付されると「digitalWrite(5, HIGH);」となりLチカとなります。

 無事にWiFiにアクセスできた場合、「Serial.println(WiFi.localIP());」でシリアルモニターにIPアドレスが表示させます。そのIPアドレスへ同じWiFi環境からブラウザ的なものでIPアドレス直打ちでアクセスをするとブラウザ的なものからIOTなLチカできる感じです。

 コード例はGPIO5をオンにする、というものなので、LED抵抗とブレッドボード、ジャンパワイヤなどで試せる場合はそのまま使う、でも良いと思います。

 今回はATOM Liteの本体LEDで手動チカチカしてみたいと思います。以前の回で示したコードを埋め込んでいく感じです。

haseharu.hatenablog.com

 さきほどのコード例のコメントを削除して、ATOM Liteの本体LEDを手動チカチカ部分を追記したコードがこちらです。

#include <M5Atom.h> //added
#include <WiFi.h>

const char* ssid     = "yourssid";
const char* password = "yourpasswd";

WiFiServer server(80);

void setup()
{
  M5.begin(false, false, true); //added
  
  Serial.begin(115200);
    //pinMode(5, OUTPUT);
    delay(10);

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected.");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    
    server.begin();

}

int value = 0;

void loop(){
 WiFiClient client = server.available();

  if (client) {
    Serial.println("New Client.");
    String currentLine = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        if (c == '\n') {

          if (currentLine.length() == 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            //client.print("Click <a href=\"/H\">here</a> to turn the LED on pin 5 on.<br>");
            //client.print("Click <a href=\"/L\">here</a> to turn the LED on pin 5 off.<br>");

            client.print("Click <a href=\"/H\">here</a> to turn the LED on.<br>"); //added
            client.print("Click <a href=\"/L\">here</a> to turn the LED off.<br>"); //added
            
            client.println();

            break;
          } else {
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
        }

        if (currentLine.endsWith("GET /H")) {
          //digitalWrite(5, HIGH);
          M5.dis.drawpix(0, 0xff0000); // Green
          delay(1000);
        
        }
        if (currentLine.endsWith("GET /L")) {
          //digitalWrite(5, LOW);
          M5.dis.drawpix(0, 0x000000); //Off
          delay(1000);
        }
      }
    }

    client.stop();
    Serial.println("Client Disconnected.");
  }
}

 うまくいくとこんな感じです。シリアルモニターでATOM Liteに割り振られたIPアドレスを確認してからブラウザ的なものに打ち込んでください。

youtu.be

 ここまでで、ほぼ完成だと思うのですが、IPアドレスをシリアルモニターで確認する、ままだとケーブルをつなぎっぱなしになります。IPアドレスを固定して取得させれば、シリアルモニターでIPアドレスを確認する必要なくなるため、外部電源をつないで固定IPアドレスをブラウザ的なものに直うちすれば動作可能です。固定IPアドレスにさせるには以下の設定を追加します。

IPAddress ip(192,168,xx,xx); // your IPaddress
IPAddress subnet(255,255,255,xxx); // your subnet

 をincludeの下あたりで設定します。あとはsetup関数に、

WiFi.config(ip,ip,subnet);

 を追記します。追記場所は「WiFi.begin()」よりも先にする必要があります。第2引数はgatewayを設定する箇所なので、もし設定が必要であれば「IPAddress gateway(X,X,X,X)」を追記してカスタマイズする必要があります。さきほどの固定しないバージョンで動作させたときに割り振られたIPアドレスとして固定して上げれば良いと思います。

 ここまででほぼ要素は揃ったと思います。このあと続けると長いので、一旦区切って次回でおしまいにしようかと思います。

 なお、今回、コード例を使いましたが、他にもたくさんあるので活用できると思います。また、今回のブログではコード、と書いていますが、Arduinoの世界では「スケッチ」と表現します。
 
 それからいまさらの補足ですが、ハンダ付とブレッドボードと分けて書いてきましたが、実際のところはブレッドボードでプロトタイプ的に作って、最終的に目指している動きをすることを確認してから、基板などにハンダ付をして作り込んでいく、という流れが一般的でやりやすい流れかと思います。ブレッドボードやジャンパワイヤはいくつあっても困らないです。ブレッドボードは今回使っている小さいもの以外にも、横につながっているラインがある中くらいのもの、

akizukidenshi.com

 さらに長めのもの、

akizukidenshi.com

 あとESP32 DevKitで、

akizukidenshi.com

 WiFiとかIOT的なプロトタイプ作成をバンバン試したいぞ、という人は穴が多い6穴版の、

akizukidenshi.com

 あたりが良いです。というかブレッドボードは個人的につい欲しくなる部品の一つで、上記のものを複数持っていて上記以外はあまり使ったことがないので比較していません。比較できるのは値段くらいで他と比べると安めの価格帯の商品だと思います。