Fun with millis(): Slow Servo Movements

In this series I want to show short snippets of code around millis(). Here we will use millis() to slow down the movement of a servo. If you use a servo.write(90) to set a new position of the servo, the servo will move very fast to the new position. By using millis() we can slow down the movement. We just do a small step and than wait an interval before the next movement.

You could use delay to slow down the movement, but as the series is called "Fun with millis()" we will write a non blocking code based on millis().

The Servo Circuit

For this sketch we will need a servo connected to the Arduino and we add two buttons to start movements.

Slow Servo Arduino

A Slow Servo Object

The Arduino "Servo.h" library offers a easy way to control servos. We will create our own servo class based on Servo.h and add some member function to gain a slow movement.

/*
   Slow Servo Movements
   based on request of https://forum.arduino.cc/t/i-want-the-servo-to-be-slower-how-do-i-control-the-speed-of-the-servo-servo-speed-control/1012695/
   
   by noiasca http://werner.rothschopf.net
   2022-07-15
*/

#include <Servo.h>

constexpr uint8_t openPin = 4;    // open door
constexpr uint8_t closePin = 3;   // force close
constexpr uint8_t servoPin = 8;   // GPIO for Servo

// make your own servo class
class SlowServo {
  protected:
    uint16_t target = 90;       // target angle
    uint16_t current = 90;      // current angle
    uint8_t interval = 50;      // delay time
    uint32_t previousMillis = 0;
  public:
    Servo servo;

    void begin(byte pin)
    {
      servo.attach(pin);
    }

    void setSpeed(uint8_t newSpeed)
    {
      interval = newSpeed;
    }

    void set(uint16_t newTarget)
    {
      target = newTarget;
    }

    void update()
    {
      if (millis() - previousMillis > interval)
      {
        previousMillis = millis();
        if (target < current)
        {
          current--;
          servo.write(current);
        }
        else if (target > current)
        {
          current++;
          servo.write(current);
        }
      }
    }
};

SlowServo myservo;  // create a servo object

void setup() {
  Serial.begin(115200);
  myservo.begin(servoPin);          // start the servo object
  pinMode(openPin, INPUT_PULLUP);
  pinMode(closePin, INPUT_PULLUP);
}

void doorOpen()
{
  Serial.println(F("open"));
  myservo.set(90);
}

void doorClose()
{
  Serial.println(F("close"));
  myservo.set(0);
}

void loop() {
  if (digitalRead(openPin) == LOW)
  {
    doorOpen();
  }
  if (digitalRead(closePin) == LOW)
  {
    doorClose();
  }
  myservo.update();  // call the update method in loop
}

The member function void begin(byte pin)

The member function begin() takes one parameter: the pin where we will connect the servo pin to. This function replaced the attach method of the Servo class. Place the begin function in your setup.

The member function void setSpeed(uint8_t newSpeed)

With this member function you can influence the speed of the servo movement. Higher values will result in a longer "delay" between each move.

The member function void set(uint16_t newTarget)

This member function replaces the "servo.write(newAngle)". It just sets the new target value for the servo angle.

The member function void update()

update() is the run method. It will adjust the current angle in the proper interval until the target angle is reached. Put this function in your loop().

Summary

You see, slowing down actions on the Arduino is quite easy using millis(). There is no need to block the code with a delay().

Links

(*) Disclosure: Some of the links above are affiliate links, meaning, at no additional cost to you I will earn a (little) comission if you click through and make a purchase. I only recommend products I own myself and I'm convinced they are useful for other makers.

History

First upload: 2022-07-15 | Version: 2024-03-22