Flange squealing on model railroad

Hi,

I'm getting into model railroading and received my first engine (DCC & sound) about two weeks ago.
I'm using an Arduino Uno with a motor shield as a base station using DCC++ software and JMRI to operate the train(s). That part is already working in a test setup.

I want to build 2 handheld (wired) controllers/throttles to operate the layout based on the throttle by Dave Bodnar in a way that when finished I don't need to have a desktop computer or a laptop in the layout room. When I need to program CV's or anything else I can do that in my computer room using a small piece of programming track.

I'm now thinking about a system to simulate flange squaling in a far corner of my (to be build) layout. In the corner there will be a turn in the single track. I would like to have a way to detect the train and then activate a sound sample to play a couple of times as long as the train is blocking the light. As I don't know how to detect if the train is running or not I will assume the train is running when passing the turn if not I can deactivate the module using a switch.

I have some light sensors but I'm not sure if they are fast enough, have to test that, which I can build below the track so a passing train will block part of the light and activate the sound.

For testing I can use a second Arduino Uno and when I got it working I can program an Attiny chip to make a dedicated squealing module.

My questions so far are:

  • Can an Uno be used to playback a sound sample via a smart phone speaker? (I have no speaker yet)
  • How can I program a sound sample into the micro chip? (I have to find a sound sample but via YT I must be able to get something)
  • Does anybody know about a project I can use as a reference?

Thanks in advance for your replies,

Leo

I have some light sensors but I'm not sure if they are fast enough,

Yes, anything moving like this is slow compared with electronics.

when I got it working I can program an Attiny chip to make a dedicated squealing module.

Can you? I don't think so.

How can I program a sound sample into the micro chip?

A Uno has enough memory for about three seconds of sound of telephone like quality, check out this video. Arduino Uno saying Yes & No without extra hardware - YouTube
Otherwise you need something like an MP3 player modules where you put your sound sample on an SD card.

Can an Uno be used to playback a sound sample via a smart phone speaker?

Not sure what you mean by this.

Does anybody know about a project I can use as a reference?

Sound maker shield

Smart phone speaker? Do you mean a bluetooth speaker?

Hi,

Here some pics to enhance the thread :).

This is the material I have got so far except the 2 pieces of flex-rail I use to program and test the engine.

EMD-GP20 H0 scale DCC & sound equipped with box car and tanker car

Light dependent resistor (I have a couple of them)

Scheme

Last week I found this 8GB SD card between my pens

I mean the/a speaker that is inside my iPhone, maybe I have written the wrong name.
(Maybe it is not suited at all for this purpose but that's is the current plan)

Why is it not possible to use an Attiny chip? Is it due to the size of the memory?
I can alway use a dedicated Uno or find out how to program a 328 chip and use that.

Maybe I will use a couple of resistors divided over the entire length of the curve to be able to have the squeal while the train is traveling the entire length of the curve. If any of them is (partly) blocked the squeal must be audible.

This is what I have so far:

What I lack:

  • code
  • definitive scheme
  • MP3 module / speaker
  • knowledge how to upload the sound sample to the MP3 module

Leo

Getting there!

So far I have written a simple code to start the buzzing as a more complex code doesn't work yet, this is good enough so maybe I will leave it like it is.

When I cover either one of the LDRs the buzzer starts to buzz.
There is a delay to make sure the playback doesn't stop when there is none of the 6 LDRs shielded from the light due to gaps between the cars.

Now have to buy a MP3 shield and a speaker and put the sample on the SD card.

  • knowledge how to upload the sound sample to the MP3 module

Plug the SD card into your computer either directly or through an SD card adaptor. It will appear on the desktop like a disk drive. Drag and drop your sound sample into this.

As I couldn’t stand the code not to do what I wanted I have tried some more and got this, it needs a bit of refinement but I think it works ok now. I think you can tell I wasn’t educated in coding but as long as it works :).

For now ledpin 13 and a buzzer are used, that part of the code has to be replaced with the commands to activate and stop the mp/WAV playback. For now sensors 0 and 4 are connected.

int sensorPin0 = A0;                                      // select the input pin for light dependent resistor 0
int sensorPin1 = A1;                                      // select the input pin for light dependent resistor 1
int sensorPin2 = A2;                                      // select the input pin for light dependent resistor 2
int sensorPin3 = A3;                                      // select the input pin for light dependent resistor 3
int sensorPin4 = A4;                                      // select the input pin for light dependent resistor 4
int sensorPin5 = A5;                                      // select the input pin for light dependent resistor 5

int ledPin = 13;                                             // select the pin for the LED (on-board led)

int sensorValue0 = 0;                                     // variable to store the value coming from light dependent resistor 0
int sensorValue1 = 0;                                     // variable to store the value coming from light dependent resistor 1
int sensorValue2 = 0;                                     // variable to store the value coming from light dependent resistor 2
int sensorValue3 = 0;                                     // variable to store the value coming from light dependent resistor 3
int sensorValue4 = 0;                                     // variable to store the value coming from light dependent resistor 4
int sensorValue5 = 0;                                     // variable to store the value coming from light dependent resistor 5

int ledPinState = 0;

unsigned long previousMillis = 0;                         
unsigned long previousMillis1 = 0;                   // will store last time the light dependent resistor value was displayed, after experimenting this can be removed

int x;                                                           // trigger value for (de-)activating the sound module
int y;                                                           // variable to remember the play state of the sample 0 == not playing, 1 == playing

const int buzzer = 9;                                    // connect buzzer to pin 9

void setup() {
  pinMode(ledPin, OUTPUT);                           // declare the ledPin as an OUTPUT:
  digitalWrite(ledPin, LOW);                           // initially there will be no playback of the sample
  pinMode (buzzer, OUTPUT);
  noTone(buzzer);
  x = 100;                                                  // trigger value can be set here, has to be established experimenting
  y = 0;
//  Serial.begin(9600);
}

void loop() {
  sensorValue0 = analogRead(sensorPin0);                  // read the value from the light dependent resistor0: value between 0 and 1023
/*  sensorValue1 = analogRead(sensorPin1);                  // read the value from the light dependent resistor1: value between 0 and 1023
  sensorValue2 = analogRead(sensorPin2);                  // read the value from the light dependent resistor2: value between 0 and 1023
  sensorValue3 = analogRead(sensorPin3);                  // read the value from the light dependent resistor3: value between 0 and 1023 */
  sensorValue4 = analogRead(sensorPin4);                  // read the value from the light dependent resistor4: value between 0 and 1023
//  sensorValue5 = analogRead(sensorPin5);                  // read the value from the light dependent resistor5: value between 0 and 1023

unsigned long currentMillis = millis();

ledPinState = digitalRead(ledPin);

if (sensorValue0 < x || sensorValue4 < x && ledPinState == 0)
  { tone(buzzer, 1000);
    digitalWrite(ledPin, HIGH);                           // this will be code to activate the MP3/WAV playback
  }

if (sensorValue0 > x && sensorValue4 > x)
  { if (ledPinState == 1 && y == 0)
    { previousMillis = currentMillis;
      y = 1;
    }  
  }  

if (sensorValue0 < x || sensorValue4 < x && ledPinState == 1)
  { previousMillis = currentMillis;
  }

if (sensorValue0 > x && sensorValue4 > x)
  { if (y == 1)
        if  (currentMillis - previousMillis > 2500)
      { noTone(buzzer);
        digitalWrite(ledPin, LOW);                          // this will be code to deactivate the MP3/WAV playback
        y = 0;
      }
  }
}

Will this card be a good one to use for this module?

Leo

[EDIT] edited 2017-12-29 as not to bump the thread all the time.

I have ordered one of these:

$1,30 shipping included. I will have to amplify the sound signal provided by digital pin 9.
I have also ordered a bunch of male to female jumper wires so testing will be easy.
I would like to test an amplifier made by a couple of resistors and a single transistor but I do not have the proper capacitors so I will have get a couple of those.

This has become a more elaborate project than I have anticipated. An affordable ready shield including an amplifier would be greatly appreciated. The Adafruit one is way too expensive for me. It must be a fun cheap gadget otherwise there will be no flange squealing on my model railroad.

Haha, one mono amplifier finished. I don’t know if it’s the best version but the beep annoys the hell out of me so it works!!!

Will this card be a good one to use for this module?

Yes but the quality of those modules is a bit variable.

Hi,

The flange squeal module is working now as desired. The WAV playback is working (finally received the SD-card module last friday), the delay is working and so is all that was in the design goal.
The only thing I can think of to improve the functionality is to detect whether the train is moving or not. (now if a train is stationary the sample will still play)
I don’t know how to do that at this time, thinking about a block detection (that can replace the LDRs if implemented) and some receiver to decode the commands given to the engine driving thru the curve. This means that the sound module will also have to identify the actual engine driving thru the curve.

However, for now I’m done with this project.

This is the final test setup only using LDR 0 and 4 out of 6 to be used in total.

For those interested below is the current code I’m using.

Thanks for the help!

/*
   Flange_Squealing_SD_Sample
 * Flange Squeal Code for use on model railroads
 * One or more light dependent resistors (LDRs) are used
 * If one or more LDRs are blocked the Arduino will start a flange squeal sound sample using a MP3/WAV shield and a SD card holding the sample 
 * Idea by Leo Groeneveld (dec, 2017 - jan 2018)
 */

#define SD_ChipSelectPin 4                                // using digital pin 4 on arduino uno 328, can use other pins
#include <TMRpcm.h>                                       // also need to include this library...
#include <SPI.h>
#include <SD.h>

TMRpcm tmrpcm;

int sensorPin0 = A0;                                      // select the input pin for light dependent resistor 0
int sensorPin1 = A1;                                      // select the input pin for light dependent resistor 1
int sensorPin2 = A2;                                      // select the input pin for light dependent resistor 2
int sensorPin3 = A3;                                      // select the input pin for light dependent resistor 3
int sensorPin4 = A4;                                      // select the input pin for light dependent resistor 4
int sensorPin5 = A5;                                      // select the input pin for light dependent resistor 5

int sensorValue0 = 0;                                     // variable to store the value coming from light dependent resistor 0
int sensorValue1 = 0;                                     // variable to store the value coming from light dependent resistor 1
int sensorValue2 = 0;                                     // variable to store the value coming from light dependent resistor 2
int sensorValue3 = 0;                                     // variable to store the value coming from light dependent resistor 3
int sensorValue4 = 0;                                     // variable to store the value coming from light dependent resistor 4
int sensorValue5 = 0;                                     // variable to store the value coming from light dependent resistor 5

unsigned long previousMillis = 0;                         // will store last time the light dependent resistor value was displayed, after experimenting this can be removed
unsigned long previousMillis1 = 0;                        // will store last time the light dependent resistor value was displayed, after experimenting this can be removed

int x;                                                    // trigger value for (de-)activating the sound module

void setup(){
tmrpcm.speakerPin=9;                                      //5,6,11 or 46 on Mega, 9 on Uno, Nano, etc
                                                          //Complimentary Output or Dual Speakers:, //pinMode(10,OUTPUT); Pin pairs: 9,10 Mega: 5-2,6-7,11-12,46-45 
Serial.begin(9600);
if(!SD.begin(SD_ChipSelectPin))
{ Serial.println("SD fail");
  return;
}
tmrpcm.setVolume(5);
x = 100;
}

void loop() {
  sensorValue0 = analogRead(sensorPin0);                  // read the value from the light dependent resistor0: value between 0 and 1023
  sensorValue1 = analogRead(sensorPin1);                  // read the value from the light dependent resistor1: value between 0 and 1023
  sensorValue2 = analogRead(sensorPin2);                  // read the value from the light dependent resistor2: value between 0 and 1023
  sensorValue3 = analogRead(sensorPin3);                  // read the value from the light dependent resistor3: value between 0 and 1023
  sensorValue4 = analogRead(sensorPin4);                  // read the value from the light dependent resistor4: value between 0 and 1023
  sensorValue5 = analogRead(sensorPin5);                  // read the value from the light dependent resistor5: value between 0 and 1023

unsigned long currentMillis = millis();

if ((sensorValue0 < x || sensorValue4 < x) && tmrpcm.isPlaying() == 0)
  { tmrpcm.play("1.wav");                                 // activate the MP3/WAV playback
  }

if ((sensorValue0 < x || sensorValue4 < x) && tmrpcm.isPlaying() == 1)
  { previousMillis = currentMillis;
  }

if (sensorValue0 > x && sensorValue4 > x && tmrpcm.isPlaying() == 1 && currentMillis - previousMillis > 2500)
      { tmrpcm.disable();                                // deactivate the MP3/WAV playback
      }
}