ラップタイマーが欲しい!
ライントレースで遊んでいると欲しくなりますよネ。どのパラメータの組みが速いかも知りたいですし。しかもブレッドボードで組むんじゃなくて、子基板(シールドって言うんですね)を載せてポータブルにしたい!ってことで作っちゃいました。
全体像
写真は Arduino のキット についてきたセンサやディスプレイをサンハヤトのArduino用ユニバーサル基板 UB-ARD03-P の上に載せたものです。この基板は Arduino のリセットボタンが隠れず、また GND と VCC がベタで引き回されているので配線が楽でした。逆に Arduino のピンから信号を引っ張り出すにはそれらを跨がなければならず、狭い基板がますます狭くなるので、使い易さと使い難さが同居している感じです。
またセンサやディスプレイはピンソケットから引っこ抜いて再利用できるようにしています(ケチ)。
センサモジュール
出力ピンがL字型で基板に対して垂直に立つタイプなので、取り外して縦型のピンヘッダに交換しようかとも思いましたが、センサの高さを低く抑えたかったのでL字型のピンソケットを介して基板に対して水平になるようにしています。
タクタイルスイッチ
サンハヤトの基盤についてくるタクタイルスイッチはリセットがかかるようパターンが引かれているので、カッターでカットしてラップのリセット用にすることにしました。
電源
006P 電池は東芝のニッケル水素電池 IMPULSE で 充電器 と一緒に Amazon 購入です。容量が 200mAh なので連続で数時間遊んでいるとなくなります。フル充電に6時間かかります。
圧電ブザー
1つはアクティブ(自励振)タイプでラップを刻んだ時に「ピッ」と音を鳴らします。もう1つはパッシブ(他励振)タイプで、ビュートローバーARM に実装した楽譜再生プログラムを Arduino に移植することを考えてます。タイムを計測しながらカッコいい曲を流す予定です!
配線とプログラムはチュートリアルから!
SunFounder の「コンポーネントの基本」ページから「IR 赤外線障害物回避センサーモジュール」と「OLEDディスプレイモジュール」を参考に “ニコイチ” にします。
回路図は描いた事がなかったので部品のレイアウトに苦労しましたが、一応 Fritzing で配線図と回路図を引いてみました。エキスパートの方々は KiCad を使っているらしいので、いづれ習熟してオリジナル基板を発注するのが夢です。
また Minima のパーツは Fritzing のフォーラム からもらいました。ホント、ありがたいですネ。
ソースコードのご紹介
ソースコードを Github に上げてありますが、ここでも簡単に解説したいと思います。
要求
- センサでロボット車の通過を検知する
- コースを1周するごとにラップタイムをディスプレイに表示する
- ディスプレイの上段に経過時間、下段にラップタイムを表示する
- タイムは 1/100 秒まで計測する
- 計測の状態変化を音と表示で知らせる
要件
- 小型、ポータブル、乾電池で動作すること
- 制約条件
- コースを1周するのに4秒以上であること
- 黒色の車体は計測の対象外とする
- …
仕様
- ロボット車の通過に伴うセンサの状態変化を割り込みで処理する
- 車体の凹凸などに伴うセンサ出力のチャタリングを除去する
- タイマーの状態は「計測前」、「計測中」の2状態とする
- ラップタイム更新時には音を鳴らし、表示を点滅させる
- ラップタイムの点滅は、点滅周期と点滅時間で制御する
実装
まずは OLED の設定です。チュートリアル「OLEDディスプレイモジュール」に従い、Adafruit の SSD1306 用ライブラリとグラフィック用ライブラリが IDE にンストールされていることが前提です。
続いてタイマーとラップ表示に関する設定です。割り込みを使わない設定もできますが、振る舞いが若干変わります。
割り込みハンドラには引数も戻り値も無いので、メインループとはグローバル変数でやりとりします。メインループ内の処理にとっては知らない所(=割り込みハンドラ)で変数の値が変更されるため、volatile
をつけてコンパイラに適切に扱うよう指示(=最適化を適用しない)しています。
次は Arduino の setup()
で呼び出す初期化の関数群です。
続いて、ミリ秒を 1/100 秒単位の文字列に変換をするためのサブルーチンです。
次は割り込みハンドラの定義です。障害物センサ FC-51 は、未検出の場合は High
、検出した場合は Low
を出力します。即ちエッジの立ち下がりを検知すれば通過を判定できるのですが、setupSensor()
で attachInterrupt()
に FALLING
を設定しても CHANGE
と同じ振る舞いが観測されたため、わざわざ digitalRead()
で状態を確認しています。
Arduino R4 コアのソースコード には HIGH
の場合に 問題がありげ なコメントが書かれているので、何かあるのかもしれません。
またアクションとして状態変化に伴う音を tone()
で鳴らしています。音の長さを BUZZER_DURATION
(16[msec])で指定していますが、鳴り終わるまでここで待っているわけではなく、タイマーに「指定した周波数で指定時間分だけアナログ出力せよ」と指示してすぐに戻ってきます。
続いて Arduino お約束の setup()
で先に定義した初期化の関数群を呼び出します。
最後はメインループです。millis()
で最新の経過時間を読み込み、その表示とラップタイムの表示を担当しています。
以上!
ライントレースで楽しんでもらえたら嬉しいです ^.^)y