Servo timing? How to get it right?

Hey all!

This is my first post and project. Like we all, doubts and difficulties arise.
Mine are servos, the basic one I guess.
I do understand code and logic bases but coding is not my thing. AT ALL!!! =)

My project, if I can call it like that, combines arduino and an external device which combined will mechanically operate a small die cast model. Like a presentation/display model.

I'll try to better describe the setup:

Arduino: to manage LED, servo and LCD/OLED (still deciding which one to be used)
External device: provides some outputs, that are sent to arduino. 3 are negative. Only 1 is a positive signal that the device will receive also.
DieCast model: will open and close doors thanks to the servo.
Remote control to test functionalities without the need of visible buttons. Just a redundancy.
(where you see buttons, will eventually be controlled by the external device or remote control)
So when the external devices output signals, arduino will turn LED's ON/OFF, display messages on LCD and control the servo.

Simple setup right? (I'm completely out of dept)

The problem I have is the servo speed.
Running the Sweep example, is clear where to tweak the rotation speed, however, when implementing that same code in my sketch, inside a for loop, the speed (delay) seems to lose any control over the servo.
The solution I got running was to write a bunch of lines with specific angles and that way I managed to get the desired speed control I was looking for.

Below you have my whole sketch. Do not make fun of it please =)
The //UNLOCK part is where I attempted the bunch of angles and the //LOCK is the sweep code inside the for loop.
Also tried different approaches from other projects but I was not able to make them work.

//DECLARATION

#include<Servo.h>
Servo servo;

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 10, 5, 4, 3, 2);

int doorsButtonState = 0;
int pos = 0;

int buttonLock = A3;
int buttonUnlock = A2;
int lockLED = 7;
int unlockLED = 8;

int imoState = 0;
int imoGV = A1;
int imoLED = 11;

int ignState = 1;
int ignGV = A4;
int ignLED = 6;

#include <IRremote.h>
int IRsensor = A0;
IRrecv irrecv(IRsensor);
decode_results results;

//SETUP

void setup() {
  servo.attach(9);
  servo.write(pos);

  pinMode(buttonLock, INPUT_PULLUP);
  pinMode(buttonUnlock, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lockLED, OUTPUT);
  pinMode(unlockLED, OUTPUT);

  lcd.begin(16, 2);
  lcd.print("Some message here");
  lcd.setCursor(0, 1);
  lcd.print("More message here");

  pinMode(imoGV, INPUT_PULLUP);
  pinMode(imoLED, OUTPUT);

  pinMode(ignGV, INPUT);
  pinMode(ignLED, OUTPUT);

  Serial.begin(9600);
  irrecv.enableIRIn();
}

//ACTIONS
void(* resetFunc) (void) = 0;

void loop() {
  //UNLOCK
  doorsButtonState = digitalRead(A2);
  if (digitalRead(buttonUnlock) == LOW) {
    for (pos = 80; pos >= 0; pos += 1) {
      lcd.setCursor(0, 0);
      lcd.print("Unlocking doors   ");
      lcd.setCursor(0, 1);
      lcd.print("Please wait...     ");
      servo.write(5);
      digitalWrite(unlockLED, HIGH);
      digitalWrite(LED_BUILTIN, HIGH);
      digitalWrite(lockLED, LOW);
      delay(100);
      servo.write(10);
      delay(100);
      servo.write(15);
      delay(100);
      servo.write(20);
      digitalWrite(unlockLED, LOW);
      delay(100);
      servo.write(25);
      delay(100);
      servo.write(30);
      delay(100);
      servo.write(35);
      digitalWrite(unlockLED, HIGH);
      delay(100);
      servo.write(40);
      delay(100);
      servo.write(45);
      delay(100);
      servo.write(50);
      digitalWrite(unlockLED, LOW);
      delay(100);
      servo.write(55);
      delay(100);
      servo.write(60);
      delay(100);
      servo.write(65);
      digitalWrite(unlockLED, HIGH);
      delay(100);
      servo.write(70);
      delay(100);
      servo.write(75);
      delay(100);
      servo.write(80);
      //digitalWrite(unlockLED, LOW);
      lcd.setCursor(0, 0);
      lcd.print("Doors Unlocked!     ");
      lcd.setCursor(0, 1);
      lcd.print("Drive safe!!     ");
      delay(100);
      //digitalWrite(unlockLED, HIGH);
      break;
    }
  }

  //LOCK
  doorsButtonState = digitalRead(A3);
  if (digitalRead(buttonLock) == LOW) {
    for (pos = 0; pos <= 90; pos -= 1) {
      servo.write(pos);
      delay(15);
      break;
    }
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(lockLED, HIGH);
    digitalWrite(unlockLED, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Locking doors   ");
    lcd.setCursor(0, 1);
    lcd.print("Please wait...     ");
    delay(250);
    digitalWrite(lockLED, LOW);
    delay(250);
    digitalWrite(lockLED, HIGH);
    delay(250);
    digitalWrite(lockLED, LOW);
    delay(250);
    digitalWrite(lockLED, HIGH);
    delay(250);
    digitalWrite(lockLED, LOW);
    delay(250);
    digitalWrite(lockLED, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("Doors Locked!     ");
    lcd.setCursor(0, 1);
    lcd.print("Good-bye!!     ");
  }

  //IMOBILIZER Button
  imoState = digitalRead(A1);
  if (digitalRead(imoGV) == LOW) {
    digitalWrite(imoLED, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
  }

  //IGNITION Button
  ignState = digitalRead(A4);
  if (digitalRead(ignGV) == HIGH) {
    digitalWrite(ignLED, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
  }

  //IR Sensor
  if (irrecv.decode(&results)) {
    switch (results.value) {
      case 16738455: //Remote UNLOCK
        servo.write(80);
        digitalWrite(unlockLED, HIGH);
        digitalWrite(lockLED, LOW);
        delay(5);
        lcd.setCursor(0, 0);
        lcd.print("Unlock Test..     ");
        lcd.setCursor(0, 1);
        lcd.print("OK!               ");
        delay(1000);
        lcd.setCursor(0, 0);
        lcd.print("Some message here");
        lcd.setCursor(0, 1);
        lcd.print("More message here");
        digitalWrite(unlockLED, LOW);
        break;

      case 16724175: //Remote LOCK
        servo.write(0);
        digitalWrite(lockLED, HIGH);
        digitalWrite(unlockLED, LOW);
        delay(5);
        lcd.setCursor(0, 0);
        lcd.print("Lock Test..     ");
        lcd.setCursor(0, 1);
        lcd.print("OK!             ");
        delay(1000);
        lcd.setCursor(0, 0);
        lcd.print("Some message here");
        lcd.setCursor(0, 1);
        lcd.print("More message here");
        digitalWrite(lockLED, LOW);
        break;

      case 16732845: //Remote RESET
        resetFunc();
        break;

      case 16718055: //Remote IMO
        digitalWrite(imoLED, HIGH);
        lcd.setCursor(0, 0);
        lcd.print("Imob Test..      ");
        lcd.setCursor(0, 1);
        lcd.print("OK!              ");
        delay(250);
        digitalWrite(imoLED, LOW);
        delay(250);
        digitalWrite(imoLED, HIGH);
        delay(250);
        digitalWrite(imoLED, LOW);
        delay(250);
        digitalWrite(imoLED, HIGH);
        delay(250);
        lcd.setCursor(0, 0);
        lcd.print("Some message here");
        lcd.setCursor(0, 1);
        lcd.print("More message here");
        break;

      case 16743045: //Remote IGN
        digitalWrite(ignLED, HIGH);
        lcd.setCursor(0, 0);
        lcd.print("Ignition Test..   ");
        lcd.setCursor(0, 1);
        lcd.print("OK!               ");
        delay(250);
        digitalWrite(ignLED, LOW);
        delay(250);
        digitalWrite(ignLED, HIGH);
        delay(250);
        digitalWrite(ignLED, LOW);
        delay(250);
        digitalWrite(ignLED, HIGH);
        delay(250);
        lcd.setCursor(0, 0);
        lcd.print("Some message here");
        lcd.setCursor(0, 1);
        lcd.print("More message here");
        break;
    }
    irrecv.resume();
    Serial.println(results.value, DEC);
  }
  else {
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(imoLED, LOW);
    digitalWrite(ignLED, LOW);
  }
}

Any ideas on how to fix the servo speed?
Thanks in advance!

Best!

Read that back to yourself, in your head
Use pencil and paper if necessary.

The varSpeedServo library may be of interest.

This is a common problem. You can use interpolation libraries like RAMP in order to control the position of the servo across a period of time with linear or sinusoidal (there are a lot more) curves.

Not sure if I got you but in my head it goes something like: To get pos 80, if it is bigger or equal to zero, move +1.

Should the -=1?

I think I tried + and - back and forth and to get the correct motion/direction this was the one that worked as I wanted

I read it as "set pos to 80.
While pos is greater than or equal to zero, do some stuff in the body of the loop, then add one to pos"

How long is it going to take for pos to from 80 to 32767?

don't you want to start at 0 and increment pos when < 80?

Hey guys,

Thanks for the feedback.
I've tried just the for loop, straight out of the sweep example, only adding the if button and still the same. The delay loses the timing ability.

When I use it like this it works just fine:

void loop() {
  for (pos = 0; pos <= 90; pos += 1) { 
    myservo.write(pos);              
    delay(100);                       // I clearly can play with time here
  }
  for (pos = 90; pos >= 0; pos -= 1) { 
    myservo.write(pos);             
    delay(100);                      
  }
}

But when I use it inside the if statement, nothing:

#include <Servo.h>
Servo myservo;

int pos =  0; 
int doorsButtonState = 0;
int buttonLock = A3;
int buttonUnlock = A2;

void setup() {
  myservo.attach(9); 
  myservo.write(pos);
  pinMode(buttonLock, INPUT_PULLUP);
  pinMode(buttonUnlock, INPUT_PULLUP);
}

void loop() {
  doorsButtonState = digitalRead(A2);
  if (digitalRead(buttonUnlock) == LOW) {
    for (pos = 0; pos <= 90; pos += 1) {
      myservo.write(pos);
      delay(100);
      break;
    }
  }
  doorsButtonState = digitalRead(A3);
  if (digitalRead(buttonLock) == LOW) {
    for (pos = 90; pos >= 0; pos -= 1) {
      myservo.write(pos);
      delay(100);
      break;
    }
  }
}

What am I doing wrong?

Thanks!

Your break is on the first iteration of each for loop

Go back to the Sweep example that works. Does it have a "break" statement? Have a look at any other programs with for loops. Do any of them have "break" statements in the for loop?

It may be worth checking what "break" actually does.

Steve

> break is used to exit from a for , while or do…​while loop, bypassing the normal loop condition. It is also used to exit from a switch case statement.

Maybe I understood it on reverse order but my logic was to exit the if statement and wait for the next order instead of continuing the loop.

But yes, the break was breaking it!

Hey guys!

Thank you all for the inputs. After some more fiddling, the tips of @TheMemberFormerlyKnownAsAWOL and @slipstick (despite what the break meant for me) shed some light. I removed the break and it works!!
Nice.

Eventually I had to make some adjustments on the structure order to keep the same behaviour and it looks something like this:

//DECLARATION
int doorsButtonState = 0;
int buttonLock = A3;
int buttonUnlock = A2;
#include<Servo.h>
Servo servo;
int pos = 0;
int lockLED = 7;
int unlockLED = 8;
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 10, 5, 4, 3, 2);
int imoState = 0;
int imoGV = A1;
int imoLED = 11;
int ignState = 1;
int ignGV = A4;
int ignLED = 6;
#include <IRremote.h>
int IRsensor = A0;
IRrecv irrecv(IRsensor);
decode_results results;

//SETUP
void setup() {
  servo.attach(9);
  servo.write(pos);
  pinMode(buttonLock, INPUT_PULLUP);
  pinMode(buttonUnlock, INPUT_PULLUP);
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(lockLED, OUTPUT);
  pinMode(unlockLED, OUTPUT);
  lcd.begin(16, 2);
  lcd.print("some text");
  lcd.setCursor(0, 1);
  lcd.print("some text");
  pinMode(imoGV, INPUT_PULLUP);
  pinMode(imoLED, OUTPUT);
  pinMode(ignGV, INPUT);
  pinMode(ignLED, OUTPUT);
  Serial.begin(9600);
  irrecv.enableIRIn();
}

//ACTIONS
void(* resetFunc) (void) = 0;

void loop() {
  //UNLOCK
  doorsButtonState = digitalRead(A2);
  if (digitalRead(buttonUnlock) == LOW) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(unlockLED, HIGH);
    digitalWrite(lockLED, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Unlocking doors   ");
    lcd.setCursor(0, 1);
    lcd.print("Please wait...     ");
    for (pos = 0; pos <= 80; pos += 1) {
      servo.write(pos);
      delay(28);
    }
    lcd.setCursor(0, 0);
    lcd.print("Doors Unlocked!     ");
    lcd.setCursor(0, 1);
    lcd.print("Drive safe!!     ");
    digitalWrite(unlockLED, LOW);
    delay(250);
    digitalWrite(unlockLED, HIGH);
    delay(250);
    digitalWrite(unlockLED, LOW);
    delay(250);
    digitalWrite(unlockLED, HIGH);
    delay(250);
    digitalWrite(unlockLED, LOW);
    delay(250);
    digitalWrite(unlockLED, HIGH);
  }
  //LOCK
  doorsButtonState = digitalRead(A3);
  if (digitalRead(buttonLock) == LOW) {
    digitalWrite(LED_BUILTIN, HIGH);
    digitalWrite(lockLED, HIGH);
    digitalWrite(unlockLED, LOW);
    lcd.setCursor(0, 0);
    lcd.print("Locking doors   ");
    lcd.setCursor(0, 1);
    lcd.print("Please wait...     ");
    for (pos = 80; pos >= 0; pos -= 1) {
      servo.write(pos);
      delay(28);
    }
    lcd.setCursor(0, 0);
    lcd.print("Doors Locked!     ");
    lcd.setCursor(0, 1);
    lcd.print("Good-bye!!     ");
    digitalWrite(lockLED, LOW);
    delay(250);
    digitalWrite(lockLED, HIGH);
    delay(250);
    digitalWrite(lockLED, LOW);
    delay(250);
    digitalWrite(lockLED, HIGH);
    delay(250);
    digitalWrite(lockLED, LOW);
    delay(250);
    digitalWrite(lockLED, HIGH);
  }
  //IMOBILIZER Button
  imoState = digitalRead(A1);
  if (digitalRead(imoGV) == LOW) {
    digitalWrite(imoLED, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
  }
  //IGNITION Button
  ignState = digitalRead(A4);
  if (digitalRead(ignGV) == HIGH) {
    digitalWrite(ignLED, HIGH);
    digitalWrite(LED_BUILTIN, HIGH);
  }
  //IR Sensor
  if (irrecv.decode(&results)) {
    switch (results.value) {
      case 16738455: //Remote UNLOCK
        digitalWrite(unlockLED, HIGH);
        lcd.setCursor(0, 0);
        lcd.print("Unlock Test..     ");
        lcd.setCursor(0, 1);
        lcd.print("                 ");
        for (pos = 0; pos <= 80; pos += 1) {
          servo.write(pos);
          delay(15);
        }
        lcd.setCursor(0, 0);
        lcd.print("Unlock Test..     ");
        lcd.setCursor(0, 1);
        lcd.print("OK!             ");
        delay(1000);
        digitalWrite(unlockLED, LOW);
        lcd.setCursor(0, 0);
        lcd.print("some text");
        lcd.setCursor(0, 1);
        lcd.print("some text");
        break;

      case 16724175: //Remote LOCK
        digitalWrite(lockLED, HIGH);
        lcd.setCursor(0, 0);
        lcd.print("Lock Test..     ");
        lcd.setCursor(0, 1);
        lcd.print("                 ");
        for (pos = 80; pos >= 0; pos -= 1) {
          servo.write(pos);
          delay(15);
        }
        lcd.setCursor(0, 0);
        lcd.print("Lock Test..     ");
        lcd.setCursor(0, 1);
        lcd.print("OK!             ");
        delay(1000);
        digitalWrite(lockLED, LOW);
        lcd.setCursor(0, 0);
        lcd.print("some text");
        lcd.setCursor(0, 1);
        lcd.print("some text");
        break;

      case 16732845: //Remote RESET
        resetFunc();
        break;

      case 16718055: //Remote IMO
        digitalWrite(imoLED, HIGH);
        lcd.setCursor(0, 0);
        lcd.print("Imob Test..      ");
        lcd.setCursor(0, 1);
        lcd.print("                 ");
        delay(250);
        digitalWrite(imoLED, LOW);
        delay(250);
        digitalWrite(imoLED, HIGH);
        delay(250);
        digitalWrite(imoLED, LOW);
        delay(250);
        digitalWrite(imoLED, HIGH);
        delay(250);
        lcd.setCursor(0, 0);
        lcd.print("Imob Test..      ");
        lcd.setCursor(0, 1);
        lcd.print("OK!             ");
        delay(1000);
        lcd.setCursor(0, 0);
        lcd.print("some text");
        lcd.setCursor(0, 1);
        lcd.print("some text");
        break;

      case 16743045: //Remote IGN
        digitalWrite(ignLED, HIGH);
        lcd.setCursor(0, 0);
        lcd.print("Ignition Test..   ");
        lcd.setCursor(0, 1);
        lcd.print("                  ");
        delay(250);
        digitalWrite(ignLED, LOW);
        delay(250);
        digitalWrite(ignLED, HIGH);
        delay(250);
        digitalWrite(ignLED, LOW);
        delay(250);
        digitalWrite(ignLED, HIGH);
        delay(250);
        lcd.setCursor(0, 0);
        lcd.print("Ignition Test..   ");
        lcd.setCursor(0, 1);
        lcd.print("OK!             ");
        delay(1000);
        lcd.setCursor(0, 0);
        lcd.print("some text");
        lcd.setCursor(0, 1);
        lcd.print("some text");
        break;
    }
    irrecv.resume();
    Serial.println(results.value, DEC);
  }
  else {
    digitalWrite(imoLED, LOW);
    digitalWrite(LED_BUILTIN, LOW);
    digitalWrite(ignLED, LOW);
  }
}

Again, thank you all for the brain challenge!
I'll be back!!!