Arduino pushbutton servo rotation

I’m just starting the journey of arduino so please be patient with me. I have some code that was posted in the arduino forum that I tweaked a bit to try to use two push buttons to rotate a servo +90 and -90 degrees. I will be using two SPDT push on/off switches to get the servo to rotate, but as the code stands now, the servo will continue to rotate if either switch is left in the on position, and I don’t know how to go about fixing it. If I were to use momentary switches it would work, but I need to use push on/off ones.

Also, how do I get the servo to stop humming once it gets to the desired position? Its going to be inside of a helmet, so the noise would get annoying very quickly.

Thank you for your help.

//zoomkat servo button test 12-29-2011

#include <Servo.h>
int button1 = 4; //button pin, connect to ground to move servo
int press1 = 0;
int button2 = 5; //button pin, connect to ground to move servo
int press2 = 0;
Servo servo1;
int pos = 0;

void setup()
{
  pinMode(button1, INPUT);
  pinMode(button2, INPUT);
  servo1.attach(9);
  digitalWrite(4, HIGH); //enable pullups to make pin high
  digitalWrite(5, HIGH); //enable pullups to make pin high
}

void loop()
{
  press1 = digitalRead(button1);
  if (press1 == LOW)
  {
    for (pos =0; pos <= 90; pos +=1)
    {
      servo1.write(pos);
      delay(5);
    }
  }    
  
  press2 = digitalRead(button2);
 
  if (press2 == LOW)
  {
    for (pos =90; pos >= 0; pos-=1)
    {
      servo1.write(pos);
      delay(5);
    }
  }
}

jc27:
but as the code stands now, the servo will continue to rotate if either switch is left in the on position, and I don’t know how to go about fixing it.

Of course it continues to rotate as you describe it. That's exactly the way you wrote your code...with a loop. Push one button, it goes from 0 to 90. Push the other button, goes from 90 to 0.

jc27:
If I were to use momentary switches it would work, but I need to use push on/off ones.

Also, how do I get the servo to stop humming once it gets to the desired position? Its going to be inside of a helmet, so the noise would get annoying very quickly.

Can you explain, in step-by-step detail how you want the switches to control the servo ? When SW1 is pushed on, the servo should go to position 1. What happens when SW1 is pushed off ? What happens if SW2 is pushed on while SW1 is still on ? What action is supposed to happen for all combinations of SW1 & SW2 being on and/or off ?

Which Arduino ?

For servo noise …

  1. Buy a better servo. Some are noisier than others.

  2. Turn the servo power off. But now external forces may cause movement.

  3. Try detach() -ing the servo. This should stop the commands going to the servo but it might like that. You’ll have to attach() it again before the next command.

The switches are going to be SPDT push on push off type.

Here is what I would like the servo to do:

Switch 1 is pushed and the servo rotates 90 degrees (12 o’clock to 3 o’clock) if s1 is pushed again nothing happens until servo is returned to the 12 o’clock position by s2

Switch 2 is pushed and the servo rotates -90 degrees (3 o’clock to 12 o’clock) if s2 is pushed again nothing happens until servo is moved to the 3 o’clock position by s1

Since these switches are push on push off, I am guessing that the code will need to read the switch input pin for a change of state (push on/high push off/low). I know the way the code is now that it will continue to rotate if either of the switches are left in the high position, I just am not sure how to fix the problem, hence the reason I am posting on the forum.

The servo I have is a hitec hs-85bb. The noise I referred to was probably the servo trying to maintain its position, and not the bearing or gears. If I detach the servo after it reaches the desired position, how would I reattach it so when a switch is pushed, it rotates?

As for the combinations of switch positions, it shouldn’t matter; if switch 1 is pushed it goes down, if switch 1 is pushed again it should stay down. The servo would only move again if switch 2 was pushed, then it would rotate up, if it was up and switch 2 was pushed again it would stay up, not rotate down. I hope that makes sense.

I am using an Uno.

What I think you need to do is read the switches and after debouncing, detect the falling edge of a switch push. Only on that falling edge command (only once per push) the servo to a new position. The latest switch push will over-ride the prior one. Switch releases (a true rising edge after debouncing) don’t cause any servo command, nor does leaving the switch pushed or released.

http://en.wikipedia.org/wiki/Switch#Contact_bounce

http://www.elexp.com/t_bounc.htm

http://playground.arduino.cc//Code/Bounce

That is some good information. I am a little familiar with some of it from dealing with PLC logic controllers. Writing it into the code sounds difficult though. I am going to try to come up with something this weekend, and I will post what I have. Hopefully with everyone’s help, I can get this figured out.

jc27:
Writing it into the code sounds difficult though.

Actually pretty simple. Read the Bounce library functions and I think you'll be pleasantly surprised.

Assuming I’ve understood them correctly. :mrgreen:

Sorry its been so long but another project has been a serious time vacuum. I have one of the momentary 315 MHz recievers and the rotation works, but not quite how I would like.

Here is the scenario I am looking for:

Switch A moves the servo 90 degrees CW

Switch B moves the servo 90 degrees CCW

I would like Switch A to move the servo, but once the servo has moved, switch A does nothing until switch B has moved the servo back to its original starting position.

As the code stands now if switch A is pushed the servo moves 90 degrees, but if its pushed again it tries to move again to the 90 degree CW position (it jerks back and forth). Switch B does the same thing. I would like each switch to ignore any other pushes after the first one that initiates the rotation to the switches coresponing location.

I hope I am clear in what I am trying to do. As I am reading this, it seems a bit confusing, hopefully you understand what I am getting at.

You might want to look at the VarSpeedServo library. In addition to slowing the rotation down, it also has a blocking feature you could use. Then add in some code to ignore any multiple same button commands and you’re done.

if(button != button_prior){               //check to see if same as last button pressed
  servo_cmd = function(button, position); //nope it's different button, command servo accordingly
  button_prior = button;                  //save last button pressed
  position = servo_cmd;                   //assume servo will end up at commanded position
}

https://github.com/netlabtoolkit/VarSpeedServo

So would I just use that servo library instead of the standard servo library? And I am guessing that the code you listed would have to be included in both switch functions, is that correct? I will try to write the code using your post and the new library this weekend and post the results.

jc27:
So would I just use that servo library instead of the standard servo library?

I suggest it only because you can set it so no code will run until the software thinks the servo has gotten to it's last commanded position. Seemingly a benefit for your application.

jc27:
And I am guessing that the code you listed would have to be included in both switch functions, is that correct?

Actually it includes both switches. The "function" mentioned could be a seperate function or replaced by a bunch of if() statements like ...
  if(button == A && position == 90){
    servo_cmd = XX;
  }
  if(button == A && position == 0){
    servo_cmd = YY;
  }
  if(.......... blah, blah, blah

See ?

A function would take the place of a bunch of if statements correct? From the small amount of VB programming I have done, the function would contain all the movement and could be called in other parts of the code right? I will read up on functions and see if it starts to make sense.

 //zoomkat servo button test 12-29-2011

    #include <Servo.h>
    int button1 = 4; //button pin, connect to ground to move servo
    int button2 = 5; //button pin, connect to ground to move servo
    Servo servo1;
    int pos = 0;
    

    void setup()
    {
      pinMode(button1, INPUT);
      pinMode(button2, INPUT);
      servo1.attach(9);
      digitalWrite(4, LOW); //to make pin low
      digitalWrite(5, LOW); // to make pin low
    }

    void loop()
    {
      if (digitalRead(button1) == HIGH && pos == 0)
      {
        for (pos =0; pos <= 90; pos +=1)
        {
          servo1.write(pos);
          delay(20);
        }
      }   
      else
      if (digitalRead(button2)== HIGH && pos == 90)
      {
        for (pos =90; pos >= 0; pos-=1)
        {
          servo1.write(pos);
          delay(20);
        }
      }
    }

I did some playing around and this code compiles and loads, but the servo just goes to 3 o’clock and sits there regardless of what I do to either switch. I thought the AND (&&) would solve my problem, but now the servo doesn’t even rotate. Any ideas?

What’s up with the parts shown below, especially the digitalWrite(X, LOW) ?

    int button1 = 4; //button pin, connect to ground to move servo
    int button2 = 5; //button pin, connect to ground to move servo

    void setup()
    {
      pinMode(button1, INPUT);
      pinMode(button2, INPUT);
      digitalWrite(4, LOW); //to make pin low
      digitalWrite(5, LOW); // to make pin low
    }

How do you have the switches wired ?

http://arduino.cc/en/Tutorial/DigitalPins

There are 20K pullup resistors built into the Atmega chip that can be accessed from software. These built-in pullup resistors are accessed by setting the pinMode() as INPUT_PULLUP. This effectively inverts the behavior of the INPUT mode, where HIGH means the sensor is off, and LOW means the sensor is on.
When connecting a sensor to a pin configured with INPUT_PULLUP, the other end should be connected to ground. In the case of a simple switch, this causes the pin to read HIGH when the switch is open, and LOW when the switch is pressed.

http://arduino.cc/en/Reference/DigitalWrite

If the pin is configured as an INPUT, writing a HIGH value with digitalWrite() will enable an internal 20K pullup resistor (see the tutorial on digital pins). Writing LOW will disable the pullup.

http://arduino.cc/en/Tutorial/InputPullupSerial

This example demonstrates the use of INPUT_PULLUP with pinMode().

Read the above tutorial. It shows the best way to use switches as inputs.

If you’ve wired the switches per the above, then think about the if() statements.

if (digitalRead(buttonX) == HIGH ...

Is there just 0 to 90 deg motion allowed, no 0 to -90 ?

Lastly let me recommend you enable the serial link and put some “print” statements (“code got to Z”) in various places. That way you can see what paths the code is taking. Note how the following tells if the button was pressed (?or the value of pos?). Though you might want to increase the delays, just for the testing phase.

http://arduino.cc/en/Tutorial/DigitalReadSerial

p.s. - You’re missing a set of { } to go with the else.

I should have stated this earlier but I’m using a wireless momentary receiver/transmitter for the switches. When I hit a button on the fob, the receiver outputs a momentary 5v signal on whichever pin is associated with that button and I have those outputs going to the Uno. So am I wrong in setting those pins to low since I will be sending a high signal to them?

Here is the receiver transmitter I am using:http://www.adafruit.com/products/1096

OK, how sure are you that both RF links are working ?

I’d ditch digitalWrites to the pins and use the serial monitor to see what’s happening.

Add this to your existing code.

void setup()
{
  Serial.begin(9600);

And add these “prints” and see what happens.

void loop()
{
  if (digitalRead(button1) == HIGH && pos == 0)
  {
    Serial.println("Button 1 pressed");
    for (pos =0; pos <= 90; pos +=1)
    {
      Serial.print("pos increment to ");
      Serial.println(pos);
      servo1.write(pos);
      delay(500);
    }
  }   
  else{
    if (digitalRead(button2)== HIGH && pos == 90)
    {
      Serial.println("Button 2 pressed");
      for (pos =90; pos >= 0; pos-=1)
      {
        Serial.print("pos decrement to ");
        Serial.println(pos);
        servo1.write(pos);
        delay(500);
      }
    }
  }
}

In my experince the raw output of those type receiver is quite noisy, bouncing btw 0 and 1 logic states. Hopefully Adafruit put some “taming logic” on them.

I wired up two LEDs to the transmitter and they light when I press the fob buttons. I know that the uno does get the signals from the r/t because I have a copy of zoomkats original code and it works when I set the input pins to low. I will give the code you posted a try tonight.

I’m going to try to start with the original code from the first post and add the serial lines as well as the Boolean statements. I don’t get why it didn’t work before, just adding the && and it’s parameter should work, I must be missing something but I don’t know what.

Ok, I wrote this today,but did not get a chance to upload it to the Uno, but it does compile in the IDE, but I’m sure that means nothing with regards to whether or not its actually going to work. I also wrote this before I looked at this thread and saw your serial print example, so I’m sure the code I wrote is just totally screwed up.

#include <Servo.h>
int button1 = 4;
int press1 = 0;
int button2 = 5;
int press2 = 0;
Servo servo1;
int pos = 0;

void setup()
  {
    pinMode(button1, INPUT);
    pinMode(button2, INPUT);
    servo1.attach (9);
    digitalWrite(4, LOW);
    digitalWrite(5, LOW);
    Serial.begin(9600);
  }
void loop()
  {
    press1 = digitalRead(button1);
    if (pos = 0 && press1 == HIGH)
      {
        for (pos = 0; pos <= 90; pos +=1)
          {
            servo1.write(pos);
            Serial.println(pos);
            delay(20);
          }
      }
    press2 = digitalRead(button2);
    if (pos = 90 && press2 == HIGH)
      {
        for (pos = 90; pos >= 0; pos -=1)
          {
            servo1.write(pos);
            Serial.println(pos);
            delay(20);
          }
      }
  }

I am wondering if I am even on the right track. I think the && will work, but I’m just not sure if I am using it correctly or if I need more arguments. I am also wondering if I am just totally wrong with the entire approach to how I am getting the servo to rotate in the first place.

I would get rid of as these statements do nothing for you. You don’t set inputs, their state is determined solely by the keyfob receiver.

    digitalWrite(4, LOW);
    digitalWrite(5, LOW);

There’s 1 mistake here (that I often make), see if you can see the inconsistency.

if (pos = 0 && press1 == HIGH)

Repeated here. Otherwise the code looks OK.

if (pos = 90 && press2 == HIGH)

http://arduino.cc/en/Reference/If

Beware of accidentally using the single equal sign (e.g. if (x = 10) ). The single equal sign is the assignment operator, and sets x to 10 (puts the value 10 into the variable x). Instead use the double equal sign (e.g. if (x == 10) ), which is the comparison operator, and tests whether x is equal to 10 or not. The latter statement is only true if x equals 10, but the former statement will always be true.