Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
653d8f6f5c | |||
ac0a9f0710 | |||
2cce2a39b8 | |||
a337403afa | |||
fd9d118fa4 | |||
e94ac6f6f1 | |||
88c58b4e76 | |||
e2eb5f35af | |||
71fe612ced | |||
e58ec06e91 | |||
538493369b | |||
56dd8e0875 | |||
1f7ef637b2 | |||
f4f2e0ba0e | |||
22c31c57df | |||
6879961297 | |||
69fcb7407a | |||
4dfada877c | |||
b10b636766 | |||
ba47fb0589 | |||
f36e14fe69 | |||
8bab919db2 | |||
89a82b54dc | |||
15ee6ebe9c | |||
9bf50665fc | |||
f594cdefac | |||
5ce7a83f5d | |||
d7ef7c353c | |||
c7cb300cd9 | |||
4e194536d3 | |||
570cd7474f | |||
9ea5597734 | |||
2c0cc6a3d7 | |||
08f79c5a1a | |||
f817912e07 |
@ -48,10 +48,23 @@
|
||||
* [show mood](/reference/brick/show-mood)
|
||||
* [show image](/reference/brick/show-image)
|
||||
* [clear screen](/reference/brick/clear-screen)
|
||||
* [print ports](/reference/brick/print-ports)
|
||||
* [on event](/reference/brick/button/on-event)
|
||||
* [is pressed](/reference/brick/button/is-pressed)
|
||||
* [was pressed](/reference/brick/button/was-pressed)
|
||||
* [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)
|
||||
* [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)
|
||||
|
@ -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.
|
||||
|
||||
## [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
|
||||
so it appears as a mounted drive (named **EV3**).
|
||||
|
@ -6,7 +6,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, function () {
|
||||
sensors.touch1.pauseUntil(ButtonEvent.Pressed)
|
||||
motors.largeBC.setSpeed(0)
|
||||
loops.pause(1000)
|
||||
brick.setLight(BrickLight.OrangeFlash)
|
||||
brick.setStatusLight(StatusLight.OrangeFlash)
|
||||
motors.largeBC.setSpeed(-50)
|
||||
loops.pause(2000)
|
||||
motors.largeBC.setSpeed(0)
|
||||
|
@ -7,7 +7,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, function () {
|
||||
sensors.touch2.pauseUntil(ButtonEvent.Pressed)
|
||||
motors.largeBC.setSpeed(0)
|
||||
loops.pause(1000)
|
||||
brick.setLight(BrickLight.OrangeFlash)
|
||||
brick.setStatusLight(StatusLight.OrangeFlash)
|
||||
motors.largeBC.setSpeed(-50)
|
||||
loops.pause(2000)
|
||||
motors.largeBC.setSpeed(0)
|
||||
|
@ -10,7 +10,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, function () {
|
||||
brick.showImage(images.eyesTiredMiddle)
|
||||
motors.largeBC.setSpeed(0)
|
||||
loops.pause(1000)
|
||||
brick.setLight(BrickLight.OrangeFlash)
|
||||
brick.setStatusLight(StatusLight.OrangeFlash)
|
||||
brick.showImage(images.eyesDizzy)
|
||||
motors.largeBC.setSpeed(-50)
|
||||
loops.pause(2000)
|
||||
|
@ -146,11 +146,11 @@ loops.forever(function () {
|
||||
}
|
||||
motors.stopAllMotors()
|
||||
st = 0;
|
||||
brick.setLight(BrickLight.RedPulse);
|
||||
brick.setStatusLight(StatusLight.RedPulse);
|
||||
brick.showImage(images.eyesKnockedOut)
|
||||
music.playSoundEffect(sounds.movementsSpeedDown)
|
||||
sensors.touch3.pauseUntil(ButtonEvent.Pressed)
|
||||
brick.setLight(BrickLight.Off);
|
||||
brick.setStatusLight(StatusLight.Off);
|
||||
})
|
||||
|
||||
// BHV
|
||||
|
@ -29,7 +29,7 @@ function DN() {
|
||||
function MNRH() {
|
||||
motors.mediumC.setBrake(true)
|
||||
brick.showImage(images.legoEv3icon)
|
||||
brick.setLight(BrickLight.OrangePulse)
|
||||
brick.setStatusLight(StatusLight.OrangePulse)
|
||||
while (!brick.buttonEnter.wasPressed()) {
|
||||
if (brick.buttonUp.wasPressed()) {
|
||||
motors.mediumC.setSpeed(-100);
|
||||
@ -41,7 +41,7 @@ function MNRH() {
|
||||
}
|
||||
motors.mediumC.stop();
|
||||
motors.mediumC.clearCounts();
|
||||
brick.setLight(BrickLight.Green);
|
||||
brick.setStatusLight(StatusLight.Green);
|
||||
}
|
||||
|
||||
function IS(t: number) {
|
||||
|
@ -20,9 +20,9 @@ INI()
|
||||
let down = false;
|
||||
loops.forever(function () {
|
||||
brick.showImage(images.informationQuestionMark)
|
||||
brick.setLight(BrickLight.OrangePulse);
|
||||
brick.setStatusLight(StatusLight.OrangePulse);
|
||||
pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed())
|
||||
brick.setLight(BrickLight.Off)
|
||||
brick.setStatusLight(StatusLight.Off)
|
||||
music.playSoundEffect(sounds.mechanicalAirRelease)
|
||||
brick.showImage(images.informationAccept)
|
||||
if (down) {
|
||||
|
@ -20,9 +20,9 @@ INI()
|
||||
let down = false;
|
||||
loops.forever(function () {
|
||||
brick.showImage(images.informationQuestionMark)
|
||||
brick.setLight(BrickLight.OrangePulse);
|
||||
brick.setStatusLight(StatusLight.OrangePulse);
|
||||
pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed())
|
||||
brick.setLight(BrickLight.Off)
|
||||
brick.setStatusLight(StatusLight.Off)
|
||||
music.playSoundEffect(sounds.mechanicalAirRelease)
|
||||
brick.showImage(images.informationAccept)
|
||||
if (down) {
|
||||
|
@ -146,11 +146,11 @@ loops.forever(function () {
|
||||
}
|
||||
motors.stopAllMotors()
|
||||
st = 0;
|
||||
brick.setLight(BrickLight.RedPulse);
|
||||
brick.setStatusLight(StatusLight.RedPulse);
|
||||
brick.showImage(images.eyesKnockedOut)
|
||||
music.playSoundEffect(sounds.movementsSpeedDown)
|
||||
sensors.touch3.pauseUntil(ButtonEvent.Pressed)
|
||||
brick.setLight(BrickLight.Off);
|
||||
brick.setStatusLight(StatusLight.Off);
|
||||
})
|
||||
|
||||
// BHV
|
||||
|
251
docs/labview.md
Normal 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.
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||
|
||||
```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.
|
||||
|
||||

|
||||
|
||||
```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.
|
||||
|
||||

|
||||
|
||||
```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.
|
||||
|
||||

|
||||
|
||||
```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.
|
||||
|
||||

|
||||
|
||||
```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``.
|
||||
|
||||

|
||||
|
||||
```blocks
|
||||
motors.largeA.setRegulated(false);
|
||||
```
|
||||
|
||||
## Brick
|
||||
|
||||
The brick category contains a number of blocks to display graphics on the brick screen.
|
||||
|
||||

|
||||
|
||||
```blocks
|
||||
brick.clearScreen()
|
||||
brick.showImage(images.expressionsWink)
|
||||
```
|
||||
|
||||

|
||||
|
||||
```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.
|
||||
|
||||

|
||||
|
||||
```blocks
|
||||
motors.largeD.setSpeed(50)
|
||||
loops.pause(1000)
|
||||
motors.largeD.stop();
|
||||
```
|
||||
|
||||

|
||||
|
||||
```blocks
|
||||
motors.largeD.setSpeed(50)
|
||||
sensors.touch1.pauseUntil(ButtonEvent.Pressed)
|
||||
motors.largeD.stop();
|
||||
```
|
||||
|
||||

|
||||
|
||||
```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
|
||||
|
||||

|
||||
|
||||
```blocks
|
||||
loops.forever(() => {
|
||||
motors.largeD.setSpeed(50, 1, MoveUnit.Rotations);
|
||||
motors.largeD.setSpeed(-50, 1, MoveUnit.Rotations);
|
||||
})
|
||||
```
|
||||
|
||||

|
||||
|
||||
```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
|
||||
|
||||

|
||||
|
||||
```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.
|
||||
|
||||

|
||||
|
||||
```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.
|
||||
|
||||

|
||||
|
||||
```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.
|
||||
|
||||

|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
motors.largeBC.steer(Math.randomRange(-5, 5), 50)
|
||||
loops.pause(100)
|
||||
})
|
||||
```
|
@ -2,10 +2,12 @@
|
||||
|
||||
```namespaces
|
||||
brick.showMood(moods.sleeping);
|
||||
motors.stopAllMotors()
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
[brick](/reference/brick),
|
||||
[motors](/reference/motors),
|
||||
[touch sensor](/reference/sensors/touch-sensor),
|
||||
[color sensor](/reference/sensors/color-sensor)
|
@ -20,7 +20,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, function () {
|
||||
brick.buttonEnter.pauseUntil(ButtonEvent.Bumped);
|
||||
brick.buttonEnter.isPressed()
|
||||
brick.buttonEnter.wasPressed()
|
||||
brick.setLight(BrickLight.Red);
|
||||
brick.setStatusLight(StatusLight.Red);
|
||||
```
|
||||
|
||||
## Other
|
||||
|
@ -22,11 +22,11 @@ loops.forever(function() {
|
||||
battery = brick.batteryLevel();
|
||||
if (battery > 15)
|
||||
{
|
||||
brick.setLight(BrickLight.Green);
|
||||
brick.setStatusLight(StatusLight.Green);
|
||||
} else if (battery > 5) {
|
||||
brick.setLight(BrickLight.Orange);
|
||||
brick.setStatusLight(StatusLight.Orange);
|
||||
} else {
|
||||
brick.setLight(BrickLight.RedPulse)
|
||||
brick.setStatusLight(StatusLight.RedPulse)
|
||||
}
|
||||
loops.pause(30000)
|
||||
})
|
||||
|
@ -34,11 +34,11 @@ Set the brick light to green when the `down` is pressed. When the button is not
|
||||
let isRed = false;
|
||||
loops.forever(function() {
|
||||
if (brick.buttonLeft.isPressed()) {
|
||||
brick.setLight(BrickLight.Green);
|
||||
brick.setStatusLight(StatusLight.Green);
|
||||
isRed = false;
|
||||
} else {
|
||||
if (!isRed) {
|
||||
brick.setLight(BrickLight.Red);
|
||||
brick.setStatusLight(StatusLight.Red);
|
||||
isRed = true;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ Your @boardname@ has touch sensors that work like buttons. Instead of saying `en
|
||||
|
||||
```block
|
||||
sensors.touch1.onEvent(ButtonEvent.Pressed, function () {
|
||||
brick.setLight(BrickLight.Orange);
|
||||
brick.setStatusLight(StatusLight.Orange);
|
||||
});
|
||||
```
|
||||
|
||||
|
@ -35,9 +35,9 @@ Set the brick light to green if the `right` button was pressed before the `left`
|
||||
```blocks
|
||||
brick.buttonLeft.onEvent(ButtonEvent.Bumped, function() {
|
||||
if (brick.buttonRight.wasPressed()) {
|
||||
brick.setLight(BrickLight.Green)
|
||||
brick.setStatusLight(StatusLight.Green)
|
||||
} else {
|
||||
brick.setLight(BrickLight.Off)
|
||||
brick.setStatusLight(StatusLight.Off)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
@ -3,7 +3,7 @@
|
||||
Set the light on the brick to a solid or flashing color.
|
||||
|
||||
```sig
|
||||
brick.setLight(BrickLight.Red);
|
||||
brick.setStatusLight(StatusLight.Red);
|
||||
```
|
||||
## Parameters
|
||||
|
||||
@ -25,13 +25,13 @@ Repeatedly show a different color pattern for the brick light.
|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
brick.setLight(BrickLight.Orange)
|
||||
brick.setStatusLight(StatusLight.Orange)
|
||||
loops.pause(1000)
|
||||
brick.setLight(BrickLight.GreenFlash)
|
||||
brick.setStatusLight(StatusLight.GreenFlash)
|
||||
loops.pause(2000)
|
||||
brick.setLight(BrickLight.RedPulse)
|
||||
brick.setStatusLight(StatusLight.RedPulse)
|
||||
loops.pause(2000)
|
||||
brick.setLight(BrickLight.Off)
|
||||
brick.setStatusLight(StatusLight.Off)
|
||||
loops.pause(500)
|
||||
})
|
||||
```
|
24
docs/reference/motors.md
Normal 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()
|
||||
```
|
31
docs/reference/motors/motor/angle.md
Normal 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)
|
35
docs/reference/motors/motor/clear-counts.md
Normal 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)
|
30
docs/reference/motors/motor/reset.md
Normal 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)
|
30
docs/reference/motors/motor/set-brake.md
Normal 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)
|
32
docs/reference/motors/motor/set-inverted.md
Normal 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)
|
32
docs/reference/motors/motor/set-regulated.md
Normal 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)
|
96
docs/reference/motors/motor/set-speed.md
Normal 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)
|
33
docs/reference/motors/motor/speed.md
Normal 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)
|
25
docs/reference/motors/motor/stop.md
Normal 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),
|
48
docs/reference/motors/motor/tacho.md
Normal 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)
|
25
docs/reference/motors/stop-all-motors.md
Normal 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)
|
84
docs/reference/motors/synced/steer.md
Normal 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)
|
81
docs/reference/motors/synced/tank.md
Normal 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
After Width: | Height: | Size: 11 KiB |
BIN
docs/static/labview/brickimage.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/static/labview/brickstatuslight.png
vendored
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
docs/static/labview/ife.png
vendored
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
docs/static/labview/invertmotor.png
vendored
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
docs/static/labview/lighttospeed.png
vendored
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
docs/static/labview/loopinfinite.PNG
vendored
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
docs/static/labview/motors.png
vendored
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
docs/static/labview/multipleloops.png
vendored
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
docs/static/labview/pausefordistance.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
docs/static/labview/pausefortime.png
vendored
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
docs/static/labview/pausefortouch.png
vendored
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
docs/static/labview/random.png
vendored
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
docs/static/labview/sequencing.png
vendored
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
docs/static/labview/speedoflight.png
vendored
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
docs/static/labview/speedoflightvar.png
vendored
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
docs/static/labview/steer.png
vendored
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
docs/static/labview/tank.png
vendored
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
docs/static/labview/unregulatedmotor.png
vendored
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
docs/static/labview/while.png
vendored
Normal file
After Width: | Height: | Size: 26 KiB |
@ -77,7 +77,7 @@ export function deployCoreAsync(resp: pxtc.CompileResult, isCli = false) {
|
||||
let rbfBIN = pxt.U.fromHex(rbfHex)
|
||||
pxt.HF2.write16(rbfBIN, 4, rbfBIN.length)
|
||||
|
||||
let origElfUF2 = UF2.parseFile(pxt.U.stringToUint8Array(atob(resp.outfiles[pxt.outputName()])))
|
||||
let origElfUF2 = UF2.parseFile(pxt.U.stringToUint8Array(ts.pxtc.decodeBase64(resp.outfiles[pxt.outputName()])))
|
||||
|
||||
let mkFile = (ext: string, data: Uint8Array = null) => {
|
||||
let f = UF2.newBlockFile()
|
||||
|
@ -4,7 +4,7 @@
|
||||
export NVM_DIR="/home/dotnet-bot/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
||||
|
||||
nvm install 5
|
||||
nvm install 8
|
||||
|
||||
# Set up build environment variables
|
||||
echo ---------- Setting build environment variables
|
||||
|
@ -115,7 +115,7 @@ namespace sensors {
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=100 blockGap=8
|
||||
//% weight=100 blockGap=12
|
||||
//% group="Color Sensor"
|
||||
onColorDetected(color: ColorSensorColor, handler: () => void) {
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
@ -174,7 +174,7 @@ namespace sensors {
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=89 blockGap=8
|
||||
//% weight=89 blockGap=12
|
||||
//% group="Color Sensor"
|
||||
onLightChanged(mode: LightIntensityMode, condition: LightCondition, handler: () => void) {
|
||||
this.setMode(<ColorSensorMode><number>mode)
|
||||
|
@ -3,9 +3,9 @@
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
if (sensors.color1.ambientLight() > 20) {
|
||||
brick.setLight(BrickLight.Green)
|
||||
brick.setStatusLight(StatusLight.Green)
|
||||
} else {
|
||||
brick.setLight(BrickLight.Orange)
|
||||
brick.setStatusLight(StatusLight.Orange)
|
||||
}
|
||||
})
|
||||
```
|
@ -3,9 +3,9 @@
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
if (sensors.color1.color() == ColorSensorColor.Green) {
|
||||
brick.setLight(BrickLight.Green)
|
||||
brick.setStatusLight(StatusLight.Green)
|
||||
} else {
|
||||
brick.setLight(BrickLight.Orange)
|
||||
brick.setStatusLight(StatusLight.Orange)
|
||||
}
|
||||
})
|
||||
```
|
@ -3,9 +3,9 @@
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
if (sensors.color1.reflectedLight() > 20) {
|
||||
brick.setLight(BrickLight.Green)
|
||||
brick.setStatusLight(StatusLight.Green)
|
||||
} else {
|
||||
brick.setLight(BrickLight.Orange)
|
||||
brick.setStatusLight(StatusLight.Orange)
|
||||
}
|
||||
})
|
||||
```
|
@ -2,7 +2,7 @@
|
||||
/**
|
||||
* Patterns for lights under the buttons.
|
||||
*/
|
||||
const enum BrickLight {
|
||||
const enum StatusLight {
|
||||
//% block=off enumval=0
|
||||
Off = 0,
|
||||
//% block=green enumval=1
|
||||
@ -116,7 +116,7 @@ namespace brick {
|
||||
//% blockId=buttonEvent block="on %button|%event"
|
||||
//% parts="brick"
|
||||
//% blockNamespace=brick
|
||||
//% weight=99 blockGap=8
|
||||
//% weight=99 blockGap=16
|
||||
//% group="Buttons"
|
||||
//% button.fieldEditor="brickbuttons"
|
||||
onEvent(ev: ButtonEvent, body: () => void) {
|
||||
@ -244,16 +244,16 @@ namespace control {
|
||||
|
||||
namespace brick {
|
||||
// the brick starts with the red color
|
||||
let currPattern: BrickLight = BrickLight.Red;
|
||||
let currPattern: StatusLight = StatusLight.Red;
|
||||
|
||||
/**
|
||||
* Set lights.
|
||||
* @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"
|
||||
//% help=brick/set-light
|
||||
export function setLight(pattern: BrickLight): void {
|
||||
//% help=brick/set-status-light
|
||||
export function setStatusLight(pattern: StatusLight): void {
|
||||
if (currPattern === pattern)
|
||||
return
|
||||
currPattern = pattern;
|
||||
|
@ -113,6 +113,7 @@ namespace motors {
|
||||
//% blockId=motorStopAll block="stop all motors"
|
||||
//% weight=1
|
||||
//% group="Move"
|
||||
//% help=motors/stop-all-motors
|
||||
export function stopAllMotors() {
|
||||
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
||||
writePWM(b)
|
||||
@ -164,21 +165,23 @@ namespace motors {
|
||||
//% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake=toggleOnOff"
|
||||
//% weight=60 blockGap=8
|
||||
//% group="Move"
|
||||
//% help=motors/motor/set-brake
|
||||
setBrake(brake: boolean) {
|
||||
this.init();
|
||||
this._brake = brake;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
//% group="Move"
|
||||
setReversed(reversed: boolean) {
|
||||
//% help=motors/motor/set-inverted
|
||||
setInverted(inverted: boolean) {
|
||||
this.init();
|
||||
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)
|
||||
}
|
||||
|
||||
@ -187,7 +190,8 @@ namespace motors {
|
||||
*/
|
||||
//% weight=6 blockGap=8
|
||||
//% group="Move"
|
||||
//% blockId=motorStop block="%motors|stop"
|
||||
//% help=motors/motor/stop
|
||||
//% blockId=motorStop block="stop %motors|"
|
||||
stop() {
|
||||
this.init();
|
||||
stop(this._port, this._brake);
|
||||
@ -206,7 +210,8 @@ namespace motors {
|
||||
*/
|
||||
//% weight=5
|
||||
//% group="Move"
|
||||
//% blockId=motorReset block="%motors|reset"
|
||||
//% help=motors/motor/reset
|
||||
//% blockId=motorReset block="reset %motors|"
|
||||
reset() {
|
||||
this.init();
|
||||
reset(this._port);
|
||||
@ -221,6 +226,7 @@ namespace motors {
|
||||
//% blockId=motorSetSpeed block="set %motor|speed to %speed=motorSpeedPicker|%"
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Move"
|
||||
//% help=motors/motor/set-speed
|
||||
setSpeed(speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
@ -279,7 +285,7 @@ namespace motors {
|
||||
* Pauses the execution until the previous command finished.
|
||||
* @param timeOut optional maximum pausing time in milliseconds
|
||||
*/
|
||||
//% blockId=motorPauseUntilRead block="%motor|pause until ready"
|
||||
//% blockId=motorPauseUntilRead block="pause until %motor|ready"
|
||||
//% weight=90
|
||||
//% group="Move"
|
||||
pauseUntilReady(timeOut?: number) {
|
||||
@ -338,6 +344,7 @@ namespace motors {
|
||||
//% blockId=outputMotorSetRegulated block="set %motor|regulated %value=toggleOnOff"
|
||||
//% weight=58
|
||||
//% group="Move"
|
||||
//% help=motors/motor/set-regulated
|
||||
setRegulated(value: boolean) {
|
||||
this._regulated = value;
|
||||
}
|
||||
@ -350,6 +357,7 @@ namespace motors {
|
||||
//% weight=72
|
||||
//% blockGap=8
|
||||
//% group="Counters"
|
||||
//% help=motors/motor/speed
|
||||
speed(): number {
|
||||
this.init();
|
||||
return getMotorData(this._port).actualSpeed;
|
||||
@ -363,6 +371,7 @@ namespace motors {
|
||||
//% weight=70
|
||||
//% blockGap=8
|
||||
//% group="Counters"
|
||||
//% help=motors/motor/angle
|
||||
angle(): number {
|
||||
this.init();
|
||||
return getMotorData(this._port).count;
|
||||
@ -377,6 +386,7 @@ namespace motors {
|
||||
//% weight=69
|
||||
//% blockGap=8
|
||||
//% group="Counters"
|
||||
//% help=motors/motor/tacho
|
||||
tacho(): number {
|
||||
this.init();
|
||||
return getMotorData(this._port).tachoCount;
|
||||
@ -385,10 +395,11 @@ namespace motors {
|
||||
/**
|
||||
* Clears the motor count
|
||||
*/
|
||||
//% blockId=motorClearCount block="%motor|clear counts"
|
||||
//% blockId=motorClearCount block="clear %motor|counters"
|
||||
//% weight=68
|
||||
//% blockGap=8
|
||||
//% group="Counters"
|
||||
//% help=motors/motor/clear-counts
|
||||
clearCounts() {
|
||||
this.init();
|
||||
const b = mkCmd(this._port, DAL.opOutputClearCount, 0)
|
||||
@ -488,6 +499,7 @@ namespace motors {
|
||||
//% weight=96 blockGap=8
|
||||
//% inlineInputMode=inline
|
||||
//% group="Move"
|
||||
//% help=motors/synced/tank
|
||||
tank(speedLeft: number, speedRight: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
|
||||
this.init();
|
||||
|
||||
@ -514,6 +526,7 @@ namespace motors {
|
||||
//% turnRatio.min=-200 turnRatio=200
|
||||
//% inlineInputMode=inline
|
||||
//% group="Move"
|
||||
//% help=motors/synced/steer
|
||||
steer(turnRatio: number, speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
|
@ -2,7 +2,7 @@ screen.clear()
|
||||
brick.print("PXT!", 10, 30, Draw.Quad)
|
||||
|
||||
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)
|
||||
|
||||
@ -12,7 +12,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Bumped, () => {
|
||||
|
||||
brick.buttonLeft.onEvent(ButtonEvent.Bumped, () => {
|
||||
brick.drawRect(10, 70, 20, 10, Draw.Fill)
|
||||
brick.setLight(BrickLight.Red)
|
||||
brick.setStatusLight(StatusLight.Red)
|
||||
brick.setFont(brick.microbitFont())
|
||||
})
|
||||
|
||||
|
@ -1,20 +1,20 @@
|
||||
|
||||
//% color="#68C3E2" weight=100 icon="\uf106"
|
||||
//% groups='["Buttons", "Screen"]'
|
||||
//% labelLineWidth=0
|
||||
//% labelLineWidth=60
|
||||
namespace brick {
|
||||
}
|
||||
|
||||
|
||||
//% color="#C8509B" weight=95 icon="\uf10f"
|
||||
//% labelLineWidth=0
|
||||
//% labelLineWidth=100
|
||||
//% groups='["Touch Sensor", "Color Sensor", "Ultrasonic Sensor", "Gyro Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Threshold"]'
|
||||
namespace sensors {
|
||||
}
|
||||
|
||||
//% color="#A5CA18" weight=90 icon="\uf10d"
|
||||
//% color="#00852B" weight=90 icon="\uf10d"
|
||||
//% groups='["Move", "Counters"]'
|
||||
//% labelLineWidth=0
|
||||
//% labelLineWidth=50
|
||||
namespace motors {
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
"touch-sensor": "file:../touch-sensor",
|
||||
"ultrasonic-sensor": "file:../ultrasonic-sensor",
|
||||
"gyro-sensor": "file:../gyro-sensor",
|
||||
"infrared-sensor": "file:../infrared-sensor",
|
||||
"mood": "file:../mood"
|
||||
},
|
||||
"public": true
|
||||
|
@ -82,12 +82,12 @@ namespace sensors {
|
||||
* Forces a calibration of the gyro. Must be called when the sensor is completely still.
|
||||
*/
|
||||
//% help=input/gyro/calibrate
|
||||
//% block="%sensor|reset"
|
||||
//% block="reset %sensor|"
|
||||
//% blockId=gyroReset
|
||||
//% parts="gyroscope"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=50 blockGap=8
|
||||
//% weight=50
|
||||
//% group="Gyro Sensor"
|
||||
reset(): void {
|
||||
if (this.calibrating) return; // already in calibration mode
|
||||
|
@ -1,29 +1,37 @@
|
||||
const enum IrSensorMode {
|
||||
const enum InfraredSensorMode {
|
||||
None = -1,
|
||||
Proximity = 0,
|
||||
Seek = 1,
|
||||
RemoteControl = 2,
|
||||
}
|
||||
|
||||
const enum IrRemoteChannel {
|
||||
const enum InfraredRemoteChannel {
|
||||
//% block="channel 0"
|
||||
Ch0 = 0, // top
|
||||
//% block="channel 1"
|
||||
Ch1 = 1,
|
||||
//% block="channel 2"
|
||||
Ch2 = 2,
|
||||
//% block="channel 3"
|
||||
Ch3 = 3,
|
||||
}
|
||||
|
||||
const enum IrRemoteButton {
|
||||
None = 0x00,
|
||||
const 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,
|
||||
}
|
||||
|
||||
const enum InfraredSensorEvent {
|
||||
//% block="object near"
|
||||
ObjectNear = 1,
|
||||
ObjectNear = 3,
|
||||
//% block="object detected"
|
||||
ObjectDetected = 2
|
||||
}
|
||||
@ -31,61 +39,44 @@ const enum InfraredSensorEvent {
|
||||
namespace sensors {
|
||||
function mapButton(v: number) {
|
||||
switch (v) {
|
||||
case 0: return IrRemoteButton.None
|
||||
case 1: return IrRemoteButton.TopLeft
|
||||
case 2: return IrRemoteButton.BottomLeft
|
||||
case 3: return IrRemoteButton.TopRight
|
||||
case 4: return IrRemoteButton.TopRight | IrRemoteButton.BottomRight
|
||||
case 5: return IrRemoteButton.TopLeft | IrRemoteButton.TopRight
|
||||
case 6: return IrRemoteButton.TopLeft | IrRemoteButton.BottomRight
|
||||
case 7: return IrRemoteButton.BottomLeft | IrRemoteButton.TopRight
|
||||
case 8: return IrRemoteButton.BottomLeft | IrRemoteButton.BottomRight
|
||||
case 9: return IrRemoteButton.CenterBeacon
|
||||
case 10: return IrRemoteButton.BottomLeft | IrRemoteButton.TopLeft
|
||||
case 11: return IrRemoteButton.TopRight | IrRemoteButton.BottomRight
|
||||
default: return IrRemoteButton.None
|
||||
case 1: return InfraredRemoteButton.TopLeft;
|
||||
case 2: return InfraredRemoteButton.BottomLeft;
|
||||
case 3: return InfraredRemoteButton.TopRight;
|
||||
case 4: return InfraredRemoteButton.BottomRight;
|
||||
case 5: return InfraredRemoteButton.TopLeft | InfraredRemoteButton.TopRight
|
||||
case 6: return InfraredRemoteButton.TopLeft | InfraredRemoteButton.BottomRight
|
||||
case 7: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopRight
|
||||
case 8: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.BottomRight
|
||||
case 9: return InfraredRemoteButton.CenterBeacon
|
||||
case 10: return InfraredRemoteButton.BottomLeft | InfraredRemoteButton.TopLeft
|
||||
case 11: return InfraredRemoteButton.TopRight | InfraredRemoteButton.BottomRight
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
let buttons: RemoteInfraredBeaconButton[]
|
||||
|
||||
function create(ir: InfraredSensor) {
|
||||
// it's created by referencing it
|
||||
const __remoteButtons: RemoteInfraredBeaconButton[] = [];
|
||||
function __irButton(id: InfraredRemoteButton): RemoteInfraredBeaconButton {
|
||||
for(let i = 0; i < __remoteButtons.length; ++i) {
|
||||
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()))
|
||||
}
|
||||
|
||||
// make sure sensors are up
|
||||
create(infraredSensor1)
|
||||
create(infraredSensor2)
|
||||
create(infraredSensor3)
|
||||
create(infraredSensor4)
|
||||
}
|
||||
|
||||
let num = -1
|
||||
while (id) {
|
||||
id >>= 1;
|
||||
num++;
|
||||
}
|
||||
num = Math.clamp(0, buttons.length - 1, num)
|
||||
return buttons[num]
|
||||
const btn = new RemoteInfraredBeaconButton(id, new brick.Button());
|
||||
__remoteButtons.push(btn);
|
||||
return btn;
|
||||
}
|
||||
|
||||
//% fixedInstances
|
||||
export class RemoteInfraredBeaconButton extends control.Component {
|
||||
private button: brick.Button;
|
||||
constructor(button: brick.Button) {
|
||||
position: InfraredRemoteButton;
|
||||
private _button: brick.Button;
|
||||
constructor(position: InfraredRemoteButton, button: brick.Button) {
|
||||
super();
|
||||
this.button = button;
|
||||
this.position = position;
|
||||
this._button = button;
|
||||
}
|
||||
|
||||
_update(curr: boolean) {
|
||||
this.button._update(curr);
|
||||
this._button._update(curr);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,7 +91,7 @@ namespace sensors {
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Remote Infrared Beacon"
|
||||
isPressed() {
|
||||
return this.button.isPressed();
|
||||
return this._button.isPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,7 +106,7 @@ namespace sensors {
|
||||
//% weight=80
|
||||
//% group="Remote Infrared Beacon"
|
||||
wasPressed() {
|
||||
return this.button.wasPressed();
|
||||
return this._button.wasPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -131,42 +122,53 @@ namespace sensors {
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Remote Infrared Beacon"
|
||||
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
|
||||
export class InfraredSensor extends internal.UartSensor {
|
||||
private channel: IrRemoteChannel;
|
||||
private proximityThreshold: sensors.ThresholdDetector;
|
||||
private _channel: InfraredRemoteChannel;
|
||||
private _proximityThreshold: sensors.ThresholdDetector;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.channel = IrRemoteChannel.Ch0
|
||||
this.proximityThreshold = new sensors.ThresholdDetector(this._id, 0, 100, 10, 90);
|
||||
irButton(0) // make sure buttons array is initalized
|
||||
|
||||
// and set the mode, as otherwise button events won't work
|
||||
this.mode = IrSensorMode.RemoteControl;
|
||||
this._channel = InfraredRemoteChannel.Ch0
|
||||
this._proximityThreshold = new sensors.ThresholdDetector(this._id, 0, 100, 10, 90);
|
||||
this.setMode(InfraredSensorMode.Proximity);
|
||||
}
|
||||
|
||||
_query() {
|
||||
if (this.mode == IrSensorMode.RemoteControl)
|
||||
return mapButton(this.getNumber(NumberFormat.UInt8LE, this.channel));
|
||||
else if (this.mode == IrSensorMode.Proximity) {
|
||||
if (this.mode == InfraredSensorMode.RemoteControl)
|
||||
return mapButton(this.getNumber(NumberFormat.UInt8LE, this._channel));
|
||||
else if (this.mode == InfraredSensorMode.Proximity) {
|
||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
if (this.mode == IrSensorMode.RemoteControl) {
|
||||
for (let i = 0; i < buttons.length; ++i) {
|
||||
let v = !!(curr & (1 << i))
|
||||
buttons[i]._update(v)
|
||||
if (this.mode == InfraredSensorMode.RemoteControl) {
|
||||
for (let i = 0; i < __remoteButtons.length; ++i) {
|
||||
const v = !!(curr & __remoteButtons[i].position);
|
||||
__remoteButtons[i]._update(v)
|
||||
}
|
||||
} else if (this.mode == IrSensorMode.Proximity) {
|
||||
this.proximityThreshold.setLevel(curr);
|
||||
} else if (this.mode == InfraredSensorMode.Proximity) {
|
||||
this._proximityThreshold.setLevel(curr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,13 +176,7 @@ namespace sensors {
|
||||
return DAL.DEVICE_TYPE_IR
|
||||
}
|
||||
|
||||
setRemoteChannel(c: IrRemoteChannel) {
|
||||
c = Math.clamp(0, 3, c | 0)
|
||||
this.channel = c
|
||||
this.setMode(IrSensorMode.RemoteControl)
|
||||
}
|
||||
|
||||
setMode(m: IrSensorMode) {
|
||||
setMode(m: InfraredSensorMode) {
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
@ -196,6 +192,7 @@ namespace sensors {
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
onEvent(event: InfraredSensorEvent, handler: () => void) {
|
||||
this._setMode(InfraredSensorMode.Proximity)
|
||||
control.onEvent(this._id, event, handler);
|
||||
}
|
||||
|
||||
@ -210,6 +207,7 @@ namespace sensors {
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
pauseUntil(event: InfraredSensorEvent) {
|
||||
this._setMode(InfraredSensorMode.Proximity)
|
||||
control.waitForEvent(this._id, event);
|
||||
}
|
||||
|
||||
@ -222,36 +220,27 @@ namespace sensors {
|
||||
//% blockId=infraredGetProximity
|
||||
//% parts="infrared"
|
||||
//% blockNamespace=sensors
|
||||
//% weight=65 blockGap=8
|
||||
//% weight=98 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
proximity(): number {
|
||||
this._setMode(IrSensorMode.Proximity)
|
||||
this._setMode(InfraredSensorMode.Proximity)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remote commandreceived the infrared sensor.
|
||||
* @param sensor the infrared sensor
|
||||
* Sets the remote channel to listen from
|
||||
* @param channel the channel to listen
|
||||
*/
|
||||
//% help=input/infrared/remote-command
|
||||
//% block="%sensor|remote command"
|
||||
//% blockId=infraredGetRemoteCommand
|
||||
//% parts="infrared"
|
||||
//% blockNamespace=sensors
|
||||
//% blockId=irSetRemoteChannel block="set %sensor|remote channel to %channel"
|
||||
//% weight=65
|
||||
//% group="Infrared Sensor"
|
||||
remoteCommand(): number {
|
||||
this._setMode(IrSensorMode.RemoteControl)
|
||||
return this.getNumber(NumberFormat.UInt8LE, this.channel)
|
||||
//% group="Remote Infrared Beacon"
|
||||
setRemoteChannel(channel: InfraredRemoteChannel) {
|
||||
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
|
||||
* @param condition the dark or bright light condition
|
||||
@ -260,11 +249,11 @@ namespace sensors {
|
||||
//% blockId=irSetThreshold block="set %sensor|%condition|to %value"
|
||||
//% group="Threshold" blockGap=8 weight=49
|
||||
//% value.min=0 value.max=100
|
||||
setThreshold(condition: InfraredSensorEvent, value: number) {
|
||||
setPromixityThreshold(condition: InfraredSensorEvent, value: number) {
|
||||
if (condition == InfraredSensorEvent.ObjectNear)
|
||||
this.proximityThreshold.setLowThreshold(value)
|
||||
this._proximityThreshold.setLowThreshold(value)
|
||||
else
|
||||
this.proximityThreshold.setHighThreshold(value);
|
||||
this._proximityThreshold.setHighThreshold(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,8 +263,14 @@ namespace sensors {
|
||||
//% blockId=irGetThreshold block="%sensor|%condition"
|
||||
//% group="Threshold" blockGap=8 weight=49
|
||||
//% sensor.fieldEditor="ports"
|
||||
threshold(condition: InfraredSensorEvent): number {
|
||||
return this.proximityThreshold.threshold(<ThresholdState><number>LightCondition.Dark);
|
||||
proximityThreshold(condition: InfraredSensorEvent): number {
|
||||
return this._proximityThreshold.threshold(<ThresholdState><number>LightCondition.Dark);
|
||||
}
|
||||
|
||||
// TODO
|
||||
private getDirectionAndDistance() {
|
||||
this._setMode(InfraredSensorMode.Seek)
|
||||
return this.getNumber(NumberFormat.UInt16LE, this._channel * 2)
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,34 +286,33 @@ namespace sensors {
|
||||
//% fixedInstance whenUsed block="infrared 4" jres=icons.port4
|
||||
export const infraredSensor4: InfraredSensor = new InfraredSensor(4)
|
||||
|
||||
|
||||
/**
|
||||
* Remote beacon (center) button.
|
||||
*/
|
||||
//% whenUsed block="center" weight=95 fixedInstance
|
||||
export const remoteButtonCenter = irButton(IrRemoteButton.CenterBeacon)
|
||||
//% whenUsed block="remote button center" weight=95 fixedInstance
|
||||
export const remoteButtonCenter = __irButton(InfraredRemoteButton.CenterBeacon)
|
||||
|
||||
/**
|
||||
* Remote top-left button.
|
||||
*/
|
||||
//% whenUsed block="top-left" weight=95 fixedInstance
|
||||
export const remoteButtonTopLeft = irButton(IrRemoteButton.TopLeft)
|
||||
//% whenUsed block="remote button top left" weight=95 fixedInstance
|
||||
export const remoteButtonTopLeft = __irButton(InfraredRemoteButton.TopLeft)
|
||||
|
||||
/**
|
||||
* Remote top-right button.
|
||||
*/
|
||||
//% whenUsed block="top-right" weight=95 fixedInstance
|
||||
export const remoteButtonTopRight = irButton(IrRemoteButton.TopRight)
|
||||
//% whenUsed block="remote button top right" weight=95 fixedInstance
|
||||
export const remoteButtonTopRight = __irButton(InfraredRemoteButton.TopRight)
|
||||
|
||||
/**
|
||||
* Remote bottom-left button.
|
||||
*/
|
||||
//% whenUsed block="bottom-left" weight=95 fixedInstance
|
||||
export const remoteButtonBottomLeft = irButton(IrRemoteButton.BottomLeft)
|
||||
//% whenUsed block="remote button bottom left" weight=95 fixedInstance
|
||||
export const remoteButtonBottomLeft = __irButton(InfraredRemoteButton.BottomLeft)
|
||||
|
||||
/**
|
||||
* Remote bottom-right button.
|
||||
*/
|
||||
//% whenUsed block="bottom-right" weight=95 fixedInstance
|
||||
export const remoteButtonBottomRight = irButton(IrRemoteButton.BottomRight)
|
||||
//% whenUsed block="remote button bottom right" weight=95 fixedInstance
|
||||
export const remoteButtonBottomRight = __irButton(InfraredRemoteButton.BottomRight)
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ namespace brick {
|
||||
export class Mood {
|
||||
private image: Image;
|
||||
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.sound = sound;
|
||||
this.light = light;
|
||||
@ -30,7 +30,7 @@ namespace brick {
|
||||
* Shows the mood on the EV3
|
||||
*/
|
||||
show() {
|
||||
brick.setLight(this.light);
|
||||
brick.setStatusLight(this.light);
|
||||
brick.showImage(this.image);
|
||||
music.playSoundEffectUntilDone(this.sound);
|
||||
loops.pause(20);
|
||||
@ -56,71 +56,71 @@ namespace moods {
|
||||
* A sleeping mood
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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
|
||||
*/
|
||||
//% 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);
|
||||
}
|
@ -3,9 +3,9 @@
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
if (sensors.touch1.isPressed()) {
|
||||
brick.setLight(BrickLight.Green)
|
||||
brick.setStatusLight(StatusLight.Green)
|
||||
} else {
|
||||
brick.setLight(BrickLight.Orange)
|
||||
brick.setStatusLight(StatusLight.Orange)
|
||||
}
|
||||
})
|
||||
```
|
@ -3,9 +3,9 @@
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
if (sensors.touch1.wasPressed()) {
|
||||
brick.setLight(BrickLight.Green)
|
||||
brick.setStatusLight(StatusLight.Green)
|
||||
} else {
|
||||
brick.setLight(BrickLight.Orange)
|
||||
brick.setStatusLight(StatusLight.Orange)
|
||||
}
|
||||
})
|
||||
```
|
@ -34,7 +34,7 @@ namespace sensors {
|
||||
//% parts="touch"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=99 blockGap=8
|
||||
//% weight=99 blockGap=12
|
||||
//% group="Touch Sensor"
|
||||
onEvent(ev: ButtonEvent, body: () => void) {
|
||||
this.button.onEvent(ev, body)
|
||||
@ -50,7 +50,7 @@ namespace sensors {
|
||||
//% parts="touch"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=98 blockGap=8
|
||||
//% weight=98 blockGap=12
|
||||
//% group="Touch Sensor"
|
||||
pauseUntil(ev: ButtonEvent) {
|
||||
this.button.pauseUntil(<ButtonEvent><number>ev);
|
||||
@ -66,7 +66,7 @@ namespace sensors {
|
||||
//% parts="touch"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=81
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Touch Sensor"
|
||||
isPressed() {
|
||||
return this.button.isPressed();
|
||||
@ -82,7 +82,7 @@ namespace sensors {
|
||||
//% parts="touch"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=81 blockGap=8
|
||||
//% weight=81
|
||||
//% group="Touch Sensor"
|
||||
wasPressed() {
|
||||
return this.button.wasPressed();
|
||||
|
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "0.0.81",
|
||||
"version": "0.0.93",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "0.0.81",
|
||||
"version": "0.0.93",
|
||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
@ -44,8 +44,8 @@
|
||||
"webfonts-generator": "^0.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-common-packages": "0.17.13",
|
||||
"pxt-core": "3.1.2"
|
||||
"pxt-common-packages": "0.18.1",
|
||||
"pxt-core": "3.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||
|
@ -83,7 +83,7 @@
|
||||
},
|
||||
"appTheme": {
|
||||
"accentColor": "#0089BF",
|
||||
"logoUrl": "https://lego.makecode.com",
|
||||
"logoUrl": "https://education.lego.com/",
|
||||
"logo": "./static/lego_education_logo.png",
|
||||
"highContrastLogo": "./static/lego_education_logo_white.png",
|
||||
"docsLogo": "./static/lego-logo.svg",
|
||||
@ -95,12 +95,12 @@
|
||||
"organizationUrl": "https://makecode.com/",
|
||||
"organizationLogo": "./static/Microsoft-logo_rgb_c-gray-square.png",
|
||||
"organizationWideLogo": "./static/Microsoft-logo_rgb_c-gray.png",
|
||||
"homeUrl": "https://lego.makecode.com/",
|
||||
"embedUrl": "https://lego.makecode.com/",
|
||||
"homeUrl": "https://makecode.legoeducation.com/",
|
||||
"embedUrl": "https://makecode.legoeducation.com/",
|
||||
"privacyUrl": "https://go.microsoft.com/fwlink/?LinkId=521839",
|
||||
"termsOfUseUrl": "https://go.microsoft.com/fwlink/?LinkID=206977",
|
||||
"githubUrl": "https://github.com/Microsoft/pxt-ev3",
|
||||
"betaUrl": "https://lego.makecode.com/",
|
||||
"betaUrl": "https://makecode.legoeducation.com/about",
|
||||
"boardName": "LEGO Mindstorms EV3 Brick",
|
||||
"selectLanguage": true,
|
||||
"highContrast": true,
|
||||
@ -137,7 +137,7 @@
|
||||
"blockColors": {
|
||||
"loops": "#58AB41",
|
||||
"logic": "#1E5AA8",
|
||||
"math": "#9DC3F7",
|
||||
"math": "#7396C8",
|
||||
"variables": "#B40000",
|
||||
"text": "#FCAC00",
|
||||
"advanced": "#969696",
|
||||
@ -157,5 +157,5 @@
|
||||
"editor.background": "#ecf6ff"
|
||||
}
|
||||
},
|
||||
"ignoreDocsErrors": true
|
||||
"ignoreDocsErrors": false
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ namespace pxsim {
|
||||
motorState: EV3MotorState;
|
||||
screenState: EV3ScreenState;
|
||||
audioState: AudioState;
|
||||
remoteState: RemoteState;
|
||||
|
||||
inputNodes: SensorNode[] = [];
|
||||
brickNode: BrickNode;
|
||||
@ -38,6 +39,7 @@ namespace pxsim {
|
||||
this.motorState = new EV3MotorState();
|
||||
this.screenState = new EV3ScreenState();
|
||||
this.audioState = new AudioState();
|
||||
this.remoteState = new RemoteState();
|
||||
}
|
||||
|
||||
receiveMessage(msg: SimulatorMessage) {
|
||||
@ -143,6 +145,7 @@ namespace pxsim {
|
||||
case DAL.DEVICE_TYPE_COLOR: this.inputNodes[port] = new ColorSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_TOUCH: this.inputNodes[port] = new TouchSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_ULTRASONIC: this.inputNodes[port] = new UltrasonicSensorNode(port); break;
|
||||
case DAL.DEVICE_TYPE_IR: this.inputNodes[port] = new InfraredSensorNode(port); break;
|
||||
}
|
||||
}
|
||||
return this.inputNodes[port];
|
||||
|
81
sim/state/infrared.ts
Normal file
@ -0,0 +1,81 @@
|
||||
/// <reference path="./sensor.ts"/>
|
||||
|
||||
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 {
|
||||
None = -1,
|
||||
Proximity = 0,
|
||||
Seek = 1,
|
||||
RemoteControl = 2
|
||||
}
|
||||
|
||||
export class InfraredSensorNode extends UartSensorNode {
|
||||
id = NodeType.InfraredSensor;
|
||||
|
||||
private proximity: number = 50; // [0..100]
|
||||
|
||||
constructor(port: number) {
|
||||
super(port);
|
||||
}
|
||||
|
||||
getDeviceType() {
|
||||
return DAL.DEVICE_TYPE_IR;
|
||||
}
|
||||
|
||||
setPromixity(proximity: number) {
|
||||
if (this.proximity != proximity) {
|
||||
this.proximity = proximity;
|
||||
this.setChangedState();
|
||||
}
|
||||
}
|
||||
|
||||
getValue() {
|
||||
switch(this.mode) {
|
||||
case InfraredSensorMode.Proximity: return this.proximity;
|
||||
case InfraredSensorMode.RemoteControl: return ev3board().remoteState.unmapButtons();
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,8 @@ namespace pxsim {
|
||||
LargeMotor = 4,
|
||||
GyroSensor = 5,
|
||||
ColorSensor = 6,
|
||||
UltrasonicSensor = 7
|
||||
UltrasonicSensor = 7,
|
||||
InfraredSensor = 8
|
||||
}
|
||||
|
||||
export interface Node {
|
||||
|
@ -17,17 +17,17 @@
|
||||
<stop offset="0.52" stop-color="#6a6a6a"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-green" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="linear-gradient-green" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#8CE300"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-red" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="linear-gradient-red" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#D02E26"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-orange" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="linear-gradient-orange" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#F8D039"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@ -1,6 +1,7 @@
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export const EV3_SVG = `<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 110.73 170.04">
|
||||
export const EV3_SVG = `
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 110.73 170.04">
|
||||
<defs>
|
||||
<linearGradient id="linear-gradient" x1="-374.89" y1="432.9" x2="-374.89" y2="432.82" gradientTransform="matrix(110.73, 0, 0, -106.94, 41567.45, 46425.3)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#f1f1f1"/>
|
||||
@ -19,17 +20,17 @@ namespace pxsim.visuals {
|
||||
<stop offset="0.52" stop-color="#6a6a6a"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-green" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="linear-gradient-green" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#8CE300"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-red" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="linear-gradient-red" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#D02E26"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linear-gradient-orange" x1="-382.07" y1="493.36" x2="-382.07" y2="494.25" gradientTransform="matrix(65.53, 0, 0, -48.84, 25091.11, 24228.69)" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="linear-gradient-orange" x1="0" y1="0" x2="145" y2="48" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#6a6a6a"/>
|
||||
<stop offset="0.52" stop-color="#F8D039"/>
|
||||
<stop offset="1" stop-color="#6a6a6a"/>
|
||||
@ -104,5 +105,6 @@ namespace pxsim.visuals {
|
||||
<path id="ev3_e" data-name="ev3 e" d="M19.39,156.1a.34.34,0,0,1,.38.3v1.17a.33.33,0,0,1-.38.3H14.34c-.11,0-.2.06-.2.14h0v.82h0c0,.08.09.14.2.14h5.05a.33.33,0,0,1,.38.3v1.15a.33.33,0,0,1-.35.3H12.67a.35.35,0,0,1-.38-.3v-6.89a.34.34,0,0,1,.38-.3h6.75a.31.31,0,0,1,.35.28v1.17a.31.31,0,0,1-.33.3H14.36c-.11,0-.22,0-.22.13V156c0,.08.09.14.19.14Z" transform="translate(0 0)" style="fill: #f1f1f1"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ namespace pxsim.visuals {
|
||||
<path id="port_2" data-name="port 2" d="M4.48,0h50V58.93h-50Z" transform="translate(-4.48)" style="fill: #eaeaea"/>
|
||||
<path id="port_1" data-name="port 1" d="M9.74,46.49V18.66H26.85V11.75h4.72V2.59H44.49v8.82h5.06V46.49h-8v7.43H38.9V46.41h-2v7.5H34.71v-7.5H32.55v7.5h-2.1v-7.5H28.6v7.5H26.5v-7.5H24.68v7.5H22.22v-7.5H20.54v7.5H18V46.46Z" transform="translate(-4.48)" style="fill: #a8aaa8"/>
|
||||
<g id="text10060" style="isolation: isolate">
|
||||
<text id="port_text" transform="translate(22.21 40.2)" style="isolation: isolate;font-size: 16px;fill: white;font-family: ArialMT, Arial">B</text>
|
||||
<text id="port_text" class="user-select-none" transform="translate(22.21 40.2)" style="isolation: isolate;font-size: 16px;fill: white;font-family: ArialMT, Arial">B</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>`;
|
||||
|
21
sim/visuals/assets/RemoteSvg.ts
Normal file
@ -0,0 +1,21 @@
|
||||
namespace pxsim.visuals {
|
||||
export const REMOVE_SVG = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="371.7" height="418.7" viewBox="0 0 98.3 110.8" id="svg8">
|
||||
<g id="layer1" transform="translate(0 -186.2)">
|
||||
<rect id="rect90-3" width="72.7" height="9.6" x="12.1" y="186.5" rx="2.1" fill="#666" stroke="#000" stroke-width=".5"/>
|
||||
<rect id="rect90" width="73.1" height="9.6" x="12.2" y="287.1" rx="2.1" stroke="#000" stroke-width=".5"/>
|
||||
<path d="M14.3 193.2c-1.1 0-2.1 1-2.1 2.1v15.5H2.4c-1.2 0-2.1 1-2.1 2.1v73.7c0 1.1 1 2.1 2.1 2.1h9.8v.6c0 1.2 1 2.1 2.1 2.1h68.3c1.2 0 2.2-1 2.2-2.1v-.6h11.1c1.2 0 2.2-1 2.2-2.1v-73.7c0-1.1-1-2.1-2.2-2.1H84.8v-15.5c0-1.2-1-2.1-2.2-2.1z" id="rect10" fill="#fff" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M31 197.9c7.3 0 7.7 8.2 7.7 9.3v17.4c0 1.2-1 2.2-2.2 2.2H25.7c-1.2 0-2.2-1-2.2-2.2v-17c0-1.1.2-9.7 7.5-9.7z" id="topleft" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M65.5 197.9c7.3 0 7.7 8.2 7.7 9.3v17.4c0 1.2-1 2.2-2.2 2.2H60.2c-1.2 0-2.1-1-2.1-2.2v-17c0-1.1.2-9.7 7.4-9.7z" id="topright" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M65.7 266.3c-7.3 0-7.6-8.2-7.6-9.4v-17.4c0-1.2 1-2.2 2.1-2.2H71c1.2 0 2.2 1 2.2 2.2v17c0 1.2-.2 9.8-7.5 9.8z" id="bottomright" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M31.2 266.3c-7.3 0-7.7-8.2-7.7-9.4v-17.4c0-1.2 1-2.2 2.2-2.2h10.8c1.2 0 2.2 1 2.2 2.2v17c0 1.2-.3 9.8-7.5 9.8z" id="bottomleft" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M27.5 273.6l40.1.1c1.2 0 5.4 6.3 5.4 7.5v5.8c0 1.1-1 2.1-2.2 2.1H25.5c-1.2 0-2.1-1-2.1-2.1v-5.5c0-1.2 3-7.9 4.1-7.9z" id="center" fill="#b3b3b3" stroke="#000" stroke-width="1.1"/>
|
||||
<rect id="rect107" width="15.1" height="3.2" x="23.1" y="231.1" ry="1.3" fill="#247aff" stroke-width=".5"/>
|
||||
<rect id="rect107-1" width="15.1" height="3.2" x="58.2" y="231.1" ry="1.3" fill="#ff242b" stroke-width=".5"/>
|
||||
<circle id="path941" cx="49.2" cy="263.3" r="2.5" fill="#ff242b" stroke-width=".5"/>
|
||||
<circle id="path943" cx="49.2" cy="263.3" r="4.5" fill="none" stroke="#949494" stroke-width=".5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
`;
|
||||
}
|
48
sim/visuals/assets/infrared.svg
Normal file
@ -0,0 +1,48 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="svg5190" viewBox="0 0 83.5 35.1">
|
||||
<defs id="defs961">
|
||||
<clipPath id="clip-path" transform="translate(0 -22.4)">
|
||||
<circle cx="17.5" cy="40" r="7" id="circle955" fill="none"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip-path-2" transform="translate(0 -22.4)">
|
||||
<circle cx="65.9" cy="40" r="7" id="circle958" fill="none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<path data-name="US main black2" id="US_main_black2" fill="#242424" d="M22.6 1.5H66v31.3H22.6z"/>
|
||||
<path data-name="US main black1" id="US_main_black1" d="M30.2 8.5h25.3v17.6H30.2z"/>
|
||||
<g id="US_eye1_net" data-name="US eye1 net">
|
||||
<g clip-path="url(#clip-path)" id="g991">
|
||||
<g id="US_eye1_net_mask" data-name="US eye1 net mask">
|
||||
<g id="US_eye1_net_total" data-name="US eye1 net total" fill="#aa7707">
|
||||
<path id="US_eye1_net14" data-name="US eye1 net14" transform="rotate(-30 -30.7 33.6)" d="M10.8 33.5h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net13" data-name="US eye1 net13" transform="rotate(-30 -18.8 36.5)" d="M11.8 47.4h22.5v.6H11.8z"/>
|
||||
<path id="US_eye1_net12" data-name="US eye1 net12" transform="rotate(-30 -28.2 32.2)" d="M13.3 32.1h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net11" data-name="US eye1 net11" transform="rotate(-30 -20.2 34)" d="M10.4 45h22.5v.6H10.4z"/>
|
||||
<path id="US_eye1_net10" data-name="US eye1 net10" transform="rotate(-30 -25.7 30.8)" d="M15.8 30.6h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net9" data-name="US eye1 net9" transform="rotate(-30 -21.7 31.5)" d="M8.9 42.5h22.5v.6H8.9z"/>
|
||||
<path id="US_eye1_net8" data-name="US eye1 net8" transform="rotate(-30 -23.2 29.3)" d="M18.3 29.2h.6V52h-.6z"/>
|
||||
<path id="US_eye1_net7" data-name="US eye1 net7" transform="rotate(-30 -23.1 29)" d="M7.5 40H30v.6H7.5z"/>
|
||||
<path id="US_eye1_net6" data-name="US eye1 net6" transform="rotate(-30 -20.7 27.9)" d="M20.8 27.8h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net5" data-name="US eye1 net5" transform="rotate(-30 -24.6 26.5)" d="M6 37.5h22.5v.6H6z"/>
|
||||
<path id="US_eye1_net4" data-name="US eye1 net4" transform="rotate(-30 -18.2 26.4)" d="M23.3 26.3h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net3" data-name="US eye1 net3" transform="rotate(-30 -26 24)" d="M4.6 35h22.5v.6H4.6z"/>
|
||||
<path id="US_eye1_net2" data-name="US eye1 net2" transform="rotate(-30 -15.7 25)" d="M25.8 24.9h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net1" data-name="US eye1 net1" transform="rotate(-30 -27.4 21.5)" d="M3.2 32.5h22.5v.6H3.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g1656">
|
||||
<g data-name="US eye1 black" id="US_eye1_black">
|
||||
<circle id="circle967" r="17.4" cy="17.6" cx="17.6" stroke="#b3b3b3" stroke-width=".3" stroke-miterlimit="10"/>
|
||||
<circle id="circle969" r="17.3" cy="17.6" cx="17.6" fill="none"/>
|
||||
</g>
|
||||
<path id="path1650" d="M5.8 17h19.7l3.1 3.6" fill="none" stroke="#e80000" stroke-width="1.7"/>
|
||||
</g>
|
||||
<g transform="matrix(-1 0 0 1 83.5 0)" id="g1656-6">
|
||||
<g data-name="US eye1 black" id="US_eye1_black-9">
|
||||
<circle id="circle967-5" r="17.4" cy="17.6" cx="17.6" stroke="#b3b3b3" stroke-width=".3" stroke-miterlimit="10"/>
|
||||
<circle id="circle969-1" r="17.3" cy="17.6" cx="17.6" fill="none"/>
|
||||
</g>
|
||||
<path id="path1650-4" d="M5.8 17h19.7l3.1 3.6" fill="none" stroke="#e80000" stroke-width="1.7"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.3 KiB |
53
sim/visuals/assets/infraredsvg.ts
Normal file
@ -0,0 +1,53 @@
|
||||
namespace pxsim {
|
||||
export const INFRARED_SVG = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="svg5190" viewBox="0 0 83.5 35.1">
|
||||
<defs id="defs961">
|
||||
<clipPath id="clip-path" transform="translate(0 -22.4)">
|
||||
<circle cx="17.5" cy="40" r="7" id="circle955" fill="none"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip-path-2" transform="translate(0 -22.4)">
|
||||
<circle cx="65.9" cy="40" r="7" id="circle958" fill="none"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<path data-name="US main black2" id="US_main_black2" fill="#242424" d="M22.6 1.5H66v31.3H22.6z"/>
|
||||
<path data-name="US main black1" id="US_main_black1" d="M30.2 8.5h25.3v17.6H30.2z"/>
|
||||
<g id="US_eye1_net" data-name="US eye1 net">
|
||||
<g clip-path="url(#clip-path)" id="g991">
|
||||
<g id="US_eye1_net_mask" data-name="US eye1 net mask">
|
||||
<g id="US_eye1_net_total" data-name="US eye1 net total" fill="#aa7707">
|
||||
<path id="US_eye1_net14" data-name="US eye1 net14" transform="rotate(-30 -30.7 33.6)" d="M10.8 33.5h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net13" data-name="US eye1 net13" transform="rotate(-30 -18.8 36.5)" d="M11.8 47.4h22.5v.6H11.8z"/>
|
||||
<path id="US_eye1_net12" data-name="US eye1 net12" transform="rotate(-30 -28.2 32.2)" d="M13.3 32.1h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net11" data-name="US eye1 net11" transform="rotate(-30 -20.2 34)" d="M10.4 45h22.5v.6H10.4z"/>
|
||||
<path id="US_eye1_net10" data-name="US eye1 net10" transform="rotate(-30 -25.7 30.8)" d="M15.8 30.6h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net9" data-name="US eye1 net9" transform="rotate(-30 -21.7 31.5)" d="M8.9 42.5h22.5v.6H8.9z"/>
|
||||
<path id="US_eye1_net8" data-name="US eye1 net8" transform="rotate(-30 -23.2 29.3)" d="M18.3 29.2h.6V52h-.6z"/>
|
||||
<path id="US_eye1_net7" data-name="US eye1 net7" transform="rotate(-30 -23.1 29)" d="M7.5 40H30v.6H7.5z"/>
|
||||
<path id="US_eye1_net6" data-name="US eye1 net6" transform="rotate(-30 -20.7 27.9)" d="M20.8 27.8h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net5" data-name="US eye1 net5" transform="rotate(-30 -24.6 26.5)" d="M6 37.5h22.5v.6H6z"/>
|
||||
<path id="US_eye1_net4" data-name="US eye1 net4" transform="rotate(-30 -18.2 26.4)" d="M23.3 26.3h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net3" data-name="US eye1 net3" transform="rotate(-30 -26 24)" d="M4.6 35h22.5v.6H4.6z"/>
|
||||
<path id="US_eye1_net2" data-name="US eye1 net2" transform="rotate(-30 -15.7 25)" d="M25.8 24.9h.6v22.8h-.6z"/>
|
||||
<path id="US_eye1_net1" data-name="US eye1 net1" transform="rotate(-30 -27.4 21.5)" d="M3.2 32.5h22.5v.6H3.2z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g id="g1656">
|
||||
<g data-name="US eye1 black" id="US_eye1_black">
|
||||
<circle id="circle967" r="17.4" cy="17.6" cx="17.6" stroke="#b3b3b3" stroke-width=".3" stroke-miterlimit="10"/>
|
||||
<circle id="circle969" r="17.3" cy="17.6" cx="17.6" fill="none"/>
|
||||
</g>
|
||||
<path id="path1650" d="M5.8 17h19.7l3.1 3.6" fill="none" stroke="#e80000" stroke-width="1.7"/>
|
||||
</g>
|
||||
<g transform="matrix(-1 0 0 1 83.5 0)" id="g1656-6">
|
||||
<g data-name="US eye1 black" id="US_eye1_black-9">
|
||||
<circle id="circle967-5" r="17.4" cy="17.6" cx="17.6" stroke="#b3b3b3" stroke-width=".3" stroke-miterlimit="10"/>
|
||||
<circle id="circle969-1" r="17.3" cy="17.6" cx="17.6" fill="none"/>
|
||||
</g>
|
||||
<path id="path1650-4" d="M5.8 17h19.7l3.1 3.6" fill="none" stroke="#e80000" stroke-width="1.7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
`;
|
||||
}
|
16
sim/visuals/assets/remote.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="371.7" height="418.7" viewBox="0 0 98.3 110.8" id="svg8">
|
||||
<g id="layer1" transform="translate(0 -186.2)">
|
||||
<rect id="rect90-3" width="72.7" height="9.6" x="12.1" y="186.5" rx="2.1" fill="#666" stroke="#000" stroke-width=".5"/>
|
||||
<rect id="rect90" width="73.1" height="9.6" x="12.2" y="287.1" rx="2.1" stroke="#000" stroke-width=".5"/>
|
||||
<path d="M14.3 193.2c-1.1 0-2.1 1-2.1 2.1v15.5H2.4c-1.2 0-2.1 1-2.1 2.1v73.7c0 1.1 1 2.1 2.1 2.1h9.8v.6c0 1.2 1 2.1 2.1 2.1h68.3c1.2 0 2.2-1 2.2-2.1v-.6h11.1c1.2 0 2.2-1 2.2-2.1v-73.7c0-1.1-1-2.1-2.2-2.1H84.8v-15.5c0-1.2-1-2.1-2.2-2.1z" id="rect10" fill="#fff" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M31 197.9c7.3 0 7.7 8.2 7.7 9.3v17.4c0 1.2-1 2.2-2.2 2.2H25.7c-1.2 0-2.2-1-2.2-2.2v-17c0-1.1.2-9.7 7.5-9.7z" id="topleft" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M65.5 197.9c7.3 0 7.7 8.2 7.7 9.3v17.4c0 1.2-1 2.2-2.2 2.2H60.2c-1.2 0-2.1-1-2.1-2.2v-17c0-1.1.2-9.7 7.4-9.7z" id="topright" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M65.7 266.3c-7.3 0-7.6-8.2-7.6-9.4v-17.4c0-1.2 1-2.2 2.1-2.2H71c1.2 0 2.2 1 2.2 2.2v17c0 1.2-.2 9.8-7.5 9.8z" id="bottomright" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M31.2 266.3c-7.3 0-7.7-8.2-7.7-9.4v-17.4c0-1.2 1-2.2 2.2-2.2h10.8c1.2 0 2.2 1 2.2 2.2v17c0 1.2-.3 9.8-7.5 9.8z" id="bottomleft" fill="#ccc" stroke="#000" stroke-width="1.1"/>
|
||||
<path d="M27.5 273.6l40.1.1c1.2 0 5.4 6.3 5.4 7.5v5.8c0 1.1-1 2.1-2.2 2.1H25.5c-1.2 0-2.1-1-2.1-2.1v-5.5c0-1.2 3-7.9 4.1-7.9z" id="center" fill="#b3b3b3" stroke="#000" stroke-width="1.1"/>
|
||||
<rect id="rect107" width="15.1" height="3.2" x="23.1" y="231.1" ry="1.3" fill="#247aff" stroke-width=".5"/>
|
||||
<rect id="rect107-1" width="15.1" height="3.2" x="58.2" y="231.1" ry="1.3" fill="#ff242b" stroke-width=".5"/>
|
||||
<circle id="path941" cx="49.2" cy="263.3" r="2.5" fill="#ff242b" stroke-width=".5"/>
|
||||
<circle id="path943" cx="49.2" cy="263.3" r="4.5" fill="none" stroke="#949494" stroke-width=".5"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -230,6 +230,14 @@ namespace pxsim.visuals {
|
||||
view = new DistanceSliderControl(this.element, this.defs, state, port);
|
||||
break;
|
||||
}
|
||||
case NodeType.InfraredSensor: {
|
||||
const state = ev3board().getInputNodes()[port] as InfraredSensorNode;
|
||||
if (state.getMode() == InfraredSensorMode.Proximity)
|
||||
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;
|
||||
}
|
||||
case NodeType.GyroSensor: {
|
||||
const state = ev3board().getInputNodes()[port] as GyroSensorNode;
|
||||
view = new RotationSliderControl(this.element, this.defs, state, port);
|
||||
@ -271,6 +279,8 @@ namespace pxsim.visuals {
|
||||
view = new ColorSensorView(port); break;
|
||||
case NodeType.UltrasonicSensor:
|
||||
view = new UltrasonicSensorView(port); break;
|
||||
case NodeType.InfraredSensor:
|
||||
view = new InfraredView(port); break;
|
||||
case NodeType.Brick:
|
||||
//return new BrickView(0);
|
||||
view = this.layoutView.getBrick(); break;
|
||||
@ -309,7 +319,7 @@ namespace pxsim.visuals {
|
||||
this.layoutView.unselectBrick();
|
||||
this.resize();
|
||||
});
|
||||
const brick =new BrickView(-1);
|
||||
const brick = new BrickView(-1);
|
||||
brick.setSelected(EV3View.isPreviousBrickSelected());
|
||||
this.layoutView.setBrick(brick, brickCloseIcon);
|
||||
|
||||
|
@ -1,64 +1,33 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class ColorWheelControl extends ControlView<ColorSensorNode> {
|
||||
private group: SVGGElement;
|
||||
private colorGradient: SVGLinearGradientElement;
|
||||
private defs: SVGDefsElement;
|
||||
|
||||
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;
|
||||
}
|
||||
private reporter: SVGTextElement;
|
||||
private rect: SVGElement;
|
||||
|
||||
getInnerWidth() {
|
||||
return CONTROL_WIDTH;
|
||||
return 111;
|
||||
}
|
||||
|
||||
getInnerHeight() {
|
||||
return CONTROL_WIDTH;
|
||||
return 192;
|
||||
}
|
||||
|
||||
private getReporterHeight() {
|
||||
return 58;
|
||||
}
|
||||
|
||||
private getSliderWidth() {
|
||||
return 62;
|
||||
}
|
||||
|
||||
private getSliderHeight() {
|
||||
return 111;
|
||||
}
|
||||
|
||||
private getMax() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
updateState() {
|
||||
@ -67,16 +36,68 @@ namespace pxsim.visuals {
|
||||
}
|
||||
const node = this.state;
|
||||
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) {
|
||||
const width = CONTROL_WIDTH;
|
||||
updateColorLevel(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
138
sim/visuals/controls/proximitySlider.ts
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
|
||||
namespace pxsim.visuals {
|
||||
|
||||
export class ProximitySliderControl extends ControlView<InfraredSensorNode> {
|
||||
private group: SVGGElement;
|
||||
private gradient: SVGLinearGradientElement;
|
||||
private slider: SVGGElement;
|
||||
|
||||
private reporter: SVGTextElement;
|
||||
|
||||
private static SLIDER_HANDLE_HEIGHT = 26;
|
||||
private static SLIDER_SIDE_PADDING = 6;
|
||||
|
||||
getInnerView(parent: SVGSVGElement, globalDefs: SVGDefsElement) {
|
||||
let gid = "gradient-slider-" + this.getId();
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
this.gradient = createGradient(gid, this.getGradientDefinition());
|
||||
this.gradient.setAttribute('x1', '0%');
|
||||
this.gradient.setAttribute('y1', '0%');
|
||||
this.gradient.setAttribute('x2', '0%');
|
||||
this.gradient.setAttribute('y2', '100%');
|
||||
// this.gradient.setAttribute('gradientTransform', 'matrix(50, 0, 0, -110, 21949.45, 46137.67)');
|
||||
// this.gradient.setAttribute('gradientUnits', 'userSpaceOnUse');
|
||||
globalDefs.appendChild(this.gradient);
|
||||
|
||||
this.group = svg.elt("g") as SVGGElement;
|
||||
|
||||
const reporterGroup = pxsim.svg.child(this.group, "g");
|
||||
reporterGroup.setAttribute("transform", `translate(${this.getWidth() / 2}, 42)`);
|
||||
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': ProximitySliderControl.SLIDER_SIDE_PADDING, 'y': 2, 'width': this.getSliderWidth() - ProximitySliderControl.SLIDER_SIDE_PADDING * 2, 'height': this.getSliderHeight(), 'style': `fill: url(#${gid})` });
|
||||
|
||||
this.slider = pxsim.svg.child(sliderGroup, "g", { "transform": "translate(0,0)" }) as SVGGElement;
|
||||
const sliderInner = pxsim.svg.child(this.slider, "g");
|
||||
pxsim.svg.child(sliderInner, "rect", { 'width': this.getSliderWidth(), 'height': ProximitySliderControl.SLIDER_HANDLE_HEIGHT, 'rx': '2', 'ry': '2', 'style': 'fill: #f12a21' });
|
||||
pxsim.svg.child(sliderInner, "rect", { 'x': '0.5', 'y': '0.5', 'width': this.getSliderWidth() - 1, 'height': ProximitySliderControl.SLIDER_HANDLE_HEIGHT - 1, 'rx': '1.5', 'ry': '1.5', 'style': 'fill: none;stroke: #b32e29' });
|
||||
|
||||
const dragSurface = svg.child(this.group, "rect", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.getInnerWidth(),
|
||||
height: this.getInnerHeight(),
|
||||
opacity: 0,
|
||||
cursor: '-webkit-grab'
|
||||
})
|
||||
|
||||
let pt = parent.createSVGPoint();
|
||||
let captured = false;
|
||||
|
||||
touchEvents(dragSurface, ev => {
|
||||
if (captured && (ev as MouseEvent).clientY != undefined) {
|
||||
ev.preventDefault();
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, ev => {
|
||||
captured = true;
|
||||
if ((ev as MouseEvent).clientY != undefined) {
|
||||
dragSurface.setAttribute('cursor', '-webkit-grabbing');
|
||||
this.updateSliderValue(pt, parent, ev as MouseEvent);
|
||||
}
|
||||
}, () => {
|
||||
captured = false;
|
||||
dragSurface.setAttribute('cursor', '-webkit-grab');
|
||||
}, () => {
|
||||
captured = false;
|
||||
dragSurface.setAttribute('cursor', '-webkit-grab');
|
||||
})
|
||||
|
||||
return this.group;
|
||||
}
|
||||
|
||||
getInnerHeight() {
|
||||
return 192;
|
||||
}
|
||||
|
||||
getInnerWidth() {
|
||||
return 111;
|
||||
}
|
||||
|
||||
private getReporterHeight() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
private getSliderHeight() {
|
||||
return 110;
|
||||
}
|
||||
|
||||
private getSliderWidth() {
|
||||
return 62;
|
||||
}
|
||||
|
||||
updateState() {
|
||||
if (!this.visible) {
|
||||
return;
|
||||
}
|
||||
const node = this.state;
|
||||
const percentage = node.getValue();
|
||||
const y = this.getSliderHeight() * percentage / this.getMax();
|
||||
this.slider.setAttribute("transform", `translate(0, ${y - ProximitySliderControl.SLIDER_HANDLE_HEIGHT / 2})`);
|
||||
// Update reporter text
|
||||
this.reporter.textContent = `${parseFloat((percentage).toString()).toFixed(0)}`;
|
||||
}
|
||||
|
||||
private updateSliderValue(pt: SVGPoint, parent: SVGSVGElement, ev: MouseEvent) {
|
||||
let cur = svg.cursorPoint(pt, parent, ev);
|
||||
const height = this.getSliderHeight();
|
||||
const bBox = this.content.getBoundingClientRect();
|
||||
let t = Math.max(0, Math.min(1, (ProximitySliderControl.SLIDER_HANDLE_HEIGHT + height + bBox.top / this.scaleFactor - cur.y / this.scaleFactor) / height))
|
||||
|
||||
const state = this.state;
|
||||
const v = Math.floor((1 - t) * (this.getMax()));
|
||||
state.setPromixity(v);
|
||||
}
|
||||
|
||||
private getMin() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private getMax() {
|
||||
return 100;
|
||||
}
|
||||
|
||||
private getGradientDefinition(): LinearGradientDefinition {
|
||||
return {
|
||||
stops: [
|
||||
{ offset: 0, color: '#626262' },
|
||||
{ offset: 100, color: "#ddd" }
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
57
sim/visuals/controls/remoteBeaconButtons.ts
Normal 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.25, 0.25)`)
|
||||
|
||||
const xml = pxsim.visuals.normalizeXml(this.id, pxsim.visuals.REMOVE_SVG);
|
||||
const content = svg.parseString(xml);
|
||||
this.group.appendChild(content);
|
||||
|
||||
const btns: Map<InfraredRemoteButton> = {
|
||||
"center": 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 98.3;
|
||||
}
|
||||
|
||||
getInnerHeight() {
|
||||
return 110.8;
|
||||
}
|
||||
}
|
||||
}
|
10
sim/visuals/nodes/infraredview.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/// <reference path="./moduleView.ts" />
|
||||
|
||||
namespace pxsim.visuals {
|
||||
export class InfraredView extends ModuleView implements LayoutElement {
|
||||
|
||||
constructor(port: number) {
|
||||
super(INFRARED_SVG, "infrared", NodeType.InfraredSensor, port);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,20 @@
|
||||
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 {
|
||||
protected content: SVGSVGElement;
|
||||
@ -9,21 +25,11 @@ namespace pxsim.visuals {
|
||||
|
||||
constructor(protected xml: string, protected prefix: string, protected id: NodeType, protected port: NodeType) {
|
||||
super();
|
||||
this.xml = this.normalizeXml(xml);
|
||||
this.xml = normalizeXml(this.prefix, xml);
|
||||
}
|
||||
|
||||
private normalizeXml(xml: string) {
|
||||
const prefix = this.prefix;
|
||||
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;
|
||||
return pxsim.visuals.normalizeXml(this.prefix, xml);
|
||||
}
|
||||
|
||||
protected normalizeId(svgId: string) {
|
||||
|
@ -5,7 +5,7 @@ tests.test("lgB set speed 10", () => {
|
||||
tests.assertClose("speedB", 10, motors.largeB.speed(), 2)
|
||||
});
|
||||
tests.test("lgB set speed 25 (reversed)", () => {
|
||||
motors.largeB.setReversed(true)
|
||||
motors.largeB.setInverted(true)
|
||||
motors.largeB.setSpeed(25)
|
||||
loops.pause(500)
|
||||
tests.assertClose("speedB", -25, motors.largeB.speed(), 2)
|
||||
|