United Kingdom
Asked
Resolved Resolved by DJ Sures!

Reading UART Integer/Float Sent From Arduino

Hi,

I've been using the following tutorial and code to get data from an Arduino for a battery of sensors...

Using Arduino as Encoder

One of my sensors is a Barometer and is sending the pressure....but the value falls outside of the 255 that this tutorial seems to accept. The number for the pressure on my arduino is a float of currently 998.10 - but I don't mind losing the decimal and just having an integer.

Could one of you kind folks give me some advice on what script / command I can use to read this number?

Thanks

Steve Haze


Related Hardware EZ-B v4
Related Control Script

ARC Pro

Upgrade to ARC Pro

Subscribe to ARC Pro, and your robot will become a canvas for your imagination, limited only by your creativity.

PRO
Synthiam
#1  

A byte is 8 bits which has a maximum value of 255 (256 possible variations of the bits)

a float, or an int, or a decimal, or a short, etc... all consist of many bytes.

so an int16 is 2 bytes

an int32 is 4 bytes

a long (int64) is 8 bytes

the bytes are assembled together using bitwise operators to recreate the original intended value.

I don’t know what’s compatible with a float between windows an Arduino, since floats are considerably platform dependent. An int16, however, is easy

you’ll need to send your in on the Arduino as two bytes

and receive it on the ezb or what ever the receiver is, as two bytes

PRO
Synthiam
#2  

Here's JavaScript code from ARC that demonstrates how to receive and convert 2 bytes from the hardware UART into an INT..

(i don't use ezscript anymore :))

First, initialize your hardware UART...


// initialize the hardware uart #0 at 9600 on ezb #0
UART.initHardwareUart(0, 9600, 0);

Now, send your data from the Arduino...



void sendSomeData() {

  Serial.begin(9600);

  int value = 12345;

  // split the value into 2 bytes and send over the wire
  Serial.write(value & 0x00FF);
  Serial.write(value & 0xFF00 >> 8);
}


// Get the number of bytes available to read
var bytesAvail = UART.hardwareUartAvailable(uartIndex, ezbIndex);

if (bytesAvail >= 2) {
   
   // Get the data as an array from the UART buffer
   var dataArray = UART.hardwareUartRead(0, 2, 0);
   
   var value = dataArray[0] + (dataArray[1] << 8);
   
   print("Your value is " + value);
   
} else {

   print("Not enough bytes available to assemble an int16");
   
}

#3   — Edited

I wrote this to receive 2 byte data ( this example for voltage) from the roomba (and charging state...single byte)....  It kind of worked but strangely just for voltage it wigged out on any other 2 byte data request... maybe it will help you out a bit...

uartinit(0, 0, 115200)
sleep(500)
$rx = UartAvailable(0, 0)

if ($rx=4)
    $RX_DATA = UARTRead(0, 0, $rx)
    $MSB=GetByteAt($RX_DATA,0)
    $LSB=GetByteAt($RX_DATA,1)
    $Charge=GetByteAt($RX_DATA,2)
    $Charge_source=GetByteAt($RX_DATA,3)
    $voltage=Round(($LSB+(256*$MSB))/1000,2)

  
 if ($Charge_source = 0)
      print("Not Docked")
    ELSE
      print("Docked")
    endif

    if ($charge=0)
      $dock_flag=0
      print("Not charging")
    ELSEif ($Charge=1)
      $dock_flag=1
      print("Recondioning charging")
    ELSEif ($Charge=2)
      $dock_flag=1
      print("Fast charging")
    ELSEif ($Charge=3)
      $dock_flag=1
      print("Trickle charging")
    ELSEif ($Charge=4)
      # $dock_flag=0
      print("Waiting to charge")
    ELSEif ($Charge=5)
      print("Error not charging/Fault")
      halt()
    endif  
   

    print("Battery Voltage = "+$voltage)
endif
PRO
Synthiam
#4  

Richard, the reason it would wig out is because the uartread() returns a string. In ezscript, you’d have to use uartreadbinary().

but, JavaScript is more powerful and faster :)

oh, the new roomba plugin I just finished reads sensor data. And has variable turning and such. It’s real great. I’ll publish it this week with the new arc.

#5  

@DJ.... Fair enough. I need to revisit that. FYI I am in the process of learning JavaScript for ARC as I can see the benefits over ezscript.... A quick JavaScript (with the plugin) for the roomba sensors would be most welcome... I like learning from example code....

Cheers

United Kingdom
#6   — Edited

Thanks DJ and Richard.....love the quick replies here.

Time to buy JavaScript for Dummies then? xD

Assuming I do switch to JavaScript....Is there a similar ControlCommand function in JavaScript to control the other plugins?

United Kingdom
#7  

Hmmm....

So with that code.... (DJ's code)...sending the number 1021....the code gives me the value 65021 at the end.

scratches head confused

PRO
Synthiam
#8   — Edited

Oh, I might have confused the byte order. Either on the sender or receiver, change the order of the bytes

so like, on the sender. Change the order to be...

Serial.write(value & 0xFF00 >> 8); Serial.write(value & 0x00FF);

United Kingdom
#9  

Hmmm.....that didn't still didn't seem to work...

SO.... I did some googling and learning and this is what worked for me for sending the Float...SORT OF..... I'm cheating a bit....but for the 1 decimal place that I need for this sensor reading, I'm happy.

(PS: I know the Ezb could poll this particular sensor itself...but my arduino is handling all my sensors and then sending to Ezb.)  :)

On the Arduino...

  // if there is data to read, read it
if (Serial1.available() > 0) {

    // read the incoming data from the ezb
    int incomingByte = Serial1.read();

   // Listen for an "x" sent from Ezb to request this data - I'm using other commands for other requests.
    if (incomingByte == 78) {      

        // Get the Pressure from the BME Barometric Sensor
        float pressure = bme.readPressure();   
        pressure = bme.seaLevelForAltitude(ALTITUDE,pressure);
        pressure = pressure/100.0F;
         
       // Multiply by 10 to get rid of the decimal
         int pressure10 = pressure * 10;   
                
        byte * b = (byte *) &pressure10;
        Serial1.write(b[0]);
        Serial1.write(b[1]);
     
    }
]


Then in ARC....JavaScript (modified from what DJ Sures posted)....

// initialize the hardware uart #0 at 9600 on ezb #0
UART.initHardwareUart(0, 115200, 0);

var x = 78;

// Tell the Arduino to send us the Barometric Pressure reading
UART.hardwareUartWrite(0, x, 0);

// Wait 100ms to allow for receipt...
sleep(100);

// Get the number of bytes available to read
var bytesAvail = UART.hardwareUartAvailable(0, 0);
print(bytesAvail);


if (bytesAvail == 2) {
   
   // Get the data as an array from the UART buffer
   var dataArray = UART.hardwareUartRead(0, 2, 0);
   
   var value = dataArray[0] + (dataArray[1] << 8);

   // Divide by 10 to regain the decimal place.
   value = value / 10; 
   
   print("Your value is " + value);
}
 else {

   print("Not enough bytes available to assemble an int16");
   
}

Thank you so much DJ for your ALWAYS quick replies and sharing of knowledge. :D

PRO
Synthiam
#10   — Edited

Oh - you were still trying to send a float? The float wouldn't work in my example, as it was only an in16. Your example would work, but you do lose one digit of resolution. It, the maximum range of a signed Int16 is -32,768 to 32,767. So with your solution, the maximum rage would be -2,768 to 2,767

If that range is acceptable for your application, it's golden :). Otherwise, use a signed Int 32 (4 bytes)

United Kingdom
#11  

I tried that...but I couldn't find or figure out the decoding of the 4 byte array... I had the arduino variable that's being sent as a Long and the following...

        // Get the Pressure from the BME Barometric Sensor
        float pressure = bme.readPressure();   
        pressure = bme.seaLevelForAltitude(ALTITUDE,pressure);
        pressure = pressure/100.0F;

        // Multiply by 100 to get rid of the decimal
         long pressure100 = pressure * 100;   
                
        byte * b = (byte *) &pressure10;
      Serial1.write(b[0]);
       Serial1.write(b[1]);
       Serial1.write(b[2]);
        Serial1.write(b[3]);

I'm only just learning about shifting... So I'm guessing after receiving 4 bytes and not 2....the Javascript line here would need to be different.....but I'm not sure how. Can you advise? :)

 var value = dataArray[0] + (dataArray[1] << 8);
PRO
Synthiam
#12   — Edited

4 byte (int32) would look like this...

On the Arduino...


  // if there is data to read, read it
if (Serial1.available() > 0) {

 // read the incoming data from the ezb
 int incomingByte = Serial1.read();

// Listen for an "x" sent from Ezb to request this data - I'm using other commands for other requests.
 if (incomingByte == 78) {

  // Get the Pressure from the BME Barometric Sensor
float pressure = bme.readPressure();
  pressure = bme.seaLevelForAltitude(ALTITUDE,pressure);
  pressure = pressure/100.0F;

 // Multiply by 10 to get rid of the decimal and convert to int32
int32 pressure10 = pressure * 10;
 
  byte * b = (byte *) &pressure10;
  Serial1.write(b[0]);
  Serial1.write(b[1]);
  Serial1.write(b[2]);
  Serial1.write(b[3]);
}

Then in ARC....JavaScript (modified from what DJ Sures posted)....


// initialize the hardware uart #0 at 9600 on ezb #0
UART.initHardwareUart(0, 115200, 0);

var x = 78;

// Tell the Arduino to send us the Barometric Pressure reading
UART.hardwareUartWrite(0, x, 0);

// Wait 100ms to allow for receipt...
sleep(100);

// Get the number of bytes available to read
var bytesAvail = UART.hardwareUartAvailable(0, 0);
print(bytesAvail);


if (bytesAvail == 4) {

// Get the data as an array from the UART buffer
var dataArray = UART.hardwareUartRead(0, 4, 0);

var value = dataArray[0] + (dataArray[1] << 8) + (dataArray[2] << 16) + (dataArray[3] << 24)

// Divide by 10 to regain the decimal place.
value = value / 10; 

print("Your value is " + value);
}
 else {

print("Not enough bytes available to assemble an int32");

}

United Kingdom
#13  

Excellent....

I'm getting 'int32' was not declared in this scope but if I use LONG then it works. :D

Namaste!

PRO
Synthiam
#14  

Oh ya! Arduino is int_32 I think or long. Thanks for correcting my codez!