2017年5月25日木曜日

アート作品にイルミネーションを追加



以前製作した 「クリスマスリース」 を、あるアートサークル会員の方に観て頂く機会がありました。
このほど、その方から図面を貰い、「この作品にイルミネーションを組み込むことは出来ませんか?」という依頼を受けました。

作品の展示は、もっと先かなと思っていたら、5月に個展を開く(!)との旨を聞いて、急きょ製作に取りかかることになりました。

以下は、コントローラ部の完成写真です。


LED点灯操作という面では、特別な要素は何もありませんが、アート作品への組み込み・「EAGLE」を使った短納期設計などのノウハウを、得ることができました。

以下はその顛末記です・・・


1、概 要

今回のアート作品は、80cm四方のキャンバスを12×12に区切った碁番目、都合144セグメントのうち、ちょうど半分72セグメントに、指定色のLEDを埋め込む旨依頼されたものです。

依頼図面の一部は、以下のような構成です。

※依頼図面の一部を抜粋 (C)Toshiaki Nagai


碁番目であることから、マトリクスLEDの要領で配線することはすぐに思いつき、操作は、恒例によりAVRマイコンを使用することにします。

問題は製作期間で、個展に間に合わせるために、短期間(約一ヶ月)で完成させなければなりません。最もクリチカルな基板製作について、何らかの解決策を検討します。


2、回 路

コントローラ側は、以下の回路です。
基板作成に、後述の通り「EAGLE」を使用しましたので、 回路図も、同ソフトウエアで作画しています。



ごく一般的なマトリクスLED駆動回路で、特に変わった点はありません。

例によって、AVRマイコン(ATmega168)を使い、リセット以外の22本を全てLED駆動用に回しました。うち10本(PNPトランジスタ接続)がアノード群用、12本(NPNトランジスタ接続)がカソード群用です。

「抵抗内蔵トランジスタ」を使うと簡略になりますが、最近入手が難しくなっており、また、LEDをダイナミック駆動するには定格の余裕がありません。
また、MOSFETを使えば、ベース(ゲート)抵抗が省略できるので採用できそうですが、対ソース間に保護抵抗が必要なので、あまりメリットはありません。
結局、一般のトランジスタで、定格に余裕のある品 (Ic = 1A) を使うことにします※。

※ 回路図上では、A1015/C1815 になっていますが、上記事由で、B562/D468 を使用しました(秋月電子で、一個\10)。

各トランジスタのベース・エミッタ間にも抵抗を配置するのが本来ですが、これ以上部品点数を増やすことは避けたいのと、LED駆動程度の速度・電流では問題は顕在化しませんので、今回は省略しました。

CN1・CN2は、AVRマイコンへのプログラム書き込み (ISP) 用端子で、CN3は、外部電源供給用です。
CN4がLEDのアノード側、CN5がカソード側です。

作品側(LEDマトリクス)は、以下の回路です。


前述の通り、Y方向(アノード側)を10本に制限したために、一部LEDは、隣りのアノード線から貰っています。

LEDは、作品が大きいので、迷わず超高輝度 5Φ品を使いました。
丸囲みで示したLEDは、作品のセグメントに合わせて、もっと大型の品を使う予定でしたが、他と同じ品種です。
また、作者が、横方向への光漏れを心配されたので、狭指向性のものを全色購入し、作者に見て頂き、配置場所を指定して頂きました。


3、基 板

出力22系統をユニバーサル基板に手組みする時間的余裕(気力?)はとても無く、さらに今回はオンリーワンの製作であるため、今までと同じように予算を組んで基板を発注することはできません。

そこで今回は、送料込み2,469円(!)で発注できる 「スイッチサイエンスPCB」 を利用することにしました。
同サービスは格安(寸法・枚数にもよる)ですが、使用するソフトウエアが事実上「EAGLE」指定であり、当ソフトウエアの使用方法を会得しなければなりません。

幸い、「EAGLE」に関するノウハウを提供している 「趣味の電子工作にようこそ」さまのサイト をが非常に参考になり、短期間で効率的に基板を設計することができました。

ライブラリは、全て、予め用意されているものを、以下の通り使いました(今回は、こだわらない)。

部品名ライブラリ備考
AVRマイコンatmelMEGA8-P


トランジスタ

transistor-small-signal
BC639
「品」型ランド
BC640
抵抗rclR-US_R_US_0207/10

コンデンサ

rcl
C-EUC-EU050-024X044
CPOL-EUCPOL-EUE2.5-6

コネクタ

con-lstb
MA03-1

MA05-2

MA06-2

VCCsupply1+5V

GNDsupply2GND

holesMOUNT-HOLE3.2


上記ライブラリを使って回路図(前項参照)を作成すると、基板パターンを自動生成 してくれます(「EAGLE」の目玉機能の一つ)

※ 部品配置は、手動で行なわねばなりません。
※ 生成結果に対して、若干のパターン修正(引き回し・電源パターンを太く、等)を行う必要が、ありました。


出来上がったパターンは、DRC(デザインルールチェック)が必要とされています。これは、スイッチサイエンスのサイトにある同チェック用ファイルを入手して、同サイトに記載の手順通りにチェックを行えばOKです。
以下が、DRCまで通したパターンです。



次に、ガーバーデータ生成(「EAGLE」では、CAMと呼んでいる) ですが、これも、同様にファイルを入手して、サイトに記載の手順通りに実行すればOKです。

基板が届くまでには約3週間かかりましたが、都度スイッチサイエンスから報告があり、不安を感じることは、ありませんでした(この間に、プログラムと作品側製作を済ませる)。


※ 初期設定では、部品名(MEGA8 や 1k 等)は、シルクに反映されませんでした。


4、プログラム

プログラム作成の時間が不足してしまい、今回は単にランダムに点滅させるだけの簡単なものになりました。

※ 今回は、ヒューズビット操作は行わず、デフォルト設定のままとしました(F_CPU = 1MHz)。

4.1 LEDアノードスキャン

今回は、LED点灯以外の機能がありませんので、アノードスキャン用に特にタイマーを割り当てて、割り込み処理の中で実行するようにしました。
Timer0 を約1msec※ のCTCモード(0から設定値までのカウントを繰り返すモード)にして、一周するごとに次のアノード端子をONにします。

このとき、前もって、全アノードを一旦オフにしておきます。1msecなので大丈夫と思っていましたが、やはり、直前の残像が出てしまいました。

※ 1msに設定すると、全アノードをスキャンするのに10msecかかります。これ以上大きくすると、LEDのチラつきが目立ちます。

また、この割り込み内で、次項で用意する各アノード毎の点灯パターンを、カソード端子に反映します。

4.2、点灯パターン生成

各アノードに対応する点灯パターンを用意しておきます。
今回は、ライブラリで標準で用意されている、rand()関数を使い、ランダムパターンを用意します。
ただ、この関数の出力は16ビットなので、今回の点灯パターン(12ビット)化するために、2^12で割った余りを採用します。

この値で実際に点灯させたところ、ランダムに点灯してはいるが、もう少し光っているLEDが少ないほうが自然ではと感じたので、上記12ビット化する際に、点灯数を約半分に減らす処置を追加しました。

4.3、点滅操作

常時点灯していると、作品の品位を損ねると感じたので、約40msecのみ点灯し、その後2秒は消灯する処理を追加しました。
LEDアノードスキャンの処理が約1msec毎に行われていますので、この回数をカウントし、指定回数に達する毎に、点灯パターンをクリアしています。



今回のソースは、以下の段階で、出品としました。


//////////////////////////////////////////////////////////////////////////////
//
// Project : LED Matrix
//
// Programmed by Ken_Craft(c)
//
// MPU =  ATmega168P
// F_CPU = 1MHz(default, decrared Configuration Options)
// Lfuse = 0x62(default)
// Hfuse = 0xDF(default)
// Efuse = 0xD9(default)
//
//////////////////////////////////////////////////////////////////////////////

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h> // for rand()

#define _SBI(p, q) ((p) |= _BV(q))
#define _CBI(p, q) ((p) &= ~_BV(q))

#define LED_OFF 0
#define LED_ON 1

//////////////////////////////////////////////////////////////////////////////
// グローバル変数及び各定義
//////////////////////////////////////////////////////////////////////////////

volatile uint8_t uLEDINDEX;
volatile uint16_t uTIMER;

volatile uint8_t uBLINK;
volatile uint16_t uMASK;

volatile uint16_t uLEDPATTERN[] = {

    0b0000111111111111,   // dummy
    0b0000000000000000,
    0b0000111111111111,   // dummy
    0b0000000000000000,
    0b0000111111111111,   // dummy
    0b0000000000000000,
    0b0000111111111111,   // dummy
    0b0000000000000000,
    0b0000111111111111,   // dummy
    0b0000000000000000

};


//////////////////////////////////////////////////////////////////////////////
// 割り込み及び各関数
//////////////////////////////////////////////////////////////////////////////
// ---------------------------------------------------------------------------
// タイマー0 比較一致割り込み
// ---------------------------------------------------------------------------
ISR(TIMER0_COMPA_vect)
{
    uTIMER++;

    /******** cathode (pattern) off ********/

    PORTB = 0;
    PORTC &= 0b00000011;

    /******** anode scan ********/

    uint16_t uLedScan = _BV(uLEDINDEX);

    uint8_t uLedScanL = ~(uLedScan) & 0b0000000011111111;
    uint8_t uLedScanH = ~(uLedScan >> 8) & 0b0000000000000011;

    PORTD = uLedScanL;
    PORTC = (PORTC & 0b11111100) | uLedScanH;

    /******** set (cathode) pattern ********/

    uint16_t uLedPattern = (uBLINK == LED_ON) ? uLEDPATTERN[uLEDINDEX] : 0;

    uint8_t uLedPatternL = uLedPattern & 0b000011111111;
    uint8_t uLedPatternH = (uLedPattern >> 8) & 0b000000001111;

    PORTB = uLedPatternL;
    PORTC = (PORTC & 0b00000011) | (uLedPatternH << 2);

    uLEDINDEX = (uLEDINDEX >= 9) ? 0 : uLEDINDEX + 1;

}

//////////////////////////////////////////////////////////////////////////////
// メインループ
//////////////////////////////////////////////////////////////////////////////
int main(void)
{
    uLEDINDEX = 0x00;
    uTIMER = 0x0000;
    uBLINK = LED_ON;
    uMASK = 0b0000010101010101;

    /******** I/O Setting ********/

    _SBI(DDRD, DDD0);   // PD0-7 Output
    _SBI(DDRD, DDD1);   // ↑
    _SBI(DDRD, DDD2);   // ↑
    _SBI(DDRD, DDD3);   // ↑
    _SBI(DDRD, DDD4);   // ↑
    _SBI(DDRD, DDD5);   // ↑
    _SBI(DDRD, DDD6);   // ↑
    _SBI(DDRD, DDD7);   // ↑

    _SBI(DDRC, DDC0);   // PC0-1 Output
    _SBI(DDRC, DDC1);   // ↑

    _SBI(DDRB, DDB0);   // PB0-7 Output
    _SBI(DDRB, DDB1);   // ↑
    _SBI(DDRB, DDB2);   // ↑
    _SBI(DDRB, DDB3);   // ↑
    _SBI(DDRB, DDB4);   // ↑
    _SBI(DDRB, DDB5);   // ↑
    _SBI(DDRB, DDB6);   // ↑
    _SBI(DDRB, DDB7);   // ↑

    _SBI(DDRC, DDC2);   // PC2-5 Output
    _SBI(DDRC, DDC3);   // ↑
    _SBI(DDRC, DDC4);   // ↑
    _SBI(DDRC, DDC5);   // ↑

    /******** Timer0 Setting ********/

    _SBI(TCCR0A, WGM01);    // TIMER0 CTCMode
    _SBI(TCCR0B, CS00);     // TIMER0 Prescaler = 1/64
    _SBI(TCCR0B, CS01);     // ↑
    OCR0A = (uint8_t)(F_CPU * 1E-3 / 64);
    _SBI(TIMSK0, OCIE0A);   // TIMER0 CTC Interrut Enable

    /******** Enable all interrupts ********/
    sei();

    while(1){

        if(uBLINK == LED_OFF && uTIMER >= 2000){

            uTIMER = 0;
            uBLINK = LED_ON;

            cli();  // disable interrupt            
                
            for(uint8_t i = 0; i <= 9; i++){

                uint16_t uRand = rand();
                uLEDPATTERN[i] = (uRand & /*0b0000111111111111*/uMASK);

            }

            uMASK = (uMASK == 0b0000010101010101) ? 0b0000101010101010 : 0b0000010101010101;

            sei();  // enable interrupt

        }else if(uBLINK == LED_ON && uTIMER >= 40){

            uTIMER = 0;
            uBLINK = LED_OFF;
        }

    }

}



5、製 作

5.1、作品側LED取り付け

当初、接着が必要?とか、リード二本の穴を開けなければいけないか?と考えていましたが、結局、
単に指定72箇所に、LEDに合わせて3Φの穴を一個だけ開け、作品表側から、以下写真のように各色LEDを差し込んで、リードを外曲げするだけで済みました。



次に、作品を裏返し、縦10本・横12本のポリウレタン線を張り、其々の交点付近に、LEDのリード線を半田付けして行きます。

※ まさに「マトリクスLEDを手作り」している状況です!




箇所を絞って拡大したものが、以下の写真です。


デザイン上、交点から外れたセグメントのLEDは、最寄りの交点に接続しています。


5.2、基板実装

トランジスタの基板パターン(「品」の形)は余り好みではありませんでしたが、コレクタのみフォーミングすれば良く、楽に早く実装することが出来ました。



6、完 成(とお詫び)

作品と基板を、フラットケーブルでドッキングして、作者に光り具合を見て頂き、展示会に搬入となりました。

※ 諸般の事情により、最終作品の画像をご紹介することができません。申訳ありません・・・


「スイッチサイエンスPCB」 の利用がなければ、期間内に完成させることは無理で、そうで無くても、予算オーバーでお断りしているところでした。

基板設計において、「EAGLE」は、業者向けの基板CADソフトウエアであり、自動配線や膨大なライブラリ(あくまでも量産用部品)を活用して、基板を短期間で作成するのに向いていると感じました。

また、アート作品に電子回路を組み込む作業は、方向を誤ると、作品の品位に影響を与えてしまうことを痛感しました(今回は、迷った箇所は、作者の指示を仰いで作業を進めることにより、影響を回避しました)。



最後に、本作品の製作でお世話になりました以下の皆さまに、この場を借りまして御礼申し上げます。

・「EAGLE」提供元 AUTODESK社
・「EAGLE」使い方の解説 趣味の電子工作にようこそ
・アートサークル主催 地域活動支援センターかけはし
・個展開催場所 谷山サザンホール