A robot does not always need a complicated display or camera to have a personality. Sometimes, a pair of simple animated eyes is enough to make a robot feel more interactive.
This project uses a Raspberry Pi 5 and a 1.8-inch ST7735 TFT display to create a small animated robot face. The display shows two expressive eyes that can move, blink, and change shape to communicate different emotions.
The main idea behind the project is to use the shape and movement of the eyes themselves to create expressions. There are no pupils or complicated graphics. This keeps the system lightweight and makes it suitable for small Raspberry Pi-based robots.
Why I Built ItI wanted to create a simple visual interface that could be added to a robot without requiring a large display or a powerful graphics system.
A small ST7735 TFT display is inexpensive, compact, and easy to interface with a Raspberry Pi using SPI. However, simply displaying static eyes does not make the robot feel very interactive.
The goal was therefore to create an animation engine that could make the eyes move naturally and respond to different events.
The project was designed around three main requirements:
- Simple graphics that can run on a small TFT display.
- Smooth eye movement without sudden jumps.
- Multiple expressions that can be controlled from another Python program.
The hardware for the project is simple.
Components:
- Raspberry Pi 5
- 1.8-inch ST7735 TFT LCD, 128 × 160
- Jumper wires(Female/Female)
The Raspberry Pi handles the graphics and animation while the ST7735 display acts as the robot's face.
Display ConnectionsThe ST7735 display communicates with the Raspberry Pi using SPI. The display's SDA pin is used as the SPI MOSI/data line, not as an I2C SDA connection.
The wiring is as follows:
For the setup I used the following guide Getting 1.8 Inch LCD Display ST7735 to Work With Raspberry Pi Zero W
sudo apt install python3-pip
sudo apt install python3-pil
sudo apt install python3-dev
sudo apt install python3-numpy
sudo apt istall python3-libgpiod
sudo pip3 install st7735 //This command throws the following error:
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
For more information visit http://rptl.io/venvIn order to overcome this error, use the following command:
sudo pip install st7735 --break-system-packagesIn addition, you need to install the following libraries:
sudo pip install gpiod --break-system-packages
sudo pip install gpiodevice --break-system-packagesSo you need to edit the main file of the installed ST7735 library with the command:
sudo nano /usr/local/lib/python3.xx/dist-packages/st7735/__init__.py
// replace the python3.xx in the path with your corrct version of python like below
//sudo nano /usr/local/lib/python3.13/dist-packages/st7735/__init__.py
//Inside this file, replace the above values with these ones:
ST7735_TFTWIDTH = 124
ST7735_TFTHEIGHT = 160
ST7735_COLS = 124
ST7735_ROWS = 160The display is configured for SPI communication and rotated so that the 160 × 124 working area is used horizontally.
The display initialization is:
disp = st7735.ST7735(
port=0,
cs=st7735.BG_SPI_CS_BACK,
dc="GPIO24",
backlight="GPIO22",
rst="GPIO25",
rotation=90,
invert=False,
spi_speed_hz=4000000
)Getting the display working first made it easier to separate hardware and software problems before developing the animation system.
Designing the Robot EyesThe first version of the project used simple rectangular eye shapes.
Instead of drawing pupils inside the eyes, the eye shapes themselves are used to communicate the robot's state.
For example, the eyes can become larger when the robot is surprised, narrower when it is sleeping, or angled when it is angry.
The main expressions implemented in the project are:
- Normal
- Happy
- Angry
- Surprised
- Sleep
- Blink
- Wink left
- Wink right
This approach keeps the graphics simple while still allowing the robot to display different emotions.
The Robot Eyes EngineThe main software component is robot_eyes_engine.py.
This file is responsible for communicating with the display, drawing the eye shapes, and controlling the animations.
It provides functions for changing the robot's expression as well as moving the eyes.
For example:
eyes.look_left()
eyes.look_right()
eyes.look_center()
eyes.look_up()
eyes.look_down()
eyes.happy()
eyes.angry()
eyes.surprised()
eyes.blink()
eyes.sleep()
eyes.look_left()
eyes.look_right()
eyes.look_center()
eyes.look_up()
eyes.look_down()
eyes.happy()
eyes.angry()
eyes.surprised()
eyes.blink()
eyes.sleep()A short section of robot_eyes_engine.py showing the main RobotEyes class and initialization
import time
import math
from PIL import Image, ImageDraw
import st7735
class RobotEyes:
def __init__(self, rotation=90):
# ==================================================
# ST7735 DISPLAY
# ==================================================
self.disp = st7735.ST7735(
port=0,
cs=st7735.BG_SPI_CS_BACK,
dc="GPIO24",
backlight="GPIO22",
rst="GPIO25",
rotation=rotation,
invert=False,
spi_speed_hz=4000000
)
self.disp.begin()
# Display size after rotation=90
self.WIDTH = 160
self.HEIGHT = 124
# ==================================================
# EYE SETTINGS
# ==================================================
self.eye_width = 38
self.eye_height = 52
self.left_x = 25
self.right_x = 97
self.center_y = 36
# Current eye movement
self.offset_x = 0
self.offset_y = 0
# Current expression
self.expression = "normal"
# Colors
self.background = (0, 0, 0)
self.eye_color = (255, 255, 255)
self.draw()Smooth Eye MovementOne of the most important parts of the project is the eye movement.
A simple implementation could instantly change the position of the eyes from one location to another. However, this produces a mechanical-looking movement.
Instead, the animation engine calculates intermediate positions between the starting and ending positions.
The movement is updated over multiple frames using an ease-in/ease-out function. The eyes start moving quickly, slow down as they approach the target position, and then settle into place.
This makes the movement appear much more natural without requiring complicated graphics.
The expressions can also be combined with movement. For example, the robot can look to the side while displaying a surprised expression.
Controlling the Robot FaceThe second main program is robot_face.py.
While the eyes engine handles the actual graphics and animation, robot_face.py controls the behaviour of the robot.
It can randomly trigger actions such as looking in different directions, blinking, or changing expressions.
This separation makes the system easier to expand. Another robot program can use the same eyes engine and trigger an expression whenever something happens.
For example, a robot could display a surprised expression when its ultrasonic sensor detects an obstacle.
# ============================================================
# FAST LOOK
# ============================================================
def look_left():
eyes.look_left(0.22)
def look_right():
eyes.look_right(0.22)
def look_center():
eyes.look_center(0.18)
def look_up():
eyes.look_up(0.20)
def look_down():
eyes.look_down(0.20)
# ============================================================
# NATURAL BLINK
# ============================================================
def blink():
eyes.blink()
# ============================================================
# QUICK DOUBLE BLINK
# ============================================================
def double_blink():
eyes.blink()
time.sleep(0.06)
eyes.blink()The complete robot_face.py file should be uploaded in the Hackster Code section.
After connecting the display and installing the required Python libraries, the robot face can be started from the Raspberry Pi terminal.
The main behaviour program can be launched with:
python3 robot_face.pyThe program initializes the display and starts the robot face animation.
Once running, the display continuously performs different movements and expressions.
Project StructureThe project contains several versions of the robot eyes software. The different versions make it possible to experiment with pupil-based eyes, pupil-free eyes, and different animation behaviours.
Robot_eyes/
│
├── robot_eyes_engine.py
├── robot_face.py
│
├── robot_eyes_engine_nop.py
├── robot_face_nop.py
├── robot_face_nop_fast.py
│
├── robot_eyes.py
└── README.mdrobot_eyes_engine.pyThis is the main pupil-based robot eyes engine. It handles the ST7735 display, draws the eyes and pupils, provides different expressions, and smoothly moves the pupils in different directions. It also includes blinking, winking, scanning, and random eye movement functions.
robot_face.pyThis is a simple behaviour program that uses robot_eyes_engine.py. It demonstrates the robot looking forward, looking left and right, returning to the center, and blinking continuously.
This is the no-pupil version of the eyes engine. Instead of using pupils to indicate direction, the entire eye shape moves around the display. The eye shapes themselves are also changed to create expressions such as normal, happy, angry, surprised, sleeping, blinking, and winking.
NOP means "No Pupils". In this version, the eyes are simply white shapes on a black background, without separate pupils.
robot_face_nop.pyThis is the demonstration program for the no-pupil version. It demonstrates the different expressions, blinking, winking, diagonal movements, scanning, and an idle animation.
robot_face_nop_fast.pyThis version focuses on fast, smooth, and seamless behaviour. It uses shorter movement durations and randomised behaviour to make the robot appear more natural and responsive. It can look around, blink, double blink, listen, and display happy, surprised, and angry reactions.
robot_eyes.pyThis is a simple standalone version that directly draws the two basic robot eyes on the ST7735 display. It was used as a basic starting point for displaying the eyes before developing the more advanced animation engines.
README.mdThis file contains additional information about the project, its files, setup, and usage.
Two Main VersionsThe project can therefore be viewed as having two main approaches.
Pupil-based eyes
robot_eyes_engine.py
↓
robot_face.pyThe eye remains in place while the pupil moves to indicate where the robot is looking.
No-pupil eyes
robot_eyes_engine_nop.py
↓
robot_face_nop.py
↓
robot_face_nop_fast.pyThe entire eye shape moves and changes to create the robot's expressions and direction of attention.
The no-pupil approach was developed to create a cleaner and more minimal robot face using only the eye shapes themselves. Hackster recommends using clear section headings and separating code from the main explanatory text, so the full .py files should be uploaded in the Code section while only short relevant snippets are shown in the Story.
The project was tested by running the different expressions and movement functions individually before combining them into the main robot behavior.
The main things tested were:
- Display initialization
- Eye rendering
- Left and right movement
- Up and down movement
- Diagonal movement
- Blinking
- Winking
- Expression changes
- Smooth transitions
- Continuous idle behavior
The final result is a small robot face capable of continuously moving and changing expressions while running entirely from the Raspberry Pi.
Possible ApplicationsAlthough this project was developed as a standalone robot face, the animation engine can be used as the visual interface for many different projects.
For example, the eyes could respond to:
- Ultrasonic obstacle detection
- Voice commands
- Speech output
- Robot movement
- Sensors
- Notifications
- AI assistant responses
- Facial recognition
- User interaction
A robot could therefore use the eyes to communicate its current state without requiring a large screen.
Future ImprovementsThere are several ways I would like to improve the project.
Future versions could include more eye shapes and animations, including different styles for emotions and reactions.
The eyes could also be synchronized with speech so that the robot's expressions change while it is talking.
Another possibility is to connect the animation engine to sensors and an AI assistant. This would allow the robot to automatically choose an expression based on what it detects or what it is doing.
Other possible improvements include:
- More expressive eye shapes
- Speech-synchronized animation
- Sensor-triggered expressions
- Voice-controlled reactions
- Facial recognition
- AI assistant integration
- More advanced transition effects
- Integration with a mobile or web interface
This project demonstrates how a small 1.8-inch ST7735 TFT display can be turned into a simple but expressive robot face using a Raspberry Pi and Python.
The project focuses on keeping the graphics lightweight while making the animations feel smooth and natural. By separating the animation engine from the robot's behaviour, the same eye system can also be reused in different robotics projects.
The result is a compact visual interface that gives a Raspberry Pi-based robot a simple personality and a way to communicate its state through movement and expressions.









Comments