Link to home
Start Free TrialLog in
Avatar of BleedScarlet
BleedScarlet

asked on

AVR (Arduino) Convert char array to double?

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.
Avatar of masheik
masheik
Flag of India image

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

Avatar of BleedScarlet
BleedScarlet

ASKER

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.
 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

ASKER CERTIFIED SOLUTION
Avatar of BleedScarlet
BleedScarlet

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
unsolved