element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Personal Blogs
  • Community Hub
  • More
Personal Blogs
Frank Milburn's Blog The Tin Man - Mechanically and Electrically Complete
  • Blog
  • Documents
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: fmilburn
  • Date Created: 25 Oct 2021 2:42 AM Date Created
  • Views 1031 views
  • Likes 0 likes
  • Comments 3 comments
  • esp32
  • jq6500
  • 3D Printing
  • servo
  • tin man
  • arduino
Related
Recommended

The Tin Man - Mechanically and Electrically Complete

fmilburn
fmilburn
25 Oct 2021

The Tin Man is now mechanically and electrically complete.

image

 

Printed Parts

 

I didn't take any photographs during assembly but it was straightforward.  The front and sectional view from the back below shows the parts minus the electronics.

image

 

Here are my comments on the outcome:

  • Appearance:  The appearance differs from the model, at least to me.  As printed, he looks thinner and the gap between the eyes and the shell is more prominent.
  • Print Quality:  As noted previously, print quality is not that great and is most apparent on the face.  I think that is due to the thin (1.6mm) shell and the orientation which shook the print as the filament was laid down.
  • Eye Movement: Eye movement has been improved by tightening up the tolerances and slop in the joints.  I have several ideas for improving this further.
  • Assembly:  The nose cap, eye irises, base plate, and funnel cap handle were glued on with epoxy.  The eye assembly and bottom entry panel are screwed in using heat-set inserts.

 

Electronics

 

A connection for a future "Neopixel" string was tested and added to the schematic but otherwise, it is unchanged.  The battery shown is a 18650 and resides in a power circuit with charging capability, boost to 5V, and 3V3 LDO regulator (not shown).  The ESP32 can be powered from the 3V3 output of the power circuit.

image

 

The circuit was then transferred from a breadboard to a prototyping board with the connections shown below.


image

I essentially use this arrangement in all my animatronic projects and it would probably be worth having a PCB made and standardizing on a microcontroller and sound chip.

 

Firmware

 

The firmware uses the same algorithm described in a previous post but modified to accommodate multiple expressions.  The main function in the example code below loops through the animatronic events stored in an array as sequences of events.

/* Sequencer_V0_2
 * Sequences servo movement and speech from JQ6500
 * Contains ESP32 specific code, tested on generic ESP32
 * 
 * Utilizes JQ6500 library from James Sleeman: http://sparks.gogo.co.nz/
 * Utilizes servo smoothing algorithm by James Bruton: https://github.com/XRobots/ServoSmoothing
 * 
 * F Milburn,  Oct 2021
 */


// Libraries
#include <ESP32Servo.h>
#include <HardwareSerial.h>
#include <JQ6500_Serial.h>
#include <Adafruit_NeoPixel.h>
#include "Sequencer.h"


const int SEQ_NUMBER = 1;


// JQ6500
// Create the mp3 module object. We're using the ESP32 Hardware Serial UART2, so:
// ESP32 Pin 16 (RX) is connected to TX of the JQ6500
// ESP32 Pin 17 (TX) is connected to RX of the JQ6500
HardwareSerial mySerial(2);
JQ6500_Serial mp3(mySerial);


// Servos
int leftEyeServoVal = sequence[0][0].leftEyeMove;
float leftEyeServoScaled = 1200;
float leftEyeServoSmoothed = 512;
float leftEyeServoSmoothedPrev = 512;
const int leftEyePin = 25;


int rightEyeServoVal = sequence[0][0].rightEyeMove;
float rightEyeServoScaled = 1200;
float rightEyeServoSmoothed = 512;
float rightEyeServoSmoothedPrev = 512;
const int rightEyePin = 26;


Servo leftEyeServo;
Servo rightEyeServo;


// NeoPixels
const int neoPixelPin = 14;
const int numNeoPixels = 3;
Adafruit_NeoPixel pixels(numNeoPixels, neoPixelPin, NEO_GRB + NEO_KHZ800);


// Global variables
long newEventStart = sequence[SEQ_NUMBER][0].eventLength;
unsigned long currentMillis;
long previousMillis = 0;    // set up timers
long interval =  5;         // update interval in milliseconds
int eventNum = 0;
long previousEventStart = 0;


void setup() {


  Serial.begin(115200);


  // Servos
  leftEyeServo.attach(leftEyePin);
  rightEyeServo.attach(rightEyePin);


  // Speech
  mySerial.begin(9600);
  mp3.reset();
  mp3.setVolume(10);                            // volume can be set 0 to 30
  mp3.setLoopMode(MP3_LOOP_NONE);               // play one file and stop


  // NeoPixels
  pixels.begin();
  pixels.clear();
  for(int i=0; i<numNeoPixels; i++){
    pixels.setPixelColor(i, pixels.Color(100, 0, 0));
  }
  pixels.show();
}


void loop() {


  currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {  // start 5ms timed loop  
      previousMillis = currentMillis;


      // Check to see if time for new event
      if ((currentMillis - previousEventStart) > newEventStart) {
        previousEventStart = currentMillis;
        leftEyeServoVal =  sequence[SEQ_NUMBER][eventNum].leftEyeMove;
        rightEyeServoVal = sequence[SEQ_NUMBER][eventNum].rightEyeMove;
        newEventStart =    sequence[SEQ_NUMBER][eventNum].eventLength;
        if (sequence[SEQ_NUMBER][eventNum].speechFile > -1){
          mp3.setVolume(sequence[SEQ_NUMBER][eventNum].speechVolume);
          mp3.playFileByIndexNumber(sequence[SEQ_NUMBER][eventNum].speechFile);
        }
        
        // set to next event
        if (eventNum < numEvents-1){ 
          eventNum++;
        }
        else{
          eventNum = 0;
        }
      }
    
      // scale all inputs for the servo microseconds range
      leftEyeServoScaled =  (leftEyeServoVal - 512)  + 1200;
      rightEyeServoScaled = (rightEyeServoVal - 512) + 1200;
   
      // smooth inputs
      leftEyeServoSmoothed =  (leftEyeServoScaled * 0.01) +  (leftEyeServoSmoothedPrev * 0.99);
      rightEyeServoSmoothed = (rightEyeServoScaled * 0.01) + (rightEyeServoSmoothedPrev * 0.99);
    
      // save previous values
      leftEyeServoSmoothedPrev =  leftEyeServoSmoothed;
      rightEyeServoSmoothedPrev = rightEyeServoSmoothed;


      // write servos
      leftEyeServo.writeMicroseconds(leftEyeServoSmoothed);                    
      rightEyeServo.writeMicroseconds(rightEyeServoSmoothed);                    


  } // end of timed loop


} // end of main loop

 

The events and sequences are stored separately in a header file named Sequencer.h and shown below.

const int numSequences = 3;
const int numEvents = 6;


// Event and Sequence Definition
struct event{
  int leftEyeMove;       // 0 to 1024
  int rightEyeMove;      // 0 to 1024
  int speechFile;        // -1, no file called
  int speechVolume;      // 0 to 30
  long eventLength;      // milliseconds
};


event sequence[numSequences][numEvents] = {
// Leye   Reye  File Vol Time      0 = Laugh Sequence
  {{512,   512,  -1,  0,  1000},
  {0,     0,    -1,  0,  1000},
  {512,   512,  -1,  0,  1000},
  {1024,  1024, -1,  0,  1000},
  {512,   512,  -1,  0,  1000},
  {512,   512,   3,  10, 3000}},
// Leye   Reye  File Vol Time      1 = Bite Sequence
  {{512,   512,  -1,  0,  1000},
  {0,     0,    -1,  0,  1000},
  {512,   512,  -1,  0,  1000},
  {1024,  1024, -1,  0,  1000},
  {512,   512,  -1,  0,  1000},
  {512,   512,   2,  10, 3000}},
// Leye   Reye  File Vol Time      2 = Cake Sequence
  {{512,   512,  -1,  0,  1000},
  {0,     0,    -1,  0,  1000},
  {512,   512,  -1,  0,  0000},
  {1024,  1024, -1,  0,  1000},
  {512,   512,  -1,  0,  1000},
  {512,   512,   1,  10, 3000}}
};

 

In this example, there are 3 sequences each of which consists of 6 events.  The events can contain separate eye movement, speech, speech volume, and the length of the event in milliseconds.  Different events and sequences can be added by changing these files.

 

Conclusion

 

 

To finish the project I need to give the Tin Man his personality.  Will he be scary or friendly?  Happy or sad?  As noted here, I have a "voice changer" to create a voice, or a recording can be made and altered with software prior to storing it on the JQ6500.  I plan to get the grandchildren involved in that and to perhaps record the voices.  Modifications to the firmware will then be made to accommodate the personality.

 

Thanks for reading.  Comments and suggestions are always welcome.

 

Links

The Tin Man - Getting Started | element14 | Frank Milburn

The Tin Man - Smooth Moves | element14 | Frank Milburn

The Tin Man - Velleman "Voice Changer Kit&... | element14 | Frank Milburn

  • Sign in to reply
Parents
  • robogary
    robogary over 3 years ago

    Very nice !

    My tinman would be a bit corny and comical responding like the movie AIRPLANE!

     

    Another thing to consider for later could be  little wrench shaped eyebrows that pivot in the middle to help make expressions.

    Neopixels will help convey expressions too.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • fmilburn
    fmilburn over 3 years ago in reply to robogary

    Airplane is a classic :-)   I left room for neopixels but ran out of time. Moving eyebrows is a good idea.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Comment
  • fmilburn
    fmilburn over 3 years ago in reply to robogary

    Airplane is a classic :-)   I left room for neopixels but ran out of time. Moving eyebrows is a good idea.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
Children
No Data
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube