Sending 8 Bytes double

Hello,

I would like to send doubles containing 8 bytes from Arduino to another Software (Which only reads 8 bytes long values).

The transfer is going to happen through UDP (which i figured out), but converting 4 bytes to 8 bytes is problematic for me.

Can someone help me?

Arduino Uno,
Arduino IDE 1.8.5
Windows 8.1

Thanks

Alright, what have you tried? What Arduino? What should the package look like? etc etc

Thank you for your reply,

I have tried seperating the values into mantissa, exponent and sign, using this

//
//    FILE: float2double.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.00
// PURPOSE: experimental expands a float in a IEEE 754 double to be posted to PC.
//
// http://en.wikipedia.org/wiki/Double_precision 
// http://en.wikipedia.org/wiki/Single-precision_floating-point_format
//
// Released to the public domain
//

struct DBL
{
unsigned long f:29; // filler
unsigned long m:23; 
unsigned int e:11;
unsigned int s:1;
} 
dbl;

union FLTCONV
{
  struct
  {
unsigned long m:23; 
unsigned int e:8;
unsigned int s:1;
  } 
  p;
  float f;
} 
flt;

union DBLCONV
{
  struct DBL p;
  byte b[8];
} 
da;



void setup()
{
  Serial.begin(115200);
  Serial.println(sizeof(dbl));

  Serial.println();
  for (float f = -50.0; f < 50.0; f += 10.0)
  {
    dumpFLOAT(f);
    float2DA(f);
    dumpDA();
    Serial.println();
  }

  dumpFLOAT(0.15625);
  dumpFLOAT(PI);
  float2DA(PI);
  dumpDA();

  Serial.println("done");

}

void loop()
{
}

///////////////////////////////////////////////////////////////////////////////////


void dumpFLOAT(float number)
{
  flt.f = number;
  Serial.print(flt.p.s, HEX);
  Serial.print("\t");
  Serial.print(flt.p.e, HEX);
  Serial.print("\t");
  Serial.println(flt.p.m, HEX);
}

void dumpDBL(struct DBL dbl)
{
  Serial.print(dbl.s, HEX);
  Serial.print("\t");
  Serial.print(dbl.e, HEX);
  Serial.print("\t");
  Serial.println(dbl.m, HEX);
}

void dumpDA()
{
  Serial.print(da.p.s, HEX);
  Serial.print("\t");
  Serial.print(da.p.e, HEX);
  Serial.print("\t");
  Serial.println(da.p.m, HEX);

  for (int i=0; i<8; i++)
  {
    Serial.print(da.b[7-i], HEX);
    Serial.print('\t');
  }
  Serial.println();
}

void float2DA(float number)
{
  flt.f = number;
  da.p.s = flt.p.s;
  da.p.e = flt.p.e-127 +1023;  // exponent differ
  da.p.m = flt.p.m;
}

from this http://forum.arduino.cc/index.php?topic=186674.0

But and now, i do not know what to do.

But what needs to receive it? And how does it need to be formatted?

Just send 2 doubles

double real_val;
double dummy = 0.0;

UDP.send(dummny);
UPD.send(real_value);

Of course, the order of dummy and real_value depends on how you interpret the 8-bytes data on the receiver.

I am actually building a car simulator. Values are collected from the pedals, the steering wheel and transmitted to the arduino, where they are processed and need to be sent to the graphic interface.
The Graphic interface, which i got from the University only reads doubles of 8 Bytes, but Arduino only works with 4 Bytes; meaning i can't send the processed values directly through UDP, without changing them to 64 bits.

I have solved everything, except the conversion to 8 bytes, which requires a lot of Informatic knowledge, which i do not have.

arduino_new

Thank you very much for the help, but Udp.send does not exist in Arduino language.

This is how far i have gone (General code):

#include <math.h>
#include <SPI.h>         
#include <Ethernet.h>
#include <EthernetUdp.h>


//Some  Variables Definitions like car handling stuffs

byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
IPAddress ip(192,168,0,100);
unsigned int localPort = 8888;
EthernetUDP Udp;
float vect[] = {speed, x, y, z};

EthernetUDP Udp;
unsigned int localPort = 25001; 

void setup() {

  Ethernet.begin(mac, ip);
  Udp.begin(localPort);

  Serial.begin(9600);
}

void loop(){
   
  speed();
 position();

  Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  Udp.write("Vektor_filled_with_8_byte_floats");
  Udp.endPacket();

}
float speed(){}
float position(){}

But why use floats in the first place for sensor data? It's not precise (only up to some digits). Would think it's way more logical to send the integer sensor data.

Yes, sorry, i used int to store sensor data and float for the processed values like the pitch angle of the vehicle.

Try this to send 2 double values:

int size = sizeof(real_value);

Udp.write(&real_value, size);
Udp.write(&dummy, size);

arduino_new
Thank you for the answer, but the issue here is not sending 2 variables. It is converting bytes.
An Arduino works with float with 4 bytes, that means byte x = 11111111111111111111111111111111 , they are 32 bits = 8x4 . But the Programm, that will display the car and the simulation works with 8 bytes, that means it is expecting byte x = 1111111111111111111111111111111111111111111111111111111111111 which are 8x8 = 64 bits. The programm doesn't run or just crashes when i send plain arduino floats.

AKJ:
arduino_new
Thank you for the answer, but the issue here is not sending 2 variables. It is converting bytes.
An Arduino works with float with 4 bytes, that means byte x = 11111111111111111111111111111111 , they are 32 bits = 8x4 . But the Programm, that will display the car and the simulation works with 8 bytes, that means it is expecting byte x = 1111111111111111111111111111111111111111111111111111111111111 which are 8x8 = 64 bits. The programm doesn't run or just crashes when i send plain arduino floats.

your working on an UNO, for which there is no implementation of a 64 bit float.

  1. you can send it as a string
  2. convert the number and send it as a 32 bit float (hint: union is your friend)

I haven't looking into this too deeply, but the IEEE-754 spec summaries I've read have said that the exponent field is a signed value. Try using a URGENT Ban on Programming via USB and OTA for certain vehicles instead of unsigned int for that value in your structs.

Don't just say that it's "problematic", post some actual results of your conversion code. What kind of output is coming from what kind of input?

BulldogLowell

Exactly, there is no implimentation of the 64 bits and that is the problem. I heard, i have to divide the numbers into 3 parts, Mantissa, exponent and sign. Then convert them to bits somehow. I manage to seperate these 3 parts but couldn't go any further.

Jiggy-Ninja:
I haven’t looking into this too deeply, but the IEEE-754 spec summaries I’ve read have said that the exponent field is a signed value.

According to the Wikipedia sites for 32 and 64 bit floating point format, the exponent is stored as unsigned. There is an assumed constant bias subtracted from it (127d for 32-bit and 1023d for 64-bit):

So, I’m thinking you could do some really ugly bit manipulation to cram the bits from a float into the proper slots for a double. The code below compiles, but is untested. Also, I could be totally wrong on the endianness of the Arduino and the receiving processor. So, you’ll need to adjust accordingly.

void float2Double(float, uint8_t *);

void setup() {
  uint8_t byteArray[8];
  float testValue = 50.0;
  Serial.begin(115200);

  float2Double(testValue, byteArray);
  for (uint8_t index = 0; index < 8; index++) {
    Serial.print("0x");
    if (byteArray[index] < 0x10) {
      Serial.print("0");
    }
    Serial.print(byteArray[index], HEX);
    if (index<7) {
      Serial.print(" ");
    }
  }
  Serial.println(); 
}

void loop() {}

void float2Double(float floatIn, uint8_t *doubleOut) {
  uint8_t temp1;
  uint8_t *bytePtr = (uint8_t *) (&floatIn);

  memset(doubleOut, 0, 8);
  if (floatIn < 0) {   // Sign Bit
    *doubleOut = 0x80;
  }
  temp1 = *bytePtr >> 3 & 0x0F;  // e7-e4 of Float32 to e7-e4 of Float64
  *doubleOut |= temp1;

  temp1 = *bytePtr << 5 & 0xE0;  // e3-e1 of Float32 to e3-e1 of Float64
  *(doubleOut + 1) |= temp1;

  temp1 = *(bytePtr + 1) >> 3 & 0x10; // e0 of Float32 to ee0 of Float64
  *(doubleOut + 1) |= temp1;

  temp1 = *(bytePtr + 1) >> 3 & 0x0F; // b22-b19 of Float32 to b51-b48 of Float64
  *(doubleOut + 1) |= temp1;

  temp1 = *(bytePtr + 1) << 5 & 0xE0; // b18-b16 of Float32 to b47-b45 of Float64
  *(doubleOut + 2) |= temp1;

  temp1 = *(bytePtr + 2) >> 3 & 0x1F; // b15-b11 of Float32 to b44-b40 of Float64
  *(doubleOut + 2) |= temp1;

  temp1 = *(bytePtr + 2) << 5 & 0xE0; // b10-b08 of Float32 to b39-b37 of Float64
  *(doubleOut + 3) |= temp1;

  temp1 = *(bytePtr + 3) >> 3 & 0x1F; // b07-b03 of Float32 to b36-b32 of Float64
  *(doubleOut + 3) |= temp1;

  temp1 = *(bytePtr + 4) << 5 & 0xE0; // b02-b00 of Float32 to b31-b29 of Float64
  *(doubleOut + 3) |= temp1;
}

AKJ:
BulldogLowell

Exactly, there is no implimentation of the 64 bits and that is the problem. I heard, i have to divide the numbers into 3 parts, Mantissa, exponent and sign. Then convert them to bits somehow. I manage to seperate these 3 parts but couldn't go any further.

Why go through all those machinations? Why not just transmit a string and let the receiver parse the data?

I don't understand your problem.

EDIT:

I just realized the code I posted won't work as-is for the exponent bits because of the different constant bias between Float32 and Float64. But, I don't have more time to spend on this. You should be able to figure out how to adjust it.

gfvalvo

Beautiful! I receive hex data from the code.
Testing with 50.0, i get

0x00 0x00 0x09 0x08 0x00 0x00 0x00 0x00

AKJ:
Testing with 50.0, i get

0x00 0x00 0x09 0x08 0x00 0x00 0x00 0x00

Like I said, the exponent bits are probably wrong. You need to adjust for the different fixed bias.
http://www.binaryconvert.com/convert_float.html
http://www.binaryconvert.com/convert_double.html

Arduino DUE supports 64-bit (8 bytes) floating point number (binary64 standard).

double x = 1.23456;
binary64 = 0x3FF3C0C1FC8F3238