The first module of the RaylFX series is the Fair module. These are various effects that you can expect to see at a fair:
- Ferris Wheel
- Carousel
- Running light
- Street lights
- Stroboscope
- Sound module
Video – RaylFX Fair Module
Components
These are the components I used:
- Arduino Nano*
- Breadboard*
- Jumper wires*
- Ribbon jumper wires* to pull apart
- Stepper motors and driver boards*
- LEDs*
- DFPlayer-Mini* MP3 player module
- Speaker*
- 1x 1kOhm resistor
Wiring Diagram
Like all RaylFX modules the fairground module needs connections to the control module (Of these you need only one module in the whole system!). This is a connection of all A4 pins (this pin is used as digital input 18) and a connection to the power supply (5V+ and GND).
Attention: The control signal of the RaylFX control module is applied to pin A4. It controls the time of day and is mandatory to synchronize all modules.
The Ferris wheel and carousel are two stepper motors that drive the models of the respective rides. Both stepper motors are controlled by one stepper motor driver each.
The LEDs for the running lights, the street lights and the strobe are each connected to digital Arduino pins via a series resistor. The resistor limits the current flow. If you need more LEDs you can simply connect them in parallel after the resistor. They will then all shine less brightly. Surely there is a maximum of LEDs you can connect like this. I don’t have an exact number. I recommend to simply try it out.
If you need many more LEDs, you should amplify the channels. This can be achieved e.g. with a ULN2803A Darlington transistor array.
The DFPlayer Mini is used for the sound output. 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 folder “01” 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 …
Since the stepper motors need a lot of power and therefore can interfere with the DFPlayer, you can put a backup capacitor (100uF) in the power rails near the driver boards.
The operation site module uses the DFRobotDFPlayerMini, and the CheapStepper library. These libraries 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 and then search for, and install the CheapStepper library by Henry Tyler.
Further info about the DF-Player on this page: DFPlayer Mini-MP3-Player for Arduino.
Code Settings
int runningLightTimeout = 100; // running light speed (ms)
int strobeFlashTimeout = 100; // strobe impulse duration (ms)
int strobePauseTimeout = 1000; // strobe pause duration (ms)
int ferrisWheelPauseTimeout = 3; // ferris wheel pause duration (s)
int carouselPauseTimeout = 2; // carousel pause duration (s)
int streetLightsTimeout = 100; // switch-on time of the street lights (ms)
int volumeDFPlayer = 10; // volume of the DFPlayer (0 – 30)
int mp3Count = 7; // amount of MP3 files on the SD-card
int mp3Duration[] = {28, 9, 20, 2, 4, 17, 23}; // duration of the MP3 files in seconds
int mp3Likelihood = 10; // likelihood with which MP3s are played, 10 often, 100 rarely
Different settings can be made in the code:
- Running light speed in milliseconds
- Stroboscope pulse duration in milliseconds
- Stroboscope pause duration in milliseconds
- Ferris wheel pause duration in seconds
- Carousel pause duration in seconds
- Street light on time in milliseconds
- Volume of the DFPlayer (0 – 30)
- Amount of MP3 files on the SD card
- Duration of MP3 files in seconds (can be shorter than MP3s)
- Likelihood with which MP3s are played: 10 often, 100 rarely
Code for the RaylFX Fair Module
/*
Rayl-FX Fair Module
StartHardware.org/en
*/
#include <CheapStepper.h>
#include "SoftwareSerial.h" // required for the DFPlayer
#include "DFRobotDFPlayerMini.h" // required for the DFPlayer
/* ***** ***** Settings ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */
int myAddress = 2; // must be unique in the system! Must therefore exist only once.
int runningLightTimeout = 100; // running light speed (ms)
int strobeFlashTimeout = 100; // strobe impulse duration (ms)
int strobePauseTimeout = 1000; // strobe pause duration (ms)
int ferrisWheelPauseTimeout = 3; // ferris wheel pause duration (s)
int carouselPauseTimeout = 2; // carousel pause duration (s)
int streetLightsTimeout = 100; // switch-on time of the street lights (ms)
int volumeDFPlayer = 10; // volume of the DFPlayer (0 – 30)
int mp3Count = 7; // amount of MP3 files on the SD-card
int mp3Duration[] = {28, 9, 20, 2, 4, 17, 23}; // 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 streetLightsPin = 9; // this pin connects to the street lights
int runningLight1Pin = 8; // this pin connects to the running light A lamps 2
int runningLight2Pin = 7; // this pin connects to the running light A lamps 3
int runningLight3Pin = 6; // this pin connects to the running light B lamps 1
int runningLight4Pin = 5; // this pin connects to the running light B lamps 2
int strobePin = 4; // this pin connects to the stroboscope (white LED?)
//int motorPins1[4] = {10, 11, 12, 13}; // pins for stepper-motor 1
//int motorPins2[4] = {14, 15, 16, 17}; // pins for stepper-motor 2
/* Storage Variables */
int runningLightPosition = 0; // stores the position of running light A
int streetLightsBrightness = 0; // stores street light brightness
/* Timer Variables */
long streetLightsTimer = 0; // timer street lights
long runningLightTimer = 0; // timer running light
long strobeTimer = 0; // timer stroboscope
long ferrisWheelTimer = 0; // timer ferris wheel
long carouselTimer = 0; // timer carousel
long soundTimer = 0; // timer DFPlayer
long soundTimeout = 0; // stores the playing time of the current MP3
long moveStartTime1 = 0; // this will save the time (millis()) when we started each new move
long moveStartTime2 = 0; // this will save the time (millis()) when we started each new move
/* State Variables */
int myState = 3; // state main-statemachine, starts at 3, since everything is switched off here
int ferrisWheelState = 0; // state ferris wheel
int carouselState = 0; // state carousel
int strobeState = 0; // state stroboscope
int soundState = 0; // state DFPlayer
bool moveClockwise21 = true;
bool moveClockwise22 = true;
int stepsLeft1 = 0;
int stepsLeft2 = 0;
int soundRandom;
int theSound;
int soundPlaying = false;
bool moveClockwise1 = true;
bool moveClockwise2 = true;
String stateName;
/* 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;
/* Create Objects */
SoftwareSerial mySoftwareSerial(3, 2); // RX, TX for DFPlayer
DFRobotDFPlayerMini myDFPlayer; // DFPlayer object
CheapStepper stepper1 (14, 15, 16, 17); // creating a stepper object for the ferris wheel
CheapStepper stepper2 (10, 11, 12, 13); // creating a stepper object for the carousel
#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
pinMode(receivePin, INPUT); // receiving pin from control-module
mySoftwareSerial.begin(9600); // starts the serial communication for DFPlayer
pinMode(runningLight1Pin, OUTPUT); // set running light as output
pinMode(runningLight2Pin, OUTPUT); // set running light as output
pinMode(runningLight3Pin, OUTPUT); // set running light as output
pinMode(runningLight4Pin, OUTPUT); // set running light as output
pinMode(strobePin, OUTPUT); // set strobe as output
runningLightOff();
strobeOff();
streetLightsOff();
stepper1.setRpm(16);
stepper2.setRpm(12);
/* 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"));
/*while (true) {
delay(0); // Code to compatible with ESP8266 watch dog.
}*/
}
Serial.println(F("DFPlayer Mini online."));
myDFPlayer.volume(volumeDFPlayer); // volume is assigned
}
/*
void receiveEvent(int bytes) {
while (Wire.available()) {
timeOfDay = Wire.read(); // stores received time data in the variable timeOfDay
if (timeOfDay > 22) {
stateName = "late evening";
myState = 0; // late evening
} else if (timeOfDay > 18) {
myState = 5; // evening
stateName = "evening";
} else if (timeOfDay > 12) {
myState = 4; // noon
stateName = "noon";
} else if (timeOfDay > 9) {
myState = 3; // forenoon
stateName = "forenoon";
} else if (timeOfDay > 7) {
myState = 2; // morning
stateName = "morning";
} else {
myState = 1; // night
stateName = "night";
}
Serial.print(millis()); Serial.print("\t timeOfDay: \t"); Serial.print(timeOfDay);
Serial.print("\t myState: \t"); Serial.print(myState); Serial.print(" — "); Serial.println(stateName);
}
}*/
void loop() {
receiveFunction(); // execute instructions for reception
if (receiveStarted == false) {
if (myTime > 22) { // ***** late evening *****
streetLightsOn(); // street lights on
runningLightOn(); // running light on
strobeOn(); // strobe on
soundOn(); // sound on
ferrisWheelMotorOn(); // ferris wheel motor on
carouselMotorOn(); // carousel motor on
} else if (myTime > 18) { // ***** evening *****
streetLightsOn(); // street lights on
runningLightOn(); // running light on
strobeOn(); // stroboscope on
soundOn(); // sound on
ferrisWheelMotorOn(); // ferris wheel motor on
carouselMotorOn(); // carousel motor on
} else if (myTime > 12) { // ***** noon *****
streetLightsOff(); // street lights off
runningLightOff(); // running light off
strobeOff(); // stroboscope off
soundOff(); // sound off
ferrisWheelMotorOn(); // ferris wheel motor on
carouselMotorOff(); // carousel motor off
} else if (myTime > 9) { // ***** forenoon *****
streetLightsOff(); // street lights off
runningLightOff(); // running light off
strobeOff(); // stroboscope off
soundOff(); // sound off
ferrisWheelMotorOff(); // ferris wheel motor off
carouselMotorOff(); // carousel motor off
} else if (myTime > 7) { // ***** morning *****
streetLightsOn(); // street lights on
runningLightOff(); // running light off
strobeOff(); // stroboscope off
soundOff(); // sound off
ferrisWheelMotorOff(); // ferris wheel motor off
carouselMotorOff(); // carousel motor off
} else { // ***** night *****
streetLightsOn(); // street lights on
runningLightOff(); // running light off
strobeOff(); // stroboscope off
soundOff(); // sound off
ferrisWheelMotorOff(); // ferris wheel motor off
carouselMotorOff(); // carousel motor off
}
}
}
void streetLightsOn() {
if (streetLightsTimer + streetLightsTimeout < millis()) {
streetLightsBrightness++;
if (streetLightsBrightness > 255) streetLightsBrightness = 255;
streetLightsTimer = millis();
analogWrite(streetLightsPin, streetLightsBrightness);
}
}
void streetLightsOff() {
streetLightsBrightness = 0;
analogWrite(streetLightsPin, 0);
streetLightsTimer = millis();
}
void runningLightOn() {
if (runningLightTimer + runningLightTimeout < millis()) {
runningLightTimer = millis();
runningLightPosition++;
if (runningLightPosition > 3) {
runningLightPosition = 0;
}
if (runningLightPosition == 0) {
digitalWrite(runningLight1Pin, HIGH);
digitalWrite(runningLight2Pin, HIGH);
digitalWrite(runningLight3Pin, HIGH);
digitalWrite(runningLight4Pin, LOW);
} else if (runningLightPosition == 1) {
digitalWrite(runningLight1Pin, HIGH);
digitalWrite(runningLight2Pin, HIGH);
digitalWrite(runningLight3Pin, LOW);
digitalWrite(runningLight4Pin, HIGH);
} else if (runningLightPosition == 2) {
digitalWrite(runningLight1Pin, HIGH);
digitalWrite(runningLight2Pin, LOW);
digitalWrite(runningLight3Pin, HIGH);
digitalWrite(runningLight4Pin, HIGH);
} else if (runningLightPosition == 3) {
digitalWrite(runningLight1Pin, LOW);
digitalWrite(runningLight2Pin, HIGH);
digitalWrite(runningLight3Pin, HIGH);
digitalWrite(runningLight4Pin, HIGH);
}
}
}
void runningLightOff() {
runningLightTimer = millis();
digitalWrite(runningLight1Pin, LOW);
digitalWrite(runningLight2Pin, LOW);
digitalWrite(runningLight3Pin, LOW);
digitalWrite(runningLight4Pin, LOW);
}
void strobeOn() {
switch (strobeState) {
case 0:
digitalWrite(strobePin, HIGH);
if (strobeTimer + strobeFlashTimeout < millis()) {
strobeTimer = millis();
strobeState = 1;
}
break;
case 1:
digitalWrite(strobePin, LOW);
if (strobeTimer + strobePauseTimeout < millis()) {
strobeState = 0;
strobeTimer = millis();
}
break;
}
}
void strobeOff() {
digitalWrite(strobePin, LOW);
strobeTimer = millis();
}
void ferrisWheelMotorOn() {
stepper1.run();
switch (ferrisWheelState) {
case 0: // fahren
stepsLeft1 = stepper1.getStepsLeft();
if (stepsLeft1 == 0) {
moveClockwise1 = !moveClockwise1;
if (random(3) <= 1) {
ferrisWheelState = 1;
ferrisWheelTimer = millis();
} else {
stepper1.newMoveDegrees (moveClockwise1, 360 + random(360));
}
}
break;
case 1: // pause
if (ferrisWheelTimer + (ferrisWheelPauseTimeout * 1000) < millis()) {
ferrisWheelState = 0;
}
break;
}
}
void ferrisWheelMotorOff() {
/*stepsLeft1 = stepper1.getStepsLeft();
if (stepsLeft1>0) stepper1.stop();*/
}
void carouselMotorOn() {
stepper2.run();
switch (carouselState) {
case 0: // spin
stepsLeft2 = stepper2.getStepsLeft();
if (stepsLeft2 == 0) {
moveClockwise2 = !moveClockwise2;
if (random(5) <= 1) {
carouselState = 1;
carouselTimer = millis();
} else {
stepper2.newMoveDegrees (moveClockwise2, 90 + random(360));
}
}
break;
case 1: // pause
if (carouselTimer + (carouselPauseTimeout * 1000) < millis()) {
carouselState = 0;
}
break;
}
}
void carouselMotorOff() {
/*stepsLeft2 = stepper2.getStepsLeft();
if (stepsLeft2>0) stepper2.stop();*/
}
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 printDetail(uint8_t type, int value) { // DF Player errors
switch (type) {
case TimeOut:
Serial.println(F("Time Out!"));
break;
case WrongStack:
Serial.println(F("Stack Wrong!"));
break;
case DFPlayerCardInserted:
Serial.println(F("Card Inserted!"));
break;
case DFPlayerCardRemoved:
Serial.println(F("Card Removed!"));
break;
case DFPlayerCardOnline:
Serial.println(F("Card Online!"));
break;
case DFPlayerUSBInserted:
Serial.println("USB Inserted!");
break;
case DFPlayerUSBRemoved:
Serial.println("USB Removed!");
break;
case DFPlayerPlayFinished:
Serial.print(F("Number:"));
Serial.print(value);
Serial.println(F(" Play Finished!"));
break;
case DFPlayerError:
Serial.print(F("DFPlayerError:"));
switch (value) {
case Busy:
Serial.println(F("Card not found"));
break;
case Sleeping:
Serial.println(F("Sleeping"));
break;
case SerialWrongStack:
Serial.println(F("Get Wrong Stack"));
break;
case CheckSumNotMatch:
Serial.println(F("Check Sum Not Match"));
break;
case FileIndexOut:
Serial.println(F("File Index Out of Bound"));
break;
case FileMismatch:
Serial.println(F("Cannot Find File"));
break;
case Advertise:
Serial.println(F("In Advertise"));
break;
default:
break;
}
break;
default:
break;
}
}
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
}
Pingback: DFPlayer Mini MP3 Player for Arduino - StartHardware - Tutorials for Arduino