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];
    }
}

No comments:

Post a Comment