user69032: I am trying to make a Bluetooth controlled 4WD robot. i was following a tutorial i found online (https://howtomechatronics.com/tutorials/arduino/arduino-robot-car-wireless-control-using-hc-05-bluetooth-nrf24l01-and-hc-12-transceiver-modules/). After successfully connecting my 2 HC 05 Bluetooth module i used the script from the tutorial and modified it slightly so it would work for my set up.
The code for the robot:
//Code for Slave
#define enA 9
#define in1 8
#define in2 7
#define enB 10
#define in3 6
#define in4 5
int xAxis, yAxis;
unsigned int  x = 0;
unsigned int  y = 0;
int motorSpeedA = 0;
int motorSpeedB = 0;
void setup() {
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  Serial.begin(9600); // Default communication rate of the Bluetooth module
}
void loop() {
  // Default value - no movement when the Joystick stays in the center
  x = 510 / 4;
  y = 510 / 4;
  // Read the incoming data from the Joystick, or the master Bluetooth device
  while (Serial.available() >= 2) {
    x = Serial.read();
    Serial.print("X: ");
    Serial.println(x);
    delay(10);
    y = Serial.read();
    Serial.print("Y: ");
    Serial.println(y);
  }
  delay(10);
  // Convert back the 0 - 255 range to 0 - 1023, suitable for motor control code below
  xAxis = x*4;
  yAxis = y*4;
  // Y-axis used for forward and backward control
  if (yAxis < 470) {
    backMov;
    // Convert the declining Y-axis readings for going backward from 470 to 0 into 0 to 255 value for the PWM signal for increasing the motor speed
    motorSpeedA = map(yAxis, 470, 0, 0, 255);
    motorSpeedB = map(yAxis, 470, 0, 0, 255);
  }
  else if (yAxis > 550) {
    fowardMov;
    // Convert the increasing Y-axis readings for going forward from 550 to 1023 into 0 to 255 value for the PWM signal for increasing the motor speed
    motorSpeedA = map(yAxis, 550, 1023, 0, 255);
    motorSpeedB = map(yAxis, 550, 1023, 0, 255);
  }
  // If joystick stays in middle the motors are not moving
  else {
    motorSpeedA = 0;
    motorSpeedB = 0;
  }
  // X-axis used for left and right control
  if (xAxis < 470) {
    // Convert the declining X-axis readings from 470 to 0 into increasing 0 to 255 value
    int xMapped = map(xAxis, 470, 0, 0, 255);
    // Move to left - decrease left motor speed, increase right motor speed
    motorSpeedA = motorSpeedA + xMapped;
    motorSpeedB = motorSpeedB - xMapped;
    // Confine the range from 0 to 255
    if (motorSpeedA > 255) {
      motorSpeedA = 255;
    }
    if (motorSpeedB < 0) {
      motorSpeedB = 0;
    }
  }
  if (xAxis > 550) {
    // Convert the increasing X-axis readings from 550 to 1023 into 0 to 255 value
    int xMapped = map(xAxis, 550, 1023, 0, 255);
    // Move right - decrease right motor speed, increase left motor speed
    motorSpeedA = motorSpeedA - xMapped;
    motorSpeedB = motorSpeedB + xMapped;
    // Confine the range from 0 to 255
    if (motorSpeedA < 0) {
      motorSpeedA = 0;
    }
    if (motorSpeedB > 255) {
      motorSpeedB = 255;
    }
  }
  // Prevent buzzing at low speeds (Adjust according to your motors. My motors couldn't start moving if PWM value was below value of 70)
  if (motorSpeedA < 70) {
    motorSpeedA = 0;
  }
  if (motorSpeedB < 70) {
    motorSpeedB = 0;
  }
  analogWrite(enA, motorSpeedA); // Send PWM signal to motor A
  analogWrite(enB, motorSpeedB); // Send PWM signal to motor B
}
void fowardMov(){
  digitalWrite(in2,HIGH);
  digitalWrite(in4,HIGH);
  digitalWrite(in1, LOW);
  digitalWrite(in3, LOW);
}

void backMov(){
  digitalWrite(in1,HIGH);
  digitalWrite(in3,HIGH);
  digitalWrite(in2, LOW);
  digitalWrite(in4, LOW);
}

The code for the Controller:
#define Xaxis A0
#define Yaxis A1

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
 Serial.write(analogRead(Xaxis)/4);
 Serial.write(analogRead(Yaxis)/4);
 delay(20);
}

After uploading the code i tried to move it but it wasn't working so i put print statements to see the value of X and Y. initially it didn't work so i swapped the Bluetooth modules i had and reconnected them. i also changed this line.
 while (Serial.available() >= 2)

To this
 if (Serial.available() > 0)

i started to receive values from the master to the slave but  i noticed the values were the same for x and y so i searched for another tutorial on the internet and found this (https://create.arduino.cc/projecthub/andriy-baranov/arduino-4wd-rc-car-639953?ref=similar&ref_id=18369&offset=3) reading his code i wondered how did the slave work. According to the official Arduino documentation Serial.read() does not take in any arguments but i still tried it and it didn't work. I decided to retry the code from the first tutorial i checked this time it looked like it was working so i tried moving the joystick and the serial monitor printed correct values for both at first then it swaps their values then freezes. How can i stop it from freezing and swapping the values? Also why doesn't the while loop run forever isn't the amount of data in the serial buffer always higher than 2? Thank you.


user68310: There is an issue with the way in which the data is sent and received because it assumes the transmission will remain perfectly synchronised for the lifetime of the programme. Consider what would happen if one byte were to be dropped due to a communication error – the x and y data would be swapped for further transmissions.
Original Sender
void loop() {
  // put your main code here, to run repeatedly:
 Serial.write(analogRead(Xaxis)/4);
 Serial.write(analogRead(Yaxis)/4);
 delay(20);
}

Original Receiver
void loop() {
  // Default value - no movement when the Joystick stays in the center
  x = 510 / 4;
  y = 510 / 4;
  // Read the incoming data from the Joystick, or the master Bluetooth device
  while (Serial.available() >= 2) {
    x = Serial.read();
    Serial.print("X: ");
    Serial.println(x);
    delay(10);
    y = Serial.read();
    Serial.print("Y: ");
    Serial.println(y);
  }
  delay(10);
  . . .
}

Therefore, there needs to be a way to synchronise to the first byte of the message. This can be achieved by using message packets where the start and end of the message are delimited with unique characters, e.g. { and }, similar to the JSON format.
As another example, the NMEA GPS standard uses $ and \n to delimit messages, and , to delimit fields. It also has a checksum at the end.
Here is a non-blocking algorithm which builds upon Majenko's readline() example and the Blink Without Delay example to read a packet. ReadPacket() returns true when incoming data has been accumulated into a valid packet. The LED is flashed to indicate that the MCU hasn't frozen.
New Sender
void loop()
{
    Serial.print("{");                  // First character delimiter.
    Serial.print(analogRead(Xaxis));    // Full resolution. No need to divide by 4.
    Serial.print(",");                  // Field delimiter.
    Serial.print(analogRead(Yaxis));    // Full resolution. No need to divide by 4.
    Serial.print("}");                  // Last character delimiter.
    delay(20);
}

New Receiver
void loop()
{
    //
    // TASK 1: Blink without delay to indicate that MCU hasn't frozen.
    //
    const unsigned int INTERVAL = 250;
    unsigned long current_timestamp = millis();
    static unsigned long previous_timestamp = current_timestamp;
    static bool led_state = false;
    if (current_timestamp - previous_timestamp >= INTERVAL)
    {
        led_state = !led_state;
        digitalWrite(LED_BUILTIN, led_state);
        previous_timestamp += INTERVAL;
    }

    //
    // TASK 2: Read and parse data packet.
    //
    static char packet[100];
    const byte NUM_FIELDS = 2;
    unsigned int fields[NUM_FIELDS];
    static unsigned int x = 512;   // Full resolution. No need to divide by 4.
    static unsigned int y = 512;   // Full resolution. No need to divide by 4.
    bool new_x = false;
    bool new_y = false;
    if (ReadPacket(Serial, packet, sizeof(packet)))
    {
        Serial.print(F("Received packet >"));
        Serial.print(packet);
        Serial.println(F("<"));

        // Parse the packet for x and y values at full resolution.
        const char delimiters[] = "{,}";
        char* field;
        int i = 0;
        field = strtok(packet, delimiters);
        while (field != NULL && i < NUM_FIELDS)
        {
            Serial.print("field = ");
            Serial.println(field);
            fields[i] = atoi(field);
            Serial.print("fields[");
            Serial.print(i);
            Serial.print("] = ");
            Serial.println(fields[i]);
            field = strtok(NULL, delimiters);
            i++;
        }
        if (i == NUM_FIELDS)
        {
            if (x != fields[0])
            {
                new_x = true;
                x = fields[0];  // Full resolution. No need to multiply by 4.
                Serial.print("New x = ");
                Serial.println(x);
            }
            if (y != fields[1])
            {
                new_y = true;
                y = fields[1];  // Full resolution. No need to multiply by 4.
                Serial.print("New y = ");
                Serial.println(y);
            }
        }
    }

    Serial.print("x = ");
    Serial.println(x);
    Serial.print("y = ");
    Serial.println(y);

    //
    // TASK 3: Process x and y values.
    //
    if (new_x || new_y)
    {
        Serial.println("Processing new values.");
        
        . . .
    }
}

bool ReadPacket(Stream& stream, char *const packet, const unsigned int SIZE)
{
    const char FIRST = '{';
    const char LAST = '}';
    static bool read_until_last = false;
    static unsigned int i = 0;
    char ch;

    if (stream.available())
    {
        ch = stream.read();

        if (ch == FIRST)
        {
            Serial.println(F("Received FIRST."));
            i = 0;
            packet[0] = ch;
            read_until_last = true;
            return false;
        }
        if (read_until_last)
        {
            i++;
            if (i > SIZE - 2)
            {
                Serial.println(F("Buffer overrun. Resetting to look for next packet."));
                i = 0;
                read_until_last = false;
                return false;
            }
            if (ch == LAST)
            {
                Serial.println(F("Received LAST."));
                packet[i++] = ch;
                packet[i] = 0;
                read_until_last = false;
                return true;
            }
            else
            {
                Serial.print(F("Received char >"));
                Serial.print(ch);
                Serial.println("<");
                packet[i] = ch;
                return false;
            }
        }
    }
    return false;
}


69032: <p>I am trying to make a Bluetooth controlled 4WD robot. i was following a tutorial i found online (<a href="https://howtomechatronics.com/tutorials/arduino/arduino-robot-car-wireless-control-using-hc-05-bluetooth-nrf24l01-and-hc-12-transceiver-modules/" rel="nofollow noreferrer">https://howtomechatronics.com/tutorials/arduino/arduino-robot-car-wireless-control-using-hc-05-bluetooth-nrf24l01-and-hc-12-transceiver-modules/</a>). After successfully connecting my 2 HC 05 Bluetooth module i used the script from the tutorial and modified it slightly so it would work for my set up.
The code for the robot:</p>
<pre><code>//Code for Slave
#define enA 9
#define in1 8
#define in2 7
#define enB 10
#define in3 6
#define in4 5
int xAxis, yAxis;
unsigned int  x = 0;
unsigned int  y = 0;
int motorSpeedA = 0;
int motorSpeedB = 0;
void setup() {
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  Serial.begin(9600); // Default communication rate of the Bluetooth module
}
void loop() {
  // Default value - no movement when the Joystick stays in the center
  x = 510 / 4;
  y = 510 / 4;
  // Read the incoming data from the Joystick, or the master Bluetooth device
  while (Serial.available() &gt;= 2) {
    x = Serial.read();
    Serial.print(&quot;X: &quot;);
    Serial.println(x);
    delay(10);
    y = Serial.read();
    Serial.print(&quot;Y: &quot;);
    Serial.println(y);
  }
  delay(10);
  // Convert back the 0 - 255 range to 0 - 1023, suitable for motor control code below
  xAxis = x*4;
  yAxis = y*4;
  // Y-axis used for forward and backward control
  if (yAxis &lt; 470) {
    backMov;
    // Convert the declining Y-axis readings for going backward from 470 to 0 into 0 to 255 value for the PWM signal for increasing the motor speed
    motorSpeedA = map(yAxis, 470, 0, 0, 255);
    motorSpeedB = map(yAxis, 470, 0, 0, 255);
  }
  else if (yAxis &gt; 550) {
    fowardMov;
    // Convert the increasing Y-axis readings for going forward from 550 to 1023 into 0 to 255 value for the PWM signal for increasing the motor speed
    motorSpeedA = map(yAxis, 550, 1023, 0, 255);
    motorSpeedB = map(yAxis, 550, 1023, 0, 255);
  }
  // If joystick stays in middle the motors are not moving
  else {
    motorSpeedA = 0;
    motorSpeedB = 0;
  }
  // X-axis used for left and right control
  if (xAxis &lt; 470) {
    // Convert the declining X-axis readings from 470 to 0 into increasing 0 to 255 value
    int xMapped = map(xAxis, 470, 0, 0, 255);
    // Move to left - decrease left motor speed, increase right motor speed
    motorSpeedA = motorSpeedA + xMapped;
    motorSpeedB = motorSpeedB - xMapped;
    // Confine the range from 0 to 255
    if (motorSpeedA &gt; 255) {
      motorSpeedA = 255;
    }
    if (motorSpeedB &lt; 0) {
      motorSpeedB = 0;
    }
  }
  if (xAxis &gt; 550) {
    // Convert the increasing X-axis readings from 550 to 1023 into 0 to 255 value
    int xMapped = map(xAxis, 550, 1023, 0, 255);
    // Move right - decrease right motor speed, increase left motor speed
    motorSpeedA = motorSpeedA - xMapped;
    motorSpeedB = motorSpeedB + xMapped;
    // Confine the range from 0 to 255
    if (motorSpeedA &lt; 0) {
      motorSpeedA = 0;
    }
    if (motorSpeedB &gt; 255) {
      motorSpeedB = 255;
    }
  }
  // Prevent buzzing at low speeds (Adjust according to your motors. My motors couldn't start moving if PWM value was below value of 70)
  if (motorSpeedA &lt; 70) {
    motorSpeedA = 0;
  }
  if (motorSpeedB &lt; 70) {
    motorSpeedB = 0;
  }
  analogWrite(enA, motorSpeedA); // Send PWM signal to motor A
  analogWrite(enB, motorSpeedB); // Send PWM signal to motor B
}
void fowardMov(){
  digitalWrite(in2,HIGH);
  digitalWrite(in4,HIGH);
  digitalWrite(in1, LOW);
  digitalWrite(in3, LOW);
}

void backMov(){
  digitalWrite(in1,HIGH);
  digitalWrite(in3,HIGH);
  digitalWrite(in2, LOW);
  digitalWrite(in4, LOW);
}
</code></pre>
<p>The code for the Controller:</p>
<pre><code>#define Xaxis A0
#define Yaxis A1

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
 Serial.write(analogRead(Xaxis)/4);
 Serial.write(analogRead(Yaxis)/4);
 delay(20);
}
</code></pre>
<p>After uploading the code i tried to move it but it wasn't working so i put print statements to see the value of X and Y. initially it didn't work so i swapped the Bluetooth modules i had and reconnected them. i also changed this line.</p>
<pre><code> while (Serial.available() &gt;= 2)
</code></pre>
<p>To this</p>
<pre><code> if (Serial.available() &gt; 0)
</code></pre>
<p>i started to receive values from the master to the slave but  i noticed the values were the same for x and y so i searched for another tutorial on the internet and found this (<a href="https://create.arduino.cc/projecthub/andriy-baranov/arduino-4wd-rc-car-639953?ref=similar&amp;ref_id=18369&amp;offset=3" rel="nofollow noreferrer">https://create.arduino.cc/projecthub/andriy-baranov/arduino-4wd-rc-car-639953?ref=similar&amp;ref_id=18369&amp;offset=3</a>) reading his code i wondered how did the slave work. According to the official Arduino documentation Serial.read() does not take in any arguments but i still tried it and it didn't work. I decided to retry the code from the first tutorial i checked this time it looked like it was working so i tried moving the joystick and the serial monitor printed correct values for both at first then it swaps their values then freezes. How can i stop it from freezing and swapping the values? Also why doesn't the while loop run forever isn't the amount of data in the serial buffer always higher than 2? Thank you.<a href="https://i.stack.imgur.com/1CY82.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/1CY82.png" alt="diagram of slave" /></a></p>
<p><a href="https://i.stack.imgur.com/xfp1I.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/xfp1I.png" alt="diagram of master" /></a></p>
 68310: <p>There is an issue with the way in which the data is sent and received because it assumes the transmission will remain perfectly synchronised for the lifetime of the programme. Consider what would happen if one byte were to be dropped due to a communication error – the x and y data would be swapped for further transmissions.</p>
<p><strong>Original Sender</strong></p>
<pre class="lang-cpp prettyprint-override"><code>void loop() {
  // put your main code here, to run repeatedly:
 Serial.write(analogRead(Xaxis)/4);
 Serial.write(analogRead(Yaxis)/4);
 delay(20);
}
</code></pre>
<p><strong>Original Receiver</strong></p>
<pre class="lang-cpp prettyprint-override"><code>void loop() {
  // Default value - no movement when the Joystick stays in the center
  x = 510 / 4;
  y = 510 / 4;
  // Read the incoming data from the Joystick, or the master Bluetooth device
  while (Serial.available() &gt;= 2) {
    x = Serial.read();
    Serial.print(&quot;X: &quot;);
    Serial.println(x);
    delay(10);
    y = Serial.read();
    Serial.print(&quot;Y: &quot;);
    Serial.println(y);
  }
  delay(10);
  . . .
}
</code></pre>
<p>Therefore, there needs to be a way to synchronise to the first byte of the message. This can be achieved by using message packets where the start and end of the message are delimited with unique characters, e.g. <code>{</code> and <code>}</code>, similar to the <a href="https://en.wikipedia.org/wiki/JSON" rel="nofollow noreferrer">JSON format</a>.</p>
<p>As another example, the <a href="https://www.gpsworld.com/what-exactly-is-gps-nmea-data/" rel="nofollow noreferrer">NMEA GPS</a> standard uses <code>$</code> and <code>\n</code> to delimit messages, and <code>,</code> to delimit fields. It also has a checksum at the end.</p>
<p>Here is a non-blocking algorithm which builds upon <a href="https://majenko.co.uk/blog/reading-serial-arduino" rel="nofollow noreferrer">Majenko's <code>readline()</code> example</a> and the <a href="https://www.arduino.cc/en/Tutorial/BuiltInExamples/BlinkWithoutDelay/" rel="nofollow noreferrer">Blink Without Delay example</a> to read a packet. <code>ReadPacket()</code> returns true when incoming data has been accumulated into a valid packet. The LED is flashed to indicate that the MCU hasn't frozen.</p>
<p><strong>New Sender</strong></p>
<pre class="lang-cpp prettyprint-override"><code>void loop()
{
    Serial.print(&quot;{&quot;);                  // First character delimiter.
    Serial.print(analogRead(Xaxis));    // Full resolution. No need to divide by 4.
    Serial.print(&quot;,&quot;);                  // Field delimiter.
    Serial.print(analogRead(Yaxis));    // Full resolution. No need to divide by 4.
    Serial.print(&quot;}&quot;);                  // Last character delimiter.
    delay(20);
}
</code></pre>
<p><strong>New Receiver</strong></p>
<pre class="lang-cpp prettyprint-override"><code>void loop()
{
    //
    // TASK 1: Blink without delay to indicate that MCU hasn't frozen.
    //
    const unsigned int INTERVAL = 250;
    unsigned long current_timestamp = millis();
    static unsigned long previous_timestamp = current_timestamp;
    static bool led_state = false;
    if (current_timestamp - previous_timestamp &gt;= INTERVAL)
    {
        led_state = !led_state;
        digitalWrite(LED_BUILTIN, led_state);
        previous_timestamp += INTERVAL;
    }

    //
    // TASK 2: Read and parse data packet.
    //
    static char packet[100];
    const byte NUM_FIELDS = 2;
    unsigned int fields[NUM_FIELDS];
    static unsigned int x = 512;   // Full resolution. No need to divide by 4.
    static unsigned int y = 512;   // Full resolution. No need to divide by 4.
    bool new_x = false;
    bool new_y = false;
    if (ReadPacket(Serial, packet, sizeof(packet)))
    {
        Serial.print(F(&quot;Received packet &gt;&quot;));
        Serial.print(packet);
        Serial.println(F(&quot;&lt;&quot;));

        // Parse the packet for x and y values at full resolution.
        const char delimiters[] = &quot;{,}&quot;;
        char* field;
        int i = 0;
        field = strtok(packet, delimiters);
        while (field != NULL &amp;&amp; i &lt; NUM_FIELDS)
        {
            Serial.print(&quot;field = &quot;);
            Serial.println(field);
            fields[i] = atoi(field);
            Serial.print(&quot;fields[&quot;);
            Serial.print(i);
            Serial.print(&quot;] = &quot;);
            Serial.println(fields[i]);
            field = strtok(NULL, delimiters);
            i++;
        }
        if (i == NUM_FIELDS)
        {
            if (x != fields[0])
            {
                new_x = true;
                x = fields[0];  // Full resolution. No need to multiply by 4.
                Serial.print(&quot;New x = &quot;);
                Serial.println(x);
            }
            if (y != fields[1])
            {
                new_y = true;
                y = fields[1];  // Full resolution. No need to multiply by 4.
                Serial.print(&quot;New y = &quot;);
                Serial.println(y);
            }
        }
    }

    Serial.print(&quot;x = &quot;);
    Serial.println(x);
    Serial.print(&quot;y = &quot;);
    Serial.println(y);

    //
    // TASK 3: Process x and y values.
    //
    if (new_x || new_y)
    {
        Serial.println(&quot;Processing new values.&quot;);
        
        . . .
    }
}

bool ReadPacket(Stream&amp; stream, char *const packet, const unsigned int SIZE)
{
    const char FIRST = '{';
    const char LAST = '}';
    static bool read_until_last = false;
    static unsigned int i = 0;
    char ch;

    if (stream.available())
    {
        ch = stream.read();

        if (ch == FIRST)
        {
            Serial.println(F(&quot;Received FIRST.&quot;));
            i = 0;
            packet[0] = ch;
            read_until_last = true;
            return false;
        }
        if (read_until_last)
        {
            i++;
            if (i &gt; SIZE - 2)
            {
                Serial.println(F(&quot;Buffer overrun. Resetting to look for next packet.&quot;));
                i = 0;
                read_until_last = false;
                return false;
            }
            if (ch == LAST)
            {
                Serial.println(F(&quot;Received LAST.&quot;));
                packet[i++] = ch;
                packet[i] = 0;
                read_until_last = false;
                return true;
            }
            else
            {
                Serial.print(F(&quot;Received char &gt;&quot;));
                Serial.print(ch);
                Serial.println(&quot;&lt;&quot;);
                packet[i] = ch;
                return false;
            }
        }
    }
    return false;
}
</code></pre>
