Eye animation on OLED display with arduino nano
Demo of the animated eyes running on the arduino nano and a 128x64 oled display.
Demo of the animated eyes on a ESP32 microcontroller and 128x128 oled display.
Intro
Source code https://github.com/intellar/oled_eye_display
#with git, use this command to clone (download) the code :
git clone https://github.com/intellar/oled_eye_display
updates:
2025-03: ported to U8G2 library. check the repo
2024-10: there is a color lcd version of this project, Animated eyes with arduino nano on color LCD display
This is a simple project to give a visual feedback to someone interacting with a device. Here the display shows eyes, that can blink, look up, look down, look amused, annoyed, etc.
The microcontroller renders simple basic forms (rounded squares, triangles) that mimic eyes. The project was realised with two microcontroller, the arduino nano and the esp32. The first section describe the animation project with the arduino nano on a 128x64 oled screen . The second section presents the project with the esp32 alternative on a 128x128 oled screen.
If you want to see a quick demo of how the project works, from wiring to compiling the code, check the following tutorial video. It takes you through each steps of described on this page:
Hardware - Arduino Nano
For this project, we used an oled display found on amazon based on the ssd1306 controller, costing 11$, and a canaduino, which is a cost effective alternative to the arduino nano v3, costing 6$. This brings the total cost under 20$cad. And if you go on aliexpress, you can get all this for under 5$. No links are published since they will most likely not age well. Both devices are shown here:
Fig.1a Amazon.ca
Fig.1b Aliexpress
The nano I bought comes without the pins attached, so a little MacGyver soldering is required to connect the pins on the arduino board. It is easily done with a fine tip and common soldering iron. You can spend the 0.50$ if you think the soldering is not worth your time (I recommand it).
The connection of the arduino to the display is fairly simple, and it is important to note that the display uses power on 3v. So dont plug it on the 5v pin. You need to use the pinout SCL,SDA on A5 and A4 for the i2c connection, this is required for the hardware i2c of the nano.
Arduino - Display
3v3 - vcc
Gnd - gnd
A5 - SCL
A4 - SDA
this results in the wiring shown in the next figure :
Fig.2a schematic of the wiring.
Fig.2b pinout of the arduino, you can see the hardware pins of the scl and sda. this is fixed by hardware, it enables faster communications.
Fig.2c Final wiring
Software - Arduino Nano
Now the fun part begins. You can download the code here (for free! just say thanks). It is a cleaned and concise example of the library. It is meant to be simple and can easily be adapted for more complexe animation.
https://github.com/intellar/oled_eye_display
There are two folders, one contains the arduino code, and the other contains the python script to communicate with the nano. To program the nano, you must upload the program "control_display.ino", that will handle the drawing and the communication with the pc. I use the program arduino ide to compile and upload. The nano must be plugged in the computer for the programmation.
Fig.3 I used the arduino ide version 2.2.1 in this project (from 2023). It will work with more recent version.
A quick note about the drawing libraries. I used 2 libraries to handle the rounded rectangle drawing, adafruitgfx and u8g2. Both work the same way and can go fast enough to create the animation illusion. I had to change some this to make the code compatible with u8g2, mainly when drawing the rounded rectangle. We need to make sure the radius of the corner is not bigger than the height or width. On the next figure, you can see the radius (7). The condition to respect is w<2*(r+1) and h<2*(r+1) , or else the behavior is not defined. Since this happens a lot in the sleep and blink animation, it needs to be adressed before calling the drawRBox function of u8g2.
Fig.4 description of a rounded rectangle.
The function are almost directly compatible, for example, to draw a rounded rectangle,
Adafruit.clearDisplay()
Adafruit.fillRoundRect(x, y, w, h, r, color);
Adafruit.display();
U8G2.clearBuffer();
U8G2.setDrawColor(color);
U8G2.drawRBox(x, y, w, h, r);
U8G2.sendBuffer();
Currently, there are 8 animations in the program, starting with the closed eyes. To trigger other animations, run the example script in the python folder. Note that in the example, the serial port in COM3, it might not be the case on your computer. To find out which one to use, start the hardware manager on windows.
Fig.5a declaration of the serial com.
Fig.5b. the serial comm can be found in the windows device manager
Quick explanation of the code
Animation
The arduino code is based on the adafruit_ssd1306 and adafruit_gfx library. There is also a port for the u8g2 library. Small modification had to be added to the drawing functions to avoid undefined states with rounded rectangles. This said, the idea behind the animations is a function that draw the eyes based on a description contained in the global reference variable : left and right eyes width, height, center, position and interspacing. A call to the function draw_eyes will draw filled round rectangle with the specified caracteristics. With this specific oled display, the reference value of the width and height is 40, with corner radius of 10, and inter spacing of 10. Calling certer_eye with reinitialized all value to these default reference and draw the eyes.
To do an animation, for example, to blink, a loop calls the draw_eyes while decrementing and incrementing the height value. In another example. the sleep animation, the height of both eyes is changed to a very small value so the eyes look like they are closed. The happy eye draws the eye and then draw filled triangled to hide a portion of the rectangle, giving the impression of a smile. Calling display at the end of each iteration create the illusion of movement.
Loop and usb
The arduino main loop, loop() will cycle the animation. It uses a state variable called "demo_mode" to know if it is cycling animation, or if a command was receive on usb, in which case it swith mode to listen on the serial data over usb with the Serial module. I made a simple protocol where command starting with the char "A" followed by a number trigger the animation by the number. As soon as a A is receive on usb, it switch the demo mode to off and start to listen. The command are sent with a python script over serial usb. Using usb like this will allow to use other command on the same connection to trigger other action, closing a robot gripper for example.
This next video shows the eyes installed on a small robot. This was my first attempt to use the eyes in a project.
Hardware - ESP32
In this second part, I upgraded the display to a full 128x128 pixels OLED screen. Unfortunatly, it was not possible to continue using the arduino nano. The internal memory is too small to map the whole screen. I had to upgrade the microcontroller. A good choice is to use the ESP32. It is faster, has more than enough memory and is almost as budget friendly as the arduino nano. you can see it on Fig6c.
The connection between the esp32 and the display is straightforward,
GND - GND
VCC - 3V3
SCL - D22
SDA - D21
I recommend using D21,D22 for hardware accelerated i2c communication. You can use other pins with the software i2c that will be slow to update the screen, very very slow.
Fig.6a A screenshot of the eyes on the 128x128 oled display
Fig.6b The back of the display, we can see the hardware driver SH1107. You can also see the IIC address (0x78) selected by the soldered jumper, on the top left. This information will be required to initialize the display.
Fig.6c The ESP32 board used in this project.
Software - ESP32
The source code is on the github repo, follow the esp32 folder. Except for the pin configuration, the code is similar to the arduino version.
https://github.com/intellar/oled_eye_display
The code to initialize the display and library u8g2 holds on 5 lines, and can be seen on Fig.7a. Special care must be taken to select the right chip and config for your setup. For my display, I used the SH1107 chip, and the pimoroni config ( U8G2_SH1107_PIMORONI_128X128_F_HW_I2C ). I tried different config before finding the right one, like the generic ( U8G2_SH1107_128X128_F_HW_I2C) which resulted in the content not aligned properly with the screen, as shown on Fig7b.
The next command set the correct I2C address, make sure it matches the one of your board
u8g2.setI2CAddress(0x78);
Next, I draw a initial image before starting the animations. I intentionally left the software simulated I2C declaration (U8G2_SH1107_PIMORONI_128X128_F_SW_I2C), so you can try it out.
Fig.7a Initialisation of the display.
Fig.7b Using the wrong config will result in alignement problem like here, or event not images at all.
Fig.7c Correctly aligned content with config pimoroni, for this specific setup.
Fig.7d the i2c address of the software must match the board ! u8g2.setI2CAddress(0x78);
To create the animation, it is similar to the arduino nano code. The screen is cleared
u8g2.clearBuffer();
After that, the shapes are drawn. Draw all the shapes one after to other without refreshing the screen. Everything is drawn in a buffer. One important note, if you change the drawRBox argument, be sure to respect the condition w >= 2*(r+1) and h >= 2*(r+1), or else the result is undefined.
u8g2.setDrawColor(color);
u8g2.drawRBox(x,y,w,h,r);
...
When everything is drawn, you call the function to send the buffer to the display
u8g2.sendBuffer();
Compilation - ESP32
To compile the project, you need to select the board you are using on arduino ide Fig.8a (https://www.arduino.cc/en/software#ide). In my case it is the "esp32 dev module", shown on Fig8b. Select the right com port. Don't forget to install the u8g2 library, by searching for "u8g2" in the library manager of arduino ide.
Fig.8a I am using arduino IDE 2.3.5 to compile and upload the project on the esp32. https://www.arduino.cc/en/software#ide
Fig.8a Selecting the correct module for your project, here it is the esp32 dev module.
Fig.8c Install the u8g2 library using the manager.
And that's about it ! you can modify the animation as you see fit. Enjoy !