From f1445c6e891c6b4c3bea74013ea02be4fa92de5f Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Mon, 18 Dec 2017 14:13:38 -0800 Subject: [PATCH] Motor pause until ready (#108) * adding command to pause until ready * adding console API * adding ready support for motors * fix time output scale * fixing angle --- docs/tests/motors.md | 84 ++++++++++++++++++++++ docs/tests/motors.ts | 66 ----------------- libs/base/_locales/base-jsdoc-strings.json | 5 ++ libs/base/_locales/base-strings.json | 4 ++ libs/base/pxt.json | 3 +- libs/core/_locales/core-jsdoc-strings.json | 6 +- libs/core/_locales/core-strings.json | 6 +- libs/core/output.ts | 51 +++++++------ 8 files changed, 132 insertions(+), 93 deletions(-) create mode 100644 docs/tests/motors.md delete mode 100644 docs/tests/motors.ts diff --git a/docs/tests/motors.md b/docs/tests/motors.md new file mode 100644 index 00000000..629cf68b --- /dev/null +++ b/docs/tests/motors.md @@ -0,0 +1,84 @@ +```typescript +let errors: string[] = []; +let tachoB = 0; +let tachoC = 0; + +function assert(name: string, condition: boolean) { + if (!condition) { + errors.push(name) + } +} + +function assertClose(name: string, expected: number, actual: number, tolerance = 5) { + const diff = Math.abs(expected - actual); + assert(name + ` ${expected}vs${actual}`, diff < tolerance); +} + +function state(name: string, motor: motors.SingleMotor, line: number) { + brick.print(`${name}: ${motor.speed()}%,${motor.angle()}deg`, 0, 12 * line) +} + +function test(name: string, f: () => void, check?: () => void) { + motors.stopAllMotors(); + motors.largeB.clearCount() + motors.largeC.clearCount() + motors.largeB.setBrake(false) + motors.largeC.setBrake(false) + loops.pause(500); + tachoB = motors.largeB.angle() + tachoC = motors.largeC.angle() + brick.clearScreen() + brick.print(name, 0, 0) + state("B", motors.largeB, 1) + state("C", motors.largeC, 2) + f(); + loops.pause(3000); + motors.largeB.setReversed(false); + motors.largeC.setReversed(false); + motors.mediumA.setReversed(false); + state("B", motors.largeB, 3) + state("C", motors.largeC, 4) + if (check) + check() + motors.stopAllMotors(); + loops.pause(1000); +} + +brick.buttonEnter.onEvent(ButtonEvent.Click, function () { + test("lgB set speed 10", () => { + motors.largeB.setSpeed(10) + }, () => assertClose("speedB", 10, motors.largeB.speed())); + test("lgB set speed 25 (reversed)", () => { + motors.largeB.setReversed(true) + motors.largeB.setSpeed(25) + }, () => assertClose("speedB", -25, motors.largeB.speed())); + test("lgBC set speed 5", () => { + motors.largeBC.setSpeed(5) + }, () => { + assertClose("speedB", 5, motors.largeB.speed()); + assertClose("speedC", 5, motors.largeC.speed()); + }); + test("lgBC steer 50% 2x", () => { + motors.largeBC.setBrake(true) + motors.largeBC.steer(50, 50, 2, MoveUnit.Rotations) + }, () => assertClose("largeB", 720, motors.largeB.angle())); + test("lgBC steer 50% 500deg", () => { + motors.largeBC.setBrake(true) + motors.largeBC.steer(50, 50, 500, MoveUnit.Degrees) + }, () => assertClose("largeB", 500, motors.largeB.angle())); + test("lgBC steer 50% 2s", () => { + motors.largeBC.setBrake(true) + motors.largeBC.steer(50, 50, 2000, MoveUnit.MilliSeconds) + }) + test("lgBC tank 50% 720deg", () => { + motors.largeBC.setBrake(true) + motors.largeBC.tank(50, 50, 720, MoveUnit.Degrees) + }, () => assertClose("largeB", 720, motors.largeB.angle())); + + brick.clearScreen() + brick.print(`${errors.length} errors`, 0, 0) + let l = 1; + for (const error of errors) + brick.print(`error: ${error}`, 0, l++ * 12) +}) +``` \ No newline at end of file diff --git a/docs/tests/motors.ts b/docs/tests/motors.ts deleted file mode 100644 index cff15a26..00000000 --- a/docs/tests/motors.ts +++ /dev/null @@ -1,66 +0,0 @@ -let errors: string[] = []; -let tachoB = 0; -let tachoC = 0; - -function assert(name: string, condition: boolean) { - if (!condition) { - errors.push(name) - } -} - -function assertClose(name: string, expected: number, actual: number, tolerance = 10) { - assert(name + ` ${expected}/${actual}`, Math.abs(expected - actual) < tolerance); -} - -function test(name: string, f: () => void, check?: () => void) { - motors.stopAllMotors(); - loops.pause(500); - tachoB = motors.largeB.tachoCount() - tachoC = motors.largeB.tachoCount() - brick.clearScreen() - brick.print(name, 0, 0) - f(); - loops.pause(3000); - motors.stopAllMotors(); - motors.largeB.setReversed(false); - motors.largeC.setReversed(false); - motors.mediumA.setReversed(false); - loops.pause(1000); - if (check) - check() -} - -brick.buttonEnter.onEvent(ButtonEvent.Click, function () { - test("lgB set speed 100", () => { - motors.largeB.setSpeed(100) - }); - test("lgB set speed (reversed)", () => { - motors.largeB.setReversed(true) - motors.largeB.setSpeed(100) - }) - test("lgBC set speed 100", () => { - motors.largeBC.setSpeed(100) - }) - test("lgBC steer 50% 2x", () => { - motors.largeBC.steer(50, 50, 2, MoveUnit.Rotations) - }, () => { - assertClose("largeB", 720, motors.largeB.tachoCount() - tachoB) - }); - test("lgBC steer 50% 500deg", () => { - motors.largeBC.steer(50, 50, 500, MoveUnit.Degrees) - }, () => { - assertClose("largeB", 500, motors.largeB.tachoCount() - tachoB) - }); - test("lgBC steer 50% 2s", () => { - motors.largeBC.steer(50, 50, 2, MoveUnit.Seconds) - }) - test("lgBC tank 50% 2s", () => { - motors.largeBC.tank(50, 50, 720, MoveUnit.Degrees) - }) - - brick.clearScreen() - brick.print(`${errors.length} errors`, 0, 0) - let l = 1; - for(const error of errors) - brick.print(`error: ${error}`, 0, l++ * 12) -}) diff --git a/libs/base/_locales/base-jsdoc-strings.json b/libs/base/_locales/base-jsdoc-strings.json index 3d209b44..c9a8d82c 100644 --- a/libs/base/_locales/base-jsdoc-strings.json +++ b/libs/base/_locales/base-jsdoc-strings.json @@ -123,6 +123,11 @@ "String.substr": "Return a substring of the current string.", "String.substr|param|length": "number of characters to extract", "String.substr|param|start": "first character index; can be negative from counting from the end, eg:0", + "console": "Reading and writing data to the console output.", + "console.log": "Write a line of text to the console output.", + "console.logValue": "Write a name:value pair as a line of text to the console output.", + "console.logValue|param|name": "name of the value stream, eg: \"x\"", + "console.logValue|param|value": "to write", "control": "Program controls and events.", "control.AnimationQueue.cancel": "Cancels the current running animation and clears the queue", "control.AnimationQueue.runUntilDone": "Runs 'render' in a loop until it returns false or the 'stop' function is called", diff --git a/libs/base/_locales/base-strings.json b/libs/base/_locales/base-strings.json index 347db075..487727cd 100644 --- a/libs/base/_locales/base-strings.json +++ b/libs/base/_locales/base-strings.json @@ -19,6 +19,9 @@ "String.length|block": "length of %VALUE", "String.substr|block": "substring of %this=text|from %start|of length %length", "String|block": "String", + "console.logValue|block": "console|log value %name|= %value", + "console.log|block": "console|log %text", + "console|block": "console", "control.assert|block": "assert %cond|with value %code", "control.deviceSerialNumber|block": "device serial number", "control.millis|block": "millis (ms)", @@ -43,6 +46,7 @@ "{id:category}Arrays": "Arrays", "{id:category}Boolean": "Boolean", "{id:category}Buffer": "Buffer", + "{id:category}Console": "Console", "{id:category}Control": "Control", "{id:category}Helpers": "Helpers", "{id:category}Loops": "Loops", diff --git a/libs/base/pxt.json b/libs/base/pxt.json index 98322f56..6af58cb4 100644 --- a/libs/base/pxt.json +++ b/libs/base/pxt.json @@ -17,7 +17,8 @@ "control.cpp", "control.ts", "serial.cpp", - "serial.ts" + "serial.ts", + "console.ts" ], "testFiles": [ "test.ts" diff --git a/libs/core/_locales/core-jsdoc-strings.json b/libs/core/_locales/core-jsdoc-strings.json index 65ede23f..8b0bd60b 100644 --- a/libs/core/_locales/core-jsdoc-strings.json +++ b/libs/core/_locales/core-jsdoc-strings.json @@ -51,10 +51,13 @@ "control.raiseEvent": "Announce that an event happened to registered handlers.", "control.raiseEvent|param|src": "ID of the Component that generated the event", "control.raiseEvent|param|value": "Component specific code indicating the cause of the event.", + "motors.Motor.isReady": "Returns a value indicating if the motor is still running a previous command.", "motors.Motor.move": "Moves the motor by a number of rotations, degress or seconds", "motors.Motor.move|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50", "motors.Motor.move|param|unit": "the meaning of the value", "motors.Motor.move|param|value": "the move quantity, eg: 2", + "motors.Motor.pauseUntilReady": "Pauses the execution until the previous command finished.", + "motors.Motor.pauseUntilReady|param|timeOut": "optional maximum pausing time in milliseconds", "motors.Motor.reset": "Resets the motor(s).", "motors.Motor.setBrake": "Sets the automatic brake on or off when the motor is off", "motors.Motor.setBrake|param|brake": "a value indicating if the motor should break when off", @@ -62,10 +65,9 @@ "motors.Motor.setSpeed": "Sets the speed of the motor.", "motors.Motor.setSpeed|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50", "motors.Motor.stop": "Stops the motor(s).", + "motors.SingleMotor.angle": "Gets motor ration angle.", "motors.SingleMotor.clearCount": "Clears the motor count", - "motors.SingleMotor.count": "Gets motor step count.", "motors.SingleMotor.speed": "Gets motor actual speed.", - "motors.SingleMotor.tachoCount": "Gets motor tacho count.", "motors.SynchedMotorPair.steer": "Turns the motor and the follower motor by a number of rotations", "motors.SynchedMotorPair.steer|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50", "motors.SynchedMotorPair.steer|param|steering": "the ratio of power sent to the follower motor, from ``-100`` to ``100``", diff --git a/libs/core/_locales/core-strings.json b/libs/core/_locales/core-strings.json index a456a014..49726aed 100644 --- a/libs/core/_locales/core-strings.json +++ b/libs/core/_locales/core-strings.json @@ -13,8 +13,8 @@ "LightsPattern.RedPulse|block": "Pulsing Red", "LightsPattern.Red|block": "Red", "MoveUnit.Degrees|block": "degrees", + "MoveUnit.MilliSeconds|block": "milliseconds", "MoveUnit.Rotations|block": "rotations", - "MoveUnit.Seconds|block": "seconds", "Output.AB|block": "A+B", "Output.AD|block": "A+D", "Output.ALL|block": "All", @@ -44,12 +44,12 @@ "control.raiseEvent|block": "raise event|from %src|with value %value", "control|block": "control", "motors.Motor.move|block": "move `icons.motorLarge` %motor|for %value|%unit|at %speed|%", + "motors.Motor.pauseUntilReady|block": "%motor|pause until ready", "motors.Motor.setBrake|block": "set `icons.motorLarge` %motor|brake %brake", "motors.Motor.setReversed|block": "set `icons.motorLarge` %motor|reversed %reversed", "motors.Motor.setSpeed|block": "set speed of `icons.motorLarge` %motor|to %speed|%", - "motors.SingleMotor.count|block": "`icons.motorLarge` %motor|count", + "motors.SingleMotor.angle|block": "`icons.motorLarge` %motor|angle", "motors.SingleMotor.speed|block": "`icons.motorLarge` %motor|speed", - "motors.SingleMotor.tachoCount|block": "`icons.motorLarge` %motor|tacho count", "motors.SynchedMotorPair.steer|block": "steer %chassis|%steering|%|at speed %speed|%|by %value|%unit", "motors.SynchedMotorPair.tank|block": "tank %chassis|left %speedLeft|%|right %speedRight|%|by %value|%unit", "motors.largeAB|block": "large A+B", diff --git a/libs/core/output.ts b/libs/core/output.ts index b4e4d1fe..25521c9d 100644 --- a/libs/core/output.ts +++ b/libs/core/output.ts @@ -30,8 +30,8 @@ enum MoveUnit { Rotations, //% block="degrees" Degrees, - //% block="seconds" - Seconds + //% block="milliseconds" + MilliSeconds } namespace motors { @@ -65,9 +65,9 @@ namespace motors { pwmMM.write(buf) } - function readPWM(buf: Buffer): void { + function readPWM(buf: Buffer): number { init() - pwmMM.read(buf); + return pwmMM.read(buf); } function mkCmd(out: Output, cmd: number, addSize: number) { @@ -220,6 +220,27 @@ namespace motors { this._move(useSteps, stepsOrTime, speed); } + + /** + * Returns a value indicating if the motor is still running a previous command. + */ + //% + isReady(): boolean { + this.init(); + const r = readPWM(mkCmd(this._port, DAL.opOutputTest, 0)) + // 0 = ready, 1 = busy + return r == 0; + } + + /** + * Pauses the execution until the previous command finished. + * @param timeOut optional maximum pausing time in milliseconds + */ + //% blockId=motorPauseUntilRead block="%motor|pause until ready" + //% group="Motion" + pauseUntilReady(timeOut: number = -1) { + pauseUntil(() => this.isReady(), timeOut); + } } //% fixedInstances @@ -248,7 +269,7 @@ namespace motors { b.setNumber(NumberFormat.Int8LE, 2, speed) writePWM(b) if (speed) { - writePWM(mkCmd(this._port, DAL.opOutputStart, 0)) + writePWM(mkCmd(this._port, DAL.opOutputStart, 0)) } } @@ -276,27 +297,15 @@ namespace motors { } /** - * Gets motor step count. + * Gets motor ration angle. * @param motor the port which connects to the motor */ - //% blockId=motorCount block="`icons.motorLarge` %motor|count" - //% weight=71 blockGap=8 - //% group="Sensors" - count(): number { - this.init(); - return getMotorData(this._port).count; - } - - /** - * Gets motor tacho count. - * @param motor the port which connects to the motor - */ - //% blockId=motorTachoCount block="`icons.motorLarge` %motor|tacho count" + //% blockId=motorTachoCount block="`icons.motorLarge` %motor|angle" //% weight=70 //% group="Sensors" - tachoCount(): number { + angle(): number { this.init(); - return getMotorData(this._port).tachoCount; + return getMotorData(this._port).count; } /**