Build a Tiny Robot Face with Two OLED Eyes!
Meet Blinky — a tiny robot face made from two OLED "eyes" mounted on a servo-powered neck. The eyes blink, look around, and glance the same way the neck turns. This is the perfect follow-up project after learning how to connect a single OLED!
😊 Say hi to Blinky, your tiny robot face!
What Is a Two-OLED Robot Face, Anyway?
Once you know how to connect one OLED display to Arduino, connecting a second one is a great next step — and it teaches something really useful: multiple I2C devices can share the exact same two wires (SDA and SCL) as long as each one has a different address. Blinky uses two OLEDs as expressive "eyes" and one servo as a "neck" that turns the whole face left and right.
What You'll Need
Gather these parts before you start building Blinky!
Arduino Uno
Drives both OLED eyes and the neck servo.
0.96" I2C OLED Displays (SSD1306)
One for each eye — ideally address-switchable modules.
SG90 Micro Servo
Acts as the neck, turning the whole face left and right.
Small Craft Head/Face Frame
Cardboard or 3D-printed housing to hold both OLEDs.
Breadboard
For connecting everything without soldering.
Jumper Wires
Male-to-male and male-to-female.
The Circuit Diagram
Both OLEDs share the same SDA/SCL wires — they just need two different I2C addresses.
Step-by-Step Build Instructions
Ask an adult to help set the OLED address jumpers if your modules need it. Let's build Blinky!
Set each OLED's I2C address
Many SSD1306 modules have a small solder pad or jumper to select address 0x3C or 0x3D. Set one OLED to each address — this is what lets them share the same two wires.
💡 Tip: If your modules can't change address, you'll need an I2C multiplexer or a software I2C library instead — check your specific module's documentation.Wire both OLEDs to the same bus
Connect both OLEDs' VCC to 5V, GND to GND, SDA to A4, and SCL to A5 — all four wires from each OLED land on the exact same Arduino pins.
Mount the OLEDs as eyes
Fix both OLED screens side by side into your craft face frame, spaced like a pair of eyes.
Attach the neck servo
Mount the servo underneath the face frame so its horn can rotate the whole head left and right, like a neck turning.
Install the libraries and upload the code
Install the Adafruit_SSD1306, Adafruit_GFX, and Servo libraries, then upload the code below.
Watch Blinky come to life!
The neck should sweep slowly left and right while both eyes blink and glance in the same direction the head is turning.
The Arduino Code
Copy this code into the Arduino IDE, then click Upload. It creates two separate display objects — one per address — and syncs their eyes with the servo's motion.
// 👀🤖 Blinky the Two-OLED Robot Face — Arduino Robotics Project // Two OLEDs share one I2C bus using different addresses, plus a servo neck #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <Servo.h> #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 // Two separate display objects, one per OLED address Adafruit_SSD1306 leftEye(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); Adafruit_SSD1306 rightEye(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); const int LEFT_ADDR = 0x3C; const int RIGHT_ADDR = 0x3D; Servo neck; const int neckPin = 9; int neckAngle = 90; int direction = 1; void setup() { leftEye.begin(SSD1306_SWITCHCAPVCC, LEFT_ADDR); rightEye.begin(SSD1306_SWITCHCAPVCC, RIGHT_ADDR); neck.attach(neckPin); neck.write(neckAngle); } void loop() { // Slowly sweep the neck left and right neckAngle += direction; if (neckAngle >= 130 || neckAngle <= 50) direction = -direction; neck.write(neckAngle); // Shift the pupils based on which way the neck is turning int pupilShift = map(neckAngle, 50, 130, -10, 10); drawEyes(pupilShift, false); // Occasionally blink if (random(0, 100) < 3) { drawEyes(pupilShift, true); delay(150); } delay(30); } // Draws both eyes; blink=true closes them with a horizontal line void drawEyes(int pupilShift, bool blink) { leftEye.clearDisplay(); rightEye.clearDisplay(); if (blink) { leftEye.drawLine(30, 32, 98, 32, SSD1306_WHITE); rightEye.drawLine(30, 32, 98, 32, SSD1306_WHITE); } else { leftEye.fillCircle(64 + pupilShift, 32, 20, SSD1306_WHITE); rightEye.fillCircle(64 + pupilShift, 32, 20, SSD1306_WHITE); } leftEye.display(); rightEye.display(); }
How Does Blinky Actually Work?
Here are the big ideas hiding inside this project:
I2C Addresses
I2C devices are identified by a small address number, not by which wires they're plugged into. As long as two devices have different addresses, they can safely share the same SDA/SCL wires.
Two Objects, One Bus
The code creates two separate Adafruit_SSD1306 objects, each initialized with its own address — from then on, drawing to leftEye or rightEye automatically talks to the correct screen.
Mapping One Value to Another
map() converts the servo's current angle into a small pupil offset — so as the neck turns further, the eyes shift further too, in the same direction.
Randomness for Personality
Using random(0, 100) < 3 gives roughly a 3% chance of blinking on any given loop — enough to feel natural and alive without following an obvious repeating pattern.
🧑🔬 Safety First!
- Double-check your OLED voltage rating (3.3V or 5V) before powering on.
- Always disconnect power before changing wiring or address jumpers.
- Handle both OLED screens gently — the glass surfaces can crack if pressed too hard.
- Keep fingers clear of the servo horn while it's moving.
- Build with an adult, especially the first time setting I2C addresses.
Frequently Asked Questions
Only one eye shows anything — what's wrong?
This almost always means both OLEDs are still set to the same address. Double-check your module's address jumper or solder pad, and confirm one is 0x3C and the other is 0x3D.
My OLED modules don't have an address jumper — now what?
You have two options: use an I2C multiplexer board (like a TCA9548A) to manage multiple fixed-address devices, or use a software I2C library on a second set of pins for the extra display.
Can I make the eyes show different expressions?
Yes! Instead of just circles, try drawing different shapes for happy, surprised, or sleepy expressions inside drawEyes(), and switch between them based on a timer or sensor input.
What age group is this project good for?
This is a great next-step project for kids around age 9 and up who have already tried connecting a single OLED, since it builds directly on that same knowledge.

Comments
Post a Comment