Notifications
Clear all

An Arduino Uno, a PCA9685, servos and model railroad turnouts

4 Posts
3 Users
0 Reactions
3,746 Views
(@dorsay)
Member
Joined: 5 years ago
Posts: 57
Topic starter  

After some investigation, I've decided to use servos to change the alignment of some of the turnouts on my model railroad.  I've also decided to use an Arduino to drive the servos.  And I know that the Uno is capable of controlling 14 servos but if I want LED indication of the track set at the turnout, it requires at least 3 pins for each servo.  That limits things greatly.

Then I discovered the PCA9685 which can drive 16 servos via SDA and SCL.  Tom's Train and Things has a sketch showing this.  In his sketch, he uses a button and a 3-way LED, which he connects to the Uno.  I've modified his sketch to use a toggle switch and I've come up with a circuit in which only 1 pin of the Uno is required for each servo.  Which means I can drive 16 servos with just 1 Arduino Uno.  This is great.  But now comes my challenge.

In Tom's sketch, he uses the pulse to limit the throw of the servo.  This means that the servo goes from one side to the other almost instantaneously.  That's not very prototypical.  I'd like to slow the movement of the servo so that it sweeps from one side to the other, thereby opening or closing the turnout in a more realistic manner.

My programming days are long gone and it was in Basic and Cobol, casually!  So the syntax of C++ leaves me confused at times.

Can some here look at my sketch and enlighten me?  I'd copy my sketch here but I'm not sure the best way of copying and not loosing the formatting.

Thanks

David


   
Quote
Robo Pi
(@robo-pi)
Robotics Engineer
Joined: 6 years ago
Posts: 1669
 
Posted by: @dorsay

Can some here look at my sketch and enlighten me?  I'd copy my sketch here but I'm not sure the best way of copying and not loosing the formatting.

1. Select the code to be posted in the Arduino IDE.

2. Right-click on the selected code and choose "Copy as HTML" from the pop-up menu.

3. Then in the forum editor window choose the source code icon {:} at the top of the editor.

4. Paste the HTML code into the pop-up window and select ok.

5. You can then select "Preview" at the bottom of the post editor to see exactly how the code will appear when posted.

This method preserves both the alignment and the color formatting of the Arduino code.

 

DroneBot Workshop Robotics Engineer
James


   
ReplyQuote
(@john40131)
Member
Joined: 6 years ago
Posts: 95
 
Posted by: @dorsay

After some investigation, I've decided to use servos to change the alignment of some of the turnouts on my model railroad.  I've also decided to use an Arduino to drive the servos.  And I know that the Uno is capable of controlling 14 servos but if I want LED indication of the track set at the turnout, it requires at least 3 pins for each servo.  That limits things greatly.

Then I discovered the PCA9685 which can drive 16 servos via SDA and SCL.  Tom's Train and Things has a sketch showing this.  In his sketch, he uses a button and a 3-way LED, which he connects to the Uno.  I've modified his sketch to use a toggle switch and I've come up with a circuit in which only 1 pin of the Uno is required for each servo.  Which means I can drive 16 servos with just 1 Arduino Uno.  This is great.  But now comes my challenge.

In Tom's sketch, he uses the pulse to limit the throw of the servo.  This means that the servo goes from one side to the other almost instantaneously.  That's not very prototypical.  I'd like to slow the movement of the servo so that it sweeps from one side to the other, thereby opening or closing the turnout in a more realistic manner.

My programming days are long gone and it was in Basic and Cobol, casually!  So the syntax of C++ leaves me confused at times.

Can some here look at my sketch and enlighten me?  I'd copy my sketch here but I'm not sure the best way of copying and not loosing the formatting.

Thanks

Hi, I also went with Toms Trains sketch and modified to operate 16 sets of points on my Model Railway build..

John


   
ReplyQuote
(@dorsay)
Member
Joined: 5 years ago
Posts: 57
Topic starter  

@robo-pi

Thanks for the heads-up.  Please excuse the code structure, it's still in development stage.  I haven't yet removed the unnecessary lines, merely commented them out.  And because of the way the servos have been mounted on the underside of the layout, I think I need to treat each servo independently so that each doesn't travel to far to cause breakages.

Thanks, David

/***************************************************
  This sketch can be used to operate any number of turnouts on a
  Model Railroad. Code blocks can be added to accomodate any number
  of servos. This sketch uses only two servos for this demonstration.

  The pushbutton can be replaced with a SPST switch
  commonly used on a control panel. Three pin Bicolor LED can be used
  in place of two seperate LEDs in each circuit.

  10K Ohm pulldown resistor used on switch
  330 Ohm resistor used on LEDs. One per pair of LEDs

  Created 03/02/2019 by Tom Kvichak
   https://tomstrainsandthings.com/ 
  Additional Arduino Projects can be found at the above web address
  
  Modified by David Orr 12/01/2020 to use SPDT togle switches instead of buttons.
  One pole goes to cathode of red LED and digital pin on Arduino, the other pole
  goes to cathode of green LED and digital pin on Arduino. The central pole goes
  to GND. 5v rail to anode of LEDs via 1k resistor.  This way only 1 digital pin
  is needed for each turnout switch and LED.  Movement of the turnouts is via
  I2C and PCA9685 using 5v, GND, SCL and SDA.

 ****************************************************/

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

int switchPin0 = 2;   // Can add as many switches as needed  - this is the 1st, set up for loop for as many as needed
int switchPin1 = 3;   //
int switchPin2 = 4;   //
int switchPin3 = 5;   //
int switchPin4 = 6;   //

//int ledPin0C = 3;     // C designates Closed position of turnout - I don't think I need this
//int ledPin0T = 4;     // T designates Thrown position of turnout - I don't think I need this
int switchState0 = 0;   // - this is the 1st, set up for loop for as many as needed
int switchState1 = 0;   //
int switchState2 = 0;   //
int switchState3 = 0;   //
int switchState4 = 0;   //

//int buttonPin1 = 5;   - I don't think I need this yet
//int ledPin1C = 6;   - I don't think I need this
//int ledPin1T = 7;   - I don't think I need this
//int buttonState1 = 0;   - I don't think I need this yet

void setup() {
  Serial.begin(9600);
  Serial.println("PCA9685_MyTurnouts");
  pwm.begin();
  pwm.setPWMFreq(60);
  delay(30);

  // pinMode(ledPin0C, OUTPUT);
  //pinMode(ledPin0T, OUTPUT);
  //pinMode(buttonPin0, INPUT);
  //pinMode(ledPin1C, OUTPUT);
  //pinMode(ledPin1T, OUTPUT);
  //pinMode(buttonPin1, INPUT);
  pinMode(switchPin0, INPUT_PULLUP);  // I'll need switchPin0 to 4 for 5 servos or 0 to 15 for 16 servos
  pinMode(switchPin1, INPUT_PULLUP);
  pinMode(switchPin2, INPUT_PULLUP);
  pinMode(switchPin3, INPUT_PULLUP);
  pinMode(switchPin4, INPUT_PULLUP);
  
  
}

void loop() {
  ///////////
  switchState0 = digitalRead(switchPin0);
  if (switchState0 == HIGH)
  {
      //for (int counter=285; counter <=370; counter++)
      //{
     // pwm.setPWM(0, 0, counter);  //swing servo left
      //delay(10); 
      //}
      pwm.setPWM(0, 0, 370);  //swing servo left
      //digitalWrite(ledPin0T, LOW);
      //digitalWrite(ledPin0C, HIGH);
  }
  else
  {
      //for (int counter=370; counter >=285; counter--)
      //{
      //pwm.setPWM(0, 0, counter);//swing servo right
      //delay(10);
      //}
           
      pwm.setPWM(0, 0, 290);  //swing servo right
      //digitalWrite(ledPin0C, LOW);
      //digitalWrite(ledPin0T, HIGH);
  }
  /////////////////////
  switchState1 = digitalRead(switchPin1);
  if (switchState1 == HIGH)
  {
    pwm.setPWM(1, 0, 370);  //swing servo left
  }
  else
  {
    pwm.setPWM(1, 0, 285);  //swing servo right
  }  
  ///////////////////////
  switchState2 = digitalRead(switchPin2);
  if (switchState2 == HIGH)
  {
    pwm.setPWM(2, 0, 370);  //swing servo left
  }
  else
  {
    pwm.setPWM(2, 0, 285);  //swing servo right
  }
  ///////////////////////
  switchState3 = digitalRead(switchPin3);
  if (switchState3 == HIGH) 
  {
    pwm.setPWM(3, 0, 370);  //swing servo left
  }
  else
  {
    pwm.setPWM(3, 0, 285);  //swing servo right
  }
  ////////////////////////
  switchState4 = digitalRead(switchPin4);
  if (switchState4 == HIGH)
  {
    pwm.setPWM(4, 0, 370);  //swing servo left
  }
  else
  {
    pwm.setPWM(4, 0, 285);  //swing servo right
  }
}

David


   
ReplyQuote