文書の過去の版を表示しています。
基礎ゼミサポートページ
ここは基礎ゼミのサポートページです.制作,ワークショップなどの情報がこのページと同期しています.授業中もこのページを開きながら作業することをおすすめします. 課題などの提出物はkibacoを利用しますので,ご注意ください.
Arduinoを使ってみる
Arduinoとはマイクロコントローラーと周辺機器がセットになった小型コンピュータのなかで,一般開発ユーザにとって最もメジャーな開発基板の一つです. この授業ではArduinoを利用して,実際にハードウェア,ソフトウェアプログラミングを体験し,PCインタフェースを創ることを目標としています.ではまず Arduinoを実際に使ってみましょう.実はArduinoにはたくさんの種類があり,この授業ではArduino Microと呼ばれるものを使います.
Arduino(ソフトウェア)のインストール
Arduino公式ウェブサイトのソフトウェアページから自身の環境に 合わせたアプリケーションをダウンロードしてください.
ダウンロードに関する注意事項
この記事の執筆時点(平成29年4月19日)では最新バージョンは1.8.2になっています.ダウンロードする際,「Support the Arduino Software」なるページで,寄付支援をするかどうかを聞かれます.Arduinoを支援したい方は金額を選び,Contributeしてください.今回はみなさん初めてArduinoを使うと思いますので,今回は下記の画像で赤丸でくくった箇所の「Just Download」を選択して,アプリケーションをダウンロードしてください. http://tetsuakibaba.jp/workshop/kisozemi/contribute.png
Windowsの注意事項
Windowsの場合:Windows Installerをダウンロード後,ダブルクリックでインストールを開始してください. インストールの途中,下の画像のように,USB Driverの項目にチェックが入っていることを確認し,チェックが入っていなければ必ずチェックを入れた上でインストールを行って下さい.Windows app形式やzipファイルでダウンロードすることはしないでください. https://www.arduino.cc/en/uploads/Guide/DRV_Capture1.png
Mac OSXの注意事項
特にありませんが,Mac OS X 10.7 Lion or newerをダウンロード後,展開されたArduino.appをアプリケーション等に移動し,起動を確認してください.
Arduinoの起動確認
実際にインストール手続きが終わったら,Arduinoを起動して,下記のようなエディタ画面が表示されるかどうかを確認してください.ここまででArduinoが起動しない場合は,もう一度インストール手続きを行ってみて下さい.念のためofficialのインストールマニュアルへのリンクも確認してください.
- オフィシャルのインストールガイド
Arduinoボードを使ってみる
それではソフトウェアの準備ができたので,Arduinoのボードを使ってみます.この授業ではArduino Microと呼ばれるものを使います.まずは下記に従って,テストプログラムを動かしてみます.
- Arduino MicroとPCをUSBケーブルで接続する
- Arduino ソフトウェアを起動する
- 「Arduinoソフトウェアメニュー」→「ツール」→「ボード:Arduino/Genuino Micro」を選択
- 「Arduinoソフトウェアメニュー」→「ツール」→「シリアルポート:」の中にある括弧書きでArduino Microと書かれた行を選択.
- Arduinoソフトウェアメニュー→「ファイル」→「スケッチブックの例」→「01.Basic」→「Blink」を選択
- Arduinoソフトウェアメニュー→「スケッチ」→「マイコンボードに書き込む」を選択
以上の手続きを終えた後,Arduino Micro上のLEDが1秒おきに点滅を始めればOKです.
プログラム入門
すでにLEDの点滅に関して上記で確認していますが,改めてプログラムを記述してみます.LEDを一秒おきに点滅させるプログラムは下記のようになります.
Hello LED
// Hello LED!! (LEDを点滅させるプログラム) void setup() { pinMode(13, OUTPUT); } void loop() { digitalWrite(13, HIGH); delay(1000); digitalWrite(13, LOW); delay(1000); }
ArduinoではC言語と呼ばれるプログラム記述方法を利用します.またC言語の一つ上の機能であるC++にも一部対応しているため,ある程度の複雑なプログラムを記述することも可能です.上記の例では2つの関数(setup, loop)の中に幾つかの命令文を記述しています.関数とは一定量の命令記述をまとめたものです.今回記述されているものは全て関数になっています.setup, loopは関数の定義を記述しており,pinMode, digitalWRite, delayに関してはすでに定義済みの関数を呼び出して命令を実行しています.それぞれの関数についてはArduinoのReferenceを参考にすることができます.下記にリンクを貼っておきます.これから新しい関数が登場した場合は,Arduino Referenceページでまずは確認してください.
なお,setup, loopの定義済み関数(the function)についてですが,こちらもArduino Referenceページに説明があります.自身で確認してください.簡単にいうと下記のとおりです.
- setup: Arduinoの起動時に一回だけ呼び出される関数
- loop: setupの後に呼び出される関数で,関数内の記述を実行し終わると,再度呼び出されて再帰的にループを実現している
変数を使う,確認する
上記では関数を利用していましたが,次に変数を利用してみます.まずは下記のプログラムを実行してみます.
// 変数を1ずつ増やし(インクリメント),PCで値を確認する void setup() { Serial.begin(9600); } int count = 0; void loop() { Serial.println(count); count = count + 1; delay(1000); }
int count = 0; というのが変数を宣言している箇所です.ここでは count という名前の整数型の変数を一つ準備しました.初期値を0としています.これをloopごとに1ずつ増やしています.Serialというものが出てきましたが,これはクラスになります.クラスとはC++における機能で,変数や関数をひとまとめにして,使いやすくするための機能です.この場合Serialという定義済みクラスを利用して,PCへcountの変数を送信しています.実際に上記プログラムを書き込んでもなにも変化が起きません.そこでArduinoメニューから「ツール」→「シリアルモニタ」を選択してください.するとcountの変数が1秒おきに表示されます.SerialとはPCにおける通信規格で,今回はArduino側から通信用のクラスを利用して,PCに文字列や変数などのデータを送信するプログラムになっています.
加速度センサの値を読み込む
みなさんにお配りしたArduino Microにはチップ(32u4)の上に加速度センサ(ADXL335)が載っていて,それぞれ下記のように接続されています.
- x軸:A4
- y軸:A3
- z軸:A2
- 加速度センサ電源:3pin
- 加速度センサグランド:23pin
そこで,各加速度値を読み取り,Arduino のシリアルモニタにて値を確認してみましょう.3pinをHigh,23pinをLOWにすることで,加速度センサの電源供給を行い,analogReadを利用して値を読み取っています.
// 加速度センサの値を読み,各値をシリアルモニタに出力するプログラム void setup() { Serial.begin(9600); pinMode(3, OUTPUT); pinMode(23, OUTPUT); digitalWrite(3, HIGH); digitalWrite(23, LOW); } int count = 0; void loop() { int x,y,z; x = analogRead(4); y = analogRead(3); z = analogRead(2); Serial.print(x); Serial.print(","); Serial.print(y); Serial.print(","); Serial.println(z); delay(100); }
加速度センサの情報からクリック操作を行う
この回では,加速度センサだけでまずはクリックを実装してみます.arduinoを手で持ち,クリックするように叩くと,各x,y,z軸の値が変化をします.これをうまく処理して,クリックとして扱いたいと思います.すでに加速度センサの値は観測してみたとおり,1023/2を中心として正方向の加速度はプラス(1023/2 - 1023),負の方向にはマイナス(0-1023/2)に値が変化します.つまりタップ動作が行われた場合も値は下がったり,上がったりしてしまいます.そこでこれらの状況を無視でき,且つどの軸に加速度が加わってもその変化量だけを取得する計算をしたいと思います.そこで3次元のユークリッド距離を考えてみます.x,y,zのそれぞれの値はセンサの更新時間(単位時間)ごとに値が変化する3次元ベクトルであり,各単位時間でどれだけベクトル値が変化したかどうかをみる一つの目安として,各ベクトルの距離を計算すればよいです.
時間をt,センサ更新速度を単位時間として,それぞれ,\( dx, dy, dz \) を考えると.下記の式で距離計算ができます. $$ a = \sqrt{(\frac{dx}{dt})^2+(\frac{dy}{dt})^2+(\frac{dz}{dt})^2} $$
では実際に上記計算式でプログラムを記述してみます.今回はクリックの感度(しきい値)を100,500[ms]をクリック反応後のキャンセリング時間としています
/* 加速度センサの値を処理し,各軸の単位時間あたりの変化量を値とした3次元ユークリッド距離を計算し,その値が閾値を超えたときにクリック動作を行うプログラム */ #include "Mouse.h" void setup() { Serial.begin(9600); pinMode(3, OUTPUT); pinMode(23, OUTPUT); digitalWrite(3, HIGH); digitalWrite(23, LOW); Mouse.begin(); } int count = 0; int x_prev, y_prev, z_prev; void loop() { int x,y,z; x = analogRead(4); y = analogRead(3); z = analogRead(2); int a; a = pow(x-x_prev, 2)+pow(y-y_prev, 2)+pow(z-z_prev,2); a = sqrt(a); if( a > 100 ){ Serial.println("Click!!"); Mouse.click(MOUSE_LEFT); delay(500); } x_prev = x; y_prev = y; z_prev = z; delay(10); }
加速度センサの情報からマウス移動を行う
マウスのクリックができるようになったので,次はポインタの移動に挑戦します.マウスクリックは Mouse.press(Mouse_LEFT); で実現できました.ポインタの移動の場合は同じようなやり方で,Mouse.move(x,y,w);を利用します.一般的なパソコン画面上ではx,yだけですが,マウスのスクロールを機能させるために,w(Wheel)のパラメータが用意されています.スクロール操作を行いたい場合は,wのパラメータを指定してください.今回は利用しないので0をいれておきます.
/* Arduino Mircoを傾けるとマウスポインタが上下左右に1ずつ移動するプログラム */ #include "Mouse.h" void setup() { Serial.begin(9600); pinMode(3, OUTPUT); pinMode(23, OUTPUT); digitalWrite(3, HIGH); digitalWrite(23, LOW); Mouse.begin(); } int count = 0; int x_prev, y_prev, z_prev; void loop() { int x,y,z; x = analogRead(4); y = analogRead(3); z = analogRead(2); int a; a = pow(x-x_prev, 2)+pow(y-y_prev, 2)+pow(z-z_prev,2); a = sqrt(a); // Click if( a > 100 ){ Serial.println("Click!!"); Mouse.click(MOUSE_LEFT); delay(500); } // Move if( x > 550 ){ Mouse.move(-1, 0, 0); } else if( x < 450 ){ Mouse.move(1, 0, 0); } if( y > 550 ){ Mouse.move(0, 1, 0 ); } else if( y < 450 ){ Mouse.move(0, -1, 0); } Serial.print(x); Serial.print(","); Serial.print(y); Serial.print(","); Serial.println(z); x_prev = x; y_prev = y; z_prev = z; delay(10); }
/* 上記例を応用して,よりポインティング作業がよくなるようなプログラムを作成せよ */ #include "Mouse.h" void setup() { Serial.begin(9600); pinMode(3, OUTPUT); pinMode(23, OUTPUT); digitalWrite(3, HIGH); digitalWrite(23, LOW); Mouse.begin(); } int count = 0; int x_prev, y_prev, z_prev; void loop() { int x,y,z; x = analogRead(4); y = analogRead(3); z = analogRead(2); int a; a = pow(x-x_prev, 2)+pow(y-y_prev, 2)+pow(z-z_prev,2); a = sqrt(a); // Click if( a > 100 ){ Serial.println("Click!!"); Mouse.click(MOUSE_LEFT); delay(500); } // Move Mouse.move((505-x)/5, (y-509)/5, 0); Serial.print(x); Serial.print(","); Serial.print(y); Serial.print(","); Serial.println(z); x_prev = x; y_prev = y; z_prev = z; delay(10); }
PONGで高得点を目指す
Pong Game(ブラウザ上でPongが楽しめます)を自作した加速度マウスポインタを利用して高得点が取れるようにプログラムを修正してみましょう.
Processingとの連携
ここまで主にArduinoを対象に説明を行ってきました。一方でArduinoから得られたデータをコーンピュータに送信し、ゲームをしたり、映像、音を操作することもよくあります。プロトタイピングをする際、なにか一つのデバイスを制作するとします。例として、デバイスを振ると音がなるデバイスを考えてみましょう。Arduinoと複数の音声再生モジュールやスピーカを組み合わせることで、デバイス単体でこのような機能を再現することは可能ですが、ハードウェアに知識や必要なモジュールを買い揃える必要があります。プロトタイプの段階ではまず動作させ、体験価値を作り出すことが重要です。そこでよく用いられる手法はセンシング部分だけはArduinoを利用し、その他の処理は全てPCで行います。例えばArduinoからは加速度センサの値だけを出力し、Processing側でその値を処理し、音声再生をおこなうプログラムを作成することで、ハードウェアにかける時間を最低限にし、ソフトウェア場で基本的な体験が可能になるわけです。
ArduinoとPCを連携させるのに手軽なソフトウェアとしてProcessingがあります。ここではProcessingを通じてPCとArduinoを連携させてみます。Processingはプログラムを学習する上で効率的なプログラミング環境を構築しています。ぜひ下記で自習してみてください。
加速度センサの値をPC上で取得する
プログラムの基礎、Processingの可能性を体験したところで、Processingを使ってArduino上の加速度センサの値を読めるようにします。ArduinoとProcessingのデータやりとりにはシリアル通信を利用します。シリアル通信を使う場合、まずArduino上で次のプログラムを記述しておきます。
// 加速度センサの値を読み,x値だけをシリアル送信するプログラム void setup() { Serial.begin(9600); pinMode(3, OUTPUT); pinMode(23, OUTPUT); digitalWrite(3, HIGH); digitalWrite(23, LOW); } int count = 0; void loop() { int x,y,z; x = analogRead(4); y = analogRead(3); z = analogRead(2); x = map(x, 0, 1023, 0,99); // x値の範囲を 0-1023から0-99へ変更 Serial.write(x); delay(30); }
// では次はProcessing側の準備です。次の例はシリアルデータを読み取り、画面上にその値を表示し、値に応じて円の直径を変化させてみます。 import processing.serial.*; Serial myPort; // Create object from Serial class int val; // Data received from the serial port void setup() { size(500,500); String portName = Serial.list()[0]; println(Serial.list()); // Change the portname as your PC myPort = new Serial(this, "/dev/tty.usbmodem14321", 9600); } void draw(){ background(255); if ( myPort.available() > 0) { // If data is available, val = myPort.read(); // read it and store it in val } text(val, 20,20); noStroke(); fill(34,150,90); ellipse(width/2, height/2, val,val); }
x,y,zの送信
さあ、これでArduinoからのデータを受け取ることができました。しかしまだxの値のみです。そこでy, zの値も同様にしてPCに送信したいと思います。しかし実際にこのやり方では問題が生じます。ArduinoからPCへ値を送信した場合に、そのデータがx,y,zのどの値なのかが分からなければなりません。そこでデータの送信形式(フォーマット)を事前に決めておく必要があります。
// Arduino void setup() { Serial.begin(9600); pinMode(3, OUTPUT); pinMode(23, OUTPUT); digitalWrite(3, HIGH); digitalWrite(23, LOW); } int count = 0; void loop() { int x,y,z; x = analogRead(4); y = analogRead(3); z = analogRead(2); x = map(x, 0, 1023, 0,99); // x値の範囲を 0-1023から0-99へ変更 y = map(y, 0, 1023, 0,99); z = map(z, 0, 1023, 0,99); Serial.write(100); Serial.write(x); Serial.write(y); Serial.write(z); delay(30); }
// Processing import processing.serial.*; Serial myPort; // Create object from Serial class int val; // Data received from the serial port void setup() { size(500,500); String portName = Serial.list()[0]; println(Serial.list()); // Change the portname as your PC myPort = new Serial(this, "/dev/tty.usbmodem14321", 9600); } int x,y,z; void draw(){ background(255); while( myPort.available() > 4) { // If data is available, val = myPort.read(); if( val == 100 ){ x = myPort.read(); y = myPort.read(); z = myPort.read(); } } text(x, 20,20); text(y, 20,40); text(z, 20,60); noStroke(); fill(34,150,90); ellipse(width/2, height/2, val,val); }
論文を書いてみよう
https://www.jstage.jst.go.jp/article/jssd/58/0/58_0_86/_article/-char/ja/
// Tetsuaki Baba // Processing のサンプルコード // str_format: データ名をカンマ区切りで書いておく PrintWriter output; boolean flg_start = false; String str_format = "time"; int count = 0; float x, y; int time_start; void setup() { pixelDensity(displayDensity()); size(800, 600); x = random(25, width-25); y = random(25, height-25); } void draw() { background(0); if ( flg_start == false ) { text("Press space key to start", width/2, height/2); return; } if ( sqrt( (x-mouseX)*(x-mouseX) + (y-mouseY)*(y-mouseY) ) < 25 ) { x = random(25, width-25); y = random(25, height-25); output.print(str(millis()-time_start)+"\n"); time_start = millis(); count++; if ( count == 10 ) { flg_start = false; output.flush(); output.close(); } } ellipse(x, y, 50, 50); println(millis()); } void keyPressed() { if ( key == ' ' ) { flg_start = !flg_start; time_start = millis(); count = 0; if ( flg_start == true ) { String filename = nf(year(), 4) + nf(month(), 2) + nf(day(), 2) + nf(hour(), 2) + nf(minute(), 2) ; output = createWriter( filename + ".csv"); output.println( str_format ); } } }