Captain Rex Mini
Disneyland Animatronic Character Performance Robot
Disneyland Animatronic Character Performance Robot
Welcome aboard! This is Captain Rex from the cockpit. I know this is probably your first flight, and it's mine too.
The following is a 1 minute video demo highlighting Captain Rex Mini's character animation, a re-enactment of various scenes from the original Disneyland Star Tours ride that he is from.
This PDF is a summarized version of the extensive design documentation on this website.
Captain Rex Mini is a fully 3D printed animatronic robot capable of dynamic character performance using motors, lights, and sound. He is ~10" (~254mm) tall and has 7 degrees of freedom, blinking eyes, a "talking" mouth, and light up dashboard buttons.
Part-integrated ball bearings and custom designed snap-fit pins are used to reduce COTS parts, reducing system complexity and the BoM cost down to just $98. The final design has 74 unique parts that I designed and about 2500 lines of code.
Designed, built, and tested in just under 2 months, this project pushed the limits on what's possible with consumer-level resources, utilizing the latest in high precision 3D printing, affordable and powerful electronics, and AI-assisted software development.
-
Captain Rex Mini was exhibited at the Bay Area Maker Faire 2025, where he was given an Editors' Choice award. Over the 3 days of the event, he performed 200 cycles of his 4.5 minute performance for attendees, with no major performance faults.
Captain Rex Mini is modeled after Captain Rex, the RX-24 pilot droid from the original 1987-2010 Disneyland motion simulator ride, Star Tours.
With a "Remove Before Flight" tag still hanging from his side, it's Captain Rex's first flight ever in the Starspeeder 3000 as his clumsy inexperience brings audiences into the Star Wars adventure of a lifetime.
AI was used in the making of this project, and will be clearly indicated where used with orange text or an "AI" icon.
All of the mechanical design is my own work. All text in this article was written by me.
CAD orientation convention for this article is Z-axis up.
A few months ago, I bought a 3D printer, a Bambu Labs A1 Mini. I was immediately impressed by the reliability, resolution, and accuracy of parts printed with the high resolution 0.2mm nozzle. I also got on a bit of a nostalgia kick on Youtube, and was reminded of my childhood memories of riding the original Star Tours. I thought it would be fun to bring back a little of that magic and build my very own Captain Rex.
My main goal is to completely replicate all of the main capabilities of the original Captain Rex animatronic. This includes having all of the same degrees of freedom, full range of motion, and other features, like lights, that are used on the ride.
My other goal is to prove that now is the best time to learn to become a mechanical engineer. In the past 2 decades, the proliferation of software development careers owes much to the fact that your BoM cost is pretty much $0. With nothing but a cheap laptop, aspiring engineers were able to build impressive pieces of software to kick start their careers as early as high school.
Mechanical engineering, on the other hand, has a huge barrier to entry. It's expensive to exist in the physical world. Parts, tools, consumables, and other fabrication costs run up the bill incredibly quickly. My high school robotics team started in the back of my school's auto shop, where we had nothing but a dull drill press and a wood bandsaw. Our robot cost 4 figures. We needed sponsors before we could even think about building a robot.
There are 3 key components that have changed the game:
3D printers have become reliable and affordable fabrication machines. A $250 machine capable of 0.1mm precision or better is incredible.
Electronics are cheaper than ever. Forget historical comparisons - even today, an ESP32 is 1/3rd (or less!) of the cost of an Arduino.
AI. Large language models have made no-code/low-code software development with considerable feature scope possible for everyone. In its current state, LLM code generation is extremely suitable for one-off projects like my own.
Captain Rex Mini uses an ESP32-S3 microcontroller and a Pololu Mini Maestro servomotor controller to send commands to MG90S servomotors and two strings of WS2812B addressable LEDs. A PC is used to run an Animatronic Performance Software, which synchronizes the playback of video, audio, motor commands, and LED commands.
Power is supplied by a USB-C PD trigger board, and the 9V input is stepped down to a 6V power rail for the servomotors, and 5V rail for all other logic components.
The Mini Maestro receives position commands from the Animatronic Performance Software in the Maestro script format, and converts it into PWM commands to the 7 servomotors, managing position control logic separately from the ESP32.
The addressable LEDs are controlled by the ESP32, sending commands for eye blinking, mouth dialogue flashing, and dashboard lighting pattern scene change. The first LED string has 3 LEDS for the eyes and the mouth, while the second LED string has 8 LEDs (#4 is turned off because it's covered) for the dashboard buttons. These are triggered by serial commands from the Animatronic Performance Software.
I originally chose to use the Pololu Mini Maestro to minimize software complexity for motor control. It handles all of the position control logic with fast hardware implemented PWM, and it translates it into easy-to-adjust values for position, velocity, and acceleration. Most importantly, I chose it because it comes with a GUI based key frame animation software that makes smooth motor control much "easier" to implement. More on that later.
There are 3 core pieces of software. The Animatronic Performance System Python code runs on a PC and synchronizes the performance between video, motors, and LEDs. The LED Control System Arduino C++ code runs on the ESP32 and handles different LED states for the eyes, mouth, and dashboard. The Servo Animator Python code enables you to use a game controller to puppeteer, record, and play back servomotor animations.
A Timing Generator Python script was also used to generate dialogue timing for the mouth LED.
All 4 files are available on Github here.
The Animatronic Performance System runs the show. It starts the video, the motor sequences, and the LED sequence at the same time. As the performance continues, it uses timestamps pulled from the VLC video player to trigger different motor animation sequences at different times. When it reaches the end, it loops back to the beginning and runs the show repeatedly until the user manually triggers the shutdown command.
The LED Control System synchronizes and controls the LED performance timing. To start a performance, the ESP32 takes a serial input and starts a 10 second countdown, displayed on the serial monitor output of the Arduino IDE. Although lights and motors are synchronized off the ESP32, the show video isn't, so the countdown timer is helpful for manually starting the video file at the right time.
Lights are synced by a timing array, prerecorded using the Timing Generator. Motor control comes from another timing array generated by the Servo Animator, which is forwarded from the ESP32 to the Pololu Mini Maestro over UART.
The LEDs have different functions. The eyes blink at a pre-specified interval, regardless of performance. The mouth flashes according to a prerecorded timing array. The throttle dashboard LED string can switch between 4 blinking patterns - idle (yellow and blue lights randomly blink on and off in a slow interval), warning (slow red flash), alarm (fast red flash), and off. The dashboard switches between these patterns according to its own prerecorded timing array, synchronized to the scene.
A diagnostic mode is included for individual testing of various functions, allowing you to independently trigger motors, lights, and sequences.
The Servo Animator connects a game controller to the Pololu Mini Maestro servo controller and allows for individual motor animation to be manually performed, recorded, combined, and played back.
A Logitech Extreme 3D Pro joystick is used for its throttle input lever, perfect for mapping 1-to-1 to a servomotor's position. You can start a recording, manually perform the character actions in sync to your reference audio/video, then save the result to a json file that can then be played back later. Each channel can be saved independently and later combined into a single performance, which can then be converted into the Pololu Maestro scripting language. The final Maestro script is loaded onto the ESP32 and forwarded to the Mini Maestro in sync with the lighting and audio (the Maestro doesn't have enough memory for the script generated by this method, so it's forwarded from the ESP32 instead).
For more context on why this ended up replacing the Pololu Maestro Control Center, see the Animation section below.
The Timing Generator is relatively simple. To create the timing array file for the mouth dialogue, you can start a timing recording with a countdown to manually start your reference audio at the same time. Every time you press spacebar, it will record a dialogue "event" that stores a time value (milliseconds) and an LED on/off (or high/low) value.
The resulting timing file is what's used by the ESP32 to send commands to the mouth to brighten in sync with the dialogue. This can also be used for the dashboard LED timing, but for my demo, I created that array manually since it only changes 3 times.
Captain Rex Mini is 99.9% 3D printed from PLA. The only non-printed parts are the steel bearing balls and the electronics. The first MVP functional prototype was completed in 1 month, with the 2nd month spent refining reliability, software, and animation.
There are 10 functioning LEDs for the face and throttle dashboard. Seven MG90S hobby servomotors provide the movement for his upper arm, lower arm, neck lift, neck rotation, head nod, visor, and throttle arm. Each is geared for a different intended range of motion to match the full scale ride animatronic.
I designed a total of 74 unique parts for this project. The final BoM part count is 111 mechanical parts plus 12 electronic components, excluding wire harnesses.
Exterior - Internal Structure - Gear Train Components
Motion - Degrees of Freedom
Part Nomenclature
CAD was done in Solidworks. I designed all of the structure and functional machine elements, with all 74 parts optimized for FDM 3D printing and my design requirements.
A fantastic STEP model of a 1:1 scale RX-24/Captain Rex was shared with me by the folks over at the RX Builders Club [2] on Facebook. I imported, scaled down, and edited the STEP files to fit my use case by remodeling it using surface and mesh modeling techniques, as well as combining multiple parts into solid bodies. The remodeled and scaled down models were then merged with the structural components I designed. A big thanks to the original designers for sharing their work with me.
With the requirements outlined so far, here are my key design constraints:
Primarily 3D printed, with a goal to reduce the number of unique COTS parts. No carbon fiber rods or heat set inserts here.
MG90S hobby servomotors are used in all moving joints because of my requirement to use the Pololu Mini Maestro.
Cost minimization. Besides being good engineering practice, COTS part reduction and commonization helps bring down the cost and complexity. My final project cost ended up being $240, and my final BoM cost is $98. See Appendix.
Two types of PLA were used - matte PLA (grey) and basic PLA (black), from Overture and Sunlu respectively. In my testing, I discovered that for my use case, matte PLA has a number of desirable properties.
Dimensional stability. Through iterative testing, I discovered that Overture matte PLA has exceptional dimensional stability, better than basic PLA. In fact, it was so good that in my later design iterations, I stopped including clearances all together for light interference/press-fit interfaces, and just dimensioned my parts edge-to-edge.
Detail and surface finish. Absolutely superb, with nearly invisible layer lines. Matte PLA also has weaker bond strength between layers, which means support material could be cleanly pulled off the model, by hand, every time.
Prototyping post-processing. Matte PLA is easier to sand and cut through compared to basic PLA, which was helpful when prototype parts needed to be modified to fix part interference or try out new ideas. I use a standard hobby x-acto knife for trimming and cutting, and a nano glass nail file for sanding, useful little tools that I picked up from my Gundam model kit hobby.
That weaker interlayer bond strength, while useful, is also matte PLA's greatest weakness when strength is a requirement. The technical datasheet for Overture Matte PLA indicates a Z-axis tensile strength of 10.9 ± 1.2 MPa, while Bambu PLA Basic has a tensile strength of 31 ± 3 MPa. (I'm using Bambu's PLA for comparison because Sunlu doesn't provide tensile strength numbers in the Z-axis in their TDS). Parts like the neck lift compound gear that needed to be printed in the length-wise orientation easily break along the layer lines when force is applied perpendicular to the shaft.
Basic PLA was used anywhere that matte PLA's properties were not suitable - namely, gears and bearing crowns. In short, these components have thin or long pieces that need to be printed along the Z-axis, and experience loads that make them susceptible to breaking along the layer lines. I also suspect that matte PLA will wear faster than normal PLA for gear teeth interfaces, although that remains to be seen after regular usage.
Side note: PETG was briefly considered for its significantly better creep resistance, but I personally have a lot of issues with clogging and print failures when printing with the finer 0.2mm nozzle. It also doesn't look anywhere as good as matte PLA does when it comes to surface finish and details.
In total, it takes 286.99 grams of filament to print all of Rex's parts using 2-3 walls, 15% adaptive cubic infill, and supports. Support structure consumes another 97.39 grams of filament, for a total of 384.38 grams. At a cost of $15/kg, the total material cost was $5.77.
Note that this does not include prototyping reprinting waste, which I estimate to be about x2 the mass of the final product.
I finished all of the initial structural design in 1 month, and had a fully assembled Captain Rex prototype with basic core functionality in all 6 internal motors.
This speed was made possible by simultaneous design and fabrication. After finishing the first revision of the core functional parts, I began printing nonstop in an iterative cycle of printing, testing, and design.
To iterate designs quickly, the design/print loop must be closed as tightly as possible. Here are 3 ways I did this:
To optimize this process, I focused on dynamically balancing print time and design time. Design time corresponds with geometric complexity, but print time corresponds with volume - two completely uncorrelated variables. For example, the head is a complex part with high design time and low print time, but the midsection structure is a part with the opposite. You can see this thinking above in the midsection reprints, where the initial iterations used easy-to-design press fit pins to fasten the structure together, before later adding the more complicated-to-design mating holes for the snap pins.
Iterative feature inclusion. Instead of finishing the entirety of a part before printing, I focused on building out the bare minimum geometry necessary to validate important functions.
You can also think of features in terms of independent and dependent variables. After determining which features are the most important, independent features should be implemented, printed, and tested first. As soon as those are validated, the next layer of dependent features can then be added.
Separating the prototype parts into high precision and low precision parts was also a huge time saver. I print them on either the 0.2mm nozzle at 0.08mm layer height or the 0.4mm nozzle at 0.20mm layer height. The high resolution prints take almost 3 times longer than the low ones - large parts could take anywhere from 6-12 hours each at high resolution.
Detailed exterior parts, gears, bearings, and anything else that required dimensional accuracy was printed in 0.2mm. I split the pedestal in half to separate the section that contained the integrated ball bearing races, and the rest was just solid support structure. I cut the outer details of the midsection structure off to be printed in 0.2mm, allowing me to print the giant midsection structure in 0.4mm, which was a huge time saver because I ended up reprinting it 5 times.
In the end, my integrated parts design approach meant that all of my parts had precision features that needed to be printed in 0.2mm for the final revision. However, for the purposes of prototyping, a split approach was definitely the way to go.
The general design concept is a stiff and static inner structure that houses all of the functional components, while the lightweight moving parts and "outer shell" details are added on top of this structure.
The structure is intended to maximize stiffness by first filling the entire available build volume, and then removing cavities, access holes, and clearances from the structure. This maximizes the area moment of inertia of the cross section, and is a uniquely 3D printing design philosophy that takes advantage of the fact that because most of the material is in the walls and the interior infill is mostly air, volume and material do not scale the same way normal materials do. Additionally, increasing the complexity of the geometry in 3D printing is, essentially, "free", with almost no effect on fabrication difficulty.
Each structure layer is connected to the next using reusable "snap pins" that I designed - see Designing the Snap Pins below for more.
My choice of using MG90S hobby servo motors were driven by my selection of the Mini Maestro servo controller, as previously detailed. This meant that I had two significant design challenges:
Packaging. After deciding that I wanted Rex to be desktop-sized, I was faced with the challenge of fitting 6 relatively bulky servo motors into a very confined space.
Servo angle limitations. Hobby servomotors can only rotate 180 degrees [3] because the potentiometer in the servo used for position feedback can't do continuous rotation. However, Rex has up to 270 degrees of motion in his upper and lower arms, and 360 degrees in his neck.
From the start, I knew that without making Rex bigger, I had to cut off the mounting flanges for the 2 motors in the pedestal (for lower ring rotation and neck rotation) and the 2 motors in his head to get them to fit.
My requirement for range of motion lead to some interesting design choices. Normally, gearboxes are gear speed reducers, but because I need an output angle greater than the 180 degrees the servomotors can do, I need gear speed multipliers instead. This is atypical of most gearboxes, where gear speed reduction is usually desired because not only does it provide more torque, it also increases the resolution of your output angle (for example, a 2:1 gear ratio gives you a finer 0.5 degrees of output for every 1 degree of input).
The head nod (2:1) was geared as a reduction to give the fairly shallow 20 degrees of rotation better angle resolution. Neck lift (1.75:1) is also geared for extra torque to support the mass of the neck and the head combined.
The visor and throttle dashboard are geared 1:1 due to packaging constraints.
The upper ring and lower ring have a gear ratio of 1:1.5, driven by the requirement for 270 degrees of rotation. The neck is geared 1:2, due to its requirement for 360 degrees of rotation.
The MG90S has 2.2kg*cm of stall torque at 6.6V, which definitely has more than enough torque to move the lightweight 3D printed parts, even after the speed reductions. The heaviest driven part is the upper ring and hero arm at only 20 grams/0.02kg combined.
The upper ring and lower ring rotate 270 degrees. To achieve this, a double compound gear layout was required due to space constraints with a larger equivalent gear interfering with the neck shaft area. These compound gears drives the inner gear teeth that are directly integrated into each ring.
Each "shell" is installed onto the corresponding outer bearing race component. I started with simple alignment notches, before later switching to integrated light-duty snap fit connectors (both pictured above).
The biggest effect of this design choice is terrible compounding backlash of up to 15 degrees of compliance on the output. This was deemed acceptable for my use case. See the Next Steps section for more thoughts on this.
The lifting mechanism for the neck is located all the way down at the base, with the gear train driving a rack and pinion setup at the base of the shaft of the neck. The mechanism for rotation is located on the pedestal layer, where a very tall compound gear drives a smaller gear on the neck.
One of the unique design choices I decided on was to avoid putting the motors onto a moving component, which is usually how it's done when an object requires more than 1 degree of freedom. In addition to consuming a lot of the internal volume when an entire motor is being moved, it also adds mass to the object being moved, something that increases inertia and would affect the smoothness of animations with higher acceleration.
This challenge appears in two pairs - the neck lift and neck rotation motors, as well as the head nod and visor motors.
The solution for the neck motors was to use a very tall compound gear (affectionately referred to as the "Giga Sprocket") the same length as the full vertical range of motion of the head. The neck is split into two halves - a lower half that is rotationally fixed and contains the rack for vertical movement, and an upper half that mates with the giga sprocket for neck rotation. A small integrated ball bearing between these halves is what allows the upper half to rotate without rotating the lower half, which would twist the rack out of alignment with the neck lift gear. Despite initial concerns about adding friction to the gear train this way, all initial animation tests proved that the torque provided by the neck lift and neck rotation motors was more than sufficient for smooth animation.
In the head, I designed it so that the internal head structure is completely static, and the visor and the head components are moving relative to the structure. As mentioned earlier, this is different than the method of placing motors onto a moving object. For example, the real Captain Rex animatronic mounts the visor motor onto the head structure, and the entire head structure + visor rotates as a single object relative to the neck. That means when the head is nodding, the visor moves along with the head. For my version, head nodding and visor movement are completely decoupled, and to make it seem like they're mounted together, I have to animate it in a way that makes it look like they're on the same structure.
The head "shell" is split into 5 main parts. The faceplate and bottom half are separated for print orientation surface detail optimization and later glued together. The head cap was made re-attachable to the lower head using magnets for easy access to the head structure. Ear cups are glued onto the head after the head structure is inserted into the head.
LEDs are installed behind the eyes and inside the mouth. Lenses for the eyes and mouth were printed from transparent PETG on a textured PEI plate for better light diffusion. Early testing showed that there was significant light bleed coming through the top of his mouth because it was printed so thin, so a light guide to block the light bleed was installed.
The head has a partial internal gear being driven by the driving gear in the head structure. The two head structure "ear pucks" are the "shaft axle" that the head shell pivots around. These originally were going to have ball bearings integrated into them, but upon testing, I realized that the gear reduction meant more than enough torque was available to completely ignore the friction in a simple sliding contact bearing.
The visor is geared 1:1 to the visor servo motor on one side, and a ball bearing is installed in both rotation joints for each arm of the visor. There are no hard stops, so it's important that the servo motor has software limits placed on its range of motion to prevent it from over-rotating the visor and snapping the arms against the head.
The dashboard design is my own, and is a rough approximation of the throttle dashboard from the ride. It was built around an MG90S servo motor and an x8 LED WS2812B strip with 1.92 mm spacing (the 144 LEDs/meter variant). The motor connects directly to the throttle through a keyed shaft. After the motor is inserted into the body, a cover panel is installed using x3 snap pegs.
The buttons were printed from transparent PETG on a textured PEI plate for better light diffusion, then glued onto the LED cover plate.
Before the project started, I came across this video by Positive Altitude, which outlines the practical application of a Conrad-style deep groove ball bearing to 3D printed designs. Instead of slots or other complicated methods of inserting the balls, these ball bearings create space by eccentric placement of the inner ring, creating enough space in the gap to drop in the steel balls. After manually adjusting the balls, a crown is placed to retain the bearing balls.
Most notably, I was inspired by his example of directly integrating bearing races into a 3D printed part on his robot rover. With the tight space constraints I had, removing the need to accommodate standard bearing size inserts (and avoiding the issue with press fit PLA creep) was very useful, if not critically essential.
Here are some of my initial tests, attempting to print the smallest ball bearing I can:
I made a fully parametric ball bearing Solidworks part based on his design, with the variables shuffled around to optimize for my main constraint, which was maximum outer diameter (since I was trying to make the smallest ball bearings possible). It generates 4 bodies - the outer race, inner race, crown, and a negative of the bearing race gap. The negative can then be imported into any 3D part and boolean subtracted, effectively integrating the ball bearing directly into the target part.
There are 12 bearings.
You can see how integrated ball bearings are better than COTS in this volume-constrained application. The neck joint and visor joints needed them the most, where a very small 6.5 mm OD bearing is built directly in line with the shafts. The two large bearings for the upper and lower rings are also important because it keeps these bearings far away from the center axis, where the neck sprocket needs radial clearance to move up and down. More design complexity would be introduced had these been accomplished using standard COTS ball bearings.
On vertically oriented shafts, only one bearing was included at the bottom, with a guide axle on top. Most of the loading is radial, coming from the torque provided by the mating drive gears. Axial loads, while present, are not significant enough to warrant the additional complexity of installing an additional ball bearing on the top axle.
A big challenge with keeping the unique part count low was reusable fasteners. I didn't want to use heat set inserts and their corresponding bolts, and I also had very little room for it in the first place. I sat on the problem for quite a while before thinking back to my childhood and realizing that there is one solution I know of - LEGO Technic pins.
In general terms, these circular-type snap fits are called annular snap fit joints. As with all snap fits, annular snap fits trace their lineage to injection molding design and are designed for completely different material properties than PLA. The biggest issue is that PLA has terrible, terrible creep when placed under constant stress. Many injection molded snap fit designs (including the LEGO Technic pin above) rely on an interference fit with the mating component in order to increase the retention force of the joint. In PLA, it would immediately lose its retention force in less than a week.
My design is slightly different. It doesn't place the pin under any constant stress in normal assembly. Instead, insertion and retention force is controlled by two variables - the overlap between the mating hole ridge and the ridge at the tip of the pin, and the angle of the leading edge and trailing edge of the ridge on the pin. Testing has shown that these two features alone are sufficient for respectable retention force suitable for reusable assembly and disassembly of components.
You may notice that it has a flat side to it. This is for strength-optimized print orientation. Tensile strength for PLA can be 40-70% weaker in the Z-axis (perpendicular to the layers) compared to the XY-axis (parallel to the layers). Printing parallel to the longitudinal axis drastically improves the axial force a fastener or pin can withstand. Printing in this orientation, however, creates overhangs that require supports. So for supportless prints, one side of the pin is cut flat.
You may also notice it looks a little skinny compared to your regular injection molded snap fit - that has to do with ensuring that the total deflection of each prong on insertion is well within the elastic deformation range of PLA, ensuring that you can reuse these pins again and again with no breakage. That is what the "notch" is for.
To date, I have not had a single pin break on me or significantly lose retention force, despite repeated assembly and disassembly.
I've started calling these useful little things "snap pins", and use them everywhere in my design. I also have a "snap peg" design used to fasten one component to another when you have access for a through-hole on one part. These also have different variants for "strong" and "light" removal force that come from varying the pin/hole overlap and the removal angle on the head of the pin.
The short version:
Animation was done using a custom "Servo Animator" Python script that connects to a game controller and allows for individual motor animation to be recorded, played back, and combined. Pololu's animation software turned out to be extremely limiting when it comes to dynamic movements, so I decided to create a new solution.
The long version:
I ended up ditching the Pololu Maestro Control Center animation software in favor of creating a custom command line "Servo Animator" Python script. To recap, the Servo Animator allows you to perform, record, combine, and play back servo motor actions by using the throttle input of a Logitech joystick controller. The resulting performance file of motor positions is converted and loaded onto the ESP32, which syncs it with the performance timeline and forwards it to the Mini Maestro.
Notably, velocity and acceleration values for each motor are still handled by the Mini Maestro. These values need to be saved to the Mini Maestro first - the Servo Animator output script has no control over these values.
Now let's talk about why I needed to do this in the first place.
For my application, Maestro Control Center is a nightmare. Animation in this software is done by saving individual key frames with the specific motor positions, as well as specifying keyframe duration in milliseconds. However, I was trying to animate it as close as I could to the source material, which means I had positions and keyframe timestamps relative to the performances timeline. I ended up with a gigantic Excel file with timecodes, motor positions, motor positions converted to PWM position values, reference dialogue, reference scene actions, the specific frames I need to create, and a VBA script to quickly calculate time duration between frames.
Additionally, asynchronous movement necessary to convey dynamic movement means more frames - if I move an arm 50ms after the head moves (instead of simultaneously), that's 2 frames instead of 1. In addition, velocity and acceleration are globally fixed, and can only be changed between frames by editing the script file text directly.
From start to finish, it took me 5 hours to set up this system and animate 10 seconds, shown below next to the source footage:
Note the lag on the head movement accompanying the dialogue, "and then we'll be on our way!". This is a direct result of the global velocity and acceleration values being set lower to match the overall movement of the scene instead of that specific action.
By comparison, here is the "panic" scene animated using Servo Animator in comparison to the source reference:
Ain't no way I'm animating that in an Excel sheet.
The Maestro revision was also only one iteration of playback and reanimating. Servo Animator lets me iterate much quicker, with a very fast cycle of animation -> playback -> reanimation -> repeat.
I mentioned earlier that the Mini Maestro still sets a global velocity and acceleration value for each motor. Some motors, like the neck rotation, lower arm, and throttle arm, have lower velocity and acceleration values applied to more easily create smooth motion. All the other motors that have some moments of high speed/acceleration have these values set very high, and the smooth movements in the rest of the scene is created by gently manipulating the controller during recording.
Fun fact - This manual knob-based controller setup is very similar to how they used to program animatronics in the 80's! Here's a photo of the Animation Console that Disney Imagineers used for Captain Rex on the original ride. Each knob is set to control a different actuator joint.
I brought Captain Rex to Bay Area Maker Faire 2025, a 3 day event in Vallejo defined as the "worlds greatest show-and-tell". In between finishing the original 1 minute animation test and the event, I painted him and finished animating the first revision of the entire 4.5 minute show performance.
Across 3 days of Maker Faire, he went through ~194 cycles of the show performance, with no major faults. At the end of the event, he was given an Editor's Choice award by the Makezine editors behind Maker Faire, and was briefly featured in a Makezine blog post about the event.
In the process of preparing for this event, I had multiple learnings and takeaways, mostly related to the assembly/disassembly process. Although his mechanical design performs to spec in normal operation, it is not robust to unexpected loads applied during the assembly/disassembly process. For example, I have snapped two gear shafts during the process of installing the gears because of accidentally applying lateral loads. Some assembly processes were also blind installations, so better self-alignment features like wider chamfers for holes would be very useful. I also didn't account for needing to "zero" the positions of the motors, which can be fixed by adding hard-stop features to the gear teeth so that the components have a "home" position when installed.
As with any project, there is always something more to be done. Here are a few that come to mind:
I really, really want to make his upper hero arm actuate at the elbow. I initially explored options involving pulley systems and dyneema string to do this, but I couldn't get over the design constraint needing to run the string off-axis to the center, because the neck occupies the center axis. Having the string off-axis means that rotating the upper ring would cause the string's length to change and twist, messing with cable actuation.
It wasn't until near the end of the project that I thought of an idea of a "wireless" system that uses a magnet mounted to a ring in the middle of the structure, which rotates to align with a mating magnet in the arm that could then pull on a cam that would rotate the arm. Unfortunately, with the way that I designed the upper structure, it would need a significant redesign to get both the magnet ring and another motor to fit, so I put this off for a later update.
Better constrained gear train components. Initial prototypes had a lot of unexpected gear teeth skipping, and it was incredibly puzzling and difficult to diagnose because the midsection rings needed to be installed to test it under load, but also completely obscures the gears when operating. I eventually deduced the problem to a few sources that can be summed up as one word - position.
First off, accurate X-Y translational position of the gear shafts in the gear train relative to each other. In certain areas, I have a gear shaft on a different part from the rest of the gear train (due to assembly constraints). But because I have such fine-toothed motors, small misalignments can cause the gears to be a little too far from each other and start skipping. This can be fixed by either improving my assembly datum setup, or having all of the gear axle bearings printed on a single part so that they have accurate positioning relative to each other.
Rotation about the X and Y axis. There is some clearance in the ball bearings that allow a little vertical movement, but it also causes rotation issues and the entire gear can "tilt". I tightened up the tolerance in the top axles of the gears and their mating holes to constrain against this issue.
Translation on the Z-axis. This one was puzzling, and I'm still not sure why it causes the teeth to start skipping, but I deduced that some of the gears were lifting off of the D-shafts that they slip onto in the midsection structure. I can fix this either with an interference fit or integrating the ball bearing D-shaft directly into the gear as a single printed piece. Herringbone gear teeth could also help solve a lot of my constraint issues, but may introduce issues on initial assembly interferences.
I want to reduce the number of ball bearings where there is more than enough torque from the motors. They work incredibly well, don't get me wrong, but they add assembly complexity and points of failure. This also helps fix the X-Y axis rotation constraint issue on my gear meshing problems.
Backlash. I expected backlash, but not this much backlash. It turns out that a double compound gear setup in the upper and lower rings amplifies the backlash significantly. The arms, with the servomotor drive gear fixed, can rotate almost 15 degrees from the backlash! It's terrible.
I can get away with it for now because the arms don't require fine motor movement, but I really want to try my own implementation of a capstan drive gearbox, popularized on Youtube by Aaed Musa's CARA quadruped robot, which promises backlash-free motor control. I actually was looking into this when I started, but eventually left it out to reduce project scope. It requires near-zero creep rope for prolonged usage, and although I am able to find Dyneema fishing line (for my smaller robot) similar to the Dyneema DM20 rope Aaed uses, there was no guarantee that it was a Dyneema formula optimized for low creep, and would require time consuming empirical testing.
Snap pins. I think releasing a standardized snap pin design would be greatly beneficial for the 3D printing prototyping community. There is still a lot of work to do, especially optimization and reliability given different filaments and nozzle sizes. The small snap pins I used were only possible to print with a 0.2mm nozzle - most printers ship with a default 0.4mm nozzle. I would also like to do empirical testing to ensure these pins work as intended, especially when tolerances are involved.
The Pololu Mini Maestro is $40, shipping inclusive, and represents 19% of my project cost and a whopping 47% of my BoM cost. Given that I'm no longer relying on the Maestro Control Center for animation, it's possible that for the level of animation fidelity required for Rex, I could just run the control logic on the ESP32 (or a second $5-$10 ESP32, dedicated just to servo control). This does come with the requirement of significantly more software development to bring much of the Maestro's functionality into the Servo Animator and ESP32, such as control over velocity and acceleration values and PWM generation. There are also likely limits to resolution and number of controllable servomotors due to the fact that it's software implemented PWM, unlike the the hardware implemented PWM of the Mini Maestro.
Given longer sourcing lead times, I can further cut costs and bring my project close closer (or lower) than my BoM cost by ordering the same parts from Aliexpress instead of Amazon. Not only does Amazon charges anywhere from 5% to 20% more, they often force you to buy multi-packs instead of single units (Aliexpress lets you order single units). You can see the effect of purchasing multi-packs vs single units in the BoM (see Appendix) when the cost drops by 59% (more than half!) after normalizing the BoM cost relative to quantity used.
I have two points on this.
Servo Animator. If fully fleshed out, this could be a useful tool for the animatronics and hobby robotics community. The Pololu Mini Maestro is commonly the go-to solution for animatronics, but as far as I can tell, there are no publicly available alternatives to the first party Maestro Control Center.
There is a lot of work to be done, including a GUI, a timeline, position/velocity/acceleration visualization, scrubbing, wider controller support, simultaneous recording and playback, and most importantly, intuitive direct editing for fine tuning position and timing values.
Bottango. Near the end of my project, while I was struggling with Maestro Control Center, I discovered Bottango, an animatronic animation software that integrates modern CG animation tools, such as a digital double 3D model and adjustable acceleration curves, with live animatronic playback. If I were working on a character much more complicated than Captain Rex, this would probably be what I would want to try next. However, I still believe that Servo Animator has a place somewhere in between Maestro Control Center and Bottango when it comes to ease of programming highly dynamic servomotor movements.
Also worth noting that at this time, Bottango doesn't support the Mini Maestro.
Thanks for checking out my project. As a thanks for reading along, I have an exciting follow up to this project that I hope you will stay tuned for. Here's a little teaser of what's coming up next.
Parts
Overture Matte PLA, Grey
Sunlu PLA Basic, Black
Overture Transparent PETG
ESP32-S3 Microcontroller
Pololu Mini Maestro 12 Channel Servo Controller Microcontroller
MG90S Servomotors, QTY x7
WS2812B LED Strips
MicroSD Card Module with SPI Interface
USB-C PD Trigger Board
LM2596 Buck Converters, QTY x2
TVS Diode P6KE15A
Filter Capacitors 2200µF 10V
Breadboard
Consumables
Wago Lever Nut Connectors
22 AWG Stranded Wire
22 AWG Solid Wire
Loctite Gel Superglue
Generic Hot Glue
Bambu Labs A1 Mini 3D Printer
0.2mm Stainless Steel Nozzle
0.4mm Stainless Steel Nozzle
Textured PEI Plate
Bambu Cool Plate SuperTack
Soldering Iron
Hot Glue Gun
X-acto Knife
Nano Glass File
Desktop PC
Solidworks
Arduino IDE
Pololu Maestro Control Center
Claude AI, Sonnet 4
ChatGPT, GPT-4
Powerpoint
Davinci Resolve
Footnotes
[1] N/A
[2] The RX Builders Club makes full scale remote control replicas of Captain Rex and his new Disneyland Galaxy's Edge design makeover, DJ R3X. Check out this awesome video of a custom RX droid named Gil!
[3] I am aware of 270 degree and "unlimited rotation" 360 degree servo motors. I didn't use 270 degree servos to reduce unique part count, and 360 degree servos are just regular open loop DC motors with no position control.