RaspberryPiとESP32でOSC通信
今日はRaspberryPiとESP32でOSC通信をしてみます!💪
前回の予告通り、UDP通信を基本にOSCのエンコード、デコードで通信をしてみます。UDP通信がバイナリーで送られて来るので、エンコード、デコードのプログラムは自分で作ってしまうこともできるんだけど、ライブリーを見つけたのでそれを使ってみます!
1、RaspberryPI側
import socket
import struct
import time
from contextlib2 import closing
from pythonosc import osc_message_builder
from pythonosc import osc_message
UDP_IP="192.168.43.41"
UDP_PORT=9000
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,True)
sock.bind((UDP_IP,UDP_PORT))
count =0
with closing(sock):
while True:
count +=1
data,addr = sock.recvfrom(1024)
#print("Send from ESP",addr,"-",data)
osc_msg = osc_message.OscMessage(data)
print('\nreceive data')
print(osc_msg.address)
print(osc_msg.params)
time.sleep(1)
builder = osc_message_builder.OscMessageBuilder(address="/LED")
builder.add_arg('Hello')
builder.add_arg(count)
builder.add_arg(100)
msg = builder.build()
print('\nsend data')
print(msg._dgram)
sock.sendto(msg._dgram,addr)
#mes = msg._dgram.encode()
#sock.sendto(mes,addr)
UDP通信で受信したバイナリーデータを.address、.paramsのオブジェクトでアドレスとデータを取り出せます。
osc_msg = osc_message.OscMessage(data)
print(osc_msg.address)
print(osc_msg.params)
実行した結果は以下のようになります。データはリストとして保管されます。
$ receive data
/SW
[1,Hello]
次に送信データは以下の部分で作成しています。
このデータを送信している。[count]は変数
/LED Hello [count] 100
builder = osc_message_builder.OscMessageBuilder(address="/LED")
builder.add_arg('Hello')
builder.add_arg(count)
builder.add_arg(100)
上記でメッセージを作成してUDP通信で送信しています。
2、ESP32側
使ったライブラリーはこちら
#include <WiFi.h>
#include <WiFiUDP.h>
#include <OSCMessage.h>
#include <OSCBundle.h>
const char ssid[] = "your ssid"; // SSID
const char pass[] = "your password"; // password
static WiFiUDP Udp;
static const char *kRemoteIpadr = "192.168.43.41";
static const int kRmoteUdpPort = 9000; //送信先のポート
static void WiFi_setup()
{
static const int kLocalPort = 7000; //自身のポート
WiFi.begin(ssid, pass);
while( WiFi.status() != WL_CONNECTED) {
delay(500);
}
Udp.begin(kLocalPort);
}
static void Serial_setup()
{
Serial.begin(115200);
Serial.println(""); // to separate line
}
//メッセージの確認
void mes_recive(OSCMessage &mess) {
char str[64];
int i;
mess.getString(0,str,16);
int val = mess.getInt(1);
int val2 = mess.getInt(2);
Serial.println("receive data");
Serial.println("LED/");
Serial.printf("%s,%d,%d\n",str,val,val2);
}
void setup() {
Serial_setup();
WiFi_setup();
}
void loop()
{
OSCErrorCode error;
int count=0;
while(1){
OSCMessage rmsg;
int size = Udp.parsePacket();
if (size > 0) {
while (size--) {
rmsg.fill(Udp.read());
}
if (!rmsg.hasError()) {
rmsg.dispatch("/LED", mes_recive, 0);
rmsg.empty();
}
else {
error = rmsg.getError();
Serial.print("error: ");
Serial.println(error);
}
}
OSCMessage mess("/sw");
mess.add(count);
mess.add("Hello");
Udp.beginPacket(kRemoteIpadr, kRmoteUdpPort);
mess.send(Udp);
Udp.endPacket();
mess.empty();
count++;
delay(3000);
}
}
長いプログラムですが、ほどんどは今まで出てきた、Wifi 設定やUDP通信の部分です。
受信バッファrmsgを定義し、UDP通信で受信したデータをfillで書き込み、dispatchでアドレス"/LED"で送られてきた場合、mes_reciveモジュールを呼び出します。
OSCMessage rmsg;
int size = Udp.parsePacket();
if (size > 0) {
while (size--) {
rmsg.fill(Udp.read());
}
if (!rmsg.hasError()) {
rmsg.dispatch("/LED", mes_recive, 0);
rmsg.empty();
}
データの取り出しは下記で行ってます。
mess.getString(0,str,16);
int val = mess.getInt(1);
int val2 = mess.getInt(2);
実行結果は
receive data
LED/
Hello 1,100
となります。送られて来るデータの型によってエンコードを変えなくてはならないのでデータフォーマットは予め取り決めしておく必要がありますね。
送信データは下記で作成しています。
OSCMessage mess("/sw");
mess.add(count);
mess.add("Hello")
送受信後データバッファは下記で空にします。
rmsg.empty();
mess.empty();
3、まとめ
今回はRaspberryPiとESP32で行いましたが、今回のプログラムはESP32ーESP32、RaspberryPiーRaspberryPiでも通信が行えます。
OSC通信は汎用フォーマットなので、クリエーター系ソフトのprocessingやRaspberryPiの音楽ソフトSonic Piなどもコントロールできるようです。
OSCはスマホアプリも沢山あるので、お気に入りのスマホアプリなどからESP32をコンロトールしても面白いですね。😊
では🤚