if looping in parsing string data

Hi all,

I want to control robot via PC serial port with arduino mega,
I send "a" to pivot to the left, "d" to the right etc
all the program is working good.

And I want to add some program to control 2 servos to move the camera pan and tilt according to the headset,
I use program from http://forum.arduino.cc/index.php/topic,165050.0.html and it works.

I want to send character "3" before accessing servos program, but it is not working.

here my code

#include <Servo.h> 
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo 
Servo myservo2;
int result;

void setup() {
  Serial.begin(9600);
  myservo1.attach(8);  //the pin for the servo control 
  myservo2.attach(7);
 Serial.println("test"); // to keep track of what is loaded
}

void loop() {

if(Serial.available()){
  result =  Serial.read();
  if (result== '3'){ 
    
      while (Serial.available()) {
   
  
    
            Serial.println("xxx"); //just make sure that the program have entered the if loop
            delay(5);  //delay to allow buffer to fill 
   
             if (Serial.available() >0) {
                  char c = Serial.read();  //gets one byte from serial buffer
                   readString += c; //makes the string readString
                      } 
                  }
      
               if (readString.length() >0) {
                Serial.println(readString); //see what was received
            
                servo1 = readString.substring(0, 3); //get the first three characters
                servo2 = readString.substring(3, 6); //get the next three characters 
      
                int n1 = servo1.toInt();
                int n2 = servo2.toInt();

                  Serial.println("the numbers are :");
                  Serial.println(n1);  //print to serial monitor to see number results
                  Serial.println(n2);
        
                   myservo1.write(n1);    
                   myservo2.write(n2);    
      
                    readString="";
                    servo1="";
                    servo2="";
                         } 
                }
   }
}

I use serial monitor, and the the program is fail to read the 6 character for moving the servos.

Do I make something wrong with the code?

Try:if (result== "3"){

Thank you

I have try my code and when I press 3, the program print xxx, so the problem is not in the

if (result== '3'){

I have tried with serial monitor, I input 3 then showed xxx in the monitor
and I input 6 data say 060120 and the monitor did not respond

            delay(5);  //delay to allow buffer to fill

What a load of crap. This is absolutely, positively, the wrong way to handle serial data. Learn to use end of packet markers.

If your requirement can't be met by sending single characters to control every option then you need to develop a more sophisticated strategy for sending data that will work in every case. As @PaulS suggests, a good idea is to receive all the characters until some end-marker is detected and then analyse what was received to decide what needs to be done. A simple end-marker is a Carriage Return. You can get the Arduino Serial Monitor to add one automatically.

Another good strategy is to separate the function for getting data from the PC from the function that acts on that data. Then both functions will be easier to debug and extend to meet future requirements.

...R

Then both functions will be easier to debug and extend to meet future requirements.

And, you can wait to call the function that uses the data until you have all the data for it to use.

From Nick Gammon:

How to process incoming serial data without blocking

You really should look at the State machine part as it directly addresses what you are doing.

snip--

State Machine

Another way of processing incoming data, without blocking, is to set up a "state machine". Effectively this means looking at each byte in the input stream, and handling it depending on the current state.

As an example, say you had this coming into the serial port:

R4500S80G3

Where Rnnn is RPM, Snnnn is speed, and Gnnnn is the gear setting.

The state machine below switches state when it gets a letter "R", "S" or "G". Otherwise it processes incoming digits by multiplying the previous result by 10, and adding in the new one.

When switching states, if first handles the previous state. So for example, after getting R4500 when the "S" arrives, we call the ProcessRPM function, passing it 4500.

This has the advantage of handling long messages without even needing any buffer, thus saving RAM. You can also process message as soon as the state changes, rather than waiting for end-of-line.

Yes, the code is there.

Thank Nick Gammon, PaulS and Robin2

the link that Nick gave is very helpful, I will use this the method, but for a moment I am using this code an working but not to well.

the different just moving the
delay(5) to the place before while (Serial.available()) {

Here is the code:

#include <Servo.h> 
String readString, servo1, servo2;
Servo myservo1;  // create servo object to control a servo 
Servo myservo2;
int result;

void setup() {
  Serial.begin(9600);
  myservo1.attach(8);  //the pin for the servo control 
  myservo2.attach(7);
 Serial.println("test"); // so I can keep track of what is loaded
}


void abc () {
   
   while (Serial.available()) {
   
    delay(5);  //delay to allow buffer to fill 
   
   if (Serial.available() >0) {
      char c = Serial.read();  //gets one byte from serial buffer
      readString += c; //makes the string readString
    } 
  }
   
  if (readString.length() >0) {
      Serial.println(readString); //see what was received
      
      servo1 = readString.substring(0, 3); //get the first four characters
      servo2 = readString.substring(3, 6); //get the next four characters 
      
    
      int n1 = servo1.toInt();
      int n2 = servo2.toInt();

      Serial.println("the numbers are :");
      Serial.println(n1);  //print to serial monitor to see number results
      Serial.println(n2);
        
        myservo1.write(n1);    
        myservo2.write(n2);    
    
      readString="";
      servo1="";
      servo2="";
  } 
}
   



void loop() {

if(Serial.available()){
    result =  Serial.read();
  if (result== 'g'){ 
    Serial.println("xxx");
    delay(30);  
  abc();

  }
}

}

but I will try the State Machine methods anyway.

    delay(5);  //delay to allow buffer to fill

Is STILL a bullshit bandaid solution that sometimes work for some baud rates. If you don't want to learn to read serial data properly, you will continue to have (intermittent) problems. Bite the bullet; learn to send and receive serial data properly.

void abc () {

Get real. This function name says NOTHING about what the function does.

PaulS:

void abc () {

Get real. This function name says NOTHING about what the function does.

I probably wouldn't have expressed myself with the same clarity, but I agree 100%.

You should use names for variables and functions and organize your code so that you will understand it with a single read-through after not seeing it for 6 months.

...R

PaulS:

    delay(5);  //delay to allow buffer to fill

Is STILL a bull$#!+ bandaid solution that sometimes work for some baud rates. If you don't want to learn to read serial data properly, you will continue to have (intermittent) problems. Bite the bullet; learn to send and receive serial data properly.

The Nick Gammon blog, if learned and understood teaches that very well.

I just hope that the OP gains proficiency at C/Arduino quickly.
One rule I learned right at the start: Everything Counts. Every last letter or symbol, anything out of place WILL cause the code to either stop or do what you did not want. Double and triple check on the slightest doubt or even lack of strong certainty.
Back in my day we had no internet but we could get books and load them with bookmarks. Now with the net I keep browser tabs to whatever references I need, the Arduino site has many and web pages make the rest. Even after years of coding I still look up commands because I hate wasting time doing to fix what I didn't do right.

DON'T be guessing. Every time you check first, you reinforce the correct knowledge where if you don't then you do not learn but your knowing fades a little in doubt and shadow-poking.