前の続きです。前回は導通チェック程度だったけど、今回はちゃんとメッセージをOSCで送受信します。今回通信するのはUnityとArduino(イーサネットシールド付き)の間でやります。
#junki::acoustic UnityでOSCを使う(UnityOSC)
Unity側の準備
セットアップは上の記事を参考に済ませてください。前回と変更した部分を書きます。
OSCHandler.cs
CreateClientのclientID部分の名前をArduinoに変えただけです。
public void Init(string targetAddr, int outGoingPort, int inComingPort)
{
CreateClient("Arduino", IPAddress.Parse(targetAddr), outGoingPort);
CreateServer("SomeOscClient", inComingPort);
}
OSCController.cs
OSCを実際に使う部分です。UpdateLogsで受信したパケットをログに突っ込んでます。とりあえずアップデートがあったときだけ表示するように変更しました。また送信部分はマウスのクリック時のXYポジションを送るように変更しました。
注意点としてUpdateLogsはUnity側のアプリのフレームレートで呼ばれるので相手側のフレームレートと合わせないとOSCパケットを取りこぼす可能性があります。あんまりシビアなものでなければとりあえず今のところ気にしなくても良いけど。
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityOSC;
public class OSCController : MonoBehaviour {
#region Network Settings
public string TargetAddr;
public int OutGoingPort;
public int InComingPort;
#endregion
private Dictionary<string, ServerLog> servers;
private int lastPacketIndex;
void Start() {
OSCHandler.Instance.Init(TargetAddr, OutGoingPort, InComingPort);
servers = new Dictionary<string, ServerLog>();
}
NOTE
void Update() {
OSCHandler.Instance.UpdateLogs();
servers = OSCHandler.Instance.Servers;
foreach( KeyValuePair<string, ServerLog> item in servers )
{
if(item.Value.packets.Count > 0 && lastPacketIndex != item.Value.packets.Count - 1) {
lastPacketIndex = item.Value.packets.Count - 1;
UnityEngine.Debug.Log(String.Format("SERVER: {0} ADDRESS: {1} VALUE 0: {2} VALUE 1: {3} VALUE 2: {4}",
item.Key,
item.Value.packets[lastPacketIndex].Address,
item.Value.packets[lastPacketIndex].Data[0].ToString(),
item.Value.packets[lastPacketIndex].Data[1].ToString(),
item.Value.packets[lastPacketIndex].Data[2].ToString()));
}
}
if(Input.GetMouseButtonDown(0)) {
Debug.Log("SendMessage");
var clickPos = new List<float>(){Input.mousePosition.x, Input.mousePosition.y};
OSCHandler.Instance.SendMessageToClient("Arduino", "/click/pos", clickPos);
}
}
}
ArdOSCのExample/SimpleRecieve
ArduinoでOSCを使うには最初oscuinoとかいうのを使おうと思ったけど、うまくOSCのアドレスマッチングが動かなかったためこちらの方のOSCライブラリを使った。ありがたや。
github recotana ArdOSC
ArdOSCを使う手順はこんな感じ。
- これをzipで落として来て、フォルダをArdOSCにリネーム
- Arduino/libraries/ArdOSC/という感じに直置きする
- Arduino IDEを再起動して、[Sketch] -> [Import Library...] -> [ArdOSC]
OSCSample.ino
MACアドレスはイーサネットシールド裏側に記載があります。myIpはArduinoに設定するIPアドレス、destIpは通信先(今回はUnity側)で設定します。ライブラリがシンプルなので説明すべき部分はほぼないですが、取り扱うOSCのアドレスに対してその処理を行う関数を関連づけておくと、OSCパケットを受信するとその関数がコールされます。パケットをArduino側で受信したらEcho的にUnity側にも"/ard/echo"として適当に3つの値を返すようにしました。
#include <SPI.h>
#include <Ethernet.h>
#include <ArdOSC.h>
byte myMac[] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX };
byte myIp[] = { 192, 168, x, x };
byte destIp[] = { 192, 168, x, x };
int inPort = 5555;
int outPort = 6666;
OSCServer server;
OSCClient client;
void setup(){
Serial.begin(19200);
Ethernet.begin(myMac ,myIp);
server.begin(inPort);
server.addCallback("/click/pos", &clickEvent);
}
void loop(){
if(server.aviableCheck()>0){
Serial.println("alive! ");
}
}
void clickEvent(OSCMessage *_mes){
Serial.println("clickEvent");
int posX = _mes->getArgFloat(0);
int posY = _mes->getArgFloat(1);
Serial.print(posX);
Serial.print(", ");
Serial.println(posY);
sendMessage();
}
void sendMessage() {
Serial.println("sendMessage");
OSCMessage msg;
msg.setAddress(destIp, outPort);
msg.beginMessage("/ard/echo");
msg.addArgInt32(10);
msg.addArgFloat(10.0f);
msg.addArgString("i am arduino.");
client.send(&msg);
msg.flush();
}
実行
Unity側で適当に画面をクリックするとArduino側のシリアルコンソールにマウス座標が飛ばされ、そのエコーとしてサンプルのデータをUnityのコンソールログでも確認できます。これで開発が捗ります。
Unityのコンソール
SendMessage
UnityEngine.Debug:Log(Object)
OSCController:Update() (at Assets/Script/OSCController.cs:68)
SERVER: SomeOscClient ADDRESS: /ard/echo VALUE 0: 10 VALUE 1: 10 VALUE 2: i am arduino.
UnityEngine.Debug:Log(Object)
OSCController:Update() (at Assets/Script/OSCController.cs:57)
alive!
clickEvent
429, 261
sendMessage
alive!