Embedded Systems & IoT Β· Course 01

Raspberry Pi for Complete Beginners

Zero to confident β€” breadboards, GPIO, Linux, sensors, and real projects. Written for people who have never seen a Raspberry Pi in their life.

πŸ“ Beginner 12 modules Python + Linux Capstone: Smart room monitor
← Back to Embedded Track Next: Course 02 β†’
πŸ“ πŸ”Œ 🧰 πŸ’‘ 🐧
Course Progress
0%
// course_01_blueprint

What learners build in this course

This course is the hardware-first starting point for the Embedded Systems & IoT track. Learners move from safe breadboard wiring to a Raspberry Pi-powered device that reads sensors, controls outputs, displays live data, and can be checked remotely over the network.

FoundationBreadboards, jumper wires, resistors, GPIO voltage safety, and first circuits.
Linux device skillsRaspberry Pi OS, SSH, terminal navigation, updates, and remote workflows.
Hardware controlLEDs, buttons, buzzers, analog sensing through ADCs, I2C/SPI modules, PWM, servos, and motors.
Portfolio capstoneA smart room monitor with BME280 sensing, OLED output, button view switching, LED/buzzer alerts, and SSH access.
MODULE 01

Breadboards, Assembly & Add-Ons

Before you ever power on a Raspberry Pi, you need to understand the board you'll be building circuits on. This module covers breadboard anatomy, safe wiring, choosing the right add-ons, and assembling your first real circuit β€” assuming you've never touched electronics hardware before.

🧱 What Is a Breadboard?

A breadboard is a plastic board full of tiny spring-loaded holes that let you build circuits by pushing wires and component legs into them β€” no soldering required. It exists so you can prototype, test, and rewire a circuit in seconds instead of permanently joining metal every time you change your mind.

The holes aren't just decoration β€” underneath the plastic, certain rows of holes are electrically connected to each other by metal strips. Understanding which holes are connected to which is the single most important thing to learn before touching one.

πŸ—ΊοΈ Breadboard Anatomy

A standard full-size breadboard has four separate zones. Here's the layout, top to bottom:

β”Œβ”€ POWER RAILS (top) ──────────────────────────────┐ + + + + + + + + + + + + + + + + + + + + + + + + + ← red line, positive rail - - - - - - - - - - - - - - - - - - - - - - - - - ← blue line, ground rail a b c d e | | f g h i j ← each column a-e is ONE connected strip a b c d e | | f g h i j (columns f-j are a SEPARATE strip) a b c d e | | f g h i j the center gap does NOT connect them ... (rows 1-30 or more) ... + + + + + + + + + + + + + + + + + + + + + + + + + ← POWER RAILS (bottom) - - - - - - - - - - - - - - - - - - - - - - - - - β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Power rails β€” the long rows running the full length of the board, marked with a red (+) line and a blue/black (βˆ’) line. Every hole along a single rail is connected to every other hole on that same rail. This is where you distribute power and ground to the whole board.
  2. Terminal strips β€” the main grid in the middle. Each short vertical column of 5 holes (labeled a–e or f–j) is electrically connected within that column only. Row 12, columns a-e are one connected group; row 12, columns f-j are a completely separate group.
  3. The center gap β€” the trench splitting the board left/right. It exists specifically so you can straddle a chip across it without shorting its left-side pins to its right-side pins.
⚠️
The #1 beginner mistakeAssuming the two halves of a row (a-e and f-j) are connected. They are NOT. If your circuit "isn't working," the very first thing to check is whether you plugged something into the wrong side of the gap.
πŸ’‘
Many boards split the power rails tooOn longer breadboards, the top power rail and bottom power rail are often electrically separate from each other, and sometimes even split in the middle left/right. Don't assume β€” test with a multimeter (covered below) if you're unsure.
πŸ“ Labeled Reference Diagram

Here's a fully labeled 830 tie-point breadboard β€” the same anatomy from above, shown on a real board layout with every region called out.

Labeled diagram of an 830 tie-point breadboard showing power rails, main terminal strip sections, the center isolation barrier, and independent vertical metal strips
LabelWhat It Means
Overall Length / Width (~165mm Γ— ~55mm)Typical physical dimensions of a standard full-size breadboard β€” useful for confirming you have a full-size (not half-size) board.
Power Rails β€” Positive (red, +) / Negative (blue, βˆ’)The two long rows running the edge of the board. Every hole along one rail is electrically tied together, letting you distribute power and ground to the whole board.
Main Terminal Strip SectionThe central grid where components and jumper wires actually plug in. Divided into short 5-hole columns, each one an isolated connected group.
Electrical Isolation Barrier (Centre Divider)The physical trench splitting the A–E row group from the F–J row group β€” lets you straddle a chip across it without shorting its own legs together.
Independent Vertical Metal Strip (A–E)One connected group of 5 holes (rows A, B, C, D, E) within a single column β€” isolated from the F–J strip in that same column.
Independent Vertical Metal Strip (F–J)The mirrored group below the center divider β€” rows F, G, H, I, J connected within a column, isolated from A–E.
Isolated Vertical Connections (5 points each)Confirms each column strip ties together exactly 5 holes β€” not the whole row, and not the opposite side of the gap.
Internal Continuous Strip (rail)The metal strip running underneath a power rail for its length, which is what actually carries the current between holes.
External Tie-PointsThe holes you see and plug into on top of that internal strip.
"Break in rail metal at midpoint" noteA real-world manufacturing detail: on many long breadboards, the + or βˆ’ rail is physically cut in the middle, so the left half's rail may not be connected to the right half's rail unless you bridge them with a jumper wire.
Detail Point Counts (630 + 200 = 830)The math behind an "830 tie-point" board: 2 row-groups Γ— 63 columns Γ— 5 holes = 630 main tie-points, plus 4 rails Γ— ~50 holes = 200 rail points.
⚠️
Column numbering varies by manufacturerSome full-size boards number continuously across the whole board; others are really two independently-numbered halves pushed together. Don't assume your board's column numbers match a diagram exactly β€” trace it with a multimeter if you're unsure.
πŸ”— Jumper Wires β€” Which Kind Do You Need?

Jumper wires connect one point on the breadboard to another, or to the Raspberry Pi's pins. They come in three end types, and picking the right one matters:

TypeLooks LikeUse For
Male–Male (M-M)Solid pin on both endsBreadboard hole β†’ breadboard hole
Male–Female (M-F)Solid pin one end, socket the otherRaspberry Pi GPIO pin β†’ breadboard hole
Female–Female (F-F)Socket on both endsPin header β†’ pin header (e.g. Pi to a HAT riser, or sensor module with pin headers)
πŸ’‘
Which one will you use most?Male-to-Female. One end plugs onto a Raspberry Pi GPIO pin (which is a solid pin sticking up, so it needs a socket), the other end plugs into a breadboard hole (which needs a solid pin). Buy a kit with all three types β€” they're cheap and you'll eventually want all of them.
⚑ GPIO Voltage Safety β€” Read This Before You Plug Anything In

The Raspberry Pi's GPIO (General Purpose Input/Output) pins operate at 3.3 volts, not 5 volts. This is different from an Arduino Uno, which is 5V β€” if you've seen Arduino tutorials, don't copy their voltage assumptions onto a Pi.

⚠️
This is the rule that protects your PiNever connect a GPIO pin directly to 5V, and never send more than 3.3V into a GPIO input pin. The GPIO pins are not 5V tolerant β€” doing this can permanently destroy that pin, or the entire board. Always double-check a sensor or module's voltage requirements before wiring it to GPIO. If a module needs 5V power, that's fine (many do) β€” just make sure its signal/data pins that talk to the Pi are 3.3V logic, or use a level shifter/logic converter in between.

The Pi's 40-pin header does provide both 3.3V and 5V power pins (for powering external components), but only ever wire the signal lines at 3.3V.

πŸ”’ Ohm's Law & Picking a Resistor for Your LED

Almost every first circuit is an LED, and almost every LED needs a current-limiting resistor in series with it β€” without one, an LED will pull too much current and burn out almost instantly. Here's the formula and how to use it:

Ohm's Law

R = (Vsupply βˆ’ VLED) Γ· ILED β€” Resistance equals the leftover voltage divided by the current you want flowing.

Worked example, using a standard red LED on a Raspberry Pi GPIO pin:

  1. GPIO supply voltage: 3.3V
  2. Typical red LED forward voltage drop: ~2V (check your LED's datasheet if unsure)
  3. Target LED current: ~20mA (0.02A) β€” a safe, typical brightness
  4. R = (3.3 βˆ’ 2) Γ· 0.02 = 65Ξ© minimum
  5. Round up to the nearest common resistor value: 220Ξ© or 330Ξ© are the standard "safe default" choices for GPIO LEDs β€” they dim the LED slightly but guarantee you're not over-driving it or the pin.
πŸ’‘
When in doubt, go biggerA resistor that's too large just makes the LED slightly dimmer. A resistor that's too small (or missing) can destroy the LED or damage the GPIO pin. If you don't have the exact calculated value, always round up.
🎨 Reading Resistor Color Bands

Resistors don't have their value printed as a number β€” they use colored bands. For the common 4-band resistors you'll use in this course, you only need to recognize a handful of colors to identify 220Ξ© and 330Ξ© on sight:

Red = 2
Orange = 3
Black = 0
Brown = 1 (also means Γ—10 as the multiplier band)
Gold = Β±5% tolerance (usually the last band)
Bands (in order)Value
Red, Red, Brown, Gold220Ξ©
Orange, Orange, Brown, Gold330Ξ©
πŸ’‘
Don't want to memorize color codes yet?That's fine β€” most beginner kits sort resistors into labeled tubes or bags. A cheap digital multimeter (below) will also just tell you the exact resistance if you're ever unsure.
πŸ”¨ Assembling Your First Circuit β€” LED + Pushbutton

Let's put it together. This circuit doesn't need a Raspberry Pi yet β€” you're only practicing breadboard wiring and safe assembly habits. (Module 6 will connect this exact circuit to GPIO code.)

  1. Place the LED so its two legs straddle the center gap β€” one leg on the left terminal strip, one on the right. Note which leg is longer β€” that's the anode (+). The shorter leg (often next to a flat edge on the LED's plastic case) is the cathode (βˆ’).
  2. Place a 220Ξ© or 330Ξ© resistor so one end shares a terminal strip column with the LED's anode (long leg), and the other end reaches a free column.
  3. Run a jumper wire from the resistor's free end to the breadboard's positive (+) power rail.
  4. Run a second jumper wire from the LED's cathode (short leg) column to the negative (βˆ’) power rail.
  5. For the pushbutton: place it straddling the center gap (most 4-leg breadboard buttons are sized exactly for this). Only two of the four legs are ever connected to each other internally β€” the other two are a separate connected pair. Straddling the gap keeps all four legs electrically separate until the button is pressed.
  6. Wire one side of the button to the positive rail (through a resistor, if you're prepping for GPIO input later β€” this is called a pull-down/pull-up resistor, covered in Module 5) and the other side to a terminal strip column you'll read as input.
⚠️
LED polarity mattersAn LED only conducts current in one direction. Plug it in backwards and it simply won't light up β€” it won't damage anything at low current, but it's the most common reason a "broken" circuit is actually just fine. If your LED doesn't light, try flipping it around before you assume anything else is wrong.
🧰 Breadboard Add-Ons & Their Uses

Once you're comfortable with the bare breadboard, a handful of inexpensive add-ons make working with a Raspberry Pi dramatically easier. Here's what's actually worth having and why:

πŸŽ—οΈ

GPIO T-Cobbler / Breakout

A ribbon cable + adapter that "unfolds" the Pi's 40-pin header onto the breadboard itself, with each pin clearly labeled. Without one, you're stuck plugging individual jumper wires straight into the Pi's header, which is cramped and easy to miscount.

πŸŽ€

GPIO Ribbon Cable

The cable that connects the Pi's header to the T-Cobbler (or directly to a HAT). Look for one long enough to comfortably reach your breadboard without straining the header pins.

πŸ”‹

Breadboard Power Supply Module

A small board that clips onto the power rails and regulates an external power source (like a 9V battery or wall adapter) down to a clean 3.3V or 5V β€” so you're not relying on the Pi itself to power power-hungry add-ons like motors or many LEDs at once.

πŸ“

Digital Multimeter

Measures voltage, resistance, and continuity. Essential for checking whether two breadboard holes are actually connected, verifying a resistor's real value, and confirming a circuit is receiving the voltage you expect before you plug in anything expensive.

🧡

Jumper Wire Kit (M-M / M-F / F-F)

Buy a mixed pack up front. You will run out of the "right" wire mid-project constantly otherwise, and improvising with the wrong connector type is how shorts happen.

🍞

Half-Size vs Full-Size Breadboards

Full-size boards (830 points) give you room for multiple components at once; half-size (400 points) are fine for simple single-circuit lessons and more portable. This course assumes a full-size board so there's room to grow.

🎩 What's a "HAT," and Do You Need One Yet?

A HAT (Hardware Attached on Top) is a add-on board that plugs directly onto the Pi's 40-pin GPIO header, sitting on top of the Pi like a lid β€” no breadboard required. HATs exist so you can skip manual wiring for common, well-defined tasks. You don't need any of these for this module, but it's worth knowing what exists so you recognize them later in the course:

HATWhat It's For
Sense HATBundles a gyroscope, accelerometer, temperature/humidity/pressure sensors, and an 8Γ—8 LED matrix β€” great for a single "starter sensor board" instead of wiring six separate parts
Motor HAT / Driver HATLets the Pi safely control DC motors or servos, which draw more current than GPIO pins can supply directly (covered in Module 9)
ADC HAT / breakout (e.g. MCP3008-based)Adds analog input β€” the Pi's GPIO pins are digital-only, so anything analog (a potentiometer, many analog sensors) needs one of these (covered in Module 7)
RTC (Real-Time Clock) HATKeeps accurate time using a small battery, for projects that run without internet access and need to know the correct time on boot
ℹ️
Breadboard first, HATs laterThis course deliberately starts on a bare breadboard rather than jumping straight to HATs β€” wiring things by hand first is what teaches you what a HAT is actually doing for you under the hood. Once you understand the wiring, HATs become time-savers instead of black boxes.
βœ… Configuration Checklist Before You Power Anything On
  1. Double-check LED and any polarized component orientation (long leg = positive).
  2. Confirm no wire bridges the gap between the positive and negative power rails directly (a dead short) β€” trace every wire back to its rail before connecting power.
  3. Confirm your resistor is actually in the circuit path β€” not just nearby on the board, but electrically in series between power and the LED.
  4. If using a multimeter, set it to continuity mode and touch both probes across your intended connections to confirm they beep/connect as expected β€” before the Pi or any power source is connected.
  5. Only after all of the above: connect power, and watch for any smoke, smell, or unusual heat β€” disconnect immediately if you notice any.
🧠 Quick Check
You accidentally wire a sensor's signal pin to the Raspberry Pi's 5V power pin instead of 3.3V. What's the risk?
🧠 Quick Check
On a standard breadboard, which holes are electrically connected to each other?
MODULE 02

πŸ“ Meet the Raspberry Pi

Boards, the GPIO pinout, and the peripherals you'll actually need before you can turn one on.

🧠 What Is a Raspberry Pi?

A Raspberry Pi is a single-board computer (SBC) β€” a complete, small computer with a CPU, memory, and ports, all on one credit-card-sized board. Unlike your laptop, it has no built-in screen, keyboard, or storage drive β€” you supply those, or run it "headless" (no monitor at all, controlled remotely).

What makes it different from a normal desktop is the GPIO header β€” a row of 40 pins along one edge that let the board directly control and read real-world electronics: LEDs, sensors, motors, switches. That's the part a laptop can't do.

πŸ” Which Board Should You Use?
BoardGood ForNotes
Raspberry Pi 5 / 4This course, general projects, anything needing real performanceFull Linux OS, runs a desktop, most powerful
Raspberry Pi Zero 2 WSmall, low-power, battery-friendly projectsSame 40-pin GPIO layout, weaker CPU, smaller form factor
Raspberry Pi PicoSimple, always-on microcontroller tasksNot the same thing β€” no OS, no Linux, programmed differently (MicroPython/C on bare metal). This course is NOT about the Pico.
ℹ️
This course assumes a Pi 4 or Pi 5Everything here β€” the OS, the GPIO pin numbers, the wiring β€” applies directly to Pi 4 and Pi 5 (and mostly to Zero 2 W). If you have a Pico, that's a different device with a different course path.
πŸ—ΊοΈ Anatomy of the Board
  • SoC (System on Chip) β€” the black chip in the middle; it's the CPU and GPU combined.
  • microSD card slot (underside) β€” this is where the entire operating system lives. There's no internal hard drive.
  • USB-C power port β€” this is power input only, not a data connection to a computer.
  • USB-A ports β€” for keyboard, mouse, flash drives.
  • Ethernet port β€” wired networking; Wi-Fi is also built in.
  • Micro-HDMI ports (Γ—2 on Pi 4/5) β€” video output to a monitor. Note: micro-HDMI, not full-size β€” you'll likely need an adapter cable.
  • Camera (CSI) and Display (DSI) connectors β€” small ribbon-cable slots for the official Camera Module (Module 11) and touchscreens.
  • 40-pin GPIO header β€” the row of pins along the top edge. This is what the rest of this course is built around.
πŸ“Œ The GPIO Pinout

The 40-pin header has three categories of pins, and mixing them up is the most common wiring mistake:

Pin 1 [3.3V] [5V] Pin 2 Pin 3 [GPIO2/SDA] [5V] Pin 4 Pin 5 [GPIO3/SCL] [GND] Pin 6 Pin 7 [GPIO4] [GPIO14] Pin 8 Pin 9 [GND] [GPIO15] Pin 10 Pin 11 [GPIO17] [GPIO18] Pin 12 ... (continues to Pin 40) ...
Pin TypeWhat It Does
Power pins (3.3V, 5V)Fixed voltage output to power external components. Never treat these as GPIO signal pins.
Ground (GND) pinsCommon reference point for every circuit. Any circuit touching GPIO needs to share ground with the Pi.
GPIO pins (numbered)General-purpose digital input/output β€” the pins you'll program in Module 4 onward.
⚠️
Two different numbering systems exist"BCM" numbers refer to the chip's internal GPIO number (e.g. GPIO17). "Physical" or "BOARD" numbers refer to the pin's position on the header (e.g. Pin 11). These are NOT the same number for the same pin β€” GPIO17 is physical Pin 11. Every tutorial should tell you which system it's using. We'll cover this in detail in Module 4.
🧰 What You Need Before Powering On
  1. A microSD card (16GB minimum, 32GB+ recommended) β€” this becomes your entire operating system and storage.
  2. A proper power supply β€” official Pi power adapters are rated for the current spikes the board needs; an underpowered phone charger causes random reboots and corrupted SD cards. This is a common, confusing failure mode for beginners.
  3. Either: a monitor + micro-HDMI cable + USB keyboard/mouse (for a normal first setup), or just a laptop on the same network (for a "headless" no-monitor setup, covered in Module 3).
  4. Optional but recommended: a case, for both physical protection and cooling.
🧠 Quick Check
A tutorial says "connect your sensor to GPIO17." Where physically is that on the 40-pin header?
MODULE 03

πŸ’Ώ Raspberry Pi OS & First Boot

Turning a blank microSD card into a working Raspberry Pi β€” imaging, first boot, and setting up headless (no monitor) access.

πŸ’Ύ Imaging the SD Card

The official Raspberry Pi Imager tool (free, from raspberrypi.com/software) writes an operating system onto your microSD card. This step happens on your regular computer, not on the Pi itself β€” the Pi doesn't exist as a working device until this card is ready.

  1. Download and install Raspberry Pi Imager on your PC/Mac.
  2. Insert your microSD card via a USB card reader.
  3. Open Imager β†’ Choose Device β†’ select your Pi model.
  4. Choose OS β†’ Raspberry Pi OS (64-bit) is the standard choice. Choose the Lite version if you plan to go headless (no desktop environment, smaller and faster); choose the full version if you want a monitor and desktop.
  5. Choose Storage β†’ select your microSD card. Double-check this is the SD card and not your PC's main drive β€” Imager will erase whatever you select.
πŸ”§ Advanced Options β€” Set This Up BEFORE First Boot

Before clicking write, click the gear/advanced options icon. This is where you configure everything you'd otherwise need a monitor and keyboard to set up manually:

  1. Enable SSH β€” check this box. Without it, you cannot connect to the Pi remotely at all.
  2. Set username and password β€” pick your own; don't leave this on any default.
  3. Configure Wi-Fi β€” enter your network name and password so the Pi connects automatically on first boot.
  4. Set hostname β€” e.g. mypi.local β€” lets you find the Pi on your network by name instead of hunting for its IP address.
πŸ’‘
This is what makes headless setup possibleDoing this now means you never need to connect a monitor or keyboard to the Pi at all β€” it'll boot straight onto your Wi-Fi with SSH already waiting for you.
πŸ”Œ First Boot
  1. Insert the finished microSD card into the Pi (slot is on the underside).
  2. Connect power last, after everything else is plugged in.
  3. Wait 60–90 seconds for first boot β€” it's doing first-time setup in the background, so don't panic if nothing appears on a monitor immediately.
  4. Headless: from your PC's terminal, run ssh username@mypi.local (using the username and hostname you set in Imager).
  5. With monitor: you'll be dropped into either a desktop or a login prompt directly.
Terminal β€” First SSH Connection
ssh jude@mypi.local
# First connection asks to confirm the host's fingerprint β€” type "yes"
# Then enter the password you set in Imager
βš™οΈ raspi-config β€” The Pi's Control Panel

Once connected, raspi-config is a text-based menu for settings you'll come back to constantly throughout this course β€” enabling I2C/SPI/Camera (Modules 7, 11), expanding filesystem, changing hostname, and more.

Terminal
sudo raspi-config

Navigate with arrow keys, Enter to select, Tab to move between buttons. You'll return to this tool repeatedly in later modules to enable specific interfaces.

🧠 Quick Check
You want to set up your Pi without ever connecting a monitor. What's the one setting in Imager's advanced options you absolutely cannot skip?
MODULE 04

⌨️ Linux & Command Line Essentials

Raspberry Pi OS is Linux, and most of this course happens in a terminal, not a mouse-driven interface. Here's the minimum command set you need before writing any GPIO code.

🧭 Finding Your Way Around
CommandWhat It Does
pwdPrint working directory β€” shows where you currently are
lsList files and folders in the current directory
ls -laList everything, including hidden files, with details (permissions, size, date)
cd foldernameChange directory into "foldername"
cd ..Move up one directory level
cd ~Jump straight to your home directory
πŸ“ Working With Files & Folders
CommandWhat It Does
mkdir projectnameCreate a new folder
touch file.pyCreate a new empty file
cp source destCopy a file
mv source destMove or rename a file
rm file.pyDelete a file β€” no trash bin, this is permanent
rm -r foldernameDelete a folder and everything inside it β€” same permanence warning, doubled
cat file.pyPrint a file's contents to the screen
⚠️
There's no undoUnlike deleting a file in a desktop file manager, rm does not go to a recycle bin. Double-check the filename before hitting enter, especially with rm -r.
✏️ Editing Files β€” nano

You'll write Python scripts directly on the Pi. nano is the easiest terminal text editor to start with (vim is more powerful but has a steeper learning curve β€” feel free to explore it later).

Terminal
nano blink.py
# Type your code directly
# Ctrl+O then Enter β†’ saves the file
# Ctrl+X β†’ exits nano
πŸ”‘ sudo & Permissions

sudo ("superuser do") runs a command with administrator privileges. Some tasks β€” installing software, editing system config, accessing certain hardware pins β€” require it; running everything with sudo out of habit is unnecessary and can mask real permission problems.

Terminal β€” Keeping Your System Updated
sudo apt update
sudo apt upgrade -y

apt is Raspberry Pi OS's package manager β€” how you install nearly all software from the command line. update refreshes the list of what's available; upgrade actually installs newer versions of what you have.

🐍 Running Your First Python Script
Terminal
python3 blink.py

Every GPIO script from Module 5 onward is run exactly this way β€” python3 followed by the filename. Press Ctrl+C to stop a running script.

🧠 Quick Check
You want to permanently delete an entire project folder called "test". Which command does that?
MODULE 05

🐍 GPIO Programming Basics

Reading and writing GPIO pins from Python β€” the bridge between the breadboard circuits from Module 1 and actual code.

πŸ”’ BCM vs BOARD Numbering β€” Pick One and Be Consistent

From Module 2: pins can be referred to by their physical position (BOARD numbering, 1–40) or by their internal chip number (BCM numbering, e.g. GPIO17). Every GPIO library needs to be told which system you're using β€” mixing them up in your head is the single most common beginner bug.

SystemExampleWhen You'll See It
BOARDPin 11Counting straight down the physical header
BCMGPIO17Most tutorials and libraries default to this β€” it's what this course uses
πŸ’‘
This course uses BCM numbering throughoutWhen you see "GPIO17" from here on, that's the BCM number β€” check a pinout diagram if you need to find its physical location on the header.
πŸ“š Two Libraries: gpiozero vs RPi.GPIO
LibraryStyleBest For
gpiozeroHigh-level, beginner-friendly (e.g. LED(17).on())This course β€” faster to read, faster to write, fewer lines for the same result
RPi.GPIOLower-level, more manual (GPIO.setup(), GPIO.output())Understanding what's happening underneath, or following older tutorials

Both come pre-installed on Raspberry Pi OS. This course leads with gpiozero because it maps directly onto real components β€” an LED object, a Button object β€” matching how you're already thinking about the breadboard.

πŸ’‘ Your First Script β€” Blink an LED

Using the exact LED + resistor circuit you built in Module 1, wired so the resistor leg connects to GPIO17 instead of the positive power rail:

Python β€” blink.py
from gpiozero import LED
from time import sleep

led = LED(17)  # GPIO17, BCM numbering

while True:
    led.on()
    sleep(1)
    led.off()
    sleep(1)

Run it with python3 blink.py, stop it with Ctrl+C. That's the entire pattern you'll reuse for every digital output device in this course β€” create an object with a pin number, call methods on it.

πŸ”˜ Reading Input β€” A Button
Python β€” button_read.py
from gpiozero import Button

button = Button(2)  # GPIO2

while True:
    button.wait_for_press()
    print("Button pressed!")

gpiozero automatically handles the internal pull-up/pull-down resistor configuration for you here β€” a detail RPi.GPIO makes you set manually. This is part of why gpiozero reads so much cleaner for beginners.

πŸ”— Combining Input and Output
Python β€” button_led.py
from gpiozero import LED, Button

led    = LED(17)
button = Button(2)

button.when_pressed  = led.on
button.when_released = led.off

from signal import pause
pause()

when_pressed and when_released let you assign a function to run automatically on an event, instead of manually polling in a loop. pause() just keeps the script alive waiting for those events.

🧠 Quick Check
A tutorial says "GPIO27." In this course's convention, what does that number refer to?
MODULE 06

πŸ’‘ Digital I/O Projects

Three complete projects β€” LED patterns, a debounced button, and a buzzer β€” combining the wiring from Module 1 with the code patterns from Module 5.

🚦 Project 1: Traffic Light Sequence

Wire three LEDs (red, yellow, green) each with their own 220Ξ© resistor, each to a separate GPIO pin, all sharing one ground connection back to the negative rail.

Python β€” traffic_light.py
from gpiozero import LED
from time import sleep

red    = LED(17)
yellow = LED(27)
green  = LED(22)

try:
    while True:
        red.on();    sleep(4);  red.off()
        green.on();  sleep(4);  green.off()
        yellow.on(); sleep(1);  yellow.off()
except KeyboardInterrupt:
    print("Stopped.")
πŸ’‘
try/except KeyboardInterruptWrapping the loop this way catches Ctrl+C cleanly instead of dumping a traceback error β€” good practice for every long-running GPIO script from here on.
πŸ”˜ Project 2: Debounced Button Counter

Mechanical buttons don't switch cleanly β€” the metal contacts physically bounce for a few milliseconds, which can register as several rapid presses instead of one. This is called bounce, and it's why a naive button script sometimes counts 3 presses for 1 press.

Python β€” button_counter.py
from gpiozero import Button

count = 0
# bounce_time filters out rapid duplicate triggers within 0.1 seconds
button = Button(2, bounce_time=0.1)

def on_press():
    global count
    count += 1
    print(f"Press #{count}")

button.when_pressed = on_press

from signal import pause
pause()
⚠️
If your button counter jumps by 2-3 per pressThat's bounce. Increase bounce_time slightly (e.g. to 0.2), or check your wiring β€” a loose breadboard connection can also mimic bounce.
πŸ”Š Project 3: Buzzer Alert

A passive piezo buzzer wires exactly like an LED (one leg to a GPIO pin through a resistor, one to ground) and is controlled identically in code.

Python β€” buzzer_alert.py
from gpiozero import Buzzer, Button
from signal import pause

buzzer = Buzzer(27)
button = Button(2)

button.when_pressed  = buzzer.on
button.when_released = buzzer.off

pause()
🎯 Checkpoint Challenge

Combine All Three

Build one circuit with all three LEDs, the button, and the buzzer on one breadboard. Write a script where pressing the button cycles through the traffic light sequence once, then sounds the buzzer for half a second at the end. This forces you to manage multiple gpiozero objects and event handlers together in one script β€” the same shape of problem you'll face in the Module 12 capstone.

🧠 Quick Check
Your button script registers 3 presses every time you press it once. What's the most likely cause?
MODULE 07

πŸ“Š Analog Sensing with ADCs

The Raspberry Pi's GPIO pins are digital-only β€” they can only read HIGH or LOW, never "somewhere in between." Here's how to add real analog sensing with an external chip.

❓ Why Doesn't the Pi Have Analog Input?

Digital pins read exactly two states: roughly 0V (LOW/off) or roughly 3.3V (HIGH/on) β€” nothing in between. Many real-world sensors β€” a potentiometer's position, a light sensor's brightness, a flex sensor's bend β€” output a continuously varying voltage, not a clean on/off signal. Microcontrollers like Arduino have built-in circuitry (an ADC) to read those in-between voltages directly. The Raspberry Pi's GPIO does not β€” you need to add that circuitry yourself with an external chip.

πŸ”Œ The MCP3008 β€” An 8-Channel ADC

The MCP3008 is a small chip that reads up to 8 separate analog inputs and reports each one back to the Pi as a digital number (0–1023) over a protocol called SPI (covered in more depth in Module 8). It's the standard, well-documented choice for adding analog sensing to a Pi project.

MCP3008 PinConnects To
VDD, VREFPi 3.3V
AGND, DGNDPi GND
CLK, DOUT, DIN, CSPi SPI pins (GPIO11, 9, 10, 8 respectively)
CH0–CH7Your analog sensors β€” up to 8 at once
⚠️
Enable SPI firstSPI is disabled by default. Run sudo raspi-config β†’ Interface Options β†’ SPI β†’ Enable, then reboot, before any code below will work.
πŸŽ›οΈ Reading a Potentiometer

Wire a potentiometer's outer two legs to 3.3V and GND, and its middle (wiper) leg to MCP3008 channel 0.

Python β€” read_pot.py
from gpiozero import MCP3008
from time import sleep

pot = MCP3008(channel=0)

while True:
    print(f"Value: {pot.value:.2f}")  # 0.0 to 1.0
    sleep(0.5)

gpiozero's MCP3008 class handles the SPI communication for you and gives back a clean 0.0–1.0 float, regardless of the chip's internal 0–1023 resolution β€” the same "let the library handle the messy part" pattern from Module 5.

πŸ’‘ Combining Analog Input With Digital Output
Python β€” pot_led_brightness.py
from gpiozero import MCP3008, PWMLED
from time import sleep

pot = MCP3008(channel=0)
led = PWMLED(17)  # PWMLED supports variable brightness, not just on/off

while True:
    led.value = pot.value  # directly map 0.0-1.0 pot reading to 0.0-1.0 LED brightness
    sleep(0.05)

Turning the potentiometer now smoothly dims the LED β€” your first real analog-to-digital-to-analog pipeline: a physical continuous input, read through the ADC, driving a continuously variable output (PWM, covered fully in Module 9).

🧠 Quick Check
Why can't you plug a potentiometer's wiper pin directly into a Raspberry Pi GPIO pin and read its position?
MODULE 08

πŸ”— I2C & SPI β€” Displays & Sensors

Two communication protocols that let you connect complex devices β€” displays, sensors, real-time clocks β€” using just a few shared wires instead of one GPIO pin per signal.

πŸ†š I2C vs SPI β€” What's the Difference?
I2CSPI
Wires needed2 (SDA, SCL) β€” shared by ALL I2C devices4+ (MOSI, MISO, CLK, plus one CS per device)
SpeedSlowerFaster
Multiple devicesEasy β€” each has a unique address on the same 2 wiresNeeds a separate CS (chip select) wire per device
Common usesSensors, small OLED displays, RTC modulesADCs (Module 7), SD cards, faster displays
πŸ’‘
Rule of thumbIf you're wiring several sensors at once and don't need blazing speed, I2C is usually the simpler choice β€” same 2 wires for every device. If you need speed or you're using something that specifically requires SPI (like the MCP3008), use SPI.
βš™οΈ Enabling I2C
Terminal
sudo raspi-config
# Interface Options β†’ I2C β†’ Enable β†’ reboot

Once enabled and rebooted, install the detection tool:

Terminal
sudo apt install -y i2c-tools
i2cdetect -y 1

This prints a grid showing every I2C device's address currently detected on the bus β€” the fastest way to confirm a sensor is wired correctly before writing a single line of code.

🌑️ Example: BME280 Temperature/Humidity/Pressure Sensor (I2C)

Wire VIN→3.3V, GND→GND, SCL→GPIO3, SDA→GPIO2 — the same two I2C pins every I2C device shares.

Terminal β€” Install the Library
pip3 install adafruit-circuitpython-bme280
Python β€” read_bme280.py
import board
from adafruit_bme280 import basic as adafruit_bme280

i2c = board.I2C()
bme = adafruit_bme280.Adafruit_BME280_I2C(i2c)

print(f"Temp: {bme.temperature:.1f} C")
print(f"Humidity: {bme.humidity:.1f} %")
print(f"Pressure: {bme.pressure:.1f} hPa")
πŸ“Ί Example: SSD1306 OLED Display (I2C)

A small 128Γ—64 OLED screen β€” same two I2C wires, different address on the bus.

Terminal β€” Install the Library
pip3 install adafruit-circuitpython-ssd1306 pillow
Python β€” oled_hello.py
import board
import adafruit_ssd1306
from PIL import Image, ImageDraw

i2c = board.I2C()
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)
oled.fill(0)
oled.show()

image = Image.new("1", (oled.width, oled.height))
draw  = ImageDraw.Draw(image)
draw.text((0, 0), "Hello, Pi!", fill=255)
oled.image(image)
oled.show()
🧠 Quick Check
You want to wire both a BME280 sensor and an SSD1306 display at the same time. How many extra GPIO pins does the second device need?
MODULE 09

βš™οΈ PWM & Motors

Controlling servos and DC motors β€” and the one rule that protects your Pi: motors never connect straight to GPIO.

πŸ“Ά What Is PWM?

PWM (Pulse Width Modulation) is how a digital-only pin fakes an analog-style output. Instead of a steady voltage, the pin switches on and off very rapidly β€” the duty cycle (the percentage of time it's on vs. off) determines the effective average power. A 100% duty cycle is full on, 50% is roughly half power, 0% is off.

You already saw this in Module 7's PWMLED β€” dimming an LED is PWM. Servos and motor speed control both use the exact same underlying concept.

🎚️ Servo Motors

A servo moves to a specific angle (usually 0°–180Β°) based on the PWM signal it receives, and holds that position β€” unlike a continuous DC motor, which just spins.

Python β€” servo_sweep.py
from gpiozero import Servo
from time import sleep

servo = Servo(17)

while True:
    servo.min()  # -1, roughly 0 degrees
    sleep(1)
    servo.mid()  # 0, roughly 90 degrees
    sleep(1)
    servo.max()  # 1, roughly 180 degrees
    sleep(1)
⚠️
Servos need their own powerA single small servo can sometimes run directly off the Pi's 5V pin for quick tests, but anything beyond one small servo needs an external 5V power supply β€” the Pi's own power rail can't supply enough current for multiple servos or continuous heavy movement.
πŸš— DC Motors β€” Why You Need a Motor Driver

DC motors draw far more current than a GPIO pin can safely provide, and β€” critically β€” spinning a motor down generates a voltage spike (back-EMF) that can damage the Pi if wired directly. A motor driver chip (like the L298N or TB6612) sits between the Pi and the motor: the Pi sends it a low-power control signal, and the driver switches the motor's separate, higher-current power supply.

Pi SideMotor DriverMotor Side
GPIO control pins (low current)Switches high current based on GPIO signalExternal motor power supply (separate from Pi)
⚠️
Never wire a DC motor directly to GPIOEven a small hobby motor can pull more current than a GPIO pin is rated for, and the back-EMF from the motor's coil can damage the pin when it stops. Always go through a motor driver.
πŸ”§ Driving a DC Motor
Python β€” dc_motor.py
from gpiozero import Motor
from time import sleep

# forward and backward pins go to the motor driver's control inputs, NOT the motor directly
motor = Motor(forward=17, backward=27)

motor.forward()
sleep(2)
motor.backward()
sleep(2)
motor.stop()

gpiozero's Motor class assumes you've wired those two GPIO pins into a motor driver's inputs β€” it's controlling the driver, which controls the motor.

🧠 Quick Check
Why can't you wire a DC motor's power leads directly to a GPIO pin, the same way you'd wire an LED?
MODULE 10

πŸ“‘ Networking & Remote Access

Going fully headless β€” reliable SSH, a graphical remote desktop when you need one, and giving your Pi an address that doesn't change.

πŸ”‘ SSH β€” The Basics You'll Use Every Session
Terminal
ssh jude@mypi.local
# or, if the hostname doesn't resolve:
ssh jude@192.168.1.42

If mypi.local doesn't resolve on your network, find the Pi's IP address instead β€” either check your router's connected-devices list, or run hostname -I directly on the Pi if you have any access to it.

πŸ–₯️ VNC β€” When You Need a Full Desktop

SSH gives you a terminal only. For a full graphical desktop remotely (useful for Module 11's camera preview, for example), enable VNC:

Terminal
sudo raspi-config
# Interface Options β†’ VNC β†’ Enable

Then install RealVNC Viewer on your PC/Mac/phone and connect using the same hostname or IP you use for SSH. Note this only works if you installed the full Raspberry Pi OS Desktop, not the Lite version from Module 3.

πŸ“Œ Giving Your Pi a Static IP

By default, your router can hand the Pi a different IP address each time it reconnects, which breaks any script or bookmark relying on a fixed address. Two ways to fix this:

MethodHowBest For
DHCP ReservationSet in your router's admin page β€” tell the router to always assign the Pi's MAC address the same IPMost setups β€” doesn't touch the Pi's own config at all
Static IP on the PiEdit /etc/dhcpcd.conf directly on the PiWhen you don't have router admin access
πŸ’‘
Prefer the router methodIt's the same result with less risk β€” misconfiguring dhcpcd.conf can knock the Pi off the network entirely, at which point you're back to needing a monitor to fix it.
πŸ“ Moving Files To and From the Pi
Terminal β€” from your PC
# copy a file TO the Pi
scp myscript.py jude@mypi.local:/home/jude/

# copy a file FROM the Pi
scp jude@mypi.local:/home/jude/data.csv ./

scp ("secure copy") uses the same SSH connection you already have configured β€” no extra setup required.

🧠 Quick Check
Your Pi's IP address keeps changing every time it reboots, breaking your SSH shortcut. What's the recommended fix?
MODULE 11

πŸ“· Camera & Computer Vision Basics

Connecting the official Camera Module, capturing photos and video, and a first pass at real computer vision with OpenCV.

πŸ”Œ Connecting the Camera Module
  1. Power off the Pi completely before connecting the ribbon cable β€” this port isn't hot-swappable.
  2. Gently pull up the black plastic clip on the CSI camera port (from Module 2's board anatomy).
  3. Insert the ribbon cable with the blue side facing the Ethernet port (orientation varies slightly by Pi model β€” check silkscreen labels if unsure), then push the clip back down to lock it.
  4. Power on, then enable the camera interface: sudo raspi-config β†’ Interface Options β†’ Camera β†’ Enable β†’ reboot.
πŸ“Έ Capturing a Photo β€” libcamera

Modern Raspberry Pi OS uses libcamera tools instead of the older raspistill/raspivid commands you may see in older tutorials.

Terminal
# Take a single photo
libcamera-still -o photo.jpg

# Record 10 seconds of video
libcamera-vid -t 10000 -o video.h264
πŸ’‘
-t is in milliseconds-t 10000 means 10,000 milliseconds β€” 10 seconds. This trips people up because most other places in Linux measure time in seconds.
🐍 Capturing From Python
Python β€” capture.py
from picamera2 import Picamera2
from time import sleep

picam2 = Picamera2()
picam2.start()
sleep(2)  # let the sensor's auto-exposure settle first
picam2.capture_file("photo.jpg")
picam2.stop()

Picamera2 is the current official Python library, replacing the older (now deprecated) picamera package β€” if you find tutorials using import picamera without the "2", they're written for the older Pi OS and won't work the same way here.

πŸ‘οΈ First Steps With OpenCV

OpenCV is the standard computer vision library β€” face detection, motion detection, edge detection, and far more, all built on the idea of treating an image as a grid of numbers you can process.

Terminal β€” Install
pip3 install opencv-python
Python β€” motion_detect.py
import cv2
from picamera2 import Picamera2

picam2 = Picamera2()
picam2.configure(picam2.create_preview_configuration())
picam2.start()

prev_frame = None

while True:
    frame = picam2.capture_array()
    gray  = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray  = cv2.GaussianBlur(gray, (21, 21), 0)

    if prev_frame is not None:
        diff = cv2.absdiff(prev_frame, gray)
        if diff.mean() > 5:
            print("Motion detected!")

    prev_frame = gray

This compares each frame to the previous one β€” a meaningful difference between frames means something moved. It's a simple, CPU-cheap technique, not full object recognition, but it's the foundation most beginner vision projects start from.

🧠 Quick Check
You find an old tutorial using import picamera (no "2") and raspistill commands. What should you do?
MODULE 12 🏁

🏁 Capstone β€” Environmental Monitor & Alert Station

One project pulling together every module: breadboard wiring, GPIO, analog sensing, I2C, PWM, networking, and (optionally) the camera β€” built into a single device that actually does something useful.

🧩 The Build

A desk or room monitor that reads real environmental data, displays it locally, alerts you when something crosses a threshold, and is checkable remotely β€” the same shape of project as any real IoT sensor node.

πŸ—‚οΈ The Build Plan
  1. Sensing: A BME280 (Module 8) reading temperature, humidity, and pressure over I2C.
  2. Display: An SSD1306 OLED (Module 8) showing current readings, updating every few seconds β€” same I2C bus as the sensor, different address.
  3. Alerting: An LED + buzzer (Module 6) that trigger when temperature crosses a threshold you set β€” e.g. too hot, flash the LED and beep.
  4. Input: A button (Module 6) that cycles the OLED display between temperature, humidity, and pressure views on press.
  5. Dimming: A potentiometer through the MCP3008 (Module 7) controlling the OLED's or LED's brightness, so the display isn't blinding in a dark room.
  6. Remote check-in: A small Python script reachable over SSH (Module 10) that prints the latest reading on demand β€” or, as a stretch goal, logs readings to a file you can scp off the Pi.
  7. Optional stretch: Add the Camera Module (Module 11) with simple motion detection to snap a photo whenever someone's in the room, timestamped alongside the sensor log.
🧡 Tying It Together β€” Structure, Not Just Snippets

The real skill this capstone tests isn't any single sensor β€” it's combining several independent event sources (a timer for sensor polling, a button press, a threshold check) into one script that doesn't block itself. A pattern worth using:

Python β€” monitor.py (skeleton)
from gpiozero import LED, Buzzer, Button, MCP3008
import board, adafruit_bme280.basic as adafruit_bme280
import adafruit_ssd1306
from time import sleep

TEMP_THRESHOLD = 28.0  # Celsius β€” adjust to your room

i2c  = board.I2C()
bme  = adafruit_bme280.Adafruit_BME280_I2C(i2c)
oled = adafruit_ssd1306.SSD1306_I2C(128, 64, i2c)

led     = LED(17)
buzzer  = Buzzer(27)
button  = Button(2)
dimmer  = MCP3008(channel=0)

view = 0  # 0=temp, 1=humidity, 2=pressure
def cycle_view():
    global view
    view = (view + 1) % 3
button.when_pressed = cycle_view

while True:
    temp = bme.temperature

    # alerting
    if temp > TEMP_THRESHOLD:
        led.on(); buzzer.on()
    else:
        led.off(); buzzer.off()

    # display β€” update based on current view + dimmer-controlled contrast could go here
    oled.fill(0)
    # ... draw whichever reading `view` selects ...
    oled.show()

    sleep(1)

Notice the loop never blocks on any single thing for long β€” the button's when_pressed callback fires independently of the main loop's timing, which is the same event-driven pattern from Module 5, just with more pieces running at once.

βœ… Definition of Done
SystemPasses When…
SensingThe BME280 returns live, plausible temperature/humidity/pressure values (not 0 or an error)
DisplayThe OLED shows a current reading and updates without a manual restart
AlertingCrossing your chosen threshold reliably triggers the LED and buzzer, and stops when it drops back below
InputPressing the button cycles the display view without duplicate/bounced triggers
Remote accessYou can SSH in from another device on the network and read the latest value without touching the Pi physically
🏁 Final Challenge

Ship It

Get every checkpoint above running as one continuous script, wired on a single breadboard, and leave it running unattended for at least an hour. This is the same bar every real embedded project has to clear β€” not just "the code runs once," but "it keeps running correctly without you standing over it."

  • BME280 sensor reading over I2C
  • SSD1306 OLED display showing live readings
  • LED + buzzer alert on a temperature threshold
  • Button-driven view cycling, debounced
  • Reachable and checkable over SSH from another device
  • Runs unattended for 60+ minutes without crashing or hanging
Embedded Track