Building a BMX gate and having sound issues

Hi all I'm very new to coding and would appreciate any help anyone can give me. I'm building a BMX gate from an open source:

bmx-start-gate/arduino/gate_seq at master · gndean/bmx-start-gate · GitHub

I've built two PCB's and I just can not get either to play the audio. Everything else works perfectly. I've got a feeling it is something to do with the sketch but I'm not sure. I would really appreciate any advice possible the sketch I'm using is:

//#define USE_LEDS 1
#define USE_NEOSTRIP 1

/*

#include <SD.h>
#include <TMRpcm.h>
#include <TM1637.h>

const int PIN_UTRIG = 4;
const int PIN_UECHO = 2;
const int PIN_SPK = 9;
const int PIN_NEOPIX = 6;
const int PIN_SD_CS = 10;
const int PIN_SD_MISO = 12;
const int PIN_SD_MOSI = 11;
const int PIN_SD_SCK = 13;
const int PIN_SEGMENT_CLK = 7;
const int PIN_SEGMENT_DIO = 8;
const int PIN_START_BUTTON = A1;
const int PIN_CANCEL_BUTTON = A0;
const int PIN_MAG_RELAY = A2;

#ifdef USE_LEDS
const int PIN_R = 8;
const int PIN_Y1 = 7;
const int PIN_Y2 = 6;
const int PIN_G = 5;
#endif // USE_LEDS

const int NEOPIXEL_BRIGHTNESS = 200; // Setting to >= 200 lead to unreliability - the stick would stop responding

const int BEAM_BREAK_MIN_DURATION = 20; // Milliseconds
const unsigned long TIMING_TIMEOUT = 10000; // Milliseconds
const unsigned long GATE_ARMED_TIMEOUT = 2L * 60 * 1000; // Milliseconds

enum {
STATE_IDLE,
STATE_GATE_ARMED,
STATE_START_SEQ,
STATE_TIMING,
STATE_BEAM_BROKEN
};

enum {
LIGHT_ALLOFF,
LIGHT_WAIT_START,
LIGHT_R,
LIGHT_Y1,
LIGHT_Y2,
LIGHT_G,
LIGHT_FINISH
};

#ifdef USE_NEOSTRIP
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel neo_strip = Adafruit_NeoPixel(8, PIN_NEOPIX, NEO_GRB + NEO_KHZ800);
#endif // USE_NEOSTRIP

TMRpcm tmrpcm; // This needs to be global, otherwise resetting the Arduino fails to play audio
TM1637 segment(PIN_SEGMENT_CLK,PIN_SEGMENT_DIO);

int state;
int thresh_dist = 400;
unsigned long broken_beam_ms;
unsigned long timing_start_ms;

void setup() {
#ifdef USE_LEDS
pinMode(PIN_R, OUTPUT);
pinMode(PIN_Y1, OUTPUT);
pinMode(PIN_Y2, OUTPUT);
pinMode(PIN_G, OUTPUT);
#endif // USE_LEDS
pinMode(PIN_SPK, OUTPUT);
pinMode(PIN_UTRIG, OUTPUT);
pinMode(PIN_UECHO, INPUT);
pinMode(PIN_START_BUTTON, INPUT);
pinMode(PIN_CANCEL_BUTTON, INPUT);
pinMode(PIN_MAG_RELAY, OUTPUT);

segment.set(7);//BRIGHT_TYPICAL = 2,BRIGHT_DARKEST = 0,BRIGHTEST = 7;
segment.init();
segment.clearDisplay();

#ifdef USE_NEOSTRIP
neo_strip.begin();
neo_strip.show();
#endif // USE_NEOSTRIP

randomSeed(analogRead(A5) + analogRead(A4) + analogRead(A3) + analogRead(A2) + analogRead(A1) + analogRead(A0));

Serial.begin(9600);

while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}

Serial.print("Initializing SD card...");
if (!SD.begin(PIN_SD_CS)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");

//sd_print_root

tmrpcm.speakerPin = PIN_SPK;
tmrpcm.setVolume(5);
tmrpcm.quality(1);
tmrpcm.loop(0);

state_enter_idle();
}

void loop() {
bool test_loop_mode = false;

if (STATE_IDLE == state) {
if (LOW == digitalRead(PIN_START_BUTTON) || test_loop_mode) {
// Debounced wait for release of start button
delay(50);
if (!test_loop_mode) {
while (LOW == digitalRead(PIN_START_BUTTON)) {
delay(10);
}
}
delay(10);

  // Arm the gate and play signal
  digitalWrite(PIN_MAG_RELAY, HIGH);
  state = STATE_GATE_ARMED;
  tmrpcm.play((char*)"GATERISE.WAV");

  // Wait till finished talking
  while (tmrpcm.isPlaying()) {
    delay(10);
  }

  // Remember this time to allow timeout
  timing_start_ms = millis();
}

}

else if (STATE_GATE_ARMED == state) {
// Wait for start button
if (LOW == digitalRead(PIN_START_BUTTON) || test_loop_mode) {
Serial.println("Start button pressed");
state = STATE_START_SEQ;
}

// Check for timeout of gate armed or reset button
if (((millis() - timing_start_ms) > GATE_ARMED_TIMEOUT) || check_for_reset_button()) {
  tmrpcm.play((char*)"ABORT.WAV");
  state_enter_idle();
}

}
else if (STATE_START_SEQ == state) {
show_start_light(LIGHT_ALLOFF);
Serial.println("OK riders. Random start.");
tmrpcm.play((char*)"RANDOM.WAV");

// Calibrate by measuring average distance for n seconds
timing_start_ms = millis();

unsigned long total_dist = 0;
int cnt_dist = 0;

while ((millis() - timing_start_ms) < 4000) {
  total_dist += measure_distance();
  cnt_dist++;

  delay(10);
  random();

  if (check_for_reset_button()) {
    // Abort. State will be reset
    return;
  }
}
int avg_dist = total_dist / cnt_dist;
thresh_dist = avg_dist * 2 / 3;

Serial.print("Calibrated distance: ");
Serial.println(avg_dist);
Serial.print("Threshold distance: ");
Serial.println(thresh_dist);

Serial.println("Riders ready. Watch the gate.");
tmrpcm.play((char*)"READY.WAV");

// Wait till finished talking
while (tmrpcm.isPlaying()) {
  delay(10);
  if (check_for_reset_button()) {
    // Abort. State will be reset
    return;
  }
}
int delay_ms = random(100, 2700);

Serial.print("Random delay = ");
Serial.println(delay_ms);

timing_start_ms = millis();
while ((millis() - timing_start_ms) < delay_ms) {
  delay(10);
  if (check_for_reset_button()) {
    // Abort. State will be reset
    return;
  }
}

show_start_light(LIGHT_R);
tmrpcm.play((char*)"T_LIGHT.WAV");
delay(120);             

show_start_light(LIGHT_Y1);
tmrpcm.play((char*)"T_LIGHT.WAV");
delay(120);

show_start_light(LIGHT_Y2);
tmrpcm.play((char*)"T_LIGHT.WAV");
delay(120);

Serial.println("Green and gate drop");
tmrpcm.quality(0); // Drop quality now to minimise interference with usonic sensor timing
show_start_light(LIGHT_G);
digitalWrite(PIN_MAG_RELAY, LOW);

tmrpcm.play((char*)"T_GATE.WAV");
timing_start_ms = millis();

// Wait till finised playing audio before timing to ensure consistent usonic signal
while (tmrpcm.isPlaying()) {
  delay(10);

  // Format as seconds and show on display
  String seconds = String((millis() - timing_start_ms) / 1000.0, 2);
  display_seconds(seconds.c_str());
}


Serial.println("Timer active");
state = STATE_TIMING;

}
else if (STATE_TIMING == state) {
// Check if we've timed out
if ((millis() - timing_start_ms) > TIMING_TIMEOUT) {
Serial.println("Timing timeout");

   tmrpcm.play((char*)"TIMEOUT.WAV");

   state_enter_idle();
   return;
}

// Allow reset button in this phase
if (check_for_reset_button()) {
  // Abort. State will be reset
  return;
}

int dist = measure_distance();

//Serial.print("Distance: ");
//Serial.println(dist);
  
if (dist <= thresh_dist || test_loop_mode) {
  broken_beam_ms = millis();
  state = STATE_BEAM_BROKEN;
  Serial.println("Beam broken");
  Serial.print("Distance: ");
  Serial.println(dist);

}

// Format as seconds and show on display
String seconds = String((millis() - timing_start_ms) / 1000.0, 2);
display_seconds(seconds.c_str());

delay(10);

}
else if (STATE_BEAM_BROKEN == state) {
int dist = measure_distance();

if (dist > thresh_dist && (!test_loop_mode)) {
  Serial.println("Beam lost");
  state = STATE_TIMING;
  }
  else if (test_loop_mode || ((millis() - broken_beam_ms) >= BEAM_BREAK_MIN_DURATION)) {
    // We're done
    // Calculate time taken
    unsigned long time_taken_ms = broken_beam_ms - timing_start_ms;

    // Format as seconds and show on display
    String seconds = String(time_taken_ms / 1000.0, 2);
    display_seconds(seconds.c_str());
    
    Serial.print("Finished! Time taken = ");
    Serial.println(seconds);

    // Light up start lights
    show_start_light(LIGHT_FINISH);

    // We can switch back to full quality now
    tmrpcm.quality(1);
    tmrpcm.play((char*)"DING.WAV");
    
    while (tmrpcm.isPlaying()) {
      delay(10);
    }

    if (test_loop_mode) {
      delay(5000);
    }

    // Clear start lights
    show_start_light(LIGHT_ALLOFF);

    // Output how long we took
    speak_seconds(seconds);

    // Back to the waiting state
    state_enter_idle();
  }
  else {
    // Beam is broken. Wait a little longer
    delay(10);
  }

}
else {
// Do nothing
delay(100);
}
}

void state_enter_idle() {
show_start_light(LIGHT_WAIT_START);

// Release the gate
digitalWrite(PIN_MAG_RELAY, LOW);

state = STATE_IDLE;
}

void show_start_light(int light)
{
#ifdef USE_LEDS
if (LIGHT_FINISH == light) {
digitalWrite(PIN_R, HIGH);
digitalWrite(PIN_Y1, HIGH);
digitalWrite(PIN_Y2, HIGH);
digitalWrite(PIN_G, HIGH);
}
else if (LIGHT_WAIT_START == light) {
digitalWrite(PIN_R, LOW);
digitalWrite(PIN_Y1, HIGH);
digitalWrite(PIN_Y2, LOW);
digitalWrite(PIN_G, LOW);
}
else {
digitalWrite(PIN_R, light == LIGHT_R ? HIGH : LOW);
digitalWrite(PIN_Y1, light == LIGHT_Y1 ? HIGH : LOW);
digitalWrite(PIN_Y2, light == LIGHT_Y2 ? HIGH : LOW);
digitalWrite(PIN_G, light == LIGHT_G ? HIGH : LOW);
}
#endif // USE_LEDS

#ifdef USE_NEOSTRIP
int b = NEOPIXEL_BRIGHTNESS;

if (LIGHT_FINISH == light) {
for (int i = 0;i < 8;i++) {
neo_strip.setPixelColor(i, 0, b, 0);
}
}
else if (LIGHT_WAIT_START == light) {
for (int i = 0;i < 8;i++) {
neo_strip.setPixelColor(i, 0, 0, i == 7 ? b : 0);
}
}
else {
neo_strip.setPixelColor(7, light == LIGHT_R ? b : 0, 0, 0);
neo_strip.setPixelColor(6, light == LIGHT_R ? b : 0, 0, 0);
neo_strip.setPixelColor(5, light == LIGHT_Y1 ? b : 0, light == LIGHT_Y1 ? b : 0, 0);
neo_strip.setPixelColor(4, light == LIGHT_Y1 ? b : 0, light == LIGHT_Y1 ? b : 0, 0);
neo_strip.setPixelColor(3, light == LIGHT_Y2 ? b : 0, light == LIGHT_Y2 ? b : 0, 0);
neo_strip.setPixelColor(2, light == LIGHT_Y2 ? b : 0, light == LIGHT_Y2 ? b : 0, 0);
neo_strip.setPixelColor(1, 0, light == LIGHT_G ? b : 0, 0);
neo_strip.setPixelColor(0, 0, light == LIGHT_G ? b : 0, 0);
}
neo_strip.show();
#endif // USE_NEOSTRIP
}

void speak_seconds(String seconds)
{
for (int i = 0;i < seconds.length();i++) {
char c = seconds.c_str()[i];

if (c >= '0' && c <= '9') {
  String fname = String(c);
  fname.concat(".WAV");
  tmrpcm.play((char*)fname.c_str());      
}
else if (c == '.') {
  tmrpcm.play((char*)"POINT.WAV");
}
while (tmrpcm.isPlaying()) {
  delay(10);
} 

}
tmrpcm.play((char*)"SECONDS.WAV");
}

// Returns state to waiting for start and returns true if reset button pressed
bool check_for_reset_button()
{
if (LOW == digitalRead(PIN_CANCEL_BUTTON)) {
Serial.println("Reset button pressed");
tmrpcm.play((char*)"ABORT.WAV");
state_enter_idle();
return true;
}

return false;
}

void display_seconds(const char* seconds_c_str)
{
int8_t disp[4];
disp[0] = 17; // space
disp[1] = seconds_c_str[0] - '0';
disp[2] = seconds_c_str[2] - '0';
disp[3] = seconds_c_str[3] - '0';
segment.point(true);
segment.display(disp);
}

type or paste code here

Welcome to the forum

You started a topic in the Uncategorised category of the forum when its description explicitly tells you not to

Your topic has been moved to a relevant category. Please be careful in future when deciding where to start new topics

Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'

Use code tags (the < CODE/ > icon above the compose window) to make it easier to read and copy for examination

Please post your full sketch, using code tags when you do

Posting your code using code tags prevents parts of it being interpreted as HTML coding and makes it easier to copy for examination

In my experience the easiest way to tidy up the code and add the code tags is as follows

Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

For debugging purposes, try the following code.
If you don't hear anything, then it may be a hardware problem.

Make sure volume control is all the way up.

// For Arduino Nano
// Sound 400Hz for 1 second then 1000Hz for 1 second.
// Audio output on pin 9
void setup()
{
  pinMode(9, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
}

void loop()
{
  digitalWrite(LED_BUILTIN, HIGH);
  tone(9, 440, 1000);
  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  tone(9, 1000, 1000);
  delay(1000);
}

Hi thanks for post this it was super helpful as I was wondering about the hardware! yes I get a high then a low tone.

Well that only proves that the amplifier and the Arduino are OK.
I suspect that the SD card interface is wrong.
To test, run the basic example from the TMRpcm examples with the following modifications:
Change the SD_ChipSelectPin from 4 to 10
Change the file name from “music” to “ready”.

I assume you have loaded the SD card with all the wav files so ready.wav file should be on the card.
You should hear the ready.wav file play

If you are running this on external power, this line will stop the sketch:

while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

It depends on the Arduino board. The test succeeds immediately on an UNO, for example, no matter how the board is powdered.

a7

I thought that line was used to halt the sketch until serial comms were established.

Serial represents a USB CDC connection.

while (!Serial);

waits until the USB connection is enumerated by a host. On boards with native USB: Leonardo, PronMicro &c.

a7

Still need help?

Hi team really appreciate all the support sorry for not getting back to you sooner.

Ok so I go the SD file to play a week ago on both pieces of hardware and was super excited about it! Now I can't for the life of me get either of them to play sound again. Serial monitor doesn't bring up any issues and when I remove the card and press the rest button it says SD error as you would expect but when I put it back in and press the rest button nothing comes up. I have done exactly as you have suggested above Jim-P and still nothing. I ran the sketch example - SD card info and it reads it fine along with the file names on the card etc. Any thoughts?

Hi, @andrewmac

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Can you post some images of your project?
So we can see your component layout.

Tom.... :smiley: :+1: :coffee: :australia:

  • It worked once but not now
  • The Amplifier and Nano work OK
  • The SD card and Interface are OK.
  • BUT it does not work. Hmmm!

I see that whoever designed the board used D10 for the card select (CS) but the TMRpcm library uses by default D9 AND D10 to output audio. D10 can be disabled in the library but I don’t see it being done. It may be an issue but I may be looking in the wrong place. I need to go through the software again.

Are you using the same exact software as published on the website without any modifications?

To do further debugging you will need to edit one of the TMRpcm files
Find your Arduino sketchbook folder. It will be shown under File->preferences.
Go to the libraries folder and open the TMRpcm folder.
Open the pcmConfig.h file with a text editor
Find the following in the file and uncomment the line

 /*Ethernet shield support etc. 
The library outputs on both timer pins, 9 and 10 on Uno by default. 
Uncommenting this will disable output on the 2nd timer pin 
and should allow it to function with shields etc that use Uno pin 10 (TIMER1 COMPB).*/
//#define DISABLE_SPEAKER2

Save it and try your software again.
I would also reformat the SD card and reload the wav files.

Hi team thanks for all the input it is super appreciated!

Ok so Jim-P I've done as you have suggested and uncommented the pcmConfig.h file so it looks like the below:

/Ethernet shield support etc. The library outputs on both timer pins, 9 and 10 on Uno by default. Uncommenting this
will disable output on the 2nd timer pin and should allow it to function with shields etc that use Uno pin 10 (TIMER1 COMPB).
/
#define DISABLE_SPEAKER2

Unfortunately this made no difference still no sound. Not sure if this helps but I get the below reading on the serial monitor

Start button pressed
OK riders. Random start.
Calibrated distance: 400
Threshold distance: 266
Riders ready. Watch the gate.
Random delay = 2573
Green and gate drop
Timer active
Timing timeout

TomGeorge
Here is the schematics


and also a pic of the actual build

I haven't modified any of the software but I must warn you I am very new to this (even had to look up how to 'uncomment' a sketch.)
I'm using
64gb SDX micro SD memory card formatted to FAT32 with wave files.
12V 3A DC power supply.
All hardware was as per specification.

Really appreciate your support team as I am loosing my hair over this one :-)

Now that you have modified the config file, please try what I described in post #5 again. If you don't hear anything then it has to be a bad solder joint, loose connection or a broken trace somewhere, probably involving the SD card circuit.

If it worked once, can you think of what you did right before it stopped working, maybe a clue there.

Does it say
Initializing SD card...
initialization done.
when you press the nano reset button or apply power?

There are a few issues with that design but probably not affecting the audio output.
Connecting the USB and 5V at the same time OR just the USB is not a good idea. You could damage the nano and/or your computer.
Whoever designed the board did not do a very good job

One more important thing:
Just to be safe while debugging the audio problem, disconnect the external 5V and the neopixels.
Disable the relay by changing A2 to A3 in the code.
const int PIN_MAG_RELAY = A2;

Now you can connect the nano to the computer via USB and not worry about overloadind anything.

Morning Jim,
Thanks for the above. So I have done as you have said formatted the micro SD card to FAT32 and re installed the WAV files. I resoldered all the joints on the sd card reader and checked for continuity. Unfortunately there is still no sound being played. It does say when I plug in the hardware initializing SD card.....initialization done. Any other thoughts on this? I'm thinking of potentially scrapping this and designing my own one. you wouldn't be keen on helping me out would you? You seem to know a lot about the right way things should be done.