Hey folks, it's been a month, so it's time for another update!
I've been polishing the work since v0.0.2 (roughly last post) and adding a few extra features in preparation for my first hover tests. There was a bit of a lull the first couple of weeks of December as real work and externalities sort of took over, pre-xmas season. I was able to make up for that, however, with some pretty good progress over winter break.
New Hardware
To physically restrain any bugs I might encounter, I rigged up an anti-takeoff frame that's weighted down with 20lbs. It has velcros that are easy to hook into and out of, and it's even fairly sturdy during transport.
Wanting to protect myself from aberrant code and mechanical failures, I finally built a remote kill switch (pictured below). It acts as an intermediate between the battery and the rest of the quad. It's a simple EC5 connector that's hooked up to a vibration resistant electromechanical relay that's hooked up to a 10 foot cable with a simple battery and toggle button at the end. It gives me some serious peace of mind when running new code. It was invaluable when testing single axis stabilization (described below). In addition, I no longer have to plug and unplug when testing code and writing code, respectively. It provides a convenience that I now wonder how I ever lived without.
I also threw together a simple voltage divider to allow for reading the battery level (described below).
Tuning
After getting the test harness built, the next step was to solidify the communication and tune the radios and sensors for remote, control algorithm development. Having a 100% reliable, 30ms round trip between reading sensors and setting motor speeds allowed for an acceptable phase delay which in turn allowed for remote prototyping of the control theory code. This was great as the theory was something I wasn't at all familiar with when starting this project. The ability to write and debug the control code remotely allowed for insanely fast iteration. It also really helped with ramping up on the theory quickly as I got to tweak the algorithms and see the effects nearly instantaneously.
To achieve these latency and reliability goals, I had to determine optimal radio configuration to allow for the highest reliability possible. Anything less than 100% reliability would severely impact my ability to test the control code remotely. This was a real pain as I was led down the wrong path a few times. In particular, many folks online said that a serial bit rate of 115200 worked great for them and their XBee projects, and since I wanted a faster RTT, I did all my initial tuning assuming 115200 was feasible.
As always, carefully reading through the datasheets revealed the source of errors I'd been seeing. After thoroughly reading through the XBee documentation, I learned that setting the baud rate to 115200 (via AT command `ATBD 7`) didn't actually set the baudrate to 115200, but to a slightly lower baudrate of 111111. This still divides nicely into any standard 16Mhz oscillator, but a good number of the packets were being dropped (I was only achieving ~90%) because the software was assuming a 115200 and not 111111 (seriously.. what? Elsewhere in the docs it references 115200). Setting the serial rates (hardware and software) to anything from 9600 to 57600 provided way more reliability. Having this assumption overturned was pretty upsetting to find out about, but at the very least I got to thoroughly test my packeting code to deal with all of the messed up packets. This will be really important in the final product when the transponder and quad need to talk to one another continuously, so I'm glad I the work to make this link solid is done and out of the way.
The end result, again, was a cool and reliable 30ms from sensor read to throttle update. All the poking and prodding was definitely worth it.
Constraints of the Embedded World
In the process of tuning the radios, I made heavy use of debug packets originating from the quad. With these debug packets came loads of debug strings in program memory. As the ATMega328P has 32KB of flash storage for code space, I wasn't too concerned with strings that I thought would be kept in and referenced from flash only. On the ATMega, however, the flash space, while being a legitimate address space, is inaccessible from the code's POV. As a result, any data referenced from code gets copied into the pitiful 2K of SRAM on program load. Of course, I only found this after adding one too many debug statements and having the FC start resetting randomly. After hunting down the erroneous line of code and finding a wandering point of failure, a quick search pointed me to consider my SRAM memory usage.
The solution to my storage woes was to make use of PROGMEM, or an AVR specific, non-C keyword that indicates that something should be kept in flash space only. Since all debug calls went through the logger, I was able to add a single method that took this PROGMEM, flash pointer type. From there, using some AVR libs, I was easily able to bring that string temporarily into SRAM for writing out on the serial line. This allowed me to push all debug strings into program memory and save considerably on space in SRAM.
Fortunately, I was able to keep a lot of debug strings around. Unfortunately, I found that formatting the debug strings was somewhat limited as common methods like sprintf have their own, rather large buffers that permanently eat up RAM when included in one's code.
Flight Computer Features
Safety was improved by powering down motors on startup and at other opportune times. I added logging and stats tracking to assist with radio performance profiling. I got to profile sensors to ensure faster read times. I also added and finalized on a UDP-like packeting protocol to protect against serial stream corruption and dropped bytes.
Simple Client Features
The simple client was phased out in preference for the web client.
Serial Server Features
The serial server was added as a local server to take RESTful web requests and forward them to the FC via the FC RPC command protocol.
I added logging and stats tracking to assist with radio performance profiling. I finalized the packeting protocol, and it successfully protects against Serial stream corruption and dropped bytes.
Web Client Features
The web client has full E2E communication between javascript in the browser, coffeescript in the serial server, and the Flight Computer code. I can, for example, slowly blink the FC LED from javascript in the browser as a simple, visual health indicator. The web client can also read and display all sensors. It can read and display the battery status. It supports simple throttling to control the throttle to all motors. Finally, I was able to quickly integrate a LeapMotion to provide simple gesture based controls for testing of the single axis stabilization code (fortunately, this only took about ~30m to integrate!).
Right now the UI is far from pretty, but it takes no time at all to create controls and diagnostics, so I'd consider that a definite win.
For example, it took no time at all to add a simple web interface for viewing the battery status. In fact, the entire battery feature only took about 2-3 hours to add the web control, add the ADC reader in the flight computer, add plumbing in the serial server, and construct the circuitry necessary to proportionally drop the voltage to something readable by a 3.3v ADC pin.
Latest Progress
These last few pictures demonstrate the quad's current ability to hold a target angle and angular rate. I'm currently in the process of tuning the control algorithm's gains to ensure a more prompt step response while minimizing overshooting the set point. There's been a lot of interesting Maths that have gone into this control, including a
sensor fusing complementary filter for attitude estimation, and the PID controller itself.
Future Work
The majority of work that now remains mostly consists of higher level Mathematics and neato algorithms. The platform is mostly mature for now. I'd like to eventually make some custom PCBs to reduce the wiring in the project box, but that's a somewhat low priority item. I'll also eventually want to make an emergency parachute and release mechanism, but this won't be necessary until test flights that fly higher than what can be done near the ground (4-5 feet up).
As for the control stuff, at some point I'll try to move away from generic gains and towards a physical model that calculates thrust and moment arms explicitly. Finally, I'd like to try out
a more fundamentally sound means of calculating the process error as input to the control feedback loop.
If I can get away with it though, I'd like to get to simple, stable flight as soon as possible.
Stay tuned!