Episode 4: The All-Seeing Eye
"Impressive. Most Impressive." ποΈ
Darth Vader enters β wait, no. Wrong side.
Luke Skywalker stands at the workbench, holding an HC-SR04 ultrasonic sensor up to the light.
LUKE: "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."
R2-D2 beeps softly, as if this is a deeply personal topic.
LUKE: "Today we give him that. The sensor eye. And this timeβ" he gestures at the screen "βCodey's going to show us something called Auto Error Fixing. Because I have a feeling we're going to need it."
From somewhere unseen, a voice floats through the Force.
VADER: "Your lack of a level-shifted data pin... disturbs me."
LUKE: "We're on 5V. We'll be fine."
ποΈ SIPOC β The Sensor Eye System
| Suppliers | Inputs | Process | Outputs | Customers |
|---|---|---|---|---|
| You (the maker) | "Add HC-SR04 on pins 9/10 and PIR on pin 2, react with beeps and dome color changes" | Codey writes sensor code, integrates with sound and dome systems from previous episodes | Unified firmware: sense β respond with light + sound | R2-D2 β who now reacts to the world around him |
| HC-SR04 Sensor | 5V power, TRIG pulse from Arduino | Emits ultrasonic pulse, measures return echo time | Distance in centimetres | The code β which decides how close is "too close" |
| PIR Motion Sensor | 5V power, GPIO input to Arduino | Digital HIGH when motion detected | A HIGH signal on the interrupt pin | The code β which triggers the alert sequence |
| Auto Error Fixing | A compilation error from incorrect code | Codey reads the error log, rewrites the offending lines, recompiles | Fixed code that compiles successfully | You β who get working firmware without decoding C++ error messages |
| Vision Feature | A photo of your breadboard | Codey reads the image and identifies component placement | A verification report: "Wiring looks correct" or specific mismatches | You β who confirm wiring before upload |
The Components π§
C-3PO enters with a tray of precisely arranged components.
C-3PO: "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."
R2-D2 beeps something that sounds like "nobody asked you to sort them."
| Component | Quantity | Notes |
|---|---|---|
| Arduino UNO R3 | 1 | Our trusted base |
| HC-SR04 ultrasonic sensor | 1 | 5V, TRIG + ECHO pins |
| HC-SR501 PIR sensor | 1 | 5V, single digital output |
| 10kΞ© resistor | 1 | PIR output pull-down (some modules need it) |
| Jumper wires | 6 | |
| USB cable | 1 |
Plus the buzzer from Episode 2 and NeoPixel ring from Episode 3 β we are building on the complete system.
The Codey Prompt β Building on What We Have π¬
Han Solo points at the screen.
HAN: "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."
LUKE: "You're comparing Codey to smuggling?"
HAN: "I'm saying context matters. Do you want the lecture or the sensor?"
Open your Codey project (from Episode 3 milestone). In Agent mode:
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 < 30cm: trigger alert animation + alert sound
- If distance < 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().
Generated Code Addition to animations.h
// ββ Sensor additions (append to animations.h) βββββββββββββββββββ
// ββ HC-SR04 βββββββββββββββββββββββββββββββββββββββββββββββββββββ
#define TRIG_PIN 9
#define ECHO_PIN 10
unsigned long lastSonarMs = 0;
float lastDistance = 999.0f;
float readDistance() {
// Non-blocking: only trigger if enough time has passed
unsigned long now = millis();
if (now - lastSonarMs < 150) return lastDistance;
lastSonarMs = now;
// Send 10Β΅s TRIG pulse
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Read echo duration (timeout 30ms = ~5m max range)
long duration = pulseIn(ECHO_PIN, HIGH, 30000UL);
if (duration == 0) return 999.0f;
// Convert to centimetres
lastDistance = (duration * 0.0343f) / 2.0f;
return lastDistance;
}
// ββ PIR Motion Sensor ββββββββββββββββββββββββββββββββββββββββββββ
#define PIR_PIN 2
volatile bool motionDetected = false;
void IRAM_ATTR onMotion() {
motionDetected = true;
}
// ββ Reactive behaviour in updateAnimations() βββββββββββββββββββββ
// (replaces/extends the existing updateAnimations function)
void updateAnimationsSensors() {
unsigned long now = millis();
// ββ Check PIR first (interrupt-driven, higher priority) βββββ
if (motionDetected) {
motionDetected = false;
currentState = SCAN;
stateStartMs = now;
Serial.println("Motion detected β scan mode!");
}
// ββ Check HC-SR04 distance βββββββββββββββββββββββββββββββββ
float dist = readDistance();
if (dist < 15.0f) {
// Very close β full red alert
if (currentState != ALERT) {
currentState = ALERT;
stateStartMs = now;
tone(BUZZER_PIN, 2637); // C6 β high alert tone
}
// Override: set all LEDs red while this close
for (int i = 0; i < NUMPIXELS; i++) {
ring.setPixelColor(i, ring.Color(BRIGHTNESS, 0, 0));
}
ring.show();
return;
} else if (dist < 30.0f) {
// Approaching β amber warning
if (currentState == IDLE) {
currentState = ALERT;
stateStartMs = now;
}
} else {
noTone(BUZZER_PIN); // Silence if moved away
}
// ββ Normal state machine ββββββββββββββββββββββββββββββββββββ
updateAnimations(); // existing function handles the rest
}
Updated r2d2-dome.ino
// r2d2-dome.ino β updated for sensor eye
#include <Adafruit_NeoPixel.h>
#include "animations.h"
void setup() {
Serial.begin(9600);
initAnimations();
// Sensor pins
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(PIR_PIN, INPUT);
// PIR interrupt β fires on rising edge (motion start)
attachInterrupt(digitalPinToInterrupt(PIR_PIN), onMotion, RISING);
Serial.println("R2-D2 sensor eye online!");
}
void loop() {
updateAnimationsSensors(); // new unified call
}
Auto Error Fixing in Action π οΈ
And then it happens.
LUKE: "I tried to compile andβ"
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
LUKE: "What does that mean? I justβ"
Before Luke can panic, the screen updates automatically.
CODEY AUTO ERROR FIX:
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...
β Compilation successful (after auto-fix)
Board: Arduino UNO R3
Sketch: r2d2-dome.ino + animations.h
Size: 9,104 bytes (28% of flash)
LUKE: "It... fixed it. By itself."
HAN: "Never tell me the odds."
LUKE: "That's not the sameβ"
HAN: "The AI fixed its own mistake without you having to understand why. That's what matters."
The Wiring Diagram β Three Systems Now π§
Click Wiring Diagram. The diagram now shows all three systems:
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 β
ββββββββββββββββββββββ΄βββββββββββββββββββββββββββββββββββ
C-3PO: "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."
Vision Feature: "Is My Breadboard Wired Correctly?" ποΈ
Luke takes a photo of his assembled breadboard.
LUKE: "Before I upload β can I check this with Codey? Just to be sure?"
Click the Vision icon in Codey (Pro feature). Upload the breadboard photo.
Codey responds:
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!
Luke examines the breadboard.
LUKE: "The resistor... it's in the wrong row. It's not actually connected to anything."
R2-D2 beeps in the tone of "I could have told you that."
LUKE: "Vision just saved R2's dome lights."
What's Next: The Holographic Projector π½οΈ
Obi-Wan's presence fills the workshop like warm light.
OBI-WAN: "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?"
LUKE: "Help me, Obi-Wan Kenobi. You're my only hope."
OBI-WAN: "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."
R2-D2 beeps the opening notes of the Princess Leia theme.
π Resources
- HC-SR04 with Arduino: Search "HC-SR04 Arduino tutorial"
- PIR HC-SR501: Search "HC-SR501 Arduino interrupt"
- Codey Online Vision: codey.online β Pro feature
- Auto Error Fixing: built into all Codey plans
π€ 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.
Top comments (0)