Compare commits
116 Commits
Author | SHA1 | Date | |
---|---|---|---|
25fded6afb | |||
fc6fb0811f | |||
49bedcbcc5 | |||
32876f4584 | |||
da9bea30b5 | |||
d0aa68aeee | |||
51731fbbc9 | |||
751ea1494b | |||
dfe84471e8 | |||
0f3de6cf07 | |||
21195e4abf | |||
c992100a38 | |||
20a4673f98 | |||
966fd81870 | |||
cb9d2aeb39 | |||
3cee55f4c2 | |||
3815d2fd3b | |||
1453b7e0a3 | |||
6fb5c54280 | |||
9d5ca35e83 | |||
893dd0f9c4 | |||
c3419c0b74 | |||
a4164470d8 | |||
0dd5ab9bde | |||
e93e659e8a | |||
8357372fb5 | |||
54cb076002 | |||
dbd3eb464b | |||
10cd39a4ec | |||
fddc4e647a | |||
798a351f15 | |||
e61dffff03 | |||
b9f5096480 | |||
9912d68c8b | |||
951b9be6e4 | |||
aa8635c4e7 | |||
4e4f5495da | |||
f64bf57000 | |||
f1242724b5 | |||
cd0c9df86e | |||
337d42287a | |||
ce3383f1b7 | |||
e51721303a | |||
50f6c77fdb | |||
5ed0135124 | |||
892a2d585f | |||
9890f2340a | |||
109b809909 | |||
9cbf5efd7e | |||
a27a7fcd55 | |||
85263fb84d | |||
b5ad898c9e | |||
456df3c442 | |||
1552eb05b4 | |||
d60e2c4a7d | |||
f4b78c3ee7 | |||
dd5e1957d5 | |||
d61a63f70a | |||
4207bd06c0 | |||
58763e398b | |||
f77bf165eb | |||
4880d9ea5b | |||
ab4fb019f9 | |||
2c2df31ba3 | |||
0f2bda2496 | |||
44386be3c7 | |||
89ca66b8a9 | |||
64389a7689 | |||
f77778ef85 | |||
7d01823caf | |||
b3f9a4c92f | |||
7fe8580de8 | |||
c70d6fe01a | |||
ed7099cc97 | |||
a79704fecc | |||
6a1b560101 | |||
5e21f9ab6d | |||
74648bd1df | |||
e24d4d56b1 | |||
0345277bef | |||
9ae6482f28 | |||
77fb64043d | |||
f875681661 | |||
fbb1fa688d | |||
485f02ed27 | |||
81f406c6cc | |||
ac0a7b326f | |||
c814728354 | |||
abeb378b17 | |||
6928f9e50e | |||
931987468a | |||
94c4e508fe | |||
ea46f1cbc7 | |||
9f9ce29476 | |||
50f6b04ed4 | |||
64d6c2b090 | |||
76ff39605a | |||
2d3ea5631a | |||
e938f354fd | |||
886464b470 | |||
b9ff9d21f1 | |||
aa06fd344a | |||
dc6ce0efc7 | |||
4039a85bc9 | |||
7bd6280292 | |||
2ebe96e563 | |||
a9be582f90 | |||
ac428a3936 | |||
de91dc6ab7 | |||
1e460eef9e | |||
0db6987ee5 | |||
148657908c | |||
f3f87331c8 | |||
5aef77ccc6 | |||
16b9a5027d | |||
cbe68b3199 |
@ -4,7 +4,8 @@
|
||||
|
||||
This repo contains the editor target hosted at https://d541eec2-1e96-4b7b-a223-da9d01d0337a.pxt.io/
|
||||
|
||||
Issue tracker: https://src.education.lego.com/groups/ev3-makecode
|
||||
LEGO Auth: https://src.education.lego.com/groups/ev3-makecode (use Google Authenticator)
|
||||
LEGO Chat: https://chat.internal.education.lego.com/make-code/channels/town-square
|
||||
|
||||
## Local Dev setup
|
||||
|
||||
|
@ -2,14 +2,10 @@
|
||||
|
||||
import * as fs from 'fs';
|
||||
|
||||
require("./editor/deploy")
|
||||
|
||||
declare namespace pxt.editor {
|
||||
function deployCoreAsync(resp: pxtc.CompileResult, disconnect?: boolean): Promise<void>;
|
||||
}
|
||||
const deploy = require("./editor/deploy")
|
||||
|
||||
export function deployCoreAsync(resp: pxtc.CompileResult) {
|
||||
return pxt.editor.deployCoreAsync(resp, process.env["PXT_SERIAL"] ? false : true)
|
||||
return deploy.deployCoreAsync(resp, process.env["PXT_SERIAL"] ? false : true)
|
||||
.then(() => {
|
||||
fs.writeFileSync("built/full-" + pxtc.BINARY_UF2, resp.outfiles[pxtc.BINARY_UF2], {
|
||||
encoding: "base64"
|
||||
|
171
docs/coding.md
Normal file
171
docs/coding.md
Normal file
@ -0,0 +1,171 @@
|
||||
# Coding Activites
|
||||
|
||||
12 computer science activities, with cross-curricular opportunities in design and technology, science, and math.
|
||||
|
||||
* [Download Curriculum Materials](https://education.lego.com/en-us/downloads/mindstorms-ev3)
|
||||
|
||||
## Three Point Turn
|
||||
|
||||
```codecard
|
||||
[
|
||||
{
|
||||
"name": "Three Point Turn 1",
|
||||
"description": "Activity 1",
|
||||
"url":"/coding/three-point-turn-1",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Three Point Turn 2",
|
||||
"description": "Activity 2",
|
||||
"url":"/coding/three-point-turn-2",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Three Point Turn 3",
|
||||
"description": "Activity 3",
|
||||
"url":"/coding/three-point-turn-3",
|
||||
"cardType": "example"
|
||||
}]
|
||||
```
|
||||
|
||||
## Reversing the robot
|
||||
|
||||
```codecard
|
||||
[{
|
||||
"name": "Reversing the robot 1",
|
||||
"description": "Activity 1",
|
||||
"url":"/coding/reversing-the-robot-1",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Reversing the robot 2",
|
||||
"description": "Activity 2",
|
||||
"url":"/coding/reversing-the-robot-2",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Reversing the robot 3",
|
||||
"description": "Activity 3",
|
||||
"url":"/coding/reversing-the-robot-3",
|
||||
"cardType": "example"
|
||||
}]
|
||||
```
|
||||
|
||||
## Light the way
|
||||
|
||||
```codecard
|
||||
[{
|
||||
"name": "Light the way 1",
|
||||
"description": "Activity 1",
|
||||
"url":"/coding/light-the-way-1",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Light the way 2",
|
||||
"description": "Activity 2",
|
||||
"url":"/coding/light-the-way-2",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Light the way 3",
|
||||
"description": "Activity 3",
|
||||
"url":"/coding/light-the-way-3",
|
||||
"cardType": "example"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Traffic Lights
|
||||
|
||||
```codecard
|
||||
[{
|
||||
"name": "Traffic Lights 1",
|
||||
"description": "Activity 1",
|
||||
"url":"/coding/traffic-lights-1",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Traffic Lights 2",
|
||||
"description": "Activity 2",
|
||||
"url":"/coding/traffic-lights-2",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Traffic Lights 3",
|
||||
"description": "Activity 3",
|
||||
"url":"/coding/traffic-lights-3",
|
||||
"cardType": "example"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Reverse Bepper
|
||||
|
||||
```codecard
|
||||
[{
|
||||
"name": "Reverse Beeper 1",
|
||||
"description": "Activity 1",
|
||||
"url":"/coding/reverse-beeper-1",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Reverse Beeper 2",
|
||||
"description": "Activity 2",
|
||||
"url":"/coding/reverse-beeper-2",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Reverse Beeper 3",
|
||||
"description": "Activity 3",
|
||||
"url":"/coding/reverse-beeper-3",
|
||||
"cardType": "example"
|
||||
}]
|
||||
```
|
||||
|
||||
## Ignition
|
||||
|
||||
```codecard
|
||||
[{
|
||||
"name": "Ignition 1",
|
||||
"description": "Activity 1",
|
||||
"url":"/coding/ingition-1",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Ignition 2",
|
||||
"description": "Activity 2",
|
||||
"url":"/coding/ignition-2",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Ignition 3",
|
||||
"description": "Activity 3",
|
||||
"url":"/coding/ignition-3",
|
||||
"cardType": "example"
|
||||
}]
|
||||
```
|
||||
|
||||
## Cruise Control
|
||||
|
||||
```codecard
|
||||
[{
|
||||
"name": "Cruise Control 1",
|
||||
"description": "Activity 1",
|
||||
"url":"/coding/cruise-control-1",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Cruise Control 2",
|
||||
"description": "Activity 2",
|
||||
"url":"/coding/cruise-control-2",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Cruise Control 3",
|
||||
"description": "Activity 3",
|
||||
"url":"/coding/cruise-control-3",
|
||||
"cardType": "example"
|
||||
}]
|
||||
```
|
||||
|
||||
## Roaming
|
||||
|
||||
```codecard
|
||||
[{
|
||||
"name": "Roaming 1",
|
||||
"description": "Activity 1",
|
||||
"url":"/coding/roaming-1",
|
||||
"cardType": "example"
|
||||
}, {
|
||||
"name": "Roaming 2",
|
||||
"description": "Activity 2",
|
||||
"url":"/coding/roaming-2",
|
||||
"cardType": "example"
|
||||
}]
|
||||
```
|
10
docs/coding/cruise-control-1.md
Normal file
10
docs/coding/cruise-control-1.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Cruise Control Activity 1
|
||||
|
||||
```blocks
|
||||
let speed = 0;
|
||||
sensors.touch1.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
if (speed < 100)
|
||||
speed = speed + 10;
|
||||
motors.largeBC.setSpeed(speed);
|
||||
})
|
||||
```
|
15
docs/coding/cruise-control-2.md
Normal file
15
docs/coding/cruise-control-2.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Cruise Control Activity 2
|
||||
|
||||
```blocks
|
||||
let speed = 0;
|
||||
sensors.touch1.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
if (speed < 100)
|
||||
speed = speed + 10;
|
||||
motors.largeBC.setSpeed(speed);
|
||||
})
|
||||
sensors.touch2.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
if (speed > -100)
|
||||
speed = speed - 10;
|
||||
motors.largeBC.setSpeed(speed);
|
||||
})
|
||||
```
|
28
docs/coding/cruise-control-3.md
Normal file
28
docs/coding/cruise-control-3.md
Normal file
@ -0,0 +1,28 @@
|
||||
# Cruise Control Activity 3
|
||||
|
||||
```blocks
|
||||
let speed = 0
|
||||
function decelerate() {
|
||||
if (speed > -100) {
|
||||
speed = speed - 10
|
||||
}
|
||||
}
|
||||
function accelerate() {
|
||||
if (speed < 100) {
|
||||
speed = speed + 10
|
||||
}
|
||||
}
|
||||
function update() {
|
||||
brick.clearScreen()
|
||||
brick.showString("speed: " + speed, 1)
|
||||
motors.largeBC.setSpeed(speed)
|
||||
}
|
||||
sensors.touch2.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
accelerate()
|
||||
update()
|
||||
})
|
||||
sensors.touch1.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
decelerate()
|
||||
update()
|
||||
})
|
||||
```
|
11
docs/coding/ignition-1.md
Normal file
11
docs/coding/ignition-1.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Ignition Activity 1
|
||||
|
||||
```blocks
|
||||
sensors.touch1.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
brick.showImage(images.eyesDizzy)
|
||||
})
|
||||
sensors.ultrasonic4.onEvent(UltrasonicSensorEvent.ObjectDetected, function () {
|
||||
brick.showImage(images.eyesTiredMiddle)
|
||||
})
|
||||
brick.showImage(images.eyesSleeping)
|
||||
```
|
12
docs/coding/ignition-2.md
Normal file
12
docs/coding/ignition-2.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Ignition Activity 2
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
if (sensors.touch1.wasPressed() &&
|
||||
sensors.ultrasonic4.distance() < 10) {
|
||||
music.playSoundEffectUntilDone(sounds.mechanicalMotorStart)
|
||||
music.playSoundEffectUntilDone(sounds.mechanicalMotorIdle);
|
||||
}
|
||||
loops.pause(1);
|
||||
}
|
||||
```
|
13
docs/coding/ignition-3.md
Normal file
13
docs/coding/ignition-3.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Ignition Activity 3
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
if (sensors.ultrasonic4.distance() < 10 &&
|
||||
sensors.touch1.wasPressed() &&
|
||||
brick.buttonEnter.wasPressed()) {
|
||||
music.playSoundEffectUntilDone(sounds.mechanicalMotorStart)
|
||||
music.playSoundEffectUntilDone(sounds.mechanicalMotorIdle);
|
||||
}
|
||||
loops.pause(1);
|
||||
}
|
||||
```
|
9
docs/coding/light-the-way-1.md
Normal file
9
docs/coding/light-the-way-1.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Light the way Activity 1
|
||||
|
||||
```blocks
|
||||
sensors.color3.onLightChanged(LightIntensityMode.Ambient, LightCondition.Dark, function () {
|
||||
brick.showImage(images.objectsLightOn)
|
||||
loops.pause(5000)
|
||||
brick.clearScreen()
|
||||
})
|
||||
```
|
10
docs/coding/light-the-way-2.md
Normal file
10
docs/coding/light-the-way-2.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Light the way Activity 2
|
||||
|
||||
```blocks
|
||||
sensors.color3.onLightChanged(LightIntensityMode.Ambient, LightCondition.Bright, function () {
|
||||
brick.clearScreen()
|
||||
})
|
||||
sensors.color3.onLightChanged(LightIntensityMode.Ambient, LightCondition.Dark, function () {
|
||||
brick.showImage(images.objectsLightOn)
|
||||
})
|
||||
```
|
13
docs/coding/light-the-way-3.md
Normal file
13
docs/coding/light-the-way-3.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Light the way Activity 3
|
||||
|
||||
```blocks
|
||||
sensors.color3.onLightChanged(LightIntensityMode.Ambient, LightCondition.Bright, function () {
|
||||
brick.clearScreen()
|
||||
})
|
||||
sensors.color3.onLightChanged(LightIntensityMode.Ambient, LightCondition.Dark, function () {
|
||||
brick.showImage(images.objectsLightOn)
|
||||
})
|
||||
sensors.touch1.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
brick.showImage(images.objectsLightOn);
|
||||
})
|
||||
```
|
11
docs/coding/reverse-beeper-1.md
Normal file
11
docs/coding/reverse-beeper-1.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Reverse Beeper Activity 1
|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
music.playTone(440, sensors.ultrasonic4.distance());
|
||||
loops.pause(50)
|
||||
})
|
||||
motors.largeBC.setSpeed(-20);
|
||||
sensors.ultrasonic4.pauseUntil(UltrasonicSensorEvent.ObjectNear);
|
||||
motors.largeBC.stop();
|
||||
```
|
13
docs/coding/reverse-beeper-2.md
Normal file
13
docs/coding/reverse-beeper-2.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Reverse Beeper Activity 2
|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
if (motors.largeB.speed() != 0 && sensors.ultrasonic4.distance() < 20) {
|
||||
music.playTone(440, sensors.ultrasonic4.distance());
|
||||
loops.pause(50)
|
||||
}
|
||||
})
|
||||
motors.largeBC.setSpeed(-20);
|
||||
sensors.ultrasonic4.pauseUntil(UltrasonicSensorEvent.ObjectNear);
|
||||
motors.largeBC.stop();
|
||||
```
|
20
docs/coding/reverse-beeper-3.md
Normal file
20
docs/coding/reverse-beeper-3.md
Normal file
@ -0,0 +1,20 @@
|
||||
# Reverse Beeper Activity 2
|
||||
|
||||
```blocks
|
||||
let beep = false
|
||||
beep = true
|
||||
control.runInBackground(function () {
|
||||
motors.largeBC.setSpeed(-20)
|
||||
sensors.ultrasonic4.pauseUntil(UltrasonicSensorEvent.ObjectNear)
|
||||
motors.largeBC.stop()
|
||||
beep = false
|
||||
})
|
||||
control.runInBackground(function () {
|
||||
while (beep) {
|
||||
if (sensors.ultrasonic4.distance() < 20) {
|
||||
music.playTone(440, sensors.ultrasonic4.distance())
|
||||
loops.pause(50)
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
14
docs/coding/reversing-the-robot-1.md
Normal file
14
docs/coding/reversing-the-robot-1.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Reversing the robot Activity 1
|
||||
|
||||
```blocks
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
||||
motors.largeBC.setSpeed(50)
|
||||
sensors.touchSensor1.pauseUntil(TouchSensorEvent.Pressed)
|
||||
motors.largeBC.setSpeed(0)
|
||||
loops.pause(1000)
|
||||
brick.setLight(LightsPattern.OrangeFlash)
|
||||
motors.largeBC.setSpeed(-50)
|
||||
loops.pause(2000)
|
||||
motors.largeBC.setSpeed(0)
|
||||
})
|
||||
```
|
15
docs/coding/reversing-the-robot-2.md
Normal file
15
docs/coding/reversing-the-robot-2.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Reversing the robot Activity 2
|
||||
|
||||
```blocks
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
||||
sensors.touchSensor1.pauseUntil(TouchSensorEvent.Pressed)
|
||||
motors.largeBC.setSpeed(50)
|
||||
sensors.touchSensor2.pauseUntil(TouchSensorEvent.Pressed)
|
||||
motors.largeBC.setSpeed(0)
|
||||
loops.pause(1000)
|
||||
brick.setLight(LightsPattern.OrangeFlash)
|
||||
motors.largeBC.setSpeed(-50)
|
||||
loops.pause(2000)
|
||||
motors.largeBC.setSpeed(0)
|
||||
})
|
||||
```
|
19
docs/coding/reversing-the-robot-3.md
Normal file
19
docs/coding/reversing-the-robot-3.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Reversing the robot Activity 3
|
||||
|
||||
```blocks
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
||||
brick.showImage(images.eyesSleeping)
|
||||
sensors.touchSensor1.pauseUntil(TouchSensorEvent.Pressed)
|
||||
brick.showImage(images.eyesNeutral)
|
||||
motors.largeBC.setSpeed(50)
|
||||
sensors.touchSensor2.pauseUntil(TouchSensorEvent.Pressed)
|
||||
brick.showImage(images.eyesTiredMiddle)
|
||||
motors.largeBC.setSpeed(0)
|
||||
loops.pause(1000)
|
||||
brick.setLight(LightsPattern.OrangeFlash)
|
||||
brick.showImage(images.eyesDizzy)
|
||||
motors.largeBC.setSpeed(-50)
|
||||
loops.pause(2000)
|
||||
motors.largeBC.setSpeed(0)
|
||||
})
|
||||
```
|
36
docs/coding/roaming-1.md
Normal file
36
docs/coding/roaming-1.md
Normal file
@ -0,0 +1,36 @@
|
||||
# Roaming Activity 1
|
||||
|
||||
```blocks
|
||||
let drive: number[] = []
|
||||
brick.buttonLeft.onEvent(ButtonEvent.Click, function () {
|
||||
drive.push(1)
|
||||
})
|
||||
brick.buttonRight.onEvent(ButtonEvent.Click, function () {
|
||||
drive.push(3)
|
||||
})
|
||||
brick.buttonUp.onEvent(ButtonEvent.Click, function () {
|
||||
drive.push(4)
|
||||
})
|
||||
brick.buttonDown.onEvent(ButtonEvent.Click, function () {
|
||||
drive.push(5)
|
||||
})
|
||||
pauseUntil(() => drive.length >= 5)
|
||||
loops.pause(1000)
|
||||
music.playSoundEffectUntilDone(sounds.communicationGo)
|
||||
for (let d of drive) {
|
||||
if (d == 1) {
|
||||
motors.largeC.setSpeedFor(50, 360, MoveUnit.Degrees)
|
||||
motors.largeC.pauseUntilReady()
|
||||
} else if (d == 3) {
|
||||
motors.largeB.setSpeedFor(50, 360, MoveUnit.Degrees)
|
||||
motors.largeB.pauseUntilReady()
|
||||
} else if (d == 4) {
|
||||
motors.largeBC.setSpeedFor(50, 360, MoveUnit.Degrees)
|
||||
motors.largeBC.pauseUntilReady()
|
||||
} else {
|
||||
motors.largeBC.setSpeedFor(-50, 360, MoveUnit.Degrees)
|
||||
motors.largeBC.pauseUntilReady()
|
||||
}
|
||||
}
|
||||
music.playSoundEffectUntilDone(sounds.communicationGameOver)
|
||||
```
|
40
docs/coding/roaming-2.md
Normal file
40
docs/coding/roaming-2.md
Normal file
@ -0,0 +1,40 @@
|
||||
# Roaming Activity 2
|
||||
|
||||
```blocks
|
||||
let drive: number[] = []
|
||||
brick.buttonLeft.onEvent(ButtonEvent.Click, function () {
|
||||
drive.push(1)
|
||||
music.playSoundEffectUntilDone(sounds.systemClick)
|
||||
})
|
||||
brick.buttonRight.onEvent(ButtonEvent.Click, function () {
|
||||
drive.push(3)
|
||||
music.playSoundEffectUntilDone(sounds.systemClick)
|
||||
})
|
||||
brick.buttonUp.onEvent(ButtonEvent.Click, function () {
|
||||
drive.push(4)
|
||||
music.playSoundEffectUntilDone(sounds.systemClick)
|
||||
})
|
||||
brick.buttonDown.onEvent(ButtonEvent.Click, function () {
|
||||
drive.push(5)
|
||||
music.playSoundEffectUntilDone(sounds.systemClick)
|
||||
})
|
||||
brick.buttonEnter.pauseUntil(ButtonEvent.Click);
|
||||
loops.pause(1000)
|
||||
music.playSoundEffectUntilDone(sounds.communicationGo)
|
||||
for (let d of drive) {
|
||||
if (d == 1) {
|
||||
motors.largeC.setSpeedFor(50, 360, MoveUnit.Degrees)
|
||||
motors.largeC.pauseUntilReady()
|
||||
} else if (d == 3) {
|
||||
motors.largeB.setSpeedFor(50, 360, MoveUnit.Degrees)
|
||||
motors.largeB.pauseUntilReady()
|
||||
} else if (d == 4) {
|
||||
motors.largeBC.setSpeedFor(50, 360, MoveUnit.Degrees)
|
||||
motors.largeBC.pauseUntilReady()
|
||||
} else {
|
||||
motors.largeBC.setSpeedFor(-50, 360, MoveUnit.Degrees)
|
||||
motors.largeBC.pauseUntilReady()
|
||||
}
|
||||
}
|
||||
music.playSoundEffectUntilDone(sounds.communicationGameOver)
|
||||
```
|
12
docs/coding/three-point-turn-1.md
Normal file
12
docs/coding/three-point-turn-1.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Three Point Turn Activity 1
|
||||
|
||||
```blocks
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
||||
motors.largeBC.tank(75, 30)
|
||||
loops.pause(1500)
|
||||
motors.largeBC.tank(-30, -75)
|
||||
loops.pause(1000)
|
||||
motors.largeBC.tank(50, 50)
|
||||
loops.pause(3000)
|
||||
})
|
||||
```
|
14
docs/coding/three-point-turn-2.md
Normal file
14
docs/coding/three-point-turn-2.md
Normal file
@ -0,0 +1,14 @@
|
||||
# Three Point Turn Activity 2
|
||||
|
||||
```blocks
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
||||
motors.largeBC.tank(75, 30)
|
||||
loops.pause(1500)
|
||||
motors.largeBC.tank(-30, -75)
|
||||
sensors.ultrasonic4.pauseUntil(UltrasonicSensorEvent.ObjectNear);
|
||||
motors.largeBC.tank(0, 0)
|
||||
loops.pause(1000)
|
||||
motors.largeBC.tank(50, 50)
|
||||
loops.pause(3000)
|
||||
})
|
||||
```
|
15
docs/coding/three-point-turn-3.md
Normal file
15
docs/coding/three-point-turn-3.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Three Point Turn Activity 3
|
||||
|
||||
```blocks
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
||||
motors.largeBC.tank(75, 30)
|
||||
loops.pause(1500)
|
||||
motors.largeBC.tank(-30, -75)
|
||||
sensors.ultrasonic4.pauseUntil(UltrasonicSensorEvent.ObjectNear);
|
||||
motors.largeBC.tank(0, 0)
|
||||
music.playSoundEffect(sounds.animalsDogBark1)
|
||||
loops.pause(1000)
|
||||
motors.largeBC.tank(50, 50)
|
||||
loops.pause(3000)
|
||||
})
|
||||
```
|
9
docs/coding/traffic-lights-1.md
Normal file
9
docs/coding/traffic-lights-1.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Traffic Lights Activity 1
|
||||
|
||||
```blocks
|
||||
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
|
||||
motors.largeBC.tank(20, 20)
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Red)
|
||||
motors.largeBC.tank(0, 0)
|
||||
})
|
||||
```
|
10
docs/coding/traffic-lights-2.md
Normal file
10
docs/coding/traffic-lights-2.md
Normal file
@ -0,0 +1,10 @@
|
||||
# Traffic Lights Activity 2
|
||||
|
||||
```blocks
|
||||
sensors.color3.onColorDetected(ColorSensorColor.Red, function () {
|
||||
motors.largeBC.tank(0, 0)
|
||||
})
|
||||
sensors.color3.onColorDetected(ColorSensorColor.Green, function () {
|
||||
motors.largeBC.tank(20, 20)
|
||||
})
|
||||
```
|
11
docs/coding/traffic-lights-3.md
Normal file
11
docs/coding/traffic-lights-3.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Traffic Lights Activity 3
|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
if (sensors.color3.light(LightIntensityMode.Reflected) < 15) {
|
||||
motors.largeBC.tank(30, 12)
|
||||
} else {
|
||||
motors.largeBC.tank(12, 30)
|
||||
}
|
||||
})
|
||||
```
|
50
docs/examples/line-follower-pid.md
Normal file
50
docs/examples/line-follower-pid.md
Normal file
@ -0,0 +1,50 @@
|
||||
# Gradien follower PID + calibration
|
||||
|
||||
```blocks
|
||||
let lasterror = 0
|
||||
let D = 0
|
||||
let I = 0
|
||||
let P = 0
|
||||
let error = 0
|
||||
let setpoint = 0
|
||||
let max = 0
|
||||
let min = 0
|
||||
let v = 0
|
||||
v = sensors.color3.light(LightIntensityMode.Reflected)
|
||||
min = v
|
||||
max = v
|
||||
setpoint = v
|
||||
while (!(brick.buttonEnter.wasPressed())) {
|
||||
brick.clearScreen()
|
||||
brick.showString("Move robot on terrain", 1)
|
||||
brick.showString("Press ENTER when done", 2)
|
||||
v = sensors.color3.light(LightIntensityMode.Reflected)
|
||||
min = Math.min(min, v)
|
||||
max = Math.max(max, v)
|
||||
setpoint = (max + min) / 2
|
||||
brick.showValue("v", v, 3)
|
||||
brick.showValue("min", min, 4)
|
||||
brick.showValue("max", v, 5)
|
||||
brick.showValue("setpoint", setpoint, 6)
|
||||
loops.pause(100)
|
||||
}
|
||||
loops.forever(function () {
|
||||
brick.clearScreen()
|
||||
v = sensors.color3.light(LightIntensityMode.Reflected)
|
||||
brick.showValue("light", v, 1)
|
||||
error = v - setpoint
|
||||
brick.showValue("error", error, 2)
|
||||
P = error * 5
|
||||
brick.showValue("P", P, 3)
|
||||
I = I + error * 0.01
|
||||
brick.showValue("I", I, 4)
|
||||
D = (error - lasterror) * 0.2
|
||||
brick.showValue("D", D, 5)
|
||||
motors.largeBC.steer(P + (I + D), 100)
|
||||
lasterror = error
|
||||
if (brick.buttonEnter.wasPressed()) {
|
||||
motors.largeBC.setSpeed(0)
|
||||
brick.buttonDown.pauseUntil(ButtonEvent.Click)
|
||||
}
|
||||
})
|
||||
```
|
109
docs/static/avatar.svg
vendored
Normal file
109
docs/static/avatar.svg
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 22.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1"
|
||||
id="svg2" inkscape:version="0.91 r13725" sodipodi:docname="avatar.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 32 32"
|
||||
style="enable-background:new 0 0 32 32;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#303030;}
|
||||
</style>
|
||||
<sodipodi:namedview bordercolor="#666666" borderopacity="1" gridtolerance="10" guidetolerance="10" id="namedview15" inkscape:current-layer="svg2" inkscape:cx="16" inkscape:cy="16" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-height="661" inkscape:window-maximized="0" inkscape:window-width="997" inkscape:window-x="0" inkscape:window-y="0" inkscape:zoom="5.2149125" objecttolerance="10" pagecolor="#ffffff" showgrid="false">
|
||||
</sodipodi:namedview>
|
||||
<g id="avatar_mf" transform="translate(-5304.979 8145.745)">
|
||||
<path id="Path_180" class="st0" d="M5317.1-8125.6c0.2,0,0.3-0.1,0.5-0.1l2.9-0.6c1.3-0.3,2.5-0.5,3.8-0.8c0.5-0.1,1-0.2,1.5-0.3
|
||||
c0.1,0,0.1,0,0.1-0.1c0-0.5,0-1-0.1-1.5c-0.1-0.6-0.2-1.1-0.3-1.7c-0.1-0.4-0.1-0.8-0.2-1.2c-0.1-0.7-0.2-1.4-0.3-2
|
||||
c-0.1-0.6-0.2-1.1-0.3-1.7c0-0.2-0.2-0.4-0.4-0.4c0,0,0,0-0.1,0c-0.2,0-0.5,0.1-0.7,0.1c-0.5,0.1-1,0.1-1.5,0.2
|
||||
c-0.5,0.1-1,0.1-1.6,0.2c-0.5,0.1-1,0.1-1.4,0.2c-0.2,0-0.3,0-0.5,0.1c-0.2,0-0.4,0.2-0.5,0.4c0,0.2-0.1,0.4-0.1,0.5
|
||||
c0,0.4-0.1,0.8-0.1,1.2c-0.1,0.5-0.1,1-0.2,1.5c0,0.4-0.1,0.9-0.1,1.3l-0.1,1.3l-0.1,1.3c-0.1,0.5-0.1,1-0.2,1.5
|
||||
C5317.1-8126,5317.1-8125.8,5317.1-8125.6z"/>
|
||||
<path id="Path_181" class="st0" d="M5316.1-8140c0,0.6,0.1,1.2,0.1,1.8c0,0.4,0.2,0.8,0.6,1c0.3,0.2,0.7,0.3,1.1,0.3
|
||||
c0.7,0.1,1.4,0.1,2.1,0c0.6,0,1.2-0.1,1.8-0.2c0.4,0,0.9-0.2,1.2-0.5c0.3-0.3,0.5-0.7,0.5-1.1c0-1.2,0-2.3-0.1-3.5
|
||||
c0-0.3-0.1-0.6-0.3-0.8c-0.3-0.4-0.8-0.6-1.4-0.6c0,0,0,0-0.1,0c-0.2,0.1-0.4,0.1-0.6,0.1c-0.9,0-1.8,0.1-2.7,0.1
|
||||
c-0.1,0-0.3,0-0.4,0c-0.4-0.1-0.8,0-1.2,0.2c-0.4,0.2-0.6,0.6-0.7,1c0,0.1,0,0.2,0,0.3C5316-8141.2,5316.1-8140.6,5316.1-8140
|
||||
L5316.1-8140z"/>
|
||||
<path id="Path_182" class="st0" d="M5312-8129.2c0,0.6,0,1.2,0,1.8c0,0.1,0,0.1,0.1,0.1c0.3,0,0.6,0.1,0.9,0.1c0.3,0,0.7,0,1,0
|
||||
c0.1,0,0.2,0,0.3,0c0.1,0,0.1,0,0.1-0.1c0.1-0.4,0.2-0.8,0.2-1.2c0.1-0.5,0.2-1,0.3-1.4c0-0.1,0.1-0.1,0.1-0.1
|
||||
c0.4-0.2,0.8-0.5,1.2-0.8c0.4-0.4,0.7-0.9,0.8-1.5c0.1-0.6,0-1.2-0.4-1.7c-0.2-0.3-0.6-0.4-0.9-0.3c-0.3,0.1-0.6,0.3-0.9,0.5
|
||||
c-0.7,0.6-1.5,1.2-2.2,1.8c-0.3,0.2-0.5,0.5-0.6,0.8c0,0.2-0.1,0.4-0.1,0.6C5311.9-8130.2,5311.9-8129.7,5312-8129.2
|
||||
C5311.9-8129.2,5312-8129.2,5312-8129.2z"/>
|
||||
<path id="Path_183" class="st0" d="M5315.5-8124.7c0,0.2-0.1,0.5-0.1,0.7c-0.1,0.5-0.4,0.9-0.8,1.1c0,0,0,0,0,0
|
||||
c-0.1,0-0.2,0.2-0.2,0.3c-0.4,1.4-0.9,2.7-1.3,4.1c0,0,0,0.1,0,0.1c0.8,1.1,1.6,2.2,2.4,3.3c0,0,0,0,0.1,0.1
|
||||
c0.1-0.2,0.1-0.3,0.2-0.5c0.1-0.3,0.2-0.5,0.3-0.8c0,0,0-0.1,0-0.1c-0.2-0.3-0.5-0.7-0.7-1c0,0,0-0.1,0-0.2
|
||||
c0.3-0.9,0.6-1.7,0.9-2.6c0,0,0-0.1,0.1-0.1c0.5-0.2,0.9-0.6,1.1-1.1c0.1-0.3,0.1-0.7,0.1-1.1c0-0.4-0.1-0.8-0.3-1.2
|
||||
c-0.2-0.4-0.5-0.8-1-1C5315.9-8124.7,5315.7-8124.7,5315.5-8124.7z"/>
|
||||
<path id="Path_184" class="st0" d="M5314.7-8134.2c0.1-0.1,0.2-0.1,0.3-0.2c0.3-0.2,0.7-0.3,1-0.3c0.4,0,0.7,0.2,0.8,0.6
|
||||
c0.6,1.1,0.5,2.4-0.4,3.3c-0.4,0.4-0.8,0.7-1.3,1c0,0-0.1,0.1-0.1,0.1c-0.2,0.8-0.3,1.6-0.5,2.5c0,0,0,0.1,0,0.1
|
||||
c0,0.2,0,0.2-0.2,0.2c-0.1,0-0.1,0-0.2,0c0,0.1,0,0.2,0,0.3c0,0,0,0,0.1,0.1l1.9,0.7c0.2,0.1,0.4,0.2,0.7,0.2c0-0.1,0-0.2,0-0.2
|
||||
c0-0.3,0-0.6,0-0.8l0.2-1.5l0.2-1.5c0.1-0.5,0.1-1,0.2-1.5c0.1-0.5,0.1-1.1,0.2-1.6c0.1-0.5,0.1-1,0.2-1.5c0-0.2,0-0.4,0-0.6
|
||||
c0-0.2-0.1-0.4-0.3-0.4c0,0,0,0,0,0c-0.1,0-0.1,0-0.2,0c-0.6-0.1-1.2-0.2-1.9-0.3c-0.1,0-0.2,0-0.3,0c-0.1,0-0.2,0.1-0.3,0.3
|
||||
C5314.8-8135,5314.7-8134.6,5314.7-8134.2z"/>
|
||||
<path id="Path_185" class="st0" d="M5324.5-8117.2c-0.2-0.7-0.5-1.3-0.7-2l-0.7,0.3c0,0-0.1,0-0.1,0c-0.1,0.1-0.2,0-0.2-0.1
|
||||
c-0.1-0.3-0.2-0.5-0.3-0.8c-0.2-0.7-0.5-1.4-0.7-2.1c0,0,0-0.1,0-0.1c0,0,0,0.1-0.1,0.1c-0.1,0.2-0.3,0.3-0.5,0.5c0,0-0.1,0-0.1,0
|
||||
c-0.3,0.1-0.6,0.1-0.8,0.2c0,0-0.1,0-0.1,0c0,0.2-0.1,0.3-0.1,0.5c0.6,1.5,1.1,3.1,1.7,4.6c0,0,0,0,0,0.1
|
||||
C5322.7-8116.3,5323.6-8116.7,5324.5-8117.2z"/>
|
||||
<path id="Path_186" class="st0" d="M5325.4-8123.1c-0.7,0.2-1.3,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.4,0.3c-0.1,0-0.2,0.1-0.1,0.2
|
||||
c0,0,0,0,0,0.1c0.2,0.5,0.3,0.9,0.5,1.4c0.2,0.5,0.4,1.1,0.6,1.6c0,0,0,0,0,0c0.1-0.1,0.2-0.1,0.3-0.2c0.2-0.1,0.3-0.2,0.5-0.2
|
||||
c0.2-0.1,0.4-0.1,0.6-0.2c0.7-0.2,1.5-0.4,2.2-0.6c0,0,0,0,0.1,0C5326.3-8121.1,5325.9-8122.1,5325.4-8123.1z"/>
|
||||
<path id="Path_187" class="st0" d="M5320.7-8124.4c-0.4,0.1-0.8,0.2-1.2,0.3c-0.6,0.1-1.3,0.3-1.9,0.4c0,0-0.1,0-0.1,0
|
||||
c-0.1,0-0.2-0.1-0.3-0.1c0,0,0,0.1,0,0.1c0.3,0.7,0.4,1.5,0.3,2.2c-0.1,0.4-0.3,0.8-0.5,1.1c0,0,0,0-0.1,0.1
|
||||
c0.2-0.1,0.4-0.1,0.6-0.1l2.5-0.6c0.5-0.1,0.9-0.6,1-1.1c0.1-0.5,0-1-0.1-1.5C5320.8-8124,5320.8-8124.2,5320.7-8124.4z"/>
|
||||
<path id="Path_188" class="st0" d="M5325.5-8127c-2.7,0.5-5.3,1.1-7.9,1.6c0,0.5,0,0.9,0.1,1.4c0.1,0,0.2,0,0.3-0.1
|
||||
c1.2-0.3,2.3-0.5,3.5-0.8c1.2-0.3,2.4-0.5,3.6-0.8c0.1,0,0.3-0.1,0.4-0.1c0,0,0.1,0,0.1-0.1
|
||||
C5325.6-8126.2,5325.5-8126.6,5325.5-8127z"/>
|
||||
<path id="Path_189" class="st0" d="M5328.6-8118.4c-0.2-0.4-0.3-0.7-0.5-1.1c-0.1-0.2-0.2-0.5-0.3-0.7c0-0.1,0-0.1-0.1,0
|
||||
c-1.2,0.3-2.4,0.6-3.6,1c0,0,0,0-0.1,0c0.2,0.7,0.5,1.3,0.7,2C5326-8117.6,5327.3-8118,5328.6-8118.4z"/>
|
||||
<path id="Path_190" class="st0" d="M5319.9-8120.9l-0.6,0.1c-1,0.2-2,0.5-3,0.7c-0.1,0-0.1,0.1-0.1,0.1c-0.3,0.7-0.5,1.5-0.8,2.2
|
||||
c0,0,0,0,0,0.1c0.2,0,0.4-0.1,0.5-0.1c1-0.3,2-0.5,3.1-0.8c0.1,0,0.2-0.1,0.3-0.2C5319.5-8119.5,5319.7-8120.2,5319.9-8120.9z"/>
|
||||
<path id="Path_191" class="st0" d="M5325.1-8125.4c-1.1,0.2-2.2,0.5-3.3,0.7c0.3,0.7,0.4,1.4,0.3,2.2c0.2,0,0.4-0.1,0.5-0.1
|
||||
c0.9-0.2,1.8-0.4,2.7-0.6c0.1,0,0.1,0,0.1-0.1c0.1-0.4,0-0.9-0.1-1.3C5325.3-8124.9,5325.2-8125.1,5325.1-8125.4
|
||||
C5325.1-8125.3,5325.1-8125.4,5325.1-8125.4z"/>
|
||||
<path id="Path_192" class="st0" d="M5325.6-8132c0.2,0,0.4,0,0.5,0c0.2,0,0.4,0,0.6,0c0.3,0,0.6-0.2,0.8-0.4c0.3-0.4,0.7-0.8,1-1.2
|
||||
c-0.1-0.1-0.1-0.1-0.1-0.2c0,0,0,0-0.1,0c-0.7-0.1-1.3-0.5-1.4-1.2c-0.1-0.2-0.1-0.4-0.1-0.6c-0.2,0.1-0.3,0.3-0.5,0.4
|
||||
c-0.1,0.1-0.2,0.1-0.3,0.2c0,0-0.1,0.1-0.2,0c-0.2,0-0.5-0.1-0.7-0.1c0,0,0,0-0.1,0C5325.3-8134.1,5325.4-8133.1,5325.6-8132z"/>
|
||||
<path id="Path_193" class="st0" d="M5328.4-8134.2c0.2-0.3,0.5-0.5,0.8-0.7c0.4-0.4,0.6-0.8,0.7-1.4c0-0.1,0-0.2-0.1-0.3
|
||||
c-0.3-0.5-0.7-1.1-1-1.6c0-0.1-0.1-0.1-0.1,0c-0.4,0.2-0.8,0.5-1.1,0.8c-0.2,0.2-0.4,0.4-0.6,0.6c-0.1,0.1-0.1,0.3,0,0.4
|
||||
c0.5,0.7,1,1.5,1.4,2.2C5328.4-8134.2,5328.4-8134.2,5328.4-8134.2z"/>
|
||||
<path id="Path_194" class="st0" d="M5314.3-8126.1c-0.1-0.1-0.1-0.1-0.2-0.2c-0.1,0-0.1-0.1-0.1-0.2c0-0.1,0-0.3,0-0.4h-0.1
|
||||
c-0.6,0-1.2-0.1-1.7-0.2c0,0-0.1,0-0.1,0c-0.4,0.2-0.7,0.4-1,0.8c-0.4,0.6-0.4,1.4,0.1,1.9c0.2,0.2,0.4,0.4,0.6,0.6
|
||||
c0.1,0.1,0.2,0.2,0.3,0.2c-0.2-0.6,0-1.3,0.5-1.8C5313-8125.9,5313.6-8126.2,5314.3-8126.1z"/>
|
||||
<path id="Path_195" class="st0" d="M5315.7-8114.9c0.5-0.1,0.9-0.3,1.4-0.4c0.8-0.2,1.6-0.4,2.4-0.7c0.1,0,0.1,0,0.1-0.1
|
||||
c0.1-0.4,0.2-0.7,0.4-1.1c0,0,0,0,0-0.1c-0.1,0-0.2,0-0.3,0.1c-1.2,0.3-2.3,0.6-3.5,1c-0.1,0-0.1,0.1-0.1,0.1
|
||||
c-0.1,0.4-0.3,0.7-0.4,1.1C5315.7-8115,5315.7-8115,5315.7-8114.9z"/>
|
||||
<path id="Path_196" class="st0" d="M5315.4-8117.4c0.2,0.3,0.4,0.6,0.6,0.9c0,0,0.1,0,0.1,0c1-0.3,1.9-0.5,2.9-0.8
|
||||
c0.3-0.1,0.6-0.2,0.9-0.2c-0.1-0.1-0.1-0.2-0.2-0.2c-0.2-0.2-0.3-0.4-0.5-0.6c0,0-0.1-0.1-0.1,0c-0.9,0.3-1.9,0.5-2.8,0.8
|
||||
C5316-8117.5,5315.7-8117.5,5315.4-8117.4z"/>
|
||||
<path id="Path_197" class="st0" d="M5321.3-8143.6c0-0.3,0-0.7,0-1c0,0-0.1,0-0.1,0c-0.7,0-1.5,0-2.2,0.1c-0.4,0-0.7,0-1.1,0.1
|
||||
c-0.1,0-0.1,0-0.1,0.1c0,0.3,0,0.6,0,0.8c0,0,0,0.1,0.1,0.1c0.4,0,0.8,0,1.1,0c0.5,0,1.1,0,1.6-0.1
|
||||
C5320.9-8143.5,5321.1-8143.6,5321.3-8143.6z"/>
|
||||
<path id="Path_198" class="st0" d="M5329.2-8134.3c0.1,0,0.2,0,0.2-0.1c0.4-0.2,0.8-0.4,1.1-0.7c0.3-0.2,0.4-0.5,0.6-0.8
|
||||
c0.1-0.3,0.1-0.6-0.1-0.9c-0.4-0.5-0.7-1-1.1-1.6c0,0,0,0-0.1-0.1c-0.2,0.2-0.4,0.4-0.6,0.6c0,0,0,0,0,0c0,0,0,0.1,0,0.1
|
||||
c0.2,0.4,0.5,0.7,0.7,1c0.1,0.2,0.2,0.4,0.1,0.6c0,0.5-0.1,0.9-0.4,1.3c-0.1,0.1-0.2,0.2-0.3,0.3
|
||||
C5329.4-8134.5,5329.3-8134.4,5329.2-8134.3C5329.2-8134.3,5329.2-8134.3,5329.2-8134.3z"/>
|
||||
<path id="Path_199" class="st0" d="M5317.5-8136.7c0,0.2,0,0.3,0,0.5c0,0,0,0.1,0.1,0.1c0.2,0,0.3,0.1,0.5,0.1c0.7,0.1,1.4,0.1,2,0
|
||||
c0.4,0,0.8-0.1,1.2-0.1c0.2,0,0.5-0.1,0.7-0.1c0.1,0,0.1,0,0.1-0.1c0-0.2,0-0.3,0-0.5C5320.5-8136.6,5319-8136.5,5317.5-8136.7z"/>
|
||||
<path id="Path_200" class="st0" d="M5312.5-8123.2c0.1-0.4,0.1-0.8,0.2-1.2c0.1-0.6,0.6-1,1.2-1c0.3,0,0.5,0.1,0.7,0.3
|
||||
c0.2,0.2,0.2,0.4,0.2,0.7c-0.1,0.3-0.2,0.6-0.2,0.9c0,0.1-0.1,0.2-0.1,0.4c0,0,0,0,0,0c0.1-0.1,0.2-0.2,0.3-0.3
|
||||
c0.3-0.4,0.4-0.9,0.4-1.4c0-0.6-0.4-1-0.9-1.1c-0.1,0-0.1,0-0.2,0c-0.5,0-1,0.3-1.4,0.7c-0.3,0.3-0.4,0.6-0.5,1
|
||||
c-0.1,0.3,0,0.7,0.2,1C5312.5-8123.2,5312.5-8123.2,5312.5-8123.2z"/>
|
||||
<path id="Path_201" class="st0" d="M5314.3-8123.2c0.1-0.5,0.3-0.9,0.4-1.4c0.1-0.2,0-0.4-0.2-0.5c-0.4-0.2-0.9-0.1-1.2,0.2
|
||||
c0,0,0,0,0,0.1c0,0.2,0,0.4,0.1,0.6c0,0.1,0.1,0.2,0.2,0.3C5313.7-8123.6,5314-8123.4,5314.3-8123.2
|
||||
C5314.2-8123.2,5314.3-8123.2,5314.3-8123.2z"/>
|
||||
<path id="Path_202" class="st0" d="M5317.4-8124.1c0-0.4,0-0.9-0.1-1.3c-0.1,0-0.1,0-0.2,0c-0.1,0-0.2,0-0.3,0
|
||||
c-0.7-0.3-1.4-0.5-2.1-0.8c0,0,0,0,0,0c0.1,0.1,0.1,0.1,0.2,0.2c0.3,0.2,0.5,0.6,0.6,0.9c0,0,0,0,0,0c0.1,0,0.3,0,0.4,0.1
|
||||
c0.3,0.1,0.6,0.3,0.9,0.5c0,0,0.1,0.1,0.1,0.1C5317.1-8124.2,5317.2-8124.1,5317.4-8124.1z"/>
|
||||
<path id="Path_203" class="st0" d="M5321.6-8124.6c-0.2,0-0.4,0.1-0.6,0.1c0.1,0.2,0.1,0.4,0.2,0.6c0.1,0.4,0.2,0.8,0.1,1.2
|
||||
c0,0.5-0.1,0.9-0.4,1.3c0,0,0,0,0,0c0.3,0,0.6-0.2,0.7-0.5c0.2-0.3,0.3-0.6,0.3-0.9C5321.9-8123.4,5321.8-8124,5321.6-8124.6z"/>
|
||||
<path id="Path_204" class="st0" d="M5315.7-8135.8c0.2,0,0.3,0.1,0.5,0.1c0.5,0.1,1,0.2,1.5,0.2c0.2,0,0.5,0,0.7,0
|
||||
c0.7-0.1,1.4-0.2,2.1-0.2c0.6-0.1,1.2-0.2,1.8-0.2c0.5-0.1,1.1-0.1,1.6-0.2l-1.5-0.2c0,0,0,0,0,0c0,0.2-0.1,0.3-0.2,0.3
|
||||
c0,0,0,0,0,0c-0.3,0.1-0.5,0.1-0.8,0.2c-0.8,0.1-1.6,0.1-2.3,0.1c-0.4,0-0.9,0-1.3-0.1c-0.1,0-0.2-0.1-0.3-0.2c0,0-0.1,0-0.1,0
|
||||
c-0.3,0-0.6,0.1-0.9,0.1L5315.7-8135.8L5315.7-8135.8z"/>
|
||||
<path id="Path_205" class="st0" d="M5327.3-8117.7c-0.3,0.1-0.5,0.2-0.8,0.2c-0.6,0.2-1.1,0.3-1.7,0.5c0,0-0.1,0-0.1,0.1
|
||||
c-0.5,0.2-1,0.5-1.5,0.7c0,0,0,0,0,0c0.3-0.1,0.5-0.1,0.8-0.2c0.5-0.2,1.1-0.3,1.6-0.5c0.1,0,0.2-0.1,0.2-0.1
|
||||
C5326.2-8117.2,5326.8-8117.5,5327.3-8117.7C5327.3-8117.7,5327.3-8117.7,5327.3-8117.7C5327.3-8117.7,5327.3-8117.7,5327.3-8117.7
|
||||
z"/>
|
||||
<path id="Path_206" class="st0" d="M5327-8135.8c0,0.1,0,0.2,0,0.4c0.1,0.5,0.3,0.9,0.7,1.1c0.1,0.1,0.3,0.1,0.4,0.2l0,0
|
||||
C5327.8-8134.7,5327.4-8135.2,5327-8135.8L5327-8135.8z"/>
|
||||
<path id="Path_207" class="st0" d="M5329-8134.4c-0.1,0.1-0.2,0.2-0.3,0.4c0,0,0,0,0,0.1c0,0.1,0,0.1,0.1,0.1c0.1,0,0.2,0,0.3-0.1
|
||||
c0.1,0,0.2-0.1,0.3-0.1c-0.1,0-0.1-0.1-0.2-0.1C5329-8134.2,5329-8134.3,5329-8134.4z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 11 KiB |
23
docs/static/fonts/icons/iconfont.css
vendored
23
docs/static/fonts/icons/iconfont.css
vendored
@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont";
|
||||
src: url("iconfont.eot?73552ec404b3a3d3769a3f04fa58c2c4?#iefix") format("embedded-opentype"),
|
||||
url("iconfont.woff2?73552ec404b3a3d3769a3f04fa58c2c4") format("woff2"),
|
||||
url("iconfont.woff?73552ec404b3a3d3769a3f04fa58c2c4") format("woff");
|
||||
src: url("iconfont.eot?8b7e57577c2d1f1ae9e810b9e010bc84?#iefix") format("embedded-opentype"),
|
||||
url("iconfont.woff2?8b7e57577c2d1f1ae9e810b9e010bc84") format("woff2"),
|
||||
url("iconfont.woff?8b7e57577c2d1f1ae9e810b9e010bc84") format("woff");
|
||||
}
|
||||
|
||||
.icon {
|
||||
@ -67,24 +67,27 @@ url("iconfont.woff?73552ec404b3a3d3769a3f04fa58c2c4") format("woff");
|
||||
.icon-variables:before {
|
||||
content: "\f111";
|
||||
}
|
||||
.icon-advancedcollapsed:before {
|
||||
.icon-console:before {
|
||||
content: "\f112";
|
||||
}
|
||||
.icon-advancedexpanded:before {
|
||||
.icon-advancedcollapsed:before {
|
||||
content: "\f113";
|
||||
}
|
||||
.icon-cancel:before {
|
||||
.icon-advancedexpanded:before {
|
||||
content: "\f114";
|
||||
}
|
||||
.icon-check:before {
|
||||
.icon-cancel:before {
|
||||
content: "\f115";
|
||||
}
|
||||
.icon-download:before {
|
||||
.icon-check:before {
|
||||
content: "\f116";
|
||||
}
|
||||
.icon-save:before {
|
||||
.icon-download:before {
|
||||
content: "\f117";
|
||||
}
|
||||
.icon-blocks:before {
|
||||
.icon-save:before {
|
||||
content: "\f118";
|
||||
}
|
||||
.icon-blocks:before {
|
||||
content: "\f119";
|
||||
}
|
||||
|
BIN
docs/static/fonts/icons/iconfont.eot
vendored
BIN
docs/static/fonts/icons/iconfont.eot
vendored
Binary file not shown.
17
docs/static/fonts/icons/iconfont.svg
vendored
17
docs/static/fonts/icons/iconfont.svg
vendored
@ -58,26 +58,29 @@
|
||||
<glyph glyph-name="variables"
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M36.8 12V7.8H3.4V12H36.8z M36.8 22.1V17.9H3.4V22.1H36.8z M36.7 32.2V28H3.3V32.2H36.7z" />
|
||||
<glyph glyph-name="advancedcollapsed"
|
||||
<glyph glyph-name="console"
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M15.6 21.3L2.3 15L2.3 19.8L11.1 23.6L2.3 27.4L2.3 32.2L15.6 25.9L15.6 21.3z M36 9.1L16.6 9.1L16.6 12.2L36 12.2L36 9.1z" />
|
||||
<glyph glyph-name="advancedcollapsed"
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M39.7 28.2L36.2 31.5L20 15.3L3.8 31.5L0.3 28.2L18.3 10.3L18.3 10.3L20 8.5L20.5 9L20.5 9z" />
|
||||
<glyph glyph-name="advancedexpanded"
|
||||
unicode=""
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M39.3 12L21.7 29.6L21.7 29.6L20 31.3L19.5 30.8L19.5 30.8L0.7 12L4 8.7L20 24.7L36 8.7z" />
|
||||
<glyph glyph-name="cancel"
|
||||
unicode=""
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M33 29.6L29.4 33.2L20.2 24L11 33.2L7.3 29.6L16.5 20.3L7.3 11.1L11 7.3L20.2 16.5L29.4 7.3L33 11.1L23.8 20.3z" />
|
||||
<glyph glyph-name="check"
|
||||
unicode=""
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M33.7 32.9L15.3 14.4L7.5 22.3L3.8 18.4L11.7 10.8L11.7 10.8L15.3 7.1L37.4 29.2z" />
|
||||
<glyph glyph-name="download"
|
||||
unicode=""
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M5.2 15.7H36.5V1.7H5.2V15.7z M28.5 24.2L26.1 26.6L22.6 23.1L22.6 36.5L19.1 36.5L19.1 23.5L16 26.6L13.6 24.2L20.9 16.7L21 16.9L21.2 16.7z" />
|
||||
<glyph glyph-name="save"
|
||||
unicode=""
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M25 34.5C25 33.6 25 32.8 25 31.9C25 31 24.7 30.9 24 30.9C23.5 30.9 22.8 30.9 22.4 30.9C22.1 30.9 21.4 31 21.4 31.7V31.9V36.9C21.4 37.3 21.6 37.8 22.3 38C22.3 38 22.3 38 22.4 38C23 38 23.7 38 24.2 38C24.7 38 25.2 37.6 25.2 37.1C25.2 37.1 25.2 37.1 25.2 36.9C25 36.3 25 35.2 25 34.5z M37.6 31.2C35.8 32.9 34.3 34.5 32.5 36.3C31 37.8 31 37.8 28.5 37.8C27.5 37.8 27.3 37.6 27.3 36.6V28.4C27.3 27.4 27.1 27.2 26.1 27.2H14.3C13.2 27.2 13 27.4 13 28.4V36.4C13 37.6 12.9 37.8 11.7 37.8H3.8C2.6 37.8 2.4 37.6 2.4 36.4V19.9C2.4 14.3 2.4 8.9 2.4 3.2C2.4 2 2.6 1.8 3.7 1.8H36.9C37.9 1.8 38.1 2.2 38.1 3.2V29.6C38.3 30.5 37.9 30.9 37.6 31.2zM33.7 6.7H7.1V23H33.7V6.7z" />
|
||||
<glyph glyph-name="blocks"
|
||||
unicode=""
|
||||
unicode=""
|
||||
horiz-adv-x="40" d=" M10.9 23H39V16.9H10.9V23z M39.2 27.1L39.2 33L0.9 33L0.9 31.1L0.9 27.1L0.9 12.9L0.9 7L39.2 7L39.2 12.9L6.9 12.9L6.9 27.1z" />
|
||||
</font>
|
||||
</defs>
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
docs/static/fonts/icons/iconfont.ttf
vendored
BIN
docs/static/fonts/icons/iconfont.ttf
vendored
Binary file not shown.
BIN
docs/static/fonts/icons/iconfont.woff
vendored
BIN
docs/static/fonts/icons/iconfont.woff
vendored
Binary file not shown.
BIN
docs/static/fonts/icons/iconfont.woff2
vendored
BIN
docs/static/fonts/icons/iconfont.woff2
vendored
Binary file not shown.
1
docs/static/loader_back.svg
vendored
Normal file
1
docs/static/loader_back.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="301.499" height="179.742" viewBox="0 0 282.655 168.508"><g transform="translate(-41.005 -446.364)"><rect ry="30" rx="30" y="458.77" x="53.41" height="143.698" width="105.312" stroke="#000" stroke-width="17.724" stroke-linecap="round" stroke-linejoin="round"/><rect width="105.668" height="144.183" x="53.232" y="458.527" rx="30.101" ry="30.101" fill="#fff"/></g><g transform="translate(111.528 -446.364)"><rect width="105.312" height="143.698" x="53.41" y="458.77" rx="30" ry="30" stroke="#000" stroke-width="17.724" stroke-linecap="round" stroke-linejoin="round"/><rect ry="30.101" rx="30.101" y="458.527" x="53.232" height="144.183" width="105.668" fill="#fff"/></g></svg>
|
After Width: | Height: | Size: 721 B |
1
docs/static/loader_front.svg
vendored
Normal file
1
docs/static/loader_front.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="301.499" height="179.742" viewBox="0 0 282.655 168.508"><g stroke="#000" stroke-linecap="round" stroke-linejoin="round"><g transform="translate(124.66 -243.829)"><circle r="25.968" cy="356.872" cx="-38.891" fill="none"/><circle cx="-38.891" cy="356.872" r="21.013" stroke-width=".809"/><path d="M-30.581 341.741a13.835 13.835 0 0 1 5.76 4.504l-11.099 8.26z" fill="#fff" stroke-width=".533"/></g><g transform="translate(277.193 -243.829)"><circle cx="-38.891" cy="356.872" r="25.968" fill="none"/><circle r="21.013" cy="356.872" cx="-38.891" stroke-width=".809"/><path d="M-30.581 341.741a13.835 13.835 0 0 1 5.76 4.504l-11.099 8.26z" fill="#fff" stroke-width=".533"/></g></g></svg>
|
After Width: | Height: | Size: 728 B |
1
docs/static/loader_full.svg
vendored
Normal file
1
docs/static/loader_full.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="301.499" height="179.742" viewBox="0 0 282.655 168.508"><g transform="translate(-41.005 -446.364)"><rect ry="30" rx="30" y="458.77" x="53.41" height="143.698" width="105.312" stroke="#000" stroke-width="17.724" stroke-linecap="round" stroke-linejoin="round"/><rect width="105.668" height="144.183" x="53.232" y="458.527" rx="30.101" ry="30.101" fill="#fff"/></g><g transform="translate(124.66 -243.829)" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><circle r="25.968" cy="356.872" cx="-38.891" fill="none"/><circle cx="-38.891" cy="356.872" r="21.013" stroke-width=".809"/><path d="M-30.581 341.741a13.835 13.835 0 0 1 5.76 4.504l-11.099 8.26z" fill="#fff" stroke-width=".533"/></g><g transform="translate(111.528 -446.364)"><rect width="105.312" height="143.698" x="53.41" y="458.77" rx="30" ry="30" stroke="#000" stroke-width="17.724" stroke-linecap="round" stroke-linejoin="round"/><rect ry="30.101" rx="30.101" y="458.527" x="53.232" height="144.183" width="105.668" fill="#fff"/></g><g transform="translate(277.193 -243.829)" stroke="#000" stroke-linecap="round" stroke-linejoin="round"><circle cx="-38.891" cy="356.872" r="25.968" fill="none"/><circle r="21.013" cy="356.872" cx="-38.891" stroke-width=".809"/><path d="M-30.581 341.741a13.835 13.835 0 0 1 5.76 4.504l-11.099 8.26z" fill="#fff" stroke-width=".533"/></g></svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -29,7 +29,8 @@ export function initAsync() {
|
||||
|
||||
let canHID = false
|
||||
if (pxt.U.isNodeJS) {
|
||||
canHID = true
|
||||
// doesn't seem to work ATM
|
||||
canHID = false
|
||||
} else {
|
||||
const forceHexDownload = /forceHexDownload/i.test(window.location.href);
|
||||
if (pxt.Cloud.isLocalHost() && pxt.Cloud.localToken && !forceHexDownload)
|
||||
|
@ -4,6 +4,9 @@
|
||||
import { deployCoreAsync, initAsync } from "./deploy";
|
||||
import { FieldPorts } from "./field_ports";
|
||||
import { FieldImages } from "./field_images";
|
||||
import { FieldSpeed } from "./field_speed";
|
||||
import { FieldBrickButtons } from "./field_brickbuttons";
|
||||
import { FieldTurnRatio } from "./field_turnratio";
|
||||
|
||||
pxt.editor.initExtensionsAsync = function(opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
|
||||
pxt.debug('loading pxt-ev3 target extensions...')
|
||||
@ -15,6 +18,15 @@ pxt.editor.initExtensionsAsync = function(opts: pxt.editor.ExtensionOptions): Pr
|
||||
}, {
|
||||
selector: "images",
|
||||
editor: FieldImages
|
||||
}, {
|
||||
selector: "speed",
|
||||
editor: FieldSpeed
|
||||
}, {
|
||||
selector: "brickbuttons",
|
||||
editor: FieldBrickButtons
|
||||
}, {
|
||||
selector: "turnratio",
|
||||
editor: FieldTurnRatio
|
||||
}],
|
||||
deployCoreAsync
|
||||
};
|
||||
@ -111,6 +123,20 @@ function updateBlocklyShape() {
|
||||
'l ' + 0 + ',' + (Blockly.BlockSvg as any).CORNER_RADIUS * 2 +
|
||||
'l ' + (Blockly.BlockSvg as any).CORNER_RADIUS + ',' + 0;
|
||||
|
||||
/**
|
||||
* Corner radius of the flyout background.
|
||||
* @type {number}
|
||||
* @const
|
||||
*/
|
||||
(Blockly as any).Flyout.prototype.CORNER_RADIUS = 0;
|
||||
|
||||
/**
|
||||
* Margin around the edges of the blocks in the flyout.
|
||||
* @type {number}
|
||||
* @const
|
||||
*/
|
||||
(Blockly as any).Flyout.prototype.MARGIN = 8;
|
||||
|
||||
}
|
||||
|
||||
// When require()d from node, bind the global pxt namespace
|
||||
|
159
editor/field_brickbuttons.ts
Normal file
159
editor/field_brickbuttons.ts
Normal file
@ -0,0 +1,159 @@
|
||||
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
|
||||
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||
|
||||
export interface FieldPortsOptions extends Blockly.FieldCustomDropdownOptions {
|
||||
columns?: string;
|
||||
width?: string;
|
||||
}
|
||||
|
||||
export class FieldBrickButtons extends Blockly.FieldDropdown implements Blockly.FieldCustom {
|
||||
public isFieldCustom_ = true;
|
||||
|
||||
// Width in pixels
|
||||
private width_: number;
|
||||
|
||||
// Columns in grid
|
||||
private columns_: number;
|
||||
|
||||
private savedPrimary_: string;
|
||||
|
||||
constructor(text: string, options: FieldPortsOptions, validator?: Function) {
|
||||
super(options.data);
|
||||
|
||||
this.columns_ = parseInt(options.columns) || 4;
|
||||
this.width_ = parseInt(options.width) || 150;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a dropdown menu under the text.
|
||||
* @private
|
||||
*/
|
||||
public showEditor_() {
|
||||
// If there is an existing drop-down we own, this is a request to hide the drop-down.
|
||||
if (Blockly.DropDownDiv.hideIfOwner(this)) {
|
||||
return;
|
||||
}
|
||||
// If there is an existing drop-down someone else owns, hide it immediately and clear it.
|
||||
Blockly.DropDownDiv.hideWithoutAnimation();
|
||||
Blockly.DropDownDiv.clearContent();
|
||||
// Populate the drop-down with the icons for this field.
|
||||
let dropdownDiv = Blockly.DropDownDiv.getContentDiv();
|
||||
let contentDiv = document.createElement('div');
|
||||
// Accessibility properties
|
||||
contentDiv.setAttribute('role', 'menu');
|
||||
contentDiv.setAttribute('aria-haspopup', 'true');
|
||||
|
||||
const buttonsSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg") as SVGGElement;
|
||||
pxsim.svg.hydrate(buttonsSVG, {
|
||||
viewBox: "0 0 256.68237 256.68237",
|
||||
width: this.width_,
|
||||
height: this.width_
|
||||
});
|
||||
contentDiv.appendChild(buttonsSVG);
|
||||
|
||||
const gWrapper = pxsim.svg.child(buttonsSVG, 'g', { 'transform': 'translate(-4.695057,58.29823)' });
|
||||
const gInnerWrapper = pxsim.svg.child(gWrapper, 'g', { 'transform': 'translate(3.9780427e-6,-32.677281)' });
|
||||
|
||||
const back = pxsim.svg.child(gInnerWrapper, 'path', {
|
||||
style: 'fill:#6a6a6a;stroke-width:3.91719985',
|
||||
d: 'M 106.30882,198.38022 C 84.431262,177.26258 50.453467,142.52878 50.453467,142.52878 v -7.12931 H 37.087971 a 32.381533,32.381533 0 1 1 0,-64.763062 H 50.457376 V 63.503186 L 105.71731,7.0563355 h 55.25604 c 25.02699,25.5048885 55.25994,55.2599395 55.25994,55.2599395 v 8.320133 h 12.77398 a 32.381533,32.381533 0 0 1 0,64.763062 h -12.77398 v 7.13323 c -29.43384,30.27603 -54.66454,55.85144 -54.66454,55.85144 z'
|
||||
})
|
||||
|
||||
const buttonLeft = pxsim.svg.child(gInnerWrapper, 'path', {
|
||||
style: 'fill:#a8a9a8;stroke-width:3.91719985',
|
||||
d: 'm 36.492567,78.357208 h 40.69971 V 126.48393 H 36.492567 A 24.063359,24.063359 0 0 1 12.429199,102.42057 v 0 A 24.063359,24.063359 0 0 1 36.492567,78.357208 Z'
|
||||
})
|
||||
|
||||
const buttonRight = pxsim.svg.child(gInnerWrapper, 'path', {
|
||||
style: 'fill:#a8a9a8;stroke-width:3.91719985',
|
||||
d: 'M 229.00727,126.48784 H 188.30756 V 78.361126 h 40.69971 a 24.063359,24.063359 0 0 1 24.06335,24.063354 v 0 a 24.063359,24.063359 0 0 1 -24.06335,24.06336 z'
|
||||
})
|
||||
|
||||
const buttonEnter = pxsim.svg.child(gInnerWrapper, 'path', {
|
||||
style: 'fill:#3c3c3c;stroke-width:3.91719985',
|
||||
d: 'm 109.27806,78.357208 h 46.9398 a 1.782326,1.782326 0 0 1 1.78233,1.782326 V 124.7016 a 1.782326,1.782326 0 0 1 -1.78233,1.78233 h -46.9398 a 1.782326,1.782326 0 0 1 -1.78233,-1.78233 V 80.139534 a 1.782326,1.782326 0 0 1 1.78233,-1.782326 z'
|
||||
})
|
||||
|
||||
const buttonTop = pxsim.svg.child(gInnerWrapper, 'path', {
|
||||
style: 'fill:#a8a9a8;stroke-width:3.91719985',
|
||||
d: 'm 108.09114,15.967966 49.90905,-0.59542 37.43276,38.619675 -15.44943,15.449437 V 97.367379 H 165.7249 V 81.306861 A 11.978797,11.978797 0 0 0 153.84012,69.422075 c -11.59883,-0.184102 -43.37516,0 -43.37516,0 A 9.6676495,9.6676495 0 0 0 100.36251,79.520618 V 97.347793 H 86.103905 V 69.422075 L 70.654464,53.97264 Z'
|
||||
})
|
||||
|
||||
const buttonBottom = pxsim.svg.child(gInnerWrapper, 'path', {
|
||||
style: 'fill:#a8a9a8;stroke-width:3.91719985',
|
||||
d: 'M 157.78865,189.01028 108.18908,189.38233 70.654464,150.794 86.323259,135.4895 v -28.08625 h 14.101921 v 16.11144 a 12.006218,12.006218 0 0 0 11.85346,11.9788 c 11.59882,0.1841 43.13227,0 43.13227,0 a 10.18472,10.18472 0 0 0 10.38059,-10.38058 v -17.70966 h 14.39179 v 28.08632 l 15.3045,15.3045 z'
|
||||
})
|
||||
|
||||
const buttons = [buttonEnter, buttonLeft, buttonRight, buttonTop, buttonBottom];
|
||||
const options = this.getOptions();
|
||||
for (let i = 0, option: any; option = options[i]; i++) {
|
||||
let content = (options[i] as any)[0]; // Human-readable text or image.
|
||||
const value = (options[i] as any)[1]; // Language-neutral value.
|
||||
const button = buttons[i];
|
||||
button.setAttribute('id', ':' + i); // For aria-activedescendant
|
||||
button.setAttribute('role', 'menuitem');
|
||||
button.setAttribute('cursor', 'pointer');
|
||||
const title = pxsim.svg.child(button, 'title');
|
||||
title.textContent = content;
|
||||
|
||||
Blockly.bindEvent_(button, 'click', this, this.buttonClick_);
|
||||
Blockly.bindEvent_(button, 'mouseup', this, this.buttonClick_);
|
||||
// These are applied manually instead of using the :hover pseudoclass
|
||||
// because Android has a bad long press "helper" menu and green highlight
|
||||
// that we must prevent with ontouchstart preventDefault
|
||||
Blockly.bindEvent_(button, 'mousedown', button, function (e) {
|
||||
this.setAttribute('stroke', '#ffffff');
|
||||
e.preventDefault();
|
||||
});
|
||||
Blockly.bindEvent_(button, 'mouseover', button, function () {
|
||||
this.setAttribute('stroke', '#ffffff');
|
||||
});
|
||||
Blockly.bindEvent_(button, 'mouseout', button, function () {
|
||||
this.setAttribute('stroke', 'transparent');
|
||||
});
|
||||
|
||||
button.setAttribute('data-value', value);
|
||||
}
|
||||
|
||||
contentDiv.style.width = this.width_ + 'px';
|
||||
dropdownDiv.appendChild(contentDiv);
|
||||
|
||||
Blockly.DropDownDiv.setColour('#ffffff', '#dddddd');
|
||||
|
||||
// Calculate positioning based on the field position.
|
||||
var scale = this.sourceBlock_.workspace.scale;
|
||||
var bBox = { width: this.size_.width, height: this.size_.height };
|
||||
bBox.width *= scale;
|
||||
bBox.height *= scale;
|
||||
var position = this.fieldGroup_.getBoundingClientRect();
|
||||
var primaryX = position.left + bBox.width / 2;
|
||||
var primaryY = position.top + bBox.height;
|
||||
var secondaryX = primaryX;
|
||||
var secondaryY = position.top;
|
||||
// Set bounds to workspace; show the drop-down.
|
||||
(Blockly.DropDownDiv as any).setBoundsElement(this.sourceBlock_.workspace.getParentSvg().parentNode);
|
||||
(Blockly.DropDownDiv as any).show(this, primaryX, primaryY, secondaryX, secondaryY,
|
||||
this.onHide_.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for when a button is clicked inside the drop-down.
|
||||
* Should be bound to the FieldIconMenu.
|
||||
* @param {Event} e DOM event for the click/touch
|
||||
* @private
|
||||
*/
|
||||
private buttonClick_ = function (e: any) {
|
||||
let value = e.target.getAttribute('data-value');
|
||||
this.setValue(value);
|
||||
Blockly.DropDownDiv.hide();
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for when the drop-down is hidden.
|
||||
*/
|
||||
private onHide_ = function () {
|
||||
Blockly.DropDownDiv.content_.removeAttribute('role');
|
||||
Blockly.DropDownDiv.content_.removeAttribute('aria-haspopup');
|
||||
Blockly.DropDownDiv.content_.removeAttribute('aria-activedescendant');
|
||||
};
|
||||
}
|
@ -24,6 +24,9 @@ export class FieldPorts extends Blockly.FieldDropdown implements Blockly.FieldCu
|
||||
this.width_ = parseInt(options.width) || 300;
|
||||
}
|
||||
|
||||
trimOptions_() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a dropdown menu under the text.
|
||||
* @private
|
||||
@ -42,7 +45,8 @@ export class FieldPorts extends Blockly.FieldDropdown implements Blockly.FieldCu
|
||||
// Accessibility properties
|
||||
contentDiv.setAttribute('role', 'menu');
|
||||
contentDiv.setAttribute('aria-haspopup', 'true');
|
||||
const options = this.getOptions();
|
||||
let options = this.getOptions();
|
||||
options = options.sort();
|
||||
for (let i = 0, option: any; option = options[i]; i++) {
|
||||
let content = (options[i] as any)[0]; // Human-readable text or image.
|
||||
const value = (options[i] as any)[1]; // Language-neutral value.
|
||||
|
96
editor/field_speed.ts
Normal file
96
editor/field_speed.ts
Normal file
@ -0,0 +1,96 @@
|
||||
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
|
||||
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||
|
||||
export interface FieldSpeedOptions extends Blockly.FieldCustomOptions {
|
||||
min?: string;
|
||||
max?: string;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
export class FieldSpeed extends Blockly.FieldSlider implements Blockly.FieldCustom {
|
||||
public isFieldCustom_ = true;
|
||||
|
||||
private params: any;
|
||||
|
||||
private speedSVG: SVGElement;
|
||||
private circleBar: SVGCircleElement;
|
||||
private reporter: SVGTextElement;
|
||||
|
||||
/**
|
||||
* Class for a color wheel field.
|
||||
* @param {number|string} value The initial content of the field.
|
||||
* @param {Function=} opt_validator An optional function that is called
|
||||
* to validate any constraints on what the user entered. Takes the new
|
||||
* text as an argument and returns either the accepted text, a replacement
|
||||
* text, or null to abort the change.
|
||||
* @extends {Blockly.FieldNumber}
|
||||
* @constructor
|
||||
*/
|
||||
constructor(value_: any, params: FieldSpeedOptions, opt_validator?: Function) {
|
||||
super(String(value_), '-100', '100', null, '10', 'Speed', opt_validator);
|
||||
this.params = params;
|
||||
if (this.params['min']) this.min_ = parseFloat(this.params.min);
|
||||
if (this.params['max']) this.max_ = parseFloat(this.params.max);
|
||||
if (this.params['label']) this.labelText_ = this.params.label;
|
||||
|
||||
(this as any).sliderColor_ = '#a8aaa8';
|
||||
}
|
||||
|
||||
createLabelDom_(labelText: string) {
|
||||
var labelContainer = document.createElement('div');
|
||||
this.speedSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg") as SVGGElement;
|
||||
pxsim.svg.hydrate(this.speedSVG, {
|
||||
viewBox: "0 0 200 100"
|
||||
});
|
||||
|
||||
labelContainer.appendChild(this.speedSVG);
|
||||
|
||||
const outerCircle = pxsim.svg.child(this.speedSVG, "circle", {
|
||||
'stroke-dasharray': '565.48', 'stroke-dashoffset': '0',
|
||||
'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 0.1s linear;`,
|
||||
'stroke': '#a8aaa8', 'stroke-width': '1rem'
|
||||
}) as SVGCircleElement;
|
||||
this.circleBar = pxsim.svg.child(this.speedSVG, "circle", {
|
||||
'stroke-dasharray': '565.48', 'stroke-dashoffset': '0',
|
||||
'cx': 100, 'cy': 100, 'r': '90', 'style': `fill:transparent; transition: stroke-dashoffset 0.1s linear;`,
|
||||
'stroke': '#f12a21', 'stroke-width': '1rem'
|
||||
}) as SVGCircleElement;
|
||||
|
||||
this.reporter = pxsim.svg.child(this.speedSVG, "text", {
|
||||
'x': 100, 'y': 80,
|
||||
'text-anchor': 'middle', 'alignment-baseline': 'middle',
|
||||
'style': 'font-size: 50px',
|
||||
'class': 'sim-text inverted number'
|
||||
}) as SVGTextElement;
|
||||
|
||||
// labelContainer.setAttribute('class', 'blocklyFieldSliderLabel');
|
||||
var readout = document.createElement('span');
|
||||
readout.setAttribute('class', 'blocklyFieldSliderReadout');
|
||||
// var label = document.createElement('span');
|
||||
// label.setAttribute('class', 'blocklyFieldSliderLabelText');
|
||||
// label.innerHTML = labelText;
|
||||
// labelContainer.appendChild(label);
|
||||
// labelContainer.appendChild(readout);
|
||||
return [labelContainer, readout];
|
||||
};
|
||||
|
||||
setReadout_(readout: Element, value: string) {
|
||||
this.updateSpeed(parseFloat(value));
|
||||
// Update reporter
|
||||
this.reporter.textContent = `${value}%`;
|
||||
}
|
||||
|
||||
private updateSpeed(speed: number) {
|
||||
let sign = this.sign(speed);
|
||||
speed = (Math.abs(speed) / 100 * 50) + 50;
|
||||
if (sign == -1) speed = 50 - speed;
|
||||
let c = Math.PI * (90 * 2);
|
||||
let pct = ((100 - speed) / 100) * c;
|
||||
this.circleBar.setAttribute('stroke-dashoffset', `${pct}`);
|
||||
}
|
||||
|
||||
// A re-implementation of Math.sign (since IE11 doesn't support it)
|
||||
private sign(num: number) {
|
||||
return num ? num < 0 ? -1 : 1 : 0;
|
||||
}
|
||||
}
|
108
editor/field_turnratio.ts
Normal file
108
editor/field_turnratio.ts
Normal file
@ -0,0 +1,108 @@
|
||||
/// <reference path="../node_modules/pxt-core/localtypings/blockly.d.ts"/>
|
||||
/// <reference path="../node_modules/pxt-core/built/pxtsim.d.ts"/>
|
||||
|
||||
export interface FieldTurnRatioOptions extends Blockly.FieldCustomOptions {
|
||||
}
|
||||
|
||||
export class FieldTurnRatio extends Blockly.FieldSlider implements Blockly.FieldCustom {
|
||||
public isFieldCustom_ = true;
|
||||
|
||||
private params: any;
|
||||
|
||||
private path_: SVGPathElement;
|
||||
private reporter_: SVGTextElement;
|
||||
|
||||
/**
|
||||
* Class for a color wheel field.
|
||||
* @param {number|string} value The initial content of the field.
|
||||
* @param {Function=} opt_validator An optional function that is called
|
||||
* to validate any constraints on what the user entered. Takes the new
|
||||
* text as an argument and returns either the accepted text, a replacement
|
||||
* text, or null to abort the change.
|
||||
* @extends {Blockly.FieldNumber}
|
||||
* @constructor
|
||||
*/
|
||||
constructor(value_: any, params: FieldTurnRatioOptions, opt_validator?: Function) {
|
||||
super(String(value_), '-100', '100', null, '10', 'TurnRatio', opt_validator);
|
||||
this.params = params;
|
||||
(this as any).sliderColor_ = '#a8aaa8';
|
||||
}
|
||||
|
||||
static HALF = 80;
|
||||
static HANDLE_RADIUS = 30;
|
||||
static RADIUS = FieldTurnRatio.HALF - FieldTurnRatio.HANDLE_RADIUS - 1;
|
||||
|
||||
createLabelDom_(labelText: string) {
|
||||
let labelContainer = document.createElement('div');
|
||||
let svg = Blockly.utils.createSvgElement('svg', {
|
||||
'xmlns': 'http://www.w3.org/2000/svg',
|
||||
'xmlns:html': 'http://www.w3.org/1999/xhtml',
|
||||
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
||||
'version': '1.1',
|
||||
'height': (FieldTurnRatio.HALF + FieldTurnRatio.HANDLE_RADIUS + 10) + 'px',
|
||||
'width': (FieldTurnRatio.HALF * 2) + 'px'
|
||||
}, labelContainer);
|
||||
let defs = Blockly.utils.createSvgElement('defs', {}, svg);
|
||||
let marker = Blockly.utils.createSvgElement('marker', {
|
||||
'id': 'head',
|
||||
'orient': "auto",
|
||||
'markerWidth': '2',
|
||||
'markerHeight': '4',
|
||||
'refX': '0.1', 'refY': '1.5'
|
||||
}, defs);
|
||||
let markerPath = Blockly.utils.createSvgElement('path', {
|
||||
'd': 'M0,0 V3 L1.5,1.5 Z',
|
||||
'fill': '#f12a21'
|
||||
}, marker);
|
||||
this.reporter_ = pxsim.svg.child(svg, "text", {
|
||||
'x': FieldTurnRatio.HALF, 'y': 96,
|
||||
'text-anchor': 'middle', 'alignment-baseline': 'middle',
|
||||
'style': 'font-size: 50px',
|
||||
'class': 'sim-text inverted number'
|
||||
}) as SVGTextElement;
|
||||
this.path_ = Blockly.utils.createSvgElement('path', {
|
||||
'x1': FieldTurnRatio.HALF,
|
||||
'y1': FieldTurnRatio.HALF,
|
||||
'marker-end': 'url(#head)',
|
||||
'style': 'fill: none; stroke: #f12a21; stroke-width: 10'
|
||||
}, svg);
|
||||
this.updateGraph_();
|
||||
let readout = document.createElement('span');
|
||||
readout.setAttribute('class', 'blocklyFieldSliderReadout');
|
||||
return [labelContainer, readout];
|
||||
};
|
||||
|
||||
updateGraph_() {
|
||||
if (!this.path_) {
|
||||
return;
|
||||
}
|
||||
let v = goog.math.clamp(parseFloat(this.getText()), -100, 100);
|
||||
if (isNaN(v)) {
|
||||
v = 0;
|
||||
}
|
||||
|
||||
const x = goog.math.clamp(parseFloat(this.getText()), -100, 100) / 100;
|
||||
const theta = x * Math.PI / 2;
|
||||
const cx = FieldTurnRatio.HALF;
|
||||
const cy = FieldTurnRatio.HALF - 14;
|
||||
const gamma = Math.PI - 2 * theta;
|
||||
const r = FieldTurnRatio.RADIUS;
|
||||
const alpha = 0.2 + Math.abs(x) * 0.5;
|
||||
const x1 = 0;
|
||||
const y1 = r * alpha;
|
||||
const y2 = r * Math.sin(Math.PI / 2 - theta);
|
||||
const x2 = r * Math.cos(Math.PI / 2 - theta);
|
||||
const y3 = y2 - r * alpha * Math.cos(2 * theta);
|
||||
const x3 = x2 - r * alpha * Math.sin(2 * theta);
|
||||
|
||||
|
||||
const d = `M ${cx} ${cy} C ${cx} ${cy - y1} ${cx + x3} ${cy - y3} ${cx + x2} ${cy - y2}`;
|
||||
this.path_.setAttribute('d', d);
|
||||
|
||||
this.reporter_.textContent = `${v}`;
|
||||
}
|
||||
|
||||
setReadout_(readout: Element, value: string) {
|
||||
this.updateGraph_();
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"behaviors.addBehavior|block": "add behavior %behavior",
|
||||
"behaviors.avoidCrash|block": "avoid crash using %ultrasonic",
|
||||
"behaviors.driveForward|block": "drive %motors|forward at %speed|%",
|
||||
"behaviors.driveForward|block": "drive %motors|forward at %speed=motorSpeedPicker|%",
|
||||
"behaviors|block": "behaviors",
|
||||
"{id:category}Behaviors": "Behaviors"
|
||||
}
|
@ -49,7 +49,7 @@ namespace behaviors {
|
||||
* @param motors
|
||||
* @param speed the desired speed, eg: 50
|
||||
*/
|
||||
//% blockId=behaviorsDriveForward block="drive %motors|forward at %speed|%"
|
||||
//% blockId=behaviorsDriveForward block="drive %motors|forward at %speed=motorSpeedPicker|%"
|
||||
export function driveForward(motors: motors.MotorBase, speed: number): behaviors.Behavior {
|
||||
return new DriveForwardBehavior(motors, speed);
|
||||
}
|
||||
|
3
libs/chassis/README.md
Normal file
3
libs/chassis/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Chassis
|
||||
|
||||
A library to control a chassis.
|
11
libs/chassis/_locales/chassis-jsdoc-strings.json
Normal file
11
libs/chassis/_locales/chassis-jsdoc-strings.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"chassis.Chassis": "A differential drive robot",
|
||||
"chassis.Chassis.drive": "Makes a differential drive robot move with a given speed (cm/s) and rotation rate (deg/s)\nusing a unicycle model.",
|
||||
"chassis.Chassis.drive|param|rotationSpeed": "rotation of the robot around the center point, eg: 30",
|
||||
"chassis.Chassis.drive|param|speed": "speed of the center point between motors, eg: 10",
|
||||
"chassis.Chassis.drive|param|value": "the amount of movement, eg: 2",
|
||||
"chassis.Chassis.setMotors": "Sets the motors used by the chassis, default is B+C",
|
||||
"chassis.Chassis.setProperty": "Sets a property of the robot",
|
||||
"chassis.Chassis.setProperty|param|property": "the property to set",
|
||||
"chassis.Chassis.setProperty|param|value": "the value to set"
|
||||
}
|
9
libs/chassis/_locales/chassis-strings.json
Normal file
9
libs/chassis/_locales/chassis-strings.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"ChassisProperty.BaseLength|block": "base length (cm)",
|
||||
"ChassisProperty.WheelRadius|block": "wheel radius (cm)",
|
||||
"chassis.Chassis.drive|block": "drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s",
|
||||
"chassis.Chassis.setMotors|block": "set %chassis|motors to %motors",
|
||||
"chassis.Chassis.setProperty|block": "set %chassis|%property|to %value",
|
||||
"chassis|block": "chassis",
|
||||
"{id:category}Chassis": "Chassis"
|
||||
}
|
88
libs/chassis/chassis.ts
Normal file
88
libs/chassis/chassis.ts
Normal file
@ -0,0 +1,88 @@
|
||||
enum ChassisProperty {
|
||||
//% block="wheel radius (cm)"
|
||||
WheelRadius,
|
||||
//% block="base length (cm)"
|
||||
BaseLength
|
||||
}
|
||||
|
||||
namespace chassis {
|
||||
/**
|
||||
* A differential drive robot
|
||||
*/
|
||||
//% fixedInstances
|
||||
export class Chassis {
|
||||
// the motor pair
|
||||
public motors: motors.SynchedMotorPair;
|
||||
// the radius of the wheel (cm)
|
||||
public wheelRadius: number;
|
||||
// the distance between the wheels (cm)
|
||||
public baseLength: number;
|
||||
|
||||
constructor() {
|
||||
this.motors = motors.largeBC;
|
||||
this.wheelRadius = 3;
|
||||
this.baseLength = 12;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a differential drive robot move with a given speed (cm/s) and rotation rate (deg/s)
|
||||
* using a unicycle model.
|
||||
* @param speed speed of the center point between motors, eg: 10
|
||||
* @param rotationSpeed rotation of the robot around the center point, eg: 30
|
||||
* @param value the amount of movement, eg: 2
|
||||
* @param unit
|
||||
*/
|
||||
//% blockId=motorDrive block="drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s"
|
||||
//% inlineInputMode=inline
|
||||
//% weight=95 blockGap=8
|
||||
drive(speed: number, rotationSpeed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
|
||||
// speed is expressed in %
|
||||
const R = this.wheelRadius; // cm
|
||||
const L = this.baseLength; // cm
|
||||
const PI = 3.14;
|
||||
const maxw = 170 / 60 * 2 * PI; // rad / s
|
||||
const maxv = maxw * R; // cm / s
|
||||
// speed is cm / s
|
||||
const v = speed; // cm / s
|
||||
const w = rotationSpeed / 360 * 2 * PI; // rad / s
|
||||
|
||||
const vr = (2 * v + w * L) / (2 * R); // rad / s
|
||||
const vl = (2 * v - w * L) / (2 * R); // rad / s
|
||||
|
||||
const sr = vr / maxw * 100; // %
|
||||
const sl = vl / maxw * 100; // %
|
||||
|
||||
this.motors.tank(sr, sl, value, unit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a property of the robot
|
||||
* @param property the property to set
|
||||
* @param value the value to set
|
||||
*/
|
||||
//% blockId=chassisSetProperty block="set %chassis|%property|to %value"
|
||||
//% blockGap=8
|
||||
//% weight=10
|
||||
setProperty(property: ChassisProperty, value: number) {
|
||||
switch (property) {
|
||||
case ChassisProperty.WheelRadius:
|
||||
this.wheelRadius = Math.max(0.1, value); break;
|
||||
case ChassisProperty.BaseLength:
|
||||
this.baseLength = Math.max(0.1, value); break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the motors used by the chassis, default is B+C
|
||||
* @param motors
|
||||
*/
|
||||
//% blockId=chassisSetMotors block="set %chassis|motors to %motors"
|
||||
//% weight=10
|
||||
setMotors(motors: motors.SynchedMotorPair) {
|
||||
this.motors = motors;
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstance whenUsed
|
||||
export const chassis = new Chassis();
|
||||
}
|
15
libs/chassis/pxt.json
Normal file
15
libs/chassis/pxt.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "chassis",
|
||||
"description": "Chassis robot support",
|
||||
"files": [
|
||||
"README.md",
|
||||
"chassis.ts"
|
||||
],
|
||||
"testFiles": [
|
||||
"test.ts"
|
||||
],
|
||||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core"
|
||||
}
|
||||
}
|
1
libs/chassis/test.ts
Normal file
1
libs/chassis/test.ts
Normal file
@ -0,0 +1 @@
|
||||
|
@ -11,5 +11,8 @@
|
||||
"sensors.ColorSensor.onLightChanged|param|handler": "the code to run when detected",
|
||||
"sensors.ColorSensor.pauseForColor": "Waits for the given color to be detected",
|
||||
"sensors.ColorSensor.pauseForColor|param|color": "the color to detect",
|
||||
"sensors.ColorSensor.pauseForLight": "Waits for the given color to be detected"
|
||||
"sensors.ColorSensor.pauseForLight": "Waits for the given color to be detected",
|
||||
"sensors.ColorSensor.setThreshold": "Sets a threshold value",
|
||||
"sensors.ColorSensor.setThreshold|param|condition": "the dark or bright light condition",
|
||||
"sensors.ColorSensor.setThreshold|param|value": "the value threshold"
|
||||
}
|
@ -18,12 +18,14 @@
|
||||
"sensors.ColorSensor.onColorDetected|block": "on %sensor|detected color %color",
|
||||
"sensors.ColorSensor.onLightChanged|block": "on %sensor|%mode|%condition",
|
||||
"sensors.ColorSensor.pauseForColor|block": "pause %sensor|for color %color",
|
||||
"sensors.ColorSensor.pauseForLight|block": "pause %sensor|for %mode|light %condition",
|
||||
"sensors.ColorSensor.pauseForLight|block": "pause %sensor|for %mode|%condition",
|
||||
"sensors.ColorSensor.setThreshold|block": "set %sensor|%condition|to %value",
|
||||
"sensors.color1|block": "color 1",
|
||||
"sensors.color2|block": "color 2",
|
||||
"sensors.color3|block": "color 3",
|
||||
"sensors.color4|block": "color 4",
|
||||
"sensors|block": "sensors",
|
||||
"{id:category}Sensors": "Sensors",
|
||||
"{id:group}Color Sensor": "Color Sensor"
|
||||
"{id:group}Color Sensor": "Color Sensor",
|
||||
"{id:group}Threshold": "Threshold"
|
||||
}
|
@ -152,7 +152,7 @@ namespace sensors {
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=99
|
||||
//% weight=98
|
||||
//% group="Color Sensor"
|
||||
color(): ColorSensorColor {
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
@ -182,7 +182,7 @@ namespace sensors {
|
||||
* @param color the color to detect
|
||||
*/
|
||||
//% help=sensors/color-sensor/pause-for-light
|
||||
//% block="pause %sensor|for %mode|light %condition"
|
||||
//% block="pause %sensor|for %mode|%condition"
|
||||
//% blockId=colorPauseForLight
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=sensors
|
||||
@ -221,17 +221,32 @@ namespace sensors {
|
||||
reflectedLight() {
|
||||
return this.light(LightIntensityMode.Reflected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a threshold value
|
||||
* @param condition the dark or bright light condition
|
||||
* @param value the value threshold
|
||||
*/
|
||||
//% blockId=colorSetThreshold block="set %sensor|%condition|to %value"
|
||||
//% group="Threshold" blockGap=8 weight=90
|
||||
//% value.min=0 value.max=100
|
||||
setThreshold(condition: LightCondition, value: number) {
|
||||
if (condition == LightCondition.Dark)
|
||||
this.thresholdDetector.setLowThreshold(value)
|
||||
else
|
||||
this.thresholdDetector.setHighThreshold(value);
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed block="color 3" weight=90 fixedInstance jres=icons.port3
|
||||
export const color3: ColorSensor = new ColorSensor(3)
|
||||
|
||||
//% whenUsed block="color 1" weight=95 fixedInstance jres=icons.port1
|
||||
export const color1: ColorSensor = new ColorSensor(1)
|
||||
|
||||
//% whenUsed block="color 2" weight=90 fixedInstance jres=icons.port2
|
||||
export const color2: ColorSensor = new ColorSensor(2)
|
||||
|
||||
//% whenUsed block="color 3" weight=90 fixedInstance jres=icons.port3
|
||||
export const color3: ColorSensor = new ColorSensor(3)
|
||||
|
||||
//% whenUsed block="color 4" weight=90 fixedInstance jres=icons.port4
|
||||
export const color4: ColorSensor = new ColorSensor(4)
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"BrickLight": "Patterns for lights under the buttons.",
|
||||
"ButtonEvent": "User interaction on buttons",
|
||||
"Draw": "Drawing modes",
|
||||
"Image.buffer": "Returns the underlaying Buffer object.",
|
||||
@ -6,14 +7,15 @@
|
||||
"Image.draw": "Draw an image on the screen.",
|
||||
"Image.height": "Returns the height of an image.",
|
||||
"Image.width": "Returns the width of an image.",
|
||||
"LightsPattern": "Patterns for lights under the buttons.",
|
||||
"MMap.getNumber": "Read a number in specified format from the buffer.",
|
||||
"MMap.ioctl": "Perform ioctl(2) on the underlaying file",
|
||||
"MMap.length": "Returns the length of a Buffer object.",
|
||||
"MMap.lseek": "Set pointer on the underlaying file.",
|
||||
"MMap.read": "Perform read(2) on the underlaying file",
|
||||
"MMap.setNumber": "Write a number in specified format in the buffer.",
|
||||
"MMap.slice": "Read a range of bytes into a buffer.",
|
||||
"MMap.write": "Perform write(2) on the underlaying file",
|
||||
"SeekWhence": "Mode for lseek()",
|
||||
"brick.Button": "Generic button class, for device buttons and sensors.",
|
||||
"brick.Button.isPressed": "Check if button is currently pressed or not.",
|
||||
"brick.Button.onEvent": "Do something when a button or sensor is clicked, up or down.",
|
||||
@ -21,22 +23,27 @@
|
||||
"brick.Button.pauseUntil": "Waits until the event is raised",
|
||||
"brick.Button.pauseUntil|param|ev": "the event to wait for",
|
||||
"brick.Button.wasPressed": "See if the button was pressed again since the last time you checked.",
|
||||
"brick.batteryLevel": "Returns the current battery level",
|
||||
"brick.buttonDown": "Down button on the EV3 Brick.",
|
||||
"brick.buttonEnter": "Enter button on the EV3 Brick.",
|
||||
"brick.buttonLeft": "Left button on the EV3 Brick.",
|
||||
"brick.buttonRight": "Right button on the EV3 Brick.",
|
||||
"brick.buttonUp": "Up button on the EV3 Brick.",
|
||||
"brick.clearScreen": "Clears the screen",
|
||||
"brick.lightPattern": "Pattern block.",
|
||||
"brick.lightPattern|param|pattern": "the lights pattern to use. eg: LightsPattern.Green",
|
||||
"brick.printLine": "Show text on the screen at a specific line.",
|
||||
"brick.printLine|param|line": "the line number to print the text at, eg: 0",
|
||||
"brick.printLine|param|text": "the text to print on the screen, eg: \"Hello world\"",
|
||||
"brick.printPorts": "Prints the port states on the screen",
|
||||
"brick.setLight": "Set lights.",
|
||||
"brick.setLight|param|pattern": "the lights pattern to use.",
|
||||
"brick.setLight|param|pattern": "the lights pattern to use. eg: BrickLight.Orange",
|
||||
"brick.showImage": "Shows an image on screen",
|
||||
"brick.showImage|param|image": "image to draw",
|
||||
"brick.showNumber": "Shows a number on the screen",
|
||||
"brick.showNumber|param|line": "the line number to print the text at, eg: 1",
|
||||
"brick.showNumber|param|value": "the numeric value",
|
||||
"brick.showString": "Show text on the screen at a specific line.",
|
||||
"brick.showString|param|line": "the line number to print the text at, eg: 1",
|
||||
"brick.showString|param|text": "the text to print on the screen, eg: \"Hello world\"",
|
||||
"brick.showValue": "Shows a name, value pair on the screen",
|
||||
"brick.showValue|param|line": "the line number to print the text at, eg: 1",
|
||||
"brick.showValue|param|value": "the numeric value",
|
||||
"console": "Reading and writing data to the console output.\n\nReading and writing data to the console output.",
|
||||
"console.addListener": "Adds a listener for the log messages",
|
||||
"console.log": "Write a line of text to the console output.",
|
||||
@ -45,6 +52,9 @@
|
||||
"console.logValue|param|value": "to write",
|
||||
"console.sendToScreen": "Sends the log messages to the brick screen and uses the brick up and down buttons to scroll.",
|
||||
"control": "Program controls and events.",
|
||||
"control.Timer.millis": "Gets the elapsed time in millis",
|
||||
"control.Timer.reset": "Resets the timer",
|
||||
"control.Timer.seconds": "Gets the elapsed time in seconds",
|
||||
"control.allocateNotifyEvent": "Allocates the next user notification event",
|
||||
"control.deviceFirmwareVersion": "Determine the version of system software currently running.",
|
||||
"control.dmesg": "Write data to DMESG debugging buffer.",
|
||||
@ -54,38 +64,33 @@
|
||||
"control.raiseEvent|param|value": "Component specific code indicating the cause of the event.",
|
||||
"motors.Motor.angle": "Gets motor angle.",
|
||||
"motors.Motor.clearCounts": "Clears the motor count",
|
||||
"motors.Motor.setRegulated": "Indicates if the motor speed should be regulated. Default is true.",
|
||||
"motors.Motor.setRegulated|param|value": "true for regulated motor",
|
||||
"motors.Motor.speed": "Gets motor actual speed.",
|
||||
"motors.Motor.tacho": "Gets motor tachometer count.",
|
||||
"motors.Motor.toString": "Returns the status of the motor",
|
||||
"motors.MotorBase.isReady": "Returns a value indicating if the motor is still running a previous command.",
|
||||
"motors.MotorBase.move": "Moves the motor by a number of rotations, degress or seconds",
|
||||
"motors.MotorBase.move|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||
"motors.MotorBase.move|param|unit": "the meaning of the value",
|
||||
"motors.MotorBase.move|param|value": "the move quantity, eg: 2",
|
||||
"motors.MotorBase.pauseUntilReady": "Pauses the execution until the previous command finished.",
|
||||
"motors.MotorBase.pauseUntilReady|param|timeOut": "optional maximum pausing time in milliseconds",
|
||||
"motors.MotorBase.reset": "Resets the motor(s).",
|
||||
"motors.MotorBase.setBrake": "Sets the automatic brake on or off when the motor is off",
|
||||
"motors.MotorBase.setBrake|param|brake": "a value indicating if the motor should break when off",
|
||||
"motors.MotorBase.setReversed": "Reverses the motor polarity",
|
||||
"motors.MotorBase.setSpeed": "Sets the speed of the motor.",
|
||||
"motors.MotorBase.setSpeed": "Sets the motor speed for limited time or distance.",
|
||||
"motors.MotorBase.setSpeed|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||
"motors.MotorBase.setSpeed|param|unit": "(optional) unit of the value",
|
||||
"motors.MotorBase.setSpeed|param|value": "(optional) measured distance or rotation",
|
||||
"motors.MotorBase.stop": "Stops the motor(s).",
|
||||
"motors.SynchedMotorPair.drive": "Makes a differential drive robot move with a given speed (%) and rotation rate (deg/s)\nusing a unicycle model.",
|
||||
"motors.SynchedMotorPair.drive|param|rotationSpeed": "rotation of the robot around the center point, eg: 30",
|
||||
"motors.SynchedMotorPair.drive|param|speed": "speed of the center point between motors, eg: 10",
|
||||
"motors.SynchedMotorPair.drive|param|value": "the amount of movement, eg: 2",
|
||||
"motors.SynchedMotorPair.setDimensions": "Sets the wheels radius and base length of a directional drive robot",
|
||||
"motors.SynchedMotorPair.setDimensions|param|wheelRadius": "@param baseLength ",
|
||||
"motors.SynchedMotorPair.steer": "Turns the motor and the follower motor by a number of rotations",
|
||||
"motors.SynchedMotorPair.steer|param|speed": "the speed from ``100`` full forward to ``-100`` full backward, eg: 50",
|
||||
"motors.SynchedMotorPair.steer|param|turnRatio": "the ratio of power sent to the follower motor, from ``-200`` to ``200``, eg: 0",
|
||||
"motors.SynchedMotorPair.steer|param|unit": "the meaning of the value",
|
||||
"motors.SynchedMotorPair.steer|param|value": "the move quantity, eg: 2",
|
||||
"motors.SynchedMotorPair.steer|param|unit": "(optional) unit of the value",
|
||||
"motors.SynchedMotorPair.steer|param|value": "(optional) move duration or rotation",
|
||||
"motors.SynchedMotorPair.tank": "The Move Tank block can make a robot drive forward, backward, turn, or stop. \nUse the Move Tank block for robot vehicles that have two Large Motors, \nwith one motor driving the left side of the vehicle and the other the right side. \nYou can make the two motors go at different speeds or in different directions \nto make your robot turn.",
|
||||
"motors.SynchedMotorPair.tank|param|speedLeft": "the speed on the left motor, eg: 50",
|
||||
"motors.SynchedMotorPair.tank|param|speedRight": "the speed on the right motor, eg: 50",
|
||||
"motors.SynchedMotorPair.tank|param|unit": "@param speedLeft the speed on the left motor, eg: 50",
|
||||
"motors.SynchedMotorPair.tank|param|value": "the amount of movement, eg: 2",
|
||||
"motors.SynchedMotorPair.tank|param|unit": "(optional) unit of the value",
|
||||
"motors.SynchedMotorPair.tank|param|value": "(optional) move duration or rotation",
|
||||
"motors.SynchedMotorPair.toString": "Returns the name(s) of the motor",
|
||||
"motors.mkCmd": "Allocates a message buffer",
|
||||
"motors.mkCmd|param|addSize": "required additional bytes",
|
||||
|
@ -1,20 +1,21 @@
|
||||
{
|
||||
"BrickLight.GreenFlash|block": "green flash",
|
||||
"BrickLight.GreenPulse|block": "green pulse",
|
||||
"BrickLight.Green|block": "green",
|
||||
"BrickLight.Off|block": "off",
|
||||
"BrickLight.OrangeFlash|block": "orange flash",
|
||||
"BrickLight.OrangePulse|block": "orange pulse",
|
||||
"BrickLight.Orange|block": "orange",
|
||||
"BrickLight.RedFlash|block": "red flash",
|
||||
"BrickLight.RedPulse|block": "red pulse",
|
||||
"BrickLight.Red|block": "red",
|
||||
"ButtonEvent.Click|block": "click",
|
||||
"ButtonEvent.Down|block": "down",
|
||||
"ButtonEvent.Up|block": "up",
|
||||
"LightsPattern.GreenFlash|block": "Flashing Green",
|
||||
"LightsPattern.GreenPulse|block": "Pulsing Green",
|
||||
"LightsPattern.Green|block": "Green",
|
||||
"LightsPattern.Off|block": "Off",
|
||||
"LightsPattern.OrangeFlash|block": "Flashing Orange",
|
||||
"LightsPattern.OrangePulse|block": "Pulsing Orange",
|
||||
"LightsPattern.Orange|block": "Orange",
|
||||
"LightsPattern.RedFlash|block": "Flashing Red",
|
||||
"LightsPattern.RedPulse|block": "Pulsing Red",
|
||||
"LightsPattern.Red|block": "Red",
|
||||
"MoveUnit.Degrees|block": "degrees",
|
||||
"MoveUnit.MilliSeconds|block": "milliseconds",
|
||||
"MoveUnit.Rotations|block": "rotations",
|
||||
"MoveUnit.Seconds|block": "seconds",
|
||||
"Output.AB|block": "A+B",
|
||||
"Output.AD|block": "A+D",
|
||||
"Output.ALL|block": "All",
|
||||
@ -28,36 +29,50 @@
|
||||
"brick.Button.onEvent|block": "on %button|%event",
|
||||
"brick.Button.pauseUntil|block": "pause until %button|%event",
|
||||
"brick.Button.wasPressed|block": "%button|was pressed",
|
||||
"brick.buttonDown|block": "down",
|
||||
"brick.buttonEnter|block": "enter",
|
||||
"brick.buttonLeft|block": "left",
|
||||
"brick.buttonRight|block": "right",
|
||||
"brick.buttonUp|block": "up",
|
||||
"brick.batteryLevel|block": "battery level",
|
||||
"brick.buttonDown|block": "button down",
|
||||
"brick.buttonEnter|block": "button enter",
|
||||
"brick.buttonLeft|block": "button left",
|
||||
"brick.buttonRight|block": "button right",
|
||||
"brick.buttonUp|block": "button up",
|
||||
"brick.clearScreen|block": "clear screen",
|
||||
"brick.lightPattern|block": "%pattern",
|
||||
"brick.printLine|block": "print %text| at line %line",
|
||||
"brick.printPorts|block": "print ports",
|
||||
"brick.setLight|block": "set light to %pattern=led_pattern",
|
||||
"brick.setLight|block": "set light to %pattern",
|
||||
"brick.showImage|block": "show image %image=screen_image_picker",
|
||||
"brick.showNumber|block": "show number %name|at line %line",
|
||||
"brick.showString|block": "show string %text|at line %line",
|
||||
"brick.showValue|block": "show value %name|= %text|at line %line",
|
||||
"brick|block": "brick",
|
||||
"console.logValue|block": "console|log value %name|= %value",
|
||||
"console.log|block": "console|log %text",
|
||||
"console.sendToScreen|block": "send console to screen",
|
||||
"console|block": "console",
|
||||
"control.Timer.millis|block": "%timer|millis",
|
||||
"control.Timer.reset|block": "%timer|reset",
|
||||
"control.Timer.seconds|block": "%timer|seconds",
|
||||
"control.raiseEvent|block": "raise event|from %src|with value %value",
|
||||
"control.timer1|block": "timer 1",
|
||||
"control.timer2|block": "timer 2",
|
||||
"control.timer3|block": "timer 3",
|
||||
"control.timer4|block": "timer 4",
|
||||
"control.timer5|block": "timer 5",
|
||||
"control.timer6|block": "timer 6",
|
||||
"control.timer7|block": "timer 7",
|
||||
"control.timer8|block": "timer 8",
|
||||
"control|block": "control",
|
||||
"motors.Motor.angle|block": "%motor|angle",
|
||||
"motors.Motor.clearCounts|block": "%motor|clear counts",
|
||||
"motors.Motor.setRegulated|block": "set %motor|regulated %value",
|
||||
"motors.Motor.speed|block": "%motor|speed",
|
||||
"motors.Motor.tacho|block": "%motor|tacho",
|
||||
"motors.MotorBase.move|block": "move %motor|for %value|%unit|at %speed|%",
|
||||
"motors.MotorBase.pauseUntilReady|block": "%motor|pause until ready",
|
||||
"motors.MotorBase.reset|block": "%motors|reset",
|
||||
"motors.MotorBase.setBrake|block": "set %motor|brake %brake",
|
||||
"motors.MotorBase.setReversed|block": "set %motor|reversed %reversed",
|
||||
"motors.MotorBase.setSpeed|block": "set speed of %motor|to %speed|%",
|
||||
"motors.SynchedMotorPair.drive|block": "drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s|for %value|%unit",
|
||||
"motors.SynchedMotorPair.steer|block": "steer %chassis turn by|%turnRatio|at speed %speed|%|for %value|%unit",
|
||||
"motors.SynchedMotorPair.tank|block": "tank %chassis|left %speedLeft|%|right %speedRight|%|for %value|%unit",
|
||||
"motors.MotorBase.setSpeed|block": "set %motor|speed to %speed=motorSpeedPicker|%",
|
||||
"motors.MotorBase.stop|block": "%motors|stop",
|
||||
"motors.SynchedMotorPair.steer|block": "steer %chassis|turn ratio %turnRatio=motorTurnRatioPicker|speed %speed=motorSpeedPicker|%",
|
||||
"motors.SynchedMotorPair.tank|block": "tank %motors|%speedLeft=motorSpeedPicker|%|%speedRight=motorSpeedPicker|%",
|
||||
"motors.largeAB|block": "large A+B",
|
||||
"motors.largeAD|block": "large A+D",
|
||||
"motors.largeA|block": "large A",
|
||||
@ -87,9 +102,9 @@
|
||||
"{id:category}Screen": "Screen",
|
||||
"{id:category}Serial": "Serial",
|
||||
"{id:group}Buttons": "Buttons",
|
||||
"{id:group}Chassis": "Chassis",
|
||||
"{id:group}Light": "Light",
|
||||
"{id:group}Motion": "Motion",
|
||||
"{id:group}Counters": "Counters",
|
||||
"{id:group}More": "More",
|
||||
"{id:group}Move": "Move",
|
||||
"{id:group}Screen": "Screen",
|
||||
"{id:group}Sensors": "Sensors"
|
||||
}
|
12
libs/core/battery.ts
Normal file
12
libs/core/battery.ts
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
namespace brick {
|
||||
/**
|
||||
* Returns the current battery level
|
||||
*/
|
||||
//% blockId=brickBatteryLevel block="battery level"
|
||||
//% group="More"
|
||||
export function batteryLevel(): number {
|
||||
const info = sensors.internal.getBatteryInfo();
|
||||
return info.current;
|
||||
}
|
||||
}
|
@ -2,35 +2,35 @@
|
||||
/**
|
||||
* Patterns for lights under the buttons.
|
||||
*/
|
||||
const enum LightsPattern {
|
||||
//% block=Off enumval=0
|
||||
const enum BrickLight {
|
||||
//% block=off enumval=0
|
||||
//% blockIdentity=brick.lightPattern
|
||||
Off = 0,
|
||||
//% block=Green enumval=1
|
||||
//% block=green enumval=1
|
||||
//% blockIdentity=brick.lightPattern
|
||||
Green = 1,
|
||||
//% block=Red enumval=2
|
||||
//% block=red enumval=2
|
||||
//% blockIdentity=brick.lightPattern
|
||||
Red = 2,
|
||||
//% block=Orange enumval=3
|
||||
//% block=orange enumval=3
|
||||
//% blockIdentity=brick.lightPattern
|
||||
Orange = 3,
|
||||
//% block="Flashing Green" enumval=4
|
||||
//% block="green flash" enumval=4
|
||||
//% blockIdentity=brick.lightPattern
|
||||
GreenFlash = 4,
|
||||
//% block="Flashing Red" enumval=5
|
||||
//% block="red flash" enumval=5
|
||||
//% blockIdentity=brick.lightPattern
|
||||
RedFlash = 5,
|
||||
//% block="Flashing Orange" enumval=6
|
||||
//% block="orange flash" enumval=6
|
||||
//% blockIdentity=brick.lightPattern
|
||||
OrangeFlash = 6,
|
||||
//% block="Pulsing Green" enumval=7
|
||||
//% block="green pulse" enumval=7
|
||||
//% blockIdentity=brick.lightPattern
|
||||
GreenPulse = 7,
|
||||
//% block="Pulsing Red" enumval=8
|
||||
//% block="red pulse" enumval=8
|
||||
//% blockIdentity=brick.lightPattern
|
||||
RedPulse = 8,
|
||||
//% block="Pulsing Orange" enumval=9
|
||||
//% block="orange pulse" enumval=9
|
||||
//% blockIdentity=brick.lightPattern
|
||||
OrangePulse = 9,
|
||||
}
|
||||
@ -92,6 +92,7 @@ namespace brick {
|
||||
//% blockNamespace=brick
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Buttons"
|
||||
//% button.fieldEditor="brickbuttons"
|
||||
isPressed() {
|
||||
return this._isPressed
|
||||
}
|
||||
@ -107,6 +108,7 @@ namespace brick {
|
||||
//% blockNamespace=brick
|
||||
//% weight=80
|
||||
//% group="Buttons"
|
||||
//% button.fieldEditor="brickbuttons"
|
||||
wasPressed() {
|
||||
const r = this._wasPressed
|
||||
this._wasPressed = false
|
||||
@ -125,6 +127,7 @@ namespace brick {
|
||||
//% blockNamespace=brick
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Buttons"
|
||||
//% button.fieldEditor="brickbuttons"
|
||||
onEvent(ev: ButtonEvent, body: () => void) {
|
||||
control.onEvent(this._id, ev, body)
|
||||
}
|
||||
@ -139,6 +142,7 @@ namespace brick {
|
||||
//% blockNamespace=brick
|
||||
//% weight=98 blockGap=8
|
||||
//% group="Buttons"
|
||||
//% button.fieldEditor="brickbuttons"
|
||||
pauseUntil(ev: ButtonEvent) {
|
||||
control.waitForEvent(this._id, ev);
|
||||
}
|
||||
@ -163,6 +167,12 @@ namespace brick {
|
||||
if (sl[i])
|
||||
ret |= 1 << i
|
||||
}
|
||||
// this needs to be done in query(), which is run without the main JS execution mutex
|
||||
// otherwise, while(true){} will lock the device
|
||||
if (ret & DAL.BUTTON_ID_ESCAPE) {
|
||||
motors.stopAllMotors(); // ensuring that all motors are off
|
||||
control.reset()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
@ -172,8 +182,6 @@ namespace brick {
|
||||
if (!btnsMM) control.fail("no buttons?")
|
||||
buttons = []
|
||||
sensors.internal.unsafePollForChanges(50, readButtons, (prev, curr) => {
|
||||
if (curr & DAL.BUTTON_ID_ESCAPE)
|
||||
control.reset()
|
||||
for (let b of buttons)
|
||||
b._update(!!(curr & b.mask))
|
||||
})
|
||||
@ -188,7 +196,7 @@ namespace brick {
|
||||
initBtns()
|
||||
buttons.push(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initBtns() // always ON as it handles ESCAPE button
|
||||
|
||||
@ -196,31 +204,31 @@ namespace brick {
|
||||
/**
|
||||
* Enter button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="enter" weight=95 fixedInstance
|
||||
//% whenUsed block="button enter" weight=95 fixedInstance
|
||||
export const buttonEnter: Button = new DevButton(DAL.BUTTON_ID_ENTER)
|
||||
|
||||
/**
|
||||
* Left button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="left" weight=95 fixedInstance
|
||||
//% whenUsed block="button left" weight=95 fixedInstance
|
||||
export const buttonLeft: Button = new DevButton(DAL.BUTTON_ID_LEFT)
|
||||
|
||||
/**
|
||||
* Right button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="right" weight=94 fixedInstance
|
||||
//% whenUsed block="button right" weight=94 fixedInstance
|
||||
export const buttonRight: Button = new DevButton(DAL.BUTTON_ID_RIGHT)
|
||||
|
||||
/**
|
||||
* Up button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="up" weight=95 fixedInstance
|
||||
//% whenUsed block="button up" weight=95 fixedInstance
|
||||
export const buttonUp: Button = new DevButton(DAL.BUTTON_ID_UP)
|
||||
|
||||
/**
|
||||
* Down button on the EV3 Brick.
|
||||
*/
|
||||
//% whenUsed block="down" weight=95 fixedInstance
|
||||
//% whenUsed block="button down" weight=95 fixedInstance
|
||||
export const buttonDown: Button = new DevButton(DAL.BUTTON_ID_DOWN)
|
||||
}
|
||||
|
||||
@ -229,6 +237,7 @@ namespace control {
|
||||
/**
|
||||
* Determine the version of system software currently running.
|
||||
*/
|
||||
//%
|
||||
export function deviceFirmwareVersion(): string {
|
||||
let buf = output.createBuffer(6)
|
||||
brick.internal.getBtnsMM().read(buf)
|
||||
@ -243,32 +252,21 @@ namespace control {
|
||||
}
|
||||
|
||||
namespace brick {
|
||||
let currPattern: LightsPattern
|
||||
// the brick starts with the red color
|
||||
let currPattern: BrickLight = BrickLight.Red;
|
||||
|
||||
/**
|
||||
* Set lights.
|
||||
* @param pattern the lights pattern to use.
|
||||
* @param pattern the lights pattern to use. eg: BrickLight.Orange
|
||||
*/
|
||||
//% blockId=setLights block="set light to %pattern=led_pattern"
|
||||
//% blockId=setLights block="set light to %pattern"
|
||||
//% weight=100 group="Buttons"
|
||||
export function setLight(pattern: number): void {
|
||||
export function setLight(pattern: BrickLight): void {
|
||||
if (currPattern === pattern)
|
||||
return
|
||||
currPattern = pattern
|
||||
let cmd = output.createBuffer(2)
|
||||
currPattern = pattern;
|
||||
const cmd = output.createBuffer(2)
|
||||
cmd[0] = pattern + 48
|
||||
brick.internal.getBtnsMM().write(cmd)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pattern block.
|
||||
* @param pattern the lights pattern to use. eg: LightsPattern.Green
|
||||
*/
|
||||
//% blockId=led_pattern block="%pattern"
|
||||
//% shim=TD_ID colorSecondary="#6e9a36" group="Light"
|
||||
//% blockHidden=true useEnumVal=1 pattern.fieldOptions.decompileLiterals=1
|
||||
export function lightPattern(pattern: LightsPattern): number {
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
/**
|
||||
* Reading and writing data to the console output.
|
||||
*/
|
||||
//% weight=12 color=#002050 icon="\uf120"
|
||||
//% weight=12 color=#00451A icon="\uf112"
|
||||
//% advanced=true
|
||||
namespace console {
|
||||
type Listener = (text: string) => void;
|
||||
@ -58,7 +58,7 @@ namespace console {
|
||||
|
||||
namespace console.screen {
|
||||
const maxLines = 100;
|
||||
const screenLines = 8;
|
||||
const screenLines = 10;
|
||||
let lines: string[];
|
||||
let scrollPosition = 0;
|
||||
|
||||
@ -66,8 +66,8 @@ namespace console.screen {
|
||||
if (!lines) {
|
||||
lines = [];
|
||||
console.addListener(log);
|
||||
brick.buttonUp.onEvent(ButtonEvent.Click, () => scroll(-1))
|
||||
brick.buttonDown.onEvent(ButtonEvent.Click, () => scroll(1))
|
||||
brick.buttonUp.onEvent(ButtonEvent.Click, () => scroll(-3))
|
||||
brick.buttonDown.onEvent(ButtonEvent.Click, () => scroll(3))
|
||||
}
|
||||
}
|
||||
|
||||
|
11
libs/core/enums.d.ts
vendored
11
libs/core/enums.d.ts
vendored
@ -1,6 +1,17 @@
|
||||
// Auto-generated. Do not edit.
|
||||
|
||||
|
||||
/**
|
||||
* Mode for lseek()
|
||||
*/
|
||||
|
||||
declare const enum SeekWhence {
|
||||
Set = 0,
|
||||
Current = 1,
|
||||
End = 2,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Drawing modes
|
||||
*/
|
||||
|
@ -114,23 +114,7 @@
|
||||
"progressWaterLevel3": "iVBORw0KGgoAAAANSUhEUgAAALIAAACAAQAAAACHQw5jAAABP0lEQVR42u2VMWrEMBBFRxGsGrNqXYT4CltuFV9lj5EqVlhImyPkKoKFbJcrrHKCKJ2XKFb+BGxsGBdbBRJ/mGHm+VtjJGNT/srQO6cG8cnFKXvKLVdHRFcjfXD3xDyybY9IFVJgbpgHtilEa5E8XJ1m/gJbVwJFXuwRrqSYa9hSCZt/A1/B1VLjqdMG1mu0bgeD4W5Te2r1A6YVJne0qfNP57fWU9AY5dYKd29tDgodldoTqagjGaoc3VAiiibQmlg1ApeIQIjuufDUq+C0Q1z1xaJFi/60iluZ28aJ3Jy9yPU5iFxlmesZvsry+kUz8/z/5qTuZKyizM2F3IYZfnDyuR7kc61fL+P4qYmq0mCZ+tuhfHZjPvhV8iKnMVejuZNXrjnK3O77aeo03hEzNGqyUcbNnJdfPjqLFv2+vgH+JtBJ4nz/SAAAAABJRU5ErkJggg==",
|
||||
"systemAccept1": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAQAQAAAAAkX4I4AAAAQElEQVR42mM4wMDMsP//X4b6//+AWI6h/p8dQ/2fOob6H/8YKj/+Y6h4/I+hxvkfQx07UJ4fiOf/A6sF6QHqBQDsYh9jNdETHwAAAABJRU5ErkJggg==",
|
||||
"systemAccept2": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAQAQAAAAAkX4I4AAAAQUlEQVR42mM4wMDMsP//X4YEBjYGB4ZHDA6MhxgcmJsYHNiZGNz4mBjcZZgYnPcwMTj+YGJw+ADECUxgtSA9QL0A+IIPxwiZFtwAAAAASUVORK5CYII=",
|
||||
"systemAlert": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAVAQAAAAB0khOLAAAARUlEQVR42iXD0QmAIAAE0IvWCtqmMbLG8MtVhAZwjBvALyE85XzwoE/QO8f5WPsd0K+An6c3Jq8sThIUUVg9qfmDDRn7AD/WMAQEJ+pCAAAAAElFTkSuQmCC",
|
||||
"systemBox": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAQAQAAAAAkX4I4AAAAGklEQVR42mM4wMDMsP//X4b6//9IwiA9QL0AlQYkzY8nCoAAAAAASUVORK5CYII=",
|
||||
"systemBusy0": "iVBORw0KGgoAAAANSUhEUgAAABMAAAAPAQAAAAAuP8mBAAAAMElEQVR42mPY/38Bg/x/BgbnHw4Msd8dGKLeA+k4IL0XSGdB6TioOFAepA6kHqgPAJCPFdTsOCPGAAAAAElFTkSuQmCC",
|
||||
"systemBusy1": "iVBORw0KGgoAAAANSUhEUgAAAA8AAAATAQAAAABnuWoHAAAAOUlEQVR42mNoYGKw/8EAJO9/A6GrYQyv1jF8jWP4tY/hbx3D730M3+4xvH/HcO8bw90yhlvbGGDqAdjhGYsKgwC5AAAAAElFTkSuQmCC",
|
||||
"systemDecline1": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAQAQAAAAAkX4I4AAAANUlEQVR42mM4wMDMsP//X4b6//8Y6urtGOrt6hjq5/xjqD8JxI+hGMQGiQHlwGqAakF6gHoBybUeX0RcSJEAAAAASUVORK5CYII=",
|
||||
"systemDecline2": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAQAQAAAAAkX4I4AAAANUlEQVR42mM4wMDMsP//X4YEBjYGx4ZDDA4HmxgckpkYHMyAWAaKQWyQGFAOpAakFqQHqBcAGz4QyzSHE/gAAAAASUVORK5CYII=",
|
||||
"systemDotEmpty": "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAfAQAAAAA31SuUAAAAYklEQVR42oWOMQ5AQBRE5yZ7FEfSKTmC25CQuILehkahkc12IvgjRqHUTPX/ew+MzsByNlhxGq7ochz90mFL9gmBFjCSGTxZoSUb1OTwTkquP/Md61cU8USWQzZ5VaCWp+oGeLZn9EklJaAAAAAASUVORK5CYII=",
|
||||
"systemDotFull": "iVBORw0KGgoAAAANSUhEUgAAAB8AAAAfAQAAAAA31SuUAAAAX0lEQVR42mP4/0H+H8P//sf/GP7V//nH8PeDfB3D7wPs+xi+MzDeY3jHAER3GBjKGG4wMJgx7GBgsGLYwMAgBSESGBh4CBAIxWC9YFPA5oFNBtsBtg1sL9gFYLeAXAUAPIwyHWLMTS8AAAAASUVORK5CYII=",
|
||||
"systemEv3small": "iVBORw0KGgoAAAANSUhEUgAAACsAAAANAQAAAAAY06pGAAAAPUlEQVR42mNg4LFvYwACFEr+n32fPYiS5/8P5PLLyz8AUXwQqs8eSMn/b7H/D6IO1NmDBA/UgbTzP/gHpwBcwBWO2QYBDwAAAABJRU5ErkJggg==",
|
||||
"systemPlay": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQAAAAA3iMLMAAAAMElEQVR42mP4Y8/wsZ/h+XOG858Z5v5k2POXwcaGoUYOhIAMIBcoCJQCKgAq+2MPAAFKFVmziLfGAAAAAElFTkSuQmCC",
|
||||
"systemSlider0": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAEklEQVR42mM4YMBwfwPV0AEDAHmKKNims3dJAAAAAElFTkSuQmCC",
|
||||
"systemSlider1": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAGklEQVR42mM4YMBwfwNFCAKuGjCc2sBwwAAAT7olG9TpXdAAAAAASUVORK5CYII=",
|
||||
"systemSlider2": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAG0lEQVR42mM4YMBwfwM5CAJObWC4aoAgDxgAACpUJGftPg+WAAAAAElFTkSuQmCC",
|
||||
"systemSlider3": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAG0lEQVR42mM4YMBwfwMJCAKuGjCc2oCFPGAAAPSIIz417p4OAAAAAElFTkSuQmCC",
|
||||
"systemSlider4": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAG0lEQVR42mM4YMBwfwNhBAGnNjBcNcBHHjAAAMJ6IooqNLP/AAAAAElFTkSuQmCC",
|
||||
"systemSlider5": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAG0lEQVR42mM4YMBwfwNOBAFXDRhObSCKPGAAAHfbIWHuFKlNAAAAAElFTkSuQmCC",
|
||||
"systemSlider6": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAG0lEQVR42mM4YMBwfwM6goBTGxiuGpBGHjAAADklIK1PooVQAAAAAElFTkSuQmCC",
|
||||
"systemSlider7": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAG0lEQVR42mM4YMBwfwMUQcBVA4ZTG8gkDxgAANmVH4SOiUHMAAAAAElFTkSuQmCC",
|
||||
"systemSlider8": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAAbAQAAAABg3VNpAAAAFElEQVR42mM4YMBwagPDVSqRBwwASoohT92wVBIAAAAASUVORK5CYII="
|
||||
"systemDecline2": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAQAQAAAAAkX4I4AAAANUlEQVR42mM4wMDMsP//X4YEBjYGx4ZDDA4HmxgckpkYHMyAWAaKQWyQGFAOpAakFqQHqBcAGz4QyzSHE/gAAAAASUVORK5CYII="
|
||||
}
|
@ -220,41 +220,10 @@ namespace images {
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemAccept2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemAlert = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemBox = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemBusy0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemBusy1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemDecline1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemDecline2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemDotEmpty = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemDotFull = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemEv3small = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemPlay = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider0 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider1 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider2 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider3 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider4 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider5 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider6 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider7 = screen.unpackPNG(hex``);
|
||||
//% fixedInstance jres blockIdentity=brick.__imagePicker
|
||||
export const systemSlider8 = screen.unpackPNG(hex``);
|
||||
}
|
||||
|
@ -89,6 +89,14 @@ namespace sensors.internal {
|
||||
//serial.writeLine("UART " + port + " / " + mode + " - " + info)
|
||||
}
|
||||
|
||||
export function getBatteryInfo(): { temp: number; current: number } {
|
||||
init();
|
||||
return {
|
||||
temp: analogMM.getNumber(NumberFormat.Int16LE, AnalogOff.BatteryTemp),
|
||||
current: Math.round(analogMM.getNumber(NumberFormat.Int16LE, AnalogOff.BatteryCurrent) / 10)
|
||||
}
|
||||
}
|
||||
|
||||
function detectDevices() {
|
||||
let conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
|
||||
let numChanged = 0
|
||||
@ -301,6 +309,10 @@ namespace sensors.internal {
|
||||
return 0
|
||||
return getUartNumber(fmt, off, this._port)
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (this.isActive()) uartReset(this._port);
|
||||
}
|
||||
}
|
||||
|
||||
function uartReset(port: number) {
|
||||
|
@ -483,7 +483,15 @@ void runLMS() {
|
||||
*/
|
||||
}
|
||||
|
||||
void stopMotors() {
|
||||
uint8_t cmd[2] = { 0xA3, 0x0F };
|
||||
int fd = open("/dev/lms_pwm", O_RDWR);
|
||||
write(fd, cmd, 2);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
extern "C" void target_reset() {
|
||||
stopMotors();
|
||||
if (lmsPid)
|
||||
runLMS();
|
||||
else
|
||||
|
@ -7,6 +7,16 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/**
|
||||
* Mode for lseek()
|
||||
*/
|
||||
enum class SeekWhence {
|
||||
Set = 0,
|
||||
Current = 1,
|
||||
End = 2,
|
||||
};
|
||||
|
||||
|
||||
namespace pxt {
|
||||
PXT_VTABLE_CTOR(MMap) {
|
||||
length = 0;
|
||||
@ -111,4 +121,10 @@ int read(MMap *mmap, Buffer data) {
|
||||
return ::read(mmap->fd, data->data, data->length);
|
||||
}
|
||||
|
||||
/** Set pointer on the underlaying file. */
|
||||
//%
|
||||
int lseek(MMap *mmap, int offset, SeekWhence whence) {
|
||||
return ::lseek(mmap->fd, offset, (int)whence);
|
||||
}
|
||||
|
||||
}
|
@ -1 +1,25 @@
|
||||
|
||||
namespace motors {
|
||||
|
||||
/**
|
||||
* A speed picker
|
||||
* @param speed the speed, eg: 50
|
||||
*/
|
||||
//% blockId=motorSpeedPicker block="%speed" shim=TD_ID
|
||||
//% speed.fieldEditor="speed" colorSecondary="#FFFFFF"
|
||||
//% weight=0 blockHidden=1 speed.fieldOptions.decompileLiterals=1
|
||||
export function __speedPicker(speed: number): number {
|
||||
return speed;
|
||||
}
|
||||
|
||||
/**
|
||||
* A turn ratio picker
|
||||
* @param turnratio the turn ratio, eg: 0
|
||||
*/
|
||||
//% blockId=motorTurnRatioPicker block="%turnratio" shim=TD_ID
|
||||
//% turnratio.fieldEditor="turnratio" colorSecondary="#FFFFFF"
|
||||
//% weight=0 blockHidden=1 turnRatio.fieldOptions.decompileLiterals=1
|
||||
export function __turnRatioPicker(turnratio: number): number {
|
||||
return turnratio;
|
||||
}
|
||||
}
|
@ -30,6 +30,8 @@ enum MoveUnit {
|
||||
Rotations,
|
||||
//% block="degrees"
|
||||
Degrees,
|
||||
//% block="seconds"
|
||||
Seconds,
|
||||
//% block="milliseconds"
|
||||
MilliSeconds
|
||||
}
|
||||
@ -94,7 +96,7 @@ namespace motors {
|
||||
return b
|
||||
}
|
||||
|
||||
function outputToName(out: Output): string {
|
||||
export function outputToName(out: Output): string {
|
||||
let r = "";
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (out & (1 << i)) {
|
||||
@ -109,8 +111,8 @@ namespace motors {
|
||||
* Stops all motors
|
||||
*/
|
||||
//% blockId=motorStopAll block="stop all motors"
|
||||
//% weight=5
|
||||
//% group="Motion"
|
||||
//% weight=1
|
||||
//% group="Move"
|
||||
export function stopAllMotors() {
|
||||
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
||||
writePWM(b)
|
||||
@ -119,7 +121,7 @@ namespace motors {
|
||||
/**
|
||||
* Resets all motors
|
||||
*/
|
||||
//% group="Motion"
|
||||
//% group="Move"
|
||||
export function resetAllMotors() {
|
||||
reset(Output.ALL)
|
||||
}
|
||||
@ -162,7 +164,7 @@ namespace motors {
|
||||
//% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake"
|
||||
//% brake.fieldEditor=toggleonoff
|
||||
//% weight=60 blockGap=8
|
||||
//% group="Motion"
|
||||
//% group="Move"
|
||||
setBrake(brake: boolean) {
|
||||
this.init();
|
||||
this._brake = brake;
|
||||
@ -173,8 +175,8 @@ namespace motors {
|
||||
*/
|
||||
//% blockId=motorSetReversed block="set %motor|reversed %reversed"
|
||||
//% reversed.fieldEditor=toggleonoff
|
||||
//% weight=59
|
||||
//% group="Motion"
|
||||
//% weight=59 blockGap=8
|
||||
//% group="Move"
|
||||
setReversed(reversed: boolean) {
|
||||
this.init();
|
||||
const b = mkCmd(this._port, DAL.opOutputPolarity, 1)
|
||||
@ -185,7 +187,9 @@ namespace motors {
|
||||
/**
|
||||
* Stops the motor(s).
|
||||
*/
|
||||
//%
|
||||
//% weight=6 blockGap=8
|
||||
//% group="Move"
|
||||
//% blockId=motorStop block="%motors|stop"
|
||||
stop() {
|
||||
this.init();
|
||||
stop(this._port, this._brake);
|
||||
@ -194,47 +198,37 @@ namespace motors {
|
||||
/**
|
||||
* Resets the motor(s).
|
||||
*/
|
||||
//%
|
||||
//% weight=5
|
||||
//% group="Move"
|
||||
//% blockId=motorReset block="%motors|reset"
|
||||
reset() {
|
||||
this.init();
|
||||
reset(this._port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the speed of the motor.
|
||||
* Sets the motor speed for limited time or distance.
|
||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||
* @param value (optional) measured distance or rotation
|
||||
* @param unit (optional) unit of the value
|
||||
*/
|
||||
//% blockId=motorSetSpeed block="set speed of %motor|to %speed|%"
|
||||
//% on.fieldEditor=toggleonoff
|
||||
//% weight=99 blockGap=8
|
||||
//% speed.min=-100 speed.max=100
|
||||
//% group="Motion"
|
||||
setSpeed(speed: number) {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
if (!speed) // always stop
|
||||
this.stop();
|
||||
else
|
||||
this._setSpeed(speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the motor by a number of rotations, degress or seconds
|
||||
* @param value the move quantity, eg: 2
|
||||
* @param unit the meaning of the value
|
||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||
*/
|
||||
//% blockId=motorMove block="move %motor|for %value|%unit|at %speed|%"
|
||||
//% weight=98 blockGap=8
|
||||
//% speed.min=-100 speed.max=100
|
||||
//% group="Motion"
|
||||
move(value: number, unit: MoveUnit, speed: number) {
|
||||
//% blockId=motorSetSpeed block="set %motor|speed to %speed=motorSpeedPicker|%"
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Move"
|
||||
setSpeed(speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
// stop if speed is 0
|
||||
if (!speed) {
|
||||
this.stop();
|
||||
return;
|
||||
}
|
||||
// special: 0 is infinity
|
||||
if (value == 0) {
|
||||
this._setSpeed(speed);
|
||||
return;
|
||||
}
|
||||
// timed motor moves
|
||||
let useSteps: boolean;
|
||||
let stepsOrTime: number;
|
||||
switch (unit) {
|
||||
@ -246,6 +240,10 @@ namespace motors {
|
||||
stepsOrTime = value >> 0;
|
||||
useSteps = true;
|
||||
break;
|
||||
case MoveUnit.Seconds:
|
||||
stepsOrTime = (value * 1000) >> 0;
|
||||
useSteps = false;
|
||||
break;
|
||||
default:
|
||||
stepsOrTime = value;
|
||||
useSteps = false;
|
||||
@ -253,6 +251,8 @@ namespace motors {
|
||||
}
|
||||
|
||||
this._move(useSteps, stepsOrTime, speed);
|
||||
// wait till motor is done with this work
|
||||
this.pauseUntilReady();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -264,13 +264,7 @@ namespace motors {
|
||||
const buf = mkCmd(this._port, DAL.opOutputTest, 2);
|
||||
readPWM(buf)
|
||||
const flags = buf.getNumber(NumberFormat.UInt8LE, 2);
|
||||
// TODO: FIX with ~ support
|
||||
for(let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
const flag = 1 << i;
|
||||
if ((this._port & flag) && (flags & flag))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return (~flags & this._port) == this._port;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,8 +272,8 @@ namespace motors {
|
||||
* @param timeOut optional maximum pausing time in milliseconds
|
||||
*/
|
||||
//% blockId=motorPauseUntilRead block="%motor|pause until ready"
|
||||
//% weight=97
|
||||
//% group="Motion"
|
||||
//% weight=90
|
||||
//% group="Move"
|
||||
pauseUntilReady(timeOut?: number) {
|
||||
pauseUntil(() => this.isReady(), timeOut);
|
||||
}
|
||||
@ -288,10 +282,12 @@ namespace motors {
|
||||
//% fixedInstances
|
||||
export class Motor extends MotorBase {
|
||||
private _large: boolean;
|
||||
private _regulated: boolean;
|
||||
|
||||
constructor(port: Output, large: boolean) {
|
||||
super(port, () => this.__init(), (speed) => this.__setSpeed(speed), (steps, stepsOrTime, speed) => this.__move(steps, stepsOrTime, speed));
|
||||
this._large = large;
|
||||
this._regulated = true;
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
@ -307,7 +303,7 @@ namespace motors {
|
||||
}
|
||||
|
||||
private __setSpeed(speed: number) {
|
||||
const b = mkCmd(this._port, DAL.opOutputSpeed, 1)
|
||||
const b = mkCmd(this._port, this._regulated ? DAL.opOutputSpeed : DAL.opOutputPower, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, speed)
|
||||
writePWM(b)
|
||||
if (speed) {
|
||||
@ -321,11 +317,24 @@ namespace motors {
|
||||
step1: 0,
|
||||
step2: stepsOrTime,
|
||||
step3: 0,
|
||||
speed: speed,
|
||||
speed: this._regulated ? speed : undefined,
|
||||
power: this._regulated ? undefined : speed,
|
||||
useBrake: this._brake
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the motor speed should be regulated. Default is true.
|
||||
* @param value true for regulated motor
|
||||
*/
|
||||
//% blockId=outputMotorSetRegulated block="set %motor|regulated %value"
|
||||
//% value.fieldEditor=toggleonoff
|
||||
//% weight=58
|
||||
//% group="Move"
|
||||
setRegulated(value: boolean) {
|
||||
this._regulated = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor actual speed.
|
||||
* @param motor the port which connects to the motor
|
||||
@ -333,7 +342,7 @@ namespace motors {
|
||||
//% blockId=motorSpeed block="%motor|speed"
|
||||
//% weight=72
|
||||
//% blockGap=8
|
||||
//% group="Sensors"
|
||||
//% group="Counters"
|
||||
speed(): number {
|
||||
this.init();
|
||||
return getMotorData(this._port).actualSpeed;
|
||||
@ -345,7 +354,8 @@ namespace motors {
|
||||
*/
|
||||
//% blockId=motorAngle block="%motor|angle"
|
||||
//% weight=70
|
||||
//% group="Sensors"
|
||||
//% blockGap=8
|
||||
//% group="Counters"
|
||||
angle(): number {
|
||||
this.init();
|
||||
return getMotorData(this._port).count;
|
||||
@ -359,7 +369,7 @@ namespace motors {
|
||||
//% blockId=motorTachoCount block="%motor|tacho"
|
||||
//% weight=69
|
||||
//% blockGap=8
|
||||
//% group="Sensors"
|
||||
//% group="Counters"
|
||||
tacho(): number {
|
||||
this.init();
|
||||
return getMotorData(this._port).tachoCount;
|
||||
@ -371,7 +381,7 @@ namespace motors {
|
||||
//% blockId=motorClearCount block="%motor|clear counts"
|
||||
//% weight=68
|
||||
//% blockGap=8
|
||||
//% group="Sensors"
|
||||
//% group="Counters"
|
||||
clearCounts() {
|
||||
this.init();
|
||||
const b = mkCmd(this._port, DAL.opOutputClearCount, 0)
|
||||
@ -418,13 +428,9 @@ namespace motors {
|
||||
|
||||
//% fixedInstances
|
||||
export class SynchedMotorPair extends MotorBase {
|
||||
private wheelRadius: number;
|
||||
private baseLength: number;
|
||||
|
||||
constructor(ports: Output) {
|
||||
super(ports, () => this.__init(), (speed) => this.__setSpeed(speed), (steps, stepsOrTime, speed) => this.__move(steps, stepsOrTime, speed));
|
||||
this.wheelRadius = 3;
|
||||
this.baseLength = 12;
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
@ -445,7 +451,7 @@ namespace motors {
|
||||
private __setSpeed(speed: number) {
|
||||
syncMotors(this._port, {
|
||||
speed: speed,
|
||||
turnRatio: 100, // same speed
|
||||
turnRatio: 0, // same speed
|
||||
useBrake: !!this._brake
|
||||
})
|
||||
}
|
||||
@ -454,7 +460,7 @@ namespace motors {
|
||||
syncMotors(this._port, {
|
||||
useSteps: steps,
|
||||
speed: speed,
|
||||
turnRatio: 100, // same speed
|
||||
turnRatio: 0, // same speed
|
||||
stepsOrTime: stepsOrTime,
|
||||
useBrake: this._brake
|
||||
});
|
||||
@ -466,18 +472,16 @@ namespace motors {
|
||||
* with one motor driving the left side of the vehicle and the other the right side.
|
||||
* You can make the two motors go at different speeds or in different directions
|
||||
* to make your robot turn.
|
||||
* @param value the amount of movement, eg: 2
|
||||
* @param unit
|
||||
* @param speedLeft the speed on the left motor, eg: 50
|
||||
* @param speedRight the speed on the right motor, eg: 50
|
||||
* @param value (optional) move duration or rotation
|
||||
* @param unit (optional) unit of the value
|
||||
*/
|
||||
//% blockId=motorPairTank block="tank %chassis|left %speedLeft|%|right %speedRight|%|for %value|%unit"
|
||||
//% weight=9 blockGap=8
|
||||
//% speedLeft.min=-100 speedLeft=100
|
||||
//% speedRight.min=-100 speedRight=100
|
||||
//% blockId=motorPairTank block="tank %motors|%speedLeft=motorSpeedPicker|%|%speedRight=motorSpeedPicker|%"
|
||||
//% weight=96 blockGap=8
|
||||
//% inlineInputMode=inline
|
||||
//% group="Chassis"
|
||||
tank(speedLeft: number, speedRight: number, value: number, unit: MoveUnit) {
|
||||
//% group="Move"
|
||||
tank(speedLeft: number, speedRight: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
|
||||
this.init();
|
||||
|
||||
speedLeft = Math.clamp(-100, 100, speedLeft >> 0);
|
||||
@ -487,56 +491,23 @@ namespace motors {
|
||||
const turnRatio = speedLeft == speed
|
||||
? (100 - speedRight / speedLeft * 100)
|
||||
: (speedLeft / speedRight * 100 - 100);
|
||||
|
||||
this.steer(turnRatio, speed, value, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a differential drive robot move with a given speed (%) and rotation rate (deg/s)
|
||||
* using a unicycle model.
|
||||
* @param speed speed of the center point between motors, eg: 10
|
||||
* @param rotationSpeed rotation of the robot around the center point, eg: 30
|
||||
* @param value the amount of movement, eg: 2
|
||||
* @param unit
|
||||
*/
|
||||
//% blockId=motorDrive block="drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s|for %value|%unit"
|
||||
//% inlineInputMode=inline
|
||||
//% group="Chassis"
|
||||
//% weight=8 blockGap=8
|
||||
drive(speed: number, rotationSpeed: number, value: number, unit: MoveUnit) {
|
||||
this.init();
|
||||
|
||||
// speed is expressed in %
|
||||
const R = this.wheelRadius; // cm
|
||||
const L = this.baseLength; // cm
|
||||
const PI = 3.14;
|
||||
const maxw = 170 / 60 * 2 * PI; // rad / s
|
||||
const maxv = maxw * R; // cm / s
|
||||
// speed is cm / s
|
||||
const v = speed; // cm / s
|
||||
const w = rotationSpeed / 360 * 2 * PI; // rad / s
|
||||
|
||||
const vr = (2 * v + w * L) / (2 * R); // rad / s
|
||||
const vl = (2 * v - w * L) / (2 * R); // rad / s
|
||||
|
||||
const sr = vr / maxw * 100; // %
|
||||
const sl = vl / maxw * 100; // %
|
||||
|
||||
this.tank(sr, sl, value, unit)
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns the motor and the follower motor by a number of rotations
|
||||
* @param turnRatio the ratio of power sent to the follower motor, from ``-200`` to ``200``, eg: 0
|
||||
* @param speed the speed from ``100`` full forward to ``-100`` full backward, eg: 50
|
||||
* @param value the move quantity, eg: 2
|
||||
* @param unit the meaning of the value
|
||||
* @param value (optional) move duration or rotation
|
||||
* @param unit (optional) unit of the value
|
||||
*/
|
||||
//% blockId=motorPairTurn block="steer %chassis turn by|%turnRatio|at speed %speed|%|for %value|%unit"
|
||||
//% weight=6 blockGap=8
|
||||
//% blockId=motorPairSteer block="steer %chassis|turn ratio %turnRatio=motorTurnRatioPicker|speed %speed=motorSpeedPicker|%"
|
||||
//% weight=95
|
||||
//% turnRatio.min=-200 turnRatio=200
|
||||
//% inlineInputMode=inline
|
||||
//% group="Chassis"
|
||||
steer(turnRatio: number, speed: number, value: number, unit: MoveUnit) {
|
||||
//% group="Move"
|
||||
steer(turnRatio: number, speed: number, value: number = 0, unit: MoveUnit = MoveUnit.MilliSeconds) {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
if (!speed) {
|
||||
@ -556,6 +527,10 @@ namespace motors {
|
||||
stepsOrTime = value >> 0;
|
||||
useSteps = true;
|
||||
break;
|
||||
case MoveUnit.Seconds:
|
||||
stepsOrTime = (value * 1000) >> 0;
|
||||
useSteps = false;
|
||||
break;
|
||||
default:
|
||||
stepsOrTime = value >> 0;
|
||||
useSteps = false;
|
||||
@ -569,17 +544,6 @@ namespace motors {
|
||||
stepsOrTime: stepsOrTime,
|
||||
useBrake: this._brake
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the wheels radius and base length of a directional drive robot
|
||||
* @param wheelRadius
|
||||
* @param baseLength
|
||||
*/
|
||||
//% group="Chassis"
|
||||
setDimensions(wheelRadius: number, baseLength: number): void {
|
||||
this.wheelRadius = wheelRadius;
|
||||
this.baseLength = baseLength;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,11 +11,13 @@
|
||||
"mmap.cpp",
|
||||
"control.cpp",
|
||||
"console.ts",
|
||||
"timer.ts",
|
||||
"serialnumber.cpp",
|
||||
"buttons.ts",
|
||||
"png.cpp",
|
||||
"screen.cpp",
|
||||
"screen.ts",
|
||||
"battery.ts",
|
||||
"output.cpp",
|
||||
"output.ts",
|
||||
"core.ts",
|
||||
|
@ -58,29 +58,7 @@ namespace brick {
|
||||
}
|
||||
}
|
||||
|
||||
export function microbitFont() {
|
||||
return {
|
||||
charWidth: 6,
|
||||
charHeight: 5,
|
||||
firstChar: 32,
|
||||
// source https://github.com/lancaster-university/microbit-dal/blob/master/source/core/MicroBitFont.cpp
|
||||
data: hex`
|
||||
0000000000 0202020002 0a0a000000 0a1f0a1f0a 0e130e190e 1309041219 0609060916 0202000000 0402020204
|
||||
0204040402 000a040a00 00040e0400 0000000402 00000e0000 0000000200 1008040201 0609090906 040604040e
|
||||
070806010f 0f08040906 0c0a091f08 1f010f100f 08040e110e 1f08040201 0e110e110e 0e110e0402 0002000200
|
||||
0004000402 0804020408 000e000e00 0204080402 0e110c0004 0e11151906 06090f0909 0709070907 0e0101010e
|
||||
0709090907 0f0107010f 0f01070101 0e0119110e 09090f0909 0702020207 1f08080906 0905030509 010101010f
|
||||
111b151111 1113151911 0609090906 0709070101 060909060c 0709070911 0e01060807 1f04040404 0909090906
|
||||
1111110a04 1111151b11 0909060909 110a040404 0f0402010f 0e0202020e 0102040810 0e0808080e 040a000000
|
||||
000000001f 0204000000 000e09091e 0101070907 000e01010e 08080e090e 060907010e 0c02070202 0e090e0806
|
||||
0101070909 0200020202 0800080806 0105030509 020202020c 001b151111 0007090909 0006090906 0007090701
|
||||
000e090e08 000e010101 000c020403 02020e021c 000909091e 0011110a04 001111151b 0009060609 00110a0403
|
||||
000f04020f 0c0406040c 0202020202 0302060203 0000061800
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
export function setPixel(on: boolean, x: number, y: number) {
|
||||
function setPixel(on: boolean, x: number, y: number) {
|
||||
x |= 0
|
||||
y |= 0
|
||||
if (0 <= x && x < DAL.LCD_WIDTH && 0 <= y && y < DAL.LCD_HEIGHT)
|
||||
@ -90,18 +68,43 @@ namespace brick {
|
||||
/**
|
||||
* Show text on the screen at a specific line.
|
||||
* @param text the text to print on the screen, eg: "Hello world"
|
||||
* @param line the line number to print the text at, eg: 0
|
||||
* @param line the line number to print the text at, eg: 1
|
||||
*/
|
||||
//% blockId=screen_print block="print %text| at line %line"
|
||||
//% blockId=screen_print block="show string %text|at line %line"
|
||||
//% weight=98 group="Screen" inlineInputMode="inline" blockGap=8
|
||||
//% line.min=0 line.max=9
|
||||
export function printLine(text: string, line: number) {
|
||||
//% line.min=1 line.max=10
|
||||
export function showString(text: string, line: number) {
|
||||
const NUM_LINES = 9;
|
||||
const offset = 5;
|
||||
const y = offset + (Math.clamp(0, NUM_LINES, line) / (NUM_LINES + 2)) * DAL.LCD_HEIGHT;
|
||||
const y = offset + (Math.clamp(0, NUM_LINES, line - 1) / (NUM_LINES + 2)) * DAL.LCD_HEIGHT;
|
||||
brick.print(text, offset, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a number on the screen
|
||||
* @param value the numeric value
|
||||
* @param line the line number to print the text at, eg: 1
|
||||
*/
|
||||
//% blockId=screenShowNumber block="show number %name|at line %line"
|
||||
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
|
||||
//% line.min=1 line.max=10
|
||||
export function showNumber(value: number, line: number) {
|
||||
showString("" + value, line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a name, value pair on the screen
|
||||
* @param value the numeric value
|
||||
* @param line the line number to print the text at, eg: 1
|
||||
*/
|
||||
//% blockId=screenShowValue block="show value %name|= %text|at line %line"
|
||||
//% weight=96 group="Screen" inlineInputMode="inline" blockGap=8
|
||||
//% line.min=1 line.max=10
|
||||
export function showValue(name: string, value: number, line: number) {
|
||||
value = Math.round(value * 1000) / 1000;
|
||||
showString((name ? name + ": " : "") + value, line);
|
||||
}
|
||||
|
||||
export function print(text: string, x: number, y: number, mode = Draw.Normal) {
|
||||
x |= 0
|
||||
y |= 0
|
||||
@ -138,12 +141,9 @@ namespace brick {
|
||||
*/
|
||||
//% blockId=screen_show_image block="show image %image=screen_image_picker"
|
||||
//% weight=100 group="Screen" blockGap=8
|
||||
export function showImage(image: Image, delay: number = 400) {
|
||||
export function showImage(image: Image) {
|
||||
if (!image) return;
|
||||
image.draw(0, 0, Draw.Normal);
|
||||
delay = Math.max(0, delay);
|
||||
if (delay > 0)
|
||||
loops.pause(delay);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -168,7 +168,7 @@ namespace brick {
|
||||
screen.clear();
|
||||
}
|
||||
|
||||
export function drawRect(x: number, y: number, w: number, h: number, mode = Draw.Normal) {
|
||||
function drawRect(x: number, y: number, w: number, h: number, mode = Draw.Normal) {
|
||||
x |= 0;
|
||||
y |= 0;
|
||||
w |= 0;
|
||||
@ -213,30 +213,32 @@ namespace brick {
|
||||
//% blockId=brickPrintPorts block="print ports"
|
||||
//% weight=1 group="Screen"
|
||||
export function printPorts() {
|
||||
const col = 44;
|
||||
clearScreen();
|
||||
|
||||
function scale(x: number) {
|
||||
if (Math.abs(x) > 1000) return Math.round(x / 100) / 10 + "k";
|
||||
return ("" + (x >> 0));
|
||||
}
|
||||
|
||||
// motors
|
||||
const datas = motors.getAllMotorData();
|
||||
for(let i = 0; i < datas.length; ++i) {
|
||||
const data = datas[i];
|
||||
if (!data.actualSpeed && !data.count) continue;
|
||||
const x = i * 52;
|
||||
print(`${data.actualSpeed}%`, x, brick.LINE_HEIGHT)
|
||||
print(`${data.count}>`, x, 2 * brick.LINE_HEIGHT)
|
||||
|
||||
console.logValue(`speed.` + "ABCD"[i], data.actualSpeed);
|
||||
console.logValue(`angle.` + "ABCD"[i], data.count);
|
||||
const x = i * col;
|
||||
print(`${scale(data.actualSpeed)}%`, x, brick.LINE_HEIGHT)
|
||||
print(`${scale(data.count)}>`, x, 2 * brick.LINE_HEIGHT)
|
||||
print(`${scale(data.tachoCount)}|`, x, 3 * brick.LINE_HEIGHT)
|
||||
}
|
||||
|
||||
// sensors
|
||||
const sis = sensors.internal.getActiveSensors();
|
||||
for(let i =0; i < sis.length; ++i) {
|
||||
const si = sis[i];
|
||||
const x = (si.port() - 1) * 52;
|
||||
const x = (si.port() - 1) * col;
|
||||
const v = si._query();
|
||||
print(`${v}`, x, 9 * brick.LINE_HEIGHT)
|
||||
|
||||
console.logValue(`sensor.` + si.port(), v);
|
||||
print(`${scale(v)}`, x, 9 * brick.LINE_HEIGHT)
|
||||
}
|
||||
}
|
||||
}
|
4
libs/core/shims.d.ts
vendored
4
libs/core/shims.d.ts
vendored
@ -41,6 +41,10 @@ declare interface MMap {
|
||||
/** Perform read(2) on the underlaying file */
|
||||
//% shim=MMapMethods::read
|
||||
read(data: Buffer): int32;
|
||||
|
||||
/** Set pointer on the underlaying file. */
|
||||
//% shim=MMapMethods::lseek
|
||||
lseek(offset: int32, whence: SeekWhence): int32;
|
||||
}
|
||||
declare namespace control {
|
||||
|
||||
|
@ -2,7 +2,7 @@ screen.clear()
|
||||
brick.print("PXT!", 10, 30, Draw.Quad)
|
||||
|
||||
brick.drawRect(40, 40, 20, 10, Draw.Fill)
|
||||
brick.setLight(LightsPattern.Orange)
|
||||
brick.setLight(BrickLight.Orange)
|
||||
|
||||
brick.heart.doubled().draw(100, 50, Draw.Double | Draw.Transparent)
|
||||
|
||||
@ -12,7 +12,7 @@ brick.buttonEnter.onEvent(ButtonEvent.Click, () => {
|
||||
|
||||
brick.buttonLeft.onEvent(ButtonEvent.Click, () => {
|
||||
brick.drawRect(10, 70, 20, 10, Draw.Fill)
|
||||
brick.setLight(LightsPattern.Red)
|
||||
brick.setLight(BrickLight.Red)
|
||||
brick.setFont(brick.microbitFont())
|
||||
})
|
||||
|
||||
|
51
libs/core/timer.ts
Normal file
51
libs/core/timer.ts
Normal file
@ -0,0 +1,51 @@
|
||||
namespace control {
|
||||
//% fixedInstances
|
||||
export class Timer {
|
||||
start: number;
|
||||
|
||||
constructor() {
|
||||
this.start = control.millis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the elapsed time in millis
|
||||
*/
|
||||
//% blockId=timerMillis block="%timer|millis"
|
||||
millis(): number {
|
||||
return control.millis() - this.start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the elapsed time in seconds
|
||||
*/
|
||||
//% blockId=timerSeconds block="%timer|seconds"
|
||||
seconds(): number {
|
||||
return this.millis() / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the timer
|
||||
*/
|
||||
//% blockId=timerRest block="%timer|reset"
|
||||
reset() {
|
||||
this.start = control.millis();
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed fixedInstance block="timer 1"
|
||||
export const timer1 = new Timer();
|
||||
//% whenUsed fixedInstance block="timer 2"
|
||||
export const timer2 = new Timer();
|
||||
//% whenUsed fixedInstance block="timer 3"
|
||||
export const timer3 = new Timer();
|
||||
//% whenUsed fixedInstance block="timer 4"
|
||||
export const timer4 = new Timer();
|
||||
//% whenUsed fixedInstance block="timer 5"
|
||||
export const timer5 = new Timer();
|
||||
//% whenUsed fixedInstance block="timer 6"
|
||||
export const timer6 = new Timer();
|
||||
//% whenUsed fixedInstance block="timer 7"
|
||||
export const timer7 = new Timer();
|
||||
//% whenUsed fixedInstance block="timer 8"
|
||||
export const timer8 = new Timer();
|
||||
}
|
3
libs/datalog/README.md
Normal file
3
libs/datalog/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Datalog
|
||||
|
||||
A tiny libraty to create CSV datalog files.
|
8
libs/datalog/_locales/datalog-jsdoc-strings.json
Normal file
8
libs/datalog/_locales/datalog-jsdoc-strings.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"datalog.addRow": "Starts a row of data",
|
||||
"datalog.addValue": "Adds a cell to the row of data",
|
||||
"datalog.addValue|param|name": "name of the cell, eg: \"x\"",
|
||||
"datalog.addValue|param|value": "value of the cell, eg: 0",
|
||||
"datalog.setFile": "Starts a new data logger for the given file",
|
||||
"datalog.setStorage": "* @param storage custom storage solution"
|
||||
}
|
6
libs/datalog/_locales/datalog-strings.json
Normal file
6
libs/datalog/_locales/datalog-strings.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"datalog.addRow|block": "datalog add row",
|
||||
"datalog.addValue|block": "datalog add %name|=%value",
|
||||
"datalog|block": "datalog",
|
||||
"{id:category}Datalog": "Datalog"
|
||||
}
|
90
libs/datalog/datalog.ts
Normal file
90
libs/datalog/datalog.ts
Normal file
@ -0,0 +1,90 @@
|
||||
//% weight=100 color=#0fbc11 icon=""
|
||||
namespace datalog {
|
||||
let _headers: string[] = undefined;
|
||||
let _headersLength: number;
|
||||
let _values: number[];
|
||||
let _start: number;
|
||||
let _filename = "data.csv";
|
||||
let _storage: storage.Storage = storage.temporary;
|
||||
|
||||
function clear() {
|
||||
_headers = undefined;
|
||||
_values = undefined;
|
||||
}
|
||||
|
||||
function init() {
|
||||
if (!_headers) {
|
||||
_headers = [];
|
||||
_headersLength = 0;
|
||||
_start = control.millis();
|
||||
_storage.remove(_filename);
|
||||
}
|
||||
_values = [];
|
||||
}
|
||||
|
||||
function commit() {
|
||||
// write row if any data
|
||||
if (_values && _values.length > 0) {
|
||||
// write headers for the first row
|
||||
if (!_headersLength) {
|
||||
_storage.appendCSVHeaders(_filename, _headers);
|
||||
_headersLength = _storage.size(_filename);
|
||||
}
|
||||
// commit row data
|
||||
_storage.appendCSV(_filename, _values);
|
||||
}
|
||||
|
||||
// clear values
|
||||
_values = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a row of data
|
||||
*/
|
||||
//% weight=100
|
||||
//% blockId=datalogAddRow block="datalog add row"
|
||||
export function addRow(): void {
|
||||
commit();
|
||||
init();
|
||||
const s = (control.millis() - _start) / 1000;
|
||||
addValue("time (s)", s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a cell to the row of data
|
||||
* @param name name of the cell, eg: "x"
|
||||
* @param value value of the cell, eg: 0
|
||||
*/
|
||||
//% weight=99
|
||||
//% blockId=datalogAddValue block="datalog add %name|=%value"
|
||||
export function addValue(name: string, value: number) {
|
||||
if (!_values) return;
|
||||
let i = _headers.indexOf(name);
|
||||
if (i < 0) {
|
||||
_headers.push(name);
|
||||
i = _headers.length - 1;
|
||||
}
|
||||
_values[i] = value;
|
||||
if (i > 0) // 0 is time
|
||||
console.logValue(name, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new data logger for the given file
|
||||
*/
|
||||
//%
|
||||
export function setFile(fn: string) {
|
||||
_filename = fn;
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param storage custom storage solution
|
||||
*/
|
||||
//%
|
||||
export function setStorage(storage: storage.Storage) {
|
||||
_storage = storage;
|
||||
clear();
|
||||
}
|
||||
}
|
16
libs/datalog/pxt.json
Normal file
16
libs/datalog/pxt.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "datalog",
|
||||
"description": "Tiny data logging framework",
|
||||
"files": [
|
||||
"README.md",
|
||||
"datalog.ts"
|
||||
],
|
||||
"testFiles": [
|
||||
"test.ts"
|
||||
],
|
||||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core",
|
||||
"storage": "file:../storage"
|
||||
}
|
||||
}
|
6
libs/datalog/test.ts
Normal file
6
libs/datalog/test.ts
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
loops.forever(function () {
|
||||
datalog.addRow()
|
||||
datalog.addValue("x", Math.random())
|
||||
datalog.addValue("y", Math.random())
|
||||
})
|
@ -8,17 +8,22 @@ namespace brick {
|
||||
|
||||
//% color="#C8509B" weight=95 icon="\uf10f"
|
||||
//% labelLineWidth=0
|
||||
//% groups='["Ultrasonic Sensor", "Touch Sensor", "Color Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
|
||||
//% groups='["Touch Sensor", "Color Sensor", "Ultrasonic Sensor", "Gyro Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Threshold"]'
|
||||
//% groupIcons='["\uf101","\uf103","\uf102","","","\uf104"]'
|
||||
namespace sensors {
|
||||
}
|
||||
|
||||
//% color="#A5CA18" weight=90 icon="\uf10d"
|
||||
//% groups='["Motion", "Sensors", "Chassis"]'
|
||||
//% groups='["Move", "Counters"]'
|
||||
//% labelLineWidth=0
|
||||
namespace motors {
|
||||
}
|
||||
|
||||
//% labelLineWidth=0
|
||||
namespace chassis {
|
||||
|
||||
}
|
||||
|
||||
//% labelLineWidth=0
|
||||
namespace behaviors {
|
||||
}
|
||||
@ -51,4 +56,9 @@ namespace loops {
|
||||
//% color="#1E5AA8"
|
||||
namespace light {
|
||||
|
||||
}
|
||||
|
||||
//% color="#b0b0b0" advanced=true weight=5
|
||||
namespace storage {
|
||||
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
{
|
||||
"sensors.GyroSensor.angle": "Get the current angle from the gyroscope.",
|
||||
"sensors.GyroSensor.rate": "Get the current rotation rate from the gyroscope."
|
||||
"sensors.GyroSensor.rate": "Get the current rotation rate from the gyroscope.",
|
||||
"sensors.GyroSensor.reset": "Forces a calibration of the gyro. Must be called when the sensor is completely still."
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"sensors.GyroSensor.angle|block": "%sensor|angle",
|
||||
"sensors.GyroSensor.rate|block": "%sensor|rotation rate",
|
||||
"sensors.GyroSensor.rate|block": "%sensor|rate",
|
||||
"sensors.GyroSensor.reset|block": "%sensor|reset",
|
||||
"sensors.gyro1|block": "gyro 1",
|
||||
"sensors.gyro2|block": "gyro 2",
|
||||
"sensors.gyro3|block": "gyro 3",
|
||||
|
@ -7,8 +7,10 @@ const enum GyroSensorMode {
|
||||
namespace sensors {
|
||||
//% fixedInstances
|
||||
export class GyroSensor extends internal.UartSensor {
|
||||
private calibrating: boolean;
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.calibrating = false;
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
@ -29,9 +31,12 @@ namespace sensors {
|
||||
//% parts="gyroscope"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=65 blockGap=8
|
||||
//% weight=64 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
angle(): number {
|
||||
if (this.calibrating)
|
||||
pauseUntil(() => !this.calibrating, 2000);
|
||||
|
||||
this.setMode(GyroSensorMode.Angle)
|
||||
return this.getNumber(NumberFormat.Int16LE, 0)
|
||||
}
|
||||
@ -41,7 +46,7 @@ namespace sensors {
|
||||
* @param sensor the gyroscope to query the request
|
||||
*/
|
||||
//% help=input/gyro/rate
|
||||
//% block="%sensor|rotation rate"
|
||||
//% block="%sensor|rate"
|
||||
//% blockId=gyroGetRate
|
||||
//% parts="gyroscope"
|
||||
//% blockNamespace=sensors
|
||||
@ -49,17 +54,54 @@ namespace sensors {
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
rate(): number {
|
||||
if (this.calibrating)
|
||||
pauseUntil(() => !this.calibrating, 2000);
|
||||
|
||||
this.setMode(GyroSensorMode.Rate)
|
||||
return this.getNumber(NumberFormat.Int16LE, 0)
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstance whenUsed block="gyro 1" jres=icons.port1
|
||||
export const gyro1: GyroSensor = new GyroSensor(1)
|
||||
/**
|
||||
* Forces a calibration of the gyro. Must be called when the sensor is completely still.
|
||||
*/
|
||||
//% help=input/gyro/calibrate
|
||||
//% block="%sensor|reset"
|
||||
//% blockId=gyroReset
|
||||
//% parts="gyroscope"
|
||||
//% blockNamespace=sensors
|
||||
//% sensor.fieldEditor="ports"
|
||||
//% weight=50 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
reset(): void {
|
||||
if (this.calibrating) return; // already in calibration mode
|
||||
|
||||
this.calibrating = true;
|
||||
// may be triggered by a button click, give time to settle
|
||||
loops.pause(500);
|
||||
// send a reset command
|
||||
super.reset();
|
||||
// we need to switch mode twice to perform a calibration
|
||||
if (this.mode == GyroSensorMode.Rate)
|
||||
this.setMode(GyroSensorMode.Angle);
|
||||
else
|
||||
this.setMode(GyroSensorMode.Rate);
|
||||
// switch back and wait
|
||||
if (this.mode == GyroSensorMode.Rate)
|
||||
this.setMode(GyroSensorMode.Angle);
|
||||
else
|
||||
this.setMode(GyroSensorMode.Rate);
|
||||
// give it more time to settle
|
||||
loops.pause(500);
|
||||
this.calibrating = false;
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstance whenUsed block="gyro 2" weight=95 jres=icons.port2
|
||||
export const gyro2: GyroSensor = new GyroSensor(2)
|
||||
|
||||
//% fixedInstance whenUsed block="gyro 1" jres=icons.port1
|
||||
export const gyro1: GyroSensor = new GyroSensor(1)
|
||||
|
||||
//% fixedInstance whenUsed block="gyro 3" jres=icons.port3
|
||||
export const gyro3: GyroSensor = new GyroSensor(3)
|
||||
|
||||
|
@ -4,6 +4,9 @@
|
||||
"sensors.InfraredSensor.pauseUntil": "Waits for the event to occur",
|
||||
"sensors.InfraredSensor.proximity": "Get the promixity measured by the infrared sensor, from ``0`` (close) to ``100`` (far)",
|
||||
"sensors.InfraredSensor.remoteCommand": "Get the remote commandreceived the infrared sensor.",
|
||||
"sensors.InfraredSensor.setThreshold": "Sets a threshold value",
|
||||
"sensors.InfraredSensor.setThreshold|param|condition": "the dark or bright light condition",
|
||||
"sensors.InfraredSensor.setThreshold|param|value": "the value threshold",
|
||||
"sensors.RemoteInfraredBeaconButton.isPressed": "Check if a remote button is currently pressed or not.",
|
||||
"sensors.RemoteInfraredBeaconButton.onEvent": "Do something when a button or sensor is clicked, up or down",
|
||||
"sensors.RemoteInfraredBeaconButton.onEvent|param|body": "code to run when the event is raised",
|
||||
|
@ -5,6 +5,7 @@
|
||||
"sensors.InfraredSensor.pauseUntil|block": "pause until %sensor| %event",
|
||||
"sensors.InfraredSensor.proximity|block": "%sensor|proximity",
|
||||
"sensors.InfraredSensor.remoteCommand|block": "%sensor|remote command",
|
||||
"sensors.InfraredSensor.setThreshold|block": "set %sensor|%condition|to %value",
|
||||
"sensors.RemoteInfraredBeaconButton.isPressed|block": "%button|is pressed",
|
||||
"sensors.RemoteInfraredBeaconButton.onEvent|block": "on %button|%event",
|
||||
"sensors.RemoteInfraredBeaconButton.wasPressed|block": "%button|was pressed",
|
||||
@ -20,5 +21,6 @@
|
||||
"sensors|block": "sensors",
|
||||
"{id:category}Sensors": "Sensors",
|
||||
"{id:group}Infrared Sensor": "Infrared Sensor",
|
||||
"{id:group}Remote Infrared Beacon": "Remote Infrared Beacon"
|
||||
"{id:group}Remote Infrared Beacon": "Remote Infrared Beacon",
|
||||
"{id:group}Threshold": "Threshold"
|
||||
}
|
@ -250,6 +250,22 @@ namespace sensors {
|
||||
this._setMode(IrSensorMode.Seek)
|
||||
return this.getNumber(NumberFormat.UInt16LE, this.channel * 2)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets a threshold value
|
||||
* @param condition the dark or bright light condition
|
||||
* @param value the value threshold
|
||||
*/
|
||||
//% blockId=irSetThreshold block="set %sensor|%condition|to %value"
|
||||
//% group="Threshold" blockGap=8
|
||||
//% value.min=0 value.max=100
|
||||
setThreshold(condition: InfraredSensorEvent, value: number) {
|
||||
if (condition == InfraredSensorEvent.ObjectNear)
|
||||
this.proximityThreshold.setLowThreshold(value)
|
||||
else
|
||||
this.proximityThreshold.setHighThreshold(value);
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstance whenUsed block="infrared 1" jres=icons.port1
|
||||
|
@ -33,34 +33,34 @@
|
||||
"music.stopAllSounds|block": "stop all sounds",
|
||||
"music.tempo|block": "tempo (bpm)",
|
||||
"music|block": "music",
|
||||
"sounds.animalsCatPurr|block": "Animals cat purr",
|
||||
"sounds.animalsDogBark1|block": "Animals dog bark 1",
|
||||
"sounds.animalsDogBark2|block": "Animals dog bark 2",
|
||||
"sounds.animalsDogGrowl|block": "Animals dog growl",
|
||||
"sounds.animalsDogSniff|block": "Animals dog sniff",
|
||||
"sounds.animalsDogWhine|block": "Animals dog whine",
|
||||
"sounds.animalsElephantCall|block": "Animals elephant call",
|
||||
"sounds.animalsInsectBuzz1|block": "Animals insect buzz1",
|
||||
"sounds.animalsInsectBuzz2|block": "Animals insect buzz2",
|
||||
"sounds.animalsInsectChirp|block": "Animals insect chirp",
|
||||
"sounds.animalsSnakeHiss|block": "Animals snake hiss",
|
||||
"sounds.animalsSnakeRattle|block": "Animals snake rattle",
|
||||
"sounds.animalsTRexRoar|block": "Animals trex roar",
|
||||
"sounds.colorsBlack|block": "Colors black",
|
||||
"sounds.colorsBlue|block": "Colors blue",
|
||||
"sounds.colorsBrown|block": "Colors brown",
|
||||
"sounds.colorsGreen|block": "Colors green",
|
||||
"sounds.colorsRed|block": "Colors red",
|
||||
"sounds.colorsWhite|block": "Colors white",
|
||||
"sounds.colorsYellow|block": "Colors yellow",
|
||||
"sounds.communicationBravo|block": "Communication bravo",
|
||||
"sounds.communicationEv3|block": "Communication ev3",
|
||||
"sounds.communicationFantastic|block": "Communication fantastic",
|
||||
"sounds.communicationGameOver|block": "Communication game over",
|
||||
"sounds.animalsCatPurr|block": "animals cat purr",
|
||||
"sounds.animalsDogBark1|block": "animals dog bark 1",
|
||||
"sounds.animalsDogBark2|block": "animals dog bark 2",
|
||||
"sounds.animalsDogGrowl|block": "animals dog growl",
|
||||
"sounds.animalsDogSniff|block": "animals dog sniff",
|
||||
"sounds.animalsDogWhine|block": "animals dog whine",
|
||||
"sounds.animalsElephantCall|block": "animals elephant call",
|
||||
"sounds.animalsInsectBuzz1|block": "animals insect buzz1",
|
||||
"sounds.animalsInsectBuzz2|block": "animals insect buzz2",
|
||||
"sounds.animalsInsectChirp|block": "animals insect chirp",
|
||||
"sounds.animalsSnakeHiss|block": "animals snake hiss",
|
||||
"sounds.animalsSnakeRattle|block": "animals snake rattle",
|
||||
"sounds.animalsTRexRoar|block": "animals trex roar",
|
||||
"sounds.colorsBlack|block": "colors black",
|
||||
"sounds.colorsBlue|block": "colors blue",
|
||||
"sounds.colorsBrown|block": "colors brown",
|
||||
"sounds.colorsGreen|block": "colors green",
|
||||
"sounds.colorsRed|block": "colors red",
|
||||
"sounds.colorsWhite|block": "colors white",
|
||||
"sounds.colorsYellow|block": "colors yellow",
|
||||
"sounds.communicationBravo|block": "communication bravo",
|
||||
"sounds.communicationEv3|block": "communication ev3",
|
||||
"sounds.communicationFantastic|block": "communication fantastic",
|
||||
"sounds.communicationGameOver|block": "communication game over",
|
||||
"sounds.communicationGoodJob|block": "communicationGoodJob",
|
||||
"sounds.communicationGoodbye|block": "communication goodbye",
|
||||
"sounds.communicationGood|block": "communication good",
|
||||
"sounds.communicationGo|block": "Communication go",
|
||||
"sounds.communicationGo|block": "communication go",
|
||||
"sounds.communicationHello|block": "communication hello",
|
||||
"sounds.communicationHi|block": "communication hi",
|
||||
"sounds.communicationLego|block": "communication lego",
|
||||
@ -159,7 +159,7 @@
|
||||
"sounds.systemOverpower|block": "system overpower",
|
||||
"sounds.systemPowerDown|block": "system power down",
|
||||
"sounds.systemReady|block": "system ready",
|
||||
"sounds.systemStartUp|block": "S",
|
||||
"sounds.systemStartUp|block": "system start up",
|
||||
"{id:category}Music": "Music",
|
||||
"{id:category}Sound": "Sound",
|
||||
"{id:category}Sounds": "Sounds"
|
||||
|
@ -1,53 +1,53 @@
|
||||
namespace sounds {
|
||||
//% fixedInstance jres block="Animals cat purr"
|
||||
//% fixedInstance jres block="animals cat purr"
|
||||
export const animalsCatPurr = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals dog bark 1"
|
||||
//% fixedInstance jres block="animals dog bark 1"
|
||||
export const animalsDogBark1 = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals dog bark 2"
|
||||
//% fixedInstance jres block="animals dog bark 2"
|
||||
export const animalsDogBark2 = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals dog growl"
|
||||
//% fixedInstance jres block="animals dog growl"
|
||||
export const animalsDogGrowl = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals dog sniff"
|
||||
//% fixedInstance jres block="animals dog sniff"
|
||||
export const animalsDogSniff = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals dog whine"
|
||||
//% fixedInstance jres block="animals dog whine"
|
||||
export const animalsDogWhine = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals elephant call"
|
||||
//% fixedInstance jres block="animals elephant call"
|
||||
export const animalsElephantCall = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals insect buzz1"
|
||||
//% fixedInstance jres block="animals insect buzz1"
|
||||
export const animalsInsectBuzz1 = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals insect buzz2"
|
||||
//% fixedInstance jres block="animals insect buzz2"
|
||||
export const animalsInsectBuzz2 = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals insect chirp"
|
||||
//% fixedInstance jres block="animals insect chirp"
|
||||
export const animalsInsectChirp = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals snake hiss"
|
||||
//% fixedInstance jres block="animals snake hiss"
|
||||
export const animalsSnakeHiss = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals snake rattle"
|
||||
//% fixedInstance jres block="animals snake rattle"
|
||||
export const animalsSnakeRattle = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Animals trex roar"
|
||||
//% fixedInstance jres block="animals trex roar"
|
||||
export const animalsTRexRoar = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Colors black"
|
||||
//% fixedInstance jres block="colors black"
|
||||
export const colorsBlack = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Colors blue"
|
||||
//% fixedInstance jres block="colors blue"
|
||||
export const colorsBlue = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Colors brown"
|
||||
//% fixedInstance jres block="colors brown"
|
||||
export const colorsBrown = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Colors green"
|
||||
//% fixedInstance jres block="colors green"
|
||||
export const colorsGreen = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Colors red"
|
||||
//% fixedInstance jres block="colors red"
|
||||
export const colorsRed = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Colors white"
|
||||
//% fixedInstance jres block="colors white"
|
||||
export const colorsWhite = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Colors yellow"
|
||||
//% fixedInstance jres block="colors yellow"
|
||||
export const colorsYellow = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Communication bravo"
|
||||
//% fixedInstance jres block="communication bravo"
|
||||
export const communicationBravo = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Communication ev3"
|
||||
//% fixedInstance jres block="communication ev3"
|
||||
export const communicationEv3 = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Communication fantastic"
|
||||
//% fixedInstance jres block="communication fantastic"
|
||||
export const communicationFantastic = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Communication game over"
|
||||
//% fixedInstance jres block="communication game over"
|
||||
export const communicationGameOver = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="Communication go"
|
||||
//% fixedInstance jres block="communication go"
|
||||
export const communicationGo = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="communicationGoodJob"
|
||||
export const communicationGoodJob = music.fromWAV(hex``);
|
||||
@ -251,7 +251,7 @@ namespace sounds {
|
||||
export const systemPowerDown = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="system ready"
|
||||
export const systemReady = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block=S
|
||||
//% fixedInstance jres block="system start up"
|
||||
export const systemStartUp = music.fromWAV(hex``);
|
||||
}
|
||||
|
||||
|
29
libs/storage/_locales/storage-jsdoc-strings.json
Normal file
29
libs/storage/_locales/storage-jsdoc-strings.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"storage.Storage.append": "Append string data to a new or existing file.",
|
||||
"storage.Storage.appendBuffer": "Append a buffer to a new or existing file.",
|
||||
"storage.Storage.appendCSV": "Append a row of CSV data",
|
||||
"storage.Storage.appendCSVHeaders": "Append a row of CSV headers",
|
||||
"storage.Storage.appendCSVHeaders|param|filename": "the file name to append data, eg: \"data.csv\"",
|
||||
"storage.Storage.appendCSVHeaders|param|headers": "the data to append",
|
||||
"storage.Storage.appendCSV|param|data": "the data to append",
|
||||
"storage.Storage.appendCSV|param|filename": "the file name to append data, eg: \"data.csv\"",
|
||||
"storage.Storage.appendLine": "Appends a new line of data in the file",
|
||||
"storage.Storage.appendLine|param|data": "the data to append",
|
||||
"storage.Storage.appendLine|param|filename": "the file name to append data, eg: \"data.txt\"",
|
||||
"storage.Storage.append|param|data": "the data to append",
|
||||
"storage.Storage.append|param|filename": "the file name to append data, eg: \"data.txt\"",
|
||||
"storage.Storage.exists": "Tests if a file exists",
|
||||
"storage.Storage.exists|param|filename": "the file name to append data, eg: \"data.txt\"",
|
||||
"storage.Storage.limit": "Resizing the size of a file to stay under the limit",
|
||||
"storage.Storage.limit|param|filename": "name of the file to drop",
|
||||
"storage.Storage.limit|param|size": "maximum length",
|
||||
"storage.Storage.overwrite": "Overwrite file with string data.",
|
||||
"storage.Storage.overwriteWithBuffer": "Overwrite file with a buffer.",
|
||||
"storage.Storage.overwrite|param|data": "the data to append",
|
||||
"storage.Storage.overwrite|param|filename": "the file name to append data, eg: \"data.txt\"",
|
||||
"storage.Storage.read": "Read contents of file as a string.",
|
||||
"storage.Storage.readAsBuffer": "Read contents of file as a buffer.",
|
||||
"storage.Storage.remove": "Delete a file, or do nothing if it doesn't exist.",
|
||||
"storage.Storage.size": "Return the size of the file, or -1 if it doesn't exists.",
|
||||
"storage.temporary": "Temporary storage in memory, deleted when the device restarts."
|
||||
}
|
15
libs/storage/_locales/storage-strings.json
Normal file
15
libs/storage/_locales/storage-strings.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"storage.Storage.appendCSVHeaders|block": "storage %source|%filename|append CSV headers %headers",
|
||||
"storage.Storage.appendCSV|block": "storage %source|%filename|append CSV %data",
|
||||
"storage.Storage.appendLine|block": "storage %source|%filename|append line %data",
|
||||
"storage.Storage.append|block": "storage %source|%filename|append %data",
|
||||
"storage.Storage.exists|block": "storage %source|%filename|exists",
|
||||
"storage.Storage.limit|block": "storage %source|limit %filename|to %size|bytes",
|
||||
"storage.Storage.overwrite|block": "storage %source|%filename|overwrite with|%data",
|
||||
"storage.Storage.read|block": "storage %source|read %filename|as string",
|
||||
"storage.Storage.remove|block": "storage %source|remove %filename",
|
||||
"storage.Storage.size|block": "storage %source|%filename|size",
|
||||
"storage.temporary|block": "temporary",
|
||||
"storage|block": "storage",
|
||||
"{id:category}Storage": "Storage"
|
||||
}
|
14
libs/storage/pxt.json
Normal file
14
libs/storage/pxt.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "storage",
|
||||
"description": "USB Pen-drive support and flash storage",
|
||||
"files": [
|
||||
"storage.cpp",
|
||||
"storage-core.ts",
|
||||
"storage.ts",
|
||||
"shims.d.ts"
|
||||
],
|
||||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core"
|
||||
}
|
||||
}
|
17
libs/storage/shims.d.ts
vendored
Normal file
17
libs/storage/shims.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// Auto-generated. Do not edit.
|
||||
declare namespace storage {
|
||||
|
||||
/** Will be moved. */
|
||||
//% shim=storage::__stringToBuffer
|
||||
function __stringToBuffer(s: string): Buffer;
|
||||
|
||||
/** Will be moved. */
|
||||
//% shim=storage::__bufferToString
|
||||
function __bufferToString(s: Buffer): string;
|
||||
|
||||
/** Create named directory. */
|
||||
//% shim=storage::__mkdir
|
||||
function __mkdir(filename: string): void;
|
||||
}
|
||||
|
||||
// Auto-generated. Do not edit. Really.
|
197
libs/storage/storage-core.ts
Normal file
197
libs/storage/storage-core.ts
Normal file
@ -0,0 +1,197 @@
|
||||
namespace storage {
|
||||
//% shim=storage::__unlink
|
||||
function __unlink(filename: string): void { }
|
||||
//% shim=storage::__truncate
|
||||
function __truncate(filename: string): void { }
|
||||
|
||||
//% fixedInstances
|
||||
export class Storage {
|
||||
csvSeparator: string;
|
||||
constructor() {
|
||||
this.csvSeparator = ",";
|
||||
}
|
||||
|
||||
protected mapFilename(filename: string) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
private getFile(filename: string): MMap {
|
||||
filename = this.mapFilename(filename)
|
||||
let r = control.mmap(filename, 0, 0)
|
||||
if (!r) {
|
||||
__mkdir(this.dirname(filename))
|
||||
__truncate(filename)
|
||||
r = control.mmap(filename, 0, 0)
|
||||
}
|
||||
if (!r)
|
||||
control.panic(906)
|
||||
return r
|
||||
}
|
||||
|
||||
dirname(filename: string) {
|
||||
let last = 0
|
||||
for (let i = 0; i < filename.length; ++i)
|
||||
if (filename[i] == "/")
|
||||
last = i
|
||||
return filename.substr(0, last)
|
||||
}
|
||||
|
||||
/**
|
||||
* Append string data to a new or existing file.
|
||||
* @param filename the file name to append data, eg: "data.txt"
|
||||
* @param data the data to append
|
||||
*/
|
||||
//% blockId=storageAppend block="storage %source|%filename|append %data"
|
||||
append(filename: string, data: string): void {
|
||||
this.appendBuffer(filename, __stringToBuffer(data))
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a new line of data in the file
|
||||
* @param filename the file name to append data, eg: "data.txt"
|
||||
* @param data the data to append
|
||||
*/
|
||||
//% blockId=storageAppendLine block="storage %source|%filename|append line %data"
|
||||
appendLine(filename: string, data: string): void {
|
||||
this.append(filename, data + "\r\n");
|
||||
}
|
||||
|
||||
/** Append a buffer to a new or existing file. */
|
||||
appendBuffer(filename: string, data: Buffer): void {
|
||||
let f = this.getFile(filename);
|
||||
f.lseek(0, SeekWhence.End)
|
||||
f.write(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a row of CSV headers
|
||||
* @param filename the file name to append data, eg: "data.csv"
|
||||
* @param headers the data to append
|
||||
*/
|
||||
//% blockId=storageAppendCSVHeaders block="storage %source|%filename|append CSV headers %headers"
|
||||
appendCSVHeaders(filename: string, headers: string[]) {
|
||||
let s = ""
|
||||
for (const d of headers) {
|
||||
if (s) s += this.csvSeparator;
|
||||
s = s + d;
|
||||
}
|
||||
s += "\r\n"
|
||||
this.append(filename, s)
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a row of CSV data
|
||||
* @param filename the file name to append data, eg: "data.csv"
|
||||
* @param data the data to append
|
||||
*/
|
||||
//% blockId=storageAppendCSV block="storage %source|%filename|append CSV %data"
|
||||
appendCSV(filename: string, data: number[]) {
|
||||
let s = ""
|
||||
for (const d of data) {
|
||||
if (s) s += this.csvSeparator;
|
||||
s = s + d;
|
||||
}
|
||||
s += "\r\n"
|
||||
this.append(filename, s)
|
||||
}
|
||||
|
||||
/** Overwrite file with string data.
|
||||
* @param filename the file name to append data, eg: "data.txt"
|
||||
* @param data the data to append
|
||||
*/
|
||||
//% blockId=storageOverwrite block="storage %source|%filename|overwrite with|%data"
|
||||
overwrite(filename: string, data: string): void {
|
||||
this.overwriteWithBuffer(filename, __stringToBuffer(data))
|
||||
}
|
||||
|
||||
/** Overwrite file with a buffer. */
|
||||
overwriteWithBuffer(filename: string, data: Buffer): void {
|
||||
__truncate(this.mapFilename(filename))
|
||||
this.appendBuffer(filename, data)
|
||||
}
|
||||
|
||||
/** Tests if a file exists
|
||||
* @param filename the file name to append data, eg: "data.txt"
|
||||
*/
|
||||
//% blockId=storageExists block="storage %source|%filename|exists"
|
||||
exists(filename: string): boolean {
|
||||
return !!control.mmap(this.mapFilename(filename), 0, 0);
|
||||
}
|
||||
|
||||
/** Delete a file, or do nothing if it doesn't exist. */
|
||||
//% blockId=storageRemove block="storage %source|remove %filename"
|
||||
remove(filename: string): void {
|
||||
__unlink(this.mapFilename(filename))
|
||||
}
|
||||
|
||||
/** Return the size of the file, or -1 if it doesn't exists. */
|
||||
//% blockId=storageSize block="storage %source|%filename|size"
|
||||
size(filename: string): int32 {
|
||||
let f = control.mmap(this.mapFilename(filename), 0, 0)
|
||||
if (!f) return -1;
|
||||
return f.lseek(0, SeekWhence.End)
|
||||
}
|
||||
|
||||
/** Read contents of file as a string. */
|
||||
//% blockId=storageRead block="storage %source|read %filename|as string"
|
||||
read(filename: string): string {
|
||||
return __bufferToString(this.readAsBuffer(filename))
|
||||
}
|
||||
|
||||
/** Read contents of file as a buffer. */
|
||||
//%
|
||||
readAsBuffer(filename: string): Buffer {
|
||||
let f = this.getFile(filename)
|
||||
let sz = f.lseek(0, SeekWhence.End)
|
||||
let b = output.createBuffer(sz)
|
||||
f.lseek(0, SeekWhence.Set);
|
||||
f.read(b)
|
||||
return b
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizing the size of a file to stay under the limit
|
||||
* @param filename name of the file to drop
|
||||
* @param size maximum length
|
||||
*/
|
||||
//% blockId=storageLimit block="storage %source|limit %filename|to %size|bytes"
|
||||
limit(filename: string, size: number) {
|
||||
if (!this.exists(filename) || size < 0) return;
|
||||
|
||||
const sz = storage.temporary.size(filename);
|
||||
if (sz > size) {
|
||||
let buf = storage.temporary.readAsBuffer(filename)
|
||||
buf = buf.slice(buf.length / 2);
|
||||
storage.temporary.overwriteWithBuffer(filename, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TemporaryStorage extends Storage {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected mapFilename(filename: string) {
|
||||
if (filename[0] == '/') filename = filename.substr(1);
|
||||
return '/tmp/logs/' + filename;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary storage in memory, deleted when the device restarts.
|
||||
*/
|
||||
//% whenUsed fixedInstance block="temporary"
|
||||
export const temporary: Storage = new TemporaryStorage();
|
||||
|
||||
class PermanentStorage extends Storage {
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
protected mapFilename(filename: string) {
|
||||
if (filename[0] == '/') return filename;
|
||||
return '/' + filename;
|
||||
}
|
||||
}
|
||||
}
|
44
libs/storage/storage.cpp
Normal file
44
libs/storage/storage.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "pxt.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace storage {
|
||||
|
||||
/** Will be moved. */
|
||||
//%
|
||||
Buffer __stringToBuffer(String s) {
|
||||
return mkBuffer((uint8_t *)s->data, s->length);
|
||||
}
|
||||
|
||||
/** Will be moved. */
|
||||
//%
|
||||
String __bufferToString(Buffer s) {
|
||||
return mkString((char*)s->data, s->length);
|
||||
}
|
||||
|
||||
//%
|
||||
void __init() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
//%
|
||||
void __unlink(String filename) {
|
||||
::unlink(filename->data);
|
||||
}
|
||||
|
||||
//%
|
||||
void __truncate(String filename) {
|
||||
int fd = open(filename->data, O_CREAT | O_TRUNC | O_WRONLY, 0777);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/** Create named directory. */
|
||||
//%
|
||||
void __mkdir(String filename) {
|
||||
::mkdir(filename->data, 0777);
|
||||
}
|
||||
|
||||
} // namespace storage
|
11
libs/storage/storage.ts
Normal file
11
libs/storage/storage.ts
Normal file
@ -0,0 +1,11 @@
|
||||
namespace storage {
|
||||
// automatically send console output to temp storage
|
||||
storage.temporary.remove("console.txt");
|
||||
console.addListener(function(line) {
|
||||
const fn = "console.txt";
|
||||
const mxs = 65536;
|
||||
const t = control.millis();
|
||||
storage.temporary.appendLine(fn, `${t}> ${line}`);
|
||||
storage.temporary.limit(fn, 65536);
|
||||
})
|
||||
}
|
@ -6,10 +6,10 @@
|
||||
"sensors.TouchSensor.onEvent|block": "on %sensor|%event",
|
||||
"sensors.TouchSensor.pauseUntil|block": "pause until %sensor|%event",
|
||||
"sensors.TouchSensor.wasPressed|block": "%sensor|was pressed",
|
||||
"sensors.touchSensor1|block": "touch 1",
|
||||
"sensors.touchSensor2|block": "touch 2",
|
||||
"sensors.touchSensor3|block": "touch 3",
|
||||
"sensors.touchSensor4|block": "touch 4",
|
||||
"sensors.touch1|block": "touch 1",
|
||||
"sensors.touch2|block": "touch 2",
|
||||
"sensors.touch3|block": "touch 3",
|
||||
"sensors.touch4|block": "touch 4",
|
||||
"{id:category}Sensors": "Sensors",
|
||||
"{id:group}Touch Sensor": "Touch Sensor"
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
sensors.touchSensor1.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
sensors.touch1.onEvent(TouchSensorEvent.Pressed, function () {
|
||||
})
|
||||
sensors.touchSensor2.onEvent(TouchSensorEvent.Bumped, function () {
|
||||
sensors.touch2.onEvent(TouchSensorEvent.Bumped, function () {
|
||||
})
|
||||
sensors.touchSensor3.onEvent(TouchSensorEvent.Released, function () {
|
||||
sensors.touch3.onEvent(TouchSensorEvent.Released, function () {
|
||||
})
|
||||
sensors.touchSensor4.isPressed();
|
||||
sensors.touchSensor4.wasPressed();
|
||||
sensors.touch4.isPressed();
|
||||
sensors.touch4.wasPressed();
|
||||
|
@ -102,11 +102,11 @@ namespace sensors {
|
||||
}
|
||||
|
||||
//% whenUsed block="touch 1" weight=95 fixedInstance jres=icons.port1
|
||||
export const touchSensor1: TouchSensor = new TouchSensor(1)
|
||||
export const touch1: TouchSensor = new TouchSensor(1)
|
||||
//% whenUsed block="touch 2" weight=95 fixedInstance jres=icons.port2
|
||||
export const touchSensor2: TouchSensor = new TouchSensor(2)
|
||||
export const touch2: TouchSensor = new TouchSensor(2)
|
||||
//% whenUsed block="touch 3" weight=95 fixedInstance jres=icons.port3
|
||||
export const touchSensor3: TouchSensor = new TouchSensor(3)
|
||||
export const touch3: TouchSensor = new TouchSensor(3)
|
||||
//% whenUsed block="touch 4" weight=95 fixedInstance jres=icons.port4
|
||||
export const touchSensor4: TouchSensor = new TouchSensor(4)
|
||||
export const touch4: TouchSensor = new TouchSensor(4)
|
||||
}
|
||||
|
@ -2,5 +2,8 @@
|
||||
"sensors.UltraSonicSensor.distance": "Gets the distance from the sonar in centimeters",
|
||||
"sensors.UltraSonicSensor.onEvent": "Registers code to run when the given color is close",
|
||||
"sensors.UltraSonicSensor.onEvent|param|handler": "the code to run when detected",
|
||||
"sensors.UltraSonicSensor.pauseUntil": "Waits for the event to occur"
|
||||
"sensors.UltraSonicSensor.pauseUntil": "Waits for the event to occur",
|
||||
"sensors.UltraSonicSensor.setThreshold": "Sets a threshold value",
|
||||
"sensors.UltraSonicSensor.setThreshold|param|condition": "the dark or bright light condition",
|
||||
"sensors.UltraSonicSensor.setThreshold|param|value": "the value threshold"
|
||||
}
|
@ -5,10 +5,12 @@
|
||||
"sensors.UltraSonicSensor.distance|block": "%sensor|distance",
|
||||
"sensors.UltraSonicSensor.onEvent|block": "on %sensor|%event",
|
||||
"sensors.UltraSonicSensor.pauseUntil|block": "pause until %sensor| %event",
|
||||
"sensors.UltraSonicSensor.setThreshold|block": "set %sensor|%condition|to %value",
|
||||
"sensors.ultrasonic1|block": "ultrasonic 1",
|
||||
"sensors.ultrasonic2|block": "ultrasonic 2",
|
||||
"sensors.ultrasonic3|block": "ultrasonic 3",
|
||||
"sensors.ultrasonic4|block": "ultrasonic 4",
|
||||
"{id:category}Sensors": "Sensors",
|
||||
"{id:group}Threshold": "Threshold",
|
||||
"{id:group}Ultrasonic Sensor": "Ultrasonic Sensor"
|
||||
}
|
@ -85,7 +85,27 @@ namespace sensors {
|
||||
this._setMode(0)
|
||||
return this._query();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets a threshold value
|
||||
* @param condition the dark or bright light condition
|
||||
* @param value the value threshold
|
||||
*/
|
||||
//% blockId=ultrasonicSetThreshold block="set %sensor|%condition|to %value"
|
||||
//% group="Threshold" blockGap=8
|
||||
//% value.min=0 value.max=255
|
||||
setThreshold(condition: UltrasonicSensorEvent, value: number) {
|
||||
switch(condition) {
|
||||
case UltrasonicSensorEvent.ObjectNear: this.promixityThreshold.setLowThreshold(value); break;
|
||||
case UltrasonicSensorEvent.ObjectFar: this.promixityThreshold.setHighThreshold(value); break;
|
||||
case UltrasonicSensorEvent.ObjectDetected: this.movementThreshold = value; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic 4" jres=icons.port4
|
||||
export const ultrasonic4: UltraSonicSensor = new UltraSonicSensor(4)
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic 1" jres=icons.port1
|
||||
export const ultrasonic1: UltraSonicSensor = new UltraSonicSensor(1)
|
||||
@ -95,7 +115,4 @@ namespace sensors {
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic 3" jres=icons.port3
|
||||
export const ultrasonic3: UltraSonicSensor = new UltraSonicSensor(3)
|
||||
|
||||
//% fixedInstance whenUsed block="ultrasonic 4" jres=icons.port4
|
||||
export const ultrasonic4: UltraSonicSensor = new UltraSonicSensor(4)
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user