The Peacock Robot
That Dances
22 synchronized servo motors open a full tail fan, ripple feathers in waves, draw spirals and hearts in the air, sway the neck, blink real eyes — all choreographed by a single ESP32. 🦚
What Are We Actually Building?
This is the most ambitious robotics project in this entire series — and arguably the most beautiful. A life-sized (or half-sized) peacock sculpture stands on a glossy black stage. Its skeleton is built from aluminium rods and 3D-printed joints. Twenty-two servo motors are embedded throughout the structure, controlled by two PCA9685 servo driver boards daisy-chained to a single ESP32.
When the program runs, the peacock performs a full choreographed display:
- The tail fan opens slowly from closed to full spread (approximately 140° arc)
- A ripple wave rolls from left to right across all 10 tail feathers simultaneously
- The feathers draw a spiral pattern — each one traces an arc like spokes on a spinning wheel
- All feathers form a heart shape by curving inward at the right timing
- The neck sways gently left to right while the head tilts and turns
- Both eyes blink using small servo-actuated eyelid mechanisms
- The body bobs up and down slightly with the rhythm
- Finally, the tail fans out and closes repeatedly in a graceful dance
Natural peacock feathers are mounted on servo arms so they physically move. Under coloured LED lighting, the iridescent feather eyes shimmer with every movement — exactly like a real peacock display, but controlled entirely by code you write.
Every Servo's Role
Each servo has a specific job. Two PCA9685 boards daisy-chained handle all 22 channels. Board A = tail and body. Board B = head, neck, and eyes.
Tail Feathers — Board A (Ch 0–9)
| Ch | Servo | Motion |
|---|---|---|
| A0 | Feather 1 (Far Left) | Rotate 0–90° |
| A1 | Feather 2 | Rotate 0–90° |
| A2 | Feather 3 | Rotate 0–90° |
| A3 | Feather 4 | Rotate 0–90° |
| A4 | Feather 5 (Left Mid) | Rotate 0–90° |
| A5 | Feather 6 (Centre) | Rotate 0–90° |
| A6 | Feather 7 (Right Mid) | Rotate 0–90° |
| A7 | Feather 8 | Rotate 0–90° |
| A8 | Feather 9 | Rotate 0–90° |
| A9 | Feather 10 (Far Right) | Rotate 0–90° |
Body & Tail Spread — Board A (Ch 10–15)
| Ch | Servo | Motion |
|---|---|---|
| A10 | Tail Left Spread | Fan left arc 0–70° |
| A11 | Tail Right Spread | Fan right arc 0–70° |
| A12 | Tail Elevation | Tilt up/down 60–110° |
| A13 | Body Sway L/R | Lean ±20° |
| A14 | Body Bob Up/Down | Rise/fall 10mm |
| A15 | Wing L (open/close) | 0–45° spread |
Head & Neck — Board B (Ch 0–5)
| Ch | Servo | Motion |
|---|---|---|
| B0 | Neck Pan (L/R) | ±40° from centre |
| B1 | Neck Tilt (U/D) | ±20° nod |
| B2 | Head Turn | ±30° yaw |
| B3 | Head Tilt | ±20° roll |
| B4 | Left Eye Blink | 0–30° eyelid |
| B5 | Right Eye Blink | 0–30° eyelid |
The 8 Dance Patterns
Each pattern is a mathematical function applied across the 10 tail feather servos. The beauty of this system is that incredibly complex visual effects come from simple trigonometry.
Ripple Wave
A sine wave travels left to right across the feathers. Each feather's angle is offset by a delay — the wave appears to travel across the whole fan.
angle[i] = centre + amplitude × sin(t + i × delay)
Spiral
Each feather rotates by a continuously increasing offset, making the whole fan appear to spin like a galaxy, spiralling inward then outward.
angle[i] = base + (i × 14°) + t × speed
Heart Pattern
Feathers curve inward symmetrically from both edges toward the centre — the tips form the top lobes of a heart, while centre feathers form the bottom point.
angle[i] = heart_curve(i, t)
Bloom Open
Starting from fully closed, all feathers radiate outward to their final spread positions simultaneously, like a flower blooming in slow motion.
angle[i] = lerp(closed, open, easeOut(t))
Electric Shimmer
Very rapid small oscillations across all feathers at slightly different frequencies create a shimmering, electrified look — perfect under LED lighting.
angle[i] = base + 6 × sin(t × (8+i))
Rainbow Cascade
Feathers open one at a time from left to right, each waiting for the previous to complete — like a rainbow appearing stroke by stroke.
start_time[i] = i × delay_ms
Dance Sway
Combines body lean left/right with feather ripple and neck sway all in synchrony — the whole robot sways rhythmically like a dancer.
body[A13] = 20 × sin(t × dance_bpm)
Greeting Bow
Neck bends forward and down while feathers close briefly, then spring open again as the head rises — like a performer taking a bow.
neck_tilt = bow_curve(t); fan = bloom(t+0.5)
Everything You Need
Order in stages — start with the electronics and test them before buying structural materials.
🧠 Electronics
ESP32 Dev Board
Master controller — dual-core 240MHz, plenty of speed to run all 22 servo calculations simultaneously.
2× PCA9685 16-Ch Servo Driver
Each board drives up to 16 servos via I²C. Daisy-chained with different addresses (0x40 and 0x41).
5V 10A Power Supply
Servos at full load can draw 500mA each. 22 servos × 0.5A = 11A peak. A 10A supply handles real-world usage comfortably.
DC-DC Buck Converter (5V 3A)
Separate 5V regulated supply for ESP32 and logic — never share servo power with the microcontroller.
Capacitors (1000µF 16V × 4)
Placed near each servo power rail on the breadboard — absorbs voltage spikes when multiple servos move at once.
Toggle Switch + Power LED
Main on/off switch for the 5V servo supply, with a status LED to show the system is live.
⚙️ Servo Motors
18× MG996R Metal Gear Servo
For all 10 tail feathers (individual rotation) + tail spread arms + body sway + wing. Metal gears essential — plastic strips under load.
4× SG90 Micro Servo
Lighter-duty servos for eye blink and head tilt where weight matters more than torque. Small and lightweight.
🏗️ Structure
Aluminium Round Rod (6mm, 2m)
Forms the spine, neck, and tail fan spreader arms. Lightweight but rigid. Cut to size with a hacksaw.
3D Printed Joints & Servo Mounts
Custom printed brackets that connect servos to the aluminium frame. Print in PETG for strength. Free STL designs on Thingiverse.
Glossy Black Acrylic Stage (30×30cm)
The performance platform. Acrylic gives the mirror-reflection effect under LED lighting. Drill mounting holes for the peacock base.
M3 Bolts, Nuts, Washers (Assorted)
For securing servo mounts to the aluminium frame. Thread-locking compound prevents vibration from loosening joints during performance.
🦚 Feathers & Decoration
20 Real Peacock Tail Feathers
Available from craft shops and bird farms. Use genuine iridescent feathers — the shimmer effect under LED light is breathtaking. Larger "eye" feathers for display, smaller coverts for fill.
RGB LED Strip (5V WS2812B, 2m)
Back-lights the stage and feathers from below. Controlled by a second ESP32 GPIO pin. Changes colour to match each dance pattern.
Foam Craft Sheet (Blue/Green)
For the body covering — cut to shape and paint with iridescent craft paint to simulate feather texture on the body and neck.
Glass Dome Eyes (20mm, amber)
Pre-made realistic bird eyes give the head an authentic alive look. Glue into 3D-printed eye sockets with small SG90 servos behind them for blinking.
Full Wiring Architecture
Two PCA9685 boards share one I²C bus. Board A controls tail feathers and body. Board B controls head, neck, and eyes. Both get power from the 5V 10A supply.
Critical wiring notes: (1) Never share the servo 5V rail with the ESP32 — motor current spikes can reset the microcontroller. (2) Add 1000µF capacitors across the 5V/GND rails near each PCA9685 board. (3) Both PCA9685 boards share the same SDA/SCL lines but have different I²C addresses — set address using the A0 jumper pad on each board (Board A: A0 unsoldered = 0x40, Board B: A0 soldered = 0x41).
Building the Frame
The frame has three sub-assemblies that build independently before being joined.
The Spine and Tail Mount
Cut a 40cm length of 6mm aluminium rod as the main spine. At the bottom, bolt it to a 3D-printed base plate that will be screwed to the acrylic stage. At the top (30cm up), attach a 3D-printed T-junction where the neck rod meets the tail fan bracket.
The tail fan bracket is a semi-circular aluminium strip (30cm diameter arc) with 10 servo mounting holes spaced evenly around it. Each MG996R servo mounts upward through these holes, shaft pointing up — this is where the feathers attach.
The Neck Assembly
The neck is two servo mechanisms stacked: a pan servo (horizontal rotation) mounted on top of the spine T-junction, and a tilt servo (nod up/down) above that. A 15cm rod connects the tilt servo to the head mount ball.
- Spine T-junction → Neck Pan servo (Board B, Ch 0)
- Pan output → Neck Tilt servo arm (Board B, Ch 1)
- Tilt output → 15cm aluminium rod → Head Ball Joint
The Head Assembly
3D print a hollow egg-shaped head (60mm diameter). Mount the Head Turn servo inside the neck connector, and the Head Tilt servo above it. The two SG90 eye-blink servos sit behind the eye sockets with a thin plastic arm that acts as the eyelid.
Body and Wing Mounts
The body is an oval foam core (approx 12×8×6cm) carved from styrofoam and covered with iridescent craft foam. Two holes in the bottom mount it on the spine. The body sway servo (Board A, Ch 13) connects via a push-rod to the body block. Wing rods (aluminium, 12cm) extend from each side with an MG996R at the shoulder joint.
Mounting the Natural Feathers
Prepare the Feathers
Select 10 matched peacock tail feathers of similar length (ideally 50–70cm). Lay them on a flat surface and sort them by size — the largest go in the centre, slightly smaller ones toward the edges. Trim the quill (stem) at the bottom with sharp scissors to leave 15cm of quill below the feather vane.
Create Feather Holders
3D print or cut 10 small tube holders (8mm inner diameter, 6cm long) that can grip each quill tightly. The top of each holder has a slot for the servo horn. Drill one small hole through the side for a set screw that grips the quill without crushing it.
Attach to Servo Horns
Position all 10 tail servos to their 0° position (closed). Attach each feather holder to the corresponding servo horn with the feather resting against the back plate. When the servo rotates to 90°, the feather should swing forward to its display position. Tighten all set screws and test each one manually before programming.
Balance Check
With all 10 feathers attached, run the fan-open sequence and check that no feather catches on another. The feathers should overlap slightly when fully open (like a real peacock tail) — this is correct. If any feather is twisted, loosen its holder, straighten it, and re-tighten. Add small neodymium magnets as inter-feather guides if needed to prevent tangling during fast movements.
Step-by-Step Build Log
Set Up the Stage Platform
Drill a 12mm hole in the centre of the acrylic stage for the spine rod. Attach four rubber feet to the underside. Run the 5V power supply cable and LED strip cable through the hole before inserting the base plate. Secure the base plate with M3 countersunk bolts from below.
Install the Electronics Box
Mount the ESP32, both PCA9685 boards, buck converter, and capacitors on a small project board attached to the back of the spine rod, approximately 10cm above the stage floor. Connect I²C wires (SDA, SCL, 3.3V, GND) from the ESP32 to both PCA9685 boards. Connect the 5V servo power bus with thick wires (at least 20 AWG) to both boards' V+ and GND terminals.
Mount Tail Servos on Fan Bracket
Install all 10 MG996R tail servos into the fan bracket holes. Connect each servo's 3-wire cable to the PCA9685 Board A channels 0–9 respectively (left-to-right = Ch0 to Ch9). Route the cables neatly down the back of the bracket and secure with cable ties every 5cm.
Connect Head and Neck Servos
Wire the 4 MG996R neck/head servos and 2 SG90 eye servos to PCA9685 Board B channels 0–5. Test each servo individually using a servo test sketch before attaching the mechanical assembly — confirming correct motion before assembly saves enormous time.
Install LED Stage Lighting
Attach the WS2812B LED strip in a ring under the acrylic stage edge, facing inward and upward. Connect its data line to GPIO4 on the ESP32. Install the Adafruit NeoPixel library and test the LEDs with a rainbow cycle before continuing.
Calibrate All Servos
Upload the calibration sketch (provided in the code section below) to find the exact minimum and maximum pulse widths for each of your specific servo units — they vary by ±10% from the nominal values. Record these in a calibration table and enter them as constants in the main code. This step makes the difference between rough and silky-smooth motion.
Full ESP32 Peacock Code
This code manages all 22 servos across two PCA9685 boards with smooth interpolation, and cycles through all 8 dance patterns automatically.
Install These Libraries First
# In Arduino Library Manager, install:
# • Adafruit PWM Servo Driver Library (PCA9685)
# • Adafruit NeoPixel (LED strip)
# • Wire.h (built-in I²C)
/* Peacock Dance Robot — Full Choreography Code ESP32 + 2× PCA9685 + 22 Servo Motors + WS2812B LEDs Board A (0x40): Tail feathers 0–9, spread 10–11, body 12–14 Board B (0x41): Neck 0–1, head 2–3, eyes 4–5 */ #include <Wire.h> #include <Adafruit_PWMServoDriver.h> #include <Adafruit_NeoPixel.h> #include <math.h> // ── Hardware objects ──────────────────────────────────────────── Adafruit_PWMServoDriver boardA = Adafruit_PWMServoDriver(0x40); Adafruit_PWMServoDriver boardB = Adafruit_PWMServoDriver(0x41); Adafruit_NeoPixel strip(30, 4, NEO_GRB + NEO_KHZ800); // ── Servo pulse width constants (µs → PCA9685 ticks at 50Hz) ─── // IMPORTANT: Calibrate these for YOUR specific servos! #define SERVOMIN 150 // ~0.5ms pulse = 0° #define SERVOMAX 600 // ~2.5ms pulse = 180° #define SERVOMID 375 // ~1.5ms pulse = 90° // ── Channel assignments ───────────────────────────────────────── #define NUM_TAIL 10 // channels A0–A9 #define CH_SPREAD_L 10 // Board A #define CH_SPREAD_R 11 #define CH_TAIL_ELV 12 #define CH_BODY_SWAY 13 #define CH_BODY_BOB 14 #define CH_NECK_PAN 0 // Board B #define CH_NECK_TILT 1 #define CH_HEAD_TURN 2 #define CH_HEAD_TILT 3 #define CH_EYE_L 4 #define CH_EYE_R 5 // ── State arrays ───────────────────────────────────────────────── float featherAngle[NUM_TAIL] = {90,90,90,90,90,90,90,90,90,90}; // 90 = centre float currentAngle[NUM_TAIL]; // actual displayed angle uint32_t t = 0; // global animation frame counter int currentPattern = 0; uint32_t patternStart = 0; const uint32_t PATTERN_DUR = 12000; // 12 seconds per pattern // ── Convert angle (0–180°) to PCA9685 tick value ──────────────── uint16_t angleToPulse(float angle) { angle = constrain(angle, 0, 180); return (uint16_t) map((long)(angle * 100), 0, 18000, SERVOMIN, SERVOMAX); } // ── Write to Board A or B ──────────────────────────────────────── void setServoA(uint8_t ch, float angle) { boardA.setPWM(ch, 0, angleToPulse(angle)); } void setServoB(uint8_t ch, float angle) { boardB.setPWM(ch, 0, angleToPulse(angle)); } // ── Smooth interpolation helper ────────────────────────────────── float lerpf(float a, float b, float t) { return a + (b - a) * constrain(t,0,1); } float easeInOut(float t) { return t*t*(3-2*t); } // ═══════════════════════════════════════════════════════════════ // PATTERN 0 — RIPPLE WAVE // ═══════════════════════════════════════════════════════════════ void patternRipple(float phase) { float f = phase * 6.28f; for (int i = 0; i < NUM_TAIL; i++) { featherAngle[i] = 90 + 35 * sin(f + i * 0.62f); } // Neck follows the wave setServoB(CH_NECK_PAN, 90 + 20 * sin(f)); setServoB(CH_HEAD_TURN, 90 + 15 * sin(f + 0.5f)); // Peacock colours setLEDPattern(0, 150, 137); // teal } // ═══════════════════════════════════════════════════════════════ // PATTERN 1 — SPIRAL // ═══════════════════════════════════════════════════════════════ void patternSpiral(float phase) { float f = phase * 6.28f; for (int i = 0; i < NUM_TAIL; i++) { float offset = i * (180.0f / NUM_TAIL); featherAngle[i] = 90 + 45 * sin(f + offset * 0.0175f); } setServoA(CH_BODY_SWAY, 90 + 12 * sin(f * 2)); setLEDPattern(100, 0, 200); // purple } // ═══════════════════════════════════════════════════════════════ // PATTERN 2 — HEART // ═══════════════════════════════════════════════════════════════ void patternHeart(float phase) { float t2 = easeInOut(sin(phase * 3.14f) * 0.5f + 0.5f); for (int i = 0; i < NUM_TAIL; i++) { float norm = (float)i / (NUM_TAIL - 1); // 0.0 to 1.0 left to right float heartY; if (norm < 0.5f) { float x = norm * 2 - 1; // -1 to 0 heartY = sqrt(1 - (x + 0.5f) * (x + 0.5f) * 1.2f); } else { float x = norm * 2 - 1; // 0 to 1 heartY = sqrt(1 - (x - 0.5f) * (x - 0.5f) * 1.2f); } featherAngle[i] = 90 + (40 * heartY - 20) * t2; } setServoB(CH_NECK_TILT, 90 - 10 * t2); setLEDPattern(220, 20, 60); // rose red } // ═══════════════════════════════════════════════════════════════ // PATTERN 3 — BLOOM OPEN & CLOSE // ═══════════════════════════════════════════════════════════════ void patternBloom(float phase) { float spread = easeInOut(phase < 0.5f ? phase * 2 : (1 - phase) * 2); for (int i = 0; i < NUM_TAIL; i++) { float delay = abs(i - 4.5f) * 0.08f; // centre opens first float localT = constrain((phase - delay) / (1.0f - delay), 0, 1); featherAngle[i] = lerpf(90, 90 + 50 * (i < 5 ? -1 : 1), easeInOut(localT)); } setServoA(CH_SPREAD_L, lerpf(90, 140, spread)); setServoA(CH_SPREAD_R, lerpf(90, 40, spread)); setLEDPattern(0, 180, 80); // emerald } // ═══════════════════════════════════════════════════════════════ // PATTERN 4 — ELECTRIC SHIMMER // ═══════════════════════════════════════════════════════════════ void patternShimmer(float phase) { float f = phase * 12.56f; // 2 full cycles per pattern for (int i = 0; i < NUM_TAIL; i++) { featherAngle[i] = 90 + 6 * sin(f * (8 + i * 1.5f) + i * 0.8f); } setServoA(CH_BODY_BOB, 90 + 8 * sin(f * 3)); uint32_t cTime = millis(); uint8_t r = 128 + 127 * sin(cTime * 0.003f); uint8_t g = 128 + 127 * sin(cTime * 0.004f + 2.1f); uint8_t b = 128 + 127 * sin(cTime * 0.005f + 4.2f); setLEDPattern(r, g, b); } // ═══════════════════════════════════════════════════════════════ // PATTERN 5 — RAINBOW CASCADE // ═══════════════════════════════════════════════════════════════ void patternCascade(float phase) { for (int i = 0; i < NUM_TAIL; i++) { float startT = i * 0.08f; float localT = constrain((phase - startT) / 0.5f, 0, 1); float target = (i < 5) ? 90 - 40 : 90 + 40; featherAngle[i] = (phase < 0.5f) ? lerpf(90, target, easeInOut(localT)) : lerpf(target, 90, easeInOut(constrain((phase - 0.5f - startT) / 0.5f, 0, 1))); } setLEDPattern(255, 165, 0); // gold } // ═══════════════════════════════════════════════════════════════ // PATTERN 6 — DANCE SWAY // ═══════════════════════════════════════════════════════════════ void patternDance(float phase) { float beat = sin(phase * 6.28f * 2); // 2 sways per cycle for (int i = 0; i < NUM_TAIL; i++) { featherAngle[i] = 90 + 25 * sin(phase * 6.28f * 2 + i * 0.5f); } setServoA(CH_BODY_SWAY, 90 + 18 * beat); setServoA(CH_BODY_BOB, 90 + 10 * abs(beat)); setServoA(CH_SPREAD_L, 90 + 30 * (0.5f + 0.5f * sin(phase * 6.28f))); setServoA(CH_SPREAD_R, 90 - 30 * (0.5f + 0.5f * sin(phase * 6.28f))); setServoB(CH_NECK_PAN, 90 + 25 * beat); setLEDPattern(60, 0, 200); // deep violet } // ═══════════════════════════════════════════════════════════════ // PATTERN 7 — GREETING BOW // ═══════════════════════════════════════════════════════════════ void patternBow(float phase) { float bowT = easeInOut(sin(phase * 3.14f)); for (int i = 0; i < NUM_TAIL; i++) { featherAngle[i] = lerpf(90, 90 + 40 * (i < 5 ? -1 : 1), phase > 0.5f ? (phase - 0.5f) * 2 : 0); } setServoB(CH_NECK_TILT, 90 - 30 * bowT); // bow forward setServoB(CH_HEAD_TILT, 90 - 15 * bowT); setLEDPattern(200, 180, 0); // gold bow } // ── Shared: blink and body update ──────────────────────────────── void updateEyesAndBody(float phase) { float f = phase * 6.28f; // Periodic eye blink (natural feel) bool blink = (sin(f * 0.4f) > 0.96f); setServoB(CH_EYE_L, blink ? 60 : 90); setServoB(CH_EYE_R, blink ? 60 : 90); // Gentle body elevation breathing setServoA(CH_TAIL_ELV, 85 + 5 * sin(f)); } // ── LED stage colour ───────────────────────────────────────────── void setLEDPattern(uint8_t r, uint8_t g, uint8_t b) { for (int i = 0; i < strip.numPixels(); i++) strip.setPixelColor(i, r, g, b); strip.show(); } // ── Apply all feather angles ────────────────────────────────────── void applyFeathers() { for (int i = 0; i < NUM_TAIL; i++) { currentAngle[i] = lerpf(currentAngle[i], featherAngle[i], 0.14f); // smooth lag setServoA(i, currentAngle[i]); } } // ── SETUP ──────────────────────────────────────────────────────── void setup() { Serial.begin(115200); boardA.begin(); boardA.setOscillatorFrequency(27000000); boardA.setPWMFreq(50); boardB.begin(); boardB.setOscillatorFrequency(27000000); boardB.setPWMFreq(50); strip.begin(); strip.setBrightness(80); strip.show(); // Startup: centre all servos for (int i = 0; i < 16; i++) { boardA.setPWM(i, 0, SERVOMID); delay(30); } for (int i = 0; i < 6; i++) { boardB.setPWM(i, 0, SERVOMID); delay(30); } for (int i = 0; i < NUM_TAIL; i++) currentAngle[i] = 90; patternStart = millis(); setLEDPattern(0, 150, 130); Serial.println("🦚 Peacock Robot Ready!"); } // ── MAIN LOOP ──────────────────────────────────────────────────── void loop() { uint32_t now = millis(); uint32_t elapsed = now - patternStart; float phase = (float)(elapsed % PATTERN_DUR) / PATTERN_DUR; // Auto-advance patterns if (elapsed >= PATTERN_DUR) { currentPattern = (currentPattern + 1) % 8; patternStart = now; Serial.print("Pattern: "); Serial.println(currentPattern); } // Dispatch current pattern switch (currentPattern) { case 0: patternRipple(phase); break; case 1: patternSpiral(phase); break; case 2: patternHeart(phase); break; case 3: patternBloom(phase); break; case 4: patternShimmer(phase); break; case 5: patternCascade(phase); break; case 6: patternDance(phase); break; case 7: patternBow(phase); break; } updateEyesAndBody(phase); applyFeathers(); delay(20); // 50 Hz update rate }
Full Performance Sequence
The robot automatically cycles through all 8 patterns in order, spending 12 seconds on each. A full performance takes about 96 seconds before looping. Here's what you'll see:
⚠️ Safety Rules — This Is a High-Current Build
- Adult supervision is mandatory for this project. The 5V 10A power supply can deliver enough current to cause a fire if wiring is incorrect.
- Always use minimum 20 AWG wire for all power rails. Thin wire overheats at the currents drawn by 22 simultaneous servos.
- Never leave the robot running unattended — servos that bind against mechanical stops draw continuous stall current and can overheat.
- Add a 5A inline fuse between the PSU and the servo power bus — this prevents fire if a wiring fault draws excessive current.
- The aluminium frame is a conductor — ensure no servo wires have bare metal touching the frame. Use heat shrink tubing on all solder joints.
- Keep the natural feathers away from any heat source, LED strips that run hot, or enclosed spaces — peacock feathers can singe easily.
- Perform a current test before first full activation: connect an ammeter inline and run each servo group one at a time to measure draw before running all 22 simultaneously.
- Install the power switch in an easily accessible location so you can cut power immediately if any servo starts smoking or the frame gets hot.
When Things Don't Go Right
Some servos don't move or twitch randomly.
This is almost always a power issue. Add 1000µF capacitors directly across V+ and GND at each PCA9685 board. Also check that your 5V 10A PSU is actually delivering 5V under load — measure with a multimeter while all servos move.
The second PCA9685 board (0x41) isn't found.
Confirm the A0 solder bridge is made on Board B. Run an I²C scanner sketch to confirm both addresses appear. Check that SDA and SCL reach both boards — use a T-junction on the breadboard rather than daisy-chaining the wires.
Feathers tangle when the full fan opens.
First confirm all servo angles are within safe ranges (0° to 180° max). Add soft guides between alternate feathers — a strip of thin foam between each pair acts as a separator. The feathers should overlap slightly but not interlock.
Motion is jerky instead of smooth.
Check the interpolation smoothing value in applyFeathers() — increase the lerp factor from 0.14 toward 0.08 for slower smoother motion. Also ensure the main loop runs at a consistent 50ms delay — add timing logic to prevent drift.
The ESP32 resets when many servos move at once.
Servo current spikes are coupling into the ESP32's power supply through shared ground. Add the buck converter for isolated ESP32 power and ensure the servo power and logic power GND rails are joined at only ONE point (the PSU negative terminal).
My PATTERN_DUR is wrong — how do I adjust pattern speed?
Change the PATTERN_DUR constant — it's in milliseconds. 12000 = 12 seconds per pattern. The phase variable (0.0 to 1.0) always represents one complete cycle regardless of duration, so all patterns scale automatically.
Peacock & Robotics Facts
Feathers in a real peacock's train — your robot uses 10 main display feathers, which is enough to create the same visual impression.
The spread angle of a full peacock tail fan — your robot achieves this with the two spread arm servos at channels A10 and A11.
The update rate of your PCA9685 servo driver — the same frequency used in industry servo controllers for smooth motion.
The iridescence of peacock feathers comes from nanostructures, not pigment — the colour changes with viewing angle, making every servo movement create a new colour display.
Next Level Upgrades
You have just built one of the most complex and visually beautiful robots in this entire project series. You used trigonometry, interpolation, multi-board I²C communication, and real-time choreography — the same skills used by animatronic engineers at theme parks and film studios. The peacock dances because you made it dance. 🦚

Comments
Post a Comment