How to Make a Swimming Stopwatch using Shock Sensor – KY-002

ky-002

In this tutorial, I am going to show the working principle of a KY-002 shock sensor module and how to set up and use it using Arduino Mega 2560. As an example, I will use it to develop an automatic swimming practice stopwatch, but it can be used similarly in a variety of applications.

Parts Required

  • Arduino Mega 2560;
  • USB 2.0 Cable Type A/B;
  • 1 KY-002 Shock Sensor Module;
  • 1 Liquid Crystal Display (LCD);
  • 1 220Ω resistor;
  • 1 10kΩ potentiometer;
  • 1 Active Buzzer;
  • 2 Push-Buttons;
  • Male to male jumper wires;
  • 1 Breadboard;

Note: Since only 10 digital pins are required for you to follow this tutorial, an Arduino Uno board or any similar board can be used instead. Just be sure to change the pin numbers in the code if necessary.

One day, I was looking into my sensor kit, trying to have an epiphany for my next tutorial, and I found a KY-002 shock sensor module. I thought I could do something interesting or fun with it, but all I could think about was an alarm in case someone is trying to break in or a toy that plays a song if a child shakes it. Not that these are not good ideas, but I was not quite convinced about them. And then, it hit me! I remembered my wonderful times as a swimmer and how difficult it was sometimes for my coach to keep track of the split times for the whole team. So, I have developed an automatic swimming practice stopwatch, which basically shows the split and split time for a few seconds whenever a swimmer touches a swimming touchpad like the one shown in Figure 1.

Figure 1 – Swimming touchpad.

The logical sequence of this system is as follows:

  1. The coach starts the system whenever he wants to start a new set;
  2. A sound signal starts in order to warn the athletes that the set is about to start;
  3. The chronometer and split times are displayed to the coach;
  4. When the set is over, the coach resets the system.

The Shock Sensor

The shock sensor module (Figure 2) is a very simple piece of hardware that functions as a switch whenever a vibration occurs. According to this module’s datasheet, it has 3 pins: 2 input pins to connect to 5V and ground and one output pin which is the signal pin in case it detects vibration.

Figure 2 – KY-002 shock sensor module.

The working principle of this sensor is very simple. From Figure 3, we can see that it is composed of a thin metal spring that is around a conductor leg. These two parts are protected by an outer case. When the sensor is shaken, the metal spring touches the conductor leg, allowing the flow of current between them. To avoid short-circuits, a resistor is added to this circuit (usually a 10kΩ resistor).

Figure 3 – Shock sensor circuit.

Circuit

One very important aspect of this sensor has to do with the connection of the internal resistor. It can either be connected between pins 1 and 2 or between pins 2 and 3. In my case, the second connection mode applies, thus the internal circuit schematic of the sensor is as shown in Figure 4 [1]. For this reason, and since I want it to work as a pull-down resistor, the correct way to connect the sensor is:

  • Pin 1 – 5V;
  • Pin 2 – 0V;
  • Pin 3 – Arduino digital pin 12.
Figure 4 – Internal circuit’s schematic of the sensor.

Then, we can connect the START and RESET buttons to ground and to Arduino digital pins 1 and 2, respectively.

The LCD display follows. For detailed info regarding this hardware, be sure to check this tutorial. Connect the LCD pins as follows:

  • Pin 1 (VSS) – 0V;
  • Pin 2 (VDD) – 5V;
  • Pin 3 (VE) – 10kΩ potentiometer;
  • Pin 4 (RS) – Arduino digital pin 9;
  • Pin 5 (RW) – 0V;
  • Pin 6 (E) – Arduino digital pin 8;
  • Pin 11 (D4) – Arduino digital pin 7;
  • Pin 12 (D5) – Arduino digital pin 6;
  • Pin 13 (D6) – Arduino digital pin 5;
  • Pin 14 (D7) – Arduino digital pin 4;
  • Pin 15 (Backlight Anode) – 5V (with the 220Ω resistor);
  • Pin 16 (Backlight Cathode) – 0V

Finally, connect the positive terminal of the buzzer to Arduino digital pin 11 and the negative terminal to ground (check this tutorial for more info on active and passive buzzers). In the end, your circuit should be set as shown in Figure 5.

Figure 5 – Circuit’s schematic.

Unfortunately, I don’t have the necessary equipment to implement a complete and fully operational automatic stopwatch for all the lanes in a swimming pool (we do the work with what we have, right?). However, I wouldn’t be surprised if the working principle described in this tutorial is in fact very similar to the one used in a real timing system applied to swimming.

Code

At last, we can start developing our code! Regarding the previously mentioned logical sequence of the system, the code presented below follows the same steps. After setting up the LCD and the system’s inputs and outputs, the code waits for the user to start the timing process by pressing the start button Meanwhile, the LCD displays a message indicating that the system is ready to start.

Then, the countDown() function was developed to activate the buzzer only after the START button has been pushed. This is performed with 3 beep sounds, simulating a count down effect of 3 seconds. Simultaneously, a message indicating the remaining seconds for the chronometer to start is displayed.

Afterwards, the chronometer() function was developed. This function is responsible for showing the running time and the slip number and time whenever an impact is detected by the shock sensor. Regarding the split number and time, a timer mechanism is used for these to be displayed for a few seconds. While these values are being displayed, the system will not detect a new impact. This was done on purpose, in order to limit the detection of a new impact for a certain amount of time, which is sufficient for the athlete to make the turn (only the first impact is considered) and does not exceed the time it takes the athlete to do the following split.

In case the user presses the RESET button, all the system is reset and it is then ready to start the entire process again.

#include <LiquidCrystal.h>

const int shockSensor = 12; //Defines shock sensor digital pin (12)
const int buzzer = 11;      //Defines buzzer digital pin (11)

// Push-Buttons related variables
const int startButton = 1;  //Defines start button digital pin (1)
const int resetButton = 2;  //Defines reset button digital pin (2)
bool stopwatch = 0;         //Variable to manage the stopwatch
bool getReady = 0;          //Variable to manage the buzzer warning

// Chronometer related variables
int cents = 0;                          //Counter for the hundredths of seconds
int seconds = 0;                        //Counter for the seconds
int minutes = 0;                        //Counter for the minutes      
int hours = 0;                          //Counter for the hours 
int c1, c2, s1, s2, m1, m2, h1;         //Variables used to put the running time in the form h1:m2m1:s2s1:c2c1
int c_1, c_2, s_1, s_2, m_1, m_2, h_1;  //Variables used to put the split time in the form h_1:m_2m_1:s_2s_1:c_2c_1
const int milisToCent = 10;             //Every 10 milliseconds there is an increase one hundredth of a second
const int showInterval = 1000;          //It shows the split number and time for a few seconds
unsigned long currentMillis = 0;        //Variable to ensure timing
unsigned long previousMillis = 0;       //Variable to ensure timing
int showTime = 0;                       //Counter of the time spent showing the split time
int countSplits = 1;                    //Counter of splits
bool showSplit = 0;                     //Auxiliary variable for the split time display
bool splitTime = 0;                     //Auxiliary variable to get the split time digits

// Defines the LCD's parameters: (rs, enable, d4, d5, d6, d7)
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);

void setup() {
  
  //Definition of the system's inputs and outputs
  pinMode(startButton, INPUT_PULLUP);
  pinMode(resetButton, INPUT_PULLUP);
  pinMode(buzzer, OUTPUT);
  // Set up the LCD's number of columns and rows
  lcd.begin(16,2);
  
}

void loop() {

  //If the reset button is pressed, the timer is reset
  if (digitalRead(resetButton) == LOW) {
    lcd.clear();
    stopwatch = 0;
    getReady = 0;
    cents = 0;
    seconds = 0;
    minutes = 0;
    hours = 0;
    showTime = 0;
    countSplits = 1;
    splitTime = 0;
    showSplit = 0;
   }
  
  //Keeps displaying "PRESS START BUTTON..." while the start button is not pressed
  if (stopwatch == 0){
    while(digitalRead(startButton) == HIGH) {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("PRESS START");
      lcd.setCursor(0, 1);
      lcd.print("BUTTON ...");
      delay(200);
     };  
  }

  //Starts the buzzer count down sequence
  if (getReady == 0){
    countDown();
  }
  
  //Starts the chronometer         
  chronometer();
}

// Buzzer warning 3 seconds before the chronometer starts
void countDown(void){

    //Initial 
    lcd.clear();
    lcd.setCursor(2, 0);
    lcd.print("STARTING IN");
    lcd.setCursor(7, 1);
    lcd.print("3");
    
    digitalWrite(buzzer, HIGH);
    delay(500);
    digitalWrite(buzzer, LOW);
    delay(500);
    
    lcd.setCursor(7, 1);
    lcd.print("2");
    
    digitalWrite(buzzer, HIGH);
    delay(500);
    digitalWrite(buzzer, LOW);
    delay(500);
    
    lcd.setCursor(7, 1);
    lcd.print("1");
    
    digitalWrite(buzzer, HIGH);
    delay(500);
    digitalWrite(buzzer, LOW);
    delay(500);

    lcd.clear();

    //For the buzzer count down sequence to happen only once after the start button is pressed
    getReady = 1;
 
}

//Display of the current time and split times
void chronometer(void){   
  
  stopwatch = 1;
  currentMillis = millis();  //Initiates timer variable

  //If 10 milliseconds have passed, it is incremented one hundredth of a second to the chronometer
  if (currentMillis - previousMillis >= milisToCent) {  
    previousMillis = currentMillis;
    cents++;
    //100 hundredths of a second = 1 second
    if (cents == 100){
      cents = 0;
      seconds++;
      //60 seconds = 1 minute
      if (seconds == 60) {
        seconds = 0;
        minutes++;
        //60 minutes = 1 hour
        if (minutes == 60){
          minutes = 0; 
          hours++;
          //Just resets the hours if it ever reaches 24 hours
          if (hours == 24){
            hours = 0;
          }
        }
      }
    }

    //Time digits division for it to be displayed as intended (h1:m2m1:s2s1:c2c1)
    int c = cents;
    int s = seconds;
    int m = minutes; 
    int h = hours;  
    
    c1 = c%10;
    c /= 10;
    c2 = c%10;
    s1 = s%10;
    s /= 10;
    s2 = s%10;
    m1 = m%10;
    m /= 10;
    m2 = m%10;

    //Current time display
    lcd.setCursor(3, 0);
    lcd.print(h1);
    lcd.print(':');
    lcd.print(m2);
    lcd.print(m1);
    lcd.print(':');
    lcd.print(s2);
    lcd.print(s1);
    lcd.print(':');
    lcd.print(c2);
    lcd.print(c1);
    
  }

  //If the shock sensor detects a vibration 
  if (digitalRead(shockSensor) == 1){
    showSplit = 1;
  }

  //Get the time digits at the moment the shock sensor detected a vibration
  if (showSplit == 1){
    if(splitTime == 0){
      c_1 = c1;
      c_2 = c2;
      s_1 = s1;
      s_2 = s2;
      m_1 = m1;
      m_2 = m2;
      h_1 = h1;
      splitTime = 1;
    }  

    //Split time display
    if(showTime <= showInterval){
      lcd.setCursor(0, 1);
      lcd.print(countSplits);
      lcd.setCursor(3, 1);
      lcd.print(h_1);
      lcd.print(':');
      lcd.print(m_2);
      lcd.print(m_1);
      lcd.print(':');
      lcd.print(s_2);
      lcd.print(s_1);
      lcd.print(':');
      lcd.print(c_2);
      lcd.print(c_1); 
      showTime++;        
    }

    //Increment split count and resets split time display process
    else {
      showTime = 0;
      countSplits++;
      splitTime = 0;
      showSplit = 0;
      lcd.clear();
    }
  }
}

That’s it! If you enjoyed this tutorial, you can visit our YouTube channel and watch this and many other tutorials. Thanks for following us and be sure to rate, comment and share our content.

References

[1] https://create.arduino.cc/projecthub/WellTronic/ky-002-shock-sensor-module-48be92

Towards the Future !!!

😉

Leave a Reply

Your email address will not be published. Required fields are marked *