0

How can I stop my following code using a key?

Basically the code should run the servo in a loop if "t" is pressed and stop the loop if "s" is pressed.

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;    // variable to store the servo position
int servodata;

void setup() {
  myservo.attach(8);  // attaches the servo on pin 9 to the servo object

  Serial.begin(9600);

}

void loop() {
  if (Serial.available()>0){
    servodata = Serial.read();
    while (servodata == 't'){
           for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
       myservo.write(pos);              // tell servo to go to position in variable 'pos'
       delay(3);                       // waits 15ms for the servo to reach the position
  }
    for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
       myservo.write(pos);              // tell servo to go to position in variable 'pos'
       delay(3);                       // waits 15ms for the servo to reach the position
    }
    }
  }
  while (servodata == 's'){
    break;
  }
}

thank you for help.

4
  • 1
    Basically: Don't use blocking for loops and delays. Delays are just busy waiting. Look into a non-blocking coding style like demontrated in the BlinkWithoutDelay example, that comes with the Arduino IDE. It has been explained throughout the internet.
    – chrisl
    Aug 30, 2019 at 20:35
  • separate the value of servodata and the servo motion ... use a flag variable ... for example, name the flag go ... if go is true then run the motor ( if (go) { ) ... read the value from serial and set go accordingly ... that way the servo code is not inside the if serial loop
    – jsotola
    Aug 30, 2019 at 20:46
  • could you post and example? thanks
    – Andy Andy
    Aug 30, 2019 at 20:48
  • why do you need a for loop to position the servo?
    – jsotola
    Aug 30, 2019 at 20:51

1 Answer 1

1

Here is a quick and dirty solution, where each loop() iteration corresponds to one “start sweeping”/“stop sweeping” cycle:

  • wait for the “start” command
  • then sweep back and forth in an infinite loop
  • stop at any point if you receive the “stop” command
void loop() {
    // Wait for the 'start' command.
    while (Serial.read() != 't')
        continue;

    // Repeatedly sweep back and forth.
    for (;;) {
        for (int pos = 0; pos <= 180; pos += 1) {
            myservo.write(pos);
            delay(3);
            if (Serial.read() == 's') // check for 'stop' command
                return;
        }
        for (pos = 180; pos >= 0; pos -= 1) {
            myservo.write(pos);
            delay(3);
            if (Serial.read() == 's') // check for 'stop' command
                return;
        }
    }
}

Note that this approach has a couple of drawbacks:

  1. As this is blocking code, you cannot easily extend the program to do other things.
  2. The sweeping runs always start at position 0, instead of resuming from the position that was current on the last “stop” command.

If you need anything more sophisticated, you should go to a non-blocking approach based on a Finite State Machine (c.f. jsotola's comment). Note that you can get away with delay(3);, as it is a quite short delay, but you would have to break the sweeps into one step per loop() iteration.

I suggest you give the FSM approach a try: read the tutorial I linked to, then try to implement it. If you cannot get it to work, you can always post another question here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.