RC Plane Library (ArdUAV)

Hello all,

Once in a while I find hobbyists and students interested in making an Arduino-based RC airplane. Myself being one of these, I've designed, wrote, and tested a new library to make the software side of Arduino RC planes easier.

Youtube of RC plane flight with ArdUAV library

Link to the (extensive) build-log of the plane in the above vid

ArdUAV is an Arduino compatible C++ library that can easily be configured and used to control a completely Arduino-based RC airplane and transmitter. ArdUAV will handle all the background processing necessary to keep your plane flying in as little as 5-10 lines of sketch code. In addition to abstracting flight functions, it also provides transparency to all sensor outputs and servo commands. This allows you to write your own custom flight controller code in your sketch (i.e. GPS waypoint flying, ILS, camera gimbal control, etc) easily and with great readability.

Here is an example of the hand controller code:

#include "GS_Tools.h"




void setup()
{
  //initialize the core ground station software class
  myGS.begin();
}




void loop()
{
  //determine each command value based off GS sensor data and send commands to plane
  myGS.computeAndSendCommands();

  //send data to datalogging computer via debugging port
  myGS.sendTelem();
}

And here is an example of the flight controller code:

#include "IFC_Tools.h"




void setup()
{
  //initialize the core flight controller software class
  myIFC.begin();
}




void loop()
{
  //get GPS data
  if(myIFC.grabData_GPS())
  {
    //optional debugging prints
    /*IFC_DEBUG_PORT.print("Latitude:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.latitude, 5);
    IFC_DEBUG_PORT.print("Longitude:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.longitude, 5);
    IFC_DEBUG_PORT.print("UTC_year:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.UTC_year);
    IFC_DEBUG_PORT.print("UTC_month:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.UTC_month);
    IFC_DEBUG_PORT.print("UTC_day:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.UTC_day);
    IFC_DEBUG_PORT.print("UTC_hour:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.UTC_hour);
    IFC_DEBUG_PORT.print("UTC_minute:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.UTC_minute);
    IFC_DEBUG_PORT.print("UTC_second:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.UTC_second);
    IFC_DEBUG_PORT.print("Speed Over Ground:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.speedOverGround, 3);
    IFC_DEBUG_PORT.print("Course Over Ground:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.courseOverGround, 3);
    IFC_DEBUG_PORT.println();*/
  }

  //get IMU data
  if(myIFC.grabData_IMU())
  {
    //optional debugging prints
    /*IFC_DEBUG_PORT.print("Pitch Angle:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.pitchAngle, 5);
    IFC_DEBUG_PORT.print("Roll Angle:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.rollAngle, 5);
    //IFC_DEBUG_PORT.print("Course Angle:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.courseAngle, 5);
    IFC_DEBUG_PORT.println();*/
  }

  //get LiDAR altimeter data
  if(myIFC.grabData_LiDAR())
  {
    //optional debugging prints
    /*IFC_DEBUG_PORT.print("Converted Altitude:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.convertedAltitude);
    IFC_DEBUG_PORT.println();*/
  }

  //get airspeed data from the pitot tube
  if(myIFC.grabData_Pitot())
  {
    //optional debugging prints
    /*IFC_DEBUG_PORT.print("Converted Airspeed:\t"); IFC_DEBUG_PORT.println(myIFC.telemetry.velocity);
    IFC_DEBUG_PORT.println();*/
  }

  //update all servo positions based on the new data
  myIFC.updateServos();

  //send the telemetry to the radio
  myIFC.sendTelem();
}

Both myGS and myIFC classes have public "telemetry" and "controlInputs" structs that provide the data transparency as described earlier. They are defined as:

	//struct to store telemetry data
	struct telemetry
	{
		float altitude;             //cm
		float convertedAltitude;    //cm
		float courseAngle;          //degrees
		float rollAngle;            //degrees
		float pitchAngle;           //degrees
		float convertedRoll;        //radians
		float convertedPitch;       //radians
		float velocity;             //m/s
		float latitude;             //dd
		float longitude;            //dd
		uint16_t UTC_year;          //y
		uint16_t UTC_month;         //M
		uint16_t UTC_day;           //d
		uint16_t UTC_hour;          //h
		uint16_t UTC_minute;        //m
		uint16_t UTC_second;        //s
		float speedOverGround;      //knots
		float courseOverGround;     //degrees
	} telemetry;

	//struct to store control values (i.e. servo commands etc.)
	struct controlInputs
	{
		bool limiter_enable; //enables and disables pitch and bank limiter
		uint16_t pitch_command;
		uint16_t roll_command;
		uint16_t yaw_command;
		uint16_t throttle_command;
		uint16_t autopilot_command;
		uint16_t limiter_command;
		uint16_t landingGear_command;
		uint16_t flaps_command;
	} controlInputs;

Let me know what y'all think and if there are any improvements to be made!