Using button as a toggle switch

So, I'm working on a project in which I needed to, at the press of a button, move two servos simultaneously to a 90-degree position and then, when I press the button again, return the servos to 0 degrees (neutral). I just wanted to share the program with others to make the switch action easier.

{
  while (!digitalRead(button)){} // While button is not pushed do nothing 
  while (digitalRead(button)){} // When button is pushed satify above condition
  if (servoState){ // When servo state nuetral move to 90 degrees on servo(s) 
    myservo.write(100); 
    myservo2.write(100);
  }
  else{ //When servo state active (not nuetral) return to 0 degrees (nuetral) on servo(s)
    myservo.write(10); 
    myservo2.write(10);
  }
  servoState = !servoState; // reset servo state to nuetral 
}

Welcome to the forum

You need to detect when the button becomes pressed rather than when it is pressed
See the StateChangeDetection example in the IDE

it's always a good idea to not rely on automatic promotion and the fact that LOW is 0. These should be written as

  while (digitalRead(buttonPin) == LOW)  {} // While button is not pushed do nothing 
  while (digitalRead(buttonPin) == HIGH) {} // When button is pushed satisfy above condition

And if your button is bouncing, this won't work anyway...


Using a button library would make the code much easier to read.

see the example here

click to see the code
#include <Servo.h>
#include <Toggle.h>

const byte servoPin = 3;
const byte buttonPin = 12;
enum {SERVO_0, SERVO_90} servoPosition = SERVO_0;
Toggle button;
Servo servo;

void moveTo0() {
  servo.write(0);
  servoPosition = SERVO_0;
}

void moveTo90() {
  servo.write(90);
  servoPosition = SERVO_90;
}

void setup() {
  button.begin(buttonPin);
  servo.attach(servoPin);
  moveTo0();
}

void loop() {
  button.poll();
  if (button.onPress()) {               // we got a new button press
    switch (servoPosition) {            // handle the change based on current position
      case SERVO_0:  moveTo90(); break; // we were at 0°, move to 90°
      case SERVO_90: moveTo0();  break; // we were at 90°, move to 0°
    }
  }
}


Note that as the Arduino doc states

Capacitors are often recommended for powering servo motors. They help stabilize the power supply, minimize voltage drops, and reduce electrical noise. The specific capacitor values may vary based on the servo motor's requirements, but including them is good practice for better performance and reliability.

When using a Feetech Mini Servo Motor we recommend using a 100 µF capacitor.

I built your project and it is nearly impossible to consistently toggle the servo. You have seen it, I am sure, and now you know it is because the processor is very fast, and pushbuttons bounce, that is to say there is a brief period when they are in transition where the value read will go back and forth.

But not so fast or brief that a sketch doesn't have plenty of time to see in between values and make it right through your logic gate at the top.

But the logic gate idea is clever - so I added just a bit of delay to each part of the gate, so the bouncing gets absorbed or ignored.

This is a bad way to handle the problem, but I thought you deserved to see it work, with just a tiny fix.

Play with it here:

Your code, with the fix and some plausible extra stuff to make a complete sketch:

// https://wokwi.com/projects/421427942117502977

# include <Servo.h>

Servo myservo;

# define button 7
# define servo  9

void setup() {
  myservo.attach(servo);

  pinMode(button, INPUT_PULLUP);
}

bool servoState;

void loop()
{
  while (!digitalRead(button)) delay(25);
  while (digitalRead(button)) delay(25);

  if (servoState) {
    myservo.write(100); 
  }
  else {
    myservo.write(10); 
  }

  servoState = !servoState;
}

Another way to fix it is to use buttons that do not bounce. IRL these are hard to come by, not normal at all. In the simulator, you can turn off the bouncing that it simulates, and see perfect buttons validate your two step logic gate.

Try it for fun: replace the delays with your original do-nothing {}, and click on the pushbutton in the diagram and turn off bouncing in the dialog that pops up. When the skethc is not running.

You can add

  Serial.begin(115200);

to your setup() function, then use serial printing at various places to see your logic flow. It is a good way to see if the flow through your code is what you think... it should never be a surprise to find out how yuor code is working, but it happens.

HTH

a7

1 Like

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