Multiple Servos, individual control with toggle switches

Hi everyone,

New to Arduino and here. I have been working on a model railway project where I am looking to control 3 different servo's with 3 different toggle switches. Switching the toggle on or off moves the servo to a set postion.
ie. Servo 1 controller by Toggle 1,
Servo 2 controller by Toggle 2,
Servo 3 controller by Toggle 3,

I have been using the following code for 1 servo/toggle but would like to expand it to what I would like. Is this even possible without any extra components?

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

// constants won't change. They're used here to set pin numbers:
const int BUTTON_PIN = 7;       // the number of the pushbutton pin
const int SERVO_PIN = 8;       // the number of the pushbutton pin


void setup() {
  // initialize the pushbutton pin as an pull-up input
  // the pull-up input pin will be HIGH when the switch is open and LOW when the switch is closed.
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  myservo.attach(SERVO_PIN);  // attaches the servo on pin 9 to the servo object

 
}

void loop() {
  // read the state of the switch/button:
  int buttonState = digitalRead(BUTTON_PIN);

  if(buttonState == LOW)
    myservo.write(45);
  else
    myservo.write(75);

    
}


I am not sure 100% what you are asking, if the question is can I have more buttons and servos, then the answer is yes, BUT you will need to use a library to use multiple buttons as it is somewhat advanced

Yes, no library required because you're using toggles, which retain the state until you change them.
So, 3 switches feed 3 inputs, 2 outputs feed 3 servos, and you're done. code to follow, in a minute or so

1 Like

just mind bouncing... (you won't see it but the servo will get very fast asks to move to 45, then 75, then 45, then 75 etc.. it's so fast if the loop does not do much that the inertia of the servo will hide it)

1 Like

DUH, of course.

1 Like

Thank you, I've been trying my best to do it but end up making switch 2 control servo 2 and switch 1 doing nothing.

The following is the simplistic approach, which will do what you want but becomes a maintenance nightmare.

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
Servo myservo2;  // create servo object to control a servo
Servo myservo3;  // create servo object to control a servo

// constants won't change. They're used here to set pin numbers:
const int BUTTON_PIN = 7;       // the number of the pushbutton pin
const int SERVO_PIN = 8;       // the number of the pushbutton pin
const int BUTTON2_PIN = 9;       // the number of the pushbutton pin
const int SERVO2_PIN = 10;      // the number of the pushbutton pin
const int BUTTON3_PIN = 11;      // the number of the pushbutton pin
const int SERVO3_PIN = 12;      // the number of the pushbutton pin


void setup() {
  // initialize the pushbutton pin as an pull-up input
  // the pull-up input pin will be HIGH when the switch is open and LOW when the switch is closed.
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  myservo.attach(SERVO_PIN);  // attaches the servo on pin 9 to the servo object
  pinMode(BUTTON2_PIN, INPUT_PULLUP);
  myservo2.attach(SERVO2_PIN);  // attaches the servo on pin 9 to the servo object
  pinMode(BUTTON3_PIN, INPUT_PULLUP);
  myservo3.attach(SERVO3_PIN);  // attaches the servo on pin 9 to the servo object

 
}

void loop() {
  if(digitalRead(BUTTON_PIN) == LOW)
    myservo.write(45);
  else
    myservo.write(75);
  if(digitalRead(BUTTON2_PIN) == LOW)
    myservo2.write(45);
  else
    myservo2.write(75);
  if(digitalRead(BUTTON3_PIN) == LOW)
    myservo3.write(45);
  else
    myservo3.write(75);
}
1 Like

And, to avoid the contact bounce referred to, for your purposes right now, a delay(50) in the loop will suffice.

1 Like

You can start with 3 servo variables and 3 servo variables; just number them (myservo1, myservo2, myservo3, buttonPin1, buttonPin2, buttonPin3).

Read a button, control the servo, read the next button, control the next servo and so on. You only need one buttonState variable.

The use of numbered variables is usually not advisable as it becomes a maintenance nightmare.

So in the next step you use an array for the button pins and an array for the servos. You can loop through the button pin array, read the button pin and based on the value you control the associated servo. Again, only one buttonState variable needed.

And in the last step you can use struct where you combine one button pin and a servo and use an array of those structs and loop through them.

1 Like

wire the switches and servos just like a classification yard, then do the same for the code along the following line
if sw1 do sw 1
else if sw2 do sw2 etc

1 Like

aaa thank you, I was so close I was just forgetting to put the different numbers after each servo here

myservo3.attach

Thank you I can see where I was going wrong with my code in camsysca example above. I was just missing a single number, so frustrating. I will look into what you suggest to simplify it next, I just needed to know it was possible. Thank you everyone

actually the last step would be a class and a method inside the class update the status. Would be very C++ :slight_smile:

here it is

click to see the code
/* ============================================
  code is placed under the MIT license
  Copyright (c) 2024 J-M-L
  For the Arduino Forum : https://forum.arduino.cc/u/j-m-l

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/

#include <Servo.h>

class RailroadSwitch {
  private:
    byte togglePin;
    byte servoPin;
    Servo servo;

  public:
    RailroadSwitch(const byte togglePin, const byte servoPin)
      : togglePin(togglePin), servoPin(servoPin) {}

    void begin() {
      pinMode(togglePin, INPUT_PULLUP);
      servo.attach(servoPin);
    }

    void update() {
      if (digitalRead(togglePin) == LOW) servo.write(45);
      else servo.write(75);
    }
};

RailroadSwitch switches[] = {{2, 3}, {4, 5}, {8, 9}};

void setup() {
  for (RailroadSwitch& rsw : switches ) rsw.begin();
}

void loop() {
  for (RailroadSwitch& rsw : switches ) rsw.update();
  delay(50);
}


servo powered separately, joined GND, not needed for the wokwi simulation.

(wokwi does not have toggles so you need to cmd-click (on a Mac, possibly use the windows key instead of cmd) to keep the button down)

1 Like

One step further would see the two endpoint angles also stored as individual values, to allow tuning of the servos; of course, those values should be tucked into EEPROM, so the tuning isn't lost during any shutdowns.

1 Like

it was not in the requirements :slight_smile:

yes, there could be even a mode where you manually move the servo to the desired position and a quick double flip flop of the toggle would register the position assigned to where the toggle was first

ie do HIGH LOW HIGH LOW and you get into position setting mode for HIGH, set the servo manually where it needs to be, and do HIGH LOW HIGH LOW again to write into EEPROM and resume control.

move to LOW. do LOW HIGH LOW HIGH and you get into position setting mode for LOW, set the servo manually where it needs to be, and do LOW HIGH LOW HIGH again to write into EEPROM and resume control.

the sky is the limit :slight_smile:

2 Likes

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