Reading the three numerical values from string coming from rx

Hi
I am new to Arduino and programming. I would like some help on a project.
what I want to do get the 3 numerical values stored of an incoming string in 3 different variables.
eg:
data received through Rx is “ANG!:12.4@54.5@36.05@”
the data will typically be 26digits long. and always end with an @.
all I want are 3 numbers (for eg: roll:12.4 pitch:54.5 yaw:36.05)
I want to do it with regular expression
Many thanks

char SensorData[30];//for the serial op coming from sensor including letters also
char temp[20];//for storing only numerical values from the string
char yawx[8];//storing value of yaw
char s[]={0};
double v1,v2,v3;
int count = 0;
const char* p;
char c;
int j,k=0,i=0;
void setup()
  {   
      Serial.begin(57600); 
      Serial.println("9dof test");
  }
void loop()
  {
      while(Serial.available()){
          if(Serial.available()>0) 
      {
        c=Serial.read();//if data available we are storing it in a character c  
        if(i<26)
        SensorData[i++]=c;//we are saving value of character c in a string SensorData
        s[i++]=SensorData[i++];
        if(i==26)
       {
        Serial.print(SensorData);//printing sensor data  TILL HERE IT IS WORKING FINE ie IT IS PRINTING THIS STRING CORRECTLY
        i=0;//putting i=0 to store next string
      }
     /* for (p = strtok( s, "@" );  p;  p = strtok( NULL, "@" )){    
                if(count == 0)sscanf(p+5,"%lf",&v1);
                if(count == 1) sscanf(p, "%lf", &v2); 
                else if(count == 2) sscanf(p, "%lf", &v3); 
                count++;
        }
        Serial.print("v1");
        Serial.println(v1);
        Serial.print("v2");
        Serial.println(v2);
        
       Serial.print("v3");
      Serial.println(v3);*/
      
         }
   }
  }

the data will typically be 26digits long. and always end with an @.

Which of those 3 @'s ends the packet?

I want to do it with regular expression

Why?

      while(Serial.available()){
          if(Serial.available()>0)

While there is serial data available to read, there is serial data available to read. The if test is redundant (and looks stupid).

        s[i++]=SensorData[i++];

s has exactly enough room for one character. You can NOT do this!

Once you have a token, atof() seems simpler than sscanf().

Hi sir

thank you for your early reply :slight_smile: :slight_smile: :slight_smile:

i> the last among the 3 @'s is the end of the packet
ii>i was told by my instructor to do with these , also i tried other things but didnt worked out

char SensorData[30];//for the serial op coming from sensor including letters also
char temp[20];//for storing only numerical values from the string
char yawx[8];//storing value of yaw
char c;
int j,k=0,i=0;
void setup(){
  Serial.begin(57600);
  Serial.println("9dof test");
}
void loop(){
  while(Serial.available()){
    if(Serial.available()>0) {
      c=Serial.read();//if data available we are storing it in a character c  
      if(i<25)
      SensorData[i++]=c;//we are saving value of character c in a string SensorData
      if(i==25)
      {
        //Serial.println("*");
         Serial.print(SensorData);//printig sensor data  TILL HERE IT IS WORKING FINE ie IT IS PRINTING THIS STRING CORRECTLY
        i=0;//putting i=0 to store next string
      }  
    /*for(j=0;j<26;j++)
    {
      if(SensorData[j]!='A'||SensorData[j]!='N'||SensorData[j]!='G'||SensorData[j]!=':'||SensorData[j]!='@'||SensorData[j]!='!')
      for(k=0;k<20;k++)//our string comes in format "ANG!:12.4@54.5@36.05@" so here if any non integer term is encountered while 
      {                   //loop wll run and all the integer values (including sign) will be saved in another temp string
      temp[k]=SensorData[j];// we I an NOT able to print this
       //Serial.print(temp);
      }
    }
    int p=0,j=0;//after storing temp as a string we defined 2 variables pand j
    while(temp[j]!='.')//now our string should be like -"12.454.536.50"
    {                 //after every '.' there are always 2 numbers
      yawx[p]=temp[j];//so here till dot has not accoured we are further storing value of temp in another string for yaw pitch roll
      p++;//if first value coming is yaw then yawx should store '12' in this loop
       j++;
    }
      yawx[p++] = temp[j++];//then after while loop this line will sotre '.' in yawx
      yawx[p++] = temp[j++];//these next line will add 2 values coming after '.' in yawx
      yawx[p]= temp[j++];
      Serial.print(yawx);//sir we are alo not able to print yaw value*/
    }
   }
  }//like this for roll and pitch

iii>ill remove that if part
iv> i have corrected it and found out there was no use of s intead used SensorData but the values of v1,v2,v3 are coming 0 all the time…HELP!!!

char SensorData[30];//for the serial op coming from sensor including letters also
char temp[20];//for storing only numerical values from the string
char yawx[8];//storing value of yaw
char s[]={0};
double v1,v2,v3;
int count = 0;
const char* p;
char c;
int j,k=0,i=0;
void setup()
  {   
      Serial.begin(57600); 
      Serial.println("9dof test");
  }
void loop()
  {
      while(Serial.available()){
          if(Serial.available()>0) 
      {
        c=Serial.read();//if data available we are storing it in a character c  
        if(i<26)
        SensorData[i++]=c;//we are saving value of character c in a string SensorData
       // s[i++]=SensorData[i++];
        if(i==26)
       {
        Serial.print(SensorData);//printing sensor data  TILL HERE IT IS WORKING FINE ie IT IS PRINTING THIS STRING CORRECTLY
        i=0;//putting i=0 to store next string
      }
      for (p = strtok( SensorData, "@" );  p;  p = strtok( NULL, "@" )){    
                if(count == 0)sscanf(p+5,"%lf",&v1);
                if(count == 1) sscanf(p, "%lf", &v2); 
                else if(count == 2) sscanf(p, "%lf", &v3); 
                count++;
        }
        Serial.print("v1");
        Serial.println(v1);
        Serial.print("v2");
        Serial.println(v2);
        
       Serial.print("v3");
      Serial.println(v3);
      
         }
   }
  }

i> the last among the 3 @'s is the end of the packet

So, you need to count '@'s, so you know when the 3rd one arrives. Not a great plan. Serial data delivery is NOT guaranteed, so you need to plan for data getting lost.

ii>i was told by my instructor to do with these , also i tried other things but didnt worked out

No idea what this means.

iii>ill remove that if part

But, not just yet. Why not?

iv> i have corrected it and found out there was no use of s intead used SensorData but the values of v1,v2,v3 are coming 0 all the time..HELP!!!!!

Don't just comment out stupid code. There's a reason that your keyboard has a delete key. Use it.

What is point to on each pass through the for loop? Don't even try to do anything with the data that p point to until you KNOW what it points to.

The strtok() and Serial.print() functions/methods expect NULL terminated arrays of chars. Your arrays of chars are NOT NULL terminated, so you should not be passing them to strtok() or Serial.print().

If you have any control of how the "ANG!:12.4@54.5@36.05@" data string is being sent, then end the data string with a unique end of data delimiter (like putting a comma at the end like "ANG!:12.4@54.5@36.05@,") . Will make parsing the sent string much easier.

adityag6994:
data received through Rx is “ANG!:12.4@54.5@36.05@”
the data will typically be 26digits long. and always end with an @.

Assuming that a “:” precedes the first number and “@” precedes the next two, this should work:

const char *imu_str = "ANG!:12.4@54.5@36.05@";

void setup (void)
{
	float roll;
	float pitch;
	float yaw;

	Serial.begin (115200);

	parse (imu_str, &roll, &pitch, &yaw);

	Serial.print ("Roll: ");
	Serial.print (roll, 2);
	Serial.print (", Pitch: ");
	Serial.print (pitch, 2);
	Serial.print (", Yaw: ");
	Serial.print (yaw, 2);
	Serial.print ("\r\n");
}

void loop (void)
{
}

// str is the IMU string, roll pitch and yaw are obvious
void parse (const char *str, float *roll, float *pitch, float *yaw)
{
	uint8_t x;
	*roll = 0;
	*pitch = 0;
	*yaw = 0;

	for (x = 0; x < strlen(str); x++) {
		if (str[x] == ':') { // we know roll follows a ":"
			*roll = atof (&str[x+1]);
		}
		if ((str[x] == '@') && (*pitch == 0)) { // next one follows a "@"
			*pitch = atof (&str[x+1]);
		}
		if ((str[x] == '@') && (*yaw == 0)) { // last one also follows a "@"
			*yaw = atof (&str[x+1]);
		}
	}
}

Anyway, there should be enough here to get you started.