C++ Objects for Layout Control, Part 1

The programming language supported by the Arduino IDE is C++, an object-oriented super-set of the C language (one of the fundamental languages of the computer programming world). This post is geared to newbies who have little or no previous experience with object-oriented programming. Experienced hands can skip past the basic explanations and see what I’m doing with it in a practical example.

Object-oriented programming (OOP) allows the programmer to conceptualize and write software in a way that is less like how the machine runs it (a list of instructions) and more like how humans think (objects, abstractions, relationships, etc.). Of course, you still have to write specific procedures, but they are placed in context within a software object. Don’t worry if this doesn’t make sense yet.

Without going into the more exotic aspects of OOP theory (we may get to some of those eventually, but not today), the point of OOP is to create the software equivalent of a “black box”—something that you can give data to and get a result from without knowing anything about how it works internally. This makes code highly reusable, the second major point of OOP.

OOP and the Arduino IDE

The Arduino IDE is a simplified environment within which to write C++ code. You cannot create and edit the formal file structures of C++ (.h header files and .cpp implementation files) within the IDE. However, within the IDE you can include C++ OOP code in your sketch with minimal formalities, so its a good place to get to know C++ objects. Those who write in C++ (whether professionally or as a dedicated amateur) can include their own work by installing it as a library the Arduino IDE can compile and include.

Given the context, from here on I’ll limit myself to how to do things in the Arduino IDE. To find out more about formal C++, here is one of many sites devoted to the subject: http://www.cplusplus.com/doc/tutorial/


Consider the things you are trying to control around the layout; would it be easier to manage turnouts, signals or animated/lit things as C++ objects? I think you’ll agree that it would. Lets explore an example.

A Basic Animated Object

My turntable bridge includes an operator’s hut containing a small stove with a fire for warmth.

If you Google Arduino fire simulations, you’ll find all kinds of algorithms and methods for simulating fire with LEDS and an Arduino. This fire is intended as a low, banked fire; the kind that has a variable glow and occasional sparks with no flame; probably coal is the fuel. So I’m keeping it simple: a single red LED on a PWM pin, its brightness rising and falling over time with random bright flashes. To do that, the code has to track the state of the led and whether brightness is rising or falling, periodically increment or decrement the brightness within a defined range, and randomly go high brightness for one cycle to represent a spark.

A First Class

The code that defines an object and its implementation is called a CLASS. Begin with the keyword class, give it a name and setup a pair of curly braces and a trailing semicolon to contain the definition:

class fire
{
};

In the Arduino IDE we can do this exactly the same way we create a TYPEDEF to define a data structure: put it in the head of your INO file (the sketch) before you use it and before the setup() function.

Now then, we need some content for this class: what data does a fire object need to do its job? It needs the know the pin it will use, the low and high values for brightness it will use, and the rate or frequency of updates. In order to run, it has to also keep track of its own state and when it was last updated.

class fire
{
  private:
   int ledPin;
   int high;  // value for maximum brightness
   int low;   // value for minimum brightness
   int rate;  // update frequency in milliseconds

   bool dirUp; // true if brightness is increasing
   int state;
   unsigned long lastUpdate;  // in milliseconds; can be a big number
  
};

That looks like a bunch of variable definitions, right? Exactly; just like local variables within a function. By convention we refer to these variables as the properties of the object. The private keyword that precedes the properties tells the compiler that these properties can only be accessed from within the object. While you can make properties public and thus directly accessible from outside the object, you should not do that without good cause because it could break the integrity of the “black box”. In general, the best practice is to create a public method to retrieve a private property from outside the object.

Methods

In order to do something useful a class has to have methods, the OOP term for class internal functions. Public methods are accessible from outside the object and constitute the interface you use to manipulate the object. Classes can also contain private methods, accessible only from within the objects. All objects require a special public method called the constructor which is called once when an object is instantiated—an instance is created in memory and initialized.

The Constructor

The constructor is a public method, with the same name as the class.

 public:
 
 fire(int pin, int zhigh, int zlow, int zrate){
   ledPin = pin;
   high = zhigh;
   low = zlow;
   rate = zrate;
 
   state = low;
   dirUp = true;
   lastUpdate = 0; 
   analogWrite(ledPin, state);
 }

The constructor takes 4 arguments. Upon entering the constructor, the first step is to transfer argument values to the object properties. Then the method sets the initial LED state to low brightness, sets the direction of brightness change to up (increasing brightness), initializes the lastUpdate property and turns the LED on at the desired PWM level.

The Update Method

In addition to the constructor, the fire object requires a public update method that is called regularly to allow the object to update itself and its LED.

void Update(unsigned long curMillis) {
   if(curMillis - lastUpdate >= rate){
     lastUpdate = curMillis;
     dirUp ? state++ : state--;
     if(random(80) == 1){ // do a spark at random intervals
       analogWrite(ledPin, 255);
     } else { // otherwise write the updated state to the LED
       analogWrite(ledPin, state);
     }
     if(state == high || state == low){ //if at end of range
       dirUp = !dirUp; // boolean logic flip
     }
   }
}

The update method takes a single argument, the current “time” (since the program started) in milliseconds. The intention here is that this method will get called more frequently than absolutely necessary, terminating immediately if it is not yet time to update. Note that here I need to use the random() function to trigger the spark, but up to this point I have not seeded the psuedo random number generator. In the final sketch, I include a call to randomSeed() in the constructor so that each instance will reseed the generator when it starts.

You might wonder why the update method doesn’t retrieve the time value on its own. Efficiency is important when running a stack of simultaneous animations, or your sketch will bog down and perform poorly. The best practice is to retrieve the time value at the beginning of your main loop() then pass that value to each animated object to allow it to determine what it should do at that time value. This also gives the function calling the update methods some flexibility in allocating time among competing priorities (for example, favoring a high priority object over a low priority one). If the update methods are efficient everything runs smoothly.

Putting it All Together

Now that we have defined a CLASS, lets create some objects and see how it works.

To try this out, create a simple double LED circuit with an UNO and a breadboard, like so — I put the resistors on the cathode side as a matter of habit because I’m using common anode wiring everywhere; put them on the anode side of the LEDs if you prefer:

A simple double LED circuit on PWM pins 5 & 6. The 220Ω resistors are on the ground side.

Why two LEDs? We are going to further enhance the class by generating random values for the initial state and direction of the fire object. That, plus instantiating each object with slightly different parameters, guarantees that each fire instance starts and progresses differently. Once started, each instance will do its own thing.

Here’s the sketch (download from the github site):

///////////////////////////////////////
// CLASS fire
// A demonstration C++ class 
// for simulating a fire with LEDS
//
// Author: Robin Simonds, theNscaler.com
// License: CC BY-SA 4.0
// https://creativecommons.org/licenses/by-sa/4.0/
///////////////////////////////////////

class fire {
 private:
   int ledPin;
   int high; // maximum brightness 
   int low; // minimum brightness 
   int rate; // update frequency in milliseconds 
   bool dirUp; // true if brightness is increasing 
   int state;
   unsigned long lastUpdate; // in milliseconds; can be a big number

public: 
 fire(int pin, int zhigh, int zlow, int zrate){
   ledPin = pin;
   high = zhigh;
   low = zlow;
   rate = zrate;

   lastUpdate = 0;
   // seed the psuedo random number generator by
   // reading an unconnected analog pin
   randomSeed(analogRead(0));
   // randomize the starting state of the object
   state = random(low + 1, high);
   dirUp = random(2) == 1;
   analogWrite(ledPin, state);
 }
 // call the Update method frequently to run the animation
 void Update(unsigned long curMillis) {
   if(curMillis - lastUpdate >= rate){
     lastUpdate = curMillis;
     dirUp ? state++ : state--;
     if(random(80) == 1){ // a possible spark
       analogWrite(ledPin, 255);
     } else {
       analogWrite(ledPin, state);
     }
     if(state == high || state == low){
       dirUp = !dirUp; // boolean logic flip
     }
   }
 } 
};

// create global instances of the fire class
fire demo_fire1 = fire(6, 80, 20, 30);
fire demo_fire2 = fire(5, 75, 15, 35);

void setup() {
 // no setup currently needed
}

void loop() {
 unsigned long current_millis = millis();
 
 demo_fire1.Update(current_millis);
 demo_fire2.Update(current_millis);
}

When you run it, it should look something like this:

Want to do a two or three LED fire algorithm (maybe red with amber/yellow for more of flame effect)? Its just a matter of additional properties and additional instructions in the Update method to implement the algorithm. Give it a try if you are so inclined. You’ll see first hand how OOP can make code more reuseable and easier to modify. For animation with Arduino, OOP provides just the right framework to create and manipulate multiple animated objects of all kinds.

In part 2 of this post, we’ll tackle a common and more complex layout object: turnouts.

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!