Tuesday, September 20, 2011

Maker Faire NY 2011

Last weekend I went down to the World Maker Faire in New York, along with some of the other builder-types from MIT and the Summer Engineering Workshop crew. Needless to say, we were responsible for most of the rideable objects on our side of the Faire:


I've been to the Cambridge Mini Maker Faire twice, but this was my first experience with one of the three World Maker Faire events. While the Mini Maker Faire probably attracts a crowd of a few thousand, the World Maker Faire numbers must be in the several tens of thousands. First off, I was amazed that a handful of people actually knew me from my blog, so here's a shout-out to the people who came by my table to say hi. I'm not as famous as certain people, but it's cool to meet my blog readers in person.

Also present was Max H., who brought TOBL to show off, and most of the tinyKart crew. A large sampling of the MITERS builders came down from Cambridge as well to show off a pair of sound-reactive EL shutter shades, giant Tesla coil driver, 3D printer, battlebot, tankboard, hub motor kick scooter, eddy current clock, and rideable freakin' hexapod.

For my part, I decided that I would attempt to bring five projects. First, my three Maker Faire veterans, Pneu Scooter, Twitch, and SegStick. Additionally, I brought 4pcb, which turned out to be an attention-getter even though I did not even attempt to fly it. I would say that quadrotors are the new Segways - the current obsession of every random tech-savvy person. But in fact, Segways are still the new Segways. For some reason, no matter what else I bring, I can't escape the Segway people. Then again, I've said a few times that the quadrotor is just two Segways and a FIRST robot, so maybe it's all inherited from one parent class of silly self-stabilizing objects.

So before I get angry, Yes, it does have an angular rate sensor, commonly known as a "gyro" for historical reasons. No, there is no mechanical flywheel keeping it balanced. No, it does not use a Kalman filter. And yes, it runs just fine on an Arduino, and it doesn't even use that much of its processing power because the code is very, very simple...much simpler than you want to think.


And that's all I want to say about quadrotors and self-balancing platforms. But here are the Maker Faire recaps for the more interesting projects:

tinyKart:


That's tinyKart in the trunk of a Ford Fusion. I loaded it into the trunk myself in about 10 minutes. It involved taking out 12 cap screws and sliding the two halves apart, then flipping the front half over so that the steering wheel rested in the seat. The back half weighs less than 40lbs and the front half weighs less than 20lbs. There was even enough extra room in the trunk for Tyler's monster Tesla coil driver.


In terms of making an ultralight, ultra portable go-kart, I consider this trip a huge success. We like to make things that don't exist, and an ultralight electric go-kart is something new. There is the Razor Ground Force, which is the same weight (55lbs) as tinyKart but there really is no comparison. Which brings me to my next point:

tinyKart is absolutely freaking awesome as a go-kart. 

Just look what reverse did to this dude's hair...
We drove it all weekend and it is actually amazing to me that we built such a thing from scratch. It's a totally different experience from Cap Kart and most other go-karts I've driven, and it's more fun than any of them. "Sprightly" might be a good word. I really don't know. It darts around in ways that defy its narrow tires and flex-y frame. The acceleration is good too, despite the lack of more formidable brushless motors. The trigger throttle just makes it even more of a unique experience. And the brakes are so good that I worry about bending the steering wheel from the deceleration force. I really would not change a single thing about the mechanical design...it's pure win.

"If it's going to break, it's going to break now." -Max
It even does things it shouldn't, like off-roading. We took it on slippery grass and dirt, and it was even more fun than on asphalt. The flex-y frame doesn't mind at all and the 17mm aluminum wheel axles, which are probably the weakest link in the structural loop, survived both the shock load from bumps and side load from drifting.

Pretty much the only things that isn't 100% perfect are the controllers. Maybe I just have a high standard for motor control...well okay, I definitely do...but the Kelly controllers just aren't quite up to the task of driving full load into these motors. They cut out occasionally, leaving you with half power for a second or two. I'm learning the acceleration threshold that works, but the motors can handle more power so I feel the urge now to give tinyKart a set of controllers that can, too.

Pneu Scooter:

A few days before Maker Faire, Pneu Scooter got a flat rear tire. I knew it would happen eventually because the front tire got a flat about a month ago. Unfortunately, the 6" pneumatic casters are not conducive to easy tire/tube changes. I thought they would be, which was one of the motivators for using pneumatic tires in the first place, but as it turns out, barring special tooling, it's easier to change the entire wheel. So changing the rear wheel means taking apart the hub motor. But, really, Pneu Scooter has been ultra-reliable, so this is more like scheduled maintenance than a design flaw.

Could use a cleaning while I'm at it...
So I opened the motor for the first time since it was built. The process is pretty simple. The only tricky part is getting the three phase wires out, since they are soldered to connectors. To fit back through the bearing, they needed to be de-soldered and shoved back into the axle slot. Here are some pictures from the teardown, with everything dirty but intact:

Windings.
Outer spacer.
Dirty rotor.
Awesome adapter ring.
After taking off the adapter ring, I could get a good look at the rim and tire to see where the damage occurred. I suspected that the tire and tube had been punctured by screws that hold the ring onto the plastic rim. (The front tire suffered a similar failure.) Sure enough, I found a bunch of slashes like this:


I guess the screws were wearing through the tire and eventually the tube over time. The solution is so simple that I have no idea why I didn't do it in the first place.

Duhhhh...
So I put the motor back together with the shorter screws and Pneu Scooter was back up an running in less than three hours...


...which is great, because it actually came in really handy during Maker Faire. Not only was it the only one of my vehicles that I actually felt reasonably safe letting the annoying little kids ride, but it turned out to be the best way to get from the Citi Field parking lot to the Maker Faire itself. There were shuttle buses, but they were crowded and only took you about 60% of the distance anyway. So, I just took the scooter instead.

Twitch

Twitch also had some lingering wheel problems before Maker Faire. Specifically, the press fit holding the custom aluminum hubs to the plastic Vex omniwheels had failed on one wheel, making it hard to drive. It's happened before and I've resorted to epoxy for a quick fix, but I wanted to make a more permanent solution before the Faire. So, I manned up and got on the lathe...


...and then the mill...


... to turn out some new hubs that will actually bolt onto the wheel instead of relying on a press fit into flimsy plastic. The six-bolt pattern lines up with the spokes such that 1/4-20 screws rest against the inside surfaces to positively transmit torque to the wheel. I only put on one new hub for now, but I have the full set for when the remaining press fits fail. 

As I was doing this, though, some other problems revealed themselves. One of the linkages had a stripped-out hole, and one of the servos that drive the linkages was also damaged. I suspect both were symptoms of the wheels running into hard stops while the servo continues to drive the linkage. So far, I've only been calibrating the servos by hard-coding in soft-stop values, but they change every time I take the robot apart and put it back together.

Twitchguts, if you don't remember.
I decided that after replacing the servo and fixing the linkage, the best way to prevent this problem from happening again would be to just write the damn trim software the way it should be written.


Now the servos each have a software-settable minimum and maximum value. Through some coding trickery I was able to "or" the calibrate state with the normal drive states (forward, sideways, omnidirectional) so that you can trim the servo end positions while in any one of the states. This is useful since the servo maxima occur in the forward state and the minima occur in the sideways state. And just for extra software hacker cred, I save all the trims to a text file that automatically loads when the program starts up.

Twitch was, as usual, a constant source of entertainment that filled in the gaps well while the vehicles were charging. Part of the fun of Twitch is that nobody (or very few people) have ever seen a robot move the way it does. I am finally able to drive it in the way that it deserves, making smooth state changes and combining rotation and translation in ways that just look cool. It took a lot of practice, but I feel like Twitch is finally living up to its potential. And on that note I'll just leave this here...


Tuesday, September 13, 2011

The great XBee 57.6kbps mystery finally solved.

Ever since I started using the STM32F103 microcontroller, I've been hindered by the inability to wirelessly program the way I could with my old MSP430F2274 setup. Which sucks because that's the entire point of the wootstick (Wireless bOOTloading). The wootstick is the MCU board I've used on all my motor controllers:


The latest one, v2.0, has the STM32F103, an FTDI USB-to-UART converter, and an XBee Series 1 digital radio built on to a 3"x1" board with 2mm breakout headers. Ideally, it should:
  • Send and receive data over USB or over the XBee as a virtual COM port to a PC. Switching from USB to XBee wireless is seemless - no software modifications required on either side.
  • Be bootloader programmable through either the USB port or (with some configuration) the XBee radio. The latter option is the most useful to me, since it means the controller can be embedded in an enclosed system and still be programmed.
The USB interface works fine, but up to now, I've been able to get only half of the wireless functionality working. I can either wirelessly bootload or send and receive data over XBee, but not both. Changing from one state to the other requires reconfiguring the XBee, which is impossible if the controller is embedded in, idk, say, a scooter.

I decided I would solve this problem before moving forward on sensorless field-oriented control, or rather, that I would use it as an excuse for not making any progress for so long... I figured it would only take a day of messing around to figure out why exactly this was happening, I just hadn't actually sat down and done it up to now.

Then, as I was spending the last two weeks playing with the PCB quadrotor, I ran into almost exactly the same problem. I tried to set up the Arduino Mini on the quadrotor to be wirelessly programmable, so that I would not have to tether it to my computer every time I want to change the controller. But I found that if I set the radio to the baud rate required for the bootloader (57.6kbps, same as the STM32F103), I would get intermittent communication under radio control. Furthermore, the problem went away under USB control with the same baud rate, which suggested a problem specific to the XBee radios. And I've seen other online sources that suggest XBee trouble at 57.6kbps. So I decided to dig a little deeper.

Step one was to round up all my XBees, minus the two high-power transceivers that I have yet to get back from certain unscrupulous borrowers.
Step two was to find a real scope.
As much as I love the Tek 2445 analog scopes in MITERS and the Edgerton Center, I absolutely needed a digital scope to see what was going on at the bit level of the PC-to-XBee-to-microcontroller serial communication. So I went down to the mechatronics lab, which I now have access to since I am apparently the TA for a new course. (Have you heard?!) And there are 12 brand-new four-channel Agilent digital storage oscilloscopes with all kinds of fancy features. They can even save waveforms as .png images to a flash drive. (Something I did not find out in time for this post, as you'll soon see.)

Anyway, based on internet rumors, I suspected a problem with baud rate timing mismatch between the computer, XBee, and microcontroller. All are nominally set to 57.6kbps, but due to the limited clock frequency dividers on the XBee and the microcontroller, there is some error. First, the PC:


I zoomed way in on the first (start) bit of the transmission, something only possible with a nice set of working trigger and holdoff settings on the new scopes. The bit width is 17.34μs/b, the inverse of which is 57.67kbps. Within the error tolerance of the measurement, that's exactly correct. Next, the XBee:


A single bit on the XBee Tx pin was 17.00μs wide. This is 58.824kbps, which is what the internet suggests a XBee set to 57.6kbps actually is. The reason for this is because the XBee has a 16MHz crystal and an integer divider the produces the buad rate. If the integer divider is of the form 16MHz/(16*N), and N=17, then the exact baud rate is 58.824kbps. The next integer up, N=18, would yield 55.556kbps, which has a higher error than N=17. So the XBee uses N=17 assumes the PC can deal with the 2.1% error in baud rate, which it can.

Now here is where it gets interesting. The Arduino, when configured with Serial.begin(57600), showed up with a bit rate of 17.50μs. (Sorry, forget to take a picture of the scope...) This is 57.140kbps. It's consistent with an integer divider of the form 16MHz/(8*N) with N=35, and digging into the Arduino serial library source code suggests that this is in fact what happens. With an error of less than 1%, it's preferred over N=34, which would make it exactly equal to the XBee rate. 

But, the error on the XBee is in the opposite direction as the error on the Arduino. So the total error of an XBee talking to an Arduino at 57.600kbps nominal is close to 3%. This is flirting with the maximum error tolerance of the USART, according to the ATmega328 reference manual, page 193. (Seriously, RTFM, you will not find this information on www.arduino.cc.) When you factor in the +/-1% error tolerance of the ceramic resonator used to generate the Arduino's 16MHz clock, the chance for framing errors increases even more.

Why exactly it works in the bootloader but not during normal data transmission, I don't know. Maybe it has trouble picking up bytes that are adjacent to each other, or maybe the bootloader just has better software error checking to verify the program data is correct. In any case, I took the safe route and forced the Arduino baud rate to match the XBee baud rate exactly:

  Serial.begin(57600);
  UCSR0A |= (1 << U2X0);
  UBRR0L = 33;

Which, now that I look at it, should be the same as:

  Serial.begin(57600);
  UCSR0A &= ~(1 << U2X0);
  UBRR0L = 16;

It's 16MHz / [16 * (16 + 1)] instead of 16MHz / [8 * (33 + 1)]. (RTFM on page 179.) The latter is preferable because slow mode has a wider error band. Either way, it forces the Arduino to have a bit rate of 58.824kHz, matching the XBee. This made the RC control much happier, and the bootloader still works. (It should be independent of the user code.)

But that was all for the Arduino. To test the clock speed deviation theory on the STM32F103, I took out DirectDrive and brushed the dust off of it:

Wasn't I going to do something with this?
I checked the USART documentation for the STM32F103 against my code only to find that the USART clock divider has significantly more resolution. Instead of an integer clock speed divider of the form 16MHz/(16*N) it is essentially 16MHz/N, and I have N=278. (For some reason, it's not quite that simple, RTFM page 768.) But the result is that it should be (and is) running at 57.55kbps. The error between this and the XBee baud rate should be within tolerance of the USART.

Additionally, sending and receiving data works just fine on the STM32F103 at 57.6kbps with 8-N-1 configuration. Only when set to 8-E-1 (even parity bit, required by the bootloader) would the wireless data transmission stop working. But the bootloader worked fine on 8-E-1, with the XBees properly configured for even parity. So now I had at least narrowed it down to a problem involving the parity bit configuration.

Interestingly, I had unknowingly managed to avoid the problem over USB, set at 57.6kbps 8-N-1, because the FTDI chip would automatically reconfigure to 8-E-1 when using the bootloader, then switch back to 8-N-1 when running user code. Only because the XBee radios are have a fixed parity setting did the problem seem to be a wireless-only issue.

I think the theme of this post is Read The Fucking Manual because after only about 10 minutes of doing just that, I found the answer:

It's right there on page 791.
Essentially, by setting the PCE bit, I thought I was appending a single, even parity bit to the end of the data frame, making it 8-E-1. Instead, it was replacing the last data bit with the parity bit, making it 7-E-1, and screwing up the entire data protocol. Only by changing the word length to 9-bit by setting the M bit could I get 8-E-1. I should point out that no other microcontroller that I've used does it this way. Setting the parity enable bit appends a parity bit to the data frame on the ATmega328 and the MSP430F2274.

Well, with that sorted out, everything works properly now. The flash bootloader works over XBee and I can send and receive data at 57.6kbps, 8-E-1. Clearly the next thing to do is go back to working on sensorless control make MIDI scooter play Railgun.

Monday, September 5, 2011

I should put the PCB quadrotor away...

...but it's just so addicting. I implemented a few simple improvements:

On the suggestion of Max H., I added 1" nylon standoffs to each of the four corners as landing gear:


You might also notice that the motor looks a little different. Although the landing gear does the job of keeping the quadrotor level during takeoff, it also transmits much more of the impact of landing into the motor. (Previously, it was being absorbed by the LiPo battery...) Now, except in the rare soft landing, the impact would dislodge the motor can almost every time. I tried a few different types of adhesive, but they were too brittle and the surface area was too small for them to withstand the shock. In a moment rage-induced inspiration, I found a piece of heat shrink that fit over the motor and cut it so it would just overhang the can when it shrank, which is what you see above. This turned out to be the best idea of the week: after heat shrinking, there have been no further motor can failures.

With the risk certainty of crash landing directly on the LiPo eliminated, I also upgraded to the more potent chemistry of the Turnigy nano-tech line, specifically the 2S, 460mAh, 25-40C pack:

Can it explode just from looking at it?
It's roughly the same size, weight, voltage, and price as the lower-power LiPo I've been testing with, but it has a much lower internal resistance, which means less voltage sag under load. The difference is noticeable, with lower throttle for takeoff and also similar flight time despite the slightly lower capacity, since the motor controllers stay above their low-voltage cutoff longer.

I made one more change which has nothing to do with the quadrotor itself: I decided to take Ryan A.'s advice and fly with a PS2-style gamepad instead of a joystick:

I haven't tried flying with a Weller power supply yet...
It's generally better for controlling robots, so I'm not sure why I expected the joystick to be more appropriate for a quadrotor. The only other quadrotor I've flown used a standard RC flight transmitter, which is closer to a gamepad than a joystick. Thumbs are more precise and faster than entire arms, or even if you're doing it right, wrists. The gamepad has a spring-loaded throttle, which I thought would be problematic. But, with no altitude control anyway, I am always going to be adjusting the throttle even to hover, so it doesn't matter if I have to keep pressure on it. 

Up to now, it sort-of flew, but it would tend to drift around a lot. The series of small changes helped, but I still wasn't really satisfied with stationary hovering. I had speculated that the control loop itself was working and stable, but that the zero angles in pitch and roll were wandering, causing it to sporadically dart off in some direction. With enough space, I could still catch it and bring it back to center, but the immediate goal was to be able to fly it in a small room. For that, a more consistent zero would be necessary. 

To troubleshoot any further, I had to spend some time getting the data acquisition up and running. This should be easy since I've been doing it the same way forever, but for some reason it took me half a day to get the XBee radios to cooperate. And I had to settle for 19200bps transmission because 57600bps seems to be very tricky with XBees, particularly when wireless bootloading is involved. I've had the same problem with the STM32 chip, and I swear I will sit down and actually solve this soon. Anyway, once I had the data running, I did a test run at full throttle with the quadrotor held down on the bench. 

My theory that the power supply was sagging, causing the ADC readings to be offset under load, was quickly disproved and replaced by a new theory:

Specifically, that the sensor signals are total garbage. What you're looking at is a plot of the angular rate signal coming from the +/-300deg/s pitch gyro...while the quadrotor is stationary. So, the noise amplitude is half the full range of the sensor. The complementary filter, which relies heavily on the gyro for computing the angle, is understandably confused, reporting an angle that wanders from -5deg to 11deg, again while the quadrotor is stationary.

And here is where I possibly violate the golden rule of troubleshooting. ("If you can hear it, it's a mechanical problem. If you can smell it, it's an electrical problem. Everything else is a software problem.") I have implemented both hardware and software filters to take out high frequency noise from the inertial sensor signals. But somehow, a massive amount of noise was still making it through. Probing with an oscilloscope revealed it to be broad-spectrum noise, including some low enough to make it through all my filters, with a little bit of an 800Hz sine wave on top of everything. The cause seems obvious now, but I'm so used to electrical noise in high-current motor controllers that I at first neglected to even think about mechanical noise. The test to separate the two was simple:


Running at full throttle with the inertial sensors off-board, the data tell the story:


The rate sensor noise is completely gone, and the angle stays much closer to zero, where it should be. This very clearly points to mechanical vibration as the source of the noise, and more so it suggests that only a mechanical solution will work; the noise is so destructive to the gyro that no amount of hardware or software filtering will take it out. So, having the inertial sensor sitting on headers is no longer an option, and it's time to break out the foam tape:


Attempt #1 used foam-tape only and replaced the headers with a long loop of flexible wire, so as not to transmit vibration through the connections.

Well now that didn't really work at all.
After this failure, I decided to switch over to the C part of the mechanical RC filter by adding some mass to the sensor board:

Sorry, Ryan.
I also made the tape thicker and looser.
The extra mass of the small aluminum plate helps the sensor board establish its own frame of reference that rejects high frequency vibrations that do make it through the tape. And the data:

Hrmmm.
Well, it doesn't look much better, visually. But the noise amplitude is a tiny bit lower and, more importantly, the angle doesn't wander around as much. (The times it does are when I was picking it up and moving it. You can tell because the rate is very clean there.) At least it gives me a little bit of hope that the vibrations can be damped enough to make the signals usable. I decided to give this configuration a chance in flight, using the best controller gains I'd established thus far:


Somewhat surprisingly, the small amount of noise reduction makes a huge difference in flight. (Well, combined with the other changes I made above.) You'll notice that I've changed venues and can actually fly it in this smaller classroom now. It still wanders around a little, but I at least feel much more in control of the wandering. I even manage to land smoothly a couple of times. And the data?


Well, that's basically still noise. Maybe there is more useful information contained in the average rate, but it's still visually lost in the noise. I think more drastic isolation measures, maybe combined with more aggressive filtering, will be required for it to give a clean rate signal. Ideally, it should reject everything above about 100Hz. Since the sensor board mass is still very low, I suspect I will need an even more compliant mount. What the heck is more compliant than loose foam tape?

But anyway, I am happy that its hovering can be contained to a 10'x10' area now...