Wednesday, November 28, 2012

Test flight with attitude stabilization

See the video here

After the hardware was "completed", I was finally able to focus on the software side of things. The linked video shows the first test flight of an attitude stabilizer, that will later on become my autopilot.

I mounted the navigation board and my RC receiver v2 (both discussed in previous posts) on my Graupner Elektro Rookie plane (I'll be later moving this stuff to my Skywalker, but I want to make sure everything works before I do that).

A simplified description of how the stabilizer works:

  • The RC transmitter is used to set target roll and pitch angles (aileron and elevator sticks).
  • The navigation board reads measurements from a gyroscope and a magnetometer, and uses those measurements to track the plane's attitude.
  • The RC receiver reads the attitude from the navigation board and compares the measured roll and pitch angles to the target roll and pitch angles. Ailerons and the elevator are then adjusted to correct for the error.
The sensor fusion algorithm used in the navigation board is explained in a previous post. The attitude control itself is done just by a P-controller (which was set for too much gain in the video). I'll probably be adding a derivative term as well, just to get a slightly faster response to turbulence. I'm guessing I won't be needing an integral term though, as I'm relatively sure the steady state errors in the roll and pitch will not be significant compared with other navigation errors.

Now to implement an autopilot, all I'll have to do is to change the way I set the target roll and pitch. I'm again planning on using just a P-controller at first. As the plane is (I hope) mostly flying quite level, the roll and pitch angles correspond with changes in heading and changes in altitude respectively. A GPS receiver, which is already on-board, provides the heading of the plane. The target heading (to the next waypoint) is computed and the roll angle is set according to the heading error. The same thing is done with the altitude and pitch angle. An important caveat, however, is that the roll and pitch angles should be kept relatively small even if the heading or altitude errors are large. I plan to address this by simply having a fairly low saturation value for the target angles.

Tuesday, November 27, 2012

Navigation board build

As I explained in a previous post, I want the plane to be able to track its attitude. The receiver is already doing a time critical function in software (namely the servo updates), so it would be quite a strain on it also to read all the different sensors and to filter the data. I thus ended up building these functions on a separate board, which interfaces with the receiver through UART.

The IMU module I ended up using
The IMU sensor board I'll be using has a gyroscope, a magnetometer and an accelerometer. The sensors are all read through I2C, which is nice as the microcontroller I thought of using (Atmega328) has built in I2C hardware support. However, in addition to these three I2C sensors, I need also to connect a GPS receiver. This presents a problem, because the microcontroller only has one hardware UART, and that is already in use for communication with the receiver. I could change my choice of microcontroller, to something that has two hardware UART ports. On the other hand, I could go with a software UART as I already have several Atmega328s in my components bin. I decided on the cheaper option, and went with an Atmega328 and software UART. I was fairly certain that this choice would bite me in the ass later on (which it did, in the form of timing issues in the code).

I ordered the IMU board from ebay and was so eager to get this thing built as fast as possible that I took measurements of the board dimensions from the photo on ebay and started the design. The board is very straightforward and there is nothing special about it what-so-ever, as can be seen in the schematics and the layout.
Unfortunately I screwed up measuring the dimensions from the photo, and as a result the mounting hole of the IMU board doesn't match up with the hole on my board. It doesn't really matter, as now I just hold the board steady with double sided tape :-).

Top side of the board after etching and drilling.

Bottom side of the board after connecting the vias
I have recently investigated the possibility of doing through hole plating for the vias, but it seems to be quite a bit more involved than what I'm currently doing. I guess I'll have to continue soldering short pins through the vias to connect them.

Top side almost completed
The hardware UART port is used to communicate with the RC receiver whereas the software UART port connects to the GPS receiver. I put in the external I2C port for the possibility to add a barometric pressure sensor later on, although now you can buy cheap sensor boards that already contain a pressure sensor.

Bottom side almost completed

While assembling the board, it turned out I had run out of 20 MHz crystals. I picked up some the next day, but I didn't take new photos of the board.

Tuesday, October 9, 2012

Inertial measuring experiment

I just posted a video on YouTube, and wanted to comment on that shortly.

What I did was that I connected my navigation board (more on that in a post later) to my receiver. The receiver was sending data from the navigation board down as telemetry, which I recorded. At the same time, I also recorded video using an 808 #11 key chain camera. As the actual test, I just walked around our house holding the device in my hand and pretending it was a space ship.

Here is a picture of the sophisticated sensor instrument:



I used MATLAB to produce a visualization of the measured attitude. This visualization was then synchronized with the video and overlaid to produce the clip uploaded to YouTube. The whole visualization process is very naive, but as a first try it'll do :-).

Saturday, October 6, 2012

Attitude inference

In my grand plan of things, I want to infer both the attitude and location of the plane. Location is somewhat easy to figure out thanks to GPS, but attitude is really a problem. Now, you might think that using an accelerometer or an inclinometer would be the solution. Unfortunately this is not the case, and the reason for this is very closely related to the so-called pendulum rocket fallacy.

The fact that accelerometers can be used to infer the orientation of a cell phone follows directly from the fact, that you can (for the most part) assume that the phone is held stationary in a users hand. The moment this assumption is no longer true, you can't directly measure the direction of gravity. To me this was quite a difficult thing to understand. My intuition originally was that you could always measure gravity as you did in the cell phone. It wasn't until later, when I did a simulation of the attitude measurements, that I realized the acceleration measurements didn't give any information on the direction of gravity. Anyway, if you don't believe me on this, there are some good explanations out there.

Okay. So how do you know which way is up? Very few methods allow you to measure your absolute attitude directly. Many of the methods give you only a part of your attitude and you have to combine many methods, to get your absolute attitude (roll, yaw, pitch). An incomplete list of possible methods:
  1. Guide stars. This is the only method I can think of right now which will actually give your absolute orientation. It only works at night. Requires you to know where you are and what time it is (GPS). Very difficult to measure.
  2. Horizon measurement. This could be either optical or thermal. Thermal works also during night, but not as well in the winter or in heavy overcast conditions. Can at most give you roll and pitch. Combined with GPS heading readings will give full absolute attitude. Sensors are quite expensive. Easy to measure.
  3. Earth's magnetic field measurements. Gives two components of the attitude. On the magnetic poles these components will correspond with roll and pitch. Combined with suitable other means of attitude inference can give full absolute attitude. Easy to measure.
  4. Polarization of the sky. Can be used to infer the components of the attitude, if you know where you are and what time it is (GPS). Combined with e.g. magnetic field measurements can give absolute attitude. Difficult to measure.
  5. Gyroscopes. Gyroscopes can be used to measure the angular velocity at which the plane is rotating. Hence they give you the changing rate of attitude. If you knew your attitude at start, and you had a perfect gyroscope, you could track your changes in attitude and thus know your current orientation. Unfortunately, there is no such thing as a perfect gyroscope (plus you'll have integration error anyway) and you end up with a drift. However, the drift can be quite low even with cheap solid state gyroscopes (in the order of a fraction of a degree per minute). Combined with e.g. magnetic field measurements can give absolute attitude (with a caveat). Easy to measure.
I want to only do easy stuff, so I can only really consider horizon measurement, magnetic field measurement and gyroscopes. Horizon measurements are a bit on the expensive side, and they also have problems during overcast conditions and winter (which sums up to about 90% of the time in Finland), so I'll have to go with magnetic fields and gyroscopes.

As luck would have it, some nice Chinese folks are selling small IMU boards on ebay. They have everything I need for attitude measurement, as well as an accelerometer :-).

Let's begin with the first thing. How to represent the attitude of the plane? The first thing that comes to mind is the classic roll, yaw, pitch formulation, also known as Tait-Bryan angles, or improper Euler angles. This formulation is ultimately the form I would like to look at the attitude, so it would make sense to store them internally in this form as well. This formulation however has a nasty feature known as gimbal locking. Also, the differential of the rotation has a form, which is heavy on computation (a lot of trigonometric functions, that would need to be evaluated at each time step). So this is not the way to go. I hate to say it (because I've been against the idea in the past), but a better solution is to use Euler rotation parameters, also known as unit quaternions. This formulation is minimal on computational complexity and it easily converts to Tait-Bryan angles when needed. See these lecture notes (starting from about lecture 7) for a very good tutorial on different rotation formalisms and their uses. Wikipedia also has an article about this, but it is not as good in my opinion.

The most important reason for using the quaternion formulation of rotations is the absolute simplicity of the rotation time derivative. It is given simply as
,
where q is the rotation quaternion, \omega_x, \omega_y and \omega_z are angular velocities, which are measured by the gyroscope and the \otimes is the quaternion product. Using explicit Euler integration, a pseudo code implementation of a rotation update given the instantaneous angular velocity measurement (wx, wy, wz) is

updaterotation(wx,wy,wz) {
   /* old rotation defined by rqs, rqx, rqy, rqz
      length of time step dt */
   rqs_up=rqs+dt*0.5f*(-rqx*wx-rqy*wy-rqz*wz);
   rqx_up=rqx+dt*0.5f*(+rqs*wx-rqz*wy+rqy*wz);
   rqy_up=rqy+dt*0.5f*(+rqz*wx+rqs*wy-rqx*wz);
   rqz_up=rqz+dt*0.5f*(-rqy*wx+rqx*wy+rqs*wz);
   /* normalize the quaternion */
   rqinvnorm = 1.0f/sqrtf(rqx_up*rqx_up+
                          rqy_up*rqy_up+
                          rqz_up*rqz_up+
                          rqs_up*rqs_up);
   rqx=rqx_up*rqinvnorm;
   rqy=rqy_up*rqinvnorm;
   rqz=rqz_up*rqinvnorm;
   rqs=rqs_up*rqinvnorm;
}

That takes care of integrating the angular velocity measurements to approximate our attitude. Now to get rid of the gyroscope drift by using measurements on the absolute direction of the magnetic field. As I only have very limited computational power on board, I had to come up with a really simple way to correct for the drift. I originally wanted to do something along the steps of the extended Kalman filter (extended Kalman filter because it was the least computationally expensive non-linear flavour I could think of), but it would end up using quite a deal of memory since in addition to the current best estimate of the attitude, the covariance matrix of the estimate must also be stored. Most of all, it would also use quite a bit of CPU time, since for each update we need to solve a general 3 unknown linear equation. It probably would work though, but I didn't want to go through the hassle of testing how close it would be.

What I ended up doing can in some sense be explained as approximating the extended Kalman filter, by using a constant scalar covariance for the states. More precisely I did the following. When the plane is in its starting position and we know its attitude, we take a measurement of the magnetic field. This magnetic field direction, as well as the initial attitude, are stored. In the future, since we know what the magnetic field was at the initial attitude, we can compute what the magnetic field should be if we knew our attitude. Let's call the magnetic field measurement m, the actual attitude q and the function which connects the two h. Hence


However, we don't know our actual attitude, we know only an estimate q_est, so in general


As the equality should hold for the correct attitude, it would make sense to change the estimate so that the equality would hold. This however is not a good idea. The solution to the equation lacks uniqueness, and even if we had uniqueness, any measurement errors in the magnetic field would be amplified. In addition, the exact solution takes a lot of computational power, which we don't have. What we do instead, is that we simply take a small step in the negative gradient direction. If you don't know what that means, it just means that we change the estimate only by a little amount, but so that the new estimate is slightly better. The update is then


where \alpha is a relaxation parameter, which defines how long the steps should be that the algorithm takes. The lower the value, the slower the estimate converges. The higher it is, the more unstable the update is.

The algorithm to correct for a magnetic field measurement (mx, my, mz) in pseudocode
correctrotation(mx,my,mz) {
   /* old rotation estimate defined by rqs, rqx, rqy, rqz
      north direction in initial coordinates is gmx, gmy, gmz. */
   /* compute difference between estimated and measured north direction */
   mx_diff=mx-(+rqs*(gmx*rqs+gmy*rqz-gmz*rqy)
               +rqx*(gmx*rqx+gmy*rqy+gmz*rqz)
               -rqy*(gmz*rqs+gmx*rqy-gmy*rqx)
               +rqz*(gmy*rqs-gmx*rqz+gmz*rqx));
   my_diff=my-(+rqs*(gmy*rqs-gmx*rqz+gmz*rqx)
               +rqx*(gmz*rqs+gmx*rqy-gmy*rqx)
               +rqy*(gmx*rqx+gmy*rqy+gmz*rqz)
               -rqz*(gmx*rqs+gmy*rqz-gmz*rqy));
   mz_diff=mz-(+rqs*(gmz*rqs+gmx*rqy-gmy*rqx)
               -rqx*(gmy*rqs-gmx*rqz+gmz*rqx)
               +rqy*(gmx*rqs+gmy*rqz-gmz*rqy)
               +rqz*(gmx*rqx+gmy*rqy+gmz*rqz));
   /* update rotation based on measured north direction error */
   rqs_up=rqs+alpha*(+mx_diff*(+gmx*rqs+gmy*rqz-gmz*rqy)
                     +my_diff*(-gmx*rqz+gmy*rqs+gmz*rqx)
                     +mz_diff*(+gmx*rqy-gmy*rqx+gmz*rqs));
   rqx_up=rqx+alpha*(+mx_diff*(+gmx*rqx+gmy*rqy+gmz*rqz)
                     +my_diff*(+gmx*rqy-gmy*rqx+gmz*rqs)
                     -mz_diff*(-gmx*rqz+gmy*rqs+gmz*rqx));
   rqy_up=rqy+alpha*(-mx_diff*(+gmx*rqy-gmy*rqx+gmz*rqs)
                     +my_diff*(+gmx*rqx+gmy*rqy+gmz*rqz)
                     +mz_diff*(+gmx*rqs+gmy*rqz-gmz*rqy));
   rqz_up=rqz+alpha*(+mx_diff*(-gmx*rqz+gmy*rqs+gmz*rqx)
                     -my_diff*(+gmx*rqs+gmy*rqz-gmz*rqy)
                     +mz_diff*(+gmx*rqx+gmy*rqy+gmz*rqz));
   /* normalize the rotation */
   rqinvnorm = 1.0f/sqrtf(rqx_up*rqx_up+
                          rqy_up*rqy_up+
                          rqz_up*rqz_up+
                          rqs_up*rqs_up);
   rqx=rqx_up*rqinvnorm;
   rqy=rqy_up*rqinvnorm;
   rqz=rqz_up*rqinvnorm;
   rqs=rqs_up*rqinvnorm;
}

These algorithms are easily light enough so that they can run on a low-end microcontroller, such as the ATmega328, over 200 times per second. In my tests, even after a long period (hours) of rotating the sensors around, the accumulated error is in the order of 5 degrees, which is about the accuracy of the magnetometer. However, I haven't as of yet done any in flight tests. I'm a bit worried of how much the large currents of the motor affects the magnetic field measurements.

Friday, October 5, 2012

Receiver v2 hardware design & build

As of this writing the receiver v2 is still somewhat of a work in progress, but the design of the main hardware is mostly done. In this new revision I wanted to address a couple of issues that I had with the old receiver, mainly that the old receiver was large, heavy, fragile and complex. The new receiver was thus supposed to be small, light, sturdy and simple :-). I also wanted to finally implement antenna diversity, which I never got around to do in the old receiver. In addition, I decided to dump the analog inputs altogether in favor of an external battery management board connected via I2C and to only have 8 servo channels.

The target size was 2 x 1 inches, which is about the footprint of the regular commercially available receivers. I originally hoped to get everything to fit on one board of that size, but it soon became apparent that if I were to manufacture the board myself using photoresist methods (two-sided this time, however), I would need to split the design in two. I might still do a single board version of the receiver, which could be manufactured by a commercial board manufacturer, for instance through ITEAD studio and their cheap prototyping service. Anyway, the boards of this new design are simply
  1. Connector board (schematic, layout)
  2. Main board (schematic, layout top, bottom, both)
The connector board is completely passive. As its name suggests, it only contains connectors. It mounts on the main board through a pin header and breaks out the servo connectors as well as I2C and UART.

Like before, I didn't want to buy too many parts specifically. So, many of the choices of components were dictated by what I had in my collection. In the end, I only had to order the AS169 antenna selector switch. A local electronics store Partco offers a quasi-cheap way to order a low quantity of components from wholesalers like Farnell. Normally for small orders Farnell would charge a fixed price for shipping and handling, which is in the order of tens of euros. Partco makes larger orders once per week, which make the handling fees more reasonable per item. It still ends up costing me around 25-50% more per component than if I ordered in bulk, but as we're talking about a couple of 0.50€ components for prototyping, it doesn't really matter.

For the RF design, as I am working with 868 MHz (~345mm) and the RF signal path lengths on the board are in the order of 20 millimeters, I was confident I didn't need to worry about impedance matching. Assuming perfect ground, the characteristic impedance of the signal paths would be around 75 ohm, which is way off the target of 50 ohm.

I took some photos along the way, as I was assembling the main board

Bare board, bottom side. Right after drilling and removing the photoresist.
The board looks covered in holes, but those are actually drops of water.
This board was my second ever two-sided board. The first was a success, so I was not too worried about this one.

Top side, with vias soldered in place.
Getting via holes copperized is something I don't know how to do at home. I understand that in commercial fabrication they actually begin (I mean even before applying the photoresist) by drilling the holes and then building a copper layer inside the holes by electrochemical methods. What I do is I push a copper wire through the via hole and cut it almost flush with the board. It leaves quite a bump on the board after soldering, so I can't have vias under components. This makes the board quite a deal bigger than what it could be.

Top side. Much of the components soldered.

Bottom side. Everything except the pin header and output series resistors in place.
As I got most of the stuff in place I tested that I could talk with the processor. This was just to make sure everything was working correctly before attaching the radio module, which is the most expensive component in the board by a factor of two. In the pictures, along with the radio module the top side is also missing the antenna selector switch, which I had to order specifically (I didn't have a hand-solder friendly version in my junk box). The bottom side is still missing the large female header as well as output channel protection resistors. I didn't want to end up killing the receiver if I accidentally shorted the servo connectors or if I plugged them the wrong way around. They limit the short-circuit current to the absolute maximum rating of the processor GPIOs. None of the servos I am using seem to have any ill effects due to the resistors or due to the fact that the signal fed to them is only 3.3V high. Getting rid of the resistors and instead being really careful, or using 0603 size instead of 0805 could help make this board still smaller, if I ever go for that.

Top side. Everything except for the antenna selector switch soldered.

Bottom side. Everything in place.
Here the board is otherwise complete, but I'm still waiting for my order of the antenna selector to arrive. I also haven't yet attached the antennas.


While waiting for the antenna selector, I assembled the connector board and tried it on. The two white connectors in the picture below are (from left to right) the I2C interface and the UART interface. The I2C is for connection to a battery management board, which will contain a high side battery current and voltage measurement IC (I found a suitable one from Texas Instruments, but haven't yet ordered it). In the current plan, the UART will be used to interface a navigation board that infers the attitude and the position of the plane (or other platform) from inertial measurements (gyroscopes), Earth's magnetic field (magnetometers) and GPS. More on that in a later post.



Connector board is completed and tested on.

View from the back.

The receiver is looking pretty good. I'm a bit worried about the strength of the connection between the main board and the connector board. My plan is to stick the connector board down to the main board with double sided foam tape. That way there is less stress on the header.

A close up, now with the antenna selector and the antennas connected.

The AS169 comes in a SOT-23-6 package,
which is among the largest cases for these things.

The antennas are just RG-174 coax, which have ~1/4 wavelength (82 millimeters) of the shield stripped at the end. These are by no means optimal antennas, and it is something I still need to look into. The idea anyway is to have one of the antennas vertically polarized and the other horizontal. This way I'm hopefully less likely to lose the connection due to orientation, or at least have less variation in the received signal strength. However, there still will be an orientation at which both of the antenna polarizations are orthogonal to the transmitter antenna. This is probably just a theoretical problem of ideal antennas, since with my old receiver I've been flying with just one vertically polarized antenna at a distance of 1.5km without any problems. Another choice would be to go with circular polarized antennas, but the size of them at 868 MHz seems a bit intimidating.

The bounding box of the entire assembly (not including the antennas) is approx. 51 x 26 x 22 millimeters. A plastic case would be very nice. I'll probably investigate getting one printed at Aalto University's fablab in the near future.

Tuesday, October 2, 2012

Receiver v1 after a year of flying

I found a set of pictures I had taken of my old receiver a couple of months ago, from around the time I switched to using my new receiver. The poor thing has gone through multiple hard impacts, which have resulted in torn and bent connectors and cracked solder joints. It has been through the rain and the snow. For all practical purposes however it still works today. I think I'll keep this one in my Elektro Rookie after I finally get my Skywalker in the air.

Top view. The sharpie markings used to read "5GS" to remind me of the incorrect pinout
You can see the deformations left behind by multiple crashes
The microcontroller (Atmel Atmega168)
A bodge wire routes 5V to the GPS. The original design had it connected to the 3.3V regulator
There is no antenna connected to the receiver in these pictures. I can't quite remember what I had done with it or why. Right now it has a 1/4 wave whip (that's just a wire about 82 millimeters long) connected and it works great.

Transmitter v1.5

After flying with my transmitter v1 for about 4 months, I thought it was time to upgrade. The biggest reason being that the PlayStation joysticks I ended up using were closer to digital than analog. What I mean by this, is that the joysticks had a very large dead zone and also the control saturated quickly. Moving the stick from the center to the right would change output for the first 1/3 of the range. It would then give a nice proportional output 1/3 of the range after that, and the last 1/3 of the range would again not change the output any further. This was not that big of a problem with an airplane, but I wanted eventually to fly also multicopters and I thought this was something that would really cause problems with them. Also, the way you trimmed the control in the old interface was horrible and I wanted to change that.

Randomly browsing through DealExtreme I came across this. That looked like something I could use! I would just remove all the electronics that were already in and replace them with my own. It would even have mechanical trims in place. Sure it was a bit on the expensive side, but the whole idea of building my own transmitter to save money was long gone anyway.

After a couple of hours of tinkering, I had removed the digitizer and transmitter boards from my old transmitter and moved them in the new enclosure and everything was working well.
Inside the transmitter it's a big mess of wires.
Front view of the transmitter. That antenna sure looks suspicious...
I originally used a small rubber ducky antenna with this transmitter and I never had any bigger problems with that during a couple of months of flying. I was planning to do FPV in the near future, however, and wanted to be sure my transmitter could do at least 1 kilometer. So I did what any sensible person does: I designed and built a 10dBi gain Yagi-Uda antenna and hot glued it to the back of the transmitter.
It is very awkward to carry this thing around. Flying with it is no problem though.
Based on RSSI (receive signal strength indicator) data sent in the plane telemetry, the antenna adds around 9 dB to the signal strength (so only 1dB less than what it was designed for), which is surprising considering it is made of scrap brass tubing, a couple of scrap pieces of pine and a lot of hot glue. Also the only sufficiently long piece of 50 ohm coaxial cable I could find in my scrap heap was RG-58, which I would not really consider ideal for the job. Like half of the stuff I do, this was first made as a prototype, which was to be refined later. But like always, this later never came and I was stuck with the prototype. And range wise, I've never run out of range with this thing. A simple extrapolation (with 5% packet loss) from the RSSI and range data of the telemetry would suggest a 6 km range at 100mW transmit power.

Monday, October 1, 2012

Transmitter v1

I had a receiver and I knew from testing it with my USB radio dongle, that it in fact worked. Now I needed a transmitter. So... you need two joysticks, a couple of buttons and that's it. Perhaps an LCD and a menu system later on for configuring and swapping models.

I was first considering using a ready made game controller, specifically one made for the Sony PlayStation. These were fairly cheap and readily available, and there were previous projects in which people had interfaced them with microcontrollers. I can't remember why I chose not to go with those. I guess it had to do with price.

I found thumb joysticks similar to those on the PlayStation controllers for a fairly cheap price on Sparkfun. They also provided the schematic symbol and the footprint of the component for CadSoft EAGLE, which made my work a lot easier. So I ordered a couple and made a couple of break-out boards for them (see schematic, layout). The 8 pin DIP in the board (misleadingly labeled IC1) is the 8 pin ribbon cable connector I was using.

The break-out boards are then to be connected to a digitizer board, which contained a microcontroller and would do the analog-to-digital conversion to read the position of the joysticks and would then communicate with the actual transmitter board via a serial link (see schematic, layout). Again, the 8 pin DIP parts in the board are the ribbon cable connectors.

I put the two joysticks and the digitizer in a plastic case, that was a nice size to hold in your hands.
The thumb joysticks use ribbon cables to connect to the digitizer, which in turn is connected to the PC via a RS232 serial link through a level shifter board I had made earlier (notice the bodge wire in the level shifter).
I guess I'm developing the digitizer software in this picture. Also, my bench is a mess.

Completed joystick and digitizer assembly on the dining room table, with some miscellaneous crap. 

The transmitter board itself was a bit more complicated, mostly because I wanted to add an extension port to it. I was planning on extending the two board design into a larger one, where I'd have an LCD and a menu system working on that. This never came to be, so most of the effort designing the more complex transmitter board was a waste (see schematic, layout). Both the transmitter and the digitizer use a 3.1V low-dropout regulator to be able to operate from a single lithium-polymer cell (and also because I happened to have a hundred of such regulators).
The transmitter board has just finished etching.
This picture was taken before removing the photoresist.
Top view of the transmitter board
Bottom view of the transmitter board
The software on the transmitter board basically does the following in an endless loop:
  1. Request a measurement from the digitizer board
  2. Wait a certain time for the digitizer board to respond
  3. Check integrity of received measurement
  4. Transmit packet to receiver over radio
  5. Wait a certain time for the receiver to respond over radio

It the digitizer doesn't respond within the window, a default (fail safe) control is sent. This is also the case, if the integrity of the measurement cannot be validated. I've actually never had the control fail due to problems with the transmitter, but the fail safe actions are still good to have there in place.

While the joysticks and digitizer did get a nice enclosure, the transmitter board wasn't so lucky. I ended up putting it inside an Orthex freezer container together with the battery I used to power the whole thing. Prior to operation, you'd have to put the box very close to your face (~1cm) to see if the green power LED was flashing inside the container. Any further away and the sun would prevent you from seeing the light. The whole process of using that transmitter was silly-looking.

And talking about silly, as I had never flown a model when I was designing all of this, I completely overlooked how important trimming the controls were. To set the trim on the left stick, you would move the stick so that control surfaces corresponded to your new zero, then you would tap the right stick. To trim the right stick, you would just do the same, but with sticks reversed. This effectively made it impossible to trim while in flight. I tried it a couple of times, and each time it ended badly. What I ended up doing, was I coarsely trimmed the plane on the ground, only eyeballing the control surface positions. In the air I would then just compensate. Even though I have proper trims on my current revision of the transmitter, I still tend to do this.

Probably the weirdest RC transmitter you've seen in a while.
Notice the strip of packing tape keeping the two halves together.
It turned out that the PlayStation thumb joysticks have a large dead zone and also their usable range is not to the very edge, which leaves them with quite a limited dynamic range, which I don't think is a very good thing for RC (especially multicopters). However, I did learn to fly my first plane (the Graupner Elektro Rookie) with this transmitter and it worked without any real problems. It might have been a bit easier to get a hang on things with a real transmitter, especially due to trimming the controls being very difficult.

The transmitter board and the digitizer board are still in use in my transmitter v1.5, which is what I use today. Basically I just changed the joysticks for something a bit nicer. I will write an article on that upgrade. However, I'm currently in the process of completely redesigning the transmitter to have support for an antenna tracker, a head tracker and most importantly: a ground-based OSD to my FPV video feed.

Sunday, September 30, 2012

USB telemetry receiver & rant about flux residues

I'll be covering this here before I write the article of my transmitter, because this thing was actually built long before the transmitter. The first tests of my receiver were in fact done using this device acting as the transmitter.

I needed a nice way to debug all the radio stuff I was doing in the spring of 2011, and the whole thought of hassling with serial ports gave me a headache. I had known for quite a while of a bit-banging USB solution on low-end 8bit Atmel microcontrollers, called the V-USB. I had been eager to try it, but I never really had a need for it, until now.

So, the vision was a USB dongle which could be used to receive and transmit packets easily through the radio module. In addition to help with debugging, I needed it to act as a PC interface to my other projects, such as home automation. Using it as a telemetry receiver, however, didn't come up until quite some time later, but as things turned out that's what I use it for mostly these days.
Bottom side view

Top side with a rubber ducky antenna in the SMA connector
The whole thing was supposed to be very simple. I Just copied the reference design of V-USB, attached a radio module through the SPI port, wrote up some software and I thought I was done (see schematics, layout). There were a couple of problems, which made things a bit more difficult.

  • ICSP and radio share SPI
  • Missing bypass capacitors
  • Flux residues
The radio module was attached to the microcontroller through SPI and will act as a slave device, which means it will listen on MOSI and talk on MISO. The microcontroller of course acts as a master device when talking to the radio. However, the microcontroller is programmed through the SPI port and will act as an SPI slave device during this time. Meaning it will too listen on MOSI and talk on MISO. Since both devices are talking on the same line at the same time, we have a conflict and the programming fails.

Okay. It's not like I didn't think of that when I was designing the board. The thing is: the radio will only talk on the MISO line if its slave select line is pulled low. As the microcontroller is being programmed, it should release the slave select line and a pull-up resistor should deselect the radio. For some reason this does not always happen, of which I'm still unclear why. Anyway, in all of my later designs I added a jumper, or some other method, which can be used to disconnect the radio from the SPI bus. This problem didn't very much affect the usability of the dongle, because it can be programmed through USB anyway. The SPI programming was only used a couple of times at first, just to get the USB boot loader programmed.


I'm not sure if it ever caused any issues, but inspecting the board later on I noticed, that I had completely forgotten about the chip level bypass capacitors. There is only one capacitor on the output side of the 3.3V regulator. I bodged a couple of small ceramics between tracks, to make sure that insufficient bypass was not an issue.

What turned out to be a real problem was flux residue. You would assume flux used in electronics solder is non-conductive, right? Wrong! I'm pretty sure it depends on the type of flux, but whatever is in my soldering paste (I think it's just kolophonium) is a bastard. The problem is that the flux flows between the radio module PCB and the main PCB as well as between the microcontroller package and the main PCB, and causes "shorts". Of course they are not zero resistance shorts or anything, but they present a significant finite resistance, which changes rise times of especially the very weak drivers of the radio module (I think they are in the order of 1mA max.). Now, getting rid of the flux residues is a real pain in the ass. Kolophonium is not really soluble in water. It is supposed to be soluble in isopropanol, but even after keeping the boards submerged in isopropanol for a full day, the residues are still there. I tried:
  • water & soap
  • isopropanol
  • commercial flux cleaning agent (smells and looks a lot like soapy water)
  • ethanol
  • acetone
  • turpentine
  • paint remover
And I'm happy to report that paint remover works amazingly well! Anything else on that list is not really worth the effort. The stuff I was using is something called Nitromors, but I've heard that many other paint removers work well too. This one has dichloromethane listed as the active ingredient and is a gooey consistency. Next bottle I buy, I'll probably go for something that's a bit easier to wash off.

Receiver v1

In the summer of 2011 I decided I had played around sufficiently with the radio modules and finally decided to continue with my project to build the RC radios. I ordered a kit of Graupner's Elektro Rookie as my plane. It came with a brushless motor and a speed controller (at first I had plans of building my own speed controllers as well, but realizing how cheap they were, I didn't bother).

I had no idea how big the space for the receiver was inside the Elektro Rookie, so I had to wait for the plane to arrive. I was surprised of the amount of space there was, but of course it was still quite small.
Horrible picture to illustrate the space for the receiver

Hardware

I was planning on making the boards at home using the standard photoresist method, and at that time I didn't really have the possibility of making two sided boards, so I decided on having multiple one-sided boards with interconnects. This way I could make each individual board have quite a small outline, but still fit all the stuff I needed. I ended up splitting the functionality to three boards as follows:
  1. External connectors & voltage regulation (schematics, layout)
  2. Processor (schematics, layout)
  3. Radio (schematics, layout)
One idea behind doing the split this way was that I could upgrade just the radio board later to get antenna diversity. I'm still not sure how useful antenna diversity really is, but the commercial radios have it implemented, and as I can add it with almost no extra cost then why not.

The connector board ended up having 9 servo channels, a UART channel, two analog channels and an external power connector which would be used to power FPV gear. I decided on 9 channels because that was the largest amount I could still easily fit on the board.

Most of the components I used were already in my parts bin. It was mostly stuff that I had bought before at a bargain price or stuff I had salvaged out of old electronics. Very few parts I actually had to buy specifically for this project.

An almost completed assembly of the connector board and the processor board.
BTW, it's annoyingly difficult to solder pin headers on the wrong side of the board...
Fully assembled receiver under the first tests.
The receiver in its designed place. It's a snug fit.

Since the radio module I was using (RFM22B @ 868MHz) is a transceiver, I could trivially have telemetry. I wanted to have at least a GPS receiver on board as well as voltage and current monitoring.

I had bought a bunch of GPS receivers some time before at a local electronics store for 10€ a piece (still the best price for GPS receivers I've seen!), which communicate at logic-level RS232. This was very nice, because the microcontroller I chose to use (Atmel's ATmega168) has a hardware UART, which directly supports the output of the GPS. Also, if I wanted, I could use the UART for adding additional sensors.

The voltage measurement was done just by resistively dividing the battery voltage to the range 0-1.1V and then measured against the microcontrollers internal 1.1V reference. The resistor divider was not included on the board to give a bit more flexibility.

Current measurements were initially done using a 1:5000 Hall-effect current transducer, which was salvaged from an old HVAC variable-frequency drive. The output was converted as a voltage in the range 0-1.1V and fed to the ADC of the microcontroller. The current transducer was quite heavy, so I just quit measuring current later on.

If you look closely at the connectors in the connector board, you'll soon find the first problem I encountered. I didn't double check my reference for the pinout of the servo connectors, so I was bound to get it wrong. Turns out I ended up using an Airtronics pinout rather than the more common Futaba/Hitec/JR. I think part of the mix-up was that I thought it to be obvious that the ground pin should stay the same even if the connector was reversed. Oh well, I just had to rearrange the pins on my servos (the connector pins are easily removed by using tweezers to release a locking tab and pulling on the wire).

The second problem was that even though I had two separate power connectors for powering the processor and radio (and four separate ground connections), I still had a brownout during almost every flight. These brownouts were so short that you could not really notice them in flight (at least I couldn't, but then again, I had never flown before). I only discovered them after reviewing telemetry from the plane. I changed the GPS VCC to the 5V rail instead of the regulated 3.3V to reduce the loading on the regulator. I also added 100 uF of additional capacitance to each of the three boards and the problem went away.

The third problem was that I needed to take off the radio board every time I wanted to program the processor board. This was originally by design, because the radio uses the same SPI-bus through which the programming of the processor is done. Anyhow, over time this constant disassembling and re-assembling of the board stack became extremely frustrating. I solved this by soldering an additional connector for debugwire (Atmel's in-circuit programming and debugging protocol that goes through the reset pin of the microcontroller) onto the processor board. This was quite of a kludgy solution, but it did fix the problem and didn't cause new ones.

The heavy three board design turned out to be quite susceptible to damage in crashes. The solder joints easily cracked, which wouldn't be too easily noticed. This became obvious during a couple of weeks, when a bad connection together with an incorrectly handled error condition in software caused a complete control lock-out and quite bad crashes. It wasn't until one particular crash, after which the electronics still remained powered on, that I could finally debug what was happening and understand the issue.

Software

The software part of the receiver was quite simple. Unfortunately I have overwritten the original source, so I'm not able to publish it here.

At the heart was the servo update routines, where the servo pulses were driven every 20 milliseconds using two timer ISRs. The first one was used to set the signal lines high. The second one was called one millisecond later and it busylooped for 1 millisecond to set the signals low at the correct time. As servo pulses are always at least 1 millisecond long, this way of implementation allowed me to save that millisecond for other use.

About 19 milliseconds out of 20 the code was running a busyloop, which checked a couple of different things
  • Do we have received data over the radio?
  • Do we have received data from the GPS?
  • Has an analog-to-digital conversion completed?
  • Is it time to put the channels to fail safe?
If a packet was received from the radio, the software would decode its contents, i.e. store the received new servo pulse widths in memory and check if servo fail safe values should be set. It would also read the RSSI (receive signal strength indicator) of that packet. After that it would build a reply packet that consisted of the most recent GPS data, the most recent measured voltage and current, the RSSI value of the received packet, a count of servo updates, a count of received packets and a couple of flags that indicated different error conditions. A reply packet was sent for each received packet.

If a complete NMEA sentence was received from the GPS, it would be decoded and its contents stored in memory. The NMEA sentences were received a byte at a time from the GPS, with a FIFO buffer of 2 bytes, which corresponds approximately to 2 milliseconds at 9600bps. This is the most important reason in saving the additional millisecond by using two ISR routines.

If an analog-to-digital conversion was completed, the value would be stored to the appropriate memory location (either voltage or current), the ADC channel was changed and a new measurement was started.

If it had been 500 milliseconds since the last packet from the transmitter, the servo pulse widths were loaded with fail safe values. The fail safe values were at first hard-coded but later set as the first received values after each power-on.

Friday, September 28, 2012

Some background info

After visiting ModelExpo exhibition (their website is in Finnish) here in Helsinki in around the mid 2000s, I really got interested in RC airplanes. I mean, I had visited ModelExpo already in the early 90s as a kid, and for a while I tried to get my parents to buy me an RC plane, but they didn't and the whole idea soon died out. This time, however, after exploring the different possibilities I came to the conclusion that as a student I just couldn't afford a hobby so expensive. One of the main problems was the radio system. I didn't want to just buy a 4 channel "cheap" transmitter, because I knew I'd definitely want to update it sometime in the future. Still, even the 4 channel ones were quite expensive as the 2.4GHz revolution hadn't yet really taken off.

I'd already been a keen electronics hobbyist for quite many years back then, so I decided that building my own RC radios was no big deal. For a couple of years, I would play around every now and then with home made 27 MHz transmitters and super-regenerative receivers, but I never really got them to work reliably. While practically given up on my goal, I happened to stumble across a company called HopeRF, and especially their radio module RFM12, which was used in quite many small wireless microcontroller projects. After looking for a supplier for these modules, I found Octamex in Germany, which also sold the modules RFM22B and RFM23B at only a marginally more expensive price. After reading the datasheets, it was a no-brainer: the RFM22/23 were much more advanced, so I ordered a couple for operation at 868MHz without ever looking back at RFM12. (For reference: this was around Christmas time in 2010).

It turned out the modules were based on Silicon Labs Si4430 family of EZRadioPRO UHF ICs. The datasheets provided by HopeRF ended up being just badly copied versions of the original Silabs documents. Within just a week or two, I got the modules talking to microcontrollers (which I think were Atmel ATtiny2313) and talking to each other over the air. As I usually can't really keep focused on just one thing for a long time, I decided to first pursue other projects I could use the radio modules with, including home automation and remote sensing. I continued with the RC stuff the following summer.