Introduction: Arduino Wireless Altitude Transmitter for RC Planes

With the arrival of new regulations governing the maximum height for radio controlled planes, helicopters and drones, I wanted to know at what altitude I flew my models.

My solution was to grab pressure (and therefore altitude) data at the model's height, then transmit it to the ground using a 433Mhz transceiver. A ground receiver displays the data in real time.

The base altitude is stored in Eeprom memory. This can be altered by connecting the transmitter to a PC and issuing a simple Serial command.

Transmitter

I decided to use the MPL3115A2 pressure sensor with the non breakout version of the RFM69CW 433Mhz wireless tramsmitter / receiver. For those requiring extended range I believe there is a RFM69HCW version, with a slightly larger transmitting current.

I used a dipole aerial setup- with a 17.3cm wire on the aerial input and the ground.

For the processor, I used an Arduino Pro mini 8MHz 3V3 which is small and light.

A 3V3 regulator provides the correct voltage using either the planes lipo balance plug as the supply, or a spare servo connector. I used a LD1117V33 3v3 reg which is rated at 800mA. (Because I had them.) Any good low dropout regulator would work, with a minimum current capability of 500mA.

With a small balsa box I was able to get the mass down to 12.55g.

.

Parts:

.
Receiver

A 16MHz Arduino Pro mini provides a little more processing power to deal with a RFM69CW 433Mhz transmitter / receiver and a 128 x 64 oled screen. Please do not ask about alternative screens- this is the one I used!

Parts:

  • Arduino Pro mini 16MHz 5V0 ( http://www.hobbytronics.co.uk )
  • RFM69CW 433Mhz Breakout wireless tramsmitter / receiver ( http://www.hobbytronics.co.uk )
  • Dipole 17.3cm aerials.
  • LD1117V33 3v3 reg or alternative with an output of at least 500mA
  • Small piece of Copper stripboard for regulator
  • 100nf Capacitor
  • 10uf 16V Capacitor
  • 3 * 220 ohm resistors
  • 2 * matched 100Kohm precision resistors
  • 2 * 3mm Red Leds
  • 1 * 3mm Green Led
  • Mini oled screen 128 * 64 ( http://www.hobbytronics.co.uk )
  • 250-300 mAh 2S lipo (You need a lipo charger)
  • Chassis mounting plastic DC power socket with integral switch ( https://www.esr.co.uk )
    • Charging plug and lead to match chassis socket and your lipo charger
  • 2 small micro switches ( with one good for 0.5A DC)
  • A small box to cram it all into. I used a 175 x 50 x 25 Black ABS Box ( https://www.rapidonline.com )
  • Card / fine tin plate to make a sun screen for the oled display
  • 2 straws to protect the aerials.


Step 1: Building the Transmitter

Small and light is beautiful.

As the transmitter resides in the radio controlled plane I had to keep the construction light. I recommend considering the final size of the containing box before soldering any wires.

Assemble the regulator on a small piece of stripboard, with the smoothing capacitors. Connect a pair of wires for the supply. If you are using a spare servo connection as the supply add a servo socket with no data lead. NB check the plane's receiver is capable of supplying 400-500mA. If you are using the Lipo balance plug add a section of Single Row Header (0.1 inch pitch) with all but the 0 and max voltage pins removed. Then heat shrink to seal.

.

It is prudent to check the output of your regulator using a suitable 2-3S Lipo

NB do not reverse connect to the lipo balance plug. You will blow the regulator and the pressure sensor. If this is a concern, use a 1n4001 diode in series with your positive lead.

.

Connect the components to the 8MHz 3v3 Pro Mini as per the diagram. Keep the leads short and use good quality wires.

  • The Arduino will need a 6 pin strip of single pole header pins at the opposite end to the reset button. Depending on your FTDI you may find 90 degree header pins a better option.
  • Note the marked colours on the Arduino 6 pin end and match to your FTDI programmer. I find marking both the Arduino and programmer with Tippex particularly useful.
  • The aerial wires should be 17.3 cm long after the wire exits the pcb. I attached one to the aerial point on the RFM69CW and the second to the zero voltage point on the arduino used to ground the RFM69CW. I deducted the length of the ground wire from the RFM to the arduino from 17.3cm, before cutting the ground aerial to length. The aerial wires were fixed with a bit of 90 second araldite to prevent shearing.
  • The Switch across pins 5 and 6 of the Arduino can be contructed by soldering a 2 pin header socket onto the board. Solder two pins from single pole header together to form a jumper link. It is best to solder a small length of wire then remove and renew the plastic connector. Araldite any bare metal on the top of the switch for insulation. Removing the link allows Serial output.

    Alternatively- solder two pins of single pole header to the board and use a 0.1" jumper link.

    • I used scraps of balsa wood and thin isocyanate glue to fabricate a box. I kept the 3 components separate with small balsa runners. The pressure sensor is light sensitive, so I made a small tray to shield it. I cut a circular hole in the outer box directly above the rectangular sensor and then covered it with a piece of foam.
    • Vent holes were cut to ensure air flow. Exit holes were required for one aerial lead and the led. I used a carbon rod to pin the tray and regulator in place.

    .

    Software and Preparation

    The pressure sensor will need to be calibrated for pressure and temperature.

    As altitude is a function of the atmospheric pressure at sea level and the pressure at the unknown altitude, we need to estimate sea level pressure. It is also a function of temperature, however we can leave this factor out in a reasonable approximation.

    A good estimate of sea level pressure can be obtained by reading the pressure at a known altitude- The base level. In my case the kichen table. So, look up the altitude for your house and adjust for the position of your transmitter. You will also need a reliable value for sea level atmospheric pressure for your calibration period. I used reports from internet weather sites.

    Download RFM69_transmitter3.zip and install the folder in your Arduino program folder. Move the RFM69 library folder to your Arduino library folder.

    • Open the Arduino IDE ( https://www.arduino.cc/en/Main/Software )
    • Open file RFM69_transmitter3
    • In Tools set the board to Ardino Pro or Pro Mini. Set the processor to ATmega328P (3.3V, 8MHz)
    • Do not power the Arduino using a Lipo.
    • Remove the link across pins 5 and 6 on the Arduino- recheck your wiring. I am not responsible for it!
    • Set the voltage on the FTDI programmer to 3v3.
    • Connect the Arduino to the FTDI programmer, checking it is orientated correctly.
    • Plug in the FTDI programmer into your computer using the USB lead.
    • Wait for the computer to recognise the USB device- use Tools Port to select the newly acquired com port.

    .

    Locate the review and amend section in the code:

    // ________ Review and amend this section ______
    // use your own 16 character encryption key!
    #define ENCRYPTKEY    "DRPattEncryptkey" // exactly the same 16 characters/bytes on all nodes! 
    #define SERIAL_BAUD   74880
    #define DATA_SIZE     20
    // set default base altitude
    // kitchen table 51.3 m 
    // cadmac flying field 46-47 m 
    const float ALTBASIS = 51.3; // base altitude in m
    
    // pressure correction
    // Pa 4Pa per bit -512 to +508 
    const int pcorrection = -64;
    
    // temperature coefficients
    
    // unboxed
    float mUB = 0.6;
    float ccUB = 0.5;
    float aUB = 0.001535;
    float bUB = -0.05264;
    float cUB = 0.666409;
    float dUB = 0.575;
    
    // boxed
    float mB = 0.7;
    float ccB = 0.30;
    float aB = 0.00255;
    float bB = -0.11437;
    float cB = 1.722786;
    float dB = -0.73676;
    
    const boolean isBoxed = true;
    const boolean Tcalibrate = false;
    
    const boolean useBase = false;
    // true: offset altitude by base height rather than calibrated base height
    // false: use calibrated base as altitude offset
    
    // _______________________________________________

    .

    The pressure and temperature corrections are for my sensor. You will need to alter these:

    1. Set the ENCRYPTKEY to your own 16 character word
    2. Set pcorrection to 0
    3. The SERIAL_BAUD should not exceed 74880
    4. Set ALTBASIS to the altitude of your current location (1 decimal place and in metres)
    5. Set Tcalibrate to True to leave temperatures un-calibrated
    6. Set isBoxed to false and expect to calibrate un-boxed

    .

    Obtain an accurate value for sea level atmospheric pressure (in Pascals) for your location. You will also need room temperature in Centigrade.

    • Now select the right arrow to upload the code!
    • When complete open the Serial monitor and set it's baud rate to the SERIAL_BAUD specified in point 2 above.
    • Switch off AutoScrolling on the monitor.

    Step 2: Transmitter Calibration

    1) Pressure

    We use local pressure and sea level pressure to estimate altitude. By subtracting the base altitude we obtain height above ground level:

    float myaltitude = altitude(currpress, seapress) - newbasealt; // get altitude above base
    
    float altitude(float lpressure, float seapressure){
    // h = 44330.77( 1 - (p/Po)^ 0.1902632 )
    float alt = pow(lpressure / seapressure, 0.1902632);
    alt = 44330.77 * (1 - alt);  
    return alt;
    }

    To get the pressure we first write to register 0x26 of the sensor:

    void oneshotP(){ // Pressure
     if(maxoversample){ 
     IIC_Write(0x26, 0b00111001); // bits 3-5 control oversample
     IIC_Write(0x26, 0b00111011); // bit 1 toggled- get immediate value
     }else{
     IIC_Write(0x26, 0b00110001);
     IIC_Write(0x26, 0b00110011);
     }
    }

    With maxoversample true we get the greatest accuracy (and slowest samplerate) .

    Now wait until the STATUS registers flags that data is ready:

     if ((IIC_Read(STATUS) & 2) == 2){
     float currpress = Baro_Read(); // read the pressure
     oneshotP(); // request next reading
    float Baro_Read(){
    //this function takes values from the read buffer and converts them to pressure units
    IIC_ReadData(); //reads registers from the sensor
    unsigned long m_pressure = IICdata[0];
    unsigned long c_pressure = IICdata[1];
    float l_pressure = (float)(IICdata[2]>>4)/4; //dividing by 4, since two lowest bits are fractional value
    return((float)(m_pressure<<10 | c_pressure<<2)+l_pressure); //shifting 2 to the left to make room for LSB
    }

    void IIC_ReadData(){  //Read Altitude/Barometer and Temperature data (5 bytes)
    //This is faster than reading individual register, as the sensor automatically
    //increments the register address, so we just keep reading...
    byte i=0;
    Wire.beginTransmission(SENSORADDRESS);
    Wire.write(0x01); // Address of CTRL_REG1
    Wire.endTransmission(false);
    Wire.requestFrom(SENSORADDRESS,5); //read 5 bytes: 3 for altitude or pressure, 2 for temperature
    while(Wire.available()) IICdata[i++] = Wire.read();
    }

    .

    Atmospheric pressure is generally reported at sea level on weather sites.

    www.xcweather.co.uk reports today's pressure as 1013mB.

    www.wunderground.com reports (with more accuracy) 1013.46 hPa

    milliBar (mB) and HectoPascals (hPa) are equivalent units. 1hPa = 100Pa

    At my location today's pressure is therefore 101346 Pascals.

    Room temperature is 23.2 C

    .

    The Serial monitor connected to the transmitter shows:

    ____________________________________________

    Initialising Transmitter
    Initialising Sensor

    Sensor OK.

    Pressure calibration...

    OverSample On

    Base altitude 51.3 m

    Use newbase = xy.z from Serial port to set a new altitude

    Pressure offset 0 (at 4 Pa per bit)

    Barometric Pressure Input, (High 197 Low 231) 101326 Pa

    Temperature offset (0) 0.0000 C (at 0.0625 C per bit)

    Altitude offset 0 (at 1 m per bit)

    Uncalibrated 46.4 m

    Average Pressure 100771.3 Pa

    Sea Pressure 101386.4 Pa

    (Allowing for temperature) 101365.51 Pa

    Altitude by sensor function 51.3 m

    Altitude by local function 51.56 m

    Base temp 23.6 C

    ____________________________________________

    The reported sea level pressure is 40 Pa more than the weather station. For this sensor we need to apply a small negative correction to the variable pcorrection. The correction must be divisible by 4.

    I recommend you apply similar positive or negative corrections until your sensor is calibrated.

    Note that the un-calibrated altitude value is pretty good. This is because today's pressure is close to the sensors default value of atmospheric pressure used in altitude calculations (101326Pa) On another day the internal sensor altitude value will be well out.

    For this reason we establish sea level pressure with a calibrated sensor and then perform our own altitude calculation based on the local pressure.

    .

    2) Temperature

    This is a bit more problematic!

    According to the manufacturer's website the temperature sensor was never really intended to provide ambient temperature values. Apparently it provides the temperature of the "sensor die".

    Since the die temperature must be affected by atmospheric temperature we should be able to calibrate the temperature data to extract ambient values.

    The sensor appears to self heat over the first 17 minutes before establishing a temperature value which is constantly above the ambient temperature. This heating must affect the internal temperature compensation for the returned pressure value. I believe this is the cause of observed pressure drift for a stationary MPL3115A2 sensor. We do not have a means of fixing this internal correction, but we can calibrate for atmospheric temperature.

    Prepare a table of Time and temperature:

    Time.. | Temperature

    0.000 |

    13/60 |

    1.000 |

    2.000 |

    ..up to 17 minutes.

      • The temperature at time zero will be the Base Temp and the value at 13 seconds the first reported value.
      • The transmitter reports in this format:

        D>P:0.0,0.0,25.0 C (Presure 100767.75 Pa ) 0:13

        D>P: current altitude, max altitude, current temperature (local pressure) minutes:seconds

        • Let the transmitter cool. Be patient. The die appears to retain heat and will affect the initial start-up temperature.

        .

        Record the current room temperature, preferably to 1 decimal place.

        • Plug in the transmitter to the PC with the Serial Inhibit link out.
        • Record the temperatures. Open the spreadsheet calibrateTemp.xlsx
        • Enter Room temperature in cell F3 and the temperature data in B3 to B21

        .

        The spreadsheet will produce temperature correction parameters.

        • For the first minute I have assumed a linear correction:

          Correction = mUB * Time + ccUB

          • For the remaining period:

            Correction = aUB * Time^3 + bUB * Time^2 + cUB * Time + dUB

            .

            Edit the temperature coefficients in the RFM69_transmitter3 sketch

            Amend the temperature correction values in the unboxed section, using the spreadsheet values.

            Upload the amended program.

            .

            Box the transmitter

            Allow it to cool then repeat the calibration process. If this is problematic wait until you have built the receiver and calibrate wirelessly.

            • Edit the sketch.
            • .. isBoxed = true;
            • .. Tcalibrate = false;
            • Upload the sketch
            • Insert the No Serial link
            • Rebox

            Step 3: Building the Receiver

            If, like me, you want the receiver velcro mounted on the top of you RC transmitter you will have to think small.

            I used a 175 x 50 x 25 mm abs box, which, unlike the Tardis, is smaller on the inside.

            Plan how to fit all the components in place before wiring it up.

            The box will contain:

            1. Arduino Pro mini 5V0 16 Mhz
            2. Power charging socket
            3. Regulator
            4. 2 Switches
            5. 3 LED
            6. Oled screen
            7. 433Mhz transceiver
            8. External Bi pole aerial

            .

            • I arranged for all the components to hang from the lid, with velcro on the inside base of the box to prevent movement.
            • The screen was located with 4 small 12BA bolts - Watch out! The mounting holes in the oled are close to the screen. Do not be tempted to use larger bolts. I used nuts on the inside to act as spaces and then additional nuts to secure. Mark out and cut the hole for the oled screen before connecting the screen to wires. Check the bolt positions. Drill the holes, cut the bolts to length and secure the spacer nuts.
            • The RFM can be mounted at an angle with the aerials at the top. I used two short 12BA bolts and nuts. This saves a lot of space.
            • You may also want to drill the rest of the lid for the other components. My box lid had an internal lip. I cut several sections away to squeeze in the components.

            .

            • Assemble the regulator on a small piece of stripboard. Test the output.
            • Connect the components as per the diagram. Pins 11 and 13 on the arduino require 2 wires each.
            • Use good quality short lengths of wire.
            • Add the leds to the arduino remembering to use the series resistors.
            • The charging point must be connected carefully. The switched terminal is used to supply 0V to the arduino circuit.

            .

            • The lipo supply goes through SW1 before the regulator and Arduino. The arduino is powered from the full Lipo voltage using the Raw terminal.
            • The RFM is powered from the Arduino 5V.
            • The oled screen requires the 3V3 supply.
            • NB there are 2 matched 100K resistors across the switched supply lines. These are connected to A0 to monitor the Lipo voltage. Do not allow the Lipo voltage to fall below 3.88V per cell (7.76V in total). The power switch must be off when charging.
            • Add the 17.3 cm bipole aerials, adding a drop of Araldite to support them.
            • I connected the regulator last and rechecked the circuit (again and ......)
            • Switch off. Connect the lipo.

            Step 4: Testing the Receiver

            Upload the software package RFM69_Receiver.zip.

            • Add the RFM69_Receiver folder to your Arduino program folder. Move the two enclosed libraries to your Arduino library area.
            • Open the Arduino IDE.
            • Open file RFM69_Receiver.
            • In Tools set the board to Ardino Pro or Pro Mini. Set the processor to ATmega328P (5V, 16MHz)
            • Make sure the circuit is switched off. Set the Serial switch to off (Off = not connected to 0v = Serial on!)

            .

            Recheck your wiring. I am not responsible for it!

            .

            • Set the voltage on the FTDI programmer to 5V. Connect the Arduino to the FTDI programmer, checking it is orientated correctly. Plug in the FTDI programmer into your computer using the USB lead. Wait for the computer to recognise the USB device- use Tools Port to select the newly acquired com port.
            • Upload the RFM69_Receiver program.

            After a short delay the oled screen will show 00:00 followed by a voltage- since we are on a USB lead it reflects the USB voltage- should low battery be declared at this point alter the following line in the float vok(boolean show) function:

            if ((V >4.4) && (V < 7.77)){ // 7.77 for 2 cells

            to:

            if ((V >5.1) && (V < 7.77)){ // 7.77 for 2 cells

            .

            • A screen logo follows- feel free to amend logo.h in the HT_SSD1306 library.
            • The display will now show "Awaiting Ak"
            • Power on your transmitter.
            • After approximately 13 seconds the display will clear.

            Incrementing time will show on the top line. This is intended to show how long the transmitter and therefore the RC plane, has been powered up.

            Below this the current Altitude, maximum altitude and temperature.

            Expect to see variations in the altitude of a couple of metres. I put this down to the internal temperature compensation.

            Try elevating the transmitter and check the receiver altitude increases.

            The green led will show when data is received.

            .

            Set the altitude warning

            The red altitude warning led is set in void printData(String S, int font):

            if(T.toFloat() > 121.9) digitalWrite(7, HIGH); else digitalWrite(7, LOW); 

            Change 121.9 (400ft) to any preferred value.

            .

            Confirm the measured Lipo voltage

            Use a meter to measure the voltage of the internal lipo.

            Compare against the voltage shown at the start. If it is inaccurate amend the constant 0.0096997 in the function vok(boolean show):

            float V = analogRead(A0) * 0.0096997; // (7.98/3.97)* 4.94/1024

            Since we are applying the lipo across 2 potential divider resistors (R1 connected to the lipo positive and R2 connected to the lipo negative), the midpoint voltage read by A0 is given by:

            V Lipo = A0 * vReference * (R1 + R2) / (R2 *1024)

            vReference is the voltage of the "5V" terminal

            If R1 = R2 = 100K and vReference = 5

            v Lipo = A0 * 0.009765625

            As you can see, I had to compensate for the measured values.

            .

            Check the charging circuit with a lipo charger

            Do not switch the box on during charging

            .

            Final Assembly

            If everything is working box the components, taking care not to break any wires. If not.. check the circuit again!

            .

            I recommend using two plastic straws as aerial protectors -

            • Put a 12mm cut in the end of one straw and push it into the other.
            • Cut 2 small holes about 15mm apart and carefully push the wires into the straws in opposite directions.
            • Use Blenderm tape to hold the straws on the lid.

            .

            The screen does need to be shielded from the sun. I made a thin tin plate shield and held it on using glue and blenderm tape.

            Add velcro to the base of the receiver and your RC transmitter, to carry the receiver.

            .

            Get Ready for the flying field

            At present the transmitter is using the default base altitude of your PC table.

            Remove the No Serial jumper in your transmitter and connect it to your PC.

            Reset the Arduino IDE to Arduino Pro Mini 3V3 8Mhz and open the Serial Monitor.

            Look up the altitude in metres for your field.

            Type: newbase = xxx.x (eg newbase = 123.4 ) into the monitor and select send

            NB 1 decimal place and in metres

            This value is stored in Eeprom. It overrides the default base altitude and can be re-written for other sites.

            Replace the no Serial link and re-box.

            .

            Safety

            433Mhz is well away from 2.4Ghz and 35Mhz in the electromagnetic spectrum.

            I range checked with both RC transmitter types (on different planes) before test flying.

            It would be prudent to do the same.

            .

            At the field

            • Power up your RC transmitter
            • Switch off Serial output on the 433Mhz receiver
            • Power the 433Mhz receiver
            • Power the plane
            • Connect the 433Mhz transmitter to the lipo / spare servo on the plane- Observe polarity!
            • Wait 13 seconds for the 433Mhz handshake

            Fly.

            Let me know if you build the setup.