receive data as float in processing programming from serial port

Viewed 555

below is a code from arduino:


typedef union{
  float number;
  uint8_t bytes[4];
} FLOATUNION_t;

FLOATUNION_t myValue;

float getFloat(){ 
 int cont = 0; 
 FLOATUNION_t f; 
 while (cont < 4 ){ 
 f.bytes[cont] = Serial.read() ; 
 cont = cont +1; 
 } 
 return f.number; 
}

is there any alternative to this for processing programming(java)?

totally i need a code which recieve binary data from serial port and i want that data in float type in processing programming.

originally i am sending some data through serial send block in Simulink to processing programming, i am using processing.serial library , but i could not get thise bits and convert them to float or int.

1 Answers

You need to :

  1. buffer each byte a time from Simulink into Processing: Serial's buffer() / serialEvent() / readBytes(bytesFromSimulink) could work nicely in tandem here
  2. pack the bytes into a an int (shifting bytes as needed) and OR-ing them: int intBits = bytesFromSimulink[3] << 24 | bytesFromSimulink[2] << 16 | bytesFromSimulink[1] << 8 | bytesFromSimulink[0];
  3. convert the int to a float via Float.intBitsToFloat(): floatFromSimulink = Float.intBitsToFloat( intBits );

Here's a basic sketch to illustrate the ideas above:

import processing.serial.*;

// how many bytes are expecting sent in one go
final int SERIAL_BUFFER_SIZE = 4;
// pre-allocate serial read buffer
byte[] bytesFromSimulink = new byte[SERIAL_BUFFER_SIZE];
// float from bytes
float floatFromSimulink;

// serial port reference
final String PORT_NAME = "COM2"; 
final int    BAUD_RATE = 115200;
Serial simulinkPort;

void setup(){
  size(300, 300);
  
  try{
    simulinkPort = new Serial(this, PORT_NAME, BAUD_RATE);
    // only fire serialEvent() when the right number of bytes has been buffered
    simulinkPort.buffer(SERIAL_BUFFER_SIZE);
  }catch(Exception e){
    println("error opening serial port(" + PORT_NAME + "): double check the port name, wiring and make sure the port isn't already open in another application");
    e.printStackTrace();
    exit();
  }
}

void draw(){
  background(0);
  // format bytes to hex and float to 2 decimal places
  text(String.format("hex: %s\nfloat: %.2f", hex(byteFromSimulink), floatFromSimulink), 
       10, 15); 
}

void serialEvent(Serial port) {
  port.readBytes(bytesFromSimulink);
  // pack bytes into a 32bit int (shifting each byte accordingly): double check the byte order (e.g. LSB / MSB)
  int intBits = bytesFromSimulink[3] << 24 | 
                bytesFromSimulink[2] << 16 | 
                bytesFromSimulink[1] << 8  | 
                bytesFromSimulink[0];
  // convert int to to float
  floatFromSimulink = Float.intBitsToFloat( intBits );
}

// pretty-print byte array
String hex(byte[] data){
  String output = "";
  for(byte singleByte : data){
    output += hex(singleByte) + ' ';
  }
  return output;
}

Hopefully the above just works, but bare in mind it's untested code. There are two things I could think could go wrong:

  1. The bytes not arriving in the correct order. (let's say Simulink is continuously streaming serial data, but Processing starts later and only catches data from the 2nd, 3rd or 4th byte instead of the first: data will be shifted). You can try to remove buffer()/serialEvent() with a blocking loop and getting one byte at a time (e.g. if(simulinkPort.available() >= 1) myNewByte = simulinkPort.read();) and counting / packing bytes into the byte array manually. You could also try a call/response approach: e.g. Simulink doesn't send any data until it receives a single character from Processing (let's say 'A'), then starts streaming, so Processing is ready to buffer 4 bytes at a time from the get go.
  2. I'm not sure in which order the bytes are sent from simulink: above I'm assuming right to left, but it's the other way around simply swap indices: int intBits = byteFromSimulink[0] << 24 | byteFromSimulink[1] << 16 | byteFromSimulink[2] << 8 | byteFromSimulink[3];

The other gotcha in Java/Processing is that bytes are from -127 to 127 so you would want mask bytes when inspecting: println(myByte & 0xFF);

Based on g00se's suggestion in the comments bellow here's an attempt at a ByteBuffer option:

import java.nio.ByteBuffer;
import processing.serial.*;

// how many bytes are expecting sent in one go
final int SERIAL_BUFFER_SIZE = 4;
// pre-allocate serial read buffer
ByteBuffer bytesFromSimulink; 
// float from bytes
float floatFromSimulink;

// serial port reference
final String PORT_NAME = "COM2"; 
final int    BAUD_RATE = 115200;
Serial simulinkPort;

void setup(){
  size(300, 300);
  
  try{
    simulinkPort = new Serial(this, PORT_NAME, BAUD_RATE);
    // only fire serialEvent() when the right number of bytes has been buffered
    simulinkPort.buffer(SERIAL_BUFFER_SIZE);
    bytesFromSimulink = ByteBuffer.allocate(SERIAL_BUFFER_SIZE);
  }catch(Exception e){
    println("error opening serial port(" + PORT_NAME + "): double check the port name, wiring and make sure the port isn't already open in another application");
    e.printStackTrace();
    exit();
  }
}

void draw(){
  background(0);
  // format bytes to hex and float to 2 decimal places
  text(String.format("hex: %s\nfloat: %.2f", hex(bytesFromSimulink), floatFromSimulink), 
       10, 15); 
}

void serialEvent(Serial port) {
  // pass new data to the byte buffer
  bytesFromSimulink.put(port.readBytes(SERIAL_BUFFER_SIZE));
  // set the index back to 0
  bytesFromSimulink.rewind();
  // read the first (rewinded) 4 bytes as a float
  floatFromSimulink = bytesFromSimulink.getFloat();
}

// pretty-print byte array
String hex(ByteBuffer data){
  String output = "";
  for(int i = 0 ; i < data.limit(); i++){
    output += hex(data.get(i)) + ' ';
  }
  return output;
}
Related