splitting ASCII string to variables

I am receiving ascii string from ARDUimu over serial into an array, and then using atoi function to convert this into an integer.
I edited the output format to !ANG:-11.35,-8.51,14.78 (message preamble,roll, pitch,yaw). I edited the following code from a former post in the forum .The code seems to work fine if the string data is just set up as a "string" in an initialized array but fails if i read stuff into a char array.

void setup() {
  // initialize both serial ports:
  Serial.begin(38400);
  Serial1.begin(38400);
}

void loop() {
  char arr[30];
  // read from port 1, send to port 0:
  if (Serial1.available()) {
    char arr[30] ={ Serial1.read()};
     Serial.write(arr);
  }
   
  
    char str[30];
    float roll, pitch, yaw;
    int errors = 0;
    
    strcpy(str, arr);

    // First is throwaway unless you want to do strcmp with "!ANG" or some such thing
    char *chpt = strtok(str, ":");
    if (chpt == NULL) {
        Serial.println("First strok returns NULL");
        ++errors;
    }

    if (errors == 0) {
        chpt = strtok(NULL, ",");
        if (chpt == NULL) {
            Serial.println("Second strok returns NULL");
            ++errors;
        }
        else {
            roll = atof(chpt);
        }
    }

    if (errors == 0) {
        chpt = strtok(NULL, ",");
        if (chpt == NULL) {
            Serial.println("Third  strok returns NULL");
            ++errors;
        }
        else {
            pitch = atof(chpt);
        }
    }

    if (errors == 0) {
        chpt = strtok(NULL, ",\r\n");
        if (chpt == NULL) {
            Serial.println("Fourth strok returns NULL");
            ++errors;
            // This is an input error: do something to handle it.
        }
        yaw = atof(chpt);
    }
    if (errors == 0) {
        Serial.print("(");
        Serial.print(roll);
        Serial.print(", ");
        Serial.print(pitch);
        Serial.print(", ");
        Serial.print(yaw);
        Serial.println(")");
    }
}

Output:
!First strok returns NULL
AFirst strok returns NULL
NFirst strok returns NULL
GFirst strok returns NULL
:First strok returns NULL
1First strok returns NULL
.First strok returns NULL
0First strok returns NULL
8First strok returns NULL
,First strok returns NULL
-First strok returns NULL
0First strok returns NULL
.First strok returns NULL
1First strok returns NULL
3First strok returns NULL
,First strok returns NULL
3First strok returns NULL
5First strok returns NULL
.First strok returns NULL
8First strok returns NULL
4First strok returns NULL

As you can see the serial data received is printed vertically as the first letter of each output line.
However when i run the first serial.read and serial.write commands alone putting everything else as comment. the output is as follows

!ANG:1.01,0.09,34.84
!ANG:1.02,0.17,34.84
!ANG:1.37,0.25,34.85
!ANG:1.08,0.47,34.85
!ANG:1.49,0.36,34.85
!ANG:1.13,0.08,34.85
!ANG:1.38,0.14,34.85
!ANG:1.00,0.17,34.84
!ANG:1.34,0.20,34.83
!ANG:1.35,0.15,34.86
!ANG:1.27,0.30,34.85
!ANG:1.30,0.46,34.85
!ANG:1.43,0.04,34.87
!ANG:1.13,0.30,34.87

Help me please i cant understand why the code doesn't work. However the code works if the value of the string arr[30] is given as
char arr[30] = {
"!ANG:-11.35,-8.51,14.78"
};
and not received in serial. =(
Is there another easy way to get the variables from the string received

  char arr[30];
  // read from port 1, send to port 0:
  if (Serial1.available()) {
    char arr[30] ={ Serial1.read()};

This little snippet of code declares TWO arrays of the same name. Really NOT what you want to do.

Tell me, is it that hard to understand that Serial1.read() returns ONE character?

    strcpy(str, arr);

Why? There is no reason to copy the array anywhere. Which arr are you copying, anyway?

    char *chpt = strtok(str, ":");
    if (chpt == NULL) {
        Serial.println("First strok returns NULL");

Would be a good idea if the message printed matched the function call. There is no call to strok.

The str functions, like strcpy(), strtok(), etc. expect strings as arguments. What you are providing are not strings.

A string is a NULL terminated array of chars. What you have is an array of chars that is not NULL terminated. Therefore, it is NOT a string. Therefore, you can not pass it to strcpy() or strtok().

If you have any control over the sender, make it shape up and sent properly delimited data. "!ANG:1.01,0.09,34.84" should be "<!ANG:1.01,0.09,34.84>". Then you can use code like this:

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
   Serial.begin(57600);
   // Other stuff...
}

void loop()
{
  // Read all serial data available, as fast as possible
  while(Serial.available() > 0)
  {
    char inChar = Serial.read();
    if(inChar == SOP)
    {
       index = 0;
       inData[index] = '\0';
       started = true;
       ended = false;
    }
    else if(inChar == EOP)
    {
       ended = true;
       break;
    }
    else
    {
      if(index < 79)
      {
        inData[index] = inChar;
        index++;
        inData[index] = '\0';
      }
    }
  }

  // We are here either because all pending serial
  // data has been read OR because an end of
  // packet marker arrived. Which is it?
  if(started && ended)
  {
    // The end of packet marker arrived. Process the packet

    // Reset for the next packet
    started = false;
    ended = false;
    index = 0;
    inData[index] = '\0';
  }
}

To receive the serial data. Where it says "Process the packet" is where you put the code to call strtok() for the NULL terminated string, inData.

Hi PaulS
Thanks mate
sorry for making silly mistakes. i am a mechanical stream student and have little(only a weak) experience in programming.

and now this is the thing .....
I am using a arduIMU to read euler angles(in the format roll,pitch,yaw). I have conected the tx pin of the imu to the rx1 pin of arduino mega.
The arduIMU serial.prints the euler angles. I need to use the arduino mega to read the data from arduimu through rx1 pin and store the values into corresponding variables (as roll=xx,pitch=xx,yaw=xx)in arduino mega board.

how can i do this ??

The arduIMU serial.prints the euler angles.

Using what code? Can you alter it?

If the current code looks something like:
Serial.print("!ANG");
Serial.print(roll);
Serial.print(",");
Serial.print(pitch);
Serial.print(",");
Serial.println(yaw);
Then, it is possible to use the ! as the start marker and the carriage return as the end marker.

If you can't determine the format of the output, then you need to print the incoming data, in character and HEX mode, to figure out whether the data is delimited by a carriage return, a line feed, or both.

Once you have the data in an array, then strtok() and atof() can be used to parse and convert the data. The assignment operator can be used to store the value in the appropriate variable.

Using what code? Can you alter it?

The code is in the format you sugested
Serial.print("!ANG");
Serial.print(roll);
Serial.print(",");
Serial.print(pitch);
Serial.print(",");
Serial.println(yaw);

I understand the code you gave and i have a doubt.
If the serial received data is stored in a array inData[index] and then if strtok function is performed wont the data be
available as seperate charecters and not as a single string to perform atof function??

If the serial received data is stored in a array inData[index] and then if strtok function is performed wont the data be
available as seperate charecters and not as a single string to perform atof function??

inData[index] is an array element, not an array. It is important to keep the terminology straight.

strtok() returns a pointer to a portion of the string that is being parsed. If inData contains "Joe is a small monkey" and strtok() is called, with a delimiter set containing just a space, strtok() will return a pointer that points to "Joe".

If inData contains "123.456 789.123 876.543", and strtok() is called, with a delimiter set containing just a space, strtok() will return a pointer that points to "123.456", which, obviously, atof() will easily handle.

Hi PaulS,
Thank you very much.
Finally made it, the code worked well.
I don't know what i would have done without your help and i thank this wonderful forum.
You stand by the quote "We make a living by what we get, but we make a life by what we give."
:slight_smile:

Finally made it, the code worked well.

Excellent. Time to move on to the next project?