Files
apress/deploy/uno-q/skills/arduino-uno-q/references/05-io-and-peripherals.md
T
Omar SobhandClaude Opus 4.8 d2135a1938 feat(uno-q): ship the arduino-uno-q expert skill on every node by default
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]>
2026-07-16 09:14:00 -07:00

5.4 KiB
Raw Blame History

UNO Q — Pins, Buses & Controlling Attached Components

All physical I/O belongs to the MCU (STM32). You control attached components by writing an Arduino sketch that owns the pin/bus. If Linux/Python needs to be involved, expose the control as a Bridge function and call it from Python (see the Bridge reference). MCU I/O is 3.3 V logic.

Digital pins

47 digital pins total (22 on the UNO-style header, 25 on the JMISC connector). UNO-style header mapping:

MCU pin Arduino Function
PB7 D0 / RX GPIO / UART RX
PB6 D1 / TX GPIO / UART TX
PB3 D2 GPIO
PB0 D3 GPIO / OPAMP OUT / PWM
PA12 D4 / FDCAN1_TX GPIO / CAN TX
PA11 D5 / FDCAN1_RX GPIO / CAN RX / PWM
PB1 D6 GPIO / PWM
PB2 D7 GPIO
PB4 D8 GPIO
PB8 D9 GPIO / PWM
PB9 D10 / SS GPIO / SPI SS / PWM
PB15 D11 / MOSI GPIO / SPI MOSI / PWM
PB14 D12 / MISO GPIO / SPI MISO
PB13 D13 / SCK GPIO / SPI SCK
PA4 D14 / DAC0 GPIO / ADC / DAC
PA5 D15 / DAC1 GPIO / ADC / DAC
PA6 D16 GPIO / ADC / OPAMP IN+
PA7 D17 GPIO / ADC / OPAMP IN-
PC1 D18 / SDA2 GPIO / ADC / I2C SDA
PC0 D19 / SCL2 GPIO / ADC / I2C SCL
PB11 D20 / SDA GPIO / I2C SDA
PB10 D21 / SCL GPIO / I2C SCL

Usage:

pinMode(pin, INPUT | OUTPUT | INPUT_PULLUP);
state = digitalRead(pin);
digitalWrite(pin, HIGH | LOW);

Button-reads-input, LED-follows example: pinMode(btn, INPUT_PULLUP); if (digitalRead(btn)==LOW) digitalWrite(led,HIGH);

Analog input (ADC) — JANALOG connector

6 channels, 14-bit ADC.

MCU pin Arduino Function
PA4 A0 ADC / DAC
PA5 A1 ADC / DAC
PA6 A2 ADC / OPAMP IN+
PA7 A3 ADC / OPAMP IN-
PC1 A4 ADC / I2C SDA
PC0 A5 ADC / I2C SCL
analogReadResolution(14);          // 016383
analogReference(AR_INTERNAL2V5);   // set V_REF+ (see table)
int v = analogRead(A0);

Voltage-reference options: AR_INTERNAL1V5 (1.5 V), AR_INTERNAL1V8 (1.8 V), AR_INTERNAL2V05 (2.048 V), AR_INTERNAL2V5 (2.5 V), AR_EXTERNAL (2 V…VDD, external).

Analog output (DAC)

Two true DAC outputs.

MCU pin Arduino
PA4 DAC0
PA5 DAC1
analogWriteResolution(12);   // 04095
analogWrite(DAC0, value);

(Good for generating waveforms — the docs include a 60 Hz sine via a 256-point LUT clocked with micros().)

PWM

6 PWM-capable pins: D3, D5, D6, D9, D10, D11. Default resolution 8-bit (0255); change with analogWriteResolution(bits). PWM frequency is fixed at 500 Hz.

analogWriteResolution(10);       // 01023
analogWrite(D3, dutyValue);

SPI

MCU pin Arduino
PB9 SS / D10
PB15 MOSI / D11
PB14 MISO / D12
PB13 SCK / D13
#include <SPI.h>
#define SS D10
void setup(){ pinMode(SS,OUTPUT); digitalWrite(SS,HIGH); SPI.begin(); }
void loop(){
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
  digitalWrite(SS, LOW);
  SPI.transfer(0x35); SPI.transfer(0xFA);
  digitalWrite(SS, HIGH);
  SPI.endTransaction();
}

I2C — two buses

Bus / object SCL SDA Where
Wire D21 (PB10) D20 (PB11) UNO-style headers
Wire1 I2C4_SCL (PD12) I2C4_SDA (PD13) Qwiic connector
#include <Wire.h>
void setup(){ Wire.begin(); }        // or Wire1.begin() for Qwiic
// Wire.beginTransmission(addr); Wire.write(...); Wire.endTransmission();

Qwiic connector

Plug-and-play I²C: polarized connector, daisy-chainable, built-in pull-ups, 3.3 V only — no breadboard/soldering. Use Wire1. Works directly with Arduino's Modulino sensor/actuator family for solder-free prototyping.

UART (hardware serial on the header)

MCU pin Arduino
PB6 USART1_TX / D1
PB7 USART1_RX / D0

Use the Serial1 object for the physical D0/D1 pins on the JDIGITAL connector:

Serial1.begin(115200);
Serial1.println("Hello UNO Q");
while (Serial1.available()) { char c = Serial1.read(); /* ... */ }

Note: Serial1 here is the header UART. It is not the reserved router link — that reserved Serial1 warning in the Bridge doc refers to the internal MPU↔MCU port; on the exposed headers Serial1 drives D0/D1. Don't confuse the two: use Serial1 for external UART devices, and never touch the internal router transport.

Serial for debugging → App Lab console

Since platform 0.55.0, plain Serial prints stream to the Arduino App Lab Console — use it like normal:

void setup(){ Serial.begin(9600); }
void loop(){ Serial.println("Hello UNO Q"); delay(1000); }

The legacy Monitor object (#include <Arduino_RouterBridge.h>Monitor.begin()/println()) still works for backward compatibility, but use Serial for new projects.

How to actually control "our node's" attached hardware — recipe

  1. Identify the interface the component uses (GPIO / ADC / PWM / SPI / I2C / UART) and the matching pins above. Mind 3.3 V levels.
  2. Write the sketch that drives it (the standard Arduino libraries work: Servo, Wire-based sensor libs, etc.).
  3. If Python/AI/networking must control or read it, wrap each action in a Bridge.provide_safe("name", fn) on the MCU and Bridge.call("name", ...) from Python (see Bridge reference).
  4. For quick prototyping of sensors/actuators, reach for Qwiic + Modulino modules to skip wiring.