Project 3.1: " JoyStick Shield"
ย
๐ Project 3.1 โ JoyStick Shield
๐ฏ What youโll learn
- โ Goal 1: Read joystick X/Y movement as changing numbers on your screen
- โ Goal 2: Detect button presses AโF and print actions
- โ Goal 3: Map joystick directions to control an LED and navigate a simple menu
Key ideas
- Short definition: A joystick sends two analog values (X and Y) and six digital button signals.
- Real-world link: Joysticks control games, robots, and remote vehicles by translating movement into actions.
๐งฑ Blocks glossary (used in this project)
- Analog input: Reads a smooth value (0โ4095) from a pin.
- Digital input (pull-up): Reads button state, pressed = 0.
- Digital output: Turns things ON/OFF like LEDs.
- Serial print: Shows messages from the robot on your screen.
- Variable: A named box that stores a value.
- if / else: Robot decides what to do next.
- Loop: Repeats actions continuously.
๐งฐ What you need
| Part | How many? | Pin connection |
|---|---|---|
| D1 R32 | 1 | USB cable (30 cm) |
| JoyStick Shield | 1 | X โ Pin 2, Y โ Pin 4, Buttons AโF as below |
| LED Module | 1 | Pin 13 (digital output) |
- Button pins: A(26), B(25), C(17), D(16), E(27), F(14)
- Available pins for extras: 13, 5, 23, 19, 18, 34, 35, 36, 39, 21, 22
- Z button: Disconnected (ignore)
๐ Wiring tip: The Funduino Joystick Shield plugs directly on top of the D1 R32 โ no loose wires needed.
๐ Pin map snapshot: Use Pin 2 (X), Pin 4 (Y). Keep Pin 13 free for the LED. Buttons use pull-up and are active LOW.
โ Before you start
- USB cable is plugged in
- Serial monitor is open
- Test print shows:
print("Ready!") # Confirm serial is working
๐ฎ Microprojects (5 mini missions)
๐ฎ Microproject 3.1.1 โ Reading X/Y axes joystick
Goal: Print joystick X and Y values to the serial monitor.
Blocks used:
- Analog input: Read X and Y
- Serial print: Show values
- Loop: Repeat reads
Block sequence:
- Setup Pin 2 and Pin 4 as analog inputs
- Configure attenuation and resolution
- Read values
- Print values
- Delay and repeat
MicroPython code:
# Microproject 3.1.1 โ Read joystick X/Y values
import machine # Load hardware control library
import time # Load time library for delays
adc2 = machine.ADC(machine.Pin(2)) # Create ADC on Pin 2 for X-axis
adc4 = machine.ADC(machine.Pin(4)) # Create ADC on Pin 4 for Y-axis
adc2.atten(machine.ADC.ATTN_11DB) # Set X-axis range to 0โ3.3V
adc2.width(machine.ADC.WIDTH_12BIT) # Set X-axis resolution to 12-bit (0โ4095)
adc4.atten(machine.ADC.ATTN_11DB) # Set Y-axis range to 0โ3.3V
adc4.width(machine.ADC.WIDTH_12BIT) # Set Y-axis resolution to 12-bit (0โ4095)
print("[Init] Joystick ADC ready on pins X=2, Y=4") # Confirm setup
while True: # Start continuous reading loop
x_value = adc2.read() # Read X-axis value (0โ4095)
y_value = adc4.read() # Read Y-axis value (0โ4095)
print("[Joystick] X:", x_value, "Y:", y_value) # Print both axis values
time.sleep_ms(300) # Delay for readable updates
Reflection: You turned hand motion into numbers your robot understands.
Challenge:
- Easy: Change the delay to 100 ms for faster updates.
- Harder: Print only when X or Y changes from the last reading.
๐ฎ Microproject 3.1.2 โ Reading joystick buttons AโF
Goal: Detect button presses and print messages.
Blocks used:
- Digital input (pull-up): Read button states
- if / else: Decide what to print
- Serial print: Show messages
Block sequence:
- Setup buttons AโF as digital inputs (pull-up)
- Read each buttonโs value
- If pressed, print a message
- Repeat
MicroPython code:
# Microproject 3.1.2 โ Read joystick buttons AโF
import machine # Load hardware control library
import time # Load time library for delays
pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP) # Button A pull-up
pin25 = machine.Pin(25, machine.Pin.IN, machine.Pin.PULL_UP) # Button B pull-up
pin17 = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP) # Button C pull-up
pin16 = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP) # Button D pull-up
pin27 = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_UP) # Button E pull-up
pin14 = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP) # Button F pull-up
print("[Init] Buttons A=26 B=25 C=17 D=16 E=27 F=14 (active LOW)") # Confirm setup
while True: # Start continuous reading loop
if pin26.value() == 0: # Check button A pressed (LOW)
print("[Button] A pressed") # Print message for A
if pin25.value() == 0: # Check button B pressed (LOW)
print("[Button] B pressed") # Print message for B
if pin17.value() == 0: # Check button C pressed (LOW)
print("[Button] C pressed") # Print message for C
if pin16.value() == 0: # Check button D pressed (LOW)
print("[Button] D pressed") # Print message for D
if pin27.value() == 0: # Check button E pressed (LOW)
print("[Button] E pressed") # Print message for E
if pin14.value() == 0: # Check button F pressed (LOW)
print("[Button] F pressed") # Print message for F
time.sleep_ms(100) # Delay to avoid spam and bounce
Reflection: Your robot now hears your button taps like a controller.
Challenge:
- Easy: Print โCombo A+B!โ when both A and B are pressed at once.
- Harder: Count how many times button C was pressed and print the total.
๐ฎ Microproject 3.1.3 โ LED control with joystick
Goal: Turn an LED ON/OFF based on joystick X direction.
Blocks used:
- Analog input: Read X
- Digital output: Control LED
- if / else: Decide ON/OFF
Block sequence:
- Setup Pin 2 as analog input (X)
- Setup Pin 13 as digital output (LED)
- If X is high (tilted right), LED ON; else, LED OFF
- Print status and repeat
MicroPython code:
# Microproject 3.1.3 โ Control LED with X-axis
import machine # Load hardware control library
import time # Load time library for delays
adc2 = machine.ADC(machine.Pin(2)) # ADC on Pin 2 for X-axis
adc2.atten(machine.ADC.ATTN_11DB) # Set X range to 0โ3.3V
adc2.width(machine.ADC.WIDTH_12BIT) # Set X resolution to 12-bit
pin13 = machine.Pin(13, machine.Pin.OUT) # LED on Pin 13 as output
print("[Init] X=2 (ADC), LED=13 (digital output)") # Confirm setup
threshold = 2800 # Threshold for RIGHT tilt
print("[Hint] Threshold:", threshold) # Show threshold value
while True: # Start control loop
x_value = adc2.read() # Read X value (0โ4095)
if x_value > threshold: # If joystick tilted RIGHT
pin13.value(1) # Turn LED ON
print("[LED] ON | X:", x_value) # Print status
else: # Otherwise (center or LEFT)
pin13.value(0) # Turn LED OFF
print("[LED] OFF | X:", x_value) # Print status
time.sleep_ms(200) # Small delay for stability
Reflection: You connected hand motion to light โ thatโs physical computing!
Challenge:
- Easy: LED ON when X is low (LEFT tilt) instead.
- Harder: Use both X and Y: LED ON only if X RIGHT AND Y UP.
๐ฎ Microproject 3.1.4 โ Mapping values to actions
Goal: Map joystick X ranges to โLEFTโ, โCENTERโ, โRIGHTโ messages.
Blocks used:
- Analog input: Read X
- if / elif / else: Range checks
- Serial print: Show direction
Block sequence:
- Read X
- If X < 1500 โ โLEFTโ
- Else if X > 2500 โ โRIGHTโ
- Else โ โCENTERโ
- Print and repeat
MicroPython code:
# Microproject 3.1.4 โ Map X-axis to LEFT/CENTER/RIGHT
import machine # Load hardware control library
import time # Load time library for delays
adc2 = machine.ADC(machine.Pin(2)) # ADC on Pin 2 for X-axis
adc2.atten(machine.ADC.ATTN_11DB) # Set X range to 0โ3.3V
adc2.width(machine.ADC.WIDTH_12BIT) # Set X resolution to 12-bit
print("[Init] Map X to LEFT/CENTER/RIGHT") # Confirm setup
while True: # Start mapping loop
x_value = adc2.read() # Read X value (0โ4095)
if x_value < 1500: # If X in LEFT range
print("[Dir] LEFT | X:", x_value) # Print LEFT
elif x_value > 2500: # If X in RIGHT range
print("[Dir] RIGHT | X:", x_value) # Print RIGHT
else: # Otherwise in CENTER band
print("[Dir] CENTER | X:", x_value) # Print CENTER
time.sleep_ms(250) # Delay for readability
Reflection: You taught the robot to interpret numbers as directions.
Challenge:
- Easy: Adjust LEFT/RIGHT cutoffs to match your joystickโs center.
- Harder: Add Y mapping too: UP, DOWN, CENTER (2D).
๐ฎ Microproject 3.1.5 โ Joystick navigation menu
Goal: Use X/Y directions to navigate a simple text menu: PLAY, SETTINGS, INFO.
Blocks used:
- Analog input: Read X/Y
- if / else: Choose item
- Serial print: Show selection
Block sequence:
- Read X/Y
- If UP(Y high) โ โPLAYโ
- If RIGHT(X high) โ โSETTINGSโ
- If DOWN(Y low) โ โINFOโ
- Print current selection
MicroPython code:
# Microproject 3.1.5 โ Navigate a 3-item menu with X/Y
import machine # Load hardware control library
import time # Load time library for delays
adc2 = machine.ADC(machine.Pin(2)) # ADC on Pin 2 (X)
adc4 = machine.ADC(machine.Pin(4)) # ADC on Pin 4 (Y)
adc2.atten(machine.ADC.ATTN_11DB) # Set X range 0โ3.3V
adc2.width(machine.ADC.WIDTH_12BIT) # Set X resolution 12-bit
adc4.atten(machine.ADC.ATTN_11DB) # Set Y range 0โ3.3V
adc4.width(machine.ADC.WIDTH_12BIT) # Set Y resolution 12-bit
print("[Init] Menu: PLAY(UP), SETTINGS(RIGHT), INFO(DOWN)") # Show controls
while True: # Start menu loop
x_value = adc2.read() # Read X (0โ4095)
y_value = adc4.read() # Read Y (0โ4095)
if y_value > 2800: # If joystick UP
print("[Menu] PLAY selected") # Announce PLAY
elif x_value > 2800: # If joystick RIGHT
print("[Menu] SETTINGS selected") # Announce SETTINGS
elif y_value < 1500: # If joystick DOWN
print("[Menu] INFO selected") # Announce INFO
else: # Otherwise CENTER
print("[Menu] (Hold to choose)") # Prompt to move
time.sleep_ms(300) # Delay for readability
Reflection: You built a tiny user interface โ all with the joystick!
Challenge:
- Easy: Add a โSELECTโ action when holding a direction for 1 second.
- Harder: Use button A = confirm, B = back.
โจ Main project โ Joystick shield mini control panel
๐ง Blocks steps (with glossary)
- Analog input: Read X/Y positions
- Digital input (pull-up): Read buttons AโF
- Digital output: Control an LED indicator
- if / else: Map values to actions
- Serial print: Show status and selection
Block sequence:
- Setup Pin 2 (X) and Pin 4 (Y) as analog inputs
- Setup Pins 26, 25, 17, 16, 27, 14 as digital inputs (pull-up)
- Setup Pin 13 as digital output (LED)
- Read X/Y and buttons
- If RIGHT โ LED ON; if LEFT โ LED OFF
- If A pressed โ print โSTARTโ
- If B pressed โ print โSTOPโ
- Repeat loop
๐ MicroPython code (mirroring blocks)
# Project 3.1 โ Joystick Shield: Mini Control Panel
import machine # Load hardware control library
import time # Load time library for delays
adc2 = machine.ADC(machine.Pin(2)) # ADC on Pin 2 (X)
adc4 = machine.ADC(machine.Pin(4)) # ADC on Pin 4 (Y)
adc2.atten(machine.ADC.ATTN_11DB) # Set X range 0โ3.3V
adc2.width(machine.ADC.WIDTH_12BIT) # Set X resolution 12-bit
adc4.atten(machine.ADC.ATTN_11DB) # Set Y range 0โ3.3V
adc4.width(machine.ADC.WIDTH_12BIT) # Set Y resolution 12-bit
pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP) # Button A input
pin25 = machine.Pin(25, machine.Pin.IN, machine.Pin.PULL_UP) # Button B input
pin17 = machine.Pin(17, machine.Pin.IN, machine.Pin.PULL_UP) # Button C input
pin16 = machine.Pin(16, machine.Pin.IN, machine.Pin.PULL_UP) # Button D input
pin27 = machine.Pin(27, machine.Pin.IN, machine.Pin.PULL_UP) # Button E input
pin14 = machine.Pin(14, machine.Pin.IN, machine.Pin.PULL_UP) # Button F input
pin13 = machine.Pin(13, machine.Pin.OUT) # LED output on Pin 13
print("[Init] X=2, Y=4, Buttons=AโF, LED=13") # Confirm setup
while True: # Start main loop
x_value = adc2.read() # Read X (0โ4095)
y_value = adc4.read() # Read Y (0โ4095)
if x_value > 2800: # If joystick RIGHT
pin13.value(1) # Turn LED ON
print("[LED] ON | X:", x_value, "Y:", y_value) # Show status
elif x_value < 1500: # If joystick LEFT
pin13.value(0) # Turn LED OFF
print("[LED] OFF | X:", x_value, "Y:", y_value) # Show status
else: # Otherwise CENTER
print("[LED] HOLD | X:", x_value, "Y:", y_value) # Show status
if pin26.value() == 0: # If A pressed (LOW)
print("[Action] START (A)") # Announce START
if pin25.value() == 0: # If B pressed (LOW)
print("[Action] STOP (B)") # Announce STOP
if pin17.value() == 0: # If C pressed (LOW)
print("[Action] MODE (C)") # Announce MODE
if pin16.value() == 0: # If D pressed (LOW)
print("[Action] SELECT (D)") # Announce SELECT
if pin27.value() == 0: # If E pressed (LOW)
print("[Action] BACK (E)") # Announce BACK
if pin14.value() == 0: # If F pressed (LOW)
print("[Action] INFO (F)") # Announce INFO
time.sleep_ms(200) # Small delay for responsiveness
๐ External explanation
- What it teaches: Reading analog and digital inputs, mapping motion and button taps to actions.
- Why it works: The joystick changes voltage (X/Y), and buttons change digital states the board reads.
- Key concept: Analog ranges (0โ4095) and digital states (pressed = 0 with pull-up).
โจ Story time
Your robot now has its first โremote brain.โ You can steer, select, and signal โ just like piloting a rover on a mission.
๐ต๏ธ Debugging (2 common problems)
๐ Debugging 3.1.A โ Inverted axes
Problem: Moving left/right changes Y instead of X.
Clues: Serial shows Y changing when you move X.
Broken code:
adc2 = machine.ADC(machine.Pin(4)) # Wrong: X wired to Pin 2, not 4
Fixed code:
adc2 = machine.ADC(machine.Pin(2)) # Correct: X-axis on Pin 2
Why it works: The hardware map defines X=2, Y=4 โ use the right pin.
Avoid next time: Confirm pin map before coding.
๐ Debugging 3.1.B โ Buttons are not responding
Problem: Pressing buttons shows nothing on serial.
Clues: No โ[Button] โฆ pressedโ messages appear.
Broken code:
pin26 = machine.Pin(26, machine.Pin.IN) # Missing pull-up configuration
Fixed code:
pin26 = machine.Pin(26, machine.Pin.IN, machine.Pin.PULL_UP) # Enable pull-up
Why it works: Pull-up sets a default HIGH; pressing connects to LOW (active low).
Avoid next time: Always use pull-up for these shield buttons.
โ Final checklist
- I saw X and Y values change when I moved the joystick
- Buttons AโF printed messages when pressed
- The LED turned ON/OFF with joystick direction
- My tweak (thresholds or menu choices) changed the result
๐ Extras
- ๐ง Student tip: Try diagonal moves โ watch both X and Y change together.
- ๐งโ๐ซ Instructor tip: Ask students to find their joystickโs โcenter bandโ by testing values.
- ๐ Glossary:
- Analog value: A smooth number from 0 to 4095.
- Digital input: A simple true/false signal.
- Pull-up: Keeps an input HIGH until the button is pressed.
- ๐ก Mini tips:
- Keep delays small to make controls responsive.
- Print short messages so the serial monitor stays readable.
- Thresholds vary slightly โ test and adjust.