Compare commits

...

25 Commits

Author SHA1 Message Date
c274259472 0.0.94 2018-02-07 09:54:24 -08:00
74ca722aac updated IR arts 2018-02-07 09:53:58 -08:00
931ca40f49 updated IR art 2018-02-07 08:13:46 -08:00
458ac847b7 updated assets for LEGO 2018-02-07 07:13:22 -08:00
653d8f6f5c 0.0.93 2018-02-07 01:50:28 -08:00
ac0a9f0710 Various example of LavView vs MakeCode (#309)
* screenshots

* more screenshots

* added pics

* more writup

* more examples
2018-02-07 01:42:46 -08:00
2cce2a39b8 updated colors for motor/math 2018-02-07 01:42:16 -08:00
a337403afa 0.0.92 2018-02-06 23:19:06 -08:00
fd9d118fa4 reversed => Inverted (#308)
* renaming "setReversed" to "setInverted" to match LabView

* fixing samples

* typo
2018-02-06 23:18:36 -08:00
e94ac6f6f1 renaming brick.setLight to brick.setStatusLight (#307)
* renaming brick.setLight to brick.setStatusLight

* updated docs
2018-02-06 22:18:39 -08:00
88c58b4e76 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
2018-02-06 19:43:50 -08:00
e2eb5f35af upgrading to node.js 8 (#306) 2018-02-06 12:50:39 -08:00
71fe612ced 0.0.91 2018-02-05 16:38:50 -08:00
e58ec06e91 IR button indexing fixes (#303)
* IR remote id fixes

* hiding private api

* fixing indexing of buttons
2018-02-05 15:11:11 -08:00
538493369b adding button class on remote buttons 2018-02-05 13:57:24 -08:00
56dd8e0875 enabling doc checks 2018-02-03 09:11:49 -08:00
1f7ef637b2 Fix links in target 2018-02-03 09:09:10 -08:00
f4f2e0ba0e 0.0.90 2018-02-02 14:19:17 -08:00
22c31c57df fix port bug 2018-02-02 14:19:07 -08:00
6879961297 0.0.89 2018-02-02 13:39:18 -08:00
69fcb7407a Simulator support for remote (#302)
* fixing up state

* upgrading ir simulator

* displaying remote

* updated infrared svg
2018-02-02 13:38:54 -08:00
4dfada877c Implement simulator sensor for ambient and reflected light (#301)
* Initial work

* More stuff

* Stuff

* Stuff

* Hardcoded dashed line

* High and low thresholds

* Use rect bBox

* Add back grabbing hand

* Threshold placement

* Cleanup

* Don't need defs

* pxtarget

* Remove dashed lines for now
2018-02-02 13:24:50 -08:00
b10b636766 0.0.88 2018-02-02 09:48:51 -08:00
ba47fb0589 Support for remote control buttons (#300)
* refactor beacon function inside IR sensor

* towards sim support

* channel labels

* reverting to singletons

* hiding unused apis

* lazy allocation of button instances

* tracking button state

* hook up the state
2018-02-02 09:48:27 -08:00
f36e14fe69 renaming remote button names 2018-02-01 22:33:05 -08:00
80 changed files with 8115 additions and 3451 deletions

View File

@ -48,10 +48,23 @@
* [show mood](/reference/brick/show-mood) * [show mood](/reference/brick/show-mood)
* [show image](/reference/brick/show-image) * [show image](/reference/brick/show-image)
* [clear screen](/reference/brick/clear-screen) * [clear screen](/reference/brick/clear-screen)
* [print ports](/reference/brick/print-ports)
* [on event](/reference/brick/button/on-event) * [on event](/reference/brick/button/on-event)
* [is pressed](/reference/brick/button/is-pressed) * [is pressed](/reference/brick/button/is-pressed)
* [was pressed](/reference/brick/button/was-pressed) * [was pressed](/reference/brick/button/was-pressed)
* [pause until](/reference/brick/button/pause-until) * [pause until](/reference/brick/button/pause-until)
* [set light](/reference/brick/set-light) * [set light](/reference/brick/set-status-light)
* [battery level](/reference/brick/battery-level) * [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 inverted](/reference/motors/motor/set-inverted)
* [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

@ -19,7 +19,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, () => {
The editor work in [most modern browsers](/browsers), work [offline](/offline) once loaded and do not require any installation. The editor work in [most modern browsers](/browsers), work [offline](/offline) once loaded and do not require any installation.
## [Compile and Flash: Your Program!](/device/usb) ## Compile and Flash: Your Program!
When you have your code ready, you connect your @boardname@ to a computer via a USB cable When you have your code ready, you connect your @boardname@ to a computer via a USB cable
so it appears as a mounted drive (named **EV3**). so it appears as a mounted drive (named **EV3**).

View File

@ -6,7 +6,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, function () {
sensors.touch1.pauseUntil(ButtonEvent.Pressed) sensors.touch1.pauseUntil(ButtonEvent.Pressed)
motors.largeBC.setSpeed(0) motors.largeBC.setSpeed(0)
loops.pause(1000) loops.pause(1000)
brick.setLight(BrickLight.OrangeFlash) brick.setStatusLight(StatusLight.OrangeFlash)
motors.largeBC.setSpeed(-50) motors.largeBC.setSpeed(-50)
loops.pause(2000) loops.pause(2000)
motors.largeBC.setSpeed(0) motors.largeBC.setSpeed(0)

View File

@ -7,7 +7,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, function () {
sensors.touch2.pauseUntil(ButtonEvent.Pressed) sensors.touch2.pauseUntil(ButtonEvent.Pressed)
motors.largeBC.setSpeed(0) motors.largeBC.setSpeed(0)
loops.pause(1000) loops.pause(1000)
brick.setLight(BrickLight.OrangeFlash) brick.setStatusLight(StatusLight.OrangeFlash)
motors.largeBC.setSpeed(-50) motors.largeBC.setSpeed(-50)
loops.pause(2000) loops.pause(2000)
motors.largeBC.setSpeed(0) motors.largeBC.setSpeed(0)

View File

@ -10,7 +10,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, function () {
brick.showImage(images.eyesTiredMiddle) brick.showImage(images.eyesTiredMiddle)
motors.largeBC.setSpeed(0) motors.largeBC.setSpeed(0)
loops.pause(1000) loops.pause(1000)
brick.setLight(BrickLight.OrangeFlash) brick.setStatusLight(StatusLight.OrangeFlash)
brick.showImage(images.eyesDizzy) brick.showImage(images.eyesDizzy)
motors.largeBC.setSpeed(-50) motors.largeBC.setSpeed(-50)
loops.pause(2000) loops.pause(2000)

View File

@ -146,11 +146,11 @@ loops.forever(function () {
} }
motors.stopAllMotors() motors.stopAllMotors()
st = 0; st = 0;
brick.setLight(BrickLight.RedPulse); brick.setStatusLight(StatusLight.RedPulse);
brick.showImage(images.eyesKnockedOut) brick.showImage(images.eyesKnockedOut)
music.playSoundEffect(sounds.movementsSpeedDown) music.playSoundEffect(sounds.movementsSpeedDown)
sensors.touch3.pauseUntil(ButtonEvent.Pressed) sensors.touch3.pauseUntil(ButtonEvent.Pressed)
brick.setLight(BrickLight.Off); brick.setStatusLight(StatusLight.Off);
}) })
// BHV // BHV

View File

@ -29,7 +29,7 @@ function DN() {
function MNRH() { function MNRH() {
motors.mediumC.setBrake(true) motors.mediumC.setBrake(true)
brick.showImage(images.legoEv3icon) brick.showImage(images.legoEv3icon)
brick.setLight(BrickLight.OrangePulse) brick.setStatusLight(StatusLight.OrangePulse)
while (!brick.buttonEnter.wasPressed()) { while (!brick.buttonEnter.wasPressed()) {
if (brick.buttonUp.wasPressed()) { if (brick.buttonUp.wasPressed()) {
motors.mediumC.setSpeed(-100); motors.mediumC.setSpeed(-100);
@ -41,7 +41,7 @@ function MNRH() {
} }
motors.mediumC.stop(); motors.mediumC.stop();
motors.mediumC.clearCounts(); motors.mediumC.clearCounts();
brick.setLight(BrickLight.Green); brick.setStatusLight(StatusLight.Green);
} }
function IS(t: number) { function IS(t: number) {

View File

@ -20,9 +20,9 @@ INI()
let down = false; let down = false;
loops.forever(function () { loops.forever(function () {
brick.showImage(images.informationQuestionMark) brick.showImage(images.informationQuestionMark)
brick.setLight(BrickLight.OrangePulse); brick.setStatusLight(StatusLight.OrangePulse);
pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed()) pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed())
brick.setLight(BrickLight.Off) brick.setStatusLight(StatusLight.Off)
music.playSoundEffect(sounds.mechanicalAirRelease) music.playSoundEffect(sounds.mechanicalAirRelease)
brick.showImage(images.informationAccept) brick.showImage(images.informationAccept)
if (down) { if (down) {

View File

@ -20,9 +20,9 @@ INI()
let down = false; let down = false;
loops.forever(function () { loops.forever(function () {
brick.showImage(images.informationQuestionMark) brick.showImage(images.informationQuestionMark)
brick.setLight(BrickLight.OrangePulse); brick.setStatusLight(StatusLight.OrangePulse);
pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed()) pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed())
brick.setLight(BrickLight.Off) brick.setStatusLight(StatusLight.Off)
music.playSoundEffect(sounds.mechanicalAirRelease) music.playSoundEffect(sounds.mechanicalAirRelease)
brick.showImage(images.informationAccept) brick.showImage(images.informationAccept)
if (down) { if (down) {

View File

@ -146,11 +146,11 @@ loops.forever(function () {
} }
motors.stopAllMotors() motors.stopAllMotors()
st = 0; st = 0;
brick.setLight(BrickLight.RedPulse); brick.setStatusLight(StatusLight.RedPulse);
brick.showImage(images.eyesKnockedOut) brick.showImage(images.eyesKnockedOut)
music.playSoundEffect(sounds.movementsSpeedDown) music.playSoundEffect(sounds.movementsSpeedDown)
sensors.touch3.pauseUntil(ButtonEvent.Pressed) sensors.touch3.pauseUntil(ButtonEvent.Pressed)
brick.setLight(BrickLight.Off); brick.setStatusLight(StatusLight.Off);
}) })
// BHV // BHV

251
docs/labview.md Normal file
View File

@ -0,0 +1,251 @@
# Coding in MakeCode
This guide is intended for users who are used to the LabView LEGO Minstorms editor.
## Snap the blocks
Just like LabView, blocks can be dragged from the cabinet and snapped together
to create a sequence of program instructions.
The program below **starts**, turns on motor A, waits a second and stop motor A.
![sequence of block](/static/labview/sequencing.png)
The blocks are similar: they snap on the ``||on start||`` block then latch to each other vertically.
```blocks
motors.largeA.setSpeed(50)
loops.pause(1000)
motors.largeA.stop()
```
All block programs can be converted to JavaScript and edited from there as well.
```typescript
motors.largeA.setSpeed(50)
loops.pause(1000)
motors.largeA.stop()
```
## Download to the EV3
The MakeCode editor provides a simulator to try out the code in your browser. It restarts automatically after you make a code change. Once you are ready to transfer it to the @boardname@, click the ``||Download||`` button and follow the instructions.
## Single motors
The program below controls a large motor on port A in a variety of ways: setting the speed,
setting the speed for a given time, angle or number of rotations.
![Single motor blocks](/static/labview/motors.png)
```blocks
motors.largeA.setSpeed(50);
motors.largeA.setSpeed(50, 1000, MoveUnit.MilliSeconds);
motors.largeA.setSpeed(50, 360, MoveUnit.Degrees);
motors.largeA.setSpeed(50, 1, MoveUnit.Rotations);
motors.largeA.stop();
```
## Steering
The **steering** blocks allow to synchronize two motors at a precise rate. They can also specify the duration, angle or number of rotations.
![Steering blocks](/static/labview/steer.png)
```blocks
motors.largeBC.steer(0, 50);
motors.largeBC.steer(0, 50, 1000, MoveUnit.MilliSeconds);
motors.largeBC.steer(0, 50, 360, MoveUnit.Degrees);
motors.largeBC.steer(0, 50, 1, MoveUnit.Rotations);
motors.largeBC.stop();
```
## Tank
The **tank** blocks control the speed of two motors, typically from a differential drive robot. They can also specify the duration, angle or number of rotations.
![Tank block](/static/labview/tank.png)
```blocks
motors.largeBC.tank(50, 50);
motors.largeBC.tank(50, 50, 1000, MoveUnit.MilliSeconds);
motors.largeBC.tank(50, 50, 360, MoveUnit.Degrees);
motors.largeBC.tank(50, 50, 1, MoveUnit.Rotations);
motors.largeBC.stop();
```
## Coasting and braking
By default, all motors coast when the move command is done. You can change this behavior with the `set brake`` block.
![Brake block](/static/labview/brake.png)
```blocks
motors.largeD.setBrake(true);
motors.largeD.setSpeed(50, 1, MoveUnit.Rotations)
```
## Inverting and regulating motors
Sometime you need to invert the direction of a motor. Use the ``set invert`` block.
![Brake block](/static/labview/invertmotor.png)
```blocks
motors.largeA.setInverted(true);
```
By default, the speed of motors is regulated. This means that if your robot goes up a hill,
the regulator will adjust the power to match the desired speed. You can disable this feature
using ``set regulated``.
![Brake block](/static/labview/unregulatedmotor.png)
```blocks
motors.largeA.setRegulated(false);
```
## Brick
The brick category contains a number of blocks to display graphics on the brick screen.
![brick image](/static/labview/brickimage.png)
```blocks
brick.clearScreen()
brick.showImage(images.expressionsWink)
```
![brick status light](/static/labview/brickstatuslight.png)
```blocks
brick.setStatusLight(StatusLight.Off);
brick.setStatusLight(StatusLight.Red);
brick.setStatusLight(StatusLight.OrangePulse);
```
## Waiting (pausing)
It is quite common to wait for a sensor state, such as a touch button pressed.
The ``pause until`` blocks provide a variety of ways to acheive this.
![pause for time](/static/labview/pausefortime.png)
```blocks
motors.largeD.setSpeed(50)
loops.pause(1000)
motors.largeD.stop();
```
![pause for touch](/static/labview/pausefortouch.png)
```blocks
motors.largeD.setSpeed(50)
sensors.touch1.pauseUntil(ButtonEvent.Pressed)
motors.largeD.stop();
```
![pause for distance](/static/labview/pausefordistance.png)
```blocks
motors.largeD.setSpeed(50)
sensors.ultrasonic4.pauseUntil(UltrasonicSensorEvent.ObjectNear)
motors.largeD.stop();
```
You can also use the ``pause until`` block to wait on any boolean expression.
The runtime will evaluate this expression until it becomes true.
```blocks
motors.largeD.setSpeed(50)
pauseUntil(() => sensors.touch1.isPressed())
motors.largeD.stop()
```
## Loops
![Single loop](/static/labview/loopinfinite.png)
```blocks
loops.forever(() => {
motors.largeD.setSpeed(50, 1, MoveUnit.Rotations);
motors.largeD.setSpeed(-50, 1, MoveUnit.Rotations);
})
```
![While loop](/static/labview/while.png)
```blocks
for(let i = 0; i < 10; i++) {
motors.largeD.setSpeed(50, 1, MoveUnit.Rotations);
motors.largeD.setSpeed(-50, 1, MoveUnit.Rotations);
}
let k = 0;
while(k < 10) {
motors.largeD.setSpeed(50, 1, MoveUnit.Rotations);
motors.largeD.setSpeed(-50, 1, MoveUnit.Rotations);
k++;
}
```
## Variables
![Variable block](/static/labview/speedoflightvar.png)
```blocks
let light = 0;
loops.forever(function () {
light = sensors.color3.light(LightIntensityMode.Reflected);
motors.largeD.setSpeed(light)
})
```
## Concurrent loops
You can spin up multiple ``forever`` loops that will run at the same time.
Only one code is running at the time, but each loop iteration will interleave.
![Brake block](/static/labview/multipleloops.png)
```blocks
loops.forever(() => {
motors.largeD.setSpeed(50, 1, MoveUnit.Rotations);
motors.largeD.setSpeed(-50, 1, MoveUnit.Rotations);
})
loops.forever(() => {
brick.showImage(images.eyesMiddleRight)
loops.pause(1000)
brick.showImage(images.eyesMiddleLeft)
loops.pause(1000)
})
```
## Conditional
The ``if`` block allow to run different code based on a boolean condition.
This is similar to the switch block.
![Brake block](/static/labview/ife.png)
```blocks
loops.forever(function() {
if(sensors.touch1.isPressed()) {
motors.largeD.setSpeed(50)
} else {
motors.largeD.stop()
}
})
```
## Random
The ``random range`` blocks returns number between two bounds.
![Brake block](/static/labview/random.png)
```blocks
loops.forever(function () {
motors.largeBC.steer(Math.randomRange(-5, 5), 50)
loops.pause(100)
})
```

View File

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

View File

@ -20,7 +20,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, function () {
brick.buttonEnter.pauseUntil(ButtonEvent.Bumped); brick.buttonEnter.pauseUntil(ButtonEvent.Bumped);
brick.buttonEnter.isPressed() brick.buttonEnter.isPressed()
brick.buttonEnter.wasPressed() brick.buttonEnter.wasPressed()
brick.setLight(BrickLight.Red); brick.setStatusLight(StatusLight.Red);
``` ```
## Other ## Other

View File

@ -22,11 +22,11 @@ loops.forever(function() {
battery = brick.batteryLevel(); battery = brick.batteryLevel();
if (battery > 15) if (battery > 15)
{ {
brick.setLight(BrickLight.Green); brick.setStatusLight(StatusLight.Green);
} else if (battery > 5) { } else if (battery > 5) {
brick.setLight(BrickLight.Orange); brick.setStatusLight(StatusLight.Orange);
} else { } else {
brick.setLight(BrickLight.RedPulse) brick.setStatusLight(StatusLight.RedPulse)
} }
loops.pause(30000) loops.pause(30000)
}) })

View File

@ -34,11 +34,11 @@ Set the brick light to green when the `down` is pressed. When the button is not
let isRed = false; let isRed = false;
loops.forever(function() { loops.forever(function() {
if (brick.buttonLeft.isPressed()) { if (brick.buttonLeft.isPressed()) {
brick.setLight(BrickLight.Green); brick.setStatusLight(StatusLight.Green);
isRed = false; isRed = false;
} else { } else {
if (!isRed) { if (!isRed) {
brick.setLight(BrickLight.Red); brick.setStatusLight(StatusLight.Red);
isRed = true; isRed = true;
} }
} }

View File

@ -16,7 +16,7 @@ Your @boardname@ has touch sensors that work like buttons. Instead of saying `en
```block ```block
sensors.touch1.onEvent(ButtonEvent.Pressed, function () { sensors.touch1.onEvent(ButtonEvent.Pressed, function () {
brick.setLight(BrickLight.Orange); brick.setStatusLight(StatusLight.Orange);
}); });
``` ```

View File

@ -35,9 +35,9 @@ Set the brick light to green if the `right` button was pressed before the `left`
```blocks ```blocks
brick.buttonLeft.onEvent(ButtonEvent.Bumped, function() { brick.buttonLeft.onEvent(ButtonEvent.Bumped, function() {
if (brick.buttonRight.wasPressed()) { if (brick.buttonRight.wasPressed()) {
brick.setLight(BrickLight.Green) brick.setStatusLight(StatusLight.Green)
} else { } else {
brick.setLight(BrickLight.Off) brick.setStatusLight(StatusLight.Off)
} }
}) })
``` ```

View File

@ -3,7 +3,7 @@
Set the light on the brick to a solid or flashing color. Set the light on the brick to a solid or flashing color.
```sig ```sig
brick.setLight(BrickLight.Red); brick.setStatusLight(StatusLight.Red);
``` ```
## Parameters ## Parameters
@ -25,13 +25,13 @@ Repeatedly show a different color pattern for the brick light.
```blocks ```blocks
loops.forever(function () { loops.forever(function () {
brick.setLight(BrickLight.Orange) brick.setStatusLight(StatusLight.Orange)
loops.pause(1000) loops.pause(1000)
brick.setLight(BrickLight.GreenFlash) brick.setStatusLight(StatusLight.GreenFlash)
loops.pause(2000) loops.pause(2000)
brick.setLight(BrickLight.RedPulse) brick.setStatusLight(StatusLight.RedPulse)
loops.pause(2000) loops.pause(2000)
brick.setLight(BrickLight.Off) brick.setStatusLight(StatusLight.Off)
loops.pause(500) loops.pause(500)
}) })
``` ```

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.setInverted(true)
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 Reversed
Change the direction of rotation for a motor.
```sig
motors.largeA.setInverted(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.setInverted(true)
motors.largeA.setSpeed(-30)
loops.pause(2000)
motors.largeA.stop()
```
## 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,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)

BIN
docs/static/labview/brake.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/static/labview/brickimage.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/static/labview/brickstatuslight.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
docs/static/labview/ife.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
docs/static/labview/invertmotor.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

BIN
docs/static/labview/lighttospeed.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/static/labview/loopinfinite.PNG vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/static/labview/motors.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/static/labview/multipleloops.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/static/labview/pausefordistance.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
docs/static/labview/pausefortime.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/static/labview/pausefortouch.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/static/labview/random.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
docs/static/labview/sequencing.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
docs/static/labview/speedoflight.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
docs/static/labview/speedoflightvar.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/static/labview/steer.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
docs/static/labview/tank.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
docs/static/labview/unregulatedmotor.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
docs/static/labview/while.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -4,7 +4,7 @@
export NVM_DIR="/home/dotnet-bot/.nvm" export NVM_DIR="/home/dotnet-bot/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm install 5 nvm install 8
# Set up build environment variables # Set up build environment variables
echo ---------- Setting build environment variables echo ---------- Setting build environment variables

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@ -3,9 +3,9 @@
```blocks ```blocks
loops.forever(function () { loops.forever(function () {
if (sensors.color1.ambientLight() > 20) { if (sensors.color1.ambientLight() > 20) {
brick.setLight(BrickLight.Green) brick.setStatusLight(StatusLight.Green)
} else { } else {
brick.setLight(BrickLight.Orange) brick.setStatusLight(StatusLight.Orange)
} }
}) })
``` ```

View File

@ -3,9 +3,9 @@
```blocks ```blocks
loops.forever(function () { loops.forever(function () {
if (sensors.color1.color() == ColorSensorColor.Green) { if (sensors.color1.color() == ColorSensorColor.Green) {
brick.setLight(BrickLight.Green) brick.setStatusLight(StatusLight.Green)
} else { } else {
brick.setLight(BrickLight.Orange) brick.setStatusLight(StatusLight.Orange)
} }
}) })
``` ```

View File

@ -3,9 +3,9 @@
```blocks ```blocks
loops.forever(function () { loops.forever(function () {
if (sensors.color1.reflectedLight() > 20) { if (sensors.color1.reflectedLight() > 20) {
brick.setLight(BrickLight.Green) brick.setStatusLight(StatusLight.Green)
} else { } else {
brick.setLight(BrickLight.Orange) brick.setStatusLight(StatusLight.Orange)
} }
}) })
``` ```

View File

@ -2,7 +2,7 @@
/** /**
* Patterns for lights under the buttons. * Patterns for lights under the buttons.
*/ */
const enum BrickLight { const enum StatusLight {
//% block=off enumval=0 //% block=off enumval=0
Off = 0, Off = 0,
//% block=green enumval=1 //% block=green enumval=1
@ -244,16 +244,16 @@ namespace control {
namespace brick { namespace brick {
// the brick starts with the red color // the brick starts with the red color
let currPattern: BrickLight = BrickLight.Red; let currPattern: StatusLight = StatusLight.Red;
/** /**
* Set lights. * Set lights.
* @param pattern the lights pattern to use. eg: BrickLight.Orange * @param pattern the lights pattern to use. eg: BrickLight.Orange
*/ */
//% blockId=setLights block="set light to %pattern" //% blockId=setLights block="set status light to %pattern"
//% weight=100 group="Buttons" //% weight=100 group="Buttons"
//% help=brick/set-light //% help=brick/set-status-light
export function setLight(pattern: BrickLight): void { export function setStatusLight(pattern: StatusLight): void {
if (currPattern === pattern) if (currPattern === pattern)
return return
currPattern = pattern; currPattern = pattern;

View File

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

View File

@ -2,7 +2,7 @@ screen.clear()
brick.print("PXT!", 10, 30, Draw.Quad) brick.print("PXT!", 10, 30, Draw.Quad)
brick.drawRect(40, 40, 20, 10, Draw.Fill) brick.drawRect(40, 40, 20, 10, Draw.Fill)
brick.setLight(BrickLight.Orange) brick.setStatusLight(StatusLight.Orange)
brick.heart.doubled().draw(100, 50, Draw.Double | Draw.Transparent) brick.heart.doubled().draw(100, 50, Draw.Double | Draw.Transparent)
@ -12,7 +12,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, () => {
brick.buttonLeft.onEvent(ButtonEvent.Bumped, () => { brick.buttonLeft.onEvent(ButtonEvent.Bumped, () => {
brick.drawRect(10, 70, 20, 10, Draw.Fill) brick.drawRect(10, 70, 20, 10, Draw.Fill)
brick.setLight(BrickLight.Red) brick.setStatusLight(StatusLight.Red)
brick.setFont(brick.microbitFont()) brick.setFont(brick.microbitFont())
}) })

View File

@ -12,7 +12,7 @@ namespace brick {
namespace sensors { namespace sensors {
} }
//% color="#A5CA18" weight=90 icon="\uf10d" //% color="#00852B" weight=90 icon="\uf10d"
//% groups='["Move", "Counters"]' //% groups='["Move", "Counters"]'
//% labelLineWidth=50 //% labelLineWidth=50
namespace motors { namespace motors {

View File

@ -1,23 +1,31 @@
const enum IrSensorMode { const enum InfraredSensorMode {
None = -1, None = -1,
Proximity = 0, Proximity = 0,
Seek = 1, Seek = 1,
RemoteControl = 2, RemoteControl = 2,
} }
const enum IrRemoteChannel { const enum InfraredRemoteChannel {
//% block="channel 0"
Ch0 = 0, // top Ch0 = 0, // top
//% block="channel 1"
Ch1 = 1, Ch1 = 1,
//% block="channel 2"
Ch2 = 2, Ch2 = 2,
//% block="channel 3"
Ch3 = 3, Ch3 = 3,
} }
const enum IrRemoteButton { const enum InfraredRemoteButton {
None = 0x00, //% block="center beacon"
CenterBeacon = 0x01, CenterBeacon = 0x01,
//% block="top left"
TopLeft = 0x02, TopLeft = 0x02,
//% block="bottom left"
BottomLeft = 0x04, BottomLeft = 0x04,
//% block="top right"
TopRight = 0x08, TopRight = 0x08,
//% block="bottom right"
BottomRight = 0x10, BottomRight = 0x10,
} }
@ -31,62 +39,44 @@ const enum InfraredSensorEvent {
namespace sensors { namespace sensors {
function mapButton(v: number) { function mapButton(v: number) {
switch (v) { switch (v) {
case 0: return IrRemoteButton.None case 1: return InfraredRemoteButton.TopLeft;
case 1: return IrRemoteButton.TopLeft case 2: return InfraredRemoteButton.BottomLeft;
case 2: return IrRemoteButton.BottomLeft case 3: return InfraredRemoteButton.TopRight;
case 3: return IrRemoteButton.TopRight case 4: return InfraredRemoteButton.BottomRight;
case 4: return IrRemoteButton.TopRight | IrRemoteButton.BottomRight case 5: return InfraredRemoteButton.TopLeft | InfraredRemoteButton.TopRight
case 5: return IrRemoteButton.TopLeft | IrRemoteButton.TopRight case 6: return InfraredRemoteButton.TopLeft | InfraredRemoteButton.BottomRight
case 6: return IrRemoteButton.TopLeft | IrRemoteButton.BottomRight case 7: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopRight
case 7: return IrRemoteButton.BottomLeft | IrRemoteButton.TopRight case 8: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.BottomRight
case 8: return IrRemoteButton.BottomLeft | IrRemoteButton.BottomRight case 9: return InfraredRemoteButton.CenterBeacon
case 9: return IrRemoteButton.CenterBeacon case 10: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopLeft
case 10: return IrRemoteButton.BottomLeft | IrRemoteButton.TopLeft case 11: return InfraredRemoteButton.TopRight | InfraredRemoteButton.BottomRight
case 11: return IrRemoteButton.TopRight | IrRemoteButton.BottomRight default: return 0;
default: return IrRemoteButton.None
} }
} }
let buttons: RemoteInfraredBeaconButton[] const __remoteButtons: RemoteInfraredBeaconButton[] = [];
function __irButton(id: InfraredRemoteButton): RemoteInfraredBeaconButton {
function create(ir: InfraredSensor) { for(let i = 0; i < __remoteButtons.length; ++i) {
// it's created by referencing it if (__remoteButtons[i].position == id)
} return __remoteButtons[i];
export function irButton(id: IrRemoteButton): RemoteInfraredBeaconButton {
if (buttons == null) {
buttons = []
for (let i = 0; i < 5; ++i) {
buttons.push(new RemoteInfraredBeaconButton(new brick.Button()))
}
// this defeats our static allocation system
// make sure sensors are up
//create(infraredSensor1)
//create(infraredSensor2)
//create(infraredSensor3)
//create(infraredSensor4)
} }
const btn = new RemoteInfraredBeaconButton(id, new brick.Button());
let num = -1 __remoteButtons.push(btn);
while (id) { return btn;
id >>= 1;
num++;
}
num = Math.clamp(0, buttons.length - 1, num)
return buttons[num]
} }
//% fixedInstances //% fixedInstances
export class RemoteInfraredBeaconButton extends control.Component { export class RemoteInfraredBeaconButton extends control.Component {
private button: brick.Button; position: InfraredRemoteButton;
constructor(button: brick.Button) { private _button: brick.Button;
constructor(position: InfraredRemoteButton, button: brick.Button) {
super(); super();
this.button = button; this.position = position;
this._button = button;
} }
_update(curr: boolean) { _update(curr: boolean) {
this.button._update(curr); this._button._update(curr);
} }
/** /**
@ -101,7 +91,7 @@ namespace sensors {
//% weight=81 blockGap=8 //% weight=81 blockGap=8
//% group="Remote Infrared Beacon" //% group="Remote Infrared Beacon"
isPressed() { isPressed() {
return this.button.isPressed(); return this._button.isPressed();
} }
/** /**
@ -116,7 +106,7 @@ namespace sensors {
//% weight=80 //% weight=80
//% group="Remote Infrared Beacon" //% group="Remote Infrared Beacon"
wasPressed() { wasPressed() {
return this.button.wasPressed(); return this._button.wasPressed();
} }
/** /**
@ -132,42 +122,53 @@ namespace sensors {
//% weight=99 blockGap=8 //% weight=99 blockGap=8
//% group="Remote Infrared Beacon" //% group="Remote Infrared Beacon"
onEvent(ev: ButtonEvent, body: () => void) { onEvent(ev: ButtonEvent, body: () => void) {
this.button.onEvent(ev, body); this._button.onEvent(ev, body);
}
/**
* Pauses until the given event is raised
* @param ev the event to wait for
*/
//% help=input/remote-infrared-beacon/pause-until
//% blockId=remoteButtonPauseUntil block="pause until %button|%event"
//% parts="remote"
//% blockNamespace=sensors
//% weight=99 blockGap=8
//% group="Remote Infrared Beacon"
pauseUntil(ev: ButtonEvent) {
this._button.pauseUntil(ev);
} }
} }
//% fixedInstances //% fixedInstances
export class InfraredSensor extends internal.UartSensor { export class InfraredSensor extends internal.UartSensor {
private channel: IrRemoteChannel; private _channel: InfraredRemoteChannel;
private proximityThreshold: sensors.ThresholdDetector; private _proximityThreshold: sensors.ThresholdDetector;
constructor(port: number) { constructor(port: number) {
super(port) super(port)
this.channel = IrRemoteChannel.Ch0 this._channel = InfraredRemoteChannel.Ch0
this.proximityThreshold = new sensors.ThresholdDetector(this._id, 0, 100, 10, 90); this._proximityThreshold = new sensors.ThresholdDetector(this._id, 0, 100, 10, 90);
irButton(0) // make sure buttons array is initalized this.setMode(InfraredSensorMode.Proximity);
// and set the mode, as otherwise button events won't work
this.mode = IrSensorMode.RemoteControl;
} }
_query() { _query() {
if (this.mode == IrSensorMode.RemoteControl) if (this.mode == InfraredSensorMode.RemoteControl)
return mapButton(this.getNumber(NumberFormat.UInt8LE, this.channel)); return mapButton(this.getNumber(NumberFormat.UInt8LE, this._channel));
else if (this.mode == IrSensorMode.Proximity) { else if (this.mode == InfraredSensorMode.Proximity) {
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff; return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
} }
return 0 return 0
} }
_update(prev: number, curr: number) { _update(prev: number, curr: number) {
if (this.mode == IrSensorMode.RemoteControl) { if (this.mode == InfraredSensorMode.RemoteControl) {
for (let i = 0; i < buttons.length; ++i) { for (let i = 0; i < __remoteButtons.length; ++i) {
let v = !!(curr & (1 << i)) const v = !!(curr & __remoteButtons[i].position);
buttons[i]._update(v) __remoteButtons[i]._update(v)
} }
} else if (this.mode == IrSensorMode.Proximity) { } else if (this.mode == InfraredSensorMode.Proximity) {
this.proximityThreshold.setLevel(curr); this._proximityThreshold.setLevel(curr);
} }
} }
@ -175,13 +176,7 @@ namespace sensors {
return DAL.DEVICE_TYPE_IR return DAL.DEVICE_TYPE_IR
} }
setRemoteChannel(c: IrRemoteChannel) { setMode(m: InfraredSensorMode) {
c = Math.clamp(0, 3, c | 0)
this.channel = c
this.setMode(IrSensorMode.RemoteControl)
}
setMode(m: IrSensorMode) {
this._setMode(m) this._setMode(m)
} }
@ -197,7 +192,7 @@ namespace sensors {
//% weight=100 blockGap=8 //% weight=100 blockGap=8
//% group="Infrared Sensor" //% group="Infrared Sensor"
onEvent(event: InfraredSensorEvent, handler: () => void) { onEvent(event: InfraredSensorEvent, handler: () => void) {
this._setMode(IrSensorMode.Proximity) this._setMode(InfraredSensorMode.Proximity)
control.onEvent(this._id, event, handler); control.onEvent(this._id, event, handler);
} }
@ -212,7 +207,7 @@ namespace sensors {
//% weight=99 blockGap=8 //% weight=99 blockGap=8
//% group="Infrared Sensor" //% group="Infrared Sensor"
pauseUntil(event: InfraredSensorEvent) { pauseUntil(event: InfraredSensorEvent) {
this._setMode(IrSensorMode.Proximity) this._setMode(InfraredSensorMode.Proximity)
control.waitForEvent(this._id, event); control.waitForEvent(this._id, event);
} }
@ -228,33 +223,24 @@ namespace sensors {
//% weight=98 blockGap=8 //% weight=98 blockGap=8
//% group="Infrared Sensor" //% group="Infrared Sensor"
proximity(): number { proximity(): number {
this._setMode(IrSensorMode.Proximity) this._setMode(InfraredSensorMode.Proximity)
return this.getNumber(NumberFormat.UInt8LE, 0) return this.getNumber(NumberFormat.UInt8LE, 0)
} }
/** /**
* Get the remote commandreceived the infrared sensor. * Sets the remote channel to listen from
* @param sensor the infrared sensor * @param channel the channel to listen
*/ */
//% help=input/infrared/remote-command
//% block="%sensor|remote command"
//% blockId=infraredGetRemoteCommand
//% parts="infrared"
//% blockNamespace=sensors //% blockNamespace=sensors
//% weight=65 //% blockId=irSetRemoteChannel block="set %sensor|remote channel to %channel"
//% group="Infrared Sensor" //% weight=99
remoteCommand(): number { //% group="Remote Infrared Beacon"
this._setMode(IrSensorMode.RemoteControl) setRemoteChannel(channel: InfraredRemoteChannel) {
return this.getNumber(NumberFormat.UInt8LE, this.channel) this.setMode(InfraredSensorMode.RemoteControl)
channel = Math.clamp(0, 3, channel | 0)
this._channel = channel;
} }
// TODO
getDirectionAndDistance() {
this._setMode(IrSensorMode.Seek)
return this.getNumber(NumberFormat.UInt16LE, this.channel * 2)
}
/** /**
* Sets a threshold value * Sets a threshold value
* @param condition the dark or bright light condition * @param condition the dark or bright light condition
@ -263,11 +249,11 @@ namespace sensors {
//% blockId=irSetThreshold block="set %sensor|%condition|to %value" //% blockId=irSetThreshold block="set %sensor|%condition|to %value"
//% group="Threshold" blockGap=8 weight=49 //% group="Threshold" blockGap=8 weight=49
//% value.min=0 value.max=100 //% value.min=0 value.max=100
setThreshold(condition: InfraredSensorEvent, value: number) { setPromixityThreshold(condition: InfraredSensorEvent, value: number) {
if (condition == InfraredSensorEvent.ObjectNear) if (condition == InfraredSensorEvent.ObjectNear)
this.proximityThreshold.setLowThreshold(value) this._proximityThreshold.setLowThreshold(value)
else else
this.proximityThreshold.setHighThreshold(value); this._proximityThreshold.setHighThreshold(value);
} }
/** /**
@ -277,9 +263,15 @@ namespace sensors {
//% blockId=irGetThreshold block="%sensor|%condition" //% blockId=irGetThreshold block="%sensor|%condition"
//% group="Threshold" blockGap=8 weight=49 //% group="Threshold" blockGap=8 weight=49
//% sensor.fieldEditor="ports" //% sensor.fieldEditor="ports"
threshold(condition: InfraredSensorEvent): number { proximityThreshold(condition: InfraredSensorEvent): number {
return this.proximityThreshold.threshold(<ThresholdState><number>LightCondition.Dark); return this._proximityThreshold.threshold(<ThresholdState><number>LightCondition.Dark);
} }
// TODO
private getDirectionAndDistance() {
this._setMode(InfraredSensorMode.Seek)
return this.getNumber(NumberFormat.UInt16LE, this._channel * 2)
}
} }
//% fixedInstance whenUsed block="infrared 1" jres=icons.port1 //% fixedInstance whenUsed block="infrared 1" jres=icons.port1
@ -294,34 +286,33 @@ namespace sensors {
//% fixedInstance whenUsed block="infrared 4" jres=icons.port4 //% fixedInstance whenUsed block="infrared 4" jres=icons.port4
export const infraredSensor4: InfraredSensor = new InfraredSensor(4) export const infraredSensor4: InfraredSensor = new InfraredSensor(4)
/** /**
* Remote beacon (center) button. * Remote beacon (center) button.
*/ */
//% whenUsed block="center" weight=95 fixedInstance //% whenUsed block="remote button center" weight=95 fixedInstance
export const remoteButtonCenter = irButton(IrRemoteButton.CenterBeacon) export const remoteButtonCenter = __irButton(InfraredRemoteButton.CenterBeacon)
/** /**
* Remote top-left button. * Remote top-left button.
*/ */
//% whenUsed block="top-left" weight=95 fixedInstance //% whenUsed block="remote button top left" weight=95 fixedInstance
export const remoteButtonTopLeft = irButton(IrRemoteButton.TopLeft) export const remoteButtonTopLeft = __irButton(InfraredRemoteButton.TopLeft)
/** /**
* Remote top-right button. * Remote top-right button.
*/ */
//% whenUsed block="top-right" weight=95 fixedInstance //% whenUsed block="remote button top right" weight=95 fixedInstance
export const remoteButtonTopRight = irButton(IrRemoteButton.TopRight) export const remoteButtonTopRight = __irButton(InfraredRemoteButton.TopRight)
/** /**
* Remote bottom-left button. * Remote bottom-left button.
*/ */
//% whenUsed block="bottom-left" weight=95 fixedInstance //% whenUsed block="remote button bottom left" weight=95 fixedInstance
export const remoteButtonBottomLeft = irButton(IrRemoteButton.BottomLeft) export const remoteButtonBottomLeft = __irButton(InfraredRemoteButton.BottomLeft)
/** /**
* Remote bottom-right button. * Remote bottom-right button.
*/ */
//% whenUsed block="bottom-right" weight=95 fixedInstance //% whenUsed block="remote button bottom right" weight=95 fixedInstance
export const remoteButtonBottomRight = irButton(IrRemoteButton.BottomRight) export const remoteButtonBottomRight = __irButton(InfraredRemoteButton.BottomRight)
} }

View File

@ -18,9 +18,9 @@ namespace brick {
export class Mood { export class Mood {
private image: Image; private image: Image;
private sound: Sound; private sound: Sound;
private light: BrickLight; private light: StatusLight;
constructor(image: Image, sound: Sound, light: BrickLight) { constructor(image: Image, sound: Sound, light: StatusLight) {
this.image = image; this.image = image;
this.sound = sound; this.sound = sound;
this.light = light; this.light = light;
@ -30,7 +30,7 @@ namespace brick {
* Shows the mood on the EV3 * Shows the mood on the EV3
*/ */
show() { show() {
brick.setLight(this.light); brick.setStatusLight(this.light);
brick.showImage(this.image); brick.showImage(this.image);
music.playSoundEffectUntilDone(this.sound); music.playSoundEffectUntilDone(this.sound);
loops.pause(20); loops.pause(20);
@ -56,71 +56,71 @@ namespace moods {
* A sleeping mood * A sleeping mood
*/ */
//% fixedInstance jres=images.eyesSleeping //% fixedInstance jres=images.eyesSleeping
export const sleeping = new brick.Mood(images.eyesSleeping, sounds.expressionsSnoring, BrickLight.OrangePulse); export const sleeping = new brick.Mood(images.eyesSleeping, sounds.expressionsSnoring, StatusLight.OrangePulse);
/** /**
* A awake mood * A awake mood
*/ */
//% fixedInstance jres=images.eyesAwake //% fixedInstance jres=images.eyesAwake
export const awake = new brick.Mood(images.eyesAwake, sounds.informationActivate, BrickLight.Orange); export const awake = new brick.Mood(images.eyesAwake, sounds.informationActivate, StatusLight.Orange);
/** /**
* A tired mood * A tired mood
*/ */
//% fixedInstance jres=images.eyesTiredMiddle //% fixedInstance jres=images.eyesTiredMiddle
export const tired = new brick.Mood(images.eyesTiredMiddle, sounds.expressionsSneezing, BrickLight.OrangeFlash); export const tired = new brick.Mood(images.eyesTiredMiddle, sounds.expressionsSneezing, StatusLight.OrangeFlash);
/** /**
* An angry mood * An angry mood
*/ */
//% fixedInstance jres=images.eyesAngry //% fixedInstance jres=images.eyesAngry
export const angry = new brick.Mood(images.eyesAngry, sounds.animalsDogGrowl, BrickLight.RedPulse); export const angry = new brick.Mood(images.eyesAngry, sounds.animalsDogGrowl, StatusLight.RedPulse);
/** /**
* A sad mood * A sad mood
*/ */
//% fixedInstance jres=images.eyesTear //% fixedInstance jres=images.eyesTear
export const sad = new brick.Mood(images.eyesTear, sounds.animalsDogWhine, BrickLight.Red); export const sad = new brick.Mood(images.eyesTear, sounds.animalsDogWhine, StatusLight.Red);
/** /**
* A dizzy mood * A dizzy mood
*/ */
//% fixedInstance jres=images.eyesDizzy //% fixedInstance jres=images.eyesDizzy
export const dizzy = new brick.Mood(images.eyesDizzy, sounds.expressionsUhOh, BrickLight.OrangeFlash); export const dizzy = new brick.Mood(images.eyesDizzy, sounds.expressionsUhOh, StatusLight.OrangeFlash);
/** /**
* A knocked out mood * A knocked out mood
*/ */
//% fixedInstance jres=images.eyesKnockedOut //% fixedInstance jres=images.eyesKnockedOut
export const knockedOut = new brick.Mood(images.eyesKnockedOut, sounds.informationError, BrickLight.RedFlash); export const knockedOut = new brick.Mood(images.eyesKnockedOut, sounds.informationError, StatusLight.RedFlash);
/** /**
* Looking around left * Looking around left
*/ */
//% fixedInstance jres=images.eyesMiddleLeft //% fixedInstance jres=images.eyesMiddleLeft
export const middleLeft = new brick.Mood(images.eyesMiddleLeft, sounds.informationAnalyze, BrickLight.Off); export const middleLeft = new brick.Mood(images.eyesMiddleLeft, sounds.informationAnalyze, StatusLight.Off);
/** /**
* Looking around right * Looking around right
*/ */
//% fixedInstance jres=images.eyesMiddleRight //% fixedInstance jres=images.eyesMiddleRight
export const middleRight = new brick.Mood(images.eyesMiddleRight, sounds.informationAnalyze, BrickLight.Off); export const middleRight = new brick.Mood(images.eyesMiddleRight, sounds.informationAnalyze, StatusLight.Off);
/** /**
* In love mood * In love mood
*/ */
//% fixedInstance jres=images.eyesLove //% fixedInstance jres=images.eyesLove
export const love = new brick.Mood(images.eyesLove, sounds.expressionsMagicWand, BrickLight.GreenPulse); export const love = new brick.Mood(images.eyesLove, sounds.expressionsMagicWand, StatusLight.GreenPulse);
/** /**
* In laughing mood * In laughing mood
*/ */
//% fixedInstance jres=images.eyesWinking //% fixedInstance jres=images.eyesWinking
export const winking = new brick.Mood(images.eyesWinking, sounds.expressionsLaughing1, BrickLight.GreenFlash); export const winking = new brick.Mood(images.eyesWinking, sounds.expressionsLaughing1, StatusLight.GreenFlash);
/** /**
* In a neutral mood * In a neutral mood
*/ */
//% fixedInstance jres=images.eyesNeutral //% fixedInstance jres=images.eyesNeutral
export const neutral = new brick.Mood(images.eyesNeutral, undefined, BrickLight.Green); export const neutral = new brick.Mood(images.eyesNeutral, undefined, StatusLight.Green);
} }

View File

@ -3,9 +3,9 @@
```blocks ```blocks
loops.forever(function () { loops.forever(function () {
if (sensors.touch1.isPressed()) { if (sensors.touch1.isPressed()) {
brick.setLight(BrickLight.Green) brick.setStatusLight(StatusLight.Green)
} else { } else {
brick.setLight(BrickLight.Orange) brick.setStatusLight(StatusLight.Orange)
} }
}) })
``` ```

View File

@ -3,9 +3,9 @@
```blocks ```blocks
loops.forever(function () { loops.forever(function () {
if (sensors.touch1.wasPressed()) { if (sensors.touch1.wasPressed()) {
brick.setLight(BrickLight.Green) brick.setStatusLight(StatusLight.Green)
} else { } else {
brick.setLight(BrickLight.Orange) brick.setStatusLight(StatusLight.Orange)
} }
}) })
``` ```

2
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "pxt-ev3", "name": "pxt-ev3",
"version": "0.0.87", "version": "0.0.94",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@ -1,6 +1,6 @@
{ {
"name": "pxt-ev3", "name": "pxt-ev3",
"version": "0.0.87", "version": "0.0.94",
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode", "description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
"private": true, "private": true,
"keywords": [ "keywords": [
@ -44,8 +44,8 @@
"webfonts-generator": "^0.4.0" "webfonts-generator": "^0.4.0"
}, },
"dependencies": { "dependencies": {
"pxt-common-packages": "0.17.13", "pxt-common-packages": "0.18.1",
"pxt-core": "3.2.1" "pxt-core": "3.3.1"
}, },
"scripts": { "scripts": {
"test": "node node_modules/pxt-core/built/pxt.js travis" "test": "node node_modules/pxt-core/built/pxt.js travis"

View File

@ -83,7 +83,7 @@
}, },
"appTheme": { "appTheme": {
"accentColor": "#0089BF", "accentColor": "#0089BF",
"logoUrl": "https://lego.makecode.com", "logoUrl": "https://education.lego.com/",
"logo": "./static/lego_education_logo.png", "logo": "./static/lego_education_logo.png",
"highContrastLogo": "./static/lego_education_logo_white.png", "highContrastLogo": "./static/lego_education_logo_white.png",
"docsLogo": "./static/lego-logo.svg", "docsLogo": "./static/lego-logo.svg",
@ -95,12 +95,12 @@
"organizationUrl": "https://makecode.com/", "organizationUrl": "https://makecode.com/",
"organizationLogo": "./static/Microsoft-logo_rgb_c-gray-square.png", "organizationLogo": "./static/Microsoft-logo_rgb_c-gray-square.png",
"organizationWideLogo": "./static/Microsoft-logo_rgb_c-gray.png", "organizationWideLogo": "./static/Microsoft-logo_rgb_c-gray.png",
"homeUrl": "https://lego.makecode.com/", "homeUrl": "https://makecode.legoeducation.com/",
"embedUrl": "https://lego.makecode.com/", "embedUrl": "https://makecode.legoeducation.com/",
"privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839", "privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839",
"termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977", "termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977",
"githubUrl": "https://github.com/Microsoft/pxt-ev3", "githubUrl": "https://github.com/Microsoft/pxt-ev3",
"betaUrl": "https://lego.makecode.com/", "betaUrl": "https://makecode.legoeducation.com/about",
"boardName": "LEGO Mindstorms EV3 Brick", "boardName": "LEGO Mindstorms EV3 Brick",
"selectLanguage": true, "selectLanguage": true,
"highContrast": true, "highContrast": true,
@ -137,7 +137,7 @@
"blockColors": { "blockColors": {
"loops": "#58AB41", "loops": "#58AB41",
"logic": "#1E5AA8", "logic": "#1E5AA8",
"math": "#9DC3F7", "math": "#7396C8",
"variables": "#B40000", "variables": "#B40000",
"text": "#FCAC00", "text": "#FCAC00",
"advanced": "#969696", "advanced": "#969696",
@ -157,5 +157,5 @@
"editor.background": "#ecf6ff" "editor.background": "#ecf6ff"
} }
}, },
"ignoreDocsErrors": true "ignoreDocsErrors": false
} }

View File

@ -13,6 +13,7 @@ namespace pxsim {
motorState: EV3MotorState; motorState: EV3MotorState;
screenState: EV3ScreenState; screenState: EV3ScreenState;
audioState: AudioState; audioState: AudioState;
remoteState: RemoteState;
inputNodes: SensorNode[] = []; inputNodes: SensorNode[] = [];
brickNode: BrickNode; brickNode: BrickNode;
@ -38,6 +39,7 @@ namespace pxsim {
this.motorState = new EV3MotorState(); this.motorState = new EV3MotorState();
this.screenState = new EV3ScreenState(); this.screenState = new EV3ScreenState();
this.audioState = new AudioState(); this.audioState = new AudioState();
this.remoteState = new RemoteState();
} }
receiveMessage(msg: SimulatorMessage) { receiveMessage(msg: SimulatorMessage) {

View File

@ -1,6 +1,48 @@
/// <reference path="./sensor.ts"/> /// <reference path="./sensor.ts"/>
namespace pxsim { namespace pxsim {
export enum InfraredRemoteButton {
//% block="center beacon"
CenterBeacon = 0x01,
//% block="top left"
TopLeft = 0x02,
//% block="bottom left"
BottomLeft = 0x04,
//% block="top right"
TopRight = 0x08,
//% block="bottom right"
BottomRight = 0x10,
}
export class RemoteState {
state: number = 0;
constructor() {
}
unmapButtons() {
switch(this.state) {
case InfraredRemoteButton.TopLeft: return 1;
case InfraredRemoteButton.BottomLeft: return 2;
case InfraredRemoteButton.TopRight: return 3;
case InfraredRemoteButton.BottomRight: return 4;
case InfraredRemoteButton.TopLeft | InfraredRemoteButton.TopRight: return 5;
case InfraredRemoteButton.TopLeft | InfraredRemoteButton.BottomRight: return 6;
case InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopRight: return 7;
case InfraredRemoteButton.BottomLeft | InfraredRemoteButton.BottomRight: return 8;
case InfraredRemoteButton.CenterBeacon: return 9;
case InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopLeft: return 10;
case InfraredRemoteButton.TopRight | InfraredRemoteButton.BottomRight: return 11;
default: return 0;
}
}
setPressed(btns: InfraredRemoteButton, down: boolean) {
if (down) this.state = this.state | btns;
else this.state = ~(~this.state | btns);
}
}
export enum InfraredSensorMode { export enum InfraredSensorMode {
None = -1, None = -1,
Proximity = 0, Proximity = 0,
@ -29,7 +71,11 @@ namespace pxsim {
} }
getValue() { getValue() {
return this.proximity; switch(this.mode) {
case InfraredSensorMode.Proximity: return this.proximity;
case InfraredSensorMode.RemoteControl: return ev3board().remoteState.unmapButtons();
default: return 0;
}
} }
} }
} }

View File

@ -0,0 +1,100 @@
namespace pxsim.visuals {
export const REMOVE_SVG = `
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="123.773" viewBox="0 0 21.166666 32.748275" id="svg10208">
<defs id="defs10202">
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.30835 7.23512 0 1161.6036 852.6532)" id="linearGradient9407">
<stop offset="0" id="stop9403" stop-color="#a9aba9"/>
<stop offset="1" id="stop9405" stop-color="#848484"/>
</linearGradient>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 2.61718 -8.4555 0 1161.6036 932.34937)" id="linearGradient9387">
<stop offset="0" id="stop9383" stop-color="#303030"/>
<stop offset="1" id="stop9385" stop-color="#777"/>
</linearGradient>
<clipPath id="clipPath9357">
<path d="M0 1145.871h1366V0H0z" id="path9355"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="rotate(124.418 344.320607 757.342015) scale(10.33459)" id="linearGradient9347">
<stop offset="0" id="stop9343" stop-color="#fff"/>
<stop offset="1" id="stop9345" stop-color="#9e9e9e"/>
</linearGradient>
<clipPath id="clipPath9305">
<path d="M0 1145.871h1366V0H0z" id="path9303"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -5.71338 10.23004 0 1161.4999 872.46655)" id="linearGradient9295">
<stop offset="0" id="stop9291" stop-color="#f2f2f2"/>
<stop offset="1" id="stop9293" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath9273">
<path d="M0 1145.871h1366V0H0z" id="path9271"/>
</clipPath>
</defs>
<g id="layer1" transform="translate(0 -264.2517)">
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9267">
<g id="g9269" clip-path="url(#clipPath9273)">
<g id="g9275" transform="translate(1188.0205 889.5135)">
<path d="M0 0h-53.041c-.541 0-.98.254-.98.566v29.585c0 .313.439.566.98.566H0c.541 0 .979-.253.979-.566V.566C.979.254.541 0 0 0" id="path9277" fill="#f2f2f2"/>
</g>
</g>
</g>
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9279">
<g id="g9281">
<g id="g9287">
<g id="g9289">
<path d="M1134.979 898.024c-.541 0-.979-.254-.979-.567v-29.584c0-.313.438-.567.979-.567h53.042c.541 0 .979.254.979.567v29.584c0 .313-.438.567-.979.567z" id="path9297" fill="url(#linearGradient9295)"/>
</g>
</g>
</g>
</g>
<path d="M19.009995 291.64843H2.236527v-22.20479h16.773468z" id="path9307" fill="#f2f2f2" stroke-width=".384845"/>
<g id="g9309" transform="matrix(.38484 0 0 -.38484 11.821398 288.69324)">
<path d="M0 0h-6.642c-.687 0-1.245.558-1.245 1.246v12.867c0 .688.558 1.246 1.245 1.246H0c.687 0 1.245-.558 1.245-1.246V1.246C1.245.558.687 0 0 0" id="path9311" fill="#f22a21"/>
</g>
<path d="M6.251333 274.21366c-.838192 0-1.517581.67957-1.517581 1.51814v3.53633h3.083082v-3.53633c0-.83857-.67939-1.51814-1.517582-1.51814z" id="topleft" fill="#a9aba9" stroke-width=".384845"/>
<path d="M4.733752 281.18484v3.72518c0 .8378.679389 1.51702 1.517581 1.51702h.04792c.838192 0 1.51758-.67922 1.51758-1.51702v-3.72518z" id="bottomleft" fill="#a9aba9" stroke-width=".384845"/>
<g id="g9327" transform="matrix(.38484 0 0 -.38484 7.497511 280.74023)">
<path d="M0 0h-6.352c-.229 0-.415.186-.415.416v1.717c0 .229.186.415.415.415H0c.229 0 .415-.186.415-.415V.416C.415.186.229 0 0 0" id="path9329" fill="#f22a21"/>
</g>
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9331">
<g id="g9333">
<g id="g9339">
<g id="g9341">
<path d="M1157.731 904.68c0-2.042 1.655-3.697 3.696-3.697 2.043 0 3.698 1.655 3.698 3.697 0 2.041-1.655 3.697-3.698 3.697-2.041 0-3.696-1.656-3.696-3.697" id="path9349" fill="url(#linearGradient9347)"/>
</g>
</g>
</g>
</g>
<g id="g9359" transform="matrix(.38484 0 0 -.38484 10.555605 276.77113)">
<path d="M0 0c-1.239 0-2.244 1.004-2.244 2.244 0 1.239 1.005 2.244 2.244 2.244 1.24 0 2.244-1.005 2.244-2.244C2.244 1.004 1.24 0 0 0" id="path9361" fill="#f22a21"/>
</g>
<g id="centerbeacon" transform="matrix(.38484 0 0 -.38484 15.001642 273.1773)">
<path d="M0 0h-23.265l-3.683 4.151v6.736H3.684V4.151z" id="path9365" fill="#a9aba9"/>
</g>
<path d="M12.061234 283.61556H9.025961v-.47952h3.035273z" id="path9367" fill="#b42e29" stroke-width=".384845"/>
<path d="M12.061234 284.49416H9.025961v-.47913h3.035273z" id="path9369" fill="#b42e29" stroke-width=".384845"/>
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9371">
<g id="g9373">
<g id="g9379">
<g id="g9381">
<path d="M1140.849 934.967c-.573 0-1.038-.466-1.038-1.039v-12.452h43.585v12.452c0 .573-.465 1.039-1.037 1.039z" id="path9389" fill="url(#linearGradient9387)"/>
</g>
</g>
</g>
</g>
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9391">
<g id="g9393">
<g id="g9399">
<g id="g9401">
<path d="M1139.811 863.778v-12.453c0-.803.651-1.453 1.453-1.453h40.679c.803 0 1.453.65 1.453 1.453v12.453z" id="path9409" fill="url(#linearGradient9407)"/>
</g>
</g>
</g>
</g>
<path d="M14.877744 274.21376c-.838192 0-1.517581.67957-1.517581 1.51815v3.53632h3.083082v-3.53632c0-.83858-.679389-1.51815-1.517582-1.51815z" id="topright" fill="#a9aba9" stroke-width=".384845"/>
<path d="M13.360163 281.18494v3.72518c0 .83781.679389 1.51702 1.517581 1.51702h.04792c.838192 0 1.517581-.67921 1.517581-1.51702v-3.72518z" id="bottomright" fill="#a9aba9" stroke-width=".384845"/>
<g id="g9323" transform="matrix(.38484 0 0 -.38484 16.12385 280.74023)">
<path d="M0 0h-6.352c-.228 0-.415.186-.415.416v1.717c0 .229.187.415.415.415H0c.229 0 .415-.186.415-.415V.416C.415.186.229 0 0 0" id="path9325" fill="#006db4"/>
</g>
</g>
</svg>
`;
}

View File

@ -0,0 +1,60 @@
<svg xmlns="http://www.w3.org/2000/svg" width="83" height="34.662998" viewBox="0 0 21.960417 9.171252" id="svg9433">
<defs id="defs9427">
<clipPath id="clipPath9203">
<path d="M0 1145.871h1366V0H0z" id="path9201"/>
</clipPath>
<clipPath id="clipPath9215">
<path d="M737.191 1004.92h12.59v-18.959h-12.59z" id="path9213"/>
</clipPath>
<clipPath id="clipPath9233">
<path d="M741.135 1011.29h5.158v-5.16h-5.158z" id="path9231"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-2.66153 2.43973 -2.43973 -2.66153 745.59473 1006.9893)" id="linearGradient9243">
<stop offset="0" id="stop9239" stop-color="#f2f2f2"/>
<stop offset="1" id="stop9241" stop-color="#7a7a7a"/>
</linearGradient>
</defs>
<g id="layer1" transform="translate(0 -287.82875)">
<g id="g10128" transform="translate(-62.249591 173.06003) scale(.74516)">
<path id="path9195" d="M92.414417 162.9553h13.538203v2.51495H92.414417z" fill="#1f1f1f" stroke-width=".352778"/>
<g id="g9197" transform="matrix(.35278 0 0 -.35278 -164.0649 511.69022)">
<g clip-path="url(#clipPath9203)" id="g9199">
<g transform="translate(719.4443 1013.8715)" id="g9205">
<path id="path9207" d="M0 0h48.387c9.634.073 17.503-7.678 17.575-17.312.073-9.633-7.678-17.502-17.312-17.575-.087-.001-.175-.001-.263 0h-5.716l-7.482 6.977H13.803l-6.827-6.977H0c-9.634-.073-17.503 7.678-17.576 17.311C-17.648-7.942-9.898-.073-.265 0H0"/>
</g>
<g id="g9209">
<g id="g9221">
<g id="g9219" clip-path="url(#clipPath9215)" opacity=".057999">
<path id="path9217" d="M737.191 1004.922h12.59v-18.961h-12.59z" fill="#fff"/>
</g>
</g>
</g>
<g transform="translate(728.0898 1013.8715)" id="g9223">
<path id="path9225" d="M0 0h31.101v-1.288L21.7-10.315H9.101L0-1.288z" fill="#1f1f1f"/>
</g>
<g id="g9227">
<g id="g9257">
<g id="g9255" clip-path="url(#clipPath9233)" opacity=".261002">
<g id="g9253">
<g id="g9251">
<g id="g9249">
<g id="g9247">
<path id="path9245" d="M743.714 1011.292c1.425 0 2.579-1.154 2.579-2.579 0-1.424-1.154-2.579-2.579-2.579-1.424 0-2.579 1.155-2.579 2.579 0 1.425 1.155 2.579 2.579 2.579" fill="url(#linearGradient9243)"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
<g transform="translate(709.8887 997.7933)" id="g9259">
<path id="path9261" d="M0 0h14.106l2.275-2.427h-4.248L10.616-.759H0z" fill="#d52715"/>
</g>
<g transform="translate(777.5391 997.7933)" id="g9263">
<path id="path9265" d="M0 0h-14.106l-2.275-2.427h4.246l1.518 1.668H.001z" fill="#d52715"/>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,79 +1,64 @@
namespace pxsim { namespace pxsim {
export const INFRARED_SVG = `<svg id="svg5190" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 83.53 35.14"> export const INFRARED_SVG = `
<defs> <svg xmlns="http://www.w3.org/2000/svg" width="83" height="34.662998" viewBox="0 0 21.960417 9.171252" id="svg9433">
<clipPath id="clip-path" transform="translate(0.04 -22.43)"> <defs id="defs9427">
<circle cx="17.53" cy="40" r="6.98" style="fill: none"/> <clipPath id="clipPath9203">
</clipPath> <path d="M0 1145.871h1366V0H0z" id="path9201"/>
<clipPath id="clip-path-2" transform="translate(0.04 -22.43)"> </clipPath>
<circle cx="65.92" cy="40" r="6.98" style="fill: none"/> <clipPath id="clipPath9215">
</clipPath> <path d="M737.191 1004.92h12.59v-18.959h-12.59z" id="path9213"/>
</defs> </clipPath>
<title>ultra sonic</title> <clipPath id="clipPath9233">
<g id="ultra_sonic" data-name="ultra sonic"> <path d="M741.135 1011.29h5.158v-5.16h-5.158z" id="path9231"/>
<rect id="US_main_black2" data-name="US main black2" x="22.57" y="1.49" width="43.38" height="31.25" style="fill: #242424"/> </clipPath>
<rect id="US_main_black1" data-name="US main black1" x="30.16" y="8.47" width="25.33" height="17.59"/> <linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-2.66153 2.43973 -2.43973 -2.66153 745.59473 1006.9893)" id="linearGradient9243">
<g id="US_eye1" data-name="US eye1"> <stop offset="0" id="stop9239" stop-color="#f2f2f2"/>
<g id="US_eye1_black" data-name="US eye1 black"> <stop offset="1" id="stop9241" stop-color="#7a7a7a"/>
<circle cx="17.57" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/> </linearGradient>
<circle cx="17.57" cy="17.57" r="17.32" style="fill: none"/> </defs>
</g> <g id="layer1" transform="translate(0 -287.82875)">
<circle id="US_eye1_red" data-name="US eye1 red" cx="17.57" cy="17.57" r="10.77" style="fill: #ab1919"/> <g id="g10128" transform="translate(-62.249591 173.06003) scale(.74516)">
<circle id="US_eye1_gold_circle" data-name="US eye1 gold circle" cx="17.57" cy="17.57" r="8.04" style="fill: #aa7707"/> <path id="path9195" d="M92.414417 162.9553h13.538203v2.51495H92.414417z" fill="#1f1f1f" stroke-width=".352778"/>
<circle id="US_eye1_wh_in_gold" data-name="US eye1 wh in gold" cx="17.57" cy="17.57" r="6.98" style="fill: #f1f1f1"/> <g id="g9197" transform="matrix(.35278 0 0 -.35278 -164.0649 511.69022)">
<g id="US_eye1_net" data-name="US eye1 net"> <g clip-path="url(#clipPath9203)" id="g9199">
<g style="clip-path: url(#clip-path)"> <g transform="translate(719.4443 1013.8715)" id="g9205">
<g id="US_eye1_net_mask" data-name="US eye1 net mask"> <path id="path9207" d="M0 0h48.387c9.634.073 17.503-7.678 17.575-17.312.073-9.633-7.678-17.502-17.312-17.575-.087-.001-.175-.001-.263 0h-5.716l-7.482 6.977H13.803l-6.827-6.977H0c-9.634-.073-17.503 7.678-17.576 17.311C-17.648-7.942-9.898-.073-.265 0H0"/>
<g id="US_eye1_net_total" data-name="US eye1 net total"> </g>
<rect id="US_eye1_net14" data-name="US eye1 net14" x="10.84" y="33.53" width="0.61" height="22.79" transform="translate(-20.93 -10.84) rotate(-30)" style="fill: #aa7707"/> <g id="g9209">
<rect id="US_eye1_net13" data-name="US eye1 net13" x="11.8" y="47.44" width="22.51" height="0.61" transform="translate(-20.75 -4.51) rotate(-30)" style="fill: #aa7707"/> <g id="g9221">
<rect id="US_eye1_net12" data-name="US eye1 net12" x="13.33" y="32.09" width="0.61" height="22.79" transform="translate(-19.88 -9.79) rotate(-30)" style="fill: #aa7707"/> <g id="g9219" clip-path="url(#clipPath9215)" opacity=".057999">
<rect id="US_eye1_net11" data-name="US eye1 net11" x="10.36" y="44.95" width="22.51" height="0.61" transform="translate(-19.7 -5.56) rotate(-30)" style="fill: #aa7707"/> <path id="path9217" d="M737.191 1004.922h12.59v-18.961h-12.59z" fill="#fff"/>
<rect id="US_eye1_net10" data-name="US eye1 net10" x="15.83" y="30.65" width="0.61" height="22.79" transform="translate(-18.82 -8.73) rotate(-30)" style="fill: #aa7707"/> </g>
<rect id="US_eye1_net9" data-name="US eye1 net9" x="8.92" y="42.45" width="22.51" height="0.61" transform="translate(-18.64 -6.62) rotate(-30)" style="fill: #aa7707"/> </g>
<rect id="US_eye1_net8" data-name="US eye1 net8" x="18.33" y="29.21" width="0.61" height="22.79" transform="translate(-17.77 -7.68) rotate(-30)" style="fill: #aa7707"/> </g>
<rect id="US_eye1_net7" data-name="US eye1 net7" x="7.47" y="39.96" width="22.51" height="0.61" transform="translate(-17.59 -7.67) rotate(-30)" style="fill: #aa7707"/> <g transform="translate(728.0898 1013.8715)" id="g9223">
<rect id="US_eye1_net6" data-name="US eye1 net6" x="20.82" y="27.77" width="0.61" height="22.79" transform="translate(-16.72 -6.62) rotate(-30)" style="fill: #aa7707"/> <path id="path9225" d="M0 0h31.101v-1.288L21.7-10.315H9.101L0-1.288z" fill="#1f1f1f"/>
<rect id="US_eye1_net5" data-name="US eye1 net5" x="6.03" y="37.46" width="22.51" height="0.61" transform="translate(-16.53 -8.73) rotate(-30)" style="fill: #aa7707"/> </g>
<rect id="US_eye1_net4" data-name="US eye1 net4" x="23.32" y="26.32" width="0.61" height="22.79" transform="translate(-15.66 -5.57) rotate(-30)" style="fill: #aa7707"/> <g id="g9227">
<rect id="US_eye1_net3" data-name="US eye1 net3" x="4.59" y="34.96" width="22.51" height="0.61" transform="translate(-15.48 -9.78) rotate(-30)" style="fill: #aa7707"/> <g id="g9257">
<rect id="US_eye1_net2" data-name="US eye1 net2" x="25.81" y="24.88" width="0.61" height="22.79" transform="translate(-14.61 -4.51) rotate(-30)" style="fill: #aa7707"/> <g id="g9255" clip-path="url(#clipPath9233)" opacity=".261002">
<rect id="US_eye1_net1" data-name="US eye1 net1" x="3.15" y="32.47" width="22.51" height="0.61" transform="translate(-14.42 -10.84) rotate(-30)" style="fill: #aa7707"/> <g id="g9253">
<g id="g9251">
<g id="g9249">
<g id="g9247">
<path id="path9245" d="M743.714 1011.292c1.425 0 2.579-1.154 2.579-2.579 0-1.424-1.154-2.579-2.579-2.579-1.424 0-2.579 1.155-2.579 2.579 0 1.425 1.155 2.579 2.579 2.579" fill="url(#linearGradient9243)"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
<g transform="translate(709.8887 997.7933)" id="g9259">
<path id="path9261" d="M0 0h14.106l2.275-2.427h-4.248L10.616-.759H0z" fill="#d52715"/>
</g>
<g transform="translate(777.5391 997.7933)" id="g9263">
<path id="path9265" d="M0 0h-14.106l-2.275-2.427h4.246l1.518 1.668H.001z" fill="#d52715"/>
</g> </g>
</g> </g>
</g> </g>
</g> </g>
</g> </g>
<g id="US_eye2" data-name="US eye2"> </svg>
<g id="US_eye2_black" data-name="US eye2 black"> `;
<circle cx="65.96" cy="17.57" r="17.44" style="stroke: #b3b3b3;stroke-miterlimit: 10;stroke-width: 0.25px"/>
<circle cx="65.96" cy="17.57" r="17.32" style="fill: none"/>
</g>
<circle id="US_eye2_red" data-name="US eye2 red" cx="65.96" cy="17.57" r="10.77" style="fill: #ab1919"/>
<circle id="US_eye2_gold_circle" data-name="US eye2 gold circle" cx="65.96" cy="17.57" r="8.04" style="fill: #aa7707"/>
<circle id="US_eye2_wh_in_gold" data-name="US eye2 wh in gold" cx="65.96" cy="17.57" r="6.98" style="fill: #f1f1f1"/>
<g id="US_eye2_net" data-name="US eye2 net">
<g style="clip-path: url(#clip-path-2)">
<g id="US_eye2_net_mask" data-name="US eye2 net mask">
<g id="US_eye2_net_total" data-name="US eye2 net total">
<rect id="US_eye2_net14" data-name="US eye2 net14" x="59.23" y="33.53" width="0.61" height="22.79" transform="translate(-14.45 13.35) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net13" data-name="US eye2 net13" x="60.18" y="47.44" width="22.51" height="0.61" transform="translate(-14.27 19.69) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net12" data-name="US eye2 net12" x="61.72" y="32.09" width="0.61" height="22.79" transform="translate(-13.4 14.41) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net11" data-name="US eye2 net11" x="58.74" y="44.95" width="22.51" height="0.61" transform="translate(-13.21 18.63) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net10" data-name="US eye2 net10" x="64.22" y="30.65" width="0.61" height="22.79" transform="translate(-12.34 15.46) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net9" data-name="US eye2 net9" x="57.3" y="42.45" width="22.51" height="0.61" transform="translate(-12.16 17.58) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net8" data-name="US eye2 net8" x="66.71" y="29.21" width="0.61" height="22.79" transform="translate(-11.29 16.52) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net7" data-name="US eye2 net7" x="55.86" y="39.96" width="22.51" height="0.61" transform="translate(-11.1 16.52) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net6" data-name="US eye2 net6" x="69.21" y="27.77" width="0.61" height="22.79" transform="translate(-10.23 17.57) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net5" data-name="US eye2 net5" x="54.42" y="37.46" width="22.51" height="0.61" transform="translate(-10.05 15.47) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net4" data-name="US eye2 net4" x="71.71" y="26.32" width="0.61" height="22.79" transform="translate(-9.18 18.63) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net3" data-name="US eye2 net3" x="52.98" y="34.96" width="22.51" height="0.61" transform="translate(-8.99 14.41) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net2" data-name="US eye2 net2" x="74.2" y="24.88" width="0.61" height="22.79" transform="translate(-8.12 19.68) rotate(-30)" style="fill: #aa7707"/>
<rect id="US_eye2_net1" data-name="US eye2 net1" x="51.54" y="32.47" width="22.51" height="0.61" transform="translate(-7.94 13.36) rotate(-30)" style="fill: #aa7707"/>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>`;
} }

View File

@ -0,0 +1,96 @@
<svg xmlns="http://www.w3.org/2000/svg" width="80" height="123.773" viewBox="0 0 21.166666 32.748275" id="svg10208">
<defs id="defs10202">
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.30835 7.23512 0 1161.6036 852.6532)" id="linearGradient9407">
<stop offset="0" id="stop9403" stop-color="#a9aba9"/>
<stop offset="1" id="stop9405" stop-color="#848484"/>
</linearGradient>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 2.61718 -8.4555 0 1161.6036 932.34937)" id="linearGradient9387">
<stop offset="0" id="stop9383" stop-color="#303030"/>
<stop offset="1" id="stop9385" stop-color="#777"/>
</linearGradient>
<clipPath id="clipPath9357">
<path d="M0 1145.871h1366V0H0z" id="path9355"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="rotate(124.418 344.320607 757.342015) scale(10.33459)" id="linearGradient9347">
<stop offset="0" id="stop9343" stop-color="#fff"/>
<stop offset="1" id="stop9345" stop-color="#9e9e9e"/>
</linearGradient>
<clipPath id="clipPath9305">
<path d="M0 1145.871h1366V0H0z" id="path9303"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -5.71338 10.23004 0 1161.4999 872.46655)" id="linearGradient9295">
<stop offset="0" id="stop9291" stop-color="#f2f2f2"/>
<stop offset="1" id="stop9293" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath9273">
<path d="M0 1145.871h1366V0H0z" id="path9271"/>
</clipPath>
</defs>
<g id="layer1" transform="translate(0 -264.2517)">
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9267">
<g id="g9269" clip-path="url(#clipPath9273)">
<g id="g9275" transform="translate(1188.0205 889.5135)">
<path d="M0 0h-53.041c-.541 0-.98.254-.98.566v29.585c0 .313.439.566.98.566H0c.541 0 .979-.253.979-.566V.566C.979.254.541 0 0 0" id="path9277" fill="#f2f2f2"/>
</g>
</g>
</g>
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9279">
<g id="g9281">
<g id="g9287">
<g id="g9289">
<path d="M1134.979 898.024c-.541 0-.979-.254-.979-.567v-29.584c0-.313.438-.567.979-.567h53.042c.541 0 .979.254.979.567v29.584c0 .313-.438.567-.979.567z" id="path9297" fill="url(#linearGradient9295)"/>
</g>
</g>
</g>
</g>
<path d="M19.009995 291.64843H2.236527v-22.20479h16.773468z" id="path9307" fill="#f2f2f2" stroke-width=".384845"/>
<g id="g9309" transform="matrix(.38484 0 0 -.38484 11.821398 288.69324)">
<path d="M0 0h-6.642c-.687 0-1.245.558-1.245 1.246v12.867c0 .688.558 1.246 1.245 1.246H0c.687 0 1.245-.558 1.245-1.246V1.246C1.245.558.687 0 0 0" id="path9311" fill="#f22a21"/>
</g>
<path d="M6.251333 274.21366c-.838192 0-1.517581.67957-1.517581 1.51814v3.53633h3.083082v-3.53633c0-.83857-.67939-1.51814-1.517582-1.51814z" id="topleft" fill="#a9aba9" stroke-width=".384845"/>
<path d="M4.733752 281.18484v3.72518c0 .8378.679389 1.51702 1.517581 1.51702h.04792c.838192 0 1.51758-.67922 1.51758-1.51702v-3.72518z" id="bottomleft" fill="#a9aba9" stroke-width=".384845"/>
<g id="g9327" transform="matrix(.38484 0 0 -.38484 7.497511 280.74023)">
<path d="M0 0h-6.352c-.229 0-.415.186-.415.416v1.717c0 .229.186.415.415.415H0c.229 0 .415-.186.415-.415V.416C.415.186.229 0 0 0" id="path9329" fill="#f22a21"/>
</g>
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9331">
<g id="g9333">
<g id="g9339">
<g id="g9341">
<path d="M1157.731 904.68c0-2.042 1.655-3.697 3.696-3.697 2.043 0 3.698 1.655 3.698 3.697 0 2.041-1.655 3.697-3.698 3.697-2.041 0-3.696-1.656-3.696-3.697" id="path9349" fill="url(#linearGradient9347)"/>
</g>
</g>
</g>
</g>
<g id="g9359" transform="matrix(.38484 0 0 -.38484 10.555605 276.77113)">
<path d="M0 0c-1.239 0-2.244 1.004-2.244 2.244 0 1.239 1.005 2.244 2.244 2.244 1.24 0 2.244-1.005 2.244-2.244C2.244 1.004 1.24 0 0 0" id="path9361" fill="#f22a21"/>
</g>
<g id="centerbeacon" transform="matrix(.38484 0 0 -.38484 15.001642 273.1773)">
<path d="M0 0h-23.265l-3.683 4.151v6.736H3.684V4.151z" id="path9365" fill="#a9aba9"/>
</g>
<path d="M12.061234 283.61556H9.025961v-.47952h3.035273z" id="path9367" fill="#b42e29" stroke-width=".384845"/>
<path d="M12.061234 284.49416H9.025961v-.47913h3.035273z" id="path9369" fill="#b42e29" stroke-width=".384845"/>
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9371">
<g id="g9373">
<g id="g9379">
<g id="g9381">
<path d="M1140.849 934.967c-.573 0-1.038-.466-1.038-1.039v-12.452h43.585v12.452c0 .573-.465 1.039-1.037 1.039z" id="path9389" fill="url(#linearGradient9387)"/>
</g>
</g>
</g>
</g>
<g transform="matrix(.38484 0 0 -.38484 -436.41402 624.06906)" id="g9391">
<g id="g9393">
<g id="g9399">
<g id="g9401">
<path d="M1139.811 863.778v-12.453c0-.803.651-1.453 1.453-1.453h40.679c.803 0 1.453.65 1.453 1.453v12.453z" id="path9409" fill="url(#linearGradient9407)"/>
</g>
</g>
</g>
</g>
<path d="M14.877744 274.21376c-.838192 0-1.517581.67957-1.517581 1.51815v3.53632h3.083082v-3.53632c0-.83858-.679389-1.51815-1.517582-1.51815z" id="topright" fill="#a9aba9" stroke-width=".384845"/>
<path d="M13.360163 281.18494v3.72518c0 .83781.679389 1.51702 1.517581 1.51702h.04792c.838192 0 1.517581-.67921 1.517581-1.51702v-3.72518z" id="bottomright" fill="#a9aba9" stroke-width=".384845"/>
<g id="g9323" transform="matrix(.38484 0 0 -.38484 16.12385 280.74023)">
<path d="M0 0h-6.352c-.228 0-.415.186-.415.416v1.717c0 .229.187.415.415.415H0c.229 0 .415-.186.415-.415V.416C.415.186.229 0 0 0" id="path9325" fill="#006db4"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -231,9 +231,11 @@ namespace pxsim.visuals {
break; break;
} }
case NodeType.InfraredSensor: { case NodeType.InfraredSensor: {
const state = ev3board().getInputNodes()[0] as InfraredSensorNode; const state = ev3board().getInputNodes()[port] as InfraredSensorNode;
if (state.getMode() == InfraredSensorMode.Proximity) if (state.getMode() == InfraredSensorMode.Proximity)
view = new ProximitySliderControl(this.element, this.defs, state, port); view = new ProximitySliderControl(this.element, this.defs, state, port);
else if (state.getMode() == InfraredSensorMode.RemoteControl)
view = new RemoteBeaconButtonsControl(this.element, this.defs, state, port);
break; break;
} }
case NodeType.GyroSensor: { case NodeType.GyroSensor: {

View File

@ -1,64 +1,33 @@
namespace pxsim.visuals { namespace pxsim.visuals {
export class ColorWheelControl extends ControlView<ColorSensorNode> { export class ColorWheelControl extends ControlView<ColorSensorNode> {
private group: SVGGElement; private group: SVGGElement;
private colorGradient: SVGLinearGradientElement; private colorGradient: SVGLinearGradientElement;
private defs: SVGDefsElement; private reporter: SVGTextElement;
private rect: SVGElement;
getInnerView(parent: SVGSVGElement) {
this.defs = <SVGDefsElement>svg.child(this.element, "defs", {});
this.group = svg.elt("g") as SVGGElement;
this.group.setAttribute("transform", `translate(12, 0) scale(2)`)
let gc = "gradient-color";
this.colorGradient = svg.linearGradient(this.defs, gc, true);
svg.setGradientValue(this.colorGradient, "50%");
svg.setGradientColors(this.colorGradient, "black", "white");
const circle = pxsim.svg.child(this.group, "g");
const innerCircle = pxsim.svg.child(circle, "circle",
{cursor: '-webkit-grab',
fill: `url(#${gc})`,
r: 17,
cx: 13,
cy: 20,
stroke: 'black',
'stroke-width': 2
});
let pt = parent.createSVGPoint();
let captured = false;
touchEvents(circle,
ev => {
if (captured && (ev as MouseEvent).clientX) {
ev.preventDefault();
this.setColor(pt, parent, ev as MouseEvent);
}
},
ev => {
captured = true;
if ((ev as MouseEvent).clientX) {
this.setColor(pt, parent, ev as MouseEvent);
}
},
ev => {
captured = false;
},
ev => {
captured = false;
}
)
return this.group;
}
getInnerWidth() { getInnerWidth() {
return CONTROL_WIDTH; return 111;
} }
getInnerHeight() { getInnerHeight() {
return CONTROL_WIDTH; return 192;
}
private getReporterHeight() {
return 58;
}
private getSliderWidth() {
return 62;
}
private getSliderHeight() {
return 111;
}
private getMax() {
return 100;
} }
updateState() { updateState() {
@ -67,16 +36,68 @@ namespace pxsim.visuals {
} }
const node = this.state; const node = this.state;
const percentage = node.getValue(); const percentage = node.getValue();
svg.setGradientValue(this.colorGradient, percentage + "%"); const inversePercentage = this.getMax() - percentage;
svg.setGradientValue(this.colorGradient, inversePercentage + "%");
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}`;
} }
private setColor(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) { updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
const width = CONTROL_WIDTH;
let cur = svg.cursorPoint(pt, parent, ev); let cur = svg.cursorPoint(pt, parent, ev);
let t = Math.max(0, Math.min(1, (width + this.left / this.scaleFactor - cur.x / this.scaleFactor) / width)); const bBox = this.rect.getBoundingClientRect();
const height = bBox.height;
let t = Math.max(0, Math.min(1, (height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height));
const state = this.state; const state = this.state;
state.setColor((1-t)*100); state.setColor(t * this.getMax());
}
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
this.group = svg.elt("g") as SVGGElement;
let gc = "gradient-color";
this.colorGradient = svg.linearGradient(globalDefs, gc, false);
svg.setGradientValue(this.colorGradient, "50%");
svg.setGradientColors(this.colorGradient, "black", "yellow");
const reporterGroup = pxsim.svg.child(this.group, "g");
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 50)`);
this.reporter = pxsim.svg.child(reporterGroup, "text", { 'text-anchor': 'middle', 'x': 0, 'y': '0', 'class': 'sim-text number large inverted' }) as SVGTextElement;
const sliderGroup = pxsim.svg.child(this.group, "g");
sliderGroup.setAttribute("transform", `translate(${this.getWidth() / 2 - this.getSliderWidth() / 2}, ${this.getReporterHeight()})`);
const rect = pxsim.svg.child(sliderGroup, "rect",
{
"x": 0,
"y": 0,
"width": this.getSliderWidth(),
"height": this.getSliderHeight(),
"style": `fill: url(#${gc})`
}
)
this.rect = rect;
let pt = parent.createSVGPoint();
let captured = false;
touchEvents(rect, ev => {
if (captured && (ev as MouseEvent).clientY) {
ev.preventDefault();
this.updateColorLevel(pt, parent, ev as MouseEvent);
}
}, ev => {
captured = true;
if ((ev as MouseEvent).clientY) {
rect.setAttribute('cursor', '-webkit-grabbing');
this.updateColorLevel(pt, parent, ev as MouseEvent);
}
}, () => {
captured = false;
rect.setAttribute('cursor', '-webkit-grab');
}, () => {
captured = false;
rect.setAttribute('cursor', '-webkit-grab');
})
return this.group;
} }
} }
} }

View File

@ -0,0 +1,57 @@
namespace pxsim.visuals {
enum InfraredRemoteButton {
CenterBeacon = 0x01,
TopLeft = 0x02,
BottomLeft = 0x04,
TopRight = 0x08,
BottomRight = 0x10,
}
export class RemoteBeaconButtonsControl extends ControlView<InfraredSensorNode> {
private group: SVGGElement;
private id = Math.random().toString();
getInnerView() {
this.group = svg.elt("g") as SVGGElement;
this.group.setAttribute("transform", `scale(0.9, 0.9)`)
const xml = pxsim.visuals.normalizeXml(this.id, pxsim.visuals.REMOVE_SVG);
const content = svg.parseString(xml);
this.group.appendChild(content);
const btns: Map<InfraredRemoteButton> = {
"centerbeacon": InfraredRemoteButton.CenterBeacon,
"topleft": InfraredRemoteButton.TopLeft,
"topright": InfraredRemoteButton.TopRight,
"bottomleft": InfraredRemoteButton.BottomLeft,
"bottomright": InfraredRemoteButton.BottomRight
}
Object.keys(btns).forEach(bid => {
const cid = btns[bid];
const bel = content.getElementById(pxsim.visuals.normalizeId(this.id, bid));
bel.setAttribute("class", "sim-button");
pointerEvents.down.forEach(evid => bel.addEventListener(evid, ev => {
ev3board().remoteState.setPressed(cid, true);
}));
bel.addEventListener(pointerEvents.leave, ev => {
ev3board().remoteState.setPressed(cid, false);
});
bel.addEventListener(pointerEvents.up, ev => {
ev3board().remoteState.setPressed(cid, false);
});
});
return this.group;
}
getInnerWidth() {
return 80;
}
getInnerHeight() {
return 123.773;
}
}
}

View File

@ -1,4 +1,20 @@
namespace pxsim.visuals { namespace pxsim.visuals {
export function normalizeId(prefix: string, svgId: string) {
return `${prefix}-${svgId}`;
}
export function normalizeXml(prefix: string, xml: string): string {
xml = xml.replace(/id=\"(.*?)\"/g, (m: string, id: string) => {
return `id="${normalizeId(prefix, id)}"`;
});
xml = xml.replace(/url\(#(.*?)\)/g, (m: string, id: string) => {
return `url(#${normalizeId(prefix, id)})`;
});
xml = xml.replace(/xlink:href=\"#(.*?)\"/g, (m: string, id: string) => {
return `xlink:href="#${normalizeId(prefix, id)}"`;
});
return xml;
}
export class ModuleView extends View implements LayoutElement { export class ModuleView extends View implements LayoutElement {
protected content: SVGSVGElement; protected content: SVGSVGElement;
@ -9,21 +25,11 @@ namespace pxsim.visuals {
constructor(protected xml: string, protected prefix: string, protected id: NodeType, protected port: NodeType) { constructor(protected xml: string, protected prefix: string, protected id: NodeType, protected port: NodeType) {
super(); super();
this.xml = this.normalizeXml(xml); this.xml = normalizeXml(this.prefix, xml);
} }
private normalizeXml(xml: string) { private normalizeXml(xml: string) {
const prefix = this.prefix; return pxsim.visuals.normalizeXml(this.prefix, xml);
xml = xml.replace(/id=\"(.*?)\"/g, (m: string, id: string) => {
return `id="${this.normalizeId(id)}"`;
});
xml = xml.replace(/url\(#(.*?)\)/g, (m: string, id: string) => {
return `url(#${this.normalizeId(id)})`;
});
xml = xml.replace(/xlink:href=\"#(.*?)\"/g, (m: string, id: string) => {
return `xlink:href="#${this.normalizeId(id)}"`;
});
return xml;
} }
protected normalizeId(svgId: string) { protected normalizeId(svgId: string) {

View File

@ -5,7 +5,7 @@ tests.test("lgB set speed 10", () => {
tests.assertClose("speedB", 10, motors.largeB.speed(), 2) tests.assertClose("speedB", 10, motors.largeB.speed(), 2)
}); });
tests.test("lgB set speed 25 (reversed)", () => { tests.test("lgB set speed 25 (reversed)", () => {
motors.largeB.setReversed(true) motors.largeB.setInverted(true)
motors.largeB.setSpeed(25) motors.largeB.setSpeed(25)
loops.pause(500) loops.pause(500)
tests.assertClose("speedB", -25, motors.largeB.speed(), 2) tests.assertClose("speedB", -25, motors.largeB.speed(), 2)