LDR_Signals_RAG_Class: (LDR controlling Red-Amber-Green signals)
Include File <LDR_Signals_RAG_Class.h>
Constructor LDR_Signals_RAG_Class(sensor,red,amber,green) arguments how object wired
Public Methods begin(polarity) polarity = 1 for positive signals
polarity = 0 for negative signals
int train_over_sensor( ) returns 1 when train is over sensor
drive_signals(red, amber, green) 1 - turns signal on. 0 turns signal off
_________________________________________________________________________________________
Abstract/Summary: This HTML page will program will develop a class/library that uses a LDR (Light Detecting Resistor) to control the individual lights on a aspect signal (RED-AMBER-GREEN). The sample client code may be used as the basis for more complex signaling sequences.
Possible Audience: Hobbyists who have an interest in micro-controller hardware for model trains and/or have an interest in C++ programming. The example program will develop a class that inherits the LDR_Sensor_Class.
Keywords: C++ Class/Library, Cpp Inheritance, instances/objects, scope resolution operator
Components: Micro-controller with 4 I/O pins for each set of signals. 1 LDR, 1 RED, AMBER and GREEN LED for each light. Tested with Arduino NANO and 4 signals.
Required Software Libraries: LDR_Sensor_Class .
An earlier HTML page/project developed a library class Signals3_Class for 3 aspect signals (Red-Amber-Green) Train_Signals_Class. In that class the signals went RED when the train arrived over the sensor and then went through a fixed RED-AMBER-GREEN sequence when the train departed. This sequence was satisfactory for a model railway display but did not following conventional railway signaling where the signal would be set RED when a train was detected by the first sensor, it would go AMBER when the train cleared a second detector and finally go GREEN when the train cleared a further sensor some distance up the track.
This HTML page/project will develop a class/library that enables the three RED-AMBER-GREEN signals to be set individually. A later project will collate the information from several sensors and control the signals in the required sequence.
The project will develop a class/library LDR_Signals_RAG_Class where the client code can can read one sensor (eg on pin A0) and control 3 outputs (eg on pins 2, 3 and 4).
As illustrated in the circuit the design will be tested with 4 instances of the class.
For evaluation on the workbench the prototyping board was used. (Note the LDRs were physically too close to the GREEN Leds so were permanently low resistance (=no train). The solution was to limit the LED current by using 10Kohm resistors.
The firmware is developed using the Arduino IDE.
1. In the Arduino IDE create a new file/project. Either use the page with the folded corner in the tool bar or use File-->New
I have chosen to give the file the name/label LDR_Signals_RAG_Class to match the name of this page.
The Arduino editor will give it the extension *.ino
For this project this will be the Client or application code. It will be used to test the class but will not be part of it.
2. On the same page create two additional files LDR_Signals_RAG_Class.cpp and LDR_Signals_RAG_Class.h
Note they must both have the same name but they have different extensions.
To create these files click on the inverted triangle near the top of the IDE window and select New_Tab.
Give the name LDR_Signals_RAG_Class.cpp. Repeat for LDR_Signals_RAG_Class.h
3. The new class will inherit the class/library LDR_Sensor_Class. If that is not available in the contributed libraries the best (safest) solution is to reconstruct it.
(i) Open a new file with the label LDR_Sensor_Class and copy/paste the *.ino file from the page LDS_Sensor_Class_code.
(ii) Using the inverted triangle in the IDE create two new tabs and give them names LDR_Sensor_Class.cpp and LDR_Sensor_Class.h
(iii) From the page LDS_Sensor_Class_code copy/paste the files LDR_Sensor_Class.cpp and LDR_Sensor_Class.h.
(iv) Verify/compile the code - correct any errors due to embedded formatting characters.
(v) In your working directory (see File-->Preferences) under the sub-folder LDR_Sensor_Class use for example Widows Explorer to create a *.zip file of LDR_Sensor_Class.cpp and LDR_Sensor_Class.h.
(vi) In the Arduino IDE (any project) use Sketch--> Add Library -->Add *.zip library and select LDR_Sensor_Class.zip. The library can now be included in the LDR_Signals_RAG_Class project.
Copies of the *cpp and *.h files will now be in the work folder under the sub folder libraries/LDR_Sensor_Class.
The very basic starting code for the three files is shown below:
1. Both the *ino and *.cpp include the header file. ie #include "LDR_Signals_RAG_Class.h". Note quotes are used since the header file is in the same directory/folder.
2. Since the header file may be included from several source it is enclosed in the #ifndef (not defined).........#endif. Note the symbol LDR_SIGNALS_RAG_CLASS_H follows convention - File name in uppercase with _H.
3. The library will require the Arduino Library so the header is included at this stage. (Normal programs implicitly include "Arduino.h" - Library programs do not.)
This project will develop a new class LDR_Signals_RAG_Class where the LDR will control the RED-AMBER-GREEN signals. The class will inherit LDR_Sensor_Class. The first step is to include the library in the header file.
In the header file use sketch-->Include Library --> and select LDR_Sensor_Class from your list of contributed libraries.
2. In the header file define the class LDR_Signals_RAG_Class. Use the format shown to inherit LDR_Sensor_Class.
3. In the public area of the class define the constructor. It has 4 arguments - the pin containing wired to the sensor being monitored and the pins where the red, amber and green lights are wired.
4. In the private area 4 variables are defined. By convention these start with an underscore to highlight they are private and not available to external programs (including LDR_Signals_RAG_Class.ino).
5. In the implementation file the constructor is defined. In this example the first argument sen1 becomes the argument for the inherited library LDR_Siensor_Class.
All programs will require initialisation. In this example begin( ) will be used
As shown in the figure there are two possible types of lights:
Positive logic where to activate the light the input is pulled high, and
Negative where the input will pull the light low to activate.
Positive and Negative logic will require different code.
To let the program know what type of signal is required an argument POLARITY will be included in the begin( ) method.
The header file will now become:.
The implementation of the begin( ) method maybe broken into 3:
1. Initialising the LDR_Sensor_Class. As part of that class there is already a public method to do that. ie LDR_Sensor_Class::begin( ). Since there are several references to the label "begin" the scope resolution operator :: must be used to distinguish between each.
2. Initialising the signals pin- this is shown below where each pin is declared as an OUTPUT and set high (positive logic) for testing.
3. Other actions. In this example the polarity is stored for later use in the program
For testing 4 instances, signal0..signal3 of the class LDR_Signals_RAG_Class will be created. This is illustrated below:
Each instance or object must be initialised. This is illustrated above. In the example the polarity of the signals has been set to positive logic.
At this point the program should compile and turn all 12 lights ON. To verify the operation with negative logic in the implementation of the begin( ) method set all outputs LOW.
To drive the 3 signals a method drive_signals(int red, int amber, int green) is included in the class. Since this will be required by the client the program it must be in the public area.
In the implementation method the arguments specify if the signals are active. If the variable _pol set as part of the begin method indicating negative polarity signals are used then the arguments are complemented.
The signals are then set as required.
The client code will be the actual test code. In this example the train_over_sensor( ) method is used to detect a train. If a train is detected the light will be set to RED . It will be set to GREEN otherwise.
Note the operation will use the train_over_sensor( ) method which was a public method in the LDR_Sensor_Class. Since its name is unique there is no need to use the scope resolution operator :: (unlike in the begin( ) methods) to tell the compiler where to find the code.
The LDR_Signals_RAG_Class library will be used in later projects. To add the library to available contributed libraries:
Use a program such as Windows Explorer to create a *zip file that includes the *.cpp and *.h files. (These files are located in the sub-folder LDR_Signals_RAG_Class in the sketchbook location. (In the IDE use file-->preferences))
In the IDE use sketch-->Include Library--> Add *zip Library and select LDR_Signals_RAG_Class.
A small class has been developed. It has the constructor plus three public methods.
1. The constructor LDR_Signals_RAG_Class ( sen, red, amber,green) gives the wiring.
2. begin(polarity) where the argument matches the implementation to the type of signal
3. train_over_sensor( ) returns true for a train over the sensor.
4. drive_signals(red,amber,green) will set the signals as specified.
The page illustrated very basic interactions between the signals and the sensors. The real power will come when the client uses several sensors to control the lights. For example go RED when train is over sensor, turn AMBER when the train passes the next sensor and then returns to GREEN when the train passes a third. This is the topic of a future project. Track_Train
Photo shows LDR between rails and prototyping board with RED - AMBER - GREEN signals. For this project the signals just flash RED when the train is over the sensor and then return to GREEN.
As implied in the project Track_Train the signal will go RED when the train is over sensor but then sensors further up the track set this signal to AMBER and back to GREEN.