String method .toInt() doesn't seem to work properly (IDE 1.8.12)

Hi all,

I recently purchased an Allbot robot kit to play around with and to get back into programming.

The provided code for a 4-legged, 8-servo robot doesn’t seem to play nice in one specific aspect; when converting parts of a command (stored in a String) using .toInt(), the conversion isn’t done properly and I’m left with a bunch of garbage.

This is the part of the provided code that gets and parses a received command:

void getcommand( void )
{ 
  int space1 = 0;
  int space2 = 0;
  
  if( Serial.available() ) 
  {
     rawcommand = Serial.readString();

     // Checking for and deleting garbage data at the beginning of received command
     if( ( rawcommand.indexOf( '<' ) != 0 ) && ( rawcommand.indexOf( '<' ) != -1 ) )
     {
        rawcommand.remove( 0, rawcommand.indexOf( '<' ) );
     }

     // Checking for and deleting garbage data at the end of received command
     if( rawcommand.length() > ( rawcommand.indexOf( '>' ) + 1 ) )
     {
        rawcommand.remove( ( rawcommand.indexOf( '>' ) + 1 ), ( rawcommand.length() - 1 ) );
     }
     
     if( receivelog )
     {
        Serial.println( "\n\n..:: START:" + rawcommand + ":END ::.." + "\r\n" );        
     }
     
     // Check if received command is properly formatted
     if( ( rawcommand.charAt( 0 ) == '<' ) && ( rawcommand.indexOf( '>' ) <= 12 ) &&
         ( rawcommand.indexOf( '>' ) != -1 ) && ( rawcommand.length() > 7 ) )
     {
       if( receivelog )
       {
         Serial.println( "Recieved command is VALID\n" ); 
       }

       // Parse command received via IR into its parts
       command = rawcommand.substring( 1, 3 );
       
       // Finding the spaces to save the times and speed
       for( int i=0; i <= rawcommand.length(); i++ )
       {
         if( ( rawcommand.charAt( i ) == ' ' ) && ( space1 == 0 ) )
         {
            space1 = i;
         }
         else if( ( rawcommand.charAt( i ) == ' ' ) && ( space2 == 0 ) )
         {
            space2 = i;
         }
       }

       // Number of times to execute the command
       times = rawcommand.substring( ( space1 + 1 ), space2 ).toInt();
       // String version of above
       timesStr = rawcommand.substring( ( space1 + 1 ), space2 );
       
       // Speed in milliseconds
       speedms = rawcommand.substring( ( space2 + 1 ), rawcommand.indexOf( '>' ) ).toInt();
       // String version of above
       speedmsStr = rawcommand.substring( ( space2 + 1 ), rawcommand.indexOf( '>' ) );

       if( receivelog )
       {
         Serial.println( "Parsed command components are: " );
         Serial.flush();
         Serial.println( "Command code = " + command );
         Serial.flush();
         Serial.println( "Number of times to execute command = " + times );
         Serial.flush();
         Serial.println( "Speed (in milliseconds) = " + speedms );
         Serial.flush();
       }
     }
     else
     {
       if( receivelog )
       {
          Serial.println( "Command is NOT valid\n" );
       }
       resetserial();  
     }
  }
}

Which yields the following output:

To make sure that the individual substrings were being formed properly, I did this:

if( receivelog )
{
Serial.println( "Parsed command components are: " );
Serial.flush();
Serial.println( "Command code = " + command );
Serial.flush();
Serial.println( "Number of times to execute command = " + timesStr );
Serial.flush();
Serial.println( "Speed (in milliseconds) = " + speedmsStr );
Serial.flush();
}

Which gave the expected results:

I read up on the documentation for .toInt(); and found that this method requires a null-terminated string to function correctly… so down the rabbit hole I went.

I tried appending the substring with a ‘\0’, I also tried the suggestion from one forum of first converting the substring into a character array (to make sure the ‘\0’ was in fact at the end of the substring) then using atoi(); on the character array. I tried many different approaches to converting these substrings to integers.

Maybe I’m not doing something correctly, maybe the standard library for whatever it is Arduino uses was updated (I found varying statements on what it actually is; C++ wrappers around C, some sort of modified C++, etc.) or maybe there’s just a simpler way of doing this that I’m not seeing.

Any help or pointing in the right direction would be much appreciated!

your println() function is what is messed up, not .toInt(). A line like this

      Serial.println( "Number of times to execute command = " + times );

will take the value of 'times' (1) and add it to the value of the string which is some pointer to memory. C/C++ does not automagically turn your integer into a string and concatenate it with the string before it.

      Serial.print( "Number of times to execute command = ");
      Serial.println(times );

It does do that with the String variables since that is a class and knows how to combine a String with a string (notice the difference. A C string is a null terminated array of chars)

I would personally throw that code away and avoid using the String class since it will lead to memory fragmentation. That function is basically a bastardized version of Robin2's tutorial here which is better to use.