Controls: Implementation
It's finally time to go into hardware mode and start building stuff. Hoo-rah.
By this point in the project (not the blog) I was already a few months into it. Most of that time was spent reading the material in the bibliography and making sure I could work out the math by hand. I also spent a bit of time surfing the web and trying to learn from other people's efforts.
My general idea was to use an Arduino as the basis of the flight controller. I say "general idea" because prior to this project I had neither physically seen nor programmed an Arduino, Raspberry Pi, Intel Edison, or any other modern, programmable I/O board. I'd never even taken a course in C/C++. That means my starting point was the examples in my Arduino UNO Starter Kit. "This is an LED. Make the little LED go blinky-blink." I even took the 'duino, a breadboard, wiring, and some electronics components in my briefcase on an international business trip and fiddled in my hotel room at night while fighting jet lag. TSA never bothered to open my briefcase and look at the jumble of mysterious electronics :-/
For the actual flight hardware I chose an Arduino Mega 2560, not the UNO, because I thought I'd eventually use the extra pin-outs for other functions not related to the flight controller, such as environmental sensing and parachute deployment.
Onto the Mega went the Arduino 9 Axes Motion Shield. This is a complete inertial measurement unit (IMU) based on the Bosch BNO055 MEMS sensor package. It contains:
- A triaxial 14-bit accelerometer
- A triaxial 16-bit gyroscope
- A triaxial geomagenetic sensor
- A 32-bit microcontroller with software to fuse the data from these 3 sensors
- Capability to output quaternion data, Euler angles, angular acceleration, linear acceleration (which we won't use), gravity (how strong?), and heading (0-360 degrees on a compass).
It's sobering to compare the size of this IMU to the one on the Apollo spacecraft. The Bosch IMU measures only 5.2mm x 3.8mm x 1.1mm and is one of the tiny black bits on the Arduino shield in the right-hand photo below. It has no visible moving parts. Interestingly, the MEMS gyros are similar in structure and operation to the halteres of a fly, which rely on the Coriolis effect to encode the insect's body positions during flight.
So down I go into my Mad Scientist Lair. A well-organized workshop is the foundation of success, right? At least that's how I justify to my wife why I spend the funds on kitting out the workshop. Thanks, Dear!
First we check out the 9 Axes Motion Shield and confirm a few things. Is it communicating with the Arduino correctly? Does the data make sense - which way is up, what's a positive versus negative rotation, etc.? This picture summarizes the native output of Euler angles from the IMU:
Here's a screen shot of the first data streaming from the shield, through the Arduino, and onto my PC through the serial monitor. Everything looks good.
Next we tweak the embedded MATLAB function from the Simulink model so it will run on the Arduino. There were a few little tricks but basically it ported with minimal modifications. The main consideration is that we want the code to loop as fast as possible, as this will give the highest refresh rate for the sensor readings. The code imposes some simple logic checks and only calculates the relevant portion of the switching curves to determine which fire zone or coast zone it inhabits on the phase plane. I'm happy to share the code with anyone interested, although it's specific to the Bosch IMU and may need to be tweaked for your sensor, particularly for the rotation sequence of Euler angles.
Even with live output to the serial monitor, the final version of the code gives a refresh time of about 7 milliseconds, which is almost 150 Hz. The Apollo Lunar Module's flight computer had a refresh rate of 100 ms so we're already doing better than the 1960s. In addition, many solenoid valves I've seen have an activation time around 20 ms and an on/off cycle even slower, so the HAPP software is already outrunning the hardware and may have to be "slowed down" anyway.
The last step is to get the Adruino - now programmed as the flight controller - to turn power relays on and off according to the jet firing commands. Recall that we need 6 independent fire control circuits, each of which will fire two jets simultaneously to apply moment around a particular axis. The relays will switch power to the gas solenoid valves, which in turn allow compressed gas to flow to the jet nozzles. I haven't specced out the valves yet, but some quick research showed that the valves might require up to 24 Volts DC and perhaps 0.2 Amps.
For now I'm using this 8-channel electromagnetic relay. For the flight hardware I'll replace it with solid-state relays or MOSFETs. Either one would have a faster response time than the electromagnetic relays, on the order of milliseconds or less. That will help with performance of the flight controller.
Enough talk - let's see it run. In the following video, six relays are labeled by jet command: Yaw +, Yaw -, etc. You can see and hear the relays turning on and off as the flight controller is rotated in space relative to the target setting of [0, 0, 0] attitude and [0, 0, 0] angular velocity. When the HAPP is complete, these relays will trigger solenoid valves and the jets will fire. The flight controller has a deadband of 7 degrees so I have to rotate it quite a bit to trigger the relays. Later we will reduce the deadband to give tighter performance and more highly stabilized video.
That's about it for the brains of the HAPP, although later we'll be adding additional hardware for environmental sensing, system monitoring (gas tank pressure, etc.), and some other tasks. Now it's time to figure out how to make the jets. Get ready for some thermodynamics..