This project was initially my second-semester project for my AT Physics, Engineering, and Technology course during my senior year of high school. I got somewhat obsessed.
It essentially taught me 70% of what I know about control theory.
Here's the original report. To be clear, I know that there is a decent number of misunderstandings and plain incorrect statements here; I have continued learning (and discovered many bugs) since I wrote this.
Highlights
Here's MPC performing a swing-up maneuver.
This was an early and somewhat flawed method for control, but it worked a little. It was my first ever MPC implementation, made with CasADi+IPOPT+HSL MA57. It was a very naive implementation - direct single shooting, no warmstarting, and complicated constraints - but it did kind of work.
It discretized the one-second lookahead horizon into five 0.2s intervals, and solved in 0.02-0.07s, depending on the state.
The solver ran on my 2019 macbook pro and communicated with the test setup via serial, adding some delay, and there were also a few bugs in the firmware I had yet to remove, but somehow it could deal with it.
and here's a complete demo of the swing up and down maneuvers with balancing at both stationary points. Recorded July 2023.
Turn audio on for nice beep boop whoosh zoom robot noises! (this was before switching to a trinamic stepper driver; the A4988 I was using creates a very nostalgic robot noise)
You can hear a key bug with my fixed-point math when balancing vertically - the minimum speed reachable by my stepper driving software was around 1 cm/s, which limited my ability to make ultra-fine adjustments.
moving forward
since that video, I've made the following changes:
swapped the AS5600 encoders for AS5048A. this gives me two more bits of precision on angle readings and lets me use SPI instead of I2C, which is much much faster. With I2C, the control ran at ~700Hz, but with SPI, it runs at 33kHz!
swapped the A4988 stepper drivers to TMC2208, which are much more advanced and convenient. Features include near-silent operation, UART config, more sensible current limiting configuration, 1/256 microstepping, and the ability to send a velocity over UART instead of just controlling using the STEP/DIR pins.
redesigned the cart and pendulums by pocketing everything, encorporating custom PCBs for nice clean wiring, and designing in auto-aligning features to make sure friction is minimized and magnets are aligned properly with the encoders.
added second pendulum
switched from Rust (with rp2040-hal) to Arduino (with arduino-pico), as I couldn't figure out the UART setup on the TMC2208 - it would throw framing errors and respond with four extra bits. The CRC would still be correct, so I was stumped, and I don't have a scope or a logic analyser, so I just gave up and used someone's arduino library.
here's the new CAD:
and here's the new top pivot. look at those nice PCBs. marvel in the glory of EAGLE, FlatCAM, and babysitting a cnc router to change out tiny tools for an hour.
with these changes, I'm hoping to implement swing-up and balancing for the double pendulum! However winter break just ended and I don't fancy having a two-meter-long contraption in my dorm room, so the physical setup has been left at home. Here are my todos for this project in the meantime:
fit the dynamics model of the double pendulum to the physical system (I collected data before I left)
fix encoder issues (I'm seeing immense amounts of noise in the encoder readings when stationary or near-stationary)
convert all remaining float math on the pico to fixed-point. I now have access to all the MATLAB tools, so maybe that'll help.
upgrade powertrain to bigger stepper (probably large nema 23) + TMC5160 + 48v PSU. Current small 3D printer-sized motor has nowhere near enough power to drive the pendulum at the neccessary speeds and accelerations for swing-up. This means re-implementing driver interfacing and figuring out the TMC5160's nice hardware ramping features.
figure out how to compile MPC for the rpi pico - really i just need to properly learn how to use gcc. The rpi pico has two cores, so I just need to figure out how to compile CasADi's generated code to interface with my existing code and get it to run on the pico. Alternative plan: use FORCES Pro from Embotech to just get a solver meant for embedded environments, and avoid having to figure out how to get WORHP onto a microcontroller.
implement swing-up with an LQR: find the trajectories with some sort of BVP solver, linearize, find linear controllers for each point, and add those to a LUT on the pico.
cope with the fact that I signed up for too many classes and there's no way I'm going to have the time to do these things this semester