2014-05-29 04:34:27 +08:00
|
|
|
/*
|
|
|
|
* leap_ardrone.js
|
2014-10-21 04:27:23 +08:00
|
|
|
*
|
2014-05-29 04:34:27 +08:00
|
|
|
* Written by Giuliano Sposito and Fábio Uechi
|
|
|
|
* Copyright (c) 2013-2014 CI&T Software
|
|
|
|
* Licensed under the Apache 2.0 license.
|
|
|
|
*/
|
|
|
|
|
2014-12-14 08:19:25 +08:00
|
|
|
"use strict";
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-12-14 08:19:25 +08:00
|
|
|
var Cylon = require("cylon");
|
|
|
|
|
|
|
|
var TURN_TRESHOLD = 0.2,
|
2014-06-01 22:11:29 +08:00
|
|
|
TURN_SPEED_FACTOR = 2.0;
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
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;
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
Cylon.robot({
|
2014-11-11 04:37:33 +08:00
|
|
|
connections: {
|
2014-12-14 08:19:25 +08:00
|
|
|
leapmotion: { adaptor: "leapmotion" },
|
|
|
|
ardrone: { adaptor: "ardrone", port: "192.168.1.1" },
|
|
|
|
keyboard: { adaptor: "keyboard" }
|
2014-11-11 04:37:33 +08:00
|
|
|
},
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-11-11 04:37:33 +08:00
|
|
|
devices: {
|
2015-04-15 12:49:12 +08:00
|
|
|
drone: { driver: "ardrone", connection: "ardrone" },
|
|
|
|
leapmotion: { driver: "leapmotion", connection: "leapmotion" },
|
|
|
|
keyboard: { driver: "keyboard", connection: "keyboard" }
|
2014-11-11 04:37:33 +08:00
|
|
|
},
|
2014-05-29 04:34:27 +08:00
|
|
|
|
|
|
|
work: function(my) {
|
2014-12-14 08:19:25 +08:00
|
|
|
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);
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-12-14 08:19:25 +08:00
|
|
|
my.keyboard.on("w", my.drone.wave);
|
|
|
|
my.keyboard.on("s", my.drone.stop);
|
|
|
|
my.keyboard.on("l", my.drone.land);
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-12-14 08:19:25 +08:00
|
|
|
my.leapmotion.on("gesture", function(gesture) {
|
2014-10-21 04:27:23 +08:00
|
|
|
var type = gesture.type,
|
|
|
|
state = gesture.state,
|
|
|
|
progress = gesture.progress;
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-12-14 08:19:25 +08:00
|
|
|
var stop = (state === "stop");
|
|
|
|
|
|
|
|
if (type === "circle" && stop && progress > CIRCLE_THRESHOLD) {
|
2014-10-21 04:27:23 +08:00
|
|
|
if (gesture.normal[2] < 0) {
|
|
|
|
my.drone.takeoff();
|
2014-05-29 04:34:27 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
if (gesture.normal[2] > 0) {
|
|
|
|
my.drone.land();
|
|
|
|
}
|
2014-05-29 04:34:27 +08:00
|
|
|
}
|
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
// emergency stop
|
2014-12-14 08:19:25 +08:00
|
|
|
if (type === "keyTap" || type === "screenTap") {
|
2014-05-29 04:34:27 +08:00
|
|
|
my.drone.stop();
|
|
|
|
}
|
2014-10-21 04:27:23 +08:00
|
|
|
});
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-12-14 08:19:25 +08:00
|
|
|
my.leapmotion.on("hand", function(hand) {
|
|
|
|
var signal, value;
|
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
var handOpen = !!hand.fingers.filter(function(f) {
|
|
|
|
return f.extended;
|
|
|
|
}).length;
|
|
|
|
|
|
|
|
if (handOpen) {
|
|
|
|
if (handWasClosedInLastFrame) {
|
|
|
|
handStartPosition = hand.palmPosition;
|
|
|
|
handStartDirection = hand.direction;
|
|
|
|
}
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-12-14 08:19:25 +08:00
|
|
|
var horizontal = Math.abs(handStartDirection[0] - hand.direction[0]),
|
|
|
|
vertical = Math.abs(hand.palmPosition[1] - handStartPosition[1]);
|
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
// TURNS
|
2014-12-14 08:19:25 +08:00
|
|
|
if (horizontal > TURN_TRESHOLD) {
|
|
|
|
signal = handStartDirection[0] - hand.direction[0];
|
|
|
|
value = (horizontal - TURN_TRESHOLD) * TURN_SPEED_FACTOR;
|
2014-06-01 22:11:29 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
if (signal > 0) {
|
2014-10-21 04:27:23 +08:00
|
|
|
my.drone.counterClockwise(value);
|
|
|
|
}
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
if (signal < 0) {
|
2014-10-21 04:27:23 +08:00
|
|
|
my.drone.clockwise(value);
|
|
|
|
}
|
2014-05-29 04:34:27 +08:00
|
|
|
}
|
2014-06-01 22:11:29 +08:00
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
// UP and DOWN
|
2014-12-14 08:19:25 +08:00
|
|
|
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;
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
if (signal > 0) {
|
|
|
|
my.drone.up(value);
|
|
|
|
}
|
2014-06-01 22:11:29 +08:00
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
if (signal < 0) {
|
|
|
|
my.drone.down(value);
|
|
|
|
}
|
|
|
|
}
|
2014-06-01 22:11:29 +08:00
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
// DIRECTION FRONT/BACK
|
|
|
|
if ((Math.abs(hand.palmNormal[2]) > DIRECTION_THRESHOLD)) {
|
|
|
|
if (hand.palmNormal[2] > 0) {
|
2014-12-14 08:19:25 +08:00
|
|
|
value = Math.abs(
|
|
|
|
Math.round(hand.palmNormal[2] * 10 + DIRECTION_THRESHOLD) *
|
|
|
|
DIRECTION_SPEED_FACTOR
|
|
|
|
);
|
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
my.drone.forward(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hand.palmNormal[2] < 0) {
|
2015-04-15 12:49:12 +08:00
|
|
|
value = Math.abs(
|
|
|
|
Math.round(hand.palmNormal[2] * 10 - DIRECTION_THRESHOLD) *
|
|
|
|
DIRECTION_SPEED_FACTOR
|
|
|
|
);
|
2014-12-14 08:19:25 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
my.drone.back(value);
|
2014-10-21 04:27:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DIRECTION LEFT/RIGHT
|
2015-04-15 12:49:12 +08:00
|
|
|
if (Math.abs(hand.palmNormal[0]) > DIRECTION_THRESHOLD) {
|
2014-10-21 04:27:23 +08:00
|
|
|
if (hand.palmNormal[0] > 0) {
|
2015-04-15 12:49:12 +08:00
|
|
|
value = Math.abs(
|
|
|
|
Math.round(hand.palmNormal[0] * 10 + DIRECTION_THRESHOLD) *
|
|
|
|
DIRECTION_SPEED_FACTOR
|
|
|
|
);
|
2014-12-14 08:19:25 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
my.drone.left(value);
|
2014-10-21 04:27:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hand.palmNormal[0] < 0) {
|
2015-04-15 12:49:12 +08:00
|
|
|
value = Math.abs(
|
|
|
|
Math.round(hand.palmNormal[0] * 10 - DIRECTION_THRESHOLD) *
|
|
|
|
DIRECTION_SPEED_FACTOR
|
|
|
|
);
|
2014-12-14 08:19:25 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
my.drone.right(value);
|
2014-10-21 04:27:23 +08:00
|
|
|
}
|
|
|
|
}
|
2014-06-01 22:11:29 +08:00
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
// AUTO FREEZE
|
2014-12-14 08:19:25 +08:00
|
|
|
if (
|
2015-04-15 12:49:12 +08:00
|
|
|
// within left/right threshold
|
|
|
|
(Math.abs(hand.palmNormal[0]) < DIRECTION_THRESHOLD) &&
|
2014-12-14 08:19:25 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
// within forward/back threshold
|
|
|
|
(Math.abs(hand.palmNormal[2]) < DIRECTION_THRESHOLD) &&
|
2014-12-14 08:19:25 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
// within up/down threshold
|
|
|
|
Math.abs(hand.palmPosition[1] - handStartPosition[1]) <
|
|
|
|
UP_CONTROL_THRESHOLD &&
|
2014-12-14 08:19:25 +08:00
|
|
|
|
2015-04-15 12:49:12 +08:00
|
|
|
// within turn threshold
|
|
|
|
Math.abs(handStartDirection[0] - hand.direction[0]) <
|
|
|
|
TURN_TRESHOLD) {
|
2014-12-14 08:19:25 +08:00
|
|
|
my.drone.stop();
|
2014-10-21 04:27:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!handOpen && !handWasClosedInLastFrame) {
|
2014-06-01 22:11:29 +08:00
|
|
|
my.drone.stop();
|
2014-10-21 04:27:23 +08:00
|
|
|
}
|
2014-05-29 04:34:27 +08:00
|
|
|
|
2014-10-21 04:27:23 +08:00
|
|
|
handWasClosedInLastFrame = !handOpen;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}).start();
|