?
Solved

AVR (Arduino) Convert char array to double?

Posted on 2010-11-11
5
Medium Priority
?
4,447 Views
Last Modified: 2012-05-10
i'm having a lot of trouble with this.

I have a text array and i've done all the stuff to extract just the numbers so i get something like this:

CurrentXascii[9]=1234.5678

but when i do an atof

CurrentX=atof(CurrentXascii);

it truncates to two decimal places.

How do I fix this? I need those four decimal places, it is pretty important.

if I serial.print the CurrentX with 9 digits it does show all 8 digits (and the period), but after the first 6 numbers the last are not consistently accurate, and the difference in .0001 is VERY significant, some of our X values are as much as 0.0003 off and some of our Y values have gone as high as 0.0009 off. This is pretty unacceptable but I'm not sure how to work around it.

here's my FULL snippet:

#include <String.h>
#include <ctype.h>
#include <Wire.h>

int compassAddress = 0x32 >> 1;
int heading = 0;
int tilt = 0;
int roll = 0;
int ledPin = 13;
int rxPin = 0;
int txPin = 1;
int byteGPS=-1;
char linea[300] = "";
char comandoGPR[7] = "$GPRMC";
int cont=0;
int bien=0;
int conta=0;
int indices[13];
char CurrentXascii[9];
char CurrentYascii[10];
float CurrentX;
float CurrentY;
float CurrentHeading;
float CurrentHeading0;
float CurrentHeadingF;
byte responseBytes[6];
int GPStimer=0;
double DeltaX=0.000;
double DeltaY=0.000;
int Instance=0;
int InstanceSize=0;
int buttonState=0;
int buttonPin = 22;
int lastButtonState=0;
int buttonPushCounter=0;
float DesiredHeading=0.0;
int LeftSpeed=0;
int RightSpeed=0;
int LeftSpeed0=0;
int RightSpeed0=0;
int LeftSpeedF=0;
int RightSpeedF=0;
double ParkingLotX[3] = {4031.24554, 4031.24116, 4031.23294};
double ParkingLotY[3] = {-7427.58914,-7427.57996,-7427.5853};
void setEngineSpeed1(signed char cNewMotorSpeedH)
{
  unsigned char cSpeedVal_Motor1 = 0;
  if(cNewMotorSpeedH==0)
  {
    Serial3.print(0,BYTE);
    return;
  }
  cSpeedVal_Motor1 = map(cNewMotorSpeedH,-100,100,1,127);
  Serial3.print(cSpeedVal_Motor1, BYTE);
}

void setEngineSpeed2(signed char cNewMotorSpeed2)
{
  unsigned char cSpeedVal_Motor2 = 0;
  if(cNewMotorSpeed2 == 0)
  {
    Serial3.print(0,BYTE);
    return;
  }
  cSpeedVal_Motor2 = map(cNewMotorSpeed2,-100,100,128,255);
  Serial3.print(cSpeedVal_Motor2, BYTE);
}

void readSensor()
{
  Wire.beginTransmission(compassAddress);
  Wire.send(0x50);
  Wire.endTransmission();
  delay(2);
  Wire.requestFrom(compassAddress, 6);
  if(6 <= Wire.available())
  {
    for(int i = 0; i<6; i++) {
	responseBytes[i] = Wire.receive();
    }
  }
  heading = ((int)responseBytes[0]<<8) | ((int)responseBytes[1]);
  tilt = (((int)responseBytes[2]<<8) | ((int)responseBytes[3]));
  roll = (((int)responseBytes[4]<<8) | ((int)responseBytes[5]));
  CurrentHeadingF = heading/10;
  CurrentHeading0=(CurrentHeadingF+CurrentHeading0)/2;
  CurrentHeading=(CurrentHeading0+CurrentHeading)/2;

}

void readGPS()
{
  GPStimer=0;
  do{
    byteGPS=Serial2.read();
    if (byteGPS == -1)
    {
	delay(100);
    }
    else {
	linea[conta]=byteGPS;
	conta++;
	if (byteGPS==13){
	  digitalWrite(ledPin, LOW);
	  cont=0;
	  bien=0;
	  for (int i=1;i<7;i++){
	    if (linea[i]==comandoGPR[i-1]){
		bien++;
	    }
	  }
	  if(bien==6){
	    for (int i=0;i<300;i++){
		if (linea[i]==','){
		  indices[cont]=i;
		  cont++;
		}
		if (linea[i]=='*'){
		  indices[12]=i;
		  cont++;
		}
	    }
	    Serial.println("");
	    Serial.println("");
	    Serial.println("---------------");
	    for (int i=0;i<12;i++){
		for (int j=indices[i],k=0;j<(indices[i+1]-1);j++,k++){
		  switch(i){
		  case 2 :
		    CurrentXascii[k]=linea[j+1];
		   break;
		  case 4 :
		    CurrentYascii[k]=linea[j+1];
		    break;
		  }
		}
	    }
/*	  for (int i=0;i<5;i++){
		CurrentX1[i]=atof(CurrentXascii[i]);
	    }
	    for (int i=5,i<10,i++){
		CurrentX2[i]=atof(CurrentXascii[i]);
	    }
	    CurrentX=CurrentX1"."CurrentX2; */
	    CurrentX=atof(CurrentXascii);
	    CurrentY=-atof(CurrentYascii);
	  }
	  conta=0;
	  for (int i=0;i<300;i++){
	    linea[i]=' ';
	  }
	}
    }
    GPStimer++;
  }
  while(GPStimer<300);
}

void setup()
{
  delay(500);
  Wire.begin();
  Wire.send(0x82);
  delay(500);
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  Serial2.begin(4800);
  for (int i=0;i<300;i++){
    linea[i]=' ';
  }
  Serial3.begin(9600);
  delay(2000);
  setEngineSpeed1(0);
  setEngineSpeed2(0);
  Instance=0;
}

void loop()
{
  buttonState = digitalRead(buttonPin);
  if (buttonState != lastButtonState) {
    if (buttonState == HIGH) {
	buttonPushCounter++;
    }
    lastButtonState = buttonState;
  }
  Instance=buttonPushCounter;
  readSensor();
  Serial.print("Heading: ");
  Serial.print(CurrentHeading);
  Serial.print("\t Tilt: ");
  Serial.print(tilt / 10, DEC);
  Serial.print("\t Roll: ");
  Serial.println(roll / 10, DEC);
  delay(50);
  readGPS();
  Serial.print("Current X Value: ");
  Serial.print(CurrentX, 10);
  Serial.print("\t");
  Serial.print("Current Y Value: ");
  Serial.println(CurrentY, 10);
  Serial.println("---------------");
  do{
    readGPS();
    DeltaX=ParkingLotX[Instance]-CurrentX;
    DeltaY=ParkingLotY[Instance]-CurrentY;
    if (DeltaY<0){
	if (DeltaX<0){
	  DesiredHeading=270-atan(DeltaY/DeltaX)*180/3.14159265;
	}else if (DeltaX>0){
	  DesiredHeading=180-atan(DeltaY/DeltaX)*180/3.14159265;
	}
    }else if (DeltaY>0){
	if (DeltaX<0){
	  DesiredHeading=360-atan(DeltaY/DeltaX)*180/3.14159265;
	}else if (DeltaX>0){
	  DesiredHeading=90-atan(DeltaY/DeltaX)*180/3.14159265;
	}
    }
    readSensor();
    if (((DesiredHeading-CurrentHeading) < 15)&&((DesiredHeading-CurrentHeading)>6)){
	LeftSpeed=40;
	RightSpeed=30;
    }else if (((DesiredHeading-CurrentHeading) <= 30)&&((DesiredHeading-CurrentHeading)>15)){
	LeftSpeed=40;
	RightSpeed=20;
    }else if (((DesiredHeading-CurrentHeading) <= 60)&&((DesiredHeading-CurrentHeading)>30)){
	LeftSpeed=40;
	RightSpeed=10;
    }else if (((DesiredHeading-CurrentHeading) <= 360)&&((DesiredHeading-CurrentHeading)>60)){
	LeftSpeed=40;
	RightSpeed=-40;
    }else if (((DesiredHeading-CurrentHeading) <= -6)&&((DesiredHeading-CurrentHeading)>-15)){
	LeftSpeed=30;
	RightSpeed=40;
    }else if (((DesiredHeading-CurrentHeading) <= -15)&&((DesiredHeading-CurrentHeading)>-30)){
	LeftSpeed=20;
	RightSpeed=40;
    }else if (((DesiredHeading-CurrentHeading) <= -30)&&((DesiredHeading-CurrentHeading)>-60)){
	LeftSpeed=10;
	RightSpeed=40;
    }else if (((DesiredHeading-CurrentHeading) <= -60)&&((DesiredHeading-CurrentHeading) >- 360)){
	LeftSpeed=-40;
	RightSpeed=40;
    }else if (((DesiredHeading-CurrentHeading) <= 6)&&((DesiredHeading-CurrentHeading) >= -6)){
	LeftSpeed=40;
	RightSpeed=40;
    }
    LeftSpeed0=.8*LeftSpeed+.2*LeftSpeed0;
    RightSpeed0=.8*RightSpeed+.2*RightSpeed0;
    setEngineSpeed1(LeftSpeed0);
    setEngineSpeed2(RightSpeed0);
    Serial.print("LeftSpeed: ");
    Serial.print(LeftSpeedF);
    Serial.print("\t");
    Serial.print("RightSpeed:");
    Serial.print(RightSpeedF);
    Serial.print("\t");
    Serial.print("DesiredHeading:");
    Serial.print(DesiredHeading);
    Serial.print("\t");
    Serial.print("CurrentHeading:");
    Serial.print(CurrentHeading);
    Serial.print("\t");
    Serial.print("CurrentX:");
    Serial.print(CurrentX, 4);
    Serial.print("\t");
    Serial.print("CurrentY:");
    Serial.print(CurrentY, 4);
    Serial.print("\t");
    Serial.print("Y:");
    Serial.print(ParkingLotY[Instance], 4);
    Serial.print("\t");
    Serial.print("X:");
    Serial.print(ParkingLotX[Instance], 4);
    Serial.print("\t");
    Serial.print("Instance:");
    Serial.println(Instance);
    delay(50);
  }while((abs(DeltaX)>0.0001)&&(abs(DeltaY)>0.0001));
  setEngineSpeed1(0);
  setEngineSpeed2(0);
}
 

Open in new window


as of now i'm using:

           CurrentX=atof(CurrentXascii);
           CurrentY=-atof(CurrentYascii);

and it's coming out a bit inaccurate, these are the coordinates i'm pulling:

http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=40.5202916,+-74.459635&sll=37.0625,-95.677068&sspn=48.15347,79.013672&ie=UTF8&ll=40.520431,-74.459603&spn=0.000711,0.001206&t=h&z=20

when the gps is actually located in the parking lot.....not good haha

the code I wrote to extract individual strings and make it into a double (basically a home made atod function) is coming up with total trash numbers:

  for (int i=0,k=5;i<5;i++,k--){
            CurrentX1=CurrentX1+(10^k)*((int)CurrentXascii[i]);
            Serial.println(CurrentX1);
          }
          for (int i=6,k=8;i<13;i++,k--){
            CurrentX2=CurrentX2+(10^k)*((int)CurrentXascii[i]);
            Serial.println(CurrentX2);
          }
          for (int i=1,k=5;i<6;i++,k--){
            CurrentY1=CurrentY1+(10^k)*((int)CurrentYascii[i]);
            Serial.println(CurrentY1);
          }
          for (int i=7,k=7;i<13;i++,k--){
            CurrentY2=CurrentY2+(10^k)*((int)CurrentYascii[i]);
            Serial.println(CurrentY2);
          }
          CurrentXi=CurrentX1+(CurrentX2/10000);
          CurrentYi=-(CurrentY1+(CurrentY2/10000));
          CurrentX=CurrentXi;
          CurrentY=CurrentYi;
          CurrentX1,CurrentX2,CurrentY1,CurrentY2,CurrentXi,CurrentYi=0;
        }

Open in new window


don't mind the serial.prints they are from when I was trying to trouble shoot the for loops. CurrentX and CurrentY are coming out to be insane numbers.

I can't seem to figure out how to convert it to a double.
0
Comment
Question by:BleedScarlet
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
5 Comments
 
LVL 9

Expert Comment

by:masheik
ID: 34117809
Try like below, I am usig codeblocks IDE it prints the digits correctely for me

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char *currentXascii[2];
    double currentX;
    currentXascii[0] = (char *)calloc(10,sizeof(char));
    strcpy(currentXascii[0],"12345.45678");
    currentX = atof(currentXascii[0]);
    printf(" currentX = %f ",currentX);
    return 0;
}

/*console output 
-----------------
 currentX = 12345.456780
Process returned 0 (0x0)   execution time : 0.000 s
Press any key to continue. */

Open in new window

0
 

Author Comment

by:BleedScarlet
ID: 34117948
I don't what works on codeblocks or not, but it doesn't work on arduino.

the main difficulty here is the character array stores each digit as a value in the array

so the array appears as: CurrentXascii={4,0,3,1,.,2,4,5,6,} and converting that array to a usable number is the problem, it's not a single value in the array that i can't pull, it's the WHOLE array.

I'm looking into how to delete the period and convert it but I think the atof and atol commands by default turn any character it doesn't understand into a 0, so if I remove the period it'll appear as 403102456 instead and while that is problematic I think I could make it worth with some creative division and floor commands. I've been at it for a while and it's more difficult than I thought, I don't know how I would do that either.
0
 
LVL 9

Expert Comment

by:masheik
ID: 34119778
 I have given some code below, may be it will help you on this issue,
it is a quick and dirty fix.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* prototypes */
void test(void);
char* InttoChar(int i);
/* end of programs */



int main()
{
    /*char *currentXascii[2];//= {'1','2','3','4','.','5','6','7','8'};
    double currentX;
    currentXascii[0] = (char *)calloc(10,sizeof(char));
    strcpy(currentXascii[0],"12345.456781");
    currentX = atof(currentXascii[0]);
    printf("currentX = %f \n",currentX);
    free(currentXascii[0])*/
    test();
    return 0;
}


void test(void)
{

    char currentXascii[10] = {4,0,3,'.',2,0,5,6,9,'\0'};
    /* I Took period as character */
    //char currentXascii[10] = {'4','0','3','1','.','2','4','5','6','\0'};
    /* The commented code only contatins the signle char values not ints inside char array */
    char digit[10] = {'\0'};
    char decimal[10] = {'\0'};
    char wholeDigit[10]= {'\0'};
    int len = 0;
    int i = 0,j = 0, k = 0;
    int value;
    double digit_d;
    printf("Digit before          = %s \n",currentXascii);
    for(len = 0; (currentXascii[len]!= '\0') || (len <(sizeof(currentXascii)/sizeof(currentXascii[0]))-1); len++);
    printf("Length                = %d \n",len);
    for(i = 0; currentXascii[i] != '.'; i++);
    printf("Dot found at          = %d \n",i);
    for(j= 0 ; j < i ; j++)
    {
        digit[j] = *(char *)InttoChar(currentXascii[j]);
    }
    digit[j] = '\0';
    for(i = 0,k= j+1; i <(len+j) ,k < len; i++,k++)
    {
        decimal[i] = *(char *)InttoChar(currentXascii[k]);
    }
    decimal[i] = '\0';
    printf("digit = %s , Decimal = %s\n",digit,decimal);
    strcat(wholeDigit,digit);
    strcat(wholeDigit,decimal);
    printf("whole digit           = %s \n",wholeDigit);
    strcat(digit,".");
    strcat(digit,decimal);
    digit_d = atof(digit);
    printf("String len of digit   = %d \n",strlen(digit));
    printf("Digit only            = %s \n",digit);
    value = atoi(wholeDigit);
    printf("Int value             = %d \n",value);
    printf("Float value           = %f \n",digit_d);
    //printf("Testing\n");
    getchar();

}

char* InttoChar(int i)
{
    static char string[1];
    sprintf(string,"%d",i);
    return string;
}

Open in new window

0
 

Accepted Solution

by:
BleedScarlet earned 0 total points
ID: 34140537
I fixed it on my own with some help from one of my professors...we did something totally different and mind numbingly simple, and it worked.

closing this question as unsolved since I got no answers here.
0
 

Author Closing Comment

by:BleedScarlet
ID: 34179076
unsolved
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Since upgrading to Office 2013 or higher installing the Smart Indenter addin will fail. This article will explain how to install it so it will work regardless of the Office version installed.
This article will show how Aten was able to supply easy management and control for Artear's video walls and wide range display configurations of their newsroom.
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…
Six Sigma Control Plans

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question