count servo movement

Hi.

I have a project where I have a servo which should change its position from 80° to 140° and back to 80° 4times. What is important I can not use delay in the code.

I tried in many ways, and all worked for continuous ‘sweep’ but I can not count the cycles.

Basically I have an RTC that provides time and in a certain time it calls the servo function that should do 4 sweeps from 80° → 140° → 80°.

I tried with a for loop then do…while cycle with no success. Coud you give me few tips? Thank you.

Code only for the servo:

#include <Servo.h>
 
Servo myservo;
int myservo_pin = 17;
long myservo_movetime = 50;
int pos = 80;
int cPos;
int gPos;
int tDelay = 10;
 
void setup() {
  myservo.attach(myservo_pin);
} 
 
void loop() {

  cPos = myservo.read();
  if (cPos == 80) gPos = 140;
  if (cPos == 140) gPos = 80;
  if (cPos != gPos && millis() >= myservo_movetime) moveServo(); 
} 

void moveServo() {
  if (cPos < gPos) myservo.write(cPos+1);
  if (cPos > gPos) myservo.write(cPos-1);
  myservo_movetime = millis() + tDelay;
}

Something to experiment with

#include <Servo.h>
Servo theServo;
byte sweepCount;
const byte servoPin = A5;
int servoIncrement = 1;
byte servoPos = 80;
boolean moving = false;
unsigned long waitStartTime;
unsigned long currentTime;
unsigned long stepPeriod = 10;

const byte buttonPin = A1;  //for testing purposes

void setup()
{
  Serial.begin(115200);
  theServo.attach(servoPin);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop()
{
  currentTime = millis();
  if (moving == false)
  {
    if (digitalRead(buttonPin) == LOW)
    {
      moving = true;
    }
  }
  else
  {
    if (currentTime - waitStartTime >= stepPeriod)  //time to move
    {
      theServo.write(servoPos);
      servoPos += servoIncrement;
      if (servoPos < 80 || servoPos > 140)
      {
        servoIncrement *= -1;
        sweepCount++;
        if (sweepCount == 8)
        {
          moving = false;
          sweepCount = 0;
        }
      }
      waitStartTime = currentTime;
    }
  }
  //other non blocking code can be put in loop()
}

In this program the servo sweeps are started with a button press but you could start them with any other required trigger.

Thank you. Exactly this is what I was looking for, In the meantime I figured out a workaround, but your solution looks better.

Thank you.

What would be even better would be a state machine controlled by switch/case with 3 states. It would be more obvious what was happening

Thank you very much. I will look forward to it and implement in the next variant.

A state machine version

#include <Servo.h>
Servo theServo;
byte sweepCount;
const byte servoPin = A5;
int servoIncrement = 1;
unsigned long stepStartTime;
unsigned long currentTime;
unsigned long stepPeriod = 10;
const byte lowerLimit = 80;
const byte upperLimit = 140;
byte servoPos = lowerLimit;

const byte triggerPin = A1;  //for testing purposes

enum states
{
  WAITING_FOR_TRIGGER,
  INCREASE_ANGLE,
  DECREASE_ANGLE
};

byte currentState = WAITING_FOR_TRIGGER;

void setup()
{
  Serial.begin(115200);
  theServo.attach(servoPin);
  theServo.write(servoPos);
  pinMode(triggerPin, INPUT_PULLUP);
}

void loop()
{
  currentTime = millis();
  switch (currentState)
  {
    case WAITING_FOR_TRIGGER:
      if (digitalRead(triggerPin) == LOW)
      {
        servoPos = lowerLimit;
        theServo.write(servoPos);
        stepStartTime = currentTime;
        currentState = INCREASE_ANGLE;
        sweepCount = 0;
      }
      break;
    //--------------------------------------------
    case INCREASE_ANGLE:
      if (currentTime - stepStartTime >= stepPeriod)
      {
        servoPos += servoIncrement;
        if (servoPos > upperLimit)
        {
          servoPos = upperLimit;
          stepStartTime = currentTime;
          currentState = DECREASE_ANGLE;
        }
        else
        {
          theServo.write(servoPos);
          stepStartTime = currentTime;
        }
        break;
      //--------------------------------------------
      case DECREASE_ANGLE:
        if (currentTime - stepStartTime >= stepPeriod)
        {
          servoPos -= servoIncrement;
          if (servoPos < lowerLimit)
          {
            sweepCount++;
            if (sweepCount == 4)
            {
              currentState = WAITING_FOR_TRIGGER;
            }
            else
            {
              servoPos = lowerLimit;
              stepStartTime = currentTime;
              currentState = INCREASE_ANGLE;
            }
          }
          theServo.write(servoPos);
          stepStartTime = currentTime;
        }
        break;
      }
  }
  //other non blocking code can be put in loop()
}

Wow. Thank you. :slight_smile: :slight_smile: