ArDrone SDK 1.8 added
[mardrone] / mardrone / ARDrone_SDK_Version_1_8_20110726 / ControlEngine / iPhone / Classes / Menus / HUD.m
diff --git a/mardrone/ARDrone_SDK_Version_1_8_20110726/ControlEngine/iPhone/Classes/Menus/HUD.m b/mardrone/ARDrone_SDK_Version_1_8_20110726/ControlEngine/iPhone/Classes/Menus/HUD.m
new file mode 100644 (file)
index 0000000..5cb4cec
--- /dev/null
@@ -0,0 +1,860 @@
+#import "HUD.h"
+#import <CoreMotion/CoreMotion.h>
+
+// Ratio to activate control yaw and gaz
+#define CONTROL_RATIO  (1.0 / 3.0)
+#define CONTROL_RATIO_IPAD (1.0 / 6.0)
+
+#define ACCELERO_THRESHOLD     0.1
+#define ACCELERO_NORM_THRESHOLD        0.0
+#define ACCELERO_FASTMOVE_THRESHOLD    1.3
+
+// Determine if a point within the boundaries of the joystick.
+static bool_t isPointInCircle(CGPoint point, CGPoint center, float radius) {
+       float dx = (point.x - center.x);
+       float dy = (point.y - center.y);
+       return (radius >= sqrt( (dx * dx) + (dy * dy) ));
+}
+
+static float sign(float value)
+{
+       float result = 1.0;
+       if(value < 0)
+               result = -1.0;
+       
+       return result;
+}
+
+static float Normalize(float x, float y, float z)
+{
+       return sqrt(x * x + y * y + z * z);
+}
+
+static float Clamp(float v, float min, float max)
+{
+       float result = v;
+       if(v > max)
+               result = max;
+       else if(v < min)
+               result = min;
+
+       return result;
+}
+
+static CONTROLS controls_table[CONTROL_MODE_MAX] = 
+{
+       [CONTROL_MODE1] = { {FALSE, inputPitch, inputYaw}, {FALSE, inputGaz, inputRoll} },
+       [CONTROL_MODE2] = { {FALSE, inputGaz, inputYaw}, {TRUE, inputPitch, inputRoll} },
+       [CONTROL_MODE3] = { {TRUE, inputPitch, inputRoll}, {FALSE, inputGaz, inputYaw} },
+       [CONTROL_MODE4] = { {FALSE, inputGaz, inputRoll}, {FALSE, inputPitch, inputYaw} }
+};
+
+@interface HUD ()
+ControlData *controlData;
+ARDroneHUDConfiguration config;
+bool_t acceleroEnabled, combinedYawEnabled;
+CONTROL_MODE controlMode;
+float accelero[3];
+float accelero_rotation[3][3];
+UIAccelerationValue lastX, lastY, lastZ;
+double lowPassFilterConstant, highPassFilterConstant;
+BOOL accelerometer_started;
+CGPoint joystickRightCurrentPosition, joystickLeftCurrentPosition;
+CGPoint joystickRightInitialPosition, joystickLeftInitialPosition;
+BOOL buttonRightPressed, buttonLeftPressed;
+CGPoint rightCenter, leftCenter;
+float tmp_phi, tmp_theta;
+BOOL screenOrientationRight;
+float alpha;
+SystemSoundID plop_id, batt_id;
+FILE *mesures_file;
+BOOL running;
+
+BOOL compiledForIPad;
+BOOL usingIPad;
+BOOL using2xInterface;
+
+
+#if TARGET_IPHONE_SIMULATOR == 1
+NSTimer *timer;
+- (void)simulate_accelerometer:(id)sender;
+#else
+
+- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration;
+#endif
+- (void)setAcceleroRotationWithPhi:(float)phi withTheta:(float)theta withPsi:(float)psi;
+- (void)refreshJoystickRight;
+- (void)refreshJoystickLeft;
+- (void)updateVelocity:(CGPoint)point isRight:(BOOL)isRight;
+- (void)hideInfos;
+- (void)showInfos;
+- (void)refreshControlInterface;
+@end
+
+@implementation HUD
+@synthesize firePressed;
+@synthesize settingsPressed;
+@synthesize mainMenuPressed;
+
+- (id)initWithFrame:(CGRect)frame withState:(BOOL)inGame withHUDConfiguration:(ARDroneHUDConfiguration)hudconfiguration withControlData:(ControlData*)data
+{
+       NSArray *targetArray = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UIDeviceFamily"];
+       compiledForIPad = NO;
+       for (int i = 0; i < [targetArray count]; i++)
+       {
+               NSNumber* num = (NSNumber*)[targetArray objectAtIndex:i];
+               int value;
+               [num getValue:&value];
+               if (2 == value)
+               {
+                       compiledForIPad = YES;
+                       break;
+               }
+       }
+       
+       usingIPad = NO;
+       if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
+       {
+               usingIPad = YES;
+       }
+       
+       using2xInterface = NO;
+       if ([UIScreen instancesRespondToSelector:@selector(scale)]) {
+               CGFloat scale = [[UIScreen mainScreen] scale];
+               if (scale > 1.0) {
+                       using2xInterface = YES;
+               }
+       }       
+       
+       if (usingIPad && compiledForIPad)
+       {
+               self = [super initWithNibName:@"HUD-iPad" bundle:nil];
+       }
+       else
+       {
+               self = [super initWithNibName:@"HUD" bundle:nil];
+       }
+       NSLog(@"HUD frame => w : %f, h : %f", data, frame.size.width, frame.size.height);
+       if(self)
+       {
+               controlData = data;
+               running = inGame;
+               firePressed = NO;
+               settingsPressed = NO;
+               mainMenuPressed = NO;
+               
+               vp_os_memcpy(&config, &hudconfiguration, sizeof(ARDroneHUDConfiguration));
+               
+               acceleroEnabled = TRUE;
+               combinedYawEnabled = FALSE;
+               controlMode = CONTROL_MODE3;
+               buttonRightPressed = buttonLeftPressed = NO;
+               
+               rightCenter = CGPointZero;      
+               leftCenter = CGPointZero;
+               lowPassFilterConstant = 0.2;
+               highPassFilterConstant = (1.0 / 5.0) / ((1.0 / kAPS) + (1.0 / 5.0));
+               
+               joystickRightInitialPosition = CGPointZero;
+               joystickRightCurrentPosition = CGPointZero;
+               joystickLeftInitialPosition = CGPointZero;
+               joystickLeftCurrentPosition = CGPointZero;
+               
+               accelero[0] = 0.0;
+               accelero[1] = 0.0;
+               accelero[2] = 0.0;
+               
+               tmp_phi = 0.0;
+               tmp_theta = 0.0;
+               
+               [self setAcceleroRotationWithPhi:0.0 withTheta:0.0 withPsi:0.0];
+               
+               accelerometer_started = NO;
+
+#if TARGET_IPHONE_SIMULATOR == 1
+               [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1.0 / kAPS) target:self selector:@selector(simulate_accelerometer:) userInfo:nil repeats:YES];
+#else
+               [[UIAccelerometer sharedAccelerometer] setUpdateInterval: (NSTimeInterval)(1.0 / kAPS)];
+               [[UIAccelerometer sharedAccelerometer] setDelegate:self];
+#endif         
+
+#ifdef WRITE_DEBUG_ACCELERO    
+               char filename[128];
+               NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0];
+               sprintf(filename, "%s/accelero_iphones_mesures.txt",
+                               [documentsDirectory cStringUsingEncoding:NSUTF8StringEncoding]);
+               mesures_file = fopen(filename, "wb");
+               fprintf(mesures_file, "ARDrone\nNumSamples;AccEnable;AccXbrut;AccYbrut;AccZbrut;AccX;AccY;AccZ;PhiAngle;ThetaAngle;AlphaAngle\n");
+#endif
+       }
+
+       return self;
+}
+
+- (void) setAcceleroRotationWithPhi:(float)phi withTheta:(float)theta withPsi:(float)psi
+{      
+       accelero_rotation[0][0] = cosf(psi)*cosf(theta);
+       accelero_rotation[0][1] = -sinf(psi)*cosf(phi) + cosf(psi)*sinf(theta)*sinf(phi);
+       accelero_rotation[0][2] = sinf(psi)*sinf(phi) + cosf(psi)*sinf(theta)*cosf(phi);
+       accelero_rotation[1][0] = sinf(psi)*cosf(theta);
+       accelero_rotation[1][1] = cosf(psi)*cosf(phi) + sinf(psi)*sinf(theta)*sinf(phi);
+       accelero_rotation[1][2] = -cosf(psi)*sinf(phi) + sinf(psi)*sinf(theta)*cosf(phi);
+       accelero_rotation[2][0] = -sinf(theta);
+       accelero_rotation[2][1] = cosf(theta)*sinf(phi);
+       accelero_rotation[2][2] = cosf(theta)*cosf(phi);
+
+#ifdef WRITE_DEBUG_ACCELERO    
+       NSLog(@"Accelero rotation matrix changed :"); 
+       NSLog(@"%0.1f %0.1f %0.1f", accelero_rotation[0][0], accelero_rotation[0][1], accelero_rotation[0][2]);
+       NSLog(@"%0.1f %0.1f %0.1f", accelero_rotation[1][0], accelero_rotation[1][1], accelero_rotation[1][2]);
+       NSLog(@"%0.1f %0.1f %0.1f", accelero_rotation[2][0], accelero_rotation[2][1], accelero_rotation[2][2]); 
+#endif
+}
+
+#if TARGET_IPHONE_SIMULATOR == 1
+- (void)simulate_accelerometer:(id)sender
+{
+       UIAcceleration *acceleration = [[UIAcceleration alloc] init];
+#else
+- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
+{              
+#endif
+       static double highPassFilterX = 0.0, highPassFilterY = 0.0, highPassFilterZ = 0.0;
+       static bool_t prev_accelero_enabled = TRUE;
+       float norm, alpha;
+       float accelerox, acceleroy, acceleroz;
+       highPassFilterX = highPassFilterConstant * (highPassFilterX + acceleration.x - lastX);
+       highPassFilterY = highPassFilterConstant * (highPassFilterY + acceleration.y - lastY);
+       highPassFilterZ = highPassFilterConstant * (highPassFilterZ + acceleration.z - lastZ);
+       lastX = acceleration.x;
+       lastY = acceleration.y;
+       lastZ = acceleration.z;
+       
+       if(running)
+       {
+               if(fabs(highPassFilterX) > ACCELERO_FASTMOVE_THRESHOLD || 
+                  fabs(highPassFilterY) > ACCELERO_FASTMOVE_THRESHOLD || 
+                  fabs(highPassFilterZ) > ACCELERO_FASTMOVE_THRESHOLD)
+               {
+                       firePressed = YES;
+               }
+               else
+               {
+                       firePressed = NO;
+                                       
+                       if(acceleroEnabled)
+                       {
+                               if(screenOrientationRight)
+                               {
+                                       accelerox = acceleration.x;
+                                       acceleroy = -acceleration.y;
+                               }
+                               else
+                               {
+                                       accelerox = -acceleration.x;
+                                       acceleroy = acceleration.y;
+                               }
+                               acceleroz = -acceleration.z;
+                               
+                               // Initialize previous values of acceleros
+                               if(accelerometer_started == NO)
+                               {
+                                       accelerometer_started = YES;
+                                       accelero[0] = accelerox;
+                                       accelero[1] = acceleroy;
+                                       accelero[2] = acceleroz;
+                               }               
+
+                               // Apply low pass filter on acceleros
+                               accelero[0] = accelerox * lowPassFilterConstant + accelero[0] * (1.0 - lowPassFilterConstant);
+                               accelero[1] = acceleroy * lowPassFilterConstant + accelero[1] * (1.0 - lowPassFilterConstant);
+                               accelero[2] = acceleroz * lowPassFilterConstant + accelero[2] * (1.0 - lowPassFilterConstant);
+
+                               // Apply rotation matrix and Clamp
+                               accelerox = Clamp((accelero_rotation[0][0] * accelero[0]) + (accelero_rotation[0][1] * accelero[1]) + (accelero_rotation[0][2] * accelero[2]), -1.0, 1.0);
+                               acceleroy = Clamp((accelero_rotation[1][0] * accelero[0]) + (accelero_rotation[1][1] * accelero[1]) + (accelero_rotation[1][2] * accelero[2]), -1.0, 1.0);
+                               acceleroz = Clamp((accelero_rotation[2][0] * accelero[0]) + (accelero_rotation[2][1] * accelero[1]) + (accelero_rotation[2][2] * accelero[2]), -1.0, 1.0);
+                               
+                               // compute
+                               if(fabs(acceleroy) < ACCELERO_THRESHOLD)
+                               {
+                                       if(accelerox >= 0.0)
+                                               alpha = M_PI_2;
+                                       else    
+                                               alpha = -M_PI_2;
+                               }
+                               else
+                               {
+                                       alpha = atan2(accelerox, acceleroy);
+                               }
+                               
+                               norm = Normalize(accelerox, acceleroy, 0.0);
+                               if(norm > ACCELERO_NORM_THRESHOLD)
+                               {
+                                       float tmp = (norm - ACCELERO_NORM_THRESHOLD) * (norm - ACCELERO_NORM_THRESHOLD);
+                                       controlData->accelero_phi = tmp * cosf(alpha);
+                                       controlData->accelero_theta = -tmp * sinf(alpha);
+                               }
+                               else
+                               {
+                                       controlData->accelero_phi = 0.0;
+                                       controlData->accelero_theta = 0.0;
+                               }
+                       }
+                       else if(prev_accelero_enabled != acceleroEnabled)
+                       {
+                               controlData->accelero_phi = 0.0;
+                               controlData->accelero_theta = 0.0;
+                       }
+                       
+                       prev_accelero_enabled = acceleroEnabled;
+                       sendControls();
+               }
+       }       
+}
+
+- (void)refreshJoystickRight
+{
+       CGRect frame = joystickRightBackgroundImageView.frame;
+       frame.origin = joystickRightCurrentPosition;
+       joystickRightBackgroundImageView.frame = frame;
+}    
+
+- (void)refreshJoystickLeft
+{
+       CGRect frame = joystickLeftBackgroundImageView.frame;
+       frame.origin = joystickLeftCurrentPosition;
+       joystickLeftBackgroundImageView.frame = frame;
+}    
+
+- (void)refreshControlInterface
+{
+       if(acceleroEnabled)
+       {
+               switch (controlMode) {
+                       case CONTROL_MODE2:
+                               joystickLeftBackgroundImageView.hidden = NO;
+                               joystickRightBackgroundImageView.hidden = YES;
+                               break;
+                               
+                       case CONTROL_MODE3:
+                       default:
+                               joystickLeftBackgroundImageView.hidden = YES;
+                               joystickRightBackgroundImageView.hidden = NO;
+                               break;
+               }
+       }
+       else
+       {
+               joystickLeftBackgroundImageView.hidden = NO;
+               joystickRightBackgroundImageView.hidden = NO;
+       }
+
+       [self refreshJoystickRight];
+       [self refreshJoystickLeft];
+}
+       
+- (void)changeState:(BOOL)inGame
+{
+       printf("%s - running : %d, inGame : %d\n", __FUNCTION__, running, inGame);
+       running = inGame;
+       if(!inGame)
+       {
+               if(buttonRightPressed)
+                       [joystickRightButton sendActionsForControlEvents:UIControlEventTouchCancel];
+               
+               if(buttonLeftPressed)
+                       [joystickLeftButton sendActionsForControlEvents:UIControlEventTouchCancel];
+       }
+}
+
+- (void)acceleroValueChanged:(bool_t)enabled
+{
+       acceleroEnabled = enabled;
+       [self performSelectorOnMainThread:@selector(refreshControlInterface) withObject:nil waitUntilDone:YES];
+}
+
+- (void)combinedYawValueChanged:(bool_t)enabled
+{
+       combinedYawEnabled = enabled;
+       [self performSelectorOnMainThread:@selector(refreshControlInterface) withObject:nil waitUntilDone:YES];
+}
+       
+- (void)interfaceAlphaValueChanged:(CGFloat)value
+{
+       joystickRightThumbImageView.alpha = value;
+       joystickRightBackgroundImageView.alpha = value;
+       joystickLeftThumbImageView.alpha = value;
+       joystickLeftBackgroundImageView.alpha = value;
+       alpha = value;
+}
+       
+- (void)controlModeChanged:(CONTROL_MODE)mode
+{
+       controlMode = mode;
+       [self performSelectorOnMainThread:@selector(refreshControlInterface) withObject:nil waitUntilDone:YES];
+}
+
+- (void)updateVelocity:(CGPoint)point isRight:(BOOL)isRight
+{
+       CGPoint nextpoint = CGPointMake(point.x, point.y);
+       CGPoint center = (isRight ? rightCenter : leftCenter);
+       UIImageView *backgroundImage = (isRight ? joystickRightBackgroundImageView : joystickLeftBackgroundImageView);
+       UIImageView *thumbImage = (isRight ? joystickRightThumbImageView : joystickLeftThumbImageView);
+       
+       // Calculate distance and angle from the center.
+       float dx = nextpoint.x - center.x;
+       float dy = nextpoint.y - center.y;
+       
+       float distance = sqrt(dx * dx + dy * dy);
+       float angle = atan2(dy, dx); // in radians
+       
+       // NOTE: Velocity goes from -1.0 to 1.0.
+       // BE CAREFUL: don't just cap each direction at 1.0 since that
+       // doesn't preserve the proportions.
+       float joystick_radius = backgroundImage.frame.size.width / 2;
+       if (distance > joystick_radius) {
+               dx = cos(angle) * joystick_radius;
+               dy = sin(angle) * joystick_radius;
+       }
+       
+       // Constrain the thumb so that it stays within the joystick
+       // boundaries.  This is smaller than the joystick radius in
+       // order to account for the size of the thumb.
+       float thumb_radius = thumbImage.frame.size.width / 2;
+       if (distance > thumb_radius) {
+               nextpoint.x = center.x + (cos(angle) * thumb_radius);
+               nextpoint.y = center.y + (sin(angle) * thumb_radius);
+       }
+       
+       // Update the thumb's position
+       CGRect frame = thumbImage.frame;
+       frame.origin.x = nextpoint.x - (thumbImage.frame.size.width / 2);
+       frame.origin.y = nextpoint.y - (thumbImage.frame.size.height / 2);      
+       thumbImage.frame = frame;
+}
+       
+- (void)setMessageBox:(NSString*)str
+{
+       static int prevSound = 0;
+       [messageBoxLabel performSelectorOnMainThread:@selector(setText:) withObject:str waitUntilDone:YES];
+       
+       struct timeval nowSound;
+       gettimeofday(&nowSound, NULL);
+       if (([str compare:ARDroneEngineLocalizeString(@"BATTERY LOW ALERT")] == NSOrderedSame) &&
+               2 < (nowSound.tv_sec - prevSound))
+       {
+               AudioServicesPlaySystemSound(batt_id);
+               prevSound = nowSound.tv_sec;
+       }
+}
+
+- (void)setTakeOff:(NSString*)str
+{
+       UIImage *image = [UIImage imageNamed:[str stringByAppendingString:@".png"]];
+       [takeOffButton setImage:image forState:UIControlStateNormal];
+}
+
+- (void)setEmergency:(NSString*)str
+{
+       if([str length] != 0)
+       {
+               UIImage *image = [UIImage imageNamed:[str stringByAppendingString:@".png"]];
+               emergencyButton.enabled = TRUE;
+               emergencyButton.alpha = 1.0;
+               [emergencyButton setImage:image forState:UIControlStateNormal];
+       }
+       else
+       {
+               emergencyButton.enabled = FALSE;
+               emergencyButton.alpha = 0.5;
+       }
+}
+
+- (void)hideInfos
+{
+       batteryLevelLabel.hidden = YES;
+       batteryImageView.hidden = YES;  
+}
+
+- (void)showInfos
+{
+       batteryLevelLabel.hidden = (config.enableBatteryPercentage == NO);
+       batteryImageView.hidden = NO;
+}
+       
+       
+- (void)enableBackToMainMenu
+{
+       backToMainMenuButton.enabled = YES;
+       backToMainMenuButton.alpha = 1.0;
+}
+
+- (void)disableBackToMainMenu
+{
+       backToMainMenuButton.enabled = NO;
+       backToMainMenuButton.alpha = 0.0;
+}
+       
+- (void)showBackToMainMenu:(BOOL)show
+{
+       if(show)
+               [self performSelectorOnMainThread:@selector(enableBackToMainMenu) withObject:nil waitUntilDone:YES];
+       else
+               [self performSelectorOnMainThread:@selector(disableBackToMainMenu) withObject:nil waitUntilDone:YES];
+}
+
+- (void)setBattery:(int)percent
+{
+       if(percent < 0)
+       {
+               [self performSelectorOnMainThread:@selector(hideInfos) withObject:nil waitUntilDone:YES];               
+       }
+       else
+       {
+               UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"battery%d.png", ((percent < 10) ? 0 : (int)((percent / 33.4) + 1))]];
+               [batteryImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
+               
+               [self performSelectorOnMainThread:@selector(showInfos) withObject:nil waitUntilDone:YES];               
+               
+               [batteryLevelLabel performSelectorOnMainThread:@selector(setTextColor:) withObject:((percent < 10) ? [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:0.7] : [UIColor colorWithRed:0.0 green:0.65 blue:0.0 alpha:0.7]) waitUntilDone:YES];            
+               [batteryLevelLabel performSelectorOnMainThread:@selector(setText:) withObject:[NSString stringWithFormat:@"%d %%", percent] waitUntilDone:YES];
+       }
+}
+
+- (IBAction)buttonPress:(id)sender forEvent:(UIEvent *)event 
+{
+       UITouch *touch = [[event touchesForView:sender] anyObject];
+       CGPoint point = [touch locationInView:self.view];
+       bool_t acceleroModeOk = NO;
+
+       if(sender == joystickRightButton)
+       {
+               buttonRightPressed = YES;
+               // Start only if the first touch is within the pad's boundaries.
+               // Allow touches to be tracked outside of the pad as long as the
+               // screen continues to be pressed.
+               BOOL joystickIsOutside =  ((point.x + (joystickRightBackgroundImageView.frame.size.width / 2) > (joystickRightButton.frame.origin.x + joystickRightButton.frame.size.width)) ||
+                                                                  (point.x - (joystickRightBackgroundImageView.frame.size.width / 2) < joystickRightButton.frame.origin.x) ||
+                                                                  (point.y + (joystickRightBackgroundImageView.frame.size.height / 2) > (joystickRightButton.frame.origin.y + joystickRightButton.frame.size.height)) ||
+                                                                  (point.y - (joystickRightBackgroundImageView.frame.size.height / 2) < joystickRightButton.frame.origin.y));
+               
+               if(joystickIsOutside)
+               {
+                       AudioServicesPlaySystemSound(plop_id);
+               }
+               
+               joystickRightCurrentPosition.x = point.x - (joystickRightBackgroundImageView.frame.size.width / 2);
+               joystickRightCurrentPosition.y = point.y - (joystickRightBackgroundImageView.frame.size.height / 2);
+               
+               joystickRightBackgroundImageView.alpha = joystickRightThumbImageView.alpha = 1.0;
+
+               // Refresh Joystick
+               [self refreshJoystickRight];
+               
+               // Update center
+               rightCenter = CGPointMake(joystickRightBackgroundImageView.frame.origin.x + (joystickRightBackgroundImageView.frame.size.width / 2), joystickRightBackgroundImageView.frame.origin.y + (joystickRightBackgroundImageView.frame.size.height / 2));
+       
+               // Update velocity
+               [self updateVelocity:rightCenter isRight:YES];
+               
+               acceleroModeOk = controls_table[controlMode].Right.can_use_accelero;
+               
+               if(combinedYawEnabled && buttonLeftPressed)
+                       controlData->accelero_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
+       }
+       else if(sender == joystickLeftButton)
+       {
+               buttonLeftPressed = YES;
+               
+               joystickLeftCurrentPosition.x = point.x - (joystickLeftBackgroundImageView.frame.size.width / 2);
+               joystickLeftCurrentPosition.y = point.y - (joystickLeftBackgroundImageView.frame.size.height / 2);
+               
+               joystickLeftBackgroundImageView.alpha = joystickLeftThumbImageView.alpha = 1.0;
+               
+               // Refresh Joystick
+               [self refreshJoystickLeft];
+               
+               // Update center
+               leftCenter = CGPointMake(joystickLeftBackgroundImageView.frame.origin.x + (joystickLeftBackgroundImageView.frame.size.width / 2), joystickLeftBackgroundImageView.frame.origin.y + (joystickLeftBackgroundImageView.frame.size.height / 2));
+               
+               // Update velocity
+               [self updateVelocity:leftCenter isRight:NO];
+
+               acceleroModeOk = controls_table[controlMode].Left.can_use_accelero;
+               if(combinedYawEnabled && buttonRightPressed)
+                       controlData->accelero_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
+       }
+       
+       if(acceleroModeOk)
+       {
+               controlData->accelero_flag |= (1 << ARDRONE_PROGRESSIVE_CMD_ENABLE);
+               if(acceleroEnabled)
+               {
+                       // Start only if the first touch is within the pad's boundaries.
+                       // Allow touches to be tracked outside of the pad as long as the
+                       // screen continues to be pressed.                      
+                       float phi, theta;
+                       phi = (float)atan2f(accelero[1], accelero[2]);
+                       theta = -(float)atan2f(accelero[0] * cosf(phi), accelero[2]);
+                       [self setAcceleroRotationWithPhi:phi withTheta:theta withPsi:0.0];
+               }
+       }                       
+}
+
+- (IBAction)buttonRelease:(id)sender forEvent:(UIEvent *)event 
+{
+       bool_t acceleroModeOk = NO;
+       if(sender == joystickRightButton)
+       {
+               buttonRightPressed = NO;
+               
+               // Reinitialize joystick position
+               joystickRightCurrentPosition = joystickRightInitialPosition;
+               joystickRightBackgroundImageView.alpha = joystickRightThumbImageView.alpha = alpha;
+               
+               // Refresh joystick
+               [self refreshJoystickRight];
+               
+               // Update center
+               rightCenter = CGPointMake(joystickRightBackgroundImageView.frame.origin.x + (joystickRightBackgroundImageView.frame.size.width / 2), joystickRightBackgroundImageView.frame.origin.y + (joystickRightBackgroundImageView.frame.size.height / 2));
+               
+               // reset joystick
+               [self updateVelocity:rightCenter isRight:YES];
+               
+               controls_table[controlMode].Right.up_down(0.0);
+               controls_table[controlMode].Right.left_right(0.0);
+
+               acceleroModeOk = controls_table[controlMode].Right.can_use_accelero;
+               
+               if(combinedYawEnabled)
+                       controlData->accelero_flag &= ~(1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
+       }
+       else if(sender == joystickLeftButton)
+       {
+               //printf("button left released\n");
+               buttonLeftPressed = NO;
+               // Reinitialize joystick position
+               joystickLeftCurrentPosition = joystickLeftInitialPosition;
+               joystickLeftBackgroundImageView.alpha = joystickLeftThumbImageView.alpha = alpha;
+               
+               // Refresh joystick
+               [self refreshJoystickLeft];
+               
+               // Update center
+               leftCenter = CGPointMake(joystickLeftBackgroundImageView.frame.origin.x + (joystickLeftBackgroundImageView.frame.size.width / 2), joystickLeftBackgroundImageView.frame.origin.y + (joystickLeftBackgroundImageView.frame.size.height / 2));
+               
+               // reset joystick
+               [self updateVelocity:leftCenter isRight:NO];
+
+               controls_table[controlMode].Left.up_down(0.0);
+               controls_table[controlMode].Left.left_right(0.0);
+
+               acceleroModeOk = controls_table[controlMode].Left.can_use_accelero;
+
+               if(combinedYawEnabled)
+                       controlData->accelero_flag &= ~(1 << ARDRONE_PROGRESSIVE_CMD_COMBINED_YAW_ACTIVE);
+       }
+       
+       if(acceleroModeOk)
+       {
+               controlData->accelero_flag &= ~(1 << ARDRONE_PROGRESSIVE_CMD_ENABLE);
+               if(acceleroEnabled)
+               {
+                       [self setAcceleroRotationWithPhi:0.0 withTheta:0.0 withPsi:0.0];
+               }
+       }
+}
+
+- (IBAction)buttonDrag:(id)sender forEvent:(UIEvent *)event 
+{
+       UITouch *touch = [[event touchesForView:sender] anyObject];
+       CGPoint point = [touch locationInView:self.view];
+       bool_t acceleroModeOk = NO;
+       
+       
+       float controlRatio = 0.5 - (CONTROL_RATIO / 2.0);
+       if (usingIPad && compiledForIPad)
+       {
+               controlRatio = 0.5 - (CONTROL_RATIO_IPAD / 2.0);
+       }
+       
+       
+       
+       if(sender == joystickRightButton)
+       {
+               if((rightCenter.x - point.x) > ((joystickRightBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.width)))
+               {
+                       float percent = ((rightCenter.x - point.x) - ((joystickRightBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.width))) / ((controlRatio * joystickRightBackgroundImageView.frame.size.width));
+                       //NSLog(@"Percent (left)  : %f\n", percent);
+                       if(percent > 1.0)
+                               percent = 1.0;
+                       controls_table[controlMode].Right.left_right(-percent);
+               }
+               else if((point.x - rightCenter.x) > ((joystickRightBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.width)))
+               {
+                       float percent = ((point.x - rightCenter.x) - ((joystickRightBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.width))) / ((controlRatio * joystickRightBackgroundImageView.frame.size.width));
+                       //NSLog(@"Percent (right) : %f\n", percent);
+                       if(percent > 1.0)
+                               percent = 1.0;
+                       controls_table[controlMode].Right.left_right(percent);
+               }
+               else
+               {
+                       controls_table[controlMode].Right.left_right(0.0);
+               }
+
+               if((point.y - rightCenter.y) > ((joystickRightBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.height)))
+               {
+                       float percent = ((point.y - rightCenter.y) - ((joystickRightBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.height))) / ((controlRatio * joystickRightBackgroundImageView.frame.size.height));
+                       //NSLog(@"Percent (down)  : %f\n", percent);
+                       if(percent > 1.0)
+                               percent = 1.0;
+                       controls_table[controlMode].Right.up_down(-percent);
+               }
+               else if((rightCenter.y - point.y) > ((joystickRightBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.height)))
+               {
+                       float percent = ((rightCenter.y - point.y) - ((joystickRightBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickRightBackgroundImageView.frame.size.height))) / ((controlRatio * joystickRightBackgroundImageView.frame.size.height));
+                       //NSLog(@"Percent (top)   : %f\n", percent);
+                       if(percent > 1.0)
+                               percent = 1.0;
+                       controls_table[controlMode].Right.up_down(percent);
+               }
+               else
+               {
+                       controls_table[controlMode].Right.up_down(0.0);
+               }
+
+               acceleroModeOk = controls_table[controlMode].Right.can_use_accelero;
+       }
+       else if(sender == joystickLeftButton)
+       {
+               if((leftCenter.x - point.x) > ((joystickLeftBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.width)))
+               {
+                       float percent = ((leftCenter.x - point.x) - ((joystickLeftBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.width))) / ((controlRatio * joystickLeftBackgroundImageView.frame.size.width));
+                       if(percent > 1.0)
+                               percent = 1.0;
+                       controls_table[controlMode].Left.left_right(-percent);
+               }
+               else if((point.x - leftCenter.x) > ((joystickLeftBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.width)))
+               {
+                       float percent = ((point.x - leftCenter.x) - ((joystickLeftBackgroundImageView.frame.size.width / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.width))) / ((controlRatio * joystickLeftBackgroundImageView.frame.size.width));
+                       if(percent > 1.0)
+                               percent = 1.0;
+                       controls_table[controlMode].Left.left_right(percent);
+               }
+               else
+               {
+                       controls_table[controlMode].Left.left_right(0.0);
+               }       
+               
+               if((point.y - leftCenter.y) > ((joystickLeftBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.height)))
+               {
+                       float percent = ((point.y - leftCenter.y) - ((joystickLeftBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.height))) / ((controlRatio * joystickLeftBackgroundImageView.frame.size.height));
+                       if(percent > 1.0)
+                               percent = 1.0;
+                       controls_table[controlMode].Left.up_down(-percent);
+               }
+               else if((leftCenter.y - point.y) > ((joystickLeftBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.height)))
+               {
+                       float percent = ((leftCenter.y - point.y) - ((joystickLeftBackgroundImageView.frame.size.height / 2) - (controlRatio * joystickLeftBackgroundImageView.frame.size.height))) / ((controlRatio * joystickLeftBackgroundImageView.frame.size.height));
+                       if(percent > 1.0)
+                               percent = 1.0;
+                       controls_table[controlMode].Left.up_down(percent);
+               }
+               else
+               {
+                       controls_table[controlMode].Left.up_down(0.0);
+               }               
+
+               acceleroModeOk = controls_table[controlMode].Left.can_use_accelero;
+       }
+               
+       if(acceleroModeOk)
+       {
+               if(!acceleroEnabled)
+               {
+                       // Update joystick velocity
+                       [self updateVelocity:point isRight:(sender == joystickRightButton)];
+               }
+       }
+       else
+       {
+               // Update joystick velocity
+               [self updateVelocity:point isRight:(sender == joystickRightButton)];
+       }
+
+}
+
+- (IBAction)buttonClick:(id)sender forEvent:(UIEvent *)event 
+{
+       static ARDRONE_VIDEO_CHANNEL channel = ARDRONE_VIDEO_CHANNEL_FIRST;
+       if(sender == settingsButton)
+               settingsPressed = YES;
+       else if(sender == backToMainMenuButton)
+               mainMenuPressed = YES;
+       else if(sender == switchScreenButton)
+       {
+               if(channel++ == ARDRONE_VIDEO_CHANNEL_LAST)
+                       channel = ARDRONE_VIDEO_CHANNEL_FIRST;
+               
+               ARDRONE_TOOL_CONFIGURATION_ADDEVENT(video_channel, (int32_t*)&channel, NULL);
+       }
+       else if(sender == takeOffButton)
+       {
+               switchTakeOff();
+       }
+       else if(sender == emergencyButton)
+       {
+               emergency();
+       }
+}
+
+- (void)viewDidLoad
+{
+       switchScreenButton.hidden = (config.enableSwitchScreen == NO);
+       backToMainMenuButton.hidden = (config.enableBackToMainMenu == NO);
+       batteryLevelLabel.hidden = (config.enableBatteryPercentage == NO);
+       
+       rightCenter = CGPointMake(joystickRightThumbImageView.frame.origin.x + (joystickRightThumbImageView.frame.size.width / 2), joystickRightThumbImageView.frame.origin.y + (joystickRightThumbImageView.frame.size.height / 2));
+       joystickRightInitialPosition = CGPointMake(rightCenter.x - (joystickRightBackgroundImageView.frame.size.width / 2), rightCenter.y - (joystickRightBackgroundImageView.frame.size.height / 2));
+       leftCenter = CGPointMake(joystickLeftThumbImageView.frame.origin.x + (joystickLeftThumbImageView.frame.size.width / 2), joystickLeftThumbImageView.frame.origin.y + (joystickLeftThumbImageView.frame.size.height / 2));
+       joystickLeftInitialPosition = CGPointMake(leftCenter.x - (joystickLeftBackgroundImageView.frame.size.width / 2), leftCenter.y - (joystickLeftBackgroundImageView.frame.size.height / 2));
+
+       joystickLeftCurrentPosition = joystickLeftInitialPosition;
+       joystickRightCurrentPosition = joystickRightInitialPosition;
+       
+       alpha = MIN(joystickRightBackgroundImageView.alpha, joystickRightThumbImageView.alpha);
+       joystickRightBackgroundImageView.alpha = joystickRightThumbImageView.alpha = alpha;
+       joystickLeftBackgroundImageView.alpha = joystickLeftThumbImageView.alpha = alpha;
+
+    // Get the URL to the sound file to play
+       CFURLRef batt_url  = CFBundleCopyResourceURL (CFBundleGetMainBundle(),
+                                                                                                  CFSTR ("battery"),
+                                                                                                  CFSTR ("wav"),
+                                                                                                 NULL);
+    CFURLRef plop_url  = CFBundleCopyResourceURL (CFBundleGetMainBundle(),
+                                                                                                  CFSTR ("plop"),
+                                                                                                  CFSTR ("wav"),
+                                                                                                  NULL);
+       
+    // Create a system sound object representing the sound file
+    AudioServicesCreateSystemSoundID (plop_url, &plop_id);
+    AudioServicesCreateSystemSoundID (batt_url, &batt_id);
+       CFRelease(plop_url);
+       CFRelease(batt_url);
+       
+       [self setBattery:-1];
+}
+
+- (void) dealloc 
+{
+#ifdef WRITE_DEBUG_ACCELERO
+       fclose(mesures_file);
+#endif
+       AudioServicesDisposeSystemSoundID (plop_id);
+       AudioServicesDisposeSystemSoundID (batt_id);
+       [super dealloc];
+}
+
+@end