How does Serial keep data in correct order.

I am learning robots. I have a tank robot with two servos connected to a Uno/motor controller/BT module. I am controlling the robot with a joystick connected to a Uno equipped with a BT module.

I have some experience in C programming, but for the most part, I use example sets of code and adapt to my needs.

My code works for the application, so no problem there, but, I do not understand how the code keeps the sequence of my data in order. There does not seem to be any explicit start or stop byte or function.

In other words, how does the following code keep my X-axis and Y-axis data properly synced since the startup and initialization of the two MCUs is random with respect to one another, i.e., the joystick could be in the middle of an X/Y data transmission when the robot starts receiving.

My code for the joystick side:

int xAxis, yAxis;

void setup() {
  Serial.begin(115200);                     // Communication rate of the Bluetooth module
}
void loop() {
  xAxis = analogRead(A0);                   // Read Joysticks X-axis
  yAxis = analogRead(A1);                   // Read Joysticks Y-axis

                                            // Send the values via the serial port to the slave HC-05 Bluetooth device
  Serial.write(xAxis/4);                    // Dividing by 4 for converting from 0 - 1023 to 0 - 256, (1 byte) range
  Serial.write(yAxis/4);

  delay(20);
}

My code for the robot side:

int joystickX, joystickY;                                           // create joystick variables

void setup() {                                                      // the setup function runs once
  Serial.begin(115200);                                             // initiate serial communication speed
}

void loop() {                                                       // the main loop
  if (Serial.available()) {                                         // check for a bluetooth connection
    
    while (Serial.available() >= 2) {                               // be sure serial buffer has enough data
      joystickX = Serial.read();                                    // read joystick x value
      delay (10);
      joystickY = Serial.read();                                    // read joystick y value
    }
    delay (10);    

    if (joystickY > 196) {                                          // if joystick y > 196 then turn left at speed 250
      Serial.println("turn left");
      carTurnLeft(250, 250);
    }
    else if (joystickY < 64) {                                      // if joystick y < 64 then turn right at speed 250
      Serial.println("turn right");
      carTurnRight(250, 250);
    }
    else if (joystickX > 196) {                                     // if joystick x > 196 then go forward at speed 500
      Serial.println("move forward");
      carAdvance(500, 500);
    }
...yada yada

Obviously there is something in the Serial function that keeps things straight since the robot always correctly follows my joystick input - can someone enlighten me? I have searched the internet including the Arduino tutorials here, and various ways to explicitly keep serial data in order, but I do not seem to find that specifically addresses this.

Frank

Hermesf: Obviously there is something in the Serial function that keeps things straight

I can guarantee you that is false. If a byte is dropped in transmission, your receiver and transmitter will become de-synced and your tank will act erratic.

I did something similar with an early prototype of my Arduino RC airplane and it happened to me often. That's when I implemented a more robust serial communication packet protocol.

You also shouldn't use delay() unless you have a really, really good reason to

It doesn’t. You’ve been lucky. The only change you have of getting it messed up is having your joystick sending data at the exact moment your receiver is doing Serial.begin() such that the first byte sent is not received but the second one is. At 115200, that time is <100 usec. After that, the bytes received will always be 2.

Thanks for the input, guys...that all makes sense and confirms my suspicion...

I have a controller coming (waiting on the slow boat from China, of course) that spits out a "packet" that contains specific bytes with the X/Y data...a library function on the receiving end will be able to decipher the packet and keep the X/Y data sequence consistent...

Thanks for the help.

Frank

Have a look at the examples in Serial Input Basics - simple reliable ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

The technique in the 3rd example will be the most reliable. It is what I use for Arduino to Arduino and Arduino to PC communication.

You can send data in a compatible format with code like this (or the equivalent in any other programming language)

Serial.print('<'); // start marker
Serial.print(value1);
Serial.print(','); // comma separator
Serial.print(value2);
Serial.println('>'); // end marker

If the project warrants it you could gain even greater reliability by including a checksum in the data, but I suspect that is not necessary in this case. I presume there is a lot of invisible error detection within the Bluetooth system.

I like the nRF24L01+ transceivers for Remote Control as they send a packet of up to 32 bytes and you can be very sure that if it receives a packet it will be correct.

…R
Simple nRF24L01+ Tutorial

Robin,

Gotcha…assume that works for Serial.write also…

Can you shorthand it? I.e.:

Serial.write('<'value1','value2'>');

Regards, Frank

Hermesf:
Can you shorthand it? I.e.:

Serial.write('<'value1','value2'>');

No.

…R

Hermesf:
Robin,

Gotcha…assume that works for Serial.write also…

Can you shorthand it? I.e.:

Serial.write('<'value1','value2'>');

Regards, Frank

Yes and no, actually. You can’t do it the way you wrote it exactly, but you can have an array of chars (or bytes) and do Serial.write(buf, len) where buf is the array and len is the length of the array

Hi Robin,

Read through your treatise on Serial Basics - very nice…

For my project, which is to use joystick for robot control, I do not think I need to worry about capturing all of the 0-255 output from the joystick, so using Example 6 as the starter, I just avoid the Start/Stop markers by filtering them from the transmission:

void loop() {
  xAxis = analogRead(A0);                   // Read Joysticks X-axis
  yAxis = analogRead(A1);                   // Read Joysticks Y-axis

  if (xAxis == 60 || xAxis == 62) {
    xAxis = 61;
  }
  
  if (yAxis == 60 || yAxis == 62) {
    yAxis = 61;
  }

                                            // Send the values via the serial port to the slave Romeo BLE device
  Serial.write("<");                        // Unique header character                                          
  Serial.write(xAxis/4);                    // Dividing by 4 for converting from 0 - 1023 to 0 - 256, (1 byte) range
  Serial.write(",");
  Serial.write(yAxis/4);
  Serial.write(">");
  delay(100);

}

I did read your extended Python/Arduino example, but seems overly complicated for this use - my robot will never notice the omissions!

I will also look over your Simple nRF24L01+ Tutorial.

I do thank you for the work on your part to present the examples…Frank

@Hermesf, thank you for your kind words.

...R