WitMotionをUnityで使う
Unity Hubで新規プロジェクトを作成します.
- 3D
- version: 2020.3.21f1
オブジェクトを配置
二つのオブジェクトをHierarchyで作成し,Main CameraをVReye下に移動させます.
- VReye
- SerialHandler
以下,階層構造
スクリプトを作成
- Rotate
- SerialHandler
それぞれの内容は以下をコピペしてください.
Rotate
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotate : MonoBehaviour
{
public SerialHandler serialHandler;
void Start(){
//
}
void Update(){
// transformを取得
Transform myTransform = this.transform;
// ワールド座標を基準に、回転を取得
Vector3 worldAngle = myTransform.eulerAngles;
worldAngle.y = (float)serialHandler.roll;
worldAngle.x = (float)serialHandler.pitch;
myTransform.eulerAngles = worldAngle;
}
}
SerialHander
using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System.Threading;
using System.Collections.Generic;
using System;
public class SerialHandler : MonoBehaviour
{
public delegate void SerialDataReceivedEventHandler(string message);
public event SerialDataReceivedEventHandler OnDataReceived;
//ポート名
public string portName = "COM1";// 自分の使用したいセンサを確認し,適切なCOM番号に変更してください
public int baudRate = 115200;
private SerialPort serialPort_;
private Thread thread_;
private bool isRunning_ = false;
public Queue cmds = new Queue();
private string message_;
private bool isNewMessageReceived_ = false;
private string msg = "";
public double roll=0.0, pitch=0.0, yaw=0.0;
byte[] buffer = new byte[100];
int cnt=0;
void Awake()
{
Open();
}
void Update()
{
// nothing
}
void OnDestroy()
{
Close();
}
private void Open()
{
serialPort_ = new SerialPort(portName, baudRate, Parity.None, 8, StopBits.One);
serialPort_.Open();
serialPort_.ReadTimeout = 50;
isRunning_ = true;
thread_ = new Thread(Read);
thread_.Start();
}
private void Close()
{
isNewMessageReceived_ = false;
isRunning_ = false;
if (thread_ != null && thread_.IsAlive) {
thread_.Join();
}
if (serialPort_ != null && serialPort_.IsOpen) {
serialPort_.Close();
serialPort_.Dispose();
}
}
private void Read()
{
int plus = 0;
int minus = 0;
double preRoll = 0;
// COMPort確認
// string[] ports = SerialPort.GetPortNames();
// foreach(string port in ports){
// // Debug.Log(port);
// }
while (isRunning_ && serialPort_ != null && serialPort_.IsOpen) {
try {
serialPort_.Read(buffer, 0, buffer.Length);
isNewMessageReceived_ = true;
} catch (System.Exception e) {
Debug.LogWarning(e.Message);
}
for(int i=0;i<buffer.Length;i++){
if(buffer[i]==0x55 && buffer[i+1]==0x53){
int start=i+2;
this.roll = (buffer[start+1]*Math.Pow(2,8)+buffer[start+0])/32768.0*180;
this.pitch = (buffer[start+3]*Math.Pow(2,8)+buffer[start+2])/32768.0*180;
this.yaw = (buffer[start+5]*Math.Pow(2,8)+buffer[start+4])/32768.0*180;
// センサ値を[-180,180]に変換する
if(this.roll > 180){
this.roll -= 360;
}
// センサ値を[0→90→0],[0→-90→0]に変換する
if (this.pitch > 180) {
this.pitch -= 360;
}
// センサ値を[-180,180]に変換する
// if (yaw > 180) {
// yaw -= 360;
// }
if(preRoll*this.roll <= 0){
if(Mathf.Abs((float)this.roll) > 150){
if(preRoll < 0){
minus++;
}else if(preRoll > 0){
plus++;
}
}
preRoll=this.roll;
}
this.roll += (plus-minus)*360;
// Check
// Debug.Log($"roll:{roll}");
// Debug.Log($"pitch:{pitch}");
// Debug.Log($"yaw:{yaw}");
}
}
}
}
public void Write(string message)
{
try {
serialPort_.Write(message);
} catch (System.Exception e) {
Debug.LogWarning(e.Message);
}
}
}
設定
Unity上でAssets内にあるSerialHanderをドラッグしHierarchyにあるSerialHanderの上でドロップし,スクリプトをアタッチします.
次に,Rotateも同様にMain Cameraにスクリプトをアタッチします.
その後,MainCameraをクリックし右側にあるInspectorタブ内のSerialHandlerの右のボックスにHierarchy内のSerialHanderオブジェクトをドラッグ&ドロップします.
※重要!
最後にUnity左上のEditタブ→Project Settings...→Player→Configuration→Api Compatibility Level*の部分を.NET standard 2.0から.NET 4.xに変更してください.
以上で終わりです!
画面上部中央の再生ボタンをクリックしてみてちゃんとセンサとUnity上のカメラが同期しているか確認してみてください.
追記(2023.9.22)
コード改良版は以下.