Saturday, December 22, 2012

Playstation controller

I had decided a while back that I needed to build a new, more capable controller for RC vehicles & robots. The goals were:
More buttons for various functions
More analog inputs than a single joystick
Operated with two hands
LCD display to show data sent back by the vehicle

I was about to start designing a board when I came across a PS2 controller. These can be found really cheap now that the PS3 has obsoleted them. Using these controller for robots is not a new idea, lots of people have done it, and they’ve put all kinds of information on the internet about how to interface with them. The controllers communicate with a form of SPI. It’s regular SPI except that the bit order is flipped to lsb first (where standard SPI is msb first). The protocol is close enough that I can use the built-in MSSP hardware in the PIC parts I’m using, if I do some data manipulation before and after exchanges. Thanks to all the people who have worked out the protocol and shared their findings, I got the controller working very quickly.

I wrote robot controller code for the PIC16F1516 (same as the one on the SAVIC board) that can talk to the PS2 controller, a Nordic radio, and a character LCD. The radio and the controller share the SPI bus, but they have different settings for clock polarity and data sampling edge, so I have to switch the MSSP settings before I activate each one with its slave select line. Later I’ll use the LCD to show data coming back from the vehicle, but for now it was just used to help me work out the bugs with the PS2 controller. It turns out the analog sticks on these give pretty messy readings, even with the genuine Sony controller. To counteract this, I’ve added a bunch of processing that the analog readings go through to center them and to apply a logarithmic curve to the output. The code can also poll the controller for which mode it’s in, so it asks you to activate analog mode before it does the centering and starts transmitting.

This first try worked out so well that I will definitely stick with the PS2 controller for robots moving forward. I’m currently working on talking to a graphic LCD so I’ll be able to display images from a camera on the vehicle. Once that’s finalized, I plan to build an add-on that attaches to the front of the controller that contains a battery, radio, LCD, and the microcontroller to operate them all.

Here’s the code for the robot controller.

SAVIC board

I finally got my Semi-Autonomous Vehicle Integrated Controller (SAVIC) boards in from batchpcb. I used this project to learn to use Eagle to do layouts; it’s my first Eagle board and my first batchpcb order. I set out to design the SAVIC board so that I could quickly and easily get moving with small robots instead of custom building new stuff every time I wanted to try something new. This board is meant to include all the features you’d need to get started on a small robot or RC vehicle, and intended to be modular so it can be expanded upon. SAVIC has:
2 H-bridges for DC motor control
2 high-current sinks for single-polarity loads with PWM
2 servo outputs
2 analog sensor inputs
2 digital (switch) inputs
RGB status LED
nRF24L01 2.4GHz radio
HC-SR04 ultrasonic rangefinder connection
SPI expansion connection

I managed to pack everything into a 1.5x1.6 inch board. I had learned something about H-bridges from the board I originally used on the RC buggy. The P-channel FETs in that design had their gates switched by the drains of the N-channel FETs, so they were directly connected to the load. That worked for very small motors (in my 6” helicopter), but when I put a bigger DC motor on it, the inductive spikes ruined it. For the SAVIC board, I used bipolar transistors to invert the gate drive signals for the P-channel FETs.

The only issue I had with the first one I assembled was voltage limitations on the peripheral devices connected to it. I designed it to interface to HC-SR04 ultrasonic rangefinders because they’re so cheap and easy to find, but they have crippling supply voltage requirements. They don’t really work outside of 4.5-5.5V, where the PIC can run from 1.8-5.5V. The Nordic radios can’t go higher than 3.6V (but luckily the signal levels can be higher), and servos need 4-6V. On the board I put a 5V regulator to run all digital devices except the radio, which has its own 2.5V regulator. Servos pull tons of current when they move so I didn’t want to load the 5V regulator with them, so they’re powered directly from input voltage (as are the H-bridges). The problem is if I power the board with 6V, the 5V regulator doesn’t have enough overhead so the digital supply isn’t high enough to operate the rangefinder. If I go higher than 6V input, the servos get overvolted.

 The next revision will have to fix this somehow (probably by ditching the HC-SR04), but for now I’m running the board from 2 Li-Ion cells (8.4V) and putting a small adapter for the servo with an independent voltage regulator on it. One big advantage of this setup is that it overvolts the drive motor on the buggy like crazy, which gives it awesome speed and power.

I’m trying to transition to only working in C for robots, so I rewrote most of the functions I had already written for other RC vehicles. It’s programmed to used the same radio packets as the helicopter so I can use the same controller for both. The code has drivers for both servo outputs, bidirectional pwm for one motor, talking to the radio, and rangefinding. Once I got it operating well under remote control, I added an autonomous mode that just wanders around and avoids crashing based on data from the rangefinder. Autonomous mode is activated by a button on the controller, so I can switch between RC and auto on the fly.

Here’s code for the SAVIC board. Controller code will be in the next post.

Saturday, December 1, 2012

UAV part 3: C code

Huge UAV progress in the last week. I had figured out that a gyroscope was needed for stable flight (that’s how the stock control boards do it) and installed a gyro on my helicopter, but I wasn’t getting anywhere on coming up with an algorithm that would accomplish stable flight. I kept working in my old source file which was written in assembly and was attempting to write very complex math with 16 bit values (actually 17 bit for some signed values) and it became totally unreadable. After years of working with PIC I reached the point where I couldn’t accomplish the goal without switching to a higher level language, so I set out one day to get things working with the C compiler.

I had been told by many people (including a Microchip FAE) that switching over to C would involve a whole lot of frustration in order to get the whole toolchain working, but it turns out they were full of crap. It was ridiculously easy, and in about 3 hours I had rewritten the entire helicopter source code in C and had it running. I keep running into bugs caused by the way the compiler handles math involving ints (16bit) and chars (8bit) (which I’m often forced to work with based on EEPROM hardware, radio packets, etc.), but once you solve a few you figure out the tricks to force it to work the way you want. Admittedly writing in C creates machine code that is bigger and slower than assembly, so for my cost- and/or time-critical applications (like the ones I write at work) assembly is still the way to go. However, for hobby projects like these, the cost of the processor is meaningless (even something ridiculously overpowered is generally under $1.50), so I have the freedom to run complex code on an awesome processor. Luckily (i.e. as planned) the 16F1824 kicks ass and can run huge amounts of compiled C with no trouble.

Once I got a version of sAAV v3 rewritten in C, I could do experiments and improvements way faster, so sAAVinC (semi-Autonomous Aerial Vehicle in C) evolved pretty fast and I learned all kinds of things about making machines like these fly. The code has now departed quite drastically from what the old assembly source was doing. I have it running a control loop based on the gyroscope reading at 10Hz, and polling the radio for new control packets at 4Hz. After a whole bunch of test flights I arrived at a gyro feedback control algorithm that’s awesome.

It has a proportional term based on a ¼ second moving average (4 readings) and an integral term at 1/4th the gain of the P term. I put in a slow decay on the integral term to counteract erratic buildup. I also do a long (5-second) period of measurements upon power-up to calibrate readings from the gyroscope to establish a baseline of what a rotation rate of zero looks like.

The gyro loop got so good that I didn’t need to do yaw trim any more. With no trimming in the code at all, the helicopter would spin for the first second of flight and then the gyro loop would figure it out and stabilize. To get it even cleaner, I started initializing the gyro integral term to an experimentally-derived value that compensates for extra drag on the top rotor. This initialization is done any time the rotors are stopped for any reason (before I did that, if I was flying and then landed (and possibly moved the heli by hand) and then started flying again, the gyro integral would have been building up the whole time so when I throttled up, only one rotor would getting power).

Another funny thing that happened is the gyro loop was so good that when I tried to send yaw commands, the gyro loop would see the turn as a disturbance and compensate for it, aiming back to the heading it started at. My solution was to remove the yaw command term from the rotor output calculation completely, and instead inject it into the calculations for the gyro P and I terms. Effectively what this accomplishes is: when a yaw command is sent, it makes the gyro loop think the vehicle has turned in the opposite direction, so the gyro loop does its job and counteracts it by turning in the direction the pilot wanted.

In order to make the controller more generic (to use with other vehicles), I moved the math that interprets joystick inputs over to the helicopter. Now, the controller essentially just sends the stick position and button information and the vehicle decides what it means. I’m still doing the same throttle algorithm where pushing the stick up and down adds or subtracts from the current throttle value at increasing intensity as the stick is angled farther from center. I also wrote an update for the controller that puts it into sleep mode so I don’t have to pull the battery when I’m done using it. The last control update was to have the helicopter gradually change to new pitch values (on the tail rotor) instead of changing instantaneously. This came after I kicked on the tail rotor while turning and caused the helicopter to roll and crash spectacularly, breaking the tail fin and tail rotor. Now, when I click the joystick in to toggle forward movement, the tail rotor speed gradually ramps up over a period of about 3 seconds.

The other items I put in the helicopter code are a low-power standby mode and some tones (played on the motor coils) to indicate things like power up, gyro calibration complete, paired with controller, loss of control link, and entering standby.

So now I’m at the point where I have control that’s just as good as the stock helicopter, but running on completely custom code and using a 2-way 2.4GHz radio link instead of infrared. The next steps are to build a more involved controller that will be better able to help develop autonomous functions, and to install ultrasonic altitude sensing on the helicopter. My weight is currently at 39g (stock weight is 42g). I plan to put double-capacity battery on that will bring the weight to 43g, and when I add ultrasonic I’ll strip down more of the metal framework to keep the weight at or below stock.

Here’s a video showing how good the control is. As far as I know, this is now the only Syma S107 in the world that is radio controlled, meaning I don’t need line of sight and I can fly outside in sunlight, which I’ve been wanting to do for so long. The second video shows an outside flight, which is fun because there’s nothing to crash into but difficult because the slightest breeze just carries it away. As you can see, the range on the radio is more than enough to fly so far away that you can’t see it well enough to fly anymore.

Here is the most recent code for the helicopter and the controller.

One more thing: if you have one of these helicopters, take the yellow USB battery charger and throw it in the garbage. I discovered recently that it significantly overcharges the lithium cell, leading to extreme danger of explosions and fire. It actually blew up two small hobbyking cells that I tried to charge with it, after it pushed the cell voltage up to 4.6V. Do yourself a favor and buy one of these chargers (but you should probably replace R2 with something around 5k to set a safe charge current).