Draw three lines on a live graph - raw, average and median - and see which filter handles a sudden spike best.
| Part | How many |
|---|---|
| Wiring from Lesson 1 (the other parts can stay) | |
| A book, and your hand (yours) |
Nothing extra - just the kit and your computer.
Every 80 ms the sketch stores the newest good reading in history[], an array of 5. When it is full, the newest reading replaces the oldest, going round in a circle.
The average adds the 5 and divides by 5. It is smooth, but a single wrong reading pulls it off, and it is slow to catch up when the target really moves.
The median sorts the 5 and takes the middle. One spike sits at the end of the sorted list and is ignored. But it too needs 3 new readings before it follows a real move.
Every filter trades smoothness for delay. Lesson 9 uses the median, because ignoring spikes matters most for a parking beeper.
Every item is in the kit — nothing extra to buy.
All 9 parts in one box, with this project and 8 more to build from them.
One of each part. Packs (resistor assortment, jumper wires) already hold more than a single build needs. a computer with the Serial Plotter, your hand or a book: included in the kit, ask us for it loose. 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 | Sensor as in Lesson 1 | TRIG pin 9 · ECHO pin 10 |
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 - Arduino Ultrasonic Distance & Parking Learning Kit
Lesson 7 of 9: Smoothing Noisy Readings
WIRING: the sensor from Lesson 1 (TRIG pin 9, ECHO pin 10).
WHAT SHOULD HAPPEN
Open Tools > Serial Plotter at 9600 baud. Three lines follow the target:
raw - every single reading (jumpy)
average - the mean of the last 5 readings (smooth, but slow to react)
median - the middle of the last 5 readings (ignores single spikes)
Wave a hand quickly through the beam and watch which line jumps.
*/
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
const int WINDOW = 5; // how many readings each filter remembers - try 3 or 9
const unsigned long ECHO_TIMEOUT_US = 30000;
const int MIN_CM = 2;
const int MAX_CM = 400;
long history[WINDOW]; // the last WINDOW good readings
int filled = 0; // how many slots hold a reading so far
int nextSlot = 0; // where the next reading goes
long readOnceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
unsigned long us = pulseIn(ECHO_PIN, HIGH, ECHO_TIMEOUT_US);
if (us == 0) return 0;
long cm = us / 58;
if (cm < MIN_CM || cm > MAX_CM) return 0;
return cm;
}
long averageOfHistory() {
long total = 0;
for (int i = 0; i < filled; i++) total = total + history[i];
long average = total / filled; // whole centimetres
return average;
}
long medianOfHistory() {
long sorted[WINDOW];
for (int i = 0; i < filled; i++) sorted[i] = history[i];
for (int i = 1; i < filled; i++) { // sort, smallest first
long value = sorted[i];
int j = i - 1;
while (j >= 0 && sorted[j] > value) {
sorted[j + 1] = sorted[j];
j--;
}
sorted[j + 1] = value;
}
return sorted[filled / 2]; // the middle one
}
void setup() {
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.begin(9600);
}
void loop() {
long cm = readOnceCm();
if (cm > 0) { // skip "no echo" readings
history[nextSlot] = cm;
nextSlot = (nextSlot + 1) % WINDOW; // go round in a circle
if (filled < WINDOW) filled++;
// "name:value,name:value" is the format the Serial Plotter draws.
Serial.print("raw:");
Serial.print(cm);
Serial.print(",average:");
Serial.print(averageOfHistory());
Serial.print(",median:");
Serial.println(medianOfHistory());
}
delay(80);
}
| In the code | What it does |
|---|---|
| long history[WINDOW]; | The array that remembers the last 5 readings. |
| nextSlot = (nextSlot + 1) % WINDOW; | Moves to the next box and wraps from 4 back to 0. |
| medianOfHistory() | Copies the readings, sorts them smallest first, and returns the middle one. |
| Serial.print("raw:") ... | The "name:value,name:value" pattern is what the Serial Plotter draws as labelled lines. |
| Problem | What to check |
|---|---|
| The Plotter shows nothing | Close the Serial Monitor first, then open the Plotter. Check the speed is 9600 baud. |
| Only one line | Upload the Lesson 7 code again: the line names come from the raw:, average: and median: labels. |
| The lines jump to 0 | No echo readings are skipped, so 0 should not appear. If it does, check the sensor wiring. |
| The upload fails | See Start here, step 6: "If the upload fails". |
Numbers 30, 30, 31, 120, 30. Work out the average and the median by hand. Which one is closer to the real 30 cm?
Sorted: 4, 5, 6, 9, 100 → the middle one is 6.
It still includes the older readings from where the book was.
The median.
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 Arduino Ultrasonic Distance & Parking Learning Kit. Lesson: __ Step number: __ What should happen: __ What happens instead: __ Error message (copied exactly): __ I'll attach a photo of my wiring.
Wire the HC-SR04 and read distances in the Serial Monitor. Compare them with a ruler to see how accurate the sensor really is. Do Start here first.
Find the sensor's limits: too close, too far and off to the side. The LEDs and running counts show good readings, "too close" and "no echo".
Type the ruler distance, get 10 readings back: average, error, minimum, maximum and spread. Paste the rows into a spreadsheet and find your sensor's accuracy.
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.