How to Build a 3D Printed Animatronic Eye with Arduino

Published  June 30, 2022   0
3D Printed Animatronic Eye with Arduino

In this project, we are going to build an animatronic eye with Arduino. I got the idea to create an animatronic eye while looking for new project ideas online, and this project immediately caught my attention. First of all, it looks cool and has a simple mechanism and I learned a lot about mechatronics while working on this project. A big shout out to Will Cogley for building the 3D model and making all the source file accessible for the community, in his words he wanted to design it so that it is more accessible to the maker community. There are two versions of this animatronic eye design, a simple one and an advanced one, and for this project, we thought to build the simple one and in the process, we will let you know the build experience along with the problems we encountered. 

Components Required to Build the 3D Printed Animatronic Eye

The BOM of this project is very small because all the hard work is done by the 3D printer and we only need some screws and bolds most of which you can find in your local hobby store. A complete list of BOM is given below.

  • Six SG90 Servo Motor
  • Screws M2, M3, and M4
  • Arduino UNO
  • Jumper Cables
  • Breadboard
  • Pinheadder
  • PLA Filament and 3D Printer

Post Processing and Assembly - Animatronic Eye Mechanism

To work with this project we need to first print all the 3D models, you can find the 3D models in the Ikkalebob instructables. Once all the 3D parts are printed you need to sand the eye and some other parts that are necessary for smooth cooperation, once those parts are done we can move on to the assembly process. If you have printed every part correctly, your products should resemble the image below.

Animatronic Eye Body Parts

We will start our build by attaching 5 of 6 servo motors to the Servo_Block module, as you can see in the image below. To capture the image I have to use black as the background because it increases the level of detail in the image.

Animatronic Eye Mechanism

Now we will connect the Servo_Block to the Main_Base which will look something like the image below. We have also used four 12mm M3 allen screws to make the leg of the device.

Animatronic Eye Setup

Next, we will connect the Eye-Adaptor with Fork for both eyes. Once that is done, we will connect the Eye-Holder with the Eye-Adaptor and the Three-point_Connector with the Fork. Once all this process is done, it will look something like the image below.

diy animatronic eye mechanism 3d printed

Once this is done, we will connect the sixth and the last servo to the Sub_Base and then connect the Sub_Base to the Main_Base with screws. After this, we will pop in the PlaceHolder Eye to the eye adaptor. We have also connected the X-Arm and Y-Arm with Screws.

Animatronic Eye 3D Model

Now we will connect the Eyelid Connectors to the Eyelid and we are using M3 screws to hold the eyelids in place from two sides.

3D Printed Animatronic Eye

If you have done everything correctly the image will look something like the image shown above where you can see we have connected all the eyelids with the eyelid connector and we have screwed them with the arms of the servo motor. Once this is done, we can move to the coding process.

3D Printed Animatronic Eye Circuit Diagram

The schematic diagram of the DIY 3D printed animatronic eye is shown below, and as you can see it's very simple and easy to understand. Although the PCA9685 IC, a 16 Channel 12-Bit PWM Servo Motor Driver, is used in the schematic diagram provided by the project's designer and author, we will not be using it for this project because the Servo Library of Arduino can easily handle six servos.

Arduino based 3D Printed Animatronic Eye Circuit Connection

As we have said earlier, the hardware connection is very simple. We are using six pins of the Arduino to control six servo motors. If we take a quick look at the specifications of the Arduino you can see that the Arduino has six PWM pins and we are using all those pins to control all six of our servo motors.

Arduino Code for Controlling the Animatronic Eye

The animatronic eye Arduino code is very simple and easy to understand. For this code to work, we will be using the Servo.h library of the Arduino.

We start our code by including the required libraries and defining all the instances required to control all six servo motors.

#include <Servo.h>
Servo top_left_eyelid;
Servo bottom_left_eyelid;
Servo top_right_eyelid;
Servo bottom_right_eyelid;
Servo Yarm;
Servo Xarm;

Next, we have our setup() function. In the setup function, we have declared which part of the eye is connected to which pin of the Arduino. This is very useful because we can unplug all the connectors and connect it as exactly as it was.

  top_left_eyelid.attach(10);
  bottom_left_eyelid.attach(11);
  top_right_eyelid.attach(5);
  bottom_right_eyelid.attach(6);
  Yarm.attach(9);
  Xarm.attach(3);

Next, we initialize the serial for debugging and we call some functions in order to keep the eye open and in the center and we also add some delay for stability.

  Serial.begin(9600);
  open_eye();
  eye_ball_centert();
  delay(2000);

Next, we have our loop() function, but before we explain the loop function, we will explain some more important functions that are necessary to understand the content inside the loop function. These functions are the most important functions and with these, we are going to move the eyeballs of the system. First, we have the open_eye() function. If you look at the hardware, you need to move one servo in the clockwise direction and another one in the anticlockwise direction, we will do the same for both the right and left eyelids.

void open_eye() {
  top_left_eyelid.write(55);
  bottom_left_eyelid.write(36);
  top_right_eyelid.write(2);
  bottom_right_eyelid.write(160);
}

Next is the close_eye() function, in the close_eye function we will do exactly the same thing as the open_eye function, but in reverse.

void close_eye() {
  top_left_eyelid.write(2);
  bottom_left_eyelid.write(120);
  top_right_eyelid.write(46);
  bottom_right_eyelid.write(55);
}

Next, we have the look_up() and look_down() function. If you look at the hardware, moving the Y-arm of the device will move the eyeball up and down.

void look_up() {
  Yarm.write(132);
}
void look_down() {
  Yarm.write(45);
}

Next, we have the eye_ball_left() and eye_ball_right() function which is the same as the up and down function, the only difference is in the angles of the device.

void eye_ball_left() {
  Xarm.write(50);
}
void eye_ball_right() {
  Xarm.write(130);
}

Next we have the eye_ball_centert() function. In this function, we have set up the X-arm and Y-arm to a 90-degree angle so that we can move the eye to the dead center.

void eye_ball_centert() {
  Xarm.write(90);
  Yarm.write(90);
}

Now we have some other functions that I wrote to make our life a lot easier. In that list we first have the synchronous_close() function, calling this function will close and open the eye one time.

void synchronous_close() {
  close_eye();
  delay(420);
  open_eye();
  delay(222);
}

Then we have the random_close() function which will randomly open and close the eye. This will make a cool effect.

void random_close() {
  close_eye();
  delay(random(220, 880));
  open_eye();
  delay(random(220, 880));
}

Next, we have the random_movement() function. In this function, we have used the random() function of the Arduino inside the delay function to make the eye move randomly.

void random_movement() {
  Xarm.write(60);
  delay(random(250, 340));
  Yarm.write(80);
  delay(random(250, 340));
  Xarm.write(120);
  delay(random(250, 340));
  Yarm.write(140);
  Xarm.write(60);
  delay(random(250, 340));
  Yarm.write(80);
  delay(random(250, 340));
  Xarm.write(120);
  delay(random(250, 340));
  Yarm.write(140);
  eye_ball_centert();
  delay(300);
  synchronous_close();
  random_close();
}

Now we will explain the void loop function which is the main function of the Arduino. In this function, we will move the eye left, right, and center and then up and down, and then we will make the eye blink. We will do this a couple of times and make a random motion. And in the end, we have two for loops. The for loops are there as an example of how you can achieve smooth motion or move the eyeballs.

void loop() {
  eye_ball_left();
  delay(680);
  eye_ball_right();
  delay(680);
  eye_ball_centert();
  delay(450);
  synchronous_close();
  eye_ball_centert();
  delay(450);
  look_up();
  delay(400);
  look_down();
  delay(400);
  eye_ball_centert();
  delay(300);
  random_close();
  delay(450);
  look_up();
  delay(400);
  look_down();
  delay(400);
  random_movement();
  delay(400);
  eye_ball_centert();
  delay(300);
  top_left_eyelid.write(2);
  bottom_left_eyelid.write(120);
  delay(200);
  top_left_eyelid.write(55);
  bottom_left_eyelid.write(36);
  delay(200);
  open_eye();
  delay(500);
  for (int i = 60; i < 120; i++)
  {
    Xarm.write(i);
    Yarm.write(i - 5);
    delay(10);
  }
  eye_ball_centert();
  delay(400);
  synchronous_close();
  for (int i = 120; i > 60; i--)  {
    Xarm.write(i);
    Yarm.write(i - 5);
    delay(10);
  }
}

This marks the end of the code portion and we can move forward to the next section of the article.

Testing and Debugging the 3D Printed Animatronic Eye

As the mechanical portion of the project was kind of hectic, there were many things that did not work in the first go, so in this section, I want to discuss those topics.

The first problem we had was that the eye_place_holders were not moving smoothly and there was a lot of friction between the eye_place_holders and the eye_lids.

Animatronic Eye Issue

The solution to this problem was to lose the screw that is holding the Eye-Holder with the sub-base of the device which are the marked screws shown above.

The next problem was how to connect the servo arms to the arms of the eye_lid and the X-arm and Y-arm. This was a huge problem because without proper joints the device will not work smoothly, so in the image below you can see pictures of all the servo arms.

Servo Arm

Other than that everything was working absolutely well and the final result was looking like the gif that is shown below.

Code

#include <Servo.h>

Servo top_left_eyelid;

Servo bottom_left_eyelid;

Servo top_right_eyelid;

Servo bottom_right_eyelid;

Servo Yarm;

Servo Xarm;

void setup() {

  top_left_eyelid.attach(10);

  bottom_left_eyelid.attach(11);

  top_right_eyelid.attach(5);

  bottom_right_eyelid.attach(6);

  Yarm.attach(9);

  Xarm.attach(3);

  Serial.begin(9600);

  open_eye();

  eye_ball_centert();

  delay(2000);

}

void loop() {

  eye_ball_left();

  delay(680);

  eye_ball_right();

  delay(680);

  eye_ball_centert();

  delay(450);

  synchronous_close();

  //synchronous_close();

  eye_ball_centert();

  delay(450);

  look_up();

  delay(400);

  look_down();

  delay(400);

  eye_ball_centert();

  delay(300);

  random_close();

  delay(450);

  look_up();

  delay(400);

  look_down();

  delay(400);

  random_movement();

  delay(400);

  eye_ball_centert();

  delay(300);

  top_left_eyelid.write(2);

  bottom_left_eyelid.write(120);

  delay(200);

  top_left_eyelid.write(55);

  bottom_left_eyelid.write(36);

  delay(200);

  open_eye();

  delay(500);

  for (int i = 60; i < 120; i++)

  {

    Xarm.write(i);

    Yarm.write(i - 5);

    delay(10);

  }

  eye_ball_centert();

  delay(400);

  synchronous_close();

  for (int i = 120; i > 60; i--)  {

    Xarm.write(i);

    Yarm.write(i - 5);

    delay(10);

  }

}

void random_movement() {

  Xarm.write(60);

  delay(random(250, 340));

  Yarm.write(80);

  delay(random(250, 340));

  Xarm.write(120);

  delay(random(250, 340));

  Yarm.write(140);

  Xarm.write(60);

  delay(random(250, 340));

  Yarm.write(80);

  delay(random(250, 340));

  Xarm.write(120);

  delay(random(250, 340));

  Yarm.write(140);

  eye_ball_centert();

  delay(300);

  synchronous_close();

  random_close();

}

void random_close() {

  close_eye();

  delay(random(220, 880));

  open_eye();

  delay(random(220, 880));

}

void synchronous_close() {

  close_eye();

  delay(420);

  open_eye();

  delay(222);

}

void eye_ball_left() {

  Xarm.write(50);

}

void eye_ball_right() {

  Xarm.write(130);

}

void eye_ball_centert() {

  Xarm.write(90);

  Yarm.write(90);

}

void look_up() {

  Yarm.write(132);

}

void look_down() {

  Yarm.write(45);

}

void close_eye() {

  top_left_eyelid.write(2);

  bottom_left_eyelid.write(120);

  top_right_eyelid.write(46);

  bottom_right_eyelid.write(55);

}

void open_eye() {

  top_left_eyelid.write(55);

  bottom_left_eyelid.write(36);

  top_right_eyelid.write(2);

  bottom_right_eyelid.write(160);

}

Have any question realated to this Article?

Ask Our Community Members