Sound byte and LED runs multiple times

Hi, I'm using an IR detector, Azatrax, to detect the presence of a model train on a track. When the train is present, a sound byte plays and an LED lights up, then slowly dims. 4 sensors can be used at the same time. My code is created for 2 sensors. One for playing sound byte and light LED, and the other to play a different sound byte. When a train enters the IR detectors, everything works just great! My problem is that when the train stays on the IR detectors, the sound byte keeps playing and the light keeps lighting. I'd like it to play just once. Then everything would be reset when nothing is on the IR detectors so that it can play again when it re-enters the IR detectors.

I figured a bool flag would take care of this, but it doesn't. Any idea why it's not working and what can I do to make it work as described in the previous paragraph?

#include <Azatrax.h>

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"

// define pins
#define AshPit1 3

#define fadingDelayTime 40 // fading time between level of fades

// initialize the serial ports
SoftwareSerial mySoftwareSerial(10, 11); // RX, TX

Azatrax RIR4(0x38); // Create RIR4 as an instance of class Azatrax.

// initialize the mini player
DFRobotDFPlayerMini myDFPlayer;

void setup()
{

  // set the LED pins for communication
  pinMode(AshPit1, OUTPUT);

  // setup the mini player
  mySoftwareSerial.begin(9600);
  Serial.begin(115200);
  // Serial.println(F("Initializing DFPlayer module ... Wait!"));
  if (!myDFPlayer.begin(mySoftwareSerial))
  {
  Serial.println(F("Not initialized:"));
  Serial.println(F("1. Check the DFPlayer Mini connections"));
  Serial.println(F("2. Insert an SD card"));
  while (true);
  }

  // Serial.println();
  // Serial.println(F("DFPlayer Mini module initialized!"));
  myDFPlayer.setTimeOut(500); //Timeout serial 500ms
  myDFPlayer.volume(20); //Volume 5
  myDFPlayer.EQ(0); //normal equalization
  //myDFPlayer.start();

}

    bool ashPit1SoundPlayed = true;
    bool blowOffSoundPlayed = true;

// main loop
void loop()
{

    static byte i2cAddr;
    static byte detNum;
    static byte devData;
    static byte newThr;

   // Read the contents of RIR4's internal register 0 (detector state bitmap).
    // The upper four bits should all be 0.
    devData = RIR4.getDetData(0x00);
    if(0xFF == devData) 
    {
        // If an unexpected value was received, then...
        i2cAddr = (byte)RIR4.devAddr;   // Get the address that was used when this
                        // RIR4 was initialized at the top of this sketch.
                        // Convert it to byte format.
//        Serial.print("Device at address 0x");
//        Serial.print(i2cAddr, HEX);     // print in hexadecimal format
//        Serial.println(" did not respond as expected.");
    }
    else 
    {
        // A good reply was received...
//        Serial.print("Detector state bitmap: ");
//        Serial.println(devData, BIN);   // print in binary format

        // Using the boolean functions:
        Serial.print("Detector 4:");
        if(true == RIR4.detOccupied(4))    // this function returns 'true' when the
        {

            Serial.print("occupied");       // specified detector is sensing an object
        }
        else 
        {
            Serial.print("vacant  ");
        }
        Serial.print(" detector 3:");
        if(true == RIR4.detOccupied(3))  // this function returns 'true' when the
        {   
            Serial.print("occupied");       // specified detector is sensing an object
        }
        else 
        {
            Serial.print("vacant  ");
        }
        Serial.print(" detector 2:");
        if(false == RIR4.detVacant(2) && blowOffSoundPlayed == false)  // this function returns 'true' when the specified detector is not sensing an object
        { 
            Serial.print("occupied");  // 
            myDFPlayer.start();
            myDFPlayer.play(1); //Play the blowoff sound byte
            myDFPlayer.stop();
            blowOffSoundPlayed = true;
        }
        else 
        {
            Serial.print("vacant");
            blowOffSoundPlayed = false;
        }
        Serial.print("  detector 1:");
        if(false == RIR4.detVacant(1) && ashPit1SoundPlayed == false) // this function returns 'true' when the specified detector is not sensing an object
        {  
            Serial.println("occupied");
            ashPit1SoundPlayed = true;
            myDFPlayer.start();
            myDFPlayer.play(2); //Play the ash pit sound byte
            myDFPlayer.stop();
            delay( 1000 );

            // This is simulating the ashing being dumped and the glow from the ashes are fading.
            for (int ashGlowValue = 255; ashGlowValue >= 0; ashGlowValue -= 1) // fades out 
            {
              analogWrite(AshPit1, ashGlowValue);
              delay(fadingDelayTime);
            }
        }
        else 
        {
          Serial.println("vacant");    // 
            analogWrite(AshPit1,0);
            ashPit1SoundPlayed = false;
        }

     }
 
}

Are you showcasing a finished product or do you look for an answer to your question?

Your "bool" stays in the "play the sound" state while the train is being detected. Immediately inside the "bool" condition, set a new "bool playOnlyOneTime = 1" flag, and if that flag says "sound was already played" then skip playing the sound. After "train is departed" you can set that "playOnlyOneTime" back to false.

I'm looking for an answer. I was explaining what was being done so that somebody can understand what I'm doing. I'll take a look at the code again, but I thought that's what I was doing with the use of one bool instead of 2.

Yes, I am doing exactly that. I use a bool (flag) to help determine whether or not to play the sound. After the sound is played, then I set the bool (flag) accordingly.

Okay... this is a chunk of your code with a form of the flag thing I described...

    if (false == RIR4.detVacant(2) && blowOffSoundPlayed == false) // this function returns 'true' when the specified detector is not sensing an object
    {
      Serial.print("occupied");  //
      if (!alreadyPlayed) { // only play the sound one time
        alreadyPlayed = 1; // SORRY... I FORGOT THIS FLAG
        myDFPlayer.start();
        myDFPlayer.play(1); //Play the blowoff sound byte
        myDFPlayer.stop();
      }
      blowOffSoundPlayed = true;
    }

You want to ONLY SKIP THE AUDIO and not the resetting/setting other flags or printing stuff.

You need to declare and configure "alreadyPlayed" and its scope.

Your "play the sound" is tied to "train is detected"... and every time "train is detected" a sound will play. The example will allow the sound ONLY ONE TIME, then it skips the sound.

Not at my PC so cannot test your code. But it sounds like you’ve made a familiar mistake. I think you’re detecting when a train is present, rather than when it became present.

EDIT @xfpd beat me to it!

This is a snippet of my code now. Unfortunately, I'm still having the same problem. It's as if the flag isn't being set.

bool blowOffSoundPlayed = true; // this is declared at the top as a global variable.

       if(RIR4.detOccupied(2) ) 
        { 
            Serial.print("occupied");   
            if( !blowOffSoundPlayed ) 
            {
              blowOffSoundPlayed = true;
              myDFPlayer.start();
              myDFPlayer.play(1); //Play the blowoff sound byte
              myDFPlayer.stop();
            }
  
        }
        else 
        {
            Serial.print("vacant");
            blowOffSoundPlayed = false;
        }

Not sure what happened here, but it seems to be working now! Thanks for the help

1 Like

You have a second sound that needs the same fix.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.