Walking is one of the easiest and healthiest forms of exercise. Whether you’re casually strolling, hiking, or trying to hit that 10,000-step daily goal, a pedometer is an excellent tool to track your steps. In this project, we will build a DIY ESP32 pedometer using an ESP32 microcontroller, a BMI160 sensor (accelerometer + gyroscope), a 0.96″ OLED display, and a 3.7V lithium-ion battery for portable operation.
This DIY project not only introduces you to the world of motion sensors and embedded systems but also results in a fully functional step counter that you can wear or carry around.
📋 ESP32 step counter project Materials Required
Component | Description |
Wi-Fi + Bluetooth MCU (e.g., ESP32 DevKitC, NodeMCU-ESP32) | |
6-axis accelerometer and gyroscope | |
SSD1306 based, I2C communication | |
Rechargeable 18650 or Li-Po battery | |
For safe battery charging (optional but recommended) | |
5V to 3.3V Regulator (optional) | If using a module without onboard regulator |
Connecting Wires | Female-to-male jumper cables |
Breadboard or PCB | For prototyping |
Enclosure Case (optional) | To create a neat, wearable device |
Note: The ESP32 step counter project also includes a boost converter, a slide switch for power management, and a push button that resets the step counter when pressed. Compact enough to fit in your pocket, this BMI160 pedometer records your walking steps accurately.
🛠️ DIY ESP32 pedometer Circuit Diagram and Connections
The wiring is relatively simple because all the modules communicate via I2C protocol.
🔌 Connections:
ESP32 Pin | Component | Connection Description |
3V3 | OLED VCC, BMI160 VCC | Power for the modules |
GND | OLED GND, BMI160 GND | Common ground |
GPIO21 (SDA) | OLED SDA, BMI160 SDA | I2C Data line |
GPIO22 (SCL) | OLED SCL, BMI160 SCL | I2C Clock line |
Power Supply:
- Connect the 3.7V battery to the VIN (or 5V pin) if your ESP32 board has an onboard 3.3V regulator.
- Use a TP4056 module between your battery and ESP32 if you also want charging support.
⚙️ Setting Up the Environment
You’ll need the following software tools:
- Arduino IDE (Latest Version)
- ESP32 Board Manager installed in Arduino IDE
- Adafruit SSD1306 library for the OLED
- Adafruit GFX library for display graphics
- BMI160 Library (You can install it via Arduino Library Manager or manually)
🧠 Understanding the Core Components of BMI160 pedometer
- ESP32
The ESP32 is a powerful microcontroller equipped with Wi-Fi, Bluetooth, dual-core processing, and sufficient GPIOs for connecting multiple peripherals.
- BMI160 Sensor
The BMI160 is a low-power, high-performance 6-axis IMU (Inertial Measurement Unit) sensor combining an accelerometer and a gyroscope. For our pedometer, we’ll primarily utilize the accelerometer readings.
- OLED Display
The 0.96″ OLED display will visually show the number of steps counted. It supports simple text and graphics with minimal power usage, perfect for battery-powered projects.
🧩 How the ESP32 pedometer Works
- The BMI160 measures the acceleration across the three axes (X, Y, Z).
- Each time your body moves, it creates a rhythmic pattern in acceleration.
- We detect these changes and infer steps using a threshold-based method.
- The step count is then displayed on the OLED screen in real-time.
📜 Arduino Sketch
Here’s a basic version of the code to get you started:
#include <Wire.h> // OLED setup // Variables void setup() { // Initialize OLED // Initialize BMI160 display.println(“Pedometer”); void loop() { float acceleration = sqrt(ax * ax + ay * ay + az * az) / 16384.0; if(acceleration > threshold && !stepDetected) { display.clearDisplay(); delay(100); |
🧪 Wearable step tracker Testing and Calibration
- Upload the code using Arduino IDE.
- Power the ESP32 through the 3.7V lithium-ion battery.
- Walk or shake the device gently.
- Watch the step count increase on the OLED screen.
🔧 Fine-tuning:
- Adjust the threshold value based on your walking style.
- You might need to introduce a debounce timer to avoid double-counting steps.
🔋 Power Management Tips for wearable step tracker
Since the device is battery-powered, here are ways to maximize battery life:
- Use deep sleep modes in ESP32 when idle.
- Lower OLED brightness or update the display less frequently.
- Optimize sensor polling rate — reading accelerometer less often saves power.
- Use high-efficiency switching regulators instead of linear ones.
📦 Enclosure and Wearable Ideas
- 3D print a custom lightweight enclosure.
- Attach a belt clip or wristband.
- Use a small power button to conserve energy when not in use.
- Keep battery accessible for easy recharging via the TP4056 module.
🚀 Possible BMI160 pedometer Upgrades
- Bluetooth Data Sync: Send step count to your phone using ESP32’s Bluetooth.
- Calories Burned Calculator: Estimate calories based on step count and stride length.
- Data Logger: Save daily steps to SPIFFS or an SD card.
- Rechargeable Solar Panel: Attach a small solar charger for extended operation.
🌟 Quick Summary:
- ESP32 handles all processing and display.
- BMI160 detects motion (steps).
- OLED screen shows the number of steps.
- 3.7V Li-ion battery powers everything, making it portable.
🛠 Schematic Connections Table
ESP32 Pin | Connected to | Description |
3V3 | OLED VCC, BMI160 VCC | Power supply (3.3V) |
GND | OLED GND, BMI160 GND | Common ground |
GPIO21 (I2C SDA) | OLED SDA, BMI160 SDA | I2C data line |
GPIO22 (I2C SCL) | OLED SCL, BMI160 SCL | I2C clock line |
VIN (or 5V) | 3.7V Battery (via TP4056 if used) | Main battery input |
🖍 Visual Description (Text-based)
+-----------------------------------------+
| ESP32 |
| +3V3 o------------------+ |
| | |
| GND o---------+ | |
| | | |
| GPIO21 (SDA) o|-----------+--- OLED SDA |
| | +--- BMI160 SDA |
| GPIO22 (SCL) o|-----------+--- OLED SCL |
| | +--- BMI160 SCL |
| | |
| +------> OLED VCC (to 3.3V) |
| +------> BMI160 VCC (to 3.3V)|
| |
| VIN/5V o-----> 3.7V Li-ion Battery (via TP4056) |
+-----------------------------------------+
🛡 Important Notes for this wearable step tracker:
- Both the OLED and BMI160 are I2C devices, so they share the same SDA and SCL lines but must have different I2C addresses.
(Usually, OLED is 0x3C, and BMI160 defaults to 0x68). - Make sure you are powering the BMI160 and OLED with 3.3V, NOT 5V, because the ESP32 and peripherals are 3.3V tolerant.
- If you are using a TP4056 charging module, connect it between the battery and ESP32 to allow safe charging without disconnection.
🔋 Battery and Charging System (Optional)
Here’s a quick simple wiring if you add TP4056:
3.7V Lithium Battery
|
|-- TP4056 IN+
|-- TP4056 IN-
TP4056 OUT+
--> ESP32 VIN/5V
TP4056 OUT-
--> ESP32 GND
This way, you can recharge the battery via a micro-USB connected to the TP4056 while still operating the ESP32!
📷 Simple Diagram (Quick Visual Reference)
3.7V Battery --> TP4056 --> ESP32 VIN/GND
|
+--------------+
|
(3V3 Output)
|
+-------+--------+
| |
OLED VCC BMI160 VCC
OLED GND BMI160 GND
OLED SDA BMI160 SDA --> ESP32 GPIO21 (SDA)
OLED SCL BMI160 SCL --> ESP32 GPIO22 (SCL)
Add the following libraries to the Arduino library folder, before working on the coding and debugging part.
- BMI160 Library: https://github.com/hanyazou/BMI160-Arduino
- Adafruit GFX Library: https://github.com/adafruit/Adafruit-GFX-Library
- Adafruit SSD1306 Library: https://github.com/adafruit/Adafruit_SSD1306
Send Pedometer (Steps Counts) Data over ESP32 BLE
To enhance this project with wireless functionality, you can take advantage of the ESP32’s built-in Bluetooth Low Energy (BLE) feature. You need to modify the original code by adding the necessary BLE libraries and creating a dedicated service and characteristic for the step count data. With these changes, the pedometer will broadcast the current step count to any BLE-enabled device, such as a smartphone or tablet.
Copy the following code and upload it to the ESP32 Board
#include <Wire.h> #include <BMI160Gen.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> // OLED display definitions for a 0.96″ (128×64) display #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 // No dedicated reset pin Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Sensor parameters: const int BMI160_I2C_ADDRESS = 0x68; // BMI160 I2C Address const int INTERRUPT_PIN = 5; // Digital pin used for sensor interrupt // Reset button pin (connected to GP23) const int RESET_BUTTON_PIN = 23; // When pressed, this pin is pulled HIGH // BLE service and characteristic UUIDs (custom values) #define SERVICE_UUID “4fafc201-1fb5-459e-8fcc-c5c9c331914b” #define CHARACTERISTIC_UUID “beb5483e-36e1-4688-b7f5-ea07361b26a8” // BLE characteristic pointer and connection flag BLECharacteristic *pCharacteristic; bool deviceConnected = false; // BLE server callbacks to print connection messages class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; Serial.println(“BLE client connected”); } void onDisconnect(BLEServer* pServer) { deviceConnected = false; Serial.println(“BLE client disconnected”); } }; // Optional: Interrupt callback (for future embellishments) void stepInterrupt() { // This callback is triggered on a sensor interrupt. // The built-in step counter operates independently. } void setup() { Serial.begin(115200); while (!Serial) { } // Wait for Serial Monitor // Configure the reset button pin with internal pull-down pinMode(RESET_BUTTON_PIN, INPUT_PULLDOWN); // Initialize the OLED display if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // OLED I2C address is typically 0x3C Serial.println(F(“SSD1306 allocation failed”)); while (1); } display.clearDisplay(); display.display(); // Initialize BMI160 sensor in I2C mode if (!BMI160.begin(BMI160GenClass::I2C_MODE, BMI160_I2C_ADDRESS, INTERRUPT_PIN)) { Serial.println(“BMI160 initialization failed!”); while (1); } BMI160.attachInterrupt(stepInterrupt); // — Auto-Calibration for Improved Accuracy — // Ensure the sensor is stationary during calibration! BMI160.autoCalibrateGyroOffset(); BMI160.autoCalibrateXAccelOffset(0); // Calibrate X-axis to 0g BMI160.autoCalibrateYAccelOffset(0); // Calibrate Y-axis to 0g BMI160.autoCalibrateZAccelOffset(1); // Calibrate Z-axis to +1g (gravity) // Set accelerometer range to 2g for higher sensitivity in step detection BMI160.setFullScaleAccelRange(BMI160_ACCEL_RANGE_2G); // — Configure the Built-In Step Counter — // Options: BMI160_STEP_MODE_NORMAL, SENSITIVE, or ROBUST BMI160.setStepDetectionMode(BMI160_STEP_MODE_NORMAL); BMI160.setStepCountEnabled(true); BMI160.resetStepCount(); // — Initialize BLE — BLEDevice::init(“ESP32_StepCounter”); BLEServer *pServer = BLEDevice::createServer(); pServer–>setCallbacks(new MyServerCallbacks()); BLEService *pService = pServer–>createService(SERVICE_UUID); pCharacteristic = pService–>createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY ); pCharacteristic–>setValue(“0”); pService–>start(); BLEAdvertising *pAdvertising = pServer–>getAdvertising(); pAdvertising–>start(); Serial.println(“BLE advertising started”); // Initial OLED decoration display.clearDisplay(); display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE); display.setTextSize(1); display.setTextColor(SSD1306_WHITE); String header = “BMI160 STEP COUNTER”; int headerWidth = header.length() * 6; // Approximate width at size 1 int headerX = (SCREEN_WIDTH – headerWidth) / 2; display.setCursor(headerX, 3); display.println(header); display.drawLine(0, 15, SCREEN_WIDTH, 15, SSD1306_WHITE); display.display(); delay(1000); } void loop() { // Check if the reset button is pressed (reads HIGH when pressed) if (digitalRead(RESET_BUTTON_PIN) == HIGH) { BMI160.resetStepCount(); Serial.println(“Counter reset!”); delay(300); // Simple debounce delay } // Read the step count from the BMI160 sensor uint16_t currentSteps = BMI160.getStepCount(); // Print the current step count to Serial Monitor Serial.print(“Steps: “); Serial.println(currentSteps); // Update OLED display display.clearDisplay(); display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SSD1306_WHITE); // — Header Section — display.setTextSize(1); display.setTextColor(SSD1306_WHITE); String header = “BMI160 STEP COUNTER”; int headerWidth = header.length() * 6; int headerX = (SCREEN_WIDTH – headerWidth) / 2; display.setCursor(headerX, 3); display.println(header); display.drawLine(0, 15, SCREEN_WIDTH, 15, SSD1306_WHITE); // — Step Count Section — String stepText = String(currentSteps); display.setTextSize(3); int stepWidth = stepText.length() * 18; // Approximate width at size 3 int stepX = (SCREEN_WIDTH – stepWidth) / 2; display.setCursor(stepX, 25); display.println(stepText); // — Footer Section — display.setTextSize(1); String footer = “Steps”; int footerWidth = footer.length() * 6; int footerX = (SCREEN_WIDTH – footerWidth) / 2; display.setCursor(footerX, 55); display.println(footer); display.display(); // Update BLE characteristic and send notification if connected String stepsStr = String(currentSteps); pCharacteristic–>setValue(stepsStr.c_str()); pCharacteristic–>notify(); // Print BLE notification info to Serial Monitor if connected if (deviceConnected) { Serial.println(“BLE notification sent”); } delay(200); // Refresh display and BLE update every 200 ms } |
📝 Conclusion
Building your own DIY pedometer using an ESP32, BMI160 sensor, and OLED display is a rewarding project that blends hardware interfacing, sensor data processing, and low-power system design. Not only does it give you a better understanding of motion tracking and microcontroller programming, but you also end up with a practical, usable fitness tracker that you built yourself!
By carefully tuning the sensor thresholds and optimizing the power consumption, you can create a reliable, long-lasting DIY ESP32 pedometer ideal for personal use or even as a base for more advanced IoT fitness projects.
FAQ:
- How long does the battery last, and can I optimize power consumption?
Battery life depends on usage and capacity (e.g., a 1000mAh LiPo may last ~24 hours). To extend it:
- Enable the ESP32’s deep sleep mode between step detections.
- Reduce the OLED display’s brightness/update frequency.
- Lower the BMI160’s sampling rate (e.g., 25Hz instead of 100Hz).
- Use a low-power linear regulator instead of a switching one.
- Can I connect the pedometer to my smartphone via Bluetooth?
Yes, you can connect the DIY ESP32 pedometer to any BLE-enabled smartphone by utilizing the ESP32’s built-in Bluetooth Low Energy (BLE) capabilities. By modifying the code to create a BLE service and characteristic for the step data, the pedometer can broadcast the current step count, allowing you to view or log your activity using a compatible mobile app or a custom app developed specifically for this purpose.
- How accurate is the DIY pedometer using the ESP32 and BMI160 sensor?
The accuracy of the DIY pedometer mainly depends on the calibration of the step detection algorithm and the threshold settings for the accelerometer data. While it may not match the precision of commercial wearable step tracker, it can achieve fairly accurate step counting with proper tuning. Adjusting the sensitivity and incorporating basic filtering can significantly improve the accuracy for casual walking or running activities.