- Home /
How do I make the YEI 3-Space Sensor Bluetooth work with unity?
So I need a way for this, YEI Sensor to work with unity. I just need for it to tell unity its location and orientation in real time, but I'm not sure how to do that. The sensor installs on the computer as a device,As shown here, but I don't know how to tell unity to get information from it. I don't want to buy it without knowing whether or not it can even work with unity. They have all the info for it on the website, so if someone smarter than me could look at it and determined it’s compatibly with unity that would be great.
I apologize for my lack of knowledge in this area; I'm new to both unity and any motion capture devices.
Answer by ChrisGeorge · Mar 05, 2013 at 08:54 PM
It seems that I somehow deleted the old answer, but this one is better suited anyways. Good to hear that your sensor is working. To do other commands, follow the comment block about the command packets located right before the declaration of send_bytes. So for wireless communication the button command it would look like this:
byte[] button_bytes = {0xf8, 0x00, 0xfa, 0xfa};
And for the tare command:
byte[] tare_bytes = {0xf8, 0x00, 0x60, 0x60};
You can find the list of commands and some more detail about the commands in the Wireless Manual.
Here are the scripts we have edited to have the button states and taring in them. They are timed based, so if you wanted to use keyboard commands you will have to look up how to capture keyboard events in Unity. There is also some bug fixes that were not apparent before that Mono has when reading from a serial port.
Communicating via USB or Bluetooth
using UnityEngine;
using System;
using System.Collections;
using System.IO.Ports;
public class cube_rotator : MonoBehaviour{
// Connect to the serial port the 3-Space Sensor is connected to
public static SerialPort sp = new SerialPort("\\\\.\\COM4");
// Command packet for getting the filtered tared orientation as a quaternion
// {header byte, command byte, [data bytes], checksum byte}
// checksum = (command byte + data bytes) % 256
public static byte[] send_bytes = {0xf7, 0x00, 0x00};
public static byte[] button_bytes = {0xf7, 0xfa, 0xfa};
public static byte[] tare_bytes = {0xf7, 0x60, 0x60};
public int counter = 0;
// Use this for initialization
void Start(){
// Allow the user to set the appropriate properties.
sp.BaudRate = 115200;
sp.Parity = Parity.None;
sp.DataBits = 8;
sp.StopBits = StopBits.One;
// Set the read/write timeouts
sp.WriteTimeout = 500;
sp.ReadTimeout = 500;
sp.Open();
sp.Write(send_bytes,0,3);
}
// Helper function for taking the bytes read from the 3-Space Sensor and converting them into a float
float bytesToFloat(byte[] raw_bytes, int offset){
byte[] big_bytes = new byte[4];
big_bytes[0] = raw_bytes[offset+3];
big_bytes[1] = raw_bytes[offset+2];
big_bytes[2] = raw_bytes[offset+1];
big_bytes[3] = raw_bytes[offset+0];
return BitConverter.ToSingle(big_bytes,0);
}
void getButtonState(){
sp.Write(button_bytes, 0, 3);
byte[] read_bytes = new byte[1];
int fail_counter = 0;
// Mono, for some reason, seems to randomly fail on the first read after a wirte so we must loop
// through to make sure the bytes are read
while (true){
try{
sp.Read(read_bytes, 0, 1);
break;
}
catch{
++fail_counter;
// Failed to read from serial port
}
if (fail_counter > 100){
throw new System.Exception("Failed to read from port too many times." +
" This could mean the port is not open or the Mono serial read is not responding.");
}
}
if (read_bytes[0] == 0){
print("No buttons are pressed.");
}
else if (read_bytes[0] == 1){
print("Right button is pressed.");
}
else if (read_bytes[0] == 2){
print("Left button is pressed.");
}
else if (read_bytes[0] == 3){
print("Left and Right buttons are pressed.");
}
}
void tareSensor(){
sp.Write(tare_bytes, 0, 3);
}
// Update is called once per frame
void Update(){
counter++;
// A quaternion consists of 4 floats which is 16 bytes
byte[] read_bytes = new byte[16];
// Mono, for some reason, seems to randomly fail on the first read after a wirte so we must loop
// through to make sure the bytes are read and Mono also seems not to always read the amount asked
// so we must also read one byte at a time
int read_counter = 100;
int byte_idx = 0;
while (read_counter > 0){
try{
byte_idx += sp.Read(read_bytes, byte_idx, 1);
}
catch{
// Failed to read from serial port
}
if (byte_idx == 16){
break;
}
if (read_counter <= 0){
throw new System.Exception("Failed to read quaternion from port too many times." +
" This could mean the port is not open or the Mono serial read is not responding.");
}
--read_counter;
}
// Convert bytes to floats
float x = bytesToFloat(read_bytes,0);
float y = bytesToFloat(read_bytes,4);
float z = bytesToFloat(read_bytes,8);
float w = bytesToFloat(read_bytes,12);
// Create a quaternion
Quaternion quat = new Quaternion(x,y,z,w);
// Perform rotation
transform.rotation = quat;
if ((counter % 25) == 0){
getButtonState();
}
else if (counter > 150){
tareSensor();
counter = 1;
}
// Send command
sp.Write(send_bytes,0,3);
}
}
Communicating via Wireless
using UnityEngine;
using System;
using System.Collections;
using System.IO.Ports;
public class cube_rotator_wireless : MonoBehaviour{
// Connect to the serial port the 3-Space Dongle is connected to
public static SerialPort sp = new SerialPort("\\\\.\\COM3");
// Wireless Command packet for getting the filtered tared orientation as
// a quaternion
// {header byte, id byte + command byte, [data bytes], checksum byte}
// checksum = (id byte + command byte + data bytes) % 256
public static byte[] send_bytes = {0xf8, 0x00, 0x00, 0x00};
public static byte[] button_bytes = {0xf8, 0x00, 0xfa, 0xfa};
public static byte[] tare_bytes = {0xf8, 0x00, 0x60, 0x60};
public int counter = 0;
// Use this for initialization
void Start(){
// Allow the user to set the appropriate properties.
sp.BaudRate = 115200;
sp.Parity = Parity.None;
sp.DataBits = 8;
sp.StopBits = StopBits.One;
// Set the read/write timeouts
sp.WriteTimeout = 500;
sp.ReadTimeout = 500;
sp.Open();
sp.Write(send_bytes, 0, 4);
}
// Helper function for taking the bytes read from the 3-Space Sensor and
// converting them into a float
float bytesToFloat(byte[] raw_bytes, int offset){
byte[] big_bytes = new byte[4];
big_bytes[0] = raw_bytes[offset + 3];
big_bytes[1] = raw_bytes[offset + 2];
big_bytes[2] = raw_bytes[offset + 1];
big_bytes[3] = raw_bytes[offset + 0];
return BitConverter.ToSingle(big_bytes, 0);
}
void getButtonState(){
sp.Write(button_bytes, 0, 4);
// Wireless packets always have a confirm and id byte pre-appened to the data
byte[] confirm_byte = new byte[1];
byte[] id_byte = new byte[1];
int fail_counter = 0;
// Mono, for some reason, seems to randomly fail on the first read after a wirte so we must loop
// through to make sure the bytes are read
while (true){
try{
sp.Read(confirm_byte, 0, 1);
sp.Read(id_byte, 0, 1);
break;
}
catch{
++fail_counter;
// Failed to read from serial port
}
if (fail_counter > 100){
throw new System.Exception("Failed to read from port too many times." +
" This could mean the port is not open or the Mono serial read is not responding.");
}
}
if (confirm_byte[0] == 0){
// Read data length of packet
byte[] length_byte = new byte[1];
sp.Read(length_byte, 0, 1);
byte length = length_byte[0];
// Read the length of the data in the packet
byte[] read_bytes = new byte[length];
sp.Read(read_bytes, 0, length);
if (read_bytes[0] == 0){
print("No buttons are pressed.");
}
else if (read_bytes[0] == 1){
print("Right button is pressed.");
}
else if (read_bytes[0] == 2){
print("Left button is pressed.");
}
else if (read_bytes[0] == 3){
print("Left and Right buttons are pressed.");
}
}
}
void tareSensor(){
sp.Write(tare_bytes, 0, 4);
// Wireless packets always have a confirm and id byte pre-appened to the data
byte[] confirm_byte = new byte[1];
byte[] id_byte = new byte[1];
int fail_counter = 0;
// Mono, for some reason, seems to randomly fail on the first read after a wirte so we must loop
// through to make sure the bytes are read
while (true){
try{
sp.Read(confirm_byte, 0, 1);
sp.Read(id_byte, 0, 1);
break;
}
catch{
++fail_counter;
// Failed to read from serial port
}
if (fail_counter > 100){
throw new System.Exception("Failed to read from port too many times." +
" This could mean the port is not open or the Mono serial read is not responding.");
}
}
if (confirm_byte[0] == 0){
// Read data length of packet
byte[] length_byte = new byte[1];
sp.Read(length_byte, 0, 1);
byte length = length_byte[0];
// Read the length of the data in the packet
byte[] read_bytes = new byte[length];
sp.Read(read_bytes, 0, length);
}
}
// Update is called once per frame
void Update(){
counter++;
// Wireless packets always have a confirm and id byte pre-appened to the data
byte[] confirm_byte = new byte[1];
byte[] id_byte = new byte[1];
int fail_counter = 0;
// Mono, for some reason, seems to randomly fail on the first read after a wirte so we must loop
// through to make sure the bytes are read
while (true){
try{
sp.Read(confirm_byte, 0, 1);
sp.Read(id_byte, 0, 1);
break;
}
catch{
++fail_counter;
// Failed to read from serial port
}
if (fail_counter > 100){
throw new System.Exception("Failed to read from port too many times." +
" This could mean the port is not open or the Mono serial read is not responding.");
}
}
if (confirm_byte[0] == 0){
// Read data length of packet
byte[] length_byte = new byte[1];
sp.Read(length_byte, 0, 1);
byte length = length_byte[0];
// Read the length of the data in the packet
byte[] read_bytes = new byte[length];
sp.Read(read_bytes, 0, length);
// Convert bytes to floats
float x = bytesToFloat(read_bytes, 0);
float y = bytesToFloat(read_bytes, 4);
float z = bytesToFloat(read_bytes, 8);
float w = bytesToFloat(read_bytes, 12);
// Create a quaternion
Quaternion quat = new Quaternion(x, y, z, w);
// Perform rotation
transform.rotation = quat;
}
if ((counter % 25) == 0){
getButtonState();
}
else if (counter > 150){
tareSensor();
counter = 1;
}
sp.Write(send_bytes, 0, 4);
}
}
Hello. Can you tell me where should I add this script for it to work?
Answer by RoadKillGrill · Jan 03, 2013 at 06:28 PM
We have used Unity in some of our demos like this bird flight demo in this video YEI 3-Space Family IMU/AHRS Sensors in Action
There are a few ways to get the orientation from the 3-Space sensor into Unity. The 3-Space sensors are assessable to any application that can open a comport. So its possible to write a simple interface in C# to get the orientations into Unity. The other option is to make a socket server where you have another application read the data from the 3-Space Sensor and then stream the bytes to Unity or any application that can open a socket.
If you are planning on using multiple sensors, the YEI 3-Space Sensor™ Wireless is the preferred option because it has lower latency and better throughput than the Bluetooth model.
Great! I'm going to go spend $300+ on something I know rather little about. Based on your answer I should be able to Google my way thought the process now, so thanks. I can't wait! :)
I can't for the life of me get it to work... I'm trying to use the ThreeSpace_API.dll they have on the site, but I don't really know what I'm doing. I give the dll file a command and it returns a number. I'm rather sure it is suppose to return much more than that, and I'm also sure that I'm not issuing the command correctly. Advise?
@BrockG, did you have any luck since then? I guess you found that this sensor doesn't give a position as you asked for in the first place.
I've had some luck. The code above works to get the orientation, and I've found mix uses for this device. I wrote some code that makes it count the number of sit-ups I've done based on the angle of my body. $$anonymous$$ostly, I'm not as focused on virtual reality as when I bought this, not that I regret getting it or anything. However, I'm not working on it now, or in the near future due to interest in other areas, so I don't have much in the form of advice to offer.
Your answer
Follow this Question
Related Questions
A node in a childnode? 1 Answer
Missing scripts and other information 1 Answer
Increasing And Decreasing An Array Through A Variable 2 Answers
Launched from a browser 1 Answer