Skip to content

Commit

Permalink
Allow servowrite to receive degrees or microseconds
Browse files Browse the repository at this point in the history
Also adds servoConfig
  • Loading branch information
dtex authored and rwaldron committed Jan 19, 2018
1 parent 7cd3947 commit 8e26cd5
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 14 deletions.
62 changes: 59 additions & 3 deletions lib/index.js
Expand Up @@ -366,6 +366,8 @@ class Pin extends Emitter {
isInverted: options.index === 0 || options.index === 1,
isPwm: false,
isServo: false,
servoMin: SERVO_MIN,
servoMax: SERVO_MAX,
index: PORTS.BY_NAME[options.port].offset + options.index,
mode: undefined,
pin,
Expand Down Expand Up @@ -423,6 +425,16 @@ class Pin extends Emitter {
state.isServo = mode === 4;
state.mode = mode;
}
},
servoMin: {
get() {
return state.servoMin;
}
},
servoMax: {
get() {
return state.servoMax;
}
}
});

Expand All @@ -439,10 +451,22 @@ class Pin extends Emitter {
});
}

servoConfig(min, max) {
const state = priv.get(this);

if (SERVO_PINS.includes(state.index)) {
this.mode = MODES.SERVO;
state.servoMin = min / (1e6 / SERVO_FREQUENCY);
state.servoMax = max / (1e6 / SERVO_FREQUENCY);
}

}

write(value) {
const state = priv.get(this);

if (state.isPwm || state.isServo) {

if (state.index === 15) {
state.pin.port.sock.write(new Buffer([Port.CMD.ANALOG_WRITE, value >> 8, value & 0xff]));
} else {
Expand Down Expand Up @@ -753,19 +777,51 @@ class Board extends Emitter {
return this;
}

servoConfig(pin, min, max) {
const state = priv.get(this);

if (typeof pin === "object" && pin !== null) {
let temp = pin;
pin = temp.pin;
min = temp.min;
max = temp.max;
}

if (typeof pin === "undefined") {
throw new Error("servoConfig: pin must be specified");
}

if (typeof min === "undefined") {
throw new Error("servoConfig: min must be specified");
}

if (typeof max === "undefined") {
throw new Error("servoConfig: max must be specified");
}

const index = ToPinIndex(pin);
this.pins[index].servoConfig(min, max);

}

servoWrite(pin, value) {
const state = priv.get(this);
const index = ToPinIndex(pin);
const constrained = constrain(value, 0, 180);


if (value < 544) {
value = scale(constrain(value, 0, 180), 0, 180, this.pins[index].servoMin, this.pins[index].servoMax);
} else {
value = constrain(value / (1e6 / SERVO_FREQUENCY), this.pins[index].servoMin, this.pins[index].servoMax);
}

// All but the last pin, which is a high frequency DAC
/* istanbul ignore else */
if (SERVO_PINS.includes(index)) {
if (state.pwm.frequency !== SERVO_FREQUENCY) {
state.pwm.frequency = SERVO_FREQUENCY;
tessel.pwmFrequency(SERVO_FREQUENCY);
}
this.pins[index].write(scale(constrained, 0, 180, 0.03, 0.12));
this.pins[index].write(value);
}
return this;
}
Expand Down
182 changes: 171 additions & 11 deletions test/index.js
Expand Up @@ -1529,79 +1529,239 @@ exports["Board.prototype.servoWrite"] = {
},

upper(test) {
test.expect(10 );
test.expect(12);

this.board.pinMode("a5", this.board.MODES.SERVO);

this.write.reset();

this.board.servoWrite("a5", 180);
this.board.servoWrite("a5", 255);
this.board.servoWrite("a5", 2400);
this.board.servoWrite("a5", true);

this.board.servoWrite(5, 180);
this.board.servoWrite(5, 255);
this.board.servoWrite(5, 2400);
this.board.servoWrite(5, true);


test.equal(this.write.callCount, 0);
test.equal(this.pwmFrequency.callCount, 1);
test.equal(this.pwmFrequency.lastCall.args[0], 50);
test.equal(this.pwmDutyCycle.callCount, 6);
test.equal(this.pwmDutyCycle.callCount, 8);
test.equal(this.pwmDutyCycle.getCall(0).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(1).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(2).args[0], 0.0305);
test.equal(this.pwmDutyCycle.getCall(3).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(2).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(3).args[0], 0.0305);
test.equal(this.pwmDutyCycle.getCall(4).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(5).args[0], 0.0305);
test.equal(this.pwmDutyCycle.getCall(5).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(6).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(7).args[0], 0.0305);
test.done();
},

lower(test) {
test.expect(10);
test.expect(12);

this.board.pinMode("a5", this.board.MODES.SERVO);

this.write.reset();

this.board.servoWrite("a5", 0);
this.board.servoWrite("a5", -1);
this.board.servoWrite("a5", 600);
this.board.servoWrite("a5", false);

this.board.servoWrite(5, 0);
this.board.servoWrite(5, -1);
this.board.servoWrite(5, 600);
this.board.servoWrite(5, false);

test.equal(this.write.callCount, 0);
test.equal(this.pwmFrequency.callCount, 1);
test.equal(this.pwmFrequency.lastCall.args[0], 50);
test.equal(this.pwmDutyCycle.callCount, 6);
test.equal(this.pwmDutyCycle.callCount, 8);
test.equal(this.pwmDutyCycle.getCall(0).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(1).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(2).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(3).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(4).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(5).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(6).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(7).args[0], 0.03);
test.done();
},

scales(test) {
test.expect(6);
test.expect(8);

this.board.pinMode("a5", this.board.MODES.SERVO);

this.write.reset();

this.board.servoWrite("a5", 0);
this.board.servoWrite("a5", 180);
this.board.servoWrite("a5", 600);
this.board.servoWrite("a5", 2400);

test.equal(this.write.callCount, 0);
test.equal(this.pwmFrequency.callCount, 1);
test.equal(this.pwmFrequency.lastCall.args[0], 50);
test.equal(this.pwmDutyCycle.callCount, 2);
test.equal(this.pwmDutyCycle.firstCall.args[0], 0.03);
test.equal(this.pwmDutyCycle.lastCall.args[0], 0.12);
test.equal(this.pwmDutyCycle.callCount, 4);
test.equal(this.pwmDutyCycle.getCall(0).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(1).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(2).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(3).args[0], 0.12);
test.done();
},
};

exports["Board.prototype.servoConfig"] = {
setUp(done) {
this.sandbox = sinon.sandbox.create();
this.write = this.sandbox.spy(tessel.port.B.pin[7].port.sock, "write");
this.pwmFrequency = this.sandbox.spy(tessel, "pwmFrequency");
this.pwmDutyCycle = this.sandbox.spy(T2.Pin.prototype, "pwmDutyCycle");

this.board = new Board();

done();
},

tearDown(done) {
Board.purge();
this.sandbox.restore();
done();
},

upper(test) {
test.expect(12);

this.board.pinMode("a5", this.board.MODES.SERVO);
this.board.pinMode("a6", this.board.MODES.SERVO);

this.write.reset();

this.board.servoConfig("a5", 1000, 2000);

this.board.servoWrite("a5", 180);
this.board.servoWrite("a5", 255);
this.board.servoWrite("a5", 2400);

this.board.servoWrite(5, 180);
this.board.servoWrite(5, 255);
this.board.servoWrite(5, 2400);

// Pin A4 should still use default servo range
this.board.servoWrite("a6", 180);
this.board.servoWrite(6, 180);

test.equal(this.write.callCount, 0);
test.equal(this.pwmFrequency.callCount, 1);
test.equal(this.pwmFrequency.lastCall.args[0], 50);
test.equal(this.pwmDutyCycle.callCount, 8);
test.equal(this.pwmDutyCycle.getCall(0).args[0], 0.1);
test.equal(this.pwmDutyCycle.getCall(1).args[0], 0.1);
test.equal(this.pwmDutyCycle.getCall(2).args[0], 0.1);
test.equal(this.pwmDutyCycle.getCall(3).args[0], 0.1);
test.equal(this.pwmDutyCycle.getCall(4).args[0], 0.1);
test.equal(this.pwmDutyCycle.getCall(5).args[0], 0.1);
test.equal(this.pwmDutyCycle.getCall(6).args[0], 0.12);
test.equal(this.pwmDutyCycle.getCall(7).args[0], 0.12);
test.done();
},

lower(test) {
test.expect(14);

this.board.pinMode("a5", this.board.MODES.SERVO);
this.board.pinMode("a6", this.board.MODES.SERVO);

this.write.reset();

this.board.servoConfig("a5", 1000, 2000);

this.board.servoWrite("a5", 0);
this.board.servoWrite("a5", -1);
this.board.servoWrite("a5", 600);
this.board.servoWrite("a5", false);

this.board.servoWrite(5, 0);
this.board.servoWrite(5, -1);
this.board.servoWrite(5, 600);
this.board.servoWrite(5, false);

this.board.servoWrite("a6", 0);
this.board.servoWrite(6, 0);

test.equal(this.write.callCount, 0);
test.equal(this.pwmFrequency.callCount, 1);
test.equal(this.pwmFrequency.lastCall.args[0], 50);
test.equal(this.pwmDutyCycle.callCount, 10);
test.equal(this.pwmDutyCycle.getCall(0).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(1).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(2).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(3).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(4).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(5).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(6).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(7).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(8).args[0], 0.03);
test.equal(this.pwmDutyCycle.getCall(9).args[0], 0.03);
test.done();
},

scales(test) {
test.expect(8);

this.board.pinMode("a5", this.board.MODES.SERVO);

this.write.reset();

this.board.servoConfig("a5", 1000, 2000);

this.board.servoWrite("a5", 0);
this.board.servoWrite("a5", 180);
this.board.servoWrite("a5", 600);
this.board.servoWrite("a5", 2400);

test.equal(this.write.callCount, 0);
test.equal(this.pwmFrequency.callCount, 1);
test.equal(this.pwmFrequency.lastCall.args[0], 50);
test.equal(this.pwmDutyCycle.callCount, 4);
test.equal(this.pwmDutyCycle.getCall(0).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(1).args[0], 0.1);
test.equal(this.pwmDutyCycle.getCall(2).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(3).args[0], 0.1);
test.done();
},

expectOptions(test) {
test.expect(5);

this.board.pinMode("a5", this.board.MODES.SERVO);

test.throws(_ => {
this.board.servoConfig();
}, "servoConfig: pin must be specified");

test.throws(_ => {
this.board.servoConfig("a5");
}, "servoConfig: min must be specified");

test.throws(_ => {
this.board.servoConfig("a5", 1000);
}, "servoConfig: max must be specified");

this.board.servoConfig({ pin: "a5", min: 1000,max: 2000});
this.board.servoWrite("a5", 0);
this.board.servoWrite("a5", 180);

test.equal(this.pwmDutyCycle.getCall(0).args[0], 0.05);
test.equal(this.pwmDutyCycle.getCall(1).args[0], 0.1);
test.done();
}
};

exports["Board.prototype.i2cConfig"] = {
Expand Down

0 comments on commit 8e26cd5

Please sign in to comment.