Android的蓝牙InputStream的实时阅读 [英] Android Bluetooth InputStream real time read

查看:171
本文介绍了Android的蓝牙InputStream的实时阅读的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在通过蓝牙接收到的实时数据,并绘制在屏幕上的Andr​​oid应用程序的工作。

I am working on an Android application that receives a real time data by Bluetooth and plots it on the screen.

的数据是一个陀螺仪传感器的位置信息。我从一个自定义的Kinetis飞思卡尔微控制器K10板(由我自己设计和测试)发送。对于蓝牙通信,我使用HC-05蓝牙模块。

The data is a gyro sensor position information. I am sending it from a custom Freescale Kinetis K10 microcontroller board (designed and tested by myself). For the Bluetooth communication I am using HC-05 Bluetooth module.

数据的格式如下所示:

byte_1:位置识别字节,恒等于-128

byte_1: position identification byte, always equals to -128

byte_2:1轴位置

byte_2: position of axis 1

byte_3:2轴位置

byte_3: position of axis 2

byte_4:轴3的位置

byte_4: position of axis 3

我不断地发送这些4个字节一个接着一个,在那个特定的顺序。我送这个包的4个字节的每5毫秒和发送数据包需要大约4.7毫秒(9600波特率)。
从微控制器输出的数据是完美的精度和定时(与逻辑分析仪检查)的条款。

I am sending these 4 bytes continuously one after another, in that particular order. I am sending this packet of 4 bytes every 5 ms and sending the packet takes about 4.7 ms (9600 baud rate). The data output from the microcontroller is perfect in terms of accuracy and timing (checked with a logic analyzer).

的问题是,当正在从电话接收到的它的一些字节似乎迷路。这里是code的一部分,在那里我读InputStream的:

The problem is that when it is being received from the phone, some of the bytes seem to get lost. Here is the part of the code, where I am reading the 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是保持许多不同的变量是独生子。

sendArray is a singleton that keeps many different variables.

errorTilt,errorRoll和errorPan是轴的电流值,其被从上述接收缓冲器更新。

errorTilt, errorRoll and errorPan are the current values of the axis, which are being updated from the receiving buffer.

位置保持位置识别字节的位置。它被用于检查,如果任何变量已被更新。

"position" keeps the position of the position identification byte. It is used for a check if any variables have been updated.

很多时候只是一个字节输入缓冲区,因为我不知道哪个轴是,应该是收到,因为我没有关于它的信息是该位置的字节相对位置,这个特殊的字节是没用的和丢失。

Many times just one byte is received in the input buffer and since I don't know which axis is that supposed to be, since I don't have information about it's relative position to the position byte, this particular byte is useless and gets lost.

我已经测试通过下面的方法接收的准确性。我做了MCU输出三角波在轴线之一,而不是轴​​数据。在电话中三角波的线不直,因为他们应该是,但随机弯曲和含文物。

I've tested the accuracy of receiving by the following method. I made the MCU output a triangular wave on one of the axis, instead of the axis data. On the phone the lines of the triangular wave are not straight as they are supposed to be, but randomly curved and containing artifacts.

要绘制数据我使用GraphView,我从一个单独的线程上更新等间隔的图形。

To plot the data I am using GraphView and I am updating the graph on equal intervals from a separate thread.

我已经使用较长的接收缓冲器(与改进的接收算法)试过了,但是这并不能帮助因为是在同一时间接收只有几个字节。

I've tried using longer receiving buffer (with a modified receiving algorithm), but this doesn't help as only a few bytes are being received at a time.

我试过实现InputStream.available(),但它总是给人提供127个字节,这似乎是不正确的。

I've tried implementing InputStream.available() but it was always giving 127 bytes available, which didn't seem to be true.

我读过有关类似的问题很多线程和我花了5天工作,但我无法找到一个很好的解决方案。

I've read many threads about similar problems and I spent the last 5 days working on it, but I couldn't find a good solution.

要总结,我需要实现准确,实时(或接近实时)接收所有字节。

To summarize, I need to achieve accurate, real time (or close to real time) receiving of all the bytes.

主题有一个类似的问题:
<一href=\"http://stackoverflow.com/questions/24934464/how-to-do-good-real-time-data-streaming-using-java-android-sdk\">How使用做好实时数据流Java的Andr​​oid SDK中

Thread with a similar problem: How to do good real-time data streaming using Java Android SDK

感谢您。

更新:

我试图发送的信息只是其中一个轴,所以它是简单明了,无需位置字节​​。我再次发送它每5毫秒,但是这一次是连续字节之间更多的时间,因为它是在数据包只是一个字节。

I've tried sending the information just for one of the axis, so it is simple and clear, without the need of position bytes. I was sending it again every 5 ms, but this time it was more time between the consecutive bytes, since it's just one byte in the packet.

我用InputStream.read()。此时,不要求一个缓冲器。然而,输入数据再次被损坏,因为随机字节不能被接收。

I used InputStream.read() this time, which doesn't require a buffer. However, the incoming data was corrupted again, because random bytes couldn't be received.

我用这个方法成功,我不知道为什么它不和我一起工作了不同类型的项目。我想这可能与我使用HC-05蓝牙模块出了问题,但我想一个不同的 - HC-06,情况是一样的。我没有尝试过不同的电话,但我的手机(三星Galaxy S3的Andr​​oid 4.1.2)似乎是工作确定。

I've seen different project using this method successfully, I don't know why it's not working with me. I thought it might be a problem with the HC-05 Bluetooth module I'm using, but I tried a different one - HC-06, and the situation is the same. I haven't tried a different phone, but my phone (Samsung Galaxy S3, Android 4.1.2) seems to be working OK.

UPDATE2:我试过从流中读取之前再次测试原来的code。与InputStream.available()

UPDATE2: I've tried again testing the original code with InputStream.available() before reading from the stream.

当条件是可用的()> 0,没有大的变化,也许它的工作原理略差。
当条件是可用的()> 1时,它从不读取。我想这是因为不可靠可用的()方法,因为它在文档中说。

When the condition is available()>0, there are no major changes, maybe it works slightly worse. When the condition is available()>1, it never reads. I guess that is because of the unreliable available() method, as it says in the documentation.

推荐答案

您的数据不正确处理,如果你想从微控制器板的数据。你必须使用bytesAvaliable由于Android的蓝牙Socket是pretty单片机电路板与蓝牙放缓。但bytesAvaliable路有细微差别 - 由于插座是缓慢的接收器,bytesAvaliable可以捕获从板多于1包在一个时间,让你得自己devide readed数据,检查我的code如下!我的code是从惯性传感器,所以你得只有字节计数的变化得到38字节的数据包!和0xAA是每一个数据包的第一个字节,所以如果你发现和0xAA字节,并有38个字节你得到数据包,并抵消迭代器。但无论如何,我敢肯定,你仍然可以有时会丢失数据,因为它不是高频数据转流方式

you have incorrect processing of data, if you want to get data from microcontroller board. You have to use bytesAvaliable because android bluetooth Socket is pretty slow over microcontroller boards with bluetooth. But "bytesAvaliable way" has nuance - As socket is slow receiver, bytesAvaliable can catch more then 1 packet from board in one time so you gotta devide readed data by yourself, Check my code out below! My code is getting 38 bytes packets from inertial sensor so you gotta only change count of bytes! 0xAA is the first byte of every next packet so if you find 0xAA byte and have 38 bytes you get packet and nullify iterator. But anyway I'm sure that you still can sometimes lose data because it's not high frequency data transfering way

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;
                }
            }
}

这篇关于Android的蓝牙InputStream的实时阅读的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆