Arduinoは単体で開発してもとても面白いデバイスだということが、これまでいろいろなパーツやシールドを利用した例を紹介してきて見ていただいている方は、十分に感じているかとは思います。さらに一歩進んで、今回は、OSC通信という通信方法を利用して、Arduinoを外部のアプリケーションと通信連携する方法を試してみたいと思います。外部アプリケーションと連携することで、スイッチやボリュームなどの電子部品からのアクションを通じて、ビジュアル言語で画面を操作するなど、表現の幅がぐんっと広がることになります!
今回の電子工作レシピ
時間目安:90分
必要なパーツ
- Arduino本体(Arduino UNO)http://www.switch-science.com/catalog/789/
- ブレッドボード http://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=3DBC-TCK4
- 温湿度センサ(DHT11) http://akizukidenshi.com/catalog/g/gM-07003/
- 抵抗器(10KΩ)
OSC通信ってなんだろう?
OSC通信とはどのような通信方式なのでしょうか?wikipediaで調べてみると…
Open Sound Control – wikipedia
OpenSound Control(OSC)とは、電子楽器(特にシンセサイザー)やコンピュータなどの機器において音楽演奏データをネットワーク経由でリアルタイムに共有するための通信プロトコルである。カリフォルニア大学バークレー校にある CNMAT(The Center for New Music and Audio Technologies)が開発した。
音楽演奏データをやりとりする目的で開発された通信方式ということがわかりました。音楽演奏データ通信といえば、聞いたことがある方も多いかもしれませんが、MIDI(Musical Instrument Digital Interface)が有名ですね。このMIDIは、1982年とはるか昔に開発されたこともあり、通信速度が低かったり、リアルタイム性に向いていないなどの理由から、昨今ではOSCが利用されるようになってきています。
では、なぜ今回音楽を扱うわけでもないのに、ArduinoでOSC通信なのでしょうか。実はこのOSC通信はその通信の柔軟さなどから音楽データ通信以外にもさまざまなケースに利用されるようになってきており、多くのソフトウェアでもOSCに対応したものが出てきています。
OSCのしくみ
さっそくOSCのしくみについて学んでいきましょう。OSCはとてもシンプルな構成です。OSCには大きく2つの種類のメッセージがあり、そのメッセージをアプリ間でやりとりしながら通信を行います。

図1 OSC通信の仕様
- Message : メッセージの種別を示すもの。「/」で区切って階層構造を作ることが可能なので、複雑な通信でも見やすい形で通信フォーマットを作成することが可能です。
- Arguments : メッセージの内容です。数値(int / float)や文字列(string)形式などのデータを受け渡すことができます。
ArduinoでOSCを利用するには?
ArduinoでOSCを利用するためには、ネットワークに繋がる環境を用意する必要がありますので、イーサネットシールドを使います。

写真1 Arduino イーサネットシールド
また、ArduinoでOSC通信をするためには、ライブラリを必要とします。ArduinoでOSC通信をするためのライブラリはいくつかありますが、今回はArdOSCを利用します。(最新バージョンのArduinoの場合、エラーが出て正常に動作しない可能性がありますので、その場合は他のOSCライブラリをご利用ください。)ライブラリを追加後、下記の送信プログラムを記述します(ライブラリの追加の方法は以前の回を参考してください)。
OSC送信テストプログラム
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 | #include <SPI.h> #include <Ethernet.h> #include <ArdOSC.h> byte myMac[] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX }; //イーサネットのMACアドレスを記述 byte myIp[] = { 192, 168, 0, 9 }; //Arduinoに割り当てるIPアドレスを記述 int destPort=12000; //送信先のポート番号 byte destIp[] = { 192, 168, 0, 2 }; //送信先のIPアドレス OSCClient client; OSCMessage global_mes; void setup(){ Ethernet.begin(myMac ,myIp); //イーサネットの設定 } void loop(){ global_mes.setAddress(destIp,destPort); //送信設定 global_mes.beginMessage( "/temperature" ); //Message global_mes.addArgString( "29.0" ); //Argument client.send(&global_mes); //データの送信 global_mes.flush(); //データのクリア delay(500); } |
Arduino側の準備ができたら、次に外部アプリケーションの準備をします。今回、外部のアプリケーションには、Processing(プロセッシング)を使います。Processingはオープンソースプロジェクトの、メディアアートやビジュアルデザインのためのプログラミング言語です。Arduino同様、初心者が手軽にあつかえるグラフィックに特化した言語と言えます。Processingのウェブサイトから「Download Processing」を選択して、Processingをダウンロードしてインストールしてください。

図2 Processingウェブサイト
Processingのインストールが完了したら、起動します。

図3 Processingアイコン

図4 Processing起動画面
起動すると、Arduinoに似た画面が表示されますね。Arduino同様、中央の箇所にプログラムを記述して再生ボタンでプログラムの実行、停止ボタンでプログラムを停止することができます。スケッチの例やライブラリの扱い方などもArduinoとほとんど同じですので違和感なく使うことができるかと思います。
さっそくProcessingに下記のOSC受信プログラムを記述します。
OSC受信プログラム(Processing)
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | import oscP5.*; import netP5.*; OscP5 oscP5; NetAddress myRemoteLocation; void setup() { size(500,500); frameRate(25); oscP5 = new OscP5( this ,12000); //受信するポートの設定 myRemoteLocation = new NetAddress( "127.0.0.1" ,12001); //送信する場合の送信IPとポート } void draw() { background(0); } //OSC void oscEvent(OscMessage theOscMessage) { theOscMessage.print(); } |
準備ができたら、Processingを実行した後に、Arduinoを実行すると、Processingのプログラムを記述する画面下のconsole枠にArduinoから送られてきたメッセージが表示されれば成功です。

図5 Processing実行結果
気温湿度を外部アプリケーションに受け渡してみる
OSC通信を使ってArduinoで気温湿度を計測結果を、外部のアプリケーションに渡してみます。
Arduino側の準備として、気温湿度パーツのDHT11を利用して計測します。DHT11はArduinoのライブラリが用意されていますので、DHT11のライブラリを追加します。

写真2 気温湿度センサDHT11
ダウンロードしたDHT11のライブラリには、サンプルファイルが用意されていますので、そのサンプルをもとにDHT11で気温湿度が正常に計測できるかどうか確認します。

図6 気温湿度センサ回路
気温湿度計測のプログラム
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 | #include "DHT.h" #define DHTPIN 2 #define DHTTYPE DHT11 // DHT 11 DHT dht(DHTPIN, DHTTYPE); void setup() { Serial.begin(9600); Serial.println( "DHT11" ); dht.begin(); } void loop() { delay(2000); float h = dht.readHumidity(); float t = dht.readTemperature(); float f = dht.readTemperature( true ); if (isnan(h) || isnan(t) || isnan(f)) { Serial.println( "Failed to read from DHT sensor!" ); return ; } float hif = dht.computeHeatIndex(f, h); float hic = dht.computeHeatIndex(t, h, false ); Serial.print( "Humidity: " ); Serial.print(h); Serial.print( " %\t" ); Serial.print( "Temperature: " ); Serial.print(t); Serial.print( " *C " ); Serial.print(f); Serial.print( " *F\t" ); Serial.print( "Heat index: " ); Serial.print(hic); Serial.print( " *C " ); Serial.print(hif); Serial.println( " *F" ); } |

図7 実行結果
正常に計測が確認できたら、OSC通信用にプログラムを修正します。
気温湿度OSC送信プログラム
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 | #include &lt;SPI.h&gt; #include &lt;Ethernet.h&gt; #include &lt;ArdOSC.h&gt; #include "DHT.h" #define DHTPIN 2 #define DHTTYPE DHT11 // DHT 11 DHT dht(DHTPIN, DHTTYPE); byte myMac[] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX }; byte myIp[] = { 192, 168, 0, 9 }; int destPort=12000; byte destIp[] = { 192,168,0,10 }; OSCClient client; OSCMessage global_mes; void setup(){ Ethernet.begin(myMac ,myIp); dht.begin(); } void loop(){ delay(2000); float h = dht.readHumidity(); float t = dht.readTemperature(); float f = dht.readTemperature( true ); if (isnan(h) || isnan(t) || isnan(f)) { Serial.println( "Failed to read from DHT sensor!" ); return ; } // float hif = dht.computeHeatIndex(f, h); // float hic = dht.computeHeatIndex(t, h, false); global_mes.setAddress(destIp,destPort); //温度を送信 global_mes.beginMessage( "/temperature" ); global_mes.addArgFloat(t); client.send(&amp;global_mes); global_mes.flush(); //object data clear delay(5000); //湿度を送信 global_mes.flush(); //object data clear global_mes.setAddress(destIp,destPort); global_mes.beginMessage( "/humidity" ); global_mes.addArgFloat(h); client.send(&amp;global_mes); delay(1000); global_mes.flush(); //object data clear } |
受信側プログラム(Processing)
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 | import oscP5.*; import netP5.*; OscP5 oscP5; NetAddress myRemoteLocation; void setup() { size(500,500); frameRate(25); oscP5 = new OscP5( this ,12000); myRemoteLocation = new NetAddress( "127.0.0.1" ,12001); } String str1 = "" ; String str2 = "" ; float val = 0; void draw() { background(0); fill(256,256,256); text(str1,50,20); text(str2,50,40); fill(val,256,256); rect(20,10,20,32); } //OSC void oscEvent(OscMessage theOscMessage) { /* print the address pattern and the typetag of the received OscMessage */ print( "### received an osc message." ); theOscMessage.print(); str1 = "OSC Message : " +theOscMessage.addrPattern(); str2 = "OSC Arguments : " +theOscMessage.get(0).floatValue(); val = theOscMessage.get(0).floatValue(); } |
両方のプログラムを実行すると、Processingの画面に下記のように温度・湿度が繰り返し表示されれば完成です。

図8 OSC通信実行結果
まとめ
今回はArduinoと外部アプリケーションを連携する方法の一つであるOSC通信を紹介しました。OSC通信を利用しなくても、独自に相互のアプリケーション同士で通信規約などを決めて通信することも可能ですが、OSC通信を利用することで、世にある数多くのソフトウェアやデバイスと連携することが可能になります。次回は、今回の基礎を発展させてOSC通信を利用することで広がるArduinoの使い方を紹介したいと思います。