作品タイトル:GR-KURUMIを利用して剣(つるぎ)POVを作ろう!
表示名:飯島 幸太
コンセプト・作品説明 |
---|
GR-KURUMIを使い外装がつるぎ型フルカラーPersistent Of Vision(”剣(つるぎ)POV”と命名)を作成します。 |
冒険について(概要)
POVとは残像で空間に絵や文字を書くものです。剣を振りかざすと絵や文字が空中に見えるようなガジェットです。
今回は、ガジェットの紹介だけではなく作れること(作る)をテーマにしてみました。だれでも簡単に作れるよう厚紙(段ボール)を利用して外装も作成しました。音や特別な演出を入れていませんが、工夫すればオリジナルの面白い剣にすることができます。さあ!あなたもオリジナルの武器を手に入れて(自作して)旅立ちましょう!
冒険の前に装備を整えよう(電子部品の準備)
◆全体の構成
剣POVは、表面にフルカラーテープLEDを20個搭載し、ここが光ります。それを制御するマイコンがGR-KURUMIです。LEDの光りかたを操作するためにA/B2つのボタンを裏面に配置します。動力の電池は小型のリチウムイオンポリマー電池を使います。
◆部品リスト
BOM.xlsx [ダウンロード]
主要な登場人物(主要部品)
◆GR-KURUMI
GR-KURUMIを利用しました。GR-COTTON(執筆時は発売予定)も、同じことができると思います。Webコンパイラで生成されたバイナリをダウンロードして、FTDIなどのUSBシリアル変換モジュールを経由してプログラムを書き込みします。
◆テープLED
利用しているLEDの型番がWS2812Bを利用しているフルカラーシリアルLEDテープを使います。
コンパクトに絵や文字を描画したいのでLEDの配置間隔が狭いものが良いです。 こちらを切って20個利用します。テープ1本買い(144個/m)すると少しお高いので、複数台製作するか、お知り合いとシェアしていただくことで価格を抑えて作ることができます。持っている方に少し分けてもらっても良いでしょう。※私に言っていただければ多少お分けすることができるかもしれません。(笑)
◆タクトスイッチ
表示開始トリガー用Aボタンと、表示内容変更用Bボタンで2つ準備します。少し大きい方が操作し易いと思います。お好みで手持ちのタクトスイッチなどで代用が可能です。
◆リチウムイオンポリマー電池&充電器
3.7V出力の充電式の電池になります。小型なのでちょっとした携帯タイプのガジェットを作成するには便利なアイテムです。今回利用するGR-KURUMIは、利用できる電圧範囲が広いので、この電池と相性が良いです。電源電圧を昇圧・降圧することなく、そのまま利用することができます。接続するためのPHコネクタが必要になります。もし、初めてお使いになる場合は、別途充電器が必要になります。
余談ですが、この電池の代わりに、アルカリ電池3本(4.5V)を利用することも可能です。実験していませんが、エネルー○などの充電池3本でも大丈夫だと思います。本体の重量が多少増加しまいますが、長時間遊ぶことができます。
ダンジョン(回路図)
もし改造(部品追加)して3.3V駆動の部品を利用する場合には注意してください。リチウムイオンポリマー電池の電圧がそのまま出力端子から出ます。※今回利用するLEDは範囲内に収まるので利用が可能です。プログラムは、GPIOの機能のみで作られているのでどのポートを利用しても大丈夫です。
回路図:schematic.pdf [ダウンロード]
攻略本を熟読(ハードウェア制作)
◆完成の全体像
製作するハードウェアを下記に示します。ユニバーサル基板を利用してマザーボードを製作し、剣型の筐体にテープLEDとそれを取り付けるようにします。
◆テープLEDを切る
私が利用したのは144個/mのタイプです。20個分(約140mm)を切って使います。配線できるだけのパッドを残して切断するのがコツです。このパッドが小さいとはんだ付けに苦労します。
◆リード線を付ける
テープLEDに3線(GND、信号線、VCC)をはんだ付けします。テープLED側のパッドと、線材側の両方に予備はんだを行っておくと作業し易いです。今回利用したものは、上からGND、信号線、VCCでしたが、WS2812Bを利用したテープLEDは、似たようなテープLEDが多数出ていますので、どの順序か必ず確認してください。また、矢印(→)の方向にも注意します。
マザーボードへの配線は、筐体に固定してから行ってください。
◆マザーボードを作る
GR-KURUMIが搭載されるマザーボードをユニバーサル基板で製作します。今回はLEDと電源以外は、全てユニバーサル基板に収まるようにレイアウトしました。ボタンは押しやすい位置が良いので、縦長で作ります。ここは回路図と合っていればどんな形でも構いません。作ったこの形はユニバーサル基板のサイズが(25x72mm)です。
◆チェックする
電源のショートが無いかテスターでチェックします。GR-KURUMIのRAWとGNDがショートしてないことを確認します。また、電源(電池)の極性が本当に間違いないか、確認しましょう。GR-KURUMIを接続しない状態で、電池を接続し、RAWとGND間の極性と電圧を確認します。約4.2V~3.7Vの電圧が見えていれば大丈夫です。
鍛冶屋に持ち込む(筐体の制作)
◆筐体を作る
A4用紙にデザインした紙をご用意しました。
剣筐体図案:剣図案.pdf[ダウンロード]
これを図案として厚紙をカット利用しても良いですし、オリジナルデザインで作られても面白いと思います。LED部分が約140mmありますので、それ以上の長さが良いでしょう。剣となる部分は、使い方にもよりますが、もし小さいお子様などハードな使い方をされる場合は、複数を貼り合わせるなどの補強が必要かもしれません。段ボール・厚紙ご自由にデザインしてください。
私は、100均でカラーダンボールを購入して切り抜きました。剣となるベースを2枚と持ち手の部分2枚の計4枚を作って張り合わせ(強度確保)ました。
◆筐体に取り付け
作った筐体に取り付けます。まずテープLEDを両面テープで取り付けます。
購入時に両面テープが付いている場合が多いですが、無い場合は100円ショップなどで購入が可能です。
10mm幅の両面テープが使いやすいと思います。マザーボードの固定化はテープでグルグル巻きにしてしまうとか、いくつか方法は考えられるのですが、私はマザーボードに穴を加工して、プラネジで固定するようにしました。最後にLEDの配線も位置を確認した上で、遊びを持たせてマザーボードに結線(はんだ付け)します。
冒険の書(ソフトウェア)
◆ソースコード
kurumi_pov-2016.03.12.zip[ダウンロード]
全てのコードはダウンロードが可能です。自由に変更・利用することが可能です。メンテナンスしやすいようにファイルが複数に分割されています。
◆メイン処理(loop)
/** * ボタンの押下を常時検出し、ボタンが押下されたら対応する処理を実施します。 * ・Aボタン → 表示する画像の切り替え * ・Bボタン → LEDに画像データを出力する。(残像出力開始) * * @param なし * * @retval なし * * @attention チャタリングで誤判定を抑制するために全8BITがON(OFF)になるのを検出します。 ***************************************************************************/ void loop() { // キー押下検出処理 key_scan(); // Aボタンの押下検出 if(pushed_flag_sw_a){ pushed_flag_sw_a = false; // モードの切り替え view_mode++; if(view_mode > IMAGE_COUNT - 1){ view_mode = 0; } pushed_counter = 0; // 10msだけ青LEDを点灯 common_set_Kurumi_led(eBLUE); delay(10); common_set_Kurumi_led(eBLACK); } // Bボタンの押下検出 if(pushed_flag_sw_b){ pushed_flag_sw_b = false; // 50msだけ緑LEDを点灯 common_set_Kurumi_led(eGREEN); delay(50); common_set_Kurumi_led(eBLACK); // 画像の表示 draw(view_mode, pushed_counter); pushed_counter++; } delay(5); }
メインループにて、5ms周期でキースキャン処理を実施します。AもしくはBのボタンが押下されたと判断するとそれらに応じた処理を実施します。BならばLEDに画像のデータを送出します。画像データの送出はBボタンを押下する都度方向を反転して送出することで、繰り返し左右に振った場合、人の目には反転させずにみせることができます。
◆LED処理
このLEDひとつは接続する端子が4つ(VCC/GND/IN/OUT)しかありません。INの端子にRGBの24ビット分のシリアルデータを入力するとLEDの1つがその色で点灯します。48ビット入力すると2つが点灯します。1列分の20個LEDを点灯させるためには、24bit×20個=480ビット分のシリアルデータをマイコン側から出力する必要があります。1ビット分の送信時間が1.25usなので、480×1.25us=600us+処理時間で20個分の色指定を行い表示させることができます。タイミングはデータシートに記述されていますが、図のようなタイミングです。この0/1の波形を24bit分送ります。
利用するテープLED(WS2812系)は制御するタイミングが速いのでNOPでタイミングを作りデータシート(https://www.adafruit.com/datasheets/WS2812B.pdf)に記載されたタイミングでデータを送信します。私はオシロスコープで波形を観測しながらNOPの個数を調整しました。
1列分のデータ(480ビット分)を出力したら、一定時間後(1ms後)に次列データを出力します。
データを出力中に、別な処理が入ると残像が綺麗に見えないので割り込みは禁止します。全データ(1枚分)を出力したら、割り込み禁止を解除します。
/** * 指定されたデータを1列単位で連続して送信します。 * * @param[in] img 画像データ * @param[in] width 画像データの横幅 * @param[in] rvs 0:順方向 1:逆方向(反転) * @param[in] wait 1列点灯時間(ms) * * @retval なし * * @attention 横幅はmax255としています。 * @attention 点灯時間は、振りの速さに影響されます。残像が間延びする場合は値を小さくしてください。 * @attention 割り込みが入ると綺麗に見えないので割り込み禁止で動作します。 ***************************************************************************/ void ledctrl_draw_image(const RGB img[][TAPELED_NUM], uint8_t width, int rvs, int wait) { DI(); if(rvs) { // 逆方向でのデータ送出 for(int y = width - 1 ; y >= 0 ; y--) { for(int x = 0 ; x < TAPELED_NUM ; x++) { ledctrl_set_rgb(img[y][x].r, img[y][x].g, img[y][x].b); } common_wait_ms(wait); // wait ms } } else { // 順方向でのデータ送出 for(int y = 0 ; y < width ; y++) { for(int x = 0 ; x < TAPELED_NUM ; x++) { ledctrl_set_rgb(img[y][x].r, img[y][x].g, img[y][x].b); } common_wait_ms(wait); // wait ms } } EI(); ledctrl_set_black(); }
ledctrl_set_rgb関数を呼び出すと24bit分のデータを出力します。TAPELED_NUMは今回20としているので、このループで480bit分データを出力します。
◆キースキャン処理(key_scan)
/** * key(プッシュボタン)をスキャンして押下判定を行います。 * * @param なし * * @retval なし * * @attention チャタリングで誤判定を抑制するために全8BITがON(OFF)になるのを検出します。 * @attention チャタリングの度合に応じて間隔を空けて呼び出してください。(5~20ms周期) ***************************************************************************/ static void key_scan(void) { //////////////////////////////////////////////////////////////////////////// // key scan A //////////////////////////////////////////////////////////////////////////// status_sw_a <<= 1; status_sw_a |= digitalRead(SW_A); if(!pushed_mask_sw_a) { // all on -> pushed if(status_sw_a == 0){ pushed_flag_sw_a = true; pushed_mask_sw_a = true; } } else { // all off if(status_sw_a == 0xFF){ pushed_mask_sw_a = false; } } //////////////////////////////////////////////////////////////////////////// // key scan B //////////////////////////////////////////////////////////////////////////// status_sw_b <<= 1; status_sw_b |= digitalRead(SW_B); if(!pushed_mask_sw_b) { // all on -> pushed if(status_sw_b == 0){ pushed_flag_sw_b = true; pushed_mask_sw_b = true; } } else { // all off if(status_sw_b == 0xFF){ pushed_mask_sw_b = false; } } }
ボタンの押下を判定するために、一発判定によるHI/LOW検出ではなく複数回(8回)一致による押下判定をソフトウェアで行っています。これはボタン(接点式のもの)特有の接点がバウンドした際に誤判定してしまうのを抑制する効果があります。ビットシフトを利用して8bit全てがON(0x00)/OFF(0xff)であるかをチェックし判定しています。約5ms周期でポートをチェックしているので、最短でも35msの間はボタンを押下していないと判定されません。(ノイズとみなされる)
キャラクター(表示データ)
私がサンプルで書いたものやフリーの素材の残像データ4種類入れておきました。LEDの数が20個なので高さは20ドット固定です。画像テーブルには、RGBの値がそのまま定義されています。もし画像を差し替える場合には、このテーブルを書き替えます。手打ちで作成するのは大変なの、テーブル値を作れるWindowsのアプリケーションをC#で作成しました。任意の画像データを読み込ませることで、画像テーブルに張り付けて利用することができます。Windowsアプリも公開させていただきますのでご興味のある方はご利用くださいませ。 afterimgCreater.zip[ダウンロード]
このアプリには少しだけ便利な機能として、画像全体の明るさを変更できる機能が搭載されています。利用するフルカラーシリアルLEDは、最高出力の0xFF, 0xFF, 0xFFの白を出力した場合に、約50mA/個消費します。つまり、今回の場合20個全てを全力で真っ白とした場合は1Aも消費することになります。個人的な見解ですが、1/4程度の0x3F, 0x3F, 0x3Fでも白として十分明るい色だと思いますので、明るさはいろいろ試してみてください。
◆プログラムを書き込む
公開されているバイナリを書き込みます。
書き込みの手順は
http://japan.renesasrulz.com/gr_user_forum_japanese/b/weblog2/archive/2015/06/10/kurumi.aspx
を参考にしてください。
では冒険に旅立ちましょう(動作確認)
電池を接続し電源を入れてみます。Aボタンを押すとLEDが一瞬光ります。では、もう一度押して右へ振ってみます。もう一度押して左へ振る。右、左、右、左・・・・ どうでしょうか? 残像で何かみえますか?
Bボタンで次画像に切り替わります。いろんな画像データを作って、試してみてください。
まとめ
本職は現役のソフトウェアエンジニア。
医療システム開発や音響系組込みシステム開発に従事。
ハードウェアや工業デザインは趣味という。技術雑誌への寄稿など教育分野へも積極的に行う。
リアルなつながりを求めMaker Faireやスタートアップイベントなどにも多数参加している。
クラウドファンディングで集めた資金で「きらきライト・コア」(https://www.facebook.com/kirakilight/)を製造中。
(2016/3現在)
https://www.facebook.com/iijima.kota
http://blogs.yahoo.co.jp/carcon999
https://twitter.com/carcon999