Vendors the comprehensive UNO Q skill (SKILL.md + 7 references/*.md) and installs it into EVERY agent's workspace on each board, so agents know this board's specifics (dual-brain arch, Bridge/RPC, pin tables, LED matrix + the ArduinoGraphics-not-installed gotcha) instead of guessing generic Arduino. Why per-agent workspace: ZeroClaw's read_skill returns only SKILL.md; the agent reads references/*.md via the workspace-sandboxed file_read tool, so references are only reachable under ~/.zeroclaw/agents/<alias>/workspace/skills/. A shared/skills bundle surfaces the skill but its references get sandbox-blocked. - push-skill.sh installs a SKILL.md+references skill into every agent workspace (discovers aliases from the board); provision-fleet runs it per board. - config.template risk profile now allows + auto-approves read_skill + file_read so agents load skills without a human approver (webhook path is non-interactive). - Flattened the folded 'description: >-' to single-line (ZeroClaw's frontmatter parser is a flat scanner, not full YAML). Verified on board 65301572 with cloud/Sonnet-5: discovered arduino-uno-q → read_skill(SKILL.md) → file_read references/04-bridge-rpc.md → correct board-specific answer citing the file. Co-Authored-By: Claude Opus 4.8 <[email protected]>
4.6 KiB
4.6 KiB
UNO Q — Workshop Playbook
Practical guidance for running a hands-on session with the board. Assumes the reader already understands the two-processor model (see SKILL.md).
Pre-flight checklist (per station)
- Board + a known-good USB-C cable rated for 5 V / 3 A (or a multiport dongle with external PD — not Apple's, it's incompatible).
- For SBC stations: HDMI monitor, USB keyboard/mouse via dongle, power to the dongle.
- Decide the mode up front: SBC (self-contained, needs 4 GB variant recommended) vs Network Mode (students drive it from their laptops).
- Each board: set a board name (becomes
<name>.local), a password, and Wi-Fi during first-run. SSH turns on automatically after this. - If any facilitator laptop runs Linux, install the udev rules first (see setup reference) — otherwise App Lab connects silently to nothing.
- Network allows mDNS / UDP 5353 (needed for Network Mode discovery). On locked-down campus Wi-Fi this is the usual blocker.
- For enterprise/eduroam Wi-Fi, pre-stage the
nmcli802.1X command (see wireless reference).
Common failure modes → fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| App Lab shows no board (Linux PC, USB) | Missing udev rules | Install rules, reconnect board, restart App Lab |
| Board absent in Network Mode | mDNS blocked | Open UDP 5353; approve mdns-discovery.exe on Windows; confirm same subnet |
| Flash/upload "permission denied" (Linux) | udev not applied | Re-run rules, udevadm control --reload-rules && udevadm trigger, replug |
| Python can't reach the sketch | router down / wrong function name | systemctl status arduino-router; check the provide() name matches the call() string; verbose logs |
| Handler crashes / hangs | Arduino API called from provide() (RPC thread) |
Use provide_safe(); never Serial.print/Bridge.call inside a handler |
| Nothing on a pin | wrong logic level or wrong processor | MCU I/O is 3.3 V; onboard RGB LEDs are active-low; confirm the sketch (not Python) owns the pin |
Serial1 acting weird |
confusing header UART with router link | Serial1 on D0/D1 is fine for external UART; never open the internal reserved transport / /dev/ttyHS1 |
| Can't SSH | no IP / SSH not set up | ip addr show (wlan0) on the board; SSH is enabled once first-run setup completes |
The canonical teaching example: "Python button decides, Arduino acts"
This one App ties the entire board together and is the best first exercise because it forces students to touch both processors and the Bridge.
Concept: the sketch owns an LED (a physical pin); Python owns the logic and calls across the Bridge to actuate it. Swap the LED for a relay/motor driver and you have real device control; swap the Python timer for a camera/AI Brick and you have an intelligent actuator.
MCU sketch (sketch.ino):
#include "Arduino_RouterBridge.h"
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Bridge.begin();
Bridge.provide_safe("set_led_state", set_led_state);
}
void loop() {}
void set_led_state(bool state) {
digitalWrite(LED_BUILTIN, state ? LOW : HIGH); // built-in LED active-low
}
Linux Python (main.py):
from arduino.app_utils import *
import time
state = False
def loop():
global state
time.sleep(1)
state = not state
Bridge.call("set_led_state", state)
App.run(user_loop=loop)
Teaching beats:
- Run it → LED blinks, but emphasize the decision happened in Python on Linux, the action happened on the MCU.
- Break it on purpose: rename
"set_led_state"on one side → show the router log error → fix. Cements the RPC contract idea. - Extend: have Python read something real (time of day, a web request, a camera Brick) and gate the LED on it.
- Reverse it: MCU reads a real sensor and
Bridge.call()s a Python function that logs/uploads it.
Progression for a full session
- Blink (App Lab example) — proves the MCU toolchain.
- Read a sensor in a sketch, print with
Serial→ App Lab console — proves I/O + debugging. - Bridge example above — proves Linux↔MCU.
- Add a Brick (vision/audio) on the Python side — shows the payoff of the Linux half.
- Deploy: set the App to Run at startup and unplug the keyboard → it's now an appliance. Manage it over SSH +
arduino-app-cli.
Deploying student projects headlessly
- Copy the App to the board:
scp -r * arduino@<IP>:~/ArduinoApps/<name>. - Start/stop/log via
arduino-app-cli app start|stop|logs ~/ArduinoApps/<name>. - Autostart the finished one:
arduino-app-cli properties set default user:<name>.