Serial Communication - Send double value from one Arduino to another

Hi,
I'm trying to send a double value from one Arduino Pro Mini to another one and after some search I found this Arduino to Arduino Serial Communication.

After changing the code to, Sender:

//Sender Code

void setup() {
  Serial.begin(9600);
}

void loop() {
  double value=0.3623;
  serialDoubleWrite(value);
}

void serialDoubleWrite(double d) {
  byte * b = (byte *) &d;
  //Serial.print("d:");
  Serial.write(b,4);
  /* DEBUG *
  Serial.println();
  Serial.print(b[0], HEX);
  Serial.print(b[1], HEX);
  Serial.print(b[2], HEX);
  Serial.println(b[3], HEX);
  //*/

}

And Receiver:

//Receiver Code

byte array[4];

void setup() {
  Serial.begin(9600);
}

void loop() {
  int i=0;
  
  if (Serial.available()) {
    delay(100);
    while(Serial.available() && i<4) {
      array[i++] = Serial.read();
      /*DEBUG*/
      Serial.print((int) i);
      Serial.println(array[i-1], HEX);
      //*/
    }
    array[i++]='\0';
  }
  
  if(i>0) {
    double intbit;
    intbit = (array[3] << 24) | ((array[2] & 0xff) << 16) | ((array[1] & 0xff) << 8) | (array[0] & 0xff);
    
    Serial.println(intbit, 4);
  }
}

The Sender seemed ok since from the debug I see he's sending 63 7F B9 3E that backwards corresponds to the value 0.3623. But I'm having issues, because the debug in Receiver shows that the second Arduino is getting the array in bad order, randomly difference each time, can someone explain me why and how to fix it? :confused:

And I think the last piece of code in Receiver to make the conversion between the bytes array to double is wrong.

the second Arduino is getting the array in bad order, randomly difference each time

Yes, there's nothing in the data stream that says "This is the first character of 4."

The sender just sends the bytes as fast as it can. When the receiver starts reading, it could be in the middle of the 4-byte sequence. It'll take bytes from the next 4-byte sequence if necessary, causing what looks like a wrong byte order. It's just picking any 4 bytes in a row.

You should send a special sequence first, and then the 4 bytes. The receiver will watch for the special sequence, then read 4 more bytes. Sending a checksum after the 4 bytes would be a good idea too. That would let the receiver verify what is received (Fletcher checksum is easy to implement).

the last piece of code in Receiver to make the conversion between the bytes array to double is wrong

Nope, it's fine. And there's no double on the Arduino. It's the same a single-precision float.

Cheers,
/dev

Your system for receiving data is not robust

 if (Serial.available()) {
    delay(100);
    while(Serial.available() && i<4) {

Have a look at Serial Input Basics - espcially the system in the 3rd example.

...R

You should NOT NULL terminate the array, writing out of bounds!

NULL terminating is for char arrays that represent strings.

/dev:
You should send a special sequence first, and then the 4 bytes. The receiver will watch for the special sequence, then read 4 more bytes. Sending a checksum after the 4 bytes would be a good idea too. That would let the receiver verify what is received (Fletcher checksum is easy to implement).

Thanks for the help /dev, makes all sense he's picking up in random positions.

I tried using a special value like 'q:' to tell the Arduino to start from there and now I have better results, but still sometimes, not sure why, he gets like 63 7F B9 B9 or 63 7F 7F B9. I'll have to look into Fletcher checksum, thanks for the reference.

Robin2:
Your system for receiving data is not robust

Yes, now I understand why... totally forgot that he could start to pickup values from nowhere since he didn't know where to start. :roll_eyes:

Robin2:
Have a look at Serial Input Basics - espcially the system in the 3rd example.

And thanks, that tutorial really got me in to the right mindset now with some basics, I still tried to use some tips from your example but ironically the 3E corresponds to '>', maybe use a sequence of two chars will prevent that, not sure.

PaulS:
You should NOT NULL terminate the array, writing out of bounds!

NULL terminating is for char arrays that represent strings.

Thanks PaulS for the heads up! :grin: I had that already commented on my code, forgot to take it off the code posted here.

My final objective is sending an Array with all the values obtained from one sensor (4 quaternions) and then add the values from another sensor to send to another one, 3 sensors in a row each with an Arduino, so since this looks more tricky that I thought my question is, should I use the same principle? Or is there another way?

Slugslinger:
but ironically the 3E corresponds to '>',

You can use any 2 characters in my example in place of < and >. Just pick two characters that will never appear in a message. I hope it is clear that the sending device must use the two start- and end-markers that you choose.

...R

Robin2:
You can use any 2 characters in my example in place of < and >.

I'm still having some issues and I decided to try your entire 3rd example and switch the markers to '[' and ']', with one Arduino sending in loop "Serial.println("qwerty[asdfg]zxcvb");" to prove my suspicion.

And it was like I suspected, for some reason it seems some values are received in different order or is simply some trash?

Some of values result in this:

This just in ... asdfg
This just in ... g
This just in ... acvb
qwerty[asdf
qwerty[asdfg
This just in ... asdfg

Slugslinger:
And it was like I suspected, for some reason it seems some values are received in different order or is simply some trash?

Post the exact code that you have used for your test and I will try it. If I don't get time to do that today (Monday) it will probably have to wait until Wednesday.

...R

Robin2:
Post the exact code that you have used for your test and I will try it.

A made the sender really simple to make no mistakes in the middle, and it's like:

//Sender Code

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println("qwerty[asdfg]zxcvb");
}

And for the Receiver since my code was having issues I tried exactly your third example:

const byte numChars = 32;
char receivedChars[numChars];

boolean newData = false;

void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
}

void loop() {
    recvWithStartEndMarkers();
    showNewData();
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '[';
    char endMarker = ']';
    char rc;
    
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

Thanks again for all the help and there's no problem if you can't see this today, I'll keep trying to figure it out by myself and if I find the solution, I'll let you know.

How are the two Arduinos connected? Describe ALL connections.

PaulS:
How are the two Arduinos connected? Describe ALL connections.

I tried sending from an Arduino Pro Mini to a Arduino Due, but I'm having the same issue. :confused:

Slugslinger:

I tried sending from an Arduino Pro Mini to a Arduino Due, but I'm having the same issue. :confused:

I like chocolate ice-cream.

I hope that my completely irrelevant reply somehow helps you.

PaulS:
I like chocolate ice-cream.

I hope that my completely irrelevant reply somehow helps you.

I'm sorry, maybe I didn't understand the question, it was not on purpose, but that's all the connections I have.

One Arduino Pro Mini (Sender) has female (shaped L) connectors from TX, VCC and GRD that are respectively connected to the RX, VCC and GRD (via cable and soldering) of the other Arduino Pro Mini (Receiver) that is connected finally to my FTDI.

I see what the problem is now. Your picture is posted somewhere I can't access, so the proxy server refused to fetch it.

Regardless of whether you need to accomplish two-way communication, you should still attach TX to RX and RX to TX on the two Arduinos (as well as ground, of course).

It appears, on the receiver end at least, that you are trying to use THE serial port to talk to the PC and to the other Arduino. Not a great idea.

Below is some simple arduino serial to serial test code which uses a comma , as the data delimiter. You probably do not need a start of data marker. Note that tx/rx connections can vary depending on the testing you are doing.

//zoomkat 3-5-12 simple delimited ',' string tx/rx 
//from serial port input (via serial monitor)
//and print result out serial port
//Connect the sending arduino tx pin to the receiving arduino rx pin. 
//Connect the arduino grounds together. 
//What is sent to the tx arduino is received on the rx arduino.
//Open serial monitor on both arduinos to test
//A diode between the slave tx and master rx is suggested 
//for isolation, with diode band attached to slave tx side. 
//

String readString;

void setup() {
  Serial.begin(9600);
  Serial.println("serial delimit test 1.0"); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like wer,qwe rty,123 456,hyre kjhg,
  //or like hello world,who are you?,bye!,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >0) {
        Serial.print(readString); //prints string to serial port out
        Serial.println(','); //prints delimiting ","
        //do stuff with the captured readString 
        readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

FYI...

On an UNO, zoomkat's example uses 3766 bytes of program space and 234 bytes of RAM. When that program is modified to use character arrays instead of the String class:

char readChars[16];
uint8_t charCount = 0;

void setup() {
  Serial.begin(9600);
  Serial.println( F("serial delimit test 1.0") ); // so I can keep track of what is loaded
}

void loop() {

  //expect a string like wer,qwe rty,123 456,hyre kjhg,
  //or like hello world,who are you?,bye!,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      readChars[ charCount ] = '\0'; // NUL-terminate character string
      Serial.print( readChars ); //prints string to serial port out
      Serial.println( ',' ); //prints delimiting ","
      //do stuff with the captured readChars 
      charCount = 0; //clears variable for new input
    } else if (charCount < sizeof(readChars)-1) {
      readChars[charCount++] = c; // save the char, if there is room
    }
  }
}

...it uses 2142 bytes of program space, and 212 bytes of RAM.

Save 1600 bytes of program space and a little RAM: don't use String. It will also save you headaches later, when your program gets more complicated and quits working at random times. Unless you're very careful, String will lead memory fragmentation, and it will fail at different points, depending on the operations. Bad juju.

Catcher in the RAM,
/dev

Slugslinger:
A made the sender really simple to make no mistakes in the middle, and it's like:

I strongly suspect your sender is too simple and is inundating the serial connection with too much data.

Try a short delay between transmissions - try delay(500); and then reduce it is steps to see what happens.

...R

Robin2:
I strongly suspect your sender is too simple and is inundating the serial connection with too much data.

Try a short delay between transmissions - try delay(500); and then reduce it is steps to see what happens.

...R

Yes, that was the problem... Thank you so much! :smiley: