Overhead view of servo-controlled turnouts on the Holgate N gauge model railway using DCC-EX, EXRAIL and a PCA9685 servo controller.

Adding Servo-Controlled Turnouts to DCC-EX Using a PCA9685 and EXRAIL

How to Add Servo-Controlled Turnouts to DCC-EX Using a PCA9685 and EXRAIL

If you're looking for a reliable way to add servo-operated points or turnouts to your DCC-EX layout, the PCA9685 16-channel servo controller is one of the simplest and most cost-effective solutions available.

Combined with DCC-EX EXRAIL, it allows you to control individual points from your throttle while also building automated routes, signalling and interlocking.

In this guide we'll show you how to connect a PCA9685 to your DCC-EX CommandStation, configure the hardware abstraction layer, define servo turnouts and calibrate them for reliable operation.

If you're using the ACI CSB1 Command Station, the Qwiic connector makes connecting a PCA9685 particularly simple, although the same principles also apply to other compatible DCC-EX CommandStations.

For anyone starting from scratch, this is also where a ready-to-run DCC-EX system such as the ACI CSB1 can make life easier. The command station is already assembled and configured, so you can spend more time adding servos, routes and EXRAIL automation rather than building the command station first.

Hardware You Need

  • PCA9685 16-channel I2C servo board
  • Servos, one per turnout
  • Regulated 5V power supply for the servos
  • I2C connection to your CommandStation, such as Qwiic on the CSB1 / EX8874 or SDA/SCL pins
  • Cables and a common ground connection

Common ground required: the CommandStation GND, PCA9685 GND and 5V servo power supply GND must all be connected together.

Power warning: Do not power servos directly from the CommandStation. Use a separate regulated 5V power supply connected to the PCA9685 servo power input.

Wiring and Initial Setup

  1. Connect PCA9685 SDA to SDA on the CommandStation.
  2. Connect PCA9685 SCL to SCL on the CommandStation.
  3. Connect VCC and GND for the PCA9685 logic side.
  4. Connect the separate 5V servo power supply to the PCA9685 servo power rail.
  5. Connect the grounds together: CommandStation GND, PCA9685 GND and 5V PSU GND.

Power up the CommandStation and watch the console log. DCC-EX should list any detected I2C devices, including the PCA9685 address. The default address is commonly 0x40, but always verify this from the log.

If you see:

< No I2C Devices found >

check the SDA/SCL wiring, connector orientation and power connections.

HAL Configuration for the PCA9685

The PCA9685 is declared in myAutomation.h using the HAL(...) macro.

// start vPin, count, I2C address
HAL(PCA9685, 100, 16, 0x40)

The PCA9685 does not appear as normal physical GPIO pins. Instead, DCC-EX assigns each servo channel a virtual pin, known as a vPin. These vPins are then used in your EXRAIL turnout definitions.

vPin to PCA9685 Channel Map

  • vPin 100 = PCA9685 channel 0
  • vPin 101 = PCA9685 channel 1
  • vPin 102 = PCA9685 channel 2
  • vPin 103 = PCA9685 channel 3
  • ...
  • vPin 115 = PCA9685 channel 15

Connecting Multiple PCA9685 Servo Controllers to DCC-EX

If you need more than 16 servo outputs, additional PCA9685 boards can be connected to the same I2C bus. However, each PCA9685 must use a unique I2C address.

A new PCA9685 normally uses the default address:

0x40

You only need to change the address of additional boards - the first PCA9685 can normally be left at its default 0x40 address.

The small A0-A5 solder pads on the PCA9685 are used to change this address. With all of the pads left open, the board remains at 0x40. Bridging one or more pads adds a binary offset to the base address.

PCA9685 Board I2C Address Address Pads to Bridge
First board 0x40 None
Second board 0x41 A0
Third board 0x42 A1
Fourth board 0x43 A0 + A1
Fifth board 0x44 A2
Sixth board 0x45 A2 + A0
Seventh board 0x46 A2 + A1
Eighth board 0x47 A2 + A1 + A0

For example, when using two PCA9685 boards, leave the first board unchanged at 0x40 and bridge the A0 solder pad on the second board. This changes the second board to address 0x41.

DCC-EX can then register each controller separately:

// First PCA9685 - vPins 100 to 115
HAL(PCA9685, 100, 16, 0x40)

// Second PCA9685 - vPins 116 to 131
HAL(PCA9685, 116, 16, 0x41)

Both controllers can share the same SDA and SCL connections, but their unique addresses allow DCC-EX to control them independently.

Important: Do not connect multiple PCA9685 boards using the same I2C address. Each PCA9685 on the I2C bus must have its own unique address.

Defining Servo Turnouts in myAutomation.h

Once the PCA9685 has been registered using HAL(...), each servo-operated turnout must be defined in myAutomation.h using SERVO_TURNOUT(...).

Syntax

SERVO_TURNOUT(turnout_id, pin, active_angle, inactive_angle, profile [, "description"]|HIDDEN)

Parameters

  • turnout_id - Turnout ID number used by throttles and automation
  • pin - Virtual pin assigned to the PCA9685 servo channel
  • active_angle - Servo position used when the turnout is thrown
  • inactive_angle - Servo position used when the turnout is closed
  • profile - Motion profile, such as Instant, Fast, Medium or Slow
  • description - Optional label shown for the turnout, or use HIDDEN with no quotes to hide it

Start by Centring the Servo

When initially installing a servo, it is good practice to set both the active_angle and inactive_angle to the same midpoint value.

For example:

// First servo, channel 0, vPin 100
SERVO_TURNOUT(1, 100, 250, 250, Fast, "Turnout 1")

// Second servo, channel 1, vPin 101
SERVO_TURNOUT(2, 101, 250, 250, Fast, "Turnout 2")

Setting both positions to the same midpoint value places the servo at a known central position instead of allowing it to move immediately between two widely separated end positions.

This is particularly useful when fitting the servo horn, linkage or mounting arrangement beneath the turnout, because you can establish the mechanical centre before setting the final closed and thrown positions.

Initial myAutomation.h Configuration

Your initial myAutomation.h configuration therefore contains both the PCA9685 HAL declaration and the centred SERVO_TURNOUT(...) definition.

// Register the PCA9685
HAL(PCA9685, 100, 16, 0x40)

// Define the servo at its initial centre position
SERVO_TURNOUT(1, 100, 250, 250, Fast, "Turnout 1")

Save myAutomation.h, recompile the CommandStation firmware and upload it to your CommandStation.

When the CommandStation restarts, the PCA9685 and turnout definition will be loaded and the servo can be centred before its final travel is calibrated.

Important: Do not begin with widely separated active and inactive values on a newly installed servo. Starting with both values at the midpoint helps avoid unexpected servo movement while the linkage and turnout mechanism are being set up.

Calibrating the Servo with EX-Toolbox

Once the servo has been centred and the mechanical linkage is correctly positioned, the next step is to determine the final closed and thrown positions.

The EX-Toolbox Android application includes servo controls that allow you to adjust the servo position interactively without repeatedly editing and recompiling myAutomation.h while searching for the correct values.

Before adding final ballast and scenery around your pointwork, spend time testing each servo and adjusting its travel. It is much easier to correct servo movement, linkage geometry or point alignment while the track is still fully accessible.

  1. Start with the servo defined at its midpoint, for example 250, 250, in myAutomation.h.
  2. Compile and upload the configuration, then reboot the CommandStation so the servo moves to its centred position.
  3. With the servo centred, position the servo horn and linkage so the turnout mechanism is approximately centred mechanically.
  4. Open the servo control in EX-Toolbox.
  5. Adjust the servo carefully towards one turnout position until the point blades close correctly without excessive pressure or strain.
  6. Record this value as either the active or inactive position.
  7. Move the servo in the opposite direction until the turnout is correctly positioned at the other end of its travel.
  8. Record the second value.
  9. Enter the two final values into the corresponding SERVO_TURNOUT(...) definition in myAutomation.h.
  10. Save myAutomation.h, recompile the CommandStation firmware and upload it again.
  11. After the CommandStation restarts, test both turnout positions and make any final adjustments if required.
Testing servo-operated DCC-EX turnouts before final ballasting on a model railway.
Testing servo-operated turnouts before final ballasting. This allows the servo travel to be adjusted and any mechanical issues corrected while access is still easy.

Making the Calibrated Positions Permanent

The values found using EX-Toolbox are used to determine the correct travel for the individual turnout. Once you are happy with both positions, enter those values into the servo definition in myAutomation.h.

For example, if EX-Toolbox shows that the turnout operates correctly at positions 120 and 400, update the definition to:

SERVO_TURNOUT(1, 100, 120, 400, Fast, "Turnout 1")

Save the file, recompile the CommandStation firmware and upload it again. These calibrated values are then part of the permanent CommandStation configuration and will be restored whenever the CommandStation starts.

Testing the Finished Turnout

You can then test the calibrated turnout directly using turnout commands.

Closed:

<t 1 C>

Thrown:

<t 1 T>

Many throttles and consoles require the angle brackets < > around the turnout commands. Do not omit them.

Example Block: Four Servos

Once each servo has been centred and calibrated, several turnout definitions can be added to the same PCA9685 configuration.

// PCA9685 mapped at vPins 100 to 115
HAL(PCA9685, 100, 16, 0x40)

// Define four calibrated turnouts
SERVO_TURNOUT(1, 100, 150, 300, Fast, "Turnout 1")
SERVO_TURNOUT(2, 101, 180, 280, Fast, "Turnout 2")
SERVO_TURNOUT(3, 102, 140, 280, Fast, "Turnout 3")
SERVO_TURNOUT(4, 103, 200, 300, Fast, "Turnout 4")

Note: The servo angle values shown above are examples only. Every turnout installation is different, so the final active and inactive angles will vary depending on the type of servo, mounting position, linkage geometry and turnout being used. Use EX-Toolbox to determine the correct values for each turnout.

Using EngineDriver or Other Throttle Apps

When using EngineDriver on Android to control turnouts:

  1. Connect EngineDriver to your DCC-EX system.
  2. Once connected, EngineDriver should briefly display Points Loaded.
  3. Tap the three dots in the top-right corner.
  4. Select Turnouts/Points.
  5. You should see the turnouts you have configured.
  6. Tap Throw or Close to operate each turnout.

Once configured, EngineDriver automatically lists every turnout you've defined, allowing you to operate them directly from your Android device.

Using ONTHROW and ONCLOSE

This is where things start to get interesting.

ONTHROW and ONCLOSE let you trigger other actions automatically when a turnout moves. This is useful for pairing points, setting signals, building simple interlocking or triggering other layout automation.

These commands are one of the reasons EXRAIL is so powerful, allowing point movements to trigger other automated actions around your layout.

This is exactly the approach used on the Holgate exhibition layout, where EXRAIL automatically sets routes during public demonstrations, helping trains move reliably through complex trackwork.

Example: Linking Two Turnouts Together

ONTHROW(1)
    THROW(2)
DONE

This will throw turnout 2 automatically when turnout 1 is thrown. You are not limited to just one extra action inside an ONTHROW() block.

Example: Setting a Signal When a Turnout Closes

ONCLOSE(3)
    RED(Signal_ID)
DONE

In this example, a signal is set to red when turnout 3 is closed.

Once you start using ONTHROW and ONCLOSE, they open the door to far more automated operation without needing complex logic.

Need a shorter setup reference?
For a condensed version of the setup and configuration process, see our DCC-EX Servo Configuration Guide .

Troubleshooting

Problem Likely Cause Solution
PCA9685 not detected Wrong wiring or I2C address Check SDA/SCL wiring and verify the address in the console log
Servo not moving Power issue Confirm the 5V supply and common ground connection
Servo chatters or jitters Over-travel or weak power supply Adjust the servo angles and use a stable 5V supply
Servo buzzes continuously End stop is too tight Reduce the travel angle slightly so the servo is not under constant strain
Wrong channel moves Incorrect vPin mapping Recheck the vPin to PCA9685 channel mapping

Taking It Further

Once you're comfortable controlling servo turnouts, EXRAIL allows you to:

  • Automatically align routes
  • Control colour light signals
  • Build simple interlockings
  • Operate hidden staging yards
  • Trigger accessories and layout animations
  • Automate train movements

The same principles can be used on small home layouts or larger exhibition layouts where reliable turnout control and automation are important.

If you would rather begin with a ready-to-run DCC-EX command station, the ACI CSB1 provides a simple starting point for train control, servo-operated turnouts and future EXRAIL automation.

With the PCA9685 configured, your servo turnouts calibrated and EXRAIL handling the automation, your DCC-EX CommandStation is ready to control individual points or fully automated routes with confidence.

Back to blog