johnny-five
Version:
The JavaScript Arduino Programming Framework.
296 lines (238 loc) • 5.34 kB
JavaScript
var Board = require("../lib/board.js"),
Emitter = require("events").EventEmitter,
util = require("util"),
__ = require("./fn");
var priv = new WeakMap(),
ESCS = [];
/**
* ESC
* @constructor
*
* @param {Object} opts Options: pin, range, pwmRange
* @param {Number} pin Pin number
*/
function ESC(opts) {
if (!(this instanceof ESC)) {
return new ESC(opts);
}
var history = [];
// Initialize a Device instance on a Board
Board.Device.call(
this, opts = Board.Options(opts)
);
// Set the pin to SERVO (OUTPUT) mode
this.mode = this.io.MODES.SERVO;
this.io.pinMode(this.pin, this.mode);
// When in debug mode, if pin is not a PWM pin, emit an error
if (opts.debug && !this.board.pins.isESC(this.pin)) {
Board.Pins.Error({
pin: this.pin,
type: "PWM",
via: "ESC",
});
}
priv.set(this, {
// All speed history for this ESC
// history = [
// {
// timestamp: Date.now(),
// speed: speed
// }
// ];
history: history
});
this.interval = null;
this.startAt = opts.startAt !== undefined ?
opts.startAt : 0;
this.range = opts.range || [0, 180];
if (opts.pwmRange) {
this.range = [
__.scale(opts.pwmRange[0], 600, 2400, 0, 180),
__.scale(opts.pwmRange[1], 600, 2400, 0, 180)
];
}
// Allow user defined ids, defaults to system ID
this.id = opts.id || Board.uid();
Object.defineProperties(this, {
history: {
get: function() {
return history.slice(-5);
}
},
last: {
get: function() {
return history[history.length - 1];
}
},
speed: {
get: function() {
return history[history.length - 1].speed;
}
}
});
this.to(this.startAt);
// Push this esc into the private
// esc instance array.
ESCS.push(this);
}
util.inherits(ESC, Emitter);
/**
* to
*
* Set the ESC's speed
*
* @param {Float} speed 0...1
*
* @return {ESC} instance
*/
ESC.prototype.to = function(speed) {
speed = +__.constrain(speed, 0, 1).toFixed(2);
if (this.interval) {
return;
}
if (this.last && this.last.speed === speed) {
return this;
}
var steps = 0;
var history = priv.get(this).history;
var lspeed, hspeed;
if (this.last) {
lspeed = this.last.speed * 100;
hspeed = speed * 100;
steps = Math.round(Math.abs(lspeed - hspeed));
if (!steps) {
return this;
}
this.interval = setInterval(function() {
var lspeed = Math.round(this.last.speed * 100);
var throttle = lspeed;
var send;
if (hspeed > throttle) {
throttle++;
} else {
throttle--;
}
this.io.servoWrite(
this.pin, __.scale(throttle, 0, 100, this.range[0], this.range[1])
);
history.push({
timestamp: Date.now(),
speed: +(throttle / 100).toFixed(2)
});
if (steps) {
steps--;
if (!steps) {
clearInterval(this.interval);
this.interval = null;
}
}
}.bind(this), 10);
} else {
process.nextTick(
this.io.servoWrite.bind(this.io, this.pin, speed)
);
history.push({
timestamp: Date.now(),
speed: speed
});
}
return this;
};
/**
* min Set ESC to minimum throttle
* @return {Object} instance
*/
ESC.prototype.min = function() {
return this.to(this.range[0]);
};
/**
* max Set ESC to maximum throttle
* @return {[type]} [description]
*/
ESC.prototype.max = function() {
return this.to(this.range[1]);
};
/**
* stop Stop the ESC
* @return {Object} instance
*/
ESC.prototype.stop = ESC.prototype.min;
/**
* ESC.Array()
* new ESC.Array()
*
* Constructs an Array-like instance of all escs
*/
ESC.Array = function(pins) {
if (!(this instanceof ESC.Array)) {
return new ESC.Array(pins);
}
var escs = [];
var pinOrESC;
if (pins) {
while (pins.length) {
pinOrESC = pins.shift();
escs.push(
typeof pinOrESC === "number" ?
new ESC(pinOrESC) : pinOrESC
);
}
} else {
escs = ESCS.slice();
}
escs.forEach(function(esc, index) {
this[index] = esc;
}, this);
this.length = escs.length;
};
/**
* each Execute callbackFn for each active esc instance
*
* eg.
* array.each(function( esc, index ) {
* `this` refers to the current esc instance
* });
*
* @param {[type]} callbackFn [description]
* @return {[type]} [description]
*/
ESC.Array.prototype.each = function(callbackFn) {
var esc, i, length;
length = this.length;
for (i = 0; i < length; i++) {
esc = this[i];
callbackFn.call(esc, esc, i);
}
return this;
};
/**
*
* ESC.Array, min()
*
* set all escs to the minimum throttle
*
* eg. array.min();
* ESC.Array, max()
*
* set all escs to the maximum throttle
*
* eg. array.max();
* ESC.Array, stop()
*
* stop all escs
*
* eg. array.stop();
*/
Object.keys(ESC.prototype).forEach(function(method) {
// Create ESC.Array wrappers for each method listed.
// This will allow us control over all ESC instances
// simultaneously.
ESC.Array.prototype[method] = function() {
var args = [].slice.call(arguments);
this.each(function(esc) {
ESC.prototype[method].apply(esc, args);
});
return this;
};
});
module.exports = ESC;