Initiate 360 servo (not continuous) to return to original position immediately

Hello,

I am currently using two 360 degree servos to turn 360 degrees from 0 - 360 degrees and then return 360 - 0 degrees on loop. That part works fine. The issue I am having is the servos are set off using a potentiometer, once its value reaches over 512 the servos start and once its value is below 512 they stop and return to their original position.

As it stands the servos do eventually return to their original position but not immediately. They keep going until they eventually reach 0 degrees again which can be upwards of 10 seconds. How do I get it so that the servos stop turning once the potentiometer is below 512 and immediately return to 0 degrees?

The following is a copy of my code:

#include <Servo.h>

Servo servo;
Servo servo2;

unsigned int pwm = 1000;

int potPin = A0;
int potVal = 0;

void setup() {

  Serial.begin(9600);

  servo.attach(9);
  servo2.attach(10);
  
}

void loop() 
{

  potVal = analogRead(potPin);
  Serial.println(potVal);

  if(potVal >= 0 && potVal <= 512) {
    initialPos();
  }

  if(potVal >= 513 && potVal <= 1024) {
    servoCommandOne();
    servoCommandTwo();
  }
}

void initialPos() {
  servo.writeMicroseconds(1000);
  delay(1);
  servo2.writeMicroseconds(1000);
  delay(1);
}

void servoCommandOne () {

  for (int pwm = 1000; pwm <= 2000; pwm ++) {
    servo.writeMicroseconds (pwm);
    delay (random(3,7));

    servo2.writeMicroseconds (pwm);
    delay (random(3,7));
  }

}

void servoCommandTwo() {

  for (int pwm = 2000; pwm >= 1000; pwm --) {
    servo.writeMicroseconds (pwm);
    delay (random(3,7));

    servo2.writeMicroseconds (pwm);
    delay (random(3,7));
  }
}

Any help would be fantastic :slight_smile:

Moderator edit: The usual.

You need to get the delay()s out of your code completely. AND you need to take the FOR loops out of your servoCommand() functions.

Both of these prevent the new position of the potentiometer from being detected by blocking the Arduino until the FOR loop completes.

Look at how the servo is controlled in planning and implementing a program and in several things at a time. In both cases millis() is used for timing without blocking. I think the servo code in planning ... is most like what you want.

...R

Thanks Robin that's great help.

It works a lot better now, although it has raised a slight new issue in the sense that the servos do now immediately return to their original position when the potentiometer value is below 512 but then the servos now also return to the position they were in prior to the potentiometer reading falling below 512. The updated code is as follows:

#include <Servo.h>

Servo servo;
Servo servo2;

unsigned int pwm = 1000;

int countUpDown = 0;

long timerVal = 50;

int potPin = A0;
int potVal = 0;

void setup() {

Serial.begin(9600);

servo.attach(9);
servo2.attach(10);

}

void loop()
{

potVal = analogRead(potPin);
Serial.println(potVal);

if(potVal >= 0 && potVal <= 512) {

servo.writeMicroseconds(1000);
servo2.writeMicroseconds(1000);

}

if(potVal >= 513 && potVal <= 1024) {

if ((timerVal + 5) <= millis()) {

servo.writeMicroseconds (pwm);
servo2.writeMicroseconds (pwm);
pwm = pwm + countUpDown;

if(pwm == 1000) {
countUpDown = 1;
}

if(pwm == 2000) {
countUpDown = -1;
}

timerVal = millis();
}
}

}

Try this (not tested)
I have tried to mark all the changes I made but study it carefully in case I missed something.

Note the use of unsigned long for variables related to millis()
Note the use of subtraction when checking millis() - that prevents problems when millis() rollsover to 0
Note the use of simplified IF and ELSE. There is not need to check an analog value below 0 or above 1023

#include <Servo.h>

Servo servo;
Servo servo2;

unsigned int pwm = 1000;

int countUpDown = 0;

unsigned long timerVal = 50;    //========
unsigned long lastMoveMillis;    //========

int potPin = A0;
int potVal = 0;

void setup() {

  Serial.begin(9600);

  servo.attach(9);
  servo2.attach(10);

}

void loop()
{

  potVal = analogRead(potPin);
  Serial.println(potVal);

  if(potVal<= 512) {    //===========

    servo.writeMicroseconds(1000);
    servo2.writeMicroseconds(1000);

  }

  else {    //===============

    if (millis() - lastMoveMillis >= timerVal) {    //==================
      lastMoveMillis += timerVal;    //=============
      servo.writeMicroseconds (pwm);
      servo2.writeMicroseconds (pwm);
      pwm = pwm + countUpDown;

      if(pwm == 1000) {
        countUpDown = 1;
      }

      if(pwm == 2000) {
        countUpDown = -1;     
      };
    }
            //=================
  }

}

And please, in future, use the code button when posting code.

...R

Hello,

Thank you for helping but the last code did not seem to make a difference to the issue. It still speeds forward to where it was located prior to the potentiometer reduced below 512.

I looked through it line by line but did not see anything you had missed.

Just found the code button, sorry did not see it before.

lukie934:
It still speeds forward to where it was located prior to the potentiometer reduced below 512.

I guess I don't understand what you are trying to tell me.

Can you describe what happens step by step.

...R

Yeah sure.

  1. The servos are both positioned at 0 degrees
  2. The potentiometer is turned and it goes above 512
  3. At this point the two servos begin to turn from 0 degrees to 360 then return 360 degrees to 0, this occurs on a loop.
  4. The servos travel to position 'x' typically mid way to 0 or 360 degrees, then potentiometer is turned back below 512.
  5. At this point both servos return immediately to 0 degrees.

The Issue:
6) The potentiometer is once again turned above 512.
7) The two servos then immediately return to position 'x' and then continue to turn to either 360 or 0 degrees.

What I want is instead of the servos going straight to position 'x' after the potentiometer is turned above 512 they just start again from 0 degrees.

Context of servos:
The servos are used within a mechanical object to drive two axles, the potentiometer is connected to a dial. The reason I need the servos to start again from zero after the potentiometer goes above 512 is that the mechanism the axles are controlling looks a bit bizarre if it keeps speeding forwards to position 'x' when the dial is turned.

Hope this is all clear :slight_smile:

Just change this

  if(potVal<= 512) { 
    servo.writeMicroseconds(1000);
    servo2.writeMicroseconds(1000);
  }

to this

  if(potVal<= 512) { 
   pwm  =1000;
    servo.writeMicroseconds(pwm);
    servo2.writeMicroseconds(pwm);
  }

This is a good illustration of why it is best to use variables rather than hard-wired values. I had not spotted that issue earlier.

In fact you can simplify things further (hope I have my brackets in the right place)

void loop()
{

  potVal = analogRead(potPin);
  Serial.println(potVal);

  if(potVal<= 512) {
     pwm = 1000;
  }

  else {
    if (millis() - lastMoveMillis >= timerVal) { 
      lastMoveMillis += timerVal; 
      pwm = pwm + countUpDown;

      if(pwm == 1000) {
        countUpDown = 1;
      }

      if(pwm == 2000) {
        countUpDown = -1;     
      };
    }
 
  }
  servo.writeMicroseconds (pwm);
  servo2.writeMicroseconds (pwm);

}

Always be suspicious of scope for improvement if you find identical code in different places.

...R

Ok so for some unknown reason there is a new issue now, related to the change just made.

The code works in the sense that the servos return back to 0 degrees and start there based upon the potentiometers reading. For some unknown reason after the potentiometer is turned over 512 on occasions the servos then travel in one direction indefinitely, they cease to stop and return to 0 degrees.

Having gone through the code line by line it appear that this part is the issue:

if(potVal<= 512) {
 --> pwm = 1000; <---
  }

When I replace that back with this code the old issue occurs again but the new one ceases to happen:

if(potVal <= 512) {
    servo.writeMicroseconds (1000);
    servo2.writeMicroseconds (1000);
  }

Any ideas on why this would occur?

I wonder if changing these lines

            if(pwm == 1000) {
                countUpDown = 1;
            }

            if(pwm == 2000) {
                countUpDown = -1;

to

           if(pwm <= 1000) {
                countUpDown = 1;
            }

            if(pwm >= 2000) {
                countUpDown = -1;

would help.

If not please post your complete code (latest version) with your reply.

...R

Fantastic that seems to have helped a lot.

I changed it slightly so that the servos now stop where they are when the potentiometer reaches under 512 and then carry on as opposed to going back to 0 degrees.

Thanks for all your help.

Least I can do is post the complete code for anyone doing anything similar:

#include <Servo.h>

Servo servo;
Servo servo2;

unsigned int pwm = 1000;

int countUpDown = 0;

unsigned long timerVal = 5;
unsigned long lastMoveMillis;

int potPin = A0;
int potVal = 0;

void setup() {

  Serial.begin(9600);

  servo.attach(9);
  servo2.attach(10);

}

void loop()
{

  potVal = analogRead(potPin);
  Serial.println(potVal);

  if(potVal<= 512) {
    unsigned long timerVal = 0;
  }

  else {
    unsigned long timerVal = 5;

    if (millis() - lastMoveMillis >= timerVal) { 
      lastMoveMillis += timerVal; 
      pwm = pwm + countUpDown;

      if(pwm <= 1000) {
        countUpDown = 1;
      }

      if(pwm >= 2000) {
        countUpDown = -1;  
      }

    }
    servo.writeMicroseconds (pwm);
    servo2.writeMicroseconds (pwm);

  }
}

This is NOT correct

if(potVal<= 512) {
    unsigned long timerVal = 0;
  }

  else {
    unsigned long timerVal = 5;

You already have a variable called timerVal declared before setup().

Using unsigned long again creates a new variable (unfortunately with the same name) and, just as important, that new variable only exists within the {} where it is declared. So, for example, the first one goes out of scope immediately it is created.

Drop the unsigned longs. The one at the top of the code is all you need.

In any case, I suspect there is no need to change the value of timerVal from its initial value.

...R