Все статьиHardware

Анимированные глаза на OLED-дисплее Arduino: проект для робототехники

БА
Бексултан Айтен
CTO, Alashed
23 мая 2025 г.
9 мин чтения
Анимированные глаза на OLED-дисплее Arduino: проект для робототехники

Создаём выразительные анимированные глаза на OLED-дисплее 0.96 дюйма с Arduino. Глаза моргают, смотрят по сторонам, меняют настроение. Полный код, схема подключения и советы для учителей.

Живые глаза для вашего робота

Когда школьники собирают робота, у него обычно есть колёса, датчики и корпус. Но чего не хватает -- так это характера. OLED-дисплей размером всего 0.96 дюйма способен превратить безликую конструкцию в персонажа с настроением. Анимированные глаза моргают, оглядываются по сторонам, хмурятся и удивляются -- всё это создаётся программно, без единой движущейся детали.

Проект основан на OLED-дисплее с разрешением 128x64 пикселя и контроллером SSD1306, который подключается к Arduino по интерфейсу I2C всего четырьмя проводами. Это один из самых простых в подключении дисплеев, и при этом он даёт чёткое изображение с высокой контрастностью.

Проект подходит для учеников 6--9 классов и собирается за один урок. Пайка не требуется -- все соединения выполняются на макетной плате.

Что понадобится

  • Arduino Uno (или Nano) -- 1 шт.
  • OLED-дисплей 0.96" 128x64 (SSD1306, I2C) -- 1 шт.
  • Макетная плата (breadboard) -- 1 шт.
  • Провода-перемычки (папа-папа) -- 4 шт.
  • USB-кабель для подключения Arduino к компьютеру

Общая стоимость компонентов составляет около 4 000--6 000 тенге. OLED-дисплеи SSD1306 широко доступны в магазинах электроники и на маркетплейсах.

Схема подключения

Схема подключения OLED-дисплея к Arduino
Схема подключения OLED-дисплея к Arduino

OLED-дисплей подключается по протоколу I2C, для которого нужны всего два сигнальных провода плюс питание.

Подключение OLED к Arduino Uno:

OLED-дисплейArduino
GNDGND
VCC3.3V
SCL (SCK)A5
SDAA4

Важный момент: рабочее напряжение OLED-дисплея составляет 3.3V, поэтому питание берётся от вывода 3.3V Arduino, а не от 5V. Подключение к 5V может повредить дисплей.

Для Arduino Nano используются те же пины A4 (SDA) и A5 (SCL). Если на дисплее не появляется изображение, проверьте I2C-адрес -- он может быть 0x3C или 0x3D в зависимости от производителя.

Установка библиотек

Для работы потребуются две библиотеки. Установите их через менеджер библиотек Arduino IDE (Скетч -- Подключить библиотеку -- Управление библиотеками):

1. Adafruit SSD1306 -- драйвер дисплея

2. Adafruit GFX Library -- графические функции (установится автоматически как зависимость)

Полный код проекта

```cpp

#include <Wire.h>

#include <Adafruit_GFX.h>

#include <Adafruit_SSD1306.h>

// Настройки дисплея

#define SCREEN_WIDTH 128 // Ширина экрана в пикселях

#define SCREEN_HEIGHT 64 // Высота экрана в пикселях

#define OLED_RESET -1 // Пин сброса (-1 если не используется)

// Создаём объект дисплея

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Параметры глаз

const int eyeWidth = 36; // Ширина глаза

const int eyeHeight = 36; // Высота глаза

const int eyeSpacing = 10; // Расстояние между глазами

const int pupilSize = 10; // Размер зрачка

const int eyeY = 14; // Вертикальное положение глаз

// Вычисляем центры глаз

const int leftEyeX = (SCREEN_WIDTH / 2) - (eyeSpacing / 2) - (eyeWidth / 2);

const int rightEyeX = (SCREEN_WIDTH / 2) + (eyeSpacing / 2) + (eyeWidth / 2);

// Смещение зрачка относительно центра глаза

int pupilOffsetX = 0;

int pupilOffsetY = 0;

// Функция рисования обоих глаз с текущим положением зрачков

void drawEyes(int offsetX, int offsetY, int lidTop, int lidBottom) {

display.clearDisplay();

// Рисуем левый глаз (белок -- заполненный скруглённый прямоугольник)

display.fillRoundRect(leftEyeX - eyeWidth/2, eyeY, eyeWidth, eyeHeight, 8, SSD1306_WHITE);

// Зрачок левого глаза (чёрный круг внутри белого)

display.fillCircle(leftEyeX + offsetX, eyeY + eyeHeight/2 + offsetY, pupilSize, SSD1306_BLACK);

// Рисуем правый глаз

display.fillRoundRect(rightEyeX - eyeWidth/2, eyeY, eyeWidth, eyeHeight, 8, SSD1306_WHITE);

// Зрачок правого глаза

display.fillCircle(rightEyeX + offsetX, eyeY + eyeHeight/2 + offsetY, pupilSize, SSD1306_BLACK);

// Веки -- чёрные прямоугольники, закрывающие глаза сверху и снизу

if (lidTop > 0) {

display.fillRect(leftEyeX - eyeWidth/2, eyeY, eyeWidth, lidTop, SSD1306_BLACK);

display.fillRect(rightEyeX - eyeWidth/2, eyeY, eyeWidth, lidTop, SSD1306_BLACK);

}

if (lidBottom > 0) {

display.fillRect(leftEyeX - eyeWidth/2, eyeY + eyeHeight - lidBottom, eyeWidth, lidBottom, SSD1306_BLACK);

display.fillRect(rightEyeX - eyeWidth/2, eyeY + eyeHeight - lidBottom, eyeWidth, lidBottom, SSD1306_BLACK);

}

display.display();

}

// Анимация моргания

void blink() {

// Закрываем глаза постепенно

for (int i = 0; i <= eyeHeight/2; i += 4) {

drawEyes(pupilOffsetX, pupilOffsetY, i, i);

delay(20);

}

delay(60);

// Открываем глаза обратно

for (int i = eyeHeight/2; i >= 0; i -= 4) {

drawEyes(pupilOffsetX, pupilOffsetY, i, i);

delay(20);

}

}

// Плавное перемещение взгляда

void lookAt(int targetX, int targetY, int steps) {

int startX = pupilOffsetX;

int startY = pupilOffsetY;

for (int i = 1; i <= steps; i++) {

pupilOffsetX = startX + (targetX - startX) * i / steps;

pupilOffsetY = startY + (targetY - startY) * i / steps;

drawEyes(pupilOffsetX, pupilOffsetY, 0, 0);

delay(30);

}

}

// Выражение "злость" -- верхние веки наполовину опущены

void angryFace() {

for (int i = 0; i < 8; i++) {

drawEyes(0, 0, i, 0);

delay(40);

}

delay(1500);

for (int i = 7; i >= 0; i--) {

drawEyes(0, 0, i, 0);

delay(40);

}

}

// Выражение "удивление" -- глаза широко раскрыты, зрачки маленькие

void surprisedFace() {

display.clearDisplay();

// Рисуем увеличенные глаза

display.fillRoundRect(leftEyeX - eyeWidth/2 - 2, eyeY - 2, eyeWidth + 4, eyeHeight + 4, 10, SSD1306_WHITE);

display.fillCircle(leftEyeX, eyeY + eyeHeight/2, pupilSize - 3, SSD1306_BLACK);

display.fillRoundRect(rightEyeX - eyeWidth/2 - 2, eyeY - 2, eyeWidth + 4, eyeHeight + 4, 10, SSD1306_WHITE);

display.fillCircle(rightEyeX, eyeY + eyeHeight/2, pupilSize - 3, SSD1306_BLACK);

display.display();

delay(2000);

}

void setup() {

Serial.begin(9600);

// Инициализация дисплея (адрес 0x3C -- стандартный для большинства модулей)

if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {

Serial.println("Ошибка: OLED не найден! Проверьте подключение.");

while (true); // Останавливаем программу

}

display.clearDisplay();

display.display();

delay(500);

}

void loop() {

// Нейтральный взгляд вперёд

drawEyes(0, 0, 0, 0);

delay(2000);

// Моргание

blink();

delay(1000);

// Смотрим влево

lookAt(-8, 0, 5);

delay(800);

// Смотрим вправо

lookAt(8, 0, 5);

delay(800);

// Возвращаемся в центр

lookAt(0, 0, 5);

delay(500);

// Моргание

blink();

delay(1200);

// Злое выражение

angryFace();

delay(800);

// Моргание

blink();

delay(600);

// Удивление

surprisedFace();

delay(500);

// Возвращаемся к нейтральному

pupilOffsetX = 0;

pupilOffsetY = 0;

}

`

Анимированные глаза на OLED-дисплее Arduino
Анимированные глаза на OLED-дисплее Arduino

Разбор кода

Геометрия глаз. Глаза рисуются с помощью графических примитивов библиотеки Adafruit GFX: fillRoundRect создаёт белый скруглённый прямоугольник (белок глаза), а fillCircle -- чёрный круг внутри него (зрачок). Смещая зрачок относительно центра, мы имитируем направление взгляда.

Анимация моргания. Веки реализованы как чёрные прямоугольники, которые постепенно закрывают глаз сверху и снизу. Цикл for увеличивает высоту прямоугольников с шагом 4 пикселя, создавая плавную анимацию. Задержка между кадрами -- 20 мс, что даёт около 50 кадров в секунду.

Плавное перемещение взгляда. Функция lookAt использует линейную интерполяцию: зрачок перемещается из текущей позиции в целевую за заданное количество шагов. Это создаёт естественное, не дёрганое движение.

Эмоции. Разные выражения лица создаются комбинацией положения зрачков и формы век. Опущенные верхние веки -- злость. Увеличенные глаза с маленькими зрачками -- удивление. Добавить новые эмоции несложно.

Советы для занятий

  • Дайте ученикам задание создать свою эмоцию. Например, грусть (зрачки смотрят вниз, веки полуприкрыты) или хитрость (один глаз прищурен).
  • Добавьте датчик расстояния HC-SR04, чтобы глаза реагировали на приближение человека -- широко раскрывались или отводили взгляд.
  • Подключите джойстик к аналоговым входам A0 и A1, чтобы управлять направлением взгляда вручную.
  • Используйте функцию `random()` для случайного выбора анимаций, чтобы робот вёл себя непредсказуемо.
  • Если изображение перевёрнуто, добавьте display.setRotation(2); в setup после инициализации.

Этот проект наглядно демонстрирует работу с I2C-интерфейсом, графическими библиотеками и принципами покадровой анимации. Готовые глаза можно встроить в корпус робота из картона или напечатанный на 3D-принтере -- результат впечатлит и одноклассников, и жюри на конкурсе.

Как Alashed помогает

Все компоненты для этого проекта -- Arduino, OLED-дисплей, провода и макетные платы -- доступны в наборах Alashed Hardware. А для написания и загрузки кода удобно использовать Alashed CodeStudio -- онлайн-среду разработки, которая позволяет писать, компилировать и загружать скетчи прямо из браузера, без установки Arduino IDE на школьные компьютеры.

Попробуйте Alashed бесплатно

Подключите школу к пилоту. Генерируйте КМЖ за 2 минуты, ведите CodeStudio уроки, заказывайте оборудование — всё в одном месте.

Попробовать бесплатноДемо