Project in progress
Autonomous High Altitude Glider

Autonomous High Altitude Glider © CC BY

A fully autonomous fixed-wing glider designed to safely return a payload after being deployed on near-space missions.

  • 14,032 views
  • 8 comments
  • 56 respects

Components and supplies

Ardgen 101
Arduino 101 & Genuino 101
The Gyro and Accelerometer in the Curie IMU is the main reason we're using the 101
×1
Servos (Tower Pro MG996R)
Used for glider flaps. We used metal gear 15g servos.
×2
u-blox uBLOX MAX-M8Q GPS
We're specifically using this due to the fact that it does not have a GPS cutoff as long as you aren't moving 515 m/s. The module itself is rated at 50,000 meters.
×1

Apps and online services

About this project

  • Update 3: Tarik uploaded Project Log 2, we'll be rebuilding the airframe this week. Feel free to ask us any questions and we'll do a video Q&A if we receive enough questions!

Introduction

High Altitude Balloon missions are usually very risky, as there is a high chance of losing or damaging one’s payload during a mission. There are a lot of points of failure, and it is easy to lose track of your payload. Our Autonomous High Altitude Glider project aims to solve that issue. The glider deploys when it reaches a target altitude, detaches from the balloon, and navigates back to a predetermined location using GPS and Gyroscope/Accelerometer data.

This project originally began in 2015, but very little progress was made until it was put on the shelf until June 2017. We plan on finishing this project with at least one successful mission by the end of 2017.

Plan

The current plan is to deploy a fixed-wing glider at an altitude of 100,000 ft(approx. 30.5 km.), and navigate back to our launch site. Our flight path is as follows:

  • Deploy at 100,000 ft
  • Detach from balloon
  • Dive until the glider reaches an altitude of 30,000 ft(In order to avoid strong winds and jet streams)
  • Maneuver to predetermined location
  • Spiral down and stall to kill speed and land safely
  • Land

We are using Tarik’s “Sequioa” UAV design, a fixed-wing, plank-style glider. The glider is controlled via a receiver and an Arduino 101 linked with a Raspberry Pi. We are currently considering fiberglassing the glider to increase its durability and endurance.

To stabilize the aircraft and implement autonomous navigation algorithms, we used a PID algorithm to adjust the servos to react to the gliders position and orientation. This is used to counteract wind, as with a normal Proportional feedback loop, the glider would not be able to account for wind and counteract current. This would be undesirable, as we would lose control of the aircraft, and regaining control would be a very difficult task.

For our navigation algorithm, we plan on integrating weather patterns, GPS data, and accelerometer data to calculate the best route possible in real time. The glider is linked to our computers via a radio link, allowing us to monitor the glider, and the glider to receive weather data in real time. Route calculation is done on the fly (pun intended), and uses a set of maneuvers that we have modeled in simulations to prevent any errors with our PID algorithm.

For telemetry data and communications purposes, we will be connected to the glider via a radio link that provides us with sensor data, location data, status updates and errors, a live video feed, and a manual override option should any issues arise from our autonomous glider program.

We are currently working on pursuing sponsors, as we would like to add more cameras to our glider to obtain high altitude footage.

Goals & Deadlines

Our main goal is to develop an autonomous glider that can successfully return a payload from an altitude of 100,000 ft.

Risks

  • Temperatures in high altitudes can reach a chilly -40 degrees Celsius, which would prevent our batteries from working properly. We plan on insulating our electronics, and possibly incorporating a heater into our control hardware.
  • Wind – Wind blowing against the glider would prevent it from following its route. This is why we are working on incorporating weather data into our navigation algorithm in order to have our glider fly through the safest and most efficient zones possible. Our initial dive maneuver is mainly to fly to lower altitudes to fly in a zone that is less likely to have strong winds.
  • Code – A lot of things can go wrong with our program, so we are currently doing our best to eliminate glitches and bugs in our code.
  • GPS Cutoff – Most GPS modules shut off after reaching 20,000 meters as a safety measure, which would mean that the glider will have to navigate without knowing its location in its initial maneuvers. We plan on reducing the risks associated with navigating with no GPS by having the glider dive to lower altitudes and attempt to navigate using our flight estimations until it can receive GPS data.

Progress

We have developed the PID loop, and are adding our finishing touches to it. Our next step in the process is to develop a navigational algorithm that uses and tracks location data to interpret weather data, measure the speed of the glider, and determine the optimal route. Once that is done, we will then run a few tests, finalize our code, and launch our glider.

Update 1: PID Stabilizer code is finally finished, and Tarik is doing some finishing touches to the code. It corrects the glider's orientation by mixing two PID loops for the Roll and Pitch Axes, and controls two servos that will be attached to the flaps of the glider soon.

Video demonstrating the PID Code. Apologies for the vertical video.

Update 2: Getting GPS Data!

We recently got our GPS sensor working, and have finally been able to pull data from it! The following program shows how we got Speed, Heading, and Location Data from a Ublox Max-M8Q connected to our Arduino 101.

We’re going to be using this data along with an Input coordinate to plan a path for the glider, then use our previous PID Code so that our target direction will be determined by the difference between its current location and the target location/waypoint in 3D space.

#include <SoftwareSerial.h>
#include <TinyGPS.h>

long lat,lon; // create variable for latitude and longitude object
float heading;
float speed;

SoftwareSerial gpsSerial(7, 8); // create gps sensor connection
TinyGPS gps; // create gps object

void setup(){
 Serial.begin(9600); // connect serial
 gpsSerial.begin(9600); // connect gps sensor
}

void loop(){
 while(gpsSerial.available()){ // check for gps data
  if(gps.encode(gpsSerial.read())){ // encode gps data
   gps.get_position(&lat,&lon); // get latitude and longitude
   speed = gps.f_speed_mps(); //Speed in m/s
   heading = gps.f_course(); //Heading in degrees

   //Output Data:
   Serial.print("Heading: "); Serial.print(heading);
   Serial.print("Speed: "); Serial.print(speed);
   Serial.print("Position: ");Serial.print("lat: ");Serial.print(lat);Serial.print(" ");// print latitude
   Serial.print("lon: ");Serial.println(lon); // print longitude
  }
 }
}

Project Log 1 by Tarik Agcayazi:

Project Log 2 by Tarik Agcayazi:

Project Log 3 by Tarik Agcayazi:

Project Log 4 by Tarik Agcayazi:

Collaborizm Project Page: https://www.collaborizm.com/project/Sk3JncxD-

Code

PID Stabilizer CodeC/C++
This is the first iteration of our glider code; it makes the glider attempt to fly straight.
/*Arduino 101 Glider Stabilizer
*By: Kemal Ficici and Tarik Agcayazi
*
*Current code only sabilizes glider back to 0,0,0 degrees X,Y,Z.
*TO DO - TEST OUT PID WITH SERVOS ATTACHED TO GLIDER FLAPS
*TO DO - Fix PID mixing(line 130,131)
*TO DO - Maneuvers(Initial Dive, Turns, Spiral)
*TO DO - Navigate to GPS Coordinate, Dive till set altitude, release mechanism
*
*https://playground.arduino.cc/Code/PIDLibrary
*https://www.arduino.cc/en/Tutorial/Genuino101CurieIMUOrientationVisualiser
*/

#include <CurieIMU.h>
#include <MadgwickAHRS.h>
#include <PID_v1.h>
#include <Servo.h>


///////////////////////////////IMU Stuff///////////////////////////////////
Madgwick filter;
unsigned long microsPerReading, microsPrevious;
float accelScale, gyroScale;
float roll, pitch, heading;
///////////////////////////////IMU Stuff///////////////////////////////////



/////////////////////////////////PID Stuff////////////////////////////////////////
double Kp=1, Ki=1, Kd=0.07;  //PID Tuning Parameters (NOTE: idk if I tuned it properly)
//     Roll PID stuff
double rollSetpoint, rollInput, rollOutput;
PID rollPID(&rollInput, &rollOutput, &rollSetpoint, Kp, Ki, Kd, DIRECT);


//   PitchPID Stuff
double pitchSetpoint, pitchInput, pitchOutput;
PID pitchPID(&pitchInput, &pitchOutput, &pitchSetpoint, Kp, Ki, Kd, DIRECT);


//Specify the links and initial tuning parameters
/////////////////////////////////PID Stuff////////////////////////////////////////


Servo leftServo, rightServo; //Servos for flaps
int leftOutput, rightOutput; //Output for flaps

void setup(){
    Serial.begin(9600);
    ///////////////PID Setup/////////////
      rollInput = roll; //Sets the PID inputs to the gyro's roll and pitch axes
      pitchInput = pitch;
    
      rollSetpoint = 0; 
      pitchSetpoint = 0;
    
      rollPID.SetOutputLimits(-90, 90); //limits the PID loop to output numbers in between -90 and 90. I used values from -90 to 90 in order to better visualize the glider position(when flaps are flat, the PID output is 0)
      pitchPID.SetOutputLimits(-90,90);
    
      rollPID.SetMode(AUTOMATIC);  //Turns PID on
      pitchPID.SetMode(AUTOMATIC);
    ///////////////PID Setup/////////////
    
    
    ///////////////IMU Setup/////////////
      // start the IMU and filter
      CurieIMU.begin();
      CurieIMU.setGyroRate(25);
      CurieIMU.setAccelerometerRate(25);
      filter.begin(25);
    
      // Set the accelerometer range to 2G
      CurieIMU.setAccelerometerRange(2);
      // Set the gyroscope range to 250 degrees/second
      CurieIMU.setGyroRange(250);
    
      // initialize variables to pace updates to correct rate
      microsPerReading = 1000000 / 25;
      microsPrevious = micros();
    ///////////////IMU Setup/////////////
    
      leftServo.attach(9);
      rightServo.attach(10); 
}//setup()


void loop() {
  rollInput = roll; //sets PID inputs to Roll and Pitch
  pitchInput = pitch;
  rollPID.SetTunings(Kp, Ki, Kd); //PID Tunings
  pitchPID.SetTunings(Kp, Ki, Kd);

  int aix, aiy, aiz;  //IMU Stuff
  int gix, giy, giz;
  float ax, ay, az;
  float gx, gy, gz;

  unsigned long microsNow;

  // check if it's time to read data and update the filter
  microsNow = micros();
  if (microsNow - microsPrevious >= microsPerReading) {

    // read raw data from CurieIMU
    CurieIMU.readMotionSensor(aix, aiy, aiz, gix, giy, giz);

    // convert from raw data to gravity and degrees/second units
    ax = convertRawAcceleration(aix);
    ay = convertRawAcceleration(aiy);
    az = convertRawAcceleration(aiz);
    gx = convertRawGyro(gix);
    gy = convertRawGyro(giy);
    gz = convertRawGyro(giz);

    // update the filter, which computes orientation
    filter.updateIMU(gx, gy, gz, ax, ay, az);

    // print the heading, pitch and roll
    roll = filter.getRoll();
    pitch = filter.getPitch();
    heading = filter.getYaw();



    //Calculates PID
    rollPID.Compute();
    pitchPID.Compute();

    //Combines the outputs and adds 90 to make it work with the servos
    leftOutput = ((rollOutput + pitchOutput) / 2) + 90;
    rightOutput = ((rollOutput - pitchOutput) / 2) + 90;

    
    /*  ^^^^^^^^^^NOTE TO TARIK: PLEASE FIX MIXING PIDS ^^^^^^^^^^^^^^^
     *  One issue with the code is that the way I mix the Roll and Pitch PID loops
     * is not the best way to mix PID loops. For instance, if the pitchPID was 90, and 
     * rollPID was 0, both flaps would not trim up, rather, rightServo would be at -45,
     * while leftServo trims at 135.  
     * 
     * ^^^^^^^^^^^NOTE TO TARIK: TEST OUT CODE WITH SERVOS ATTACHED TO GLIDER FLAPS^^^^^^^^^^^^
     */

     
    //writes to the servos
    leftServo.write(leftOutput);
    rightServo.write(rightOutput);
    Serial.println(pitch);
    // increment previous time, so we keep proper pace
    microsPrevious = microsPrevious + microsPerReading;
  } //if
    
} //loop()

float convertRawAcceleration(int aRaw) {
  // since we are using 2G range
  // -2g maps to a raw value of -32768
  // +2g maps to a raw value of 32767
  
  float a = (aRaw * 2.0) / 32768.0;
  return a;
}

float convertRawGyro(int gRaw) {
  // since we are using 250 degrees/seconds range
  // -250 maps to a raw value of -32768
  // +250 maps to a raw value of 32767
  
  float g = (gRaw * 250.0) / 32768.0;
  return g;
}
  

Comments

Similar projects you might like

Arduino Bluetooth Basic Tutorial

by Mayoogh Girish

  • 454,712 views
  • 42 comments
  • 237 respects

Home Automation Using Raspberry Pi 2 And Windows 10 IoT

Project tutorial by Anurag S. Vasanwala

  • 285,500 views
  • 95 comments
  • 671 respects

Security Access Using RFID Reader

by Aritro Mukherjee

  • 229,333 views
  • 38 comments
  • 236 respects

OpenCat

Project in progress by Team Petoi

  • 195,923 views
  • 154 comments
  • 1,361 respects
Add projectSign up / Login