Monday, June 4, 2012

NEVER Build a Quadrotor for 6.115

Don't ever program a quadrotor in assembly, or for that matter try to build one with an 8051 core unless are: 1) a wizard or 2) have a chip which runs a couple of MIPS, has loads of memory, more than one UART/SPI/I2C, an onboard boot loader, and isn't larger than your quadrotor. Even then, you still might hate yourself.

(P. S. It's a bad sign if your processor is older than you...)

Also don't buy a (surprise! ratiometric) analog IMU because you wanted to skip I2C, JUST LEARN I2C.

Me on the outside
Me on the inside.
Unfortunately, for my Microcontroller Class (6.115), I stupidly (well, rather naively), decided that making a quadrotor for a final project would be cool. And then I stupidly decided to change Babycopter (my originally "analog-esque" quadrotor) to digital because I'm an idiot (to be fair, it would've been hard in analog too).

*sigh* Sometimes I make such HORRIBLE decisions.

So my lovely, adorable, sweet quadrotor turned into a SOFTWARE NIGHTMARE, but before we get to that part, let's start out with what I like best - hardware.

Analog PD controller:
Gross but at least easy to tweak.
True, doing all the analog controls ever wasn't going to be pretty but hey, they make quad op amp packages. Also yeah, those high-passes freaked the crap out of me, but I kinda prayed and hoped and then ran into a piece of knowledge that basically made me switch to digital.

The AT89C2051 hasn't a DAC or an ADC and to implement them would require a lot of (unavailable) space. What kind of freaking chip doesn't have a DAC or ADC onboard?

Oh yeah, one that's 5 billion years old.

For those of you who don't know, 6.115's final project requirements are that you have to have some assembly-written program on some 8051 core, of which you have available either a real 8051, or you have free at89c2051s. You also get about 3-4 weeks to do it. To be honest, the assembly part isn't what breaks my soul; it's the goddamn 30 year old processor. There's a reason why quadrotors weren't common in the 80s...

Anyway, most people make something that uses the 6.115 kit (which has a signal generator, power supply, breadboard space, etc), but I again (naively) decided to make things harder than necessary. You can't make a quadrotor with the kit (it's like 20 pounds) and bringing a wire really is too messy, so I made my own PCB boards.

Here are all the versions of my control boards and why they all failed (to some degree). See, real engineering is an iterative process...


Version 1: 

Problems: ADC can't collect values properly because P1 must be completely set high before any read, which wouldn't work if you're also trying to use those pins to select values with a multiplexer... Also I labeled "yaw" as "raw"? Plus, it was a lot of chips. Luckily I never routed this board. 

Version 2:

Problems: Close but no cigar. Bit-banging two 2051s got into a lot of trouble with framing errors. Less chips though. I did route this sucker, only to spend hours trying to fix bit-banging which really wasn't going to be a happy at my baud rate. If I had more time, I would've done SPI, but I had about 4 days left...


Well, more routing practice I guess. Did I mention I hate bit-banging?

Version 3:

Problems: At this point in time I only had a few days before demos, and I was about to die from lack of sleep, so I drew a rough version of this circuit by hand and my lovely boyfriend Joe made the schematics/routed it up for me as I slept for the first time in 2 and a half days. Also this is done in some hipster open-source layout program called KiCAD. Don't grow up to be Richard Stallman. I'll never forgive you. <3


Again, routed in KiCAD,  ended up kinda working. 

For both boards, I etched PCB versions of them (pretty fast process, like under an hour). But hardware is hardware and usually debug-able on my part. I think the only real issue I had with any of my hardware is checking which P1 pins on the 2051 were pull-ups, oh and also dragging the reset line first high then low with a cap (can't leave it floating). 

;---------------------------------------------------------------------------------------------------------------------------------

NOW THE SOFTWARE NIGHTMARE BEGINS:

PEOPLE WHO WRITE MATH LIBRARIES ARE MAGIC.

Honestly! I think I must've written 3 PD programs each over 1000 lines of assembly and each dangerously close to the 2K bytes of flash on the damn chip. In fact, several times I thought I had run overboard when my compiled hex file was over 2K, but luckily you can find out how much memory your program actually takes by reading the hex file.

I'm going to write how to read your hex file as it's probably good in case some poor 6.115 student stumbles on this post. This is an excerpt from a chat where I learned how to decode this crap. Oh yeah, read the Wikipedia page on Intel Hex Format.


So every line is going to start like this
  :AABBBBCCDDblaaaaaaaaaaaaaaaaaaaaaaahhhhh
1:04 AM BBBB is the starting address of where to start program
  AA is how many bytes to program
  CC is 00 if it's supposed to actually do programming at that location. If CC is 01 (the only case rasm ever produces this is at the very, very last line of the OBJ file), then it means that this is the end of the file
  So:
1:05 AM 1. Try to find the highest BBBB that you can
  2. Add AA to BBBB
  that's the number of bytes you program
  3. Make sure that BBBB isn't repeated anywhere else


Luckily, if you haven't overwritten any of your previous program, you'll find this all in the second to last line of your hex file. For example, on the wiki file:


:10010000214601360121470136007EFE09D2190140
:100110002146017EB7C20001FF5F16002148011988
:10012000194E79234623965778239EDA3F01B2CAA7
:100130003F0156702B5E712B722B732146013421C7
:00000001FF


The number of bytes would be 0x0130 + 0x10 = 320 bytes (304 + 16)

This saved me from several panic attacks.

Next, in my rant of a post, there were all the math libraries where I basically wasted a lot of time -_-

First I tried fixed point, which is actually nice to some degree except I kept using 8.8 bit math, which didn't have enough resolution. Also AH WHY CAN'T I HAVE NEGATIVE NUMBERS? ALSO WHY DOES EVERYTHING OVERFLOW SOMETIMES????

Basically that wasn't fun, but if you want there's a nice tutorial on 16 bit math (which is really all that it was) on the 8052 website. Here's also my fixed point library (in C, you can decompile it into assembly if you'd like). Also, here's a wonderful 8051 emulator that you can test out all your math on! You can even see on which instructions it messes up! Yaaaaaaaaaaaaaaaaaaaaaaay!

However, due to the lack of negatives and 8 bit not having enough resolution, I ended up switching to signed integer, which would've killed me had it not been for this beautiful signed integer library (note, you must view source of the html to see it).

WILLIAM MARSHALL, CREATOR OF THIS LIBRARY, I DON'T KNOW WHO YOU ARE OR WHERE YOU COME FROM, BUT I'LL BUY YOU A DRINK IF WE EVER MEET. THANK YOU FOR EVERYTHING. XOXO JORDAN.

That library basically saved my butt. True, it has some issues. It takes a million machine cycles to do anything, but if you read through the programs, you can optimize them quite a bit yourself. Also you have to change the flag bits to PSW flags because we have no dbit command with Rasm (our assembly compiler). Whatever, still baller.

However, this did increase the size/machine cycles of everything, which meant in the end, I could only perform the D math reliably. Running on a 24 MHz crystal with a control loop of 100 Hz, I only had 20K machine cycles. And while you'd think this would be enough, for loads of math, it's really not. If you ever do attempt this, get a micro running a few MIPS, because you need that much speed.

Oh, but then of course I would run into communication problems!

;---------------------------------------------------------------------------------------------------------------------------------

COMMUNICATION NIGHTMARE:

Ahem, before I start, I should get this rant out of the way.

THERE ARE VERY SPECIFIC INTERRUPT FLAGS WHICH NEED TO BE SET FOR RELIABLE SERIAL WITH THE AT89C2051. YOU WON'T FIND THEM ON THE DATASHEET BECAUSE ATMEL PUT THEM IN SOME OBSCURE APPLICATION NOTE FILE WHICH YOU WON'T FIND UNTIL YOU GIVE UP ON ASSEMBLY AND LOOK AT WHAT PEOPLE WROTE IN C BECAUSE YOU HATE ASSEMBLY. ALSO BIT-BANGING CAN BE SUPER SKETCHY.

Least for UART. I probably should've done SPI, but I ran out of time for this project, and I already had to even push my baud rate to be fast enough. At 9600, each bit is 104 microseconds. For my IMU, I was sending packets of 12 bytes with a control loop of 100 Hz. For me to have sufficiently sent one packet (not counting how long the math was or having to again receive it), it would've taken 12*8*1/9600 = 0.01 seconds, the same period as my overall control loop.

So I made the baud rate faster to 31250, then tried this serial bit-bang code. Unforunately, it doesn't hold well over 9600, and you start to get framing errors. Oh, make sure you don't accidentally full-duplex your UART either, or else it will give you absolute garbage.

At the end of the day, I really couldn't Xbee UART my 2051 and bit-bang my IMU/second 2051. I started panicking and freaking out until I figured out a somewhat passable solution - do what you know will work.

ARDUINO

I really, really, really love Arduino. WHEN ALL ELSE FAILS IN LIFE, ARDUINO IS YOUR BEST FRIEND. Arduino only has one UART, but also a software serial library (bit-bang) which was more reliable than the one I had, so I made do.

Of course, it wasn't perfect. After a while, I would start to lose about 1/4 to 1/3 of all my packets from my 2051 (checksums are your BFFLs), but if you fly your quadrotor steadily, hopefully you won't have frequent changes.

What I ended up doing was having my P math in Arduino, and having my D math/sensor zero-ing in 2051, which really wasn't terribly good, and then fed all that 2051 crap back into Arduino which sent servo pulses to my motors.

Here's my extremely tired/exasperated video from checkoff day. Babycopter derps at flying the first 2 times, but kinda manages the 3rd. Also I look like a motorcycle punk lol.




But yeah, it flew enough to the point where I was somewhat happy. Hmm, that was also when I crappily tuned my PD the night before... clearly that wasn't optimized yet. Oops.

Anyway, here's the lesson learned. Sometimes, life really sucks because you bit off more than you can chew, but you've got 2 options: 1) spit it out, 2) keep chewing. Clearly I belong in the later class of masochists, but oh well. When push comes to shove and your project looks like it's about to die several times in hell, don't panic (for a long amount of time). Calm down, paint your nails, and look up what people have done on the internet. You might have to give yourself 3 manicures a day for two weeks, but at least you're not paralyzed with fear. Just remember not to stress yourself out the next time.

Oh, and don't forget: NEVER EVER EVER build a quadrotor for 6.115


1 comment:

  1. I enjoyed this from both a technical and literary standpoint. Thank you =)

    ReplyDelete