Real Accelerometer Data Collection and POSTing

The questions below are due on Monday March 30, 2026; 06:00:00 PM.
 
You are not logged in.

Please Log In for full access to the web site.
Note that this link will take you to an external site (https://shimmer.mit.edu) to authenticate, and then you will be redirected back to this page.
Back to Exercise 07

Overview

Two weeks you wrote a stack of code that, upon a button push, would collect a bunch of random values for a while, send them to a server, and then log them before allowing you to recall and download them to your computer for later ocnsumption. This week, now that you have a functioning accelerometer on a PCB that you, yourself, developed, we're going to collect the accelerometer data and try to make a basic step counter.

Minimal Changes

Your wiring should basically be a hybrid of the end of EX05 and your lab. We need to be able to read the button press and use that to trigger the collection of 10 seconds of IMU data at a sample rate of 50 ms. Depending on exactly what you wrote last week, this could be as little as a few extra lines in your main.cpp file. When done, instead of posting random data to the server like before, you should be posting the data from a data collection session.

Note you will be walking around for this assignment so you will likely not have your computer terminal up and running, so you may (up to you) want to add in a LED indicator that is on during the data collection stage and turns off when data has posted successfully. This is totally up to you, though. You can also just count to ten I guess.

The Data Sets

With everything up and running, we're going to collect two sets of data:

  1. At least three 10-second grabs of data with you holding your system and standing still.
  2. At least three 10-second grabs of data with you holding your system and walking around at a reasonable rate.

Make sure that you hold the system in the same way (or attach it to a belt/loop or something in the same way both times).

Once you have verified that you have decent data sets on the server, download them as CSVs from the download endpoint you created last time.

Data Analysis

Usually when figuring out how to analyze data using a scripting language is the right choice since it is easiser to write, supported by more libraries, and just overall a smoother experience. For example in this assignment we'd like you to figure out a basic step-counting algorithm that will count steps when there are steps and not when they're aren't steps. You could do this in C/C++ on the ESP, but that would be frustrating. Instead, figure out the algorithm, the numbers, the thresholds, etc... in Python, then when that is solid, port it over to C/C++ for actual final deployment. We'll just need you to do the first part here (the Python figuring-out part).

Below is a very simple script to read out a CSV file of the format of what your web endpoint should be providing. Note, if you made different choices, you may need to modify this a little bit:

You'll need numpy and matplotlib installed (pip install numpy matplotlib). Save the following as analyze.py and run it with your walk.csv file in the same directory. This loads your data and plots the raw axes so you can see what you're working with.

import numpy as np
import matplotlib.pyplot as plt

data = np.genfromtxt("walk.csv", delimiter=",",
                     skip_header=1, encoding="utf-8")

sample = data[:, 0]
time_s = data[:, 1] / 1000.0   # convert ms to seconds if you want
ax     = data[:, 2]
ay     = data[:, 3]
az     = data[:, 4]

# Very basic reader/plotter code:
fig, axes = plt.subplots(3, 1, figsize=(10, 7), sharex=True)
for i, (signal, label) in enumerate([(ax, "X"), (ay, "Y"), (az, "Z")]):
    axes[i].plot(time_s, signal)
    axes[i].set_ylabel(f"{label} (g)")
    axes[i].grid(True, alpha=0.3)
axes[2].set_xlabel("Time (s)")
axes[0].set_title("Raw Accelerometer Data")
plt.tight_layout()
plt.savefig("raw_axes.png", dpi=150)
plt.show()

Run this script targeting both a walking and not-walking series of data just so you can see what you're working with.

Once that is done, work through the tasks below in order to build up to something that can detect steps. Each one builds on the previous. Add your code to the analyze.py (or whatever you called it) that you already had.

Task 1: Compute the acceleration magnitude

The three axes (X, Y, Z) depend on how you hold the board. If you rotate the board, the signal on each axis changes completely, even if you're walking the same way. You need a single signal that captures the total acceleration regardless of orientation.

The task: Compute the vector magnitude of the acceleration. Plot it on a new figure with time on the x-axis and magnitude in g's on the y-axis. Add a horizontal dashed line at 1.0g for reference.

Question: What value does the magnitude hover around when the board is stationary? Why? If yours is different, why is it different (it could be because your IMU was having issues).

Task 2: Smooth the Signal

Your magnitude plot probably looks spiky and noisy...real sensor data always is. Before you can reliably detect peaks, you need to clean it up. The simplest approach is a moving average: replace each sample with the average of itself and its neighbors.

The task: Write a function that computes a moving average of a signal with a given window size. Apply it to your magnitude signal with a window of 5 samples. Plot both the raw and smoothed magnitude on the same figure so you can see the difference.

Question: At 20 Hz, a 5-sample window averages over how many milliseconds? A typical walking step lasts 500–600ms. Is your window small enough to preserve the step peaks?

Task 3: Detect steps

Now you have a clean signal with visible peaks for each step. You need an algorithm to count them. The simplest approach: pick a threshold value, and every time the signal crosses upward through that threshold, call it a "step".

The task: Choose a threshold by looking at your plot...it should be above the resting noise but below the peaks. Loop through the smoothed signal and record the index of every upward threshold crossing. Print how many steps you detected.

At this point make sure to test your script with an example of inactive data as well as actual step data. You want to make sure your systemCompare your detected count to the steps you actually counted while walking. How close is it? If it's too high, what might be going wrong?

Task 4: Deal with double-counting

If your count is too high, it's likely because a single step produces a signal that wobbles above and below the threshold multiple times. You need a way to ignore crossings that happen too soon after a detected step.

The task: Add a "cooldown mechanism" to your detector: after detecting a step, skip a fixed number of samples before looking for the next one. A reasonable starting point is 0.3–0.4 seconds. Tune it until your detected count matches your actual step count.

Question: How many samples is 0.35 seconds at 20 Hz? What happens if you set the cooldown too long (e.g., 1 second)?

Task 5: Visualize your results

A good plot is the best way to verify your algorithm is working and to communicate your results.

The task: Make a final plot that shows the smoothed magnitude signal, the threshold as a horizontal line, and a vertical marker at each detected step. Include a title that states how many steps were found. Save it as step_detection.png. It'll be one of the uploads below.

Deliverable(s)

Make sure this is all actually working. We'll be assuming you have a good data collection system in future weeks so we can do some data analysis.

Submit your functioning cpp file (just the cpp)
 No file selected

Submit your database with at least six data sets posted from your ESP32
 No file selected

Submit your Python file that has the step counting algorithm working
 No file selected

Submit the plot image described above showing up through the steps!
 No file selected

Back to Exercise 07