Monday, May 31, 2010

Helicopter SAS: A summary

This post is meant to be a summary of my helicopter project so far.

Purpose


My dad likes R/C helicopters. Well, the idea of them, anyways. The truth is, he doesn't have the patience to learn how to fly one, at least not one of the cool single-rotor ones. So the project is to create an electronic stability augmentation system (SAS) that would sit between the helicopter radio receiver and the servos to provide some additional stabilizing control input.

April 5 to 16: Planning and Preparations


Picked out sensors (SparkFun's "Razor" IMU unit with accelerometer, gyro, and magnetometer), control board (Arduino Pro Mini), and helicopter (E-sky King 3, a cheap, 600mm rotor diameter, collective pitch helicopter with modular electronics). Brainstormed potential ways to measure velocity. Wrote some Arduino and MATLAB code to function as an oscilloscope so I can look at servo pulses.

April 18 to 28: First Impressions


The sensor board has an 8-bit Atmel microprocessor on board, so the plan is to have it run the estimator algorithm, i.e. function as an Attitude and Heading Reference System (AHRS). Played with the sf9domahrs code very briefly before deciding that I didn't like it and could do better. Changed the internal angle representation from rotation matrix to quaternion, increased the sensor update frequency and made the update code non-blocking. Started on an Extended Kalman Filter but had a hard time casting each sensor's particular brand of uncertainty into the Kalman paradigm, so ended up doing pole placement on a quaternion-based linear kinematic estimator that incorporated all 3 sensors (gyro, accelerometer, magnetometer).

Got the helicopter in the mail; completely ready to fly out of the box (well, had to charge the battery and install my ping-pong ball landing gear, but that was it). Did a test flight that mainly consisted of skittering across the parking lot on the ping-pong balls, but I did get some good insight into the dynamics for the few seconds I actually had it completely off the ground. I think the primary take-away point was that having to close a control loop from cyclic input to attitude was too much pilot workload for me, and that simply having attitude track the cyclic stick would be a huge step in making it easier to fly.

April 29 to May 15: Hardware


Designed a circuit board that would interface the Arduino, sensor board, helicopter, and wireless (XBee module, for telemetry) hardware all together.
Pretty simple: it's got some level shift chips, voltage regulator, capacitors, and some LEDs. Tried to keep the back as solid as possible, as this board serves as the top for the shielded box enclosing the sensor board.
Putting everything together involved porting the AHRS code from MATLAB to the AVR microprocessor, writing the serial communications code, machining the box out of polycarbonate, and assembling everything. In the process, I came across some unforeseen hurdles:
  1. Sensor board doesn't bring out the AVR SPI module's SS pin. As a result, it is impossible to use the sensor board in SPI slave mode without some PCB rework. I'd naively assumed that the 6-pin ICSP header would include all 4 SPI pins, but that was incorrect. Hence the white wire running from the other header: it will connect to the Arduino's SS pin (sensor board is master, Arduino is slave).
  2. I really started feeling the lack of a real oscilloscope. My Arduino/MATLAB contraption was fine for the 50 kHz sample rate needed to measure servo pulses, but I couldn't use it to debug serial communications, measure code execution time, or probe any analog signals.
  3. Got a new Weller soldering iron tip, but it was really difficult to use. I've never had to use pre-tin on the tip (usually my problem is too much solder; wettability hasn't been a problem before), but maybe that was the problem here. Anyways, the whole soldering process took about 5 times as long as it should have with a good tip.
  4. While the AVR compiler does support C++, it's a little funny using object-oriented code in an embedded environment. Without dynamic memory allocation, you need to pre-instantiate all your objects. The proper relationship between objects and ISRs is also a little tricky. Template classes are nice, though: I wrote a queue class that I re-used several times with different storage requirements.
  5. Magnetometer readings are no good anymore. I think the magnetic fields due to the helicopter's motors are throwing off the magnetometer reading. Maybe it'll turn out to be a constant offset that I can remove in software, but for now I'm letting it go.
  6. Lots of noise in the sensor readings when the main motor is running. I've got the sensors pretty well shielded, so it must be mechanical vibrations. The box is held to the helicopter using double-sided foam tape.

May 16 to 28: Control Design and Debugging

With the hardware all ready to go, I started doing some control design. Put in a open-loop chirp (stabilized the helicopter by holding it as gently as I could without having it fall over...the safety of this method depends on the ratio of main rotor diameter to your arm length) and used linear regression to identify a first-order autoregressive model.

Pitch/roll actually worked pretty well right off the bat, but yaw was very troublesome. Eventually I used frequency-domain identification to create an empirical transfer function estimate, and from that I realized that there was a lot more phase lag than I'd originally thought. I think this is due to the servo dynamics.

However, in order to narrow it down that far I had to run a gauntlet of software bugs:
  1. Pitch and roll angle estimates would drift sinusoidally with a period of about 20 minutes. Turns out it was because my initialization of the reference gravity vector caused it to have x and y components, thus coupling the inevitable yaw drift into the pitch and roll estimates.
  2. The gyro offsets I measure during initialization are always off from the run-time values by about one ADC bit. I spent a long time looking through my code looking for off-by-one errors, but it turned out not to be a software problem at all. I turn on an LED during initialization, the additional current drain taxed the voltage regulator enough that the analog reference voltage was lower during initialization than run time. This bug was particularly frustrating because it wouldn't have been a problem during normal operation, when the circuit uses a different voltage regulator and I don't turn on the LED at all. 
  3. Occasional glitches where the sensor board reports spurious readings. I don't have the communications bandwidth to report all the raw sensor readings, so I put in code to report max/min and that showed glitches happening in the raw sensor readings. Spent a long time trying to figure that out before realizing that my max/min code was buggy (non-atomic access to 16-bit variable modified by ISR). After a lot more debugging I narrowed it down to the Arduino side of things: an ISR was taking too long and causing the Arduino to drop SPI bytes. I had a checksum to prevent this from producing spurious readings, but even then you've got a 1/256 chance of getting a false positive. So I re-wrote the offending ISR and the problems went away.
So now I have independent PD compensators on pitch/roll (where I have angle and rate measurements) and a lead/lag on yaw (where I only have a rate measurement).

May 29 and 30: Flight Tests


May 29: Found a big open parking lot and flew it around. This being only the second time I've flown (the first was the pre-SAS test flight in April), I count my spastic maneuvers and rolling landings as a success. With the SAS running, it returns to upright if you let go of the cyclic stick. While that won't put it into a hover, it gives you enough time to see which way it's pointed and do the necessary coordinate transformation to figure out which way you need to push the stick. Didn't get any telemetry that day...it's almost like the R/C transmitter is jamming the XBee modules.

May 30: Flew it in the smaller parking lot near my apartment. Tied the yaw gain to the transmitter knob, so I was able to push up the gain to the point of instability and then back it down some (the gain margin predicted by MATLAB was actually pretty accurate). This made it a lot easier to stay oriented with the helicopter, and I got in some longer hovers (still wouldn't call it sustained) and some legitimate landings. Got careless, though, and crashed it into my car, bashing open a blade tip and bending two steel shafts. Miraculously, everything else seems fine.

And that brings us up to date. I'm waiting on replacement parts, one of which (the feathering shaft, which bolts the blade clamps onto the main shaft) is completely sold out in the United States, so it's shipping from Hong Kong, perhaps tomorrow.

No comments:

Post a Comment