# Synchronized Head/Mouth movement with Arduino and IMUs



## Greg G (Nov 4, 2012)

So using two BNO055 Inertial Management units (IMUs) and my Arduino (Mega2560), I am able to synchronize my vampire prop head and mouth movement to my head and mouth movement. I plan to use this as an interactive prop this year for the TOTers.
https://photos.app.goo.gl/xc7iGbY2n55qaNbT9

In the video I kind of exaggerated my mouth movements to better see what if any delay there would be between my voice and that movement (It looked to be acceptable when I covered up myself in the video and just watched the prop). Note: you could replace the mouth IMU method with a voice activated servo scheme. I also can use this same setup to record the whole thing to allow it to be played back (along with an audio file).
I have a speaker in the prop for talking via audio from a head mic on me, and plan to use a small web cam (Relohas WIFI spy cam) that also has receive audio for my eyes and ears. I plan on embedding the webcam on/in the prop head somewhere. The audio and video feed can then be viewed/heard on a smartphone using the Relohas webcam app. I'll probably get a cheap $20 VR headset that holds the smartphone and provides focus to make it easier to see the phone display while my head is moving around. It can replace my cap so the one IMU is on the VR headset now. Hopefully I can get all that done in time.
The BNO055 is an Adafruit 9-DOF Absolute Orientation IMU Fusion device ($34 on the Adafruit.com website). It connects to the Arduino via the I2C bus. Adafruit provides the Arduino software package for using it and it is really easy to get accurate heading (yaw), pitch, and roll from it (just a single call to get that once the device is setup). I was running a 50 millisecond interval to read the IMUs, and update the servos.


----------



## ViennaMike (Nov 24, 2010)

That is truly excellent! I've been fooling around with something similar using the same sensor board, but with Pi Zeros, communicating wirelessly. But I've been having trouble with where / how to mount the IMU, and hadn't thought of the hat brim! 

A couple of questions: What are you using for the servos? I don't hear any servo noise. 

Also, did you have any issues with calibrating the magnetometer to get the yaw movements right?


----------



## Greg G (Nov 4, 2012)

So I'm using Hitec servos. There is some noise depending on what position the head is held stationary at. When the top of the head is level to the ground (i.e. normally upright) there is very little torque load on the vertical servo of the head and thus little noise of the servo trying to hold that position. However if the head were to be tilted forward say 30 degrees and held stationary at that point you would hear more servo whine as the servo is trying to hold that position under the load of the head. When the servo is moving to a position it seems to not be so noisy. If you turn the volume up you can hear the whine at points in the video. Both the vertical and rotational servos are pretty beefy servos because I wanted the head to move as quickly as possible. They are both Hitec HS-7954SH High Voltage, High Torque servos run at 6 volts (333 oz in of torque and 0.15 seconds per 60° no load). 

I just do the normal BNO055 calibration (pointing the device in various directions until it indicates calibrated) then save it off in eeprom of the Arduino then restore it to the BNO055 before running the prop. However even when I do that, it seems like I still need to go through calibration movements of the BNO055 again after each power cycle and restore to reach the fully calibrated state of yaw, pitch ,roll although it seems to calibrate quicker using the restored values. 
The way I get around having to know if the device values are absolutely correct and if the device is positioned level on my head is by storing a starting position reference by holding my head upright and level and looking straight forward at the start. Then the code uses the difference between the current device pitch, roll, yaw readings and the reference and adds it to the known pitch, roll, yaw servo settings for the prop head where it is in the same upright, level, looking straightforward position to determine the actual servo settings to use. This allows my straight ahead and the props straight ahead to be pointing in different directions and everything still works because it's all relative to a given starting point.


----------



## Greg G (Nov 4, 2012)

One other thing I found is that the BNO055 needs to have its chip side more or less pointing up when your head is in the normal level looking position otherwise the yaw readings tended to go crazy when the pitch from level is more than 30 degrees. Maybe there is a setting to handle this but I had these crazy yaw readings if the pitch was more than a certain value when I had the chip side pointing down.


----------



## ViennaMike (Nov 24, 2010)

Very good to know! Thanks!


----------



## Batbuddy (Sep 3, 2014)

That is very cool! I really like this work! I will have to get some of these IMU's. So as I understand it you are getting readings from two IMUs and the data is being sent to the servos via the Arduino? I wonder if you would be willing to share your code with us?


----------



## Greg G (Nov 4, 2012)

ViennaMike said:


> That is truly excellent! I've been fooling around with something similar using the same sensor board, but with Pi Zeros, communicating wirelessly. But I've been having trouble with where / how to mount the IMU, and hadn't thought of the hat brim!
> ....


Thanks. I like your idea of making it all wireless. A future planned enhancement/dream is to add servos to add arm movement to the prop and wireless would eliminate the wire clutter of the IMUs that I'd attach to my arms for this.


----------



## Greg G (Nov 4, 2012)

Batbuddy said:


> That is very cool! I really like this work! I will have to get some of these IMU's. So as I understand it you are getting readings from two IMUs and the data is being sent to the servos via the Arduino? I wonder if you would be willing to share your code with us?


Yep, getting readings from the IMUs, calculating servo settings, and setting the servos. The mouth servo requires the IMU pitch reading of the head to be subtracted from the pitch reading of the mouth and then subtracting the pitch reference readings difference from that. Also I do some scaling to make the mouth movements more pronounced on the prop.

Here is a zip of my entire prop controller code. The sections of interest are those involving ADAFRUIT...., else if (0 == strcmp(token, "Visualize3D"))... (for calibrating), else if (0 == strcmp(token, "ImuHeadMouth"))... , and the 
if (AdafruitImuHeadMouthEnabled ) ..... sections.
Note that you can get the Adafruit libraries from the Adafruit website from their documentation on the BNO055


----------



## Batbuddy (Sep 3, 2014)

Your awesome, thanks for sharing! This is just so fantastic.


----------



## Greg G (Nov 4, 2012)

Another thing to note is that the BNO055 supports only two selectable I2C addresses so you can't have more than two of these BNO055s connected on the same I2C bus wires. You would need to use a simple I2C multiplexer chip to handle this like an Adafruit TCA9548A I2C Multiplexer ($6.95) or use separate I2C buses.


----------



## Greg G (Nov 4, 2012)

Although you probably don't need it if you're already controlling servos in your setup, here is the Arduino software servo interface package that my controller prop code uses.


----------



## [email protected] (Sep 16, 2019)

Really cool. Do you have wiring diagram for these?


----------



## Greg G (Nov 4, 2012)

[email protected] said:


> Really cool. Do you have wiring diagram for these?


Here is how I used it.
Adafruit BNO055 Absolute Orientation Sensor wiring:
Vin --->5V Arduino
3VO --->NC
Gnd --->Gnd Arduino
SCL --->Arduino Mega 2560 pin 21 (SCL). This is the I2C clock bus
SDA --->Arduino Mega 2560 pin 20 (SDA) This is the I2C data bus
RST --->NC
INT --->NC
ADR --->3V Arduino for 0x29 I2C ID, Open for 0x28 ID
PSO, PS1 --->NC


----------



## Greg G (Nov 4, 2012)

Another thing to note is that since my prop only has yaw and pitch servos (to rotate in the horizontal and vertical planes), I don't use the roll readings from the IMU. If your prop has a servo to tilt the head from side to side then you would use that roll IMU reading to control the tilt servo.


----------



## ViennaMike (Nov 24, 2010)

I've finally gotten back to working on my skull mime project and have learned that the bouncing around I asked about earlier may be because the I2C interface on all Raspberry Pi's before the Pi 4 (not sure about the 4) doesn't handle I2C clock stretching correctly. It's a problem in the chip, so it can't be fixed by software. This doesn't affect Arduinos or other boards with a different chip for I2C. There's some workarounds posted (lower the i2c clock speed to 10,000 to hopefully avoid the board needing to clock stretch, and the latest Adafruit interface also supports the UART interface on the BNO055 to avoid this problem. I'm posting this in case others are trying to use the BNO055 with a Pi. I've got the UART interface up and running successfully.


----------



## pintoshine (Apr 19, 2021)

Have you thought about porting this to a Teensy 4.0 or 4.1? It certainly has the power of a Raspberry PI without the OS overhead but programs like an Arduino. I recently built an OctoBanger clone with one and it decodes and plays the audio from the internal cpu along with playing the scare sequence.


----------



## Greg G (Nov 4, 2012)

pintoshine said:


> Have you thought about porting this to a Teensy 4.0 or 4.1? It certainly has the power of a Raspberry PI without the OS overhead but programs like an Arduino. I recently built an OctoBanger clone with one and it decodes and plays the audio from the internal cpu along with playing the scare sequence.


 Ahh, sorry I didn't see this sooner. That is a really good idea. Yeah that is a pretty powerful board and still has all the existing interfaces of the Mega 2560.


----------

