UNPKG

3.83 kBJavaScriptView Raw
1var Board = require("./board"),
2 events = require("events"),
3 util = require("util"),
4 within = require("./mixins/within");
5
6var priv = new Map();
7var Devices;
8
9/**
10 * Sonar
11 * @constructor
12 *
13 * @param {Object} opts Options: pin (analog)
14 */
15
16function Sonar(opts) {
17
18 if (!(this instanceof Sonar)) {
19 return new Sonar(opts);
20 }
21
22 Board.Component.call(
23 this, opts = Board.Options(opts)
24 );
25
26 var device, state;
27
28 // Sonar instance properties
29 this.freq = opts.freq || 100;
30 this.value = null;
31
32 state = {
33 last: 0,
34 median: 0,
35 samples: []
36 };
37
38 priv.set(this, state);
39
40 if (typeof opts.device === "string") {
41 device = Devices[opts.device];
42 } else {
43 device = opts.device;
44 }
45
46 if (typeof device === "undefined") {
47 device = Devices.DEFAULT;
48 }
49
50 device.initialize.call(this, opts);
51
52 if (!device.descriptor.inches) {
53 device.descriptor.inches = {
54 get: function() {
55 return +(this.cm * 0.39).toFixed(2);
56 }
57 };
58 }
59
60 device.descriptor.in = device.descriptor.inches;
61
62 Object.defineProperties(this, device.descriptor);
63
64 // Throttle
65 setInterval(function() {
66 // Nothing read since previous interval
67 if (state.samples.length === 0) {
68 return;
69 }
70
71 state.median = state.samples.sort()[Math.floor(state.samples.length / 2)];
72 this.value = state.median;
73
74 this.emit("data", state.median);
75
76 // If the state.median value for this interval is not the same as the
77 // state.median value in the last interval, fire a "change" event.
78 //
79 if (state.last && state.median &&
80 (state.median.toFixed(1) !== state.last.toFixed(1))) {
81 this.emit("change", state.median);
82 }
83
84 // Store this media value for comparison
85 // in next interval
86 state.last = state.median;
87
88 // Reset state.samples;
89 state.samples.length = 0;
90 }.bind(this), this.freq);
91}
92
93util.inherits(Sonar, events.EventEmitter);
94Object.assign(Sonar.prototype, within);
95
96Devices = {
97 SRF10: {
98 initialize: function(opts) {
99
100 var samples = priv.get(this).samples;
101 var address = 0x70;
102 var delay = 65;
103
104 // Set up I2C data connection
105 this.io.i2cConfig(opts);
106
107 // Startup parameter
108 this.io.i2cWrite(address, [0x01, 16]);
109 this.io.i2cWrite(address, [0x02, 255]);
110
111 this.io.setMaxListeners(100);
112
113 function read() {
114 this.io.i2cWrite(address, [0x02]);
115 this.io.i2cReadOnce(address, 2, function(data) {
116 samples.push((data[0] << 8) | data[1]);
117 }.bind(this));
118
119 prime.call(this);
120 }
121
122 function prime() {
123 // 0x52 result in us (microseconds)
124 this.io.i2cWrite(address, [0x00, 0x52]);
125
126 setTimeout(read.bind(this), delay);
127 }
128
129 prime.call(this);
130 },
131 descriptor: {
132 cm: {
133 get: function() {
134 var median = priv.get(this).median;
135 return +((((median / 2) * 343.2) / 10) / 1000).toFixed(1);
136 }
137 }
138 }
139 },
140
141 DEFAULT: {
142 initialize: function() {
143 var samples = priv.get(this).samples;
144
145 // Set the pin to ANALOG mode
146 this.mode = this.io.MODES.ANALOG;
147 this.io.pinMode(this.pin, this.mode);
148
149 this.io.analogRead(this.pin, function(data) {
150 samples.push(data);
151 }.bind(this));
152 },
153 descriptor: {
154 cm: {
155 get: function() {
156 var median = priv.get(this).median;
157 return +((median / 2) * 2.54).toFixed(1);
158 }
159 }
160 }
161 }
162};
163
164Devices.SRF02 = Devices.SRF08 = Devices.SRF10;
165
166module.exports = Sonar;
167
168// Reference
169//
170// http://www.maxbotix.com/tutorials.htm#Code_example_for_the_BasicX_BX24p
171// http://www.electrojoystick.com/tutorial/?page_id=285
172
173// Tutorials
174//
175// http://www.sensorpedia.com/blog/how-to-interface-an-ultrasonic-rangefinder-with-sensorpedia-via-twitter-guide-2/