How to accomplish a SERVO sweep Forward and Reverse both with millis?

Hi,
The sketch below just sweep CW, and doesn't return, why?
Thanks
Adam

#include <Servo.h>
Servo myservo;  // create servo object to control a servo

// BOTH FLSERVO and FRSERVO use same millis:
unsigned long SweepstartMillis;  //some global variables available anywhere in the program
unsigned long SweepcurrentMillis;
const unsigned long Sweepperiod = 50;  //the value is a number of milliseconds

unsigned long SweepstartMillisn;  //some global variables available anywhere in the program
unsigned long SweepcurrentMillisn;
const unsigned long Sweepperiodn = 50;  //the value is a number of milliseconds

unsigned long LedstartMillis;  //some global variables available anywhere in the program
unsigned long LedcurrentMillis;
const unsigned long Ledperiod = 20;  //the value is a number of milliseconds

int pos = 0;    // variable to store the servo position
int posn = 180;
int led = 13;

int SweepStart = 0;
int ReturnStart = 0;

void setup() {
  // put your setup code here, to run once:

 pinMode(led, OUTPUT);
  myservo.attach(47);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  // put your main code here, to run repeatedly:
SERVO_sweep();
}

void SERVO_sweep()
{
  while (!SweepStart == 0)
  {
    Serial.println("L55 wait for!");
  }

  // put your main code here, to run repeatedly:
  SweepcurrentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (SweepcurrentMillis - SweepstartMillis >= Sweepperiod)  //test whether the period has elapsed
  {
    //  digitalWrite(ledPin, !digitalRead(ledPin));  //if so, change the state of the LED.  Uses a neat trick to change the state
    pos = pos + 2;
    if (pos > 180) ///// WAS: 180, [int SERVO_range = 180;]  SERVO scan the first 180 degree and then no readings but just turn ~175 degree?
    {
      SweepStart = 1;
      ReturnStart = 1;
      SERVO_return();
      posn = 180;
      pos = 180;
    }
    myservo.write(pos);
    SweepstartMillis = SweepcurrentMillis;  //IMPORTANT to save the start time of the current LED state.
  }
}

void SERVO_return()
{
  while (!ReturnStart == 1)
  {
    Serial.println("L87 wait for!");
  }

  Serial.println("SERVO_return start!");

  SweepcurrentMillisn = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (SweepcurrentMillisn - SweepstartMillisn >= Sweepperiodn)  //test whether the period has elapsed
  {
    //  digitalWrite(ledPin, !digitalRead(ledPin));  //if so, change the state of the LED.  Uses a neat trick to change the state
    posn = posn - 2;
    if (posn = 0)  ///// WAS: 180, [int SERVO_range = 180;]  SERVO scan the first 180 degree and then no readings but just turn ~175 degree?
    {
      //   SERVO_return();
      SweepStart = 0;
      pos = 0;
      posn = 0;
    }
    myservo.write(posn);
    SweepstartMillisn = SweepcurrentMillisn;  //IMPORTANT to save the start time of the current LED state.
  }
}

You only call SERVO_return() once so its timing and servo movement have no chance of working. You need to call it repeatedly once the initial sweep has taken place

Call it from loop() rather than SERVO_sweep()

1 Like

Using millis() is looking at the clock, and do what should be done at that moment.
When using millis(), the sketch will run smooth if there are no delay() and there is no waiting for something with a while-statement. Let the loop() run as fast and as many times per second as possible.

To control a servo motor with millis(), the current servo position is often updated every 10ms or every 20ms. That means that only a single millis-timer with a fixed delay of 10ms or 20ms is needed to control many servo motors at the same time.

You need math to calculate where the posistion of the servo motor should be at that moment. You might also need extra variables to tell if the servo motor is moving or not or going upward or downward and at what speed.

I have made a example in Wokwi simulation for that. Click the start button and turn the knobs and push the buttons. The explanation is in the sketch.

2 Likes

The mobaTools-Library can slowly sweep a servo in the backround
You set a slow turning speed and do a simple

myServo.setSpeed(mySpeed);
myServo.write(TargetAngle);

and the slowly sweeping is done "in the backround"
You can read status-information

myServo.moving();
myServo.read();

So the sweeping reduces to
set sweeping-speed

set target-angle
check if target-angle is reached
if target-ange is reached set new target-angle
repeat

#include <MobaTools.h>
/* Demo to move a servo slowly
   In this example a servo sweeps slowly between two positions as long as
   a button is pressed. If the button is released, it stops immediately and
   starts again from that position if the button is pressed again.
   The sketch does not block and can be extended to do other tasks.
*/

// The button must be connected between pin and Gnd
const int buttonPin1 = A2;  //button1 Pin 2
const int servoPin   = 3 ;  // The servo is connected to this pin

// Position to sweep
const byte target1 = 30;
const byte target2 = 120;

bool buttonPressed;
byte targetPos = target1;    // actual targetposition for the servo

MoToServo myServo;

void setup() {
  pinMode(buttonPin1, INPUT_PULLUP);

  myServo.attach(servoPin);
  myServo.setSpeed( 5 );    // set speed of servo
}

void loop() {
  buttonPressed =  !digitalRead(buttonPin1); // 'ButtonPressed is 'true' if pin is LOW

  if (buttonPressed && not myServo.moving() ) {
    if ( myServo.read() == target1 ) targetPos = target2;
    if ( myServo.read() == target2 ) targetPos = target1;
    myServo.write(targetPos); //will move slowly
  }

  if ( !buttonPressed ) myServo.write( myServo.read() );    // stop immediately
}

best regards Stefan

1 Like

You are setting ReturnStart to 1 just before calling SERVO_return().

At the beginning of SERVO_return() you wait for "not ReturnStart" (in other words, false or 0) to be equal to 1. That is never going to be true. Your function will be stuck in that loop sending "L87 wait for!" forever.

1 Like

Hello

Another example here exemple_servo_15_01_22.ino - Wokwi Arduino and ESP32 Simulator

1 Like
#include <Servo.h>
Servo myservo;  // create servo object to control a servo

const byte ServoPin = 47;
const unsigned StepPeriod = 50;
const int StepIncrement = 2;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  myservo.attach(ServoPin);
}

void loop()
{
  // put your main code here, to run repeatedly:
  SERVO_sweep();
}

void SERVO_sweep()
{
  static int pos = 0;
  static int increment = StepIncrement;
  static unsigned long startMillis = 0;
  
  unsigned long currentMillis = millis();
  if (currentMillis - startMillis >= StepPeriod)
  {
    startMillis = currentMillis;
    
    pos += increment;
    if (pos > 180)
    {
      pos = 180;
      increment = -StepIncrement;
    }
    
    if (pos < 0)
    {
      pos = 0;
      increment = StepIncrement;
    }
    
    myservo.write(pos);
  }
}
2 Likes

Thank you johnwasser
perfect!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.