diff --git a/docs/labview.md b/docs/labview.md index 34eb20d6..59a986d1 100644 --- a/docs/labview.md +++ b/docs/labview.md @@ -61,6 +61,12 @@ motors.largeBC.steer(0, 50, 1, MoveUnit.Rotations); motors.largeBC.stop(); ``` +### ~ hint + +The **turn ratio range is -200, 200** unlike LabView who used -100,100. + +### ~ + ## Tank The **tank** blocks control the speed of two motors. These are commonly used for a differential drive robot. The blocks can also specify the duration, angle, or number of rotations. diff --git a/docs/reference/motors/synced/steer.md b/docs/reference/motors/synced/steer.md index ab3319b8..37649a76 100644 --- a/docs/reference/motors/synced/steer.md +++ b/docs/reference/motors/synced/steer.md @@ -22,7 +22,7 @@ If you decide to use a **value** of rotation distance, you need to choose a type ## Parameters -* **turnRatio**: a [number](/types/number) that is the percentage of speed of the drive motor. The follower motor runs at this speed. A negative number steers to the left and a positive number steers to the right. This is a number between `-100` and `100`. +* **turnRatio**: a [number](/types/number) that is the percentage of speed of the drive motor. The follower motor runs at this speed. A negative number steers to the left and a positive number steers to the right. This is a number between `-200` and `200`. * **speed**: a [number](/types/number) that is the percentage of full speed. A negative value runs the motors in the reverse direction. This is the speed that the drive motor runs at. * **value**: the [number](/types/number) of movement units to rotate for. A value of `0` means run the motor continuously. * **unit**: the movement unit of rotation. This can be `milliseconds`, `seconds`, `degrees`, or `rotations`. If the number for **value** is `0`, this parameter isn't used. diff --git a/editor/deploy.ts b/editor/deploy.ts index ba15a19f..38cdb72a 100644 --- a/editor/deploy.ts +++ b/editor/deploy.ts @@ -64,7 +64,6 @@ class WebSerialPackageIO implements pxt.HF2.PacketIO { private _writer: any; constructor(private port: SerialPort, private options: SerialOptions) { - this.openAsync(); } async readSerialAsync() { @@ -173,7 +172,7 @@ export function initAsync(): Promise { } if (WebSerialPackageIO.isSupported()) - pxt.tickEvent("bluetooth.supported"); + pxt.tickEvent("webserial.supported"); return Promise.resolve(); } @@ -274,7 +273,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult) { if (!useHID) return saveUF2Async() - pxt.tickEvent("bluetooth.flash"); + pxt.tickEvent("webserial.flash"); let w: Ev3Wrapper; return initHidAsync() .then(w_ => { @@ -291,12 +290,14 @@ export function deployCoreAsync(resp: pxtc.CompileResult) { ``, hasCloseIcon: true, hideCancel: true, hideAgree: false, agreeLbl: lf("Try again"), }).then(() => w.disconnectAsync()) + .then(() => Promise.delay(1000)) .then(() => w.reconnectAsync()); // nothing we can do @@ -309,11 +310,11 @@ export function deployCoreAsync(resp: pxtc.CompileResult) { .then(() => w.flashAsync(rbfPath, rbfBIN)) .then(() => w.runAsync(rbfPath)) .then(() => { - pxt.tickEvent("bluetooth.success"); + pxt.tickEvent("webserial.success"); return w.disconnectAsync() //return Promise.delay(1000).then(() => w.dmesgAsync()) }).catch(e => { - pxt.tickEvent("bluetooth.fail"); + pxt.tickEvent("webserial.fail"); useHID = false; useWebSerial = false; // if we failed to initalize, tell the user to retry diff --git a/editor/extension.ts b/editor/extension.ts index 1f64d6d1..67817159 100644 --- a/editor/extension.ts +++ b/editor/extension.ts @@ -7,6 +7,13 @@ let bluetoothDialogShown = false; pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise { const projectView = opts.projectView; pxt.debug('loading pxt-ev3 target extensions...') + + function enableWebSerialAndCompileAsync() { + return enableWebSerialAsync() + .then(() => Promise.delay(500)) + .then(() => projectView.compile()); + } + const res: pxt.editor.ExtensionResult = { deployCoreAsync, showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise) => { @@ -84,7 +91,7 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P onclick: () => { pxt.tickEvent("bluetooth.enable"); if (bluetoothDialogShown) { - enableWebSerialAsync().done(); + enableWebSerialAndCompileAsync().done(); } else { bluetoothDialogShown = true; confirmAsync({ @@ -99,13 +106,13 @@ pxt.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): P }], htmlBody: `

${lf("You will be prompted to select a serial port.")} -${pxt.BrowserUtils.isWindows() ? lf("Look for 'Standard Serial over Bluetooth link'.") : lf("Loop for 'tty.EV3-SerialPort' or 'cu.EV3-SerialPort'")} +${pxt.BrowserUtils.isWindows() + ? lf("Look for 'Standard Serial over Bluetooth link'.") + : lf("Loop for 'cu.EV3-SerialPort'.")} ${lf("If you have paired multiple EV3, you might have to try out multiple ports until you find the correct one.")}

` - }).then(() => enableWebSerialAsync()) - .then(() => Promise.delay(500)) - .then(() => projectView.compile()) + }).then(() => enableWebSerialAndCompileAsync()) } } } : undefined, downloadAgain ? { diff --git a/editor/wrap.ts b/editor/wrap.ts index 76fafb8c..25df52ef 100644 --- a/editor/wrap.ts +++ b/editor/wrap.ts @@ -1,8 +1,12 @@ +/** + * See https://www.lego.com/cdn/cs/set/assets/blt6879b00ae6951482/LEGO_MINDSTORMS_EV3_Communication_Developer_Kit.pdf + * https://github.com/mindboards/ev3sources/blob/master/lms2012/lms2012/source/bytecodes.h#L146 + */ import HF2 = pxt.HF2 import U = pxt.U function log(msg: string) { - pxt.debug("EWRAP: " + msg) + pxt.log("serial: " + msg) } export interface DirEntry { @@ -19,7 +23,7 @@ export class Ev3Wrapper { private cmdSeq = U.randomUint32() & 0xffff; private lock = new U.PromiseQueue(); isStreaming = false; - dataDump = false; + dataDump = /talkdbg=1/.test(window.location.href); constructor(public io: pxt.HF2.PacketIO) { io.onData = buf => { diff --git a/fieldeditors/field_turnratio.ts b/fieldeditors/field_turnratio.ts index 5273c590..3ecfe284 100644 --- a/fieldeditors/field_turnratio.ts +++ b/fieldeditors/field_turnratio.ts @@ -23,7 +23,7 @@ export class FieldTurnRatio extends Blockly.FieldSlider implements Blockly.Field * @constructor */ constructor(value_: any, params: FieldTurnRatioOptions, opt_validator?: Function) { - super(String(value_), '-100', '100', null, '10', 'TurnRatio', opt_validator); + super(String(value_), '-200', '200', null, '10', 'TurnRatio', opt_validator); this.params = params; (this as any).sliderColor_ = '#a8aaa8'; } @@ -76,26 +76,26 @@ export class FieldTurnRatio extends Blockly.FieldSlider implements Blockly.Field if (!this.path_) { return; } - let v = goog.math.clamp(parseFloat(this.getText()), -100, 100); + let v = goog.math.clamp(parseFloat(this.getText()), -200, 200); if (isNaN(v)) { v = 0; } - - const x = goog.math.clamp(parseFloat(this.getText()), -100, 100) / 100; - const theta = x * Math.PI / 2; - const cx = FieldTurnRatio.HALF; - const cy = FieldTurnRatio.HALF - 14; - const gamma = Math.PI - 2 * theta; - const r = FieldTurnRatio.RADIUS; - const alpha = 0.2 + Math.abs(x) * 0.5; - const x1 = 0; + const x = v / 100; + const nx = Math.max(-1, Math.min(1, x)); + const theta = Math.max(nx) * Math.PI / 2; + const r = FieldTurnRatio.RADIUS - 6; + let cx = FieldTurnRatio.HALF; + const cy = FieldTurnRatio.HALF - 22; + if (Math.abs(x) > 1) { + cx -= (x - (x > 0 ? 1 : -1)) * r / 2; // move center of circle + } + const alpha = 0.2 + Math.abs(nx) * 0.5; const y1 = r * alpha; const y2 = r * Math.sin(Math.PI / 2 - theta); const x2 = r * Math.cos(Math.PI / 2 - theta); const y3 = y2 - r * alpha * Math.cos(2 * theta); const x3 = x2 - r * alpha * Math.sin(2 * theta); - const d = `M ${cx} ${cy} C ${cx} ${cy - y1} ${cx + x3} ${cy - y3} ${cx + x2} ${cy - y2}`; this.path_.setAttribute('d', d);