Skip to content

Commit 7a63e48

Browse files
committed
Add ability to set servo position in microseconds
If servo.write value is < 544 then SERVO_WRITE degrees, otherwise SERVO_WRITE_MICROSECONDS. Includes tests.
1 parent 08945e5 commit 7a63e48

File tree

4 files changed

+170
-17
lines changed

4 files changed

+170
-17
lines changed

lib/particle.js

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ var errors = {
1414
};
1515

1616
var pins = [
17-
{ id: "D0", modes: [0, 1, 3, 4] },
18-
{ id: "D1", modes: [0, 1, 3, 4] },
19-
{ id: "D2", modes: [0, 1, 3, 4] },
20-
{ id: "D3", modes: [0, 1, 3, 4] },
17+
{ id: "D0", modes: [0, 1, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
18+
{ id: "D1", modes: [0, 1, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
19+
{ id: "D2", modes: [0, 1, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
20+
{ id: "D3", modes: [0, 1, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
2121
{ id: "D4", modes: [0, 1] },
2222
{ id: "D5", modes: [0, 1] },
2323
{ id: "D6", modes: [0, 1] },
@@ -26,14 +26,14 @@ var pins = [
2626
{ id: "", modes: [] },
2727
{ id: "", modes: [] },
2828

29-
{ id: "A0", modes: [0, 1, 2, 3, 4] },
30-
{ id: "A1", modes: [0, 1, 2, 3, 4] },
29+
{ id: "A0", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
30+
{ id: "A1", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
3131
{ id: "A2", modes: [0, 1, 2] },
3232
{ id: "A3", modes: [0, 1, 2] },
33-
{ id: "A4", modes: [0, 1, 2, 3, 4] },
34-
{ id: "A5", modes: [0, 1, 2, 3, 4] },
35-
{ id: "A6", modes: [0, 1, 2, 3, 4] },
36-
{ id: "A7", modes: [0, 1, 2, 3, 4] }
33+
{ id: "A4", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 1000, servoMax: 2000 }},
34+
{ id: "A5", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
35+
{ id: "A6", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
36+
{ id: "A7", modes: [0, 1, 2, 3, 4], pwm: { servoMin: 600, servoMax: 2400 }},
3737
];
3838

3939
var modes = Object.freeze({
@@ -252,6 +252,7 @@ function Particle(opts) {
252252
name: pin.id,
253253
supportedModes: pin.modes,
254254
mode: pin.modes[0],
255+
pwm: pin.pwm,
255256
value: 0
256257
};
257258
});
@@ -479,10 +480,11 @@ Particle.prototype.pinMode = function(pin, mode) {
479480
return this;
480481
};
481482

482-
["analogWrite", "digitalWrite", "servoWrite"].forEach(function(fn) {
483+
484+
485+
["analogWrite", "digitalWrite"].forEach(function(fn) {
483486
var isAnalog = fn === "analogWrite";
484-
var isServo = fn === "servoWrite";
485-
var action = isAnalog ? 0x02 : (isServo ? 0x41 : 0x01);
487+
var action = isAnalog ? 0x02 : 0x01;
486488

487489
Particle.prototype[fn] = function(pin, value) {
488490
var state = priv.get(this);
@@ -502,6 +504,67 @@ Particle.prototype.pinMode = function(pin, mode) {
502504
};
503505
});
504506

507+
Particle.prototype.servoWrite = function(pin, value) {
508+
var state = priv.get(this);
509+
var buffer;
510+
var offset = pin[0] === "A" ? 10 : 0;
511+
var pinInt = (String(pin).replace(/A|D/i, "") | 0) + offset;
512+
513+
if (value < 544) {
514+
buffer = new Buffer(3);
515+
value = constrain(value, 0, 180);
516+
buffer[0] = 0x41;
517+
buffer[1] = pinInt;
518+
buffer[2] = value;
519+
} else {
520+
buffer = new Buffer(4);
521+
value = constrain(value, this.pins[pinInt].pwm.servoMin, this.pins[pinInt].pwm.servoMax);
522+
buffer[0] = 0x43;
523+
buffer[1] = pinInt;
524+
buffer[2] = value & 0x7f;
525+
buffer[3] = value >> 7;
526+
}
527+
528+
// console.log(buffer);
529+
state.socket.write(buffer);
530+
this.pins[pinInt].value = value;
531+
532+
return this;
533+
};
534+
535+
Particle.prototype.servoConfig = function(pin, min, max) {
536+
var offset = pin[0] === "A" ? 10 : 0;
537+
var pinInt = (String(pin).replace(/A|D/i, "") | 0) + offset;
538+
var temp;
539+
540+
if (typeof pin === "object" && pin !== null) {
541+
temp = pin;
542+
pin = temp.pin;
543+
min = temp.min;
544+
max = temp.max;
545+
}
546+
547+
if (typeof pin === "undefined") {
548+
throw new Error("servoConfig: pin must be specified");
549+
}
550+
551+
if (typeof min === "undefined") {
552+
throw new Error("servoConfig: min must be specified");
553+
}
554+
555+
if (typeof max === "undefined") {
556+
throw new Error("servoConfig: max must be specified");
557+
}
558+
559+
if (this.pins[pinInt].mode !== modes.SERVO) {
560+
this.pinMode(pinInt, modes.SERVO);
561+
}
562+
563+
pins[pinInt].pwm.servoMin = min;
564+
pins[pinInt].pwm.servoMax = max;
565+
566+
};
567+
505568
// TODO: Define protocol for gather this information.
506569
["analogRead", "digitalRead"].forEach(function(fn) {
507570
var isAnalog = fn === "analogRead";
@@ -812,6 +875,11 @@ Particle.prototype.close = function() {
812875
state.server.close();
813876
};
814877

878+
function scale(value, inMin, inMax, outMin, outMax) {
879+
return (value - inMin) * (outMax - outMin) /
880+
(inMax - inMin) + outMin;
881+
}
882+
815883
function constrain(value, lower, upper) {
816884
return Math.min(upper, Math.max(lower, value));
817885
}

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "particle-io",
33
"description": "Particle Core & Photon IO Plugin for Johnny-Five",
4-
"version": "0.14.0",
4+
"version": "0.15.0",
55
"homepage": "https://github.com/rwaldron/particle-io",
66
"author": {
77
"name": "Rick Waldron <[email protected]>",
@@ -31,6 +31,10 @@
3131
{
3232
"name": "Brian Genisio",
3333
"email": "<[email protected]>"
34+
},
35+
{
36+
"name": "Donovan Buck",
37+
"email": "<[email protected]>"
3438
}
3539
],
3640
"keywords": [

readme.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ board.on("ready", function() {
214214

215215
**servoWrite(pin, value)**
216216

217-
> Sets the pin to a value between 0 and 180, where the value represents degrees of the servo horn. The value is converted to a PWM signal. PWM is available on D0, D1, A0, A1, A4, A5, A6 and A7.
217+
> If the value is less than 544, sets the pin to a value constrained between 0 and 180, where the value represents degrees of the servo horn. If the value is 545 or greater, sets the pin to a value in microseconds.
218218
219219
Example:
220220
```js
@@ -228,6 +228,34 @@ board.on("ready", function() {
228228
});
229229
```
230230

231+
```js
232+
var board = new Particle(...);
233+
234+
board.on("ready", function() {
235+
236+
// Set the servo duty cycle to 1759 microseconds
237+
// Note that the servo pwm frequency is 50mhz and
238+
// the default servo range is 600-2400 microseconds
239+
this.servoWrite("D0", 1759);
240+
241+
});
242+
```
243+
244+
**servoConfig(pin, min, max)**
245+
246+
> Sets the range for the servo PWM duty cycle. The default range is 600 - 2400 microseconds. Can be called instead of pin mode.
247+
248+
Example:
249+
```js
250+
var board = new Particle(...);
251+
252+
board.on("ready", function() {
253+
254+
this.servoConfig("D0", 690, 2310);
255+
256+
});
257+
```
258+
231259

232260
**digitalRead(pin, handler)** Setup a continuous read handler for specific digital pin (D0-D7).
233261

test/particle.js

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,6 @@ exports["Particle.prototype.servoWrite"] = {
759759
}
760760
test.done();
761761
},
762-
763762
servoWriteDigital: function(test) {
764763
test.expect(3);
765764

@@ -774,7 +773,6 @@ exports["Particle.prototype.servoWrite"] = {
774773
}
775774
test.done();
776775
},
777-
778776
servoWriteAnalog: function(test) {
779777
test.expect(3);
780778

@@ -787,6 +785,61 @@ exports["Particle.prototype.servoWrite"] = {
787785
for (var i = 0; i < sent.length; i++) {
788786
test.equal(sent[i], buffer.readUInt8(i));
789787
}
788+
test.done();
789+
},
790+
servoWriteOutsideRange: function(test) {
791+
test.expect(3);
792+
793+
var sent = [0x41, 10, 180];
794+
795+
this.particle.servoWrite("A0", 220);
796+
797+
var buffer = this.socketwrite.args[0][0];
798+
799+
for (var i = 0; i < sent.length; i++) {
800+
test.equal(sent[i], buffer.readUInt8(i));
801+
}
802+
test.done();
803+
},
804+
servoWriteMicroseconds: function(test) {
805+
test.expect(4);
806+
807+
var sent = [0x43, 10, 14, 12];
808+
809+
this.particle.servoWrite("A0", 1550);
810+
811+
var buffer = this.socketwrite.args[0][0];
812+
813+
for (var i = 0; i < sent.length; i++) {
814+
test.equal(sent[i], buffer.readUInt8(i));
815+
}
816+
test.done();
817+
},
818+
servoWriteMicrosecondsOutsideRange: function(test) {
819+
test.expect(4);
820+
821+
var sent = [0x43, 10, 96, 18];
822+
823+
this.particle.servoWrite("A0", 3000);
824+
825+
var buffer = this.socketwrite.args[0][0];
826+
827+
for (var i = 0; i < sent.length; i++) {
828+
test.equal(sent[i], buffer.readUInt8(i));
829+
}
830+
test.done();
831+
},
832+
servoConfig: function(test) {
833+
test.expect(4);
834+
835+
test.equal(this.particle.pins[10].pwm.servoMin, 600);
836+
test.equal(this.particle.pins[10].pwm.servoMax, 2400);
837+
838+
this.particle.servoConfig("A0", 1000, 2000);
839+
840+
test.equal(this.particle.pins[10].pwm.servoMin, 1000);
841+
test.equal(this.particle.pins[10].pwm.servoMax, 2000);
842+
790843
test.done();
791844
}
792845
};

0 commit comments

Comments
 (0)