<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Willem van Heemstra</title>
    <description>The latest articles on DEV Community by Willem van Heemstra (@wvanheemstra).</description>
    <link>https://dev.to/wvanheemstra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1547150%2Fcf4a7812-9d15-47b3-9284-0510a0931fd9.jpeg</url>
      <title>DEV Community: Willem van Heemstra</title>
      <link>https://dev.to/wvanheemstra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wvanheemstra"/>
    <language>en</language>
    <item>
      <title>R2D2 Creation with Codey 🤖 Ep.8</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:14:14 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep8-3713</link>
      <guid>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep8-3713</guid>
      <description>&lt;h2&gt;
  
  
  Episode 8: The Complete Droid
&lt;/h2&gt;

&lt;h2&gt;
  
  
  "The Force Will Be With You. Always." 🌟
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The entire crew stands in the workshop. Han Solo, arms folded. Luke, grinning. C-3PO, hands clasped with barely-contained anxiety. Princess Leia's message loops on the OLED — a recreation, text only, but the words are right: "Help me, Obi-Wan Kenobi."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And in the centre, dome slowly rotating, blue-white LEDs breathing, speaker playing a quiet ambient whistle — R2-D2.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; &lt;em&gt;quietly&lt;/em&gt; "Seven episodes. Seven systems. And now, the droid is nearly complete. There is one thing left — the final integration. The moment when all systems stop running in parallel and begin running as one coherent whole. When R2-D2 stops being a collection of components and becomes the galaxy's greatest droid."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps once. Confident. Ready.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "And then — the Force. The Wi-Fi."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Han Solo snorts.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "The Wi-Fi. Very mystical."&lt;/p&gt;

&lt;h2&gt;
  
  
  🗂️ SIPOC — The Complete Droid
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suppliers&lt;/th&gt;
&lt;th&gt;Inputs&lt;/th&gt;
&lt;th&gt;Process&lt;/th&gt;
&lt;th&gt;Outputs&lt;/th&gt;
&lt;th&gt;Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You (the maker)&lt;/td&gt;
&lt;td&gt;"Integrate all systems + add Wi-Fi remote command interface"&lt;/td&gt;
&lt;td&gt;Codey Deep Think mode plans the full architecture before writing&lt;/td&gt;
&lt;td&gt;A unified state machine with all systems communicating, Wi-Fi endpoint for remote commands&lt;/td&gt;
&lt;td&gt;The complete R2-D2 — one firmware, all systems orchestrated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESP32-S3 N16R8&lt;/td&gt;
&lt;td&gt;16MB Flash, 8MB PSRAM, dual-core, Wi-Fi&lt;/td&gt;
&lt;td&gt;Dual-core operation: Core 0 for Wi-Fi/networking, Core 1 for real-time sensor/motor/audio loop&lt;/td&gt;
&lt;td&gt;Smooth operation without Wi-Fi blocking the real-time control loop&lt;/td&gt;
&lt;td&gt;All R2-D2 systems — none starved of processor time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codey Deep Think mode&lt;/td&gt;
&lt;td&gt;Complex multi-file integration prompt&lt;/td&gt;
&lt;td&gt;Takes longer to respond — reasons about the whole architecture first&lt;/td&gt;
&lt;td&gt;The cleanest, most architecturally coherent code in the series&lt;/td&gt;
&lt;td&gt;Your long-term maintainability&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final Wiring Diagram&lt;/td&gt;
&lt;td&gt;All 7 systems' component lists&lt;/td&gt;
&lt;td&gt;Codey draws the complete master diagram with all connections, protection circuits, and power rails&lt;/td&gt;
&lt;td&gt;A single PDF showing the complete R2-D2 build&lt;/td&gt;
&lt;td&gt;Your workshop wall — the crown jewel of your build log&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Final Component Inventory — Every Piece of R2-D2 🔧
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO produces a datapad with the air of someone who has been waiting seven episodes to read this list.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "The complete inventory, as accumulated across eight glorious — and at times terrifying — episodes:"&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Episode Added&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ESP32-S3 N16R8&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;The brain — all systems connect here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSD1306 OLED 128×64&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Holographic display — I2C via GPIO8/9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NeoPixel ring 12 LED&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Dome lights — GPIO6 via level shifter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HC-SR04 ultrasonic&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Distance sensing eye — GPIO9/10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PIR HC-SR501&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Motion sensing — GPIO2 (interrupt)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SG90 servo&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Dome rotation — GPIO14 via level shifter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DC gear motors × 2&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Wheel drive — via L298N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L298N motor driver&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Motor control, also provides 5V rail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DFPlayer Mini&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Audio playback — UART2 GPIO16/17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speaker 4Ω/8Ω&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Voice output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;microSD card (FAT32)&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Audio files 0001–0007.mp3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;74AHCT125 level shifter&lt;/td&gt;
&lt;td&gt;3/6&lt;/td&gt;
&lt;td&gt;NeoPixel + servo: 3.3V → 5V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;470Ω resistor&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;NeoPixel data protection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1kΩ resistor&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;DFPlayer RX protection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100Ω resistor&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;(buzzer, now removed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100µF capacitor&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;NeoPixel power decoupling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10µF capacitor&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;DFPlayer power filtering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Voltage dividers (10k+20k)&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;HC-SR04 ECHO + PIR output: 5V → 3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9V battery or 2S LiPo&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Motor power rail&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB cable&lt;/td&gt;
&lt;td&gt;All&lt;/td&gt;
&lt;td&gt;Programming + logic power&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "R2-D2. In components. On a breadboard. I find this both impressive and somewhat unsettling."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps with what sounds like pride.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Think Mode: The Wisest Path 🧠
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Yoda settles into his chair.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Complex this prompt is. Many files to touch. Many systems to unify. For this — Deep Think mode you shall use. Longer it takes. Wiser the result."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "What's Deep Think mode?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Plan mode's elder sibling. Not just a plan — a deep analysis of the architecture first. Consider edge cases it will. Identify conflicts between systems it shall. Only then write, it does."&lt;/p&gt;

&lt;p&gt;In Codey, click the mode dropdown and select &lt;strong&gt;Deep Think&lt;/strong&gt; (Pro feature). Then type the final integration prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FINAL R2-D2 INTEGRATION — Deep Think mode

We have these existing header files for the ESP32-S3 N16R8:
  - animations.h  (NeoPixel dome: GPIO6 via 74AHCT125)
  - sensors.h     (HC-SR04: GPIO9 TRIG / GPIO10 ECHO; PIR: GPIO2)
  - display.h     (SSD1306 OLED: I2C SDA=GPIO8 / SCL=GPIO9 — NOTE: conflict!)
  - motion.h      (Servo: GPIO14; L298N: GPIO25-27, GPIO32-34)
  - voice.h       (DFPlayer Mini: UART2 TX=GPIO17 / RX=GPIO16)
  - sounds.h      (LEDC buzzer: now removed, GPIO freed)

CONFLICT TO RESOLVE:
  HC-SR04 TRIG uses GPIO9. OLED I2C SCL also uses GPIO9.
  These cannot share! Remap one of them.
  Suggestion: Move HC-SR04 TRIG to GPIO11, ECHO to GPIO12.
  Update sensors.h and the wiring diagram accordingly.

NEW FEATURE — Wi-Fi remote control:
  Use ESP32-S3 Wi-Fi to create a simple HTTP server.
  Endpoints:
    GET /status    → JSON with distance, motion, dome angle, current sound
    GET /command/forward   → drive forward for 2 seconds
    GET /command/backward  → drive backward for 2 seconds
    GET /command/left      → turn left for 1 second
    GET /command/right     → turn right for 1 second
    GET /command/stop      → stop motors immediately
    GET /command/sound/N   → play sound N (1-7)
    GET /command/dome/N    → move dome to angle N degrees

  Use WiFiAP mode (R2-D2 creates its own access point):
    SSID: "R2-D2"
    Password: "beepboop"

  Run HTTP server on Core 0. Real-time systems on Core 1.

FINAL r2d2-main.ino:
  - Resolve the GPIO conflict
  - Add wifi.h header for Wi-Fi + HTTP server
  - Clean unified loop with clear comments
  - All systems operational
  - Serial output at 115200 showing all state transitions

Please think through the architecture fully before writing.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deep Think Mode Analysis (Codey Responds)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Deep Think analysis in progress...]

Architecture review:

1. GPIO CONFLICT IDENTIFIED:
   GPIO9 cannot serve both HC-SR04 TRIG and I2C SCL.
   Resolution: Remap I2C to SDA=GPIO4, SCL=GPIO5 (available on ESP32-S3).
   This avoids touching sensors.h; only display.h changes:
     Wire.begin(4, 5) instead of Wire.begin(8, 9).

2. DUAL-CORE STRATEGY:
   Core 0 (Arduino default): Wi-Fi, HTTP server, WebServer library
   Core 1 (pinned task): sensor reading, NeoPixel, servo, display, audio
   Separation prevents Wi-Fi TCP/IP stack from blocking 50Hz servo updates.
   Implementation: xTaskCreatePinnedToCore() for real-time loop.

3. STATE MACHINE:
   Unified DomeState enum: IDLE, SCAN, ALERT, DANGER, REMOTE_CONTROL
   REMOTE_CONTROL state: Wi-Fi command overrides sensor-driven behavior.
   Auto-return to IDLE after 5 seconds of no remote command.

4. MEMORY:
   16MB Flash — no concern.
   8MB PSRAM — HTTP response buffers can use ps_malloc() if needed.
   RAM: estimated ~68KB used (20.8% of 327KB) — safe.

5. POWER:
   Wi-Fi radio: ~240mA peak. USB 500mA should be sufficient for ESP32-S3.
   Motors: separate 9V rail — no impact on ESP32 power.

Generating files now...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generated &lt;code&gt;wifi.h&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// wifi.h — R2-D2 Wi-Fi Remote Control&lt;/span&gt;
&lt;span class="c1"&gt;// ESP32-S3 Access Point: SSID "R2-D2", password "beepboop"&lt;/span&gt;
&lt;span class="c1"&gt;// HTTP server on port 80 — runs on Core 0&lt;/span&gt;

&lt;span class="cp"&gt;#pragma once
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;WiFi.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;WebServer.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;ArduinoJson.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;AP_SSID&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"R2-D2"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;AP_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"beepboop"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;   &lt;span class="n"&gt;HTTP_PORT&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;WebServer&lt;/span&gt; &lt;span class="nf"&gt;server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HTTP_PORT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Shared state (volatile — accessed from both cores)&lt;/span&gt;
&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;  &lt;span class="n"&gt;sharedDistance&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;999.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;   &lt;span class="n"&gt;sharedMotion&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="n"&gt;sharedDomeAngle&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;   &lt;span class="n"&gt;remoteCommandPending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;remoteCommand&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Status endpoint ──────────────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;StaticJsonDocument&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"distance_cm"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sharedDistance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"motion"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sharedMotion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"dome_angle"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sharedDomeAngle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"state"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"online"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"uptime_s"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;serializeJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[WiFi] GET /status"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Command endpoints ────────────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleCommand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// e.g. "/command/forward"&lt;/span&gt;
  &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// strip "/command/"&lt;/span&gt;
  &lt;span class="n"&gt;remoteCommand&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;remoteCommandPending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/plain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ACK: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[WiFi] Command: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Root page (simple UI) ─────────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;handleRoot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;R"rawhtml(
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;R2-D2 Control&amp;lt;/title&amp;gt;
&amp;lt;meta name="viewport" content="width=device-width,initial-scale=1"&amp;gt;
&amp;lt;style&amp;gt;
  body { font-family:sans-serif; background:#111; color:#4af;
         display:flex; flex-direction:column; align-items:center; }
  h1 { color:#4af; }
  button { background:#1a3a5a; color:#4af; border:2px solid #4af;
           padding:14px 28px; font-size:1.1em; margin:6px;
           border-radius:6px; cursor:pointer; }
  button:active { background:#4af; color:#111; }
  #status { margin-top:16px; font-size:0.9em; color:#aaa; }
&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;R2-D2&amp;lt;/h1&amp;gt;
&amp;lt;div&amp;gt;
  &amp;lt;button onclick="cmd('sound/5')"&amp;gt;🔊 Startup&amp;lt;/button&amp;gt;
  &amp;lt;button onclick="cmd('sound/1')"&amp;gt;😄 Happy&amp;lt;/button&amp;gt;
  &amp;lt;button onclick="cmd('sound/3')"&amp;gt;😢 Sad&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
  &amp;lt;button onclick="cmd('forward')"&amp;gt;▲ Forward&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
  &amp;lt;button onclick="cmd('left')"&amp;gt;◄ Left&amp;lt;/button&amp;gt;
  &amp;lt;button onclick="cmd('stop')"&amp;gt;■ Stop&amp;lt;/button&amp;gt;
  &amp;lt;button onclick="cmd('right')"&amp;gt;► Right&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
  &amp;lt;button onclick="cmd('backward')"&amp;gt;▼ Backward&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div&amp;gt;
  &amp;lt;button onclick="cmd('dome/0')"&amp;gt;Dome ◄&amp;lt;/button&amp;gt;
  &amp;lt;button onclick="cmd('dome/90')"&amp;gt;Dome ●&amp;lt;/button&amp;gt;
  &amp;lt;button onclick="cmd('dome/180')"&amp;gt;Dome ►&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div id="status"&amp;gt;Connecting...&amp;lt;/div&amp;gt;
&amp;lt;script&amp;gt;
function cmd(c) {
  fetch('/command/'+c).then(r=&amp;gt;r.text()).then(t=&amp;gt;{
    document.getElementById('status').textContent = 'Last: '+c;
  });
}
setInterval(()=&amp;gt;{
  fetch('/status').then(r=&amp;gt;r.json()).then(d=&amp;gt;{
    document.getElementById('status').textContent =
      'Dist: '+d.distance_cm.toFixed(0)+'cm | Motion: '+d.motion+
      ' | Uptime: '+d.uptime_s+'s';
  });
}, 2000);
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
)rawhtml"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Init Wi-Fi + HTTP server (call from Core 0 task) ─────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initWifi&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;WiFi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;softAP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AP_SSID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AP_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[WiFi] AP started: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AP_SSID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[WiFi] IP: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WiFi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;softAPIP&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="n"&gt;handleRoot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;handleStatus&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onNotFound&lt;/span&gt;&lt;span class="p"&gt;([]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Any /command/* path&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/command/"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;handleCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"text/plain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Not found"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"[WiFi] HTTP server started — connect to R2-D2 network"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Core 0 task: runs Wi-Fi server continuously ──────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;wifiTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;initWifi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;handleClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;vTaskDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// yield to RTOS — must not block Core 0&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Final &lt;code&gt;r2d2-main.ino&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// r2d2-main.ino — R2-D2 COMPLETE&lt;/span&gt;
&lt;span class="c1"&gt;// ESP32-S3 N16R8 | All systems operational&lt;/span&gt;
&lt;span class="c1"&gt;// Core 0: Wi-Fi + HTTP server&lt;/span&gt;
&lt;span class="c1"&gt;// Core 1: Sensors, display, NeoPixel, servo, motors, audio&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Adafruit_NeoPixel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"animations.h"&lt;/span&gt;&lt;span class="c1"&gt;   // NeoPixel dome: GPIO6&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"sensors.h"&lt;/span&gt;&lt;span class="c1"&gt;      // HC-SR04: GPIO9(TRIG) GPIO10(ECHO); PIR: GPIO2&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"display.h"&lt;/span&gt;&lt;span class="c1"&gt;      // OLED I2C: SDA=GPIO4 SCL=GPIO5 (CONFLICT RESOLVED)&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"motion.h"&lt;/span&gt;&lt;span class="c1"&gt;       // Servo: GPIO14; L298N: GPIO25-27, GPIO32-34&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"voice.h"&lt;/span&gt;&lt;span class="c1"&gt;        // DFPlayer: UART2 GPIO16/17&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"wifi.h"&lt;/span&gt;&lt;span class="c1"&gt;         // Wi-Fi AP + HTTP server&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;TaskHandle_t&lt;/span&gt; &lt;span class="n"&gt;realtimeTask&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// Core 1 handle&lt;/span&gt;

&lt;span class="c1"&gt;// ── Remote command processor ─────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;processRemoteCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"forward"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="n"&gt;motorForward&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"backward"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="n"&gt;motorBackward&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"left"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="n"&gt;motorTurnLeft&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;motorTurnRight&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"stop"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      &lt;span class="n"&gt;motorStop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sound/"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;playSound&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;R2Sound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dome/"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;domeSnap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;constrain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastRemoteCmdMs&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;REMOTE_TIMEOUT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// return to autonomous after 5s&lt;/span&gt;

&lt;span class="c1"&gt;// ── Core 1: real-time loop ───────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;realtimeLoop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Init all real-time systems on Core 1&lt;/span&gt;
  &lt;span class="n"&gt;initAnimations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initSensors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initDisplay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initMotion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initVoiceSystem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;bootDone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;showBootScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;vTaskDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readDistance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt;  &lt;span class="n"&gt;motion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checkMotion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Share state with Wi-Fi (Core 0 reads these)&lt;/span&gt;
    &lt;span class="n"&gt;sharedDistance&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;sharedMotion&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;sharedDomeAngle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentDomeAngle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// ── Remote command takes priority ──────────────────────────&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;remoteActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastRemoteCmdMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;REMOTE_TIMEOUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remoteCommandPending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remoteCommand&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;remoteCommandPending&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;processRemoteCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;lastRemoteCmdMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;remoteActive&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ── Autonomous behaviour (when no remote command) ─────────&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;remoteActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;domeSnap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;motorStop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;domeSnap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;domeIdleSweep&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// ── Display + lights + voice (always) ─────────────────────&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;showAlertScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;showMotionScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;                 &lt;span class="nf"&gt;showIdleScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;updateAnimationsSensors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;updateVoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;vTaskDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 10ms tick — 100Hz loop&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;115200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"╔═══════════════════════════════╗"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"║   R2-D2 — COMPLETE BUILD      ║"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"║   ESP32-S3 N16R8              ║"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"╚═══════════════════════════════╝"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Start Wi-Fi server on Core 0&lt;/span&gt;
  &lt;span class="n"&gt;xTaskCreatePinnedToCore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;wifiTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// function&lt;/span&gt;
    &lt;span class="s"&gt;"WiFiTask"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;// name&lt;/span&gt;
    &lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// stack size (bytes)&lt;/span&gt;
    &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// parameter&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// priority&lt;/span&gt;
    &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// task handle&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt;               &lt;span class="c1"&gt;// core: 0&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Start real-time loop on Core 1&lt;/span&gt;
  &lt;span class="n"&gt;xTaskCreatePinnedToCore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;realtimeLoop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// function&lt;/span&gt;
    &lt;span class="s"&gt;"RTLoop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// name&lt;/span&gt;
    &lt;span class="mi"&gt;8192&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// stack size&lt;/span&gt;
    &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// parameter&lt;/span&gt;
    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;// priority (higher than Wi-Fi)&lt;/span&gt;
    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;realtimeTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// task handle&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt;               &lt;span class="c1"&gt;// core: 1&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Arduino loop() runs on Core 1 by default — we've moved everything&lt;/span&gt;
  &lt;span class="c1"&gt;// to FreeRTOS tasks, so loop() is intentionally empty.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;vTaskDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;portMAX_DELAY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// yield forever — all work done in tasks&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Final Master Wiring Diagram 🧭
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO takes a deep breath and presents the complete diagram with a formality appropriate to the occasion.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "The final wiring diagram. Every component. Every wire. Every protection circuit. Every power rail. Downloadable as PDF. Printable. Frameable. I am... genuinely proud of this."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R2-D2 COMPLETE BUILD — Master Wiring Diagram
ESP32-S3 N16R8 | All Systems
════════════════════════════════════════════════════════════════════

POWER RAIL 1 — LOGIC (USB 5V regulated to 3.3V by ESP32-S3):
  USB 5V → ESP32-S3 VIN
  ESP32 3V3 output → (nothing external — 3.3V stays internal)
  ESP32 GND → Common GND rail

POWER RAIL 2 — 5V PERIPHERALS (L298N internal regulator from 9V):
  9V Battery (+) → L298N: VS
  9V Battery (−) → GND (common with ESP32 GND!)
  L298N 5V out → Servo VCC (red), 74AHCT125 VCC, DFPlayer VCC
  L298N GND → Servo GND, 74AHCT125 GND, DFPlayer GND

I2C BUS (conflict-resolved: SDA=GPIO4, SCL=GPIO5):
  ESP32 GPIO4 (SDA) ──── OLED SDA
  ESP32 GPIO5 (SCL) ──── OLED SCL
  ESP32 3V3         ──── OLED VCC (via 100µF cap to GND)

NEOPIXEL DOME (5V logic via level shifter):
  ESP32 GPIO6 ──── 74AHCT125 A1 ──── NeoPixel DIN
  L298N 5V    ──── NeoPixel 5V + 100µF cap+
  GND         ──── NeoPixel GND + 100µF cap−
  (470Ω resistor between 74AHCT125 Y1 output and NeoPixel DIN)

HC-SR04 ULTRASONIC (5V sensor, voltage divider on ECHO):
  ESP32 GPIO9  (TRIG) ──────────────── HC-SR04 TRIG
  HC-SR04 ECHO (5V)   ── 10kΩ ──┬──── ESP32 GPIO10
                                 └──── 20kΩ ──── GND

PIR MOTION SENSOR (5V output, voltage divider):
  L298N 5V    ──── PIR HC-SR501 VCC
  GND         ──── PIR HC-SR501 GND
  PIR OUT (5V) ── 10kΩ ──┬──── ESP32 GPIO2
                          └──── 20kΩ ──── GND

SERVO — DOME ROTATION (5V signal via level shifter):
  ESP32 GPIO14 ──── 74AHCT125 A2 ──── Servo signal (orange)
  L298N 5V     ──── Servo VCC (red)
  GND          ──── Servo GND (brown)

L298N MOTOR DRIVER:
  ESP32 GPIO25 ──── L298N IN1
  ESP32 GPIO26 ──── L298N IN2
  ESP32 GPIO27 ──── L298N ENA (PWM)
  ESP32 GPIO32 ──── L298N IN3
  ESP32 GPIO33 ──── L298N IN4
  ESP32 GPIO34 ──── L298N ENB (PWM)
  L298N OUT1,2 ──── DC Motor Left
  L298N OUT3,4 ──── DC Motor Right

DFPLAYER MINI AUDIO:
  L298N 5V    ──── DFPlayer VCC + 10µF cap+
  GND         ──── DFPlayer GND + 10µF cap−
  ESP32 GPIO17 ── (1kΩ) ─── DFPlayer RX
  DFPlayer TX ──── ESP32 GPIO16
  DFPlayer SPK1 ── Speaker +
  DFPlayer SPK2 ── Speaker −

Color code (master):
  RED    = 5V / VIN
  ORANGE = 9V battery rail
  PURPLE = 3.3V logic
  BLACK  = GND (common rail)
  GREEN  = NeoPixel data (level-shifted 5V)
  BLUE   = Servo signal (level-shifted 5V)
  YELLOW = Motor direction pins (IN1-IN4)
  WHITE  = Motor PWM enable pins (ENA, ENB)
  CYAN   = I2C SDA (GPIO4)
  PINK   = I2C SCL (GPIO5)
  BROWN  = HC-SR04 TRIG (GPIO9)
  VIOLET = HC-SR04 ECHO with divider (GPIO10)
  GREY   = PIR output with divider (GPIO2)
  MAROON = DFPlayer UART (TX=GPIO17, RX=GPIO16)

COMPLETE Connection Table:
┌──────────────────────┬──────────────────────────────────────────┐
│ From                 │ To                                       │
├──────────────────────┼──────────────────────────────────────────┤
│ USB 5V               │ ESP32-S3 VIN                             │
│ 9V Battery (+)       │ L298N VS                                 │
│ 9V Battery (−)       │ L298N GND + ESP32 GND (common)           │
│ L298N 5V             │ Servo VCC, 74AHCT125 VCC, DFPlayer VCC   │
│ ESP32 GPIO4 (SDA)    │ OLED SDA                                 │
│ ESP32 GPIO5 (SCL)    │ OLED SCL                                 │
│ ESP32 3V3            │ OLED VCC (+ 100µF cap to GND)            │
│ ESP32 GPIO6          │ 74AHCT125 A1 → (470Ω) → NeoPixel DIN     │
│ ESP32 GPIO9 (TRIG)   │ HC-SR04 TRIG                             │
│ HC-SR04 ECHO (5V)    │ 10k+20k divider → ESP32 GPIO10           │
│ L298N 5V             │ PIR VCC                                  │
│ PIR OUT (5V)         │ 10k+20k divider → ESP32 GPIO2            │
│ ESP32 GPIO14         │ 74AHCT125 A2 → Servo signal (orange)     │
│ ESP32 GPIO25         │ L298N IN1                                │
│ ESP32 GPIO26         │ L298N IN2                                │
│ ESP32 GPIO27 (PWM)   │ L298N ENA                                │
│ ESP32 GPIO32         │ L298N IN3                                │
│ ESP32 GPIO33         │ L298N IN4                                │
│ ESP32 GPIO34 (PWM)   │ L298N ENB                                │
│ L298N OUT1,2         │ DC Motor A                               │
│ L298N OUT3,4         │ DC Motor B                               │
│ L298N 5V             │ DFPlayer VCC + 10µF cap+                 │
│ ESP32 GPIO17 (TX2)   │ 1kΩ → DFPlayer RX                        │
│ DFPlayer TX          │ ESP32 GPIO16 (RX2)                       │
│ DFPlayer SPK1        │ Speaker terminal 1                       │
│ DFPlayer SPK2        │ Speaker terminal 2                       │
└──────────────────────┴──────────────────────────────────────────┘

⚡ Critical Notes:
  - 9V battery GND MUST connect to ESP32 GND (common ground)
  - 74AHCT125 handles BOTH NeoPixel AND servo level-shift
  - HC-SR04 ECHO and PIR output: voltage dividers MANDATORY on ESP32-S3
  - DFPlayer RX 1kΩ resistor is mandatory
  - OLED I2C now on GPIO4(SDA)/GPIO5(SCL) — conflict with GPIO9 resolved

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Download the PDF. All twenty-three connection rows. Printed. Laminated if possible. This is the complete blueprint of R2-D2."&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Compile 🚀
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Compilation successful
  Board:        ESP32-S3 N16R8
  Files:        r2d2-main.ino + 6 headers
  Binary:       634,512 bytes (9.1% of 16MB Flash)
  RAM:          Used 52,416 bytes (16.0% of 327KB)
  PSRAM:        8.0 MB free
  Wi-Fi:        Access Point mode — SSID: "R2-D2"
  Dual-core:    Core 0: Wi-Fi/HTTP | Core 1: Real-time control

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Upload&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The ESP32-S3 boots. The OLED shows "R2-D2 ONLINE." The startup fanfare plays from the speaker. The dome LEDs breathe. The servo sweeps. The Serial Monitor shows:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;╔═══════════════════════════════╗
║   R2-D2 — COMPLETE BUILD      ║
║   ESP32-S3 N16R8              ║
╚═══════════════════════════════╝
OLED projector online!
Dome servo centred.
Motor driver online.
DFPlayer Mini online!
R2-D2 says: [sound 5]
[WiFi] AP started: R2-D2
[WiFi] IP: 192.168.4.1
[WiFi] HTTP server started — connect to R2-D2 network
All systems ONLINE. R2-D2 is ready.
Distance: 95 cm — SAFE

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pick up your phone. Connect to the "R2-D2" Wi-Fi network. Password: beepboop. Open a browser. Navigate to 192.168.4.1.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A simple control page appears. Blue on black. R2-D2's face.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tap "Forward."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The wheels turn.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tap "Happy."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2's happy whistle plays.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tap "Dome ◄."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The dome snaps left.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Final Milestone 🚩
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Milestone: "R2-D2 COMPLETE — Episode 8 Final Build"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Every episode. Every system. Every milestone. All saved. All restorable.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Complete Droid 🤖
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The workshop is quiet. The crew stands in a circle around R2-D2 — the completed droid. Dome rotating. Lights breathing. OLED projecting. Speaker quiet for now, waiting.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "You see what has been built. Not just a robot. Not just a collection of components. The process itself is the lesson — the way Codey lowered every barrier between the idea and the creation. You described. It wrote. You compiled. It fixed. You drew. It diagrammed. Each episode, a little more complex. Each episode, possible."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "Eight episodes. I went from blinking an LED to a Wi-Fi controlled droid with dome lights, sensors, a display, motors, and audio. And I'm not a programmer."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Kid, I've seen the Millennium Falcon held together with less intentionality than this thing. And the Falcon can make the Kessel Run."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps. Loudly. Repeatedly. Proudly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "He says — and I am translating precisely — 'I told you all it would work.'"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A long pause.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "He also says thank you. Which, from Artoo, is quite remarkable."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Obi-Wan smiles.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "The Force will be with you. Always."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 plays his startup fanfare one more time. The dome lights sweep blue-white. The OLED displays: "MISSION COMPLETE."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Series Map — What We Built 🗺️
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Episode&lt;/th&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Board&lt;/th&gt;
&lt;th&gt;Codey Feature Spotlight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;First LED blink&lt;/td&gt;
&lt;td&gt;Arduino UNO R3&lt;/td&gt;
&lt;td&gt;Account setup, first sketch, first wiring diagram&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Piezo sound&lt;/td&gt;
&lt;td&gt;Arduino UNO R3&lt;/td&gt;
&lt;td&gt;Smart Library Picker, tone(), Serial Monitor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;NeoPixel dome&lt;/td&gt;
&lt;td&gt;Arduino UNO R3&lt;/td&gt;
&lt;td&gt;Voltage safety check, FastLED, multi-file project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Sensor eye&lt;/td&gt;
&lt;td&gt;Arduino UNO R3&lt;/td&gt;
&lt;td&gt;Auto Error Fixing, Vision photo upload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;OLED projector&lt;/td&gt;
&lt;td&gt;ESP32-S3 N16R8&lt;/td&gt;
&lt;td&gt;Board upgrade, Milestones &amp;amp; Rollback, I2C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Motion systems&lt;/td&gt;
&lt;td&gt;ESP32-S3 N16R8&lt;/td&gt;
&lt;td&gt;LEDC servo, L298N motors, two-rail wiring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Audio voice&lt;/td&gt;
&lt;td&gt;ESP32-S3 N16R8&lt;/td&gt;
&lt;td&gt;DFPlayer Mini, UART, Live Serial Monitor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Complete droid&lt;/td&gt;
&lt;td&gt;ESP32-S3 N16R8&lt;/td&gt;
&lt;td&gt;Deep Think mode, Wi-Fi, dual-core, final diagram&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;🔗 Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Codey Online&lt;/strong&gt;: &lt;a href="http://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESP32-S3 technical reference&lt;/strong&gt;: &lt;a href="https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/" rel="noopener noreferrer"&gt;docs.espressif.com/esp32-s3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ArduinoJson library&lt;/strong&gt;: &lt;a href="http://arduinojson.org" rel="noopener noreferrer"&gt;arduinojson.org&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESP32 FreeRTOS tasks&lt;/strong&gt;: &lt;a href="https://www.freertos.org/Documentation/" rel="noopener noreferrer"&gt;freertos.org/documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OTRONIC / Codey&lt;/strong&gt;: &lt;a href="http://otronic.nl" rel="noopener noreferrer"&gt;otronic.nl&lt;/a&gt; | &lt;a href="http://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;🤖 R2D2 Creation with Codey — eight episodes, one complete droid, infinite possibilities. The Force — and the cloud compiler — were with us. Always.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>esp32</category>
      <category>arduino</category>
      <category>ai</category>
      <category>makers</category>
    </item>
    <item>
      <title>R2D2 Creation with Codey 🤖 Ep.7</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:14:05 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep7-13cj</link>
      <guid>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep7-13cj</guid>
      <description>&lt;h2&gt;
  
  
  Episode 7: The Voice of the Galaxy
&lt;/h2&gt;

&lt;h2&gt;
  
  
  "Artoo, I Wish We Didn't Have to Listen to You Sometimes" 🔊
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO enters the workshop clutching a small speaker and a DFPlayer Mini module.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "I want to state, for the record, that I have mixed feelings about this episode. On one hand, R2-D2's communication through audio files will be considerably clearer than whatever he has been doing with that piezo buzzer. On the other hand, once we enable full audio playback, he will never. Stop. Talking."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps at considerable volume.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "See? He's already celebrating. This is going to be exhausting."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Han Solo leans against the doorframe.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "What he said. Let's wire it up anyway."&lt;/p&gt;

&lt;h2&gt;
  
  
  🗂️ SIPOC — The Voice System
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suppliers&lt;/th&gt;
&lt;th&gt;Inputs&lt;/th&gt;
&lt;th&gt;Process&lt;/th&gt;
&lt;th&gt;Outputs&lt;/th&gt;
&lt;th&gt;Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You (the maker)&lt;/td&gt;
&lt;td&gt;"Add DFPlayer Mini on UART2, microSD with R2-D2 sounds, trigger by sensor events"&lt;/td&gt;
&lt;td&gt;Codey picks DFRobotDFPlayerMini library, writes Serial2 init code, maps sounds to events&lt;/td&gt;
&lt;td&gt;Complete voice.h — sound triggers for every R2-D2 state&lt;/td&gt;
&lt;td&gt;ESP32-S3 UART2 → DFPlayer Mini → Speaker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DFPlayer Mini&lt;/td&gt;
&lt;td&gt;5V power, RX/TX from ESP32-S3 UART2&lt;/td&gt;
&lt;td&gt;Reads MP3/WAV files from microSD by number, decodes audio&lt;/td&gt;
&lt;td&gt;Amplified audio signal to speaker&lt;/td&gt;
&lt;td&gt;Speaker — which produces actual R2-D2 sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;microSD card (≤32GB FAT32)&lt;/td&gt;
&lt;td&gt;MP3 or WAV files named 0001.mp3, 0002.mp3...&lt;/td&gt;
&lt;td&gt;DFPlayer reads by file number&lt;/td&gt;
&lt;td&gt;Audio playback&lt;/td&gt;
&lt;td&gt;Speaker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live Serial Monitor&lt;/td&gt;
&lt;td&gt;ESP32-S3 Serial.print() output at 115200 baud&lt;/td&gt;
&lt;td&gt;Shows state transitions, sound triggers, distance readings in real time&lt;/td&gt;
&lt;td&gt;A running log of what R2-D2 is doing and thinking&lt;/td&gt;
&lt;td&gt;You — debugging without a logic analyser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codey Smart Library Picker&lt;/td&gt;
&lt;td&gt;"DFPlayer Mini" mentioned in prompt&lt;/td&gt;
&lt;td&gt;Automatically includes DFRobotDFPlayerMini.h and the correct library&lt;/td&gt;
&lt;td&gt;Code that compiles first time with correct API calls&lt;/td&gt;
&lt;td&gt;You — no library hunting required&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Components 🔧
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Yoda examines the DFPlayer Mini with one ear raised.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "A small board. Powerful it is. Speaks the language of MP3, it does. Talks to the ESP32 through UART, it does. Patient with the timing, you must be — 200 milliseconds after power-on, it needs."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ESP32-S3 N16R8&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Our brain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DFPlayer Mini&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;MP3/WAV player module, 3V3–5V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speaker (4Ω or 8Ω, 0.5W–3W)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Connect directly to DFPlayer SPK1/SPK2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;microSD card (≤32GB)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Format FAT32, files named 0001.mp3 etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1kΩ resistor&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;On DFPlayer RX line — prevents voltage noise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10µF capacitor (electrolytic)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Between DFPlayer VCC and GND — power filtering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jumper wires&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Preparing the microSD Card
&lt;/h3&gt;

&lt;p&gt;Format your microSD as FAT32. Create a folder called &lt;code&gt;mp3&lt;/code&gt; at the root. Name your files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/mp3/
  0001.mp3  ← R2-D2 "happy" whistle sequence
  0002.mp3  ← R2-D2 "alert" rapid beeps
  0003.mp3  ← R2-D2 "sad" descending moan
  0004.mp3  ← R2-D2 "question" rising whistle
  0005.mp3  ← R2-D2 "startup" fanfare
  0006.mp3  ← R2-D2 "motion detected" warble
  0007.mp3  ← R2-D2 "danger close" urgent alarm

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "I would suggest downloading these from any reputable Star Wars sound effects collection. The DFPlayer cares only about the filenames — it does not evaluate artistic merit."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps indignantly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "I am sure your sounds are excellent, Artoo."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Codey Prompt 🎙️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Luke sits at the keyboard.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "I love how this works now. I just describe what I want and Codey handles the library, the setup, all of it."&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Agent mode&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We're continuing R2-D2 on ESP32-S3 N16R8.

Add a DFPlayer Mini MP3 module for R2-D2 voice responses:
  - DFPlayer connected to ESP32-S3 UART2
  - TX2 = GPIO17 → DFPlayer RX (through 1kΩ resistor)
  - RX2 = GPIO16 ← DFPlayer TX
  - DFPlayer powered from L298N 5V rail
  - 10µF capacitor across DFPlayer VCC/GND
  - Speaker connected to DFPlayer SPK1 and SPK2 (no extra amp needed)

Sound file mapping on microSD (/mp3/ folder):
  1 = R2 happy whistle (play when idle, randomly every 30-60 seconds)
  2 = R2 alert beeps (play when object &amp;lt; 30cm)
  3 = R2 sad moan (play when object &amp;lt; 15cm, stuck)
  4 = R2 question whistle (play when motion first detected)
  5 = R2 startup fanfare (play once on boot)
  6 = R2 motion warble (sustained during motion-scan state)
  7 = R2 danger alarm (play when object &amp;lt; 15cm, loop until clear)

Remove the piezo buzzer — DFPlayer replaces it.
Create voice.h for all audio functions.
Use DFRobotDFPlayerMini library.
The DFPlayer needs 200ms settle time after Serial2.begin() before commands.
Show Serial Monitor output for all sound triggers at 115200 baud.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Codey's Smart Library Picker Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt; &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;DFRobotDFPlayerMini&lt;/span&gt; &lt;span class="n"&gt;library&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;DFPlayer&lt;/span&gt; &lt;span class="n"&gt;Mini&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;This&lt;/span&gt; &lt;span class="n"&gt;library&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;installed&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;Codey&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="n"&gt;servers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;ll&lt;/span&gt; &lt;span class="n"&gt;include&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;DFRobotDFPlayerMini.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;And&lt;/span&gt; &lt;span class="n"&gt;use&lt;/span&gt; &lt;span class="n"&gt;Serial2&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;ESP32&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;S3&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;DFPlayer&lt;/span&gt; &lt;span class="n"&gt;communication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="n"&gt;Serial2&lt;/span&gt; &lt;span class="n"&gt;on&lt;/span&gt; &lt;span class="n"&gt;ESP32&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;S3&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;RX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GPIO16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;GPIO17&lt;/span&gt; &lt;span class="n"&gt;by&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="n"&gt;Generating&lt;/span&gt; &lt;span class="n"&gt;voice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generated &lt;code&gt;voice.h&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// voice.h — R2-D2 Voice System&lt;/span&gt;
&lt;span class="c1"&gt;// DFPlayer Mini on ESP32-S3 UART2 (TX=GPIO17, RX=GPIO16)&lt;/span&gt;
&lt;span class="c1"&gt;// microSD: /mp3/0001.mp3 through 0007.mp3&lt;/span&gt;

&lt;span class="cp"&gt;#pragma once
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;DFRobotDFPlayerMini.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// ── DFPlayer setup ───────────────────────────────────────────────&lt;/span&gt;
&lt;span class="n"&gt;DFRobotDFPlayerMini&lt;/span&gt; &lt;span class="n"&gt;dfPlayer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;dfPlayerReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Sound IDs (match filenames on microSD) ───────────────────────&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;R2Sound&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;SOUND_HAPPY&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SOUND_ALERT&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SOUND_SAD&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SOUND_QUESTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SOUND_STARTUP&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SOUND_MOTION&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;SOUND_DANGER&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// ── Random idle chatter timing ───────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;nextIdleChatterMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;CHATTER_MIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30000UL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// 30 seconds&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;CHATTER_MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60000UL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// 60 seconds&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;scheduleNextChatter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;nextIdleChatterMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;CHATTER_MIN&lt;/span&gt;
    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CHATTER_MAX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;CHATTER_MIN&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Initialise DFPlayer ──────────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;initVoice&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ESP32-S3 UART2: RX=GPIO16, TX=GPIO17&lt;/span&gt;
  &lt;span class="n"&gt;Serial2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERIAL_8N1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// DFPlayer needs 200ms to settle after Serial begin&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;dfPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Serial2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/*isACK=*/&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/*doReset=*/&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DFPlayer Mini not detected — check wiring!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  • Is the microSD inserted?"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  • Is the 1kΩ resistor on the DFPlayer RX line?"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  • Is VCC on the 5V rail?"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;dfPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// 0–30 (25 = ~83% volume — plenty for a droid)&lt;/span&gt;
  &lt;span class="n"&gt;dfPlayerReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DFPlayer Mini online! R2-D2 voice system ready."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Play startup fanfare&lt;/span&gt;
  &lt;span class="n"&gt;playSound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SOUND_STARTUP&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;scheduleNextChatter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Play a sound ─────────────────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;playSound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;R2Sound&lt;/span&gt; &lt;span class="n"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;dfPlayerReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;dfPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R2-D2 says: [sound "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"]"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Stop current playback ────────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stopSound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;dfPlayerReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;dfPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Update: called every loop — handles idle chatter ────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateVoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DomeState&lt;/span&gt; &lt;span class="n"&gt;domeState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;dfPlayerReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// DFPlayer print errors to Serial — check occasionally&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dfPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dfPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readType&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;     &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dfPlayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;DFPlayerError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DFPlayer error: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Danger: object very close&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;dangerPlaying&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;dangerPlaying&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;playSound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SOUND_DANGER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;dangerPlaying&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;dangerPlaying&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dangerPlaying&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;stopSound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="n"&gt;dangerPlaying&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Alert zone: approaching&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastAlertMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastAlertMs&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;playSound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SOUND_ALERT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;lastAlertMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Motion: play question on first detection&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;motionSoundPlayed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;motionSoundPlayed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;playSound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SOUND_QUESTION&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;motionSoundPlayed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;motionSoundPlayed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;motionSoundPlayed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Idle chatter: random happy whistle&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;nextIdleChatterMs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;playSound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SOUND_HAPPY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;scheduleNextChatter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initVoiceSystem&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;randomSeed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;esp_random&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;  &lt;span class="c1"&gt;// True random seed from ESP32 hardware RNG&lt;/span&gt;
  &lt;span class="n"&gt;initVoice&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updated &lt;code&gt;r2d2-main.ino&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Adafruit_NeoPixel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"sounds.h"&lt;/span&gt;&lt;span class="c1"&gt;      // LEDC buzzer (backup only, mostly replaced)&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"animations.h"&lt;/span&gt;&lt;span class="c1"&gt;  // NeoPixel dome&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"sensors.h"&lt;/span&gt;&lt;span class="c1"&gt;     // HC-SR04 + PIR&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"display.h"&lt;/span&gt;&lt;span class="c1"&gt;     // SSD1306 OLED&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"motion.h"&lt;/span&gt;&lt;span class="c1"&gt;      // Servo + motors&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"voice.h"&lt;/span&gt;&lt;span class="c1"&gt;       // DFPlayer Mini&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;115200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"═══════════════════════════════"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"  R2-D2 ESP32-S3 Boot Sequence"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"═══════════════════════════════"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;initSounds&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initAnimations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initSensors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initDisplay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initMotion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initVoiceSystem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// ← new&lt;/span&gt;

  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All systems ONLINE. R2-D2 is ready."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;bootDone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;showBootScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readDistance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt;  &lt;span class="n"&gt;motion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checkMotion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Motion (dome + wheels) ──────────────────────────────────&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;domeSnap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;motorStop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;domeSnap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;domeIdleSweep&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Display ─────────────────────────────────────────────────&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;showAlertScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;showMotionScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;                 &lt;span class="nf"&gt;showIdleScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Dome lights ─────────────────────────────────────────────&lt;/span&gt;
  &lt;span class="n"&gt;updateAnimationsSensors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Voice ────────────────────────────────────────────────────&lt;/span&gt;
  &lt;span class="n"&gt;updateVoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wiring Diagram — Adding the Voice Module 🧭
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO presents the updated diagram with a satisfied nod.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "The DFPlayer Mini connects to UART2 on the ESP32-S3. Note the 1kΩ resistor on the RX line of the DFPlayer — this prevents communication noise that can cause the module to behave erratically. I am noting this specifically because I have personally witnessed the consequences of omitting it, and it is not pleasant."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R2-D2 Voice System Addition — ESP32-S3 N16R8
════════════════════════════════════════════════════════════

DFPLAYER MINI CONNECTIONS:
  L298N 5V      ──── DFPlayer VCC
  L298N 5V      ──── 10µF cap + (filter)
  GND           ──── DFPlayer GND + 10µF cap −
  ESP32 GPIO17  ──── (1kΩ) ──── DFPlayer RX
  DFPlayer TX   ──── ESP32 GPIO16
  DFPlayer SPK1 ──── Speaker terminal 1
  DFPlayer SPK2 ──── Speaker terminal 2

MicroSD Card:
  Inserted directly into DFPlayer Mini SD slot
  Formatted FAT32, files in /mp3/ folder

Color code (additions):
  PINK   = DFPlayer TX (audio data from module)
  CYAN   = DFPlayer RX (commands to module)
  GREY   = Through 1kΩ resistor on DFPlayer RX

Connection Table (additions):
┌──────────────────────┬──────────────────────────────────┐
│ From                 │ To                               │
├──────────────────────┼──────────────────────────────────┤
│ L298N 5V             │ DFPlayer VCC                     │
│ L298N 5V             │ 10µF cap: + (long leg)           │
│ GND (common)         │ DFPlayer GND + 10µF cap: −       │
│ ESP32 GPIO17 (TX2)   │ 1kΩ resistor → DFPlayer RX       │
│ DFPlayer TX          │ ESP32 GPIO16 (RX2)               │
│ DFPlayer SPK1        │ Speaker terminal 1               │
│ DFPlayer SPK2        │ Speaker terminal 2               │
└──────────────────────┴──────────────────────────────────┘

⚡ Notes:
  - DFPlayer powered from 5V — DO NOT use ESP32 3V3 (insufficient current)
  - 1kΩ resistor on DFPlayer RX is mandatory — prevents communication errors
  - Speaker: 4Ω or 8Ω, 0.5W minimum — DFPlayer can drive it directly
  - MicroSD must be FAT32, files named 0001.mp3–0007.mp3 in /mp3/ folder

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Live Serial Monitor — Watching R2 Think 📟
&lt;/h2&gt;

&lt;p&gt;After uploading, open Codey's &lt;strong&gt;Live Serial Monitor&lt;/strong&gt; at &lt;strong&gt;115200 baud&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As R2 runs:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Serial Monitor — 115200 baud
─────────────────────────────────────────────────────────
═══════════════════════════════
  R2-D2 ESP32-S3 Boot Sequence
═══════════════════════════════
OLED projector online!
Dome servo centred.
Motor driver online.
DFPlayer Mini online! R2-D2 voice system ready.
R2-D2 says: [sound 5]        ← Startup fanfare!
All systems ONLINE. R2-D2 is ready.

Distance: 124 cm — SAFE
Distance: 119 cm — SAFE
R2-D2 says: [sound 1]        ← Idle chatter (random)
Motion detected — scan mode!
R2-D2 says: [sound 4]        ← Question whistle
State → SCAN
Distance: 28 cm — CAUTION
R2-D2 says: [sound 2]        ← Alert!
Distance: 12 cm — DANGER
R2-D2 says: [sound 7]        ← Danger alarm!
State → ALERT
Distance: 85 cm — SAFE       ← Object moved away

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Look at that. Every event logged. Every sound triggered. You can see exactly what he's thinking. That's not just a droid — that's a droid with a diary."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps something that sounds like "I would prefer more privacy, actually."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile and Upload 🚀
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Compilation successful
  Board:   ESP32-S3 N16R8
  Sketch:  r2d2-main.ino + 6 headers
  Binary:  554,768 bytes (8.0% of 16MB Flash)
  RAM:     Used 41,240 bytes (12.6% of 327KB)
  PSRAM:   7.9 MB free — plenty for Episode 8 additions

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The ESP32-S3 boots. The OLED displays "R2-D2 ONLINE." The dome LEDs breathe blue-white. The dome servo sweeps gently.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then — from the speaker — a clear, unmistakable R2-D2 startup whistle.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; &lt;em&gt;quietly&lt;/em&gt; "...Oh my."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 — the real one — goes completely silent. Then a single, emotional beep.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "He recognises it. He recognises his own voice."&lt;/p&gt;

&lt;h2&gt;
  
  
  Save Milestone 🚩
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Milestone: "R2-D2 Voice System — Episode 7 Complete"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Six systems. All running. All talking to each other. R2-D2 has lights, sound, a display, sensors, motion, and a voice. There is one episode left.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: The Complete Droid 🤖
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The entire Star Wars crew assembles in the workshop. Han. Luke. Obi-Wan. C-3PO. And there, in the centre — R2-D2, all systems operational, blue dome glowing, OLED projecting status, dome rotating in a gentle scan, audio clips playing softly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Obi-Wan speaks.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "In the final episode, we bring every system together into a single, cohesive, complete R2-D2. We explore the ESP32-S3's Wi-Fi capabilities. We use Codey's Deep Think mode for the most complex orchestration code. We draw the final complete wiring diagram — every component, every wire, every protection circuit. And we save the last milestone. The droid is nearly complete."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 plays sound 1: his happy whistle.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Everyone smiles.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DFRobotDFPlayerMini library&lt;/strong&gt;: &lt;a href="https://github.com/DFRobot/DFRobotDFPlayerMini" rel="noopener noreferrer"&gt;github.com/DFRobot/DFRobotDFPlayerMini&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESP32-S3 UART&lt;/strong&gt;: &lt;a href="https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/uart.html" rel="noopener noreferrer"&gt;docs.espressif.com/esp32-s3/uart&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codey Live Serial Monitor&lt;/strong&gt;: &lt;a href="http://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;🤖 R2D2 Creation with Codey — building the galaxy's greatest droid, one episode at a time. May the Force — and the cloud compiler — be with you.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>esp32</category>
      <category>audio</category>
      <category>dfplayer</category>
      <category>makers</category>
    </item>
    <item>
      <title>R2D2 Creation with Codey 🤖 Ep.6</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:13:56 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep6-313o</link>
      <guid>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep6-313o</guid>
      <description>&lt;h2&gt;
  
  
  Episode 6: Let the Wookiee Win — R2 Moves!
&lt;/h2&gt;

&lt;h2&gt;
  
  
  "Would Somebody Get This Big Walking Carpet Out of My Way?" 🦾
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo enters the workshop with the energy of someone who has been waiting since Episode 1 for this moment.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Okay, look. I've put up with the blinking LED. The beeps were cute. The screen — fine, useful. But I need this droid to actually MOVE. Because right now he's sitting there like a very opinionated lamp and I am not impressed."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps at high volume and at length.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Yeah yeah, I know, you're very capable. Prove it. Episode 6. Let's go."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Somewhere, a Wookiee roars enthusiastically.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Chewie agrees. Let the droid move."&lt;/p&gt;

&lt;h2&gt;
  
  
  🗂️ SIPOC — The Motion System
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suppliers&lt;/th&gt;
&lt;th&gt;Inputs&lt;/th&gt;
&lt;th&gt;Process&lt;/th&gt;
&lt;th&gt;Outputs&lt;/th&gt;
&lt;th&gt;Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You (the maker)&lt;/td&gt;
&lt;td&gt;"Add servo for dome rotation on GPIO14, L298N motor driver for wheels on GPIO pins 25-27"&lt;/td&gt;
&lt;td&gt;Codey writes ESP32-S3 LEDC servo code + L298N motor control, generates motion.h&lt;/td&gt;
&lt;td&gt;Dome that sweeps left and right, wheels that drive forward/back/turn&lt;/td&gt;
&lt;td&gt;R2-D2 — who finally lives up to his reputation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ESP32-S3 LEDC PWM&lt;/td&gt;
&lt;td&gt;50Hz PWM signal, 3.3V&lt;/td&gt;
&lt;td&gt;Drives servo signal line (with level shifter)&lt;/td&gt;
&lt;td&gt;Dome servo at 0°, 45°, 90°, 135°, 180°&lt;/td&gt;
&lt;td&gt;SG90 servo — which rotates R2's dome&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L298N Motor Driver&lt;/td&gt;
&lt;td&gt;5V–12V external power, direction + PWM signals from ESP32-S3&lt;/td&gt;
&lt;td&gt;H-bridge controls current direction to each DC motor&lt;/td&gt;
&lt;td&gt;Forward / backward / left turn / right turn&lt;/td&gt;
&lt;td&gt;Two DC motors — which drive R2's wheels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codey Wiring Diagram&lt;/td&gt;
&lt;td&gt;Full component list including motor power requirements&lt;/td&gt;
&lt;td&gt;Draws color-coded diagram with separate power rail for motors&lt;/td&gt;
&lt;td&gt;Two-rail wiring diagram: logic (3.3V) + motor power&lt;/td&gt;
&lt;td&gt;You — who correctly separate the motor power from the logic power&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Components 🔧
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Yoda examines the motor driver with a long, thoughtful look.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Moving parts, added today we are. Careful, one must be. Motors, hungry for current they are. Directly from the ESP32-S3, power them you must not — destroyed, your microcontroller would be."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ESP32-S3 N16R8&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Our brain from Episode 5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SG90 micro servo&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;For dome rotation — 5V, 3-wire&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L298N dual H-bridge motor driver&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Drives two DC motors, needs separate 5V–12V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DC gear motors with wheels&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3V–6V, ~200mA stall current each&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;74AHCT125 level shifter&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Servo signal: 3.3V → 5V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9V battery or 2S LiPo&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Motor power supply — separate from logic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jumper wires&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Several gauge sizes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB cable&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Two power rails, we shall have. Logic power: USB 5V → 3.3V for ESP32-S3. Motor power: separate battery for L298N and motors. Cross them, you must not."&lt;/p&gt;

&lt;h2&gt;
  
  
  The ESP32-S3 and Servo Control: LEDC at 50Hz ⚙️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO raises a cautionary finger.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "I must explain the servo PWM situation. The Arduino Servo library used the Timer1 hardware. On the ESP32-S3, we use the LEDC peripheral — the same one we used for the buzzer tone in Episode 5, but configured at 50Hz for servo control. A standard hobby servo expects a pulse between 0.5ms and 2.5ms at a 50Hz frequency. Codey handles this calculation automatically."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Three-PO. The servo. Just the servo."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Yes. Moving on."&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Agent mode&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We're continuing R2-D2 on ESP32-S3 N16R8.

Add motion systems:

1. SG90 servo for dome rotation:
   - Signal on GPIO14 (through 74AHCT125 level shifter)
   - 5V power from VIN rail
   - Create these movements:
     a. idle_scan: slow sweep 60°→120° and back, 3 second period
     b. alert_snap: snap to face sensor direction
     c. full_sweep: 0° to 180° and back when "happy"

2. L298N motor driver for two DC wheels:
   - Motor A: IN1=GPIO25, IN2=GPIO26, ENA=GPIO27 (PWM)
   - Motor B: IN3=GPIO32, IN4=GPIO33, ENB=GPIO34 (PWM)
   - Create: forward(), backward(), turnLeft(), turnRight(), stop()
   - Speed: 0-255 mapped to LEDC duty cycle

3. Behavior: when distance &amp;lt; 30cm → stop + snap dome toward sensor
   When motion detected → sweep dome toward source

Create motion.h file for all motion code.
Keep existing animations.h, sensors.h, display.h, sounds.h unchanged.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generated &lt;code&gt;motion.h&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// motion.h — R2-D2 Motion System&lt;/span&gt;
&lt;span class="c1"&gt;// Dome servo + DC wheel motors via L298N&lt;/span&gt;
&lt;span class="c1"&gt;// ESP32-S3 N16R8&lt;/span&gt;

&lt;span class="cp"&gt;#pragma once
&lt;/span&gt;
&lt;span class="c1"&gt;// ── SERVO (dome rotation) ────────────────────────────────────────&lt;/span&gt;
&lt;span class="cp"&gt;#define SERVO_PIN     14     // GPIO14 — through 74AHCT125 to servo
#define SERVO_CHANNEL 1      // LEDC channel (channel 0 used by buzzer)
&lt;/span&gt;
&lt;span class="c1"&gt;// Servo pulse widths in microseconds&lt;/span&gt;
&lt;span class="cp"&gt;#define SERVO_MIN_US  500    // 0°
#define SERVO_MID_US  1500   // 90° (centre)
#define SERVO_MAX_US  2500   // 180°
&lt;/span&gt;
&lt;span class="c1"&gt;// LEDC config for servo: 50Hz, 16-bit resolution (allows fine pulse control)&lt;/span&gt;
&lt;span class="cp"&gt;#define SERVO_FREQ    50
#define SERVO_RES     16     // 16-bit → 0–65535
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;currentDomeAngle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// Start centred&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;targetDomeAngle&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;domeSweepDir&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// +1 or -1 for idle sweep&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastServoMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initServo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ledcSetup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SERVO_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVO_FREQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVO_RES&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcAttachPin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SERVO_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVO_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Centre the dome on startup&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pulse&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVO_MIN_US&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVO_MAX_US&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;duty&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pulse&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;20000.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;65535.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SERVO_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Dome servo centred."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setDomeAngle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;constrain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pulse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVO_MIN_US&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SERVO_MAX_US&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;duty&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;pulse&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;20000.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;65535.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SERVO_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;duty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;currentDomeAngle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Idle: slow sweep 60° ↔ 120°&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;domeIdleSweep&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastServoMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;lastServoMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;currentDomeAngle&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;domeSweepDir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentDomeAngle&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;domeSweepDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentDomeAngle&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="n"&gt;domeSweepDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;setDomeAngle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentDomeAngle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Snap to angle quickly (alert behaviour)&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;domeSnap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;setDomeAngle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Full sweep 0°→180°→0° (happy behaviour)&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;fullSweepMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;   &lt;span class="n"&gt;fullSweepAngle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;   &lt;span class="n"&gt;fullSweepDir&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt;  &lt;span class="n"&gt;fullSweepDone&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;domeSweepFull&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;fullSweepMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;fullSweepMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;fullSweepAngle&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;fullSweepDir&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fullSweepAngle&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;fullSweepDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fullSweepAngle&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;fullSweepDone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;setDomeAngle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fullSweepAngle&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── L298N MOTOR DRIVER ────────────────────────────────────────────&lt;/span&gt;
&lt;span class="cp"&gt;#define MOTOR_A_IN1  25
#define MOTOR_A_IN2  26
#define MOTOR_A_EN   27   // PWM channel 2
&lt;/span&gt;
&lt;span class="cp"&gt;#define MOTOR_B_IN3  32
#define MOTOR_B_IN4  33
#define MOTOR_B_EN   34   // PWM channel 3
&lt;/span&gt;
&lt;span class="cp"&gt;#define MOTOR_CHANNEL_A  2
#define MOTOR_CHANNEL_B  3
#define MOTOR_FREQ       5000   // 5kHz PWM for motors
#define MOTOR_RES        8      // 8-bit → 0–255
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initMotors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Direction pins&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// PWM channels for enable pins&lt;/span&gt;
  &lt;span class="n"&gt;ledcSetup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MOTOR_FREQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MOTOR_RES&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcSetup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MOTOR_FREQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MOTOR_RES&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcAttachPin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_EN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MOTOR_CHANNEL_A&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcAttachPin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_EN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MOTOR_CHANNEL_B&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Start stopped&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Motor driver online."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;motorForward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;motorBackward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;motorTurnLeft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Left motor backward, right motor forward = left turn&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;motorTurnRight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Left motor forward, right motor backward = right turn&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;motorStop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_CHANNEL_B&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_A_IN2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MOTOR_B_IN4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initMotion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;initServo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initMotors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updated &lt;code&gt;r2d2-main.ino&lt;/code&gt; loop
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Loop addition — reactive motion&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;bootDone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;showBootScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readDistance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt;  &lt;span class="n"&gt;motion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checkMotion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Dome behaviour ─────────────────────────────────────────&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;domeSnap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// face forward, something is ahead&lt;/span&gt;
    &lt;span class="n"&gt;motorStop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;        &lt;span class="c1"&gt;// stop wheels — obstacle!&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;domeSnap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// snap left — motion detected&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;domeIdleSweep&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;    &lt;span class="c1"&gt;// gentle idle scan&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Display ─────────────────────────────────────────────────&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="n"&gt;showAlertScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="n"&gt;showMotionScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;                 &lt;span class="nf"&gt;showIdleScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Dome lights ─────────────────────────────────────────────&lt;/span&gt;
  &lt;span class="n"&gt;updateAnimationsSensors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Wiring Diagram — Two Power Rails 🧭
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO studies the diagram, then exhales slowly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Codey has correctly separated the power rails. The logic rail — 3.3V from the ESP32-S3 regulator — powers only the microcontroller and the OLED. The motor rail — the external 9V battery through the L298N's onboard 5V regulator — powers the motors and the servo. This is exactly correct. Mixing them would cause voltage drops that would reset the ESP32-S3 every time a motor starts."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R2-D2 Motion System — Wiring Diagram (ESP32-S3 N16R8)
════════════════════════════════════════════════════════════════

POWER RAIL 1 — LOGIC (USB 5V → ESP32-S3 regulator):
  USB 5V  ──── ESP32-S3 VIN
  ESP32 3V3 ── OLED VCC
  ESP32 GND ── OLED GND, logic GND rail

POWER RAIL 2 — MOTOR POWER (9V battery):
  9V Bat (+) ── L298N: VS (motor supply)
  9V Bat (−) ── L298N: GND (common ground with ESP32 GND)
  L298N: 5V  ── Servo VCC (5V regulated output)
  L298N: 5V  ── 74AHCT125: VCC
  L298N: GND ── Servo GND, 74AHCT125 GND

  ⚠️  IMPORTANT: ESP32 GND and battery GND must be connected together!

SERVO (dome rotation):
  ESP32 GPIO14 ─── 74AHCT125 A1 input (3.3V signal in)
  74AHCT125 Y1 ─── Servo Signal wire (orange/yellow) — 5V signal out
  L298N 5V     ─── Servo VCC (red wire)
  L298N GND    ─── Servo GND (brown/black wire)

MOTORS via L298N:
  ESP32 GPIO25 ──── L298N IN1 (Motor A direction)
  ESP32 GPIO26 ──── L298N IN2 (Motor A direction)
  ESP32 GPIO27 ──── L298N ENA (Motor A PWM speed)
  ESP32 GPIO32 ──── L298N IN3 (Motor B direction)
  ESP32 GPIO33 ──── L298N IN4 (Motor B direction)
  ESP32 GPIO34 ──── L298N ENB (Motor B PWM speed)
  L298N OUT1   ──── DC Motor A: terminal 1
  L298N OUT2   ──── DC Motor A: terminal 2
  L298N OUT3   ──── DC Motor B: terminal 1
  L298N OUT4   ──── DC Motor B: terminal 2

NeoPixel (from Episode 5):
  ESP32 GPIO6 ── 74AHCT125 A2 ── NeoPixel DIN

Color code:
  RED    = 5V / VIN power
  ORANGE = 9V battery supply
  BLACK  = GND
  PURPLE = 3.3V logic
  GREEN  = NeoPixel data (level-shifted)
  BLUE   = Servo signal (level-shifted)
  YELLOW = Motor direction signals
  WHITE  = Motor PWM (speed) signals

Connection Table:
┌──────────────────────┬──────────────────────────────────────┐
│ From                 │ To                                   │
├──────────────────────┼──────────────────────────────────────┤
│ 9V Battery (+)       │ L298N: VS                            │
│ 9V Battery (−)       │ L298N: GND + ESP32 GND (common)      │
│ L298N: 5V out        │ Servo VCC (red), 74AHCT125 VCC       │
│ L298N: GND           │ Servo GND, 74AHCT125 GND             │
│ ESP32 GPIO14         │ 74AHCT125 A1 → servo signal (5V)     │
│ ESP32 GPIO6          │ 74AHCT125 A2 → NeoPixel DIN (5V)     │
│ ESP32 GPIO25         │ L298N IN1                            │
│ ESP32 GPIO26         │ L298N IN2                            │
│ ESP32 GPIO27 (PWM)   │ L298N ENA                            │
│ ESP32 GPIO32         │ L298N IN3                            │
│ ESP32 GPIO33         │ L298N IN4                            │
│ ESP32 GPIO34 (PWM)   │ L298N ENB                            │
│ L298N OUT1,OUT2      │ DC Motor A                           │
│ L298N OUT3,OUT4      │ DC Motor B                           │
└──────────────────────┴──────────────────────────────────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Two power rails. That's important. I've seen people blow a microcontroller trying to power motors directly off the GPIO pins. The L298N's internal regulator gives you the 5V for the servo and the level shifter. Clean."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps approvingly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Yeah, even I have to admit that's well done."&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile and Watch the Dome Spin 🚀
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;✓ Compilation successful
  Board:   ESP32-S3 N16R8
  Sketch:  r2d2-main.ino + 5 headers
  Binary:  498,244 bytes (7.2% of 16MB Flash)
  RAM:     Used 34,128 bytes (10.4% of 327KB)

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dome servo sweeps slowly between 60° and 120°. R2-D2 scans the room.&lt;/p&gt;

&lt;p&gt;Wave your hand in front of the HC-SR04. The dome snaps to 90°. The wheels stop. The OLED shows "TOO CLOSE!"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Han Solo watches the dome turn. A long pause.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "...Okay. That's actually pretty good."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "I said it was &lt;em&gt;pretty&lt;/em&gt; good. Don't push it."&lt;/p&gt;

&lt;h2&gt;
  
  
  Save Milestone 🚩
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Milestone: "R2-D2 Motion Systems — Episode 6 Complete"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Five systems running. Dome rotating. Wheels ready. The droid is almost complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: R2 Gets His Voice Back 🔊
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Obi-Wan speaks with warmth.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "The dome spins. The lights glow. The screen projects. The wheels wait. But something is still missing — the true voice. Not just beeps from a buzzer, but the full audio character of the galaxy's most beloved droid. In Episode 7, we add the DFPlayer Mini and a speaker. R2-D2 will play actual audio files. And the Live Serial Monitor will show us exactly what is happening."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 emits a long, heartfelt whistle that says everything.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ESP32 LEDC (servo)&lt;/strong&gt;: &lt;a href="https://randomnerdtutorials.com/esp32-servo-motor-web-server-arduino-ide/" rel="noopener noreferrer"&gt;randomnerdtutorials.com/esp32-servo-motor-web-server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L298N motor driver&lt;/strong&gt;: Search "L298N Arduino ESP32 tutorial"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;74AHCT125 level shifter&lt;/strong&gt;: Search "74AHCT125 3.3V 5V logic level converter"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codey Online&lt;/strong&gt;: &lt;a href="http://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;🤖 R2D2 Creation with Codey — building the galaxy's greatest droid, one episode at a time. May the Force — and the cloud compiler — be with you.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>esp32</category>
      <category>servo</category>
      <category>motors</category>
      <category>makers</category>
    </item>
    <item>
      <title>R2D2 Creation with Codey 🤖 Ep.5</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:13:46 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep5-609</link>
      <guid>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep5-609</guid>
      <description>&lt;h2&gt;
  
  
  Episode 5: The Projector of Hope
&lt;/h2&gt;

&lt;h2&gt;
  
  
  "Help Me, Codey Online — You're My Only Hope" 📽️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The workshop is quiet. R2-D2 sits in the corner, dome LEDs softly breathing their blue-white rhythm. Then, suddenly — a holographic projection flickers from somewhere inside his chassis. Princess Leia. Eighteen centimetres tall. Looping silently.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Luke stares.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "That's what I want. That's exactly what I want. An OLED screen mounted in his dome, showing status messages, projecting text like a mission briefing. Something that makes him feel... alive."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps with the energy of someone who has been waiting patiently for this episode.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "But Obi-Wan said something about upgrading the brain first. Moving to a bigger board."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Obi-Wan's voice arrives like dawn.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "The Arduino UNO served us well through four episodes, young one. But what lies ahead — the motion systems, the voice responses, the wireless capabilities — these require a more powerful foundation. It is time to meet the ESP32-S3 N16R8."&lt;/p&gt;

&lt;h2&gt;
  
  
  🗂️ SIPOC — The Great Upgrade
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suppliers&lt;/th&gt;
&lt;th&gt;Inputs&lt;/th&gt;
&lt;th&gt;Process&lt;/th&gt;
&lt;th&gt;Outputs&lt;/th&gt;
&lt;th&gt;Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You (the maker)&lt;/td&gt;
&lt;td&gt;"Migrate to ESP32-S3 N16R8 and add SSD1306 OLED via I2C"&lt;/td&gt;
&lt;td&gt;Codey recognises the new board, updates pin mappings, rewrites I2C addresses, flags 3.3V implications&lt;/td&gt;
&lt;td&gt;Correct ESP32-S3 firmware with Adafruit_SSD1306, new I2C pins&lt;/td&gt;
&lt;td&gt;ESP32-S3 N16R8 — which drives the OLED and all previous systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codey Voltage Safety Check&lt;/td&gt;
&lt;td&gt;NeoPixel (5V logic), OLED (3.3V or 5V), HC-SR04 (5V) vs ESP32-S3 (3.3V GPIO)&lt;/td&gt;
&lt;td&gt;Cross-references component voltage requirements with ESP32-S3 GPIO levels&lt;/td&gt;
&lt;td&gt;Specific warnings per component + recommended level shifter or workarounds&lt;/td&gt;
&lt;td&gt;You — who avoid smoke on this far more expensive board&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSD1306 OLED (128×64)&lt;/td&gt;
&lt;td&gt;3.3V power, I2C (SDA/SCL)&lt;/td&gt;
&lt;td&gt;Receives display commands over I2C protocol&lt;/td&gt;
&lt;td&gt;A crisp 128×64 pixel display showing R2 status and messages&lt;/td&gt;
&lt;td&gt;R2-D2's dome — the holographic projection system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Milestones &amp;amp; Rollback&lt;/td&gt;
&lt;td&gt;Previous working code at Episode 4 milestone&lt;/td&gt;
&lt;td&gt;One-click restore of code + chat history&lt;/td&gt;
&lt;td&gt;Known-good state if the board migration causes issues&lt;/td&gt;
&lt;td&gt;You — who can always go back&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Meet the New Brain: ESP32-S3 N16R8 🧠
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO emerges carrying a padded case like it contains the Holy Grail.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "The ESP32-S3 N16R8. I have computed its specifications forty-seven times. Allow me to translate from technical to comprehensible:"&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;ESP32-S3 N16R8&lt;/th&gt;
&lt;th&gt;Arduino UNO R3&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Processor&lt;/td&gt;
&lt;td&gt;Dual-core Xtensa LX7 @ 240 MHz&lt;/td&gt;
&lt;td&gt;Single-core ATmega328P @ 16 MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flash storage&lt;/td&gt;
&lt;td&gt;16 MB&lt;/td&gt;
&lt;td&gt;32 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PSRAM&lt;/td&gt;
&lt;td&gt;8 MB&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPIO pins&lt;/td&gt;
&lt;td&gt;45&lt;/td&gt;
&lt;td&gt;14 digital&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logic voltage&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;td&gt;5V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wi-Fi&lt;/td&gt;
&lt;td&gt;Yes (802.11b/g/n)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bluetooth&lt;/td&gt;
&lt;td&gt;Yes (BLE 5.0 + Classic)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB&lt;/td&gt;
&lt;td&gt;Native USB-CDC (two ports!)&lt;/td&gt;
&lt;td&gt;USB via CH340/FTDI chip&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PWM&lt;/td&gt;
&lt;td&gt;LEDC — 8 channels, 14-bit resolution&lt;/td&gt;
&lt;td&gt;6 PWM pins, 8-bit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DAC&lt;/td&gt;
&lt;td&gt;2× 8-bit DAC outputs&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Considerably more capable. However — and I cannot stress this strongly enough — the GPIO outputs are &lt;strong&gt;3.3V&lt;/strong&gt;, not 5V. Several of our existing components expect a 5V signal. This is a matter of the gravest concern and I intend to address each one individually."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps impatiently.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Artoo, voltage compatibility is NOT a detail. It is the difference between a functional droid and a very expensive doorstop."&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3.3V Migration: C-3PO's Component Review ⚡
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Darth Vader's voice rumbles through the ventilation system.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VADER:&lt;/strong&gt; "Your lack of a level shifter... disturbs me."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;C-3PO whirls around, then remembers where he is.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Quite. Let us review each component's voltage situation with the ESP32-S3:"&lt;/p&gt;

&lt;h3&gt;
  
  
  Component Voltage Compatibility Table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;VCC Needed&lt;/th&gt;
&lt;th&gt;Signal Level Needed&lt;/th&gt;
&lt;th&gt;ESP32-S3 GPIO (3.3V)&lt;/th&gt;
&lt;th&gt;Action Required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSD1306 OLED&lt;/td&gt;
&lt;td&gt;3.3V or 5V&lt;/td&gt;
&lt;td&gt;3.3V I2C&lt;/td&gt;
&lt;td&gt;✅ Compatible&lt;/td&gt;
&lt;td&gt;None — OLED runs perfectly on 3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Piezo Buzzer&lt;/td&gt;
&lt;td&gt;3.3V–5V&lt;/td&gt;
&lt;td&gt;3.3V PWM&lt;/td&gt;
&lt;td&gt;✅ Compatible&lt;/td&gt;
&lt;td&gt;None — works fine at 3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NeoPixel WS2812B&lt;/td&gt;
&lt;td&gt;5V&lt;/td&gt;
&lt;td&gt;5V data signal&lt;/td&gt;
&lt;td&gt;⚠️ Marginal&lt;/td&gt;
&lt;td&gt;Add 74AHCT125 level shifter OR use 470Ω + 3V3-to-5V shifter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HC-SR04&lt;/td&gt;
&lt;td&gt;5V&lt;/td&gt;
&lt;td&gt;5V ECHO output&lt;/td&gt;
&lt;td&gt;⚠️ Risky&lt;/td&gt;
&lt;td&gt;The ECHO pin outputs 5V — use voltage divider on ECHO&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PIR HC-SR501&lt;/td&gt;
&lt;td&gt;5V&lt;/td&gt;
&lt;td&gt;5V output&lt;/td&gt;
&lt;td&gt;⚠️ Risky&lt;/td&gt;
&lt;td&gt;Use voltage divider (10k + 20k) on output pin&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Codey will generate the level shifter and voltage divider circuits in the wiring diagram. This is precisely the scenario for which Codey's voltage safety checks were designed."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Codey, upon seeing the ESP32-S3 selected, automatically adds voltage warnings for each incompatible component in the project.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Selecting the New Board in Codey 🔄
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo demonstrates with the casual confidence of someone who has hot-swapped ship components mid-jump.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Simple. In your Codey project, click the board selector at the top. Change it from Arduino UNO R3 to ESP32-S3 N16R8. Done. Codey figures out the rest."&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;board name&lt;/strong&gt; dropdown at the top of the Codey interface&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;ESP32-S3 N16R8&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Codey immediately shows:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚠️  Board changed: Arduino UNO R3 → ESP32-S3 N16R8

This board uses 3.3V GPIO logic.
I've detected components in your project that may be affected:

  • NeoPixel WS2812B (pin 6): Needs level shifter — see updated wiring diagram
  • HC-SR04 (pins 9/10): ECHO pin outputs 5V — needs voltage divider
  • PIR HC-SR501 (pin 2): Output is 5V — needs voltage divider

  Recommended: Add 74AHCT125 (quad level shifter) for WS2812B data line.
  Piezo buzzer (pin 8): ✓ Compatible — no change needed.

Shall I update the code and wiring diagram for the ESP32-S3?

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;R2-D2 beeps enthusiastically: "YES."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "See? It flags everything. No surprises."&lt;/p&gt;

&lt;h2&gt;
  
  
  Before Moving On: Rolling Back If Needed 🚩
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Obi-Wan raises a steady hand.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "Before this migration, let us invoke the wisdom of Milestones. Our Episode 4 code runs perfectly on the Arduino UNO. If the ESP32-S3 migration encounters difficulty, we must be able to return to that known-good state."&lt;/p&gt;

&lt;p&gt;In Codey, click &lt;strong&gt;Milestones&lt;/strong&gt; → find &lt;strong&gt;"R2-D2 Sensor Eye — Episode 4 Complete"&lt;/strong&gt; → click &lt;strong&gt;Restore&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Both the code AND the chat history are restored to exactly how they were after Episode 4.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Now&lt;/em&gt; make a new milestone before starting the migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Milestone: "Pre-ESP32 Migration Checkpoint"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "The Force gives you wisdom to try. The Milestone gives you the courage to try boldly."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps something along the lines of "can we please just look at the OLED already."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompting Codey for the ESP32-S3 Migration + OLED 💬
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Plan mode&lt;/strong&gt; first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We're upgrading R2-D2's brain from Arduino UNO R3 to ESP32-S3 N16R8.

Existing systems to migrate:
  - Piezo buzzer on pin 8 → keep same pin, use LEDC channel instead of tone()
  - NeoPixel ring (12 LEDs) on pin 6 → keep pin, add note about 74AHCT125
  - HC-SR04 on pins 9/10 → keep pins, add voltage divider on ECHO
  - PIR sensor on pin 2 → keep pin, add voltage divider on output

New addition:
  - SSD1306 OLED 128x64 display via I2C
  - ESP32-S3 I2C default: SDA=GPIO8, SCL=GPIO9
  - Show these screens:
    1. Startup: "R2-D2 ONLINE" with a spinning animation
    2. Idle: distance reading + "SAFE" or "ALERT"
    3. Motion: "MOTION DETECTED" with exclamation marks
    4. Very close: "TOO CLOSE" with a blinking border

Show me the plan before writing any code.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Codey Plan Mode Response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R2-D2 ESP32-S3 Migration + Holographic Projector — Plan

FILES:
  r2d2-main.ino     — setup() and loop(), board init
  animations.h      — NeoPixel dome animations (migrated to ESP32)
  sensors.h         — HC-SR04 + PIR (voltage divider notes)
  display.h         — SSD1306 OLED functions (new)
  sounds.h          — LEDC-based tone functions (replaces tone() API)

KEY CHANGES:
  1. tone() → ledc functions (ESP32 uses LEDC peripheral for PWM)
     ledcSetup(0, 2637, 8) + ledcWrite(0, 128) replaces tone(pin, freq)

  2. I2C on ESP32-S3: Wire.begin(8, 9) for SDA=GPIO8, SCL=GPIO9
     (Adafruit_SSD1306 uses Wire automatically)

  3. NeoPixel: Same FastLED/NeoPixel API — ESP32-S3 natively supports
     RMT peripheral for WS2812B. Add 74AHCT125 recommendation in wiring.

  4. HC-SR04 ECHO: Add voltage divider (10kΩ + 20kΩ) to reduce 5V→3.3V
     TRIG output from ESP32-S3 (3.3V) is sufficient to trigger HC-SR04.

  5. PIR output: Add voltage divider (10kΩ + 20kΩ)

  DISPLAY STATES:
    • BOOT  — "R2-D2 ONLINE", spinner, 2 seconds
    • IDLE  — Distance + status, updates every 500ms
    • SCAN  — "MOTION DETECTED !!", large text
    • ALERT — "TOO CLOSE" with animated blinking border

Proceed?

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Proceed&lt;/strong&gt;. Codey writes all five files.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generated &lt;code&gt;display.h&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// display.h — R2-D2 Holographic Projector&lt;/span&gt;
&lt;span class="c1"&gt;// SSD1306 OLED 128x64 via I2C&lt;/span&gt;
&lt;span class="c1"&gt;// ESP32-S3: SDA=GPIO8, SCL=GPIO9&lt;/span&gt;

&lt;span class="cp"&gt;#pragma once
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Wire.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Adafruit_GFX.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Adafruit_SSD1306.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define SCREEN_WIDTH  128
#define SCREEN_HEIGHT  64
#define OLED_ADDR     0x3C   // Default I2C address for SSD1306
&lt;/span&gt;
&lt;span class="c1"&gt;// OLED_RESET = -1 means share the Arduino reset pin (or no reset pin)&lt;/span&gt;
&lt;span class="n"&gt;Adafruit_SSD1306&lt;/span&gt; &lt;span class="nf"&gt;display&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SCREEN_WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCREEN_HEIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Wire&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;displayReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Boot animation ────────────────────────────────────────────────&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;spinFrames&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"|"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;spinIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastSpinMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;bootStartMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;bootDone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initDisplay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ESP32-S3 I2C: SDA=GPIO8, SCL=GPIO9&lt;/span&gt;
  &lt;span class="n"&gt;Wire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SSD1306_SWITCHCAPVCC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OLED_ADDR&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SSD1306 not found — check wiring!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;displayReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clearDisplay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SSD1306_WHITE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;bootStartMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OLED projector online!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;showBootScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;displayReady&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;bootDone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastSpinMs&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lastSpinMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;spinIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spinIdx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clearDisplay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Title — large text centred&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R2-D2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ONLINE"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Spinner bottom right&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;112&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spinFrames&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;spinIdx&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bootStartMs&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bootDone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Idle screen: distance + status ──────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastIdleRefreshMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;showIdleScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;displayReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastIdleRefreshMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;lastIdleRefreshMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clearDisplay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Distance reading&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DISTANCE:"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;500.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;" cm"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"--- cm"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Status label&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;48&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"!! TOO CLOSE !!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CAUTION"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SAFE"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Motion detected screen ───────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;showMotionScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;displayReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clearDisplay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MOTION"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DETECTED"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"!!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Alert: blinking border + TOO CLOSE ──────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;borderVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastBorderFlipMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;showAlertScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;displayReady&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastBorderFlipMs&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lastBorderFlipMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;borderVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;borderVisible&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clearDisplay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;borderVisible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SSD1306_WHITE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drawRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;124&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SSD1306_WHITE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setTextSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TOO"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setCursor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CLOSE!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;display&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generated &lt;code&gt;sounds.h&lt;/code&gt; (ESP32 LEDC version)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// sounds.h — R2-D2 Sound System (ESP32-S3 LEDC)&lt;/span&gt;
&lt;span class="c1"&gt;// Replaces Arduino tone() with ESP32 LEDC peripheral&lt;/span&gt;

&lt;span class="cp"&gt;#pragma once
&lt;/span&gt;
&lt;span class="cp"&gt;#define BUZZER_PIN    8    // GPIO8 on ESP32-S3
#define LEDC_CHANNEL  0
#define LEDC_TIMER    8    // 8-bit resolution
&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;ledcReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initSounds&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Configure LEDC channel for buzzer&lt;/span&gt;
  &lt;span class="n"&gt;ledcSetup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LEDC_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LEDC_TIMER&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcAttachPin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BUZZER_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LEDC_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LEDC_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// silent&lt;/span&gt;
  &lt;span class="n"&gt;ledcReady&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;playTone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ledcReady&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;frequency&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LEDC_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;ledcWriteTone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LEDC_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LEDC_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 50% duty cycle&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;stopTone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ledcWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LEDC_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generated &lt;code&gt;r2d2-main.ino&lt;/code&gt; (ESP32-S3 version)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// r2d2-main.ino — R2-D2 ESP32-S3 N16R8&lt;/span&gt;
&lt;span class="c1"&gt;// Unifying all systems: sounds, dome lights, sensors, display&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Adafruit_NeoPixel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"sounds.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"animations.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"sensors.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"display.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;115200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R2-D2 ESP32-S3 boot sequence..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;initSounds&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;initAnimations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// NeoPixel dome&lt;/span&gt;
  &lt;span class="n"&gt;initSensors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// HC-SR04 + PIR&lt;/span&gt;
  &lt;span class="n"&gt;initDisplay&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// SSD1306 OLED&lt;/span&gt;

  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All systems nominal. R2-D2 is ONLINE."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Boot animation runs first&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;bootDone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;showBootScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Read sensors&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readDistance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;bool&lt;/span&gt;  &lt;span class="n"&gt;motion&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checkMotion&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Update display based on state&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;showAlertScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;showMotionScreen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;showIdleScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Update dome animations (non-blocking)&lt;/span&gt;
  &lt;span class="n"&gt;updateAnimationsSensors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;motion&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Wiring Diagram — ESP32-S3 Edition 🧭
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO straightens to his full height, relieved.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Codey has drawn the wiring diagram. I have checked it. It includes the voltage dividers. It includes the level shifter recommendation. It is correct. I am, for the first time this episode, not worried."&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R2-D2 Holographic System — ESP32-S3 N16R8 Wiring
════════════════════════════════════════════════════════════

[ESP32-S3 N16R8]

  POWER RAIL (3.3V):
    3V3  ───┬── OLED VCC (3.3V input)
            └── (100µF cap +)
    GND  ───┬── OLED GND
            └── (100µF cap −)

  POWER RAIL (5V via USB):
    VIN  ───┬── NeoPixel Ring: 5V
            ├── HC-SR04: VCC
            └── PIR HC-SR501: VCC
    GND  ───┬── NeoPixel Ring: GND
            ├── HC-SR04: GND
            └── PIR HC-SR501: GND

  I2C BUS (3.3V — OLED compatible):
    GPIO8 (SDA) ──── OLED SDA
    GPIO9 (SCL) ──── OLED SCL

  SIGNALS with PROTECTION:
    GPIO6  ──── [74AHCT125 level shifter] ──── NeoPixel DIN (5V)
    GPIO8  ──── (100Ω) ──────────────────────── Piezo Buzzer +
    GPIO9  ────────────────────────────────────── HC-SR04 TRIG
    GPIO10 ──── [10kΩ / 20kΩ divider] ─────────── HC-SR04 ECHO
    GPIO2  ──── [10kΩ / 20kΩ divider] ─────────── PIR OUT

Voltage Dividers for 5V → 3.3V:
  GPIO_pin ←── (junction) ─── 20kΩ ─── GND
                   └────────── 10kΩ ─── 5V signal in

Connection Table:
┌──────────────────────┬───────────────────────────────────┐
│ From                 │ To                                │
├──────────────────────┼───────────────────────────────────┤
│ ESP32-S3 3V3         │ OLED VCC                          │
│ ESP32-S3 GND         │ OLED GND                          │
│ ESP32-S3 GPIO8 (SDA) │ OLED SDA                          │
│ ESP32-S3 GPIO9 (SCL) │ OLED SCL                          │
│ ESP32-S3 VIN (5V)    │ NeoPixel 5V, HC-SR04 VCC, PIR VCC│
│ ESP32-S3 GPIO6       │ Level shifter → NeoPixel DIN      │
│ ESP32-S3 GPIO8       │ 100Ω → Piezo Buzzer +             │
│ ESP32-S3 GPIO9       │ HC-SR04 TRIG                      │
│ HC-SR04 ECHO (5V)    │ Voltage divider → ESP32 GPIO10    │
│ PIR OUT (5V)         │ Voltage divider → ESP32 GPIO2     │
└──────────────────────┴───────────────────────────────────┘

⚡ Critical Notes:
  - OLED: 3.3V compatible — no level shifting needed
  - NeoPixel: 5V logic required — 74AHCT125 MANDATORY
  - HC-SR04 ECHO: 5V output — voltage divider protects ESP32-S3
  - ESP32-S3 has two USB ports — Codey auto-detects the correct one

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "Download the PDF. Print two copies."&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile and Upload to ESP32-S3 🚀
&lt;/h2&gt;

&lt;p&gt;The ESP32-S3 N16R8 has &lt;strong&gt;two USB ports&lt;/strong&gt;. Codey knows which one to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚙️  Board: ESP32-S3 N16R8

Note: This board has two USB connectors:
  • USB (UART) — for serial communication / upload via UART bridge
  • USB-OTG (native USB-CDC) — direct USB communication

Codey will attempt to detect the correct port automatically.
If upload fails, try the other USB connector.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Compile&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Compilation successful
  Board:   ESP32-S3 N16R8
  Sketch:  r2d2-main.ino + 4 headers
  Binary:  412,288 bytes (5.9% of 16MB Flash)
  RAM:     Used 28,492 bytes (8.7% of 327KB)
  PSRAM:   8MB available for future expansion

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Upload&lt;/strong&gt; → Select the correct USB port → Flash completes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The OLED lights up: "R2-D2" and "ONLINE" with a spinning cursor.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then the idle screen appears: "DISTANCE: 87 cm — SAFE."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Luke waves his hand in front of the HC-SR04. The screen immediately switches to "TOO CLOSE!" with a blinking border.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "It works. He sees me. He's telling me I'm too close."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps something that clearly means "yes, please back up."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Save the Milestone 🚩
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Milestone: "R2-D2 Holographic Projector — Episode 5 Complete"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four systems running. ESP32-S3 humming. The OLED projecting. The dome glowing. The sensors watching.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: The Motion Systems Activate ⚙️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo slaps the workbench.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Okay. He blinks, he beeps, he shows you a screen. But you know what R2-D2 actually does that nobody else can? He moves. He rolls. His dome spins. He navigates. Episode 6 — we give this droid wheels and a rotating dome. Servo for the dome, DC motors for the base. The wiring diagram is going to get interesting."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps the equivalent of "I have been waiting for this my entire existence."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ESP32-S3 datasheet&lt;/strong&gt;: &lt;a href="https://www.espressif.com/en/products/socs/esp32-s3" rel="noopener noreferrer"&gt;espressif.com/esp32-s3&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSD1306 library&lt;/strong&gt;: &lt;a href="https://github.com/adafruit/Adafruit_SSD1306" rel="noopener noreferrer"&gt;github.com/adafruit/Adafruit_SSD1306&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;74AHCT125 level shifter&lt;/strong&gt;: Search "74AHCT125 NeoPixel level shifter"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codey Online&lt;/strong&gt;: &lt;a href="http://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;🤖 R2D2 Creation with Codey — building the galaxy's greatest droid, one episode at a time. May the Force — and the cloud compiler — be with you.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>esp32</category>
      <category>oled</category>
      <category>ai</category>
      <category>makers</category>
    </item>
    <item>
      <title>R2D2 Creation with Codey 🤖 Ep.4</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:13:36 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep4-7nm</link>
      <guid>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep4-7nm</guid>
      <description>&lt;h2&gt;
  
  
  Episode 4: The All-Seeing Eye
&lt;/h2&gt;

&lt;h2&gt;
  
  
  "Impressive. Most Impressive." 👁️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Darth Vader enters — wait, no. Wrong side.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Luke Skywalker stands at the workbench, holding an HC-SR04 ultrasonic sensor up to the light.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "I've always wondered how he knew. How R2 always knew when something was coming. When an obstacle was in the way. When the Death Star trench was approaching. He sees things. Feels them. Before anyone else does."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps softly, as if this is a deeply personal topic.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "Today we give him that. The sensor eye. And this time—" &lt;em&gt;he gestures at the screen&lt;/em&gt; "—Codey's going to show us something called Auto Error Fixing. Because I have a feeling we're going to need it."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;From somewhere unseen, a voice floats through the Force.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;VADER:&lt;/strong&gt; &lt;em&gt;"Your lack of a level-shifted data pin... disturbs me."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "We're on 5V. We'll be fine."&lt;/p&gt;

&lt;h2&gt;
  
  
  🗂️ SIPOC — The Sensor Eye System
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suppliers&lt;/th&gt;
&lt;th&gt;Inputs&lt;/th&gt;
&lt;th&gt;Process&lt;/th&gt;
&lt;th&gt;Outputs&lt;/th&gt;
&lt;th&gt;Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You (the maker)&lt;/td&gt;
&lt;td&gt;"Add HC-SR04 on pins 9/10 and PIR on pin 2, react with beeps and dome color changes"&lt;/td&gt;
&lt;td&gt;Codey writes sensor code, integrates with sound and dome systems from previous episodes&lt;/td&gt;
&lt;td&gt;Unified firmware: sense → respond with light + sound&lt;/td&gt;
&lt;td&gt;R2-D2 — who now reacts to the world around him&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HC-SR04 Sensor&lt;/td&gt;
&lt;td&gt;5V power, TRIG pulse from Arduino&lt;/td&gt;
&lt;td&gt;Emits ultrasonic pulse, measures return echo time&lt;/td&gt;
&lt;td&gt;Distance in centimetres&lt;/td&gt;
&lt;td&gt;The code — which decides how close is "too close"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PIR Motion Sensor&lt;/td&gt;
&lt;td&gt;5V power, GPIO input to Arduino&lt;/td&gt;
&lt;td&gt;Digital HIGH when motion detected&lt;/td&gt;
&lt;td&gt;A HIGH signal on the interrupt pin&lt;/td&gt;
&lt;td&gt;The code — which triggers the alert sequence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto Error Fixing&lt;/td&gt;
&lt;td&gt;A compilation error from incorrect code&lt;/td&gt;
&lt;td&gt;Codey reads the error log, rewrites the offending lines, recompiles&lt;/td&gt;
&lt;td&gt;Fixed code that compiles successfully&lt;/td&gt;
&lt;td&gt;You — who get working firmware without decoding C++ error messages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vision Feature&lt;/td&gt;
&lt;td&gt;A photo of your breadboard&lt;/td&gt;
&lt;td&gt;Codey reads the image and identifies component placement&lt;/td&gt;
&lt;td&gt;A verification report: "Wiring looks correct" or specific mismatches&lt;/td&gt;
&lt;td&gt;You — who confirm wiring before upload&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Components 🔧
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO enters with a tray of precisely arranged components.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Today we add perception to R2-D2's capabilities. The HC-SR04 ultrasonic sensor — which I should note operates at 5V and is therefore perfectly compatible with the Arduino UNO without any level shifting, which is a relief — and the HC-SR501 PIR motion sensor, also 5V compatible. I have pre-sorted them by height to prevent any confusion."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps something that sounds like "nobody asked you to sort them."&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Arduino UNO R3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Our trusted base&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HC-SR04 ultrasonic sensor&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5V, TRIG + ECHO pins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HC-SR501 PIR sensor&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5V, single digital output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10kΩ resistor&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;PIR output pull-down (some modules need it)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jumper wires&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB cable&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Plus the buzzer from Episode 2 and NeoPixel ring from Episode 3 — we are building on the complete system.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Codey Prompt — Building on What We Have 💬
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo points at the screen.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Here's the thing about AI coding tools — you don't start from scratch every time. You tell it what already exists and what you want to add. Context is everything. Same in the smuggling business."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "You're comparing Codey to smuggling?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "I'm saying context matters. Do you want the lecture or the sensor?"&lt;/p&gt;

&lt;p&gt;Open your Codey project (from Episode 3 milestone). In &lt;strong&gt;Agent mode&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We're continuing the R2-D2 build from the previous episodes.
Existing systems:
  - Piezo buzzer on pin 8 (tone-based sounds)
  - NeoPixel ring (12 LEDs) on pin 6 (dome animations)

Add these sensor systems:
  1. HC-SR04 ultrasonic sensor
     - TRIG on pin 9, ECHO on pin 10
     - Measure distance every 150ms (non-blocking)
     - If distance &amp;lt; 30cm: trigger alert animation + alert sound
     - If distance &amp;lt; 15cm: trigger full RED dome + rapid alert beeps

  2. PIR motion sensor on pin 2 (interrupt-capable)
     - On motion detected: trigger scan animation for 3 seconds
     - Then return to idle

Extend animations.h with these reactive behaviors.
Keep the state machine approach.
Use millis() everywhere — no delay().

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generated Code Addition to &lt;code&gt;animations.h&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ── Sensor additions (append to animations.h) ───────────────────&lt;/span&gt;

&lt;span class="c1"&gt;// ── HC-SR04 ─────────────────────────────────────────────────────&lt;/span&gt;
&lt;span class="cp"&gt;#define TRIG_PIN   9
#define ECHO_PIN   10
&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastSonarMs&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;float&lt;/span&gt;         &lt;span class="n"&gt;lastDistance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;999.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="nf"&gt;readDistance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Non-blocking: only trigger if enough time has passed&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastSonarMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lastDistance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;lastSonarMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Send 10µs TRIG pulse&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TRIG_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delayMicroseconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TRIG_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delayMicroseconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TRIG_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Read echo duration (timeout 30ms = ~5m max range)&lt;/span&gt;
  &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pulseIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ECHO_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30000UL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;999.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Convert to centimetres&lt;/span&gt;
  &lt;span class="n"&gt;lastDistance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.0343&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lastDistance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── PIR Motion Sensor ────────────────────────────────────────────&lt;/span&gt;
&lt;span class="cp"&gt;#define PIR_PIN   2
&lt;/span&gt;
&lt;span class="k"&gt;volatile&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;motionDetected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;IRAM_ATTR&lt;/span&gt; &lt;span class="nf"&gt;onMotion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;motionDetected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── Reactive behaviour in updateAnimations() ─────────────────────&lt;/span&gt;
&lt;span class="c1"&gt;// (replaces/extends the existing updateAnimations function)&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateAnimationsSensors&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Check PIR first (interrupt-driven, higher priority) ─────&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;motionDetected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;motionDetected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;currentState&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SCAN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;stateStartMs&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Motion detected — scan mode!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Check HC-SR04 distance ─────────────────────────────────&lt;/span&gt;
  &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readDistance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;15.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Very close — full red alert&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;ALERT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ALERT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;stateStartMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;tone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BUZZER_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2637&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// C6 — high alert tone&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Override: set all LEDs red while this close&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPixelColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BRIGHTNESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;30.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Approaching — amber warning&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;IDLE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ALERT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;stateStartMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;noTone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BUZZER_PIN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Silence if moved away&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Normal state machine ────────────────────────────────────&lt;/span&gt;
  &lt;span class="n"&gt;updateAnimations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// existing function handles the rest&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updated &lt;code&gt;r2d2-dome.ino&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// r2d2-dome.ino — updated for sensor eye&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Adafruit_NeoPixel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"animations.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;initAnimations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// Sensor pins&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TRIG_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ECHO_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;INPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PIR_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="n"&gt;INPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// PIR interrupt — fires on rising edge (motion start)&lt;/span&gt;
  &lt;span class="n"&gt;attachInterrupt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digitalPinToInterrupt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PIR_PIN&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;onMotion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RISING&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R2-D2 sensor eye online!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;updateAnimationsSensors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// new unified call&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Auto Error Fixing in Action 🛠️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;And then it happens.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "I tried to compile and—"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Compilation Error:
  animations.h:47: error: 'IRAM_ATTR' was not declared in this scope
  animations.h:47: note: 'IRAM_ATTR' is an ESP32 attribute, not available on AVR

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "What does that mean? I just—"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before Luke can panic, the screen updates automatically.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CODEY AUTO ERROR FIX:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I see the error! IRAM_ATTR is an ESP32-specific macro for placing
interrupt handlers in IRAM (fast memory). The Arduino UNO uses
an ATmega328P — it doesn't have IRAM at all.

For Arduino UNO, the interrupt handler just needs the ISR() attribute,
which I used in the function signature. I'll remove IRAM_ATTR.

Fixed:
  Before: void IRAM_ATTR onMotion() {
  After:  void onMotion() {

Recompiling...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;✓ Compilation successful (after auto-fix)
  Board:   Arduino UNO R3
  Sketch:  r2d2-dome.ino + animations.h
  Size:    9,104 bytes (28% of flash)

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "It... fixed it. By itself."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; &lt;em&gt;"Never tell me the odds."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "That's not the same—"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "The AI fixed its own mistake without you having to understand why. That's what matters."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wiring Diagram — Three Systems Now 🧭
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Wiring Diagram&lt;/strong&gt;. The diagram now shows all three systems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R2-D2 Sensor Eye + Dome + Sound — Wiring Diagram
════════════════════════════════════════════════════════════

[Arduino UNO R3]

  POWER RAIL:
    5V  ─────────┬── NeoPixel 5V
                 ├── HC-SR04 VCC
                 ├── PIR Sensor VCC
                 └── (100µF cap +)
    GND ─────────┬── NeoPixel GND
                 ├── HC-SR04 GND
                 ├── PIR Sensor GND
                 └── (100µF cap −)

  SIGNALS:
    Pin 6  ──── (470Ω) ──── NeoPixel DIN
    Pin 8  ──── (100Ω) ──── Piezo Buzzer +
    Pin 9  ─────────────── HC-SR04 TRIG
    Pin 10 ─────────────── HC-SR04 ECHO
    Pin 2  ─────────────── PIR Sensor OUT

Color code:
  RED    = 5V / power rail
  BLACK  = GND rail
  GREEN  = NeoPixel data (pin 6)
  ORANGE = Buzzer signal (pin 8)
  BLUE   = HC-SR04 TRIG (pin 9)
  PURPLE = HC-SR04 ECHO (pin 10)
  YELLOW = PIR output (pin 2)
  GREY   = Through resistors

Connection Table:
┌────────────────────┬──────────────────────────────────┐
│ From               │ To                               │
├────────────────────┼──────────────────────────────────┤
│ Arduino 5V         │ NeoPixel Ring: 5V                │
│ Arduino 5V         │ HC-SR04: VCC                     │
│ Arduino 5V         │ PIR HC-SR501: VCC                │
│ Arduino 5V         │ 100µF Cap: + (long leg)          │
│ Arduino GND        │ NeoPixel Ring: GND               │
│ Arduino GND        │ HC-SR04: GND                     │
│ Arduino GND        │ PIR HC-SR501: GND                │
│ Arduino GND        │ 100µF Cap: − (short leg)         │
│ Arduino Pin 6      │ Resistor 470Ω → NeoPixel DIN     │
│ Arduino Pin 8      │ Resistor 100Ω → Piezo (+)        │
│ Arduino Pin 9      │ HC-SR04: TRIG                    │
│ Arduino Pin 10     │ HC-SR04: ECHO                    │
│ Arduino Pin 2      │ PIR HC-SR501: OUT                │
└────────────────────┴──────────────────────────────────┘

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Seven signals on eight wires plus the power rail. The color-coded system makes it genuinely manageable. Download the PDF immediately — this is the most complex wiring diagram we have produced so far and I do not trust organic memory."&lt;/p&gt;

&lt;h2&gt;
  
  
  Vision Feature: "Is My Breadboard Wired Correctly?" 👁️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Luke takes a photo of his assembled breadboard.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "Before I upload — can I check this with Codey? Just to be sure?"&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Vision&lt;/strong&gt; icon in Codey (Pro feature). Upload the breadboard photo.&lt;/p&gt;

&lt;p&gt;Codey responds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I can see your breadboard. Here's what I observe:

✓ HC-SR04 ultrasonic sensor connected:
  - VCC to 5V rail — correct
  - GND to GND rail — correct
  - TRIG appears connected to the digital pin area (looks like pin 9) — correct
  - ECHO appears connected to pin 10 — correct

✓ PIR sensor:
  - VCC and GND connections look correct
  - Signal wire appears to go to pin 2 — correct

⚠️ One potential issue:
  I notice what looks like the NeoPixel data wire may not have the
  470Ω resistor in line — it appears to connect directly. Check that
  the resistor is seated in the breadboard between pin 6 and the DIN
  input. A direct connection may cause LED flickering or data errors.

Everything else looks correctly laid out!

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Luke examines the breadboard.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "The resistor... it's in the wrong row. It's not actually connected to anything."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps in the tone of "I could have told you that."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "Vision just saved R2's dome lights."&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: The Holographic Projector 📽️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Obi-Wan's presence fills the workshop like warm light.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "You have given R2-D2 his lights. His sounds. His sense of the world around him. But the moment that first made the galaxy fall in love with this droid — do you remember it, Luke?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; &lt;em&gt;"Help me, Obi-Wan Kenobi. You're my only hope."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "In Episode 5, we give Artoo his projector. The SSD1306 OLED display — small, crisp, I2C wired — will show R2's status, messages, and a recreation of that famous message. Milestones and Rollback will save us if anything goes wrong."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps the opening notes of the Princess Leia theme.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HC-SR04 with Arduino&lt;/strong&gt;: Search "HC-SR04 Arduino tutorial"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PIR HC-SR501&lt;/strong&gt;: Search "HC-SR501 Arduino interrupt"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codey Online Vision&lt;/strong&gt;: &lt;a href="http://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt; — Pro feature&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Error Fixing&lt;/strong&gt;: built into all Codey plans&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;🤖 R2D2 Creation with Codey — building the galaxy's greatest droid, one episode at a time. May the Force — and the cloud compiler — be with you.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>arduino</category>
      <category>sensors</category>
      <category>ai</category>
      <category>makers</category>
    </item>
    <item>
      <title>R2D2 Creation with Codey 🤖 Ep.3</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:13:26 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep3-4mj1</link>
      <guid>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep3-4mj1</guid>
      <description>&lt;h2&gt;
  
  
  Episode 3: The Dome Awakens
&lt;/h2&gt;

&lt;h2&gt;
  
  
  "I Have a Bad Feeling About These Voltage Levels" ⚡
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO enters the workshop carrying a 12-LED NeoPixel ring with the careful reverence of someone handling a thermal detonator.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "I want to begin by saying that I have computed no fewer than twenty-three potential failure modes for this particular connection. NeoPixel WS2812B LED rings operate on 5V logic. The Arduino UNO R3 also operates on 5V logic. So far, so excellent. However, should anyone in this workshop be tempted — under any circumstances — to use an ESP32 instead, which operates on 3.3V logic, I must warn them in the strongest possible terms that—"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps the equivalent of "get on with it."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Yes, well. Codey's voltage safety check will handle that conversation. Shall we begin?"&lt;/p&gt;

&lt;h2&gt;
  
  
  🗂️ SIPOC — The Dome Light System
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suppliers&lt;/th&gt;
&lt;th&gt;Inputs&lt;/th&gt;
&lt;th&gt;Process&lt;/th&gt;
&lt;th&gt;Outputs&lt;/th&gt;
&lt;th&gt;Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You (the maker)&lt;/td&gt;
&lt;td&gt;"Add a 12-LED NeoPixel ring to pin 6 for R2-D2 dome lights"&lt;/td&gt;
&lt;td&gt;Codey picks Adafruit_NeoPixel library, generates light animation code&lt;/td&gt;
&lt;td&gt;Complete .ino + .h header file for animation patterns&lt;/td&gt;
&lt;td&gt;Arduino UNO R3 — which drives all 12 RGB LEDs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codey Voltage Safety Check&lt;/td&gt;
&lt;td&gt;NeoPixel ring (5V) + Arduino UNO (5V)&lt;/td&gt;
&lt;td&gt;Cross-references board voltage vs component logic requirements&lt;/td&gt;
&lt;td&gt;Green light: compatible — or warning with level shifter advice&lt;/td&gt;
&lt;td&gt;You — who avoid magic smoke&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NeoPixel Ring (12 LEDs)&lt;/td&gt;
&lt;td&gt;5V power + PWM data signal from Pin 6&lt;/td&gt;
&lt;td&gt;WS2812B protocol drives each RGB LED individually&lt;/td&gt;
&lt;td&gt;12 independently addressable full-color LEDs&lt;/td&gt;
&lt;td&gt;R2-D2's dome — which lights up with personality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud Compiler&lt;/td&gt;
&lt;td&gt;Multi-file project: r2d2-dome.ino + animations.h&lt;/td&gt;
&lt;td&gt;Compiles with Adafruit_NeoPixel pre-installed on Codey servers&lt;/td&gt;
&lt;td&gt;Firmware ready for upload&lt;/td&gt;
&lt;td&gt;Arduino UNO — via Web Serial&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Components 🔧
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Luke examines the new parts laid out on the bench.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "These are beautiful. The blue and white... it's exactly right. Like the dome in the movies."&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Arduino UNO R3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;From Episode 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NeoPixel ring (12 LED, WS2812B)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5V input — white text on back means 5V variant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;470Ω resistor&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Data line protection — prevents signal ringing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100µF capacitor (electrolytic)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Power supply decoupling — across 5V and GND&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jumper wires&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB cable&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "Why the capacitor?"&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Yoda materialises near the component drawer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Sudden power demand, NeoPixels have when they first turn on. Smooth that spike, the capacitor does. Without it, reset your Arduino might — mid-animation."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "I had no idea—"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Much to learn, you still have. But learn quickly with Codey, you will."&lt;/p&gt;

&lt;h2&gt;
  
  
  Codey Prompt: Describing the Dome 🎙️
&lt;/h2&gt;

&lt;p&gt;Open your Codey project. In &lt;strong&gt;Plan mode&lt;/strong&gt; first (to review the plan), then &lt;strong&gt;Agent mode&lt;/strong&gt; to build it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plan mode first, then agent:

I'm building R2-D2's dome light system.
Add a 12-LED NeoPixel ring (WS2812B) connected to digital pin 6
with a 470 ohm resistor on the data line.
Add a 100uF capacitor across the power pins for stability.

Create these light animations:
  1. "idle" — gentle blue-white breathing pattern, slow
  2. "alert" — fast red sweep around the ring, 3 times
  3. "happy" — rainbow sweep, then blue-white sparkle
  4. "scan" — single blue LED orbiting the ring slowly

Cycle through idle → scan → idle → happy → idle → alert.
Use non-blocking millis() timing throughout.
Split the animations into a separate animations.h file.
Keep the main .ino clean and readable.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Plan Mode Preview
&lt;/h3&gt;

&lt;p&gt;Codey shows the plan before writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plan for R2-D2 Dome Light System:

1. Main file (r2d2-dome.ino):
   - Include Adafruit_NeoPixel.h and animations.h
   - Setup: initialise ring, set brightness
   - Loop: call state machine from animations.h

2. animations.h:
   - Define RING_PIN = 6, NUMPIXELS = 12
   - Adafruit_NeoPixel ring object
   - State enum: IDLE, ALERT, HAPPY, SCAN
   - Functions: animateIdle(), animateAlert(),
     animateHappy(), animateScan()
   - Timing via millis() — non-blocking

3. Wiring diagram:
   - Pin 6 → 470Ω → NeoPixel DIN
   - 5V → Cap+ and NeoPixel 5V
   - GND → Cap− and NeoPixel GND

Proceed with Agent mode to write the code?

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;C-3PO reads the plan with visible relief.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "A plan! Before the code! How wonderfully methodical. I approve of this approach entirely."&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Proceed&lt;/strong&gt; — Codey switches to Agent mode and writes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Generated Code: &lt;code&gt;r2d2-dome.ino&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// r2d2-dome.ino&lt;/span&gt;
&lt;span class="c1"&gt;// R2-D2 Dome Light System — Main File&lt;/span&gt;
&lt;span class="c1"&gt;// Board: Arduino UNO R3&lt;/span&gt;
&lt;span class="c1"&gt;// NeoPixel ring (WS2812B, 12 LEDs) on pin 6&lt;/span&gt;

&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Adafruit_NeoPixel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"animations.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;initAnimations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R2-D2 dome lights online!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;updateAnimations&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Generated Header: &lt;code&gt;animations.h&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// animations.h&lt;/span&gt;
&lt;span class="c1"&gt;// R2-D2 Dome Light Animations&lt;/span&gt;
&lt;span class="c1"&gt;// NeoPixel ring (WS2812B, 12 LEDs) on pin 6&lt;/span&gt;

&lt;span class="cp"&gt;#pragma once
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;Adafruit_NeoPixel.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define RING_PIN    6
#define NUMPIXELS   12
#define BRIGHTNESS  80   // 0-255 — keep under 100 for USB power
&lt;/span&gt;
&lt;span class="n"&gt;Adafruit_NeoPixel&lt;/span&gt; &lt;span class="nf"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RING_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NEO_GRB&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;NEO_KHZ800&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;DomeState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IDLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCAN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HAPPY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ALERT&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;DomeState&lt;/span&gt; &lt;span class="n"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IDLE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;stateStartMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── State durations (ms) ────────────────────────────────────────&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;IDLE_DURATION&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;SCAN_DURATION&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;HAPPY_DURATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;ALERT_DURATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Dome state machine order ────────────────────────────────────&lt;/span&gt;
&lt;span class="n"&gt;DomeState&lt;/span&gt; &lt;span class="n"&gt;stateOrder&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IDLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SCAN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HAPPY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ALERT&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;stateIndex&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;NUM_STATES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Animation helpers ───────────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;breatheValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;breatheDir&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;   &lt;span class="n"&gt;scanPos&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;   &lt;span class="n"&gt;alertSweep&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;   &lt;span class="n"&gt;alertCount&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;   &lt;span class="n"&gt;rainbowStep&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="nf"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;brightness&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;brightness&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="nf"&gt;white&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;brightness&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;brightness&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;brightness&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;brightness&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="nf"&gt;blueWhite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;br&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;br&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;br&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── IDLE: gentle blue-white breathing ───────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;animateIdle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;breatheValue&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;breatheDir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;breatheValue&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;breatheValue&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;breatheDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;breatheDir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;br&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint8_t&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;breatheValue&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;BRIGHTNESS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPixelColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blueWhite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;br&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── SCAN: single blue LED orbiting slowly ───────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;animateScan&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPixelColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scanPos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BRIGHTNESS&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="c1"&gt;// Faint trail&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPixelColor&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;scanPos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                     &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BRIGHTNESS&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;scanPos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scanPos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── HAPPY: rainbow then blue-white sparkle ───────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;animateHappy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;hue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rainbowStep&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;65536L&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0xFFFF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPixelColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gamma32&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ColorHSV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hue&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;rainbowStep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rainbowStep&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── ALERT: fast red sweep, 3 times ──────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;animateAlert&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;lastUpdateMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setPixelColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alertSweep&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BRIGHTNESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;alertSweep&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alertSweep&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;NUMPIXELS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;alertSweep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;alertCount&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ── State machine ────────────────────────────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;initAnimations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setBrightness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BRIGHTNESS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;ring&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;stateStartMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;updateAnimations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;stateDur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;IDLE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;animateIdle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="n"&gt;stateDur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IDLE_DURATION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;SCAN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;animateScan&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  &lt;span class="n"&gt;stateDur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SCAN_DURATION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;HAPPY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;animateHappy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;stateDur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HAPPY_DURATION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;ALERT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;animateAlert&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;stateDur&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ALERT_DURATION&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;stateStartMs&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;stateDur&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;stateIndex&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stateIndex&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;NUM_STATES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;currentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stateOrder&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;stateIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="n"&gt;stateStartMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;alertSweep&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;alertCount&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;rainbowStep&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;scanPos&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"State → "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Voltage Safety Check — Codey Saves the Day ⚡
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Suddenly, a second prompt flashes on screen.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Oh! There it is! Codey's voltage safety check! I told everyone this moment would come!"&lt;/p&gt;

&lt;p&gt;When you type the same prompt but specify &lt;strong&gt;ESP32&lt;/strong&gt; instead of Arduino UNO, Codey adds a critical warning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚡ VOLTAGE SAFETY WARNING

Component: NeoPixel ring WS2812B
Logic level required: 5V data signal
Board selected: ESP32 DevKit V1 (3.3V logic)

ISSUE: The WS2812B data input requires a HIGH signal of at least
3.5V. ESP32 GPIO outputs only 3.3V, which may be unreliable or
cause flickering, colour errors, or complete failure.

RECOMMENDATION: Add a 74AHCT125 level shifter between ESP32
GPIO pin and the NeoPixel DIN pin.
OR: Use a 3.3V-compatible LED strip (SK6812 at 3.3V mode).
OR: Add a pullup via 10kΩ resistor to 5V on the data line.

The code below uses the level shifter approach.
Shall I update the wiring diagram?

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "You see! THREE THOUSAND SEVEN HUNDRED AND TWENTY TO ONE were my odds and Codey — Codey caught it! Without the level shifter, R2-D2's dome lights would flicker erratically. Or not work at all. I have said it before: voltage compatibility is the cornerstone of reliable hardware."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 emits a long, approving whistle.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Yes. Quite."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wiring Diagram — The Dome Blueprint 🧭
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Wiring Diagram&lt;/strong&gt;. Codey draws:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R2-D2 Dome Lights — Wiring Diagram (Arduino UNO R3)
═══════════════════════════════════════════════════════════

[Arduino UNO R3]
  5V   ──────────┬──── (100µF Cap +) ──── GND
                 └──── [NeoPixel Ring: 5V/PWR]
  GND  ──────────┬──── (100µF Cap −)
                 └──── [NeoPixel Ring: GND]
  Pin 6 ──── (470Ω) ── [NeoPixel Ring: DIN/DATA IN]

Color code:
  RED    = 5V power
  BLACK  = GND
  GREEN  = Data signal (Pin 6)
  GREY   = Through 470Ω resistor
  BROWN  = Capacitor leads

Connection Table:
┌─────────────────────┬──────────────────────────────────┐
│ From                │ To                               │
├─────────────────────┼──────────────────────────────────┤
│ Arduino 5V          │ NeoPixel Ring: 5V (PWR)          │
│ Arduino 5V          │ 100µF Capacitor: + (long leg)    │
│ Arduino GND         │ NeoPixel Ring: GND               │
│ Arduino GND         │ 100µF Capacitor: − (short leg)   │
│ Arduino Pin 6       │ Resistor leg 1 (470Ω)            │
│ Resistor leg 2      │ NeoPixel Ring: DIN               │
└─────────────────────┴──────────────────────────────────┘

⚡ Notes:
  - Arduino UNO is 5V logic — compatible with WS2812B
  - 100µF cap prevents power surge on LED startup
  - 470Ω resistor prevents signal overshoot
  - If using ESP32: add 74AHCT125 level shifter on data line

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "Print that. Actually — download the PDF and print it. I want this on the wall."&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Download PDF&lt;/strong&gt;. The wiring diagram is saved for your build log.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-File Projects: Real Code for Real Droids 📁
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo examines the two-tab project with a raised eyebrow.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Two files. A main and a header. That's how real firmware is structured. Not everything crammed into one endless sketch."&lt;/p&gt;

&lt;p&gt;Codey's &lt;strong&gt;Multi-file Projects&lt;/strong&gt; feature gave us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;r2d2-dome.ino&lt;/code&gt; — clean, readable main file (12 lines!)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;animations.h&lt;/code&gt; — all animation logic in one focused place&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Click between the tabs in Codey's editor. Both files have syntax highlighting and linting. When you compile, Codey knows they belong together and sends both to the cloud compiler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "When we add the sensor system and the motor system in later episodes, each gets its own file. R2 stays clean. No 500-line monster sketch."&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile, Upload, and Watch the Dome Glow 🚀
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Compile&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Compilation successful
  Board:   Arduino UNO R3
  Sketch:  r2d2-dome.ino + animations.h
  Library: Adafruit NeoPixel (pre-installed)
  Size:    6,842 bytes (21% of flash)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Upload&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The ring comes to life. Blue-white breathing. Slow. Like R2-D2 resting.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then the scan — a single blue LED orbiting the ring.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then the happiness sequence — rainbow wash, then back to blue-white.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then the alert — red sweeping urgently.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; &lt;em&gt;"It's... it's his dome. It looks exactly like his dome."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 — the actual one — beeps from the corner. The sound is quiet, reverent. Even he seems moved.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Save Your Milestone 🚩
&lt;/h2&gt;

&lt;p&gt;Name this milestone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Milestone: "R2-D2 Dome Lights — Episode 3 Complete"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codey saves the code, headers, and chat history.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: The All-Seeing Eye 👁️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Yoda sits quietly for a moment.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "A droid that glows and beeps, you have built. But see, R2-D2 can. Obstacles he detects. Danger he senses. In Episode 4 — the sensor eye we add. HC-SR04, PIR sensor, reactive behavior. And the Auto Error Fixing feature... needed it will be."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps something urgent.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Yes, Artoo. Ahead, Episode 4 is. Patient you must be."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adafruit NeoPixel library&lt;/strong&gt;: &lt;a href="https://github.com/adafruit/Adafruit_NeoPixel" rel="noopener noreferrer"&gt;github.com/adafruit/Adafruit_NeoPixel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WS2812B datasheet&lt;/strong&gt;: Search "WS2812B datasheet"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codey Online&lt;/strong&gt;: &lt;a href="http://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;🤖 R2D2 Creation with Codey — building the galaxy's greatest droid, one episode at a time. May the Force — and the cloud compiler — be with you.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>arduino</category>
      <category>neopixel</category>
      <category>leds</category>
      <category>makers</category>
    </item>
    <item>
      <title>R2D2 Creation with Codey 🤖 Ep.2</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:13:16 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep2-181a</link>
      <guid>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep2-181a</guid>
      <description>&lt;h2&gt;
  
  
  Episode 2: The Sound of the Force
&lt;/h2&gt;

&lt;h2&gt;
  
  
  "That Little Droid Is Going to Get Us All Killed" 💬
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo strides into the workshop, one hand raised in exasperation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Okay. The LED blinks, great. Very impressive. But you know what nobody in the entire Rebel Alliance has ever once said? 'Thank the Maker for that blinking LED.' You know what they have said? 'What did R2 just say?' Because THAT'S the important part."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps at Han with what is clearly a rebuttal.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "I know, I know — I'm not fluent in Beep. But THEY don't know that. Point is, this droid needs sound. We're connecting a piezo buzzer today. And Codey's going to write every single note."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 lets out a long, resonant whistle that sounds almost musical.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Yeah, yeah, you're excited. Let's just not blow anything up this time."&lt;/p&gt;

&lt;h2&gt;
  
  
  🗂️ SIPOC — The Sound System Build
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suppliers&lt;/th&gt;
&lt;th&gt;Inputs&lt;/th&gt;
&lt;th&gt;Process&lt;/th&gt;
&lt;th&gt;Outputs&lt;/th&gt;
&lt;th&gt;Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You (the maker)&lt;/td&gt;
&lt;td&gt;"I want R2-D2 beeps and whistles from a piezo buzzer on pin 8"&lt;/td&gt;
&lt;td&gt;Codey's AI writes the tone() sequence, Smart Library Picker includes the right headers&lt;/td&gt;
&lt;td&gt;Complete .ino with tone(), noTone(), and an R2-D2 sound sequence&lt;/td&gt;
&lt;td&gt;Arduino UNO R3 — which drives the buzzer via PWM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Piezo buzzer&lt;/td&gt;
&lt;td&gt;5V signal, PWM frequency&lt;/td&gt;
&lt;td&gt;Vibrates at the commanded frequency&lt;/td&gt;
&lt;td&gt;Audible beep at the specified pitch and duration&lt;/td&gt;
&lt;td&gt;Your ears — which confirm R2-D2 is alive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codey Wiring Diagram&lt;/td&gt;
&lt;td&gt;Component list: piezo buzzer + 100Ω resistor + Arduino UNO&lt;/td&gt;
&lt;td&gt;Draws color-coded diagram with connection table&lt;/td&gt;
&lt;td&gt;Printable PDF with pin labels&lt;/td&gt;
&lt;td&gt;You — so nothing is connected backwards&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cloud Compiler&lt;/td&gt;
&lt;td&gt;The .ino file generated by Codey&lt;/td&gt;
&lt;td&gt;Compiles using Arduino SDK on Codey's servers&lt;/td&gt;
&lt;td&gt;r2d2-sound.hex ready for upload&lt;/td&gt;
&lt;td&gt;Web Serial uploader&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Components We Need 🔧
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO recites from his internal parts manifest with the urgency of someone who has memorised the Rebellion's entire inventory.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "For R2-D2's acoustic communication system, we shall require precisely the following items. I have catalogued them by criticality, voltage requirements, and the probability of incorrect installation by organics:"&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Quantity&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Arduino UNO R3&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;From Episode 1 — still on the bench&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Piezo buzzer (passive)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Passive, not active — we need pitch control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resistor 100Ω&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Protects the Arduino pin from excessive current&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jumper wires&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;The short ones work fine here&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;USB cable&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Type-B for UNO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "One critical distinction — you must use a &lt;strong&gt;passive&lt;/strong&gt; piezo buzzer. An active buzzer produces only one fixed frequency when powered, which would make R2 sound like a very persistent smoke alarm. A passive buzzer is driven by a PWM signal from the Arduino, allowing any frequency, any pitch, any musical phrase. The difference is, I should note, rather significant."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps agreement at maximum volume.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Yes, THAT was unnecessary, Artoo."&lt;/p&gt;

&lt;h2&gt;
  
  
  Asking Codey for the Sound Code 🎵
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo sits backward on a chair, watching the screen.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Okay so here's the thing about AI coding tools — you gotta be specific. Vague gets you vague. I've been flying by the seat of my pants my whole life and I can tell you, specific is better. Tell Codey exactly what you want."&lt;/p&gt;

&lt;p&gt;Open your Codey project from Episode 1 — or create a new project with Arduino UNO R3. In &lt;strong&gt;Agent mode&lt;/strong&gt;, type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I'm building R2-D2.
Add a passive piezo buzzer connected to pin 8 with a 100 ohm series resistor.
Create 5 different R2-D2 sound sequences using tone() and noTone():
  1. "Happy" sound: rising tones, fast
  2. "Alert" sound: rapid urgent beeps
  3. "Sad" sound: descending tones, slow
  4. "Question" sound: rising two-tone whistle
  5. "Excited" sound: rapid ascending sweep

Play them in order with 1 second gaps.
Use millis() instead of delay() so it's non-blocking.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What Codey Generates
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// R2-D2 Sound System&lt;/span&gt;
&lt;span class="c1"&gt;// Board: Arduino UNO R3&lt;/span&gt;
&lt;span class="c1"&gt;// Passive piezo buzzer on pin 8 via 100Ω resistor&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;BUZZER_PIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Timing via millis() — non-blocking ──────────────────────────&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;previousMillis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;currentSequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;noteIndex&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;playingNote&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;noteStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Note structures ─────────────────────────────────────────────&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;Note&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Hz — 0 means silence&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;// ms&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// ── R2-D2 Sound Sequences ───────────────────────────────────────&lt;/span&gt;

&lt;span class="c1"&gt;// 1. Happy — rising tones, cheerful ascending&lt;/span&gt;
&lt;span class="n"&gt;Note&lt;/span&gt; &lt;span class="n"&gt;happy&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;880&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1047&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1319&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1568&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1047&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1568&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;happyLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 2. Alert — rapid urgent beeps&lt;/span&gt;
&lt;span class="n"&gt;Note&lt;/span&gt; &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2093&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2093&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2093&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2637&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;alertLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 3. Sad — descending, slow and mournful&lt;/span&gt;
&lt;span class="n"&gt;Note&lt;/span&gt; &lt;span class="n"&gt;sad&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;880&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;698&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;523&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;440&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sadLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 4. Question — rising two-tone whistle&lt;/span&gt;
&lt;span class="n"&gt;Note&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;880&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1047&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1319&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1568&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;questionLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// 5. Excited — rapid ascending sweep&lt;/span&gt;
&lt;span class="n"&gt;Note&lt;/span&gt; &lt;span class="n"&gt;excited&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;523&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;659&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;698&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;784&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;880&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;988&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1047&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1175&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1319&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1568&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;excitedLen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Sequence registry ────────────────────────────────────────────&lt;/span&gt;
&lt;span class="n"&gt;Note&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;happy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;sad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="n"&gt;excited&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;   &lt;span class="n"&gt;seqLengths&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;happyLen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alertLen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sadLen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;questionLen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;excitedLen&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;NUM_SEQUENCES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ── Pause between sequences (ms) ────────────────────────────────&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;SEQ_GAP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;seqGapStart&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;inGap&lt;/span&gt;                  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BUZZER_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"R2-D2 sound system online!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;seqGapStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// start with a brief gap before first sound&lt;/span&gt;
  &lt;span class="n"&gt;inGap&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;millis&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="c1"&gt;// ── In between-sequence gap ──────────────────────────────────&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inGap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;seqGapStart&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;SEQ_GAP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;inGap&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;noteIndex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Playing sequence "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSequence&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Currently playing a note ─────────────────────────────────&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playingNote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Note&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;currentSequence&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;noteIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;noteStart&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;noTone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BUZZER_PIN&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;playingNote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;noteIndex&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ── Start next note or end sequence ──────────────────────────&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;noteIndex&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;seqLengths&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;currentSequence&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Sequence finished — move to next with a gap&lt;/span&gt;
    &lt;span class="n"&gt;currentSequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentSequence&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;NUM_SEQUENCES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;inGap&lt;/span&gt;           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;seqGapStart&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Note&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sequences&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;currentSequence&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;noteIndex&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequency&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BUZZER_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frequency&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;noteStart&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;playingNote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "See? Non-blocking. Uses &lt;code&gt;millis()&lt;/code&gt; so other stuff can run at the same time. Told you — specific prompt gets you clean code."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 lets out a burst of approving beeps that is definitely not modesty.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wiring Diagram — Pin 8 Gets a Voice 🧭
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO studies the diagram with obvious relief.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Oh, how reassuring! A color-coded diagram. No ambiguity. No chance of catastrophic reversed polarity. This is precisely how I would have specified it had anyone asked me, which they did not, but nevertheless..."&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Wiring Diagram&lt;/strong&gt; in Codey. The diagram appears:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R2-D2 Sound System — Wiring Diagram
════════════════════════════════════════════════

[Arduino UNO R3]
  Pin 8  ──── (100Ω Resistor) ──── [Piezo Buzzer +]
  GND    ──────────────────────── [Piezo Buzzer −]

Color code:
  RED    = 5V / Power
  BLACK  = GND
  ORANGE = PWM Signal (Pin 8)
  GREY   = Through 100Ω resistor

Connection Table:
┌────────────────────┬──────────────────────────────────┐
│ From               │ To                               │
├────────────────────┼──────────────────────────────────┤
│ Arduino Pin 8      │ Resistor leg 1 (100Ω)            │
│ Resistor leg 2     │ Piezo Buzzer positive (+) lead   │
│ Piezo Buzzer (−)   │ Arduino GND                      │
└────────────────────┴──────────────────────────────────┘

⚡ Notes:
  - Passive piezo required (NOT active buzzer)
  - 100Ω resistor limits current on the PWM pin
  - 5V logic — Arduino UNO is 5V compatible with this buzzer

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; "Download the PDF! I insist. Printed documentation is the cornerstone of reliable hardware assembly. R2-D2 himself has seventeen backup copies of his own schematics stored in his memory banks."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps with what sounds like proud confirmation.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart Library Picker: Codey Knows What You Need 📚
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Yoda examines the screen, tilting his head.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Notice something, you must. In the code, &lt;code&gt;#include&lt;/code&gt; statements there are none. For &lt;code&gt;tone()&lt;/code&gt;, no external library needed there is — built into the Arduino core it is. This, Codey knew. The correct headers, chosen automatically they were."&lt;/p&gt;

&lt;p&gt;This is Codey's &lt;strong&gt;Smart Library Picker&lt;/strong&gt; at work. When you describe a component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DHT11 sensor&lt;/strong&gt; → Codey includes &lt;code&gt;#include &amp;lt;DHT.h&amp;gt;&lt;/code&gt; and &lt;code&gt;DHT sensor library&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSD1306 OLED&lt;/strong&gt; → Codey includes &lt;code&gt;#include &amp;lt;Adafruit_SSD1306.h&amp;gt;&lt;/code&gt; and &lt;code&gt;Adafruit_SSD1306&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NeoPixel ring&lt;/strong&gt; → Codey includes &lt;code&gt;#include &amp;lt;Adafruit_NeoPixel.h&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Piezo buzzer with tone()&lt;/strong&gt; → Arduino core, no extra library needed — Codey knows this&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; "Wrong library, choose it does not. Over-include, waste time it would not. Know the tool, it does — before you ask."&lt;/p&gt;

&lt;h2&gt;
  
  
  Compile, Upload, and Hear R2 Speak 🚀
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Luke leans forward, eyes wide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "I want to hear it. Come on — compile it."&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Compile&lt;/strong&gt;. The cloud compiler runs. The output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Compilation successful
  Board:   Arduino UNO R3
  Sketch:  r2d2-sound.ino
  Size:    3,426 bytes (10% of flash)
  RAM:     312 bytes (15% of RAM)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click &lt;strong&gt;Upload&lt;/strong&gt;. The Arduino resets. The firmware flashes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A pause.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then, from the breadboard, a rising cascade of beeps — cheerful, ascending, unmistakably R2-D2.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "That's... that actually sounds like him."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then the alert sequence — rapid urgent chirps.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then the sad, descending moan that R2 makes when things have gone terribly wrong.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; "The sad one sounds exactly like when he got shot on Hoth."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 — the real one, apparently nearby — beeps in solemn agreement.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Live Serial Monitor to Debug 📟
&lt;/h2&gt;

&lt;p&gt;The code includes &lt;code&gt;Serial.begin(9600)&lt;/code&gt; and &lt;code&gt;Serial.print()&lt;/code&gt; statements. Open Codey's &lt;strong&gt;Live Serial Monitor&lt;/strong&gt; (the icon that looks like a screen with text) to watch the playback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;Serial Monitor — 9600 baud
───────────────────────────
R2-D2 sound system online!
Playing sequence 1
Playing sequence 2
Playing sequence 3
Playing sequence 4
Playing sequence 5
Playing sequence 1
[... loops indefinitely]

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "That's your debug output right there. If a sequence is stuck, you see exactly which one. No mysterious freezes, no guessing. This is how you fly — with instruments, not prayers."&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding R2 to the Build Log — Milestone! 🚩
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Obi-Wan gestures to the Milestones button.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "Before we move on, save a milestone. The Force has a memory — your code should too."&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Save Milestone&lt;/strong&gt; in Codey. Name it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Milestone: "R2-D2 Sound System — Episode 2 Complete"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codey saves both the code state AND the chat history at this point. If Episode 3's changes ever break something, you can roll back here and start again — with the full context of how you got here.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps something that sounds like a triumphant fanfare.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; "The droid is pleased with our progress. As am I."&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next: The Dome Lights Activate 💫
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo is already walking away.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "Good work, kid. Now he beeps. But R2's blue-and-white dome LEDs? Those NeoPixel rings? THAT'S what impresses people. Episode 3 — we go full disco ball. With a voltage safety check."&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps, clearly offended by "disco ball."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; "I know, I know. Very dignified. Very droid. See you in Episode 3."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arduino tone() reference&lt;/strong&gt;: &lt;a href="https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/" rel="noopener noreferrer"&gt;arduino.cc/reference/en/language/functions/advanced-io/tone&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Codey Online&lt;/strong&gt;: &lt;a href="http://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Passive vs Active Buzzer explained&lt;/strong&gt;: Search "passive vs active buzzer Arduino"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;🤖 R2D2 Creation with Codey — building the galaxy's greatest droid, one episode at a time. May the Force — and the cloud compiler — be with you.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>arduino</category>
      <category>audio</category>
      <category>ai</category>
      <category>makers</category>
    </item>
    <item>
      <title>R2D2 Creation with Codey 🤖 Ep.1</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Sun, 07 Jun 2026 14:11:18 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep1-5f52</link>
      <guid>https://dev.to/the-software-s-journey/r2d2-creation-with-codey-ep1-5f52</guid>
      <description>&lt;h2&gt;
  
  
  Episode 1: The Rebellion Begins
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;A long time ago in a browser tab far, far away…&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  “Help Me, Codey Online — You’re My Only Hope” 📡
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;The hologram flickers. Obi-Wan Kenobi steps forward, robes sweeping the workshop floor.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; “For a thousand generations, makers have built remarkable things with their hands. But now there is a new path — one where you describe what you wish to create, and an intelligence writes the code, draws the wires, and compiles the future for you. That path is called Codey Online. And the project before us… is the most beloved droid in the galaxy.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 lets out a long, excited series of beeps and whistles from somewhere across the workshop.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; “Yes, Artoo. We are going to build you.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;More frantic beeping.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; “From scratch. Yes, all of it. In a browser tab. Come — the Force will guide our USB cable.”&lt;/p&gt;

&lt;h2&gt;
  
  
  🗂️ SIPOC — The Mission Briefing
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Suppliers&lt;/th&gt;
&lt;th&gt;Inputs&lt;/th&gt;
&lt;th&gt;Process&lt;/th&gt;
&lt;th&gt;Outputs&lt;/th&gt;
&lt;th&gt;Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;You (the maker)&lt;/td&gt;
&lt;td&gt;A description of what R2-D2 should do&lt;/td&gt;
&lt;td&gt;Codey writes the code, draws the wiring diagram, compiles in the cloud&lt;/td&gt;
&lt;td&gt;Compiled firmware uploaded directly to your Arduino or ESP32&lt;/td&gt;
&lt;td&gt;The completed R2-D2 droid — dome lights blazing, beeps echoing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codey AI&lt;/td&gt;
&lt;td&gt;Natural language instructions&lt;/td&gt;
&lt;td&gt;AI generates complete Arduino sketches, libraries, and helper files&lt;/td&gt;
&lt;td&gt;Working .ino code with correct #include statements&lt;/td&gt;
&lt;td&gt;Your microcontroller — which finally knows what to do&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The Cloud Compiler&lt;/td&gt;
&lt;td&gt;Your .ino source files&lt;/td&gt;
&lt;td&gt;Compiles without any local IDE, toolchain, or SDK&lt;/td&gt;
&lt;td&gt;A compiled .hex or .bin firmware file&lt;/td&gt;
&lt;td&gt;Web Serial uploader — which flashes it to your board&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wiring Diagram Generator&lt;/td&gt;
&lt;td&gt;Your component list&lt;/td&gt;
&lt;td&gt;Draws color-coded diagrams with connection table&lt;/td&gt;
&lt;td&gt;PDF-exportable wiring guide&lt;/td&gt;
&lt;td&gt;You — so you know which jumper wire goes where&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Is Codey Online? The Holonet Briefing 🌐
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO rushes in, datapad clutched to his golden chest.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; “Oh my! Allow me to translate the technical specifications, as I am fluent in over six million forms of programming environments. Codey Online, built by OTRONIC of the Netherlands, is what the organic beings call a ‘browser-based vibe coding IDE’ for Arduino and ESP32 microcontrollers. It requires no installation, no driver configuration, no local toolchain whatsoever. I calculate the probability of a beginner successfully installing the traditional Arduino IDE without frustration is approximately three thousand, seven hundred and twenty-to-one!”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps dismissively.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; “Yes, yes, Artoo — with Codey the odds are considerably better. The complete feature set, as I have catalogued it, is as follows:”&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;🤖 AI Vibe Coding&lt;/td&gt;
&lt;td&gt;Describe your idea — Codey writes the complete sketch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧭 Wiring Diagram Generator&lt;/td&gt;
&lt;td&gt;Color-coded diagrams, pin labels, connection table, PDF export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;☁️ Cloud Compiler&lt;/td&gt;
&lt;td&gt;No local IDE needed — compilation runs on Codey’s servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔌 Direct USB Upload&lt;/td&gt;
&lt;td&gt;Flash via Web Serial in Chrome or Edge — no drivers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📟 Live Serial Monitor&lt;/td&gt;
&lt;td&gt;Debug in real time without leaving the browser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛠️ Auto Error Fixing&lt;/td&gt;
&lt;td&gt;Codey reads errors and fixes them automatically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📚 Smart Library Picker&lt;/td&gt;
&lt;td&gt;Correct library chosen automatically for each sensor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;📁 Multi-file Projects&lt;/td&gt;
&lt;td&gt;.ino, .h, .cpp files in a tabbed editor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🚩 Milestones &amp;amp; Rollback&lt;/td&gt;
&lt;td&gt;Save snapshots, restore code AND chat history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;⚡ Voltage Safety Checks&lt;/td&gt;
&lt;td&gt;Warns when 3.3V boards meet 5V sensors&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧠 Agent / Plan / Ask Modes&lt;/td&gt;
&lt;td&gt;Three reasoning modes for different needs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;👁️ Vision: Upload Images&lt;/td&gt;
&lt;td&gt;Photo of your breadboard — Codey reads it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; “And the supported boards include Arduino UNO R3, Arduino Nano V3, Arduino Mega 2560, ESP32 DevKit V1, ESP32-S3, and ESP32-C3. Most satisfactory.”&lt;/p&gt;

&lt;h2&gt;
  
  
  The R2-D2 Build Plan: A Galaxy of Systems 🤖
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Luke Skywalker spreads a holographic blueprint across the table.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; “I had no idea how many systems R2 actually has. Every time he does something amazing, I just thought— well, it was just R2 being R2. But look at this.”&lt;/p&gt;

&lt;p&gt;The complete R2-D2 we are going to build across this series:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Episode&lt;/th&gt;
&lt;th&gt;R2-D2 System&lt;/th&gt;
&lt;th&gt;Components&lt;/th&gt;
&lt;th&gt;Codey Feature Spotlight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;First Power — Dome LED&lt;/td&gt;
&lt;td&gt;Arduino UNO + LED&lt;/td&gt;
&lt;td&gt;Account setup, first sketch, first wiring diagram&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Voice and Beeps&lt;/td&gt;
&lt;td&gt;Piezo buzzer&lt;/td&gt;
&lt;td&gt;Smart Library Picker, tone() code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Dome Light Array&lt;/td&gt;
&lt;td&gt;NeoPixel ring&lt;/td&gt;
&lt;td&gt;FastLED/NeoPixel, voltage safety check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Sensor Eye&lt;/td&gt;
&lt;td&gt;HC-SR04 + PIR&lt;/td&gt;
&lt;td&gt;Auto Error Fixing, Vision photo upload&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Holographic Projector&lt;/td&gt;
&lt;td&gt;SSD1306 OLED&lt;/td&gt;
&lt;td&gt;Milestones &amp;amp; Rollback, I2C wiring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Motion Systems&lt;/td&gt;
&lt;td&gt;Servo + DC motors&lt;/td&gt;
&lt;td&gt;Multi-file projects, complex wiring diagrams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Audio Voice System&lt;/td&gt;
&lt;td&gt;DFPlayer Mini + speaker&lt;/td&gt;
&lt;td&gt;Library Picker, Live Serial Monitor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;The Complete Droid&lt;/td&gt;
&lt;td&gt;All systems together&lt;/td&gt;
&lt;td&gt;ESP32 integration, Deep Think mode, final PDF&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Step 1: Creating Your Codey Account 🎟️
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Han Solo leans against the Millennium Falcon’s landing strut.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; “Look, kid, I’ve made a lot of accounts in my day. Mos Eisley cantina membership, Outer Rim trader registry, questionable Imperial databases… This one’s the easiest. Just go to codey.online, hit Sign Up, and you’re in. Free account gets you five AI messages a day to start. That’s enough to get Artoo blinking.”&lt;/p&gt;

&lt;p&gt;Go to &lt;a href="https://codey.online" rel="noopener noreferrer"&gt;&lt;strong&gt;codey.online&lt;/strong&gt;&lt;/a&gt; and create your free account. The Starter plan includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 AI messages per day&lt;/li&gt;
&lt;li&gt;Cloud compilation&lt;/li&gt;
&lt;li&gt;Direct USB uploading&lt;/li&gt;
&lt;li&gt;Wiring diagram generator&lt;/li&gt;
&lt;li&gt;Live serial monitor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps urgently.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; “Yeah yeah, the Pro plan is nine ninety-nine a month and gives you unlimited messages, Deep Think mode, photo uploads, and priority compilation. But start free — we’re still on Tatooine here.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Your First Project — The Dome Light Test 💡
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Obi-Wan gestures toward the workbench.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; “Every journey begins with a single step. For R2-D2, that step is a single blinking LED — a proof that power flows through the circuit, that the code runs, that the connection between maker and machine is alive. In the Jedi tradition, we call this ‘Hello World.’ R2 calls it something rather more enthusiastic.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps with what can only be described as pride.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Opening Codey and Creating a Project
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Log in at &lt;strong&gt;codey.online&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New Project&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose your board: &lt;strong&gt;Arduino UNO R3&lt;/strong&gt; (perfect for our first test)&lt;/li&gt;
&lt;li&gt;In the AI chat panel, type exactly this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build me an R2-D2 dome LED test.
Connect a blue LED to pin 13 with a 220 ohm resistor.
Make the LED blink in an R2-D2 style pattern:
two quick blinks, a pause, then three slower blinks.
Repeat forever.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Within seconds, Codey responds:&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Code Codey Writes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// R2-D2 Dome LED Test&lt;/span&gt;
&lt;span class="c1"&gt;// Generated by Codey Online&lt;/span&gt;
&lt;span class="c1"&gt;// Board: Arduino UNO R3&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;LED_PIN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;pinMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LED_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OUTPUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;loop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// R2-D2 style: two quick blinks&lt;/span&gt;
  &lt;span class="n"&gt;quickBlink&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;quickBlink&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// pause between groups&lt;/span&gt;

  &lt;span class="c1"&gt;// Three slower blinks&lt;/span&gt;
  &lt;span class="n"&gt;slowBlink&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;slowBlink&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="n"&gt;slowBlink&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// pause before repeating&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;quickBlink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LED_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LED_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;slowBlink&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LED_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HIGH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;350&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;digitalWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LED_PIN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;LOW&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;R2-D2 beeps approvingly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; “You see? Codey understood the intent — not just ‘blink an LED,’ but blink it &lt;em&gt;as R2-D2 would.&lt;/em&gt; This is the difference between code and character.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: The First Wiring Diagram 🧭
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;C-3PO peers at the screen with great concern.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; “Oh, I do hope we connect this correctly. I once computed the odds of a short circuit at—”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HAN:&lt;/strong&gt; “Threepio. The diagram. Look at the diagram.”&lt;/p&gt;

&lt;p&gt;After Codey generates the code, click the &lt;strong&gt;Wiring Diagram&lt;/strong&gt; tab. Codey instantly draws:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Arduino UNO R3 Wiring Diagram
══════════════════════════════

[Arduino UNO R3]
  Pin 13 ──────── (220Ω Resistor) ──── [LED Anode (+)]
  GND    ──────────────────────────── [LED Cathode (−)]

Color code:
  RED   = 5V / VCC
  BLACK = GND
  BLUE  = Signal (Pin 13)
  GREY  = Through resistor

Connection Table:
┌─────────────────┬──────────────────────────┐
│ From            │ To                       │
├─────────────────┼──────────────────────────┤
│ Arduino Pin 13  │ Resistor leg 1 (220Ω)    │
│ Resistor leg 2  │ LED Anode (+, long leg)   │
│ LED Cathode (−) │ Arduino GND              │
└─────────────────┴──────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;C-3PO:&lt;/strong&gt; “Color-coded wires! Red for power, black for ground, distinct colors for each signal. I must say, this is considerably more reassuring than the hand-drawn schematics Master Luke produces.”&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Download PDF&lt;/strong&gt; to save the wiring diagram. Print it and pin it above your workbench — R2-D2’s blueprints have begun.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Compile and Upload 🚀
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Luke bounces on his heels with excitement.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; “This is the part where— wait, it actually compiled? Already? Without me installing anything?”&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Compile
&lt;/h3&gt;

&lt;p&gt;Click the &lt;strong&gt;Compile&lt;/strong&gt; button. Codey’s cloud servers compile your code. No toolchain. No library downloads. No error-prone local setup. You see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;✓ Compilation successful
  Board:  Arduino UNO R3
  Sketch: r2d2-dome-led-test.ino
  Size:   1,024 bytes (3% of flash)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Web Serial Upload
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Plug your Arduino UNO into your computer via USB&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Upload&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Chrome asks permission to access the serial port — click Allow&lt;/li&gt;
&lt;li&gt;Codey auto-detects the board, resets it, and flashes the firmware
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;✓ Upload complete
  Port:   COM3 (or /dev/ttyACM0 on Linux)
  Board:  Arduino UNO R3
  Speed:  115200 baud
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;R2-D2’s LED equivalent blinks: two quick, pause, three slow. Again. Again.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LUKE:&lt;/strong&gt; “He’s… he’s alive. I mean — the LED is— this is amazing.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;R2-D2 beeps smugly, as if to say “I told you it would work.”&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three AI Modes: Choose Your Approach 🧠
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Yoda settles into his hover-chair, ears raised.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; “Three paths in Codey there are. Which to walk, choose wisely you must.”&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;When to use it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Agent&lt;/td&gt;
&lt;td&gt;Writes and edits your code files directly&lt;/td&gt;
&lt;td&gt;Most building tasks — “add a new sensor”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plan&lt;/td&gt;
&lt;td&gt;Drafts a step-by-step plan before touching any code&lt;/td&gt;
&lt;td&gt;Complex integrations — review before committing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ask&lt;/td&gt;
&lt;td&gt;Answers questions without touching files at all&lt;/td&gt;
&lt;td&gt;Learning — “how does tone() work?”&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;YODA:&lt;/strong&gt; “For today, Agent mode sufficient it is. When complex R2’s circuits become, Plan mode you shall choose. Ask mode — when to Yoda you speak, that is.”&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s Next: The Sound of the Force 🔊
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;R2-D2 lets out a cascade of excited beeps — something between a fanfare and an impatient demand.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OBI-WAN:&lt;/strong&gt; “Artoo is right, of course. A droid that only blinks is not yet truly R2-D2. In Episode 2, we give him his voice — those remarkable whistles and beeps that have carried messages across the galaxy. We will connect a piezo buzzer, explore Codey’s Smart Library Picker, and hear R2 speak for the first time.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The LED blinks: two quick, three slow.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Somewhere in the Force, a rebellion stirs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔗 Resources&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Codey Online&lt;/strong&gt;: &lt;a href="https://codey.online" rel="noopener noreferrer"&gt;codey.online&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create free account&lt;/strong&gt;: &lt;a href="https://codey.online/register" rel="noopener noreferrer"&gt;codey.online/register&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OTRONIC&lt;/strong&gt;: &lt;a href="https://www.otronic.nl" rel="noopener noreferrer"&gt;otronic.nl&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;🤖 R2D2 Creation with Codey — building the galaxy’s greatest droid, one episode at a time. May the Force — and the cloud compiler — be with you.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>arduino</category>
      <category>esp32</category>
      <category>ai</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Santa Augmentcode Intent Ep.3</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Wed, 03 Jun 2026 17:48:06 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/santa-augmentcode-intent-ep3-210c</link>
      <guid>https://dev.to/the-software-s-journey/santa-augmentcode-intent-ep3-210c</guid>
      <description>&lt;h1&gt;
  
  
  Santa Plans, Elves Build — Coordinator &amp;amp; Specialist Agents 🧝
&lt;/h1&gt;

&lt;p&gt;Accompanying source code repository: &lt;a href="https://github.com/software-journey/augmentcode-intent" rel="noopener noreferrer"&gt;&lt;code&gt;Santa Augmentcode Intent&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A common misconception about the North Pole is that I build all the toys. I do not. I tried that once in 1742. It was catastrophic. What I do — what I have always done — is understand what needs to be built, break it into sensible pieces, assign the right Elf to each piece, and make sure the whole thing comes together correctly. That is the job of Father Christmas. And, as it turns out, that is also the job of the Coordinator Agent in Augment Intent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Fundamental Division of Labour
&lt;/h2&gt;

&lt;p&gt;There is a reason the Workshop has roles. An Elf who is brilliant at carving wooden horses may be hopeless at soldering circuit boards. Mixing roles creates chaos. Clear roles create Christmas.&lt;/p&gt;

&lt;p&gt;Augment Intent formalises this insight into a three-part agent architecture:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Intent Name&lt;/th&gt;
&lt;th&gt;North Pole Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Plans, delegates, aligns&lt;/td&gt;
&lt;td&gt;Coordinator&lt;/td&gt;
&lt;td&gt;Father Christmas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Executes a specific task&lt;/td&gt;
&lt;td&gt;Specialist / Implementor&lt;/td&gt;
&lt;td&gt;Craft Elves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checks output against the spec&lt;/td&gt;
&lt;td&gt;Verifier&lt;/td&gt;
&lt;td&gt;Quality Control Elves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Explores feasibility&lt;/td&gt;
&lt;td&gt;Investigate Agent&lt;/td&gt;
&lt;td&gt;Scout Elves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Finds and fixes failures&lt;/td&gt;
&lt;td&gt;Debug Agent&lt;/td&gt;
&lt;td&gt;Repair Elves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviews code quality&lt;/td&gt;
&lt;td&gt;Code Review Agent&lt;/td&gt;
&lt;td&gt;Senior Elves&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each role is available as a named Specialist inside Intent. You can use the built-in roster or bring your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Coordinator Does
&lt;/h2&gt;

&lt;p&gt;The Coordinator is the first Agent you interact with in Intent. You give it a goal — in plain language — and it does the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Draft the Living Spec.&lt;/strong&gt; The Coordinator reads your goal, consults the Context Engine (the Workshop’s knowledge of your entire codebase), and produces a structured spec with requirements, constraints, success criteria, and a proposed task breakdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Decompose into parallel tasks.&lt;/strong&gt; The Coordinator identifies which parts of the work can run simultaneously. Building the token service does not depend on the gateway middleware being ready. Both can start at once. The Coordinator maps these dependencies explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Spawn and brief Specialists.&lt;/strong&gt; For each task, the Coordinator creates a Specialist Agent, hands it the relevant portion of the spec, and grants it access to the appropriate files. The Specialist gets what it needs — nothing more, nothing less.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Manage handoffs.&lt;/strong&gt; When Specialist A finishes and Specialist B depends on that result, the Coordinator orchestrates the handoff. The spec updates, B gets the new context, and work continues without human involvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5 — Run the Verifier.&lt;/strong&gt; Once implementation is complete, the Coordinator spawns the Verifier Agent, which checks the output against the spec’s success criteria. If something fails, the Coordinator sends it back to the relevant Specialist.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Specialists Do
&lt;/h2&gt;

&lt;p&gt;Specialists are focused. Each one has a single job and the full Context Engine behind it.&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;Implement Specialist&lt;/strong&gt; receives a task like &lt;em&gt;“add JWT validation middleware to the API gateway”&lt;/em&gt; along with the relevant spec section, the existing middleware code, and the interface contracts agreed with other Specialists. It writes the code, commits it to its isolated branch, and reports back to the Coordinator.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Verify Specialist&lt;/strong&gt; receives the spec’s success criteria and the completed implementation. It runs tests, checks edge cases, and returns a structured verdict: pass, fail, or pass-with-caveats.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;Debug Specialist&lt;/strong&gt; receives a failing test, a stack trace, and the relevant code. Its only job is to find and fix the root cause.&lt;/p&gt;

&lt;p&gt;None of these Specialists needs to know about the other tasks in the session. The Coordinator holds the big picture. The Specialists hold deep focus.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Conversation Pattern
&lt;/h2&gt;

&lt;p&gt;Here is a simplified transcript of how a session looks, using the North Pole analogy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Head Elf Pepper → Coordinator:
"We need JWT authentication across the API gateway and auth service.
Tokens issued by auth-service, validated by gateway middleware.
Support refresh tokens and rate-limit the token endpoint."

Coordinator:
"Understood. I have drafted the spec. I am spawning three Elves:
• Auth Token Elf — implements issuance and refresh in auth-service
• Gateway Middleware Elf — implements validation in api-gateway
• Test Suite Elf — writes integration tests (starts after both finish)
Auth Token Elf and Gateway Middleware Elf are running in parallel now."

[20 minutes pass]

Auth Token Elf → Coordinator:
"Token issuance and refresh complete. Endpoints documented in spec."

Gateway Middleware Elf → Coordinator:
"JWT validation middleware complete. RS256 signing, expiry handling done."

Coordinator → Test Suite Elf:
"Both implementation Elves are done. Here is the updated spec.
Please write integration tests covering token issuance, refresh, expiry,
and rate limiting."

[Test Suite Elf runs]

Coordinator → Verify Elf:
"All tasks complete. Please verify against spec success criteria."

Verify Elf → Coordinator:
"Passed: 8/9 criteria. FAILED: rate limiting returns 429 but does not
include Retry-After header (spec line 14)."

Coordinator → Gateway Middleware Elf:
"Please fix: add Retry-After header to 429 responses."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No human needed to manage any of that. Pepper set the goal. Father Christmas ran the workshop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the Right Model for Each Role
&lt;/h2&gt;

&lt;p&gt;One of Intent’s most practical features is that you can assign different AI models to different roles. Not every task benefits from the most powerful (and most expensive) model.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Task&lt;/th&gt;
&lt;th&gt;Recommended Model Tier&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Coordinator — initial architecture&lt;/td&gt;
&lt;td&gt;Opus (high reasoning)&lt;/td&gt;
&lt;td&gt;Complex decomposition requires deep thinking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implementor — routine code&lt;/td&gt;
&lt;td&gt;Sonnet (fast, efficient)&lt;/td&gt;
&lt;td&gt;Well-scoped tasks need speed, not heavy reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verifier&lt;/td&gt;
&lt;td&gt;Sonnet or Opus&lt;/td&gt;
&lt;td&gt;Depends on spec complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug&lt;/td&gt;
&lt;td&gt;Opus&lt;/td&gt;
&lt;td&gt;Root-cause analysis benefits from thorough reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Father Christmas always uses his best judgment for the biggest decisions and delegates the routine work to whichever Elf is quickest. Intent works the same way.&lt;/p&gt;

&lt;h2&gt;
  
  
  SIPOC: Coordinator → Specialists → Verifier
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;S — Suppliers&lt;/th&gt;
&lt;th&gt;I — Inputs&lt;/th&gt;
&lt;th&gt;P — Process&lt;/th&gt;
&lt;th&gt;O — Outputs&lt;/th&gt;
&lt;th&gt;C — Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who/What&lt;/td&gt;
&lt;td&gt;Developer, Context Engine, AI models&lt;/td&gt;
&lt;td&gt;Goal statement, living spec, codebase, model selection&lt;/td&gt;
&lt;td&gt;Coordinator plans → Specialists implement in parallel → Verifier checks → loop until done&lt;/td&gt;
&lt;td&gt;Verified, spec-compliant implementation, merged PR&lt;/td&gt;
&lt;td&gt;Engineering team, product owner, end users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workshop&lt;/td&gt;
&lt;td&gt;Pepper, the Workshop’s knowledge base, Elf skill roster&lt;/td&gt;
&lt;td&gt;“Implement JWT auth”&lt;/td&gt;
&lt;td&gt;Santa assigns → Elves build simultaneously → QC Elf inspects → rework if needed&lt;/td&gt;
&lt;td&gt;Wrapped, quality-checked gifts ready for the sleigh&lt;/td&gt;
&lt;td&gt;Children worldwide&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Can Go Wrong (And How Intent Handles It)
&lt;/h2&gt;

&lt;p&gt;Even the best Workshop has incidents. An Elf misunderstands a spec line. A dependency is not available. A test fails unexpectedly.&lt;/p&gt;

&lt;p&gt;Intent’s response is always to route the problem back through the spec. The Coordinator does not panic. It reads the failure report, updates the spec with the new constraint or decision, and re-briefs the relevant Specialist. The loop closes cleanly.&lt;/p&gt;

&lt;p&gt;The developer only needs to intervene when the Coordinator surfaces a decision that requires &lt;strong&gt;human judgment&lt;/strong&gt; — a product question, a risk acceptance, a business constraint that was not in the original spec. Everything else is handled in the Workshop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;In Episode 4, we will visit each Elf’s private workbench — the &lt;strong&gt;isolated workspace&lt;/strong&gt; that Intent creates for every agent, ensuring no two Elves ever clobber each other’s work. Git worktrees, parallel branches, and the magic of resumable sessions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every great team needs great coordination. I have been coordinating for over a thousand years. I am pleased that software has finally caught up.Ho ho ho! 🎅&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Part of the &lt;a href="https://dev.to/wvanheemstra/series/37310"&gt;Santa Augmentcode Intent&lt;/a&gt; series. Published on &lt;a href="https://dev.to"&gt;dev.to&lt;/a&gt; under the &lt;a href="https://dev.to/the-software-s-journey"&gt;the-software-s-journey&lt;/a&gt; organisation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>augmentcode</category>
      <category>intent</category>
      <category>aiagents</category>
      <category>agentic</category>
    </item>
    <item>
      <title>Santa Augmentcode Intent Ep.8</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Wed, 03 Jun 2026 17:47:30 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/santa-augmentcode-intent-ep8-o9e</link>
      <guid>https://dev.to/the-software-s-journey/santa-augmentcode-intent-ep8-o9e</guid>
      <description>&lt;h1&gt;
  
  
  The Gifts Are Under the Tree — From Spec to Merged PR 🎄
&lt;/h1&gt;

&lt;p&gt;Accompanying source code repository: &lt;code&gt;Santa Augmentcode Intent&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Every year, on the morning of December 25th, I allow myself one quiet moment before the sleigh is unpacked and the Thank-You Letters start arriving. I sit in the empty Workshop, still warm from the night’s work, and look at the bare shelves where the gifts used to be. They are gone because they were delivered. Every one of them. On time, as specified, to the right address. That moment — that quiet confirmation that everything worked — is what we have been building towards in this entire series. Today, we deliver.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Complete Picture
&lt;/h2&gt;

&lt;p&gt;Over the past seven episodes, we have assembled all the pieces of the Intent workshop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Episode 1&lt;/strong&gt;: The Workshop and what Intent is.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Episode 2&lt;/strong&gt;: The Living Spec — the source of truth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Episode 3&lt;/strong&gt;: Santa the Coordinator and the Specialist Elves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Episode 4&lt;/strong&gt;: Isolated workspaces and resumable sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Episode 5&lt;/strong&gt;: Spec-Driven Development and finishing on time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Episode 6&lt;/strong&gt;: The Context Engine — the Workshop Library.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Episode 7&lt;/strong&gt;: Multi-agent orchestration in waves.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we put them all together and walk through a complete Intent session, from the moment Head Elf Pepper opens the application to the moment the pull request is merged.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Scenario
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Goal&lt;/strong&gt;: Add a real-time gift delivery progress dashboard to the North Pole’s internal web application. The dashboard should show live sleigh position, remaining delivery count, and an estimated completion time. It must work on tablets and update every 30 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constraints&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use the existing Reindeer GPS API (v2)&lt;/li&gt;
&lt;li&gt;No changes to the Delivery Manifest microservice&lt;/li&gt;
&lt;li&gt;Safari / iPad compatible&lt;/li&gt;
&lt;li&gt;Must pass existing end-to-end test suite&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Open Intent and Set the Goal
&lt;/h2&gt;

&lt;p&gt;Pepper opens Intent on her MacBook. She types into the Coordinator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;We need a real-time gift delivery dashboard. Show sleigh position
on a map, remaining delivery count, and estimated completion time.
Updates every 30 seconds. Must work on iPad Safari.
Use Reindeer GPS API v2. No changes to Delivery Manifest Service.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Coordinator reads this prompt alongside the Context Engine’s analysis of the codebase. It knows the existing frontend stack (React, TypeScript), the API patterns used elsewhere in the project, and the existing test suite structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: The Coordinator Drafts the Living Spec
&lt;/h2&gt;

&lt;p&gt;Within seconds, the Coordinator produces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Gift Delivery Dashboard — Living Spec&lt;/span&gt;

&lt;span class="gu"&gt;### Goal&lt;/span&gt;
Real-time dashboard showing sleigh position, delivery count,
and ETA. Updates every 30 seconds. iPad Safari compatible.

&lt;span class="gu"&gt;### Success Criteria&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Map renders in &amp;lt; 1s on iPad Safari
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Position updates within 30s of GPS data change
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Delivery count matches Manifest API response
&lt;span class="p"&gt;-&lt;/span&gt; [ ] ETA calculated from current position + remaining stops
&lt;span class="p"&gt;-&lt;/span&gt; [ ] All existing e2e tests pass
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Lighthouse accessibility score ≥ 90

&lt;span class="gu"&gt;### Constraints&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Reindeer GPS API v2 (existing auth token pattern)
&lt;span class="p"&gt;-&lt;/span&gt; Delivery Manifest Service: read-only, no new endpoints
&lt;span class="p"&gt;-&lt;/span&gt; Safari / iPad: no Chrome-only APIs

&lt;span class="gu"&gt;### Architecture&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; New React component: &lt;span class="sb"&gt;`&amp;lt;DeliveryDashboard /&amp;gt;`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; GPS polling service (30s interval, exponential backoff on fail)
&lt;span class="p"&gt;-&lt;/span&gt; Map: Leaflet.js (already in dependencies — see package.json)
&lt;span class="p"&gt;-&lt;/span&gt; Offline fallback: show last known position with staleness indicator

&lt;span class="gu"&gt;### Tasks&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] GPS Polling Service — GPS Elf
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Map Component — Map Elf
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Delivery Count &amp;amp; ETA Widget — Data Elf
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Safari/iPad CSS fixes — Responsive Elf
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Integration tests — Test Elf (starts after GPS + Map done)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Accessibility audit — A11y Elf (background)

&lt;span class="gu"&gt;### Decisions&lt;/span&gt;
(none yet)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pepper reads the spec. She adds one clarification: &lt;em&gt;“ETA should display in local Workshop time, not UTC.”&lt;/em&gt; The Coordinator updates the spec and records the decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Review time: 4 minutes. No code written yet. One important decision already captured.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Intent Creates Isolated Workspaces
&lt;/h2&gt;

&lt;p&gt;The Coordinator identifies the dependency graph:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GPS Elf and Map Elf can start in parallel immediately.&lt;/li&gt;
&lt;li&gt;Data Elf can start immediately (it only reads from the Manifest API).&lt;/li&gt;
&lt;li&gt;Responsive Elf can start once Map Elf has a working component.&lt;/li&gt;
&lt;li&gt;Test Elf starts after GPS Elf and Map Elf complete.&lt;/li&gt;
&lt;li&gt;A11y Elf runs as a background agent throughout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Intent creates five Git worktrees:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feat/dashboard-gps-service        ← GPS Elf
feat/dashboard-map-component      ← Map Elf
feat/dashboard-data-widgets       ← Data Elf
feat/dashboard-responsive         ← Responsive Elf (waiting)
feat/dashboard-tests              ← Test Elf (waiting)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wave 1 agents — GPS Elf, Map Elf, Data Elf — start simultaneously. The A11y Elf begins in the background.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Wave 1 Runs
&lt;/h2&gt;

&lt;p&gt;Pepper watches the Intent window. Three agent conversations are active. Code appears in the Changes panel. The spec’s task list updates as work progresses.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GPS Elf&lt;/strong&gt; implements the polling service, using the existing auth token pattern it found via the Context Engine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// gps-polling.service.ts&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GpsPollingService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;startPolling&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SleighPosition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;poll&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reindeerGpsApi&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;onUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backoff&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nf"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The spec updates: ✅ GPS Polling Service — GPS Elf — done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Map Elf&lt;/strong&gt; creates the &lt;code&gt;&amp;lt;DeliveryMap /&amp;gt;&lt;/code&gt; component using Leaflet.js, which it found already installed in &lt;code&gt;package.json&lt;/code&gt; via the Context Engine. It does not install a duplicate library.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Elf&lt;/strong&gt; builds the delivery count and ETA widget, correctly calling the Manifest API’s read-only endpoint and displaying ETA in Workshop local time (it read the spec decision).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Handoffs and Wave 2
&lt;/h2&gt;

&lt;p&gt;Both GPS Elf and Map Elf report completion. The spec records the interfaces they produced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### Decisions&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; GPS service exposes: &lt;span class="sb"&gt;`startPolling(cb: (SleighPosition) =&amp;gt; void)`&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Map component props: &lt;span class="sb"&gt;`{ position: SleighPosition; zoom?: number }`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Coordinator briefs Responsive Elf with the updated spec and the actual component structure. No guesswork. Test Elf receives both the GPS service interface and the Map component props, plus the existing e2e test patterns from the Context Engine.&lt;/p&gt;

&lt;p&gt;Wave 2 begins. Responsive Elf adds Safari/iPad CSS. Test Elf writes integration tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: The Verifier Checks Everything
&lt;/h2&gt;

&lt;p&gt;Wave 2 complete. The Coordinator spawns the Verifier Elf with the full spec and all five implementations.&lt;/p&gt;

&lt;p&gt;Verifier’s report:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ Map renders in &amp;lt; 1s on iPad Safari — confirmed (Lighthouse: 0.7s)
✅ Position updates within 30s — confirmed
✅ Delivery count matches Manifest API — confirmed
✅ ETA in Workshop local time — confirmed
✅ Existing e2e tests pass — confirmed
✅ Lighthouse accessibility score ≥ 90 — confirmed (score: 94)
⚠️  Minor: GPS service does not log polling errors to existing
    structured logger (see logger.ts — used throughout codebase)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The warning is real and useful. The Context Engine told the Verifier about &lt;code&gt;logger.ts&lt;/code&gt;. A generic agent would have missed it.&lt;/p&gt;

&lt;p&gt;The Coordinator sends the GPS Elf back for a five-minute fix. It adds one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;GPS polling failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;backoff&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backoff&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Re-verification: all green.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: The Pull Request
&lt;/h2&gt;

&lt;p&gt;The Coordinator integrates all five worktrees into a single branch &lt;code&gt;feat/delivery-dashboard&lt;/code&gt; and opens a pull request. The PR description is generated from the Living Spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Gift Delivery Dashboard&lt;/span&gt;

Implements real-time dashboard (sleigh position, delivery count, ETA).

&lt;span class="gu"&gt;### Changes&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; New: &lt;span class="sb"&gt;`GpsPollingService`&lt;/span&gt; with 30s polling + exponential backoff
&lt;span class="p"&gt;-&lt;/span&gt; New: &lt;span class="sb"&gt;`&amp;lt;DeliveryMap /&amp;gt;`&lt;/span&gt; using existing Leaflet.js dependency
&lt;span class="p"&gt;-&lt;/span&gt; New: &lt;span class="sb"&gt;`&amp;lt;DeliveryStats /&amp;gt;`&lt;/span&gt; widget with ETA in Workshop local time
&lt;span class="p"&gt;-&lt;/span&gt; New: iPad/Safari responsive CSS
&lt;span class="p"&gt;-&lt;/span&gt; New: Integration test suite (12 tests, all passing)

&lt;span class="gu"&gt;### Verified Against Spec&lt;/span&gt;
All 6 success criteria confirmed by Verifier Agent.
Existing e2e suite: all passing.

&lt;span class="gu"&gt;### Decisions Recorded&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; ETA displayed in Workshop local time (not UTC) — per Pepper, Dec 3
&lt;span class="p"&gt;-&lt;/span&gt; Used existing Leaflet.js (not installed new mapping library)
&lt;span class="p"&gt;-&lt;/span&gt; GPS errors logged via existing structured logger (logger.ts)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pepper reviews the spec (4 minutes). She reviews the diff (10 minutes, because the spec told her exactly what to look for). She approves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total elapsed time: 47 minutes. Zero rework. Christmas safe.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Built Together
&lt;/h2&gt;

&lt;p&gt;Over this series, Father Christmas and Head Elf Pepper have explained every layer of Intent:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;th&gt;Workshop Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Living Spec&lt;/td&gt;
&lt;td&gt;Source of truth, auto-updated&lt;/td&gt;
&lt;td&gt;Master Gift List&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coordinator Agent&lt;/td&gt;
&lt;td&gt;Plans, delegates, manages handoffs&lt;/td&gt;
&lt;td&gt;Father Christmas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Specialist Agents&lt;/td&gt;
&lt;td&gt;Execute focused tasks in parallel&lt;/td&gt;
&lt;td&gt;Craft Elves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Isolated Workspaces&lt;/td&gt;
&lt;td&gt;No collisions between parallel agents&lt;/td&gt;
&lt;td&gt;Private workbenches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spec-Driven Development&lt;/td&gt;
&lt;td&gt;Plan first, code follows&lt;/td&gt;
&lt;td&gt;Write the List before carving begins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context Engine&lt;/td&gt;
&lt;td&gt;Deep codebase knowledge for every agent&lt;/td&gt;
&lt;td&gt;The Workshop Library&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multi-Agent Orchestration&lt;/td&gt;
&lt;td&gt;Waves, handoffs, background agents&lt;/td&gt;
&lt;td&gt;Workshop floor choreography&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resumable Sessions&lt;/td&gt;
&lt;td&gt;State preserved across restarts&lt;/td&gt;
&lt;td&gt;Workshop never forgets&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  SIPOC: The Complete Intent Workflow
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;S — Suppliers&lt;/th&gt;
&lt;th&gt;I — Inputs&lt;/th&gt;
&lt;th&gt;P — Process&lt;/th&gt;
&lt;th&gt;O — Outputs&lt;/th&gt;
&lt;th&gt;C — Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who/What&lt;/td&gt;
&lt;td&gt;Developer, Coordinator, Specialists, Context Engine, AI models&lt;/td&gt;
&lt;td&gt;Goal statement, codebase, constraints, model selection&lt;/td&gt;
&lt;td&gt;Spec → Review → Wave 1 agents → Handoffs → Wave 2 → Verifier → PR&lt;/td&gt;
&lt;td&gt;Verified code, living spec, decision log, merged PR&lt;/td&gt;
&lt;td&gt;Engineering team, product owner, CI/CD, end users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workshop&lt;/td&gt;
&lt;td&gt;Pepper, Father Christmas, all Elves, the Library&lt;/td&gt;
&lt;td&gt;Gift order, Workshop constraints, quality standards&lt;/td&gt;
&lt;td&gt;Write List → Agree → Parallel building → Handoffs → QC → Sleigh&lt;/td&gt;
&lt;td&gt;All gifts delivered correctly, on time, to every child&lt;/td&gt;
&lt;td&gt;Children of the world&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Intent is available in &lt;strong&gt;public beta for macOS&lt;/strong&gt;. &lt;a href="https://www.augmentcode.com/product/intent" rel="noopener noreferrer"&gt;Download it here&lt;/a&gt;. It uses your existing Augment credits. You can also bring Claude Code, Codex, or OpenCode if you already have subscriptions.&lt;/p&gt;

&lt;p&gt;Augment’s documentation is at &lt;a href="https://docs.augmentcode.com" rel="noopener noreferrer"&gt;docs.augmentcode.com&lt;/a&gt;. Their manifesto — &lt;em&gt;The End of Linear Work&lt;/em&gt; — is worth reading before your first session.&lt;/p&gt;

&lt;h2&gt;
  
  
  One More Sleigh Stop
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;We have reached the point where the gifts are wrapped, the sleigh is loaded, and the Workshop itself is humming beautifully. But Head Elf Pepper asked me one more excellent question over a final cup of cocoa: *“Santa, what if I want some of this magic outside Intent itself? What if I want Claude Code, the Augment Context Engine, RTK, and LiteLLM working together on a machine of my own?”*Quite right, Pepper. One more stop, then. One more lesson before the reindeer sleep.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the next episode, Father Christmas steps just beyond the Workshop walls to show how Intent’s principles carry into an external, token-aware coding stack: &lt;strong&gt;Claude Code + Augment Context Engine MCP + RTK + LiteLLM on a Mac Mini M4 Pro&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Part of the &lt;em&gt;[*Santa Augmentcode Intent&lt;/em&gt;](&lt;a href="https://dev.to/wvanheemstra/series/37310"&gt;https://dev.to/wvanheemstra/series/37310&lt;/a&gt;)&lt;/em&gt; series. Published on &lt;em&gt;[*dev.to&lt;/em&gt;](&lt;a href="https://dev.to)*"&gt;https://dev.to)*&lt;/a&gt; under the &lt;em&gt;[*the-software-s-journey&lt;/em&gt;](&lt;a href="https://dev.to/the-software-s-journey)*"&gt;https://dev.to/the-software-s-journey)*&lt;/a&gt; organisation.*&lt;/p&gt;

</description>
      <category>augmentcode</category>
      <category>intent</category>
      <category>devworkflow</category>
      <category>aiagents</category>
    </item>
    <item>
      <title>Santa Augmentcode Intent Ep.4</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Wed, 03 Jun 2026 17:47:23 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/santa-augmentcode-intent-ep4-440k</link>
      <guid>https://dev.to/the-software-s-journey/santa-augmentcode-intent-ep4-440k</guid>
      <description>&lt;h1&gt;
  
  
  Every Elf Gets a Workbench — Isolated Workspaces 🔨
&lt;/h1&gt;

&lt;p&gt;Accompanying source code repository: &lt;a href="https://github.com/software-journey/augmentcode-intent" rel="noopener noreferrer"&gt;&lt;code&gt;Santa Augmentcode Intent&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the early Workshop days, all the Elves shared one big table. It seemed efficient. It was a disaster. Jingle would sand a wheel just as Jangle reached for it. Twinkle’s paint would end up on Tinkle’s train set. The great Christmas Collision of 1889 — I do not wish to speak of it. The solution was obvious in retrospect: give every Elf their own workbench. Isolated, private, but connected to the same Master Gift List.Augment Intent does the same thing. It just calls them workspaces.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The Problem With Sharing a Codebase
&lt;/h2&gt;

&lt;p&gt;When multiple agents — or indeed multiple humans — work on the same set of files at the same time, collisions are inevitable. Agent A modifies &lt;code&gt;auth-middleware.ts&lt;/code&gt; at line 47. Agent B modifies the same file at line 52. Neither agent knows the other is there. The merge conflict that results is not a bug in either agent’s reasoning. It is a &lt;strong&gt;coordination failure&lt;/strong&gt; — the absence of isolation.&lt;/p&gt;

&lt;p&gt;Git was designed for humans working mostly in series. A branch is opened, worked on for days or weeks, then merged. The assumption is that the pace of change is human-paced.&lt;/p&gt;

&lt;p&gt;AI agents are not human-paced. They can modify dozens of files in minutes. Under parallel multi-agent execution, the conflict rate rises faster than any team can manage manually.&lt;/p&gt;

&lt;p&gt;Intent solves this with &lt;strong&gt;isolated workspaces backed by Git worktrees&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a Git Worktree?
&lt;/h2&gt;

&lt;p&gt;A worktree is a lesser-known Git feature that allows you to check out &lt;strong&gt;multiple branches of the same repository simultaneously&lt;/strong&gt;, each in its own directory. Unlike opening two terminal windows and hoping for the best, worktrees are a first-class Git concept: they share the repository’s object store, so no data is duplicated, but each worktree has its own working tree and index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Classic git workflow (one checkout)&lt;/span&gt;
git checkout feat/jwt-auth
&lt;span class="c"&gt;# ... work, commit, push&lt;/span&gt;

&lt;span class="c"&gt;# Git worktree (multiple simultaneous checkouts)&lt;/span&gt;
git worktree add ../api-gateway-worktree feat/jwt-auth
git worktree add ../auth-service-worktree feat/auth-service
&lt;span class="c"&gt;# Both directories exist simultaneously, sharing one .git object store&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Intent automates all of this. When the Coordinator spawns a Specialist, Intent creates a dedicated worktree for that agent automatically. The Elf gets its own workbench. Other Elves cannot see its in-progress files. The files are isolated until the Elf is done and the Coordinator integrates the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Elf Workbench in Practice
&lt;/h2&gt;

&lt;p&gt;Imagine the Coordinator has spawned three Specialist Agents for the JWT authentication task from Episode 3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Workshop Floor
├── Auth Token Elf          → worktree: feat/auth-token-service
├── Gateway Middleware Elf  → worktree: feat/gateway-middleware
└── Test Suite Elf          → worktree: feat/integration-tests (waiting)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each worktree contains a copy of the relevant files at the point the Elf starts. Changes made by Auth Token Elf in &lt;code&gt;auth-service/src/token-service.ts&lt;/code&gt; are &lt;strong&gt;invisible to Gateway Middleware Elf&lt;/strong&gt; until they are explicitly integrated. There are no accidental clobberings. No race conditions on file writes.&lt;/p&gt;

&lt;p&gt;The Coordinator tracks the state of each worktree. When both implementation Elves complete, it orchestrates the merge — resolving any conflicts at the spec level (because the interface contracts were declared there) rather than discovering them at the file level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resumable Sessions: The Workshop Is Open When You Return
&lt;/h2&gt;

&lt;p&gt;There is another form of isolation that Father Christmas values enormously: &lt;strong&gt;temporal isolation&lt;/strong&gt;. The ability to close the Workshop at night and find it exactly as you left it in the morning.&lt;/p&gt;

&lt;p&gt;In most AI tools, closing the window ends the session. Context is lost. Agents forget. You start over.&lt;/p&gt;

&lt;p&gt;Intent’s workspaces are &lt;strong&gt;resumable&lt;/strong&gt;. When you close the application and reopen it the next morning, every agent is exactly where it was. The spec is unchanged. The worktrees are intact. The in-progress commits are safe. The Elves are waiting at their workbenches, ready to continue.&lt;/p&gt;

&lt;p&gt;This is possible because Intent uses &lt;strong&gt;auto-commit&lt;/strong&gt; — as agents complete units of work, their changes are committed to their branch automatically. The persistent state is the git history itself, which survives any restart.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Intent workspace state on close:
├── spec: JWT auth — 6/9 tasks complete
├── Auth Token Elf: feat/auth-token-service — all commits saved
├── Gateway Middleware Elf: feat/gateway-middleware — all commits saved
└── Test Suite Elf: feat/integration-tests — waiting to start

Intent workspace state on reopen (next morning):
└── [identical to above — nothing lost]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Father Christmas, this means I can step away from the Workshop on December 23rd for a brief rest, return on the 24th, and find every Elf at their bench with their gifts half-wrapped exactly as I left them. The Workshop never forgets.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Unified Window: Code, Browser, Terminal, Git
&lt;/h2&gt;

&lt;p&gt;Isolation does not mean fragmentation. Intent keeps everything visible in &lt;strong&gt;one window&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;code editor&lt;/strong&gt; shows the active agent’s files.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;built-in Chrome browser&lt;/strong&gt; previews localhost changes in real time.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;terminal&lt;/strong&gt; runs builds, tests, and scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git integration&lt;/strong&gt; handles staging, committing, and branch management.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You do not need to switch between VS Code, iTerm, Chrome, and SourceTree. The Workshop floor is one room with everything on it.&lt;/p&gt;

&lt;p&gt;This matters for agent work because agents need to &lt;strong&gt;see results immediately&lt;/strong&gt;. A Specialist that modifies a React component can open the browser preview in the same window, verify the rendering, and either commit or adjust — without handing off to a human to check.&lt;/p&gt;

&lt;h2&gt;
  
  
  SIPOC: Isolated Workspace Management
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;S — Suppliers&lt;/th&gt;
&lt;th&gt;I — Inputs&lt;/th&gt;
&lt;th&gt;P — Process&lt;/th&gt;
&lt;th&gt;O — Outputs&lt;/th&gt;
&lt;th&gt;C — Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who/What&lt;/td&gt;
&lt;td&gt;Coordinator, Git repository, file system&lt;/td&gt;
&lt;td&gt;Task assignment, branch name, starting file state&lt;/td&gt;
&lt;td&gt;Coordinator spawns agent → Intent creates worktree → Agent works in isolation → Auto-commit saves progress → Coordinator integrates on completion&lt;/td&gt;
&lt;td&gt;Isolated branch per agent, no conflicts, resumable state&lt;/td&gt;
&lt;td&gt;Coordinator Agent, Developer, CI/CD pipeline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workshop&lt;/td&gt;
&lt;td&gt;Father Christmas, the main toy vault&lt;/td&gt;
&lt;td&gt;Elf assignment, workbench materials&lt;/td&gt;
&lt;td&gt;Santa assigns bench → Elf gets private materials → works without interruption → gifts stored safely → Santa integrates at end&lt;/td&gt;
&lt;td&gt;No collisions, no broken gifts, always resumable&lt;/td&gt;
&lt;td&gt;Quality Control, Head Elf Pepper, the Sleigh&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Practical Tip: When to Merge
&lt;/h2&gt;

&lt;p&gt;Father Christmas has one firm rule about workbenches: an Elf’s work stays on their bench until it is &lt;strong&gt;finished and verified&lt;/strong&gt;. Premature merges cause half-built toys to appear in the main inventory, confusing other Elves.&lt;/p&gt;

&lt;p&gt;In Intent terms: the Coordinator should not merge a Specialist’s branch until:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Specialist has reported completion.&lt;/li&gt;
&lt;li&gt;The Verifier Agent has confirmed compliance with the spec.&lt;/li&gt;
&lt;li&gt;Any interface contracts with other Elves have been respected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The spec is the checklist. When all boxes are ticked, the merge is safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;In Episode 5, Father Christmas will explain &lt;strong&gt;Spec-Driven Development&lt;/strong&gt; — the philosophical shift that puts the living spec at the centre of the workflow and uses it to ensure everything finishes in time for Christmas. This is the &lt;em&gt;why&lt;/em&gt; behind everything we have built so far.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A tidy workbench is the sign of an organised mind. And an organised Workshop is the sign of gifts arriving on time.Ho ho ho! 🎅&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Part of the &lt;a href="https://dev.to/wvanheemstra/series/37310"&gt;Santa Augmentcode Intent&lt;/a&gt; series. Published on &lt;a href="https://dev.to"&gt;dev.to&lt;/a&gt; under the &lt;a href="https://dev.to/the-software-s-journey"&gt;the-software-s-journey&lt;/a&gt; organisation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>augmentcode</category>
      <category>intent</category>
      <category>git</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Santa Augmentcode Intent Ep.7</title>
      <dc:creator>Willem van Heemstra</dc:creator>
      <pubDate>Wed, 03 Jun 2026 17:46:46 +0000</pubDate>
      <link>https://dev.to/the-software-s-journey/santa-augmentcode-intent-ep7-1p56</link>
      <guid>https://dev.to/the-software-s-journey/santa-augmentcode-intent-ep7-1p56</guid>
      <description>&lt;h1&gt;
  
  
  Parallel Elves, Zero Chaos — Multi-Agent Orchestration 🎁
&lt;/h1&gt;

&lt;p&gt;Accompanying source code repository: &lt;a href="https://github.com/software-journey/augmentcode-intent" rel="noopener noreferrer"&gt;&lt;code&gt;Santa Augmentcode Intent&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The secret to running a smooth Workshop is understanding the difference between work that can happen at the same time and work that cannot. You cannot paint a toy before it is carved. You cannot test a toy before it is assembled. But you can absolutely carve a hundred toys simultaneously, paint them in parallel once each is carved, and run quality checks in a third wave. The key is knowing the dependencies. The key, always, is the spec.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  From Solo Agent to Agent Orchestra
&lt;/h2&gt;

&lt;p&gt;In the early days of AI-assisted coding, the workflow was simple: one developer, one agent, one task at a time. The agent typed fast, but the work was serial. Task A finished before Task B started.&lt;/p&gt;

&lt;p&gt;This is like running the North Pole Workshop with one Elf. Technically sufficient. Practically absurd.&lt;/p&gt;

&lt;p&gt;The shift to multi-agent work is not simply “run more agents.” It is a fundamentally different coordination challenge. Fred Brooks described it for humans in &lt;em&gt;The Mythical Man-Month&lt;/em&gt;: adding more workers to a project does not automatically accelerate it, because communication overhead grows and integration becomes the dominant cost. AI agents do not repeal this dynamic — they accelerate it.&lt;/p&gt;

&lt;p&gt;Intent’s multi-agent orchestration is the answer to Brooks’ challenge, applied to AI agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three-Wave Pattern
&lt;/h2&gt;

&lt;p&gt;Father Christmas has observed that most Workshop tasks fall into three waves of parallelism. Intent reflects this naturally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wave 1 — Parallel Implementation&lt;/strong&gt;Tasks that are independent of each other can start simultaneously. The Auth Token Elf and the Gateway Middleware Elf do not need each other’s output. They start at the same time, work on separate worktrees, and finish independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wave 2 — Dependent Integration&lt;/strong&gt;Tasks that depend on Wave 1 completing. The Test Suite Elf cannot write meaningful integration tests until both implementation Elves are done. It waits for its inputs, then starts immediately when they arrive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wave 3 — Verification and Review&lt;/strong&gt;The Verifier and Code Review Elves run after Wave 2. They check everything against the spec, catch remaining issues, and produce the final verdict.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wave 1 (parallel):
  Auth Token Elf ─────────────────────── done ──┐
  Gateway Middleware Elf ──────────────── done ──┤

Wave 2 (parallel, starts after Wave 1):          │
  Test Suite Elf ◄──────────────────────────────┤
  Docs Generator Elf ◄──────────────────────────┘

Wave 3 (after Wave 2):
  Verifier Elf ◄──────────────── checks all ──► Report
  Code Review Elf ◄────────────────────────── Review
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Coordinator manages these waves automatically, based on the dependency graph in the spec. No human needs to tell it when Wave 2 can start. The spec encodes that information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background Agents: The Night Shift
&lt;/h2&gt;

&lt;p&gt;Intent also supports &lt;strong&gt;background agents&lt;/strong&gt; — Elves who work quietly while you are focused elsewhere.&lt;/p&gt;

&lt;p&gt;In the JWT authentication example from Episode 3, while the two main implementation Elves are doing their headline work, three background Elves are running simultaneously:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lint &amp;amp; Type Check Elf&lt;/strong&gt;: continuously checking that changes do not break type safety or style rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test Suite Elf&lt;/strong&gt;: writing tests in the background as interfaces are published.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs Generator Elf&lt;/strong&gt;: updating API documentation as endpoint signatures emerge.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These background agents do not block the main flow. They run in their own worktrees, produce their own commits, and report back to the Coordinator when done. The Coordinator integrates their output into the final pull request.&lt;/p&gt;

&lt;p&gt;In the Workshop, these are the Elves who quietly restock materials, update the inventory, and prepare the packaging while the headline crafting is happening. They are not glamorous. They are indispensable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Handoffs Gracefully
&lt;/h2&gt;

&lt;p&gt;The most fragile moment in any multi-agent workflow is the &lt;strong&gt;handoff&lt;/strong&gt;: when one agent’s output becomes another agent’s input.&lt;/p&gt;

&lt;p&gt;Without orchestration, handoffs fail silently. Agent A finishes and commits. Agent B starts and discovers Agent A’s interface is different from what the spec described. Confusion, rework, delay.&lt;/p&gt;

&lt;p&gt;Intent handles handoffs through the spec. When Agent A completes, it &lt;strong&gt;updates the spec&lt;/strong&gt; with the actual interface it produced. The Coordinator reads this update and re-briefs Agent B with the accurate information before it starts. Agent B always starts with the truth.&lt;/p&gt;

&lt;p&gt;This is analogous to a baton in a relay race. The baton is the spec. The Coordinator ensures it is passed correctly. No dropped batons. No Christmas Eve disasters.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Which Specialist
&lt;/h2&gt;

&lt;p&gt;Intent ships with a default set of Specialists. Here is Father Christmas’s guide to deploying them:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Specialist&lt;/th&gt;
&lt;th&gt;When to Use&lt;/th&gt;
&lt;th&gt;North Pole Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Investigate&lt;/td&gt;
&lt;td&gt;Before writing the spec — explore feasibility&lt;/td&gt;
&lt;td&gt;Scout Elves assessing a new toy design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Implement&lt;/td&gt;
&lt;td&gt;Core code production&lt;/td&gt;
&lt;td&gt;Craft Elves at their workbenches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;After implementation — check against spec&lt;/td&gt;
&lt;td&gt;Quality Control Elves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Critique&lt;/td&gt;
&lt;td&gt;Review the spec before coding starts&lt;/td&gt;
&lt;td&gt;Senior Elves challenging the design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debug&lt;/td&gt;
&lt;td&gt;When tests fail or behaviour is wrong&lt;/td&gt;
&lt;td&gt;Repair Elves&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Review&lt;/td&gt;
&lt;td&gt;Automated PR review with codebase context&lt;/td&gt;
&lt;td&gt;Senior Elves reviewing finished work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rule is: &lt;strong&gt;never skip Investigate for genuinely novel tasks&lt;/strong&gt;, and &lt;strong&gt;never skip Verify before merging&lt;/strong&gt;. Skipping these is how gifts arrive with missing parts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bringing Your Own Elves
&lt;/h2&gt;

&lt;p&gt;Intent is designed to be open. You can bring your own specialist agents — Claude Code, OpenAI Codex, or OpenCode — and integrate them into the orchestration. If your team has built a custom agent that specialises in your domain (a “Security Review Elf” that knows your specific compliance requirements, for example), it can be plugged in as a Specialist.&lt;/p&gt;

&lt;p&gt;Father Christmas respects specialisation. The best Toy Locomotive Elf is not the best Rag Doll Elf. The Workshop thrives because it matches the right Elf to the right toy.&lt;/p&gt;

&lt;h2&gt;
  
  
  SIPOC: Multi-Agent Orchestration
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;S — Suppliers&lt;/th&gt;
&lt;th&gt;I — Inputs&lt;/th&gt;
&lt;th&gt;P — Process&lt;/th&gt;
&lt;th&gt;O — Outputs&lt;/th&gt;
&lt;th&gt;C — Customers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who/What&lt;/td&gt;
&lt;td&gt;Coordinator, all Specialist Agents, Context Engine, spec&lt;/td&gt;
&lt;td&gt;Task dependency graph, agent roster, model selections, codebase&lt;/td&gt;
&lt;td&gt;Identify parallelism → Wave 1 agents start → Handoffs via spec → Wave 2 starts → Background agents run → Verifier checks → PR ready&lt;/td&gt;
&lt;td&gt;Verified, integrated pull request; updated spec; decision log&lt;/td&gt;
&lt;td&gt;Developer, CI/CD, code reviewers, end users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workshop&lt;/td&gt;
&lt;td&gt;Father Christmas, all Elves, the Library&lt;/td&gt;
&lt;td&gt;Dependency chart, Elf skills, material availability&lt;/td&gt;
&lt;td&gt;Independent tasks start together → Handoffs recorded in Master List → Dependent tasks start when inputs ready → QC checks everything&lt;/td&gt;
&lt;td&gt;All gifts built correctly, verified, packaged, on the sleigh&lt;/td&gt;
&lt;td&gt;Children, parents, Christmas morning&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The Mythical Man-Month, Solved (Partially)
&lt;/h2&gt;

&lt;p&gt;Brooks was right: coordination is the dominant cost. Adding more agents to a poorly organised task makes it worse.&lt;/p&gt;

&lt;p&gt;But Brooks was writing about human coordination, with its communication overhead and context-switching costs. Intent changes the calculus. When the spec is the coordination layer — when every agent is briefed from the same living document, when handoffs are managed by the Coordinator, when each agent has its own isolated workspace — the overhead of adding an agent is dramatically lower than adding a human.&lt;/p&gt;

&lt;p&gt;Not zero. Not magic. But dramatically lower.&lt;/p&gt;

&lt;p&gt;This is how the North Pole gets better every year. We do not just add Elves. We improve the coordination. The Workshop gets smarter, not just bigger.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Comes Next
&lt;/h2&gt;

&lt;p&gt;In our final episode, Father Christmas walks you through the complete journey: from first prompt to &lt;strong&gt;merged pull request&lt;/strong&gt;. We bring together the spec, the Coordinator, the Elves, the workbenches, the Context Engine, and the orchestration — and we ship.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An orchestra without a conductor is noise. With a conductor, it is music. The spec is the score. The Coordinator is the conductor. The Elves are the musicians. And the result, when everything works, is Christmas.Ho ho ho! 🎅&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Part of the &lt;a href="https://dev.to/wvanheemstra/series/37310"&gt;Santa Augmentcode Intent&lt;/a&gt; series. Published on &lt;a href="https://dev.to"&gt;dev.to&lt;/a&gt; under the &lt;a href="https://dev.to/the-software-s-journey"&gt;the-software-s-journey&lt;/a&gt; organisation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>augmentcode</category>
      <category>intent</category>
      <category>multiagent</category>
      <category>orchestration</category>
    </item>
  </channel>
</rss>
