Arduino to Arduino wireless serial communication failures

I have this code working on two Arduino Nanos with HC-12 wireless modules. Everything works great as long as I power the main controller first, never get out of range, and never have a corrupted byte. Once any of these issues arise I start having intermittent issues or complete failure. Any recommendations on how to sync the serial data back up is greatly appreciated.

Code for the remote control:

 int pushButton = 2;// Set PushButton to DI Pin 2
  int HB = 1; //intialize the heartbeat to 1 on startup
  int HBSTEP = 1;//Step to increment the heartbeat by
  byte SendArray[5] = {0,0,0,0,0};//Array to print to the serial port ([0]=HB, [1]=XIN, [2]=YIN, [3]=PB, [4]=Checksum)

  
void setup() {
// Start serial communication at 1200 buad more stable for wireless
  Serial.begin(1200);
// Assign pushbutton as an input
 pinMode(pushButton, INPUT);
}

void loop() {

// Read the X value at A0
  int XIN = analogRead(A0);
// Read the Y value at A1
  int YIN = analogRead(A1);
// Read the pushbutton at digtal pin 2
  int PB = digitalRead(pushButton);

//Assign variables to an array
SendArray[0] = HB;
SendArray[1] = map(XIN,0,1024,0,255);//map the AI (0-1024) to the byte size (0-255)
SendArray[2] = map(YIN,0,1024,0,255);//map the AI (0-1024) to the byte size (0-255)
SendArray[3] = PB;//Only using one bit in this byte but leaving room for more push buttons 

//Calculate the Checksum
//Find the sum of the product of each array multiplied by its position int he array
int SumP = SendArray[0]*5 + SendArray[1]*4 + SendArray[2]*3 + SendArray[3]*2;
//Checksum is the remainder of the sum of the products divided by the number of positions + 1
SendArray[4] = SumP % 6;

//Print HB, X, Y, PB and checksum to serail
Serial.write(SendArray, 5);

//Increment the heatbeat by step amount unless it is at 255, then set it to 0
   if (HB < 255)
    {
      HB = HB + HBSTEP;
    }
    else
    {
      HB = 0;
    }
    
  //Delay 1 second before going to begining of loop
  delay(100);

}

Code for the Main Controller / Receiver:

int HB; //Heartbeat from remote
int HBLAST;//Heartbeat from last scan
int FROZEN = 6;// Heatbeat frozen count initialize greater than frozen counter to ensure motor does not turn or go into gear until remote signal is being received
int XVAL; //X value from joystick
int YVAL; //Y value from joystick
int PB;// Push Button State
int CS;// Checksum to verify data was received coreectly
int led = 13;// Test LED on when checksum is verifed
byte ReceiveArray[5] = {0,128,128,1,0}; // Serial data array initialize in the center positon for throttle/transmission and stearing.

  
  void setup() {
// Start serial communication at 1200 buad more stable for wireless
  Serial.begin(1200);
//Assign led pin as OUTPUT  
  pinMode(led, OUTPUT);
}


void loop() {
// Get serial data for HB, X, Y, PB and checksum from Serial 
if (Serial.available() >0)
{
  Serial.readBytes(ReceiveArray, 5);
}

// Calculate the Checksum
//Find the sum of the product of each array multiplied by its position int he array
int SumP = ReceiveArray[0]*5 + ReceiveArray[1]*4 + ReceiveArray[2]*3 + ReceiveArray[3]*2;
//Checksum is the remainder of the sum of the products divided by the number of positions + 1
CS = SumP % 6;

//If serial no new serial data has been received for more than 5 cycles then the throttle/transmission and stearing should return to center position.
if (FROZEN >5)
{
  HB = ReceiveArray[0];
  XVAL = 128;
  YVAL = 128;
  PB = 1;
}
// If not frozen and checksum is verified Split serail data for HB, X, Y, and PB from Serail array
else if (CS == ReceiveArray[4])
{

HB = ReceiveArray[0];
XVAL = ReceiveArray[1];  
YVAL = ReceiveArray[2]; 
PB = ReceiveArray[3];
}
else
{
Serial.flush();
}
 
//Print the values to the serial port

//  Serial.print("RAW = ");
//  Serial.println(ReceiveArray);
//  Serial.print("HB = " );
//  Serial.println(HB);
//  Serial.print("X = ");
//  Serial.println(XVAL);
//  Serial.print("Y = ");
//  Serial.println(YVAL);
//  Serial.print("PB = ");
//  Serial.println(PB); 
//  Serial.print("Frozen = ");
//  Serial.println(FROZEN);
//  Serial.println("----------------------");
    
//Check to see if the heatbeat value is changing

  if (HBLAST == HB)
    {
      FROZEN = FROZEN +1; 
    } 
    else
    {
      FROZEN = 0;
    }

   
// If the checksum is verfied as accurate and receiving continous data then turn the onboard LED on.  If not turn the LED off
  if ((CS == ReceiveArray[4]) and FROZEN < 6 )
  {
    digitalWrite(led, HIGH);
  }
  else
  {
    digitalWrite(led, LOW);
  }

//Set the last heartbeat value to the new heartbeat value for the next scan
HBLAST = HB;

delay(100);

}

You need to decide for a protocol that handles errors, link going down and up, lost data etc..
Check what warnings or errors that might be available from Your hardware. Either You pic up a protocol that will work or You prepare Your code for every possible error.

Railroader - Thanks for reading my post. I don't know how to check errors on hardware and to my knowledge I am not getting any. That was the reason for adding the checksum. If you are going to help a fellow programmer please use specifics and give examples. I am aware that I need to do something different that was the reason for posting in the "Project Guidance" forum. Have a blessed day!

All,

I have programmed a fix and it seems to work every time, but it is far from perfect. If you know of a better way to resolve this issue please let me know. Most of the time this fix works in less than 1 second, but occasionally i get a failure that my take 3-5 seconds to correct. What I did was to program a data dump. I am incrementing the data dump length by 1 byte on each cycle until the checksum is verified. Below is the new code for the main controller. The code for the remote stays the same as the original post.

int HB; //Heartbeat from remote
int HBLAST;//Heartbeat from last scan
int FROZEN = 6;// Heartbeat frozen count initialize greater than frozen counter to ensure motor does not turn or go into gear until remote signal is being received
int XVAL; //X value from joystick
int YVAL; //Y value from joystick
int PB;// Push Button State
int CS;// Checksum to verify data was received correctly
int led = 13;// Test LED on when checksum is verified
byte ReceiveArray[5] = {0,128,128,1,0}; // Serial data array initialize in the center position for throttle/transmission and steering.
byte datadump[5]; // Array used to dump bad data
int i = 0; //integer to increment the data dump

  void setup() {
// Start serial communication at 1200 buad more stable for wireless
  Serial.begin(1200);
//Assign led pin as OUTPUT  
  pinMode(led, OUTPUT);
}


void loop() {
// Get serial data for HB, X, Y, PB and checksum from Serial 
if (Serial.available() >0)
{
  Serial.readBytes(ReceiveArray, 5);
}

// Calculate the Checksum
//Find the sum of the product of each array multiplied by its position int he array
int SumP = ReceiveArray[0]*5 + ReceiveArray[1]*4 + ReceiveArray[2]*3 + ReceiveArray[3]*2;
//Checksum is the remainder of the sum of the products divided by the number of positions + 1
CS = SumP % 6;

//if checksum is not verified dump the data until the checksum is verified
if (CS != ReceiveArray[4])
{
    //increment the number of bytes to dump by one each cycle
    if (i < 5)
  {
    i = i + 1;
  }
  else
  {
    i = 1;
  }
Serial.readBytes(datadump, i);
}


//If serial no new serial data has been received for more than 5 cycles then the throttle/transmission and steering should return to center position.
if (FROZEN >5)
{
  HB = ReceiveArray[0];
  XVAL = 128;
  YVAL = 128;
  PB = 1;
}
// If not frozen and checksum is verified Split serial data for HB, X, Y, and PB from Serial array
else if (CS == ReceiveArray[4])
{

HB = ReceiveArray[0];
XVAL = ReceiveArray[1];  
YVAL = ReceiveArray[2]; 
PB = ReceiveArray[3];
i = 0;
}
 
//Print the values to the serial port

//  Serial.print("RAW = ");
//  Serial.println(ReceiveArray);
//  Serial.print("HB = " );
//  Serial.println(HB);
//  Serial.print("X = ");
//  Serial.println(XVAL);
//  Serial.print("Y = ");
//  Serial.println(YVAL);
//  Serial.print("PB = ");
//  Serial.println(PB); 
//  Serial.print("Frozen = ");
//  Serial.println(FROZEN);
//  Serial.println("----------------------");
    
//Check to see if the heartbeat value is changing

  if (HBLAST == HB)
    {
      FROZEN = FROZEN +1; 
    } 
    else
    {
      FROZEN = 0;
    }

   
// If the checksum is verified as accurate and receiving continuous data then turn the on board LED on.  If not turn the LED off
  if ((CS == ReceiveArray[4]) and FROZEN < 6 )
  {
    digitalWrite(led, HIGH);
  }
  else
  {
    digitalWrite(led, LOW);
  }

//Set the last heartbeat value to the new heartbeat value for the next scan
HBLAST = HB;

delay(100);

}

I am not familiar with the HC-12 modules and I don't think You supplied the entire code.

Here is a link to something I found. Are You familiar with the contents?

Suppose Your neighbour alse plays with HC-12. What will happend? Collisions and rubbish data.

I read the link properly I see a way to use coaxial cable instead of RF. That could be a way do verify the basic function of Your Project.

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

My Tutorial does not use a checksum but you can add one into the data.

...R

@Robin2
Thanks for stepping in.

Railroader:
@Robin2
Thanks for stepping in.

Feel free to post a link to any of my Tutorials any time you think one of them might help.

...R

@Robin2, again.

What about handshake, "ACK/NACK" etc.? Protocol…. If corrupted data is received, how to ask for a retransmission?

Thanks for the great replies. I double checked and the program is complete and is currently loaded on my Nanos and functioning. The HC-12 has 100 or so channels so I could just change channels if an interference issue arises. For the purpose of this discussion we can forget about this HC-12 module and just think of it as a hardwired serial. I tried using the marker option to start with and it did work great, however it slowed down the rate at which I could transfer my data. If I tried to send new data more than once every 2 seconds the Main Controller would lock up and stop functioning until the serial connection was broken then it would try to catch up. It was awful. That is why I started scaling my data to bytes and transmitting as few bytes as possible. This application requires updates multiple times per second. The handshake option may be realistic if it doesn't slow down my data transmission capabilities to be more than 250 ms. Do you have an example?

@Op
Greate!
If the receiver sends an acknowledge to the sender, the sender than knows that the message is recieved and no retransmission is needed. This You can do if the integrity, no message lossed, is important.
Else there is the CAN buss filosofie. A message is valid for a limited amount of time. Within that time frame a new message must be sent to, f ex., keep a motor running.

Of course, sending acknowledge, decreases the effective capacity of the numer of messages transmitted per time unit.

casawyer:
I tried using the marker option to start with and it did work great, however it slowed down the rate at which I could transfer my data.

Without seeing the program that you tried I can't comment. The start and end markers just add 2 characters to the message which should have very little impact on throughput.

...R