From 4efb534325ea3df1f65af0f1f41559d42adb66d3 Mon Sep 17 00:00:00 2001 From: Donovan Buck Date: Sun, 5 Jul 2020 10:35:48 -0500 Subject: [PATCH 1/7] Update test template --- CONTRIBUTING.md | 55 ++--------------------------- build/templates/test.js | 77 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 53 deletions(-) create mode 100644 build/templates/test.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9ba17b3..048ece0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,5 @@ ## j5e Repo Anatomy -One goal of j5e is write once, run anywhere. We are building toward this goal before TC-53 IOCP conformant platforms exist. To that end, the structure of this repo may change to help us support more platforms. The JS is the same across platforms, but the different implementations of ECMAScript Modules may require special concessions (package.json vs manifest.json and varying module resolution schemes). +One goal of j5e is write once, run anywhere. We are building toward this goal before TC-53 IOCP conformant platforms exist. To that end, the structure of this repo may change to help us support more platforms. The JS is the same across platforms, but the different implementations of ECMAScript Modules may require special concessions (package.json vs manifest.json and varying module resolution schemes for example). ### Special Scaffolding j5e is designed to import just the parts it needs, so subpath exports in node.js are absolutely necessary. To make everything link up you will need to symlink your dev folder to itself. From the root run ```npm link``` and then ```npm link j5e```. This will allow tests to import subpaths, and for subpaths to import their siblings. @@ -11,55 +11,4 @@ j5e is designed to import just the parts it needs, so subpath exports in node.js Tests are run using Mocha, Chai, Sinon, and node's built-in Assert module. Each class has its own js file in the ```./tests/``` folder. You can run tests by running ```npm run test``` or on a specific module by running ```npm run test ./test/rgb``` for example. **Test Organiztion** -Test files should be organized with the following heirarchy - -````js -describe('className', function() { - - describe('Instantiation', function() { - // All tests related to default instantiation - /* describe('Options', function() { - describe('someOptionProperty', async function() { - - it('should be configured appropriately for the option', async function() { - // ... - }); - // [ All other tests related to sink ] - }); - }); */ - // [ All other options, each with it's own describe ] - } - - describe('Properties', function() { - /* describe('someProperty', function() { - it('should respong with the property value', async function() { - // ... - }); - [ all other tests related to someProperty ] - }); - */ - // [ All other properties, each with it's own describe ] - }); - - describe('Methods', function() { - /* describe('doSomething', function() { - it('should doSomething', async function() { - // ... - }); - // [ all other tests related to doSomething ] - }); */ - // [ All other methods, each with it's own describe ] - }); - - describe('Events', function() { - /* describe('someEvent', function() { - it('should fire the event at the right time', async function() { - // ... - }); - // [ all other tests related to the event ] - }); */ - // [ All other Events, each with it's own describe ] - }); - -}); -```` +Test files should be organized with the heirarchy described in [/build/templates/test.js](build/templates/test.js). diff --git a/build/templates/test.js b/build/templates/test.js new file mode 100644 index 0000000..2aaba73 --- /dev/null +++ b/build/templates/test.js @@ -0,0 +1,77 @@ +import assert from "assert"; +import sinon from "sinon"; +import { Digital, PWM } from "@dtex/mock-io"; +import ClassName from "j5e/classname"; + +describe("ClassName", function() { + + describe("Instantiation", function() { + + // All tests related to default instantiation + + describe("Options", function() { + + describe("someOptionProperty", async function() { + + it("should be configured appropriately for the option", async function() { + // ... + }); + + // [ All other tests related to this option ] + + }); + }); + + // [ All other options, each with it's own describe ] + + }); + + describe("Properties", function() { + + describe("someProperty", function() { + + it("should respong with the property value", async function() { + // ... + }); + + // [ all other tests related to someProperty ] + + }); + + // [ All other properties, each with it's own describe ] + + }); + + describe("Methods", function() { + + describe("someMethod", function() { + + it("should do the right thing", async function() { + // ... + }); + + // [ all other tests related to someMethod ] + + }); + + // [ All other methods, each with it's own describe ] + + }); + + describe("Events", function() { + + describe("someEvent", function() { + + it("should emit the event at the appropriate time", async function() { + // ... + }); + + // [ all other tests related to someEvent ] + + }); + + // [ All other events, each with it's own describe ] + + }); + +}); From ea9b6abcf8716e7f993a2419b1ccd292bfe937e0 Mon Sep 17 00:00:00 2001 From: Donovan Buck Date: Sun, 5 Jul 2020 15:44:10 -0500 Subject: [PATCH 2/7] Update servo tests --- test/servo.js | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/test/servo.js b/test/servo.js index 0ebde32..f25d773 100644 --- a/test/servo.js +++ b/test/servo.js @@ -1,6 +1,6 @@ import assert from "assert"; import sinon from "sinon"; -import { Digital, PWM } from "@dtex/mock-io"; +import { PWM } from "@dtex/mock-io"; import Servo from "j5e/servo"; describe("Servo - Standard", function() { @@ -17,6 +17,103 @@ describe("Servo - Standard", function() { }); + describe("Options", function() { + + // pwmRange + // deadband + // Range + // deviceRange + // startAt + // offset + // invert + // center + + describe("type", async function() { + + it("should behave as contiuous rotation servo when type is \"continuous\"", async function() { + const servo = await new Servo({ + pin: 12, + io: PWM, + type: "continuous" + }); + + servo.cw(); + assert.equal(servo.position, 180); + + servo.stop(); + assert.equal(servo.position, 90); + }); + + }); + }); + + // [ All other options, each with it's own describe ] + + }); + + describe("Properties", function() { + + // history + // last + // position + + describe("someProperty", function() { + + it("should respond with the property value", async function() { + // ... + }); + + // [ all other tests related to someProperty ] + + }); + + // [ All other properties, each with it's own describe ] + + }); + + describe("Methods", function() { + + // to + // step + // min + // max + // center + // home + // sweep + // stop + // cw + // ccw + // normalize + // rangeToKeyFrames + describe("someMethod", function() { + + it("should do the right thing", async function() { + // ... + }); + + // [ all other tests related to someMethod ] + + }); + + // [ All other methods, each with it's own describe ] + + }); + + describe("Events", function() { + + //moveComplete + describe("someEvent", function() { + + it("should emit the event at the appropriate time", async function() { + // ... + }); + + // [ all other tests related to someEvent ] + + }); + + // [ All other events, each with it's own describe ] + }); }); From 024957d65f1df37cc4a6b69af491cd75d0579816 Mon Sep 17 00:00:00 2001 From: Donovan Buck Date: Sun, 5 Jul 2020 15:44:36 -0500 Subject: [PATCH 3/7] Add servo sweep example --- examples/servo-sweep/main.js | 4 ++++ examples/servo-sweep/manifest.json | 9 +++++++++ 2 files changed, 13 insertions(+) create mode 100644 examples/servo-sweep/main.js create mode 100644 examples/servo-sweep/manifest.json diff --git a/examples/servo-sweep/main.js b/examples/servo-sweep/main.js new file mode 100644 index 0000000..7a920a6 --- /dev/null +++ b/examples/servo-sweep/main.js @@ -0,0 +1,4 @@ +import Servo from "j5e/servo"; + +const servo = await new Servo(12); +servo.sweep(); \ No newline at end of file diff --git a/examples/servo-sweep/manifest.json b/examples/servo-sweep/manifest.json new file mode 100644 index 0000000..b29e394 --- /dev/null +++ b/examples/servo-sweep/manifest.json @@ -0,0 +1,9 @@ +{ + "include": [ + "$(MODDABLE)/modules/io/manifest.json", + "$(j5e)/lib/servo/manifest.json" + ], + "modules": { + "*": "./main" + } +} \ No newline at end of file From 521cfc17a22c99a9f9ef696e75a130a0c56ca37b Mon Sep 17 00:00:00 2001 From: Donovan Buck Date: Sun, 5 Jul 2020 15:44:50 -0500 Subject: [PATCH 4/7] Fix a typo --- build/templates/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/templates/test.js b/build/templates/test.js index 2aaba73..87d04fe 100644 --- a/build/templates/test.js +++ b/build/templates/test.js @@ -30,7 +30,7 @@ describe("ClassName", function() { describe("someProperty", function() { - it("should respong with the property value", async function() { + it("should respond with the property value", async function() { // ... }); From 2431b4dcb1904d3c3fe33778d598b741fac779ab Mon Sep 17 00:00:00 2001 From: Donovan Buck Date: Sun, 5 Jul 2020 15:46:02 -0500 Subject: [PATCH 5/7] Updates to servo Handle deadband with degrees instead of microseconds and defer mapping to microseconds until it's time to call write on the IO. --- lib/servo/index.js | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/lib/servo/index.js b/lib/servo/index.js index 162ee6d..784f343 100644 --- a/lib/servo/index.js +++ b/lib/servo/index.js @@ -35,7 +35,7 @@ class Servo extends Emitter { * @param {(string|constructor)} [options.io=builtin/pwm] - If passing an object, a string specifying a path to the IO provider or a constructor * @param {string} [options.type="standard"] - Type of servo ("standard" or "continuous") * @param {number[]} [options.pwmRange=[600, 2400]] - The pulse width range in microseconds - * @param {number[]} [options.deadband=[1500,1500]] - The range at which a continuos motion servo will not turn + * @param {number[]} [options.deadband=[90,90]] - The degree range at which a continuos motion servo will not turn * @param {number[]} [options.range=[0, 180]] - The allowed range of motion in degrees * @param {number[]} [options.deviceRange=[0, 180]] - The physical range of the servo in degrees * @param {number} [options.startAt="Any value within options.range"] - The desired start position of the servo @@ -50,6 +50,7 @@ class Servo extends Emitter { * @property {object[]} last.timestamp - Timestamp of position update * @property {object[]} last.target - The user requested position * @property {object[]} last.degrees - The corrected position (factors in offset and invert) + * @property {object[]} last.pulseWidth - The corrected pulseWidth (factors in offset and invert) * @property {number} position - The most recent request and corrected position (factors in offset and invert) * @example * Sweep a servo back and forth @@ -79,14 +80,8 @@ class Servo extends Emitter { }); this.#state.pwmRange = options.pwmRange || [600, 2400]; - - // This line is a hack until we can write in µs - this.#state.pwmRange = [34, 120]; this.#state.degreeRange = options.degreeRange || [0, 180]; - this.#state.deadband = options.deadband || [1500, 1500]; - - // This line is a hack until we can write in µs - this.#state.deadband = options.deadband || [77, 77]; + this.#state.deadband = options.deadband || [90, 90]; this.#state.offset = options.offset || 0; this.#state.startAt = options.startAt || (this.#state.degreeRange[1] - this.#state.degreeRange[0]) / 2; this.#state.range = options.range || [0 - this.offset, 180 - this.offset]; @@ -122,8 +117,6 @@ class Servo extends Emitter { this.initialize(options); - // If "startAt" is defined and center is falsy - // set servo to min or max degrees if (typeof options.startAt !== "undefined") { this.to(options.startAt); } else { @@ -152,7 +145,7 @@ class Servo extends Emitter { /** * Calls the write param on the IO instance for this servo. - * @param {number} degrees - The absolute position to move a servo to + * @param {number} pulseWidth - The target pulseWidth * @returns {Servo} * @ignore */ @@ -163,17 +156,19 @@ class Servo extends Emitter { return this; } - // Map value from degreeRange to pwmRange - let microseconds = map( - degrees, - this.#state.degreeRange[0], this.#state.degreeRange[1], - this.#state.pwmRange[0], this.#state.pwmRange[1] - ); + // Presumably not all IO's will support writeMicroseconds + if (this.io.writeMicroseconds) { + + let microseconds = map(degrees, this.#state.degreeRange[0], this.#state.degreeRange[1], this.#state.pwmRange[0], this.#state.pwmRange[1]); + this.io.write(microseconds | 0); + + } else { + + let value = map(degrees, this.#state.degreeRange[0], this.#state.degreeRange[1], 0, this.io.resolution ** 2 - 1); + this.io.write(value | 0); - // Restrict values to integers - microseconds |= 0; + } - this.io.write(microseconds); } /** @@ -282,6 +277,7 @@ class Servo extends Emitter { degrees: degrees, target: target }); + } } @@ -513,7 +509,7 @@ class Servo extends Emitter { */ cw(speed = 1) { speed = constrain(speed, 0, 1); - speed = map(speed, 0, 1, this.#state.deadband[1] + 1, this.#state.pwmRange[1]); + speed = map(speed, 0, 1, this.#state.deadband[1] + 1, this.#state.degreeRange[1]); return this.to(speed); } From 2a3876fb4a15014d41c2024232d23bd8d6468da9 Mon Sep 17 00:00:00 2001 From: Donovan Buck Date: Sun, 5 Jul 2020 15:47:52 -0500 Subject: [PATCH 6/7] Update docs --- docs/module-j5e_servo-Servo.html | 33 ++++++++++++++++----------- docs/servo_index.js.html | 38 ++++++++++++++------------------ 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/docs/module-j5e_servo-Servo.html b/docs/module-j5e_servo-Servo.html index 0a57c5e..cc0ff77 100644 --- a/docs/module-j5e_servo-Servo.html +++ b/docs/module-j5e_servo-Servo.html @@ -170,9 +170,9 @@
Parameters
deadband Array.<number> <optional>
- [1500,1500] + [90,90] - The range at which a continuos motion servo will not turn + The degree range at which a continuos motion servo will not turn @@ -321,6 +321,13 @@
Properties
The corrected position (factors in offset and invert) + + pulseWidth + Array.<object> + + The corrected pulseWidth (factors in offset and invert) + + @@ -384,7 +391,7 @@
Properties
@@ -503,7 +510,7 @@
Parameters
@@ -595,7 +602,7 @@
Parameters
@@ -677,7 +684,7 @@
Parameters
@@ -759,7 +766,7 @@
Parameters
@@ -851,7 +858,7 @@
Parameters
@@ -908,7 +915,7 @@

home @@ -993,7 +1000,7 @@
Parameters
@@ -1042,7 +1049,7 @@

stop @@ -1124,7 +1131,7 @@
Parameters
@@ -1206,7 +1213,7 @@
Parameters
diff --git a/docs/servo_index.js.html b/docs/servo_index.js.html index aa4b3ef..e83d88a 100644 --- a/docs/servo_index.js.html +++ b/docs/servo_index.js.html @@ -131,7 +131,7 @@

servo/index.js

* @param {(string|constructor)} [options.io=builtin/pwm] - If passing an object, a string specifying a path to the IO provider or a constructor * @param {string} [options.type="standard"] - Type of servo ("standard" or "continuous") * @param {number[]} [options.pwmRange=[600, 2400]] - The pulse width range in microseconds - * @param {number[]} [options.deadband=[1500,1500]] - The range at which a continuos motion servo will not turn + * @param {number[]} [options.deadband=[90,90]] - The degree range at which a continuos motion servo will not turn * @param {number[]} [options.range=[0, 180]] - The allowed range of motion in degrees * @param {number[]} [options.deviceRange=[0, 180]] - The physical range of the servo in degrees * @param {number} [options.startAt="Any value within options.range"] - The desired start position of the servo @@ -146,6 +146,7 @@

servo/index.js

* @property {object[]} last.timestamp - Timestamp of position update * @property {object[]} last.target - The user requested position * @property {object[]} last.degrees - The corrected position (factors in offset and invert) + * @property {object[]} last.pulseWidth - The corrected pulseWidth (factors in offset and invert) * @property {number} position - The most recent request and corrected position (factors in offset and invert) * @example * <caption>Sweep a servo back and forth</caption> @@ -175,14 +176,8 @@

servo/index.js

}); this.#state.pwmRange = options.pwmRange || [600, 2400]; - - // This line is a hack until we can write in µs - this.#state.pwmRange = [34, 120]; this.#state.degreeRange = options.degreeRange || [0, 180]; - this.#state.deadband = options.deadband || [1500, 1500]; - - // This line is a hack until we can write in µs - this.#state.deadband = options.deadband || [77, 77]; + this.#state.deadband = options.deadband || [90, 90]; this.#state.offset = options.offset || 0; this.#state.startAt = options.startAt || (this.#state.degreeRange[1] - this.#state.degreeRange[0]) / 2; this.#state.range = options.range || [0 - this.offset, 180 - this.offset]; @@ -218,8 +213,6 @@

servo/index.js

this.initialize(options); - // If "startAt" is defined and center is falsy - // set servo to min or max degrees if (typeof options.startAt !== "undefined") { this.to(options.startAt); } else { @@ -248,7 +241,7 @@

servo/index.js

/** * Calls the write param on the IO instance for this servo. - * @param {number} degrees - The absolute position to move a servo to + * @param {number} pulseWidth - The target pulseWidth * @returns {Servo} * @ignore */ @@ -259,17 +252,19 @@

servo/index.js

return this; } - // Map value from degreeRange to pwmRange - let microseconds = map( - degrees, - this.#state.degreeRange[0], this.#state.degreeRange[1], - this.#state.pwmRange[0], this.#state.pwmRange[1] - ); + // Presumably not all IO's will support writeMicroseconds + if (this.io.writeMicroseconds) { + + let microseconds = map(degrees, this.#state.degreeRange[0], this.#state.degreeRange[1], this.#state.pwmRange[0], this.#state.pwmRange[1]); + this.io.write(microseconds | 0); + + } else { + + let value = map(degrees, this.#state.degreeRange[0], this.#state.degreeRange[1], 0, this.io.resolution ** 2 - 1); + this.io.write(value | 0); - // Restrict values to integers - microseconds |= 0; + } - this.io.write(microseconds); } /** @@ -378,6 +373,7 @@

servo/index.js

degrees: degrees, target: target }); + } } @@ -609,7 +605,7 @@

servo/index.js

*/ cw(speed = 1) { speed = constrain(speed, 0, 1); - speed = map(speed, 0, 1, this.#state.deadband[1] + 1, this.#state.pwmRange[1]); + speed = map(speed, 0, 1, this.#state.deadband[1] + 1, this.#state.degreeRange[1]); return this.to(speed); } From 6abebe092c0aace67d317f610441e6a5684f0af5 Mon Sep 17 00:00:00 2001 From: Donovan Buck Date: Sun, 5 Jul 2020 15:48:01 -0500 Subject: [PATCH 7/7] Version bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 98c88d3..0e6478e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "j5e", - "version": "0.4.3", + "version": "0.4.4", "description": "j5e is a device framework built for ECMA TC-53's IO pattern", "main": "index.js", "exports": {