From c25b84d51005e47010547350e17ba8c595dc6ca4 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Fri, 12 Apr 2019 16:56:09 -0400 Subject: [PATCH 1/7] Clean up color sensing using IDs --- src/extensions/scratch3_boost/index.js | 166 ++++++++++++------------- 1 file changed, 79 insertions(+), 87 deletions(-) diff --git a/src/extensions/scratch3_boost/index.js b/src/extensions/scratch3_boost/index.js index f1657f8f..d48b889c 100644 --- a/src/extensions/scratch3_boost/index.js +++ b/src/extensions/scratch3_boost/index.js @@ -101,18 +101,30 @@ const BoostPort = { }; /** - * Enum for indexed colors read by the Boost Vision Sensor + * Ids for each color sensed by the Boost Vision Sensor + */ +const COLOR_ID_ANY = 'any'; +const COLOR_ID_NONE = 'none'; +const COLOR_ID_RED = 'red'; +const COLOR_ID_BLUE = 'blue'; +const COLOR_ID_GREEN = 'green'; +const COLOR_ID_YELLOW = 'yellow'; +const COLOR_ID_WHITE = 'white'; +const COLOR_ID_BLACK = 'black'; + +/** + * Object to look up a color ID by color index * @readonly * @enum {number} */ -const BoostColor = { - NONE: 255, - RED: 9, - BLUE: 3, - GREEN: 5, - YELLOW: 7, - WHITE: 10, - BLACK: 0 +const BoostColorIdByIndex = { + 255: COLOR_ID_NONE, + 9: COLOR_ID_RED, + 3: COLOR_ID_BLUE, + 5: COLOR_ID_GREEN, + 7: COLOR_ID_YELLOW, + 10: COLOR_ID_WHITE, + 0: COLOR_ID_BLACK }; /** @@ -481,7 +493,7 @@ class BoostMotor { this.pendingPromiseFunction(); return; } - + degrees = Math.max(0, degrees); const cmd = this._parent.generateOutputCommand( @@ -600,8 +612,8 @@ class Boost { this._sensors = { tiltX: 0, tiltY: 0, - color: BoostColor.NONE, - previousColor: BoostColor.NONE + color: COLOR_ID_NONE, + previousColor: COLOR_ID_NONE }; /** @@ -661,6 +673,13 @@ class Boost { return this._sensors.color; } + /** + * @return {number} - the previous color value received from the vision sensor. + */ + get previousColor () { + return this._sensors.previousColor; + } + /** * Access a particular motor on this peripheral. * @param {int} index - the index of the desired motor. @@ -770,8 +789,8 @@ class Boost { this._sensors = { tiltX: 0, tiltY: 0, - color: BoostColor.NONE, - previousColor: BoostColor.NONE + color: COLOR_ID_NONE, + previousColor: COLOR_ID_NONE }; if (this._ble) { @@ -903,7 +922,7 @@ class Boost { case BoostMessage.HUB_ATTACHED_IO: { // IO Attach/Detach events const event = data[4]; const typeId = data[5]; - + switch (event) { case BoostIOEvent.ATTACHED: this._registerSensorOrMotor(portID, typeId); @@ -918,7 +937,7 @@ class Boost { } case BoostMessage.PORT_VALUE: { const type = this._ports[portID]; - + switch (type) { case BoostIO.TILT: this._sensors.tiltX = data[4]; @@ -929,12 +948,16 @@ class Boost { if (this._colorSamples.length > BoostColorSampleSize) { this._colorSamples.pop(); if (this._colorSamples.every((v, i, arr) => v === arr[0])) { - this._sensors.color = this._colorSamples[0]; + const firstSample = this._colorSamples[0]; + if (BoostColorIdByIndex[firstSample]) { + this._sensors.previousColor = this._sensors.color; + this._sensors.color = BoostColorIdByIndex[firstSample]; + } } else { - this._sensors.color = BoostColor.NONE; + this._sensors.color = COLOR_ID_NONE; } } else { - this._sensors.color = BoostColor.NONE; + this._sensors.color = COLOR_ID_NONE; } break; case BoostIO.MOTOREXT: @@ -1029,7 +1052,7 @@ class Boost { default: mode = BoostMode.UNKNOWN; } - + const cmd = this.generateInputCommand( portID, mode, @@ -1051,7 +1074,7 @@ class Boost { this._sensors.tiltX = this._sensors.tiltY = 0; } if (type === BoostIO.COLOR) { - this._sensors.color = BoostColor.NONE; + this._sensors.color = COLOR_ID_NONE; } this._ports[portID] = 'none'; this._motors[portID] = null; @@ -1096,21 +1119,6 @@ const BoostTiltDirection = { ANY: 'any' }; -/** - * Enum for vision sensor colors. - * @readonly - * @enum {string} - */ -const BoostColorLabel = { - ANY: 'any', - RED: 'red', - BLUE: 'blue', - GREEN: 'green', - YELLOW: 'yellow', - BLACK: 'black', - WHITE: 'white' -}; - /** * Scratch 3.0 blocks to interact with a LEGO Boost peripheral. */ @@ -1296,7 +1304,7 @@ class Scratch3BoostBlocks { COLOR: { type: ArgumentType.STRING, menu: 'COLOR', - defaultValue: BoostColorLabel.ANY + defaultValue: COLOR_ID_ANY } } }, @@ -1545,61 +1553,60 @@ class Scratch3BoostBlocks { { text: formatMessage({ id: 'boost.color.red', - default: BoostColorLabel.RED, - description: BoostColorLabel.RED + default: 'red', + description: 'the color red' }), - value: BoostColorLabel.RED + value: COLOR_ID_RED }, { text: formatMessage({ id: 'boost.color.blue', - default: BoostColorLabel.BLUE, - description: BoostColorLabel.BLUE + default: 'blue', + description: 'the color blue' }), - value: BoostColorLabel.BLUE + value: COLOR_ID_BLUE }, { text: formatMessage({ id: 'boost.color.green', - default: BoostColorLabel.GREEN, - description: BoostColorLabel.GREEN + default: 'green', + description: 'the color green' }), - value: BoostColorLabel.GREEN + value: COLOR_ID_GREEN }, { text: formatMessage({ id: 'boost.color.yellow', - default: BoostColorLabel.YELLOW, - description: BoostColorLabel.YELLOW + default: 'yellow', + description: 'the color yellow' }), - value: BoostColorLabel.YELLOW + value: COLOR_ID_YELLOW }, { text: formatMessage({ id: 'boost.color.white', - default: BoostColorLabel.WHITE, - desription: BoostColorLabel.WHITE + default: 'white', + desription: 'the color white' }), - value: BoostColorLabel.WHITE + value: COLOR_ID_WHITE }, { text: formatMessage({ id: 'boost.color.black', - default: BoostColorLabel.BLACK, - description: BoostColorLabel.BLACK + default: 'black', + description: 'the color black' }), - value: BoostColorLabel.BLACK + value: COLOR_ID_BLACK }, { text: formatMessage({ id: 'boost.color.any', - default: BoostColorLabel.ANY, - description: BoostColorLabel.ANY + default: 'any color', + description: 'any color' }), - value: BoostColorLabel.ANY + value: COLOR_ID_ANY } - ], - OP: ['<', '>'] + ] } }; } @@ -1791,7 +1798,7 @@ class Scratch3BoostBlocks { getMotorPosition (args) { let portID = null; switch (args.MOTOR_REPORTER_ID) { - + case BoostMotorLabel.A: portID = BoostPort.A; break; @@ -1919,44 +1926,29 @@ class Scratch3BoostBlocks { } /** - * Test whether the tilt sensor is currently tilted. + * Test whether the vision sensor is detecting a certain color. * @param {object} args - the block's arguments. - * @property {Color} COLOR - the color to test. - * @return {boolean} - true if the tilt sensor is tilted past a threshold in the specified direction. + * @return {boolean} - true when the color sensor senses the specified color. */ whenColor (args) { - return this._isColor(args); - } - - /** - * @return {number} - the vision sensor's color value. Indexed LEGO brick colors. - */ - getColor () { - // To get a string representation, lookup the key of the BoostColor-enum value - return Object.keys(BoostColor).find(key => BoostColor[key] === this._peripheral.color) - .toLowerCase(); + return this._isColor(args.COLOR); } /** * Test whether the vision sensor is detecting a certain color. - * @param {number} args - the color to test. + * @param {string} colorId - the id of the color to test. * @return {boolean} - true when the color sensor senses the specified color. * @private */ - _isColor (args) { - switch (args.COLOR) { - case BoostColorLabel.ANY: - if (Object.keys(BoostColor).find(key => BoostColor[key]) - .toLowerCase() !== this.getColor()) { - if (this.getColor() === this._peripheral._sensors.previousColor) { - return false; - } - this._peripheral._sensors.previousColor = this.getColor(); - return true; + _isColor (colorId) { + switch (colorId) { + case COLOR_ID_ANY: + if (this._peripheral.color === this._peripheral.previousColor) { + return false; } - break; + return true; default: - return this.getColor() === args.COLOR; + return colorId === this._peripheral.color; } } From d77944beff3c77ef2e60aa0051e36af02dd1025b Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Fri, 12 Apr 2019 17:09:10 -0400 Subject: [PATCH 2/7] Clean up detection of color any --- src/extensions/scratch3_boost/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/extensions/scratch3_boost/index.js b/src/extensions/scratch3_boost/index.js index d48b889c..2631f4e9 100644 --- a/src/extensions/scratch3_boost/index.js +++ b/src/extensions/scratch3_boost/index.js @@ -1943,10 +1943,11 @@ class Scratch3BoostBlocks { _isColor (colorId) { switch (colorId) { case COLOR_ID_ANY: - if (this._peripheral.color === this._peripheral.previousColor) { - return false; + if (this._peripheral.color !== COLOR_ID_NONE && + this._peripheral.color !== this._peripheral.previousColor) { + return true; } - return true; + return false; default: return colorId === this._peripheral.color; } From 0cadf685b263eb222e2b5327ff5635202d5c05d6 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Fri, 12 Apr 2019 17:14:34 -0400 Subject: [PATCH 3/7] Remove color reporter --- src/extensions/scratch3_boost/index.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/extensions/scratch3_boost/index.js b/src/extensions/scratch3_boost/index.js index 2631f4e9..ae3dfbc7 100644 --- a/src/extensions/scratch3_boost/index.js +++ b/src/extensions/scratch3_boost/index.js @@ -1308,15 +1308,6 @@ class Scratch3BoostBlocks { } } }, - { - opcode: 'getColor', - text: formatMessage({ - id: 'boost.getColor', - default: 'color', - description: 'the color returned by the vision sensor' - }), - blockType: BlockType.REPORTER - }, { opcode: 'whenTilted', text: formatMessage({ From bd5bc7947b4aff8dfc70dfe69d67888fe3fd47c7 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Mon, 15 Apr 2019 09:58:44 -0400 Subject: [PATCH 4/7] =?UTF-8?q?rename=20hat=20to=20=E2=80=9Cwhen=20color?= =?UTF-8?q?=20brick=20seen=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/extensions/scratch3_boost/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extensions/scratch3_boost/index.js b/src/extensions/scratch3_boost/index.js index ae3dfbc7..83eb8dbf 100644 --- a/src/extensions/scratch3_boost/index.js +++ b/src/extensions/scratch3_boost/index.js @@ -1296,7 +1296,7 @@ class Scratch3BoostBlocks { opcode: 'whenColor', text: formatMessage({ id: 'boost.whenColor', - default: 'when [COLOR] color seen', + default: 'when [COLOR] brick seen', description: 'check for when color' }), blockType: BlockType.HAT, From 1381d2c4c00aa5a103aafac0974140e13b3e79b6 Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Mon, 15 Apr 2019 09:59:03 -0400 Subject: [PATCH 5/7] =?UTF-8?q?Add=20boolean=20=E2=80=9Cseeing=20color=20b?= =?UTF-8?q?rick=3F=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/extensions/scratch3_boost/index.js | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/extensions/scratch3_boost/index.js b/src/extensions/scratch3_boost/index.js index 83eb8dbf..0ee52ee2 100644 --- a/src/extensions/scratch3_boost/index.js +++ b/src/extensions/scratch3_boost/index.js @@ -1308,6 +1308,22 @@ class Scratch3BoostBlocks { } } }, + { + opcode: 'seeingColor', + text: formatMessage({ + id: 'boost.seeingColor', + default: 'seeing [COLOR] brick?', + description: 'is the color sensor seeing a certain color?' + }), + blockType: BlockType.BOOLEAN, + arguments: { + COLOR: { + type: ArgumentType.STRING, + menu: 'COLOR', + defaultValue: COLOR_ID_ANY + } + } + }, { opcode: 'whenTilted', text: formatMessage({ @@ -1925,6 +1941,20 @@ class Scratch3BoostBlocks { return this._isColor(args.COLOR); } + /** + * Test whether the vision sensor is detecting a certain color. + * @param {object} args - the block's arguments. + * @return {boolean} - true when the color sensor senses the specified color. + */ + seeingColor (args) { + switch (args.COLOR) { + case COLOR_ID_ANY: + return this._peripheral.color !== COLOR_ID_NONE; + default: + return args.COLOR === this._peripheral.color; + } + } + /** * Test whether the vision sensor is detecting a certain color. * @param {string} colorId - the id of the color to test. From 07768652f963899159f7539785944dc196eede3d Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Mon, 15 Apr 2019 11:34:02 -0400 Subject: [PATCH 6/7] clean up whencolor is seeingcolor functions --- src/extensions/scratch3_boost/index.js | 41 ++++++++++---------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/src/extensions/scratch3_boost/index.js b/src/extensions/scratch3_boost/index.js index 0ee52ee2..78a3af76 100644 --- a/src/extensions/scratch3_boost/index.js +++ b/src/extensions/scratch3_boost/index.js @@ -1933,45 +1933,36 @@ class Scratch3BoostBlocks { } /** - * Test whether the vision sensor is detecting a certain color. + * Edge-triggering hat function, for when the vision sensor is detecting + * a certain color. * @param {object} args - the block's arguments. * @return {boolean} - true when the color sensor senses the specified color. */ whenColor (args) { - return this._isColor(args.COLOR); + if (args.COLOR === COLOR_ID_ANY) { + // For "any" color, return true if the color is not "none", and + // the color is different from the previous color detected. This + // allows the hat to trigger when the color changes from one color + // to another. + return this._peripheral.color !== COLOR_ID_NONE && + this._peripheral.color !== this._peripheral.previousColor; + } + + return args.COLOR === this._peripheral.color; } /** - * Test whether the vision sensor is detecting a certain color. + * A boolean reporter function, for whether the vision sensor is detecting + * a certain color. * @param {object} args - the block's arguments. * @return {boolean} - true when the color sensor senses the specified color. */ seeingColor (args) { - switch (args.COLOR) { - case COLOR_ID_ANY: + if (args.COLOR === COLOR_ID_ANY) { return this._peripheral.color !== COLOR_ID_NONE; - default: - return args.COLOR === this._peripheral.color; } - } - /** - * Test whether the vision sensor is detecting a certain color. - * @param {string} colorId - the id of the color to test. - * @return {boolean} - true when the color sensor senses the specified color. - * @private - */ - _isColor (colorId) { - switch (colorId) { - case COLOR_ID_ANY: - if (this._peripheral.color !== COLOR_ID_NONE && - this._peripheral.color !== this._peripheral.previousColor) { - return true; - } - return false; - default: - return colorId === this._peripheral.color; - } + return args.COLOR === this._peripheral.color; } /** From 8dc4832100d3ddc9f054949af48fa36ded343fee Mon Sep 17 00:00:00 2001 From: Eric Rosenbaum Date: Tue, 16 Apr 2019 15:24:39 -0400 Subject: [PATCH 7/7] Reorganize color ids and indices --- src/extensions/scratch3_boost/index.js | 97 ++++++++++++++------------ 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/src/extensions/scratch3_boost/index.js b/src/extensions/scratch3_boost/index.js index 78a3af76..dd42e839 100644 --- a/src/extensions/scratch3_boost/index.js +++ b/src/extensions/scratch3_boost/index.js @@ -101,30 +101,34 @@ const BoostPort = { }; /** - * Ids for each color sensed by the Boost Vision Sensor + * Ids for each color sensor value used by the extension. + * @readonly + * @enum {string} */ -const COLOR_ID_ANY = 'any'; -const COLOR_ID_NONE = 'none'; -const COLOR_ID_RED = 'red'; -const COLOR_ID_BLUE = 'blue'; -const COLOR_ID_GREEN = 'green'; -const COLOR_ID_YELLOW = 'yellow'; -const COLOR_ID_WHITE = 'white'; -const COLOR_ID_BLACK = 'black'; +const BoostColor = { + ANY: 'any', + NONE: 'none', + RED: 'red', + BLUE: 'blue', + GREEN: 'green', + YELLOW: 'yellow', + WHITE: 'white', + BLACK: 'black' +}; /** - * Object to look up a color ID by color index + * Enum for indices for each color sensed by the Boost vision sensor. * @readonly * @enum {number} */ -const BoostColorIdByIndex = { - 255: COLOR_ID_NONE, - 9: COLOR_ID_RED, - 3: COLOR_ID_BLUE, - 5: COLOR_ID_GREEN, - 7: COLOR_ID_YELLOW, - 10: COLOR_ID_WHITE, - 0: COLOR_ID_BLACK +const BoostColorIndex = { + [BoostColor.NONE]: 255, + [BoostColor.RED]: 9, + [BoostColor.BLUE]: 3, + [BoostColor.GREEN]: 5, + [BoostColor.YELLOW]: 7, + [BoostColor.WHITE]: 10, + [BoostColor.BLACK]: 0 }; /** @@ -612,8 +616,8 @@ class Boost { this._sensors = { tiltX: 0, tiltY: 0, - color: COLOR_ID_NONE, - previousColor: COLOR_ID_NONE + color: BoostColor.NONE, + previousColor: BoostColor.NONE }; /** @@ -680,6 +684,16 @@ class Boost { return this._sensors.previousColor; } + /** + * Look up the color id for an index received from the vision sensor. + * @param {number} index - the color index to look up. + * @return {BoostColor} the color id for this index. + */ + boostColorForIndex (index) { + const colorForIndex = Object.keys(BoostColorIndex).find(key => BoostColorIndex[key] === index); + return colorForIndex || BoostColor.NONE; + } + /** * Access a particular motor on this peripheral. * @param {int} index - the index of the desired motor. @@ -789,8 +803,8 @@ class Boost { this._sensors = { tiltX: 0, tiltY: 0, - color: COLOR_ID_NONE, - previousColor: COLOR_ID_NONE + color: BoostColor.NONE, + previousColor: BoostColor.NONE }; if (this._ble) { @@ -948,16 +962,13 @@ class Boost { if (this._colorSamples.length > BoostColorSampleSize) { this._colorSamples.pop(); if (this._colorSamples.every((v, i, arr) => v === arr[0])) { - const firstSample = this._colorSamples[0]; - if (BoostColorIdByIndex[firstSample]) { - this._sensors.previousColor = this._sensors.color; - this._sensors.color = BoostColorIdByIndex[firstSample]; - } + this._sensors.previousColor = this._sensors.color; + this._sensors.color = this.boostColorForIndex(this._colorSamples[0]); } else { - this._sensors.color = COLOR_ID_NONE; + this._sensors.color = BoostColor.NONE; } } else { - this._sensors.color = COLOR_ID_NONE; + this._sensors.color = BoostColor.NONE; } break; case BoostIO.MOTOREXT: @@ -1074,7 +1085,7 @@ class Boost { this._sensors.tiltX = this._sensors.tiltY = 0; } if (type === BoostIO.COLOR) { - this._sensors.color = COLOR_ID_NONE; + this._sensors.color = BoostColor.NONE; } this._ports[portID] = 'none'; this._motors[portID] = null; @@ -1304,7 +1315,7 @@ class Scratch3BoostBlocks { COLOR: { type: ArgumentType.STRING, menu: 'COLOR', - defaultValue: COLOR_ID_ANY + defaultValue: BoostColor.ANY } } }, @@ -1320,7 +1331,7 @@ class Scratch3BoostBlocks { COLOR: { type: ArgumentType.STRING, menu: 'COLOR', - defaultValue: COLOR_ID_ANY + defaultValue: BoostColor.ANY } } }, @@ -1563,7 +1574,7 @@ class Scratch3BoostBlocks { default: 'red', description: 'the color red' }), - value: COLOR_ID_RED + value: BoostColor.RED }, { text: formatMessage({ @@ -1571,7 +1582,7 @@ class Scratch3BoostBlocks { default: 'blue', description: 'the color blue' }), - value: COLOR_ID_BLUE + value: BoostColor.BLUE }, { text: formatMessage({ @@ -1579,7 +1590,7 @@ class Scratch3BoostBlocks { default: 'green', description: 'the color green' }), - value: COLOR_ID_GREEN + value: BoostColor.GREEN }, { text: formatMessage({ @@ -1587,7 +1598,7 @@ class Scratch3BoostBlocks { default: 'yellow', description: 'the color yellow' }), - value: COLOR_ID_YELLOW + value: BoostColor.YELLOW }, { text: formatMessage({ @@ -1595,7 +1606,7 @@ class Scratch3BoostBlocks { default: 'white', desription: 'the color white' }), - value: COLOR_ID_WHITE + value: BoostColor.WHITE }, { text: formatMessage({ @@ -1603,7 +1614,7 @@ class Scratch3BoostBlocks { default: 'black', description: 'the color black' }), - value: COLOR_ID_BLACK + value: BoostColor.BLACK }, { text: formatMessage({ @@ -1611,7 +1622,7 @@ class Scratch3BoostBlocks { default: 'any color', description: 'any color' }), - value: COLOR_ID_ANY + value: BoostColor.ANY } ] } @@ -1939,12 +1950,12 @@ class Scratch3BoostBlocks { * @return {boolean} - true when the color sensor senses the specified color. */ whenColor (args) { - if (args.COLOR === COLOR_ID_ANY) { + if (args.COLOR === BoostColor.ANY) { // For "any" color, return true if the color is not "none", and // the color is different from the previous color detected. This // allows the hat to trigger when the color changes from one color // to another. - return this._peripheral.color !== COLOR_ID_NONE && + return this._peripheral.color !== BoostColor.NONE && this._peripheral.color !== this._peripheral.previousColor; } @@ -1958,8 +1969,8 @@ class Scratch3BoostBlocks { * @return {boolean} - true when the color sensor senses the specified color. */ seeingColor (args) { - if (args.COLOR === COLOR_ID_ANY) { - return this._peripheral.color !== COLOR_ID_NONE; + if (args.COLOR === BoostColor.ANY) { + return this._peripheral.color !== BoostColor.NONE; } return args.COLOR === this._peripheral.color;