Wednesday, August 14, 2013

Testing Distance Sensor

We have tried to test and calibrate the distance sensor (SHARP 2Y0A21) using Arduino. Based on the lab test of a specific detector, the sensor data is noisy sometimes and only works for distance from 5 cm to 40 cm. We added a filter using median data of readings. And, we convert the readings to actual distance by using a quadratic regression curve fit. The test result is not perfect but acceptable. The Arduino code is attached below.

/********************************************************************
  Blinking two LED repeatly for visual effect.
  Measuring distance using SHARP 2YOA21 IR distance detector.
  Based on the lab test, the distance detector works between 5-40 cm.
*********************************************************************/

// pin 10 & pin 13 have LEDs connected.
int led1 = 13;
int led2 = 10;

// pin A2 has an distance detector connected.
int IRSensor = A2;

// number of readings used to smooth the sensor data.
const int numReadings = 5;

// distance detector readings array
int readings[numReadings];

// distance array for comparison
int IRState[numReadings];

// median of the "numReadings" distance detector readings
int IRMedian;

int i, j;
int tmp;
int distance;

// the setup routine runs once when you press reset:
void setup() {               
  // initialize the digital pin as an output.
  pinMode(led1, OUTPUT);   
  pinMode(led2, OUTPUT);  
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);
  // make the IRSensor's pin an input:
  pinMode(IRSensor, INPUT);
  // initialize arrays
  for (i = 0; i <
numReadings; i++)
  {
    readings[i] = 650;
    IRState[i] = 650;
  }
}

// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led1, HIGH);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(led2, LOW);   // turn the LED on (HIGH is the voltage level)
  delay(20);               // wait for 0.02 second
  digitalWrite(led1, LOW);    // turn the LED off by making the voltage LOW
  digitalWrite(led2, HIGH);    // turn the LED off by making the voltage LOW
  delay(20);               // wait for 0.02 second
 
  // read the input pin and put the value at the end of the readings array:
  for (i = 0; i < numReadings - 1; i++)
    readings[i] = readings[i+1];
  readings[numReadings - 1] = 650 - analogRead(IRSensor);
 
  // copy readings array to IRState array for comparison
  for (i = 0; i < numReadings; i++)
    IRState[i] = readings[i];
 
  // bubble sort IRState array
  for (i = 0; i < numReadings - 1; i++)
  for (j = i+1; j < numReadings; j++)
    if(IRState[i] <= IRState[j])
    {
      tmp = IRState[i];
      IRState[i] = IRState[j];
      IRState[j] = tmp;
    }
  // find median 
  IRMedian = IRState[numReadings/2]; 
 
  // converting the sensor readings to distance through a quadratic regression curve fit
  distance = 0.000162059 * (float) IRMedian * (float) IRMedian - 0.0290382 * (float) IRMedian + 7.17082;

  // Print out the distance on serial port
  Serial.println(distance);
  delay(1);        // delay in between reads for stability
}

Thursday, August 8, 2013

Programming Notes of City Drone App (An Modified AR Drone FreeFlight App)

AR Drone SDK 2.0.1 provides the source code of the FreeFlight App for controlling the AR Drone 2.0. In the past month, we have spent time to study this complex code from scratch. The objectives are two folds.
  1. Understand how FreeFlight App control the motions of AR Drone 2.0 such that we can direct the drone to move in any ways we want, and perform a sequence of actions through our program.
  2. Understand how to acquire and interpret the sensor data from the drone such that we can develop algorithms to generate navigation commands based on the sensor data.
The final goal is to create our own apps with various functions which the drone can perform the tasks autonomously.

So far, we have achieve the first objective, and ready to look into the sensor data. A couple of lessons have been learned through this exploration process, and are summarized below.
  1. The XCode warning: "PIE disabled": This annoying warning causing lots of confusing and costing lots of time at the beginning of the project can be removed by simply change the Build Settings > Linking > Don't Create Position Independent Executables flag from No to Yes.
  2. Since the FreeFlight App includes ARDroneLib and ARDroneEngine, the motion control can be done in many different levels such as the user interface level, the ARDronetool level, the AT commands level, or the mix of some of them.
  3. Before we looking into the FreeFlight code, we have learned to use the app to control the drone. This experience helped us understand the organization and function of the user interface.
  4. Our focus has been on the ARDroneEngine.xcodeproj > ARDroneEngine > Classes > Menus > hud.h & hud.m. They include four major IBAction methods (buttonClick, buttonPress, buttonDrag, and buttonRelease) reacting to the user interactions.
  5. To take over the control of the original interface, I deleted the left and right joysticks in the current interface and create fourteen new buttons (taking-off, landing, up, down, forward, backward, left, right, rotate clockwise, rotate counter-clockwise, flip left, flip right, hovering, and flight routine) to implement the motion control of AR Drone 2.0. Instead of using all four methods, we used only the buttonClick method, and expanded its function to cover all fourteen buttons.
  6. The original motion control of forward, backward, left and right through tilting the iPhone/iPad has been disabled. The new motion control is done by changing the tilting angles (theta and phi) to preset values depending on the buttons clicked.
  7. The original motion control of upward, downward, rotate clockwise and rotate counter-clockwise through dragging the right joystick iPhone/iPad has been disabled. The new motion control is done by changing the percentages of dragging (percent) to preset values depending on the buttons clicked. 
  8. The flight routine is currently implemented with a series of NSTimers (not been posted) for proof of concept. The code will need to be further simplified.
The modified code for the buttonClick method is attached in the following:

- (IBAction)buttonClick:(id)sender forEvent:(UIEvent *)event
{
    static ARDRONE_VIDEO_CHANNEL channel = ARDRONE_VIDEO_CHANNEL_FIRST;
    if(sender == settingsButton)
    {   ......   }
    else if(sender == backToMainMenuButton)
    {   ......   }
    else if(sender == switchScreenButton)
   
{   ......   }
    else if(sender == cameraButton)
   
{   ......   }
    else if(sender == takeOffButton)
   
{   ......   }
    else if(sender == emergencyButton)
    {   ......   }
    else if(sender == latencyButton)
    {   ......   }
    else if(sender == recordButton)
    {   ......   }
    else if(sender == popUpCloseButton)
    {   ......   }
    else if(sender == flight0Button)    // Hovering
    {
        controls_table[controlMode].Right.up_down(0.0);
        controls_table[controlMode].Right.left_right(0.0);
        controls_table[controlMode].Left.up_down(0.0);
        controls_table[controlMode].Left.left_right(0.0);
        angle_theta = 0.0;
        angle_phi   = 0.0;       
        ctrldata.command_flag |= (0 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
        ctrldata.command_flag |= (0 << ARDRONE_PROGRESSIVE_CMD_ENABLE);
    }
    else if(sender == flight1Button)    // Taking Off
    {
        ardrone_tool_set_ui_pad_start(1);
    }
    else if(sender == flight2Button)    // Moving Right
    {
        ctrldata.command_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
        ctrldata.command_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_ENABLE);       
        angle_theta = 0.0;
        angle_phi   = 0.1;
    }
    else if(sender == flight3Button)    // Right Flip
    {
        string_t anim;
        snprintf (anim, STRING_T_SIZE, "%d,%d", ARDRONE_ANIM_FLIP_RIGHT, MAYDAY_TIMEOUT[ARDRONE_ANIM_FLIP_RIGHT]);
        ARDRONE_TOOL_CONFIGURATION_ADDEVENT(flight_anim,anim,NULL);
    }
    else if(sender == flight4Button)    // Landing
    {
        ardrone_tool_set_ui_pad_start(0);
    }
    else if(sender == flight5Button)    // Moving Up
    {
        controls_table[controlMode].Right.up_down(0.2);
    }
    else if(sender == flight6Button)    // Moving Left
    {
        ctrldata.command_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
        ctrldata.command_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_ENABLE);
        angle_theta = 0.0;
        angle_phi   = -0.1;
    }
    else if(sender == flight7Button)    // Left Flip
    {
        string_t anim;
        snprintf (anim, STRING_T_SIZE, "%d,%d", ARDRONE_ANIM_FLIP_LEFT, MAYDAY_TIMEOUT[ARDRONE_ANIM_FLIP_LEFT]);
        ARDRONE_TOOL_CONFIGURATION_ADDEVENT(flight_anim,anim,NULL);
    }
    else if(sender == flight8Button)    // Moving Down
    {
        controls_table[controlMode].Right.up_down(-0.2);
    }
    else if(sender == flight9Button)    // Rotating Clockwise
    {
        controls_table[controlMode].Right.left_right(0.6);
    }
    else if(sender == flight10Button)   // Rotating Counter Clockwise
    {
        controls_table[controlMode].Right.left_right(-0.6);
    }
    else if(sender == flight11Button)   // Moving Forward
    {
        ctrldata.command_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
        ctrldata.command_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_ENABLE);
        angle_theta = -0.1;
        angle_phi   = 0.0;
    }
    else if(sender == flight12Button)   // Moving Backward
    {
        ctrldata.command_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
        ctrldata.command_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_ENABLE);
        angle_theta = 0.1;
        angle_phi   = 0.0;
    }
    else if(sender == flight13Button)   // Flight Routine (Taking Off)
    {
        ardrone_tool_set_ui_pad_start(1);
        timer1 = [[NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(5) target:self selector:@selector(action1) userInfo:nil repeats:YES] retain];
    }
}

Wednesday, August 7, 2013

City Drone Test App

City Drone Icon
Based on our collective efforts in the past few weeks, I have made an iOS App, City Drone, to integrate all the test functions and a flight routine together in a simple user interface. You can see the screenshots from the App.

The interface of motion control include 14 buttons (taking-off, landing, up, down, forward, backward, left, right, rotate clockwise, rotate counter-clockwise, flip left, flip right, hovering, and flight routine).

The flight routine includes a series of movements performed by the drone autonomously.The following video captured this flight routine.
Launch Image
Motion Control User Interface

Flight Routine Video

Final Breakthrough

Alan and Jason had tested numerous times to break the code and get control of the drone. They finally made a breakthrough and came up this circular flight routine.
 

Altitude and Position Control Simulation

Pablo and Massaer have been working on the altitude and position control for the drone. They studied the physics and mathematical models of the drone, and used Matlab to build and simulate a PID controller. Please see their results.
A PID Controller for Altitude Contro

Matlab Simulation of Altitude Control
Simulation of Altitude (Blue) and Position (Magenta) Control

Altitude Change Detection (Vidoe Shared by Eric)


Autonomous Flight Based on a Python Script

Eric and Daniel have been working on the Drone control using Windows-based tool AutoFlight. In the video, the drone is operated based on a Python script which will detect the altitude change. It will take off, move forward, and land autonomously when it detects the table.

Thursday, August 1, 2013

Drone: A Shadow Chaser

Last night I was testing my AR Drone App at home. After it broke something in my living room, I decided to go out and test it out on the street. It was 1:30 am, and it's so quiet and dark on the street....

The drone was taking off and starting running the flight routine according to my program. "It works!!!" I almost screamed. However, it drifted a lot!?! Pretty soon  I noticed that the reason may come from the drone's own shadow!

During the taking-off and hovering process, the drone uses its vertical camera to maintain its location. In the night time, the street light makes a vivid shadow of the drone, and the shadow becomes the most visible feature on the ground. When drone rises, the shadow moves away from the street light, and thus from the drone itself. The drone's control software will try to hover above its own shadow by moving toward it, and the shadow will further move away,......
So, the drone becomes a shadow chaser!

It sounds like an interesting combination of a feedback control problem and a related rates problem in calculus. The drone's own shadow might become a threat to its autonomous flight during night time. Any solutions? Sounds like a mini topic for MAV research. What do you think?