Friday, 21 September 2012

Meet QBot1 (Caution: mumbo jumbo ahead!)

I went for a run this morning and there was ice on the wooden bridges in the park!  It's not ice that froze there, though...  it was leftovers from a pretty big hailstorm last night (note: I wrote this paragraph last week).  I wouldn't say it made me homesick, but I definitely had a small bout of home-miss-ness.  This is the first ice I've seen on the ground in Auckland and it made me think of the true North strong and free and the fact that as we transition into Spring down here, a lot of you are transitioning to fall up there.  Here the spring lambs dot the hillsides and calves cavort next to their mothers while the Canadian leaves are falling and Thanksgiving plans are being made.  While I will miss the North American fall, I think it's fair to say that we're looking forward to finally having summer after more than a year without.

At the time I wrote last, I had great intentions of following up with some details on my research.  At that point, I thought I was within a week or two of having my robot airborne.  Now, I don't know about you, but I sometimes feel that despite 36+ years of experience on this planet, my mind has a fairly fragile grasp of the relationship between the amount of work I have to do and the time it will take.  I console myself with the idea that I can't predict the vagaries of circumstance.  For example, on renovation: how could I know that the wallpaper would be glued directly to the drywall without even any primer (who in their right mind would do that)?; on car repair: how could I know that the starter constitutes an effective motor mount and that, on removing it, the motor would drop (ever so slightly) and thereby make installation of the new one virtually impossible (without a jack)?; on building my ramshackle boardwalk: how could I know that I could only carry one 12-foot long, 100-pound log at a time?  (okay, that last one I did kind of know, but I thought I'd be able to walk faster...) (note: all of those are from the past; no renos, no car repairs, and no boardwalk construction for me here in Kiwi-land)  So, yeah, things generally conspire against me (says I) and I have my own internal selfish motto: Nothing is ever easy.  And the implied perspective there is that "Nothing is ever as easy as it should be".  And here, once again, my faith is revealed for the weak thing that it is.  The truth is that things are generally a lot easier, finer, better, and more wonderful than they could be.  What they should be is up to my Maker and not up to me and for that, I would do well to be grateful (alas, easily said, seldom done).
Weeks and weeks have gone by and, I'm very pleased to report, my bot can now fly!  Despite the fact that quadrotor flight is pretty commonplace these days, it's surprisingly complex and tricky to manage it from only parts and first principles.  When I arrived at the University in May, I was presented with an untested circuit board and a bare airframe.  First step was to try out the board and get the microprocessor working with all of its peripherals.  I've done some coding in a computer language called 'C' in the past, but this was my first foray into development for a small embedded processor.  And it's been a long time since I thought that 16MHz was a respectable processor speed or 8-bit a respectable architecture.  Regardless, it was lots of fun to be employing my skills in a whole new area and I spent the first month or so writing code that would enable the microprocessor to talk with its GPS (used for outdoor positioning), its sonar rangefinder (used for low-altitude height control), its Inertial Measurement Unit (used for orientation and acceleration measurements; the key component for stable flight), its current & voltage sensors (used to determine battery and motor state), and its wireless RF communication module (used for bot-to-base communication).  I found a couple of small issues with that control board and the University technicians undertook to make a new one for me.
While I waited for that, I turned my attention to the airframe.  it consists of a plastic/nylon platform in the center with 4 carbon-fiber rods radiating out from it.  At the end of each rod is a platic/nylon motor mount that holds a small electric motor.  (The airframe was designed by an AUT mechanical engineering student and the plastic/nylon pieces were made in-house on a 3D printer - very cool.)  Each motor requires an Electronic Speed Controller that basically allows low-current digital (microprocessor) control of an electric motor that requires high current (lots of power) and is inherently somewhat analog.  So, I wired those up and got them all attached to the airframe.  By then, my microprocessor board was back and the next step was to wire all of the bits together.  That was all done by sometime early-mid July.
With a fully assembled Quadrotor robot (long since dubbed QBot1 (QBot0 and QBot2 are in the hands of the undergrads)), it was time to start writing motor control code to see what it could do.  With not uncharacteristic hubris, my first attempts were largely intuitive and I somewhat ignored the careful equations my thesis advisor had provided me with.  I quickly determined that a quadrotor aircraft is a highly unstable thing.  We have a testing stand that the robot sits atop and that prevents it from flying into a wall or ceiling while still allowing free rotation around it's roll (left/right tilt), pitch (nose up/down), and yaw (compass heading) axes.  On that stand, the whole airframe would gyrate like a thing possessed.  Many days and much analysis later, I was able to get it somewhat stable so long as I held it level when powering up.  To call it "stable" was a bit of a stretch, though; my kids exhibit about the same amount of stability when it comes to their emotions.  A content and happy child one moment is only a slight nudge (for example, the word "no") away from hysterics the next.  Just so with temperamental QBot1.  I tried and I tweaked, I blamed center-of-gravity imbalance and testing-stand interference, but in the end, it was mostly me (as it almost always is).
 I had the wrong sign (+ verus -) on one term of my control loop and I believe that was the majority of my problem.  In the effort to track that down, though, I rewrote everything and applied the principals and equations originally given me by my advisor (Dr. Loulin Huang who holds two Master's degrees and a PhD in mechanical engineering and is one of the most natural and enthusiastic applied mathematicians I've ever seen).  Doing so gave me much better grounding in the principles governing our system and forced me to clean up my code.  With that, I was able to get QBot1 rock solid on his tethered stand (sans battery; which is significant) and I was certain that free flight was only a week or two away.  That was when I wrote my last post.
The next step was to sort out the dynamics for free flight at the high thrust rates needed for takeoff and hover.  For that, I had devised a bearing clamp system that would limit my bot to rotation around a single axis (so that I could test pitch control only, or roll control only).  Early in my tuning and re-testing, though, it became apparent that my motor mounts wouldn't be up to the task.  At the higher (load bearing) RPMs, they would vibrate immensely and it was clear that they wouldn't hold up when airborne.  The young man who had designed them quickly developed new ones but we had to wait a couple of weeks for the 3D printer to have an open slot.  In the meantime, I started adding features to my code to improve communication robustness; I had noticed that my wireless base-to-bot link would occassionally drop information and that could obviously be disastrous during flight.  So, I added checksums to the communicated data (a checksum is a very simple data integrity method that adds together the inherent numerical value of all parts of a computerized message; only if the sum matches between sender and receiver is the data accepted).  But then things really started to get weird.
With the checksums in place and a fresh overhaul of my code structure, I suddenly started getting random reboots, crazy branch paths, skipped instructions and the like.  By changing a few debug messages things could work better, or worse, and the connection between cause (a new change) and its effect entirely broke down.  My first suspicion was that I was the victim of a somewhat common computer issue known as stack overflow.  That occurs in situations where memory regions are too close to one another and/or a program has too many nested subroutine calls (where one calls another that calls another...) (quick description: each time a program calls a subroutine, it sort of sets aside what it is doing in a place called “the stack” and when it finishes up, it picks up where it left off by grabbing that work back off the stack).  Many security issues through the years have come through exploitation of stack overflow vulnerabilities.  In my case, I was certain that my problem was elsewhere; a modern programmer generally relies on his compiler to manage the stack and I was certain that mine would be doing the right thing (I'm using a targeted version of a compiler called gcc - it's known to be very good).  Since I had lots of available memory (I was only using 10% of the total), there's no way the compiler would place my stack anywhere near my program instructions.  So, the problem was presumed to be with my code and I figured that I had stuffed up my memory references somewhere along the way.  I searched and searched and couldn't find anything.  I wrote and rewrote my program, I went down one rabbit trail after another and I was starting to wonder what more I could do.
In the end, by painstakingly watching the processor execute one instruction at a time; I directly observed the source of my trouble.  Guess what it was.  Stack overflow!  Not possible, says inner-me!  I have too much memory for that to be the problem!  Ah yes, says the wiser me that only speaks in hindsight… but did you check the processor specification?  Well, no… but the company who made the chip and wrote the specification also provides the compile environment.  Why would they lie?  Because they made a small mistake and they calculate memory usage not based on what you really have but what you could have.  So, that was it.  What was reported to me at 10% was actually 100% and I was out of luck.  Others have reported the issue to the manufacturer and they have fixed it for themselves, but have yet to roll it out to customers.  C’est la vie, non?
Anyhow, with the communication path up and working, I was back to the races.  I spent some time tweaking my motor control parameters and then spent a bunch of time writing a base station program for windows.  Included with that were the routines to allow remote control of the bot via my playstation sixaxis controller.  After much testing, I put the bot back on its stand and ran it at liftoff thrust; it went crazy!  Bleh!  Can we please get a competent engineer in Aisle 1?    Amazingly, though, I changed 2 control parameters and Blam-o (technical engineer jargon for: Eureka!)!  Rock solid on the stand; with the battery!  I could hardly stop grinning.
The next step was to take it off the stand and attempt the first flight of Qbot1.  I only managed a few inches and things looked very, very good.  Nice, stable holding of position parallel to the ground.  It would drift a fair bit because I have no position controls in place yet but I headed home for a happy weekend.  The next Monday, I tethered it with string to prevent it from drifting out of its cage (or into the walls) and was able to fly it several feet in the air.  It’s pretty cool.  Many people came by to see it work and I had fun showing it off.
But now it’s in pieces.  I have accomplished a lot and the undergrad working on Qbot2 had a controller but no airframe.  So, I donated mine.  Hopefully in the next few weeks, it will be flying again.  Meanwhile, I will be building a new airframe and need to spend some time understanding the advanced theoretical formulas that we will be applying next.  Without the grounding in Kinematics and Dynamics that mechanical engineering students get, I have a lot of foundational concepts to work through.  The fun doesn’t stop…

3 comments:

  1. Dan....that is super cool! Makes a great racket too!

    ReplyDelete
  2. Hey Dan, this was fascinating to read! It sounds like great fun working on this. I've always been interested in physics, math, flight, and programming, and this combines all 4! How is it doing debugging on an embedded process? Sounds like hunting down bugs (especially that stack overflow) would be a real challenge. I can't wait to see the next steps, which I assume would be trying to control some of the direction in flight? Wish I could work on it with you!

    ReplyDelete
  3. Hi Jason, debugging is actually pretty good; it can be done in-system via a JTAG interface. The micro we're using is made by Atmel and the latest version of their development environment is based on Windows Visual Studio. So, it's actually pretty slick; well integrated and with great features like breakpoints, instantaneous register values, and disassembly. The problem I had is that they don't have source code for built-in functions (like printf), so you're forced to debug from assembly. That wouldn't be so bad, except for the fact that, without source code, stepping through assembly resets the assembler view and you have to keep telling it to take you back to the program counter (after each instruction). So, it's a bit tedious.
    Yes, next steps are: 1) Assemble new airframe, 2) Height control (via sonar range finder), 3) Position control. I'll keep you posted. (I wish you could help me, too! That would be a ton of fun!)

    ReplyDelete