RaylFX – Operation Site with Arduino and flashing blue light

RaylFX operation site flashing blue light, siren, MP3 player with Arduino Nano

This module of the RaylFX system controls an operation site. It includes four pairs of blue lights that can flash at different speeds, a 3-channel running light, e.g. for barriers, a strobe light, vehicle lighting (headlights, taillights) and accident scene lighting in the evening. This allows fire department and/or police operations to be equipped with appropriate effects. This module also has a sound output via DFPlayer-Mini.

We need your consent to load the content of YouTube.

If you click on this video we will play the video, load scripts on your device, store cookies and collect personal data. This enables [Google Ireland Limited, Irland] to track activities on the Internet and to display advertising in a target group-oriented manner. There is a data transfer to the USA, which does not have EU-compliant data protection. You will find further information here.

Jmx0O2RpdiBjbGFzcz0mcXVvdDtudi1pZnJhbWUtZW1iZWQmcXVvdDsmZ3Q7Jmx0O2lmcmFtZSB0aXRsZT0mcXVvdDtSYWlsRlggRWluc2F0enN0ZWxsZSAmbmRhc2g7IEVmZmVrdGUgZiZ1dW1sO3IgTW9kZWxsYmFobiB1bmQgTW9kZWxsYmF1IG1pdCBBcmR1aW5vJnF1b3Q7IHdpZHRoPSZxdW90OzEyMDAmcXVvdDsgaGVpZ2h0PSZxdW90OzY3NSZxdW90OyBzcmM9JnF1b3Q7aHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvdWhtUWtHUGJZMWs/ZmVhdHVyZT1vZW1iZWQmcXVvdDsgZnJhbWVib3JkZXI9JnF1b3Q7MCZxdW90OyBhbGxvdz0mcXVvdDthY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgY2xpcGJvYXJkLXdyaXRlOyBlbmNyeXB0ZWQtbWVkaWE7IGd5cm9zY29wZTsgcGljdHVyZS1pbi1waWN0dXJlJnF1b3Q7IGFsbG93ZnVsbHNjcmVlbiZndDsmbHQ7L2lmcmFtZSZndDsmbHQ7L2RpdiZndDs=

Wiring Diagram

RaylFX traffic light module wiring diagram for model railroad

The module is based on the Arduino Nano. Four pairs of blue lights are connected to pins 4, 5, 6, 7, 15 (A1), 16 (A2), 17 (A3), 19 (A5). Here the analog pins are used as digital pins. The 3-channel running light is connected to pins 10, 11, 12 and the strobe light to pin 9. At night the operation site is illuminated via pin 8. At the same time, a vehicle lighting also switches on at pins 13 and 14 (A0).

Attention: The control signal of the RaylFX control module is applied to pin A4. It controls the time of day and is mandatory.

Code Settings

Several settings can be made in the code. These are explained in more detail in the code section. They are basically the speeds of the running light and the blue lights.

As with other modules with sound output, the DFPlayer Mini is also used here. It plays MP3 and WAV files from an SD card. The SD card must be formatted in the FAT16 or FAT32 file system. In addition, the files must be in the “01” folder and the file names must be sequentially named 001.mp3, 002.mp3, 003.mp3, and so on. As mentioned, WAV files may also be used: 001.mp3, 002.wav, 003.mp3 …

The number of MP3 files must be specified in the variable mp3Count. For this you can specify the playing time of the files via the variable mp3Duration. Via mp3Likelihood the frequency of sound triggering can be influenced.

The operation site module uses the DFRobotDFPlayerMini library. This library must be installed first. For this go in the Arduino menu to Sketch>Include Library>Manage Libraries … and search for DFRobotDFPlayerMini in the search field. Install the current version of the DFRobotDFPlayerMini library from DFRobot.

Further info about the DF-Player on this page: DFPlayer Mini-MP3-Player for Arduino.

int runningLightTimeout = 500;            // running light speed (ms) e. g. as street barriers
int flashingLightDelay = 1000;            // flashing light delay
int volumeDFPlayer = 10;                  // volume of the DFPlayer (0 – 30)
int mp3Count = 2;                         // amount of MP3 files on the SD-card
int mp3Duration[] = {3, 14};              // duration of the MP3 files in seconds
int mp3Likelihood = 10;                   // likelihood with which MP3s are played, 10 often, 100 rarely

When uploading you have to make sure that the correct board is selected in the Arduino menu. To do this, “ATmega328P (Old Bootlaoder)” must also be selected in the Processor subitem of the Tools menu.

The following program code can be easily copied with the above mentioned changes and loaded onto the Arduino nano.

Code for the RaylFX Operation Site Module

/*
     Rayl-FX Operation Site Module
     StartHardware.org/en
*/

#include "SoftwareSerial.h"              // required for the DFPlayer
#include "DFRobotDFPlayerMini.h"         // required for the DFPlayer

/* ***** ***** Settings ***** ***** ***** *****  ***** ***** ***** *****  ***** ***** ***** ***** */

int runningLightTimeout = 500;            // running light speed (ms) e. g. as street barriers
int flashingLightDelay = 1000;            // flashing light delay
int volumeDFPlayer = 10;                  // volume of the DFPlayer (0 – 30)
int mp3Count = 2;                         // amount of MP3 files on the SD-card
int mp3Duration[] = {3, 14};              // duration of the MP3 files in seconds
int mp3Likelihood = 10;                   // likelihood with which MP3s are played, 10 often, 100 rarely

/* ***** ***** From here begins the program code, which does not need to be adjusted ***** ***** ***** ***** */

int blueLightPins[8] = {15, 16, 17, 19, 7, 6, 5, 4};  // pins for the flashing blue light
int runningLightPins[3] = {10, 11, 12};               // pins for the running lights
int vehicleLightingPins[2] = {13, 14};                // pins for vehicle lighting
int flashingLightPin = 9;                             // pin for flashing light
int lightingPin = 8;                                  // pin for operation site lighting

/* State Variables */
int soundState = 0;                      // state of DFPlayer

int soundRandom;                         // auxiliary variable for sound output
int theSound;                            // auxiliary variable for sound output
int soundPlaying = false;                // auxiliary variable for sound output

/* Memory Variables */
int advertisingLed1 = 1;                 // stores the state of the advertising-LED 1
int advertisingLed2 = 1;                 // stores the state of the advertising-LED 2
int runningLightPosition = 0;            // stores the state of the running lights A

/* Timer Variables */
long runningLightTimer;
int blueLightTimer[4] = {800, 700, 650, 730};   // blue light flashing frequency
long soundTimer = 0;                     // timer of the DFPlayer
long soundTimeout = 0;                   // stores the playback time of the current MP3 file

/* Create Objects */
SoftwareSerial mySoftwareSerial(3, 2);   // RX, TX for the DFPlayer
DFRobotDFPlayerMini myDFPlayer;          // DFPlayer object

/* Variables from the control module to determine the time of day */
boolean receive = false;
boolean receiveStarted = false;
int receiveTimeout = 10;
long receiveTimer = 0;
int receivedTime = 0;
int receivePulse = 0;
int lastReceivePulse = 0;
int receivePin = 18;
int myTime = 0;

#define PAYLOAD_SIZE 2                  // mandatory for communication with master-module
int timeOfDay = 0;                      // stores timeOfDay of master-module (0 and 255)
byte nodePayload[PAYLOAD_SIZE];         // temporarily stores data of master-module

void setup() {
  Serial.begin(115200);                     // starts the serial communication
  mySoftwareSerial.begin(9600);             // starts the serial communication for the DFPlayer

  pinMode(flashingLightPin, OUTPUT);            // pin for the flashing light
  pinMode(lightingPin, OUTPUT);                 // pin for the operation site lighting

  for (int i = 0; i < 2; i++) {                 // for the number of vehicle lighting pins
    pinMode(vehicleLightingPins[i], OUTPUT);    // declare this pin as output
    digitalWrite(vehicleLightingPins[i], HIGH); // turn off the LED at this pin
  }

  for (int i = 0; i < 8; i++) {                 // for the number of blue light pins
    pinMode(blueLightPins[i], OUTPUT);          // declare this pin as output
    digitalWrite(blueLightPins[i], HIGH);       // turn off the LED at this pin
  }

  for (int i = 0; i < 3; i++) {                 // for the number of running light pins
    pinMode(runningLightPins[i], OUTPUT);       // declare this pin as output
    digitalWrite(runningLightPins[i], HIGH);    // turn off the LED at this pin
  }

  /* DFPlayer Setup */
  Serial.println(F("Initializing DFPlayer ... "));
  if (!myDFPlayer.begin(mySoftwareSerial)) {      // use softwareSerial to communicate with DFPlayer
    Serial.println(F("Error: Check connection to DFPlayer and SD-Card"));
  }
  Serial.println(F("DFPlayer Mini online."));
  myDFPlayer.volume(volumeDFPlayer);              // volume is assigned

}

void loop() {
  receiveFunction();                // execute instructions for reception
  if (receiveStarted == false) {    // if no data is currently being received:
    
    if (myTime > 22) {              // ***** late evening *****
      runningLightOn();             // running light on
      blueLightOn();                // blue light on
      flashingLightOn();            // flashing light on
      lightingOn();                 // lighting on
      vehicleLightingOn();          // vehicle lighting on
      soundOn();                    // sound On
      
    } else if (myTime > 18) {       // ***** evening *****
      runningLightOn();             // running light on
      blueLightOn();                // blue light on
      flashingLightOn();            // flashing light on
      lightingOn();                 // lighting on
      vehicleLightingOn();          // vehicle lighting on
      
    } else if (myTime > 12) {       // ***** noon *****
      runningLightOn();             // running light on
      blueLightOn();                // blue light on
      flashingLightOn();            // flashing light on
      lightingOff();                // lighting off
      vehicleLightingOff();         // vehicle lighting off
      
    } else if (myTime > 9) {        // ***** forenoon *****
      runningLightOn();             // running light on
      blueLightOn();                // blue light on
      flashingLightOn();            // flashing light on
      lightingOff();                // lighting off
      vehicleLightingOff();         // vehicle lighting off
      
    } else if (myTime > 7) {        // ***** morning *****
      runningLightOn();             // running light on
      blueLightOn();                // blue light on
      flashingLightOn();            // flashing light on
      lightingOff();                // lighting off
      vehicleLightingOff();         // vehicle lighting off
      
    } else {                        // ***** night *****
      runningLightOn();             // running light on
      blueLightOn();                // blue light on
      flashingLightOn();            // flashing light on
      lightingOn();                 // lighting on
      vehicleLightingOn();          // vehicle lighting on
    }
  }
}

void vehicleLightingOn() {
  digitalWrite(vehicleLightingPins[0], LOW);
  digitalWrite(vehicleLightingPins[1], LOW);
}

void vehicleLightingOff() {
  digitalWrite(vehicleLightingPins[0], HIGH);
  digitalWrite(vehicleLightingPins[1], HIGH);
}

void lightingOn() {
  digitalWrite(lightingPin, LOW);
}

void lightingOff() {
  digitalWrite(lightingPin, HIGH);
}

void blueLightOn() {
  for (int i = 0; i < 4; i++) {
    if (millis() % blueLightTimer[i] < blueLightTimer[i] / 2) {
      digitalWrite(blueLightPins[i * 2], HIGH);
      digitalWrite(blueLightPins[i * 2 + 1], LOW);
    } else {
      digitalWrite(blueLightPins[i * 2], LOW);
      digitalWrite(blueLightPins[i * 2 + 1], HIGH);
    }
  }
}

void blueLightOff() {
  for (int i = 0; i < 8; i++) {
    digitalWrite(blueLightPins[i], HIGH);
  }
}

void flashingLightOn() {
  if (millis() % flashingLightDelay < 40) {
    digitalWrite(flashingLightPin, LOW);
  } else {
    digitalWrite(flashingLightPin, HIGH);
  }
}

void flashingLightOff() {
  digitalWrite(flashingLightPin, HIGH);
}

void runningLightOn() {
  if (runningLightTimer + runningLightTimeout < millis()) {
    runningLightTimer = millis();
    runningLightPosition++;
    if (runningLightPosition > 2) {
      runningLightPosition = 0;
    }
    for (int i = 0; i < 3; i++) {
      digitalWrite(runningLightPins[i], HIGH);
    }
    digitalWrite(runningLightPins[runningLightPosition], LOW);
  }
}

void runningLightOff() {
  runningLightTimer = millis();
  for (int i = 0; i < 3; i++) {
    digitalWrite(runningLightPins[i], HIGH);
  }
}

void soundOn() {
  switch (soundState) {
    case 0:
      Serial.println("soundTimer 0");
      soundRandom = random(mp3Likelihood);
      if (soundRandom < 1) {
        soundState = 1;
        theSound = random(mp3Count) + 1;
        soundTimer = millis();
        soundTimeout = mp3Duration[theSound - 1] * 1000;
        Serial.print("Playsound: \t\t\t"); Serial.print(theSound); Serial.print("\t\t\t"); Serial.println(soundTimeout);
        myDFPlayer.playFolder(1, theSound); // play specific mp3 in SD:/15/004.mp3; Folder Name(1~99); File Name(1~255)
        soundPlaying = true;
      } else {
        soundTimer = millis();
        soundTimeout = 500;
        soundState = 1;
      }
      break;
    case 1:
      if (soundTimer + soundTimeout < millis()) {
        soundPlaying = false;
        soundState = 0;
      }
      break;
  }
}


void soundOff() {
  if (soundPlaying == true) {
    Serial.println(soundPlaying);
    myDFPlayer.pause();
    soundPlaying = false;
  }
}

/* ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */

void receiveFunction() {                      // receives time of day from control-module
  receivePulse = digitalRead(receivePin);     // read out the receive pin
  
  if ((receiveTimer + receiveTimeout < millis()) && (receiveStarted == true)) {
    // on timeout and active reception
    receiveStarted = false;                   // end active reception
    myTime = receivedTime - 1;                // store received time
    receivedTime = 0;                         // reset the auxiliary variable for time reception
    Serial.println(myTime);                   // serial output
  }
  // if a pulse is detected at the receive pin that was not there before
  if ((receivePulse == 0) && (lastReceivePulse == 1)) {
    receiveTimer = millis();                  // restart timer
    if (receiveStarted == false) receiveStarted = true;  // start active reception, if not already done
    receivedTime++;                           // there was a pulse, so increase the auxiliary variable to receive time
  }
  lastReceivePulse = receivePulse;            // remember current state at pin for next pass
}

    Leave a Reply

    Your email address will not be published. Required fields are marked *