今回は、Arduinoを使ったユニークな電子工作を前編、後編の2回に分けてご紹介していきたいと思います。この興味深い電子工作を紹介してくれるのは、物事の関係性をテーマに活動するアーティストである平原真さん。大阪芸術大学准教授でもある平原さんは、これまでもコンピュータや電子デバイスを使ったメディアアートを多数制作されており、Device Plusでも「Arduinoを使ったソーラーパネルで動くデジタル飼育箱」や「ArduinoとTOF距離センサでつくるドーナツプレーヤ」といったセンス溢れる電子工作を制作してくれています。今回はどんな作品になるのか、早速見ていきたいと思います。
はじめに
みなさん、こんにちは。平原と申します。突然ですが、皆さんは巨大迷路で遊んだことがありますか?身長よりも高い壁で作られた迷路に入り、回転扉や立体交差などの仕掛けを乗り越えてゴールを目指すというアトラクションです。1980年代に全国的にブームとなりましたが、今では数えるほどしか残っていないそうです。私は子供の頃に体験して「空から見下ろせたら簡単なのに!」と思ったものです。
今回は、そんな子供の頃の夢を叶える作品を作っていきたいと思います。実物の迷路を傾けると、画面の中の迷路も傾きボールが転がっていく装置を制作し、実物と画面を交互に見くらべながらゴールを目指しましょう!
記事の構成について
この記事は次の6つのパートに分かれています。
- 作品のプランと制作の準備
- 電子回路
- Arduinoのプログラム
- 筐体の作成
- 迷路の3Dモデルの作成
- Unityのプログラム
今回の前編は1~3までを紹介し、最後に電子回路の動作テストをおこないます。後編は迷路の筐体をレーザー加工機で作成し、Unityで3Dの迷路のゲームを完成させます。
1. 作品のプランと制作の準備
全体のイメージ
今回の作品は、実物の迷路を傾けると、画面の中の迷路も傾きボールが転がります。実物の迷路は全体を見渡せますがボールの位置は分からず、画面ではボールの周辺しか見えないので、実物の迷路と画面の迷路を交互に確認しなければいけないところがポイントです。
箱の中には、傾きを検出するための加速度センサと、マイコンボードArduino UNOが入っていて、USBケーブルでPCとつなぎます。箱を傾けると、PCで動作している3Dの迷路を表示するUnityというソフトに、傾きのデータが送られます。Unityは、受け取ったデータと同じように3Dの迷路を傾け、ボールが物理演算によって転がります。
それから、いろいろなステージを遊べるように、実物の迷路を交換すると3Dの迷路も切り替わるようにしたいと思います。さらに、ゴールした時に振動したら楽しそうですね。
システム構成
全体のイメージを実現するために必要な機器を図に描いて、全体の機器構成を考えます。
まず、傾きを読み取るための加速度センサが必要です。それから、迷路の切り替えを読み取るフォトリフレクタと、振動を発生させる振動モータも入れましょう。そして、これらの電子部品を制御したり、PCと通信をするためにマイコンボードArduinoが必要です。ArduinoとPCはUSBケーブルで接続します。PCの中でUnityを実行し、Arduinoとの通信と迷路の表示をおこないます。
次に、電圧や消費電流、使用するピン、通信方法、実物のサイズ、カッコよさなどを考慮して、具体的な部品を選定します。主要な部品や選択肢の少ない部品から決めると考えやすくなります。
加速度センサ
加速度センサは、加速度を電圧として出力するアナログタイプと、I2Cなどで通信するデジタルタイプがあり、最近はデジタルタイプが主流となっています。今回は、ローム社製加速度センサモジュール「KX224-1053」とArduinoで簡単に使えるセンサシールド「SHIELD-EVK-001」を使用します。
ロームセンサ評価キット
フォトリフレクタ
フォトリフレクタは、赤外線を照射し対象物から反射を読み取るデバイスです。対象の色によって反射量が変わることを利用し、迷路の種類を読み取ります。2つのフォトリフレクタがあれば、4種類を見分けることができます。今回は定番の「RPR-220」を使用します。
振動モータ
振動モータは、偏った重りを回転させることで振動を発生させるデバイスです。偏心モータとも呼ばれます。今回は回路を簡単にするために、2.0v 〜3.0v、50mA程度で動作し、 Arduinoから直接制御できる物を使用します。
Serial Port Utility Pro
UnityとArduinoの通信は、標準の機能だけでも実現できますが、今回はSerial Port Utility Pro(SPUP)というアセットを利用します。SPUPを使うと実行環境の違いを気にすることなく手軽に通信することができます。アセットストアでの販売価格は$79ですが、公式サイトから試用版をダウンロードすることができます。試用版は、通信量が一定上になるとUnityの再起動が必要になります。開発中は試用版を使い、長時間動作させ続けたい場合に購入するといいでしょう。
筐体の構造
全体のイメージと必要な機能から、筐体の構造を考えます。最初は手書きでラフに書き、大枠が固まってからCADなどで設計すると効率的です。今回はシンプルな箱なのでIllustrator で設計しました。
今回の要件は、両手で持てるサイズ、迷路を交換できる事、迷路の裏側をフォトリフレクタで読み取れることです。箱状にして回路を納め、蓋に迷路が乗っているようにします。蓋の裏側に白と黒のマーカーを付け、フォトリフレクタで読み取れるようにします。
素材はシナベニヤを使い、レーザー加工機で切断、木工用ボンドで接着します。中身を見せたい場合は透明のアクリル板などでもいいでしょう。好みに合わせて変更してください。
部品リスト
使用する物品をまとめました。価格と購入先URLは執筆時点のものです。送料が別途かかります。
配布ファイル
作成例を作るために必要なデータを以下のリンクからダウンロードしてください。Arduinoのプログラムや、シナベニヤをカットするための形状データなどが含まれています。
>> データのダウンロード(50.4MB)
- CutBox.ai
筐体の箱部分のレーザー加工用データ - CutMaze.ai
筐体の迷路部分のレーザー加工用データ - ArduinoApp
Arduino用プログラム - UnityApp
Unityのプロジェクト - BreadboadHolder.stl
ブレッドボードの高さを上げるためのパーツ - MazeLv1.obj、MazeLv2.obj、MazeLv3-A.obj、MazeLv3-B.obj
迷路の3Dモデル
2. 電子回路
配線図と回路図
電子部品のデータシートを確認しながら回路を設計します。同時に、実際の物の大きさや位置関係を考慮しながら、配線の長さなど考えます。
加速度センサモジュールは、センサシールドに取り付けてArduino UNOの上に固定できるので配線が簡単です。フォトリフレクタと振動モータは、ブレッドボードに乗せます。
配線図
回路図は電気的な接続関係を表したもので、配線図は実際のサイズや位置関係などを考慮した図です。慣れないうちは配線図をそっくりそのまま再現すると作りやすいですが、制作に慣れてきて自分で回路を作ったり他の人の回路を取り入れる時は、回路図で考えるほうが理解しやすくなります。
回路図
組み立て
それでは、電子回路を組み立てていきましょう。今回はハンダ付けはせずに、ブレッドボードとジャンパワイヤで結線するので、失敗の心配はありません。配線図と写真を見比べながら作業をおこなってください。作業の手順は以下のとおりです。
- 加速度センサモジュールとセンサシールド
- フォトリフレクタ
- 振動モータ
- 配線
手順1:加速度センサモジュールとセンサシールド
センサシールドには、全部で8つのセンサモジュールを取り付けられるソケットがあります。加速度センサモジュールはI2Cという通信規格なので、I2C_1と書いてあるソケットに差し込んでください。モジュールが水平になるように角度を調整してください。
次に、センサーシールドをArduino UNOに連結します。加速度センサモジュールが水平になるように、全てのピンをしっかりと奥まで差し込んでください。また、長いピンが曲がらないように、垂直に力をかけてください。あとから取り外す事もできますが、長いピンが曲がる事が多いので、慎重に扱ってください。
手順2:フォトリフレクタ
フォトリフレクタの足は4本あります。長さがバラバラなので一番短い足に合わせて切りそろえてください。ニッパで切る時に端材が勢いよく飛ぶことがあるので、注意してください。
抵抗器は根本から直角に曲げ、1cmくらいのところで切ります。
次に、配線図を参考にブレッドボードに差し込んでください。フォトリフレクタは45度カットされた角の位置に注意してください。カットされた角が右上の場合、フォトリフレクタの左半分が赤外線LED、右半分がフォトトランジスタです。赤外線LED側(左側)の抵抗器は150Ω、フォトトランジスタ側(右側)は10kΩです。抵抗器に極性はないので向きはどちらでも構いません。ジャンパワイヤは固く真っ直ぐなタイプを使うとスッキリします。ジャンパワイヤの色は何色でも構いませんが、配線図では分かりやすように電源(5V)は赤、グランド(GND)は黒を使う事が多いです。
手順3:振動モータ
振動モータのリード線の皮膜を1cmほど剥き、ブレッドボードに差し込みます。線が細く差し込みにくい場合は、抵抗の足を切り離した端材などをリード線にハンダ付けしてください。振動モータを両面テープでブレッドボードにしっかりと固定してください。この振動モータの標準電圧は3V、標準電流は55mA、電源はArduinoからの5Vなので、(5v – 3v) / 0.055A = 36.4Ωとなり、使用する抵抗器は39Ωです。
手順4:配線
Arduino UNOの上に乗せたセンサシールドとブレッドボードをジャンパワイヤで接続します。箱に収めた時にジャンパワイヤが邪魔になる場合は、先端のピンを90度曲げるとスッキリまとまります。
3. Arduinoのプログラム
それではArduinoのプログラムについて見ていきましょう。今回必要となる機能は次の4点です。
- 加速度センサモジュールから値を読み取る
- フォトリフレクタの値を読み取る
- 読み取ったセンサの値をシリアル通信で送る
- Unityから送られてきたコマンドを受け取り処理する
それぞれの機能を説明したあとで、プログラム全体を掲載します。
加速度センサモジュールから値を読み取る
加速度センサモジュール「KX224-1053」との通信をするために、専用のライブラリを使用します。まず、製品紹介のページのソフトウェアの項目からZIPファイルをダウンロードしてください。次に、Arduino IDEのメニューの[スケッチ] > [ライブラリをインクルード] > [.ZIP形式のライブラリをインストール]を選択し、ダウンロードしたZIPファイルを選んでください。またこのページからはマニュアルもダウンロードできるので、参考にしてください。
Arduinoのプログラムでは、まずI2Cライブラリと加速度センサモジュールのライブラリを読み込みます。
そしてKX224クラスのオブジェクトを生成します。このオブジェクトから加速度センサの値を読み取ることができます。
1 2 3 | #include <Wire.h>//I2Cライブラリ #include <KX224_I2C.h>//加速度センサーライブラリ KX224 kx224(KX224_DEVICE_ADDRESS_1E); //加速度センサーのオブジェクト生成 |
setup関数の中ではI2Cライブラリの起動とKX224オブジェクトの初期化をおこない、失敗したらシリアル通信でメッセージを送ります。
1 2 3 4 5 6 7 8 | byte rc; //起動チェック用変数 Wire.begin(); //I2Cライブラリ開始 rc = kx224.init(); //加速度センサーオブジェクトの初期化 if (rc != 0) { //加速度センサーオブジェクトの起動チェック Serial.println(F( "KX224 initialization failed" )); Serial.flush(); } |
KX224オブジェクトのget_val関数にfloatの配列を渡すとセンサの値が入ります。戻り値が0なら読み取り成功です。
1 2 3 | byte rc; //センサーの読み取り確認用。 float acc[3]; // rc = kx224.get_val(acc); //accに加速度を代入し、読み取りできていれば0を返す。 |
フォトリフレクタの値を読み取る
フォトリフレクタはA0、A1ピンに接続し、analogRead関数で読み取ります。箱の裏のマーカーは白と黒ですが、アナログで読み取り閾値をUnityのソフトウェアで変更します。
1 2 | int photoRef1 = analogRead(A0); //フォトリフレクターの読み取り int photoRef2 = analogRead(A1); |
読み取ったセンサの値をシリアル通信で送る
加速度センサの3つの値と、2つのフォトリフレクタの値をカンマ区切りの文字列として送信します。最後に改行コードを送ります。Unityは受け取った文字列をカンマ区切りで配列に戻して使用します。
01 02 03 04 05 06 07 08 09 10 | Serial.print(acc[0]); //X軸 Serial.print( "," ); Serial.print(acc[1]); //Y軸 Serial.print( "," ); Serial.print(acc[2]); //Z軸 Serial.print( "," ); Serial.print(photoRef1); //フォトリフレクタ1 Serial.print( "," ); Serial.print(photoRef2); //フォトリフレクタ2 Serial.println( "" ); |
Unityから送られてきたコマンドを受け取り処理する
Unityからコマンドが送られた時に、シリアル通信の受信イベントが実行されます。受け取った文字列を連結していき、改行コードが来たら受信完了フラグをTrueにします。
1 2 3 4 5 6 7 8 9 | void serialEvent() { //シリアル通信を受信したイベント while (Serial.available()) { char inChar = ( char )Serial.read(); // 受信データを文字列に変換する inputString += inChar; // inputStringに付け足す if (inChar == '\n' ) { // 改行コードを受け取ったら、受信完了フラグを立てる stringComplete = true ; } } } |
loop関数の中で受信完了フラグをチェックし、Trueならコマンドの中身を調べて、対応した処理をおこないます。今回は「start」という文字列なら振動モータを動かし、「stop」なら止めます。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 | if (stringComplete) { //受信完了のフラグが立っていた場合の処理 String is = inputString; //受信文字列のコピーを作る is.trim(); //改行コードを削除 if ( is.equals( "start" ) ) //startを受信したら { digitalWrite(2, HIGH); //モーターを動かす } if ( is.equals( "stop" ) ) //stopを受信したら { digitalWrite(2, LOW); //モーターを止める } inputString = "" ; //受信文字列をクリア stringComplete = false ; //受信フラグをクリア } |
スケッチ全体
下記のソースコードをArduino IDEに入力して、Arduino UNOに書き込んでください。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | #include <Wire.h>//I2Cライブラリ #include <KX224_I2C.h>//加速度センサーライブラリ KX224 kx224(KX224_DEVICE_ADDRESS_1E); //加速度センサーのオブジェクト生成 String inputString = "" ; //受信データを保持する変数 bool stringComplete = false ; //受信を完了したかどうかのフラグ void setup() { byte rc; Serial.begin(57600); //シリアル通信開始 while (!Serial); Wire.begin(); //I2Cライブラリ開始 rc = kx224.init(); //加速度センサーオブジェクトの初期化 if (rc != 0) { //加速度センサーオブジェクトの起動チェック Serial.println(F( "KX224 initialization failed" )); Serial.flush(); } pinMode(2, OUTPUT); pinMode(A0, INPUT); pinMode(A1, INPUT); } void loop() { // ============================================ // 加速度センサーの読み取りと送信 // ============================================ byte rc; //センサーの読み取り確認用。 float acc[3]; // int photoRef1 = analogRead(A0); //フォトリフレクターのよみとり int photoRef2 = analogRead(A1); rc = kx224.get_val(acc); //accに加速度を代入し、読み取りできていれば0を返す。 if (rc == 0) { Serial.print(acc[0]); //X軸 Serial.print( "," ); Serial.print(acc[1]); //Y軸 Serial.print( "," ); Serial.print(acc[2]); //Z軸 Serial.print( "," ); Serial.print(photoRef1); //フォトリフレクタ1 Serial.print( "," ); Serial.print(photoRef2); //フォトリフレクタ2 Serial.println( "" ); } // ============================================ // 受信したコマンドの処理 // ============================================ if (stringComplete) { //受信完了のフラグが立っていた場合の処理 String is = inputString; //受信文字列のコピーを作る is.trim(); //改行コードを削除 if ( is.equals( "start" ) ) //startを受信したら { digitalWrite(2, HIGH); //モーターを動かす } if ( is.equals( "stop" ) ) //stopを受信したら { digitalWrite(2, LOW); //モーターを止める } inputString = "" ; //受信文字列をクリア stringComplete = false ; //受信フラグをクリア } delay(10); } // ============================================ // シリアル通信の受信 // ============================================ void serialEvent() { //シリアル通信を受信したイベント while (Serial.available()) { char inChar = ( char )Serial.read(); // 受信データを文字列に変換する inputString += inChar; // inputStringに付け足す if (inChar == '\n' ) { // 改行コードを受け取ったら、受信完了フラグを立てる stringComplete = true ; } } } |
動作テスト
電子回路とArduinoのプログラムができたので、動作を確認してみましょう。Arduino UNOとPCをUSBケーブルで接続してから、Arduino IDEのシリアルモニタを開き、通信速度を57600bpsに設定してください。初めに「KX224_WHO_AMI Register Value = 0x2B」というメッセージが表示され、次の行からカンマ区切りで5つの数字が流れていきます。
前半の3つは加速度センサモジュールのX,Y,Zの値です。センサモジュールが水平に置かれていると、XとYは0、Zは1が出力されています。傾けると-1~1の範囲で値が変化します。Arduino UNOを傾けて値の変化を確認してください。
後半の2つの数値はフォトリフレクタです。近くに何もない状態では1桁の数値が出力され、5mm程度まで物が近づくと500を超える値になります。指などで実際に反応を確かめてみてください。
続いてコマンドを受け取って振動モータが動作するかチェックします。シリアルモニタの入力欄に「start」と入力しエンターキーを押してください。振動モータが動作すれば成功です。動作しない場合は、ブレッドボードの配線、プログラムのコマンドの受信している箇所に間違いがないかよく確認してください。今度は「stop」と入力して停止することを確認してください。
加速度センサモジュール、フォトリフレクタ、振動モータの動作を確認できたら、前編は完了です。みなさんお疲れ様でした!後編では、いよいよ実物の迷路を作成し、Unityで3D迷路を作っていきます。お楽しみに!
今回の連載の流れ
前編:Arduinoと加速度センサで作るデジタルボール転がし迷路(今回)
後編:Arduinoと加速度センサで作るデジタルボール転がし迷路