/* * leap_ardrone.js * * Written by Giuliano Sposito and Fábio Uechi * Copyright (c) 2013-2014 CI&T Software * Licensed under the Apache 2.0 license. */ "use strict"; var Cylon = require("cylon"); var TURN_TRESHOLD = 0.2, TURN_SPEED_FACTOR = 2.0; var DIRECTION_THRESHOLD = 0.25, DIRECTION_SPEED_FACTOR = 0.05; var UP_CONTROL_THRESHOLD = 50, UP_SPEED_FACTOR = 0.01, CIRCLE_THRESHOLD = 1.5; var handStartPosition = [], handStartDirection = []; var handWasClosedInLastFrame = false; Cylon.robot({ connections: { leapmotion: { adaptor: "leapmotion" }, ardrone: { adaptor: "ardrone", port: "192.168.1.1" }, keyboard: { adaptor: "keyboard" } }, devices: { drone: { driver: "ardrone", connection: "ardrone" }, leapmotion: { driver: "leapmotion", connection: "leapmotion" }, keyboard: { driver: "keyboard", connection: "keyboard" } }, work: function(my) { my.keyboard.on("right", my.drone.rightFlip); my.keyboard.on("left", my.drone.leftFlip); my.keyboard.on("up", my.drone.frontFlip); my.keyboard.on("down", my.drone.backFlip); my.keyboard.on("w", my.drone.wave); my.keyboard.on("s", my.drone.stop); my.keyboard.on("l", my.drone.land); my.leapmotion.on("gesture", function(gesture) { var type = gesture.type, state = gesture.state, progress = gesture.progress; var stop = (state === "stop"); if (type === "circle" && stop && progress > CIRCLE_THRESHOLD) { if (gesture.normal[2] < 0) { my.drone.takeoff(); } if (gesture.normal[2] > 0) { my.drone.land(); } } // emergency stop if (type === "keyTap" || type === "screenTap") { my.drone.stop(); } }); my.leapmotion.on("hand", function(hand) { var signal, value; var handOpen = !!hand.fingers.filter(function(f) { return f.extended; }).length; if (handOpen) { if (handWasClosedInLastFrame) { handStartPosition = hand.palmPosition; handStartDirection = hand.direction; } var horizontal = Math.abs(handStartDirection[0] - hand.direction[0]), vertical = Math.abs(hand.palmPosition[1] - handStartPosition[1]); // TURNS if (horizontal > TURN_TRESHOLD) { signal = handStartDirection[0] - hand.direction[0]; value = (horizontal - TURN_TRESHOLD) * TURN_SPEED_FACTOR; if (signal > 0) { my.drone.counterClockwise(value); } if (signal < 0) { my.drone.clockwise(value); } } // UP and DOWN if (vertical > UP_CONTROL_THRESHOLD) { if ((hand.palmPosition[1] - handStartPosition[1]) >= 0) { signal = 1; } else { signal = -1; } value = Math.round(vertical - UP_CONTROL_THRESHOLD) * UP_SPEED_FACTOR; if (signal > 0) { my.drone.up(value); } if (signal < 0) { my.drone.down(value); } } // DIRECTION FRONT/BACK if ((Math.abs(hand.palmNormal[2]) > DIRECTION_THRESHOLD)) { if (hand.palmNormal[2] > 0) { value = Math.abs( Math.round(hand.palmNormal[2] * 10 + DIRECTION_THRESHOLD) * DIRECTION_SPEED_FACTOR ); my.drone.forward(value); } if (hand.palmNormal[2] < 0) { value = Math.abs( Math.round(hand.palmNormal[2] * 10 - DIRECTION_THRESHOLD) * DIRECTION_SPEED_FACTOR ); my.drone.back(value); } } // DIRECTION LEFT/RIGHT if (Math.abs(hand.palmNormal[0]) > DIRECTION_THRESHOLD) { if (hand.palmNormal[0] > 0) { value = Math.abs( Math.round(hand.palmNormal[0] * 10 + DIRECTION_THRESHOLD) * DIRECTION_SPEED_FACTOR ); my.drone.left(value); } if (hand.palmNormal[0] < 0) { value = Math.abs( Math.round(hand.palmNormal[0] * 10 - DIRECTION_THRESHOLD) * DIRECTION_SPEED_FACTOR ); my.drone.right(value); } } // AUTO FREEZE if ( // within left/right threshold (Math.abs(hand.palmNormal[0]) < DIRECTION_THRESHOLD) && // within forward/back threshold (Math.abs(hand.palmNormal[2]) < DIRECTION_THRESHOLD) && // within up/down threshold Math.abs(hand.palmPosition[1] - handStartPosition[1]) < UP_CONTROL_THRESHOLD && // within turn threshold Math.abs(handStartDirection[0] - hand.direction[0]) < TURN_TRESHOLD) { my.drone.stop(); } } if (!handOpen && !handWasClosedInLastFrame) { my.drone.stop(); } handWasClosedInLastFrame = !handOpen; }); } }).start();