Projects

Three Stage Clap Switch

Mike Hansell

Issue 7, January 2018

This article includes additional downloadable resources.
Please log in to access.

Log in

Before voice control was everywhere, there were clap switches. These simple devices are easy to build, and provide clever functionality.

While Siri and her friends provide very comprehensive responses to sometimes complex voice commands, what if you really only have a simple outcome required. Clap activated switches are still a handy piece of kit. While you can certainly develop a clap switch without a microcontroller, it gives us more flexibility to adjust parameters without changing hardware. Given the ever-falling cost of the micros, it's quite cost effective to use one even for simple projects like this one.

The benefit of something simple like a clap switch is that there's no voice processing. This means it's offline, WiFi free, with no reliance on any external factors. Of course, just as voice-controlled hardware works best with low ambient noise, this circuit does too. However we'll intelligently adapt to ambient noise, so as long as you're "louder", it should still work as expected. All of this within thresholds, of course. If you're having a big party with loud music, you might be clapping for some time before the switch activates. That's probably not the time to demonstrate your DIY clap switch to your friends and family!

THE BROAD OVERVIEW

This project uses a small electret microphone to detect the sounds in the environment, and of course, “listen” to our claps. The microphone is fed into our Arduino via a very small amplifier circuit. This provides a useful signal for the Arduino to monitor and process. If a sound is detected above a certain threshold, that is one clap, the Arduino sits up and takes notice. If another is detected within a certain timeframe, then that’s a double clap. We're actually taking things one-step further, for a triple clap detection. In this project we're triggering a simple relay module, which provides us with a useful output to control whatever you like. Of course, you can omit the relay and modify the code to trigger just about anything.

This triple-clap configuration can easily be modified in the Arduino software, to only listen for a single or double clap. However we wanted it to be reasonably robust and less prone to false triggering. A single "clap" could mistakenly be triggered from a door slamming shut in the wind, dropping something on the floor, and many other actions that create a loud noise. However most "accidental" options won't trigger a succession of three loud noises.

HOW IT WORKS

You have probably come across electret microphones in various educational projects. They're cheap, offer high sensitivity, and work rather well for what they're designed for. Often used as a cheap microphone for FM bugs and other audio projects. They're not high fidelity, but for this purpose it's of little consequence.

In this project, our small electret microphone to listen for claps means it is very sensitive to vibration. The mic feeds a small one transistor amplifier and the output of that is fed to an Arduino for analog to digital conversion; it’s much easier to deal with this in the digital realm.

If a signal is detected above a certain threshold, there is one clap. If another is detected within a certain timeframe, then there is a double clap. It can also detect triple claps. A critical aspect of this situation is that every environment has background noise. Many years ago my instructor took our class into a “soundproof” room. Sure enough, initially we could hear nothing. But within a few minutes our ears, or maybe our brains, adjusted to the low background noise levels and we could hear people walking by and speaking. This project tests the background sound level each minute, and sets a threshold level based on that.

THE BUILD

We constructed the prototype on a breadboard. In an effort to isolate the mic from vibration, we’ve tried mounting it away from the desk, on a piece of fabric, and other variables; but the background noise seems to be unaffected. The amplifier uses just a handful of common components and values are not critical. There are just three connections to the Arduino, being 5V and ground to power the pre-amp and the output back to the Arduino.

To keep electrical noise to a minimum we’ve specified a BC549 transistor. This is the low noise version of the BC548. There is another member to this family, which is the BC547; this can handle a higher voltage. Of course, breadboards are electrically noisy, so moving it to veroboard isn't a bad idea, and will only improve performance further.

Parts Required:JaycarAltronics
1 x Arduino Nano (or Better) XC4414 Z6372
1 x BC549 NPN Transistor ZT2156 Z1044
1 x Electret Microphone AM4010 C0160
1 x 1k Resistor RR0572 R7558
2 x 10k Resistors RR0596 R7582
1 x 100k Resistor RR0620 R7606
2 x 0.1uF Greencap Capacitor RG5125 R2736B
1 x Relay Module XC4419 Z6325
Optional:
1 x Red LED ZD0100 Z0700
1 x Green LED ZD0120 Z0701
1 x Blue LED ZD0130 Z0707
3 x 220Ω Resistors RR0556 R7542

The parts list included in our schematic and prototype contains optional LEDs. They're the "clap" indicators which illuminate when claps are detected. This is valuable for debugging and experimentation, but if you're mounting it into a case to use, they can be omitted.

BUILDING THE CIRCUIT

breadboard diagram

Build a prototype onto breadboard following the diagram above. Take care with the orientation of the BC549 transistor (ours is shown flat-side down).

As noted in the parts list on the previous page, the three LEDs and their associated current-limiting resistors are optional. These provide a great visual indication of what's happening, though we provide this feedback to the serial monitor also, if you're testing while connected to your computer.

The current requirements are very low, so you can use the 5V power from your Arduino to run the circuit.

As the microphone is rather sensitive, it is wise to mount it off the breadboard. Some light duty figure-8 cable is often a good choice for connection (simply tin stranded cable with your soldering iron to insert it into the breadboard more easily). Though keep in mind we're amplifying a small signal, so long leads can potentially introduce more noise to the circuit depending on your working environment.

circuit
We have demostrated this circuit using an Arduino Mega and UNO, as that's what we had handy. However you can pretty much any Arduino-compatible board.
It's also worth noting that most relay moduleshave an activation light on them to indicate relay activation. If your module does not have this, you can simple connect an LED (with suitable current-limit resistor) to the relay contacts.

THE CODE

You'll find the code in the digital resources. Load the code onto your Arduino, and check all of your connections. Serial monitor is very useful here, as well as the circuit's optional LEDs if installed.

We have tried to make the code as versatile as possible, to try and establish working parameters automatically in any environment. In a particularly noisy environment (sound noise, not electrical noise), it's possible that sound levels will be such that our determined threshold is too high to be useful. But a clap switch in a very noisy environment probably isn't the best idea anyway.

There is no additional hardware configuration for this project. Instead, the code will attempt to determine the background sound level. It does this by taking 1,000 samples, and averaging those out. You can see this in the FindAveBGLevel() function below. This function not only determines the average background level, but sets a "clap threshold" at around 135% of ambient. During development we found this to be a good level to avoid incorrect detection, but also not miss too many either. It's a fine balance, and you can experiment with adjustments to this value to see the results. Adjustment to this may be required in particularly noisy environments too.

void FindAveBGLevel()
{
  int i;
  unsigned long sum = 0; Serial.print("...calculating background 
sound level...  ");
  for (i = 0; i < 1000; i++) // 1000 samples
    {
    sum += analogRead(micPin);
    delay(1);    
    }
  threshold = int((sum/1000) * 1.35); // avg of samples plus clap level
  mySPL("threshold set at ", threshold);
} // End of FindAveBGLevel()

You may notice the function we've called here "mySPL". This is a helper function to effectively Serial.print() more easily. Arduino currently doesn't support different variables together very well, so this helper function allows us to do it with one line of code.

void mySPL(String p1, unsigned long p2)
{
  Serial.print(p1);
  Serial.println(p2);
} // End of mySerialprintln() 

Though it's important to note that Serial.print() does slow things down. When we're trying to detect a clap which can last a tiny fraction of a second, we could be too busy printing outputs and miss the next clap. This was OK in original testing, but should be kept out of the system (outside of setup functionality) whenever possible. It was for this reason we added the three LEDs. These visual indicators of how many claps it's recorded in a series, is valuable feedback.

We want to detect a series of claps in quick succession, otherwise there's little point to counting multiples. In that scenario, a clap from one day could contribute to a clap the next day, and so on. Our main loop runs perpetually, continuously sampling, checking if there's a clap above the automatically-adjusted threshold.

level = analogRead(micPin);
if (level > threshold) // we have a sample above the threshold
    {
    clapcount = 1;      
    digitalWrite(LED1, LOW);
    digitalWrite(RelayPin, HIGH);

Detecting one clap is easy, but we need to intelligently handle multiple claps. This is handled by a loop that's entered when we first detect a clap. The code takes another 1,000 audio samples, looking for a second, and a third clap above the background threshold. This process runs for 2-3 seconds total, which is more than enough to get a few claps in with little effort.

for (i = 0; i < 1000 * dctimeout; i++)  
      {
      level = analogRead(micPin);
      if (level > threshold) // we have a sample above the threshold
        {
        clapcount += 1;
        delay(40);

You'll notice that on the second last line of the above snippet, we're keeping track of "clapcount" variable. This holds the number of claps, meaning we can remain in the same loop to do the sampling.

From this point, we increment the "clapcount" to 2 or 3, based on detection. This is kept quite straight forward in the code, to make it easy to trigger various fuctions at different steps, based on your own requirements.

We could have created a function but the code is so simple, keeping it literal maintains readability.

if (clapcount == 2)
          {
          digitalWrite(LED2, LOW);
          delay(40);
          }
          
        if (clapcount == 3)
          {
          digitalWrite(LED3, LOW);
          delay(40);
          }

The 40 millisecond delay is also added to help avoid double-sampling the same clap.

To action the relay, or perform any other function at this stage. Simply insert your code between the digitalWrite and the delay functions (although really, anywhere within the IF statement works fine). We have a relay trigger on the first clap in our example code. To trigger another relay, or any other action, you can trigger it similarly to the code below.

if (clapcount == 2)
          {
          digitalWrite(LED2, LOW);
           digitalWrite(RelayPin, HIGH);
          delay(40);
          }

You'll also notice that we're setting the relevant LEDs to LOW. This is purely a design choice. This active high state works pretty much the same as active low for LEDs. However instead of the Arduino providing the power for the LED (with the LED's cathode grounded), we provide the ground by setting the pin to low. The only thing to note here is that the LEDs must be the correct orientation to work this way, which may be reverse of what you're used to doing.

Finally, after around 1-minute, the background level is automatically adjusted. For this reason, the device would be more sensitive at night for instance, than through the day when there's probably a lot more general background noise. Likewise, if you suddenly turn the TV on, the device isn't going to treat all noise as a clap.

Though, it is worth noting that we're still working with a 35% threshold between what is a clap, and what is purely background noise. If you suddenly go from a quiet household to having your music blasting, the background level may not have had a chance to re-adjust. Though, of course, you're going to have to be able to clap louder than your loud music anyway, so it may be rendered ineffective.

On that note, there is one hack you could implement on the code, to help work with noisy environments. It would effectively "disable" the switch while high average noise levels are detected.

In the main loop, you can add a condition such as below, before the first level comparison.

void loop() 
{
  int i;
  
  level = analogRead(micPin);
  
  if (threshold < 800)   // new line
    {                    // new line
    if (level > threshold)
       {

Some experimentation would need to be done to determine the correct threshold where the system ignores all noise, but you get the idea (don't forget to add a closing curly-brace at the end for your new if condition).

The background level sensing is re-run every minute or so, so once the music (or whatever the noise source was) was turned off, function would quickly resume normally.

WHERE TO FROM HERE?

We're driving relays here, which are probably the most useful output in a "switch on / switch off" environment. What more can you do?

You now effectively have a powerful clap-detecting switch. The more claps required, the less likely it is to be triggered unintentionally. You can experiment, expanding functionality to 6 or 10 claps, to perform very different functions based on how many claps are detected!

Perhaps it can form a fun game. See how many loud claps you can get in before the system resets!