【发布时间】:2014-08-15 16:25:54
【问题描述】:
我正在开发一个通过蓝牙接收实时数据并将其绘制在屏幕上的 Android 应用程序。
数据是陀螺传感器位置信息。我从定制的飞思卡尔 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 是轴的当前值,正在从接收缓冲区更新。
"position" 保存位置标识字节的位置。它用于检查是否有任何变量已更新。
很多时候在输入缓冲区中只接收到一个字节,由于我不知道应该是哪个轴,因为我没有关于它与位置字节的相对位置的信息,所以这个特定字节是无用的然后迷路了。
我已经通过以下方法测试了接收的准确性。我让 MCU 在其中一个轴上输出三角波,而不是轴数据。在手机上,三角波的线条并不像想象的那样笔直,而是随机弯曲并包含伪影。
为了绘制我使用 GraphView 的数据,我正在从一个单独的线程中以相等的时间间隔更新图表。
我尝试过使用更长的接收缓冲区(使用修改后的接收算法),但这无济于事,因为一次只能接收几个字节。
我尝试实现 InputStream.available() 但它总是提供 127 个字节可用,这似乎不是真的。
我已经阅读了很多关于类似问题的帖子,并且我花了过去 5 天的时间来解决这个问题,但我找不到一个好的解决方案。
总而言之,我需要实现对所有字节的准确、实时(或接近实时)接收。
有类似问题的线程: How to do good real-time data streaming using Java Android SDK
谢谢。
更新:
我尝试只为其中一个轴发送信息,所以它简单明了,不需要位置字节。我每 5 毫秒再次发送一次,但这次连续字节之间的时间更长,因为它只是数据包中的一个字节。
这次我使用了 InputStream.read(),它不需要缓冲区。但是,传入的数据再次损坏,因为无法接收随机字节。
我已经看到不同的项目成功地使用了这种方法,我不知道为什么它不适合我。我以为可能是我正在使用的HC-05蓝牙模块有问题,但我尝试了一个不同的——HC-06,情况也是一样。我没有尝试过其他手机,但我的手机(Samsung Galaxy S3,Android 4.1.2)似乎工作正常。
UPDATE2:在从流中读取之前,我再次尝试使用 InputStream.available() 测试原始代码。
条件为available()>0时,没有大的变化,可能效果稍差。 当条件可用()> 1时,它永远不会读取。我想这是因为它在文档中所说的不可靠的 available() 方法。
【问题讨论】:
标签: android bluetooth inputstream