Teensy based Animated Eyes


I know it is a long way to Halloween, but I thought I would share my build of the Teensy Animated Eyes project.

Some of you may have come across the animated eyes by Adafruit, that utilises the Teensy 3.1/3.2 micro controller and a couple of screen, either TFT or OLED. I had been playing around with a single eye for a while and decided to build a project utilising two TFT screens and make a pair of animated eyes. You can find the original project, with all of the wiring and code details here, on the Adafruit Learn site.

The project needs the following:

A lot of the connections between the screens are shared, so to simplify the wiring I connected both screens to a piece of copper strip board so the 6 shared connections where easy to solder up. I also included the TCS connections onto my strip board so all of the connections where distributed from a single small pcb. The connections where then made to the Teensy processor - see the Adafruit tutorial as the connections are slightly different based on type of screens you use.

With one screen hooked up the Teensy and distribution board looks like this:

With two screens you will end up with this:

You’ll notice that the wiring is folded back on itself on the back of the screens. This just helps a little to line up the wiring exit hole on the case with the wiring.

So to the case. The original case was designed for one TFT screen with a 38mm lens (clear half sphere). As I couldn’t get any 38mm half spheres I knew I had to modify the case, and while making the case work with the 40mm half spheres that I had, I also joined two cases together for a pair of eyes, so the cases look like this:

In the STL on Thingiverse, there are two small rings. I have yet to test these but they are designed just to finish off the mount and hide any small glue eruptions from mounting the glass. So why do you need the glass half spheres? Will here is the mounted screens without the spheres:

Please excuse the reflections of my desk lamp on the right screen, the next photo has the same issue. But, the next photo shows the setup with the glass in place:

Hopefully you’ll agree that the glass spheres really make a difference.

I will come back with a future post on creating your own eye designs etc. It is covered in the Adafruit article but I’ll update this thread with my take on it. Also, you may have noticed 4 headers on my Teensy. You can setup the eyes to be controlled by a joystick, and use buttons to wink and blink the eyes, although it does blink automatically as well. You can also add a light sensor and have the pupils of the eyes react to the ambient light.

My plan is to have a hooded figure ready for Halloween, and I plan to have these eyes (or a custom set - more on that in a future post) staring out form the hood.

So to finish, this is the effect you can get - please excuse the lamp glare again.

InMoov Eyes Conversion
InMoov Eyes Conversion

Now this is truly awesome. Thank you for sharing this. And as always, it is very well written up and presented. I have to work on my skills there.

Seeing this has given me a great idea. This could go really nice in the InMoov Robot I am working on. And it would free up quite a bit of room in his head. Hmmm… Now to think about how to implement this. I am hoping to get back to that project soon, I am trying to finish up a few smaller ones that I have been delaying.


Truly fascinating! I believe I see the pupils contract slightly at time. Do you have any control over pupil dilation? Would be amusing if you could contract / dilate the pupils if you were to shine light at it or put it in a dark room.


Right now the pupil dilation is just done in software, so it is minimal (I reduced the range in the code Adafruit supplied). The Teensy has plenty of I/O and one of the things they detail in their docs is adding a photoresistor to an analogue input to adjust the pupils to the lighting conditions. I have yet to try it but it is on my list. :grin:


I would love to see that.


Software and Configuration
The Teensy Eyes project uses the Teensy 3.1/3.2 board for two reasons:

  • The processor speed
  • The larger ememeory and DMA memory access

The increased memory allow the large graphics maps to be loaded into memory for high speed access through the DMA.

You will find the software download at https://learn.adafruit.com/animated-electronic-eyes-using-teensy-3-1/software about half way down the page (green box). Do follow the instructions on this page to get your environment configured and watch out for the Teensyduino installer, it seems to install the incorrect version of some of the libraries. paricularly the Adafruit_GFX, Adafruit_SSD1351 or Adafruit_ST7735 libraries.

Set up your board under the Tools menu in the IDE. The board settings in the IDE should be set to:

  • Board: Teensy 3.1/3.2
  • USB Type: Serial
  • CPU Speed: 72 MHz
  • Optimize: faster
  • Keyboard Layout: {your choice) mine is US English
  • Port: {whatever port your Teensy is showing as} in my case COM6 on my windows 10 PC

These need to be set before you attempt to compile so that the IDE knows what processor it is compiling for.

You can now attempt to compile the uncannyEyes.ino file.

If you get a compiler error about INITR_144GREENTAB not being defined, you have the wrong libraries. In this case go to your arduino IDE install directory and look in the path, hardware\teensy\avr\libraries and delete the conflicting libraries there. You can then use the Arduino Library Manager (in the IDE its under Sketch>Include Library>Manage Libraries) to install the correct version of the libraries. You can search for the libraries you need and install them from this interface.

Once you can compile the code you can download the default code to your project and you should get the effect from the previous video.

Configuring the uncannyEyes.ino
The structure of arduino software is a little different to basic Arduino projects. You will find the uncannyEyes.ino and a file called config.h in the root of the project, plus a subfolder called graphics, which holds a number of .h files for the different eye designs included with the project.

When you open the uncannyEyes.ino file in the Arduino IDE it will also open the config.h file in a separate tab. The config.h file allows you to configure your preferences for the project. Lets look at the key options:

Eye design:
Near the top of the file you will find a section like this:

// Enable ONE of these #includes – HUGE graphics tables for various eyes:
#include “graphics/defaultEye.h” // Standard human-ish hazel eye -OR-
//#include “graphics/dragonEye.h” // Slit pupil fiery dragon/demon eye -OR-
//#include “graphics/noScleraEye.h” // Large iris, no sclera -OR-
//#include “graphics/goatEye.h” // Horizontal pupil goat/Krampus eye -OR-
//#include “graphics/newtEye.h” // Eye of newt -OR-
//#include “graphics/terminatorEye.h” // Git to da choppah!
//#include “graphics/catEye.h” // Cartoonish cat (flat “2D” colors)
//#include “graphics/owlEye.h” // Minerva the owl (DISABLE TRACKING)
//#include “graphics/naugaEye.h” // Nauga googly eye (DISABLE TRACKING)
//#include “graphics/doeEye.h” // Cartoon deer eye (DISABLE TRACKING)

The // at the front of most of the lines means they are remarked out and will not do anything. You’ll notice one line is not remarked out. This is the eye design that is selected and will be displayed, in our case the default eye which you can see in the video in the first post. Change the included .h file to change the eye design, always ensure only one eye design is selected.

Type of Display:
Around line 64 of the config.h file you will find the following

//#include <Adafruit_SSD1351.h> // OLED display library -OR-
#include <Adafruit_ST7735.h> // TFT display library (enable one only)

This lets you select the type of display you are using - in my case TFT. If you are using OLED, remark out the TFT line and enabled the OLED line.

Movement and Blinking:
Around line 93 you will see some remarked out Joystick definitions. This allows you to hook up a small analogue joystick and direct the eye movement using it. You can also, in the line below, define how the eye blinks etc., and again you can attached buttons to the teensy to make the eyes blink, and wink, on command.

//#define JOYSTICK_X_PIN A0 // Analog pin for eye horiz pos (else auto)
//#define JOYSTICK_Y_PIN A1 // Analog pin for eye vert position (")
//#define JOYSTICK_X_FLIP // If defined, reverse stick X axis
//#define JOYSTICK_Y_FLIP // If defined, reverse stick Y axis
#define TRACKING // If defined, eyelid tracks pupil
#define BLINK_PIN 1 // Pin for manual blink button (BOTH eyes)
#define AUTOBLINK // If defined, eyes also blink autonomously

As the joystick input is via two analogue pins it would be possible to use anything that can output an analogue signal to control the eye movement. I was thinking about using this on a robot with sound location capabilities, where you could get the eyes to look in the direction of the sound, but that is for another project.

You will also see, at around line 106, the definition for the light sensor input that controls pupil dilation, this shows that analogue input A2 is used for the light sensor (more on that in the next post)

#define LIGHT_PIN A2 // Photocell or potentiometer (else auto iris)
#define LIGHT_PIN_FLIP // If defined, reverse reading from dial/photocell
#define LIGHT_MIN 0 // Lower reading from sensor
#define LIGHT_MAX 1023 // Upper reading from sensor

And to finish off the iris and pupil details, at line 112 you will see details that allows you to configure the max and min size of the iris, which really means the size of the pupil as you observe the eyes. If you don’t have a light sensor attached you will still see small iris/pupil changes from the noise on the unconnected analogue input.


Thanks for sharing this. Very well written, I will be able to test this out in the near future. I had ordered the items you listed in the first post. I want to complete this so I can see if there is a way to incorporate this into the InMoov Project, if not then I will just play around with it.

I love seeing these types of projects.


So let’s talk about light detection and pupil size.

The software already contains the code to read a light sensor on Analogue pin 2 and use this value to change the size of the pupil. In reality, it resizes the iris and during the resize you will see the iris pattern change as it contracts or expands, giving a very nice feeling that the muscle is actually moving and working like a muscle.

The analogue light sensor is easy to build. It is a light dectecting resistor and a 10k ohm resistor in the following curcuit:

As previously discussed, you can tweak the software’s config.h file to control how much the pupil dilates and contracts and you will get a result something like this video (excuse the shaky video, I couldn’t find my tripod):

You may also notice that the iris in this example isn’t the default iris. I particularly like the iris from the dragon eye example and have used this iris, with the standard eye files, to create a custom eye. I will do a post on creating custom eyes in the near future.


That is very cool. Add’s to the reality of it for sure.


I am working on a change to the case as I am not happy with how I have to glue the glass to the PLA. I will also add a mount for the LDR into the bridge between the eyes. Will be test printing this on Monday and it all goes to plan it will be on Thingiverse shortly after.


Absolutely fantastically awesome!!! :+1:t2::+1:t2::sunglasses:


The new improved version of the Teensy Eyes Case is up on Thingiverse https://www.thingiverse.com/thing:3365042.

This version has a new mounting method for the half spheres, where you can slip the mounting collars over the glass and just glue the collar to the body of the mount, no need to put any glue near the glass parts. It also has a recess for a 6mm LDR between the eyes, so you can incorporate the light reactive pupils directly onto the case (well sort of). And it is purple!!!


Today I realised I had an exposed PCB when I wired up the LDR. Silly of me, I should have thought.

So a quick play in TinkerCad (I know it isn’t real 3d modelling lol) and I have created a back-plate to protect the board. The new piece has been added to the Thingiverse project in case anyone else needs it. It just screws on using the 4 central bolts.


Some of my goodies have arrived. I believe the rest comes tomorrow and Saturday. This will be for the InMoov Project when I get back at that.


More goodies have arrived.


Looking forward to seeing your take on this project


Hoping to incorporate it into the InMoov I am building. I have to find some time to look at the existing setup inside the head and figure out how to get this to work. My best guess is that I shouldn’t be to difficult assuming the eye openings are roughly the same size. But in a worst case scenario I can redesign the eye area to accommodate this.


Customising the Eyes on your Teensy Animated Eyes project
Firstly, there is a lot of information on customising the eye design on the Adafruit Project pages, you can find it here, but I wanted to give you an overview and mention an issue I found.

When you download the software from the Adafruit github or the project page and unzip it you will see two directories, the uncannyEyes directory has the code for the Teensy, that we looked at in an earlier post. There is also a directory called convert, and this has a python program that lets you create your own eye designs.

The design for the eye is made up of a number of images that correlate to the various bits of an eye. So we will need images for:

  • The Sclera - the white of the eye
  • The Iris
  • The top and bottom eyelids
  • A pupil map - only required for odd shaped pupils

For the simplest customisation, you may want to start by changing the iris. Here how:

Design a new Iris image, I normally base mine on the dimensions of the iris.png file in the defaultEye example. So the iris image is approximately 256 pixels by 64 pixels, although the size isn’t critical. The iris image gets wrapped around to make the iris and the Adafruit page has all of the mathematics for working out the optimum size.

So, as an example, here is an iris image that makes the iris appear like a burning ball or sun.

You can, of course also change the eyelids and sclera. Once you have all of your images, put them in a subdirectory under the convert program. We will call our subdirectory ‘fire’.

In the convert directory there is a python program called tablegen.py, this is the program that will generate a .h file you can include in your uncannyEyes Teensy application.

So to the issue, to get the tablegen.py application to run you need to have PIL (Python Image Library) installed. I didn’t so I tried to pip install it. No joy, pip couldn’t find it!!!

It turns out that it isn’t available as a separate library but is installed if you install Pillow. Pillow is a friendly fork of PIL . To install it just go:

pip install Pillow

Now pillow will fulfil all the needs for tablegen.py to run without any code changes.

To run tablegen.py for our custom fire iris use the following command line:

python tablegen.py fire/sclera.png fire/iris.png fire/lid-upper-symmetrical.png fire/lid-lower-symmetrical.png fire/lid-upper.png fire/lid-lower.png 80 > fire.h

The images must be specified in order: sclera, iris, symmetrical upper lid, symmetrical lower lid, asymmetrical upper lid, asymmetrical lower lid. There is an 80 right at the end, this is the iris diameter in pixels. Finally, the output is redirected to a .h file, in our case fire.h.

Once run, you will find a new file called fire.h in your convert directory. Copy this to your graphics folder under the folder containing uncannyEyes.ino and config.h.

Edit config.h and add the following line into the section where all of the other eye header files are. Remember to remark out whatever eye you were previously using and make sure the fire.h file is not remarked out.

#include “graphics/fire.h”

Compile and upload the uncannyEyes.ino to your Teensy, it will reboot and, hopefully, you’ll see something like this:


And some more arrived today. Now just waiting on the copper strip board.


Have the holder parts printed now.