A beginner's Arduino UNO kit with a step-by-step path: Start here, then 7 lessons - LEDs, traffic light, buzzer, distance sensor, servo and LCD - ending in a Parking Assistant that uses every part. Each lesson has a wiring diagram, code and troubleshooting. Wiring design-reviewed and code compiler-checked; the complete physical assembly is not bench-tested. A separate 5V servo supply is recommended for the last lesson.
1×UNO R3 Development Board ATmega328P Microcontroller with USB Cable
1×400 Tie Point Solderless Breadboard
1×Jumper Wire Assorted Pack 120 Pieces
1×RESISTOR ASSORTED 220-1K-10K
1×Active Buzzer Module 5V DC
1×HC-SR04 Ultrasonic Distance Sensor Module for Arduino
1×SG90 9g Micro Servo Motor
1×10K Ohm Rotary Potentiometer PCB Type
1×LCD 1602A Character Display Module| Item | For | Note |
|---|---|---|
| A computer (Windows, macOS or Linux) where you can install the free Arduino IDE 2 - or a Chromebook with the Arduino Cloud Editor | All lessons | |
| A free USB-A port, or an adapter, for the kit's USB cable | All lessons | |
| An internet connection, to download the IDE and copy the code | Start here | |
| A book or flat box, and a ruler | Lessons 4 and 7 | |
| A separate regulated 5V supply for the servo, with wires | Lesson 7 - recommended | Adult help. Without it, do Lesson 7 without the servo. |
| A 16-pin header and soldering | Lesson 6 - only if your LCD has no pins fitted | Adult only |
| A multimeter | Optional | No lesson needs one. Useful for an adult checking 5V and GND. |
| # | Step and what you should see | Done | Date |
|---|---|---|---|
| 1 | Start here: install the Arduino IDE, select Arduino Uno and your port, and upload Blink - the L light blinks. | ||
| 2 | Lesson 1 - LED Basics & Brightness (30 min): the yellow LED blinks 3 times, then the knob fades it. | ||
| 3 | Lesson 2 - Traffic Light (25 min): red, red + yellow, green and yellow on pins 2, 3 and 4. | ||
| 4 | Lesson 3 - Buzzer Patterns (25 min): slow beep, fast alarm and SOS; type 0-3 to choose. | ||
| 5 | Lesson 4 - Ultrasonic Distance (30 min): the distance as a live graph in the Serial Plotter. | ||
| 6 | Lesson 5 - Servo & Knob (30 min): the servo arm follows the knob, then sweeps by itself. | ||
| 7 | Lesson 6 - LCD Display (45-60 min): your name and a seconds counter on the LCD. Check the LCD has its pins fitted first. | ||
| 8 | Lesson 7 - Parking Assistant (45-60 min): LEDs and buzzer by distance, LCD readout and servo gauge. Separate 5V servo supply recommended (adult help). |
Every lesson uses this one pin plan, so a part wired in one lesson can stay where it is for the next. A dot means the lesson uses that pin. Lesson 7 uses everything at once.
| UNO pin | Connects to | S | L1 | L2 | L3 | L4 | L5 | L6 | L7 | Note |
|---|---|---|---|---|---|---|---|---|---|---|
| 5V | + rail of the breadboard | ● | ● | ● | ● | ● | ● | ● | Powers the parts. In Lesson 7 the servo gets its own 5V supply instead. | |
| GND | − rail of the breadboard | ● | ● | ● | ● | ● | ● | ● | Shared ground. Every part and any extra supply joins here. | |
| D0, D1 | Nothing - leave free | The USB connection uses these two pins. Wires here can stop uploads. | ||||||||
| D2 | Red LED, through 220 Ω | ● | ● | |||||||
| D3 ~ | Yellow LED, through 220 Ω | ● | ● | ● | ~ means it can dim (PWM). | |||||
| D4 | Green LED, through 220 Ω | ● | ● | |||||||
| D5 ~ | Servo signal (orange wire) | ● | ● | |||||||
| D6 ~ | Buzzer S (signal) | ● | ● | May be labelled I/O or IN. | ||||||
| D7 | LCD pin 12 (D5) | ● | ● | |||||||
| D8 | HC-SR04 TRIG | ● | ● | |||||||
| D9 | HC-SR04 ECHO | ● | ● | |||||||
| D10 | LCD pin 11 (D4) | ● | ● | |||||||
| D11 | LCD pin 6 (E) | ● | ● | |||||||
| D12 | LCD pin 4 (RS) | ● | ● | |||||||
| D13 | Built-in L light only | ● | Blink in Start here. Nothing is wired to it. | |||||||
| A0 | Potentiometer middle pin | ● | ● | In Lessons 6 and 7 the middle pin moves to LCD pin 3 (VO) for contrast. | ||||||
| A1 | LCD pin 13 (D6) | ● | ● | Used as a normal on/off pin. | ||||||
| A2 | LCD pin 14 (D7) | ● | ● | Used as a normal on/off pin. | ||||||
| A3, A4, A5 | Nothing - free | Spare pins for your own ideas. |
S = Start here · L1-L7 = Lessons. ~ marks a pin that can dim an LED or drive a servo (PWM). The same pins are in every lesson's diagram and code.
Follow these 7 steps before Lesson 1. They take about 30-45 minutes and prove that your computer, cable and UNO all work - so if something goes wrong later, you know it is the wiring, not the setup.
Lessons 1-5 need only the kit and a computer. Lesson 6 needs an adult only if your LCD has no pins fitted. Lesson 7 is the first that needs extra equipment: a separate 5V supply for the servo (recommended) - or do it without the servo.
| Something is missing or broken | Send us a photo with your order number on WhatsApp. |
| The download or install is blocked | School and work computers often block installs. Ask an adult or use a home computer. |
| No light at all | Push the plug fully into the UNO. Try another USB port, then another cable. |
| The Port menu is greyed out or empty | Some USB cables only charge and carry no data. Try the kit's cable in another port, or another data cable. |
| Windows shows "USB2.0-Serial" or an unknown device | Look at the small chip next to the UNO's USB socket. If it says CH340, the computer needs the free CH340 driver - ask us on WhatsApp and we'll send the link. |
| Mac: no new port appears | Do the same CH340 check. After installing a driver, you may need to allow it in System Settings → Privacy & Security. |
| Linux: "permission denied" on the port | Ask an adult to add your user to the dialout group (sudo usermod -a -G dialout $USER), then log out and back in. |
| "can't open device" or "Access is denied" | The port is busy or wrong. Close other Arduino windows, choose the port again (step 5) and try again. |
| "programmer is not responding" | The wrong board or port is selected, or the cable carries no data. Check step 5 and try another cable. |
| A red "Compilation error" | The example was changed by accident. Close it without saving and open Blink again from File → Examples. |
| "Done uploading" but L doesn't change | Your board may already have been running Blink. Do the change below (delay 200) and look for faster blinking. |
| UNO R3 + USB cable | 1 |
| 400-point breadboard | 1 |
| Yellow LED | 1 |
| 220 Ω resistor (red-red-brown) | 1 |
| 10K potentiometer | 1 |
| Male-to-male jumper wires | about 7 |
An LED only works one way round: current goes in through the long leg (+) and out through the short leg (−). On its own it would take too much current, so a 220 Ω resistor always goes in line with it to protect the LED and the UNO pin.
digitalWrite(3, HIGH) puts 5 volts on pin 3 and the LED lights. LOW turns it off. That is how the 3 blinks at the start work.
The potentiometer is a knob. Its middle pin gives a voltage between 0 and 5V depending on how far you turn it, and analogRead(A0) turns that into a number from 0 to 1023.
The UNO cannot make "half a volt". Instead analogWrite() switches pin 3 on and off very fast (PWM). On for half the time looks half as bright. 0 is off, 255 is full brightness.
| Part / pin | Connect to | Note |
|---|---|---|
| UNO 5V | + rail (red line) | Powers the knob |
| UNO GND | − rail (blue line) | Shared ground for everything |
| UNO pin 3 | 220 Ω resistor → yellow LED long leg (+) | Pin 3 has a ~ mark, so it can dim |
| Yellow LED short leg (−) | − rail (GND) | |
| Potentiometer outer pin | + rail (5V) | Either outer pin |
| Potentiometer other outer pin | − rail (GND) | |
| Potentiometer middle pin | UNO A0 | On the lower header, by ANALOG IN |
Easiest: scan the QR code above and press Copy or Download .ino on the lesson page, then paste it into the Arduino IDE and click Upload. The full listing is here for reading along.
/*
DIY KIT - Arduino UNO Sensor & Output Starter Kit
Lesson 1 of 7: LED Basics & Brightness
WIRING (unplug the USB cable before you wire)
Yellow LED long leg (+) -> 220 ohm resistor -> UNO pin 3
Yellow LED short leg (-) -> GND
Potentiometer outer pins -> 5V and GND (either way round)
Potentiometer middle pin -> UNO pin A0
WHAT SHOULD HAPPEN
1. The LED blinks 3 times. That proves the LED is wired the right way.
2. Then turn the knob: the LED fades from off to fully bright.
*/
const int LED_PIN = 3; // the yellow LED. Pin 3 has a ~ mark, so it can dim (PWM)
const int KNOB_PIN = A0; // the middle pin of the potentiometer
const int BLINK_MS = 300; // how long each start-up blink lasts, in milliseconds
void setup() {
pinMode(LED_PIN, OUTPUT); // pin 3 sends power OUT to the LED
Serial.begin(9600); // talk to the computer (Serial Monitor at 9600 baud)
Serial.println("Lesson 1: LED Basics & Brightness");
// Part A: blink 3 times so you know the LED works.
for (int i = 1; i <= 3; i++) {
digitalWrite(LED_PIN, HIGH); // HIGH = 5 volts = LED on
delay(BLINK_MS); // wait
digitalWrite(LED_PIN, LOW); // LOW = 0 volts = LED off
delay(BLINK_MS);
}
Serial.println("Now turn the knob");
}
void loop() {
// Part B: the knob sets the brightness.
int knob = analogRead(KNOB_PIN); // 0 at one end of the turn ... 1023 at the other
int brightness = map(knob, 0, 1023, 0, 255); // squeeze 0-1023 into 0-255
analogWrite(LED_PIN, brightness); // 0 = off, 128 = half, 255 = full
// Two numbers the Serial Plotter can draw as lines.
Serial.print("knob:");
Serial.print(knob);
Serial.print(",brightness:");
Serial.println(brightness);
delay(100); // 10 readings a second is plenty
}
| const int LED_PIN = 3; | Gives pin 3 a name. If you ever move the LED, you only change this number. |
| setup() | Runs once when the UNO starts. It makes pin 3 an OUTPUT and blinks the LED 3 times with digitalWrite() and delay(). |
| loop() | Runs again and again: read the knob (analogRead), change 0-1023 into 0-255 (map), set the brightness (analogWrite). |
| Serial.print(...) | Sends the two numbers to your computer. Open Tools → Serial Monitor or Serial Plotter at 9600 baud to see them. |
| The LED never lights, not even the 3 blinks | Unplug USB. The LED is probably the wrong way round: turn it so the long leg is in the resistor's row. Check the wire goes to pin 3 and the short leg reaches the − rail. |
| The LED blinks 3 times but the knob does nothing | The LED is fine. Check the potentiometer: middle pin to A0, outer pins to the + and − rails. |
| The LED is only fully on or fully off | The wire is on a pin without a ~ mark. Move it to pin 3. |
| The LED is very dim even at full brightness | Check the resistor colours: red-red-brown is 220 Ω. Brown-black-orange is 10 kΩ, which is far too big. |
| The knob works backwards | Nothing is wrong. Swap the two outer potentiometer wires if you prefer the other way. |
| The upload fails | See Start here, step 6: "If the upload fails". |
Cover the LED with a sheet of paper and turn the knob up slowly. At what knob number (shown in the Serial Monitor) can you first see light through the paper?
| UNO R3 + USB cable | 1 |
| 400-point breadboard | 1 |
| Red, yellow and green LED | 1 each |
| 220 Ω resistors (red-red-brown) | 3 |
| Jumper wires | about 8 |
Each LED has its own pin: red on 2, yellow on 3, green on 4. HIGH turns an LED on and LOW turns it off.
showLights() switches all three LEDs at once, prints the name of the phase and waits. loop() calls it four times, one full cycle, and then starts again.
The order is the one many countries use: red (stop), red + yellow (get ready), green (go), yellow (prepare to stop).
| Part / pin | Connect to | Note |
|---|---|---|
| Red LED long leg (+) | 220 Ω → UNO pin 2 | |
| Yellow LED long leg (+) | 220 Ω → UNO pin 3 | Already wired in Lesson 1 |
| Green LED long leg (+) | 220 Ω → UNO pin 4 | |
| All three short legs (−) | − rail (GND) | |
| UNO 5V / GND | + rail / − rail | Already wired in Lesson 1 |
| Potentiometer | Can stay as in Lesson 1 | Not used in this lesson |
Easiest: scan the QR code above and press Copy or Download .ino on the lesson page, then paste it into the Arduino IDE and click Upload. The full listing is here for reading along.
/*
DIY KIT - Arduino UNO Sensor & Output Starter Kit
Lesson 2 of 7: Traffic Light
WIRING (unplug the USB cable before you wire)
Keep the yellow LED from Lesson 1 on pin 3 and add two more:
Red LED long leg (+) -> 220 ohm resistor -> UNO pin 2
Yellow LED long leg (+) -> 220 ohm resistor -> UNO pin 3
Green LED long leg (+) -> 220 ohm resistor -> UNO pin 4
Every short leg (-) -> GND rail of the breadboard
The potentiometer from Lesson 1 can stay where it is.
WHAT SHOULD HAPPEN
Red (3 s) -> red + yellow (1 s) -> green (3 s) -> yellow (1.2 s) -> repeat.
*/
const int RED_PIN = 2;
const int YELLOW_PIN = 3;
const int GREEN_PIN = 4;
// How long each light stays on, in milliseconds (1000 ms = 1 second).
const unsigned long RED_MS = 3000; // stop
const unsigned long RED_YELLOW_MS = 1000; // get ready
const unsigned long GREEN_MS = 3000; // go
const unsigned long YELLOW_MS = 1200; // prepare to stop
// Switch the three lights, tell the Serial Monitor, then wait.
// true = on, false = off.
void showLights(bool red, bool yellow, bool green, const char *name, unsigned long holdMs) {
digitalWrite(RED_PIN, red ? HIGH : LOW);
digitalWrite(YELLOW_PIN, yellow ? HIGH : LOW);
digitalWrite(GREEN_PIN, green ? HIGH : LOW);
Serial.println(name);
delay(holdMs);
}
void setup() {
pinMode(RED_PIN, OUTPUT);
pinMode(YELLOW_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
Serial.begin(9600);
Serial.println("Lesson 2: Traffic Light");
}
void loop() {
showLights(true, false, false, "RED", RED_MS);
showLights(true, true, false, "RED + YELLOW", RED_YELLOW_MS);
showLights(false, false, true, "GREEN", GREEN_MS);
showLights(false, true, false, "YELLOW", YELLOW_MS);
}
| const int RED_PIN = 2; ... | Names for the three LED pins. |
| const unsigned long RED_MS = 3000; | How long each phase lasts, in milliseconds. |
| showLights(red, yellow, green, name, holdMs) | Our own function: true means on, false means off. It also prints the phase name and waits holdMs. |
| loop() | Four calls to showLights(): one full traffic-light cycle. |
| One LED never lights | Unplug USB and turn that LED round (long leg towards the resistor). Check its wire goes to the right pin. |
| The wrong colour lights at the wrong time | Two pin wires are swapped. Red must be on 2, yellow on 3, green on 4. |
| All the LEDs stay off | Check the − rail is connected to a UNO GND pin. |
| Nothing in the Serial Monitor | Set the speed in the Serial Monitor to 9600 baud. |
Use a stopwatch (or a phone) to time the green phase. Is it really 3 seconds? Change GREEN_MS and time it again.
| UNO R3 + USB cable | 1 |
| Active buzzer module | 1 |
| Male-to-female jumper wires | 3 |
The active buzzer beeps at one fixed pitch whenever it is switched on. The sketch only decides when and for how long: the rhythm is the message, like a smoke alarm.
Some buzzer modules beep when their signal pin is HIGH (active-high), others when it is LOW (active-low). BUZZER_ACTIVE_LOW in the code lets you match your module.
While a pattern plays, the sketch keeps checking for anything you type in the Serial Monitor. Type 1, 2 or 3 and press Enter to choose a pattern, or 0 for silence. Until you type something, it shows off each pattern for 6 seconds.
| Part / pin | Connect to | Note |
|---|---|---|
| Buzzer S (signal) | UNO pin 6 | May be labelled I/O or IN |
| Buzzer + | + rail (5V) | May be labelled VCC |
| Buzzer − | − rail (GND) | May be labelled GND |
Easiest: scan the QR code above and press Copy or Download .ino on the lesson page, then paste it into the Arduino IDE and click Upload. The full listing is here for reading along.
/*
DIY KIT - Arduino UNO Sensor & Output Starter Kit
Lesson 3 of 7: Buzzer Patterns
WIRING (unplug the USB cable before you wire)
Active buzzer module, using 3 male-to-female jumper wires:
S (signal, may be labelled I/O or IN) -> UNO pin 6
+ (VCC) -> 5V
- (GND) -> GND
The LEDs and potentiometer from Lessons 1-2 can stay where they are.
WHAT SHOULD HAPPEN
The buzzer plays pattern 1 (slow beep), then 2 (fast alarm), then 3 (SOS),
changing every 6 seconds. Open the Serial Monitor (9600 baud), type a
number 0-3 and press Enter to choose a pattern yourself. 0 = silence.
*/
const int BUZZER_PIN = 6;
// Most modules beep when the pin is HIGH. If yours beeps in the gaps or
// all the time, change false to true and upload again.
const bool BUZZER_ACTIVE_LOW = false;
const unsigned long SLOW_ON_MS = 300, SLOW_OFF_MS = 700; // pattern 1: slow warning
const unsigned long FAST_ON_MS = 80, FAST_OFF_MS = 120; // pattern 2: urgent alarm
const unsigned long DOT_MS = 120, DASH_MS = 360; // pattern 3: SOS in Morse code
const unsigned long AUTO_CHANGE_MS = 6000; // demo mode: next pattern every 6 s
int pattern = 1; // the pattern playing now (0-3)
bool demoMode = true; // true until you type a number
bool newChoice = false; // set when you type a number
unsigned long patternStarted = 0;
void buzzer(bool on) {
if (BUZZER_ACTIVE_LOW) {
digitalWrite(BUZZER_PIN, on ? LOW : HIGH);
} else {
digitalWrite(BUZZER_PIN, on ? HIGH : LOW);
}
}
void announce() {
Serial.print("Pattern ");
Serial.print(pattern);
if (pattern == 0) Serial.println(": silence");
else if (pattern == 1) Serial.println(": slow beep");
else if (pattern == 2) Serial.println(": fast alarm");
else Serial.println(": SOS");
patternStarted = millis();
}
// Read anything typed in the Serial Monitor.
void readKeyboard() {
while (Serial.available() > 0) {
char c = Serial.read(); // one character at a time
if (c >= '0' && c <= '3') {
pattern = c - '0'; // the character '2' becomes the number 2
demoMode = false; // you chose: stop changing by itself
newChoice = true;
announce();
}
}
}
// Wait, but keep listening to the keyboard.
// Returns true if you typed a new pattern while waiting.
bool waitAndListen(unsigned long ms) {
unsigned long start = millis();
while (millis() - start < ms) {
readKeyboard();
if (newChoice) return true;
delay(1); // a tiny pause before checking again
}
return false;
}
// One beep: on for onMs, then off for offMs. Returns true if interrupted.
bool beep(unsigned long onMs, unsigned long offMs) {
buzzer(true);
bool stop = waitAndListen(onMs);
buzzer(false);
if (stop) return true;
return waitAndListen(offMs);
}
void playSOS() {
for (int i = 0; i < 3; i++) if (beep(DOT_MS, DOT_MS)) return; // S = . . .
if (waitAndListen(DASH_MS)) return;
for (int i = 0; i < 3; i++) if (beep(DASH_MS, DOT_MS)) return; // O = - - -
if (waitAndListen(DASH_MS)) return;
for (int i = 0; i < 3; i++) if (beep(DOT_MS, DOT_MS)) return; // S = . . .
waitAndListen(1000);
}
void setup() {
pinMode(BUZZER_PIN, OUTPUT);
buzzer(false);
Serial.begin(9600);
Serial.println("Lesson 3: Buzzer Patterns - type 0, 1, 2 or 3 and press Enter");
announce();
}
void loop() {
newChoice = false;
// Demo mode: move on to the next pattern every few seconds.
if (demoMode && millis() - patternStarted > AUTO_CHANGE_MS) {
pattern = pattern % 3 + 1; // 1 -> 2 -> 3 -> 1
announce();
}
if (pattern == 1) beep(SLOW_ON_MS, SLOW_OFF_MS);
else if (pattern == 2) beep(FAST_ON_MS, FAST_OFF_MS);
else if (pattern == 3) playSOS();
else { // pattern 0: silence
buzzer(false);
waitAndListen(100);
}
}
| BUZZER_ACTIVE_LOW | false for most modules. Change it to true if your buzzer beeps in the gaps instead of on the beeps. |
| buzzer(true / false) | Our function that switches the buzzer on or off the right way for your module. |
| readKeyboard() | Reads the characters you type. A digit 0-3 becomes the new pattern and stops the automatic demo. |
| waitAndListen(ms) | Waits, but keeps checking the keyboard, so a new choice works straight away. |
| playSOS() | Three short, three long, three short beeps: S-O-S in Morse code. |
| The buzzer sounds all the time, or in the gaps | Your module is active-low. Change BUZZER_ACTIVE_LOW to true and upload again. |
| No sound at all | Check S is on pin 6 and + is on the + rail (5V), not swapped with −. |
| Only a click, no beep | That is how a passive buzzer behaves. Ask us on WhatsApp: the kit should contain an active buzzer. |
| Typing a number does nothing | Click in the Serial Monitor's message box, type the digit and press Enter. Check the speed is 9600 baud. |
Look up the first letter of your name in Morse code. Copy playSOS(), rename it and change the dots and dashes to beep your letter.
| UNO R3 + USB cable | 1 |
| HC-SR04 distance sensor | 1 |
| Jumper wires | 4 |
| A book or flat box, and a ruler (yours) | 1 |
The HC-SR04 has two round "eyes": one sends a short burst of ultrasound, the other listens for the echo. The sketch starts a measurement with a 10 µs pulse on TRIG.
The sensor then keeps ECHO HIGH until the echo comes back. pulseIn() measures how long that was, in microseconds. Sound takes about 58 µs to go 1 cm and come back, so distance in cm = time ÷ 58.
Single readings sometimes jump. So the sketch also takes 5 readings, sorts them and keeps the middle one. Both numbers are printed, so you can compare them in the Serial Plotter.
| Part / pin | Connect to | Note |
|---|---|---|
| HC-SR04 VCC | + rail (5V) | |
| HC-SR04 TRIG | UNO pin 8 | |
| HC-SR04 ECHO | UNO pin 9 | |
| HC-SR04 GND | − rail (GND) |
Easiest: scan the QR code above and press Copy or Download .ino on the lesson page, then paste it into the Arduino IDE and click Upload. The full listing is here for reading along.
/*
DIY KIT - Arduino UNO Sensor & Output Starter Kit
Lesson 4 of 7: Ultrasonic Distance
WIRING (unplug the USB cable before you wire)
HC-SR04 VCC -> 5V
HC-SR04 TRIG -> UNO pin 8
HC-SR04 ECHO -> UNO pin 9
HC-SR04 GND -> GND
Parts from Lessons 1-3 can stay where they are.
WHAT SHOULD HAPPEN
Open Tools > Serial Plotter (9600 baud). Move a book slowly towards and
away from the sensor. Two lines follow it: raw_cm (jumpy) and
median_cm (smoother). 0 means "no echo" - nothing in range.
*/
const int TRIG_PIN = 8; // we send the "click" from here
const int ECHO_PIN = 9; // the sensor answers on this pin
const unsigned long ECHO_TIMEOUT_US = 30000; // give up after 30 ms (about 5 m there and back)
const int MIN_CM = 2; // closer than this the sensor cannot measure
const int MAX_CM = 400; // further than this is out of range
const int SAMPLES = 5; // readings in each median - try 1 or 9
const unsigned long REPORT_MS = 250; // a new line 4 times a second
// One measurement in centimetres, or 0 if no echo came back.
long readOnceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH); // a 10-microsecond pulse starts the measurement
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// pulseIn() times how long ECHO stays HIGH, in microseconds.
unsigned long us = pulseIn(ECHO_PIN, HIGH, ECHO_TIMEOUT_US);
if (us == 0) return 0; // no echo
// Sound goes there and back: 58 microseconds for every centimetre of distance.
long cm = us / 58;
if (cm < MIN_CM || cm > MAX_CM) return 0;
return cm;
}
// Take several readings, sort them, keep the middle one (the median).
// One wild reading cannot move the middle value much.
long medianCm() {
long v[SAMPLES];
for (int i = 0; i < SAMPLES; i++) {
v[i] = readOnceCm();
delay(20); // let the last echo die away
}
for (int i = 1; i < SAMPLES; i++) { // sort, smallest first
long key = v[i];
int j = i - 1;
while (j >= 0 && v[j] > key) {
v[j + 1] = v[j];
j--;
}
v[j + 1] = key;
}
return v[SAMPLES / 2];
}
void setup() {
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.begin(9600);
Serial.println("Lesson 4: Ultrasonic Distance");
}
void loop() {
long raw = readOnceCm();
long smooth = medianCm();
// "name:value,name:value" is the format the Serial Plotter draws.
Serial.print("raw_cm:");
Serial.print(raw);
Serial.print(",median_cm:");
Serial.println(smooth);
delay(REPORT_MS);
}
| readOnceCm() | Sends one pulse on TRIG, times the echo with pulseIn() and turns microseconds into centimetres (÷ 58). Returns 0 if no echo came back. |
| medianCm() | Takes SAMPLES readings, sorts them and returns the middle one. |
| Serial.print("raw_cm:") ... | Prints name:value pairs - the format the Serial Plotter draws as two labelled lines. |
| Always 0 | TRIG and ECHO are swapped, or VCC is not on the + rail. Check the 4 wires against the table. |
| Numbers jump around | Use a flat, hard target held straight in front. Soft things (cushions, clothes) and slanted surfaces scatter the sound. |
| The plotter shows nothing | Check the speed is 9600 baud and the port is your UNO. |
| Readings far too big | The sensor may be seeing something behind your target, like a wall. Move the target closer. |
Point the sensor at a cushion and then at a book, at the same distance. Which gives steadier readings, and why?
| UNO R3 + USB cable | 1 |
| SG90 servo with one plastic arm | 1 |
| 10K potentiometer (from Lesson 1) | 1 |
| Male-to-male jumper wires | 3 |
The servo has three wires: brown (−), red (+) and orange (signal). The UNO sends a short pulse on the signal wire every 20 ms, and the length of the pulse tells the servo which angle to hold. The Servo library does this for you: servo.write(90) means "go to 90 degrees".
The knob still gives 0-1023 on A0. map() turns that into an angle from 10 to 170 degrees.
The sketch remembers when the knob last moved. After 4 seconds without a change it starts sweeping by itself; turn the knob and you are back in control.
| Part / pin | Connect to | Note |
|---|---|---|
| Servo orange (signal) | UNO pin 5 | Pin 5 has a ~ mark |
| Servo red (+) | + rail (5V) | See the power warning in step 5 |
| Servo brown (−) | − rail (GND) | |
| Potentiometer middle pin | UNO A0 | Still wired from Lesson 1 |
Easiest: scan the QR code above and press Copy or Download .ino on the lesson page, then paste it into the Arduino IDE and click Upload. The full listing is here for reading along.
/*
DIY KIT - Arduino UNO Sensor & Output Starter Kit
Lesson 5 of 7: Servo & Knob
WIRING (unplug the USB cable before you wire)
SG90 servo, using 3 male-to-male jumper wires in its plug:
orange (signal) -> UNO pin 5
red (+) -> 5V
brown (-) -> GND
Potentiometer (still wired from Lesson 1):
outer pins -> 5V and GND, middle pin -> UNO pin A0
Parts from Lessons 1-4 can stay where they are.
POWER: fit only the small plastic arm - nothing else on the servo.
If the UNO resets or the servo twitches, unplug USB and read the
troubleshooting table on the lesson page.
WHAT SHOULD HAPPEN
Turn the knob: the arm follows it. Let go for 4 seconds: the arm
sweeps back and forth by itself until you turn the knob again.
*/
#include <Servo.h> // comes with the Arduino IDE - nothing to install
const int SERVO_PIN = 5;
const int KNOB_PIN = A0;
const int MIN_ANGLE = 10; // the servo's travel limits, in degrees
const int MAX_ANGLE = 170; // (0 and 180 can make some servos buzz at the end)
const int SWEEP_STEP = 2; // degrees per step while sweeping
const unsigned long SWEEP_STEP_MS = 20; // smaller = faster sweep
const unsigned long WAIT_BEFORE_SWEEP_MS = 4000;
const int KNOB_DEADBAND = 8; // ignore tiny wobbles of the knob
Servo servo;
int lastKnob = -1000;
unsigned long lastKnobMove = 0;
int sweepAngle = 90;
int sweepDirection = 1; // +1 = counting up, -1 = counting down
unsigned long lastSweepStep = 0;
void setup() {
servo.attach(SERVO_PIN); // the Servo library now pulses pin 5 for us
servo.write(90); // start in the middle
Serial.begin(9600);
Serial.println("Lesson 5: Servo & Knob - turn the knob, or wait for the sweep");
}
void loop() {
int knob = analogRead(KNOB_PIN); // 0 ... 1023
if (abs(knob - lastKnob) > KNOB_DEADBAND) {
// The knob moved: the arm follows it.
lastKnob = knob;
lastKnobMove = millis();
int angle = map(knob, 0, 1023, MIN_ANGLE, MAX_ANGLE);
servo.write(angle);
sweepAngle = angle;
Serial.print("knob ");
Serial.print(knob);
Serial.print(" -> ");
Serial.print(angle);
Serial.println(" degrees");
} else if (millis() - lastKnobMove > WAIT_BEFORE_SWEEP_MS && millis() - lastSweepStep > SWEEP_STEP_MS) {
// Nobody touched the knob for 4 seconds: sweep by ourselves.
lastSweepStep = millis();
sweepAngle = sweepAngle + sweepDirection * SWEEP_STEP;
if (sweepAngle >= MAX_ANGLE) { sweepAngle = MAX_ANGLE; sweepDirection = -1; }
if (sweepAngle <= MIN_ANGLE) { sweepAngle = MIN_ANGLE; sweepDirection = 1; }
servo.write(sweepAngle);
}
delay(10);
}
| #include <Servo.h> | Loads the Servo library. |
| servo.attach(SERVO_PIN) | Tells the library which pin the servo's signal wire is on. |
| map(knob, 0, 1023, MIN_ANGLE, MAX_ANGLE) | Changes the knob number into an angle. |
| KNOB_DEADBAND | Ignores tiny changes, so the servo doesn't jitter when nobody touches the knob. |
| millis() - lastKnobMove > WAIT_BEFORE_SWEEP_MS | True when the knob has been still for 4 seconds: time to sweep. |
| The UNO restarts, its lights flicker, or the servo twitches | Unplug USB. The servo is taking more current than the USB port gives. Try a USB port on the computer itself (not a hub). If it still happens, stop and ask an adult: Lesson 7 shows how to give the servo its own 5V supply. |
| The servo buzzes at the end of its travel | Some servos can't reach the very end. Keep MIN_ANGLE at 10 and MAX_ANGLE at 170, or make the range smaller. |
| The servo doesn't move at all | Check orange is on pin 5, red on the + rail and brown on the − rail. |
| The knob works backwards | Swap the potentiometer's two outer wires. |
Stick a small paper pointer on the arm and draw a scale behind it (10°, 90°, 170°). When the Serial Monitor says 90 degrees, does the pointer really point to the middle?
| UNO R3 + USB cable | 1 |
| LCD1602 display | 1 |
| 10K potentiometer (moved from A0) | 1 |
| 220 Ω resistor (backlight) | 1 |
| Jumper wires | about 16 |
The LCD has its own controller chip. The UNO sends it letters over 4 data wires (D4-D7) and 2 control wires: RS (letter or command?) and E (read it now!). The LiquidCrystal library does all of this for you.
LCD pin 3 (VO) sets the contrast. The potentiometer's middle pin gives a voltage between 0 and 5V, so turning the knob makes the letters darker or lighter.
lcd.setCursor(column, row) chooses where to write: row 0 is the top line, row 1 the bottom. Numbers are printed with spaces in front, so old digits never stay behind.
| Part / pin | Connect to | Note |
|---|---|---|
| LCD 1 VSS | − rail (GND) | |
| LCD 2 VDD | + rail (5V) | |
| LCD 3 VO | Potentiometer middle pin | MOVED from A0 - contrast |
| LCD 4 RS | UNO pin 12 | |
| LCD 5 RW | − rail (GND) | |
| LCD 6 E | UNO pin 11 | |
| LCD 7, 8, 9, 10 | Nothing | Leave empty |
| LCD 11 D4 | UNO pin 10 | |
| LCD 12 D5 | UNO pin 7 | |
| LCD 13 D6 | UNO A1 | Used as a normal pin |
| LCD 14 D7 | UNO A2 | Used as a normal pin |
| LCD 15 A (backlight +) | 220 Ω → + rail (5V) | Always through the resistor |
| LCD 16 K (backlight −) | − rail (GND) | |
| Potentiometer outer pins | + rail and − rail | Same as before |
Easiest: scan the QR code above and press Copy or Download .ino on the lesson page, then paste it into the Arduino IDE and click Upload. The full listing is here for reading along.
/*
DIY KIT - Arduino UNO Sensor & Output Starter Kit
Lesson 6 of 7: LCD Display
WIRING (unplug the USB cable before you wire) - LCD pins are numbered 1-16
LCD 1 VSS -> GND LCD 2 VDD -> 5V
LCD 3 VO -> potentiometer middle pin (MOVE this wire from A0 - the knob
now sets the contrast; outer pins stay on 5V and GND)
LCD 4 RS -> pin 12 LCD 5 RW -> GND LCD 6 E -> pin 11
LCD 7-10 -> nothing
LCD 11 D4 -> pin 10 LCD 12 D5 -> pin 7
LCD 13 D6 -> pin A1 LCD 14 D7 -> pin A2
LCD 15 A -> 220 ohm resistor -> 5V (backlight +)
LCD 16 K -> GND (backlight -)
WHAT SHOULD HAPPEN
Top line: Hello, Maker!
Bottom line: Time: 12 s (counting up)
If you see nothing, or only blocks, turn the knob slowly.
*/
#include <LiquidCrystal.h> // comes with the Arduino IDE - nothing to install
// The pins in this order: RS, E, D4, D5, D6, D7
LiquidCrystal lcd(12, 11, 10, 7, A1, A2);
const char NAME[] = "Maker"; // put your name here (up to 8 letters)
const unsigned long REFRESH_MS = 250; // redraw 4 times a second
unsigned long lastRefresh = 0;
// Print a number in a fixed width, with spaces in front,
// so "9" does not leave the old "0" of "10" behind.
void printPadded(unsigned long value, int width) {
String s = String(value);
while ((int) s.length() < width) s = " " + s;
lcd.print(s);
}
void setup() {
lcd.begin(16, 2); // 16 characters, 2 rows
lcd.setCursor(0, 0); // column 0, row 0 = top left
lcd.print("Hello, ");
lcd.print(NAME);
lcd.print("!");
Serial.begin(9600);
Serial.println("Lesson 6: LCD Display");
}
void loop() {
if (millis() - lastRefresh < REFRESH_MS) return;
lastRefresh = millis();
unsigned long seconds = millis() / 1000;
lcd.setCursor(0, 1); // column 0, row 1 = bottom line
lcd.print("Time: ");
printPadded(seconds, 5);
lcd.print(" s");
Serial.print("time_s:");
Serial.println(seconds);
}
| LiquidCrystal lcd(12, 11, 10, 7, A1, A2); | Tells the library which UNO pins go to RS, E, D4, D5, D6 and D7 - in that order. |
| lcd.begin(16, 2) | The display has 16 columns and 2 rows. |
| lcd.setCursor(0, 1) | Move to column 0 of row 1: the start of the bottom line. |
| printPadded(seconds, 5) | Prints the number 5 characters wide, with spaces in front. |
| const char NAME[] = "Maker"; | The name on the top line. Up to 8 letters fit. |
| Backlight on, but no text and no blocks | Turn the knob slowly all the way: the contrast is too low. Check LCD pin 3 goes to the knob's middle pin. |
| A row of solid blocks on the top line | Power and contrast are fine but the signal wires are not. Check RS → 12, E → 11, D4 → 10, D5 → 7, D6 → A1, D7 → A2, and RW to GND. |
| Random or strange characters | A loose signal wire. Press the LCD firmly into the breadboard, then press the UNO's RESET button. |
| The backlight doesn't light | Check pin 15 goes through the 220 Ω resistor to the + rail and pin 16 to the − rail. |
| The backlight is very dim | Some LCDs already have their own backlight resistor, so with ours as well it is dimmer. That is safe. Ask an adult before removing any resistor. |
Turn the knob slowly from one end to the other while the text is showing. Where do the letters disappear, and where do they turn into solid blocks?
| Everything from Lessons 1-6 | all |
| Separate regulated 5V supply for the servo, with wires (recommended, not in the box) | 1 |
Every loop the sketch measures the distance, works out the zone and updates everything: 25 cm or more is green, 10-24 cm is yellow, under 10 cm is red with the buzzer.
The same distance, limited to 5-50 cm, becomes a servo angle, so the arm moves like a fuel-gauge needle. The LCD shows the distance and the angle.
If no echo comes back, the LCD shows --, all the LEDs and the buzzer go off and the servo goes to the middle.
| Part / pin | Connect to | Note |
|---|---|---|
| Red / yellow / green LED (each through 220 Ω) | UNO pins 2 / 3 / 4 | From Lesson 2 |
| Buzzer S | UNO pin 6 | From Lesson 3 |
| HC-SR04 TRIG / ECHO | UNO pins 8 / 9 | From Lesson 4 |
| LCD RS, E, D4, D5, D6, D7 | UNO pins 12, 11, 10, 7, A1, A2 | From Lesson 6 |
| Potentiometer middle pin | LCD pin 3 (VO) | From Lesson 6 |
| Servo orange (signal) | UNO pin 5 | From Lesson 5 |
| Servo red (+) | Separate 5V supply + | NEW - not the UNO 5V or the + rail |
| Servo brown (−) | − rail (GND) | |
| Separate supply GND | − rail (GND) | NEW - joins the grounds |
Easiest: scan the QR code above and press Copy or Download .ino on the lesson page, then paste it into the Arduino IDE and click Upload. The full listing is here for reading along.
/*
DIY KIT - Arduino UNO Sensor & Output Starter Kit
Lesson 7 of 7: Parking Assistant & Sensor Dashboard (uses every part)
PIN PLAN - the same pins as Lessons 1-6, so nothing moves:
Red LED -> 220 ohm -> pin 2 Yellow LED -> 220 ohm -> pin 3
Green LED -> 220 ohm -> pin 4 (LED short legs -> GND)
Servo signal (orange) -> pin 5 Buzzer S -> pin 6
HC-SR04 TRIG -> pin 8, ECHO -> pin 9
LCD RS 12, E 11, D4 10, D5 7, D6 A1, D7 A2; VO -> potentiometer middle pin
SERVO POWER (ask an adult): the servo's red wire goes to a SEPARATE
regulated 5 V supply, its brown wire to GND, and that supply's GND joins
the UNO GND. Never join the supply's + to the UNO 5V pin.
No supply? Leave the servo unplugged - everything else still works.
WHAT SHOULD HAPPEN (hold a book in front of the sensor)
25 cm or more : green LED 10-24 cm : yellow LED
under 10 cm : red LED + buzzer LCD shows the distance and servo angle,
and the servo arm swings like a gauge between about 5 and 50 cm.
*/
#include <Servo.h>
#include <LiquidCrystal.h>
const int RED_LED = 2;
const int YELLOW_LED = 3;
const int GREEN_LED = 4;
const int SERVO_PIN = 5;
const int BUZZER_PIN = 6;
const int TRIG_PIN = 8;
const int ECHO_PIN = 9;
const long NEAR_CM = 10; // closer than this: red LED + buzzer
const long SLOW_CM = 25; // closer than this: yellow LED
const bool BUZZER_ACTIVE_LOW = false; // same setting as Lesson 3
LiquidCrystal lcd(12, 11, 10, 7, A1, A2); // RS, E, D4, D5, D6, D7
Servo gauge;
void buzzer(bool on) {
if (BUZZER_ACTIVE_LOW) {
digitalWrite(BUZZER_PIN, on ? LOW : HIGH);
} else {
digitalWrite(BUZZER_PIN, on ? HIGH : LOW);
}
}
// Distance in cm, or -1 when no echo comes back (nothing in range).
long readDistanceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long us = pulseIn(ECHO_PIN, HIGH, 30000);
if (us == 0) return -1;
return us / 58;
}
// Light exactly one LED for the zone - or none when there is no reading.
void showZone(long cm) {
bool valid = cm > 0;
digitalWrite(RED_LED, valid && cm < NEAR_CM);
digitalWrite(YELLOW_LED, valid && cm >= NEAR_CM && cm < SLOW_CM);
digitalWrite(GREEN_LED, valid && cm >= SLOW_CM);
buzzer(valid && cm < NEAR_CM);
}
// 5 cm -> 170 degrees ... 50 cm -> 20 degrees. No reading -> middle (90).
int gaugeAngle(long cm) {
if (cm < 0) return 90;
cm = constrain(cm, 5, 50);
return map(cm, 5, 50, 170, 20);
}
void setup() {
pinMode(RED_LED, OUTPUT);
pinMode(YELLOW_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
buzzer(false);
lcd.begin(16, 2);
lcd.print("Parking Assist");
gauge.attach(SERVO_PIN);
gauge.write(90);
Serial.begin(9600);
Serial.println("Lesson 7: Parking Assistant & Sensor Dashboard");
delay(1000);
lcd.clear();
}
void loop() {
long cm = readDistanceCm();
int angle = gaugeAngle(cm);
showZone(cm);
gauge.write(angle);
lcd.setCursor(0, 0);
lcd.print("Dist: ");
if (cm < 0) {
lcd.print("-- ");
} else {
lcd.print(cm);
lcd.print(" cm "); // spaces wipe old digits
}
lcd.setCursor(0, 1);
lcd.print("Servo: ");
lcd.print(angle);
lcd.print(" deg ");
Serial.print("dist_cm:");
Serial.print(cm);
Serial.print(",servo_deg:");
Serial.println(angle);
delay(200);
}
| NEAR_CM and SLOW_CM | The two thresholds: under 10 cm is "too close", under 25 cm is "slow down". |
| readDistanceCm() | The Lesson 4 measurement. Returns -1 when no echo comes back. |
| showZone(cm) | Lights exactly one LED for the zone and switches the buzzer on only when too close. |
| gaugeAngle(cm) | 5 cm → 170°, 50 cm → 20°: the closer the object, the further the needle swings. |
| lcd.print(" cm ") | The extra spaces wipe out old digits when the number gets shorter. |
| Some parts work, others don't | Go back to that part's lesson and run its sketch: every lesson uses the same pins. |
| The UNO restarts when the servo moves | Stop. In this build the servo must not run from the UNO 5V. Use the separate supply, or unplug the servo. |
| The servo doesn't move with the supply connected | Check the supply's GND is joined to the − rail (common ground) and that the supply is switched on. |
| The buzzer is on all the time | Set BUZZER_ACTIVE_LOW = true, as you found in Lesson 3. |
| The LCD is blank or shows blocks | Turn the contrast knob, then recheck the Lesson 6 wiring. |
| Distance shows -- with a book in front | Check TRIG is on pin 8 and ECHO on pin 9, and aim at a flat, hard target. |
Make a parking space: tape a line on the table 10 cm from the sensor and push a toy car (or a box) towards it. Can you stop on the line using only the LEDs and the buzzer?
Unplug the USB cable first. Every problem below has its fix in the table of the lesson or step named on the right.
Every project in this kit uses the same parts, so you can combine them: add the display to a sensor project, or a buzzer to a measuring one. The project pages on diykit.ae have the code, the parts list and ideas to take each build further.
Most problems are one wire in the wrong hole. Check these first, then the lesson's "If it doesn't work" table:
Still stuck? Send us this message on WhatsApp with a photo of your wiring - scan the code to open WhatsApp with it already filled in: