Did more pruning of the stem plants in the aquarium today; now you can actually see the water surface. And more importantly, the rasboras will be able to get food from the surface.
The rasboras did some fighting right after I finished with the plants. They flare all their fins out and sidle up to each other (parallel) or circle each other (antiparallel) until one lunges for the other and the other runs. They eventually calmed down. With more open space now, we hope they'll start schooling together again.
We also found both otos...it's been a long time since we've seen both of them at the same time (and it's hard to tell which is which without a direct comparison) that I'd declared one missing, presumed dead. Here's one (I think this is the older oto) sucked onto the glass being fat:
And here's the other one chilling with a shrimp along the back wall:
Monday, May 31, 2010
Helicopter SAS: A summary
This post is meant to be a summary of my helicopter project so far.
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.
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.
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.
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:
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:
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: 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.
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:
- 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).
- 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.
- 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.
- 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.
- 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.
- 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:
- 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.
- 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.
- 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.
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.
Sunday, May 30, 2010
Safeway ribs adventure
Had a very enjoyable afternoon (despite the helicopter crash) thanks to the confluence of:
- Safeway ribs They had a long rack of ribs for $6; we pulled the ad from the display case but the cashier couldn't get it to ring up at the sale price so eventually management had to come over to find and tear out a coupon from the circular. It was also midnight, so there was only the one cashier and he was getting pretty nervous as the line started building up behind us. So maybe we made a scene, but it had to be done. We can't let their marketing department pull stunts like this.
- Fresh baked bread Came out very nice...the difference this time was making the dough way too wet.
- Cherries
- Season 2 of The Wire This season got a lot more interesting a couple episodes in. Unfortunately we have to wait until Thursday for Netflix to send us the next disc!
It flies!
With the subsystems working and a stable yaw controller in place, I took the helicopter out for a test flight at the Marguerite parking lot yesterday.
It's a lot easier to control now; the SAS is definitely keeping it upright. I had a lot of space to fly it in and it was pretty tame. It picks up velocity pretty fast if you're not careful, though, and you have to be pretty thoughtful about how you respond. Took some rolling landings, but everything was fine.
Today, tied the yaw gain to the transmitter knob so that I could push it up a bit. Much easier to control yaw now. Flew it in the parking lot by the apartment.
Pretty docile and easy to control, for the most part. Yaw is a little tougher to wrap your mind around, but if you can keep it pointing in the same direction then the rest of the controls are much easier. I got it to hover for a few moments, had some deliberate landings, and then crashed it into the narrow space between the car and the garage.
Looks like I bent the flybar (stainless steel rod holding the stabilizer paddles) and the feathering bar (bolt holding the blade clamps to the main shaft). Also, one blade tip is smashed up, but that seems to be it. I'm surprised nothing else is broken: the plastic pieces all held while the steel yielded.
I'll need to do some grinding to get the bent flybar out, and I'll have to find a pair of small metric sockets to get the nuts off the feathering bar. Also I can't seem to find a replacement feathering bar anywhere in the States. But all in all, that crash could have been a lot worse.
It's a lot easier to control now; the SAS is definitely keeping it upright. I had a lot of space to fly it in and it was pretty tame. It picks up velocity pretty fast if you're not careful, though, and you have to be pretty thoughtful about how you respond. Took some rolling landings, but everything was fine.
Today, tied the yaw gain to the transmitter knob so that I could push it up a bit. Much easier to control yaw now. Flew it in the parking lot by the apartment.
Pretty docile and easy to control, for the most part. Yaw is a little tougher to wrap your mind around, but if you can keep it pointing in the same direction then the rest of the controls are much easier. I got it to hover for a few moments, had some deliberate landings, and then crashed it into the narrow space between the car and the garage.
Looks like I bent the flybar (stainless steel rod holding the stabilizer paddles) and the feathering bar (bolt holding the blade clamps to the main shaft). Also, one blade tip is smashed up, but that seems to be it. I'm surprised nothing else is broken: the plastic pieces all held while the steel yielded.
I'll need to do some grinding to get the bent flybar out, and I'll have to find a pair of small metric sockets to get the nuts off the feathering bar. Also I can't seem to find a replacement feathering bar anywhere in the States. But all in all, that crash could have been a lot worse.
Friday, May 28, 2010
Adventures!
Sunday: Hung out with our friend LA. Saw an asparagus tree, had sweet peas fresh off the vine, saw a very pretty chicken with black-outlined white feathers, went to Half Moon Bay where it was overcast and freezing and SC got attacked by the ocean, leaving her soaked. We'd gotten halibut at a nearby fish market (next to the Flying Fish Grill) and we grilled those on the beach. Unfortunately the freezing wind made it near impossible to cook anything, but the "seared" halibut was quite good. We also had beets, fresh out of the ground that morning, and they were the sweetest beets I'd ever had. Until then, I'd never understood how you could get sugar from beets; I thought there must have been some sort of enzyme conversion like in HFCS.
Tuesday: Got the car smog checked at Fair Oaks Smog check. Was worried because it almost failed HC last time, but it passed with flying colors. The tech said the CC was probably cold that last test, and that does seem consistent with the test results: high HC and CO emissions along with non-zero O2 would indicate there's something not right with the CC.
Hung out with LA again before he flew back to Princeton. Ate lobster, discussed the brutality of lobster cooking vs. other forms of animal slaughter, played Settlers of Catan, watched stupid YouTube videos (scraper bikes), discovered that a certain plastic mug catches fire in the microwave, got very nauseous from burning plastic fumes.
Thursday: Went to Sultana in Menlo Park. Had an awesome appetizer plate: various dips (Ezme, humus, babaganush, tabuleh, dolmas, kizartma and garbanzo salad) with a very soft bread. The entrees (kofte and adana kebab) were...meh. Ground meats in a vaguely cafeteria-esque presentation.
Started season 2 of The Wire. We didn't realize how good season 1 was until we watched another cop show. The Wire doesn't feel as dumbed-down, and it showed off some new facets of life and crime while developing a relatively complex set of characters. Season 2 is getting off to a rough start in that regard...we get quick little updates of all the characters; not enough to really see what is going on, and we got introduced to a real villain-y kind of guy who was set up in a third-degree-interrogation-of-henchmen scene. So I hope there is more to his character than just that.
Tuesday: Got the car smog checked at Fair Oaks Smog check. Was worried because it almost failed HC last time, but it passed with flying colors. The tech said the CC was probably cold that last test, and that does seem consistent with the test results: high HC and CO emissions along with non-zero O2 would indicate there's something not right with the CC.
Hung out with LA again before he flew back to Princeton. Ate lobster, discussed the brutality of lobster cooking vs. other forms of animal slaughter, played Settlers of Catan, watched stupid YouTube videos (scraper bikes), discovered that a certain plastic mug catches fire in the microwave, got very nauseous from burning plastic fumes.
Thursday: Went to Sultana in Menlo Park. Had an awesome appetizer plate: various dips (Ezme, humus, babaganush, tabuleh, dolmas, kizartma and garbanzo salad) with a very soft bread. The entrees (kofte and adana kebab) were...meh. Ground meats in a vaguely cafeteria-esque presentation.
Started season 2 of The Wire. We didn't realize how good season 1 was until we watched another cop show. The Wire doesn't feel as dumbed-down, and it showed off some new facets of life and crime while developing a relatively complex set of characters. Season 2 is getting off to a rough start in that regard...we get quick little updates of all the characters; not enough to really see what is going on, and we got introduced to a real villain-y kind of guy who was set up in a third-degree-interrogation-of-henchmen scene. So I hope there is more to his character than just that.
Wednesday, May 19, 2010
Updates all around!
Lots of things are happening:
Food: We still have some strawberry-rhubarb pie left over. It's pretty great. Rhubarb has a tartness to it that is very pleasing in conjunction with the strawberries. We used a graham cracker crust for the bottom. I used an extra layer of aluminum foil around the glass pie pan to prevent it from burning, but it seems that was unnecessary. We were concerned that it was too runny and that the graham cracker crust would not hold, but it firmed up significantly after refrigerating. We used a frozen-butter-in-food-processor recipe for the top crust; cut down on the butter a bit but it still turned out good. Somewhat bland, though; maybe next time we add some sugar and vanilla or something.
Fishes: Saw a tiny fish! Maybe. I thought it moved like a fish, but SC thinks it moved like a shrimp. And it's probably more likely to be a shrimp, anyways. But we definitely saw one, a sort of grey-transparent color, quite small, hiding out around the jar.
Helicopter: Figured out the transmission noise...it's definitely on the wireless side. It helps to move the receiver closer to the transmitter, but I thought it was supposed to have at least a 30m range? Anyways, the telemetry is looking really good today. Still struggling with controlling the yaw mode; have now resorted to using the transmitter knob (channel 5) to control the gain, so I can play with it in real-time.
Food: We still have some strawberry-rhubarb pie left over. It's pretty great. Rhubarb has a tartness to it that is very pleasing in conjunction with the strawberries. We used a graham cracker crust for the bottom. I used an extra layer of aluminum foil around the glass pie pan to prevent it from burning, but it seems that was unnecessary. We were concerned that it was too runny and that the graham cracker crust would not hold, but it firmed up significantly after refrigerating. We used a frozen-butter-in-food-processor recipe for the top crust; cut down on the butter a bit but it still turned out good. Somewhat bland, though; maybe next time we add some sugar and vanilla or something.
Fishes: Saw a tiny fish! Maybe. I thought it moved like a fish, but SC thinks it moved like a shrimp. And it's probably more likely to be a shrimp, anyways. But we definitely saw one, a sort of grey-transparent color, quite small, hiding out around the jar.
Helicopter: Figured out the transmission noise...it's definitely on the wireless side. It helps to move the receiver closer to the transmitter, but I thought it was supposed to have at least a 30m range? Anyways, the telemetry is looking really good today. Still struggling with controlling the yaw mode; have now resorted to using the transmitter knob (channel 5) to control the gain, so I can play with it in real-time.
Monday, May 17, 2010
System identification
Took a crack at a control system over the weekend.
First tried model estimation using linear regression (input = ω's, control input, output = ω at next time step) to get a first-order system in each axis independently. Designed a lead compensator for pitch/roll (using angle estimate and low-passed gyro signal) and a lag for yaw (just using the gyro signal), but that was way unstable (oscillatory).
So I turned down the gains, but it was still oscillatory.
Figured I needed to do some more system identification, so I put in a double chirp on each control input; swept up to 3 Hz. Bode ETFE didn't tell me much (I also don't really know how to interpret it, aside from there possibly being a pole of some sort at a slightly higher frequency than the end of my sweep), but it gave me more data on which to use the same linear regression technique to estimate coupled equations of motion. Designed an LQR off of that, and that gave me something very similar to what I'd had, but with the gains even lower.
First pass produced some funny gains from the integrated yaw rate to aileron and elevator control inputs. So changed the linear regression method to force decoupling of the yaw and pitch/roll modes. Tried that, worked all right (better than the lead/lag compensators, but probably just due to the lower gains), but there is a 4 Hz oscillation; doesn't explode (probably due to nonlinear effects), but definitely still there. At that high a frequency, I think it's either sensor mounting compliance (sensors are mounted on a sprung platform to reduce vibration noise), or servo or rotor dynamics.
What next? Perhaps I can try gain stabilization by putting an additional pole (at 2 Hz) on the yaw axis to give it a 40 dB/dec HF rolloff, like on the other axes. And if the problem is non-colocated control, then the additional phase lag will make it easier to add phase stabilization at 4 Hz.
Can also try a better system model; run the chirp up to 5 Hz this time to try to capture these dynamics. With this data, I can also try a parameter-based model identification (which is basically what I ended up doing when I forced the regression to decouple yaw and pitch/roll), like in Tischler's "System Identification Modeling of a Model-Scale Helicopter". Yeah, that sounds like what I'm trying to do...
Underwater gardening
The stem plants and riccia having been growing unchecked in the aquarium for some time, and I think the rasboras were getting annoyed at the lack of open water. Yesterday we took out a ton of plants (moved them to the other tank; we can plant them there later) and the aquarium is much clearer now. I hope this doesn't trigger an algae bloom, though the shrimp seem to be keeping that in check. Water is still a little blue; don't know why...maybe clearing out the plants (also took out a ton of algae) might help.
Spent half an hour looking for the second cowfish today. Thought I'd checked everywhere (started checking outside of the tank, which is always a bad sign), and then he just casually swam out from behind a leaf that I'd checked several times. What!
Rasboras are looking okay. Thought I'd developed a scheme for identifying them (double-stripe-fish, hunchback-fish, potbelly-fish, dark-fish, skinny-fish, and normal-fish), but I looked again after feeding them, and the coloration / body shape cues are not all that permanent (and they were quite subtle to begin with). The double-stripe on the anal fin is a unique distinction, though, so I guess that's 1 fish down, 5 to go. There was one fish listing slightly last night; thought I saw him doing it today (it was hunchback fish), but the more I looked, the more it seemed like all the fishes were listing, so maybe it's just the optics playing tricks on me.
Saturday, May 15, 2010
Integer cast order of operations
Using the Arduino integer types:
byte moo = 166;
int pok = 500;
This doesn't work:
long cat = moo*pok;
This works:
long cat = (long) moo*pok;
But only because the default order of operations makes it:
long cat = ((long) moo) * pok;
byte moo = 166;
int pok = 500;
This doesn't work:
long cat = moo*pok;
This works:
long cat = (long) moo*pok;
But only because the default order of operations makes it:
long cat = ((long) moo) * pok;
Friday, May 14, 2010
All systems functional!
Regarding yesterday's to do list:
- Fixed it! I think. I hope. I added a check to prevent spurious signals from being sent to the outputs. I also added clipping to the outputs so that it won't overdrive the servos, even if we have spurious signals. I'm currently outputting only when I get a full set of channel updates, but I should add another check to ensure that a full set of channel updates happens in a timely manner (nominally within 20 ms).
- Haven't gotten around to it, despite how easy it would be. Should also edit estimator code to take out magnetometer stuff.
- In the process of learning to live without.
- Haven't gotten around to it. Plan to machine the box (oh, it's a serious box) over the weekend. Do this in conjunction with designing rev 2 of the helicopter interface board, and send that off to BatchPCB; get the soldermask and silkscreen, the works. I can even label the connectors! HAH.
- Increased the UART buffer size and decreased the data reporting rate to 25 Hz. Between the two, it seems to have solved the problem.
So next step is a control system! Woot! I think I can do some system identification by holding the helicopter in my hand (yeah, so much for that 3-D linkage) and giving it some control inputs. I've noticed the pitch/roll gyroscopic coupling (both in flight and holding it in my hand), but the controls are pretty responsive and they feel more like 1/s than 1/s2, so I may be able to ignore it for a simpler controller.
Controller options, in order of increasing complexity:
- Straight gain. If the cyclic-to-attitude transfer function really is 1/s, then we have 90 degrees of phase margin already. It's probably more like 1/s(s+a), but as long as we're not too aggressive with bandwidth it should be okay. Don't need system identification, can probably just pick a gain and see how it works. If I want to get fancy, I have a knob, right on the transmitter, that I can tie the gain to and twiddle in real-time.
- Lead compensator on each axis, independently. We have the gyro signal, but it's too noisy (for now, at least) to do PD, so it'll have to be a lead compensator. Noise threshold sets the pole location; we can choose the zero and gain to give us the bandwidth and phase margin we want. Might not need sys ID either; zero location can also be a trial-and-error kind of design.
- If we do sys ID, we have the hard part over with; might as well go to state-space and LQR. Still remains 1 degree of freedom to twiddle.
Awesome! I'm excited...
Wednesday, May 12, 2010
Helicopter making some progress
Have a lot of integration going now. Have the entire SAS mounted on the helicopter, plugged into the receiver and getting power from the battery. At some point or another, have had the Arduino talking to the AHRS, R/C receiver, servos, and wireless module. Almost ready to start designing a controller. Remaining issues:
- Not talking properly to R/C receiver and servos anymore, although earlier today it was relaying commands quite transparently. So will need to debug that; at least I should be able to revert to my earlier code (yay SVN).
- Would be nice to get residual acceleration data from the AHRS. Easy change.
- AHRS magnetometer is no good anymore. Even just mounted on the helicopter (with helicopter unpowered), the readings aren't right. Don't know if it's the helicopter's own magnetic fields or what's going on; have decided to let it go for now, although I did put a lot of work into it :(
- Still lots of noise when the main motor is running. Attitude estimation is fairly clean (because it's integrated), but gyro signal is pretty bad. Haven't had a chance to look at acceleration yet. Yaw axis is much cleaner, though, but it's unclear whether that's due to:
- Better sensor, as that axis is on a different chip. Unlikely; I remember it having worse noise than the others in the past. If it is, though, there's nothing I can do about that.
- Less electrical noise because it's better shielded. I have no idea whether that's true, but it wouldn't be too hard to wrap the whole thing in aluminum foil.
Update: checked out the past data; when shielded, I had ±10 deg/s of noise an all 3 axes, unshielded I had the same but ±100 deg/s on pitch (seems kinda extreme, may be a bad experimental setup), and currently I have ±25 deg/s pitch/roll and ±2 deg/s yaw. Noise when off is ±0.4 deg/s. - Less mechanical vibration along that axis. Plausible: that's the major axis of the enclosure and the foam tape is less stiff in shear than in compression. Could double layer the foam tape (decrease effective stiffness), and put it down in pads rather than an entire sheet. Sidewalls to the enclosure would also help, as would rigid mounting for the Arduino board.
- Serial communication is dropping bytes. It's not the Arduino-AHRS communication anymore (I fixed that problem; didn't have sufficient delay between end of transmission and driving the SS line high again). The pattern of dropped bytes suggests either buffer overrun in the Arduino's UART queue or in the wireless module. If it's the former, then I might be able to do something about the transmission timing, but if it's the latter, then I just need to send fewer bytes.
Sunday, May 9, 2010
The curse of the C++ template class
So I thought I was all clever writing a Queue class using C++ and templates. But now that means everything that uses it has to be in C++ rather than C, and that's coming around to bite me with all these ISRs that want access to objects' private fields, and it's just a mess.
Moral of the story: for embedded applications, code in C.
Moral of the story: for embedded applications, code in C.
Arduino disassembly
Moved the schedule around a bit. Today I am looking at AVR assembly to try to optimize my ISRs.
Just looking at the assembly listing was not very intuitive. The steps to follow:
Just looking at the assembly listing was not very intuitive. The steps to follow:
- Hold shift while pressing the Arduino IDE compile button. This puts it into verbose mode.
- Take note of the temp directory it's performing your build in
- From the command prompt, "D:\Programs\arduino-0018\hardware\tools\avr\bin\avr-objdump -S HeliSAS.cpp.elf >> disassembly.txt"
Am looking at it now; there's a lot of optimization going on; fortunately my ISRs are short enough as it is, so maybe I can wrap my head around it and see if there's any improvement to be had.
Also, 0x3f is the SREG. Confused the hell out of me at first...
Update: My SPI ISR is 53 clocks = 6.6us (not counting jump/reti): 35 for context saving, 6 to check for queue buffer overflow, and 12 for the actual operation. I could cut out 8 clocks (1 us) in context saving by rewriting the Queue::push() routine in assembly (reduce the number of registers that get trashed), and there's another 9 clocks if I write the entire ISR in assembly (gcc pushes/pops some registers that don't change in the ISR), though that gets into modifying Queue's private members. Oh...that reminds me; Queue is a template class...so there's no way to do this without it being a hack.
On the other hand, 6.6 us is only 0.7% of the servo pulse full range (1-2 ms), so maybe we can just live with that.
Also, 0x3f is the SREG. Confused the hell out of me at first...
Update: My SPI ISR is 53 clocks = 6.6us (not counting jump/reti): 35 for context saving, 6 to check for queue buffer overflow, and 12 for the actual operation. I could cut out 8 clocks (1 us) in context saving by rewriting the Queue::push() routine in assembly (reduce the number of registers that get trashed), and there's another 9 clocks if I write the entire ISR in assembly (gcc pushes/pops some registers that don't change in the ISR), though that gets into modifying Queue's private members. Oh...that reminds me; Queue is a template class...so there's no way to do this without it being a hack.
On the other hand, 6.6 us is only 0.7% of the servo pulse full range (1-2 ms), so maybe we can just live with that.
Saturday, May 8, 2010
Okay, time to qualify some earlier statements
So it turns out it wasn't the silver solder that sucks, it's the soldering iron tip. Got some non-RoHS solder today, and it worked a little better, but still not what I'm used to. So that leaves the soldering iron tip (and possibly my non-use of pre-tin) as the culprit. Oh well.
Also I have learned that programming embedded systems in C++ is a whole lot more trouble than it's worth. It can be elegant to go object-oriented, but then it turns out that the Arduino compiler I'm using doesn't really support "new" and "delete" (yeah, kinda important for OOP), and then I tried to make a template class and that didn't work...I think the limitations of the embedded platform just make it easier to think in C than C++.
Got Hello World with non-blocking serial code working on the Arduino, next up is Arduino-AHRS SPI communications.
Also I have learned that programming embedded systems in C++ is a whole lot more trouble than it's worth. It can be elegant to go object-oriented, but then it turns out that the Arduino compiler I'm using doesn't really support "new" and "delete" (yeah, kinda important for OOP), and then I tried to make a template class and that didn't work...I think the limitations of the embedded platform just make it easier to think in C than C++.
Got Hello World with non-blocking serial code working on the Arduino, next up is Arduino-AHRS SPI communications.
Silver solder sucks
Tried really hard to hit my milestone for today (electronics assembled), but it's just not happening. I have this RoHS compliant lead-free silver solder, and it's absolutely a pain to work with. Part of it is that I'm used to rosin-core solders, but even using flux the higher melting point is just killing me, particularly with the weak-ass soldering iron I have.
It doesn't help that the solder tip is huge and the solder itself is larger in diameter than the SOIC pins I'm soldering. For those, I finally settled on cutting off little chunks of solder and pushing them onto the pin/pad and squishing it there until the heat finally melts it and it flows onto the pad (which is fortunately pre-tinned).
What finally made me give up was the difficulty soldering the through-hole pins. Something that should have taken 5 seconds per pin now takes 30, and that's really frustrating. Also I screwed up the PCB rework because I was pushing too hard on the trace when soldering to it, so now the SPI SS line is going to look very different. There may be an alligator clip involved.
I think I am just going to have to get a second rev of this helicopter interface board. There was the printout scaling fiasco (a.k.a. why the hell doesn't SparkFun have a dimensioned layout for that 9dof IMU board), and this rework, and along those lines it'd be good to have a connection to the AHRS Rx/Tx pins. Finally, some weight reduction (thinner board and/or hatching of the ground plane), a solder mask, and top side ground connections would also be nice to have. And we'll see how the mechanical design goes; there may be some adjustment to hole placement.
It doesn't help that the solder tip is huge and the solder itself is larger in diameter than the SOIC pins I'm soldering. For those, I finally settled on cutting off little chunks of solder and pushing them onto the pin/pad and squishing it there until the heat finally melts it and it flows onto the pad (which is fortunately pre-tinned).
What finally made me give up was the difficulty soldering the through-hole pins. Something that should have taken 5 seconds per pin now takes 30, and that's really frustrating. Also I screwed up the PCB rework because I was pushing too hard on the trace when soldering to it, so now the SPI SS line is going to look very different. There may be an alligator clip involved.
I think I am just going to have to get a second rev of this helicopter interface board. There was the printout scaling fiasco (a.k.a. why the hell doesn't SparkFun have a dimensioned layout for that 9dof IMU board), and this rework, and along those lines it'd be good to have a connection to the AHRS Rx/Tx pins. Finally, some weight reduction (thinner board and/or hatching of the ground plane), a solder mask, and top side ground connections would also be nice to have. And we'll see how the mechanical design goes; there may be some adjustment to hole placement.
Friday, May 7, 2010
Helicopter milestones
Yay milestones! Don't they make you feel all warm and fuzzy inside?
No.
Not at all; it's dreadful making them (so much uncertainty, and it reminds me of how much work there is to be done), but they're necessary for proper planning and resource leveling. Therefore, without further ado, here are my helicopter project milestones:
Friday: Electronics assembled
Saturday: Arduino-AHRS integration
Sunday: Reporting orientation on helicopter
Monday: Talking to R/C receiver
Tuesday: Control of free servos
Wednesday: Relaying receiver pulses to servos
Thursday: Wireless integration
Saturday: Yaw control, with wireless telemetry
Also I have decided that the system will be called the HeliSAS. It comprises a Helicopter Interface Board (HIB), Arduino Pro 328 Mini (Arduino) running my HeliSAS code, and a Sparkfun 9DOF Razor IMU (AHRS) running my HeliAHRS code.
No.
Not at all; it's dreadful making them (so much uncertainty, and it reminds me of how much work there is to be done), but they're necessary for proper planning and resource leveling. Therefore, without further ado, here are my helicopter project milestones:
Friday: Electronics assembled
Saturday: Arduino-AHRS integration
Sunday: Reporting orientation on helicopter
Monday: Talking to R/C receiver
Tuesday: Control of free servos
Wednesday: Relaying receiver pulses to servos
Thursday: Wireless integration
Saturday: Yaw control, with wireless telemetry
Also I have decided that the system will be called the HeliSAS. It comprises a Helicopter Interface Board (HIB), Arduino Pro 328 Mini (Arduino) running my HeliSAS code, and a Sparkfun 9DOF Razor IMU (AHRS) running my HeliAHRS code.
Thursday, May 6, 2010
Curses!
It would appear that the AHRS SPI pins aren't all connected...the SS line isn't connected to anything, which makes it impossible to use the AHRS in SPI slave mode. Looks like there will be some PCB rework after all...
This is pretty annoying. My options are:
This is pretty annoying. My options are:
- Continue as planned. Cut and jump on the AHRS board: solder a wire from a TQFP pin to the 6-pin header.
- Make the AHRS the SPI master. The SS line is currently connected to CLR on the shift register (used for PWM output),
- The hard way: connect an AHRS UART pin to the 6-pin header (at least this jump is from a .025" post to another .025" post). We won't be using the UART in normal operation, anyways. Then connect that pin to the Arduino SS.
- The easy way: connect the Arduino SS pin to ground, so that it is always active. There isn't any contingency if the SPI gets out of sync, though.
Looks like 2.1 is probably the best option. I'll use pin 6 on the SPI header (currently connected to RESET on the AHRS and nothing on the HIB). On the AHRS, I'll need to cut that trace and solder a wire to it from the RXI pin of the UART header. On the HIB, I'll cut the trace and solder a wire from the pin to the Arduino side of the cut, and a wire from one of the extra I/O pins to the shift register side of the cut.
Okay. No big deal. Whew.
Fruit tart!
After getting a 4 lb box of giant hollow strawberries (one thought: fill the hollow with chocolate!), we decided to make a fruit tart.
Dyslexia strikes again!
Actually not dyslexia, just inattentiveness. I've been calling it ARHS, but it's supposed to be AHRS (Attitude and Heading Reference System). I just caught that, and now my files and code repository and many other things are named incorrectly.
Whatever you call it, I've ported the MATLAB code over to the ATmega328. It's a bit slow; it takes ~5 ms to run the estimator update, but that's okay. Don't need assembly optimization. Synchronizing the ADC interrupt (so that it doesn't run at 1.5 kHz) would probably produce more speed gain.
As for performance, I tried it out a bit; response isn't great, but I can't really find any particular places to fault it. Is the performance worth the 2 weeks I spent on developing it? Probably not, but the experience gained in the process may be. Anyways, I can't see myself accepting the sf9domahrs code as it was; some sort of revision was inevitable.
Before the AHRS is fully functional, I'll need an SPI library and a protocol for talking to the main board. Some sort of synchronization would be nice; I'll have to see about that.
Also, the wireless modules arrived today. So that'll be fun to play with. Looks like everything is set for (potentially) a lot of work getting done this weekend.
Whatever you call it, I've ported the MATLAB code over to the ATmega328. It's a bit slow; it takes ~5 ms to run the estimator update, but that's okay. Don't need assembly optimization. Synchronizing the ADC interrupt (so that it doesn't run at 1.5 kHz) would probably produce more speed gain.
As for performance, I tried it out a bit; response isn't great, but I can't really find any particular places to fault it. Is the performance worth the 2 weeks I spent on developing it? Probably not, but the experience gained in the process may be. Anyways, I can't see myself accepting the sf9domahrs code as it was; some sort of revision was inevitable.
Before the AHRS is fully functional, I'll need an SPI library and a protocol for talking to the main board. Some sort of synchronization would be nice; I'll have to see about that.
Also, the wireless modules arrived today. So that'll be fun to play with. Looks like everything is set for (potentially) a lot of work getting done this weekend.
Tuesday, May 4, 2010
A troublesome switch
Check engine light came on last week. Went through the self-diagnostic routine (turn a knob on the ECM, and it'll blink the code to you) and it turns out that it's an error with the neutral position switch (and also something with the knock sensor, but the knock sensor error doesn't trigger the check engine light).
Now, in some cars, the neutral position switch is used to inhibit starting when the transmission isn't in neutral. But that's not the case with this car: the starter inhibit is tied to the clutch. In fact, this switch doesn't seem to do anything (besides triggering the check engine light).
When I probed the switch, it turned out that it works pretty consistently when shifting into neutral from 3rd, and sometimes 5th. Strange. Maybe it's loose, and shifting from 3rd produces the right amount of overtravel to trigger it, or something.
Anyways, I reset the check engine light and now, as a bit of a voodoo ritual, I shift between 3rd and neutral a few times after starting the car, just to convince the ECM that the switch is still functional, so that it won't activate the check engine light.
Now, in some cars, the neutral position switch is used to inhibit starting when the transmission isn't in neutral. But that's not the case with this car: the starter inhibit is tied to the clutch. In fact, this switch doesn't seem to do anything (besides triggering the check engine light).
When I probed the switch, it turned out that it works pretty consistently when shifting into neutral from 3rd, and sometimes 5th. Strange. Maybe it's loose, and shifting from 3rd produces the right amount of overtravel to trigger it, or something.
Anyways, I reset the check engine light and now, as a bit of a voodoo ritual, I shift between 3rd and neutral a few times after starting the car, just to convince the ECM that the switch is still functional, so that it won't activate the check engine light.
PCB Away!
Sent out the PCB for fab today. Also ordered the kit; both should get here on Friday.
The design should be pretty simple. One AHRS board, one Arduino, and one helicopter interface board. The interface board will be stacked on top of the AHRS and the Arduino stacked on top of the interface board. Both sets will mate in rows of headers. Both the AHRS and interface board have mounting holes to connect to the enclosure. The bottom of the interface board is a pretty complete ground plane. It will sit like a lid on the shielded enclosure and the exposed ground plane will contact the shield.
With that away, time to turn to the next steps:
The design should be pretty simple. One AHRS board, one Arduino, and one helicopter interface board. The interface board will be stacked on top of the AHRS and the Arduino stacked on top of the interface board. Both sets will mate in rows of headers. Both the AHRS and interface board have mounting holes to connect to the enclosure. The bottom of the interface board is a pretty complete ground plane. It will sit like a lid on the shielded enclosure and the exposed ground plane will contact the shield.
With that away, time to turn to the next steps:
- Port AHRS code from MATLAB to the embedded system
- Write Arduino code to talk to servos, AHRS, and UART
- Build rig to constrain helicopter to rotations about CG
I think step 3 won't be as hard as it sounds. If I tie 3 strings to the helicopter skids (or 4...4 is redundant, but may be easier to implement due to symmetry) and anchor those strings to the ground such that, when taught, the strings point towards the helicopter CG, then for small angles the helicopter's constrained motion will approximate rotation about the CG. Depending on how much extra lift the helicopter is generating (there will need to be extra lift to keep the strings taught), there will be some restoring moment in yaw. But using this setup and running a frequency sweep in the cyclic inputs should be sufficient for system identification.
The other option is to put a straight gain on the feedback, control that gain with channel 5 (the "gyro gain" knob on the transmitter), and fly it and hope for the best :)
Subscribe to:
Posts (Atom)