从 Android 应用读取 Unity 中的串行数据
Reading Serial data in Unity from Android app
我正在使用 Android 的 SensoDuino (Official website) 应用程序通过蓝牙串行通信将加速度计、陀螺仪等传感器数据发送到 PC 中的 Unity。我在 Unity 中使用以下代码接收数据 -
using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System;
public class COM : MonoBehaviour {
public SerialPort sp;
public float data;
void Start () {
sp = new SerialPort("COM3", 9600,Parity.None, 8, StopBits.One);
Debug.Log ("Connection started");
if (sp != null)
{
if (sp.IsOpen)
{
sp.Close();
Debug.Log ("Closing port, because it was already open!");
}
else
{
sp.Open(); // opens the connection
// sets the timeout value before reporting error
sp.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
Debug.Log("Port Opened!");
}
}
else
{
if (sp.IsOpen)
{
print("Port is already open");
}
else
{
print("Port == null");
}
}
Debug.Log ("Open Connection finished running");
}
void Update () {
data = float.Parse( sp.ReadTo ("\r") ) ;
print ("data = " + data);
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort spl = (SerialPort)sender;
data = float.Parse( spl.ReadTo ("\r") ) ;
Debug.Log(data.ToString());
print ("data = " + data);
}
}
但是我收不到任何数据。 DataReceiveHandler
根本没有开火。我也尝试使用 ReadLine()
,但它冻结了 Unity。
SensoDuino 发送加速计数据的格式是
1,104,0.54437256,-0.2632141,9.826126
1,105,0.56111145,-0.279953,9.8524475
1,106,0.54556274,-0.2632141,9.833298
1,107,0.5515442,-0.26081848,9.841675
1,108,0.5312042,-0.2644043,9.867996
这是连续流,可能是使用 ReadLine()
时卡住的原因。
请帮我看一下数据
我找到了解决办法。 ReadLine()
是一个阻塞调用,所以我不得不使用 ReadByte()
不断读取字节并稍后转换数据。为了减少延迟,在线程中调用了 ReadByte()
函数。
void recData() {
if ((sp != null) && (sp.IsOpen)) {
byte tmp;
string data = "";
string avalues="";
tmp = (byte) sp.ReadByte();
while(tmp !=255) {
data+=((char)tmp);
tmp = (byte) sp.ReadByte();
if((tmp=='>') && (data.Length > 30)){
avalues = data;
parseValues(avalues);
data="";
}
}
}
}
我做了一个很详细的教程here
关于Unity为什么不处理串行事件,这里回答:
问题:
如answered here。这个问题是因为Unity的Mono没有完整实现SerialPort class.
简单的解决方案:
一个简单的解决方案是使用 this C# library 实现 MessageReceived 事件。我已经在 Windows 上对其进行了测试并且没有任何问题。
库在 NuGet 中可用。然后,您可以从资产商店安装一些 Unity 插件作为“Nuget For Unity”,然后在您的游戏中安装和使用该库。
另一个解决方案:
另一种解决方案是自己实现一个class,它在另一个线程中永久读取串行端口中的数据,然后调用一个事件来通知何时有新数据可用。
您可以 read this method 从前面提到的库中获得一些灵感。
这里复制一下图书馆的串口读取方法:
public delegate void MessageReceivedHandler(byte[] message);
public event MessageReceivedHandler MessageReceived;
void ReaderTask ()
{
// Will ask for data while connected to the serial port
while (IsConnected)
{
int messageLength = serialPort.BytesToRead;
if (msglen > 0)
{
byte[] message = new byte[messageLength];
int offset = 0;
int count = messageLength - offset;
// Ask data for ever if there is no data yet in the serial port
while (serialPort.Read(message, offset, count) <= 0)
; // noop
// Check if there are subscribed listeners
if (MessageReceived != null)
{
MessageReceived(message);
}
}
else
{
Thread.Sleep(100);
}
}
}
// In the main thread
// Start the Reader task
reader = new Thread(ReaderTask);
reader.Start();
注意:我知道这个问题 post 很久以前就被编辑过,但我 post 在这里回答这个问题以供将来参考。
我正在使用 Android 的 SensoDuino (Official website) 应用程序通过蓝牙串行通信将加速度计、陀螺仪等传感器数据发送到 PC 中的 Unity。我在 Unity 中使用以下代码接收数据 -
using UnityEngine;
using System.Collections;
using System.IO.Ports;
using System;
public class COM : MonoBehaviour {
public SerialPort sp;
public float data;
void Start () {
sp = new SerialPort("COM3", 9600,Parity.None, 8, StopBits.One);
Debug.Log ("Connection started");
if (sp != null)
{
if (sp.IsOpen)
{
sp.Close();
Debug.Log ("Closing port, because it was already open!");
}
else
{
sp.Open(); // opens the connection
// sets the timeout value before reporting error
sp.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
Debug.Log("Port Opened!");
}
}
else
{
if (sp.IsOpen)
{
print("Port is already open");
}
else
{
print("Port == null");
}
}
Debug.Log ("Open Connection finished running");
}
void Update () {
data = float.Parse( sp.ReadTo ("\r") ) ;
print ("data = " + data);
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort spl = (SerialPort)sender;
data = float.Parse( spl.ReadTo ("\r") ) ;
Debug.Log(data.ToString());
print ("data = " + data);
}
}
但是我收不到任何数据。 DataReceiveHandler
根本没有开火。我也尝试使用 ReadLine()
,但它冻结了 Unity。
SensoDuino 发送加速计数据的格式是
1,104,0.54437256,-0.2632141,9.826126
1,105,0.56111145,-0.279953,9.8524475
1,106,0.54556274,-0.2632141,9.833298
1,107,0.5515442,-0.26081848,9.841675
1,108,0.5312042,-0.2644043,9.867996
这是连续流,可能是使用 ReadLine()
时卡住的原因。
请帮我看一下数据
我找到了解决办法。 ReadLine()
是一个阻塞调用,所以我不得不使用 ReadByte()
不断读取字节并稍后转换数据。为了减少延迟,在线程中调用了 ReadByte()
函数。
void recData() {
if ((sp != null) && (sp.IsOpen)) {
byte tmp;
string data = "";
string avalues="";
tmp = (byte) sp.ReadByte();
while(tmp !=255) {
data+=((char)tmp);
tmp = (byte) sp.ReadByte();
if((tmp=='>') && (data.Length > 30)){
avalues = data;
parseValues(avalues);
data="";
}
}
}
}
我做了一个很详细的教程here
关于Unity为什么不处理串行事件,这里回答:
问题: 如answered here。这个问题是因为Unity的Mono没有完整实现SerialPort class.
简单的解决方案: 一个简单的解决方案是使用 this C# library 实现 MessageReceived 事件。我已经在 Windows 上对其进行了测试并且没有任何问题。
库在 NuGet 中可用。然后,您可以从资产商店安装一些 Unity 插件作为“Nuget For Unity”,然后在您的游戏中安装和使用该库。
另一个解决方案: 另一种解决方案是自己实现一个class,它在另一个线程中永久读取串行端口中的数据,然后调用一个事件来通知何时有新数据可用。
您可以 read this method 从前面提到的库中获得一些灵感。
这里复制一下图书馆的串口读取方法:
public delegate void MessageReceivedHandler(byte[] message);
public event MessageReceivedHandler MessageReceived;
void ReaderTask ()
{
// Will ask for data while connected to the serial port
while (IsConnected)
{
int messageLength = serialPort.BytesToRead;
if (msglen > 0)
{
byte[] message = new byte[messageLength];
int offset = 0;
int count = messageLength - offset;
// Ask data for ever if there is no data yet in the serial port
while (serialPort.Read(message, offset, count) <= 0)
; // noop
// Check if there are subscribed listeners
if (MessageReceived != null)
{
MessageReceived(message);
}
}
else
{
Thread.Sleep(100);
}
}
}
// In the main thread
// Start the Reader task
reader = new Thread(ReaderTask);
reader.Start();
注意:我知道这个问题 post 很久以前就被编辑过,但我 post 在这里回答这个问题以供将来参考。