Servo Moving On Its Own

So I am using an Mg 996R servo motor and it seems to be moving by itself. I am trying to get it to move from 0 to 90 degrees whenever I press a button. I am also trying to make a timer of 10 seconds which starts whenever the servo is done moving. However, as soon as I upload the program the servo just starts repeatedly moving from the 0 to 90 degrees without the button being pressed. I have another code where it is similar just without the timer section and it works fine there.

I think that the problem may be in the loop section. Here it is. Anyone have any recommendations?

void loop() {

int button1State = digitalRead(button1Pin);

if (button1State == HIGH) {
    servo1.attach(servo1Pin);
    servo1.write(90);
    delay(2000);
    servo1.write(0); 
    delay(100);
    startMillis = millis();
}
  
  currentMillis = millis();
  if (BeginTimer1 < (currentMillis - startMillis) < Timer1) {   //current time minus 0 checking time
    servo1.detach();    //if 0 < time < 10000 
  } else {
    servo1.attach(servo1Pin);
  }
  if (currentMillis - startMillis >= Timer1) {
    servo1.attach(servo1Pin);
  }
}

Servo "moving on its own" is almost always a power supply problem. For that servo, a separate, 5-6V, 3 Ampere power supply is required. Never try to use the Arduino 5V as power for motors or servos.

Get the servo working with the Arduino sweep example first.

That said, what could you possibly be trying to do with all those attach/detach calls? detach() is almost never necessary.

Show us a good schematic of your proposed circuit. Show us a good image of your ‘actual’ wiring.
Give links to components.


In the Arduino IDE, use Ctrl T or CMD T to format your code then copy the complete sketch.
Use the </> icon from the ‘reply menu’ to attach the copied sketch.

Thanks. I'll try out the separate power supply.

As for the multiple attach and detach calls I am trying to make sure that the servo isn't able to move even when the button is pressed while the timer is running. If this won't work, do you know what will?

Please explain what you are trying to do, and as requested above, post a wiring diagram (hand drawn) for the project.

"Timer running" is completely independent of the processor.

I am trying to make sure that the servo isn't able to move

In fact, detaching the servo enhances the probabilty that it will move in reaction to electrical noise in the wiring.

Here's is how I have everything wired.

And then here is the entire code.

#include <Servo.h>
Servo servo1;

const int button1Pin = 4;
const int servo1Pin = 10;

unsigned long BeginTimer1 = 0;    //start of timer
unsigned long Timer1 = 10000;  //duration of timer is set to 10 seconds
unsigned long startMillis;   //setting start time as 0
unsigned long currentMillis;  //currentMillis to get the current time when needed

void setup() {
  servo1.attach(servo1Pin);
  servo1.write(0);           //setting up servo to start in original position
  delay(1000);
  servo1.detach();

  pinMode(button1Pin, INPUT);   //button is the input
  pinMode(servo1Pin, OUTPUT);  //servo is the output

}

void loop() {

  int button1State = digitalRead(button1Pin);

  if (button1State == HIGH) {
    servo1.attach(servo1Pin);
    servo1.write(90);
    delay(2000);
    servo1.write(0);
    // delay(100);
    startMillis = millis();
  }

  currentMillis = millis();
  if (BeginTimer1 < (currentMillis - startMillis) < Timer1) {   //current time minus 0 checking time
    servo1.detach();    //if 0 < time < 10000
  } else {
    servo1.attach(servo1Pin);
  }
  if (currentMillis - startMillis >= Timer1) {
    servo1.attach(servo1Pin);
  }
}

Please confirm Arduino 5v is connected to the correct 5v pin on your servo.

It is never recommended that you power motors from the Arduino.

Motors and high current loads should be powered from an external power supply.

EDIT

Instead of:

  servo1.attach(servo1Pin);
  servo1.write(0);

Try:

  servo1.write(0);       
  servo1.attach(servo1Pin);

Tell us what you think this does ?
if (BeginTimer1 < (currentMillis - startMillis) < Timer1) {

Please avoid Fritzing diagrams. Post a photo of a hand drawn diagram instead.

The breadboard is a big problem, as they are intended for low current logic circuits. If used for motors or servos (especially powerful ones like the MG996R), the breadboard tracks will burn.

Either solder the power connections, or use a servo power distribution PCB (DIY: https://diyodemag.com/projects/servo_power).

It is connected to the 5v pin.

I'm trying to see if the current time (currentMillis) minus the time that the startMillis = mills() is in between 0 and 10 seconds.

I’ve been trying out different ways to do the timer but my main focus is fixing the servo. I haven’t been able to continue working on the timer since I haven’t been able to figure out how to get the servo to work.

Stop doing that immediately!

1 Like

Do you have a recommendation of an alternative power supply I can use?

Two problems

  1. The BeginTimer1 is set to zero and is never changed.
  2. You can't cascade < functions like you do here. Even if you could then you seem to want to detach the servo during the first ten seconds and only after that attach them. So the last two lines are redundant.

As you have been told that repeated attach and detach calls are not necessary the whole lower part of that code is not necessary

It is always bad when comments don't match the code. Tell me what is the point of subtracting zero from any variable?
If you did want to use this, which is the wrong thing to do then I think you need to use

if ( (millis() - startMillis) < Timer1) {  

I can try it out. I also want to make sure that once the 10 seconds have passed that the timer is reset so that the next time the button is pressed it starts over. Will this still work?

Only if you know the stall current of the servo.

Also note that you failed to enable the internal pull up resistors to make your push button work correctly. You need to use

pinMode(buttonPin, INPUT_PULLUP);

And then in your if statement look for a LOW to indicate that the button has been pressed.

No you don't want to do that at all. You let the timer run and set the
startMillis when you see the button pressed.

A point on that code, The sweep will happen all the time the button is pressed.

Confirm

On button press, move servo to 90' for 10 seconds then back to 0'

It's actually move servo to 90' for 2 seconds and then back to 0. The ten seconds is the timer in which the servo isn't able to move.

Sorry I'm not exactly sure what is meant by "look for low". Could you show what this would look like please?