L&NC Update; Running Lots of Turnouts

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:

Progress on the 1st Module as of June 2017. Fascia and dressing up of the edges will be the very last step; its pointless to do that while I’m disturbing things with new features and gear. Wires hanging out the pipe at the bottom of the photo are Anderson Powerpole connectors (track and master power) to the upper level.

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.

The turntable rotating beacon comes on whenever the turntable is in motion.

Then stove fire simulation inside the hut is visible through the door. It’s managed by a little PWM code that will the subject of an upcoming post.

The parking lot side of the Roundhouse has been enhanced with Rix power poles and some EZLINE power cables (which comes in two thicknesses and several colors. I use fine, and chose green–old copper–for its visibility). I fabricated a simple power connection and breaker box for the roundhouse out of a piece of styrene and a brass rod, and an EZLINE cable.

A Woodland Scenics light pole casts a pleasant white-yellow light over the parking lot in night mode. Figures, such as the worker (a Woodland Scenics prepainted figure) at the turntable end of the parking lot breath life into a scene.

Having gone to all the trouble to light the Roundhouse, I’ve started populating the space with some appropriate gear and figures.

A view of the lit Roundhouse interior.

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.

The Red Bluffs Yard Office is fully lit for night operations. The Woodland Scenics light pole works just fine with my Duino Nodes controlled by an Arduino; treat it like any other 20 mA LED. The truck tailights in the background are from LEDS placed in the rear wheel wells, with the light allowed through tiny holes in the fenders.

Its amazing what a couple of SMD LED headlights can do for a really basic pot metal pickup truck kit from Micro Engineering.

The first of three planned scratch built Signal Bridges has been erected to control one of the approaches to the yard interchange.

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!.

The underside of this module is rapidly filling with gear. Obviously overhead soldering is not an issue since I can put the module on its side. That said, I rely primarily on screw terminals and crimped fittings for connections.

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.

Adafruit 16-Channel 12-bit PWM/Servo Driver, assembled with original terminal block (blue) that did not hold up to use. I eventually soldered leads to the underside of the board.

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.

Adafruit 12 bit 16 Channel PWM Driver installed and connected to servos and lighting.

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!

Current Sensing and Occupancy Detection for DCC

I’ve had several projects going on more or less simultaneously over the last 6 weeks in connection with the build-out of the 1st module of the L&NC. One project has been to further refine block occupancy detection in DCC to achieve 1 mA detection sensitivity—the sensitivity needed to detect rolling stock equipped with a 10kΩ resistor wheel set. High sensitivity occupancy detection will be especially useful in the Red Bluffs yard part of the layout I’m working on right now

This part of the L&NC is a Yard/Staging facility with a roundhouse & turntable, so it has lots of blocks

Commercial block occupancy detection systems for DCC typically use current transformers to sense current draw from locomotives or resistor wheelsets. The sensors are usually attached to stand-alone logic boards that turn outputs on or off to signal occupancy detection. Typically, these outputs are used to directly power signals. The December 2016 issue of Model Railroader Magazine included an article (Build a signal system with Arduino micro-controllers) where the author connected the outputs of RRCir-Kits BOD boards to an Arduino Mega, and ran his signals from there.

I’ve been avoiding solutions like that because of the high cost and inflexibility of commercial detection systems. All I need is a way to sense very low current flow; the Arduino can do all the rest of the work.Thinking about the issue further, I wondered why not just use current transformers as sensors that can be directly read by an Arduino?

Finding Experimental Sensors

Current Transformer

The type of current transformer useful in model railroading are designed to allow you to wrap a wire (e.g. track feeders) around it through the central hole making the wire the “primary” coil of the transformer. The secondary coil produces an A/C current, that you can measure, proportional to the A/C current running through the primary wire.

I had seen little about using CT sensors with Arduino until I bumped into a seller on Amazon of boards with current transformers marketing them as Gikfun DIY 5A Range AC Current Transformer Module for Arduino. The assembled boards were about $7.50 each, a bit expensive, but then I found a 5 sensor unassembled kit from the same vendor for just under $9. Less than $2 per sensor is my price point for BOD sensors, so I bought the kit to see what i could do with it.

Gikfun Current Transformer Kit

The kit consisted five current transformers, five 82Ω resistors, connector pins and five 19mm x 19mm pc boards on a break-apart strip, drilled and traced for the parts. The resistor is placed across the transformer leads, placing a load (I’ve seen it referred to as a “burden”) on the transformer enabling current flow. No instructions on how to use the sensor were anywhere to be found.

So I went with the methods I already know work with ACS712 sensors. I set up some feeders from the DCC system to my cleaning track, wrapping one of the feeders around the CT coil three times. I hooked leads from the sensor board to pin 0 and ground of my Mayhhew Labs Extended ADC Shield, then threw together a test sketch with the current reading utilities I’d previously used (adapted for the shield).

A Simple CT Sensor Test Rig

I “let her rip” and watched the readings go by on the serial monitor.

Oh My! Putting a DCC equipped locomotive on the track and turning track power on, I was rewarded with a clear reading even though the decoder was idling and all lights were off.  Bring up the lights and the readings jumped up appropriately. Then, taking the loco off the track, I tried shorting the track with a 10kΩ resistor: an immediate and clear response in the readings told me this was going to work.

Test readings in single ended mode using a Mayhew Labs 14 bit ADC Shield. Everything from a 10k resistor shorting the track, to different stages of locomotive operation are clearly shown by the sensor outputs.

I tried it again, this time connecting the CT sensor to A0 and ground on my UNO, and got different but workable results. Amazing!

The readings through the UNO’s built-in ADC are similar, especially at the low end. But notice that the scaling, which is spot-on correct in the first example, fails at higher current levels here. Evidently, the greater bit depth of the Mayhew Labs Shield (14 bits) vs the built-in ADC’s (10 bits) makes a difference where absolute accuracy is concerned. Our purposes are much cruder — we just want to know when a minimum current (1 mA) is flowing. For that purpose direct-to-UNO works fine.

Testing current sensing with and InterMountain EMD F3A

Wait! This Shouldn’t Work!

You see, I was using the ADC in “single-ended”, “uni-polar” mode so that it would read a single input in the range of 0 to +5 volts; this is the same way Arduino analog inputs are read by the built-in ADC. However, the signal from the CT is an A/C signal that the ADC (in single-ended, uni-polar mode) will not be able to read during the negative voltage part of the cycle. Nevertheless, it works with both the built-in and the external ADC, even though it shouldn’t.

I was puzzling as to why, apparently, I was able to cheat when it occurred to me that the difference from ordinary applications was probably the frequency of the signal. Ordinary A/C is a 60 Hz cycle (60 cycles per second).  That is slow compared to the rate at which an Arduino ADC can sample, so a lot of samples would be at 0 during negative phase of the cycle. This would throw calculations off.

DCC is an 8kHz  (8000 cycles per second) cycle which is very fast. My Mayhew Labs ADC can sample at a maximum rate of 3kHz, which is somewhat faster than the Arduino built-in ADC but still slower than the DCC cycle. So even at the fastest rate every ADC read will span multiple DCC cycles, resulting in the ADC returning a positive reading every time.

Or something along those lines is going on.

Mayhew Labs Extended ADC Shield on an UNO, reading the test CT sensor in differential mode.

For hard core accuracy, a CT should be read in differential, bi-polar (+/- voltage) mode, requiring a 14 or 16 bit external ADC with that capability. In differential mode, each CT lead is attached to an ADC port, then the two ports are compared and their difference reported. This effectively captures the entire A/C cycle. Read in differential mode, CT sensors produce stable, high accuracy readings. During testing with my 14 bit ADC I was able to sense down to near 400µA in differential mode, the draw of a 20kΩ resistor at 11 volts. Now that is sensitive!

Same test sequence using the Mayhew ADC to read the sensor in differential mode. Notice the increased accuracy, stability and sensitivity.

Next Steps

The Gikfun 5 sensor kit is a viable sensor package where you will be watching no more than a few (up to the 6 or 8 analog ports on your Arduino or Mayhew Labs ADC shield) blocks. For small installations, buy these sensors and use the ADC in your favorite Arduino board to read them.

For larger installations, the external ADC shield is worth the cost because it is fast and more accurate.

But what if you are watching more blocks than you have analog ports for? That is a bit of a problem, especially if you don’t want to have to use a new microcontroller for every 8 blocks. The module I’m working with has this problem, because it is a yard zone (with turntable and roundhouse) with 24 blocks, and I want just one Arduino board to listen to them all and run signals for this part of the layout.

In the next post, I’ll go into a solution to the problem and install the system.


Code

My experiment was complicated by the fact that I was testing different ADC’s and different connection methods. Below is some basic code for testing a CT sensor such as the Gikfun units discussed above by directly attaching one lead to an Arduino analog port, and the other lead to ground. This is the simplest way to use CT sensors.

The code is built around current sensing techniques originally developed for ACS712 sensors. For more in-depth discussion of that development process, see these posts – 1 , 2, 3 and 4. ADC’s (analog-to-digital converters) read the voltage produced by a sensor which, in the case both current transformers and ACS712 sensors, is proportional to the current it is measuring.

The challenge with sensing alternating current comes from the fact that at any given moment when a sensor is read, the current could be anywhere in its cycle with a voltage somewhere between -Vmax and +Vmax (the nominal A/C voltage). Since we are sampling a bipolar wave form, it is necessary to take multiple samples spanning multiple cycles, then calculate the current from the samples using the Root Mean Square algorithm. This is the generally accepted method for determining A/C voltage and current from digital samples.

In addition to solving the basic problems of sampling an A/C signal, the RMS algorithm cuts through signal and sampling noise, a significant problem with ACS712 sensors when measuring low current. Since CT sensors are far less noisy, we can get accurate readings with fewer samples; but we still need the RMS method to calculate current flow.

To make the process I’ve described accurate across an array of sensors, I developed a calibration routine. All ADC’s will produce some minimal reading for a sensor even when the sensor is not producing a signal. This is a form of noise that has to be filtered out. Also, some sensors (such as the ACS712) produce a signal in the absence of any current to measure — this too is noise that has to be filtered.

Each ADC port / sensor combination will produce a unique amount of noise. The purpose of the calibration routine is to measure and record the noise level — I call it ADC Zero — for each port/sensor. This is recorded both as raw mV, and as a calculated current in mA. Later, the measured noise is subtracted from each raw reading (in mV) to determine what current (if any) has been detected. Then, when current is detected, I use a multiple of the ADC Zero calculated current to establish an occupancy threshold. This method allows me to overcome sensor differences and manage the sensor system in a uniform way.

// CT Sensor test
// Using UNO built-in ADC to read the sensor
//////////////////////////////////////////////////////////////////

#define VERSION "1.006"
#define SYS_ID "CT Sensor Test - Direct to UNO ADC"
const int adcpin = 0;

// Sampling Parameters
const unsigned long sampleTime = 2000UL; 
const unsigned long numSamples = 100UL; 
const unsigned long sampleInterval = sampleTime/numSamples; 

#define SENSITIVITY 5000
#define DETECTION_MULTIPLIER 1.3
#define CALIBRATION_READS 300

// variables to hold sensor quiescent readings
float aqv;  // Average Quiescent Voltage; e.g. ADC Zero
float aqc;  // Average Quiescent Current; 

void setup()
{
  Serial.begin(9600);
  Serial.println(String(F(SYS_ID)) + String(F(" - SW:")) + String(F(VERSION)));
  Serial.print("\nCalibrating the sensor at pin ");
  Serial.println(adcpin);
  aqv = determineVQ(adcpin); 
  Serial.print("AQV: ");
  Serial.print(aqv * 1000, 4);
  Serial.print(" mV\t");
  aqc = determineCQ(adcpin, aqv);
  Serial.print("AQC: ");
  Serial.print(aqc * 1000, 4);
  Serial.print(" mA\t");
  float sense = (aqc * DETECTION_MULTIPLIER) - aqc;
  Serial.print("Detection Sensitivity: ");
  Serial.print(sense * 1000, 3);
  Serial.println(" mA\n\n");
  delay(7500);
}

void loop(){
  float current = readCurrent(adcpin, aqv);
  float delta = abs(aqc - current);
  bool occupied = delta > ((aqc * DETECTION_MULTIPLIER) - aqc);
  
  Serial.print("Current Sensed: ");
  Serial.print(current * 1000,3);
  Serial.print(" mA\t");
  
  if(occupied){
    Serial.println("Occupied");
  } else {
    Serial.println("Not occupied");
  }
  delay(3000);
}

//////////////////////////////////////////
// Current Sensor Functions
//////////////////////////////////////////
float readCurrent(int pin, float adc_zero)
{
  float currentAcc = 0;
  unsigned int count = 0;
  unsigned long prevMicros = micros() - sampleInterval ;
  while (count < numSamples)
  {
    if (micros() - prevMicros >= sampleInterval)
    {
      float adc_raw = (float) analogRead(pin) - adc_zero; // sensor reading in volts
      adc_raw /= SENSITIVITY; // convert to amperes
      currentAcc += (adc_raw * adc_raw); // sum the squares
      count++;
      prevMicros += sampleInterval;
    }
  }
  //https://en.wikipedia.org/wiki/Root_mean_square
  float rms = sqrt((float)currentAcc / (float)numSamples);
  return rms;
}

//////////////////////////////////////////
// Calibration
// Track Power must be OFF during calibration
//////////////////////////////////////////

float determineVQ(int pin) {
  float VQ = 0;
  //read a large number of samples to stabilize value
  for (int i = 0; i < CALIBRATION_READS; i++) {
    VQ += analogRead(pin);
    delayMicroseconds(sampleInterval);
  }
  VQ /= CALIBRATION_READS;
  return VQ;
}

float determineCQ(int pin, float aqv) {
  float CQ = 0;
  // set reps so the total actual analog reads == CALIBRATION_READS
  int reps = (CALIBRATION_READS / numSamples);
  for (int i = 0; i < reps; i++) {
    CQ += readCurrent(pin, aqv);
  }
  CQ /= reps;
  return CQ;
}

Adjusting the Sketch

The SENSITIVITY and DETECTION_MULTIPLIER constants are the main values you can manipulate to adjust the sketch.  The SENSITIVITY constant defines the conversion from raw mV to sensed current in mA; raise that number to reduce the current reading and decrease dynamic range of the sensor readings (lower it to do the reverse).  The DETECTION_MULTIPLIER determines when a current reading is high enough to mean that a block is occupied. Try different values for these items and see what happens. The interaction between these two constants is the primary determinant of how the sketch performs.

If you have having stability trouble with your readings, try increasing the number of samples taken on each pass (numSamples) and/or changing the sampleTime variable that controls the interval between samples.

Bear in mind that for low current sensing, the 10-bit ADC in an UNO is just barely sensitive enough to work with a CT. For low current sensing you’ll need to adjust the variables to get a minimum of false readings.  The values given in the sketch above are what worked for me with the Gikfun CT coil and a particular UNO to achieve stable detection.  Expect different readings and different variable values for different brands of CT coils, and different Arduino boards. Working with large numbers of CT sensors, I can say that a given Arduino board and a given brand/model CT, using the same value for the load resistor, will generally produce the same readings.

 

Wiring Module 1 of L&NC

After a long pause, I’ve starting in on wiring the L&NC by doing the basic wiring on module 1, lower level (each module has two levels). Module one is the largest of the three modules at 54″ long, and is the intended entry point for all the incoming power and control connections. Everything I do here is intended to set the methods and practices for the remaining modules.

Applying Lessons from the Past

Test Loop wiring. Block sensors were added in Phase 2. Phase 3 signals and lighting in progress.

Test Loop wiring. Block sensors were added in Phase 2. Phase 3 signals and lighting in progress.

My early layouts were primitive from a wiring perspective (and other perspectives…. but lets not dwell on that ….). I never did get into the suitcase connector thing, but the old layouts were wired using a single bus pair connecting to feeders every few feet.  Not much to it, so there was not much to organize. Like many layouts, the wiring was somewhat exposed and disorganized underneath.

While I was experimenting on the Test Loop, the wiring was built up in layers without a master plan.  For example, the power distribution from a central barrier strip was fine at first, but later it became necessary to create secondary distribution points to support various power needs. I ended up with wiring  less than optimally organized. On the plus side, I found that small circuit boards with banks of screw terminals are an excellent way to distribute power to to individual feeders or devices.

The other major lesson from the test loop is that it is a pain in the rail to add a major electronic component after everything else has been wired up. Major components should be sited and accounted for before interconnecting anything.  Components that move—e.g., servos, turntable mechanisms or whatever—get priority to ensure they get the placement and space they need — everything else has to adapt to their needs. In this case I will be installing the servos and the turntable early … but I’m getting ahead of myself again.

Special Issues with the L&NC

The L&NC has to be wired with a different aesthetic given that it is intended to be dissembled, moved and reassembled reliably. I am using the Digitrax Empire Builder DCC system, along with my Arduino-based independent control system and a multi-voltage power system supporting the layout — with power provided by a converted computer power supply. Computer power supplies can furnish 300 or more watts of fully regulated power at 12, 5 and 3.3 volts, perfect for every need other than track power.

L&NC Lower Level, Version 2

L&NC Lower Level

The lower level of module 1 (left-most module in the drawing) is fairly complex to wire because it contains the Red Bluffs Yard and the Roundhouse/Turntable complex. Including the feeders needed for the Roundhouse/Turntable area, 24 track feeders with current sensors have to be managed.

Yikes! That’s a lot of feeders for a 54″ x 27″ layout section! Its because of the yard, Roundhouse and turntable. Each roundhouse bay, the turntable bridge and any adjacent track segments adjoining the turntable all need individual feeders; the turntable is a reversing segment. Then each leg of the yard needs feeders, plus the base feeder for the ladder, to support occupancy detection and reliable operation. The main track loops each have two feeders. It all adds up…

So there is a lot more wiring in the L&NC than might be considered normal, and it has to be secure and well organized.

Step 1

With most track laid (I’m deferring the Roundhouse area until the turntable is installed) and the locations of all feeders and turnouts established, the first step is to place the primary distribution nodes then route, terminate and secure the main power bundle, the track bus and the LOCONET bus.

Connection Panel

Connection Panel

At the far left end of the module I placed a connection panel fabricated from styrene. There are four connections:

 

  1. Main power (4 conductors: 12 volt, 5 volt & 3.3 volt, plus ground);
  2. track power connection (2 conductors: Track A & Track B);
  3. LOCONET RJ12 jack (6 conductors); and
  4. Ethernet RJ45 jack (8 conductors).

 

 

My primary color coding scheme:

  • Black = Ground
  • Yellow = 12 volts DC
  • Red = 5 volts DC
  • Blue = 3.3 volts DC
  • Green = Track A (right-hand rail)
  • Violet = Track B (left-hand rail)

For the two power connections, I’m using Anderson Powerpole 15 Amp connectors to create polarized, color coded connectors. 2 connector and 4 connector brackets secure the receiving connection to the panel. I really love these connectors because they are easy to assemble (provided you invest in the crimper), come in a wide variety of colors, allowing you to assemble plugs and matching receptacles that can only be connected together one way. I get my supplies from Powerwerx.com.

Connection Panel, Inside

Connection Panel, Inside

From the panel, the wires run a few inches to a barrier strip.  Here the power is split – one branch going off to feed other parts of this level, with another branch heading to the upper level.

To supply power to the upper level I installed a short piece of PVC pipe from underneath the module, running up next to the corner post, terminating above the bottom edge of the upper level (when installed) I ran wires from the barrier strip up through the pipe, leaving 8″ or so extra cable extending from the top of the pipe, terminated with Powerpole plugs coded for the two power bundles.

Center Barrier Strip

Center Barrier Strip

To get to other areas of the lower level I ran cables from the first barrier, along the edge of the frame, using screw-in eyelets every 6 – 8 inches to channel the cables.  I terminated the cable run at a strip near the middle of the module, then ran an addition  set of cables from the middle strip to the right hand edge of the module.  Leaving 8 inches of slack, I terminated the cables with Powerpole plugs to be connected to a panel on the adjoining module.

The RJ11 jack has leads that I soldered to a six wire cable, then run that cable along the front edge of the module, opposite the power cables, to the location of a Digitrax UP5 universal panel (attached to the frame pending the addition of fascia), terminating the cable with an RJ11 plug as required to attach to theUP5. I fabricated another cable to run from the UP5 to interconnect bundle at the right side of the module.

Track power distribution block with ACS712 current sensors.

Track power distribution block with ACS712 current sensors.

The Ethernet jack on the panel is one end of a prefabricated cable available from Adafruit Industries. The other end will connect to a small Ethernet switch which will install at a later date. From there I’ll  make custom Ethernet cables (my crimper does both 6 and 8 conductor connectors) to fit where needed. Ethernet wiring will be added after I know the location of the Arduinos it will be supporting. I have an 8 port unit ready for the task.

I set up two track power distribution areas with a current sensor for each block, one on each end of the module. At this point I’m keeping the center area clear pending installation of the turntable. A third distribution area will be setup in that area to service the Roundhouse, turntable, service  and approach tracks.

Wiring phase 1

The big picture: wiring step 1 done

Now that the basic wiring is in, its time — finally! — to test the track installation, and fix what ever problems I find before moving on to the next step.  Until then, happy railroading!

Correcting track problems for flawless running.

Correcting track problems for flawless running.

 

Block Occupancy Detection for DC and DCC, Part 4

Through the first three parts of this series (links to part 1, part 2 and part 3) I’ve experimented with and refined to a degree the use of ACS712 current sensors for block occupancy detection. The system works well in DC mode, lighting up whenever a running DC train enters or is powered up in a block; program logic “remembers” block states when power is off for control reasons. My DC locos typically start drawing 30 – 50  mA when the lamps come on.

In DCC mode, ultra low current detection becomes an issue and the off-the-shelf ACS712 sensors don’t meet every need. My BLI DCC/Sound Locomotive draws enough power to be detected with the current system in idle mode, all sound and lights off. However, some standard DCC decoders draw so little current in idle mode that they are not consistently detectable. Further, constant track power in DCC invites us to find a way to sense any object drawing some minimal increment of current — such as 1.1 mA for a 10KΩ resistor wheelset on an 11 volt (in N scale) feed. There are a number of obstacles to achieving 1 mA  sensitivity with ACS712 sensors.

The Challenges

First, there is a question of how low a current the ACS712 can resolve. Theoretically, because the chip responds in a ratiometric way to current input, any amount of current will provoke a proportional output response. In reality, the output of the chip is a little noisy, and the noise masks the low current response.

Allegro MicroSystems says that the best resolution with the optimum filter capacitor is 20 mA. There is some general agreement among internet cognoscenti that with some amplification of the signal from the ACS712, greater sensitivity should be possible.

Second, the 10 bit ADC built into most Arduino boards has a maximum resolution of 4.88 mV (5 volts / 1024 steps), limiting the minimum detectable current to 26 mA (4.88 mV resolution / 185 mV/A sensitivity). Even the 12 bit ADC found in the Due and Zero boards is not quite close enough, with a maximum resolution of 1.22 mV (5 volts / 4096 steps), resulting in minimum detectable current of 6.6 mA.

A Better Analog-to-Digital Converter

Of the two problems, this is by far the easier problem to solve by using an external ADC with a 14 or 16 bit resolution. A 14 bit ADC has a maximum resolution of .305 mV, which is a good resolution for consistently detecting current at the 1.6 mA level or higher; a 16 bit ADC would provide 76 µV resolution and current detection in the mid to high µA range.  For those wanting to detect a single resistor wheelset, 16-bit is the way to go.

For my purposes and goals, I’m going to see how it goes with 14 bits so I’m not pushing resolution past the point of usefulness at this stage. My thinking is that 1.6 mA should be sufficient to detect a pair of resistor wheels. Two 10kΩ resistors in parallel have a resulting resistance of 5kΩ, which at 11 volts will draw 2.2 mA (@16 volts, 3.2 mA). Assuming I can overcome the noise problem to the point where 14 bits of resolution provides accurate current detection, the final step would be to go to 16 bits.

I looked at several ADC products and settled on the Mayhew Labs Extended ADC Shield, which is also available at Amazon. I chose this for several reasons: it supports 8 inputs, comes in a shield format and (perhaps most importantly) offers enough bandwidth to be able to sample multiple sensors at a reasonable rate.

Mayhew provides a code library for reading a variety of sensor types through the shield. It is fairly straight forward to use, and the shield is a very good quality piece of gear. I have found other ADC boards, but none with the unique capabilities of this one.

Mayhew Labs Extended ADC Shield

Sparkfun Low Current Sensor

Sparkfun sells a breakout board as a low current sensor using the ACS712 sensor chip plus an operational amplifier to amplify the signal. This is the only commercial solution of its type I’m aware of, so I bought one to check out and test. The schematic for the board can be seen here.

SparkFun Low Current Sensor Breakout – ACS712. This image is from an older version; different trimpots are used in the current version.

Although the circuit is promising, this board is really an experimental item and not suitable for production use on a model railroad. Part of the problem is that it does not provide — and is not drilled for — standard screw terminals for attaching the input current source, adding additional challenges to deployment. On the input side (I+ / I-) it is drilled for a pair of header pins and two larger holes with contact pads. The control side (VCC, OUT, GND) is drilled for standard headers.

Secondly, because this is an experimental board, it has two trim-pots for configuring the Op-amp.  Sounds great, but in practice this setup doesn’t work well. Add sketchy instructions for setting and using the board and I think most will find this board impractical for large scale use, though an interesting experimental tool.

Learning By Failing

So when the board arrived, I soldered on some header pins and hooked up the sensor to an UNO with the Mayhew ADC Shield, then attempted to configure and use the board. Here are the setup instructions in their entirety:

“To calibrate, first set the output offset to the desired level (with zero current on the sense lines, read output with a DVM). Then with a known current input (a 100mA limited supply works well for this), set the output deflection with the gain pot. Sensitivity is then calculated as (Vref – Vdeflect)/(current input).”

The “output offset” is (presumably, though not literally stated) adjusted with the vref trim-pot.  But what “level” is “desirable” for this application?  The second instruction is even weirder, since you are not going to short out a power supply by directly attaching it to the sensor without a load, and its the load that determines the current flow. I’m sure they meant to say something like “supply a load with a known current draw.”

I tinkered fruitlessly with the trim-pots for hours, testing various theories about how it should work and getting nothing intelligible out of the sensor. The gain pot is straightforward enough, resulting obvious changes to readings as the trim-pot is adjusted. Its the vref adjustment that mystified me and seemed to have no logic. I  did notice that when setting it there was a point where the output would suddenly, but only briefly, drop to O. That zero point is so finely specific that it is essentially impossible to set the trim-pot at that level; it always ends up off one way or another. That was a clue, but I did not yet understand.

Back to School

I found a nice tutorial about Op-amp circuits and, after a while started to understand the circuit and comprehend the problem. If you don’t understand Op-amps (who does among those of us not trained in electrical engineering?), check out the tutorial before reading further here.

The Op-amp circuit Sparkfun uses is a “voltage subtractor,” the intent of which is to  subtract the input voltage from the reference voltage and amplify the difference. This is the right choice—I think—but the implementation is wrong, at least for my purposes.

Unique ACS712 Properties

Many sensors that one might use with an Arduino are straight forward linear output devices where the output voltage ranges from 0 to 5volts in proportion to an input (light, temperature, etc.).

What makes the ACS712 different is that it senses both polarity and current of the measured input.  The “quiescent voltage” we measure when calibrating a sensor is the sensor’s “zero” point: ideally VCC/2 — midway between 0 and VCC (nominally 5 volts).  When the polarity is one way the measured current is represented by a value above VCC/2; when the polarity is the opposite, the sensor produces a value under VCC/2.

That means that we are only interested in the offset between the sensor output and its quiescent value. The software calibration routine I’ve been using seeks to get the most accurate average mid-point value possible to enhance the accuracy of the offset measurement. Amplifying that offset should be the route to gaining sensitivity.

Shouldn’t vRef be VCC / 2?

It may well be that the vref adjustment has value when measuring DC current with a fixed polarity. However, I’ve seen no math or theory in support of that proposition. For measuring DCC current, which is an 8kHz alternating polarity wave form, there is only one correct reference voltage for comparison to the ACS712 output: VCC/2.  So, Sparkfun had the right idea using a trim-pot as a voltage divider circuit to generate the reference voltage, but the trim-pot inhibits setting vref to VCC/2 because it is too imprecise to set the two resistor legs to exactly the same value.

What Now?

The Sparkfun sensor experiment was a bust in that it did not produce a usable result.  But it did help me research and think about what it is I need an operational amplifier to do in order to successfully amplify the ACS712 signal. Sometimes we learn more from failure than we do from success.

The next step is the set up an Op-amp with a fixed reference voltage of VCC/2, then continue experimenting from there.  I have the parts. In a few weeks, if time permits (between work and our ailing Beagle, time is tight right now), I should have some sort of result.

Block Occupancy Detection for DC and DCC, Part 1

Block occupancy detection is central to advanced layout control. Without it systems like control panels, signals or animation that depend on knowing the position of your trains can’t function. If my concept of building a layout around a network of Arduino boards and off-the-shelf peripherals is going to work, it has to be able to do block occupancy detection.

A Control Panel made with JMRI

A Control Panel made with JMRI PanelPro

As it turns out, block occupancy detection is possible and economical (in terms of equipment cost) with an Arduino and some sensors. In this post I’ll talk about and demonstrate what I’ve learned so far about the electronics of block occupancy detection.


Block occupancy detection can be accomplished a number of ways. The simplest methods involve installing trigger points that detect a passing train using optical or magnetic sensors. These methods generally only work with moving trains, and can’t detect stationary objects located on the tracks between trigger points.

Detecting Current Flow

Enter current sensing, the block detection method most closely tied to the electronic function of the layout. The idea behind sensing current for block occupancy detection is simple enough: current should only flow across the rails in a block that has a locomotive or other device (such as rolling stock with lights or a sound car decoder) on it.  If current flows, the block is occupied; if not, it is (or should be) clear.

How Current is Sensed

Digitrax BDL168 Detection Unit

Digitrax BDL168 Detection Unit

 

Current sensing is generally done indirectly, to avoid drawing on the current (more of a problem in high voltage applications than for a model railroader) and to enable sensors to operate at a different voltage/current from that being sensed. Early commercial block detection systems used  induction coils to sense current passing through wires wrapped around the coil. Newer systems tend to be hybrid or solid-state, reducing size and power consumption. The majority are optimized for DCC and few systems claim to work in DC.

RRCirKits Detection Coils

RRCirKits Detection Coils

To put it another way, there is no block occupancy sensor device on the market with a generic analog or digital output that could be directly read by a general purpose computing device, such as an Arduino. For that matter, I could not identify a single BO system that could easily interconnect with a system from another manufacturer. There aren’t any real standards in this area.

Current Sensing, the Arduino Way

The Allegro ACS712 chip is a leading solid state current sensing solution for power feeds up to 30 amps.  Its works using a phenomena called the “hall effect” to indirectly detect current flow through a silicon chip. The output of the ACS712 connects to an analog port on an Arduino board (or any other microcontroller/microcomputer that supports analog sensing). Connected to an Arduino, a call to analogRead() gives you the output of the sensor.

ACS712 Board

ACS712 Sensor Board

As is usually the case, the chip requires a few external components to function properly; primarily connectors and a filter capacitor/resistor combination to fine tune the sensitivity of the device.  As it happens there is a robust market for simple ACS712 sensing boards, resulting in prices under $2 per sensor if you buy directly from a Chinese source on Ebay, or Alibaba. Even on Amazon.com, sensors can be purchased for about $7 each with Prime 2-day shipping, which makes them slightly cheaper per block than sensors for the most cost-effective systems specifically marketed for DCC.

The only issue I’ve seen with these open market sensors is that there is no specific standard for the filter capacitor. Accordingly, different batches of these boards may have a slightly different sensitivity which would have to be accounted for in the software. As you’ll see, that is not nearly as big a deal as it sounds.

For now I think the optimal strategy for anyone trying to install a block detection system with these components, is to buy all the ones you will need (plus a few extra) in a single batch from a single source. At $2 a pop from China, it makes sense to buy in bulk. In my experience that will guarantee they are all tuned the same way.

DC and DCC Ready

It’s more important for model railroaders that the sensor functions equally well with alternating and direct current. The only difference in the way the sensors work as a system in DC versus DCC comes from the fact that in DC track power is used to control trains; an occupied block may have no power at all for control reasons. That could throw a block occupancy detection system off.

Any current sensing system for DC has to account this; as should any DCC friendly system that wants to preserve block occupancy information between track power outages (such as caused by a short circuit on the track).  We’ll get to solving that problem in the next post.

Plug and Read . . . Not!

I should tell you that if you plug in a sensor and try to determine current state with a single reading…. well, you’re going to be disappointed.  Individual readings seem to jump around a lot although you can discern trends in either direction.

Alternating current presents the additional problem of sensing a current flow that reverses polarity; at any given moment the power could be anywhere in its cycle, including 0 volts at polarity transition. For AC, multiple samples taken at a frequency that is greater than the frequency of the power cycle is required. Something like 8 – 12 samples per cycle will allow proper detection of AC current. Multi-sampling helps with DC too.

First, Calibration

Different sensor chips will produce slightly different analog readings under the same conditions. Any differences in filter capacitors between boards will also produce different readings, as will any +/- variation from 5 volts supplied as Vcc to the chip. To deal with these differences and actual power conditions, we have to calibrate each sensor on startup.

What we need to know is the output of each sensor when there is no current flow (no load); we’ll call this condition adc-zero. The difference between sensor output and adc-zero represents the current sensed by the device.

Getting an accurate number for adc-zero requires averaging a large number of quick readings — 5000 seems to be optimal — like this (we call adc-zero the “quiescent voltage” output):

long VQ = 0;
//read 5000 samples to stabilize value
for (int i=0; i<5000; i++) {
   VQ += analogRead(PIN);
   delay(1);
 }
 VQ /= 5000;
 return int(VQ);

With that number calculated for each sensor, we can get  consistent readings across multiple sensors.

Sampling Current

Reading current consistently requires a multi-sample approach over a defined time span. For this demonstration we’ll accumulate 250 samples taken over a 100 ms span on each read cycle.

Alternating current drives you to calculate the Root Mean Square of the data to filter polarity shifts and get a very stable mean current value you can work with.  Not only does this work well with A/C, it also is equally helpful in getting stable readings of DC current because the output of the sensor varies over time [for the hardcore math and theory, see the Wikipedia page].

Its an easy formula to translate into a computer algorithm, using a function like this :

float readCurrent(int PIN, float adc_zero)
{
  float currentAcc = 0;
  unsigned int count = 0;
  unsigned long prevMicros = micros() - sampleInterval ;
  while (count < numSamples)
  {
    if (micros() - prevMicros >= sampleInterval)
    {
      float adc_raw = analogRead(PIN) - adc_zero; // Electical offset voltage
      adc_raw /= SENSITIVITY; // convert to amperes
      // accumulate sum of the squares of converted raw data
      currentAcc += (adc_raw * adc_raw); 
      ++count;
      prevMicros += sampleInterval;
    }
  }
  // calculate the root mean square of the data set
  float rms = sqrt((float)currentAcc / (float)numSamples);
  return rms;
}

Finally, we have to use the rms values to determine whether or not a block is occupied. For the purposes of this demonstration, I’m using a hard rms threshold of .0259 (the adc-zero rms is about .021 on the sensor used for the demonstration); I’ll adopt a different approach when I scale up to a multi-block arrangement.

To further smooth the sketch response, it averages each reading with the previous one. Here is the key code that determines if a block is occupied:

  prev_current = current; // save last reading
  current = readCurrent(currentPin, adc_zero);
  avg_current = (current + prev_current)/2;
  occupied = avg_current > occupancy_threshold;

So lets put the whole journey to this point together in a video demonstration. This demonstrates current sensing in a DC context:

Here’s the sketch in its entirety:

// Advanced Sensing with ASC712
// Using Calibration to find sensor 0
// then sensing by compiling multiple readings to obtain an RMS (Root Mean Square).
// Derived from these forum posts: https://forum.arduino.cc/index.php?topic=179541.0
// NOTE: Forum posters did not account for device sensitivity
///////////////////////////////////////////////////////////////////////////////////
const int currentPin = 0;
// Sampling Parameters
const unsigned long sampleTime = 100000UL; // sample over 100ms
const unsigned long numSamples = 250UL; // the number of samples divides sampleTime exactly, 
                                        // but low enough for the ADC to keep up
const unsigned long sampleInterval = sampleTime/numSamples;  // the sampling interval
                                         //  must be longer than then ADC conversion time
#define SENSITIVITY 185  // from ACS712 data sheet for 5A version, in mV/A
int adc_zero;  // variable to hold calibrated sensor quiescent voltage

boolean occupied = false;
float occupancy_threshold = .0259;

float current = 0;
float prev_current;
void setup()
{
  Serial.begin(9600);
  Serial.println("\nACS712 Current Sensing Basic Demonstration\nMultiple Readings converted to RMS at 1 second intervals\nValues for quiescent output are determined by Calibration.\n\nCalibrating the sensor:\n");
  adc_zero = determineVQ(currentPin); //Quiescent output voltage - the average voltage ACS712 shows with no load (0 A)
  delay(1000);
}

void loop(){
  float avg_current;
  prev_current = current;
  current = readCurrent(currentPin, adc_zero);
  avg_current = (current + prev_current)/2;
  occupied = avg_current > occupancy_threshold;
  
  Serial.print("Current Sensed:");
  Serial.print(current * 1000 ,1);
  Serial.print(" mA\t\t");
  Serial.print("The block is ");
  if(occupied){
    Serial.println("occupied");
  } else {
    Serial.println("not occupied");
  }
  
  delay(1000);
}

int determineVQ(int PIN) {
  Serial.print("estimating avg. quiscent voltage:");
  long VQ = 0;
  //read 5000 samples to stabilize value
  for (int i=0; i<5000; i++) {
    VQ += analogRead(PIN);
    delay(1);//depends on sampling (on filter capacitor), can be 1/80000 (80kHz) max.
  }
  VQ /= 5000;
  Serial.print(map(VQ, 0, 1023, 0, 5000));
  Serial.println(" mV");
  return int(VQ);
}
float readCurrent(int PIN, float adc_zero)
{
  float currentAcc = 0;
  unsigned int count = 0;
  unsigned long prevMicros = micros() - sampleInterval ;
  while (count < numSamples)
  {
    if (micros() - prevMicros >= sampleInterval)
    {
      float adc_raw = analogRead(PIN) - adc_zero; // Electical offset voltage
      adc_raw /= SENSITIVITY; // convert to amperes
      currentAcc += (adc_raw * adc_raw);
      ++count;
      prevMicros += sampleInterval;
    }
  }
  //https://en.wikipedia.org/wiki/Root_mean_square
  float rms = sqrt((float)currentAcc / (float)numSamples);
  return rms;
}

Next installment, we go to the next level: multiple blocks and adding signals to the mix. And I’ll demonstrate everything in both DC and DCC.


 

Chasing Electronic Gremlins

I built the test loop for a couple of reasons. First I needed to revive my long unused track laying skills. Second, I needed a place to test and repair locos and rolling stock. Third, and perhaps most importantly, I needed to learn how to deploy Arduinos on a layout in a bullet-proof sort of way, before investing time and money building the main layout.

If you’ve been following along, you know that lighting is one of my big challenges in building the layout in the chosen location. The soffits above the bar are a thin skin of paneling, with little structure supporting it, hiding HVAC duct-work. Standard light fixtures are not possible here.

Addressable RGB LED Strip

Addressable RGB LED Strip

That constraint started a search for a lighting solution that was light enough to affix to the paneling with 3M Command Strips, but would produce enough light to effectively light the layout. When I found strip ALEDS, I knew I’d found a solution. The first two light bars I made are demonstrated here (a simple light show accompanied by a little Debussy):

The bars are easy to create.  Mine are sized at 26″ long; the right size to both light from above and install on the underside of the top level of the layout to light the lower level.

To make them I split 1/2″ PVC pipe on a table saw, then cut the pipe halves to length [TIP: PVC pipe from your home store is dirty stuff. I clean the cut halves with denatured alcohol before final assembly]. I attach 1/2″ reflective Mylar tape to each inside half of the pipe (creating a reflector), leaving a strip of bare PVC down the center of the pipe.  A bead of Liquid Nails for Projects down the middle holds a prepared (with JST 3 wire connectors at each end) 38 LED strip.

My standard RGB LED light bar.

My standard RGB LED light bar.

The demo above shows two bars chained together. You can keep lengthening the array by adding additional bars, at least until you reach the limits of your power supply.

Not So Fast

I have to admit that when I made and tested 4 bars together (152 LEDS), I was  disappointed with the amount of light I was getting. It was good, but just not quite enough.  Two more bars (228 LEDS) ought to do it I thought.

What I got when I expanded the array to 6 bars was a very obvious light intensity drop off (and resulting color change, since these are RGB LEDS) from the beginning to end of the array. Nowhere in the information I’ve assembled about ALEDS has there been any mention of this problem.  I got out the multi-meter and, sure enough, the supply voltage drops steadily as you progress along the strip; and the greater the total number of ALEDS chained together, the more pronounced the effect throughout the strip.

Well, I’m a model railroader and I know all about resistance and current drop off; this is our classic problem of current loss over long runs. The solution? A 16Ga supply bus that injects current every two bars.

Light Controller and Bus Bar

Light Controller and Bus Bar

Head end of the lighting bus bar.

Head end of the lighting bus bar.

A strip of plywood provides the mounting surface for the required capacitor near the first LED, the bus wire (I CA’ d it to the wood) and circuit board fragments with with PCB screw terminals.

The test loop under lights.

The test loop under lights.

Problem solved.

Booting a Loaded Arduino

The basic reliability of the Atmel platform used by Arduino boards is impressive. So when I started seeing boot problems, I was puzzled.  In all cases, the problem occurred on initial power up; rebooting the affected board by hitting the reset button solved the problem.

This was not a good development.

My first three loaded up Arduinos are installed on the Test loop, Lighting Control and the Control Panel.  All three have an Ethernet Shield and are attached to additional devices. All three evidenced cold boot problems in one form or another.

It had to be a power problem.  The additional load from the Ethernet Shield and other devices (although, in most cases I supply power to attached devices separately so they don’t draw from the Arduino’s limited current handling capacity) had to be the issue. One of the confusing things about UNOs is that you can power them from USB at 5 volts DC, or from a separate DC power supply at 7 – 12 volts.

Umm, how much power should I be supplying?

Enercell Power Supply

Enercell Power Supply

In the context of the control panel, where an UNO has an Ethernet shield with multiple digital and analog connections to the touchscreen, I found that I need to supply 12 volts.  At that level the rig is 100% reliable, something I easily established with the help of an adjustable power supply. The trade-off with the control panel, because everything is enclosed, is heat buildup, requiring a fan I didn’t originally plan for.

New deployment rule: the standard power supply for Arduino boards with built-in voltage regulators (primarily UNOs and MEGAs on this project) will be 12 volts DC. Connected devices will run at the standard logic 5 volt level. Smaller Arduino boards without a voltage regulator will get 5 or 3.3 volts DC as required.

Modified Computer Power Supply

Modified Computer Power Supply

I use converted computer power supplies with simultaneous outputs at 3.3, 5 and 12 volts DC, so my layout bus has all three feeds.

It may not seem like it, but that is progress.

Powering Up In Order

Unlike the control panel, the lighting controller did not settle down with a 12 volt supply. There, the Ethernet Shield would go into an initialization loop (attempting to start up and failing, over and over) on power up — but would work fine after a hard reset.

On the test loop, the problem was even subtler: upon cold power up everything appeared normal and the sketch would start to execute…. then freeze at the point where it is supposed to send a broadcast message across the network.

It had to be something about power again that manifests only on a cold start, but what? Faulty Ethernet shields?

Here the clue was a little warning from Adafruit about neopixels (ALED strips): always make sure the power supply to the strip is on before the data connection from the Arduino goes live, or the strip could be damaged.

I always figured that if the Arduino and the ALEDS (and other peripheral sensors and actuators) were powered from the same source and came on simultaneously, Adafruit’s warning would be satisfied.  Since I’ve never had damage to the strip, and I’ve been working with the same strip for some months now, I think technically I was right.  However, it seems that from the Arduino side, simultaneous start up is not necessarily so blessed, especially when attached to an Ethernet shield.

I conducted a simple experiment on the lighting controller:  I unplugged the power from the board/shield combo then powered up the ALEDS before plugging the power into the board.

BAM. Worked perfectly every single time. No confused Ethernet shield; perfect response to commands; no hitting the reset button.

Of course, manually plugging a fleet of embedded Arduino boards was not going to do at all.

Automating Power On Delay

Consulting the Internet Machine, I found a simple power-on delay circuit.  In my first attempt I built it as shown, except for substituting a variable resistor for R2 (on original schematic) to allow some adjustment of the delay.  For the relay, I chose a low power signal type — adequate for the power draw of the Arduino/Shield, but possibly not sufficiently durable for this application. Only long term experience will tell.

Anyway, as built it provides about a 50 – 100 millisecond delay in powering on the board. That turns out to be enough.  With the delay circuit attached, the lighting controller powers up perfectly every time.

I modified the circuit slightly for my second build, including both input and output indication LED’s [ green for input power on, and blue for output power on. ] and increased the size of the capacitor to 100µf. The bigger capacitor gives a little more time range to the delay (as adjusted by R4; if you go out of range either direction on R4, the circuit will not work.) from about 1/10th to 1/2 second. The I/O LEDs really help see the timing of the delay.

Here’s schematic of the board as I’m building it now:

Power-On Delay Circuit Schematic

Power-On Delay Circuit Schematic

Built on one quadrant from an SB4 Snappable Breadboard (these are my go-to, two sided solderable breadboards), the top looks like this:

 

Power-on Delay Circuit Top

Power-on Delay Circuit Top

And, the bottom:

Power-on Delay Circuit Bottom

Power-on Delay Circuit Bottom

Installed on the test loop and in operation:

Uno, Ethernet Shield and Power-on- Delay board.

Uno, Ethernet Shield and Power-on- Delay board, mounted under the Test Loop.

From here on, power on delays circuits are another standard component for reliable operation, though I think I’m going to double the size of the resistor on the blue led to tamp down its brightness more!.


 

A Programmable Layout Controller

Programming an Arduino to run turnouts, lights or animation on the layout is only part of the challenge. The other part is how do you control the board and tell it what you want it to do?

Servo Control with LED Feedback

Servo Control with LED Feedback

From an Arduino point of view, any sensor attached to a pin can trigger action in a sketch. As shown in Turnout Control with Arduino & Servos, mechanical buttons and switches can be attached to pins to tell the board what to do. In the example circuit, a single button triggers servo action. If you want to include feedback indicators as in this example circuit — these could be layout signals or panel indicators — you can hard-wire everything together to the same Arduino board.

Until you run out of pins

Pin management is critical as you ask the Arduino to do more and more. Every new sensor or triggering device consumes pins (as does every new actuator or output device). While learning what I could do with an Arduino on the layout, I realized that I needed get beyond the hardwired controls used in experiments and demos to a generic, software-based control system. To do that I was going to have to network everything together.

Networking Arduinos

Uno with Ethernet Shield

Uno with Ethernet Shield

In Roundhouse Rebuild Part 2 I mentioned, without explanation, that I was using Ethernet, and went on to discuss the evolving Simple Network Command System. I decided to go with wired Ethernet because of the easy availability of inexpensive Ethernet shields based on the WIZnet W5100 Ethernet Controller chip (under 10 dollars per shield), and an easy to use Arduino library included in the IDE. It is as close to plug & play as networking gets on an Arduino. The only additional equipment required are one or more inexpensive 10/100 switches (for example: TP-LINK TL-SF1005D 5-port 10/100Mbps Desktop Switch; don’t get gigabit switches to work with these shields, you’re just asking for trouble) to  interconnect the devices. I use a per-device assigned address system which helps keep the equipment roster simple (no router or DHCP required).

Why not just use the Digital Command Control system for the Arduino net? The short answer is that while it is clearly doable, for the purposes of this project I am going to keep the Arduino net separate because:

  1. Everything I do here has to work for both DC and DCC layouts. I own both DCC and unconverted DC locomotives; the layout has to work the same in either mode.
  2. Compared to conventional networking, DCC is a relatively difficult way to conduct bidirectional communications between Arduino boards.
  3. Keeping them separate does not preclude enabling communication between the two systems down the road.

If you want to pursue DCC communication and Arduino, the Model Railroading with Arduino site is a great place to start. The biggest impediment for most modelers will be the lack of commercial interface hardware to connect an Arduino to either track power or the command bus (although the circuits are easy enough to build); the closest commercial solution would be to use a USB interface, like the Digitrax PR3XTRA USB Programmer, RR-CirKits LocoBuffer-USB or the SPROG II USB, to tap into the DCC command system just as you would with JMRI.

My ultimate goal is to build the layout’s electronic and mechanical foundation around a network of Arduino boards. For communication among Arduino boards, Ethernet makes the most sense right now because it is the most “frictionless” route to achieve my goals (a wireless form would be even better, but would be a little more difficult to implement, so I’m holding that option for the future); communication between the Arduino net and the DCC system is a topic for the future—and the possibilities go way beyond treating Arduinos as decoders.

Building The Controller

2050-04

Adafruit 3.5″ TFT screen displaying a bitmap.

The concept for a prototype controller was simple enough: start with an Uno, add an Ethernet shield and add a small touchscreen for display and user input. Put it all in a box with an Ethernet jack, a USB jack and power connector. Software generates screen displays, interprets touches and communicates with devices it is controlling.

For the screen I chose the Adafruit 3.5″ TFT Touchscreen, seen here attached to an Uno via a breadboard (NB: The wiring shown is the minimum required to run the screen; the touch overlay and the SD Card reader require additional connections). It is capable of full 16bit color with a resolution of 320 x 480 pixels. The Adafruit library provides basic graphic primitive functions, basic text functions and bitmap functions allowing image display. It has a resistive touch overlay. Adafruit has an excellent tutorial on using this screen with their library.

Back of 3.8" TFT Screen

Back of 3.5″ TFT Touchscreen

The screen comes with a choice of interfaces: you can use the SPI bus interface in order to use the fewest pins on your Arduino, or you can devote more pins to use the faster 8 bit interface. You select the interface and solder the header pins on the appropriate side.  A  solder jumper on the back determines which interface is active; the decision is reversible. An SD Card reader is included for convenient storage of bitmap files.

On an Uno, the Ethernet shield dictates that the TFT screen has to be run via SPI; there aren’t enough pins otherwise. The application does not require the SD Card Reader so I don’t connect it to the UNO.

I fabricated a wiring harness for attaching the screen to the Uno\Ethernet combo, then mounted everything in a Radio Shack project box as shown below.

Wiring Harness

Wiring Harness

The connectors on the wiring harness are male or female PCB Headers; I solder the wires to the PCB side of the fittings, then cover each connection with heat shrink tubing. White wires connect to digital pins 7 through 13 (except 10, which is reserved for the Ethernet shield) and are for the TFT interface. Green wires are for the touch overlay and connect to Analog pins A2 – A5. Red supplies 5v, and black ground, to the TFT screen. The Ethernet extension cable and the USB extension cable both came from Adafruit.

Inside the Controller

Inside the Controller

Controller with Screen Wiring Attached

Controller with Screen Wiring Attached

 

 

 

 

 

 

 

Here it is in operation:

The Programmable Controller

The Programmable Controller

 

 

 

 

 

 

You may have guessed the fan ( on the left side ) was an afterthought. The cheap Ethernet shields I use are heat sensitive; they will crash when put in a confined space with poor air circulation.  Out in the open no problem; in a box, its a problem. Found that out the hard way. So I added a little fan to pull the air through the box (if you look closely, you’ll see there are holes around the bottom); works fine if noisily. Obviously, I will plan for air circulation when I build the main layout control panel. Such is prototyping!

What it Does

The controller sketch displays menus with buttons that, when touched, will cause the controller to either go to a different menu or send a command packet to the target device. Command packets are strings, formatted thus: function / option / data. For more about my protocol and the network polling process, see the Simple Network Command System section near the end of Roundhouse Rebuild Part 2.

The Main Menu provides access to sub-menus that I’ve created to support parts of the project.

Controller Main Menu

Controller Main Menu

All menus are built with buttons. A structure type called button_t holds button data:

typedef struct {
  int x;
  int y;
  int txtX;
  int txt;
} button_t;

X and y are the coordinates of the upper left corner of the button; the width and height are the same for all buttons in this version of the system. txtX is the x coordinate for the button text; the y coordinate is calculated and there is no text centering function. Finally, txt is an offset into a button_labels array pointing to the button text.

For the main menu, the button set definition looks like this:

const button_t buttons_main[SIZE_MAIN_SET] = {
  {90, 80, 115, 0 },
  {250, 80, 254, 1},
  {175, 140, 185, 16}};

Determining if a button has been touched is fairly straight forward. The coordinates of a touch p are compared to each button, as b, in the current set to see if it is on or within the button boundaries.

p.x >= b.x && p.x <= (b.x + BUTTON_WIDTH) && p.y >= b.y && p.y <= (b.y + BUTTON_HEIGHT)

Whacking My Head on the Memory Ceiling

The graphics libraries contain a lot of code. With the newest Arduino IDE, the controller sketch compiles to 27,030 bytes, about 83% of available program space; it was about 29k bytes with the previous IDE.

That is still tight enough that I cannot include SD Card access and a function to draw a bitmap from a file without going 15% over the absolute memory limit for an UNO. In the future I’ll use an Arduino MEGA 2560 Board instead of an UNO for control panel applications because of its vastly superior memory resources (and it has a lot more pins to work with). The remaining 17% with the current sketch gives me plenty of room for now.

The trickier bit of memory management is “dynamic memory,” which (on an UNO) is 2,048 bytes of shared memory space used for local variables. Local variables are created when functions are called and destroyed when they are exited. Global variables–variables declared outside of any function that are always in scope and available wherever you are in your sketch–are also stored in the same space. Global variables reduce the amount of dynamic memory available for local variables and, if not managed, can strangle your sketch.

Fortunately, the majority of global variables turn out to be constants — unchanging values or text used by the application. This kind of data can be stored in the program space instead of dynamic memory; the limitations are that

  • you can’t change the value stored in program space while the sketch is running, and
  • you have to copy a value from program space to dynamic memory in order to use it.

The PROGMEM keyword is used to tell the compiler to store something in program space instead of dynamic memory. To park menu titles and button text in program space, I did this:

const char mstr_0[] PROGMEM = "Main Menu";
const char mstr_1[] PROGMEM = "Lighting Menu";
const char mstr_2[] PROGMEM = "Roundhouse Menu";
const char mstr_3[] PROGMEM = "Test Loop Menu";

const char* const menus[] PROGMEM = {mstr_0, mstr_1, mstr_2, mstr_3};

const char str_0[] PROGMEM = "Lights";
const char str_1[] PROGMEM = "Roundhouse";
const char str_2[] PROGMEM = "<-Back";
const char str_3[] PROGMEM = "  Night";
const char str_4[] PROGMEM = "   Day";
const char str_5[] PROGMEM = " Mid-Day";
const char str_6[] PROGMEM = " Sunrise";
const char str_7[] PROGMEM = " Sunset";
const char str_8[] PROGMEM = "   Low";
const char str_9[] PROGMEM = "  High";
const char str_10[] PROGMEM = " Stall 1";
const char str_11[] PROGMEM = " Stall 2";
const char str_12[] PROGMEM = " Stall 3";
const char str_13[] PROGMEM = " Stall 4";
const char str_14[] PROGMEM = " Stall 5";
const char str_15[] PROGMEM = "Afternoon";
const char str_16[] PROGMEM = "Test Loop";
const char str_17[] PROGMEM = "Main";
const char str_18[] PROGMEM = "Siding";
const char str_19[] PROGMEM = "Occupancy";

const char* const button_labels[] PROGMEM = {str_0, str_1, str_2, str_3,
 str_4, str_5, str_6, str_7, str_8, str_9, str_10, str_11, str_12,
 str_13, str_14, str_15, str_16, str_17, str_18, str_19};

Copying the title of the main menu into a local variable text looks like this:

strcpy_P(text, (char*)pgm_read_word((&menus[0])));

For getting the button labels:

 strcpy_P(text, (char*)pgm_read_word((&button_labels[b.txt])));

An alternate way to store static data in program memory is to use the F macro, as in this declaration of a local variable that initializes with a static value that is stored in and retrieved from program memory:

String readyStr = F("Ready");

At this point I find it useful to make it a habit to use these tools in all sketches to tame dynamic memory space. Currently the controller sketch uses only 771 bytes or 37% of dynamic memory for global variables, leaving plenty of space for locals.

Menus

The Lighting and Roundhouse menus look like this:

lighting_menu

Lighting Menu

 

Roundhouse Menu

Roundhouse Menu

These are the controls I used off screen to control lighting when making the Roundhouse demo video. Overhead lighting was supplied by 4 led light bars (152 RGB ALEDS total) controlled by a networked UNO.


I’ve been busy at the test loop trying out various ideas.  Turnout control, signals and block occupancy detection (I have a method that works for both DC and DCC layouts), all play a part in the next step toward the layout. I’ll leave you to ponder the test loop menu until next time.

Test Loop Controls

Test Loop Controls

 


 


 

Model Railroader, Meet Arduino

I was not even slightly surprised when I opened the December 2014 Model Railroader Magazine, to encounter “RFID for Model Railroad Operations.” There seems to be considerable interest in RFID among model railroaders, enough that there is JMRI support available, and this project looks like a particularly nice piece of work.

The illustrations caught my eye and I recognized that at the heart of their system is an open source microcontroller board called the Arduino Uno.

Arduino Uno R3

Arduino Uno R3

You have to know what you are looking at, or dig into the article to get that bit of information.  A one sentence editor’s note explains that Uno’s are “simple computers that can be programmed to do many useful model railroading tasks.”

Oh, my.  That’s no way to introduce a hobby to a new dance partner. We’ve met once before in the June 2013 Model Railroader Magazine article “High Tech Turnout Controls.” But everyone was a little shy back then, there was really not enough information about the new partner to truly understand its potential. Referring to unseen computer code that has to be compiled and uploaded was probably a bit frightening to some. And, I suppose it didn’t help that the servo installation presented was, shall we say, a little too utilitarian.

No matter. Lets start over and get the introduction right this time, because the dance has already begun!

What is a Microcontroller?

Microcontrollers are integrated circuit chips that have the basic logic and input/output capabilities that constitute a simple computer. Microcontroller boards place that chip with a few essential external components on a board with power and ways to plug things in. Microcontrollers have been around for a long time; you’ll find them in almost everything electronic.  What’s new is how inexpensive the chips and supporting components have become.

The best known, and by far best developed open source microcontroller board system is the Arduino Project. In their words:

Arduino is a tool for making computers that can sense and control more of the physical world than your desktop computer. It’s an open-source physical computing platform based on a simple microcontroller board, and a development environment for writing software for the board.

Microcontroller boards like Arduino are simpler than microcomputers like the Raspberry Pi or the Beaglebone.  Aside from differences in the controller/processor used, the big difference is that microcomputers come with more peripheral components and memory to allow them to load an operating system.  You don’t generally use an “operating system” with a microcontroller: rather the board is designed to run whatever code you’ve loaded in the board’s permanent memory. In essence, your program is the firmware/operating system for the board.

The Arduino interacts with the physical world using sensors and actuators. Sensors can be anything that responds to an external influence:

  • buttons and switches,

    micro button

    Micro Push Button

  • optical sensors, such as photoresistors, IR/UV and so on,
  • current and voltage sensors,
  • touch and proximity sensors,
  • RFID sensors,
  • GPS and other position sensors, include tilt and acceleration,
  • USB and various kinds of network communications,
  • anything that can produce a 0-5v current to signal its state, either as an on/off (digital) signal, or as a variable current (analog).
Combination accelerometer, Gyro and Magnetometer

Combination accelerometer, gyro and magnetometer

Sensors can be a single chip/component, or another board or external assembly that communicates with the Arduino.

The code you upload to the Arduino can read the sensors and take logical actions based on those readings.  It takes actions by controlling actuators. Actuators include:

  • AC/DC motors,
  • servos & steppers,
  • switches, relays, transistors and other current amplification and modulation devices,
  • LCD’s, LED’s, OLED’s both individually and in arrays up to and including small screens,
  • USB and various kinds of network communications.
Adafruit TFT Touchscreen

Adafruit 3.8″ TFT Touchscreen and an Uno

Adafruit Industries has the above touchscreen, along with a lot of other cool sensor and actuator devices to use with Arduino.

Stepper motor.

Stepper motor.

The basic structure of an Arduino sketch (program) is a continuous loop that checks the sensors and acts as required. Depending on the complexity of the sketch, the basic sense/act loop can cycle hundreds or thousands of times per second. Since you are directly interacting with the hardware without an operating system, your sketch has fairly precise control of all interactions.

 

Programming?

The Arduino is a teaching and learning tool.  If you don’t know anything about computer programming, this little board was designed for you! You don’t really have to know C++ (the language used by the development tool) as such; you just have to learn and follow the basic rules as applied to the Arduino, all laid out in the tutorial system. If you can do basic math and logic, you can learn this.

If anything, novices may have an advantage over folks who program larger and more complex systems–who may have to rethink a few habits to adapt to the limits of the Arduino. The Arduino IDE hides most compiler preprocessing, which is great for newbies and lousy for those used to having total control of the preprocessing/compiling process.

Lets take the basic use case–turnout control–as discussed in the June 2013 MRR article. I’ve done a little Q&D on the basics of setting up and using a servo for turnout control; take a look to see what the code looks like. It’s a lot more straightforward than you might expect.

But What’s it For?

So turnout control is one use, but it may not be entirely clear why this is better than traditional turnout motors and wiring. From my point of view, it comes down to leverage: getting a lot more functionality for the money.

Given that a single Arduino Uno ($25) can support multiple micro servos costing $2 – $4 each, its easy to see how an Uno running 4 turnout servos is saving money; even more if one Uno can manage an Yard full of servos. Other functions that might be handled by accessory contacts on an expensive turnout machine can be handled easily by the Arduino at the same time, like running signals, managing track power relays or triggering other systems. As you stack related functionality onto a network of Arduinos, instead of investing in multiple single-purpose systems, the combined enhanced functionality and cost savings of this approach becomes quite compelling.

Among model railroaders on the web who are working with Arduino, the most common thread I’m finding is to use the Arduino as an adjunct to the DCC system. An obvious approach is to use a stationary decoder as a “sensor” that the Arduino responds to with whatever task you have in mind — for instance, this would work well where the Arduino is an animation controller.

To get an Arduino and DCC system to communicate with each other without a decoder, you could use the generic USB interface, which most Arduino boards and many DCC systems support. Since DCC systems don’t speak Arduino, something like JMRI is needed to glue it all together.

Others, like the Model Railroading with Arduino project, an off-shoot of the Open DCC Project, are working on direct Arduino/DCC interfaces. It’s pretty straight forward to interface an Arduino with the DCC command bus. Check out this project using an Arduino Mini to create a 17 function DCC decoder. As to the unreasonably low price the author reports for his Arduino Mini Pro, please see this post about Arduinos, compatibles and counterfeits. If you find these things useful and want the benefits of further development, then you should care about the ecosystem. An official Mini Pro from SparkFun lists for $9.95. and a portion of its proceeds are given back to the Arduino Project.

Controlling turnouts with servos and an Arduino, RFID decoding or even creating a “programmable DCC decoder” using an Arduino represents a small fraction of the potential of these devices. The trend today seems to be toward greater centralization of model railroad control systems. Embedded microcontrollers can be a step down that road as well, adding considerable functionality as “decoders with brains”; or they can take you in an entirely different direction–where semi-autonomous logic devices controlling different aspects of the layout interact with each other and with the operators in dynamic ways.

I’ll give a little more substance to these ideas as this project progresses.