Bluetooth data transfer

frohr

Well-known member
Hey,
I want to send data (array of 30000 floats) to PC. Now I have it via USB. I found some examples with Serial.write but it seems too slow.
What is important for me is to transfer data under 0.5 second.
Does anyone have experience with this?
Thanks
 
Hey,
I want to send data (array of 30000 floats) to PC. Now I have it via USB. I found some examples with Serial.write but it seems too slow.
What is important for me is to transfer data under 0.5 second.
Does anyone have experience with this?
Thanks

30000 floats x 4 bytes/float / 0.5 sec = 240000 bytes/sec = 2.4Mbps

Teensy 4.x can go a lot faster than that. Based on a long thread I've seen on the forum, the issue is probably that your PC is not keeping up on the receive side. However, since you have not said (or shown code) for the Teensy, it could also be related to how you are sending the data. There's no way to say without more information.
 
I am working with this basic code. For testing I am trying terminal on my mobile but I see only nonsense letters. Tomorrow I will have bluetooth adapter for my PC.

Code:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(0, 1); // RX, TX
float y = 0;
#define BUFFER_SIZE     (30000)
float buf[BUFFER_SIZE];

void setup()
{
  Serial.begin(38400);
  mySerial.begin(38400);
}
void loop()
{
  for (int i = 0; i < BUFFER_SIZE; i++) {
    y = random(1, 500) / 100.0;
    buf[i] = y;
//  mySerial.write(y);
  }
  mySerial.write(buf);
  delay(1000);
}

I tried just mySerial.write(y); in For loop but does not work.
 
Try using mySerial.print. This translates the data into ASCII values. .write just sends raw binary data that is why you are seeing "nonsense letters".
 
Sorry I don't fully understand your setup and/or expectations... For example what Teensy are you using?

Also your above code does not build for T4.1 at least with IDE2...
I am not sure about link error I am seeing, but lots of valid warning/errors on the line: mySerial.write(buf);

Code:
C:\Users\kurte\Documents\Arduino\yyy\yyy.ino: In function 'void loop()':
C:\Users\kurte\Documents\Arduino\yyy\yyy.ino:19:21: warning: invalid conversion from 'float*' to 'uint8_t {aka unsigned char}' [-fpermissive]
   mySerial.write(buf);
                     ^
In file included from C:\Users\kurte\Documents\Arduino\yyy\yyy.ino:1:0:
c:\Users\kurte\Documents\Arduino\libraries\SoftwareSerial/SoftwareSerial.h:64:17: note:   initializing argument 1 of 'virtual size_t SoftwareSerial::write(uint8_t)'
  virtual size_t write(uint8_t byte);
                 ^

That is it is not sure what to write... believe your line might need to be something like: mySerial.write((char*)buf, sizeof(buf));
which will now write out 30000*4 bytes over the serial port.

However what do you have on the other side that will receive this binary data? Each float is encoded in specific way which could be very different between processors. So something like terminal is probably
just going to show garbage.

Now you could output ASCII string for your floats by doing something like: Serial.print(y, 2);
which will print out y with two decimal places... but then you data may be very likely increase in size and be variable length.
 
Another thing I meant to mention was wondering why are you including SoftwareSerial here?

You should simply use Serial1 instead... It has been awhile since I looked at SoftwareSerial on T4.x, but I think it may simply redirect to Serial1 anyway, but...
 
I am testing this code:

Code:
#include <SoftwareSerial.h>
#define RX 0 
#define TX 1
SoftwareSerial sserial =  SoftwareSerial(RX, TX); 
String data; 
#define BUFFER_SIZE     (100)
String buf[BUFFER_SIZE];

void setup() {
  sserial.begin(9600);
  for(int i=0; i<BUFFER_SIZE; i++) {
      buf[i] = "1";
    }
}

void loop() {   
  while(sserial.available()) {      
    char c = sserial.read();  
    if (c != -1) {
      data += c; 
      if (c == '\n') { 
        Serial.println(data);
        sserial.print(data);  [B]// no problem - I can see text on my mobile[/B]
        sserial.write((char*)buf, sizeof(buf)); [B] // I see just nonsense chars on my mobile[/B]
        data = "";
        break;
     }
    }
  }  
}

I can see correct text with sserial.print(data);
With sserial.write((char*)buf, sizeof(buf)); I see nonsense - see picture:

mobile-BT.jpg
 
UPDATED code but same issue:

Code:
String data; 
#define BUFFER_SIZE     (100)
String buf[BUFFER_SIZE];

void setup() {
  Serial1.begin(9600);
  for(int i=0; i<BUFFER_SIZE; i++) {
      buf[i] = "1";
    }
}

void loop() {   
  while(Serial1.available()) {      
    char c = Serial1.read();  
    if (c != -1) {
      data += c; 
      if (c == '\n') { 
        Serial.println(data);
        Serial1.print(data);  // no problem - I can see text on my mobile
        Serial1.write((char*)buf, sizeof(buf));  // I see just nonsense chars on my mobile
        data = "";
        break;
     }
    }
  }  
}
 
UPDATED code but same issue:
Not sure what you are expecting with 100 String objects.
Note I typically never use String objects, but...

Try:
Code:
String data; 
#define BUFFER_SIZE     (100)
char buf[BUFFER_SIZE];
int cch = 0;

void setup() {
    Serial1.begin(9600);
    for(int i=0; i<BUFFER_SIZE; i++) {
      buf[i] = `1`;
    }
}

void loop() {   
   while(Serial1.available()) {      
     int  c = Serial1.read();  
     if (c != -1) {
       data += c; 
       buf[cch++] = c;
       if (c == '\n') { 
         Serial.println(data);
         Serial1.print(data);  // no problem - I can see text on my mobile
         Serial1.write(buf, cch);  // I see just nonsense chars on my mobile
         data = "";
         cch = 0; 
         break;
      }
     }
   }  
 }
maybe some typos here, but hopefully should give you more hints...
 
Yes, you are right, I want to send float values. If I use your code, I can see on my mobile just "971310a"

With this code I can see floats on my mobile but seem quite slow.

Code:
String data; 
#define BUFFER_SIZE     (30000)
String buf[BUFFER_SIZE];
int in_time;
int out_time;

void setup() {
  Serial1.begin(9600);
}

void loop() {   
  while(Serial1.available()) {      
    char c = Serial1.read();  
    if (c != -1) {
      data += c; 
      if (c == '\n') { 
        Serial.println(data);
        Serial1.print(data); 
        in_time = micros();
        for(int i=0; i<BUFFER_SIZE; i++) {
          buf[i] = String(random(1, 500) / 100.0);
          Serial1.println(buf[i]);
        }
        out_time = micros();
        Serial.println(out_time-in_time);
        data = "";
        break;
     }
    }
  }  
}
 
I am testing this code:

Code:
#include <SoftwareSerial.h>
#define RX 0 
#define TX 1
SoftwareSerial sserial =  SoftwareSerial(RX, TX); 
String data; 
#define BUFFER_SIZE     (100)
String buf[BUFFER_SIZE];

void setup() {
  sserial.begin(9600);
  for(int i=0; i<BUFFER_SIZE; i++) {
      buf[i] = "1";
    }
}

void loop() {   
  while(sserial.available()) {      
    char c = sserial.read();  
    if (c != -1) {
      data += c; 
      if (c == '\n') { 
        Serial.println(data);
        sserial.print(data);  [B]// no problem - I can see text on my mobile[/B]
        sserial.write((char*)buf, sizeof(buf)); [B] // I see just nonsense chars on my mobile[/B]
        data = "";
        break;
     }
    }
  }  
}

I can see correct text with sserial.print(data);
With sserial.write((char*)buf, sizeof(buf)); I see nonsense - see picture:

View attachment 28877
As I said earlier if you use write you are sending 4 BYTES of BINARY data. If you used print that binary data is converted into MANY MORE BYTES is ASCII text.
Code:
    uint32_t num;

    num = 1094795585;    // = 0xAAAA
    Serial.print(num);  // will print ASCII representation of num - 1094795585 to the screen / serial port - 10 BYTES

    Serial.write(num);  // will print the binary representation of num - A to the screen / serial port
 
OK, thanks! Now I have continue with my Python code to read bluetooth and decode binary data.
 
Now I use this code and it works if I send data in loop. But not if I send data as array (buf):

Code:
#define BUFFER_SIZE     (30000)
float buf[BUFFER_SIZE];
char inChar;
float num;

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {   
  if (Serial1.available() > 0) {
    inChar = Serial1.read();// get incoming byte:
    for(int i=0; i<BUFFER_SIZE; i++) {
      buf[i] = 1;
      //Serial1.write(char(buf[i])); //Works OK but very slow of course - it takes 16 secodns to read id in Python
    }
    Serial1.write((char*)buf, sizeof(buf)); // I receive sometimes 1 number or 10 numbers but not more
    Serial.println("Array sent.");
   }  
}

Python code:
Code:
import bluetooth
import time
v_data = []
rec_value = 0
value = 0
bd_addr = "FC:A8:9A:00:22:33" 
port = 1
sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
sock.connect((bd_addr, port))
print('Connected')
sock.send("r")
print('Sent char to start sending data from Teensy')
rec = 0
start_time = time.time() 
while rec < 1: # or < 30000 for reading one by one
    #value = sock.recv(1)
    #rec_value = ord(value)
    #v_data.append(rec_value) # I can rear 30000 values but very very slow
    v_data = sock.recv(30000)  # does not work
    #if rec_value == 0: break
    rec += 1
end_time = time.time()
print(end_time-start_time)
print(v_data[0:100])
print(len(v_data))
print("Finished")

Any idea how to improve my code?
Thank you
 
Sorry I am not really sure what your code is doing.

So if you have received at least one byte on Serial1, you then read it in: inChar = Serial1.read();// get incoming byte:
You then never actually use what you read in. Which I understand is just the trigger.

You then loop 30000 times filling an array of floats with the value 1, which will be converted to a 4 byte value and stored in the
And the way you say works, but is slow, you send I believe one byte of the float value.
//Serial1.write(char(buf)); //Works OK but very slow of course - it takes 16 secodns to read id in Python

In the other case you send: Serial1.write((char*)buf, sizeof(buf)); // I receive sometimes 1 number or 10 numbers but not more
300000 * 4 bytes or 120,000 bytes at 9600 baud, or about 960 characters per second = or about 2 minutes

As for the Python, I have no idea what it is doing. Python is not my my main language, although I have gotten better with it using CircuitPython and doing some HLA for the Saleae Logic Analyzer...
And I have never used Bluetooth on it.
So I don know what : v_data = sock.recv(30000)
Is supposed to do? I can guess it is supposed to recv 30000 bytes? But you are actually trying to receive 30000 4 byte values.
And it is possible that the internal format of the float could be different between the two processors. For example the order of the bytes that are stored in memory could be reversed...

So again that could be one of your issues...
 
Teensy is waiting for char and then starts sending array via bluetooth. I fill array by some numbers and then I want send all array via bluetooth
Code:
Serial1.write((char*)buf, sizeof(buf));

I can setup higher baudrate - I am sure, if I play for example mp3 via bluetooth there must be also lot of data quite fast.

I think, teensy code works well (if I setup higher speed). I have problem to catch data in Python and decode them. Or am i wrong?
 
I understand what you are trying to do. The issue is more with the details.

And isolating where the issues with code and hardware.

For example you say you send using Bluetooth. So for example which Serial to Bluetooth adapter are you using?
For example if you are using the Adafruit one: https://www.adafruit.com/product/2479

As far as I can tell, the Uart talks at 9600, Not sure if you can set it higher or not. My quick look through their tutorial pages, I did not see any way to change the baud rate. Some other may have some command string to do so, but again not sure.

You say you need to send 30000 values in a half second. At 9600 baud with data (8 bits plus start and stop big) you can send max 960 characters per second or 480 in half second. And that is just the bottleneck from Serial1 to the your bluetooth adapter. Now maybe you have an adapter that can communicate faster with Teensy.

Hardware wise do you need to have RTS and CTS pins connected between your processors and Bluetooth?

Assuming you can get a higher baud rate, then you probably need to check the to see if the Bluetooth Profile will support the throughput you need. I believe the two bluetooth adapters are talking Serial Port Profile (SPP).

So with basic math of (30K items 4 bytes per item, each byte is 10 bits and in half second) 300000 *4 * 10 *2 = 2400000 baud rate 2.4M.
Yes Teensy Uart can talk that fast. Not sure if SPP can or not..

Then there is the data. You say you want to send that many floats... Question is are these completely random float values or are they in some specific range. For example if the range is 0.0 to 1.0
And how much precision do you need? if for example 3 or 4 decimal places is sufficient. Then you could send the values as integers, like multiply by 1000 and send as uint16_t, which would cut your
amount of data in half.
Also if it is sent as integers, easy to reconstruct on other side. Take two bytes at a time, and shift one byte by 8 bits and add the second byte. Which of the two bytes is shifted depends on your receiving processor....

Again order of bytes.. Which is why a lot of devices for example Servos will do things like specify the order of the bytes when you talk to them with values which take more than one byte.

Sorry not sure if this helps or not.
 
I use HC-05. It seems it there is higher baud rate possible (1382400 baud rate?)

https://www.instructables.com/Modify-The-HC-05-Bluetooth-Module-Defaults-Using-A/

Floats are numbers from adxl accelerometer and 24 bit adc converter. I need maximum precision.
Now I use serial communication via USB and it is OK (30k floats in 0.2 second), but lot of noise via cable and will be much better in field without cables.

Or will be better use wifi instead bluetooth?
 
Sorry, some of this stuff, I think you are just going to have to experiment with:

Example, again suppose you can run at the baud rate you specified: 1382400
Quick check: (30000 * 4 * 10)/1382400 = .868055 seconds

And again that is just the UART speed. Unclear about how fast you can push the data through Bluetooth SPP. Some sites say 1MBS some say can go up to 2MBS with some hardware...

Wifi - I have not tried any Serial to WIFI adapters...

There could be other options, like T4 supports USB Host. We do support some Bluetooth, however I don't think anyone has implemented SPP... I know I have not.
I don't know any general Wifi Adapter support yet. Wanted to do some, but... But there is support for Ant+ https://en.wikipedia.org/wiki/ANT_(network) that was added,
but this does not have anywhere near the throughput you need.
 
I am checking now my code for usb cable data transfer and try to modify for bluetooth.

Code:
#define BUFFER_SIZE     (300)
float buf[BUFFER_SIZE];
char inChar;
float num;
float adc_volt;

void setup() {
  Serial.begin(115200);
  Serial1.begin(115200);
}

void loop() {   
  if (Serial1.available() > 0) {
    inChar = Serial1.read();// get incoming byte:
    for(int i=0; i<BUFFER_SIZE; i++) {
      adc_volt = random(100);
      byte *b = (byte *)&adc_volt;
      Serial1.write(b[0]);
      Serial1.write(b[1]);
      Serial1.write(b[2]);
      Serial1.write(b[3]);
    }
   }  
}

in Python I have:
Code:
import bluetooth
import struct

SAMPLES= 300
s = struct.Struct('<' + str(SAMPLES) + 'f')
bt_data = []

bd_addr = "FC:A8:9A:00:22:33" 
port = 1
sock=bluetooth.BluetoothSocket(bluetooth.RFCOMM )
sock.connect((bd_addr, port))
print('Connected')
sock.send("r")
print('Sent char to start sending data from Teensy')

bt_data = sock.recv(SAMPLES*4)
unpacked_data = s.unpack(bt_data)

print(unpacked_data)
print(len(unpacked_data))

But I have error in Python:
Traceback (most recent call last):
File "c:\Users\frohr\bt.py", line 18, in <module>
unpacked_data = s.unpack(bt_data)
struct.error: unpack requires a buffer of 1200 bytes

Could it works or is it nonsense?
 
Sorry I only know enough Python to be dangerous...

I do a lot of google each time I try anything...

like how to convert byte array to float...
https://stackoverflow.com/questions/56396524/how-to-convert-a-byte-array-to-float-in-python

What I would try to do is something logically like:
So I know I have: bt_data = sock.recv(SAMPLES*4)

I am not sure what bt_data is, but lets assume something like bytearray: logically something like:
Code:
for i in range(0, len(bt_data, 4):
    print(struct.unpack('>f', bt_data[i:4]))
    print(struct.unpack('<f', bt_data[i:4]))
And I would see if either of them looked correct (and did not error out)

If that worked I would probably have created a collection or an array and instead of printing I would add that value to the collection or array.

At least that is how I would stumble along on this.

For testing I would also on Teensy side set the values to known data, such that I could easier tell if the data I am seeing in python is correct or not
 
Good questions... There are several different manufacturers of breakout boards for NRF24l01+ For example I see several up on Amazon...

Will it work for you? Don't know, you can pickup a few of them pretty cheap, so you can always give them a try.
Note: they connect up using SPI instead of Hardware Serial, so it may depend on if you can connect it up on both sides... Easy on Teensy.
Maybe others here have played with them and give more insight.

Some of the things you may need to look at and experiment with include things like:

Things like: Distance, how much interference is there...
It says up to 2mbs, but what does that mean? Can it reliably send 120000 bytes of data
Do you need to first receive a request from Host and then send data? How long does it take for this module to switch from RX to TX?
Or can you hook up two per node, one for Rx and other for TX?
...

Earlier message (#19) mentioned cable that was too noisy. Have you tried some form of shielded cable?
What about RS485. Use an RS485 Transceiver on both sides connected up to Hardware serial port...
 
I measured low noise on my PC:

PC-noise.jpg

And much higher nosie with my laptop and tablet:

tablet-noise.jpg

Now I am pretty sure it will be not possible to send my data via bluetooth so I have to solve the noise.
¨
As you mentioned, I will try RS485.

Maybe those devices will help (It is in Czech but easy to translate...)

https://www.laskakit.cz/usb-2-0-izolator/#relatedFiles

Which one RS485 will be better?

https://www.laskakit.cz/prevodnik-usb-rs485--ch340/

or

https://www.laskakit.cz/prevodnik-uart-na-rs-485--max485/

THANKS!
 
Back
Top