The agent now drives the matrix in <1s via the resident responder instead of compiling+flashing a sketch (~95s). Pieces: - matrix-relay/: a tiny container (python-apps-base) running relay.py — a TCP:9999 → RouterBridge relay. The ZeroClaw daemon runs on the host for hardware access, but the RouterBridge python binding (arduino.app_utils) only ships in the App Lab image, so JUST the relay runs containerized, mounting the router socket + publishing :9999 to loopback. - config.template.toml: add matrix_pattern + matrix_text to the default risk profile's allowed_tools/auto_approve (the capability filter hides tools not listed — this was why matrix_text wasn't exposed to the agent). - skills/led-matrix: lead with "use matrix_text / matrix_pattern first"; only flash for custom frames (flashing overwrites the responder). NOTE skills load from each agent's workspace copy, not shared/skills — push to all workspaces. - provision-host-daemon.sh: flash the responder once + start the relay. Proven on-hardware: "show a heart" and "scroll GO CLAWS" both instant via the agent, no flash. Co-Authored-By: Claude Opus 4.8 <[email protected]>
108 lines
4.4 KiB
Markdown
108 lines
4.4 KiB
Markdown
---
|
||
name: led-matrix
|
||
description: Drive the Arduino Uno Q's built-in 13x8 blue LED matrix — draw frames with the always-bundled Arduino_LED_Matrix frame API, or scroll text with ArduinoGraphics when it's installed. Load this whenever the user mentions the LED matrix, drawing pixels, or displaying words on the board.
|
||
---
|
||
|
||
# Uno Q Built-in LED Matrix
|
||
|
||
The Uno Q has a built-in **13 columns × 8 rows** (104-pixel) **blue** LED matrix,
|
||
driven by the STM32U585 MCU. (It is NOT an LCD, and NOT red.)
|
||
|
||
## Instant runtime control — USE THIS FIRST (no flashing)
|
||
|
||
The board runs a **resident responder sketch** that already drives the matrix, so
|
||
you can change what it shows **instantly** with these tools — no sketch, no
|
||
compile, no flash:
|
||
|
||
- **`matrix_text`** — scroll a short message. Use for ANY "scroll / show / display
|
||
/ print `<text>`" request (e.g. `text="GO CLAWS"`).
|
||
- **`matrix_pattern`** — switch to a preset animation: `off, rain, heart, wave,
|
||
sparkle, checker, solid, blink`.
|
||
|
||
**Always reach for these tools first** for text or a preset animation. They take
|
||
effect in under a second. Do **NOT** write and flash a sketch for these — flashing
|
||
takes ~90s **and overwrites the resident responder, breaking `matrix_text` /
|
||
`matrix_pattern` until it's re-flashed.** Only write + flash a sketch (below) for a
|
||
**custom** frame pattern the tools can't produce, and know it replaces the
|
||
responder.
|
||
|
||
## Prefer the frame API (always available)
|
||
|
||
`Arduino_LED_Matrix` is bundled with the `arduino:zephyr` core — **no lib install**.
|
||
The **frame API** works on every core version and is the safe default. A frame is
|
||
**four `uint32_t` words** (128 bits; the first 104 map to the pixels). `loadFrame`
|
||
displays one:
|
||
|
||
```cpp
|
||
#include "Arduino_LED_Matrix.h"
|
||
|
||
Arduino_LED_Matrix matrix;
|
||
|
||
const uint32_t FULL[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; // all on
|
||
const uint32_t BLANK[4] = {0, 0, 0, 0}; // all off
|
||
|
||
void setup() {
|
||
matrix.begin(); // REQUIRED — without it the matrix stays dark
|
||
}
|
||
|
||
void loop() {
|
||
matrix.loadFrame(FULL);
|
||
delay(500);
|
||
matrix.loadFrame(BLANK);
|
||
delay(500);
|
||
}
|
||
```
|
||
|
||
- `matrix.loadFrame(const uint32_t[4])` — show a raw frame.
|
||
- `matrix.renderBitmap(bitmap, rows, cols)` — show an 8×13 `uint8_t` bitmap (1 = on).
|
||
- The matrix is **charlieplexed**: the MCU must keep running to refresh it. If the
|
||
sketch halts or stops driving it, the display freezes/goes dark — a *static*
|
||
pattern that never changes usually means the sketch isn't running (see `flashing`).
|
||
|
||
## Scrolling text (needs `ArduinoGraphics` — install it first)
|
||
|
||
Text scrolling needs `ArduinoGraphics`. On core 0.51.0 the matrix lib includes it
|
||
**conditionally** (`__has_include`), so it is NOT present by default — a scroll
|
||
sketch fails with `'endText'/'SCROLL_LEFT' not declared`. Install it once (needs
|
||
network), then it stays available offline:
|
||
|
||
```
|
||
arduino-cli lib install ArduinoGraphics # run with TMPDIR=/tmp on the Uno Q
|
||
```
|
||
|
||
Verified working sketch on core 0.51.0 with [email protected] (compiles to ~7.6 KB):
|
||
|
||
```cpp
|
||
#include "ArduinoGraphics.h" // MUST come before Arduino_LED_Matrix.h (defines SCROLL_LEFT)
|
||
#include "Arduino_LED_Matrix.h"
|
||
|
||
ArduinoLEDMatrix matrix; // ArduinoLEDMatrix and Arduino_LED_Matrix are aliases
|
||
|
||
void setup() {
|
||
matrix.begin();
|
||
matrix.textFont(Font_5x7); // fits the 8-row height
|
||
matrix.textScrollSpeed(80); // ms per step; lower = faster
|
||
}
|
||
|
||
void loop() {
|
||
matrix.beginText(0, 1, 0xFF, 0xFF, 0xFF); // x, y, R, G, B — the 5-arg form
|
||
matrix.print(" HELLO UNO Q "); // pad with spaces so it scrolls in and out
|
||
matrix.endText(SCROLL_LEFT);
|
||
delay(200);
|
||
}
|
||
```
|
||
|
||
If installing a library isn't an option (fully offline, no network ever), scroll a
|
||
hand-rendered font with the frame API instead: build an 8×N `uint8_t` bitmap of the
|
||
message and `renderBitmap(window, 8, 13)` a sliding 13-column window each step.
|
||
|
||
## Pitfalls
|
||
|
||
- **`ArduinoGraphics` may be absent** (core 0.51.0) — prefer the frame API; only use
|
||
the text API when the sketch is known to compile against a core that bundles it.
|
||
- Always call `matrix.begin()` in `setup()`, or the matrix stays dark.
|
||
- Include order for the text path: `ArduinoGraphics.h` **before** `Arduino_LED_Matrix.h`.
|
||
- Use the **5-argument** `beginText(x, y, R, G, B)` form; the 3-arg form is a
|
||
training-data artifact.
|
||
- It's a monochrome **blue** matrix — RGB args only set on/off, not hue.
|