openFrameworks x Arduino #001 from Takepepe on Vimeo.
そろそろこのアバターの格好で記事投稿するのが辛くなり始める今日この頃。
皆様いかがお過ごしでしょうか。
今回はopenFrameworksをArduinoでコントロールするネタです。(Arduinoはほぼオマケですが…)
動画ではひらひら揺らめく面と、再生している音楽が同期しています。
赤外線センサーに手を近づけて、面の揺らめきと音楽のスピード・音量をコントロールします。
ArduinoはINとOUTを備えたマイコンボードの統合開発環境です。
一般的なPCやガジェットには無いセンサーをコンテンツに取り込むだけでなく、
LED、モーターや家電のコントロールも出来る素敵インターフェースです。
Arduino http://www.arduino.cc/
Arduinoはボードにプログラムを書き込み、電源を供給すればスタンドアロンでも動かす事ができます。
Processing・openFrameworksでも簡単に相互通信できるAPIが用意されています。
とても面白いプラットフォームなのでいろんな記事を調べてみてください。
いつもの様に制作過程の流れで説明していきます。
- Arduinoボードの設定
- openFrameworksとArduinoをつなぐ
- ofxSimpleGuiTooを追加
- 3D空間にofCircleを描く
- PerlinNoiseでゆらゆら
- 音楽を再生
- Arduinoの値を摘要
1.Arduinoボードの設定
今回のインスタレーションでは赤外線測距モジュール(GP2Y0A21)を使っています。
参考というか、出版されている書籍に載っているものをそのままですw
「5章 レシピ2:距離を測りたい」
Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ
http://www.oreilly.co.jp/books/9784873114538/
まずは下記回路図の様にArduinoを組み立てます。
赤外線センサーから値が取れていることを確認します。
以下のスケッチでは距離がcm単位でSerialに出力されます。
OA001.ino
// アナログピン0番 const int sensorPin = 0; // 閾値 const int threshold = 80; void setup(){ // 接続速度の設定 Serial.begin(9600); } void loop(){ int value = analogRead(sensorPin); if(value > threshold){ // cm単位に変換 float range = (6787 / (value -3)) -4; Serial.println(range+"cm"); } }
2.openFrameworksとArduinoをつなぐ
openFrameworksで値を取得する行程に入りますが、Arduinoでは先程のスケッチは使用しません。
ArduinoボードにはStandardFirmataを書き込んでおきます。
StandardFirmataは、色んなプラットフォームとArduinoを繋ぐものです。
StandardFirmataのインストール方法とArduinoへの書き込み方法については割愛します。
openFrameworksのコードに移ります。
OA001.h
class OA001 : public ofBaseApp{ public: void setup(); void draw(); private : ofArduino ard; float ardValue; float distance; void setupArduino(const int & version); void analogPinChanged(const int & pinNum); }
OA001.cpp
// Arduinoとの接続速度 #define SPEED 57600 //-------------------------------------------------------------- void OA001::setup(){ // Arduinoに接続 ard.connect("/dev/cu.usbmodemfd321", SPEED); ofAddListener(ard.EInitialized, this, &OA001::setupArduino); } //-------------------------------------------------------------- void OA001::setupArduino(const int & version) { // イベントリスナ削除 ofRemoveListener(ard.EInitialized, this, &OA001::setupArduino); // アナログピン0番からのレポートを取得 ard.sendAnalogPinReporting(0, ARD_ANALOG); ofAddListener(ard.EAnalogPinChanged, this, &OA001::analogPinChanged); //cout << ard.getFirmwareName() << endl; //cout << "firmata v" << ard.getMajorFirmwareVersion() << "." << ard.getMinorFirmwareVersion() << endl; } //-------------------------------------------------------------- void OA001::analogPinChanged(const int & pinNum) { int value = ard.getAnalog(pinNum); cout << value << endl; } //-------------------------------------------------------------- void OA001::update(){ // Arduinoを更新 ard.update(); }
コンソールにセンサー値が出力されたら接続成功です。
このセンサー値は近くに何も無い場合、150以下で推移、最も手を近づけた時600強の値が出ます。
純粋なセンサー値とは別に、この回で使用しているローパスフィルターをかけながら
distanceに変換後の値を入れていきます。
OA001.cpp
void OA001::analogPinChanged(const int & pinNum) { // そのままのセンサー値を格納 ardValue = ard.getAnalog(pinNum); // センサー値を調整して格納 if(ardValue < 100){ distance = 100; }else if(ardValue > 700){ distance = 700; }else{ // ローパスフィルターを摘要 distance = distance*0.9+ardValue*0.1; } }
ここまででArduinoについて分からない場合は田所先生の講義資料を見て勉強してみてください。
本当に素晴らしい講義資料ばかりを公開していただいています。感謝!
yoppa.org 「第9回:openFrameworksとArduinoを連携する」
http://yoppa.org/ma2_11/3383.html
3.ofxSimpleGuiTooを追加
開発を進めるにあたり、アドオンのofxSimpleGuiTooを使います。
とても便利で、作品を作るにあたり開発効率が良くなるので早期に取り入れます。
先程取得したセンサー値も、簡単に視覚化することが出来ます。
筆者はmemoさんのバージョンを使っています。
ofxSimpleGuiToo
https://github.com/memo/ofxSimpleGuiToo
OA001.h
class OA001 : public ofBaseApp{ public: void setup(); void draw(); private : ofxSimpleGuiToo gui; void setupGUI(); }
OA001.cpp
void OA001::setup(){ // ofxSimpleGuiTooをセットアップ setupGUI(); } //-------------------------------------------------------------- void OA001::setupGUI() { gui.setup(); // GUIの見た目を設定 gui.config->textColor = 0xFFFFFF; gui.config->buttonHeight = 20; gui.config->sliderHeight = 10; gui.config->titleHeight = 20; gui.config->fullActiveColor = 0x00aec3; // Arduinoのセンサー値 gui.addTitle("ARDUINO"); gui.addSlider("ardValue", ardValue, 0.0f, 700.0f); gui.addSlider("distance", distance, 0.0f, 700.0f); // 前回終了した時の設定で起動 gui.loadFromXML(); // 最初から表示させる gui.show(); } //-------------------------------------------------------------- void OA001::draw(){ // ofxSimpleGuiTooを描画 gui.draw(); }
4.3D空間にofCircleを描く
まずは縦横100個のofCircleを画面のセンターに表示させます。
ofRotateYとかに適当に値を入れると、3D空間にofCircleが描かれているのが確認出来ます。
OA001.h
class OA001 : public ofBaseApp{ public: void setup(); void draw(); private : float rotateX; float rotateY; float rotateZ; int count; float margin; float radius; int color; int alpha; }
OA001.cpp
void OA001::setup(){ // 画面全体の回転値を初期化 rotateX = 0.0f; rotateY = 0.0f; rotateZ = 0.0f; // ofCircleで使用する値を初期化 count = 100; margin = 25.0f; radius = 5.0f; color = 255; alpha = 255; } //-------------------------------------------------------------- void OA001::draw(){ // この段階のMatrixを保持 ofPushMatrix(); // 画面センターに移動 ofTranslate(ofGetWidth()/2, ofGetHeight()/2); // 画面全体の回転値を摘要 ofRotateX(rotateX); ofRotateY(rotateY); ofRotateZ(rotateZ); // ofCircleの描画 int totalLen = (count-1)*margin; ofTranslate(totalLen/-2, totalLen/-2); ofSetColor(color, color, color, alpha); for(int i=0; i<count; i++){ for(int j=0; j<count; j++){ ofCircle(i*margin, j*margin, 0, radius); } } // 保持したMatrixに戻す ofPopMatrix(); }
5.PerlinNoiseでゆらゆら
ofNoiseはパターン化されたランダム値を取得する事が出来ます。
ofNoiseからPerlinNoiseを取得するために以下記事を参考にしました。
Noise – 【oF】openFrameworks
https://sites.google.com/site/ofauckland/examples/noise
このPerlinNoiseで得たグレースケール値を、ofCircleの奥行きに摘要していきます。
先程と同じ箇所を改変します。
OA001.cpp
void OA001::draw(){ // この段階のMatrixを保持 ofPushMatrix(); // 画面センターに移動 ofTranslate(ofGetWidth()/2, ofGetHeight()/2); // 画面全体の回転値を摘要 ofRotateX(rotateX); ofRotateY(rotateY); ofRotateZ(rotateZ); // ofCircleの描画 int totalLen = (count-1)*margin; ofTranslate(totalLen/-2, totalLen/-2); ofSetColor(color.r*255, color.g*255, color.b*255, alpha); for(int i=0; i<count; i++){ for(int j=0; j<count; j++){ float a = i * xForce; float b = j * yForce; float c = ofGetFrameNum() / 60.0; float noise = ofNoise(a,b,c) * zForce; ofCircle(i*margin, j*margin, noise, radius); } } // 保持したMatrixに戻す ofPopMatrix(); }
ここまでの様子は以下の様になります。
ofxSimpleGuiTooで各パラメーターを操作して遊んでみます。
画面収録している分フレームレートが落ちていますが、実際は60fpsで動きます。
openFrameworks x Arduino #001( Process ) from Takepepe on Vimeo.
6.音楽を再生
ofSoundPlayerで音楽を取り込みます。
openFrameworksで音楽をコントロールする、恐らく最も簡単な方法です。
ofSoundPlayerのボリュームをPerlinNoiseに係数として与えることで、
音に併せて揺らめきが変わることが確認出来ます。
OA001.h
class OA001 : public ofBaseApp{ public: void setup(); private : ofSoundPlayer mySound; float speed; float volume; void setupMusic(); }
OA001.cpp
void OA001::setupMusic() { // 音楽を読み込んでループ再生 mySound.loadSound("sound.wav"); mySound.setLoop(true); mySound.play(); } //-------------------------------------------------------------- void OA001::update(){ // ofSoundPlayerを設定 mySound.setSpeed(speed); mySound.setVolume(volume); }
7.Arduinoの値を摘要
冒頭で取得したArduinoの値をofMapで音楽の音量・スピードに摘要すれば完成です!
OA001.cpp
void OA001::update(){ // Arduinoのセンサー値をofSoundPlayerの設定値に変換 speed = ofMap(distance, 150, 600, 0.1f, 3.0f); volume = ofMap(distance, 150, 600, 0.1f, 1.0f); // ofSoundPlayerを設定 mySound.setSpeed(speed); mySound.setVolume(volume); }