I've been struggling with the problem of sending continuous data from arduino to Android.
What I want to do is get analog read convert it to 0-5V information, and send that information to Android app.
My arduino code is just simply:
//(...)defining pins and levels
SoftwareSerial BTSerial(rxPin, txPin);
void setup()
{
pinMode(getData, INPUT);
digitalWrite(keyPin, LOW);
BTSerial.begin(9600);
}
void loop()
{
contact = digitalRead(getData);
if (contact == HIGH) {
sensorValue = analogRead(sensorPin);
double voltage = sensorValue * (5.0 / 1023.0);
if (BTSerial.available()) {
Serial.write(BTSerial.read());
}
BTSerial.println(voltage, 3);
BTSerial.write("\r");
if (Serial.available()) {
BTSerial.write(Serial.read());
}
}
delay(5);
}
I need to send data informing about measurment with ~200Hz frequency.
After sending the data to application it seems that part of data is lost.
I tried higher bound rates but the problem still occurs. Is there a way to send continuous data from arduino using serial port without loosing some % of that data?
I think the problem is in the design of the receiver. I Solved BTL communication in .net Xamarin, but the principle should be the same. In Android reading from InputStream must be quick and can not use sleep. You need to use an endless cycle and there quick read data into temp buffer. Immediately a dune bytes to an auxiliary large buffer (use read / write cursor) and then, for example, in timer treat the data (I suppose you are using some packet protocol)
public override void Run()
{
WriteLogInfoToLog("ConnectedThread.Run() - before");
while (true)
{
try
{
int readBytes = 0;
lock (InternaldataReadLock)
{
readBytes = clientSocketInStream.Read(InternaldataRead, 0, InternaldataRead.Length);
Array.Copy(InternaldataRead, TempdataRead, readBytes);
}
if (readBytes > 0)
{
lock (dataReadLock)
{
dataRead = new byte[readBytes];
for (int i = 0; i < readBytes; i++)
{
dataRead[i] = TempdataRead[i];
}
}
}
}
catch (System.Exception e)
{
btlManager.btlState = BTLService.BTLState.Nothing;//Spadlo spojeni, musi spustit cele od zacatku
WriteLogInfoToLog("ConnectedThread.Run() - EXCEPTION " + e.Message + ", " + e.HResult + ", " + e.StackTrace + ", " + e.InnerException);
if (e is Java.IO.IOException)
{
}
else
{
}
break;
}
}
WriteLogInfoToLog("ConnectedThread.Run() - after");
}
Related
I'm try to send and receive data between Android device and Arduino Mega 2560 via bluetooth low energy bt-410,
When I receive data type is byte[] and I decode to string it's a question symbol so I try to Log byte[] convert to byte and then value is -32, and when I send some string from my app to Serial Monitor in Arduino is nothing.
how can I send and receive data?
//Receive data:
#Override
public void onCharacteristicChanged(BluetoothGatt mGatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(mGatt, characteristic);
String textRX;
try {
textRX = new String(characteristic.getValue(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
writeLine("Received: " + textRX);
hideKeyboard();
scrollDown();
}
//Send data:
public void sendClick(View view) {
String message = editInput.getText().toString();
if (tx == null || message.isEmpty()) {
return;
}
try {
value = message.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
tx.setValue(value);
if (mGatt.writeCharacteristic(tx)) {
writeLine("Sent: " + message);
editInput.setText("");
hideKeyboard();
scrollDown();
Log.e("textTX", tx + "");
} else {
writeLine("Couldn't write TX characteristic!");
}
}
//Arduino Code:
String inputString="";
void setup() {
Serial.begin(9600);
}
void loop() {
if(Serial.available() > 0) {
inputString = Serial.readStringUntil('\n');
Serial.println(inputString);
if (inputString == "R1") {
delay(100);
Serial.println("R1 on");
}
}
delay(10);
}
Bytes in Java are signed, not the most bone-headed decision I've ever seen but it comes close. There are possibly use cases where it makes sense to treat it as signed, but I can't think of any off the type of my head. I probably would have preferred an unsigned byte type, using a type like shorter as the signed variant :-)
In any case, that means that getting a value greater than 127 from your comms channel is going to look like a negative number to Java.
More precisely, it will look like unsignedEquivalent - 256 and that should therefore provide you the clue on how to "fix" it.
Take your byte, put it into a wider data type (such as int), then add 256:
byte bdata = -32; // should have been 224
int idata = bdata;
idata + 256; // is 224
I am working on an Android application that receives a real time data by Bluetooth and plots it on the screen.
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.
The format of the data is as follows:
byte_1: position identification byte, always equals to -128
byte_2: position of axis 1
byte_3: position of axis 2
byte_4: position of axis 3
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).
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 is a singleton that keeps many different variables.
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.
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.
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.
I've tried implementing InputStream.available() but it was always giving 127 bytes available, which didn't seem to be true.
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.
Thread with a similar problem:
How to do good real-time data streaming using Java Android SDK
Thank you.
UPDATE:
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.
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.
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: I've tried again testing the original code with InputStream.available() before reading from the stream.
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.
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;
}
}
}
Moved from Android forums
Im at a loss here. It want to send some serial data from arduino to android but what I send is not what is received. For example, If I put Serial.write(5), on the android side I get 48. If I put Serial.write(6) I get 1. The same problem happens when I send characters. If I send a 't', on android I get a T with 2 points on top(as if its a character from another language). ??????? What's happening?
Arduino
int count = 5;
const unsigned int BAUD_RATE = 115200;
void setup() {
Serial.begin(BAUD_RATE);
delay(10000);
}
void loop() {
//Serial.print(count, DEC);
//Serial.print(count, HEX);
Serial.print(count, OCT);
//Serial.println(count, BIN);
//Serial.write(temp);
//Serial.write("t");
Serial.write(count);
count++;
delay(2000);
}
Android
RFComm: UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
byte[] buffer = new byte[255];
Handler myHandler1 = new Handler();
Runnable receiveValues = new Runnable() {
public void run() {
try {
while (connected) {
while (in.available() > 0) {
Log.v("Note",
"For value: " + String.valueOf(in.read(buffer)));
for (int x = 0; x < buffer.length; x++)
Log.v("Note", "A " + buffer[x]);
}
Thread.sleep(50);
}
} catch (Exception e) {
connected = false;
e.printStackTrace();
}
}
};
The timing is right, every two seconds something gets sent but still I get the wrong value. As you can also see, I tried other ways to write to the serial port on the arduino but none of them work. Another thing, the end of line(when I do Serial.println()) is consistently received as a 0 on android.
Running on android 2.3.7 where min sdk = 8 (android 2.2)
Answer is really simple... Forgot about int ranges(-32768 to +32767) or in this case unsigned int(0 - 65534) and when I directly entered the baud rate, it worked well.
Serial.begin(115200);
I am having a strange issue with reading an writing to/from the Bluetooth Socket on my Samsung Express (4.1.2). The issue does not present itself when I run the App on my Google Nexus 4 (4.3)
When I attempt to do any action on the socket i get a "genlock attach lock open" msg in my Logcat. Normally followed quickly with a "genlock close" . The issue here is that if I attempt to write onto the socket I get a "genlock close" , the data is sent successfully, but I cannot access new data in the input stream until the lock opens again.
Also there are numerous "availableNative" messeges popping up in the Logcat.
Here is the code where I send a command , wait for 0.5 second and attempt to read the input buffer:
public boolean ReadFaultTable()
{
byte[] in_packet = new byte[100];
int err_byte_count;
int err_symp_count;
if(!(BTCheck()))
{
Log.i(TAG,"ReadFaultTable() BT Fail!");
//Toast.makeText(getApplicationContext(), "Socket not open for fault read", Toast.LENGTH_SHORT).show();
return false;
}
byte [] out_packet = new byte[1];
out_packet[0]= 0x0a;//READ_CURRENT_FAULT_CODES_CMD
byte []full_packet=AddDRCheckSum(out_packet);
connectedThread.clearBuffer();
try{
Thread.sleep(200);
}
catch(InterruptedException e){}
connectedThread.write(full_packet);
Log.i("Read Faults", "After Write");
sleepForProcessingTime(500);
Log.i("Read Faults", "0.5 Secs, Num Bytes = "+Integer.toString(connectedThread.bytesAvail()));
if(connectedThread.bytesAvail() > 3)
{
//Log.i("Read Faults", "bytes avail = " + Integer.toString(connectedThread.bytesAvail()));
for (int i =0;i<3;i++)
{
Log.i("Read Faults", "In here");
if((in_packet[i]=connectedThread.readByte())==-1)
{
Log.i(TAG, "End of Input stream reached on iteration= "+ Integer.toString(i));
return false;
}
Log.i("Read Faults", "Byte read in =" +Integer.toHexString(in_packet[i]));
}
}
else
{
Log.i("Read Faults", "No Bytes to read .. return false");
return false;
}
/*
if(connectedThread.bytesAvail() > 0)
{
in_packet= new byte[connectedThread.bytesAvail()];
in_packet = connectedThread.read();
Log.i("Read Faults","Bytes Read in =" + printCMD(in_packet));
}
*/
Log.i("Read Faults", "Made it here with "+ printCMD(in_packet));
int fault_table_index =0;
if (in_packet[0] == 0x0A && in_packet[1] == 0x0E )
{
Log.i("Read Faults","in packet passed checks");
err_byte_count=in_packet[2];
fault_table= new boolean[err_byte_count*8];
Log.i("Read Faults","err byte count = "+ Integer.toString(err_byte_count));
for (int i=0;i<(err_byte_count);i++)
{
int val =connectedThread.readByte();
Log.i("Read Faults","Next byte read in =0x" + Integer.toHexString(val));
in_packet[3+i]=(byte)val;
int mask =0x01;
for (int x = 0; x < 8; x++)
{
if ((val & mask)== mask)
{
Log.i("Read Faults","Fault Index "+ Integer.toString(fault_table_index +1) + "true");
fault_table[fault_table_index++]=true;
}
else
{
Log.i("Read Faults","Fault Index "+ Integer.toString(fault_table_index +1) + "false");
fault_table[fault_table_index++] = false;
}
mask <<= 1;
}
}
Log.i("Read Faults","Made it to here");
in_packet[3 + err_byte_count] = (byte)connectedThread.readByte();
err_symp_count = in_packet[3 + err_byte_count];
symp_table = new byte[err_symp_count];
for (int i=0; i < err_symp_count; i++)
{
in_packet[3 + err_byte_count + 1 + i] = (byte)connectedThread.readByte();
symp_table[i] = in_packet[3 + err_byte_count + 1 + i];
}
return true;
}
else
{
return false;
}
}
If I was to run this command once the bytes will never reach the inputStream , but if i ran the command again, all of the bytes are there from the first time, it's like a flood gate gets opened. I'm stumped. Can anyone help ? (Note the write and read commands all work else where in the app and the Bluetooth socket is functioning for other commands and responses .
Please ask if you require further info.
Just found a work around. For whatever reason the phone did not like the idea of reading more than one byte off the Bluetooth Socket at a time. So I implemented a byte by byte approach that has provided an acceptable patch. I didn't pick up on the socket reporting one byte available before because I was checking for at least 3 bytes on the socket before reading in (this makes sense for my purposes).
Phone continually reports 1 byte available on the inputStream, so you take a byte while the inputStream reports one.
Would still be interested in an explanation if someone has one. Thanks
Using: HTC Legend and HTC Salsa
I'm calculating the speed using:
while(true)
{
try
{
int num = in.read(buffer);
if(reading == false)
{
prevTime = SystemClock.uptimeMillis();
reading = true;
}
else
{
//Calculate KB/s
count += num;
Long deltaTime = SystemClock.uptimeMillis()- prevTime;
if(deltaTime >= 1000)
{
Float speed = (float)count/deltaTime;
Log.d(TAG,"Data: " + speed + "KB/s");
count = 0;
prevTime = SystemClock.uptimeMillis();
}
}
} catch (IOException e) {
}
}
And writing some test data using
out.writeUTF("ababababababababababababababababbabababaababababababababababababababababbabababaababababababababababababababababbabababa" +
"ababababababababababababababababbabababaababababababababababababababababbabababaababababababababababababababababbabababa" +
"ababababababababababababababababbabababaababababababababababababababababbabababaababababababababababababababababbabababa" +
"ababababababababababababababababbabababaababababababababababababababababbabababaababababababababababababababababbabababa");
out.flush();
The writes are within another threads while(true) also.
I'm getting the following results.
02-13 18:17:16.897: D/krazyTag(3432): Data: 31.554672KB/s
02-13 18:17:17.927: D/krazyTag(3432): Data: 29.854227KB/s
02-13 18:17:18.977: D/krazyTag(3432): Data: 29.285034KB/s
02-13 18:17:20.067: D/krazyTag(3432): Data: 38.446888KB/s
02-13 18:17:21.097: D/krazyTag(3432): Data: 35.89484KB/s
02-13 18:17:22.127: D/krazyTag(3432): Data: 33.67118KB/s
02-13 18:17:23.227: D/krazyTag(3432): Data: 33.512726KB/s
02-13 18:17:24.307: D/krazyTag(3432): Data: 33.277622KB/s
Which is confusing me since the phones specs state they use Bluetooth® 2.1 with EDR
Which is capable of 260KB/S but I'm not even getting the old standard 90KB/s
I'm not sure if it's my stream and read/write calls (I'm using a buffered datainputstream)
Or if I'm calculating things wrong or have the wrong information?
I think the speed depends on your implementation of the Send and Receive threads, since you connects 2 Android devices with your own applications. Could you post your implementation?
I got the same problem also.
I am using ACER TAB A500 to communicate with a Bluetooth stick connected to PC and I got even slower result 12,3KB/s for sending data only.
That's why I did some experiments. I sent a message for 10000times and I got that the data rate depends on the length of the message.
For 1KB message, the data rate is 232KB/s. For 40Byte message, the
data rate is 18KB/s. For 1Byte message, the data rate is
0.48KB/s.
Here is my code:
// Get the BluetoothDevice object.
while(true){
driverBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
driverBluetoothDevice = driverBluetoothAdapter.getRemoteDevice("XX:XX:XX:XX:XX:XX");
if (driverBluetoothDevice == null){
break;
}
Method insecureMethod = driverBluetoothDevice.getClass().getMethod("createInsecureRfcommSocket", new Class[] { int.class });
byte portNumber = 5; // The SPP in port 5.
driverBluetoothSocket = (BluetoothSocket) insecureMethod.invoke(driverBluetoothDevice, portNumber);
// Try to connect to the Bluetooth device.
try {
driverBluetoothSocket.connect();
} catch (IOException e1) {
// Failed to connect to the device
break;
}
// Open input and output stream.
try {
driverInputStream = driverBluetoothSocket.getInputStream();
} catch (IOException e) {
break;
}
try {
driverOutputStream = driverBluetoothSocket.getOutputStream();
} catch (IOException e) {
break;
}
byte[] message = new byte[3000];
Random randomGenerator = new Random();
for (int i = 0; i < message.length; i++){
message[i] = (byte) randomGenerator.nextInt(100);
}
Date TimeValue = new Date();
long TimeStamp1 = TimeValue.getTime();
for (int i = 0; i < 10000; i++){
try {
driverOutputStream.write(message, 0, message.length);
} catch (IOException e) {
break;
}
}
TimeValue = new Date();
long TimeStamp2 = TimeValue.getTime();
long TimeDifference = TimeStamp2 - TimeStamp1;
TimeDifference = 0;
break;
}
Not sure if this helps with your speed problem and I could have overlooked this detail in your code snippet but are you reading and writing on the same thread? The documentation suggests you don't,
First and foremost, you should use a dedicated thread for all stream reading and writing. This is important because both read(byte[]) and write(byte[]) methods are blocking calls.
Bluetooth Android Developer