Pages: [1]   Go Down
Author Topic: sending a float over serial  (Read 2906 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi all:

I know there have been a few threads on this topic already, but I haven't found anything that's worked for me yet.

I'm making a simple speedometer with a reed switch, and I want to send a MPH value with 2 decimal places over USB to a Processing app. So far everything works perfectly, except that what's being sent over USB seems to be an integer approximation of my float value. I've tried multiplying by 100, but I just end up with round 100's, like "800". So I'm not sure what to do. Thanks in advance for your help!

Arduino:
Code:
#define LED 13                   //pin for the LED
#define SWITCH 0                 //input for REED SWITCH
int rim = 2170;                  //circumference in mm

int val = 0;                     // used to store input value
int previousVal = 0;             // lets not be too repetitious
unsigned long revTimer;          // the last time the output pin was toggled
unsigned long serialTimer;
long debounce = 10;              // the debounce time, increase if the output flickers
int cycles = 1;                  // total number of revolutions
float currentSpeed = 0;           // current speed in MPH

void setup() {
 pinMode(LED, OUTPUT);           //tell arduino LED is an output
 pinMode(SWITCH, INPUT);         //SWITCH is input
 Serial.begin(9600);
 revTimer = millis();
 serialTimer = millis();
}

void loop(){
 val=digitalRead(SWITCH);        //read input value and store it

 //check whether input is HIGH (switch closed)
 if (val==HIGH) {
   digitalWrite(LED, HIGH);     //turn LED on
   previousVal = HIGH;
   //if(millis()-revTimer > 2000) currentSpeed = 0;
 } else{
   digitalWrite(LED, LOW);
   if (previousVal != LOW && millis() - revTimer > debounce) {
     currentSpeed = (float) (millis() - revTimer)*0.001;   // Convert time elapsed to milliseconds to seconds
     currentSpeed = rim/currentSpeed;               // S = d/t: Rim circumference divided by time elapsed
     currentSpeed = currentSpeed*0.002237;          // MPH Conversion: 1 mm/s = 0.001 m/s * 3600 s/hr * 1 mile / 1609 m = 0.002237 mi/hr
     revTimer = millis();                           // Keep a log of the timestamp for each reed switch pulse
     cycles++;                                      // The wheel has obviously turned another revolution
     sendStats();
     serialTimer = millis();
   }
   previousVal = LOW;
 }
 
 if (millis() - serialTimer > 1000) {
   sendStats();
   serialTimer = millis();
 }
 
}

void sendStats() {
  Serial.print("cycles="); Serial.print(cycles);
  Serial.print("&currentSpeedx100="); Serial.print((int)currentSpeed*100);
  Serial.print(10,BYTE);
}

void decimate(char test[],int dec) {
 int i=0;  
 int length=strlen(test);
 char msg[10]="";

 strcpy(msg,test);

 if (length <= dec) {
   for(i=dec;i>(dec-length);i--)  msg[i] = msg[i-(dec-length+1)];
   for(i=0;i<(dec+1-length);i++)  msg[i]='0';
   length = strlen(msg);
 }
 for (i=length;i>(length-dec);i--)  msg[i]=msg[i-1];
 msg[length-dec]='.';

 strcpy(test,msg);
}

Processing:
Code:
import processing.opengl.*;
import processing.serial.*;
Serial myPort;  // Create object from Serial class
PFont fontA;
String val;
String prev;
int lf = 10; //Linefeed in ASCII

void setup()
{
  size(400,400,OPENGL);
  hint(ENABLE_OPENGL_4X_SMOOTH);
  fontA = loadFont("HelveticaNeue-Bold-48.vlw");
  textFont(fontA, 48); // Set the font and its size (in units of pixels)
  
  String portName = Serial.list()[0];        
  // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  myPort = new Serial(this, portName, 9600);
}

void draw()
{
  background(255);
  if ( myPort.available() > 0) {  // If data is available,
        val = myPort.readStringUntil(lf);         // read it and store it in val
        if(val != null) val = trim(val);
  }
  fill(0); textAlign(CENTER); noStroke();
  if(val != null && val != prev)
  {
    println(val);
    prev = val;
  }
}

Result:

...
cycles=56&currentSpeedx100=1900
cycles=56&currentSpeedx100=1900
cycles=56&currentSpeedx100=1900
cycles=56&currentSpeedx100=1900
cycles=56&currentSpeedx100=1900
cycles=56&currentSpeedx100=1900
Logged

UK
Offline Offline
Faraday Member
**
Karma: 17
Posts: 2884
Gorm deficient
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
what's being sent over USB seems to be an integer approximation of my float value

Quote
Serial.print((int)currentSpeed*100);

Not surprising - you're truncating "currentSpeed" into an "int" and then multiplying by 100.

Quote
Serial.print((int)(currentSpeed*100.0));

[edit]BTW this isn't a hardware troubleshooting issue.[/edit]
« Last Edit: April 19, 2010, 02:08:14 am by GrooveFlotilla » Logged

Per Arduino ad Astra

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Sorry for the mis-categorization of the post. Is there a way to have it moved to the appropriate forum?

Sorry, leaving in the (int) when I posted this question was a mistake. Without the (int) there, I can't send the message. Your response did get me thinking however, and this solutions seems to have worked:

Code:
 currentSpeed = currentSpeed*100;
  Serial.print("&currentSpeedx100="); Serial.print((int) currentSpeed);

It's a shame I can't just send the dang float straight over!

Thanks!
Logged

Portugal
Offline Offline
God Member
*****
Karma: 6
Posts: 962
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Why you just don't use ftoa(float to ascii) to send the float trough the serial connection?
You cant send one float directly because it uses one specific order of bits, and one serial connection is made to send ascii chars so it would end up killing the float number and in the pc side you would only receive garbage.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Why you just don't use ftoa(float to ascii) to send the float trough the serial connection?

I'm not quite sure what you mean by that. I couldn't find anything in the forums quite like what you describe, but this seems to work out well:

Code:
 char ascii[32];
  int currentSpeedDec = (currentSpeed - (int)currentSpeed) * 100;
  sprintf(ascii,"&currentSpeed=%0d.%d", (int)currentSpeed, currentSpeedDec);
  Serial.print(ascii);
Logged

Middle of the Pacific
Offline Offline
Full Member
***
Karma: 0
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

have you tried using

Serial.println(val, format) ;

Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
have you tried using

Serial.println(val, format) ;

Hmm, that hasn't worked for me so far (just sends an int), plus it inserts a linefeed smiley-sad
Logged

Middle of the Pacific
Offline Offline
Full Member
***
Karma: 0
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Serial.print((int)currentSpeed*100);

why do you do this here?

try doing the multiplying by 100 prior to the serial.print.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As you can see above, my current method doesn't:

Code:
char ascii[32];
  int currentSpeedDec = (currentSpeed - (int)currentSpeed) * 100;
  sprintf(ascii,"&currentSpeed=%0d.%20d", (int)currentSpeed, currentSpeedDec);
  Serial.print(ascii);
« Last Edit: April 20, 2010, 02:50:45 pm by adamohern » Logged

Middle of the Pacific
Offline Offline
Full Member
***
Karma: 0
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just to get this straight:

Code:
float currentSpeed;
...
...
currentSpeed = currentSpeed * 100;
...
...
 Serial.print(currentSpeed, 2);

will only print integers?
« Last Edit: April 20, 2010, 04:13:06 pm by donkahones » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not quite. It won't even print integers; it just prints combinations of one's and zeros.

Arduino:
Code:
float currentSpeed;
...
Serial.print(currentSpeed,2); Serial.print(10,BYTE);

Processing:
Code:
void draw()
{
  if ( myPort.available() > 0) {  // If data is available,
        val = myPort.readStringUntil(lf);         // read it and store it in val
        if(val != null) val = trim(val);
  }
  if(val != null && val != prev)
  {
    println(val);
    prev = val;
  }
}

Result:
Code:
...
100
0
110
101
1
11
100
100
...
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
Serial.print(currentSpeed,2);

What version of the IDE are you using. As I recall, with 18, this should print a float with two decimal places. Older versions, I think, treated the second argument as a base. So, you might be getting this interpreted as "print this as in integer in base 2" instead of "print this as a float with 2 decimal places".
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 24
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
What version of the IDE are you using. As I recall, with 18, this should print a float with two decimal places.

Ah, that indeed was the problem. I hadn't updated in quite some time as it turns out! Thanks a ton!!
Logged

Pages: [1]   Go Up
Jump to: