Bi directional serial communication between two Arduinos

 

Protocol issues….

  • I have a Rover 5 managed by an Arduino Uno and a remote with a Arduino Pro as a brain. They communicate via radio APC220.
  •  The remote has a joystick, and a few pushbuttons. Till now communication was one way. From the remote to the rover: joystick to control the rover and the push buttons to switch from operation mode and to switch features on and off (e.g. headlights). No probs till here.
  • I want to expand my project and added a lcd and a SD-card to the remote. I want to display Rover–status-info on the display (e.g. operating mode (autonomous, remote driving, remote gripper, battery voltage…) and I want to log Rover-data to the SD-card (e.g. heading and distance).
  • This requires bidirectional communication. I've experimented a bit but the results are disappointing. I let the Uno send three strings to the Pro, with a an second interval, preceded by a start byte ‘# ‘and terminated with a stop byte ‘@’.

   if(millis() - Timer >= 1000)

        Timer = millis();       

        if (a == 0)           {Serial.println("#string1@");}       

        else if (a == 1) {Serial.println("#string2@");} 

        else             {Serial.println("#string3");}      

        a = a + 1;

        if (a == 3) {a=0;}                      

  }

  • I want the Pro to receive the strings and display them to the lcd. I am using the code below.

     #define STRING_MAX_LENGTH 10

      byte inByte;

      char inBytes[STRING_MAX_LENGTH];

      int i = 0;

      boolean retrieveData = false;

      byte startByte = '#';

      byte stopByte = '@';

 

void loop() {  

    while(Serial.available() > 0) {

 

          inByte = Serial.read();        

                                                      

          if(inByte == stopByte){

            inBytes[i] = '\0';

            retrieveData = false;

            executeCommand(inBytes);

          }

          else {

            if(retrieveData){

              inBytes[i] = inByte;

              ++i;

              if(i >= STRING_MAX_LENGTH - 1) {i = STRING_MAX_LENGTH - 1;}

            }

          }

         

          if(inByte == startByte){

            for(i = 0; i < STRING_MAX_LENGTH; i++)

              inBytes[i] = '\0';

            i = 0;

            retrieveData = true;

          }

     

    } // End while (Serial.available)

 

    if(millis() - time1 > =  50){                                    // execute each 50 ms

    

        time1 = millis();                               

                      

        GetJoyStickStatus ();

        GetPushButtonStatus();              

     }               

}  

 

void executeCommand(char * commandString)

{

  lcd.clear();

  lcd.print(commandString);

  lcd.setCursor(0,1);

}

 

  • If I only let the Pro receives data from the Uno everything goes well (yellow code lines left out). If I give the Pro other assignments such as sending data to the other side (e.g. joystick data, yellow code lines included) the receipt at the Pro side becomes unreliable and erratic.
  • I've been searching for clues but am still not sure how to proceed from here? Should I develop a a protocol (checksums, handshakes, ...)? Are these problems related to timing issues? Or something entirely different? I expected to find lots of info and examples on this topic but the was not the (my) case. Therefore I like your help. What is the best way to proceed?

Thanks in advance.

Best regards, Ko

 

 

Thanks for your reaction. I

Thanks for your reaction. I had indeed seen this lib. Big chance that I’m going to use it too. But before I do so I would like to see whether I can get this done myself. For my own learning process. So I am still interested in your suggestions.

+1 on the easy transfer

Dude, use the Easy Transfer, period. If you are going from Arduino to Arduino, there is nothing else to use. As long as your variables match each other on both sides, the thing is 100% solid, no BS. Serial, I2c, softSerial --whatever you want to use. Ah! An awesome library. --And Bill Porter is a great guy too.

**Timing problem @ Easy Transfer **

 

Chris’s recommendation was very clear. So I started with Easy Transfer.

The situation

I let the Rover and the remote perform the same task:

·         transmit two integers, every half second

·         print three strings to the LCD in the same loupe (first line)

·         always check whether data is received (the two mentioned integers :wink: and print it to the LCD (second line).

 

My code is as follows.

 

Rover side

 

     struct RECEIVE_DATA_STRUCTURE{  

         int botMode;

         int joyStickDirection;

         int x_position;

         int y_position;

     };

   

     struct SEND_DATA_STRUCTURE{    

         int xx;

         int yy;

     };   

   

     RECEIVE_DATA_STRUCTURE rxdata;   //give a name to the group of data

     SEND_DATA_STRUCTURE txdata;

 

void loop(){

        

    if(millis() - Timer1 >= 500)

    {     

       Timer1 = millis();   

      

       lcd.setCursor(0,0);

       if (a == 0)      {lcd.print ("Dog "); txdata.xx =   1; txdata.yy =   2; }   

       else if (a == 1) {lcd.print ("Cat “); txdata.xx =  10; txdata.yy =  20; }   

       else             {lcd.print (“Fish”); txdata.xx = 100; txdata.yy = 200; }   

       a = a + 1;

       if (a == 3) {a = 0;}               

 

       ETout.sendData();

      

    } // End timer/millis() loop

     

 

     

    if(ETin.receiveData())                             //check and see if a data packet has come in.

    {                           

       lcd.setCursor(0,1);

       lcd.print(rxdata.x_position);

       lcd.print(”, “);

       lcd.print(rxdata.y_position);

       lcd.print(”    ");

    }

 

Remote side

 

     struct RECEIVE_DATA_STRUCTURE{                              

         int xx;

         int yy;

     };

    struct SEND_DATA_STRUCTURE{                               

         int botMode;

         int joyStickDirection;

         int x_position;

         int y_position;   

     };   

   

     RECEIVE_DATA_STRUCTURE rxdata;                                //give a name to the group of data

     SEND_DATA_STRUCTURE txdata;

 

void loop() { 

   

   if(millis() - Timer1 >= 500)

   { 

       Timer1 = millis();   

        

       lcd.setCursor(0,0);

       if (a == 0)         {lcd.print ("Ford "); txdata.x_position = 25; txdata.y_position = 50; }   

       else if (a == 1) {lcd.print (“Volvo”); txdata.x_position = 30; txdata.y_position = 60; }   

       else                   {lcd.print ("Opel “); txdata.x_position = 35; txdata.y_position = 70; }   

       a = a + 1;

       if (a == 3) {a = 0;}                

 

       ETout.sendData();

        

   } // End timer/millis() loop

 

 

 

   if(ETin.receiveData())                             //check and see if a data packet has come in.

    {                     

       lcd.setCursor(0,1);

       lcd.print(rxdata.xx);

       lcd.print(”, “);

       lcd.print(rxdata.yy);

       lcd.print(”    ");

    }

 

The problem

This code works well. But it goes wrong when the transmission frequency on one side increases. If I for example let the Rover transmit every 50 ms (instead of every half second, 500 ms) things seems ok at the remote side (data is printed to lcd with increased frequency). But Rover side it goes wrong. It seems that no data is coming in (I see nothing on the lcd) or that the Rover is to bussy sending it has no time for handling / receiving incoming data.

Is this a timing issue?. How do I fix this? Please help.

 

 

 

Solved

Finally solved. Made my own serial protocol (flow control, error handling, checksum, ack / nack etc.).  It took a while, but the result is elegant, simple and above all effective!

Bidirectional comms

Ko,

Can you post your bidirectional comms between to arduinos.  I last read that you had CRC added.

 

I’ve been trying the Easy Transfer and seem to have the same issue.

Thanks!

Doyle

maleche 1 at com cast dot net