Session 4: Capstone Planning: From Prototype to Robust Async System
Synopsis
Guides learners in defining a substantial final project that integrates asynchronous hardware control, communication, resilience, and maintainable architecture.
Session Content
Session 4: Capstone Planning: From Prototype to Robust Async System
Session Overview
This session helps learners move from a simple MicroPython prototype on the Raspberry Pi Pico 2 W to a more robust asynchronous system design. The focus is on planning a capstone project that uses multiple concurrent tasks, clean code organization, error handling, and responsive I/O.
Duration
~45 minutes
Prerequisites
- Basic Python knowledge
- Familiarity with MicroPython on Raspberry Pi Pico 2 W
- Understanding of
asynciobasics from prior sessions - A working Pico 2 W flashed with MicroPython
- Thonny IDE installed and connected to the board
Learning Objectives
By the end of this session, learners will be able to: - Identify the difference between a prototype and a robust embedded system - Plan a capstone project using asynchronous task decomposition - Organize code into modules for maintainability - Add basic error handling and recovery to async programs - Sketch a development plan for integrating sensors, actuators, and Wi-Fi-based IoT features
1. Theory: From Prototype to Robust System
1.1 Prototype vs Robust System
A prototype usually proves an idea quickly: - One sensor - One output - Minimal validation - Often written in a single file
A robust system is designed for: - Reliability over time - Clear separation of concerns - Non-blocking behavior - Recovery from errors - Maintainability and future expansion
1.2 Why Async Matters in Capstone Projects
On the Pico 2 W, asynchronous programming is useful because it allows the device to: - Read sensors regularly - Update displays or LEDs - React to buttons - Communicate over Wi-Fi - Avoid long blocking delays
Instead of writing code that does one thing at a time, async lets you schedule tasks that cooperate.
1.3 Typical Capstone Architecture
A practical asynchronous IoT project may include: - Sensor task: reads temperature, humidity, light, motion, etc. - Actuator task: controls LEDs, buzzer, relay, or fan - Network task: connects to Wi-Fi and sends data to a server - UI task: button input, OLED display, or serial logging - Supervisor task: monitors health, retries failures, and manages state
1.4 Design Principles
- Keep tasks short and cooperative
- Avoid
time.sleep()in async code - Use
await asyncio.sleep(...)to yield control - Isolate hardware access into small functions or modules
- Add retries and fallback behavior for Wi-Fi and sensors
- Use meaningful names for tasks and functions
2. Planning the Capstone
2.1 Example Capstone Ideas
Choose one project concept for the final build:
Option A: Smart Environmental Monitor
- Reads temperature and humidity
- Displays status using an LED
- Sends readings to a cloud endpoint or local web service
- Alerts if values exceed thresholds
Option B: Motion-Activated Security Node
- Uses PIR sensor
- Triggers buzzer and LED
- Sends alert over Wi-Fi
- Logs motion events
Option C: Connected Plant Monitor
- Reads soil moisture
- Activates pump or warning LED
- Publishes data to a dashboard
- Supports manual override button
2.2 Define System Requirements
Before coding, define: - What hardware is included? - What data needs to be read? - What should happen on an alert? - How often should each task run? - What should happen if Wi-Fi is unavailable?
2.3 Example Requirements for a Smart Environmental Monitor
- Read a DHT22 sensor every 5 seconds
- Blink a status LED every second
- Connect to Wi-Fi at startup
- Send data every 30 seconds
- Continue reading sensors even if network upload fails
3. Hands-On Exercise 1: Build a Capstone Plan
Goal
Create a project plan for a capstone system with at least three async tasks.
Suggested Template
Fill in the following fields:
| Item | Example |
|---|---|
| Project name | Smart Environment Monitor |
| Inputs | DHT22, button |
| Outputs | LED, buzzer |
| Connectivity | Wi-Fi |
| Main tasks | sensor_read_task, status_led_task, network_task |
| Failure handling | retry Wi-Fi, keep local logging |
| Update intervals | 5s, 1s, 30s |
Task
Write down: 1. Your project goal 2. The hardware components 3. The tasks required 4. The update interval for each task 5. The main failure scenarios
Deliverable
A short project plan that can be used to guide implementation.
4. Code Organization for a Robust Async System
4.1 Recommended File Structure
For a capstone project, keep code modular:
main.py
config.py
wifi_manager.py
sensor_task.py
actuator_task.py
utils.py
4.2 Responsibilities
main.py: starts the program and creates tasksconfig.py: stores constants such as SSID, passwords, intervalswifi_manager.py: handles network connection and reconnectionsensor_task.py: reads sensorsactuator_task.py: controls LEDs, buzzers, relaysutils.py: shared helper functions
5. Hands-On Exercise 2: Async Skeleton for a Capstone
Goal
Create a clean asynchronous structure that can later be expanded with sensors and Wi-Fi.
main.py
# main.py
# Basic async application skeleton for a Pico 2 W capstone project.
import asyncio
from machine import Pin
# Built-in LED on Raspberry Pi Pico 2 W
led = Pin("LED", Pin.OUT)
async def blink_status_led():
"""
Blink the onboard LED every second to show the device is alive.
"""
while True:
led.toggle()
print("Status LED:", led.value())
await asyncio.sleep(1)
async def monitor_system():
"""
Placeholder for future sensor and system monitoring logic.
"""
while True:
print("Monitor task running...")
await asyncio.sleep(5)
async def main():
"""
Create and run concurrent tasks.
"""
print("Starting capstone async skeleton...")
asyncio.create_task(blink_status_led())
asyncio.create_task(monitor_system())
while True:
await asyncio.sleep(60)
try:
asyncio.run(main())
finally:
asyncio.new_event_loop()
Expected Output
Starting capstone async skeleton...
Status LED: 1
Monitor task running...
Status LED: 0
Status LED: 1
Monitor task running...
Discussion Points
asyncio.create_task()runs tasks concurrentlyawait asyncio.sleep()prevents blocking- The main loop keeps the program alive
6. Adding Error Handling and Recovery
6.1 Why Error Handling Matters
In embedded systems, failures are normal: - A sensor may return invalid readings - Wi-Fi may disconnect - A network request may fail - A peripheral may stop responding
6.2 Best Practices
- Use
try...exceptaround risky operations - Log errors with helpful messages
- Retry with a delay
- Keep the rest of the system running if one task fails
7. Hands-On Exercise 3: Add a Resilient Task
Goal
Modify the async skeleton so one task handles errors gracefully.
Example: Simulated Sensor Task
# sensor_task.py
# Simulated sensor task with error handling.
import asyncio
import random
async def read_sensor():
"""
Simulate reading a sensor value.
Randomly raises an exception to mimic hardware failure.
"""
if random.randint(0, 4) == 0:
raise OSError("Sensor read failed")
return random.randint(20, 35)
async def sensor_monitor():
"""
Periodically read a sensor and recover from errors.
"""
while True:
try:
value = await read_sensor()
print("Sensor value:", value)
except OSError as e:
print("Sensor error:", e)
await asyncio.sleep(3)
Example Integration in main.py
# main.py
import asyncio
from machine import Pin
from sensor_task import sensor_monitor
led = Pin("LED", Pin.OUT)
async def blink_status_led():
while True:
led.toggle()
await asyncio.sleep(1)
async def main():
asyncio.create_task(blink_status_led())
asyncio.create_task(sensor_monitor())
while True:
await asyncio.sleep(60)
try:
asyncio.run(main())
finally:
asyncio.new_event_loop()
Expected Output
Sensor value: 27
Sensor value: 31
Sensor error: Sensor read failed
Sensor value: 24
8. Wi-Fi Planning for IoT Integration
8.1 What to Consider
For Wi-Fi-based capstone functionality: - Should the device connect at startup only? - Should it retry indefinitely? - Should it keep running offline? - Should it buffer data locally?
8.2 Robust Connection Strategy
A good strategy is: - Attempt Wi-Fi connection - Retry a few times if needed - Keep core tasks running even if online features fail - Reconnect in the background if connection drops
9. Hands-On Exercise 4: Planning a Wi-Fi Task
Goal
Design a network task that can be added to a capstone project.
Sample Planning Checklist
- Connect using SSID and password
- Wait for connection
- Print IP address when connected
- Retry after failure
- Avoid blocking other tasks
Example Skeleton
# wifi_manager.py
import asyncio
import network
async def connect_wifi(ssid, password, retries=5):
"""
Attempt to connect to Wi-Fi with retries.
"""
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if wlan.isconnected():
print("Wi-Fi already connected")
return wlan
print("Connecting to Wi-Fi...")
wlan.connect(ssid, password)
for attempt in range(retries):
if wlan.isconnected():
print("Connected:", wlan.ifconfig())
return wlan
print("Retry", attempt + 1)
await asyncio.sleep(2)
print("Wi-Fi connection failed")
return wlan
Example Usage
import asyncio
from wifi_manager import connect_wifi
async def main():
wlan = await connect_wifi("YourSSID", "YourPassword")
print("Connected status:", wlan.isconnected())
asyncio.run(main())
Example Output
Connecting to Wi-Fi...
Retry 1
Retry 2
Connected: ('192.168.1.42', '255.255.255.0', '192.168.1.1', '8.8.8.8')
Connected status: True
10. Capstone Development Workflow
Suggested Workflow
- Define the problem
- Choose sensors and outputs
- Write a task list
- Build each task independently
- Combine tasks into
main.py - Test locally on the Pico
- Add Wi-Fi and cloud features
- Add recovery and logging
- Refactor into modules
- Finalize the demonstration
Incremental Build Strategy
Start small: - Blink LED - Read one sensor - Add one async task - Add one network task - Add alerts - Add recovery
11. Mini Design Challenge
Challenge
Design a capstone for a connected room monitor.
Requirements
- Monitor temperature
- Show system alive with onboard LED
- Send readings over Wi-Fi
- Continue operating if network is unavailable
Learner Task
Write a brief answer for: - Tasks needed - Hardware required - Failure handling plan - Data transmission plan
12. Session Summary
In this session, learners planned how to transform a prototype into a robust async system by: - Defining system requirements - Identifying concurrent tasks - Organizing code into modules - Adding error handling and recovery - Planning Wi-Fi integration for IoT functionality
13. Suggested Capstone Next Steps
For the next session or final project build: - Select one capstone idea - Create a full task diagram - Implement sensor reading - Add actuator control - Add Wi-Fi upload - Test failure recovery and reconnection
14. Quick Reference: Async Design Checklist
- Use
asynciofor concurrent tasks - Keep tasks short and non-blocking
- Use
await asyncio.sleep()instead of blocking delays - Separate hardware and network logic
- Add error handling with retries
- Keep the system alive even when one feature fails
15. Environment Setup Reminder
- Install Thonny
- Select MicroPython interpreter for Raspberry Pi Pico 2 W
- Connect Pico via USB
- Save files directly to the device
- Use the Thonny Shell for output and debugging
16. Reference Links
- https://github.com/micropython/micropython/wiki
- https://docs.micropython.org/en/latest/rp2/quickref.html
- https://www.raspberrypi.com/documentation/microcontrollers/micropython.html
- https://www.raspberrypi.com/documentation/microcontrollers/pico-series.html#pico2