Bluetooth client speed and buffering issue

Dear Sirous please find here below a chunk of Arduino code.
I've tested it on a Uno board.
What it does is:
it initializes the BT line @115200
it acquires a ne value every 10 milliseconds
it converts the byte into the two characters representing the byte
it appends the two characters to a string (initialized to empty every 4 bytes)
when 4 bytes have been acquired it transmits the string once on BT
repeats forever.

I hope the comments wil lhelp you.
This means that you will receive a string on the APP once every 4 bytes. the string has a fixed length of 14 characters: 8 of them are the 4 bytes (two characters each) 4 commas and a CRLF pair.
The two lines commented are for debug purposes only. you can throw them away. I have used them to verify if the algorithm works (it works :slightly_smiling_face:)

On the APP now you receive a unique string of 14 characters terminated with a CRLF pair.
An improvement is: to avoid the commas, since every value is on two characters, so the values that the app receives are always in fixed position in the string : for example char 1 and char 2 are value 1;
char 3 and 4 are value 2 and so on until the CRLF is reached.
In this case you trasmits 4 characters less (the 4 commas). But try first with the commas.

Good luck !
Ugo.


#define baudBT 115200


int i = 0;
String TxBuf;
long oldmillis;
byte ByBuf = 0;
byte CarBy = 0;
char CarHi;
char CarLo;




void setup() {
  // put your setup code here, to run once:
  Serial.begin(baudBT);                                               // initialize baudrate for BT @115200
  
}

void loop() {

         if (millis() - oldmillis >= 10)                              // if 10 milliseconds have elapsed, triggers a new acquisition
         {
               oldmillis = millis();                                  // snapshot to the time for next slot
               ByBuf = map(analogRead(A0), 0, 4096.0, 0, 255);        // acquires from A/D converter and reduces  value to 1 byte
//   ByBuf = ByBuf + 1;                                                 *********** debug  
//   if(ByBuf == 255) ByBuf = 0;                                        *********** debug
               CarBy = (ByBuf & 0xF0) >> 4;                           // keep high nibble and shifts down to right (reduces to 0-0x0F)
               if(CarBy > 9) CarBy += 7;                              // converts to ASCII char (takes into account the gap between number 9 and 0x0A: see ASCII map) 
               CarHi = CarBy +'0';                                    // see above
               CarBy = (ByBuf & 0x0F);                                // repeats for the low nibble (does not need to shift down since it is already on the right) 
               if(CarBy > 9) CarBy += 7;                              // converts to ASCII char
               CarLo = CarBy +'0'; 
               TxBuf = TxBuf + CarHi + CarLo + ",";                   // appends the two characters representing the byte to the string plus a comma 
               i = i + 1;                                             // increases the counter of bytes

               if(i > 3)                                              // four bytes acquired, transmits the buffer on BT
               {

                         Serial.println(TxBuf);                       // transmits the characters to the APP
                         TxBuf = "";                                  // resets the tx buffer to empty  
                         i = 0;                                       // resets the counter
               }
         }
}

Hi

If you are "Receiving commas" and they are being used as the value delimiter, make sure you are using commas as the delimiter in the App. Sounds like you have a mismatch!
The total size of the payload (send string) should not exceed 32 bytes, including the end-of-data character. It is possible to extend this if the sending device allows, by adjusting the MTU, but only when using BLE.

Sorry I forgot to say:
each character pair received by the app represents a single byte: therefore you will receive, for example a string like CF,35,A0,BB, Carriage Return LineFeed.
The pairs shall then be converted in decimal to 207,53,160,187, with an AI2 conversion operation (a math block).
stay tuned :sunglasses:

(I added a ``` line before your inline code, to preserve its indentation. I learned of this markup through word of mouth from ewpatton.)

Wow really awesome! Many thanks for this hint :smiley:
... and with your post I've also leanrt a way of saying ("word of mouth").
Much appreciated.

@Sirous : did you try ? Shall I rewrite it for the NodeMCU ESP board ?
(I should have one, somewhere, lost in a drawer....) :thinking:
Cheers

Not yet!
I am working on a few projects at the same time, plus my regular "job".
I'll test as soon as I can.
Thanks

Sure !!! Take it easy :slight_smile:
Cheers!

Dear friends,

I chose the "comma" approach, with ten bytes in every pack, and I'm happy with the results.
Thank you so much for your help. :heart:

Sirous

2 Likes

Thanks for your feedback Sirous. I'm really happy having been of some help.
in effect an Arduino board is much faster than the CPU we were using to make a spacecraft to fly.... :crazy_face:
Cheers.

1 Like

Hi Sirous

I am running into pretty much the same problem. I am using interrupt to initialize Arduino wakeup and then read via MCP3208 at 200 Hz for 30 seconds, send that to BT via a Bluesmirf and then go back to sleep. When I use a BT serial monitor I can see the data come in nicely but just cannot seem to graph that at all (it just plots random repeating values and not the actual readings). Could I please get some advice on this.

Cheers

Here's the standard advice for BlueTooth (not BLE) text transmission ...


global message
(draggable)

Please see the Delimiter article in FAQ

Be sure to use println() at the end of each message to send from the sending device, to signal end of message. Do not rely on timing for this, which is unreliable.

In the AI2 Designer, set the Delimiter attribute of the BlueTooth Client component to 10 to recognize the End of Line character.

Also, return data is not immediately available after sending a request,
you have to start a Clock Timer repeating and watch for its arrival in the Clock Timer event. The repeat rate of the Clock Timer should be faster than the transmission rate in the sending device, to not flood the AI2 buffers.

In your Clock Timer, you should check

  Is the BlueTooth Client still Connected?
  Is Bytes Available > 0?
     IF Bytes Available > 0 THEN
       set message var  to BT.ReceiveText(-1) 

This takes advantage of a special case in the ReceiveText block:

ReceiveText(numberOfBytes)
Receive text from the connected Bluetooth device. If numberOfBytes is less than 0, read until a delimiter byte value is received.

If you are sending multiple data values per message separated by | or comma, have your message split into a local or global variable for inspection before trying to select list items from it. Test if (length of list(split list result) >= expected list length) before doing any select list item operations, to avoid taking a long walk on a short pier. This bulletproofing is necessary in case your sending device sneaks in some commentary messages with the data values.

Further advice would require examination of your code on both sides.

Hi! I found very interesting this:

Wich are the dimensions of that buffers?? I have some problems with incoming data (via BT) from Arduino (stored in a SdCard).
The Mit app crash down and not processing the whole incoming data.

You can estimate maximal buffer size by setting a Label.Text to BluetoothClient.BytesAvaiabletoReceive each Timer cycle. It will either hover around 0 or climb steadily up to the buffer size, depending on transmit and receive pacing.

As a rule of thumb, the time interval taken by the App to receive and process the data needs to be around 20% faster than the Arduino Loop time interval.

Another rule of thumb is that both intervals should be set to be as slow as practical requirements allow. I have seen people attempt to update their App screen with data every 200 milliseconds or so - which has no merit at all, the human eye cannot follow the information at that speed.

I use that and I can't see the upper limit. Theren't no any official document about this?

If I didn't use delay() in the Arduino sketch, How can I estimate the clock timer interval for Mitapp?

You can alternatively save the last transmit time in milliseconds (system time) in Arduino, and in your delay-free Arduino loop check if (current time milliseconds - last transmit time) exceeds your desired inter-transmission interval.

Hi javier

There are very few times when a delay can be used safely - the reason being that it blocks everything. Here is an example Sketch showing how to use elapsed milliseconds:

//#include<SoftwareSerial.h>

//vars
unsigned int igUpdateTime;
char val[];

void setup()
{
         Serial.begin(9600);
         igUpdateTime = millis();
}

void loop()
{
         //Excute loop every 10 seconds
	     if((millis() - igUpdateTime) > 10000) 
         {
              igUpdateTime = millis();

              if (Serial.available() > 0)
              {
                   //Read Data From App
                   val = Serial.read();

                   switch (val) {

                     case '1':
                              digitalWrite(led1, HIGH);
                              break;

                     case '2':
                              digitalWrite(led1, LOW);
                              break;

                     case '3':
                              digitalWrite(led2, HIGH);
                              break;

                     case '4':
                              digitalWrite(led2, LOW);
                              break;
                   }
              }
         }
}

Thanks to everybody!
I use often millis() to avoid block my Arduino. My main question is about the official documents for technical information about buffers because I need to avoid the overflow. Where can I find information about them ?

When the App has read the data, the buffer is empty until the Arduino sends again. So to avoid overflow, follow my advice in my post above.