去年、浅草橋でこーゆーものを買って来ました。
Arduinoでも入ってそうだけど、ただの電池ボックス pic.twitter.com/hxy0HLNmRI
— おごちゃん / 垢未凍結 (@ogochan) 2016年10月10日
before
いかにもMAKERっぽい感じなんですが、そういった詳細はよくわかりませんが、結構なお値段でした。値段が値段なので、ライトが点滅したりするのかと思ったのですがそうでもなかったので、ちょっといじってクリスマスっぽいライトにしてみました。
まず、この右の方にある箱ですが、これは単なる電池ボックスでした。単三電池が2本入ってました。雪の結晶型になっているものの中に豆球が入っていて、これが
点灯
するようになっています。「点滅」ではありません。点灯するだけです。何も面白みがないどころか、目立つことさえありません。値段の割につまらないものを買ってしまいました。
方針
要求仕様
何はさて置き、まずは「点滅」するようにしたいと思います。でも、「電球色」ではあまりに目立たないので、もうちょっと色を何とかしたい。となると、電球じゃなくて、それなりの色のLEDにしたいものです。
LEDと言えば、秋月に
なんてものが売っていて、興味を持って買って来ていたのを思い出しました。これを使うことを考えます。ストックは数個だったのですが、いくらでも買って来れば良いだけのことです。
せっかくなので、単に点滅するだけじゃなくて、色が変わった方が嬉しいなとか、その変化もいろいろ変えられたら嬉しいなと思ったので、制御するマイコンにもそれなりにいろいろ出来るものが嬉しいなということで、いつも通りのESP8266を使うことにしました。元々はATTiny10とかであれこれやろうと思っていたのですが、いくら何でもこれだと本当に点滅するだけになりそうなんで。
ESP8266だとネットにつながるわけなので、色の変化とかネットで設定出来れば便利ですね。また、お天気とか時間に連動して色の変化が変わったりすると楽しいと思いませんか?
設計
動く回路が出来るのは当然のことであり、それが動くソフトウェアが作れるのは当然のことなので、それ以外の部分についての設計をします。つまり、ソフトウェアの設計ということです。
まず考えたことは、
- プログラムは運用時に交換可能であること
プログラムを交換するのに、デバッグツールの類をつないだりを必要としない - LEDの数や色の変化パターンは、出来る限り自由に設定出来ること
つまり、プログラムを固定してパラメータを変えるだけではなく、好きなようにプログラム出来ること - ネットにつながるのだから、常識のセキュリティがあること
まぁ言うまでもないことです
これを手軽に実現するために考えたのは、
LED点灯制御仮想CPUを実装し、外からコードを与える
ことです。こうすると、マイコン側から見た「プログラム」は単なるデータになりますから運用時の交換は簡単ですし、「プログラム」は自由に書けます。また、仮想CPUをsecureに設計しておけば、随時プログラム書き換え可能なものとは言え、変ないたずらも難しいでしょう。マイコンには一度実行系を入れてしまえば、あとはその辺をいじる必要はありません。
実装
基盤
個人的にはあまり好きではないのですが、Arduinoを使うことにしました。と言うのも、件のLEDをコントロールするためのライブラリがArduinoにあるためです。Nativeライブラリでも頑張って書けばいいんですが、高々1ヶ月しか動かさないおもちゃに、そこまでエネルギーをかける暇はありません。
Arduinoがなんで嫌いあまり好きではないかと言えばIDEを要求するからなのですが、platform IOを使えば、全てコマンドラインで作業出来ます。Makefileもあればもっといいんですが、まぁそれは我慢します。
ライブラリ
LEDをコントロールするライブラリは、「Adafruit NeoPixel Library」というのを使います。
それ以外のライブラリについては、弊社で作った適当なライブラリを使います。元は某デバイスのためで、MarvellのSDKを使っていたものなので、互換レイヤーを適当にでっち上げてます。
回路
今回は「ちょっとしたお遊び」として作ったので、回路図とか描かずにいきなり作りました。
こんな感じにまとめてます。USBを電源にして、適当なレギュレータで3.3Vを作ってます。LEDにはUSBの5Vを直接つないでいます。LEDのコントロール線は、特にバッファ的回路を入れないで、いきなりESP8266につないでいます。プログラムの書込みは、ブレークアウト基板をつないでいるピン端子に必要な時にUARTをつなぐということにして、この基板上には載せていません。
こういったものが別途用意してあります。足っぽく見えてるのが、ピンソケットです。ESP8266を使う人は用意しておくといいです。
実装方針
とりあえず、仮想CPUを実装して行きます。
お遊びでやるものなので、「どんなCPU」という明確な方針はありません。また、プラットフォームもそれ程強力なものではないので、使わない命令や利用頻度の低い命令を作ることは避けます。
仮想CPUを作る時は、どうも「綺麗なコード体系」みたいなことを考えがちなのですが、それよりはむしろ
ご都合主義だけど使いでのある命令
を実装することを考えるべきです。
LEDドライバを組み込んだら、それを適宜操作出来る命令を定義し、その命令をハンドアセンブルで作りつつ、その仮定で必要になった命令をさらに定義して... ということにします。こうすれば、「アーキテクト」として頭を働かせる必要もあまりなく、無駄に実装工数が増えることもなく作ることが出来ます。
とりあえず作ってみた命令は以下のようになります
#define CODE_SET_SP 1 #define CODE_PUSH_I 2 #define CODE_STORE 3 #define CODE_LOAD 4 #define CODE_DUP 5 #define CODE_DEC 10 #define CODE_INC 11 #define CODE_CLEAR 21 #define CODE_LED_SET 22 #define CODE_LED_FLUSH 23 #define CODE_WAIT 24 #define CODE_MARK 31 #define CODE_LOOP_LT 32 #define CODE_HALT 100 #define CODE_EXIT 101
たった15個ですが、これでも多いかなと思います。
LED_FLUSHとかLED_SETとか、いかにもご都合主義っぽい命令もあります。WAITは1ms待つという命令です。
これで書いたテストコードが、こんな感じです。
static uint8_t Code[] = { CODE_SET_SP, 1, CODE_CLEAR, CODE_PUSH_I, 3, 0xE8, // 1000 CODE_WAIT, CODE_PUSH_I, 0,0, // i = 0 CODE_STORE, MEM_I, CODE_MARK, CODE_PUSH_I, 0,0, // j = 0 CODE_STORE, MEM_J, CODE_MARK, CODE_LOAD, MEM_I, CODE_PUSH_I, 0,0, CODE_LOAD, MEM_J, CODE_PUSH_I, 0,0, CODE_LED_SET, CODE_LED_FLUSH, CODE_PUSH_I, 0,2, CODE_WAIT, CODE_LOAD, MEM_J, CODE_INC, CODE_DUP, CODE_STORE, MEM_J, CODE_PUSH_I, 0,250, CODE_LOOP_LT, CODE_LOAD, MEM_I, CODE_INC, CODE_DUP, CODE_STORE, MEM_I, CODE_PUSH_I, 0,NUMPIXELS, CODE_LOOP_LT, CODE_EXIT };
このコードを実行すると、
こんな感じに点灯します。
なかなかいい感じじゃないかと思います。少なくとも、元のアレな感じから比べると、ずっといい。
と言いますか、あまりにいい感じ過ぎて、「これでいいじゃないか?」という気持ちになってしまって、開発はここで終了となってしまいました。いや、よく考えたら、温度やら何やらでパターンが変化しても、
で?
という感じでしかないですし。つまりまぁ、
ということですね。自分が「顧客」で良かったですw