Build your first circuit, understand why the resistor is there, and read a switch reliably from Python.
~5 hrsBreadboard
Concept Voltage, current, and why resistors matter
Ohm's Law, V = I × R, is the one equation that explains why an LED needs a resistor: wired directly to a 3.3V GPIO pin, an LED would try to draw far more current than either it or the Pi can safely handle. A red LED drops about 2V across itself; if we want roughly 10mA flowing, the resistor needs to drop the remaining 1.3V at that current: R = 1.3V / 0.01A ≈ 130Ω. A 220Ω resistor is a safe, common choice that errs on the side of dimmer-but-safe. The same GPIO pins can also be inputs: a switch wired with a pull-up resistor reads HIGH when open and LOW when pressed (or the reverse with a pull-down) — every homing routine later in the course depends on reading a switch exactly this way.
Why 220Ω specifically?R = (Vsource − VLED) / ILED. The Pi's GPIO output is 3.3V, a typical LED drops about 2V, and a comfortable target current is 5–15mA — giving (3.3 − 2.0) / 0.01 ≈ 130Ω as a rough minimum. Anything at or above that is safe; going higher just dims the LED a bit and pulls even less current. 220Ω is the value everyone's kit already has, and at (3.3 − 2.0) / 220 ≈ 6mA it sits comfortably under the GPIO pin's ~16mA limit with real margin to spare — still bright enough to see clearly, but nowhere near a value that could stress the pin or the LED.
Kit What you need this week
Breadboard
2-3 LEDs (any colour)
220Ω resistors
Jumper wires
A push-button or contact/limit switch
Multimeter
Wiring Diagrams
Finding pin 1 on the boardThe diagrams below use physical pin numbers, which only mean something once you can find pin 1 on the actual header — pin numbers are never printed next to the pins themselves. Two reliable ways to spot it: the square pad — every other pin on the header has a round solder pad, but pin 1 (and only pin 1) has a square one, visible on the underside of the board (or, if you soldered your own header per Week 1, on the top where you soldered it); and the silkscreen label — most Pi boards print a small “1” or a white square outline on the PCB right next to pin 1, usually at the corner of the header nearest the corner of the board. Once you've found it: hold the board with the GPIO header's two rows running away from you and pin 1 at the near-left corner — pin 2 is directly opposite it (near-right), and numbering then alternates down the two rows (1, 3, 5… down the left column, 2, 4, 6… down the right), ending with pins 39 and 40 at the far end. That's the same “top view” layout the diagram below uses, so once pin 1 is physically identified, every other pin can be counted off directly against it.
LED circuit (top) and pull-up switch circuit (bottom) — schematic, not to scale.
powergroundused this weekunused GPIO
The two pins used this week on the 40-pin header — everything else is drawn for context.
Build Step by step
Step 1
Build the LED circuit
On the breadboard: GPIO pin → 220Ω resistor → LED anode (long leg) → LED cathode → GND. Getting the LED backwards won't damage it at these currents, it just won't light — flip it if nothing happens.
Step 2
Blink it from Python
Write your own blink script before looking at any reference version:
import RPi.GPIO as GPIO
import time
PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(PIN, GPIO.OUT)
try:
while True:
GPIO.output(PIN, True)
time.sleep(0.5)
GPIO.output(PIN, False)
time.sleep(0.5)
finally:
GPIO.cleanup()
Step 3
Measure it
With the LED lit, use the multimeter (set to DC volts) across the LED's two legs. You should read roughly 2V — that's the forward voltage the resistor calculation above assumed.
Step 4
Wire a switch
Wire the switch between a GPIO pin and GND, and set the pin up with an internal pull-up so it reads HIGH when open:
GPIO.setup(20, GPIO.IN, pull_up_down=GPIO.PUD_UP)
Step 5
Read it in a loop
Poll the switch and print its state, adding a small debounce delay so a single press doesn't get read as several:
import time
while True:
if GPIO.input(20) == False:
print("Pressed")
time.sleep(0.2) # crude debounce
Why debounce at all?A mechanical switch doesn't move from open to closed cleanly — as the metal contacts touch, they physically bounce apart and together several times over a few milliseconds before settling. GPIO pins sample fast enough to see that bouncing as a rapid flicker of several presses instead of one, so without debouncing, a single physical press can print “Pressed” five or six times. There are two ways to fix it: hardware debouncing (a small capacitor across the switch smooths out the flicker electrically, before the Pi ever sees it) or software debouncing (ignore the pin for a short window right after a change is detected). The time.sleep(0.2) above is the simplest possible software debounce — it works, but it also blocks the whole program for 200ms, which becomes a problem once you're doing other things at the same time. A better pattern checks a real clock instead of sleeping:
import time
last_press = 0
DEBOUNCE_S = 0.2
while True:
if GPIO.input(20) == False:
now = time.time()
if now - last_press > DEBOUNCE_S:
print("Pressed")
last_press = now
This only accepts a new press if enough time has passed since the last accepted one, without ever blocking the loop — the same technique the real project's limit switches use, since a homing routine can't afford to freeze for 200ms every time a switch is checked.
Step 6
Combine them
Light the LED only while the switch is held down — the same logical pattern (“read an input, act on an output”) that later drives homing routines and status LEDs.
Make it yours
Use a second LED to show “released” instead of just turning one off.
Replace the crude sleep-based debounce with one that checks the pin twice a few milliseconds apart and only accepts the reading if both agree.
If it breaks Troubleshooting
LED doesn't lightCheck polarity (long leg to resistor/positive side), check you're using a BCM pin number that matches GPIO.setmode(GPIO.BCM), and check the resistor value isn't absurdly high.
Switch reads the “wrong” way roundIf it reads pressed when it's actually open, your wiring matches a pull-down assumption while the code assumes pull-up (or vice versa) — match one to the other, don't fight it.
“RuntimeError: channel already in use”A previous script didn't call GPIO.cleanup() before exiting. Ctrl+C the old one properly, or add cleanup in a finally block as shown above.
This week's checkpointAn LED blinks under program control, and a switch press is read reliably in a loop with basic debouncing — the two building blocks every later homing routine depends on.
Next week: Parametric CAD in Fusion 360 — designing your first real part.