Adding power and brightness ramping back in
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Nathan Kellenicki 2020-01-13 10:58:57 -08:00
parent 63f1c10fcc
commit 5fde49c0c2
6 changed files with 104 additions and 4 deletions

View File

@ -44,6 +44,7 @@ export class AbsoluteMotor extends TachoMotor {
if (this.isWeDo2SmartHub) { if (this.isWeDo2SmartHub) {
throw new Error("Absolute positioning is not available on the WeDo 2.0 Smart Hub"); throw new Error("Absolute positioning is not available on the WeDo 2.0 Smart Hub");
} }
this.cancelEventTimer();
return new Promise((resolve) => { return new Promise((resolve) => {
this._busy = true; this._busy = true;
if (speed === undefined || speed === null) { if (speed === undefined || speed === null) {
@ -78,6 +79,7 @@ export class AbsoluteMotor extends TachoMotor {
if (this.isWeDo2SmartHub) { if (this.isWeDo2SmartHub) {
throw new Error("Absolute positioning is not available on the WeDo 2.0 Smart Hub"); throw new Error("Absolute positioning is not available on the WeDo 2.0 Smart Hub");
} }
this.cancelEventTimer();
return new Promise((resolve) => { return new Promise((resolve) => {
this._busy = true; this._busy = true;
let message; let message;
@ -97,6 +99,7 @@ export class AbsoluteMotor extends TachoMotor {
} }
public async calibrateServo () { public async calibrateServo () {
this.cancelEventTimer();
const oldMode = this.mode; const oldMode = this.mode;
let currentAngle = 0; let currentAngle = 0;
const listener = ({ angle }: { angle: number }) => { const listener = ({ angle }: { angle: number }) => {
@ -142,6 +145,7 @@ export class AbsoluteMotor extends TachoMotor {
} }
public async resetServo (angle: number) { public async resetServo (angle: number) {
this.cancelEventTimer();
const oldMode = this.mode; const oldMode = this.mode;
let currentAngle = 0; let currentAngle = 0;
const listener = ({ angle }: { angle: number }) => { const listener = ({ angle }: { angle: number }) => {

View File

@ -4,7 +4,7 @@ import { IDeviceInterface } from "../interfaces";
import * as Consts from "../consts"; import * as Consts from "../consts";
import { mapSpeed } from "../utils"; import { calculateRamp, mapSpeed } from "../utils";
export class BasicMotor extends Device { export class BasicMotor extends Device {
@ -20,7 +20,10 @@ export class BasicMotor extends Device {
* @param {number} power For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. * @param {number} power For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
* @returns {Promise} Resolved upon successful completion of command. * @returns {Promise} Resolved upon successful completion of command.
*/ */
public setPower (power: number) { public setPower (power: number, interrupt: boolean = true) {
if (interrupt) {
this.cancelEventTimer();
}
return new Promise((resolve) => { return new Promise((resolve) => {
this.writeDirect(0x00, Buffer.from([mapSpeed(power)])); this.writeDirect(0x00, Buffer.from([mapSpeed(power)]));
return resolve(); return resolve();
@ -28,12 +31,33 @@ export class BasicMotor extends Device {
} }
/**
* Ramp the motor power.
* @method BasicMotor#rampPower
* @param {number} fromPower For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
* @param {number} toPower For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0.
* @param {number} time How long the ramp should last (in milliseconds).
* @returns {Promise} Resolved upon successful completion of command.
*/
public rampPower (fromPower: number, toPower: number, time: number) {
this.cancelEventTimer();
return new Promise((resolve) => {
calculateRamp(this, fromPower, toPower, time)
.on("changePower", (power) => {
this.setPower(power, false);
})
.on("finished", resolve);
});
}
/** /**
* Stop the motor. * Stop the motor.
* @method BasicMotor#stop * @method BasicMotor#stop
* @returns {Promise} Resolved upon successful completion of command. * @returns {Promise} Resolved upon successful completion of command.
*/ */
public stop () { public stop () {
this.cancelEventTimer();
return this.setPower(0); return this.setPower(0);
} }
@ -44,6 +68,7 @@ export class BasicMotor extends Device {
* @returns {Promise} Resolved upon successful completion of command. * @returns {Promise} Resolved upon successful completion of command.
*/ */
public brake () { public brake () {
this.cancelEventTimer();
return this.setPower(127); return this.setPower(127);
} }

View File

@ -20,6 +20,7 @@ export class Device extends EventEmitter {
private _isWeDo2SmartHub: boolean; private _isWeDo2SmartHub: boolean;
private _isVirtualPort: boolean = false; private _isVirtualPort: boolean = false;
private _eventTimer: NodeJS.Timer | null = null;
constructor (hub: IDeviceInterface, portId: number, modeMap: {[event: string]: number} = {}, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) { constructor (hub: IDeviceInterface, portId: number, modeMap: {[event: string]: number} = {}, type: Consts.DeviceType = Consts.DeviceType.UNKNOWN) {
super(); super();
@ -136,6 +137,17 @@ export class Device extends EventEmitter {
} }
} }
public setEventTimer (timer: NodeJS.Timer) {
this._eventTimer = timer;
}
public cancelEventTimer () {
if (this._eventTimer) {
clearTimeout(this._eventTimer);
this._eventTimer = null;
}
}
private _ensureConnected () { private _ensureConnected () {
if (!this.connected) { if (!this.connected) {
throw new Error("Device is not connected"); throw new Error("Device is not connected");

View File

@ -3,6 +3,7 @@ import { Device } from "./device";
import { IDeviceInterface } from "../interfaces"; import { IDeviceInterface } from "../interfaces";
import * as Consts from "../consts"; import * as Consts from "../consts";
import { calculateRamp } from "../utils";
export class Light extends Device { export class Light extends Device {
@ -14,11 +15,14 @@ export class Light extends Device {
/** /**
* Set the light brightness. * Set the light brightness.
* @method Light#brightness * @method Light#setBrightness
* @param {number} brightness Brightness value between 0-100 (0 is off) * @param {number} brightness Brightness value between 0-100 (0 is off)
* @returns {Promise} Resolved upon successful completion of command. * @returns {Promise} Resolved upon successful completion of command.
*/ */
public setBrightness (brightness: number) { public setBrightness (brightness: number, interrupt: boolean = true) {
if (interrupt) {
this.cancelEventTimer();
}
return new Promise((resolve) => { return new Promise((resolve) => {
this.writeDirect(0x00, Buffer.from([brightness])); this.writeDirect(0x00, Buffer.from([brightness]));
return resolve(); return resolve();
@ -26,4 +30,24 @@ export class Light extends Device {
} }
/**
* Ramp the light brightness.
* @method Light#rampBrightness
* @param {number} fromBrightness Brightness value between 0-100 (0 is off)
* @param {number} toBrightness Brightness value between 0-100 (0 is off)
* @param {number} time How long the ramp should last (in milliseconds).
* @returns {Promise} Resolved upon successful completion of command.
*/
public rampBrightness (fromBrightness: number, toBrightness: number, time: number) {
this.cancelEventTimer();
return new Promise((resolve) => {
calculateRamp(this, fromBrightness, toBrightness, time)
.on("changePower", (power) => {
this.setBrightness(power, false);
})
.on("finished", resolve);
});
}
} }

View File

@ -40,6 +40,7 @@ export class TachoMotor extends BasicMotor {
if (this.isWeDo2SmartHub) { if (this.isWeDo2SmartHub) {
throw new Error("Motor speed is not available on the WeDo 2.0 Smart Hub"); throw new Error("Motor speed is not available on the WeDo 2.0 Smart Hub");
} }
this.cancelEventTimer();
return new Promise((resolve) => { return new Promise((resolve) => {
this._busy = true; this._busy = true;
if (speed === undefined || speed === null) { if (speed === undefined || speed === null) {
@ -81,6 +82,7 @@ export class TachoMotor extends BasicMotor {
if (this.isWeDo2SmartHub) { if (this.isWeDo2SmartHub) {
throw new Error("Rotation is not available on the WeDo 2.0 Smart Hub"); throw new Error("Rotation is not available on the WeDo 2.0 Smart Hub");
} }
this.cancelEventTimer();
return new Promise((resolve) => { return new Promise((resolve) => {
this._busy = true; this._busy = true;
if (speed === undefined || speed === null) { if (speed === undefined || speed === null) {

View File

@ -1,3 +1,6 @@
import { EventEmitter } from "events";
import { Device } from "./devices/device";
// @ts-ignore // @ts-ignore
export const isWebBluetooth = (typeof navigator !== "undefined" && navigator && navigator.bluetooth); export const isWebBluetooth = (typeof navigator !== "undefined" && navigator && navigator.bluetooth);
@ -55,3 +58,33 @@ export const roundAngleToNearest90 = (angle: number) => {
} }
return -180; return -180;
}; };
export const calculateRamp = (device: Device, fromPower: number, toPower: number, time: number) => {
const emitter = new EventEmitter();
const steps = Math.abs(toPower - fromPower);
let delay = time / steps;
let increment = 1;
if (delay < 50 && steps > 0) {
increment = 50 / delay;
delay = 50;
}
if (fromPower > toPower) {
increment = -increment;
}
let i = 0;
const interval = setInterval(() => {
let power = Math.round(fromPower + (++i * increment));
if (toPower > fromPower && power > toPower) {
power = toPower;
} else if (fromPower > toPower && power < toPower) {
power = toPower;
}
emitter.emit("changePower", power);
if (power === toPower) {
clearInterval(interval);
emitter.emit("finished");
}
}, delay);
device.setEventTimer(interval);
return emitter;
};