Arduino OLED Eyes Animation for Robotics Projects

The “Arduino OLED Eyes Animation for Robotics Projects” is a curated guide showcasing five different methods for creating lively and expressive eye animations on Arduino-based robots using OLED displays. Each method offers unique features and functionalities, from simple eye movements and mood expressions to more sophisticated techniques involving bitmap images and optimized memory usage. Whether you’re a beginner or seasoned hobbyist, this project provides a comprehensive overview of how to implement captivating eye animations that add personality and realism to your robotic creations. Explore the diverse options and unleash your creativity in the exciting realm of Arduino robotics!

Project description

In the vast realm of robotics, enthusiasts are venturing into the exciting world of OLED eye animations for Arduino robots. If you’ve found yourself lost in the maze of online searches, fear not! We’ve done the legwork and distilled the top five methods for creating captivating eye animations into a clear and fun comparison.

Introducing our selections:

Option 1: Eye Animation on OLED Display by Intellar

Eye Animation on OLED Display by Intellar

Intellar’s approach brings cool eye animations to life with simple functions mimicking various moods (Normal, Sleep, Smile) and versatile eye movements. Pro: Easy to use with adjustable eye positions. Con: Limited to three moods.

Option 2: Simple Animated Eye Using Arduino by SpiderMaf

Simple Animated Eye Using Arduino by SpiderMaf

SpiderMaf’s method features circular eyes with pupils for precise movements, adding a touch of humanity to your robot. Pro: Compact functions with customizable features. Con: Similar to Intellar’s approach.

Option 3: Akno by AbdulsalamAbbod

Akno by AbdulsalamAbbod

Akno stands out with its expressive rectangular eyes and a wide range of emotions, suitable for various display types. Pro: Supports multiple expressions. Con: Less flexible in adjusting eye size.

Option 4: Arduino OLED Moving Eyes by Vinny

Arduino OLED Moving Eyes by Vinny

Vinny’s innovative technique involves rendering custom images on OLED displays, though it comes with memory constraints. Pro: External image rendering capability. Con: Memory-intensive process.

Option 5: Arduino UNO Robotic Eye Animations by Picaio

Arduino UNO Robotic Eye Animations by Picaio

Picaio offers a sophisticated yet realistic approach with diverse eye movements and expressions, enhancing animation realism. Pro: Optimized technique for efficient memory usage. Con: May be challenging for beginners due to its complexity.

Whether you’re a seasoned hobbyist or just starting out, these methods provide a gateway to bringing your robot’s personality to life! Get ready to dive in, experiment, and unleash your creativity with our official webpage Explaining this project $ Arduino OLED Animations $ as your guide!

Let’s animate those robotic eyes and inject some fun into your Arduino projects! 🤖👀

Code

Eye Animation on OLED Display by Intellar

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


#define SCREEN_WIDTH 128  // OLED display width, in pixels
#define SCREEN_HEIGHT 64  // OLED display height, in pixels

#define OLED_RESET -1        // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C  ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


// Adjustable
int ref_eye_height = 40;
int ref_eye_width = 40;
int ref_space_between_eye = 10;
int ref_corner_radius = 10;

//current state of the eyes
int left_eye_height = ref_eye_height;
int left_eye_width = ref_eye_width;
int left_eye_x = 32;
int left_eye_y = 32;
int right_eye_x = 32 + ref_eye_width + ref_space_between_eye;
int right_eye_y = 32;
int right_eye_height = ref_eye_height;
int right_eye_width = ref_eye_width;

int dir_x = 0;
int dir_y = 0;
int count = 0;

void draw_eyes(bool update = true);
void center_eyes(bool update = true);
void blink(int speed = 12);
void sleep();
void wakeup();
void happy_eye();
void saccade(int direction_x, int direction_y);
void move_right_big_eye();
void move_left_big_eye();
void move_big_eye(int direction);

int timeD = 1000;


void draw_eyes(bool update = true) {
  display.clearDisplay();
  //draw from center
  int x = int(left_eye_x - left_eye_width / 2);
  int y = int(left_eye_y - left_eye_height / 2);
  display.fillRoundRect(x, y, left_eye_width, left_eye_height, ref_corner_radius, SSD1306_WHITE);
  x = int(right_eye_x - right_eye_width / 2);
  y = int(right_eye_y - right_eye_height / 2);
  display.fillRoundRect(x, y, right_eye_width, right_eye_height, ref_corner_radius, SSD1306_WHITE);
  if (update) {
    display.display();
  }
}

void center_eyes(bool update = true) {
  //move eyes to the center of the display, defined by SCREEN_WIDTH, SCREEN_HEIGHT
  left_eye_height = ref_eye_height;
  left_eye_width = ref_eye_width;
  right_eye_height = ref_eye_height;
  right_eye_width = ref_eye_width;

  left_eye_x = SCREEN_WIDTH / 2 - ref_eye_width / 2 - ref_space_between_eye / 2;
  left_eye_y = SCREEN_HEIGHT / 2;
  right_eye_x = SCREEN_WIDTH / 2 + ref_eye_width / 2 + ref_space_between_eye / 2;
  right_eye_y = SCREEN_HEIGHT / 2;

  draw_eyes(update);
}

void blink(int speed = 12) {
  draw_eyes();


  for (int i = 0; i < 3; i++) {
    left_eye_height = left_eye_height - speed;
    right_eye_height = right_eye_height - speed;
    draw_eyes();
    delay(1);
  }
  for (int i = 0; i < 3; i++) {
    left_eye_height = left_eye_height + speed;
    right_eye_height = right_eye_height + speed;

    draw_eyes();
    delay(1);
  }
}

void sleep() {  // DRAWS A LINE TO LOOK LIKE SLEEPING
  left_eye_height = 2;
  right_eye_height = 2;
  draw_eyes(true);
}

void wakeup() {  // WAKE UP THE EYES FROM AN LINE TO ROUND CORNERED SQUARE

  sleep();

  for (int h = 0; h <= ref_eye_height; h += 2) {
    left_eye_height = h;
    right_eye_height = h;
    draw_eyes(true);
  }
}

void happy_eye() {
  center_eyes(false);
  //draw inverted triangle over eye lower part
  int offset = ref_eye_height / 2;
  for (int i = 0; i < 10; i++) {
    display.fillTriangle(left_eye_x - left_eye_width / 2 - 1, left_eye_y + offset, left_eye_x + left_eye_width / 2 + 1, left_eye_y + 5 + offset, left_eye_x - left_eye_width / 2 - 1, left_eye_y + left_eye_height + offset, SSD1306_BLACK);
    // display.fillRect(left_eye_x-left_eye_width/2-1, left_eye_y+5, left_eye_width+1, 20,SSD1306_BLACK);

    display.fillTriangle(right_eye_x + right_eye_width / 2 + 1, right_eye_y + offset, right_eye_x - left_eye_width / 2 - 1, right_eye_y + 5 + offset, right_eye_x + right_eye_width / 2 + 1, right_eye_y + right_eye_height + offset, SSD1306_BLACK);
    // display.fillRect(right_eye_x-right_eye_width/2-1, right_eye_y+5, right_eye_width+1, 20,SSD1306_BLACK);
    offset -= 2;
    display.display();
    delay(1);
  }


  display.display();
  delay(1000);
}

void saccade(int direction_x, int direction_y) {
  //quick movement of the eye, no size change. stay at position after movement, will not move back,  call again with opposite direction
  //direction == -1 :  move left
  //direction == 1 :  move right

  int direction_x_movement_amplitude = 8;
  int direction_y_movement_amplitude = 6;
  int blink_amplitude = 8;

  for (int i = 0; i < 1; i++) {
    left_eye_x += direction_x_movement_amplitude * direction_x;
    right_eye_x += direction_x_movement_amplitude * direction_x;
    left_eye_y += direction_y_movement_amplitude * direction_y;
    right_eye_y += direction_y_movement_amplitude * direction_y;

    right_eye_height -= blink_amplitude;
    left_eye_height -= blink_amplitude;
    draw_eyes();
    delay(1);
  }

  for (int i = 0; i < 1; i++) {
    left_eye_x += direction_x_movement_amplitude * direction_x;
    right_eye_x += direction_x_movement_amplitude * direction_x;
    left_eye_y += direction_y_movement_amplitude * direction_y;
    right_eye_y += direction_y_movement_amplitude * direction_y;

    right_eye_height += blink_amplitude;
    left_eye_height += blink_amplitude;

    draw_eyes();
    delay(1);
  }
}

void move_right_big_eye() {
  move_big_eye(1);
}

void move_left_big_eye() {
  move_big_eye(-1);
}

void move_big_eye(int direction) {  // MOVES TO RIGHT OR LEFT DEPENDING ON 1 OR -1 INPUT.
  //direction == -1 :  move left
  //direction == 1 :  move right

  int direction_oversize = 1;
  int direction_movement_amplitude = 2;
  int blink_amplitude = 5;

  for (int i = 0; i < 3; i++) {
    left_eye_x += direction_movement_amplitude * direction;
    right_eye_x += direction_movement_amplitude * direction;
    right_eye_height -= blink_amplitude;
    left_eye_height -= blink_amplitude;
    if (direction > 0) {
      right_eye_height += direction_oversize;
      right_eye_width += direction_oversize;
    } else {
      left_eye_height += direction_oversize;
      left_eye_width += direction_oversize;
    }

    draw_eyes();
    delay(1);
  }
  for (int i = 0; i < 3; i++) {
    left_eye_x += direction_movement_amplitude * direction;
    right_eye_x += direction_movement_amplitude * direction;
    right_eye_height += blink_amplitude;
    left_eye_height += blink_amplitude;
    if (direction > 0) {
      right_eye_height += direction_oversize;
      right_eye_width += direction_oversize;
    } else {
      left_eye_height += direction_oversize;
      left_eye_width += direction_oversize;
    }
    draw_eyes();
    delay(1);
  }

  delay(1000);

  for (int i = 0; i < 3; i++) {
    left_eye_x -= direction_movement_amplitude * direction;
    right_eye_x -= direction_movement_amplitude * direction;
    right_eye_height -= blink_amplitude;
    left_eye_height -= blink_amplitude;
    if (direction > 0) {
      right_eye_height -= direction_oversize;
      right_eye_width -= direction_oversize;
    } else {
      left_eye_height -= direction_oversize;
      left_eye_width -= direction_oversize;
    }
    draw_eyes();
    delay(1);
  }
  for (int i = 0; i < 3; i++) {
    left_eye_x -= direction_movement_amplitude * direction;
    right_eye_x -= direction_movement_amplitude * direction;
    right_eye_height += blink_amplitude;
    left_eye_height += blink_amplitude;
    if (direction > 0) {
      right_eye_height -= direction_oversize;
      right_eye_width -= direction_oversize;
    } else {
      left_eye_height -= direction_oversize;
      left_eye_width -= direction_oversize;
    }
    draw_eyes();
    delay(1);
  }


  center_eyes();
}


void setup() {

  Serial.begin(115200);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {  // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for (;;)
      ;  // Don't proceed, loop forever
  }


  // Clear the buffer
  display.clearDisplay();

  display.setTextSize(1);               // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);  // Draw white text
  display.setCursor(0, 0);              // Start at top-left corner

  display.println(F("GITHUB Link:"));
  display.println(F("  "));
  display.println(F("intellar/oled_eye_display"));
  display.println(F("  "));
  display.println(F("Press \"N\" for          Next Animation"));

  display.display();
  delay(5000);
}


void loop() {
  // delay(timeD);
  // wakeup();
  // Serial.println("Wake UP!");
  // delay(timeD);
  // center_eyes(true);
  // Serial.println("Center Eyes!");
  // delay(timeD);
  // move_right_big_eye();
  // Serial.println("Moving Right!");
  // delay(timeD);
  // move_left_big_eye();
  // Serial.println("Moving Left!");
  // delay(timeD);
  // blink(10);
  // Serial.println("Short Blink!");
  // delay(timeD);
  // happy_eye();
  // Serial.println("Happy Eye!");
  // delay(timeD);
  // blink(20);
  // Serial.println("Long Blink!");
  // delay(timeD);
  // Serial.println("All Motion!");
  // // BOTTOM LEFT
  // dir_x = -1;
  // dir_y = 1;
  // saccade(dir_x, dir_y);
  // delay(300);
  // saccade(-dir_x, -dir_y);
  // delay(300);

  // // BOTTOM
  // dir_x = 0;
  // dir_y = 1;
  // saccade(dir_x, dir_y);
  // delay(300);
  // saccade(-dir_x, -dir_y);
  // delay(300);

  // // BOTTOM RIGHT
  // dir_x = 1;
  // dir_y = 1;
  // saccade(dir_x, dir_y);
  // delay(300);
  // saccade(-dir_x, -dir_y);
  // delay(300);

  // // RIGHT
  // dir_x = 1;
  // dir_y = 0;
  // saccade(dir_x, dir_y);
  // delay(300);
  // saccade(-dir_x, -dir_y);
  // delay(300);

  // // TOP RIGHT
  // dir_x = 1;
  // dir_y = -1;
  // saccade(dir_x, dir_y);
  // delay(300);
  // saccade(-dir_x, -dir_y);
  // delay(300);

  // // TOP
  // dir_x = 0;
  // dir_y = -1;
  // saccade(dir_x, dir_y);
  // delay(300);
  // saccade(-dir_x, -dir_y);
  // delay(300);

  // // TOP LEFT
  // dir_x = -1;
  // dir_y = -1;
  // saccade(dir_x, dir_y);
  // delay(300);
  // saccade(-dir_x, -dir_y);
  // delay(300);

  // // LEFT
  // dir_x = -1;
  // dir_y = 0;
  // saccade(dir_x, dir_y);
  // delay(300);
  // saccade(-dir_x, -dir_y);
  // delay(300);
  // delay(timeD);
  // sleep();

  //send A for one by one animation
  if (Serial.available()) {
    String data = Serial.readString();
    data.trim();
    char cmd = data[0];

    if (cmd == 'N') {

      switch (count) {
        case 0:
          wakeup();
          Serial.println("Wake UP!");
          break;
        case 1:
          center_eyes(true);
          Serial.println("Center Eyes!");
          break;
        case 2:
          move_right_big_eye();
          Serial.println("Moving Right!");
          break;
        case 3:
          move_left_big_eye();
          Serial.println("Moving Left!");
          break;
        case 4:
          blink(10);
          Serial.println("Short Blink!");
          break;
        case 5:
          happy_eye();
          Serial.println("Happy Eye!");
          break;
        case 6:
          blink(20);
          Serial.println("Long Blink!");
          break;
        case 7:
          Serial.println("All Motion!");
          // BOTTOM LEFT
          dir_x = -1;
          dir_y = 1;
          saccade(dir_x, dir_y);
          delay(300);
          saccade(-dir_x, -dir_y);
          delay(300);

          // BOTTOM
          dir_x = 0;
          dir_y = 1;
          saccade(dir_x, dir_y);
          delay(300);
          saccade(-dir_x, -dir_y);
          delay(300);

          // BOTTOM RIGHT
          dir_x = 1;
          dir_y = 1;
          saccade(dir_x, dir_y);
          delay(300);
          saccade(-dir_x, -dir_y);
          delay(300);

          // RIGHT
          dir_x = 1;
          dir_y = 0;
          saccade(dir_x, dir_y);
          delay(300);
          saccade(-dir_x, -dir_y);
          delay(300);

          // TOP RIGHT
          dir_x = 1;
          dir_y = -1;
          saccade(dir_x, dir_y);
          delay(300);
          saccade(-dir_x, -dir_y);
          delay(300);

          // TOP
          dir_x = 0;
          dir_y = -1;
          saccade(dir_x, dir_y);
          delay(300);
          saccade(-dir_x, -dir_y);
          delay(300);

          // TOP LEFT
          dir_x = -1;
          dir_y = -1;
          saccade(dir_x, dir_y);
          delay(300);
          saccade(-dir_x, -dir_y);
          delay(300);

          // LEFT
          dir_x = -1;
          dir_y = 0;
          saccade(dir_x, dir_y);
          delay(300);
          saccade(-dir_x, -dir_y);
          delay(300);

          break;
        case 8:
          sleep();
          break;
        default:
          Serial.println("Default!");
          break;
      }

      count += 1;
      if (count == 9) { count = 0; }
    }
  }
}

Similar Posts

Leave a Reply