First set of 'motors' topics (#305)

* Start of 'motors' topics

* Draft the 'motor motion' side doc

* Add / update more topics

* Last blast of edits

* Capture some more edits

* Put in movement and steering details
This commit is contained in:
Galen Nickel 2018-02-06 19:43:50 -08:00 committed by Peli de Halleux
parent e2eb5f35af
commit 88c58b4e76
17 changed files with 635 additions and 0 deletions

View File

@ -54,3 +54,17 @@
* [pause until](/reference/brick/button/pause-until)
* [set light](/reference/brick/set-light)
* [battery level](/reference/brick/battery-level)
* [Motors](/reference/motors)
* [set speed](/reference/motors/motor/set-speed)
* [stop](/reference/motors/motor/stop)
* [reset](/reference/motors/motor/reset)
* [set brake](/reference/motors/motor/set-brake)
* [set reversed](/reference/motors/motor/set-reversed)
* [set regulated](/reference/motors/motor/set-regulated)
* [tank](/reference/motors/synced/tank)
* [steer](/reference/motors/synced/steer)
* [tacho](/reference/motors/motor/tacho)
* [angle](/reference/motors/motor/angle)
* [speed](/reference/motors/motor/speed)
* [clear counts](/reference/motors/motor/clear-counts)
* [stop all motors](/reference/motors/stop-all-motors)

View File

@ -2,10 +2,12 @@
```namespaces
brick.showMood(moods.sleeping);
motors.stopAllMotors()
```
## See Also
[brick](/reference/brick),
[motors](/reference/motors),
[touch sensor](/reference/sensors/touch-sensor),
[color sensor](/reference/sensors/color-sensor)

24
docs/reference/motors.md Normal file
View File

@ -0,0 +1,24 @@
# Motors
## Motion
```cards
motors.largeA.setSpeed(50)
motors.largeAB.tank(50, 50)
motors.largeAB.steer(0, 50)
motors.largeA.pauseUntilReady()
motors.largeA.setBrake(false)
motors.largeA.setReversed(false)
motors.largeA.setRegulated(false)
motors.largeA.stop()
motors.largeA.reset()
motors.stopAllMotors()
```
## Counters
```cards
motors.largeA.speed()
motors.largeA.angle()
motors.largeA.tacho()
motors.largeA.clearCounts()
```

View File

@ -0,0 +1,31 @@
# angle
Get the current angle of the motor's rotation in degrees.
```sig
motors.largeA.angle()
```
When a motor is started for the first time, or after a reset, it's angle of rotation starts at `0` degrees. A complete rotation (a turn in a full circle) is `360` degrees. At `360` degrees, the motor angle gets set back to `0`. So, one and a half turns adds up to `540` degrees of total rotation but the motor only cares about the current angle from `0` degrees which is `180` degrees.
## Returns
* a [number](/types/number) which is the current angle of rotation for the motor. The value returned is the number of degrees from `0` to `359`.
## Example
Reset the motor connected to port **A** and run it for for 2 seconds at a speed of `45`. Stop and get the current angle of rotation.
```blocks
let motorAngle = 0;
motors.largeA.reset()
motors.largeA.setSpeed(45)
loops.pause(2000)
motors.largeA.stop()
motorAngle = motors.largeA.angle()
```
## See also
[tacho](/reference/motors/motor/tacho), [speed](/reference/motors/motor/speed),
[reset](/reference/motors/motor/reset), [clear counts](/reference/motors/motor/clear-counts)

View File

@ -0,0 +1,35 @@
# clear Counts
Set all counters for the motor back to zero.
```sig
motors.largeA.clearCounts()
```
The counters for a motor are: **tacho**, **angle**, and **speed**. Each of these counters is set to start counting from `0` again. This is a way to begin new counts without having to reset the motor.
## Example
See if the motor turns the same number of times for each of two count periods. Run the motor connected to port **A** twice for 10 seconds and compare the tacho counts.
```blocks
let tachoCount = 0;
motors.largeA.reset()
motors.largeA.setSpeed(50)
loops.pause(10000)
tachoCount = motors.largeA.tacho()
motors.largeA.clearCounts()
motors.largeA.setSpeed(50)
loops.pause(10000)
if (tachoCount == motors.largeA.tacho()) {
brick.showString("Motor turns equal.", 1)
} else {
brick.showString("Motor turns NOT equal.", 1)
}
motors.largeA.stop()
```
## See also
[tacho](/reference/motors/motor/tacho), [angle](/reference/motors/motor/angle),
[speed](/reference/motors/motor/speed), [reset](/reference/motors/motor/reset)

View File

@ -0,0 +1,30 @@
# reset
Reset the motor's speed setting and it's counters.
```sig
motors.largeA.reset()
```
The motor's speed is set back to `0` and the **tacho**, **angle**, and **speed** counters are set to `0`.
## Example
See what the angle count is when a motor is stopped. Then, try it again after a reset.
```blocks
motors.largeA.setSpeed(30)
loops.pause(2000)
motors.largeA.stop()
brick.showString("Angle count:", 1)
brick.showNumber(motors.largeA.angle(), 2)
motors.largeA.setSpeed(30)
loops.pause(2000)
motors.largeA.reset()
brick.showString("Angle count:", 4)
brick.showNumber(motors.largeA.angle(), 5)
```
## See also
[stop](/reference/motors/motor/stop), [clear counts](/reference/motors/motor/clear-counts)

View File

@ -0,0 +1,30 @@
# set Brake
Set the brake on the motor so it won't turn when it has no power.
```sig
motors.largeA.setBrake(false)
```
When a the motor is stopped, it can still rotate if an external force is applied to it. This can happen, for example, if your're tanking your brick on a inclined surface and stop the motors. Gravity will push down on the brick and might cause it to start rolling again. You can prevent this movement by setting the brake.
Also, you can use the brake to do simple skid steering for your brick.
## Paramters
* **brake**: a [boolean](/types/boolean) value which is either `true` to set the brake on or `false` to set the brake off.
## Example
Run the motor connected to port **A** for 2 seconds at a speed of `30`. Stop and set the brake.
```blocks
motors.largeA.setSpeed(30)
loops.pause(2000)
motors.largeA.stop()
motors.largeA.setBrake(true)
```
## See also
[stop](/reference/motors/motor/stop)

View File

@ -0,0 +1,32 @@
# set Regulated
Tell a motor to regulate its speed or not.
```sig
motors.largeA.setRegulated(true)
```
In order for a motor to always rotate at a constant speed it needs regulation. This means that the motor control electronics need to continously measure how much rotation has happened. The controller takes several rotation counts for a small amount of time and compares them to see if the speed is changing. The output power is adjusted if the controller detects that the motor is running too slow or too fast.
If it's not regulated, your motor can change from the speed that you've set for it. Some examples are if your brick is driving forward and bumps into an object or it drives up a slope creating more load on the motor. In theses situations, if your motor speed is regulated, the controller will boost the power to the motor to keep it's speed from slowing down. Another example is when you run the motors to drive your brick down a slope. In this case, the motors would go faster than the speed you set for them if not regulated. To regulate this the controller reduces the power output to the motors to keep the brick from going faster.
Motor regulation is always set to **ON** when your program first starts or the motor is reset.
## Paramters
* **value**: a [boolean](/types/boolean) value which means that the motor speed is regulated if `true`. The motor speed is not regulated when this is `false`.
## Example
Turn off the speed regulation for the motor connected to port **A**.
```blocks
motors.largeA.setRegulated(false)
motors.largeA.setSpeed(75)
loops.pause(20000)
motors.largeA.stop()
```
## See also
[set speed](/reference/motors/motor/set-speed), [stop](/reference/motors/motor/stop)

View File

@ -0,0 +1,32 @@
# set Reversed
Change the direction of rotation for a motor.
```sig
motors.largeA.setReversed(true)
```
You use a positive value (some number greater than `0`) to drive you motor in the default direction. If you're using a motor in a way that makes more sense for your program to use a negative speed setting for that direction, you can reverse the speed range.
## Paramters
* **reversed**: a [boolean](/types/boolean) value that is `false` if the motor will use a speed value between `0` and `100` to turn in the default direction. If `true`, the motor uses a speed value between `0` and `-100` to turn in the default direction.
## Example
Run the motor connected to port **A** for 2 seconds at a speed of `30`. Stop and switch the direciton of rotation. Run the motor at a speed of `-30`. Watch and see if the motor turns in the same direction as before.
```blocks
motors.largeA.setSpeed(30)
loops.pause(2000)
motors.largeA.stop()
loops.pause(2000)
motors.largeA.setReversed(true)
motors.largeA.setSpeed(-30)
loops.pause(2000)
motors.largeA.stop()
```
## See also
[stop](/reference/motors/motor/stop)

View File

@ -0,0 +1,96 @@
# set Speed
Set the rotation speed of the motor as a percentage of maximum speed.
```sig
motors.largeA.setSpeed(50)
```
The speed setting is a pecentage of the motor's full speed. Full speed is the speed that the motor runs when the brick supplies maximum output voltage to the port.
If you use just the **speed** number, the motor runs continously and won't stop unless you tell it to. You can also give a value for a certain amount of distance you want the motor to rotate for. The **value** can be an amount of time, a turn angle in degrees, or a number of full rotations.
If you decide to use a **value** of rotation distance, you need to choose a type of movement **unit**.
## ~hint
If you use a number of milliseconds as movement units, then you don't need to include the unit type.
To run the motor for 500 milliseconds:
```block
motors.largeA.setSpeed(50, 500)
```
## ~
Here is how you use each different movement unit to run the motor for a fixed rotation distance.
```typescript
// Run motor for 700 Milliseconds.
motors.largeA.setSpeed(25, 700, MoveUnit.MilliSeconds);
// Run motor for 700 Milliseconds again but no units specified.
motors.largeA.setSpeed(25, 700);
// Run the motor for 45 seconds
motors.largeA.setSpeed(50, 45, MoveUnit.Seconds);
// Turn the motor for 270 degrees
motors.largeA.setSpeed(50, 270, MoveUnit.Degrees)
// Turn the motor at full speed for 9 full rotations
motors.largeA.setSpeed(100, 9, MoveUnit.Rotations);
```
## Parameters
* **speed**: a [number](/types/number) that is the percentage of full speed. A negative value runs the motor in the reverse direction.
* **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.
## ~hint
** Reverse is negative speed**
Turning the motor in the opposite direction (reverse) is simple. Reverse is just a negative speed setting. To drive the motor in reverse at 25% speed:
```block
motors.largeB.setSpeed(-25)
```
## ~
## Examples
### Drive the motor for 20 seconds
Run the motor connected to port **A** continuously. Pause 20 seconds and then stop the motor.
```blocks
motors.largeA.setSpeed(75)
loops.pause(20000)
motors.largeA.stop()
```
### Backwards motion
Run the motor connected to port **A** in reverse. Pause 5 seconds and then stop the motor.
```blocks
motors.largeA.setSpeed(-60)
loops.pause(5000)
motors.largeA.stop()
```
### Run the motor for 35 rotations
Run the motor connected to port **B** for 35 full rotations and then stop.
```blocks
motors.largeB.setSpeed(50, 35, MoveUnit.Rotations)
```
## See also
[tank](/reference/motors/synced/tank), [steer](/reference/motors/synced/steer), [stop](/reference/motors/motor/stop)

View File

@ -0,0 +1,33 @@
# speed
Get the current speed of motor rotation as a percentage of maximum speed.
```sig
motors.largeA.speed()
```
The actual speed of the motor is the same or very close to it's current speed setting when the motor is regulated. If not regulated, the actual speed can change from the set speed when a force, or load, is applied to it.
## Returns
* a [number](/types/number) which is the motor's current speed. This value is a percentage of maximum speed from `0` to `100`. This number is negative, like `-27`, if the direction of rotation is in reverse.
## Example
Turn speed regulation off and report the actual speed of the large motor in the forward direction. Occasionally touch the wheel on the motor to see if it changes the speed.
```blocks
motors.largeA.setRegulated(false)
motors.largeA.setSpeed(55)
brick.showString("Actual speed:", 1)
for (let i = 0; i < 30; i++) {
loops.pause(500)
brick.showNumber(motors.largeA.speed(), 3)
}
motors.largeA.stop()
```
## See also
[tacho](/reference/motors/motor/tacho), [speed](/reference/motors/motor/speed),
[reset](/reference/motors/motor/reset), [clear counts](/reference/motors/motor/clear-counts)

View File

@ -0,0 +1,25 @@
# stop
Stop the motor.
```sig
motors.largeA.stop()
```
The motor stops but any motion caused from previously running the motor continues until it runs down. If you are driving your brick and then stop the motors, it will coast for awhile before stopping. If you want the brick to stop right away, use ``||motors:set brake||`` to stop it.
## Example
Run the motor connected to port **A** for 2 seconds at a speed of `30`. Stop and wait for 2 seconds, then continue at a speed of `50`.
```blocks
motors.largeA.setSpeed(30)
loops.pause(2000)
motors.largeA.stop()
loops.pause(2000)
motors.largeA.setSpeed(50)
```
## See also
[set brake](/reference/motors/motor/set-brake), [reset](/reference/motors/motor/reset),

View File

@ -0,0 +1,48 @@
# tacho
Get the current number of degress of rotation.
```sig
motors.largeA.tacho()
```
The motors that come with your @boardname@ have a way to detect their own turning motion. They count the amount of motor rotation in degrees. The motor will count each degree of angle rotation up to 360 degrees for a full rotation. As the motor continues to turn, the _tacho_ count keeps adding up the degrees even past one full rotation. So, if the motor makes 3 complete rotations, the count will be 1080.
The name _tacho_ comes from the first part of the word [tachometer](https://en.wikipedia.org/wiki/Tachometer) which is a device to measure how fast something is turning. The motor controller in the brick uses the tacho count to regulate the motor's speed.
## ~hint
**Measure RPM**
A standard way to know how fast a motor is turning is by measuring its _revolutions per minute_ (rpm). One revolution is the same thing as a rotation, or one turn. How do you measure rpm? Well, here's a simple way:
1. Record the current tacho count
2. Run the motor for 60 seconds
3. Get the tacho count again
4. Subtract the first tacho count from the second one
5. Divide that number by `360`
## ~
## Returns
* a [number](/types/number) which is the total count of degrees of rotation that the motor has turned since it was first started or reset.
## Example
Run the motor connected to port **A** at half speed for 5 seconds. Display the number of full rotations on the screen.
```blocks
motors.largeA.setSpeed(50)
loops.pause(5000)
motors.largeA.stop()
brick.showString("Motor rotations:", 1)
brick.showNumber(motors.largeA.tacho() / 360, 3)
motors.largeA.setSpeed(50)
```
## See also
[angle](/reference/motors/motor/tacho), [speed](/reference/motors/motor/speed),
[set regulated](/reference/motors/motor/set-regulated),
[reset](/reference/motors/motor/reset), [clear counts](/reference/motors/motor/clear-counts)

View File

@ -0,0 +1,25 @@
# stop All Motors
Stops all motors currently running on the brick.
```sig
motors.stopAllMotors();
```
The motors stops but any motion caused from previously running the motors continues until it runs down. If you are driving your brick and then stop the motors, it will coast for awhile before stopping.
## Example
Tank the @boardname@ forward at half speed for 5 seconds and then stop.
```blocks
motors.largeAB.tank(50, 50);
loops.pause(5000);
motors.stopAllMotors();
```
## See also
[stop](/reference/motors/motor/stop),
[reset](/reference/motors/motor/reset),
[set brake](/reference/motors/motor/set-brake)

View File

@ -0,0 +1,84 @@
# steer
Steer the brick in one direction using a turn ratio between two motors.
```sig
motors.largeAB.steer(0, 0)
```
A brick driving with two motors can steer itself by changing the speed of one motor compared to the speed of the other. To make a slow turn to the left, you might make the right motor run slightly faster than the left one. To make a fast, or sharp, turn to the right, the left motor could run at least twice as fast as the right one.
The @boardname@ steers by using a percentage value of _follow_ for one of the motors. This means that the motor in the turn direction will rotate slower than the other. It is the _follower_ motor and the other motor is the _drive_ motor. The drive motor runs at a percentage of full speed set in **speed**. The follower motor runs at a percentage of speed of the drive motor. So, it runs at a percentage of a percentage of full speed.
To make the turn happen you give a _turn ratio_ which is a percentage value of steer to the left or right. If you want to steer to the left at 30% of the of the drive motor speed, use the value of `-30` for **turnRatio**. Left turns use negative values and right turns use positive values. A really sharp turn to the right might use a turn ratio value of `80`.
## Speed and distance
The speed setting is a pecentage of the motor's full speed. Full speed is the speed that the motors run when the brick supplies maximum output voltage to the port.
If you use just the **speed** number, the motors run continously and won't stop unless you tell them to. You can also give a value for a certain amount of distance you want the motors to rotate for. The **value** can be an amount of time, a turn angle in degrees, or a number of full rotations.
If you decide to use a **value** of rotation distance, you need to choose a type of movement **unit**. Also, if you use a number of milliseconds as movement units, then you don't need to include the unit type. The description in [set speed](/reference/motors/motor/set-speed) shows how to use different movement units.
## 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`.
* **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.
## ~hint
** Reverse is negative speed**
Steering the brick backwards (in reverse) is simple. Reverse is just a negative speed setting. To steer the brick to the left in reverse at 75% speed:
```block
motors.largeBC.steer(-15, -75)
```
## ~
## Examples
### Make a slight right
Turn to the right with a turn ratio of 10%.
```block
motors.largeBC.steer(10, 55)
```
### Make a sharp left
Turn sharply to the left.
```block
motors.largeBC.steer(-80, 40)
```
### Steer straight
Use **steer** but go straight ahead.
```block
motors.largeBC.steer(0, 100)
```
### Sneaky snake
Steer the brick in a snake pattern for a short time.
```block
for (let i = 0; i < 4; i++) {
motors.largeBC.steer(30, 30)
loops.pause(5000)
motors.largeBC.steer(-30, 30)
loops.pause(5000)
}
motors.stopAllMotors()
```
## See also
[tank](/reference/motors/synced/tank), [set speed](/reference/motors/motor/set-speed)

View File

@ -0,0 +1,81 @@
# tank
Rotate two motors in synchronization.
```sig
motors.largeAB.tank(50, 50)
```
Tanking the brick will drive two motors in synchronization. This means that both motors will start at the same time. Also, each motor uses the same amount of rotation when running at the same speed. You can use different speed values for each motor to perform turns or spins.
## Speed and distance
The speed setting is a pecentage of the motor's full speed. Full speed is the speed that the motors run when the brick supplies maximum output voltage to the port.
If you use just the **speed** number, the motors run continously and won't stop unless you tell them to. You can also give a value for a certain amount of distance you want the motors to rotate for. The **value** can be an amount of time, a turn angle in degrees, or a number of full rotations.
If you decide to use a **value** of rotation distance, you need to choose a type of movement **unit**. Also, if you use a number of milliseconds as movement units, then you don't need to include the unit type. The description in [set speed](/reference/motors/motor/set-speed) shows how to use different movement units.
## Parameters
* **speedLeft**: a [number](/types/number) that is the percentage of full speed for the motor attached to the left of the brick. A negative value runs the motor in the reverse direction.
* **speedRight**: a [number](/types/number) that is the percentage of full speed for the motor attached to the right of the brick. A negative value runs the motor in the reverse direction.
* **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.
## ~hint
** Reverse is negative speed**
Tankng the brick in the opposite direction (reverse) is simple. Reverse is just a negative speed setting. To drive the motors in reverse at 75% speed:
```block
motors.largeBC.tank(-75, -75)
```
## ~
## Examples
### Tank forward and backward
Move the brick straight ahead and then go backward.
```blocks
motors.largeAB.tank(75, 75)
loops.pause(10000)
motors.largeAB.tank(-55, -55)
loops.pause(10000)
motors.stopAllMotors()
```
### Slip steer
Run the right motor at 50% and let the left motor spin freely.
```blocks
motors.largeAB.tank(0, 50)
```
### Skid steer
Set the brake on the right motor. Run the left motor at 60% and let the right motor skid.
```blocks
motors.largeB.setBrake(true)
motors.largeAB.tank(60, 0)
```
### Spin around
Run both motors in opposite directions to spin the brick around to the left.
```blocks
motors.largeAB.tank(-30, 30)
loops.pause(5000)
motors.stopAllMotors()
```
## See also
[steer](/reference/motors/synced/steer), [set speed](/reference/motors/motor/set-speed)

View File

@ -113,6 +113,7 @@ namespace motors {
//% blockId=motorStopAll block="stop all motors"
//% weight=1
//% group="Move"
//% help=motors/stop-all-motors
export function stopAllMotors() {
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
writePWM(b)
@ -164,6 +165,7 @@ namespace motors {
//% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake=toggleOnOff"
//% weight=60 blockGap=8
//% group="Move"
//% help=motors/motor/set-brake
setBrake(brake: boolean) {
this.init();
this._brake = brake;
@ -175,6 +177,7 @@ namespace motors {
//% blockId=motorSetReversed block="set %motor|reversed %reversed=toggleOnOff"
//% weight=59 blockGap=8
//% group="Move"
//% help=motors/motor/set-reversed
setReversed(reversed: boolean) {
this.init();
const b = mkCmd(this._port, DAL.opOutputPolarity, 1)
@ -187,6 +190,7 @@ namespace motors {
*/
//% weight=6 blockGap=8
//% group="Move"
//% help=motors/motor/stop
//% blockId=motorStop block="stop %motors|"
stop() {
this.init();
@ -206,6 +210,7 @@ namespace motors {
*/
//% weight=5
//% group="Move"
//% help=motors/motor/reset
//% blockId=motorReset block="reset %motors|"
reset() {
this.init();
@ -221,6 +226,7 @@ namespace motors {
//% blockId=motorSetSpeed block="set %motor|speed to %speed=motorSpeedPicker|%"
//% weight=100 blockGap=8
//% group="Move"
//% help=motors/motor/set-speed
setSpeed(speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
this.init();
speed = Math.clamp(-100, 100, speed >> 0);
@ -338,6 +344,7 @@ namespace motors {
//% blockId=outputMotorSetRegulated block="set %motor|regulated %value=toggleOnOff"
//% weight=58
//% group="Move"
//% help=motors/motor/set-regulated
setRegulated(value: boolean) {
this._regulated = value;
}
@ -350,6 +357,7 @@ namespace motors {
//% weight=72
//% blockGap=8
//% group="Counters"
//% help=motors/motor/speed
speed(): number {
this.init();
return getMotorData(this._port).actualSpeed;
@ -363,6 +371,7 @@ namespace motors {
//% weight=70
//% blockGap=8
//% group="Counters"
//% help=motors/motor/angle
angle(): number {
this.init();
return getMotorData(this._port).count;
@ -377,6 +386,7 @@ namespace motors {
//% weight=69
//% blockGap=8
//% group="Counters"
//% help=motors/motor/tacho
tacho(): number {
this.init();
return getMotorData(this._port).tachoCount;
@ -389,6 +399,7 @@ namespace motors {
//% weight=68
//% blockGap=8
//% group="Counters"
//% help=motors/motor/clear-counts
clearCounts() {
this.init();
const b = mkCmd(this._port, DAL.opOutputClearCount, 0)
@ -488,6 +499,7 @@ namespace motors {
//% weight=96 blockGap=8
//% inlineInputMode=inline
//% group="Move"
//% help=motors/synced/tank
tank(speedLeft: number, speedRight: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
this.init();
@ -514,6 +526,7 @@ namespace motors {
//% turnRatio.min=-200 turnRatio=200
//% inlineInputMode=inline
//% group="Move"
//% help=motors/synced/steer
steer(turnRatio: number, speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
this.init();
speed = Math.clamp(-100, 100, speed >> 0);