Draw the total g-force on a live graph and count every jolt and every drop - the two signals the main build looks for.
| Part | How many |
|---|---|
| Wiring from Lesson 2 - nothing new | |
| A book or card with the breadboard taped on, and a cushion (yours) |
The sketch combines x, y and z into one number, the total g: about 1.0 when still, whichever way the sensor faces.
It sets the sensor to ±8 g so a hard landing does not go off the scale (Lesson 2 used ±2 g for finer angles).
A crossing is counted once: only when total g goes above 2.5 g (or below 0.45 g) after being on the other side.
The Serial Plotter draws total_g with the two limits as flat lines, so you can see how close each movement gets.
Every item below is in the kit. Not in the box: A cushion or foam pad to drop the test platform onto (yours).
All 6 parts in one box, with this project and 4 more to build from them.
One of each part. Packs (resistor assortment, jumper wires) already hold more than a single build needs. a foam pad or cushion (yours): included in the kit, ask us for it loose. Backorder parts ship once they arrive. Delivery is AED 20, free on orders AED 100+.
Unplug USB before you change any wire. Pin names are the labels printed on the board.
| Part / pin | Connect to | Note |
|---|---|---|
| No changes | Same as Lesson 2 | GY-521 and OLED on GPIO21/22, button on GPIO26 |
One thing at a time. Tick nothing off until it matches the diagram.
Written for the board in the kit. Copy it into the Arduino IDE; change the pin numbers if you wire it differently.
/*
DIY KIT - ESP32 Fall-Detection Learning Prototype
Lesson 3 of 5: Motion Data Lab
WIRING: the same as Lesson 2 (OLED and GY-521 on GPIO21/22, button on GPIO26).
WHAT SHOULD HAPPEN
Open Tools > Serial Plotter at 115200 baud. The total_g line sits at about
1.0 while the sensor is still. Lift and drop the test platform gently onto
foam: total_g dips towards 0 while it falls and spikes when it lands.
The OLED counts every IMPACT (above 2.5 g) and FREE FALL (below 0.45 g).
Press the button to set the counts back to 0.
Use a padded, unoccupied test platform - never a person.
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
const int SDA_PIN = 21;
const int SCL_PIN = 22;
const int BUTTON_PIN = 26;
const float IMPACT_G = 2.5; // the same limits as Lesson 5
const float FREEFALL_G = 0.45;
const unsigned long SAMPLE_MS = 20; // 50 readings a second
const unsigned long REPORT_MS = 100; // 10 plotter points a second
Adafruit_SSD1306 display(128, 64, &Wire, -1);
bool displayOk = false;
int mpuAddress = 0;
int impacts = 0, freefalls = 0;
bool wasImpact = false, wasFreefall = false;
float peakG = 0, lowestG = 10;
unsigned long lastSample = 0, lastReport = 0;
bool lastButton = HIGH;
bool answers(int address) {
Wire.beginTransmission(address);
return Wire.endTransmission() == 0;
}
bool writeRegister(int reg, int value) {
Wire.beginTransmission(mpuAddress);
Wire.write(reg);
Wire.write(value);
return Wire.endTransmission() == 0;
}
bool readAccel(float &x, float &y, float &z) {
Wire.beginTransmission(mpuAddress);
Wire.write(0x3B);
if (Wire.endTransmission(false) != 0) return false;
if (Wire.requestFrom(mpuAddress, 6) != 6) return false;
int16_t rx = (int16_t)((Wire.read() << 8) | Wire.read());
int16_t ry = (int16_t)((Wire.read() << 8) | Wire.read());
int16_t rz = (int16_t)((Wire.read() << 8) | Wire.read());
x = rx / 4096.0; // +-8 g range: 4096 counts per g
y = ry / 4096.0;
z = rz / 4096.0;
return true;
}
void showCounts(float g) {
if (!displayOk) return;
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println("MOTION DATA LAB");
display.setTextSize(2);
display.setCursor(0, 12);
display.print(g, 2);
display.println(" g");
display.setTextSize(1);
display.setCursor(0, 34);
display.print("impacts "); display.println(impacts);
display.print("free falls "); display.println(freefalls);
display.print("peak "); display.print(peakG, 1); display.print(" low "); display.println(lowestG, 2);
display.display();
}
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT_PULLUP);
Wire.begin(SDA_PIN, SCL_PIN);
displayOk = display.begin(SSD1306_SWITCHCAPVCC, 0x3C) || display.begin(SSD1306_SWITCHCAPVCC, 0x3D);
if (answers(0x68)) mpuAddress = 0x68;
else if (answers(0x69)) mpuAddress = 0x69;
if (mpuAddress == 0 || !writeRegister(0x6B, 0x00) || !writeRegister(0x1C, 0x10)) { // wake up, +-8 g
Serial.println("GY-521 not found - see Lesson 2");
while (true) delay(1000);
}
Serial.println("Lesson 3: open the Serial Plotter");
}
void loop() {
bool button = digitalRead(BUTTON_PIN);
if (button == LOW && lastButton == HIGH) { // press: reset the counts
impacts = 0; freefalls = 0; peakG = 0; lowestG = 10;
}
lastButton = button;
if (millis() - lastSample < SAMPLE_MS) return;
lastSample = millis();
float x, y, z;
if (!readAccel(x, y, z)) return;
float g = sqrt(x * x + y * y + z * z); // total g-force, whichever way it points
if (g > peakG) peakG = g;
if (g < lowestG) lowestG = g;
// Count each crossing once, not every reading above the line.
bool impact = g > IMPACT_G;
if (impact && !wasImpact) impacts++;
wasImpact = impact;
bool freefall = g < FREEFALL_G;
if (freefall && !wasFreefall) freefalls++;
wasFreefall = freefall;
if (millis() - lastReport >= REPORT_MS) {
lastReport = millis();
Serial.print("total_g:");
Serial.print(g, 2);
Serial.print(",impact_line:");
Serial.print(IMPACT_G, 2);
Serial.print(",freefall_line:");
Serial.println(FREEFALL_G, 2);
showCounts(g);
}
}
| In the code | What it does |
|---|---|
| writeRegister(0x1C, 0x10) | Sets the sensor's range to ±8 g: 4096 counts per g. |
| sqrt(x*x + y*y + z*z) | The total g-force, whichever way the sensor points. |
| if (impact && !wasImpact) impacts++; | Counts a crossing only when it starts, not every reading above the line. |
| Serial.print("total_g:") | "name:value" pairs are what the Serial Plotter draws as labelled lines. |
| Problem | What to check |
|---|---|
| "GY-521 not found" | Unplug USB. Check VCC to 3V3, GND, SDA to GPIO21 and SCL to GPIO22. Are the GY-521 header pins soldered? Loose pins pushed through the holes do not make contact. |
| The Plotter shows nothing | Close the Serial Monitor first, then open the Plotter at 115200 baud. |
| Nothing ever crosses the impact line | A soft cushion slows the landing. Try a firmer pad, or lower IMPACT_G to see the data. |
| Counts go up while it sits still | A loose wire or loose sensor. Tape everything down and check SDA and SCL. |
Drop the platform 5 times from 10 cm and 5 times from 20 cm. Write down the peak g each time. Does a higher drop always give a bigger spike?
Close to 0.
Otherwise one impact lasting several readings would count many times.
A landing can go far above 2 g; ±8 g keeps it on the scale.
Most problems are one wire in the wrong hole. Check these first:
Open the troubleshooting table for this step →
Hi DIY KIT, I'm stuck on the ESP32 Fall-Detection Learning Prototype. Lesson: __ Step number: __ What should happen: __ What happens instead: __ Error message (copied exactly): __ I'll attach a photo of my wiring.
The GY-521 learns which way is "upright" in 3 seconds, then the OLED shows how far you have tilted it from there - and flags 55°, the limit the main build uses.
A button starts a 20-second countdown on the OLED and a second press cancels it - the user-interface half of the fall detector, with no motion yet. Do Start here first.
Add the buzzer module (an optional add-on), powered from 3V3: an alert pattern the button acknowledges, with a 15-second time-out so it never runs for ever.
We use cookies that the shop needs to work — signing in, your cart, form security. We also measure how the shop is used so we can stock the right parts and fix what is broken. Choose “Only essential” and we will not load Google Analytics or the Meta pixel, and will not record your visit. Read more.