SPCoast
Railroading on the Southern Pacific Coast

ControlPoint

From SPCoast

Jump to: navigation, search

When we build our model railroad empires, we value being true to the prototype. Exact details on our engines ("rivet counting"), scale blueprints for buildings, layout design elements for trackwork, operations, dispatching, cTc machines and signals - all are aimed at recreating the romance, excitement and fun of the real thing.

Except for wiring the layout, that is. We seem to wire our railroads in arbitrary, hodgepodge ways, with little regard to how the prototype does/did things. I'm involved with the JMRI project, and so get to see quite a few "layout wiring systems". Most depend on a PC that can see and control everything on the layout. C/MRI, Loconet, DCC AIU's - all focus on exposing the raw sensor info to a central program that then simulates the vital logic and superimposes some sort of control system on top.

In the last year or so, I got involved in the ATCS monitoring part of the railfan community - monitoring and decoding the radio code line systems that the real railroads use to control and monitor their trains and tracks. This combination lead me to wonder what a model railroad would look like of it was designed and wired as a series of control points connected by a codeline instead.

Here's a PDF file that shows the layout: CP-Michael2.pdf

What's a codeline, and why is it interesting? A codeline delivers *indications* from the field to the dispatcher, and sends *commands* from the dispatcher to the field. These indications and commands contain the complete state of a control point (also known as an interlocking), including track circuits, switch states and whether the signals controlling that interlocking are showing STOP or not. The key point for me is that it is up to the relays and circuitry in the control point to monitor and manage all the vital logic and interlocking interconnects for itself. An example:

The Dispatcher sets all the signals to STOP. This causes a codeline control packet to be sent to the control point. The packet contains bits that represent "Signal XXX Set to Stop" for all the signals in that control point.

The CP receives this command packet, validates it (i,.e, is it legal to set those signals to stop right at this moment, based on home/remote track circuits, timers, and the like), sets the signals to STOP and returns an indication packet showing the new state of the control point.

Assuming a train is stopped before the CP's signal and the dispatcher wants to allow it to proceed, the dispatcher would line a route thru the control point, setting switches and signals to match. When the Code button is pressed, another control packet is sent to the CP, containing new commands.

The CP digests this new packet, sends back an indications packet, then sets switches to match; when the points report "in position" and "locked", the signals get released from STOP to show something other than STOP. The particular aspect they show is entirely dependent on the state of the interlocking - if there is another train close by, the aspect will be more restrictive than if the track is clear.

It is this last set of behaviors that is interesting - the dispatcher has no direct control over whether a signal shows ADVANCE APPROACH, CLEAR or RESTRICTING when it is not showing STOP - that part is entirely up to the vital logic part of the system.
Loconet Interface
Loconet Interface

By modeling a control point in electronics hardware and arduino software, I hope to explore the ramifications of keeping the vital logic close to the tracks being controlled - and away from the higher level software abstractions hosted elsewhere on the layout. One key benefit I hope to achieve is the ability to run a full featured signaling system without the need for a PC running C/MRI or JMRI or ...)

i2c 8-bit I/O modules, 1 per breadboard
i2c 8-bit I/O modules, 1 per breadboard

My first step was to breadboard some prototypes. An Arduino based Loconet interface came first, followed by an i2c based I/O expander card. One of my pet peeves with Bruce Chubb's C/MRI system is that the I/O boards don't provide visual feedback on the state of their inputs/outputs and that the boards use Molex pins instead of RJ45 connections. My first design of an I/O board corrects both those shortcomings, though it added a few of its own: the I/O board's address jumper's pads shorted together, the power connector needed milled mounting holes and the board house didn't support milled holes, the LED footprints had A and K swapped, and I "forgot" a couple of decoupling caps and the i2c pullup resistors :-) Here's the Eagle schematics and pcb layouts, complete with those bugs.

The good news is that, with a little dremel tool work and creative component mounting, the modular stack works! I2C communication between the Arduino-clone processor board and the '8574 8-bit I/O board as well as a "directly" connected Loconet interface. There is provision for a CAN bus interconnect (aka NMRAnet), but I haven't tried it out yet. I've built up 3 I/O boards and breadboarded 2 more, for a total of 40 I/O pins. As I've got another set of processor and Loconet boards, my next step is to mock up a couple of Control Points and see what I can make them do together.

   Update:  I've built up a dozen first and second generation boards, with both 
   8-bit and 16-bit IO expanders, and mocked up a crude cTc board and field unit.

Here's the latest:
Locoduino
Loconet + CAN Interface
8-bit I2C based I/O board

If anyone knows how to easily make the color pallets of different Eagle schematics & PCB boards the same, please let me know :-)

I fab'd a bunch of I2C-based 8-bit I/O boards along with an Arduino-clone processor base and a loconet/CAN interface board and connected all it to a "virtual layout" full of LEDs and toggle switches (but no track!) in order to simulate the track circuits and turnout controllers a real layout would have, without the space - all the fun of a real layout without the bother and mess :-)

I've got code running on a pair of 'duino clones that read/write Loconet packets and interact with the I2C I/O boards; one stack pretends to be a Control Point, and reads the "track circuits", turnout position feedback & turnout control panel switches and generates Indication packets; the other node listens for Indications and responds by translating them into Loconet turnout commands which, in turn, are sent out to a LocoIO-based turnout controller. The CP node enforces "don't throw switches if the track is occupied" and has enuf smarts to combine several track circuits into one logical "section". The code looks a lot like Chubb's C/MRI stuff, without the GUI overhead:

   loop() {
       read everything (I2C, Loconet queue, CAN queue, ...)
       process it
       write whatever is needed
   }

Arduino sketches (both need the Loconet Library from the Embedded Loconet project:

ControlPoint_Loconet2.pde for "dispatcher node"
ControlPoint_Michael.pde for "Control Point node"

The Indication packet is a Loconet OPC_PEER_XFER packet, which holds 8 bytes of payload data. This payload capacity is, oddly enough, the same as used by many ATCS-based codeline systems in use today, and seems sufficient for even very complex control points; this is something I want to pursue with openLCB once my testbed matures.

CP-Michael's indication structure looks like

   Indications:
     Byte      || bit 0 | bit 1 | bit 2 | bit 3 || bit 4 | bit 5 | bit 6 | bit 7 ||
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++
       1       || 1NWK  | 1RWK  | 3NWK  | 3RWK  || 5NWK  | 5RWK  | 7NWK  | 7RWK  ||  Turnout states, Normal and Reverse
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++
       2       || 1NATK | 2NATK | 3NATK | 1TK   || 1STK  | 2STK  | 3TK   | 4SATK ||  Track circuits
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++
       3       || 4SBTK |       |       |       ||       |       |       |       ||  Track circuits & (future) signals showing stop
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++
       4       ||       |       |       |       ||       |       |       |       || 
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++
       5       ||       |       |       |       ||       |       |       |       ||
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++
       6       ||       |       |       |       ||       |       |       |       ||
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++
       7       ||       |       |       |       ||       |       |       |       ||
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++
       8       ||       |       |       |       ||       |       |       |       ||
   ------------++-------+-------+-------+-------++-------+-------+-------+-------++

Still up in the air:

  • Control packets are the other side of the coin, and still need to be implemented. The dispatcher creates and sends them (by pressing the "code" button on a cTc panel, for example) and the CP responds with an Indication packet that reflects the (possibly changed) state of the plant. As timers run out, points actually move, etc, additional Indication packets are generated by the control point so the dispatcher can follow what is happening out in the field.
  • The I2C/Loconet combination works well with room to spare. With all my debugging code in place, and with no attempt to optimize anything, it is currently consuming just under 10K bytes of the 14K available on the chip I'm using; I don't know how much more space is needed for openLCB. I may need to migrate to a 'mega or even an ARM as my baseline processor to fit everything in.
  • While there are no signal heads in the mix today, there will be some soon. They will be driven by the CP, with bits in the control packet overriding the field derived settings and forcing them to show stop. The Indication packet will only show "stop or not-stop"; remote observers won't be able to see the actual aspects/indications.
  • I'm hoping to use the CAN bus to interconnect modules, and use a "local Loconet" on each module. This will let me use off the shelf occupancy detectors, accessory decoders, LocoIO devices and Tower Controllers for my interfacing needs while not exposing any of their config/addressing foibles to other modules. The only inter-module connections will be Control and Indication packets on the CAN bus, which means I won't use most of the other features in OpenLCB in the beginning.
  • I'm waiting for Vol2 of Bruce's CMRI Handbook so I can implement locking, fleeting, stick logic for reverse moves and the like :-)
  • I'm still undecided on how to handle situations where track circuits need to be exposed across module boundaries - I'm leaning towards using multiple occupancy detectors wired to the same track leads, one for each module so to keep things as isolated as possible...

The next step is to make an Arduino Shield: Railroad_Shield, an IOShield, a better cTc console and morph my existing mockup into a real field unit.