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.