EYEMECH 3.2 – Mega with PCA9685 Servo Controller
- Chris Wong
- Sep 29
- 2 min read
Updated: 3 days ago
For robotics and animatronics enthusiasts, Will Cogley’s EYEMECH is a famous open design of realistic animatronic eyes.
This post showcases an adaptation of the EYEMECH 3.2 control code for ESP32, using the PCA9685 servo controller to drive multiple servos smoothly via I²C.

Project Overview
Platform: ESP32 (MicroPython)
Servo Driver: PCA9685 (16‑channel PWM over I²C)
Servos Controlled: 6 (Left/Right, Up/Down, 4 eyelids)
Modes:
Calibration mode – eyes centered, eyelids closed
Auto mode – random blinks and movements
Controller mode – joystick/potentiometer control with eyelid following
The system replicates natural eye movements while allowing manual controller input, making it a strong foundation for props, robots, or interactive art pieces.
⚙️ How It Works
PCA9685 Driver (pca9685.py)
Initializes the PWM chip over I²C
Provides functions to set PWM frequency and servo angles
Maps 0–180° angles into pulse widths (servo‑friendly 50 Hz PWM range)
Main Control Script (main.py)
Imports and uses the PCA9685 class
Defines servo limits for realistic eyelid motion (some inverted)
Adds calibration, neutral, blink, and coordinated movement functions
Supports potentiometer/joystick control via ADC inputs on ESP32
Includes random movement logic for lifelike animation in auto mode
📂 Code Files
Below are the full original source codes as provided.
Simplied Arduino Code with Wire Library
Arduino Code with I²C Communication
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
// Create the servo driver instance
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// Define servo pulse limits
#define SERVOMIN 150 // Minimum pulse length count
#define SERVOMAX 600 // Maximum pulse length count
void setup() {
Serial.begin(9600);
Serial.println("16 channel servo test!");
pwm.begin();
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz
delay(10);
}
void loop() {
// Sweep all servos one by one
for (uint8_t servoNum = 0; servoNum < 4; servoNum++) { // Example: 4 servos
for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
pwm.setPWM(servoNum, 0, pulselen);
}
delay(500);
for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
pwm.setPWM(servoNum, 0, pulselen);
}
delay(500);
}
}
Comments