johnny-five
Version:
The JavaScript Arduino Programming Framework.
282 lines (242 loc) • 5.74 kB
JavaScript
var Board = require("../lib/board.js"),
events = require("events"),
util = require("util"),
__ = require("../lib/fn.js"),
sum = __.sum,
scale = __.scale,
fma = __.fma;
var priv = new Map();
var axes = ["x", "y", "z"];
var rad2deg = 180 / Math.PI;
function ToPrecision(val, precision) {
return +(val).toPrecision(precision);
}
function magnitude(x, y, z) {
var a;
a = x * x;
a = fma(y, y, a);
a = fma(z, z, a);
return Math.sqrt(a);
}
function gravity(aref, value) {
var voltage = value * aref;
var mvG = aref / 10;
var bias = aref / 2;
voltage /= 1024;
return (voltage - bias) / mvG;
}
/**
* Accelerometer
* @constructor
*
* five.Accelerometer([ x, y[, z] ]);
*
* five.Accelerometer({
* pins: [ x, y[, z] ]
* zeroV: ...
* sensitivity: ...
* });
*
*
* @param {Object} opts [description]
*
*/
function Accelerometer(opts) {
if (!(this instanceof Accelerometer)) {
return new Accelerometer(opts);
}
var err = null;
var aref = 5;
var zeroV = 478;
var sensitivity = 96;
var state = {
x: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
},
y: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
},
z: {
value: 0,
previous: 0,
stash: [],
orientation: null,
inclination: null,
acceleration: null,
}
};
// Initialize a Device instance on a Board
Board.Device.call(
this, opts = Board.Options(opts)
);
if (opts.aref) {
aref = opts.aref;
}
if (opts.zeroV) {
zeroV = opts.zeroV;
}
if (opts.sensitivity) {
sensitivity = opts.sensitivity;
}
this.mode = this.io.MODES.ANALOG;
this.pins.forEach(function(pin, index) {
this.io.pinMode(pin, this.mode);
this.io.analogRead(pin, function(data) {
var axis = axes[index];
var sensor = state[axis];
var isChange = false;
// The first run needs to prime the "stash"
// of data values.
if (sensor.stash.length === 0) {
for (var i = 0; i < 5; i++) {
sensor.stash[i] = data;
}
}
sensor.previous = sensor.value;
sensor.stash.shift();
sensor.stash.push(data);
sensor.value = (sum(sensor.stash) / 5) | 0;
this.emit("data", {
x: state.x.value,
y: state.y.value,
z: state.z.value
});
if (this.acceleration !== sensor.acceleration) {
sensor.acceleration = this.acceleration;
isChange = true;
this.emit("acceleration", sensor.acceleration);
}
if (this.orientation !== sensor.orientation) {
sensor.orientation = this.orientation;
isChange = true;
this.emit("orientation", sensor.orientation);
}
if (this.inclination !== sensor.inclination) {
sensor.inclination = this.inclination;
isChange = true;
this.emit("inclination", sensor.inclination);
}
if (isChange) {
this.emit("change", {
x: this.x,
y: this.y,
z: this.z
});
}
}.bind(this));
}, this);
priv.set(this, state);
Object.defineProperties(this, {
/**
* [read-only] Calculated pitch value
* @property pitch
* @type Number
*/
pitch: {
get: function() {
var x, y, z, rads;
x = this.x;
y = this.y;
z = this.pins.length === 3 ? this.z : 1;
rads = Math.atan2(x, Math.hypot(y, z));
return ToPrecision(rads * rad2deg, 2);
}
},
/**
* [read-only] Calculated roll value
* @property roll
* @type Number
*/
roll: {
get: function() {
var x, y, z, rads;
x = this.x;
y = this.y;
z = this.pins.length === 3 ? this.z : 1;
rads = Math.atan2(y, Math.hypot(x, z));
return ToPrecision(rads * rad2deg, 2);
}
},
x: {
get: function() {
return ToPrecision((state.x.value - zeroV) / sensitivity, 2);
}
},
y: {
get: function() {
return ToPrecision((state.y.value - zeroV) / sensitivity, 2);
}
},
z: {
get: function() {
return this.pins.length === 3 ?
ToPrecision((state.z.value - zeroV) / sensitivity, 2) : 0;
}
},
gravity: {
get: function() {
return {
x: ToPrecision(gravity(aref, state.x.value), 2),
y: ToPrecision(gravity(aref, state.y.value), 2),
z: ToPrecision(gravity(aref, state.z.value), 2),
};
}
},
acceleration: {
get: function() {
return magnitude(
this.gravity.x,
this.gravity.y,
this.gravity.z
);
}
},
inclination: {
get: function() {
return Math.atan2(this.gravity.y, this.gravity.x) * rad2deg;
}
},
orientation: {
get: function() {
var abs = Math.abs;
var x = this.x;
var y = this.y;
var z = this.pins.length === 3 ? this.z : 1;
var xAbs = abs(x);
var yAbs = abs(y);
var zAbs = abs(z);
if (xAbs < yAbs && xAbs < zAbs) {
if (x > 0) {
return 1;
}
return -1;
}
if (yAbs < xAbs && yAbs < zAbs) {
if (y > 0) {
return 2;
}
return -2;
}
if (zAbs < xAbs && zAbs < yAbs) {
if (z > 0) {
return 3;
}
return -3;
}
return 0;
}
}
});
}
util.inherits(Accelerometer, events.EventEmitter);
module.exports = Accelerometer;