Added initial autonomy mission class
Esse commit está contido em:
@@ -0,0 +1,27 @@
|
|||||||
|
var df = require('dateformat')
|
||||||
|
, autonomy = require('../')
|
||||||
|
, mission = autonomy.createMission()
|
||||||
|
;
|
||||||
|
|
||||||
|
mission.log("mission-" + df(new Date(), "yyyy-mm-dd_hh-MM-ss") + ".txt");
|
||||||
|
|
||||||
|
mission.takeoff()
|
||||||
|
.hover(1000)
|
||||||
|
.forward(1)
|
||||||
|
.right(1)
|
||||||
|
.backward(1)
|
||||||
|
.left(1)
|
||||||
|
.hover(1000)
|
||||||
|
.land();
|
||||||
|
|
||||||
|
mission.run(function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
console.trace("Oops, something bad happened: %s", err.message);
|
||||||
|
mission.client().stop();
|
||||||
|
mission.client().land();
|
||||||
|
} else {
|
||||||
|
console.log("We are done!");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
+12
-4
@@ -1,12 +1,20 @@
|
|||||||
var autonomy = exports;
|
var autonomy = exports;
|
||||||
|
var ardrone = require('ar-drone');
|
||||||
|
|
||||||
exports.StateEstimator = require('./lib/StateEstimator');
|
|
||||||
exports.EKF = require('./lib/EKF');
|
exports.EKF = require('./lib/EKF');
|
||||||
exports.Camera = require('./lib/Camera');
|
exports.Camera = require('./lib/Camera');
|
||||||
exports.Controller = require('./lib/Controller');
|
exports.Controller = require('./lib/Controller');
|
||||||
|
exports.Mission = require('./lib/Mission');
|
||||||
|
|
||||||
exports.estimateState = function(client, options) {
|
exports.control = function(client, options) {
|
||||||
var estimator = new autonomy.StateEstimator(client, options);
|
return new autonomy.Controller(client, options);
|
||||||
return estimator;
|
}
|
||||||
|
|
||||||
|
exports.createMission = function(options) {
|
||||||
|
var client = ardrone.createClient(options);
|
||||||
|
var control = new autonomy.Controller(client, options);
|
||||||
|
var mission = new autonomy.Mission(client, control, options);
|
||||||
|
|
||||||
|
return mission;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,6 +174,37 @@ Controller.prototype.ccw = function(angle, callback) {
|
|||||||
return this.cw(-angle, callback);
|
return this.cw(-angle, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Climb ups by the given distance (in meters).
|
||||||
|
*/
|
||||||
|
Controller.prototype.up = function(distance, callback) {
|
||||||
|
var state = this.state();
|
||||||
|
return this.go({x: state.x, y: state.y, z: state.z + distance, yaw: state.yaw}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lower itself by the given distance (in meters).
|
||||||
|
*/
|
||||||
|
Controller.prototype.down = function(distance, callback) {
|
||||||
|
return this.up(-distance, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go to the target altitude
|
||||||
|
*/
|
||||||
|
Controller.prototype.altitude = function(altitude, callback) {
|
||||||
|
var state = this.state();
|
||||||
|
return this.go({x: state.x, y: state.y, z: altitude, yaw: state.yaw}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go to the target yaw
|
||||||
|
*/
|
||||||
|
Controller.prototype.yaw = function(yaw, callback) {
|
||||||
|
var state = this.state();
|
||||||
|
return this.go({x: state.x, y: state.y, z: state.z, yaw: yaw}, callback);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sets a new goal and enable the controller. When the goal
|
* Sets a new goal and enable the controller. When the goal
|
||||||
* is reached, the callback is called with the current state.
|
* is reached, the callback is called with the current state.
|
||||||
@@ -193,6 +224,11 @@ Controller.prototype.go = function(goal, callback) {
|
|||||||
goal.yaw = Math.atan2(Math.sin(yaw),Math.cos(yaw));
|
goal.yaw = Math.atan2(Math.sin(yaw),Math.cos(yaw));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure we don't attempt to go too low
|
||||||
|
if (goal.z != undefined) {
|
||||||
|
goal.z = Math.max(goal.z, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
// Update our goal
|
// Update our goal
|
||||||
this._goal = goal;
|
this._goal = goal;
|
||||||
this._goal.reached = false;
|
this._goal.reached = false;
|
||||||
|
|||||||
@@ -0,0 +1,201 @@
|
|||||||
|
var async = require('async')
|
||||||
|
, fs = require('fs')
|
||||||
|
;
|
||||||
|
|
||||||
|
module.exports = Mission;
|
||||||
|
function Mission(client, controller, options) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
this._options = options;
|
||||||
|
this._client = client;
|
||||||
|
this._control = controller;
|
||||||
|
|
||||||
|
this._steps = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.client = function() {
|
||||||
|
return this._client;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.run = function(callback) {
|
||||||
|
async.waterfall(this._steps, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.log = function(path) {
|
||||||
|
var dataStream = fs.createWriteStream(path);
|
||||||
|
this._control.on('controlData', function(d) {
|
||||||
|
dataStream.write(d.state.x + "," +
|
||||||
|
d.state.y + "," +
|
||||||
|
d.state.z + "," +
|
||||||
|
d.state.yaw + "," +
|
||||||
|
d.state.vx + "," +
|
||||||
|
d.state.vy + "," +
|
||||||
|
d.goal.x + "," +
|
||||||
|
d.goal.y + "," +
|
||||||
|
d.goal.z + "," +
|
||||||
|
d.goal.yaw + "," +
|
||||||
|
d.error.ex + "," +
|
||||||
|
d.error.ey + "," +
|
||||||
|
d.error.ez + "," +
|
||||||
|
d.error.eyaw + "," +
|
||||||
|
d.control.ux + "," +
|
||||||
|
d.control.uy + "," +
|
||||||
|
d.control.uz + "," +
|
||||||
|
d.control.uyaw + "," +
|
||||||
|
d.last_ok + "," +
|
||||||
|
d.tag + "\n");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.takeoff = function() {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._client.takeoff(cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.land = function() {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._client.land(cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.hover = function(delay) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.hover();
|
||||||
|
setTimeout(cb, delay);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.wait = function(delay) {
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
setTimeout(cb, delay);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.task = function(task) {
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
task(cb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.taskSync = function(task) {
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
task();
|
||||||
|
cb();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.go = function(goal) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.go(goal, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.forward = function(distance) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.forward(distance, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.backward = function(distance) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.backward(distance, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.left = function(distance) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.left(distance, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.right = function(distance) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.right(distance, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.up = function(distance) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.up(distance, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.down = function(distance) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.down(distance, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.cw = function(angle) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.cw(angle, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.ccw = function(angle) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.ccw(angle, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.altitude = function(altitude) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.altitude(altitude, cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mission.prototype.yaw = function(angle) {
|
||||||
|
var self = this;
|
||||||
|
this._steps.push(function(cb) {
|
||||||
|
self._control.yaw(angle,cb);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
var df = require('dateformat')
|
||||||
|
, common = require('../common')
|
||||||
|
, autonomy = require(common.root)
|
||||||
|
, mockClient = require('./mock/client')
|
||||||
|
;
|
||||||
|
|
||||||
|
var client = new mockClient();
|
||||||
|
var controller = new autonomy.Controller(client);
|
||||||
|
var mission = new autonomy.Mission(client, controller);
|
||||||
|
|
||||||
|
mission.log("mission-" + df(new Date(), "yyyy-mm-dd_hh-MM-ss") + ".txt");
|
||||||
|
|
||||||
|
mission.takeoff()
|
||||||
|
.hover(1000)
|
||||||
|
.forward(1)
|
||||||
|
.right(1)
|
||||||
|
.backward(1)
|
||||||
|
.left(1)
|
||||||
|
.hover(1000)
|
||||||
|
.land();
|
||||||
|
|
||||||
|
mission.run(function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
console.trace("Oops, something bad happened: %s", err.message);
|
||||||
|
mission.client().stop();
|
||||||
|
mission.client().land();
|
||||||
|
} else {
|
||||||
|
console.log("We are done!");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
@@ -20,6 +20,14 @@ function Client(options) {
|
|||||||
}, DT);
|
}, DT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client.prototype.takeoff = function(callback) {
|
||||||
|
setTimeout(callback, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Client.prototype.land = function(callback) {
|
||||||
|
setTimeout(callback, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
Client.prototype.front = function(speed) {
|
Client.prototype.front = function(speed) {
|
||||||
this._speed.vx = speed;
|
this._speed.vx = speed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// TODO This is broken. Need to write real tests.
|
|
||||||
console.log("The test is broken. Will have to write proper tests :-)");
|
|
||||||
|
|
||||||
var autonomy = require('..');
|
|
||||||
var client = require('./mock/client');
|
|
||||||
|
|
||||||
var controller = new autonomy.Controller(new client(), {state: {x: 0, y:0, z:1, yaw: 0}});
|
|
||||||
|
|
||||||
console.log("State: %j", controller.state());
|
|
||||||
|
|
||||||
controller.on('controlData', function(data) {
|
|
||||||
console.log("%j", data);
|
|
||||||
});
|
|
||||||
|
|
||||||
controller.go({x: 1, y: 1}, function(state) {
|
|
||||||
console.log("Reached state %j", state);
|
|
||||||
controller.disable();
|
|
||||||
});
|
|
||||||
@@ -115,5 +115,57 @@ test('Controller', {
|
|||||||
|
|
||||||
ctrl.zero();
|
ctrl.zero();
|
||||||
assert(ctrl._ekf.reset.calledOnce);
|
assert(ctrl._ekf.reset.calledOnce);
|
||||||
|
},
|
||||||
|
|
||||||
|
'up': function() {
|
||||||
|
var ctrl = new autonomy.Controller(this.mockClient);
|
||||||
|
var state = {x: 1, y: 2, z: 3, yaw: 0};
|
||||||
|
|
||||||
|
ctrl._state = state;
|
||||||
|
ctrl.up(1);
|
||||||
|
var goal = ctrl._goal;
|
||||||
|
|
||||||
|
assert.equal(goal.x, state.x);
|
||||||
|
assert.equal(goal.y, state.y);
|
||||||
|
assert.equal(goal.z, state.z + 1);
|
||||||
|
assert.equal(goal.yaw, state.yaw);
|
||||||
|
},
|
||||||
|
|
||||||
|
'down is invserse of up': function() {
|
||||||
|
var ctrl = new autonomy.Controller(this.mockClient);
|
||||||
|
var cb = function() {};
|
||||||
|
ctrl._state = {x: 0, y: 0, z: 1, yaw: 0};
|
||||||
|
sinon.spy(ctrl, 'up');
|
||||||
|
|
||||||
|
ctrl.down(1, cb);
|
||||||
|
assert(ctrl.up.calledWith(-1, cb));
|
||||||
|
},
|
||||||
|
|
||||||
|
'cannot go too low': function() {
|
||||||
|
var ctrl = new autonomy.Controller(this.mockClient);
|
||||||
|
var state = {x: 0, y: 0, z: 1, yaw: 0};
|
||||||
|
|
||||||
|
ctrl._state = state;
|
||||||
|
ctrl.down(1);
|
||||||
|
var goal = ctrl._goal;
|
||||||
|
|
||||||
|
assert.equal(goal.x, state.x);
|
||||||
|
assert.equal(goal.y, state.y);
|
||||||
|
assert.equal(goal.z, 0.5);
|
||||||
|
assert.equal(goal.yaw, state.yaw);
|
||||||
|
},
|
||||||
|
|
||||||
|
'altitude': function() {
|
||||||
|
var ctrl = new autonomy.Controller(this.mockClient);
|
||||||
|
var state = {x: 0, y: 0, z: 1, yaw: 0};
|
||||||
|
|
||||||
|
ctrl._state = state;
|
||||||
|
ctrl.altitude(3);
|
||||||
|
var goal = ctrl._goal;
|
||||||
|
|
||||||
|
assert.equal(goal.x, state.x);
|
||||||
|
assert.equal(goal.y, state.y);
|
||||||
|
assert.equal(goal.z, 3);
|
||||||
|
assert.equal(goal.yaw, state.yaw);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Referência em uma Nova Issue
Bloquear um usuário