我正在开发一个Android应用程序,它通过蓝牙接收实时数据并将其绘制在屏幕上。
数据是陀螺仪传感器位置信息。我是从定制的Freescale Kinetis K10微控制器板(由我自己设计和测试)发送的。对于蓝牙通信,我使用的是HC-05蓝牙模块。
数据格式如下:
byte_1:位置标识字节,始终等于-128
byte_2:轴1的位置
byte_3:轴2的位置
byte_4:轴3的位置
我按照特定的顺序一个接一个地连续发送这4个字节。我每隔5毫秒发送一个4字节的数据包,发送数据包大约需要4.7毫秒(9600波特率)。 微控制器输出的数据在精度和时序方面是完美的(用逻辑分析仪检查)。
问题在于,当从手机接收时,一些字节似乎丢失了。这是代码的一部分,我在这里阅读InputStream:
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e("Printer Service", "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
@Override
public void run() {
Log.i("BluetoothService", "BEGIN mConnectedThread");
byte[] buffer = new byte[4];
int bytes;
while (true) {
try {
bytes = mmInStream.read(buffer);
int position = 0;
if(buffer[0] == -128) {
if(bytes >= 2) {
sendArray.errorTilt = buffer[1];
}
if(bytes >= 3) {
sendArray.errorRoll = buffer[2];
}
if(bytes == 4) {
sendArray.errorPan = buffer[3];
}
}
else if(buffer[1] == -128) {
position = 1;
if(bytes >= 3) {
sendArray.errorTilt = buffer[2];
}
if(bytes == 4) {
sendArray.errorRoll = buffer[3];
}
if(bytes >= 2) {
sendArray.errorPan = buffer[0];
}
}
else if(buffer[2] == -128 && bytes >= 3) {
position = 2;
sendArray.errorRoll = buffer[0];
sendArray.errorPan = buffer[1];
if(bytes == 4) {
sendArray.errorTilt = buffer[3];
}
}
else if(buffer[3] == -128 && bytes == 4) {
position = 3;
sendArray.errorTilt = buffer[0];
sendArray.errorRoll = buffer[1];
sendArray.errorPan = buffer[2];
}
if(position <= bytes && bytes > 1) {
sendArray.errorUpdate = true;
}
} catch (Exception e) {
e.printStackTrace();
connectionLost();
BluetoothService.this.stop();
break;
}
}
}
public void write(int oneByte) {
try {
mmOutStream.write(oneByte);
} catch (IOException e) {
Log.e("BluetoothService", "Exception during write", e);
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
Log.e("BluetoothService", "close() of connect socket failed", e);
}
}
}
sendArray是一个保留许多不同变量的单例。
errorTilt,errorRoll和errorPan是轴的当前值,它们正在从接收缓冲区更新。
&#34;位置&#34;保持位置识别字节的位置。它用于检查是否已更新任何变量。
很多时候输入缓冲区只收到一个字节,因为我不知道应该是哪个轴,因为我没有关于它的相对位置的信息。位置字节,这个特殊的字节是无用的,并且会丢失。
我通过以下方法测试了接收的准确性。我在其中一个轴上输出了一个三角波,而不是轴数据。在电话中,三角波的线条不应该是直的,而是随机弯曲并包含伪影。
为了绘制我正在使用GraphView的数据,我正在从一个单独的线程中以相等的间隔更新图形。
我尝试使用较长的接收缓冲区(使用修改后的接收算法),但这并不会有帮助,因为一次只能接收几个字节。
我尝试过实现InputStream.available()但它总是提供127个字节,这似乎不是真的。
我已经阅读了很多关于类似问题的帖子,我花了最近5天的时间来处理它,但我找不到一个好的解决方案。
总而言之,我需要实现准确,实时(或接近实时)接收所有字节。
有类似问题的主题: How to do good real-time data streaming using Java Android SDK
谢谢。
更新:
我尝试仅为其中一个轴发送信息,因此它简单明了,无需位置字节。我每5毫秒再次发送一次,但这次连续字节之间的时间更长,因为它只是数据包中的一个字节。
这次我使用了InputStream.read(),它不需要缓冲区。但是,传入的数据再次被破坏,因为无法接收随机字节。
我已成功使用此方法看到不同的项目,我不知道为什么它不与我合作。我认为这可能是我使用的HC-05蓝牙模块的一个问题,但我尝试了另一个 - HC-06,情况是一样的。我没有尝试过不同的手机,但我的手机(三星Galaxy S3,Android 4.1.2)似乎工作正常。
UPDATE2:在尝试从流中读取之前,我再次尝试使用InputStream.available()测试原始代码。
当条件可用()> 0时,没有重大变化,可能会稍微恶化。 当条件可用()> 1时,它永远不会读取。我想这是因为不可靠的available()方法,正如文档中所述。
答案 0 :(得分:0)
您的数据处理不正确。你必须使用bytesAvaliable,因为android蓝牙套接字在蓝牙微控制器板上相当慢。但是“bytesAvaliable方式”有细微差别 - 由于套接字是慢速接收器,bytesAvaliable可以一次从板上捕获超过1个数据包所以你必须自己发送readed数据,请在下面检查我的代码!我的代码从惯性传感器获取38个字节的数据包,所以你只需要改变字节数! 0xAA是每个下一个数据包的第一个字节,因此如果找到0xAA字节并且有38个字节,则会得到数据包并使迭代器无效。但无论如何,我确信你有时会丢失数据,因为它不是高频数据传输方式 的 的
的public void run() {
byte[] bytes = new byte[38];
int iterator = 0;
while (true) {
try {
int bytesAvailable = mmInStream.available();
if (bytesAvailable > 0) {
byte[] curBuf = new byte[bytesAvailable];
mmInStream.read(curBuf);
for (byte b : curBuf) {
if (b == (byte) 0xAA && iterator == 38) {
mHandler.obtainMessage(MainActivity.DATA_READ, bytes.length, -1, bytes).sendToTarget();
iterator = 0;
bytes[iterator] = b;
} else {
bytes[iterator] = b;
}
iterator++;
}
}
} catch (IOException ex) {
Log.e(TAG, "disconnected", ex);
connectionLost();
break;
}
}
}
的