Goal: Develop a stabilisation system for model rockets so they will always fly straight.
Original plan of action:
Control surfaces: Several possible options:
Flight computer: I am using an Arduino Uno. With these sensors:
and an SD card reader.
Everything on the breadboard
The next task was to build the hardware. It was decided to try a gimbaled motor approach, which would be actuated by 3 servos (Power HD High-Speed Digital Sub-Micro Servo DSP33) positioned radially near the end of the motor. The only small motor with a relatively long burn time (3 seconds) which we could get from Rockets and Things was an Aerotech F22J.
3D printed servo mounting ring
View of the servo arrangment
The rocket was quite heavy (1kg) which would result in about 1 g of acceleration. The parachute lives in the top white section, a black powder charge at the base of the top section ejects the nose cone and with it the chute. The top section is held to the lower section by 4 radial screws. In the lower section lives the flight computer and below that the gimbal arrangement.
In hindsight this arrangement had a number of annoying flaws:
For the next version I would use a different gimbal design which would allow 2 servos to be mounted above it.
The flight computer required an addition circuit to ignite the ejection charge. This was simply a mosfet controlled by a digital pin which when opened would discharge a capacitor through the E-match. Some resistors featured to limit current flow. The flight computer now looked quite cramped.
The next major element was how should the control software operate. The basic principle is to integrate the angular velocities from the 3 axis gyroscope, then feed this information through a PID loop to move the servos. As 3D rotations are non commutative they can not be integrated separately. After several headaches the approach which made the most sense used matrices. The method is referred to as the “Direct Cosine Matrix” by people who use it for drones. Search google for DCM draft for an explanation of how it works. The orientation of the rocket is represented by a 3×3 matrix which describes the transformation between the ground coordinate system and the rocket coordinate system. To update the matrix you multiple it by a matrix calculated from the angular velocities multiplied by the time interval. It is the equivalent of adding a small rotation. I recall finding out that a vector cross product can be written as a matrix multiplication which helped understanding at some point.
As far as I'm concerned the accelerometer is of no use in determining attitude as you can't differentiate between the acceleration form the motor and that from gravity. By using the accelerometer to detect launch the gyro drift becomes insignificant over the 3 seconds of flight. It is required to renormalise the rotation matrix during the integration otherwise due to errors the matrix will blow up.
The next trick is to get something to feed into the PID controller, or as it turned out the 2 PIDs, one for yaw and one for pitch. It is worth noting that the convention I used for pitch, yaw and roll is not the standard as I wasn't aware of the standard when starting. For a second version I would adopt the standard, which is: to use a right-hand coordinate system for rockets where the long axis (nozzle to nosecone, your “vertical”) is X with +ve toward the nose. So your “horizontal” axes are Y and Z.
As it turns out all that needs to be fed into the PIDs is the correct elements of the rotation matrix. As we are aiming to fly straight the J vector in the inertial frame is the demanded direction. The rotation matrix transforms a vector from the body frame to the inertial frame (I think this just depends on the sign used on the angular velocities). This means the columns of the matrix are the axis of rocket expressed in the inertial frame. This quickly becomes a mind fuck. If we take the inverse of the rotation matrix (which is conveniently the transpose) the transformation matrix reverses so that it goes from the inertial frame to the body frame. This can be used to convert the upwards vector in the inertial frame (our desired heading is defined in the inertial frame) to the body frame (which is changing).
What we are trying to achieve is to get the upwards vector in the inertial frame expressed in the body frame this gives the components in each of the 3 body axes, the errors are the terms in the 2 horizontal axes. We feed these numbers into their respective PIDs. It is worth noting that there is a small angle approximation here, however if we exceed 45° from the vertical we have bigger problems.
The next challenge is tuning the PIDs. The plan was to use a Simulink simulation of the rocket to do this. Using SimMechanics it was relatively easy to model the rocket as a system, using the Solidworks model to find the inertia matrix. Failing any better ideas I resorted to trial and error for tuning until a robust response was achieved for a variety of disturbances.
The code for the Arduino then had to be written. One problem encountered was the mean spirited nature of SD cards, this meant some of our loops took much longer than others. With some streamlining the code was efficient enough to achieve 100Hz. If something more powerful was used then a solution with ring buffers and multi-threading would be the way to go. I attempted to use time based interrupts but this wasn't compatible with the sensor libraries.
Testing day finally arrived. The first half of the flight was very promising but then instability occurred. I'm yet to determine what caused this. Possible explanations include:
The current plan is to repeat the test then perhaps build a model which can be used to verify the simulation in the lab, perhaps using compressed air to provide the thrust.
The Arduino code and the Simulink file are both on Github. https://github.com/cuspaceflight/kestrel
Disclaimer, I'm writing most of this from fairly old memories so there may be errors, the lesson is to document things as you go along.