package com.dronecontrol.leapcontrol.control; import com.google.inject.Inject; import com.dronecontrol.droneapi.DroneController; import com.dronecontrol.droneapi.data.NavData; import com.dronecontrol.droneapi.data.enums.Camera; import com.dronecontrol.droneapi.data.enums.FlightAnimation; import com.dronecontrol.droneapi.data.enums.LedAnimation; import com.dronecontrol.droneapi.listeners.NavDataListener; import com.dronecontrol.droneapi.listeners.ReadyStateChangeListener; import com.dronecontrol.leapcontrol.helpers.RaceTimer; import com.dronecontrol.leapcontrol.input.leapmotion.data.DetectionData; import com.dronecontrol.leapcontrol.input.leapmotion.data.GestureData; import com.dronecontrol.leapcontrol.input.leapmotion.listeners.DetectionListener; import com.dronecontrol.leapcontrol.input.leapmotion.listeners.GestureListener; import com.dronecontrol.leapcontrol.input.speech.data.SpeechData; import com.dronecontrol.leapcontrol.input.speech.listeners.SpeechListener; import com.dronecontrol.leapcontrol.ui.data.UIAction; import com.dronecontrol.leapcontrol.ui.listeners.UIActionListener; import org.apache.log4j.Logger; public class DroneInputController implements ReadyStateChangeListener, NavDataListener, DetectionListener, GestureListener, SpeechListener, UIActionListener { private static final float PITCH_DECAY = 0.5f; private static final float ROLL_DECAY = 0.5f; // Max height in meters private static final float MAX_HEIGHT = 2.0f; private static final float HEIGHT_THRESHOLD = 0.25f; private final Logger logger = Logger.getLogger(DroneInputController.class); private final DroneController droneController; private final RaceTimer raceTimer; private boolean navDataReceived = false; private float currentHeight; private boolean flying = false; private boolean expertMode = false; private boolean ready = false; @Inject public DroneInputController(DroneController droneController, RaceTimer raceTimer) { this.droneController = droneController; this.raceTimer = raceTimer; } @Override public void onSpeech(SpeechData speechData) { String sentence = speechData.getSentence(); if (sentence.endsWith("take off")) { takeOff(); } else if (sentence.endsWith("land")) { land(); } else if (sentence.endsWith("emergency")) { emergency(); } else if (sentence.endsWith("flat trim")) { flatTrim(); } } @Override public void onAction(UIAction action) { switch (action) { case TAKE_OFF: takeOff(); break; case LAND: land(); break; case FLAT_TRIM: flatTrim(); break; case EMERGENCY: emergency(); break; case SWITCH_CAMERA: switchCamera(); break; case PLAY_LED_ANIMATION: playLedAnimation(); break; case PLAY_FLIGHT_ANIMATION: playFlightAnimation(); break; case ENABLE_EXPERT_MODE: logger.warn("Enabling expert mode"); expertMode = true; break; case DISABLE_EXPERT_MODE: logger.info("Disabling expert mode"); expertMode = false; break; } } @Override public void onDetect(DetectionData data) { float desiredHeight = data.getHeight() * MAX_HEIGHT; float heightDelta = navDataReceived ? calculateHeightDelta(desiredHeight) : 0.0f; if (desiredHeight <= HEIGHT_THRESHOLD) { land(); } move(PITCH_DECAY * -data.getRoll(), ROLL_DECAY * data.getPitch(), expertMode ? data.getYaw() : 0.0f, heightDelta); } @Override public void onNoDetect() { move(0.0f, 0.0f, 0.0f, 0.0f); } private float calculateHeightDelta(float desiredHeight) { return 3 * (desiredHeight - currentHeight) / MAX_HEIGHT; } @Override public void onNavData(NavData navData) { navDataReceived = true; currentHeight = navData.getAltitude() < HEIGHT_THRESHOLD ? 0.0f : navData.getAltitude(); flying = navData.getState().isFlying(); if (navData.getState().isEmergency()) { raceTimer.stop(); } } @Override public void onGesture(GestureData gestureData) { switch (gestureData.getGestureType()) { case TYPE_CIRCLE: takeOff(); break; case TYPE_SWIPE: // TODO Now we could do the flip animation break; } } private void takeOff() { if (ready && !flying) { raceTimer.start(); droneController.takeOff(); } } private void land() { if (ready && flying) { raceTimer.stop(); droneController.land(); } } private void flatTrim() { if (ready) { droneController.flatTrim(); } } private void emergency() { if (ready) { droneController.emergency(); } } private void switchCamera() { if (ready) { droneController.switchCamera(Camera.NEXT); } } private void playLedAnimation() { if (ready) { droneController.playLedAnimation(LedAnimation.RED_SNAKE, 2.0f, 3); } } private void playFlightAnimation() { if (ready) { droneController.playFlightAnimation(FlightAnimation.FLIP_LEFT); } } private void move(float roll, float pitch, float yaw, float gaz) { if (ready) { droneController.move(roll, pitch, yaw, gaz); } } @Override public void onReadyStateChange(ReadyState readyState) { if (readyState == ReadyState.READY) { ready = true; } else if (readyState == ReadyState.NOT_READY) { ready = false; } } }