From c9e0b0214e7a7fe30ecbc19fe253eb4e382a3fe9 Mon Sep 17 00:00:00 2001 From: Nathan Kellenicki Date: Sat, 4 Aug 2018 23:24:06 +0100 Subject: [PATCH] Added speed ramping capability --- DOCS.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ boostmovehub.ts | 18 ++++++++++++++++++ hub.ts | 40 ++++++++++++++++++++++++++++++++-------- puphub.ts | 19 +++++++++++++++++++ wedo2smarthub.ts | 18 ++++++++++++++++++ 6 files changed, 183 insertions(+), 8 deletions(-) diff --git a/DOCS.md b/DOCS.md index f0501ad..d2eb9cb 100644 --- a/DOCS.md +++ b/DOCS.md @@ -82,6 +82,7 @@ Emits when a LPF2 Hub device is found. * [.setLEDColor(color)](#WeDo2SmartHub+setLEDColor) ⇒ Promise * [.setLEDRGB(red, green, blue)](#WeDo2SmartHub+setLEDRGB) ⇒ Promise * [.setMotorSpeed(port, speed, [time])](#WeDo2SmartHub+setMotorSpeed) ⇒ Promise + * [.rampMotorSpeed(port, fromSpeed, toSpeed, time)](#WeDo2SmartHub+rampMotorSpeed) ⇒ Promise * [.playSound(frequency, time)](#WeDo2SmartHub+playSound) ⇒ Promise * [.connect()](#Hub+connect) ⇒ Promise * [.disconnect()](#Hub+disconnect) ⇒ Promise @@ -198,6 +199,21 @@ Set the motor speed on a given port. | speed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | | [time] | number | How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely. | + + +### weDo2SmartHub.rampMotorSpeed(port, fromSpeed, toSpeed, time) ⇒ Promise +Ramp the motor speed on a given port. + +**Kind**: instance method of [WeDo2SmartHub](#WeDo2SmartHub) +**Returns**: Promise - Resolved upon successful completion of command. + +| Param | Type | Description | +| --- | --- | --- | +| port | string | | +| fromSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| toSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| time | number | How long the ramp should last (in milliseconds). | + ### weDo2SmartHub.playSound(frequency, time) ⇒ Promise @@ -378,6 +394,7 @@ Emits when an attached motor or sensor is detached from the Hub. * [.batteryLevel](#Hub+batteryLevel) * [.setLEDColor(color)](#BoostMoveHub+setLEDColor) ⇒ Promise * [.setMotorSpeed(port, speed, [time])](#BoostMoveHub+setMotorSpeed) ⇒ Promise + * [.rampMotorSpeed(port, fromSpeed, toSpeed, time)](#BoostMoveHub+rampMotorSpeed) ⇒ Promise * [.setMotorAngle(port, angle, [speed])](#BoostMoveHub+setMotorAngle) ⇒ Promise * [.setName(name)](#LPF2Hub+setName) ⇒ Promise * [.connect()](#Hub+connect) ⇒ Promise @@ -480,6 +497,21 @@ Set the motor speed on a given port. | speed | number \| Array.<number> | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds. | | [time] | number | How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely. | + + +### boostMoveHub.rampMotorSpeed(port, fromSpeed, toSpeed, time) ⇒ Promise +Ramp the motor speed on a given port. + +**Kind**: instance method of [BoostMoveHub](#BoostMoveHub) +**Returns**: Promise - Resolved upon successful completion of command. + +| Param | Type | Description | +| --- | --- | --- | +| port | string | | +| fromSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| toSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| time | number | How long the ramp should last (in milliseconds). | + ### boostMoveHub.setMotorAngle(port, angle, [speed]) ⇒ Promise @@ -673,6 +705,7 @@ Emits when an attached motor or sensor is detached from the Hub. * [.batteryLevel](#Hub+batteryLevel) * [.setLEDColor(color)](#PUPHub+setLEDColor) ⇒ Promise * [.setMotorSpeed(port, speed, [time])](#PUPHub+setMotorSpeed) ⇒ Promise + * [.rampMotorSpeed(port, fromSpeed, toSpeed, time)](#PUPHub+rampMotorSpeed) ⇒ Promise * [.setName(name)](#LPF2Hub+setName) ⇒ Promise * [.connect()](#Hub+connect) ⇒ Promise * [.disconnect()](#Hub+disconnect) ⇒ Promise @@ -773,6 +806,21 @@ Set the motor speed on a given port. | speed | number \| Array.<number> | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds. | | [time] | number | How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely. | + + +### pupHub.rampMotorSpeed(port, fromSpeed, toSpeed, time) ⇒ Promise +Ramp the motor speed on a given port. + +**Kind**: instance method of [PUPHub](#PUPHub) +**Returns**: Promise - Resolved upon successful completion of command. + +| Param | Type | Description | +| --- | --- | --- | +| port | string | | +| fromSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| toSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| time | number | How long the ramp should last (in milliseconds). | + ### pupHub.setName(name) ⇒ Promise diff --git a/README.md b/README.md index 76969bd..d860bcf 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ Emits when a LPF2 Hub device is found. * [.setLEDColor(color)](#WeDo2SmartHub+setLEDColor) ⇒ Promise * [.setLEDRGB(red, green, blue)](#WeDo2SmartHub+setLEDRGB) ⇒ Promise * [.setMotorSpeed(port, speed, [time])](#WeDo2SmartHub+setMotorSpeed) ⇒ Promise + * [.rampMotorSpeed(port, fromSpeed, toSpeed, time)](#WeDo2SmartHub+rampMotorSpeed) ⇒ Promise * [.playSound(frequency, time)](#WeDo2SmartHub+playSound) ⇒ Promise * [.connect()](#Hub+connect) ⇒ Promise * [.disconnect()](#Hub+disconnect) ⇒ Promise @@ -250,6 +251,21 @@ Set the motor speed on a given port. | speed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | | [time] | number | How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely. | + + +### weDo2SmartHub.rampMotorSpeed(port, fromSpeed, toSpeed, time) ⇒ Promise +Ramp the motor speed on a given port. + +**Kind**: instance method of [WeDo2SmartHub](#WeDo2SmartHub) +**Returns**: Promise - Resolved upon successful completion of command. + +| Param | Type | Description | +| --- | --- | --- | +| port | string | | +| fromSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| toSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| time | number | How long the ramp should last (in milliseconds). | + ### weDo2SmartHub.playSound(frequency, time) ⇒ Promise @@ -430,6 +446,7 @@ Emits when an attached motor or sensor is detached from the Hub. * [.batteryLevel](#Hub+batteryLevel) * [.setLEDColor(color)](#BoostMoveHub+setLEDColor) ⇒ Promise * [.setMotorSpeed(port, speed, [time])](#BoostMoveHub+setMotorSpeed) ⇒ Promise + * [.rampMotorSpeed(port, fromSpeed, toSpeed, time)](#BoostMoveHub+rampMotorSpeed) ⇒ Promise * [.setMotorAngle(port, angle, [speed])](#BoostMoveHub+setMotorAngle) ⇒ Promise * [.setName(name)](#LPF2Hub+setName) ⇒ Promise * [.connect()](#Hub+connect) ⇒ Promise @@ -532,6 +549,21 @@ Set the motor speed on a given port. | speed | number \| Array.<number> | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds. | | [time] | number | How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely. | + + +### boostMoveHub.rampMotorSpeed(port, fromSpeed, toSpeed, time) ⇒ Promise +Ramp the motor speed on a given port. + +**Kind**: instance method of [BoostMoveHub](#BoostMoveHub) +**Returns**: Promise - Resolved upon successful completion of command. + +| Param | Type | Description | +| --- | --- | --- | +| port | string | | +| fromSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| toSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| time | number | How long the ramp should last (in milliseconds). | + ### boostMoveHub.setMotorAngle(port, angle, [speed]) ⇒ Promise @@ -725,6 +757,7 @@ Emits when an attached motor or sensor is detached from the Hub. * [.batteryLevel](#Hub+batteryLevel) * [.setLEDColor(color)](#PUPHub+setLEDColor) ⇒ Promise * [.setMotorSpeed(port, speed, [time])](#PUPHub+setMotorSpeed) ⇒ Promise + * [.rampMotorSpeed(port, fromSpeed, toSpeed, time)](#PUPHub+rampMotorSpeed) ⇒ Promise * [.setName(name)](#LPF2Hub+setName) ⇒ Promise * [.connect()](#Hub+connect) ⇒ Promise * [.disconnect()](#Hub+disconnect) ⇒ Promise @@ -825,6 +858,21 @@ Set the motor speed on a given port. | speed | number \| Array.<number> | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. If you are specifying port AB to control both motors, you can optionally supply a tuple of speeds. | | [time] | number | How long to activate the motor for (in milliseconds). Leave empty to turn the motor on indefinitely. | + + +### pupHub.rampMotorSpeed(port, fromSpeed, toSpeed, time) ⇒ Promise +Ramp the motor speed on a given port. + +**Kind**: instance method of [PUPHub](#PUPHub) +**Returns**: Promise - Resolved upon successful completion of command. + +| Param | Type | Description | +| --- | --- | --- | +| port | string | | +| fromSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| toSpeed | number | For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. | +| time | number | How long the ramp should last (in milliseconds). | + ### pupHub.setName(name) ⇒ Promise diff --git a/boostmovehub.ts b/boostmovehub.ts index 0aae010..2f4dbfd 100644 --- a/boostmovehub.ts +++ b/boostmovehub.ts @@ -133,6 +133,24 @@ export class BoostMoveHub extends LPF2Hub { } + /** + * Ramp the motor speed on a given port. + * @method BoostMoveHub#rampMotorSpeed + * @param {string} port + * @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. + * @param {number} toSpeed 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 rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) { + return new Promise((resolve, reject) => { + this._calculateRamp(fromSpeed, toSpeed, time).on("changeSpeed", (speed) => { + this.setMotorSpeed(port, speed); + }).on("finished", resolve); + }); + } + + /** * Rotate a motor by a given angle. * @method BoostMoveHub#setMotorAngle diff --git a/hub.ts b/hub.ts index 46b338a..4dc1372 100644 --- a/hub.ts +++ b/hub.ts @@ -6,6 +6,7 @@ import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); +import { resolve } from "path"; const debug = Debug("hub"); @@ -89,7 +90,6 @@ export class Hub extends EventEmitter { this._peripheral.connect((err: string) => { this._rssi = this._peripheral.rssi; - const rssiUpdateInterval = setInterval(() => { this._peripheral.updateRssi((err: string, rssi: number) => { if (!err) { @@ -113,22 +113,16 @@ export class Hub extends EventEmitter { } debug("Service/characteristic discovery started"); - const servicePromises: Array> = []; - services.forEach((service) => { - servicePromises.push(new Promise((resolve, reject) => { - service.discoverCharacteristics([], (err, characteristics) => { characteristics.forEach((characteristic) => { this._characteristics[characteristic.uuid] = characteristic; }); return resolve(); }); - })); - }); Promise.all(servicePromises).then(() => { @@ -303,13 +297,43 @@ export class Hub extends EventEmitter { if (speed < -100) { speed = -100; } - return Math.round((speed - -100) * (240 - 158) / (-1 - -100) + 158); // In reverse, minimum speed is 245, maximum speed is 160 + return Math.round((speed - -100) * (240 - 158) / (-1 - -100) + 158); // In reverse, minimum speed is 240, maximum speed is 158 } else { return 0; } } + protected _calculateRamp (fromSpeed: number, toSpeed: number, time: number) { + const emitter = new EventEmitter(); + const steps = Math.abs(toSpeed - fromSpeed); + let delay = time / steps; + let increment = 1; + if (delay < 50 && steps > 0) { + increment = 50 / delay; + delay = 50; + } + if (fromSpeed > toSpeed) { + increment = -increment; + } + let i = 0; + const interval = setInterval(() => { + let speed = Math.round(fromSpeed + (++i * increment)); + if (toSpeed > fromSpeed && speed > toSpeed) { + speed = toSpeed; + } else if (fromSpeed > toSpeed && speed < toSpeed) { + speed = toSpeed; + } + emitter.emit("changeSpeed", speed); + if (speed === toSpeed) { + clearInterval(interval); + emitter.emit("finished"); + } + }, delay); + return emitter; +} + + protected _portLookup (port: string) { if (!this._ports[port.toUpperCase()]) { throw new Error(`Port ${port.toUpperCase()} does not exist on this Hub type`); diff --git a/puphub.ts b/puphub.ts index 321236f..47e3cb3 100644 --- a/puphub.ts +++ b/puphub.ts @@ -6,6 +6,7 @@ import { Port } from "./port"; import * as Consts from "./consts"; import Debug = require("debug"); +import { resolve } from "path"; const debug = Debug("puphub"); @@ -126,4 +127,22 @@ export class PUPHub extends LPF2Hub { } + /** + * Ramp the motor speed on a given port. + * @method PUPHub#rampMotorSpeed + * @param {string} port + * @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. + * @param {number} toSpeed 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 rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) { + return new Promise((resolve, reject) => { + this._calculateRamp(fromSpeed, toSpeed, time).on("changeSpeed", (speed) => { + this.setMotorSpeed(port, speed); + }).on("finished", resolve); + }); + } + + } diff --git a/wedo2smarthub.ts b/wedo2smarthub.ts index bafc27d..4a9ff9c 100644 --- a/wedo2smarthub.ts +++ b/wedo2smarthub.ts @@ -136,6 +136,24 @@ export class WeDo2SmartHub extends Hub { } + /** + * Ramp the motor speed on a given port. + * @method WeDo2SmartHub#rampMotorSpeed + * @param {string} port + * @param {number} fromSpeed For forward, a value between 1 - 100 should be set. For reverse, a value between -1 to -100. Stop is 0. + * @param {number} toSpeed 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 rampMotorSpeed (port: string, fromSpeed: number, toSpeed: number, time: number) { + return new Promise((resolve, reject) => { + this._calculateRamp(fromSpeed, toSpeed, time).on("changeSpeed", (speed) => { + this.setMotorSpeed(port, speed); + }).on("finished", resolve); + }); + } + + /** * Play a sound on the Hub's in-built buzzer * @method WeDo2SmartHub#playSound