Sunday, September 30, 2012

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.

No comments:

Post a Comment