Android SDK Tutorial : Taking off and landing the drone

Overview

In the previous tutorial, we identified four steps to build an App that controls a drone.

  1. Our GHOSTDRONE's sensors have to be functioning well.
  2. Our GHOSTDRONE's flight control system has to be functioning well.
  3. Our phone has to be functioning well.
  4. We have to find a way to transform phone sensory data to drone control command.

This tutorial will walk you through the second step. We will build an App to disarm, takeoff and land the drone. We would not say taking off and landing the drone successfully indicates the soundness of the the flight control system. There are a lot more to do to fully test a drone. The point is, controlling a drone with unverified code, yes, the code we are writing, is very dangerous. Let's be conservative. We take our first step by testing simple takeoff and landing.

Setting up the Android project

In the GhostTakeoff app, we only keep necessary buttons for connection along with two text views for drone status and remaining battery percentage. We add six buttons to control ARM, DISARM, GPS, RETURN, TAKEOFF and LAND respectively. The buttons are exaggeratedly made large and colored to help you easily locate when needed.

In particular, DISARM button is colored red and the drone will only be disarmed when the button is double tapped to avoid misoperation, as DISARM occurs unconditionally and immediately. Always DISARM with extreme caution.

//MainActivity.java private final static int TAKEOFF_ALTITIDE = 10; private long lastTap_disArmButton = -1; private static long DOUBLE_TAP_SENSITIVITY = 1000; @Override public void onClick(View v){ switch (v.getId()){ case R.id.bt_Connect: CopterControl.getInstance().getConnection().connect(MAC, new OnConnectionListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "Connection Succeeds", Toast.LENGTH_SHORT).show(); initStatusCheckTimer(); } @Override public void onFailure() { Toast.makeText(getApplicationContext(), "Connection Fails", Toast.LENGTH_SHORT).show(); } }); break; case R.id.bt_Bind: CopterControl.getInstance().startPair(new OnSendListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "Pairing Succeeds", Toast.LENGTH_SHORT).show(); } @Override public void onFailure() { Toast.makeText(getApplicationContext(), "Pairing Fails", Toast.LENGTH_SHORT).show(); } }); break; case R.id.bt_Disarm: if (CopterControl.getInstance().isCopterConnected())){ long now = System.currentTimeMillis(); if (now - lastTap_disArmButton >= DOUBLE_TAP_SENSITIVITY) { lastTap_disArmButton = now; return; } else { CopterControl.getInstance().lock(new OnSendListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "Lock Succeeds", Toast.LENGTH_SHORT).show(); } @Override public void onFailure() { Toast.makeText(getApplicationContext(), "Lock Fails", Toast.LENGTH_SHORT).show(); } }); } } break; case R.id.bt_Arm: if (CopterControl.getInstance().isCopterConnected()){ CopterControl.getInstance().unlock(new OnSendListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "UnLock Succeeds", Toast.LENGTH_SHORT).show(); } @Override public void onFailure() { Toast.makeText(getApplicationContext(), "UnLock Fails", Toast.LENGTH_SHORT).show(); } }); } break; case R.id.bt_Takeoff: if (CopterControl.getInstance().isCopterConnected()) { CopterControl.getInstance().takeoff(TAKEOFF_ALTITIDE, new OnSendListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "Takeoff Succeeds", Toast.LENGTH_SHORT).show(); } @Override public void onFailure() { Toast.makeText(getApplicationContext(), "Takeoff Fails", Toast.LENGTH_SHORT).show(); } }); } break; case R.id.bt_GPS: if (CopterControl.getInstance().isCopterConnected()) { CopterControl.getInstance().gps(new OnSendListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "GPS Mode Succeeds", Toast.LENGTH_SHORT).show(); } @Override public void onFailure() { Toast.makeText(getApplicationContext(), "GPS Mode Fails", Toast.LENGTH_SHORT).show(); } }); } break; case R.id.bt_Return: if (CopterControl.getInstance().isCopterConnected()) { CopterControl.getInstance().returnToBase(new OnSendListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "Return Succeeds", Toast.LENGTH_SHORT).show(); } @Override public void onFailure() { Toast.makeText(getApplicationContext(), "Return Fails", Toast.LENGTH_SHORT).show(); } }); } break; case R.id.bt_Land: if (CopterControl.getInstance().isCopterConnected()) { CopterControl.getInstance().land(new OnSendListener() { @Override public void onSuccess() { Toast.makeText(getApplicationContext(), "Landing Succeeds", Toast.LENGTH_SHORT).show(); } @Override public void onFailure() { Toast.makeText(getApplicationContext(), "Landing Fails", Toast.LENGTH_SHORT).show(); } }); } break; } }

The CopterControl class takes care of arm/disarm in unlock() and lock() with a listener that handles the result of arm/disarm. Takeoff is handled by takeoff() with a specified target altitude. GPS is done by calling gps(), which, as how it's named, uses GPS signals to stabilize the drone itself. Return and Land are done by calling returnToBase() and land() respectively.

Testing takeoff and landing

Having setup the App and compiled successfully, it is high time to test it out. Find an open space without a crowd. You are encouraged to run GhostDiagnostics app first to make sure everything looks good, especially the number of satellites available, which is critical when we need to switch to GPS mode to stabilize the drone. Below is the recommended list of steps to test your App:

  1. Tap on ARM.
  2. Double tap on DISARM.
  3. Tap on ARM
  4. Tap on Takeoff.
  5. When the drone is stable, tap on Land.
  6. When landing is almost done, double tap to disarm.

Please note that disarming when landing is almost done is not a standard procedure. In ideal conditions, landing could be done by the drone itself safely. In uneven or sandy landing area, it may help to avoid accidents to disarm the drone by yourself as it's close to the ground.

Project files