Wireless (nrf24l01) altimeter for RC plane (completed project with code)

actually just have the Pro Mini, NRF, and BMP085 bundled together in bubble wrap.

People often have problems with unreliability when they start using nRF24L01 units. It SEEMS this is often connection, and power problems. What can we learn from what you did??

What is the power source in each of the units you made? How long are the wires to the RF unit, and what are the wires like?

Did you end up with added capacitor(s) on the +3.3V - Gnd connections at the RF unit?

Have you had instances in which the units just "did not come up working" but they did work after power cycling etc?

Do you usually have a set sequence of which unit is powered up first?

Thanks! I want to update http://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo with whatever I can learn.

And tell your father he is an awesome Aircraft builder and always ends up flying again.

"Any landing where you can walk over and pick up the pieces with one hand is a good landing"

:P

Hi Terry,

First of all, I am happy to announce that I have successfully incorporated a gy-neo6mv2 GPS unit (like this one: http://www.ebay.ca/itm/GY-NEO6MV2-Flight-Controller-GPS-Module-For-Arduino-EEPROM-MWC-APM-2-5-/390647042336) to the transmitter part of my project. I can now transmit both altitude and speed. I just got back from driving around with my wife to verify the speed readings are correct (they are!). I have made some modifications to my code (such as displaying speed instead of temperature, and showing the max speed and max altitude when the "reset" button is pressed, unless it is held down for > 6 s, in which case it does reset everything). For some reason the GPS unit did not initially work when I tried to run it with the NRF. After a lot of playing around, I got it to work by making the GPS code run repeatedly for 1 s, followed by the NRF code running for 0.5 s (you will see this in my code). Once I have finished putting appropriate annotation into my code, I will post it. The whole transmitter now weighs ~ 50 g (the GPS antenna is quite heavy), which is acceptable for the RC plane it will be used for.

As for your questions, here are my answers:

1) Power source: The receiver is powered by a 9 V battery. The transmitter is powered by a 3.7V 150mAh Li-Po. Google "RC Champ battery" to see the exact battery. 2) Wires to the RF unit: I have used the cheapest jumper cables I could find on ebay. Since they were quite long (20 cm), I cut them in half and soldered them back together (now probably ~ 7-10 cm). 3) When breadboading the circuit, I did use capacitors. However, when I was assembling everything to my Pro Mini, it became too annoying, so I left them out. Fortunately, it all seems to still work fine. 4) Intermittent functioning: Yes, this can be an issue. Sometimes if the transmitter is not positioned correctly, it can lose connection with the receiver.I usually just have to touch the antenna, or give the whole transmitter unit a nudge, and then it starts working . I built in a timer into the receiver code to let me know if it has been out of communication for more than 5 s (see code). However, when my transmitter is wrapped up in bubble wrap, it is very reliable. This makes me think the occasional lost connection (when not wrapped up) is due to a lose wire, or something of the sort, that does not occur when the unit is wrapped up. 5) Order of turning on: It definitely does not matter what order I use to turn on the unit.

I hope that is useful, and I would be very happy if any of this helps you with your wikispace link. For anyone else reading this, the link Terry posted is very useful. It helped me enormously when learning how to write code for the RF unit.

Thanks,

Dustin

Hello All,

I have now incorporated a GPS unit into my project so that I can transmit speed, as well as altitude (from my BMP085 unit). I have modified the transmitter and received code to allow for the following modifications:

  1. Speed is now reported where temperature used to be reported.
  2. The receiver unit no longer cycles through to show maximum altitude. Instead, if the “reset” button is pressed for less than 6 s, both the maximum altitude and maximum speed are displayed. If the button is pressed for longer than 6 s, the unit is reset (max speed and altitude are reset, and the unit is “zeroed”).

I did run into an unexpected problem when trying to incorporate the GPS unit into the transmitter. For some reason, when I first tried to add the GPS unit, and the associated code, I wasn’t able to get any data from the GPS. I have no idea why this occurs. After A LOT of playing around, I found that I could get it to work if I had the GPS code run repeatedly for 1 s, followed by the NRF code running for 0.5 s. Without doing this, it seems like the GPS unit just does not pick up any data. You will see where I made this modification in the code.

Here is the new code for both units:

Transmitter Code:

// Libraries

//For NRF
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>
// End

// For BMP085
#include <Wire.h>
#include <Adafruit_BMP085.h>
// End

// For GPS
#include <SoftwareSerial.h>
#include <TinyGPS.h>

// End

//-----------------------------------------------------------

// Constants

//For GPS
unsigned long time;
float kmhspeed;
float test;
float flat, flon;
long courses;
// End


// For NRF
float data[3]; // 3 element array to hold temp, altitude, and speed
const uint64_t pipe = 0xE8E8F0F0E1LL;
// End

//-----------------------------------------------------------

// Declarations

//For GPS
SoftwareSerial gpsSerial(4, 3);
TinyGPS gps;
// End

// For NRF
RF24 radio(9,10);
// End

// For BMP085
Adafruit_BMP085 bmp;
// End

//-----------------------------------------------------------


void setup(void)
{
   Serial.begin(115200); // connect serial
// For NRF
  radio.begin();
  radio.openWritingPipe(pipe);
// End

// For BMP085
  if (!bmp.begin()) 
      {
	Serial.println("Could not find a valid BMP085 sensor, check wiring!");
	while (1) {}
      }  
// End

//For GPS
 gpsSerial.begin(9600); // connect gps sensor
// End

}
 
void loop(void)
{
  // For GPS
  
time = millis(); // I have included this to make the program run through the GPS stuff a few times before moving on to the NRF stuff. Without doing this, I am unable to get data from the GPS unit when paired with the NRF. This is not just an issue with the NRF, since I am unable to even print GPS data to the serial monitor without doing this.

do
{
  
  while(gpsSerial.available())
  {
   if(gps.encode(gpsSerial.read()))
   {
    gps.f_get_position(&flat, &flon);
    kmhspeed = gps.f_speed_kmph();
   }
  }
  
} while (millis()-time < 1000); // Had to have this run continuously for 1 s before moving onto the NRF code, otherwire the GPS code does not seem to work. I chose 1 s based on trial and error.
  // End

time = millis();

do
{
   
 //For NRF and BMP085
  data[0] = bmp.readAltitude();
  data[1] = bmp.readTemperature();
  data[2] = kmhspeed;
      for (int i = 1; i < 3; i++)
      {
        radio.write(data, sizeof(data));
      }

} while (millis()-time < 500);
// End
}

Receiver Code:

//Code for Radio
//Begins
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;
float data[3]; // 3 element array to hold the temp, pressure, and speed data
// Ends

//Code for LCD
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 7, 6, 4, 3, 5);
//Ends

// Constants
//Begins
int Temp;
float Zero = 100;
float Actual;
int height;
unsigned long time;
unsigned long timeTwo;
int maxHeight = 0;
boolean TempOrMaxHeight = true;
int tarePin = 14;
int setTriggerHeight = 15;
int triggerHeight = 16;
int alarmPin = 17;
int val = 0;
float var;
int beepingHeight = 1000; //I set this at 1000 so that the unit does not start beeping as soon as it is turned on.
int i = 0;
float kmph;
float currentSpeed = 0;
float maxSpeed = 0;
//Ends


 
void setup(void)
{
  //Code for Radio
  Serial.begin(9600);
  radio.begin();
  radio.openReadingPipe(1,pipe);
  radio.startListening();
  //Ends
  
  //Code for LCD
  pinMode(tarePin,INPUT);
  pinMode(triggerHeight, INPUT);
  pinMode(setTriggerHeight,INPUT);
  pinMode(alarmPin, OUTPUT);
  Zero = 100;  // I just set this to give mysefl a baseline when testing
  lcd.begin(16, 2);
      
      //This will show up, then scroll off the screen when the unit is first turned on. 
      lcd.print("TwoChain inc.");
      delay(2000);
        for (int positionCounter = 0; positionCounter < 16; positionCounter++) 
        {
        // scroll one position left:
        lcd.scrollDisplayLeft(); 
        // wait a bit:
        delay(300);
        }  
      lcd.clear(); 
      
  // Ends
}
 
void loop(void)
{
  //Code for radio begins
  if (radio.available())
  {
    time = millis(); // Check time when last signal was detected.
    bool done = false;  
    while (!done)
    {
      done = radio.read(data, sizeof(data));
    }
  // Ends
  
  
  digitalWrite(triggerHeight, HIGH); // I am using the internal pull up resistor to keep this pin high until a button is pressed.
  // Code for LCD
    
    if (digitalRead(tarePin) == LOW) // Check when tare button has been pressed
    {
      timeTwo=millis();
    do // If the resent button is pressed down for less than 6 seconds, the max speed and height are reported. If the button is held for more than 6 s, the values are reset. 
       {      
        lcd.clear();
        lcd.print("Max Alt. ");
        lcd.print(maxHeight); // Subtracting these two gives the "tared" altitude.
        lcd.print(" ft");
        lcd.setCursor(0,1); // Begin the speed display
        lcd.print("MaxS ");
        lcd.print(maxSpeed);
        lcd.print(" ");
        lcd.print("km/h");
        delay(6000);
        digitalRead(tarePin);
        
        if (digitalRead(tarePin) == LOW)
        {
        Zero = Actual; // Set "Zero" to the last measured altiitude
        maxHeight = 0;
        maxSpeed = 0;
        i = 0; // i is also reset to zero if the "zero" button is pressed.
        lcd.clear();
        lcd.print("Calibrated!");
        delay(2000);
        lcd.clear();
        for (int i = 0; i < 3;i++) // This loop is not necessary, but I find it exciting!
        {
          lcd.print("Ready for ");
          lcd.setCursor(0,1);
          lcd.print("takeoff!!!");
          delay(500);
          lcd.clear();
          delay(500);
        }
          digitalWrite(tarePin, HIGH);
       }
       }while (digitalRead(tarePin) == LOW);
    }
      
   
    while (digitalRead(triggerHeight) == LOW) // If my "set switch" is pressed, the user can set the altitude at which the alarm will trigger.
    {
      lcd.clear();
      val = analogRead(setTriggerHeight);
      var =(1000-val*24)/100; // I am switching between a float and int, and playing with the math, to make the "alarm altitude" increase in 50 f increments.
      beepingHeight = var*50+500;
      lcd.print("Alarm will sound");
      lcd.setCursor(0,1);
      lcd.print("at ");
      lcd.print(beepingHeight);
      lcd.print(" ft");
      delay(500);
     }
    
    
    Actual = data[0]; // Convert the float to an int cause there is no point in reporting the extra decimal places due to variations in pressure
    lcd.clear();
    lcd.print("Altitude ");
    height = (Actual-Zero)*3.28; // Multiplying by 3.28 to convert to ft.
    lcd.print(height); // Subtracting these two gives the "tared" altitude.
    lcd.print(" ft");
    
    currentSpeed = data[2];
    lcd.setCursor(0,1); // Begin the speed display
    lcd.print("Spd. ");
    lcd.print(currentSpeed);
    lcd.print(" ");
    lcd.print("km/h");
    
    if (height > maxHeight) // Continually store the maximum altitude to be displayed later on.
    {
     maxHeight = height; 
    }
       
    if (currentSpeed > maxSpeed) // Continually store the maximum altitude to be displayed later on.
    {
     maxSpeed = currentSpeed; 
    } 
    
    delay(500);
  }
  
  else
  {
    if (millis()-time > 5000) // Check how long it has been since last successful signal was detected.
     {
    lcd.clear();
    lcd.print("No Signal!");    
    lcd.setCursor(0,1);
    lcd.print("Out of Range!");
    delay(1000);
    }
  }
  
  if (height > beepingHeight && i < 1) // Sound an alarm if the max altitude is reached.
  {
   tone(alarmPin,750,2000);
   i = 1; // Set i = 1 so that the alarm does not sound again until the unit is reset.
  }
  
}

Please let me know if you have any questions.

Thanks,

Dustin

I've done this before.. pls hv a look at my blog entry below...

I've to split up the GPS NMEA sentences into 3 fragments as RF24 only have a max payload of 32 Bytes

Hv to do with the software serial not fast enough ... you may try AltSoftSerial https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html from PJRC or swap the h/w and s/w serial....

http://arduino-for-beginners.blogspot.com/2013/06/arduino-serial-over-nrf24l01.html

Hi Stanley,

Thanks for the post. I didn't have to split up the GPS NMEA, and it works just fine. The only issue I ran into was having to delay the program in key places, as I explained earlier in this thread. Maybe this is because I am only sending the speed, and not everything else. I was actually surprised at how smoothly the whole thing came together...

When you say you did this before, are you referring to sending GPS data wirelessly, or making a wireless altimeter/speedometer. I believe you need to use something like the BMP085 for measuring altitude, since you can't get reliable altitude from a GPS unit.

Thanks,

Dustin

Hi.

First of all thanks very much for sharing your experiences with these transmitters.

I'm hoping to do something similar to this and I just had one question regarding the code. In the first example without GPS you have an array of 2 floats. Then you have a loop which seems to write the same data twice. I know that there is a 32 byte packet limit on the NRF24L01 , but i thought a float was 4 bytes. Would something like

radio.write(&data, sizeof(data))

work too in this case?

Did you use this loop routine to send smaller packets which are more likely to be received intact?

Then in the GPS example, the data array contains 3 floats, but it seems that in the loop only 2 are sent.

In my application I'll have 6 integers to send (using a teensy -so 32 bits I think) so I'm wondering the best way to do this. Getting my head round the code is step 1.

Many thanks for any pointers/ help. Colin

Hi Dustin I am very impressed with your project and wanted to try to emulate it. But your post had everything apart from the wiring diagram. Will you be posting it as i would love to see it to.

Tried to compile the above receiver code but comes up with a compile error. Apparently it used to work ok when it was built first up. I tried downloading an earlier IDE version from Arduino site ( 1.56) and earlier version of RF24 (1.0) but that came up with the same error.

Arduino: 1.8.9 (Windows 7), Board: "Arduino Pro or Pro Mini, ATmega328P (5V, 16 MHz)"

C:\Users\Jeff\Desktop\Electronics stuff\Arduino Altimeter NRF24L01\Receiver_2\Receiver_2\Receiver_2.ino: In function 'void loop()':

Receiver_2:84:12: error: void value not ignored as it ought to be

done = radio.read(data, sizeof(data));

^

exit status 1 void value not ignored as it ought to be

bluejets: Receiver_2:84:12: error: void value not ignored as it ought to be

done = radio.read(data, sizeof(data));

^

exit status 1 void value not ignored as it ought to be

I think that is because you are using the wrong version of the RF24 library. I think that style requires the newer TMRh20 version of the RF24 library. I suspect you have the earlier ManiacBug version. Unfortunately they both use the same name.

...R Simple nRF24L01+ Tutorial

Robin2: I think that is because you are using the wrong version of the RF24 library. I think that style requires the newer TMRh20 version of the RF24 library. I suspect you have the earlier ManiacBug version. Unfortunately they both use the same name.

...R Simple nRF24L01+ Tutorial

Ok...thanks...I did try a different one but it did not change anything so will try the one you link to.

Thanks again.

Edit...just had a quick peek at the one you link to and in the RF24.h section it mentions "maniacbug".

That was it Robin2.

Guessing you tripped over that before.

Will have a good look at your other suggestion also.

Thankyou.