週刊アスキー

  • Facebookアイコン
  • Twitterアイコン
  • RSSフィード

Arduinoで夏休みを満喫!電子工作超入門

2012年07月24日 19時30分更新

実践インターバルタイマーを作る

 電子工作を簡単・手軽に始められるマイコンボード『Arduino』。最小限のハンダ付けやプログラミングで動くモノを作れるという点では、電子工作入門者に最適なシロモノだが、LEDを点滅させるような勉強ばかりでは楽しくない。なにか実際に使えるものを作ってみようというわけで作ったのが“インターバルタイマー”だ。

 一定時間おきにカメラのシャッターを切るインターバルタイマーは、最近はやりの“タイムラプス動画撮影”の必需品だ。カメラ内の機能として内蔵している製品もあるが、外付けだと1万円前後とややお高い。しかし、Arduinoで自作すれば5000円強程度。ハンダごてなど、いろいろとそろえたらそれほどお得というわけではないが、Arduinoボード自体はほかにも転用できるし、プログラムを多少いじれば使い勝手を自分で改良することもできる。

●用意したもの
Arduino Duemilanove 3200円※
キャラクター液晶(SD1602VBWB) 800円
Arduino用ユニバーサル基板 600円
2.5mmステレオプラグ 100円
フォトカプラー(TLP521) 50円
タクトスイッチ×3 60円
LED 20円
抵抗(10kΩ)×3 3円
半固定抵抗(5kΩ) 20円
汎用コネクタ 10円
配線素材(適量)
※Arduino Duemilanoveは販売終了し、現在は後継の『Arduino Uno R3』(2520円)がある。

●ブレッドボード上で作ってみる
 まず、シャッターを切る“レリーズ端子”。これは一眼機では一般的な2.5mmイヤホンプラグを使うタイプなのだが、ステレオイヤホンプラグの真ん中の端子と外側の端子を短絡(つまりつないだら)シャッターが切れる。ステレオなので3極あり、中間の端子と外側を短絡させると半押しになる。今回はシンプルに作るため半押しは省略した。

 まずはブレッドボードを使って配線する。キャラクター液晶だけ接続し、サンプルスケッチの“HelloWorld”を走らせてみて間違ってないか確かめよう。次に入力のタクトスイッチ接続、出力のフォトカプラーを接続する。

ブレッドボード上に回路を構成
Arduinoでインターバルタイマーを作る
↑液晶搭載のブレッドボードをベースに作り上げたのがこれだ。
出力側にも素子を追加
Arduinoでインターバルタイマーを作る
↑レリーズ端子の通電をON/OFFするのはフォトカプラーという素子。LEDは確認用。
3つのスイッチを追加
Arduinoでインターバルタイマーを作る
↑操作する必要があるので、タクトスイッチ3つを追加。それぞれ抵抗がある。

 ちなみにフォトカプラーは一方の端子に電流を流すことでもう一方の端子(つまりレリーズ端子)を通電するリレーのような素子だ。データ通信などに使えるほど高速に動作するのが魅力だが、こういった用途ではフォトカプラーよりもリレーのほうが応用が効いていいはず。リレーならば小さめの素子でも100Vの通電/遮断に耐えるものもあるので、家電のON/OFFだって可能になる。
 なお、フォトカプラーは入力2、出力2のものを使用しているので、シャッター半押し機能追加も可能だ。

●プログラムを書き込もう
 Arduinoのプログラム開発環境(IDE)はarduino.cc(http://arduino.cc/en/Main/Software)から無料で入手できる。現在の最新バージョンは1.01で、メニューなどが日本語化されている。

 インストールしてUSBでArduinoを接続すると、シリアルデバイスとして認識され、COMポート上にあるのが確認できるはずだ。IDEにスケッチを入力したらIDE上部のボタン“マイコンボードに書き込む”を押せばいい。いちおう“スケッチを検証”で間違っていないか、COMポートが合っているかなどを確認しておくのも忘れずに。特にコメント文(//より右)以外に全角スペースが存在するとエラーになるが、その行ではなく別の行にエラー表示が出るので見つけにくい。

●インターバルタイマー用スケッチ(超簡単版)
 

#include                  // 液晶を使うためのライブラリ宣言 LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);  // 液晶を接続するピンの指定 int buttonPin[] = {6,7,8}                ;  // pushbutton pin  スイッチのピン番号は6,7,8 int buttonState[] = {0,0,0}              ;  // pushbutton state スイッチの状態、押されているときON int lastbuttonState[] = { 0,0,0}         ;  // pushbutton state スイッチの状態を格納するための数値 int i                   ;   // 汎用カウンタ int count1 = 30         ;   // インターバル秒数の初期値 int count2 = 30         ;   // インターバルカウントダウン用数値 int count3 = 0          ;   // 撮影枚数カウンタ boolean selecter = true ;   // 動作セレクタ TrueでSET(設定モード)/FaleでRUN(実行モード) //  setup()は最初に1回実行されるプログラム void setup() { lcd.begin(16, 2)             ;  // 液晶を使う宣言文 lcd.clear()                  ;  // 液晶をクリア pinMode(buttonPin[0], INPUT) ;  // 6,7,8ピンを入力に使う宣言 pinMode(buttonPin[1], INPUT) ; pinMode(buttonPin[2], INPUT) ; pinMode(9, OUTPUT)           ;  // 9ピン(フォトカプラ)は出力に使う宣言 } //   メインプログラム部分(ループする) void loop() { disp()                ;  // サブルーチンdispを呼び出す buttoncheck()         ;  // サブルーチンbuttoncheckを呼び出す action()              ;  // サブルーチンactionを呼び出す } // スイッチ状態読み出し部分 void buttoncheck() { for(i = 0 ; i <= 2 ; i ++ ) { buttonState[i] = digitalRead(buttonPin[i])  ;  //  buttonState[0-2]にそれぞれスイッチのON/OFF状態が入る } } // ボタン状態の確認・処理部 void action() { for(i = 0 ; i <= 2 ; i ++ ) { if((buttonState[i] != lastbuttonState[i]) && (buttonState[i] == HIGH))     //  ボタンの状態が変わったことをチェック { buttonState[i] = 1 - buttonState[i]  ; switch (i) { case 0 :                   // ボタン1ならカウンタ1をアップ count1 ++          ; count2 = count1    ; break ; case 1 :                   // ボタン2ならカウンタ1をダウン if(count1 > 1 )         //  1以下には設定できないよ count1 --       ; count2 = count1 ; break ; case 2 :                   // ボタン3なら動作モードを変更 selecter = ! selecter ; break ; default:                   // ボタン状態を記憶する lastbuttonState[i] = buttonState[i] ; } } } if(! selecter)    //   設定モード時でなければ running()  ;   //   実行モードに移行 delay(100)    ;  //  ループにタイムラグを入れる(スイッチのチャタリングを抑えるためのもの)  } // インターバル撮影実行部 void running() { if(count2 == 0)          //  カウントが0になったら shutter()       ;     //    shutterに飛ぶ else { delay(1000)      ;     //  1秒なにもしない count2 --       ;     //  カウンタを減算 } } // レリーズ動作部 void shutter() { digitalWrite(9,HIGH) ;  //  9ピン端子出力 delay(500)           ;  //  0.5秒待つ digitalWrite(9,LOW)  ;  //  9ピン端子出力停止 count2 = count1      ;  //  減算用カウンタをリセット count3 ++            ;  //  撮影枚数カウンタを+1 } //  液晶表示部 void disp() { // 動作モード表示 lcd.setCursor(0,0)    ;    // カーソル位置左上に if(selecter) { lcd.print("SET")   ;    //  SETモードを表示 lcd.setCursor(5,0) ;    //  カーソル位置を上の行5桁目に if(count1 < 1000 )      //  カウンタの桁数にあわせた0を頭に付けるための処理 { if(count1 < 100 ) { if(count1 < 10 ) lcd.print("0")  ; lcd.print("0")        ; } lcd.print("0")          ; } lcd.print(count1)       ;  //  設定秒数カウンタを表示   } } else { lcd.print("RUN")        ;  //  RUNモードを表示 lcd.setCursor(5,1)      ;  //  カーソル位置を下の行5桁目に(以下、上と同じ動作) if(count2 < 1000 ) { if(count2 < 100 ) { if(count2 < 10 ) lcd.print("0")  ; lcd.print("0")     ; } lcd.print("0")        ; } lcd.print(count2)          ;  //  カウントダウンする秒数を表示 // 撮影枚数を表示 lcd.setCursor(12,0) ;      //  カーソル位置を上段12桁目に lcd.print("SHOT")   ;      //  SHOTを表示 lcd.setCursor(12,1) ;      //  撮影枚数カウンタ表示位置 lcd.print(count3)  ;       //  設定秒数カウンタを表示(カーソル位置的に表示できるのは最大9999枚) } }
サンプルを読み込む
Arduinoでインターバルタイマーを作る
↑最初は液晶をつないでサンプルのHalloWorldを読み込んでみよう。ちなみにサンプルとこの作例では、使うピンが違ってそのままでは動作しない。HelloWorldのLiquidCrystal lcd(12, 11, 5, 4, 3, 2) ;という行をLiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2) ;に変更してほしい。
シリアルポートを確認
Arduinoでインターバルタイマーを作る
↑Arduinoを接続したらシリアルポートを確認しよう。接続する前にはなかったポートがArduinoだ。
動作を確認する
Arduinoでインターバルタイマーを作る
↑スケッチを書き込むボタンが上部のバーにある。まずはサンプルスケッチなどで動作を試してみよう。サンプルスケッチには液晶やLEDをつなぐことが前提のものが多いが、Arduinoに何もつながっていなくても壊れたりはしない。
スケッチを転送する
Arduinoでインターバルタイマーを作る
↑“マイコンボードに書き込む”を選ぶと、スケッチのコンパイル、スケッチの転送が行なわれる。下部の黒い部分に赤い文字が出るとエラーなので冷静に対処しよう。

 転送が終われば
 SET 0030
 というシンプルな表示になるはず。タクトスイッチの上を押せば数値が上がり、下を押せば数値が下がる。左スイッチで“RUN”(実行モード)という表示になり、下の行や右側にも数値が表示され、カウントダウンが“0”になったらLEDがチカッと光り、撮影枚数が加算される。もう一度左のスイッチを押せば中断し、“SET”(設定モード)に復帰する。

 なお、書き込んだスケッチは電源を切っても消えないので、あとは電池ボックス(単3×4本)やUSB充電器などといっしょに持ち運んで使うことができる。

●ユニバーサル基板に作り込んでみよう
 ブレッドボード上で動作を確認できたら、携帯して使うためにも、ユニバーサルボードに移植しよう。それには、配線(ブレッドボードに使うものよりやや細い電線)をブレッドボード上の配線どおりにつなげばいい。

 本来ならば配線しやすいようにパーツ配置をもっと考慮するべきなのだが(多用する“GND”は端のほうにまとめた線を作っておくとか)、ここではまるで考えていないため配線がかなりスパゲッティーになっている。なお、ハンダ付けがしっかり行なわれているかをテスターでチェックする作業は、すべて配線してからではなく、ハンダ付けをしながらこまめにやろう。

●配線図
実践インターバルタイマーを作る

※この図ではピン番号は16 … 01と並んでいるが、実際の製品では、ピンは一列に並んでいるもののピン番号は14,13,12,11,……,3,2,1,16,15と並んでいるので要注意。また、同じような一列に並んだピンをもつキャラクタ液晶モジュールでも1番ピン(GND)と2番ピン(+5V)が逆になっている製品もある。製品に付属する説明書などをよく読んで接続してほしい。

まずは汎用基板にコネクターを
Arduinoでインターバルタイマーを作る
↑ブレッドボードのままでは携帯に不便なので、基板に移植してみよう。
基板上の配置がキモ
Arduinoでインターバルタイマーを作る
↑基板上にパーツを並べつつハンダ付けしていく。
裏面はかなりスパゲッティー
Arduinoでインターバルタイマーを作る
↑ブレッドボード時の配線そのままに空中配線。正直、見栄えは×。
通電する前にチェックしよう
Arduinoでインターバルタイマーを作る
↑ハンダ付けミスはよくあることなのでテスターで通電チェック。
レリーズ端子は適当なコネクターで
Arduinoでインターバルタイマーを作る
↑イヤホンプラグ型レリーズ端子は通電するとシャッターが切れる。
動作時は秒数と撮影枚数が表示
Arduinoでインターバルタイマーを作る
↑動作しているところ。スイッチ(黄)で秒数を増減して設定、スイッチ(赤)で実行/中断する。

 完成したらArduinoに載せ、ピンを差し込めば固定される。USBケーブルでPCと接続し、問題なければUSBからの給電で液晶バックライトが光るはずだ。あとはスケッチをPCから転送しよう。

 なお、もう少しキレイに配線したければ、プリント基板を自作するという手だってある。銅を被覆した基板に配線図を保護インクで書いて、酸で処理すれば必要な配線だけ残ったオリジナル基板の完成だ。やや手間はかかるが自分オリジナルのシールドを作れるのは楽しいし、本当に“使える”シールドならば、量産すれば誰かが買ってくれる。Arduinoの文化ではそんなシールドの売り買い(イベントなどでも売られていて、いわば同人誌みたいなものだ)も、ごく当たり前に行なわれているのがおもしろい。

●スケッチはこんな動作をしている
 スケッチは、手早く、わかりやすく組んだこともあって、特に複雑な処理や凝ったプログラム技法は使っていない。
 Arduinoではメインのプログラムloop()が自動実行され、その名前のとおり電源が入っている限りループする。disp()、buttoncheck()、action()といった部分はいわゆるサブルーチンだ。

 スイッチ状態を読み込む部分では、スイッチが押されたことのチェックに、なぜひとつ前のステータスと比べる必要があるのかなど、説明するとかなり長くなってしまうので、Arduinoの教科書的な存在『Arduinoをはじめよう』(オライリー・ジャパン)を読んでほしい。

 液晶表示部分は数値を“0000”というフォーマットで表示するためif文を重ねているのでやや見苦しいが、一定のケタ数で表示するもう少しスマートな方法はあるはずだ。

 スイッチ1が押されて実行モードに入ると、“running”というサブルーチンに入り、1秒待ってカウントダウン、0になったらサブルーチン“sutter()”に入る。動作はピン9番をONにし、半秒待ってOFF、カウントダウンしていた数値を設定秒数に戻して復帰するというシンプルなつくりだ。

●スケッチの問題と改良のポイント
 今回のスケッチは、超簡単版なのでいくつかの問題点がある。もちろん動作はするのだが、改善すべき点を挙げてみよう。

 まず、実行モードでは“delay”(なにもしない命令)で1秒待ってカウントダウンを実直に繰り返すという動作なため、中断するスイッチの効きがかなり悪い(キーを押して離すタイミングを覚えないと、一度中断してもすぐ実行モードに入ってしまう)。スイッチはサブルーチン化してあるので、delay数値を少なくしつつループ回数を多くし、ループ内でスイッチをチェックするべきだろう。

 また、実行モードでは1秒ごとにカウンタを減らし、“0”になったら半秒のシャッターを切っているわけだが、インターバルタイマーとしては実は正確でない(常に半秒多い)。カウントダウンが0秒になったらシャッターを切るのではなく、1秒前でシャッターモードに入って、そちらで別途delay処理をするほうがよい。

 このほか、単なる秒数を表示するのではなく “時:分:秒”表示にするのが“使い勝手”というもの。簡単な計算で済むのだが、“00:00:00”とすると液晶横幅のケタ数がやや足りなくなるので、SET/RUNといった表示レイアウトも見直したい。

●もう少しいじってみよう
 スケッチに手を加えて応用を効かせるとするなら、タイムラプス撮影途中でfpsを変えると、それまで目まぐるしく動いていたものが通常に近い速度になるという演出も可能となる。いずれにせよRUNモードの中からスイッチの状態を読めるようにしておくのに越したことはない。

 今回のスケッチではレリーズ端子への通電時間は一定だが、この時間を指定できるようにしてもいい。普通の風景をタイムラプス撮影する場合、シャッター時間にはカメラまかせにしてもよいのだが、星空を撮るときなどはカメラ側をBULBにして、シャッターを開けている時間もインターバルタイマー側で制御するわけだ。スイッチ3でもうひとつの数値をどう設定するか悩むだろうが、工夫すればなんとでもなるはずだ。

 ハードウェアも含めた比較的簡単にできる機能拡張としては、まずはシャッター半押しの制御。フォトカプラーはもう1端子あるので、配線を追加すれば可能だ。また、LEDの接続方法を変えてスケッチをいじれば、インターバル動作中にLEDが点滅し、シャッターが切れる直前は点滅速度が速めになるという“セルフタイマーふう動作”もそれほど難しいものではない。

 ただし、この作例ではデジタルIOピンのほとんどを使ってしまっているので、いろいろ追加しようとするとピン数が足りなくなる。アナログ入力ピンは余っているので、値の増減はポテンショメータ(可変抵抗、つまりボリウム)にするといった工夫や、より少ないピンで使えるキャラクター液晶(Arduinoとシリアル接続する)などを考えてみるのもいいだろう。

 最低限の工作とプログラミングでいろんなことができるのがArduinoのおもしろさ。インターバルタイマーひとつ作ってみても、スイッチと液晶でどれだけのことができるかを学びつつ、自分が考えた工夫を盛り込んでいけるのは、なかなかな楽しいはず。作っただけで満足するのではなく、タイムラプス撮影という本来の目的もがんばって撮ってみてほしい。


 7月24日発売の週刊アスキー8月7日号では、『4000円ではじめる 電子工作超入門』という特集で、電子工作のおもしろさをギュギュッと徹底紹介しています。あわせてご覧ください。

(7月25日23:00追記:配線図のところで、ピン番号に関する説明を修正しました。)

この記事をシェアしよう

週刊アスキーの最新情報を購読しよう