Its been a long stretch where there has been too much going on in real life and little time to write about model railroading. But I’ve been working away on the first module of the L&NC and have made lots of progress, so there’s plenty to write about.
This module has nine turnouts, presenting resource management problems that would arise in any substantial yard or staging facility. If you are familiar with the servo library then you know that you are limited to about 10 servos per microcontroller. With that many servos, your microcontroller will have few resources left to do anything else. This post will focus on a solution that problem, expanding the number of servos and other PWM devices a single microcontroller can manage.
Progress Tour
But first, a quick overview of progress to date.
Here’s the module in its current state:
As you can see I’ve done quite a bit of detailing. I realized early on that I need to complete all the basic scenicking and detailing of the module before moving on to the next. The big reason is having the module alone on a work table gives the best possible access, especially for electronic or animated items that require access to the underside. That’s not to say detailing will not continue after I move on to the next module, but it will mostly be passive rather than active elements.
By the way, if I were to build a room-sized layout, I’d use a modular (some call it “sectional” because you build it in sections) approach to construction even though the layout would not be portable. After laying mainline and other track spanning sections and cutting gaps between sections, I’d pull each section and do most of the remaining work in a work area under optimal conditions. When ready its just a matter of returning the section to its place in the layout and (literally) plugging it in.
Lets take a quick tour of some details so far.
Roundhouse / Turntable
If you’ve read the previous posts about the Roundhouse and the Turntable, you know these have been long term projects.
Having gone to all the trouble to light the Roundhouse, I’ve started populating the space with some appropriate gear and figures.
Red Bluffs Yard
The Red Bluffs Yard area has its first structure — a fully lit Yard Office — plus a pickup truck with lighting passing by on the adjacent road.
And, finally, here is the underside, which is rapidly filling with gear supporting the layout above. This module, with its yard, multiple main tracks and turntable is one of the most electronically “dense” parts of the layout plan, to be exceeded only by the city scene planned for the upper level — that is going to be quite a project and I can hardly wait to finish the lower level and get started on the top!.
PWM Drivers for Turnouts and Other Uses
Pulse Width Modulation (PWM) is used to output a timed pulse, where the output is on only part of the time. The width of the pulses — the percentage of time the pulse in the on state — is used to control external devices like servos or to vary the brightness of an LED.
Some, but not all, Arduino digital outputs are hardware PWM capable. Some of the PWM pins are SPI pins and the two serial pins, leaving only 5 or 6 PWM pins available for unrestricted use depending on the board model. If you want to make extensive use of PWM, that just won’t cut it.
PWM can also be synthesized with timed interrupts on any pin, which is how the servo library works and why it does not require you to attach to PWM pins. Unlike hardware PWM pins, PWM synthesized with interrupts represents a hidden load on your board that can affect the performance of your sketch.
External PWM Boards or “Drivers”
External PWM drivers allow you to greatly expand the number of PWM devices a single Arduino can manage. PWM is used extensively in robotics, so PWM drivers are fairly ubiquitous and inexpensive. Aside from expanding the number of PWM devices you can control, PWM drivers allow you to off-load all of the PWM overhead and timing routines to the external device, freeing your Arduino for other tasks.
I decided to try Adafruit 16-Channel 12-bit PWM/Servo Driver for servo control and a couple of lighting applications on this module. Adafruit also sells a similar device in shield form.
I chose the independent board rather than the shield because it has a number of advantages, not least of which it is chain-able with up to 61 additional boards, for a total 992 PWM outputs. A single chain of these can handle the servo needs of most club and museum sized layouts! A more modest layout could use these for both turnout servos and all lights and lighting effects, effectively centralizing and simplifying control of all connected devices. It uses the shared I2C interface for fast communication without using any regular pins on your Arduino. For more details, and a tutorial, see the Adafruit product page.
Assembling the board was straight forward, though there are a lot of pins to solder. The terminal block in the center provides independent power for the servo outputs (V+ center pin on outputs) per standard servo wiring; independent power is required by servos because of their substantial current draw. LED’s and other devices that draw their power from the PWM signal itself will not use the independent power. Be warned: the terminal block Adafruit supplies is poor quality—substitute a better quality part or solder power leads directly to the board. The headers on the sides are for input and output, transferring both data and power to subsequent boards in a chain.
Connecting servos is just a matter of having a male->female servo extension the right size, or combining multiple extensions for longer runs. Any robotics supply store should have an assortment of extensions; as does Amazon. I have three different sizes to work with, which has worked well so far.
On the board positions 0 through 8 (1st 2 banks of four, plus the first pin of bank 3) are attached to the 9 turnout servos. Positions 9 and 10 are for headlights and taillights on the pickup truck. Using PWM I can have the headlights go between low beam and high beam, or have the taillights brighten as if the brakes have been applied. I have some thoughts about an animated animal crossing in front of the truck from time to time….
Using Adafruit’s PWM Driver Software
Adafruit’s software library for this device is available from their GitHub site. Using the software you create an object that you then use to control the board outputs:
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
Creating the Adafruit_PWMServoDriver object without arguments uses the base SPI address to access the board; any different address has to be specified as an argument (and the appropriate jumpers on the board have to be closed). With multiple boards, you create a pwm object for each board using its unique SPI address.
From there, the PWM pulse is set on any output by calling the setPWM() member function:
pwm.setPWM(pin, on, off);
where pin is the board output (a number between 0 and 15), on sets the point in the cycle when the signal goes from low to high (usually 0, the beginning of the cycle, but it can be another value) and 0ff is a number between 0 and 4095 setting the point in the cycle when the signal transitions from high to low.
With the Adafruit driver board you do not use degrees to set a servo’s position. Instead we use timing “tick” values that control the signal transitions from low to high and back. There are 4096 “ticks” (12 bits of resolution) during each cycle. That turns out to be a good thing. For servos, the correct off tick values (assuming the on tick is 0) range from about 150 (the minimum or 0 degree position) to 600 (maximum position, 180 degrees).
Directly setting the cycle through ticks at 12 bits of resolution confers highly granular control and extra smooth servo motion. Using degrees for position, as the standard servo library does, results in jerkier motion since a degree represents a lower resolution–between 8 and 9 bits–than the 12 bit resolution of the Adafruit board. For LEDS and other lighting, you can vary brightness from off to full on in 4096 steps, allowing fine control of lighting effects.
If you ask me, the smooth motion you can achieve with this board makes its $14.95 price more than worthwhile.
The only difference in your code between working with the standard servo library and the Adafruit driver, is in the object and member function you use to cause the servo to move. Every other aspect of your code and logic should remain the same.
What’s Next?
More coding, and I promise I won’t make you wait long. In the next installment I’m going to introduce you to simplified Object Oriented Programming (OOP) in C++ with the Arduino IDE. I’ll demonstrate a different way to code that, I think, improves several aspects of working with multiple turnouts, and makes the intent and flow of your code easier to understand and maintain. We’ve done it procedurally; we are going to take what we’ve learned and create some OOP code to do the work using either the Adafruit driver or the standard servo driver (Hint: we’ll use a compiler directive to select which driver gets implemented, making the object itself agnostic on the issue and universally usable around the layout).
Until then, happy railroading!
Robin.my friend Dave and i are trying to make a stand alone signaling system using arduino and digital IR sensors for block detection and bicolor leds for signal aspects. We have created a sketch
But are having a hard time keeping the first block active until we clear the second block detector so we can run shorter trains or just an engine between blocks if you send me your email I will send a copy of our sketch and more detail. We are using PWM for IO pins for red brilliance and using bicolor leds for red,green and yellow aspects. Any help will be greatly appreciated.
Thank you
Bob Bijeau
Hi Bob, I’ll send a message to your email so we can correspond off-line. Robin
Hello Robin and Bob,
I have a demo section using reflective IR sensors one at each end of the block when it clears it goes to green and vice versa. Robin has also helped with using current sensors to keep the block signals active as well. I am sure he will help you on your way as he did me. =-)
Hello, how are you controlling your Turntable?
I like your drive system.
I have a Stepper motor.
Thank you.
Hello Jay,
I’m using the Sparkfun Easy Driver to run the stepper. I’m circling back to that soon and hope to have a blog post with more information, pictures and so on, later this month.
Best,
Robin
Hi Rob,
Following my earlier questions/comments about jerky servos, I am now thinking of PCA9685, as a possible solution. I realize higher resolution means smoother running of servos, but what about sound ? do you see (hear) less noise ?
Smoother running is good, but sound is a real issue, I think.
(By the way, cutting power and pulse cables shorter removed my problem with servos going crazy)
Also, on using this for other things than servos; I need only 5 servos as of now, so there would be capability for more stuff. You described a car with both headlights and rear lights, using two outputs; do I get it right that these two outputs power the actual LED:s directly(with resistors), meaning LED:s with a totally controllable brightness ?
Best Regards
Peter
Hi Peter,
The SG90 servos are cheaply made and prone to growling, under load. I would toss any servo that growls when tested with no load. With turnouts, we like to apply some pressure to keep the points in contact with the rails, leading to noise generated by the servo pushing against resistance. Best way to avoid noise is to keep the gauge of the actuator wire thin, so that it bends and stores the energy instead of fighting the servo. A friend produces mounted servos with the right gauge actuator wires: https://www.smarthobbyllc.com/
You definitely get better resolution with a PCA9695 card — 500 steps across a 180 arc of motion. That helps with smoothness of motion and incremental noise.
As to the LEDS, yes. Attach the positive lead to the data pin, ground to grd, and ignore the V++ pin required for servos. Put a 270 ohm or greater resistor on either side. Use the PWM level to control brightness, or to create special effects. Play with that a bit… you’ll be pleased.
R
Hi Rob,
I have another question, and you may have posted something about this, but I can’t find it;
I am installing your sketch, specifically the demo sketch for 5 turnouts and shiftregisters. This works fine, but I would rather use switches instead of push buttons, so switches sets input pins to a constant VCC or GND.
Would appreciate some help with that, or of course a pointer to that other answer I suspect exists.
Best Regards
Peter
Think of switches as buttons that stay pushed indefinitely. in the case of an SPDT switch. with power to center tap and each leg attached to a pin, its like two buttons that alternate (unless you have only one side live, in which case its a sticky button). So, you wire them like buttons (+5v power, with a pull-down resistor on every pin). The main difference from a logic point of view is that with switches you have to keep track of their state and respond only to state changes. With buttons you can usually get away with blindly responding to presses, but a held button will lead to duplicate actions. In fact, its best to handle all inputs on a state change basis for “bounce” free stability.
I have an IO board system that I’ve been working on that makes both inputs and digital outputs easier. I’m in the process of bringing them to market … not ready to go fully public yet. If you are interested, let me know and I’ll send you information outside of the blog.
Best, Rob
Rob,
I wrote my new question before I saw your reply about servos. Not sure how to post pictures here, but I use a small brass tube, positioned about 10 mm from the switch. in the tube is a pianowire, I think it’s 0,8 mm. Two 90 degrees bends create an actuator. Under the layout the wire can be bent in any suitable direction, and connected to a servo laying on its side. It has a standard servo arm pointing “down” and is simply mounted in a 90 degrees plastic angle(not sure if this is the right expression…). That relatively thin pianowire keeps the turnout tight, while seemingly not stressing the servo. The actuator idea, by the way, is the same as Swithmaster stalling motors use, works fine here too.
Best Rgds /Peter
Hi Rob,
I am still installing servos, controlled by your fine coding, as stated before the sound and smoothness is not so fine, but, my PCA9685 should arrive any day now and that item should improve things. This, finally, leads to my question, coding. I’m a bit confused….
What I use so far is the example with 5 turnouts and shiftregisters for LEDs.
As I understand it all the coding concerning buttons and turnout movement can stay the same, except for those lines in the end
#ifdef ADAF_DRIVER
extern Adafruit_PWMServoDriver pwm;
pwm.setPWM(pin, 0, data);
The driver has to know about Arduino output pins and servo positions; so is this “simply” collected by the library and transferred in the I2C signal ?
I do try to understand your coding, but this is quite complex, so some guidance would be most welcome.
Best Rgds Peter
The standard Servo library uses regular pins. The PCA9685 has its own output “pins” and only interacts with the microcontroller through I2C serial communication. The PCA9685 knows how to use I2C; all it needs is the board’s I2C address to initialize the driver. The Servo library has no knowledge of I2C or PCA9685 boards.
So you are dealing with two completely different, incompatible ways of running servos. The code you have uses compiler directives (#ifdef ADAF_DRIVER …. #endif) to determine what is included and what is excluded at compile time. The sketch has to contain the correct addressing which ever way you are running servos, and there is no transfer between the different systems.
Most people are not trying to support multiple methods of accessing servos. Pick one method, write the code for it and skip the compiler directives.
Best, R
Rob,
You are right of course, no point mixing methods. So, with PCA9685 servos are adressed with the actual driver pins (0-15), and servo movement in “ticks”.
Is then every servo position defined 0 – 600 (max numbers) ? (i.e. not defined sequentially)
When my driver arrives I will do some actual testing, and hopefully find out some basics…..
Best Rgds
Peter
Hi Rob,
I have now hooked up and tested the PCA9685, so far only with Adafruit’s tutorial, which
ran a servo pretty much like the “servo” coding, only faster. Hoping for better results I am now aiming (note:not trying; aiming…) to convert your coding to using this item. This leads to a couple of questions; I have added the ServoDriver library, and created a servo driver object (Adafruit_PWMServoDriver pwm=Adafruit_PWMServodriver();).
Then I get unsure about “TURNOUT_DATA”; My thoughts are that button pins A0 – A4 should stay the same, but servo pins 2 – 6 will have to change to 0,1,2,3,4 being servo outputs on PCA9685 (?) Is it that simple ? Also, Main and Divergent angles must change to proper “tick” values, and actual servo movement must be initiated, with the correct coding; that is where I’m confused – I see “write(++turnouts…..”,
but also “setTurnout(i, ALIGN_MAIN);” in both cases arrays of servos are controlled, and I fail to see the difference, and also how to use “pwm.setPWM” .
Appreciate some hints about that.
Your coding put all sorts of ideas in my head… The sketch now moves the servos to a predetermined position at program start, so it can define servo position. To avoid that, why not use a sensor to determine servo position, so startup doesn’t initiate a total hickup ?
Best Rgds
Peter
Hi — This post should get you started: C++ Objects for Layout Control, Part 2 — Turnouts.
If you use servos, they will twitch when you start up. You have to power up the servo and set the initial positions in order to lock the servo in position (and your turnout as well) — I just have all servos move to default position on startup which puts the power up twitch to good use. RS
R.
Hi Robin,
Thanks for your helpful efforts and patience !
I have looked at the “enchilada”, which to me looks like a whole new concept.
So, humbly, a basic question: I first set up your 5 servo demo sketch, and got it working.
Then I have tried to adapt that to PCA9685, thinking this sketch can be used if changing servo addressing; is this correct or am I missing out ?
If this is doable, please have a look at the sketch
Trying to compile I get an error “pulselen not declared….” This happens the second time pulselen is visible in the sketch.
What I’ve changed is this: denoted by “!”
! //#include
! #include
! #include
! Adafruit_PWMServoDriver pwm=Adafruit_PWMServoDriver();
// Definitions
#define NUMBER_OF_TURNOUTS 4 // Basic parameters; adjust for actual setup
#define STEP_DELAY 70 // servo movement step delay, in milliseconds
// Data Structures
// TURNOUT_DEF holds all configuration information about t-outs and panel LEDS
typedef struct TURNOUT_DEF {
uint8_t button_pin; // Digital or analog pin for the button associated with this turnout
! uint8_t servo_port;
// Digital pin for the servo associated with this turnout
int pos_main;
// servo position for the MAIN leg, in degrees
int pos_div;
// servo position for the DIVERGENT leg, in degrees
};
/////////////////////////////////////
// TURNOUT_DATA is wrapper structure holding
// both configuration and runtime data for turnout operation
/////////////////////////////////////
typedef struct TURNOUT_DATA {
TURNOUT_DEF data; // configuration
bool is_moving;
byte alignment;
int pos_now;
int target_pos;
unsigned long last_move;
};
// Alignment state values
#define ALIGN_NONE 0
#define ALIGN_MAIN 1
#define ALIGN_DIVERGENT 2
//////////////////////////////////////////
//
// Global variables
//
//////////////////////////////////////////
// TURNOUT_DATA Array
// * A0, A1, etc refer to analog pins which are used for buttons in this example
// * Replace pos_main (93) and pos_div (117) with real values for each turnout
// Only the TURNOUT_DEF part of the TURNOUT_DATA structure has to be initialized here;
// The remaining elements are managed internally and are initialized automatically
TURNOUT_DATA turnouts[NUMBER_OF_TURNOUTS] = {
! {A0, 0, 93, 117, 0, 1, 2, 3},
! {A1, 1, 93, 117, 4, 5, 6, 7},
! {A2, 2, 93, 117, 8, 9, 10, 11},
! {A3, 3, 93, 117, 12, 13, 14, 15},
// {A4, 6, 93, 117, 16, 17, 18, 19}
};
// servo objects
Servo servos[NUMBER_OF_TURNOUTS];
void setup()
{
// initialize each turnout
for(int i = 0; i < NUMBER_OF_TURNOUTS; i++){ // attach the servo
servos[i].attach(turnouts[i].data.servo_port); // set the pin mode for the button pin
pinMode(turnouts[i].data.button_pin, INPUT); // test and position the turnout by moving
// to divergent then to main positions
! //servos[i].write(turnouts[i].data.pos_div);
! pulselen = map(turnouts[i].pos_now, 93, 117, SERVOMIN, SERVOMAX);
! pwm.setPWM(turnouts[i].data.servo_port, 93, pulselen);
turnouts[i].pos_now = turnouts[i].data.pos_div;
setTurnout(i, ALIGN_MAIN);
}
} // end of setup
void loop()
{
unsigned long currentMillis = millis(); // get elapsed milliseconds at loop start
for(int i = 0; i = STEP_DELAY ) { // if sufficient time has elapsed since the last move
turnouts[i].last_move = currentMillis; // move the turnout one degree
if (turnouts[i].pos_now < turnouts[i].target_pos) { // if the new angle is higher
! pulselen = map(++turnouts[i].pos_now, 93, 117, SERVOMIN, SERVOMAX);
! pwm.setPWM(turnouts[i].data.servo_port, 93, pulselen);
! //servos[i].write(++turnouts[i].pos_now);
} else // otherwise the new angle is equal or lower
if (turnouts[i].pos_now != turnouts[i].target_pos) { // not already at destination
! pulselen = map(–turnouts[i].pos_now, 93, 117, SERVOMIN, SERVOMAX);
! pwm.setPWM(turnouts[i].data.servo_port, 117, pulselen);
}
// servos[i].write(–turnouts[i].pos_now);
}
}
}
if (turnouts[i].pos_now == turnouts[i].target_pos) { // if target position reached, stop turnout motion
turnouts[i].is_moving = false;
turnouts[i].last_move = 0;
setIndicators(i);
}
} else {
int button_state = digitalRead(turnouts[i].data.button_pin); // if a turnout is NOT in motion, check to see if its button is pressed
if(button_state == HIGH){
if(turnouts[i].alignment == ALIGN_MAIN){ // toggle position
setTurnout(i, ALIGN_DIVERGENT);
} else {
setTurnout(i, ALIGN_MAIN);
}
}
}
}
} // end of main loop
////////////////////////////////////////////////////////////////
// Supporting Functions
////////////////////////////////////////////////////////////////
void setTurnout(int id, int align){
// Set indicators to show turnout in motion
turnouts[id].alignment = ALIGN_NONE;
setIndicators(id);
// Set values to trigger motion on next loop iteration
switch(align){
case ALIGN_MAIN:
turnouts[id].is_moving = true;
turnouts[id].last_move = 0;
turnouts[id].target_pos = turnouts[id].data.pos_main;
turnouts[id].alignment = ALIGN_MAIN;
break;
case ALIGN_DIVERGENT:
turnouts[id].is_moving = true;
turnouts[id].last_move = 0;
turnouts[id].target_pos = turnouts[id].data.pos_div;
turnouts[id].alignment = ALIGN_DIVERGENT;
break;
}
}
void setIndicators(int id){
switch(turnouts[id].alignment){
case ALIGN_NONE: // means the turnout is in motion and not aligned
break;
case ALIGN_MAIN:
break;
case ALIGN_DIVERGENT:
break;
}
}
I kind of suspect the SetTurnout part should be changed, but….
Appreciate help.
Best Regards
Peter
HI Peter – I am trying to develop code to operate multiple servos to control turnouts on my model RR. I am using a PCA9685 board and leveraging off of Robin’s awesome work. I have been reading your posts and I find that many of the questions that you have asked are the same as what I have. I was wondering if you might be able to please share the code that you have developed with me? It would help me better understand what is going on. Thanks in advance. Dave
Hello, Nice setup. interesting site.
I work in HO and have started to ply with SG90’s and Arduino Nano to control switches. I use button actuators to trigger the servo angle. On my test setup ( 3 servos ) everything works fine. Servos respond as they are expected to. When I install things on my actual layout and test the servos they work fine. Then, when I run an engine on the track or run the motor that turns my turntable or turn one of my transformers the servos start to act up. I have searched for solutions to this but it does not seem to be mentioned anywhere my searches have taken me. I am guessing there is some kind of electromagnetic interference going on. The servos and Arduino are on their own 5V power source.
Did you have any experience with this issue in your journey?
Any suggestions or links would be appreciated.
Tom
Hi Tom,
When you say the servos “act up,” what do they do? It sounds like some sort of EMF or power supply issue. Are you using DCC or DC for your trains? Are you using a single 5 volt power source for both the Arduino and the servos? How are the servos connected to power? What kind of power source is it? How do you power your turntable and what sort of motor does it use? Your “transformers” are for what … track power?
I think I know what the problem is, but I need information to be sure.
Best, Rob
Hi Robin,
The “acting up” occurs in various ways. If I turn on the transformer/rectifier that powers the track on block that has the servos, one or two and sometimes all of the servos move(most of the time within the range I have set 40 75).
I am running DC.
I have tried both using one power supply ( a 5v / 1 amp phone charger ) and powering the servos from the 5V out on the Arduino.
I have also tried using a separate power supply ( another 5v / 1amp phone charger) for the servos and connecting the common GND. With the second setup the servos are a little bit less reactive but do act up.
Someone suggested I add a 0.1uF capacitor between the button switch and the resistor in the circuit that goes to GND on the Arduino. I tried that on one of the button sets. Now neither straight nor turn activates the servo, but it still reacts to turning on or off the rectifier. No change in the other 2 servos.
The turntable is run by a small electric motor right on the turntable and is powered by a standard dc train rectifier so I can easily control the direction and speed.
I think I answered all your questions..
regards,
Tom
Hi Tom,
I’m guessing that when the servos move, its a jerk not a smooth movement.
Everything is pointing to some form of interference. There are only two things that cause a servo to move: a change in the pwm signal, or a power supply interruption/re-energize cycle. Your track power/turntable power seem to be interacting with the servos, possibly by causing a brief power drop at the servo, of by causing back EMF to hit the servos on the ground side. I’m guessing that track power and servo power (or the Arduino itself) are interconnected in some way.
Here are the rules I follow for successful use of Arduino technologies on a layout:
1. For all systems, track power must be electrically isolated from other power uses. I recommend having a separate layout control power bus, powered by an independent power supply, in addition to your track bus and power supply. I use a dual voltage layout control power – +5v and +12v. I use computer power supplies with easy-to-get breakout connectors to get high wattage, and very stable, +5v and +12 v from a single power supply.
2. Run the 5 volt Arduino boards using a 12 volt power supply. Yes, you read that right. The 5 volt boards need a higher voltage supply to run right. Connect 12 volts from the layout control bus to the VCC terminal of the Arduino. Alternatively, get a 12volt (fixed, or adjustable) wall transformer with a 2.1mm DC plug, and use that to power the Arduino (making sure to interconnect all non-track grounds).
3. Use a PCA9685 board to run your servos. Use the +5volt source from your layout control bus to power the PCA9685 — it will supply power to the servos. They payoff is simpler code on the Arduino since PCA board does all the work to generate PWM. The only annoying thing about PCA boards is they will generate a small “jerk” when you apply power to the board — the solution is to control board power with a relay on the main power feed (power feed for logic is separate from the main feed, and also +5v), turning on PWM and setting default position before causing the relay to turn on main power to the PCA board — what that does is start the PWM signal so the servo can react to power correctly when applied.
4. Everything that isn’t track or independent motor power should share a single ground. Track and your turntable should be kept isolated from everything else. Using dual buses (1 for track power, 1 for layout control) helps enforce that discipline.
Give some thought to where your setup does not follow these rules.
Another way to go, is to go Arduino whole hog. What I mean by that, is everything including your DC locomotives and independent motors can be run via Arduino motor drivers. The all-Arduino solution would eliminate all your electrical issues, though at the cost of the programming necessary to make it all work. You can use devices called “digital encoders” for speed control — much better for the PWM approach to motor control.
Best,
Rob
Hi Rob,
Have tried a variety of things that are within my scope. One solution was to put a .1uF capacitor across each resistor at each button. That reduced most of the interference. I also put the Arduino on a seperate power supply ( an adjustable wall wart set to 6 VDC but outputting 11.8 DC) The power to the servos is from a 5V wall wart. Both are connected to power to a completely different circuit in the house. Where these two are connected seems to make no difference though.
When I trigger another traditional electromagnetic switch that is close to one of the servo track switches it causes that switch to move to the higher angle setting. This also happens if an engine with dirty wheels or a noisy motor runs near the servo. It will trigger the servo even if it is already in the higher angle setting. Strangely the other two servos are fine.
If I run a smooth engine everything runs fine until I trigger the nearby switch. They are on completely different circuits, no common wires?
I have read about PCA9685 boards, but have also visited sites that seem to have things going without one as I am doing.
Is there a way to turn off the servos until a button is pressed, set the position and turn off again?
Getting close but still no cigar.. 🙂
Hi Tom,
You didn’t say but I assume that when you power the Arduino and the servos separately, you are joining the grounds together.
On the buttons, are you using 10k pull-down resistors from the pin to ground? A cap on a button shouldn’t do anything noticeable, except maybe delay button recognition, unless the button doesn’t have a pull-down resistor to drain stray current (you didn’t say how the resistor you have is used — inline to limit current, or as a slow drain to ground?). What is your power source for the button?
Out of curiosity, have you tried connecting a different servo to the same pins? Also, have you taken steps to determine if the code is being triggered to change the servo settings, or if its purely mechanical? Since the servos are directly connected to the Arduino, and the one that changes position does so without returning(it moves and stays, rather than moving and returning), that suggests that either your code or the servo library is reacting to the issue. This sort of points back to the button and a possible lack of current drain.
Another modeler I know had weird issues until he attached his layout ground to a copper household pipe. That is certainly a way to drain off EMF of various kinds.
It you want to control power to the servos, you have to use a relay on the servo power lead to turn power on or off. With the servo library you have to have a relay for each servo — with a PCA9685 board, you can use a single relay to control the main power feed for all connected servos.
Best, Rob
Going back over the whole exchange, you did mention resistors going to ground. What value are the resistors?
Have you tried using a different Arduino pin for the cranky servo?
“When I trigger another traditional electromagnetic switch that is close to one of the servo track switches it causes that switch to move to the higher angle setting. This also happens if an engine with dirty wheels or a noisy motor runs near the servo. It will trigger the servo even if it is already in the higher angle setting. ”
Is there any place where wiring crosses and might be creating an induction situation? Perhaps something like a wire is looped around another creating an induction loop. Induction loops magnify the effect of changes in the primary signal — like sparks and spikes.
Here’s the thing: assuming the servo has been set to a position by the servo library, then the library will generate a pwm signal at the frequency necessary to maintain position. The only way the servo moves from then on is 1) if the library changes the PWM frequency, which usually manifests as normal movement, or 2) if the PWM Signal gets interrupted or changed by a transient, but this change will manifest as a jerk because the continuous signal from the library will correct the position as soon as the transient passes.
I think at this point, I’d recheck wiring and look for something creating an induction loop (also, recheck all grounds — grounding anomalies cause this sort of thing too). From there, I’d put some Serial.println() probes in the code to see what its doing. You want to output key info every time the servo movement function is called … eventually you should see function calls that you didn’t intentionally trigger. If the position is being changed and it sticks even after the interference source is gone, then something is going on in the code that might better explain the behavior.
Best, Rob
Hi Robin,
Yes, the GND of the servos and the Arduino are connected.
The resistors (10K) are each connected to one pin on a button switch, with a .1uF capacitor in parallel and connected to GND. A wire also goes to the Arduino from the same pin. The other pin of each button is connected to its own 5v power. The capacitors are a new addition and have quieted things down considerably.
I have swapped out servos but it makes no difference.
I cleaned the wheels on the engine that was also triggering the one servo and that stopped that problem interestingly.
I could share my Arduino sketch. Should I just paste it into a reply?
regards,
Tom
So everything sounds right. But one thing stuck out for me: “The resistors (10K) are each connected to one pin on a button switch, with a .1uF capacitor in parallel and connected to GND. A wire also goes to the Arduino from the same pin” — if I’m reading this right, it sounds like the pull-down resistor and the filter cap are attached to a button pin, with a wire leading from the button pin to an Arduino pin. I’ll bet that wire is longer than just a few inches or centimeters.
That might be the problem. The pull-down resistor should be attached to the Arduino pin directly — you want the current drain as physically close to microcontroller pin as possible. This is something I picked up a few years ago, but its rarely talked about or considered. That wire leading to the Arduino can act like an antenna, picking up EMF and delivering it to the processor instead of going to ground (because the path of least electrical resistance is toward the processor with no intermediate dumping path to ground — polarity determines the direction of current flow.) It makes sense that the capacitor adds a filter function that can draw EMF, but it can’t trap all of it because of where it is positioned in the circuit.
If I’m understanding the situation correctly, you need only move the resistor from the button to the Arduino. The capacitor should no longer be necessary. Give it a try and let me know if it helps. Since the expedient of cleaning wheels and preventing EMF works, I suspect this small change will fix your problem by eliminating the EMF antenna.
Best,
Rob
Hello Rob. I found this site whilst on my long quest to try and get my arduino nano and pca 9685 working to control the turnouts on my Nscale layout that i have just started to build for myself and my six year old. I was reading a post (from back in 2016) where the writer was having problems upscaling the code ypou had to control more turnouts, which is exactly the problem i am currently having. I have found a few examples but none seem just right, some use toggles ( want to use momentay push switches) some dont use pca9685, some have relays and leds included. its all a bit confusing for an old timer like me. In your reply you said you would make a code to suit his requirements and post it on the main blog. I have been looking for it because his requirements seem very similar to mine. Can you point me in the right direction. I need a sketch to control 8 turnouts using an Arduino Nano, a pca9685 controlled with push switches, one push to move the turnout and another push to return it. I do not need it to control LED’s as I am using a micro switch connected to the same servo mount and when the servo arm moves as well as throughing the turnout the arm of the servo also presses the microswitch and changes the LED.
I hope you can help, im already a bit bald on top so tearing my hair out trying to work this out is not helping.
Hi Seamus,
Glad you found the site. I specialize in hair preservation for model railroaders!
I’ve done quite a few posts about turnouts, each from a different perspective. You found the post that gives you the basics of the pca9685, but that just a starting point. The important part is the Adafruit library and the basic commands you need to use it. Are you able to connect the board and run one servo? If not, have you seen the adafruit tuturial: https://learn.adafruit.com/16-channel-pwm-servo-driver?
I don’t have canned solution for you, but I do have some posts & code that will help. You should read (and get the turnout object code through the link at the end) C++ Objects for Layout Control, Part 2 — Turnouts. For a general primer on C++ objects see part 1: C++ Objects for Layout Control, Part 1.
The turnout object provides methods for causing it to change positions, including a simple toggle() method. Your buttons are a separate problem: you have to capture button presses and send the appropriate command to the target turnout object. For basic button use, see Running a Small Layout with an Uno (however, I recommend you use the newer C++ turnout object instead of the turnout code in the example; still studying the old way may help understand the turnout object).
For buttons and switches, I prefer an input board I created to directly attaching to the Nano or other MCU. Called Digital Input duinoNodes, these 8 port devices use three ports on your Nano, and you can chain multiple boards to get up to 255 input ports. The board controls input “bounce” and, with software driver that comes with it, makes monitoring input states easy.
Let me know if this helps getting you going in the right direction.