Laboratory track
Fourteen labs, one for each line of the syllabus. Every lab runs in simulation: in Python on the code you download with the unit, or in the Wokwi simulator for the two firmware labs. Each lab ends with an optional box for a real ESP32 kit.
Python and a sense-think-act simulation
Goal. Simulate a thermostat as a loop of sensing, deciding and acting, and see what delay and noise do.
Needs. Unit 1. Files. Unit 1 code zip (sense_think_act)
python codes/foundations/sense_think_act/example_basic.py; then readsense_think_act.simulate.- Run
simulate(BangBang(21, 0.5), delay=d)for d = 0, 2, 5 minutes and comparemetrics(...)['max_abs_err']. - Add noise (
sigma=0.3) and count the heater switches per hour.
Check yourself
On a real ESP32 kit (optional). Optional kit: read a real thermistor on an ESP32 ADC pin and print it once a second.
Circuits and power budget
Goal. Size a series resistor and a divider, quantise a signal with an ADC, and compute a node's battery life.
Needs. Unit 2. Files. Unit 2 code zip (circuits_np)
circuits_np.led_resistor,divider(with and withoutr_load),lsb,adc_rms_error.power_budget(states)for the wake, connect, publish, shutdown and sleep states; thenbattery_life_days.- Find the awake time that reaches 30 days with
max_awake_seconds.
Check yourself
On a real ESP32 kit (optional). Optional kit: measure the real current of a board in deep sleep with a multimeter in series.
Sensor calibration and filtering
Goal. Calibrate a noisy soil sensor by least squares and choose a filter.
Needs. Unit 3. Files. Unit 3 code zip (sensors_np)
sensors_np.fit_lineon calibration points; compare withtwo_point.moving_averageandema: match their smoothing withalpha_matching_maand comparenoise_gain_*andmean_delay_*.alias_frequency(70, 100), then sample a 70 Hz sine at 100 Hz and look at the result.
Check yourself
On a real ESP32 kit (optional). Optional kit: log a capacitive soil sensor in dry and wet soil and fit your own line.
ESP32 GPIO and finite-state machine (Wokwi)
Goal. Debounce a button and run a three-mode LED state machine; the logic is tested on the host.
Needs. Unit 4. Files. Unit 4 code zip (fsm_sim, firmware/)
python -m pytest codes/embedded/fsm_sim/tests -q(the debouncer and the node state machine, with a fake hardware object).- Open
firmware/wokwi/diagram.jsonin the Wokwi simulator, pastefirmware/arduino/button_fsm.inoor the MicroPython files, and press the button. fsm_sim.bouncy_pressandcount_events: how many events do you count with and without a 20 ms stable time?
Check yourself
On a real ESP32 kit (optional). Optional kit: wire a real button and LED to an ESP32 (pins in the firmware README); the Wokwi diagram was not opened in Wokwi by the author.
I2C sensor read
Goal. Read a register over I2C, decode it, and compute how long the transfer takes.
Needs. Unit 4. Files. Unit 4 code zip (fsm_sim: i2c_sensor.py, firmware/micropython/i2c_read.py)
i2c_sensor.decode_temp(bytes([0x19, 0x00]))andencode_temp;read_tempworks with any object that hasreadfrom_mem.fsm_sim.i2c_read_clocks(2)andi2c_transfer_time_us(2, 100e3); repeat at 400 kHz.i2c_rise_time_nsandi2c_max_pullup: pick a pull-up resistor for a 100 pF bus.
Check yourself
On a real ESP32 kit (optional). Optional kit: connect a TMP102-style sensor to GPIO 21 and 22 and run `i2c_read.py`. The register format is modelled from memory and the file was not run on a board or in Wokwi.
MQTT publish/subscribe
Goal. Run a small broker and client and compare them with the real paho-mqtt client.
Needs. Unit 5. Files. Unit 5 code zip (mqtt_mini)
python codes/net/mqtt_mini/example_basic.py(broker, publisher and subscriber in one process).- Publish at QoS 0 and 1 over a lossy link; count packets with
netcalc.qos_simulate(0.1, 1). - Optional, in a venv with
paho-mqtt:python codes/net/mqtt_mini/conformance.py(the real client against our broker).
Check yourself
On a real ESP32 kit (optional). Optional kit: point a real ESP32 or phone MQTT app at the broker and watch the retained messages.
Dashboard and alerts
Goal. Ingest readings into a store, raise alerts and serve a dashboard with Flask.
Needs. Unit 6. Files. Unit 6 code zip (telemetry_np, dashboard.py)
telemetry_np.TimeSeries,ThresholdDetector,ZScoreDetector,EwmaDetector,CusumDetector: feed each a series with a step.python codes/cloud/telemetry_np/dashboard.pythen open the local page; POST a reading to/ingest.- Compare payload sizes with
encode_json,cbor_encode,pack_reading.
Check yourself
On a real ESP32 kit (optional). Optional kit: send real readings from the ESP32 node of Lab 6 to the dashboard.
HMAC-secured commands
Goal. Forge a command, then block the forgery with an HMAC envelope and a counter.
Needs. Unit 7. Files. Unit 7 code zip (iot_sec)
iot_sec.sign_command(key, counter, b'water 0,2')thenverify_command.- Replay the same envelope and flip one tag byte: read the
reasonreturned. forgery_probability(8)againstforgery_probability(1); try 5000 random guesses against a 1-byte tag.
Check yourself
On a real ESP32 kit (optional). Optional kit: run the verifier in MicroPython (`hmac` availability differs between ports; check before relying on it).
Arm kinematics
Goal. Move a 2-link arm to targets with forward and inverse kinematics and see singularities.
Needs. Unit 8. Files. Unit 8 code zip (kinematics_np)
kinematics_np.fk_2link,ik_2link(both elbows),jacobian_2link,reachable_2link.- Check
fk_2link(ik_2link(x, y, ...)) == (x, y)over a grid of targets. - Approach the workspace boundary and watch
joint_ratesgrow.
Check yourself
On a real ESP32 kit (optional). Optional kit: a two-servo pen plotter (Unit 3 servo pulse widths).
Differential-drive odometry
Goal. Integrate wheel counts into a pose and measure the drift caused by a wheel-radius error and by slip.
Needs. Unit 8. Files. Unit 8 code zip (kinematics_np)
kinematics_np.Rover(eps_r=0.005);drive(0.5, 0.0, 40)and readposition_error().- Compare with
radius_mismatch_arcandrandom_slip_lateral_std. - Calibrate: run 5 m, measure with a tape, correct the radius, rerun.
Check yourself
On a real ESP32 kit (optional). Optional kit: two wheel encoders and a tape measure on a real chassis.
PID motor control
Goal. Tune a wheel-speed loop and see windup, delay and saturation.
Needs. Unit 9. Files. Unit 9 code zip (control_np)
control_np.lambda_pi(K, tau, 0.03);simulate_speed_loop(PID(...), WheelMotor(), 3.0);step_metrics.ultimate_gain(motor, 0.01, delay_samples=1)thenzn_pid: compare with your lambda design.- Block the wheel and release it with
windup='none','clamp'and'backcalc'.
Check yourself
On a real ESP32 kit (optional). Optional kit: a geared motor with an encoder on an H-bridge; step the setpoint and log the speed.
Kalman localisation
Goal. Fuse encoders, a gyroscope and wall ranges and see what the filter can and cannot correct.
Needs. Unit 10. Files. Unit 10 code zip (localize_np)
localize_np.patrol('odom'),'gyro','ekf': compareerrandcrashed.Kalman1Don a drifting level againstema;steady_state_gain(q, r)against the iterated gain.- Check the filter's own uncertainty against the actual error (consistency): where is it overconfident?
Check yourself
On a real ESP32 kit (optional). Optional kit: an IMU (gyro) and an ultrasonic sensor on a chassis driven along a wall.
A* navigation
Goal. Plan on an inflated occupancy grid and follow the path with pure pursuit.
Needs. Unit 11. Files. Unit 11 code zip (planning_np)
planning_np.inflate,astar,dijkstra,bfs: compareexpandedon the same grid.shortcutthenfollow_path(xy, lookahead=0.2): readmax_xte; repeat with 0.1 and 0.8.max_ping_period(0.5, 0.05, 0.015)andwatchdog_stop_distance(0.5, 0.2).
Check yourself
On a real ESP32 kit (optional). Optional: a ROS 2 install is NOT needed for this lab; the miniature `Bus` and `TFTree` imitate the concepts.
Capstone: the Smart Greenhouse Rover
Goal. Run the whole system for a day, compare it with a timer baseline, and write the report.
Needs. Unit 12. Files. Unit 12 code zip (greenhouse_rover and its dependencies)
greenhouse_rover.simulate_day('event', 3, plan_legs(), detect_lo=0.33)and the same with'timer'.- Change one thing (sampling period, packet loss, detector threshold, pose source) and report the effect with its interval.
- Write the report with the skeleton of Unit 12; pick one of the ten alternative briefs if you prefer.
Check yourself
On a real ESP32 kit (optional). Optional kit: any subset of the earlier kit boxes, wired into one node and one vehicle.
What the labs do and don’t show
- Firmware that touches hardware (Labs 4 and 5) was not run on a board or in Wokwi by the author: the logic is tested on the host with a fake hardware object. The Wokwi diagram for Lab 4 was not opened in Wokwi; there is no Wokwi project for Lab 5, and its register format is modelled from memory, not from a datasheet.
- The MQTT conformance script (Lab 6) needs
paho-mqttin a separate environment; it passed 17 of 17 checks when the author ran it, and it is not part of the offline tests. - Nothing in the course ran on real sensors, motors or radios; where a number depends on an assumed value, the unit PDF says so.
- The assessment short answers are model answers, and the papers are the author’s own samples, not past papers.