Experimental Arduino RC Plane Build Log

Would you use the hardware and/or software designed as part of this project for your own RC planes?

  • Yes

    Votes: 10 100.0%
  • No

    Votes: 0 0.0%

  • Total voters
    10

Power_Broker

Active member
Here's a layout/diagram as to how the ArdUAV library is going to work.

ArdUAV_Library_Diagram.png


There isn't a lot of detail in the diagram since it's supposed to be a high level overview, but I'll post a full description of publicly accessible classes, functions, variables, and constants later.
 

Power_Broker

Active member
Update #35.)

I've decided to use Google Drive to create a website for my new library. NOTE: The website isn't finished...yet.

Here is the link

The website, when done, will include how to install the library, how to use the library, and will describe all public functions, variables, and constants available to the user in their own RC plane sketch.
 

Power_Broker

Active member
The website in post #82 is updated as of today - I'll keep it updated as I make changes and expansions to the library itself. I'm also thinking about posting the current PCB designs on the site for easy access - might make that edit to the site soon.
 

Power_Broker

Active member
Update #35.)

Ok, after almost 2 weeks of overhauling the code, building, and debugging my new master library, I finally got it all working for basic manual flight!

Current Features:
- Full manual control (transmits commands at 100Hz)
- Ground station receives telemetry at 10Hz. Telemetry includes:
- latitude (in dd)
- longitude (in dd)
- roll angle (in degrees)
- pitch angle (in degrees)
- pitot tube pressure reading (I will update the library to automatically convert it to airspeed in m/s later on)
- altitude in cm

All the source code (including an example plane and hand controller Arduino sketches) can be viewed at my gitHub here.

A full description of the current library contents and how to use it can be found at the ArdUAV API website here.
 

Power_Broker

Active member
Update #36.)

I did an in-depth evaluation of the performance of how the AirComms library handles incoming serial data. Turns out I was getting packet errors (especially on the flight controller) due to incorrect packet sizes, packets starting and ending with bytes other than START_BYTE and END BYTE.

The packet size error was mainly due to the fact that I was blindly looking for the first byte in the serial stream that shared the same value as the constant defined as "END_BYTE". For instance, if "END_BYTE" = 50 and the command for the elevator servo happens to be 50, the input string buffer will be terminate early (at the elevator servo command). This causes the input string buffer to have a total length less than the fixed packet size defined as "BUFF_LEN" and cause an error to be thrown and the data in the packet ignored.

The start/end byte error was due to the code becoming periodically "desynced" with the packets. Imagine that I have the ground station/hand controller running and transmitting, but I leave the plane off. The ground station doesn't know that the plane isn't actually receiving data - it constantly broadcasts data packets via the radio either way. Then lets imagine I turn the plane on at a random time. The plane might come online and connect to the ground station while the ground station is halfway finished transmitting a packet. In this case, the first byte in the flight controller's input buffer will not be the "START_BYTE" but could be any value from 0 to 255!! This causes an offset for the rest of the values in the input buffer and, in a sense, "desyncs" the flight controller from the ground station. It also cause packet size issues because the "END_BYTE" wouldn't be in the right position due to the desync.

Good news though: I developed a fix for all these bugs and the code so far has had 0 errors after the update ;)

Here's the old way I was doing it (the code that was causing all the above problems):
C++:
void serialEvent2()
{
    while (IFC_COMMAND_PORT.available())
    {
        // get the new byte:
        char inChar = (char)IFC_COMMAND_PORT.read();

        // add it to the inputString:
        if (!myRadio.stringComplete_Radio)
            myRadio.inputString_Radio += inChar;

        // if the incoming character is a newline, set a flag so the main loop can
        // do something about it:
        if (inChar == END_BYTE)
        {
            myRadio.stringComplete_Radio = true;
        }
    }

    return;
}


Now here's the new algorithm with the bugs fixed:
C++:
void serialEvent2()
{
    while (IFC_COMMAND_PORT.available())
    {
        //add it to the inputString if the packet isn't complete yet:
        if (!myRadio.stringComplete_Radio)
        {
            //get the new byte:
            char inChar = (char)IFC_COMMAND_PORT.read();

            //add char to input string buffer
            myRadio.inputString_Radio += inChar;

            //test if the length of the string is at least one
            if (myRadio.inputString_Radio.length() >= 1)
            {
                //if the first byte isn't correct, clear the string buffer and start over
                if (myRadio.inputString_Radio[0] != START_BYTE)
                {
                    //clear the string buffer
                    myRadio.inputString_Radio = "";
                }
            }
        }
        else
        {
            //not time to read from buffer - need to finish processing the completed packet contained in inputString_Radio first
            //break the loop - otherwise "while (IFC_COMMAND_PORT.available())" could be an infinite blocking loop if bytes aren't being read from the port
            break;
        }

        //check size of input buffer to see if it is big enough to fit a full packet
        if (myRadio.inputString_Radio.length() >= BUFF_LEN)
        {
            //check to see if the char in the (BUFF_LEN - 1) position is correctly the value of END_BYTE
            if (myRadio.inputString_Radio[BUFF_LEN - 1] == END_BYTE)
            {
                //optional debugging prints
                for (byte i = 0; i < myRadio.inputString_Radio.length(); i++)
                {
                    Serial.print((int)myRadio.inputString_Radio[i]); Serial.print(" ");
                }
                Serial.println();

                //set this flag to true so the data can be processed
                myRadio.stringComplete_Radio = true;
            }
            else
            {
                //clear the string buffer and start over
                myRadio.inputString_Radio = "";
            }
        }
    }

    return;
}

The ArdUAV library will be updated to reflect this bug fix soon.
 

Power_Broker

Active member
Quickie update:

I tried adding the pitot tube calibration curve to the flight controller to convert pitot pressure to airspeed in m/s. The calibration curve was defined way back in post #9.

Turns out the sensor characteristics have changed since doing wind tunnel tests. Unfortunately, this means I'm going to have to find a way to recalibrate the pressure sensor. I might have to get a friend to drive me holding the pitot tube out of the window at different speeds :ROFLMAO:

As a workaround, I'm just sending the raw ADC (Analog to Digital Conversion) output of the pitot tube sensor to the ground station instead of velocity in m/s.
 

JLJ

New member
A way to avoid such an issue is to calibrate only the pitot probe within the wind tunnel, not the assembly (electronics + aerodynamic probe+test piping). In such a way you exactly know what the deviation of your probe from the ideal probe at different Reynolds numbers is.

With such an information you can replace straight you pressure sensor.

Anyway,
Pressure sensors calibration drift with time, aging is one know factor. To work with uncalibrated pressure sensors will introduce relevant uncertainty to your measurements.
 

Power_Broker

Active member
A way to avoid such an issue is to calibrate only the pitot probe within the wind tunnel, not the assembly (electronics + aerodynamic probe+test piping). In such a way you exactly know what the deviation of your probe from the ideal probe at different Reynolds numbers is.

With such an information you can replace straight you pressure sensor.

Anyway,
Pressure sensors calibration drift with time, aging is one know factor. To work with uncalibrated pressure sensors will introduce relevant uncertainty to your measurements.

Hmm. I don't think I can recalibrate it in a wind tunnel since I don't have access to one anymore.

Do you know where I can find calibration curves for pressure sensors? Maybe there's a database somewhere? Do you know of any that have documented calibration curves that link output voltage to airspeed?

Sorry for bombarding you with questions, but it would be a big help.
 

Power_Broker

Active member
Watchdog timers (WDT) are critical in avionics design because they automatically restart flight computers in case a serious program error or processor lockup occurs. Since nobody is flying on my RC plane to hit the "reset" button in case something goes wrong, this watchdog timer will.

I'm looking into making use of the Teensy's Watchdog timer in the flight controller code. I think I'll be able to use parts of the code from this blog.

First though, I need to figure out why I'm not able to easily center my servos. Tried a little yesterday with little luck :unsure:
 

JLJ

New member
Do you know where I can find calibration curves for pressure sensors? Maybe there's a database somewhere? Do you know of any that have documented calibration curves that link output voltage to airspeed?
No, I don't know where you can find such curves, but that kind of curve will be probably useless to correct an uncalibrated pressure sensor.

A broadly used approach is to determine the relationship between the differential pressure you measure at your pitot pressure ports and the airspeed. Without a wind tunnel, you should use some approximation(with a wind tunnel you can construct a curve of correction factors for your mechanical probe, probes are different), you find base airspeed/deltap relationships in this site(Eq. p1.).

So, in your case, you can calibrate your pressure sensor using some calibration rig (in this link a commercial unit and a DIY unit). Speaking of DIY, you put some known set of differential pressures at your sensor inputs, and you record the sensor output; in such a way you can correct sensor gain and offset(Introduction here).

If you are willing to accept some added uncertainty you can use straight the uncalibrated sensor and the basic formula.
 

clolsonus

Well-known member
Hmm. I don't think I can recalibrate it in a wind tunnel since I don't have access to one anymore.

Do you know where I can find calibration curves for pressure sensors? Maybe there's a database somewhere? Do you know of any that have documented calibration curves that link output voltage to airspeed?

In the system we are developing at the U of MN UAV lab we simply zero the differential pressure sensor before the flight and then apply a small scaling factor to the inflight readings. We use this code to compute airspeed. Note that the "pitot" variable is the current pitot tube pressure reading and "pitot_offset" is some average reading we collected at the start to estimate the zero airspeed reading:

float Pa = pitot - pitot_offset;
if ( Pa < 0.0 ) { Pa = 0.0; } // avoid sqrt(neg_number) situation
float airspeed_mps = sqrt( 2*Pa / 1.225 ) * pitot_calibrate;
float airspeed_kt = airspeed_mps * SG_MPS_TO_KT;

pitot_calibrate is a scaling value we determine from past flight data and for normal pitot tube installations usually has a value of around 1.1 for eageltree/3dr/mro style pitot tubes that are properly installed.

If you think through the formula a bit and plot it out, you might see that as your speed increases, the affect of calibration errors gets smaller.

Personally, I wouldn't over think the pitot tube calibration too much. Our hobby grade sensors aren't super great and there are lots of other sources of error in the system that could dwarf your careful wind tunnel calibration. My recommendation is to start with a simple calibration, do some flight testing, and then get your own feel of how well it is (or isn't working) and then you can decide if you want to concentrate more of your effort here, or call it good enough for now.

Follow on: I've found it useful to filter the pressure sensor reading before using it. Even on 'digital' pressure sensors you see quite a bit of noise. Filtering the signal a before using it has worked well for us. I started with a simple low pass filter, but then learned about butterworth filters (theoretically more optimal) so switched to those. You'd probably have plenty of compute power on your teensy to do some filtering if you decide you want to try it some day.

You are welcome to examine, copy, use any of our code (licensed with the MIT open-source license) if you find it helpful. I have my personal tiny slice of experience with these things, and I'm happy to answer questions about what I have done if it helps your project: https://github.com/AuraUAS

And by the way, the fact that you are doing all this from scratch including the airframe design and construction is super impressive. Not many people in the world can assemble all the skills you need to this sort of thing in their head all at the same time! Wishing you continued good luck, good progress, and safe flying!
 

JLJ

New member
First though, I need to figure out why I'm not able to easily center my servos. Tried a little yesterday with little luck :unsure:
I don't get exactly your issue. During a pre-flight test I memorize the center value for each servo so I can use this values during flight. Can you expand your issue?
 

Power_Broker

Active member
In the system we are developing at the U of MN UAV lab we simply zero the differential pressure sensor before the flight and then apply a small scaling factor to the inflight readings. We use this code to compute airspeed. Note that the "pitot" variable is the current pitot tube pressure reading and "pitot_offset" is some average reading we collected at the start to estimate the zero airspeed reading:

float Pa = pitot - pitot_offset;
if ( Pa < 0.0 ) { Pa = 0.0; } // avoid sqrt(neg_number) situation
float airspeed_mps = sqrt( 2*Pa / 1.225 ) * pitot_calibrate;
float airspeed_kt = airspeed_mps * SG_MPS_TO_KT;

pitot_calibrate is a scaling value we determine from past flight data and for normal pitot tube installations usually has a value of around 1.1 for eageltree/3dr/mro style pitot tubes that are properly installed.

If you think through the formula a bit and plot it out, you might see that as your speed increases, the affect of calibration errors gets smaller.

Personally, I wouldn't over think the pitot tube calibration too much. Our hobby grade sensors aren't super great and there are lots of other sources of error in the system that could dwarf your careful wind tunnel calibration. My recommendation is to start with a simple calibration, do some flight testing, and then get your own feel of how well it is (or isn't working) and then you can decide if you want to concentrate more of your effort here, or call it good enough for now.

Follow on: I've found it useful to filter the pressure sensor reading before using it. Even on 'digital' pressure sensors you see quite a bit of noise. Filtering the signal a before using it has worked well for us. I started with a simple low pass filter, but then learned about butterworth filters (theoretically more optimal) so switched to those. You'd probably have plenty of compute power on your teensy to do some filtering if you decide you want to try it some day.

You are welcome to examine, copy, use any of our code (licensed with the MIT open-source license) if you find it helpful. I have my personal tiny slice of experience with these things, and I'm happy to answer questions about what I have done if it helps your project: https://github.com/AuraUAS

And by the way, the fact that you are doing all this from scratch including the airframe design and construction is super impressive. Not many people in the world can assemble all the skills you need to this sort of thing in their head all at the same time! Wishing you continued good luck, good progress, and safe flying!

Wow, this is great stuff! Thanks for sharing and for the compliments. I'll definitely be looking into the code on github.

Quick Q: what is the bit resolution for your pitot readings? 16-bit, 12-bit, etc?
 

Power_Broker

Active member
I don't get exactly your issue. During a pre-flight test I memorize the center value for each servo so I can use this values during flight. Can you expand your issue?

I was half joking and figured it out last night anyway. I was messing with the min and max servo positions in the Shared_Tools.h file to center the servos, but realized that after I change that config header, I need to re-upload the code to BOTH the ground station and the plane. Up until then, I was only uploading the new configured code to the ground station and it wasn't working quite how I wanted it to.
 

clolsonus

Well-known member
Wow, this is great stuff! Thanks for sharing and for the compliments. I'll definitely be looking into the code on github.
Quick Q: what is the bit resolution for your pitot readings? 16-bit, 12-bit, etc?

The pressure sensors we typically fly with have 14-bit resolution with an i2c interface to the sensor IO board (aka teensy 3.6.) These are the ones we use: https://bolderflight.com/technical/#Swift-Air-Data

This gives us both airspeed and altitude. The static pressure sensor is also ported so we aren't just measuring cabin pressure (which is biased by airspeed.) We "tee" the static port off the pitot tube to feed the static pressure sensor for barometric altitude.

From my experience, I don't think you'll notice much practical difference between 10-bit resolution vs. 16-bit resolution on the airspeed sensor. It's just going to be a noisy thing no matter what. That's why I add some smoothing. Smoothing also adds delay, so it's a delicate balance and where you set the knob (between smooth vs. fast) depends on what you want to use the value for ... airspeed control, ground station display, data logging, stall warning, etc....
 

JLJ

New member
The pressure sensors we typically fly with have 14-bit resolution with an i2c interface to the sensor IO board (aka teensy 3.6.) These are the ones we use: https://bolderflight.com/technical/#Swift-Air-Data

This gives us both airspeed and altitude. The static pressure sensor is also ported, so we aren't just measuring cabin pressure (which is biased by airspeed.) We "tee" the static port off the pitot tube to feed the static pressure sensor for barometric altitude.

From my experience, I don't think you'll notice much practical difference between 10-bit resolution vs. 16-bit resolution on the airspeed sensor. It's just going to be a noisy thing no matter what. That's why I add some smoothing. Smoothing also adds delay, so it's a delicate balance and where you set the knob (between smooth vs. fast) depends on what you want to use the value for ... airspeed control, ground station display, data logging, stall warning, etc....

That is quite good material!

I've fiddled around with air data computers for a while.

A DIY release of an air data computer is that one by Basic Air Data. An ADC is a unit capable to provide airspeed (IAS), true airspeed (TAS), outside temperature, barometric altitude

As all the code is available on Github, it is pretty hackable. There is also a dedicated Android app for helping with telemetry on the field.
To calculate the airspeed IAS you can go straight with the following microcontroller friendly formula

Airspeed, IAS(m/s).
_qc is the differential pressure (Pa) (remember to trash the negative values if you are flying)
_uqc is the uncertainty on pressure measurement (Pa)

IAS=1.27775310604201*sqrt(_qc);
Uncertainty on IAS uIAS=0.638876553021004/(sqrt(abs(_qc)))*_uqc;

Regarding measurements, if you want high-frequency measurements you should place the sensors as close as possible to the pitot tube; piping adds delay.
 

Power_Broker

Active member
On a much less technical note, I want to share this video.

Somewhere around 3 years ago I saw the vid on youtube and inspired all of this. Pretty much the whole idea to fly planes with my own Arduinos came to me after I was memorized by this video:


A big thanks and shout-out to icastel101!
 
  • Like
Reactions: JLJ

clolsonus

Well-known member
Hah, that same p-51 video has stuck in my head ever since I saw it too. My pipe dream goes something like this: 1. paint the interior of the airplane green (like for green screening it.) 2. paste an aruco code (kind of like a qr code) where the panel should be. 3. Fly with a flight data logger (imu, gps, air data, etc.) 3. Use augmented reality tricks to rerender the cockpit video, but this time draw a "live" virtual cockpit (maybe borrowing from FlightGear's immensely impressively detailed virtual p-51 cockpit.) The virtual cockpit could be animated from the real flight data log so all the gauges would read correct values (including the artificial horizon) ... and you would see the real out the world view, real wing/tail/nose, etc.
I was thinking about this same thing when the guys did the giant A-10 video ... if they would have only collected flight data logs and pasted an aruco code where the panel would have gone, I could have done the rest (maybe?) :)
 
  • Like
Reactions: JLJ

Power_Broker

Active member
Update #37.)

Because of the look of my latest plane's frame design and color, I've decided to give it the nickname "Screamin' Seagull"

The inspiration also came from being an avid follower of memes:

Etg0UCK.jpg

- I've also fixed the GPS library to intake and process all UTC fix-time, course over ground, and speed over ground data
- The telemetry algorithms have also been updated to pass the new data to the ground station
- I've taken the GS-to-PC telemetry printouts that were originally included in the example GS sketch as individual serial.print() calls and replaced them with a single new function within the myGS class called sendTelem(). This simplifies the GS code and allows a standard reporting format for datalogging programs running on a PC. This will make it easier for the datalogging programs to read in, unpack, and process plane telemetry data as it streams from the hand controller.
- I also have been messing with a Python GUI on my laptop to log airplane telemetry data, display telemetry real-time, and display the FPV video feed
- Noticed that the Python GUI is having a tough time processing all the telemetry data as fast as it needs to - It's processing and logging telemetry data at 2Hz while the telemetry packets are being sent at 10Hz :(
 

JTarmstr

Elite member
Ok so I have to ask. I have been watching this for about 3 months now and watching your progress with this. How hard would it be for someone with a basic understanding of how computers and Arduinos work, minimal soldering skills, limited funding and a good understanding of aerodynamics to build something like this and get it to work?