Connect with us

Detecting A Knock Pattern

Discussion in 'Microcontrollers, Programming and IoT' started by Jouellet, Mar 31, 2016.

Scroll to continue with content
  1. Jouellet

    Jouellet

    86
    19
    Feb 2, 2015
    Hi everyone,

    I'm looking for a way to detect a knock pattern. something like:

    toc----toc---------------toc

    Getting the 'toc' shouldn't be a big problem: I'm planning on using a microphone or a piezo, and detect 'spike' of signal, corresponding to the knock themselves.

    I mostly use Arduino, but open to any other solution. Anyone has an idea on how to 'record' the pattern, and recognize it with a certain 'room' for similar pattern, as 2 knock sequences will never be perfectly the same.
     
  2. Gryd3

    Gryd3

    4,098
    875
    Jun 25, 2014
    I can think of two ways immediately to do this.
    Both require a hard-coded knock pattern, but I'm sure they can be adjusted to be dynamically programmed.
    The first knock will have no variation, initialize a timer here. Subsequent knocks will trigger a comparison of the timer to the currently stored value, and if the timer is within range, allow it to proceed to the next knock, otherwise exit your 'listen' loop and show an error.
    The narrower this variation, the more exact the knock will need to be. If the second knock time is set to 500ms , and your variation is set to 20ms, then the second knock should be accepted anywhere from 480ms to 520ms.

    The other method is less 'timer' orientated, and will be designed more like a 'bit-mask' ...
    A bit mask for your included knock pattern could be b10000101 .. The first knock would start the process of course. Each bit could represent 100ms for example, but this could be adjusted. After each 'time' unit, you can 'shift' this binary 'mask' and compare the bit on the end. If a knock happens while that bit is a 1, it's accepted. Otherwise you show an error and end you loop. You can use more than 8 bits for the mask and adjust timing based on the accuracy you want.

    That is the two ideas I would try. But there is always more than one way to do things when it comes to code and design!
     
    Jouellet likes this.
  3. duke37

    duke37

    5,334
    750
    Jan 9, 2011
    There are morse code receiving programs. I wrote one many years ago for an Acorn Atom. The more I sent, the more the program seemed to understand me.:)
     
    Gryd3 likes this.
  4. wingnut

    wingnut

    237
    8
    Aug 9, 2012
    I would try a frequency counter. There are plenty of free programs out there, including for Arduino, which are able to return a frequency of some regular repetitive motion, as a value in Hertz. Just do a Google search for "frequency counter" and "software". Through your computer mic. you should be able to detect the pattern. In your case patterns, since it has at least two frequencies.
     
  5. Colin Mitchell

    Colin Mitchell

    1,418
    314
    Aug 31, 2014
    This circuit only turns ON when it detects 2 knocks:
    [​IMG]
     
  6. Jouellet

    Jouellet

    86
    19
    Feb 2, 2015
    Hi Guys,

    follow up on my project.

    I did it by enabling the interrupt to capture when a knock is detected, then sampling every 25ms and saving the result.

    I "teach" the sequence and for every position where a bit is recorded, I set the 2 bits before and after to '1', therefore making it a bit easier to get the same exact pattern when reading.

    Every time a bit is expected and found, I keep doing a comparison. if I end my sampling sequence and found a '1' when one was expected, I call it a good code !

    I first tried with a piezo, but I had to knock exactly where the piezo is. Result was not so impressive.

    Ended up using a microphone as the pickup element.
     
    Gryd3 likes this.
  7. hevans1944

    hevans1944 Hop - AC8NS

    4,455
    2,073
    Jun 21, 2012
    So, your spiffy program can detect a "shave and a hair-cut... two bits" knock pattern? I'm impressed.

    Next will be whistle codes I suppose, maybe followed by voice recognition... hmmm. How about recognizing tunes, like the theme from the movie Close Encounters of the Third Kind?
     
    Last edited: May 2, 2016
  8. Jouellet

    Jouellet

    86
    19
    Feb 2, 2015
    Hevans1944: Being francophone, I'm not sure what you mean by "shave and a hair-cut... two bits", but I guess it's positive !

    As for whistle recognition, I like your optimism, but I don't think it's going to happen soon !

    For those interested, here's the (almost) final code:
    Code:
    /*
    * knock detector
    * Jasmin Ouellet
    * [email protected]
    *
    * pin 2 = Digital pulse from microphone board
    * pin 4 : learn/run toggle switch
    * pin 11: high/low sensitivity jumper
    * pin 12: output connected to an Opto/relay
    *
    * Print to serial port enabled for debugging
    *
    * still need to save/recall bytes containing knock pattern to EEPROM
    */
    
    
    
    
    #include <TimerOne.h>
    
    bool Learning = 0;
    bool Reading = 0;
    bool RawData[65];
    bool DataRead[65];
    bool SavedData[65];
    byte Data[12];
    int  Pointer = 0;
    int  Pos = 0;
    bool GotOne = 0;
    int  SetNextOne = 0;
    bool KeepGoing = 0;
    bool KnockDetected = 0;
    
    void setup()
    {
      attachInterrupt(0, StartAcquisition, RISING);
      pinMode(2, INPUT);
      pinMode(4, INPUT);
      pinMode(11, INPUT);  
      pinMode(12, OUTPUT);
      digitalWrite(12,LOW);
      Serial.begin(9600);
      Timer1.initialize(50000);                 // set a timer of length 50000 microseconds (or 0.05 sec)
      Timer1.attachInterrupt( timerIsr );       // attach the service routine here
      Serial.println("Erasing Data");           //Debug message
    for (int i=1; i <= 63; i++)
        {
        RawData[i] = 0;                         // Erase everything
        DataRead[i] = 0;                        // Erase everything
        }
        Serial.println("Setup Done");
    }
    void loop()
    {
    if (Pointer == 64)                          // all sample acquired
      {
    // what if we are in Learning mode
      if(Learning == 1)
        {
        Learning = 0;
        for (int w=0; w <= 7; w++)
          {
          Data[w] = 0;
          for (int i=0; i <= 7; i++)
            {
              Pos = (w*8)+i;
              Serial.print(RawData[Pos]);         // debug message
            }
          Serial.println("");
          }
        Pointer = 0;          
        BuildBytes();                             //Go transform bits into bytes
        }
    
    // what if we are in Reading mode
      if(Reading == 1)
        {
        //Reading = 0;
        for (int w=0; w <= 7; w++)
          {
          Data[w] = 0;
          for (int i=0; i <= 7; i++)
            {
              Pos = (w*8)+i;
              Serial.print(RawData[Pos]);         // debug message
            }
          Serial.println("");                     // debug message
          }
          Serial.println("with deadband now !");  // debug message
        AddDeadband();                            // go add 1 level of deadband (bit before & Bit after)
    if(digitalRead(11)==1)                        // if "High Sensibility" jumper in place, add another set of deadband
      {
      AddAnotherDeadband();
      }
        for (int w=0; w <= 7; w++)
          {
          for (int i=0; i <= 7; i++)
            {
              Pos = (w*8)+i;
              Serial.print(DataRead[Pos]);         // debug message
            }
          Serial.println("");                      // debug message
          }
        CompareData();                             // check if received data fit with learned bits + deadband
        }
    Pointer = 0;
      }
    
    }
    
    void AddDeadband()
    {
    DataRead[0] = 1;
    for (int i=1; i <= 63; i++)
        {
            if (RawData[i] == 0)
            {
                if(SetNextOne == 0)
                {
                    if(RawData[i+1] == 1)
                    {
                    DataRead[i] = 1;
                    SetNextOne = 1;
                    }
                    else
                    {
                    DataRead[i] = 0;
                    }
                }
                else
                {
                    DataRead[i] = 1;
                    SetNextOne = 0;
                }
             }
            else
            {
            DataRead[i] = 1;  
            }
        }
    
    }
    
    void AddAnotherDeadband()
    {
    DataRead[0] = 1;
    for (int i=1; i <= 63; i++)
        {
            if (DataRead[i] == 0)
            {
                if(SetNextOne == 0)
                {
                    if(DataRead[i+1] == 1)
                    {
                    DataRead[i] = 1;
                    SetNextOne = 1;
                    }
                    else
                    {
                    DataRead[i] = 0;
                    }
                }
                else
                {
                    DataRead[i] = 1;
                    SetNextOne = 0;
                }
             }
            else
            {
            DataRead[i] = 1;  
            }
        }
    
    }
    
    void CompareData()
    {
    
    Serial.println("Begin Compare");             // debug message
    Reading = 0;
    KeepGoing = 1;
    for (int i=1; i <= 63; i++)
        {
        if (SavedData[i] == 1)
          {
          if(DataRead[i] == 0)
            {
            Serial.println("oops !");             // debug message
            KeepGoing = 0;
            }
          }
         else
         {
         }
        }
    if(KeepGoing ==1)
      {
    Serial.println("Code the same");               // debug message
      digitalWrite(12,HIGH);                       // set output (relay) 'ON'
      delay(2500);
      digitalWrite(12,LOW);                        // set output (relay) 'OFF'
      }
    }
    void timerIsr()
    {
    if ((Learning == 1)||(Reading ==1))
      {
      if (KnockDetected == 1)
        {
        Serial.println("knock detected");           // debug message  
        if (GotOne == 0)
          {
          RawData[Pointer] = 1;
          GotOne = 1;    
          }
        else
          {
          RawData[Pointer] = 0;
          KnockDetected = 0;    
          }
        }
      if (KnockDetected == 0)
        {
        RawData[Pointer] = 0;
        GotOne = 0;
        }
      Pointer = Pointer + 1;
      }
    KnockDetected = 0;
    }
    
    
    void BuildBytes()
    {
      Pointer = 0;
      Serial.println("Ready to Build....");             // debug message
        for (int w=0; w <= 7; w++)
          {
          for (int i=0; i <= 7; i++)
            {
            if(RawData[Pointer]==1)
              {
              bitSet(Data[w], (7-i));
              SavedData[Pointer] = 1;
              }
            else
              {
              bitClear(Data[w], (7-i));        
              SavedData[Pointer] = 0;
              }
            Pointer = Pointer +1;
            }
    
          Serial.println(Data[w]);
          }
    }
    
    void StartAcquisition()
    {
    KnockDetected = 1;
    if(digitalRead(4) == 0)
      {
      if(Learning == 0)
        {
        Learning = 1;
        Reading = 0;
        Serial.println("Beginning to learn.....");      // debug message
        }
      }
    
    if(digitalRead(4) == 1)
      {
      if(Reading == 0)
        {
        Learning = 0;
        Reading = 1;
        Serial.println("Beginning to Read.....");       // debug message
        }
      }
    }
    
    I also included a picture of the final montage, with a 3D printed support.

    J.
     

    Attached Files:

    hevans1944 likes this.
  9. hevans1944

    hevans1944 Hop - AC8NS

    4,455
    2,073
    Jun 21, 2012
    The notes at the end of this short YouTube video (located at 0:25) are "shave and hair-cut <short pause> two bits".
     
  10. Jouellet

    Jouellet

    86
    19
    Feb 2, 2015
    Okaaaaay !

    I thought it was some kind of expression in English !

    I actually was able to use that as my knock pattern !

    Due to the closenest of some notes, I had to be a bit slower and could not use the "high sensitivity" on my circuit...
     
  11. hevans1944

    hevans1944 Hop - AC8NS

    4,455
    2,073
    Jun 21, 2012
  12. donkey

    donkey

    1,286
    56
    Feb 26, 2011
  13. Gryd3

    Gryd3

    4,098
    875
    Jun 25, 2014
    Jouellet did it without asking about any pre-existing content on instructables though... I'll consider it a better resource when there is some form of quality control
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-