Compare commits

..

84 Commits

Author SHA1 Message Date
02b0716043 0.0.75 2018-01-30 08:28:12 -08:00
188d5b3aa7 threshold query api 2018-01-30 08:27:23 -08:00
16c67f0e30 Refactoring datalog in common packages (#249)
* using datalog from common packages

* upgrading common package link

* updated block signatures

* more docs
2018-01-29 19:46:54 -08:00
104185a41e 0.0.74 2018-01-29 15:21:37 -08:00
73363d11b2 Download dialog (#248)
* download dialog

* updated pxt reference

* typo
2018-01-29 15:21:15 -08:00
61996acdd9 0.0.73 2018-01-29 13:26:46 -08:00
21deb45728 fixing release fiber 2018-01-29 13:26:31 -08:00
34578d2370 0.0.72 2018-01-29 11:20:46 -08:00
3f50b5c39a updated pxt references + hero banner 2018-01-29 11:20:34 -08:00
d371225066 0.0.71 2018-01-23 14:53:09 -08:00
387effbdd0 upgraded to run in parallel 2018-01-23 14:52:41 -08:00
18480080e7 updated tutorial format 2018-01-19 15:42:23 -08:00
bf6a932e5f Color calibration (#245)
* better handling of thresholds, color calibration strategy

* updating calibration parameters
2018-01-19 13:11:11 -08:00
23bb316403 settle robot once brake is applied 2018-01-18 21:28:00 -08:00
138de504e5 minor high contrast fixes 2018-01-18 21:03:57 -08:00
df13e40a45 fixing make it move 2018-01-18 16:47:00 -08:00
511ea2374b fixing summary 2018-01-18 16:44:57 -08:00
db4ed6daf3 fixing a bunch of snippets 2018-01-18 16:43:16 -08:00
a60427e2cf using audio context manager function (#243)
* using audio context manager function

* updated pxt reference

* trigger build
2018-01-18 13:53:33 -08:00
ef5b4172e8 missing file logo 2018-01-18 12:42:11 -08:00
7baf7cfede 0.0.70 2018-01-18 12:13:17 -08:00
efd6718ea3 converted lesson to tutorial 2018-01-18 12:09:43 -08:00
057a1d66dc PID support (#242)
* updated block definitions

* updated dependency on common packages
2018-01-18 10:34:06 -08:00
5ddfcd5508 Prototype lesson 'Make it Move" (#241)
* Prototype lesson 'Make it Move"

* Wrong blockq type
2018-01-17 19:45:07 -08:00
00f0922189 Merge pull request #240 from Microsoft/line-detect-lesson
Prototype lesson for 'Line Detection'
2018-01-17 19:07:29 -08:00
41f4b64087 Add to gallerys 2018-01-17 18:52:49 -08:00
ea5ee1c007 Prototype lesson for 'Line Detection' 2018-01-17 17:02:11 -08:00
603e4c0fc1 0.0.69 2018-01-16 17:06:52 -08:00
e50c88008a updated gyrobox 2018-01-16 17:05:57 -08:00
f057964a50 pausing until sound is done in mood 2018-01-16 16:44:32 -08:00
2eda2061cf updated modified gyro boy 2018-01-16 16:26:49 -08:00
a4ebf4c746 moving moods in separate namespace 2018-01-16 16:21:02 -08:00
f1880897d4 0.0.68 2018-01-16 16:08:53 -08:00
ad2e82060d removing BrickLight blockIdenity notations 2018-01-16 15:59:40 -08:00
d1bb19e30e adding a mood block (image+sound+light) 2018-01-16 14:52:49 -08:00
280963d1eb 0.0.67 2018-01-15 23:58:31 -08:00
9fadf49b0e Support for multiple motors in "used" logic. (#238)
* handle registerion of dual / single motors

* updated puppy
2018-01-15 23:57:21 -08:00
3c2be25384 some core set adapted codes 2018-01-15 21:27:19 -08:00
e1f623a94d Added description to timers 2018-01-15 03:41:14 -08:00
cb5f9648f5 fixed sound name 2018-01-14 19:49:40 -08:00
9158cfe4f6 0.0.66 2018-01-13 08:31:38 -08:00
0b763978f2 gyro boy improvements (#236)
gyro boy improvements
2018-01-13 08:31:10 -08:00
25fded6afb 0.0.65 2018-01-13 00:02:01 -08:00
fc6fb0811f Timers (#235)
* adding timer support

* updates strings
2018-01-13 00:00:55 -08:00
49bedcbcc5 0.0.64 2018-01-12 16:12:02 -08:00
32876f4584 Merge pull request #234 from Microsoft/largemotorview
Fix large motor SVG hole
2018-01-12 13:51:00 -08:00
da9bea30b5 Update large motor view SVG so that the drop shadow is outside the hole SVG 2018-01-12 13:50:09 -08:00
d0aa68aeee 0.0.63 2018-01-12 13:33:45 -08:00
51731fbbc9 bump pxt-common-packages to 0.15.5, 2018-01-12 13:33:40 -08:00
751ea1494b motor slider fixes and fix motor output in vm 2018-01-12 13:33:25 -08:00
dfe84471e8 Merge pull request #144 from Microsoft/motorslider
Add motor slider control
2018-01-12 13:04:45 -08:00
0f3de6cf07 0.0.62 2018-01-11 22:56:34 -08:00
21195e4abf Datalog (#233)
* support for custom csv separator

* simple datalog frameowrk

* api strings

* hide setfile

* storage fixes

* log seconds, not milliseconds
2018-01-11 22:53:28 -08:00
c992100a38 added option to append CSV headers 2018-01-11 21:36:43 -08:00
20a4673f98 First draft of storage APIs (#122)
* First draft of storage APIs

* bumped pxt-core

* using fixed instances to seprate temp from permanent

* send console to storage

* sim support

* missing sim stubs

* adding storage blocks

* more sim support

* remove storage from default package

* fix rendering of ms

* render raw ms

* slize at better place

* duplicate bundled dir

* refactor limit

* simplify limit logic
2018-01-11 20:05:45 -08:00
966fd81870 0.0.61 2018-01-11 14:08:14 -08:00
cb9d2aeb39 bumping pxt dependency 2018-01-11 14:08:01 -08:00
3cee55f4c2 0.0.60 2018-01-11 13:43:41 -08:00
3815d2fd3b simplifiying brick light api (#231) 2018-01-11 13:43:11 -08:00
1453b7e0a3 gyro reset fix 2018-01-11 11:17:23 -08:00
6fb5c54280 fix build break 2018-01-11 08:55:31 -08:00
9d5ca35e83 fix battery encoding 2018-01-11 08:47:09 -08:00
893dd0f9c4 rename "enter..." to "button enter" 2018-01-11 08:28:25 -08:00
c3419c0b74 support for unregulated motors (#227) 2018-01-10 23:34:27 -08:00
a4164470d8 updated api to align with labview 2018-01-10 22:29:35 -08:00
0dd5ab9bde appliying manual speed 2018-01-10 14:08:50 -08:00
e93e659e8a nit: remove unnecessary comment 2018-01-10 13:51:35 -08:00
8357372fb5 Update to make it more like a crank 2018-01-10 13:47:39 -08:00
54cb076002 Merge pull request #226 from Microsoft/legoavatar
Add lego avatar
2018-01-10 13:03:15 -08:00
dbd3eb464b Add lego avatar 2018-01-10 12:59:53 -08:00
10cd39a4ec Merge branch 'master' into motorslider 2018-01-10 12:52:51 -08:00
fddc4e647a 0.0.59 2018-01-10 12:52:48 -08:00
798a351f15 updated package lock 2018-01-10 12:52:36 -08:00
e61dffff03 fixing threshold 2018-01-10 11:45:08 -08:00
b9f5096480 pause until motor measured move is done 2018-01-10 11:29:27 -08:00
9912d68c8b fixing chassis 2018-01-10 11:14:25 -08:00
951b9be6e4 fixing motors 2018-01-10 11:14:18 -08:00
aa8635c4e7 Always use the motor slider control 2018-01-10 10:00:48 -08:00
4e4f5495da Merge branch 'master' into motorslider 2018-01-10 09:56:59 -08:00
f64bf57000 Merge master 2018-01-10 09:56:32 -08:00
f1242724b5 Fix legofont icons 2018-01-10 09:55:58 -08:00
cd0c9df86e bump to 3.0.8 2018-01-10 08:58:54 -08:00
16b9a5027d Add rotate icons 2017-12-29 11:39:06 -08:00
cbe68b3199 Add motor slider control 2017-12-28 13:23:30 -08:00
126 changed files with 4468 additions and 752 deletions

View File

@ -5,7 +5,7 @@
This repo contains the editor target hosted at https://d541eec2-1e96-4b7b-a223-da9d01d0337a.pxt.io/
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
LEGO Chat: https://chat.internal.education.lego.com/make-code/channels/town-square
## Local Dev setup

View File

@ -1,5 +1,43 @@
# @extends
## Projects #projects
* [Maker](/maker)
* [Sound Machine](/maker/sound-machine)
* [Sound of Color](/maker/sound-of-color)
* [Security Gadget](/maker/security-gadget)
* [Intruder detector](/maker/intruder-detector)
* [Puppet](/maker/puppet)
* [Coding](/coding)
* [Three Point Turn 1](/coding/three-point-turn-1)
* [Three Point Turn 2](/coding/three-point-turn-2)
* [Three Point Turn 3](/coding/three-point-turn-3)
* [Reversing the robot 1](/coding/reversing-the-robot-1)
* [Reversing the robot 2](/coding/reversing-the-robot-2)
* [Reversing the robot 3](/coding/reversing-the-robot-3)
* [Light the way 1](/coding/light-the-way-1)
* [Light the way 2](/coding/light-the-way-2)
* [Light the way 3](/coding/light-the-way-3)
* [Traffic Lights 1](/coding/traffic-lights-1)
* [Traffic Lights 2](/coding/traffic-lights-2)
* [Traffic Lights 3](/coding/traffic-lights-3)
* [Reverse Beeper 1](/coding/reverse-beeper-1)
* [Reverse Beeper 2](/coding/reverse-beeper-2)
* [Reverse Beeper 3](/coding/reverse-beeper-3)
* [Ignition 1](/coding/ignition-1)
* [Ignition 2](/coding/ignition-2)
* [Ignition 3](/coding/ignition-3)
* [Cruise Control 1](/coding/cruise-control-1)
* [Cruise Control 2](/coding/cruise-control-2)
* [Cruise Control 3](/coding/cruise-control-3)
* [Roaming 1](/coding/roaming-1)
* [Roaming 2](/coding/roaming-2)
* [Lessons](/lessons)
* [Make it move](/lessons/make-it-move)
* [Line detection](/lessons/line-detection)
## Reference #reference
* [Reference](/reference)

View File

@ -6,14 +6,14 @@ Welcome to the **Microsoft MakeCode** editor for the **@boardname@**!
You can program the @boardname@ using [Blocks](/blocks) or [JavaScript](/javascript) in your web browser:
```block
input.buttonA.onEvent(ButtonEvent.Click, () => {
light.showRing(`blue blue blue blue blue blue blue blue blue blue`)
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Click, () => {
motors.largeA.setSpeed(50)
})
```
```typescript
input.buttonA.onEvent(ButtonEvent.Click, () => {
light.showRing(`blue blue blue blue blue blue blue blue blue blue`)
brick.buttonEnter.onEvent(ButtonEvent.Click, () => {
motors.largeA.setSpeed(50)
})
```
@ -22,10 +22,10 @@ The editor work in [most modern browsers](/browsers), work [offline](/offline) o
## [Compile and Flash: Your Program!](/device/usb)
When you have your code ready, you connect your @boardname@ to a computer via a USB cable
**then press the reset button** so it appears as a mounted drive (named **CPLAYBOOT**).
so it appears as a mounted drive (named **EV3**).
Compilation to machine code from [Blocks](/blocks) or [JavaScript](/javascript) happens in the browser. You save the binary
program to a **.uf2** file, which you then copy to the **CPLAYBOOT** drive, which flashes the device with the new program.
program to a **.uf2** file, which you then copy to the **EV3** drive, which flashes the device with the new program.
## Simulator: Test Your Code
@ -33,11 +33,7 @@ You can run your code using the micro:bit simulator, all within the confines of
The simulator has support for the LED screen, buttons, as well as compass, accelerometer, and digital I/O pins.
```sim
loops.forever(() => {
light.pixels.showAnimation(light.animation(LightAnimation.Rainbow), 1000)
brick.buttonEnter.onEvent(ButtonEvent.Click, () => {
motors.largeA.setSpeed(50)
})
```
```package
light
```

View File

@ -3,13 +3,13 @@
```blocks
let beep = false
beep = true
control.runInBackground(function () {
control.runInParallel(function () {
motors.largeBC.setSpeed(-20)
sensors.ultrasonic4.pauseUntil(UltrasonicSensorEvent.ObjectNear)
motors.largeBC.stop()
beep = false
})
control.runInBackground(function () {
control.runInParallel(function () {
while (beep) {
if (sensors.ultrasonic4.distance() < 20) {
music.playTone(440, sensors.ultrasonic4.distance())

View File

@ -3,10 +3,10 @@
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
motors.largeBC.setSpeed(50)
sensors.touchSensor1.pauseUntil(TouchSensorEvent.Pressed)
sensors.touch1.pauseUntil(TouchSensorEvent.Pressed)
motors.largeBC.setSpeed(0)
loops.pause(1000)
brick.setLight(LightsPattern.OrangeFlash)
brick.setLight(BrickLight.OrangeFlash)
motors.largeBC.setSpeed(-50)
loops.pause(2000)
motors.largeBC.setSpeed(0)

View File

@ -2,12 +2,12 @@
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
sensors.touchSensor1.pauseUntil(TouchSensorEvent.Pressed)
sensors.touch1.pauseUntil(TouchSensorEvent.Pressed)
motors.largeBC.setSpeed(50)
sensors.touchSensor2.pauseUntil(TouchSensorEvent.Pressed)
sensors.touch2.pauseUntil(TouchSensorEvent.Pressed)
motors.largeBC.setSpeed(0)
loops.pause(1000)
brick.setLight(LightsPattern.OrangeFlash)
brick.setLight(BrickLight.OrangeFlash)
motors.largeBC.setSpeed(-50)
loops.pause(2000)
motors.largeBC.setSpeed(0)

View File

@ -3,14 +3,14 @@
```blocks
brick.buttonEnter.onEvent(ButtonEvent.Click, function () {
brick.showImage(images.eyesSleeping)
sensors.touchSensor1.pauseUntil(TouchSensorEvent.Pressed)
sensors.touch1.pauseUntil(TouchSensorEvent.Pressed)
brick.showImage(images.eyesNeutral)
motors.largeBC.setSpeed(50)
sensors.touchSensor2.pauseUntil(TouchSensorEvent.Pressed)
sensors.touch2.pauseUntil(TouchSensorEvent.Pressed)
brick.showImage(images.eyesTiredMiddle)
motors.largeBC.setSpeed(0)
loops.pause(1000)
brick.setLight(LightsPattern.OrangeFlash)
brick.setLight(BrickLight.OrangeFlash)
brick.showImage(images.eyesDizzy)
motors.largeBC.setSpeed(-50)
loops.pause(2000)

View File

@ -19,17 +19,13 @@ 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()
motors.largeC.setSpeed(50, 360, MoveUnit.Degrees)
} else if (d == 3) {
motors.largeB.setSpeedFor(50, 360, MoveUnit.Degrees)
motors.largeB.pauseUntilReady()
motors.largeB.setSpeed(50, 360, MoveUnit.Degrees)
} else if (d == 4) {
motors.largeBC.setSpeedFor(50, 360, MoveUnit.Degrees)
motors.largeBC.pauseUntilReady()
motors.largeBC.setSpeed(50, 360, MoveUnit.Degrees)
} else {
motors.largeBC.setSpeedFor(-50, 360, MoveUnit.Degrees)
motors.largeBC.pauseUntilReady()
motors.largeBC.setSpeed(-50, 360, MoveUnit.Degrees)
}
}
music.playSoundEffectUntilDone(sounds.communicationGameOver)

View File

@ -23,17 +23,13 @@ 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()
motors.largeC.setSpeed(50, 360, MoveUnit.Degrees)
} else if (d == 3) {
motors.largeB.setSpeedFor(50, 360, MoveUnit.Degrees)
motors.largeB.pauseUntilReady()
motors.largeB.setSpeed(50, 360, MoveUnit.Degrees)
} else if (d == 4) {
motors.largeBC.setSpeedFor(50, 360, MoveUnit.Degrees)
motors.largeBC.pauseUntilReady()
motors.largeBC.setSpeed(50, 360, MoveUnit.Degrees)
} else {
motors.largeBC.setSpeedFor(-50, 360, MoveUnit.Degrees)
motors.largeBC.pauseUntilReady()
motors.largeBC.setSpeed(-50, 360, MoveUnit.Degrees)
}
}
music.playSoundEffectUntilDone(sounds.communicationGameOver)

View File

@ -0,0 +1,178 @@
# Gyroboy
Work in progress
```blocks
let motorSpeed1 = 0
let motorSpeed2 = 0
let motorSpeed3 = 0
let motorSpeed = 0
let fallen = false
let motorSpeed0 = 0
let oldControlDrive = 0
let controlDrive = 0
let power = 0
let motorAngle = 0
let gyroAngle = 0
let controlSteering = 0
let state = 0
let motorPosition = 0
let temp = 0
let gyroRate = 0
let timestep = 0
sensors.color1.onColorDetected(ColorSensorColor.Red, function () {
music.playTone(2000, 100)
controlDrive = 0
controlSteering = 0
})
// reads the motor angle and computes the motor speed,
// position
function computeMotors() {
temp = motorAngle
// read angle on both motors
motorAngle = motors.largeD.angle() + motors.largeA.angle()
// and estimate speed as angle difference
motorSpeed0 = motorAngle - temp
// average last 4 speed readings
motorSpeed = (motorSpeed0 + motorSpeed1 + motorSpeed2 + motorSpeed3) / 4 / timestep
// shift all previous recorded speeds by one
motorSpeed3 = motorSpeed2
motorSpeed2 = motorSpeed1
motorSpeed1 = motorSpeed0
// compute position from speed
motorPosition = motorPosition + timestep * motorSpeed
}
// read the gyro rate and computes the angle
function computeGyro() {
gyroRate = sensors.gyro2.rate()
gyroAngle = gyroAngle + timestep * gyroRate
}
function reset() {
state = 0
// sleeping
moods.sleeping.show();
// reset counters
motors.largeA.reset()
motors.largeD.reset()
// motors are unregulated
motors.largeA.setRegulated(false)
motors.largeD.setRegulated(false)
// clear the gyro sensor to remove drift
sensors.gyro2.reset()
// fall detection timer
control.timer2.reset()
// timestep computation timer
control.timer3.reset()
motorAngle = 0
motorPosition = 0
motorSpeed = 0
motorSpeed0 = 0
motorSpeed1 = 0
motorSpeed2 = 0
motorSpeed3 = 0
gyroRate = 0
gyroAngle = 0
fallen = false
power = 0
controlSteering = 0
controlDrive = 0
// awake
moods.awake.show();
gyroAngle = -0.25
state = 1;
}
// compute set point for motor position and required
// motor power
function computePower() {
// apply control and compute desired motor position
motorPosition -= timestep * controlDrive;
// estimate power based on sensor readings and control
// values
power = 0.8 * gyroRate + 15 * gyroAngle + (0.08 * motorSpeed + 0.12 * motorPosition) - 0.01 * controlDrive
// ensure that power stays within -100, 100
if (power > 100) {
power = 100
} else if (power < -100) {
power = -100
}
}
// test if the robot has fallen off
function checkFallen() {
if (Math.abs(power) < 100) {
control.timer2.reset()
}
if (control.timer2.seconds() > 2) {
fallen = true
}
}
// stop all motors and wait for touch button to be
// pressed
function stop() {
motors.stopAllMotors()
state = 0
moods.knockedOut.show();
sensors.touch3.pauseUntil(TouchSensorEvent.Pressed)
moods.neutral.show();
}
sensors.ultrasonic4.onEvent(UltrasonicSensorEvent.ObjectNear, function () {
moods.dizzy.show()
controlSteering = 0
oldControlDrive = controlDrive
controlDrive = -10
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
motors.mediumC.setSpeed(-30, 60, MoveUnit.Degrees);
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
if (Math.randomRange(-1, 1) >= 1) {
controlSteering = 70
} else {
controlSteering = -70
}
loops.pause(4000)
music.playTone(2000, 100)
controlSteering = 0
controlDrive = oldControlDrive
moods.neutral.show()
})
// compute the elapsed time since the last iteration
function computeTimestep() {
timestep = control.timer3.seconds()
control.timer3.reset()
}
sensors.color1.onColorDetected(ColorSensorColor.Green, function () {
moods.winking.show()
controlDrive = 150
controlSteering = 0
})
sensors.color1.onColorDetected(ColorSensorColor.Blue, function () {
moods.middleRight.show()
controlSteering = 70
})
// apply power to motors
function controlMotors() {
motors.largeA.setSpeed(power + controlSteering * 0.1)
motors.largeD.setSpeed(power - controlSteering * 0.1)
}
sensors.color1.onColorDetected(ColorSensorColor.Yellow, function () {
moods.middleLeft.show()
controlSteering = -70
})
sensors.color1.onColorDetected(ColorSensorColor.White, function () {
moods.sad.show();
controlDrive = -75
})
timestep = 0.014
// main loop
loops.forever(function () {
reset()
while (!fallen) {
control.timer3.pauseUntil(5)
computeTimestep()
computeGyro()
computeMotors()
computePower()
controlMotors()
checkFallen()
}
stop()
})
```

View File

@ -0,0 +1,215 @@
# Gyroboy LabView
```typescript
let mSum = 0;
let mPos = 0;
let mSpd = 0;
let mD = 0;
let mDP1 = 0;
let mDP2 = 0;
let mDP3 = 0;
let Crdv = 0;
let cLo = 0;
let gAng = 0;
let ok = false;
let pwr = 0;
let Cstr = 0;
let Cdrv = 0;
let gMn = 0;
let gMx = 0;
let gSum = 0;
let gyro = 0;
let gOS = 0;
let gSpd = 0;
let tInt = 0.014;
let lpwr = 0
let rpwr = 0
let tStart = 0
let st = 0
let oldDr = 0
function RST() {
motors.largeA.reset()
motors.largeD.reset()
motors.largeA.setRegulated(false)
motors.largeD.setRegulated(false)
sensors.gyro2.reset()
sensors.gyro2.rate()
control.timer2.reset()
loops.pause(5000)
mSum = 0;
mPos = 0;
mD = 0;
mDP1 = 0;
mDP2 = 0;
mDP3 = 0;
Crdv = 0;
cLo = 0;
gAng = 0;
ok = false;
pwr = 0;
st = 0;
Cstr = 0;
Cdrv = 0;
}
function OS() {
// OSL
do {
gMn = 1000;
gMx = -100;
gSum = 0;
// gChk
for (let i = 0; i < 200; i++) {
gyro = sensors.gyro2.rate()
gSum = gyro;
gMx = Math.max(gMx, gyro)
gMn = Math.min(gMn, gyro)
loops.pause(4);
}
} while (gMx - gMn > 2);
gOS = gSum / 200;
}
function GT() {
if (cLo == 0) {
tInt = 0.014;
control.timer1.reset();
} else {
tInt = control.timer1.seconds() / cLo;
}
cLo++;
}
function GG() {
gyro = sensors.gyro2.rate();
gOS = 0.0005 * gyro + (1 - 0.0005) * gOS
gSpd = gyro - gOS;
gAng = gAng + tInt * gSpd;
}
function GM() {
let temp = mSum
mSum = motors.largeD.angle() + motors.largeA.angle();
mD = mSum - temp;
mPos = mPos + mD;
mSpd = ((mDP1 + mDP2 + mDP3 + mD) / 4) / tInt;
mDP3 = mDP2;
mDP2 = mDP1;
mDP1 = mD;
}
function EQ() {
mPos = mPos - Cdrv * tInt;
pwr = (0.8 * gSpd + 15 * gAng) + (0.08 * mSpd + 0.12 * mPos) - 0.01 * Cdrv
if (pwr > 100) pwr = 100
else if (pwr < -100) pwr = -100
}
function cntrl() {
mPos = mPos - tInt * Cdrv
lpwr = (pwr + Cstr * 0.1)
rpwr = (pwr - Cstr * 0.1)
}
function CHK() {
if (Math.abs(pwr) < 100)
control.timer2.reset();
if (control.timer2.seconds() > 2) {
ok = true;
}
}
// M
loops.forever(function () {
RST();
brick.showImage(images.eyesSleeping)
OS()
gAng = -0.25;
music.playSoundEffect(sounds.movementsSpeedUp)
brick.showImage(images.eyesAwake)
st = 1;
// BALANCE
while (!ok) {
GT();
let t1 = control.timer1.millis()
GG();
GM();
EQ();
cntrl();
motors.largeA.setSpeed(lpwr)
motors.largeD.setSpeed(rpwr)
CHK()
let t2 = control.timer1.millis();
let p = 5 - (t2 - t1);
loops.pause(Math.max(1, p))
}
motors.stopAllMotors()
st = 0;
brick.setLight(BrickLight.RedPulse);
brick.showImage(images.eyesKnockedOut)
music.playSoundEffect(sounds.movementsSpeedDown)
sensors.touch3.pauseUntil(TouchSensorEvent.Pressed)
brick.setLight(BrickLight.Off);
})
// BHV
loops.forever(function () {
switch (st) {
case 0:
Cdrv = 0;
Cstr = 0;
break;
case 1:
Cdrv = 40;
loops.pause(4000);
Cdrv = 0;
music.playTone(1000, 100);
st = 2;
break;
case 2:
switch (sensors.color1.color()) {
case ColorSensorColor.Red:
music.playTone(2000, 100);
Cdrv = 0;
Cstr = 0;
break;
case ColorSensorColor.Green:
music.playTone(2000, 100);
Cdrv = 150;
Cstr = 0;
break;
case ColorSensorColor.Blue:
music.playTone(2000, 100);
Cstr = 70;
break;
case ColorSensorColor.Yellow:
music.playTone(2000, 100);
Cstr = -70;
break;
case ColorSensorColor.White:
music.playTone(2000, 100);
Cdrv = -75;
break;
}
if (sensors.ultrasonic4.distance() < 25) {
Cstr = 0;
oldDr = Cdrv;
Cdrv = -10;
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
motors.mediumC.setSpeed(-30, 60, MoveUnit.Degrees);
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
if (Math.randomRange(-1, 1) >= 1)
Cstr = 70;
else
Cstr = -70;
loops.pause(4000);
music.playTone(2000, 100)
Cstr = 0;
Cdrv = oldDr;
}
break;
}
loops.pause(80);
})
```

View File

@ -0,0 +1,390 @@
# Puppy
```typescript
let P_T = 0;
let ISS = 0;
let F_T = 0;
let P_C = 0;
let F_C = 0;
let DB_S = 0;
let NS = false;
let IBP = 0;
let IAP = 0;
let C = false;
let TC = false;
let OTC = false;
let COL = 0;
let OCOL = 0;
let _C = false;
let GTO = 0;
function DN() {
motors.largeAD.setBrake(true);
motors.largeAD.tank(50, 50, 1, MoveUnit.Seconds);
loops.pause(100);
motors.largeA.clearCounts()
motors.largeD.clearCounts()
}
function MNRH() {
motors.mediumC.setBrake(true)
brick.showImage(images.legoEv3icon)
brick.setLight(BrickLight.OrangePulse)
while (!brick.buttonEnter.wasPressed()) {
if (brick.buttonUp.wasPressed()) {
motors.mediumC.setSpeed(-100);
} else if (brick.buttonDown.wasPressed()) {
motors.mediumC.setSpeed(100);
} else {
motors.mediumC.stop();
}
}
motors.mediumC.stop();
motors.mediumC.clearCounts();
brick.setLight(BrickLight.Green);
}
function IS(t: number) {
ISS = t;
switch (t) {
case 0:
brick.showImage(images.eyesNeutral);
break;
case 1:
brick.showImage(images.eyesSleeping);
break;
case 2:
brick.showImage(images.eyesTear);
// draw rect...
break;
case 3:
brick.showImage(images.eyesHurt);
break;
case 4:
brick.showImage(images.eyesAngry);
break;
case 5:
brick.showImage(images.eyesTiredMiddle);
break;
case 6:
brick.showImage(images.eyesTiredRight);
break;
case 7:
brick.showImage(images.eyesTiredLeft);
break;
case 8:
brick.showImage(images.eyesLove);
break;
}
}
function UP() {
if (motors.largeA.angle() > -50) {
control.runInParallel(function () {
motors.largeD.clearCounts()
motors.largeD.setSpeed(-35);
pauseUntil(() => motors.largeD.angle() < -25);
motors.largeD.stop();
motors.largeD.setRegulated(false)
motors.largeD.setSpeed(-15)
pauseUntil(() => motors.largeD.angle() < -65);
motors.largeD.stop();
})
motors.largeA.clearCounts()
motors.largeA.setSpeed(-35);
pauseUntil(() => motors.largeA.angle() < -25);
motors.largeA.stop();
motors.largeA.setRegulated(false)
motors.largeA.setSpeed(-15)
pauseUntil(() => motors.largeA.angle() < -65);
motors.largeA.stop();
loops.pause(500);
}
}
function RST() {
P_T = Math.randomRange(3, 6);
F_T = Math.randomRange(2, 4);
P_C = 1;
F_C = 1;
control.timer1.reset();
control.timer2.reset();
control.timer3.reset();
CS(0);
}
function CS(db: number) {
if (DB_S != db) {
DB_S = db;
NS = true;
}
}
function MON() {
if (control.timer2.seconds() > 10) {
control.timer2.reset();
P_C--;
if (P_C < 0) {
P_C = 0;
}
}
if (control.timer1.seconds() > 20) {
control.timer1.reset()
F_C--;
if (F_C < 0) {
F_C = 0;
}
}
if (control.timer3.seconds() > 30) {
control.timer3.reset();
CS(1);
}
}
function UIS() {
if (control.timer5.seconds() > IBP) {
control.timer5.reset();
if (ISS == 1) {
ISS = 6;
IBP = Math.randomRange(1, 5);
} else {
ISS = 1;
IBP = 0.25;
}
IS(ISS);
}
if (control.timer6.seconds() > IAP) {
if (ISS != 1) {
control.timer6.reset();
IAP = Math.randomRange(1, 10)
if (ISS != 7) {
ISS = 7
} else {
ISS = 6;
}
IS(ISS);
}
}
}
function UPDB() {
if ((P_T == P_C) && (F_T == F_C)) {
CS(6);
}
if ((P_T > P_C) && (F_T < F_C)) {
CS(3);
}
if ((P_T < P_C) && (F_T > F_C)) {
CS(5);
}
if ((P_C == 0) && (F_C > 0)) {
CS(2)
}
if (F_C == 0) {
CS(4)
}
}
function PTC() {
C = false;
OTC = TC;
TC = sensors.touch1.isPressed()
if (TC != OTC && TC) {
P_C++;
control.timer3.reset();
if (DB_S != 4) {
IS(2);
music.playSoundEffect(sounds.animalsDogSniff);
C = true;
}
}
return C;
}
function FDC() {
OCOL = COL;
COL = sensors.color4.color();
_C = false;
if ((COL != 0) && (OCOL != COL)) {
F_C++;
_C = true;
control.timer3.reset();
IS(2);
music.playSoundEffect(sounds.expressionsCrunching)
}
return _C;
}
function IDL() {
if (NS) {
NS = false;
UP();
}
UIS();
UPDB();
PTC();
FDC();
}
function MHT(Pos: number) {
let _R = Pos - motors.mediumC.angle();
if (_R >= 0) {
motors.mediumC.setSpeed(100, _R, MoveUnit.Degrees);
} else {
motors.mediumC.setSpeed(-100, Math.abs(_R), MoveUnit.Degrees);
}
}
function SLP() {
if (NS) {
NS = false;
IS(5)
DN()
MHT(3000)
IS(1)
music.playSoundEffect(sounds.expressionsSnoring)
}
if (sensors.touch1.isPressed() || brick.buttonEnter.isPressed()) {
music.stopAllSounds();
control.timer3.reset();
CS(7);
}
}
function PLF() {
if (NS) {
NS = false
IS(0)
UP()
music.playSoundEffect(sounds.animalsDogBark2)
control.timer4.reset()
GTO = Math.randomRange(4, 8);
}
if(PTC()) {
CS(0);
}
if (control.timer4.seconds() > GTO) {
music.playSoundEffect(sounds.animalsDogBark2)
control.timer4.reset();
GTO = Math.randomRange(4, 8);
}
}
function NGR() {
NS = false
IS(4)
music.playSoundEffect(sounds.animalsDogGrowl);
UP();
loops.pause(1500);
music.stopAllSounds()
music.playSoundEffect(sounds.animalsDogBark1)
P_C--;
CS(0);
}
function HNG() {
if (NS) {
NS = false;
IS(3)
DN();
music.playSoundEffect(sounds.animalsDogWhine);
}
if(FDC()) {
CS(0)
}
if (PTC()) {
CS(3);
}
}
function PPP() {
NS = false;
IS(2);
UP();
loops.pause(100)
motors.largeA.setSpeed(-30, 70, MoveUnit.Degrees);
loops.pause(800);
music.playSoundEffect(sounds.mechanicalHorn1);
loops.pause(1000);
for(let i = 0; i < 3; ++i) {
motors.largeA.setSpeed(-30, 20, MoveUnit.Degrees);
motors.largeA.setSpeed(30, 20, MoveUnit.Degrees);
}
motors.largeA.setSpeed(30, 70, MoveUnit.Degrees);
F_C = 1;
CS(0);
}
function HPY() {
IS(8)
MHT(0);
motors.largeAD.setSpeed(10, 0.8, MoveUnit.Seconds);
for(let i = 0; i < 3; ++i) {
music.playSoundEffect(sounds.animalsDogBark1);
motors.largeAD.setSpeed(-100, 0.2, MoveUnit.Seconds);
loops.pause(300)
motors.largeAD.setSpeed(10, 0.3, MoveUnit.Seconds)
}
loops.pause(500);
music.stopAllSounds();
DN();
RST();
}
function STL() {
UP();
motors.largeAD.setSpeed(-20, 60, MoveUnit.Degrees);
music.playSoundEffect(sounds.animalsDogWhine);
motors.largeAD.setSpeed(20, 60, MoveUnit.Degrees);
}
function WKU() {
let stateC = false;
IS(5);
music.playSoundEffect(sounds.animalsDogWhine)
MHT(0)
DN()
STL()
loops.pause(1000);
UP()
CS(0;)
}
DN();
MNRH();
// compare button state???
IS(1);
UP();
RST();
loops.forever(function () {
MON();
switch (DB_S) {
case 0:
IDL();
break;
case 1:
SLP();
break;
case 2:
PLF();
break;
case 3:
NGR();
break;
case 4:
HNG();
break;
case 5:
PPP();
break;
case 6:
HPY();
break;
case 7:
WKU();
break;
}
})
```

View File

@ -0,0 +1,51 @@
# Robot Arm
```typescript
function INI() {
motors.largeB.setBrake(true)
motors.largeC.setBrake(true)
motors.mediumA.setBrake(true)
motors.largeB.setSpeed(-50)
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
motors.largeB.stop();
motors.mediumA.setSpeed(30, 1, MoveUnit.Seconds);
motors.mediumA.setSpeed(-50, 90, MoveUnit.Degrees);
motors.largeC.setSpeed(50)
sensors.touch1.pauseUntil(TouchSensorEvent.Pressed);
motors.largeC.setSpeed(-50, 0.86, MoveUnit.Rotations);
}
INI()
let down = false;
loops.forever(function () {
brick.showImage(images.informationQuestionMark)
brick.setLight(BrickLight.OrangePulse);
pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed())
brick.setLight(BrickLight.Off)
music.playSoundEffect(sounds.mechanicalAirRelease)
brick.showImage(images.informationAccept)
if (down) {
brick.showImage(images.informationForward)
motors.largeC.setSpeed(65, 0.85, MoveUnit.Rotations);
} else {
brick.showImage(images.informationBackward)
motors.largeC.setSpeed(-65, 0.85, MoveUnit.Rotations);
}
motors.largeB.setSpeed(20, 275, MoveUnit.Degrees)
motors.mediumA.setSpeed(30, 1, MoveUnit.Seconds)
motors.largeB.setSpeed(-55)
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
motors.largeB.stop();
if (down) {
motors.largeC.setSpeed(-65, 0.86, MoveUnit.Rotations);
} else {
motors.largeC.setSpeed(65, 0.85, MoveUnit.Rotations);
}
motors.largeB.setSpeed(20, 275, MoveUnit.Degrees);
motors.mediumA.setSpeed(-30, 90, MoveUnit.Degrees);
motors.largeB.setSpeed(-55)
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
motors.largeB.stop()
})
```

View File

@ -0,0 +1,51 @@
# Crane LabView
```blocks
function INI() {
motors.largeB.setBrake(true)
motors.largeC.setBrake(true)
motors.mediumA.setBrake(true)
motors.largeB.setSpeed(-50)
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
motors.largeB.stop();
motors.mediumA.setSpeed(30, 1, MoveUnit.Seconds);
motors.mediumA.setSpeed(-50, 90, MoveUnit.Degrees);
motors.largeC.setSpeed(50)
sensors.touch1.pauseUntil(TouchSensorEvent.Pressed);
motors.largeC.setSpeed(-50, 0.86, MoveUnit.Rotations);
}
INI()
let down = false;
loops.forever(function () {
brick.showImage(images.informationQuestionMark)
brick.setLight(BrickLight.OrangePulse);
pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed())
brick.setLight(BrickLight.Off)
music.playSoundEffect(sounds.mechanicalAirRelease)
brick.showImage(images.informationAccept)
if (down) {
brick.showImage(images.informationForward)
motors.largeC.setSpeed(65, 0.85, MoveUnit.Rotations);
} else {
brick.showImage(images.informationBackward)
motors.largeC.setSpeed(-65, 0.85, MoveUnit.Rotations);
}
motors.largeB.setSpeed(20, 275, MoveUnit.Degrees)
motors.mediumA.setSpeed(30, 1, MoveUnit.Seconds)
motors.largeB.setSpeed(-55)
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
motors.largeB.stop();
if (down) {
motors.largeC.setSpeed(-65, 0.86, MoveUnit.Rotations);
} else {
motors.largeC.setSpeed(65, 0.85, MoveUnit.Rotations);
}
motors.largeB.setSpeed(20, 275, MoveUnit.Degrees);
motors.mediumA.setSpeed(-30, 90, MoveUnit.Degrees);
motors.largeB.setSpeed(-55)
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
motors.largeB.stop()
})
```

View File

@ -0,0 +1,215 @@
# Gyro Boy LabView
```blocks
let mSum = 0;
let mPos = 0;
let mSpd = 0;
let mD = 0;
let mDP1 = 0;
let mDP2 = 0;
let mDP3 = 0;
let Crdv = 0;
let cLo = 0;
let gAng = 0;
let ok = false;
let pwr = 0;
let Cstr = 0;
let Cdrv = 0;
let gMn = 0;
let gMx = 0;
let gSum = 0;
let gyro = 0;
let gOS = 0;
let gSpd = 0;
let tInt = 0.014;
let lpwr = 0
let rpwr = 0
let tStart = 0
let st = 0
let oldDr = 0
function RST() {
motors.largeA.reset()
motors.largeD.reset()
motors.largeA.setRegulated(false)
motors.largeD.setRegulated(false)
sensors.gyro2.reset()
sensors.gyro2.rate()
control.timer2.reset()
loops.pause(5000)
mSum = 0;
mPos = 0;
mD = 0;
mDP1 = 0;
mDP2 = 0;
mDP3 = 0;
Crdv = 0;
cLo = 0;
gAng = 0;
ok = false;
pwr = 0;
st = 0;
Cstr = 0;
Cdrv = 0;
}
function OS() {
// OSL
do {
gMn = 1000;
gMx = -100;
gSum = 0;
// gChk
for (let i = 0; i < 200; i++) {
gyro = sensors.gyro2.rate()
gSum = gyro;
gMx = Math.max(gMx, gyro)
gMn = Math.min(gMn, gyro)
loops.pause(4);
}
} while (gMx - gMn > 2);
gOS = gSum / 200;
}
function GT() {
if (cLo == 0) {
tInt = 0.014;
control.timer1.reset();
} else {
tInt = control.timer1.seconds() / cLo;
}
cLo++;
}
function GG() {
gyro = sensors.gyro2.rate();
gOS = 0.0005 * gyro + (1 - 0.0005) * gOS
gSpd = gyro - gOS;
gAng = gAng + tInt * gSpd;
}
function GM() {
let temp = mSum
mSum = motors.largeD.angle() + motors.largeA.angle();
mD = mSum - temp;
mPos = mPos + mD;
mSpd = ((mDP1 + mDP2 + mDP3 + mD) / 4) / tInt;
mDP3 = mDP2;
mDP2 = mDP1;
mDP1 = mD;
}
function EQ() {
mPos = mPos - Cdrv * tInt;
pwr = (0.8 * gSpd + 15 * gAng) + (0.095 * mSpd + 0.13 * mPos) - 0.01 * Cdrv
if (pwr > 100) pwr = 100
else if (pwr < -100) pwr = -100
}
function cntrl() {
mPos = mPos - tInt * Cdrv
lpwr = (pwr + Cstr * 0.1)
rpwr = (pwr - Cstr * 0.1)
}
function CHK() {
if (Math.abs(pwr) < 100)
control.timer2.reset();
if (control.timer2.seconds() > 2) {
ok = true;
}
}
// M
loops.forever(function () {
RST();
brick.showImage(images.eyesSleeping)
OS()
gAng = -0.25;
music.playSoundEffect(sounds.movementsSpeedUp)
brick.showImage(images.eyesAwake)
st = 1;
// BALANCE
while (!ok) {
GT();
let t1 = control.timer1.millis()
GG();
GM();
EQ();
cntrl();
motors.largeA.setSpeed(lpwr)
motors.largeD.setSpeed(rpwr)
CHK()
let t2 = control.timer1.millis();
let p = 5 - (t2 - t1);
loops.pause(Math.max(1, p))
}
motors.stopAllMotors()
st = 0;
brick.setLight(BrickLight.RedPulse);
brick.showImage(images.eyesKnockedOut)
music.playSoundEffect(sounds.movementsSpeedDown)
sensors.touch3.pauseUntil(TouchSensorEvent.Pressed)
brick.setLight(BrickLight.Off);
})
// BHV
loops.forever(function () {
switch (st) {
case 0:
Cdrv = 0;
Cstr = 0;
break;
case 1:
Cdrv = 40;
loops.pause(4000);
Cdrv = 0;
music.playTone(1000, 100);
st = 2;
break;
case 2:
switch (sensors.color1.color()) {
case ColorSensorColor.Red:
music.playTone(2000, 100);
Cdrv = 0;
Cstr = 0;
break;
case ColorSensorColor.Green:
music.playTone(2000, 100);
Cdrv = 150;
Cstr = 0;
break;
case ColorSensorColor.Blue:
music.playTone(2000, 100);
Cstr = 70;
break;
case ColorSensorColor.Yellow:
music.playTone(2000, 100);
Cstr = -70;
break;
case ColorSensorColor.White:
music.playTone(2000, 100);
Cdrv = -75;
break;
}
if (sensors.ultrasonic4.distance() < 25) {
Cstr = 0;
oldDr = Cdrv;
Cdrv = -10;
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
motors.mediumC.setSpeed(-30, 60, MoveUnit.Degrees);
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
if (Math.randomRange(-1, 1) >= 1)
Cstr = 70;
else
Cstr = -70;
loops.pause(4000);
music.playTone(2000, 100)
Cstr = 0;
Cdrv = oldDr;
}
break;
}
loops.pause(80);
})
```

View File

@ -3,10 +3,10 @@
Use a touch sensor to make the brick happy.
```blocks
sensors.touchSensor1.onEvent(TouchSensorEvent.Pressed, function () {
sensors.touch1.onEvent(TouchSensorEvent.Pressed, function () {
brick.showImage(images.expressionsBigSmile)
})
sensors.touchSensor1.onEvent(TouchSensorEvent.Released, function () {
sensors.touch1.onEvent(TouchSensorEvent.Released, function () {
brick.showImage(images.expressionsSick)
})
```

27
docs/lessons.md Normal file
View File

@ -0,0 +1,27 @@
# Lessons
Learning activities for LEGO Mindstorms with MakeCode.
## Motors and motion
```codecard
[{
"name": "Make it Move",
"imageUrl":"/static/lessons/make-it-move.jpg",
"url": "/lessons/make-it-move",
"cardType": "project",
"description": "Make a robot that moves itself without wheels."
}, {
"name": "Make it Move TUTORIAL",
"imageUrl":"/static/lessons/make-it-move.jpg",
"url": "/lessons/make-it-move-tutorial",
"cardType": "tutorial",
"description": "Make a robot that moves itself without wheels."
}, {
"name": "Line Detection",
"imageUrl":"/static/lessons/line-detection.jpg",
"url": "/lessons/line-detection",
"cardType": "project",
"description": "Make your robot drive itself by following lines."
}]
```

View File

@ -0,0 +1,266 @@
# Line Detection
## Objective
Design ways to improve driving safety by helping to prevent drivers from falling asleep and causing an accident.
![Car driving on highway](/static/lessons/line-detection/car-driving.jpg)
## Connect
Make sure that you can answer the following questions:
* Can autonomous cars react to different traffic light signals?
* What can happen if a driver falls asleep while driving?
* How can we detect when a driver is falling asleep?
Think about what you have learned, then document it. Describe the problem in your own words. Creatively record your ideas and findings.
## Construct
Start by constructing this model. Read the building instructions [here](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/building-instructions/ev3-rem-color-sensor-down-driving-base-d30ed30610c3d6647d56e17bc64cf6e2.pdf) first.
![Color sensor on the driving base](/static/lessons/line-detection/color-sensor-driving.jpg)
## Program
Autonomous cars need to recognize and respond to traffic lights automatically.
First, create a program that will make your robot stop at red lights.
Make sure your robot is only responding to the color red.
Once you have succeeded, program your robot to drive forward again when the light changes from red to green.
There are two coding tasks for this lesson:
1. Create a program that will make your robot stop at red lights.
2. Create a program that drives the robot forward until the Color Sensor sees red. The robot then stops.
## Coding task 1 - Stop at red lights
**Goal:** Create a program that will make your robot stop at red lights.
### Step 1
Create a program that drives the robot forward until the Color Sensor sees red. The robot then stops.
Place a ``||motors:steer large B+C||`` block from ``||motors:Motors||`` under ``||loops:on start||``. Change the speed to 20%.
```blocks
motors.largeBC.steer(0, 20)
```
### Step 2
Place a ``||loops:while||`` loop block under ``||motors:steer large B+C||``.
```blocks
motors.largeBC.steer(0, 20)
while (true) {
}
```
### Step 3
Place a ``||sensors:pause for color||`` from ``||sensors:Sensors||`` inside the ``||loops:while||`` loop block. Change the color to red.
```blocks
motors.largeBC.steer(0, 20)
while (true) {
sensors.color3.pauseForColor(ColorSensorColor.Red)
}
```
### Step 4
Place a ``||motors:stop all motors||`` block under the ``||sensors:pause for color||`` block.
Study the program...what do you think the program will do?
**Hint:** The motors will run until the Color Sensor senses the color red, then all motors will stop. The motors will run until the sensor reading in the while block is true.
```blocks
motors.largeBC.steer(0, 20)
while (true) {
sensors.color3.pauseForColor(ColorSensorColor.Red)
motors.stopAllMotors()
}
```
### Step 5
Click `|Download|` and follow the instructions to get your code onto your EV3 Brick. Press the **center** button on the EV3 Brick to run the program.
## Coding task 2 - Detect light changes
**Goal:** Program your robot to drive forward again when the light changes from red to green.
### Step 1
Place a ``||loops:while||`` loop block under ``||loops:on start||``.
```blocks
while (true) {
}
```
### Step 2
Place a ``||motors:steer large B+C||`` block from ``||motors:Motors||`` inside the ``||loops:while||`` loop block. Change the speed to 20%.
```blocks
while (true) {
motors.largeBC.steer(0, 20)
}
```
### Step 4
Place a ``||loops:while||`` loop block under the ``||motors:steer large B+C||`` block.
```blocks
while (true) {
motors.largeBC.steer(0, 20)
while (true) {
}
}
```
### Step 5
Place a ``||sensors:pause for color||`` block from ``||sensors:Sensors||`` inside the ``||loops:while||`` loop block. Change the color to red.
```blocks
while (true) {
motors.largeBC.steer(0, 20)
while (true) {
sensors.color3.pauseForColor(ColorSensorColor.Red)
}
}
```
### Step 6
Place a ``||motors:stop all motors||`` block under the ``||sensors:pause for color||`` block.
```blocks
while (true) {
motors.largeBC.steer(0, 20)
while (true) {
sensors.color3.pauseForColor(ColorSensorColor.Red)
motors.stopAllMotors()
}
}
```
### Step 7
Place a ``||loops:while||`` loop block under the second ``||loops:while||`` loop block.
```blocks
while (true) {
motors.largeBC.steer(0, 20)
while (true) {
sensors.color3.pauseForColor(ColorSensorColor.Red)
motors.stopAllMotors()
}
while (true) {
}
}
```
### Step 8
Place a ``||sensors:pause for color||`` block inside the new ``||loops:while||`` loop block. Change the color to red.
What do you think the program will do?
**Hint:** The motors will run until the Color Sensor detects the color red, then it will stop all motors. The motors will also run and not stop when the color sensor detects the color green.
```blocks
while (true) {
motors.largeBC.steer(0, 20)
while (true) {
sensors.color3.pauseForColor(ColorSensorColor.Red)
motors.stopAllMotors()
}
while (true) {
sensors.color3.pauseForColor(ColorSensorColor.Red)
}
}
```
### Step 9
Click `|Download|` and follow the instructions to get your code onto your EV3 Brick. Press the **center** button on the EV3 Brick to run the program.
## Contemplate
To simulate what could happen if a driver falls asleep while driving, your robot could sound an alarm signal when it crosses the line. This feature is often available in new cars.
Program your robot to perform this function.
Think about what you have learned, then document it. Describe your pseudocode for this task. Creatively record your ideas, and findings.
### Programming hint
```blocks
motors.largeBC.steer(0, 20)
while (true) {
sensors.color3.pauseForColor(ColorSensorColor.Yellow)
music.playSoundEffect(sounds.systemGeneralAlert)
}
while (true) {
while (true) { sensors.color3.pauseForLight(LightIntensityMode.Reflected, LightCondition.Bright)
motors.largeB.setSpeed(10)
motors.largeC.setSpeed(-10)
}
while (true) {
sensors.color3.pauseForLight(LightIntensityMode.Reflected, LightCondition.Bright)
motors.largeA.setSpeed(-10)
motors.largeA.setSpeed(10)
}
}
```
## Continue
Program your robot to drive on “autopilot” along a given route. You will need to create a program that recognizes and responds to a dark line (or white line). You will create a line-following program and your robot will need to travel along the line without losing contact with it.
You will need to constantly debug your program in order to make your robot travel as smoothly as possible along the line.
### Programming hint
```blocks
while (true) {
while (true) { sensors.color3.pauseForLight(LightIntensityMode.Reflected, LightCondition.Bright)
motors.largeB.setSpeed(10)
motors.largeC.setSpeed(-10)
}
while (true) {
sensors.color3.pauseForLight(LightIntensityMode.Reflected, LightCondition.Bright)
motors.largeB.setSpeed(-10)
motors.largeC.setSpeed(10)
}
}
```
## Share
Consider the following questions:
1. What challenged you?
2. Where there any surprises?
3. How could you improve your program?
4. Could your program have been more streamlined?
5. Have you used too many blocks?
6. Is there a more efficient way of building your program?
7. How could your program be used in real-world scenarios?
Think about what you have learned, then document it. Creatively record and present your ideas, creations, and findings.

View File

@ -0,0 +1,72 @@
# Make It Move Without Wheels
## Objective @unplugged
Design, build and program a robot that can move itself:
Your robot will:
* Go a distance of at least 30cm
* Use at least one motor
* Use NO wheels for locomotion
![LECG Mindstorms brick with parts](/static/lessons/make-it-move/locomotion-no-wheels.jpg)
## Construct @unplugged
Build a Walker Bot!
The Walker Bot is one example of many possible solutions for making a robot move without wheels.
The Walker Bot combines an EV3 Frame and two legs that are mirror-images to create left and right legs.
The legs in the Walker Bot are designed to show how to change the rotary motion of a motor to reciprocating motion.
Start by reading [these](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/ev3-dep/building%20instructions/walker-bot-bi-180fc24f9298e1dd6201099627d43903.pdf) instructions first.
![LEGO Mindstorms Walker Bot](/static/lessons/make-it-move/walker-bot.jpg)
## Program 1 @fullscreen
In nature, creatures use many methods to get around. None of them, however, use wheels to move. Can we copy the method of animal locomotion with our robot? Using motors and legs, make the robot move without using any wheels.
Place a ``||motors:tank large B+C||`` block from ``||motors:Motors||`` under ``||loops:on start||``.
Change the speed to `-60%` (for motor B) and `+60%` (for motor C).
Change the rotations to `9`.
The ``||motors:tank large B+C||`` block will run for `9` rotations when the **center** button is pressed on the EV3 brick. The motors are set for the reverse direction because they are mounted upside down in this model.
```blocks
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
```
## Program 2 @fullscreen
Place a ``||motors:stop all motors||`` block under ``||motors:tank large B+C||``.
The ``||motors:tank large B+C||`` block will run for `9` rotations when the **center** button is pressed on the EV3 brick then stop.
```blocks
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
motors.stopAllMotors()
```
## Program 3 @fullscreen
Place a ``||brick:show string||`` block under ``||motors:stop all motors||``.
Change the `"Hello World"` text to `"30 cm"`.
The ``||motors:tank large B+C||`` will run for `9` rotations when the **center** button is pressed on the EV3 brick then stop and display "30 cm" on the EV3 Bricks screen.
```blocks
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
motors.stopAllMotors()
brick.showString("30 cm", 1)
```
## Download @fullscreen
Click `|Download|` and follow the instructions to get your code onto your EV3 Brick. Press the **center** button on the EV3 Brick to run the program.

View File

@ -0,0 +1,73 @@
# Make It Move Without Wheels
## Objective
Design, build and program a robot that can move itself:
Your robot will:
* Go a distance of at least 30cm
* Use at least one motor
* Use NO wheels for locomotion
![LECG Mindstorms brick with parts](/static/lessons/make-it-move/locomotion-no-wheels.jpg)
## Construct
Build a Walker Bot!
The Walker Bot is one example of many possible solutions for making a robot move without wheels.
The Walker Bot combines an EV3 Frame and two legs that are mirror-images to create left and right legs.
The legs in the Walker Bot are designed to show how to change the rotary motion of a motor to reciprocating motion.
Start by reading [these](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/ev3-dep/building%20instructions/walker-bot-bi-180fc24f9298e1dd6201099627d43903.pdf) instructions first.
![LEGO Mindstorms Walker Bot](/static/lessons/make-it-move/walker-bot.jpg)
## Program
In nature, creatures use many methods to get around. None of them, however, use wheels to move. Can we copy the method of animal locomotion with our robot? Using motors and legs, make the robot move without using any wheels.
### Step 1
Place a ``||motors:tank large B+C||`` block from ``||motors:Motors||`` under ``||loops:on start||``.
Change the speed to `-60%` (for motor B) and `+60%` (for motor C).
Change the rotations to `9`.
The ``||motors:tank large B+C||`` block will run for `9` rotations when the **center** button is pressed on the EV3 brick. The motors are set for the reverse direction because they are mounted upside down in this model.
```blocks
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
```
### Step 2
Place a ``||motors:stop all motors||`` block under ``||motors:tank large B+C||``.
The ``||motors:tank large B+C||`` block will run for `9` rotations when the **center** button is pressed on the EV3 brick then stop.
```blocks
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
motors.largeBC.stop()
```
### Step 3
Place a ``||brick:show string||`` block under ``||motors:stop all motors||``.
Change the `"Hello World"` text to `"30 cm"`.
The ``||motors:tank large B+C||`` will run for `9` rotations when the **center** button is pressed on the EV3 brick then stop and display "30 cm" on the EV3 Bricks screen.
```blocks
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
motors.largeBC.stop()
brick.showString("30 cm", 1)
```
### Step 4
Click `|Download|` and follow the instructions to get your code onto your EV3 Brick. Press the **center** button on the EV3 Brick to run the program.

View File

@ -2,10 +2,8 @@
This program will activate an alarm when an object moves in front of the Ultrasonic Sensor.
TODO support for event when value changes
```blocks
input.ultrasonic4.onObjectNear(function () {
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
sensors.ultrasonic4.onEvent(UltrasonicSensorEvent.ObjectNear, function () {
music.playSoundEffectUntilDone(sounds.informationActivate)
})
```

View File

@ -4,14 +4,12 @@ Use this program with the Programmable Brick and Large Motor.
```blocks
loops.forever(function () {
output.largeMotorA.setPower(30)
output.largeMotorA.on(true)
motors.largeA.setSpeed(30)
loops.pause(100)
output.largeMotorA.on(false)
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
output.largeMotorA.setPower(-30)
output.largeMotorA.on(true)
motors.largeA.stop()
music.playSoundEffectUntilDone(sounds.animalsCatPurr)
motors.largeA.setSpeed(-30)
loops.pause(100)
output.largeMotorA.on(false)
motors.largeA.stop()
})
```

View File

@ -3,7 +3,7 @@
This program will activate an alarm when an object is lifted from the Touch Sensor.
```blocks
input.touchSensor1.onEvent(TouchSensorEvent.Released, function () {
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
sensors.touch1.onEvent(TouchSensorEvent.Released, function () {
music.playSoundEffectUntilDone(sounds.informationActivate);
})
```

View File

@ -4,9 +4,9 @@ This example program combined with the small model will make a beat and rhythm o
```blocks
loops.forever(function () {
output.motorA.on(50)
motors.largeA.setSpeed(50)
loops.pause(200)
output.motorA.on(100)
motors.largeA.setSpeed(100)
loops.pause(200)
})
```

View File

@ -3,13 +3,13 @@
This program will play different sounds when the wheel is rotated. The sound is determined by which color is placed in front of the color Sensor.
```blocks
input.color3.onColorDetected(ColorSensorColor.Blue, function () {
sensors.color3.onColorDetected(ColorSensorColor.Blue, function () {
music.playTone(Note.G4, music.beat(BeatFraction.Half))
})
input.color3.onColorDetected(ColorSensorColor.Red, function () {
sensors.color3.onColorDetected(ColorSensorColor.Red, function () {
music.playTone(Note.C5, music.beat(BeatFraction.Half))
})
input.color3.onColorDetected(ColorSensorColor.Green, function () {
sensors.color3.onColorDetected(ColorSensorColor.Green, function () {
music.playTone(Note.D5, music.beat(BeatFraction.Half))
})
```

109
docs/static/avatar.svg vendored Normal file
View 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

331
docs/static/download/connect.svg vendored Normal file
View File

@ -0,0 +1,331 @@
<svg xmlns="http://www.w3.org/2000/svg" width="261.3" height="109.3" viewBox="0 0 69.1 28.9" id="svg9461">
<defs id="defs9455">
<clipPath id="clipPath8689">
<path d="M0 1145.9h1366V0H0z" id="path8687"/>
</clipPath>
<clipPath id="clipPath8663">
<path d="M309.8 89.4h3.7v3.7h-3.7z" id="path8661"/>
</clipPath>
<clipPath id="clipPath8647">
<path d="M0 1145.9h1366V0H0z" id="path8645"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 .6661 -.32488 0 300.7 115)" id="linearGradient8637">
<stop offset="0" id="stop8633" stop-color="#757575"/>
<stop offset="1" id="stop8635" stop-color="#393939"/>
</linearGradient>
<clipPath id="clipPath8595">
<path d="M0 1145.9h1366V0H0z" id="path8593"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 12.8096 -17.18704 0 300.7 98.4)" id="linearGradient8585">
<stop offset="0" id="stop8579" stop-color="#6a6a6a"/>
<stop offset=".5" id="stop8581" stop-color="#48e400"/>
<stop offset="1" id="stop8583" stop-color="#6a6a6a"/>
</linearGradient>
<clipPath id="clipPath8561">
<path d="M0 1145.9h1366V0H0z" id="path8559"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -1.33016 5.597 0 300.7 88.4)" id="linearGradient8551">
<stop offset="0" id="stop8547" stop-color="#a9aba9"/>
<stop offset="1" id="stop8549" stop-color="#535453"/>
</linearGradient>
<clipPath id="clipPath8525">
<path d="M0 1145.9h1366V0H0z" id="path8523"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -.56074 .70884 0 300.7 115.6)" id="linearGradient8515">
<stop offset="0" id="stop8511" stop-color="#a9aba9"/>
<stop offset="1" id="stop8513" stop-color="#818181"/>
</linearGradient>
<clipPath id="clipPath8493">
<path d="M0 1145.9h1366V0H0z" id="path8491"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.39765 2.48247 0 300.7 98.1)" id="linearGradient8483">
<stop offset="0" id="stop8479" stop-color="#f2f2f2"/>
<stop offset="1" id="stop8481" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath8449">
<path d="M0 1145.9h1366V0H0z" id="path8447"/>
</clipPath>
<clipPath id="clipPath8977">
<path d="M0 1145.9h1366V0H0z" id="path8975"/>
</clipPath>
<clipPath id="clipPath8951">
<path d="M593 101h3.6v3.7H593z" id="path8949"/>
</clipPath>
<clipPath id="clipPath8935">
<path d="M0 1145.9h1366V0H0z" id="path8933"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 .67046 -.32706 0 583.8 126.8)" id="linearGradient8925">
<stop offset="0" id="stop8921" stop-color="#757575"/>
<stop offset="1" id="stop8923" stop-color="#393939"/>
</linearGradient>
<clipPath id="clipPath8883">
<path d="M0 1145.9h1366V0H0z" id="path8881"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 12.89405 -17.29507 0 583.7 110)" id="linearGradient8873">
<stop offset="0" id="stop8867" stop-color="#6a6a6a"/>
<stop offset=".5" id="stop8869" stop-color="#48e400"/>
<stop offset="1" id="stop8871" stop-color="#6a6a6a"/>
</linearGradient>
<clipPath id="clipPath8849">
<path d="M0 1145.9h1366V0H0z" id="path8847"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -1.33884 5.6329 0 583.7 100)" id="linearGradient8839">
<stop offset="0" id="stop8835" stop-color="#a9aba9"/>
<stop offset="1" id="stop8837" stop-color="#535453"/>
</linearGradient>
<clipPath id="clipPath8813">
<path d="M0 1145.9h1366V0H0z" id="path8811"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -.56429 .71345 0 583.7 127.4)" id="linearGradient8803">
<stop offset="0" id="stop8799" stop-color="#a9aba9"/>
<stop offset="1" id="stop8801" stop-color="#818181"/>
</linearGradient>
<clipPath id="clipPath8781">
<path d="M0 1145.9h1366V0H0z" id="path8779"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.41323 2.4988 0 583.7 109.8)" id="linearGradient8771">
<stop offset="0" id="stop8767" stop-color="#f2f2f2"/>
<stop offset="1" id="stop8769" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath8737">
<path d="M0 1145.9h1366V0H0z" id="path8735"/>
</clipPath>
<clipPath id="clipPath9285">
<path d="M0 1145.9h1366V0H0z" id="path9283"/>
</clipPath>
<clipPath id="clipPath9259">
<path d="M852.5 96.3h3.3v3.3h-3.3z" id="path9257"/>
</clipPath>
<clipPath id="clipPath9243">
<path d="M0 1145.9h1366V0H0z" id="path9241"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 .61565 -.3002 0 844 120)" id="linearGradient9233">
<stop offset="0" id="stop9229" stop-color="#757575"/>
<stop offset="1" id="stop9231" stop-color="#393939"/>
</linearGradient>
<clipPath id="clipPath9191">
<path d="M0 1145.9h1366V0H0z" id="path9189"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 11.84237 -15.8829 0 844 104.6)" id="linearGradient9181">
<stop offset="0" id="stop9175" stop-color="#6a6a6a"/>
<stop offset=".5" id="stop9177" stop-color="#48e400"/>
<stop offset="1" id="stop9179" stop-color="#6a6a6a"/>
</linearGradient>
<clipPath id="clipPath9157">
<path d="M0 1145.9h1366V0H0z" id="path9155"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -1.22922 5.1724 0 844 95.3)" id="linearGradient9147">
<stop offset="0" id="stop9143" stop-color="#a9aba9"/>
<stop offset="1" id="stop9145" stop-color="#535453"/>
</linearGradient>
<clipPath id="clipPath9121">
<path d="M0 1145.9h1366V0H0z" id="path9119"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -.51809 .65506 0 844 120.5)" id="linearGradient9111">
<stop offset="0" id="stop9107" stop-color="#a9aba9"/>
<stop offset="1" id="stop9109" stop-color="#818181"/>
</linearGradient>
<clipPath id="clipPath9089">
<path d="M0 1145.9h1366V0H0z" id="path9087"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.21578 2.29436 0 844 104.3)" id="linearGradient9079">
<stop offset="0" id="stop9075" stop-color="#f2f2f2"/>
<stop offset="1" id="stop9077" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath9009">
<path d="M0 1145.9h1366V0H0z" id="path9007"/>
</clipPath>
<clipPath id="clipPath9041">
<path d="M779.5 134.7h16.7v-12.6h-16.7z" id="path9039"/>
</clipPath>
<clipPath id="clipPath9045">
<path d="M779.5 134.7h16.7v-12.6h-16.7z" id="path9043"/>
</clipPath>
<clipPath id="clipPath8907">
<path d="M0 1145.9h1366V0H0z" id="path8905"/>
</clipPath>
<clipPath id="clipPath8881">
<path d="M309.8 89.4h3.7v3.7h-3.7z" id="path8879"/>
</clipPath>
<clipPath id="clipPath8865">
<path d="M0 1145.9h1366V0H0z" id="path8863"/>
</clipPath>
<clipPath id="clipPath8813-1">
<path d="M0 1145.9h1366V0H0z" id="path8811-4"/>
</clipPath>
<clipPath id="clipPath8779">
<path d="M0 1145.9h1366V0H0z" id="path8777"/>
</clipPath>
<clipPath id="clipPath8743">
<path d="M0 1145.9h1366V0H0z" id="path8741"/>
</clipPath>
<clipPath id="clipPath8711">
<path d="M0 1145.9h1366V0H0z" id="path8709"/>
</clipPath>
<clipPath id="clipPath8667">
<path d="M0 1145.9h1366V0H0z" id="path8665"/>
</clipPath>
</defs>
<g id="layer1" transform="translate(0 -268)">
<g id="g11329" transform="matrix(.35278 0 0 -.35278 -42.7 327.3)">
<g id="g8661">
<g clip-path="url(#clipPath8667)" id="g8663">
<g transform="translate(134 148)" id="g8669">
<path id="path8671" d="M0 0h83a4 4 0 0 0 4-4v-52.5H-4V-4a4 4 0 0 0 4 4" fill="#e6e6e6"/>
</g>
<g transform="translate(134 146.5)" id="g8673">
<path id="path8675" d="M0 0h83c1.3 0 2.4-1.1 2.4-2.5V-52c0-.9-.6-1.5-1.5-1.5H-1c-.8 0-1.5.6-1.5 1.5v49.5C-2.5-1.1-1.4 0 0 0z" fill="none" stroke="#282828" stroke-width="3"/>
</g>
<g transform="translate(121 91)" id="g8677">
<path id="path8679" d="M0 0h108.8v-1.2a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3z" fill="#626262"/>
</g>
<g transform="translate(165.8 91)" id="g8681">
<path id="path8683" d="M0 0h19.3c0-.8-.6-1.4-1.4-1.4H1.4C.6-1.4 0-.8 0 0" fill="#818181"/>
</g>
</g>
</g>
<g id="g8685">
<g id="g8687">
<g id="g8693">
<g id="g8695">
<path id="path8703" d="M285 127.8a.6.6 0 0 1-.7-.5V96.9c0-.3.3-.6.6-.6h31.5c.3 0 .6.3.6.6v30.4c0 .3-.3.5-.6.5z" fill="url(#linearGradient8483)"/>
</g>
</g>
</g>
</g>
<g id="g8705">
<g clip-path="url(#clipPath8711)" id="g8707">
<g transform="translate(286.8 99.6)" id="g8713">
<path id="path8715" d="M0 0h27.8c.4 0 .6-.3.6-.6v-11.3c0-.4-.2-.6-.6-.6H0c-.3 0-.6.2-.6.6V-.6c0 .3.3.6.6.6" fill="#f2f2f2"/>
</g>
</g>
</g>
<g id="g8717">
<g id="g8719">
<g id="g8725">
<g id="g8727">
<path id="path8735-5" d="M286.5 137.2a.6.6 0 0 1-.6-.6v-22.2c0-.3.3-.6.6-.6h28.4c.3 0 .5.3.5.6v22.2c0 .3-.2.6-.5.6z" fill="url(#linearGradient8515)"/>
</g>
</g>
</g>
</g>
<g id="g8737">
<g clip-path="url(#clipPath8743)" id="g8739">
<g transform="translate(289.7 134.1)" id="g8745">
<path id="path8747" d="M0 0h22c.6 0 1-.5 1-1.1v-12.4c0-.6-.4-1-1-1H0c-.6 0-1.1.4-1.1 1V-1c0 .5.5 1 1.1 1" fill="#393939"/>
</g>
<g transform="translate(291.4 133.5)" id="g8749">
<path id="path8751" d="M0 0h18.7c.4 0 .8-.4.8-.8v-11.9c0-.4-.4-.8-.8-.8H0c-.4 0-.8.3-.8.8V-.8c0 .4.4.8.8.8" fill="#98b6a7"/>
</g>
</g>
</g>
<g id="g8753">
<g id="g8755">
<g id="g8761">
<g id="g8763">
<path id="path8771" d="M286.2 94v-6.4c0-.3.2-.6.6-.6h27.8c.3 0 .6.3.6.6V94z" fill="url(#linearGradient8551)"/>
</g>
</g>
</g>
</g>
<g id="g8773">
<g clip-path="url(#clipPath8779)" id="g8775">
<g transform="translate(298.7 97.7)" id="g8781">
<path id="path8783" d="M0 0l-4.2 4.2v.5h-1a2.4 2.4 0 0 0 0 5h1v.5L0 14.4h4l4.2-4.2v-.6h1a2.4 2.4 0 1 0 0-4.9h-1v-.5L4.2 0z" fill="#6a6a6a"/>
</g>
</g>
</g>
<g id="g8785">
<g id="g8787">
<g id="g8793">
<g id="g8795">
<path id="path8805" d="M298.7 112.1l-4.2-4.3v-.5h-1c-1.4 0-2.5-1-2.5-2.4s1.1-2.5 2.5-2.5h1v-.5l4.2-4.2h4.2l4 4.2v.5h1c1.4 0 2.5 1.1 2.5 2.5 0 1.3-1.1 2.4-2.5 2.4h-1v.6l-4 4.2z" fill="url(#linearGradient8585)"/>
</g>
</g>
</g>
</g>
<g id="g8807">
<g clip-path="url(#clipPath8813-1)" id="g8809">
<g transform="translate(293.4 106.7)" id="g8815">
<path id="path8817" d="M0 0h3v-3.6H0c-1 0-1.8.8-1.8 1.8S-1 0 0 0" fill="#a9aba9"/>
</g>
<g transform="translate(308 103.1)" id="g8819">
<path id="path8821" d="M0 0h-3v3.6h3c1 0 1.8-.8 1.8-1.8S1 0 0 0" fill="#a9aba9"/>
</g>
<g transform="translate(299 106.7)" id="g8823">
<path id="path8825" d="M0 0h3.5l.2-.1v-3.4l-.2-.1H0l-.1.1V0H0" fill="#393939"/>
</g>
<g transform="translate(298.8 111.4)" id="g8827">
<path id="path8829" d="M0 0h3.8l2.8-2.9L5.4-4v-2.1h-1V-5c0 .5-.5.9-1 .9H.2a.7.7 0 0 1-.8-.8V-6h-1v2l-1.2 1.2z" fill="#a9aba9"/>
</g>
<g transform="translate(302.6 98.4)" id="g8831">
<path id="path8833" d="M0 0h-3.7l-2.9 2.9L-5.4 4v2.1h1V5c0-.5.5-.9 1-.9h3.2c.4 0 .8.4.8.8v1.3h1v-2L2.8 3z" fill="#a9aba9"/>
</g>
<path id="path8835" d="M300.3 119.6h.9v-4.1h-1z" fill="#393939"/>
<path id="path8837" d="M300.3 115.7h.9v-1.8h-1z" fill="#9b9b9b"/>
</g>
</g>
<g id="g8839">
<g id="g8841">
<g id="g8847">
<g id="g8849">
<path id="path8857" d="M300.3 113.8h.9v1.9h-1z" fill="url(#linearGradient8637)"/>
</g>
</g>
</g>
</g>
<g id="g8859">
<g clip-path="url(#clipPath8865)" id="g8861">
<path id="path8867" d="M300.3 113.8h.9v-1.7h-1z" fill="#818181"/>
<g transform="translate(288.2 113.8)" id="g8869">
<path id="path8871" d="M0 0h7v-1.7L5.2-3.4H.6c-.3 0-.6.2-.6.5z" fill="#a9aba9"/>
</g>
<path id="path8873" d="M309.9 93h3.6v-3.6h-3.6z" fill="#fff"/>
</g>
</g>
<g id="g8875">
<g clip-path="url(#clipPath8881)" id="g8877">
<g transform="translate(313.2 91.6)" id="g8883">
<path id="path8885" d="M0 0v-.3C-.3-.7-.4-1-.8-1l-.3.2v.1a.6.6 0 0 0-.5-.3c-.1 0-.2 0-.3.2l-.4-.1h-.6c-.2 0-.3 0-.3.2l.3 1h.4V0l.1.1.5.2.3-.1h.3c.2.1.3 0 .4 0V.1l.4.2.3-.1L0 0m-3.4-2.1H.2v3.6h-3.6z" fill="#fe0"/>
</g>
<g transform="translate(313.3 91.4)" id="g8887">
<path id="path8889" d="M0 0c0-.2 0-.3-.2-.5 0-.2-.3-.4-.6-.4l-.4.1a.7.7 0 0 0-.4-.1H-2a.6.6 0 0 0-.4 0H-3c-.3 0-.4.1-.4.3 0 .4.1.7.3 1 0 .2.2.2.4.2h2.1L0 .5V0m-3.5-2H.1v3.6h-3.6z" fill="#d52715"/>
</g>
<path id="path8891" d="M313.4 89.5H310V93h3.5zm-3.6 0h3.7V93h-3.7z" fill="#171714"/>
<g transform="translate(313.3 92)" id="g8893">
<path id="path8895" d="M0 0v-.2.2m0 0v-.2.1m0 0zm0 0z" fill="#171714"/>
</g>
<g transform="translate(312.9 91.6)" id="g8897">
<path id="path8899" d="M0 0l-.2-.5v-.1h-.1c0 .2 0 .4.2.6H0m.3-.2L0-.6C0-.8-.2-1-.3-1c-.2 0-.3 0-.3.3l.1.5c.1.2.2.4.5.4s.3-.3.3-.5M-1 .1V0l-.3-.5.1-.1.2.2c0 .2 0 .2.2.2s.2-.1.1-.2c0-.3-.2-.5-.5-.5a.3.3 0 0 0-.2.3v.5c.2.2.3.4.6.4.2 0 .3 0 .3-.2 0-.1 0-.2-.2-.2h-.1v.2m-1-.5v-.2h.3c0-.2-.2-.3-.3-.3-.2 0-.3.1-.3.2 0 .3 0 .5.2.7 0 .2.2.3.4.3l.2-.1c0-.1 0-.2-.2-.2h-.1v-.1c.1 0 .2 0 .1-.2h-.3m-.6-.3h.2c0-.2-.1-.3-.3-.3 0 0-.2 0-.2.2l.3.9s.1.1.2 0h.1c0-.3-.1-.5-.3-.8M0 .4C-.2.4-.3.4-.4.2l-.4.2-.4-.1-.3.1c-.2 0-.3 0-.4-.2v.1l-.3.1s-.2 0-.3-.2l-.3-.9c0-.2.1-.3.3-.3l.4.1h.9l.5.1.4-.2c.3 0 .5.3.6.7V0a.4.4 0 0 1-.3.4" fill="#171714"/>
</g>
</g>
</g>
<g id="g8901">
<g clip-path="url(#clipPath8907)" id="g8903">
<g transform="translate(295 91.5)" id="g8909">
<path id="path8911" d="M0 0v-.3h-.6l-.1-.1v-.4H0v-.4h-1l-.2.1h-.3l-.1-.1v-.5l.1-.1H.6V.5h-2.2v-.6h.5V0H0z" fill="#f2f2f2"/>
</g>
<g transform="translate(293 92)" id="g8913">
<path id="path8915" d="M0 0h-.5l-.1-.1-.6-1.3L-2 0h-.6v-.1l.9-2 .2-.1h.4l.1.1 1 2V0" fill="#f2f2f2"/>
</g>
<g transform="translate(290 91.1)" id="g8917">
<path id="path8919" d="M0 0h.1v-.4L0-.5h-1.5v-.3H0L.1-1v-.4h-2.2v2c0 .1 0 .2.1.1H.1V.4h-1.6V0z" fill="#f2f2f2"/>
</g>
<path id="path8921" d="M249 87h-13v7.9h13z" fill="#a9aba9"/>
<path id="path8923" d="M263.5 87h-12.9v7.9h12.9z"/>
<path id="path8925" d="M240.7 92.2h-1.3v1.4h1.3z"/>
<path id="path8927" d="M240.7 88.2h-1.3v1.4h1.3z"/>
<path id="path8929" d="M258.2 86h-14.5v9.9h14.5z"/>
<path id="path8931" d="M311.6 141h-5v9h5z" fill="#a9aba9"/>
<path id="path8933-4" d="M311.2 151.6h-4v9.3h4z"/>
<path id="path8935" d="M311.2 141.4h-.3v3h.3z"/>
<path id="path8937" d="M307.3 141.4h-.4v3h.4z"/>
<path id="path8939" d="M312.9 145h-7.3v12.2h7.3z"/>
<g transform="translate(309.2 158)" id="g8941">
<path id="path8943" d="M0 0v8.8h-36.4v-75.5h-15.1" fill="none" stroke="#000" stroke-width="2"/>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

252
docs/static/download/firmware.svg vendored Normal file
View File

@ -0,0 +1,252 @@
<svg xmlns="http://www.w3.org/2000/svg" width="261.3" height="109.3" viewBox="0 0 69.1 28.9" id="svg9461">
<defs id="defs9455">
<clipPath id="clipPath8689">
<path d="M0 1145.9h1366V0H0z" id="path8687"/>
</clipPath>
<clipPath id="clipPath8663">
<path d="M309.8 89.4h3.7v3.7h-3.7z" id="path8661"/>
</clipPath>
<clipPath id="clipPath8647">
<path d="M0 1145.9h1366V0H0z" id="path8645"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 .6661 -.32488 0 300.7 115)" id="linearGradient8637">
<stop offset="0" id="stop8633" stop-color="#757575"/>
<stop offset="1" id="stop8635" stop-color="#393939"/>
</linearGradient>
<clipPath id="clipPath8595">
<path d="M0 1145.9h1366V0H0z" id="path8593"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 12.8096 -17.18704 0 300.7 98.4)" id="linearGradient8585">
<stop offset="0" id="stop8579" stop-color="#6a6a6a"/>
<stop offset=".5" id="stop8581" stop-color="#48e400"/>
<stop offset="1" id="stop8583" stop-color="#6a6a6a"/>
</linearGradient>
<clipPath id="clipPath8561">
<path d="M0 1145.9h1366V0H0z" id="path8559"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -1.33016 5.597 0 300.7 88.4)" id="linearGradient8551">
<stop offset="0" id="stop8547" stop-color="#a9aba9"/>
<stop offset="1" id="stop8549" stop-color="#535453"/>
</linearGradient>
<clipPath id="clipPath8525">
<path d="M0 1145.9h1366V0H0z" id="path8523"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -.56074 .70884 0 300.7 115.6)" id="linearGradient8515">
<stop offset="0" id="stop8511" stop-color="#a9aba9"/>
<stop offset="1" id="stop8513" stop-color="#818181"/>
</linearGradient>
<clipPath id="clipPath8493">
<path d="M0 1145.9h1366V0H0z" id="path8491"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.39765 2.48247 0 300.7 98.1)" id="linearGradient8483">
<stop offset="0" id="stop8479" stop-color="#f2f2f2"/>
<stop offset="1" id="stop8481" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath8449">
<path d="M0 1145.9h1366V0H0z" id="path8447"/>
</clipPath>
<clipPath id="clipPath8977">
<path d="M0 1145.9h1366V0H0z" id="path8975"/>
</clipPath>
<clipPath id="clipPath8951">
<path d="M593 101h3.6v3.7H593z" id="path8949"/>
</clipPath>
<clipPath id="clipPath8935">
<path d="M0 1145.9h1366V0H0z" id="path8933"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 .67046 -.32706 0 583.8 126.8)" id="linearGradient8925">
<stop offset="0" id="stop8921" stop-color="#757575"/>
<stop offset="1" id="stop8923" stop-color="#393939"/>
</linearGradient>
<clipPath id="clipPath8883">
<path d="M0 1145.9h1366V0H0z" id="path8881"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 12.89405 -17.29507 0 583.7 110)" id="linearGradient8873">
<stop offset="0" id="stop8867" stop-color="#6a6a6a"/>
<stop offset=".5" id="stop8869" stop-color="#48e400"/>
<stop offset="1" id="stop8871" stop-color="#6a6a6a"/>
</linearGradient>
<clipPath id="clipPath8849">
<path d="M0 1145.9h1366V0H0z" id="path8847"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -1.33884 5.6329 0 583.7 100)" id="linearGradient8839">
<stop offset="0" id="stop8835" stop-color="#a9aba9"/>
<stop offset="1" id="stop8837" stop-color="#535453"/>
</linearGradient>
<clipPath id="clipPath8813">
<path d="M0 1145.9h1366V0H0z" id="path8811"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -.56429 .71345 0 583.7 127.4)" id="linearGradient8803">
<stop offset="0" id="stop8799" stop-color="#a9aba9"/>
<stop offset="1" id="stop8801" stop-color="#818181"/>
</linearGradient>
<clipPath id="clipPath8781">
<path d="M0 1145.9h1366V0H0z" id="path8779"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.41323 2.4988 0 583.7 109.8)" id="linearGradient8771">
<stop offset="0" id="stop8767" stop-color="#f2f2f2"/>
<stop offset="1" id="stop8769" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath8737">
<path d="M0 1145.9h1366V0H0z" id="path8735"/>
</clipPath>
</defs>
<g id="layer1" transform="translate(0 -268)">
<g id="g10860" transform="translate(-20.8 -2)">
<g transform="matrix(.35278 0 0 -.35278 62.8 291.4)" id="g8727">
<path id="path8729" d="M0 0h24" fill="none" stroke="#000" stroke-width="2"/>
</g>
<g id="g8731" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g clip-path="url(#clipPath8737)" id="g8733">
<g transform="translate(458 159.9)" id="g8739">
<path id="path8741" d="M0 0h83a4 4 0 0 0 4-4v-52.5H-4V-4a4 4 0 0 0 4 4" fill="#e6e6e6"/>
</g>
<g transform="translate(458 158.4)" id="g8743">
<path id="path8745" d="M0 0h83c1.3 0 2.4-1.1 2.4-2.5V-52c0-.9-.6-1.5-1.5-1.5H-1c-.8 0-1.5.6-1.5 1.5v49.5C-2.5-1.1-1.4 0 0 0z" fill="none" stroke="#282828" stroke-width="3"/>
</g>
<g transform="translate(445 102.9)" id="g8747">
<path id="path8749" d="M0 0h108.8v-1.2a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3z" fill="#626262"/>
</g>
<g transform="translate(489.8 102.9)" id="g8751">
<path id="path8753" d="M0 0h19.3c0-.8-.6-1.4-1.4-1.4H1.4C.6-1.4 0-.8 0 0" fill="#818181"/>
</g>
</g>
</g>
<g id="g8755" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g id="g8757">
<g id="g8763">
<g id="g8765">
<path id="path8773" d="M567.9 139.7a.6.6 0 0 1-.6-.6v-30.6c0-.3.2-.6.6-.6h31.7c.3 0 .5.3.5.6v30.6c0 .3-.2.6-.5.6z" fill="url(#linearGradient8771)"/>
</g>
</g>
</g>
</g>
<g id="g8775" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g clip-path="url(#clipPath8781)" id="g8777">
<g transform="translate(569.7 111.2)" id="g8783">
<path id="path8785" d="M0 0h28c.3 0 .6-.3.6-.6V-12c0-.4-.3-.6-.6-.6H0c-.3 0-.6.2-.6.6V-.6c0 .3.3.6.6.6" fill="#f2f2f2"/>
</g>
</g>
</g>
<g id="g8787" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g id="g8789">
<g id="g8795">
<g id="g8797">
<path id="path8805" d="M569.4 149.1a.6.6 0 0 1-.6-.6v-22.3c0-.3.3-.6.6-.6H598c.3 0 .6.3.6.6v22.3c0 .3-.3.6-.6.6z" fill="url(#linearGradient8803)"/>
</g>
</g>
</g>
</g>
<g id="g8807" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g clip-path="url(#clipPath8813)" id="g8809">
<g transform="translate(572.7 146)" id="g8815">
<path id="path8817" d="M0 0h22.1c.6 0 1.1-.5 1.1-1.1v-12.5c0-.6-.5-1-1-1H0c-.6 0-1.1.4-1.1 1V-1c0 .5.5 1 1.1 1" fill="#393939"/>
</g>
<g transform="translate(574.4 145.4)" id="g8819">
<path id="path8821" d="M0 0h18.8c.4 0 .8-.4.8-.8v-12c0-.4-.4-.8-.8-.8H0c-.4 0-.8.4-.8.8v12c0 .4.4.8.8.8" fill="#98b6a7"/>
</g>
</g>
</g>
<g id="g8823" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g id="g8825">
<g id="g8831">
<g id="g8833">
<path id="path8841" d="M569.1 105.6v-6.4c0-.3.3-.6.6-.6h28c.3 0 .6.3.6.6v6.4z" fill="url(#linearGradient8839)"/>
</g>
</g>
</g>
</g>
<g id="g8843" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g clip-path="url(#clipPath8849)" id="g8845">
<g transform="translate(581.7 109.3)" id="g8851">
<path id="path8853" d="M0 0l-4.2 4.2v.6h-1a2.5 2.5 0 0 0 0 4.9h1v.5L0 14.5h4l4.2-4.2v-.6h1a2.5 2.5 0 0 0 0-5h-1v-.5L4.2 0z" fill="#6a6a6a"/>
</g>
</g>
</g>
<g id="g8855" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g id="g8857">
<g id="g8863">
<g id="g8865">
<path id="path8875" d="M581.7 123.8l-4.2-4.2v-.6h-1a2.5 2.5 0 1 1 0-5v.1h1v-.5l4.2-4.3h4.2l4.2 4.3v.5h1a2.5 2.5 0 0 1-.1 4.9h-1v.7l-4.1 4.1z" fill="url(#linearGradient8873)"/>
</g>
</g>
</g>
</g>
<g id="g8877" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g clip-path="url(#clipPath8883)" id="g8879">
<g transform="translate(576.4 118.4)" id="g8885">
<path id="path8887" d="M0 0h3v-3.6H0A1.8 1.8 0 1 0 0 0" fill="#a9aba9"/>
</g>
<g transform="translate(591 114.8)" id="g8889">
<path id="path8891" d="M0 0h-3v3.6h3A1.8 1.8 0 1 0 0 0" fill="#a9aba9"/>
</g>
<g transform="translate(582 118.4)" id="g8893">
<path id="path8895" d="M0 0h3.6v-3.6H-.1V0H0" fill="#393939"/>
</g>
<g transform="translate(581.9 123.2)" id="g8897">
<path id="path8899" d="M0 0h3.8l2.8-2.9L5.5-4v-2H4.3v1c0 .5-.4 1-1 1h-3a.7.7 0 0 1-.8-.8v-1.4h-1V-4l-1.2 1.2z" fill="#a9aba9"/>
</g>
<g transform="translate(585.6 110)" id="g8901">
<path id="path8903" d="M0 0h-3.8l-2.8 2.9 1.2 1.2v2h1V5c0-.5.5-1 1-1h3.2c.5 0 .8.4.8.8v1.4h1.1V4l1.2-1.2z" fill="#a9aba9"/>
</g>
<path id="path8905" d="M583.3 131.4h.9v-4.1h-.9z" fill="#393939"/>
<path id="path8907" d="M583.3 127.4h.9v-1.8h-.9z" fill="#9b9b9b"/>
</g>
</g>
<g id="g8909" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g id="g8911">
<g id="g8917">
<g id="g8919">
<path id="path8927" d="M583.3 125.6h.9v1.8h-.9z" fill="url(#linearGradient8925)"/>
</g>
</g>
</g>
</g>
<g id="g8929" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g clip-path="url(#clipPath8935)" id="g8931">
<path id="path8937" d="M583.3 125.6h.9v-1.8h-.9z" fill="#818181"/>
<g transform="translate(571.2 125.6)" id="g8939">
<path id="path8941" d="M0 0h7v-1.7L5.3-3.5H.6c-.3 0-.6.3-.6.6z" fill="#a9aba9"/>
</g>
<path id="path8943" d="M593 104.7h3.6V101H593z" fill="#fff"/>
</g>
</g>
<g id="g8945" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g clip-path="url(#clipPath8951)" id="g8947">
<g transform="translate(596.4 103.2)" id="g8953">
<path id="path8955" d="M0 0v-.3C-.3-.8-.4-1-.8-1l-.3.2a.6.6 0 0 0-.5-.2c-.1 0-.2 0-.3.2C-2-1-2.1-1-2.2-1h-.6a.3.3 0 0 0-.3.2l.3 1h.5l.5.2.2-.1h.4c.1.1.3 0 .4 0V.1l.4.2.3-.1L0 0m-3.4-2.1H.2v3.6h-3.6z" fill="#fe0"/>
</g>
<g transform="translate(596.5 103)" id="g8957">
<path id="path8959" d="M0 0c0-.2 0-.3-.2-.5 0-.2-.3-.4-.6-.4l-.4.1a.7.7 0 0 0-.4-.1H-2a.7.7 0 0 0-.4 0H-3c-.2 0-.3.1-.4.3 0 .4.2.7.4 1 0 .2.2.2.4.2h2.1L0 .5V0m-3.5-2H.1v3.6h-3.6z" fill="#d52715"/>
</g>
<path id="path8961" d="M596.6 101H593v3.6h3.6zm-3.7 0h3.7v3.7H593z" fill="#171714"/>
<g transform="translate(596.5 103.7)" id="g8963">
<path id="path8965" d="M0 0v-.2.2m0 0v-.2.1m0 0zm0 0z" fill="#171714"/>
</g>
<g transform="translate(596 103.2)" id="g8967">
<path id="path8969" d="M0 0a3 3 0 0 0-.2-.6h-.1c0 .2 0 .4.2.6H0m.3-.2L0-.6C0-.8-.2-1-.3-1c-.2 0-.3 0-.3.3l.1.4c.1.3.2.5.5.5s.3-.3.3-.5M-1 .1V0l-.3-.5.1-.1.2.2c0 .2 0 .2.2.2s.2-.1.1-.2c0-.3-.2-.5-.5-.5a.3.3 0 0 0-.3.3l.2.5c0 .2.2.4.5.4.2 0 .3 0 .3-.2 0-.1 0-.2-.2-.2h-.1v.2m-1-.5v-.2h.3c0-.2-.2-.3-.3-.3-.2 0-.3.1-.3.2 0 .3 0 .5.2.7 0 .2.2.3.4.3l.2-.1c0-.2 0-.2-.2-.2h-.1v-.1c.1 0 .2 0 .1-.2l-.3-.1m-.6-.2h.2c0-.2-.1-.3-.3-.3 0 0-.2 0-.2.2l.3.9s.1.1.2 0h.1c0-.3-.2-.5-.3-.8M0 .4C-.2.4-.3.4-.4.2l-.4.2-.4-.1-.3.1c-.2 0-.3 0-.4-.2v.1l-.3.1c-.1 0-.2 0-.3-.2-.1-.3-.3-.6-.3-1 0 0 .1-.2.3-.2l.3.1c.1 0 .2-.1.4 0h.6l.5.1.4-.2c.3 0 .5.3.6.6V0a.4.4 0 0 1-.3.4" fill="#171714"/>
</g>
</g>
</g>
<g id="g8971" transform="matrix(.35278 0 0 -.35278 -129 330.1)">
<g clip-path="url(#clipPath8977)" id="g8973">
<g transform="translate(578 103)" id="g8979">
<path id="path8981" d="M0 0v-.3h-.6l-.1-.1v-.4H0v-.4h-1l-.2.2h-.3l-.1-.1v-.6H.7V.5h-2.3v-.6h.5V0H0z" fill="#f2f2f2"/>
</g>
<g transform="translate(576 103.6)" id="g8983">
<path id="path8985" d="M0 0h-.5l-.1-.1-.6-1.3L-2-.1V0h-.5s-.1 0 0-.1l.9-2 .2-.1h.5l1 2L0 0" fill="#f2f2f2"/>
</g>
<g transform="translate(573 102.8)" id="g8987">
<path id="path8989" d="M0 0h.1v-.4L0-.5h-1.5v-.3H0L.1-1v-.4h-2.2v2l.1.2H.1V.4h-1.6V0z" fill="#f2f2f2"/>
</g>
<g transform="translate(583.5 136.6)" id="g8991">
<path id="path8993" d="M0 0l-.8 1.3-1.4-2.9 4-1c-.5.5-.5.7-.9 1.3.5.1 1 .4 1.4.7.8.4 1.5 1 2 1.9a4 4 0 0 1-.6 3.6c-.4 0-.8 0-1.3-.2C3.5 3 3.5 1 0 0" fill="#303030"/>
</g>
<g transform="translate(583.1 141.4)" id="g8995">
<path id="path8997" d="M0 0l.8-1.2 1.4 2.8-3.8 1 .7-1.3-1.3-.7a4.5 4.5 0 0 1-2-2c-.4-1-.2-2.4.5-3.4.4 0 .8 0 1.2.2C-3.3-3-3.3-1 0 0" fill="#303030"/>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

327
docs/static/download/transfer.svg vendored Normal file
View File

@ -0,0 +1,327 @@
<svg xmlns="http://www.w3.org/2000/svg" width="261.3" height="109.3" viewBox="0 0 69.1 28.9" id="svg9461">
<defs id="defs9455">
<clipPath id="clipPath8689">
<path d="M0 1145.9h1366V0H0z" id="path8687"/>
</clipPath>
<clipPath id="clipPath8663">
<path d="M309.8 89.4h3.7v3.7h-3.7z" id="path8661"/>
</clipPath>
<clipPath id="clipPath8647">
<path d="M0 1145.9h1366V0H0z" id="path8645"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 .6661 -.32488 0 300.7 115)" id="linearGradient8637">
<stop offset="0" id="stop8633" stop-color="#757575"/>
<stop offset="1" id="stop8635" stop-color="#393939"/>
</linearGradient>
<clipPath id="clipPath8595">
<path d="M0 1145.9h1366V0H0z" id="path8593"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 12.8096 -17.18704 0 300.7 98.4)" id="linearGradient8585">
<stop offset="0" id="stop8579" stop-color="#6a6a6a"/>
<stop offset=".5" id="stop8581" stop-color="#48e400"/>
<stop offset="1" id="stop8583" stop-color="#6a6a6a"/>
</linearGradient>
<clipPath id="clipPath8561">
<path d="M0 1145.9h1366V0H0z" id="path8559"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -1.33016 5.597 0 300.7 88.4)" id="linearGradient8551">
<stop offset="0" id="stop8547" stop-color="#a9aba9"/>
<stop offset="1" id="stop8549" stop-color="#535453"/>
</linearGradient>
<clipPath id="clipPath8525">
<path d="M0 1145.9h1366V0H0z" id="path8523"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -.56074 .70884 0 300.7 115.6)" id="linearGradient8515">
<stop offset="0" id="stop8511" stop-color="#a9aba9"/>
<stop offset="1" id="stop8513" stop-color="#818181"/>
</linearGradient>
<clipPath id="clipPath8493">
<path d="M0 1145.9h1366V0H0z" id="path8491"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.39765 2.48247 0 300.7 98.1)" id="linearGradient8483">
<stop offset="0" id="stop8479" stop-color="#f2f2f2"/>
<stop offset="1" id="stop8481" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath8449">
<path d="M0 1145.9h1366V0H0z" id="path8447"/>
</clipPath>
<clipPath id="clipPath8977">
<path d="M0 1145.9h1366V0H0z" id="path8975"/>
</clipPath>
<clipPath id="clipPath8951">
<path d="M593 101h3.6v3.7H593z" id="path8949"/>
</clipPath>
<clipPath id="clipPath8935">
<path d="M0 1145.9h1366V0H0z" id="path8933"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 .67046 -.32706 0 583.8 126.8)" id="linearGradient8925">
<stop offset="0" id="stop8921" stop-color="#757575"/>
<stop offset="1" id="stop8923" stop-color="#393939"/>
</linearGradient>
<clipPath id="clipPath8883">
<path d="M0 1145.9h1366V0H0z" id="path8881"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 12.89405 -17.29507 0 583.7 110)" id="linearGradient8873">
<stop offset="0" id="stop8867" stop-color="#6a6a6a"/>
<stop offset=".5" id="stop8869" stop-color="#48e400"/>
<stop offset="1" id="stop8871" stop-color="#6a6a6a"/>
</linearGradient>
<clipPath id="clipPath8849">
<path d="M0 1145.9h1366V0H0z" id="path8847"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -1.33884 5.6329 0 583.7 100)" id="linearGradient8839">
<stop offset="0" id="stop8835" stop-color="#a9aba9"/>
<stop offset="1" id="stop8837" stop-color="#535453"/>
</linearGradient>
<clipPath id="clipPath8813">
<path d="M0 1145.9h1366V0H0z" id="path8811"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -.56429 .71345 0 583.7 127.4)" id="linearGradient8803">
<stop offset="0" id="stop8799" stop-color="#a9aba9"/>
<stop offset="1" id="stop8801" stop-color="#818181"/>
</linearGradient>
<clipPath id="clipPath8781">
<path d="M0 1145.9h1366V0H0z" id="path8779"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.41323 2.4988 0 583.7 109.8)" id="linearGradient8771">
<stop offset="0" id="stop8767" stop-color="#f2f2f2"/>
<stop offset="1" id="stop8769" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath8737">
<path d="M0 1145.9h1366V0H0z" id="path8735"/>
</clipPath>
<clipPath id="clipPath9285">
<path d="M0 1145.9h1366V0H0z" id="path9283"/>
</clipPath>
<clipPath id="clipPath9259">
<path d="M852.5 96.3h3.3v3.3h-3.3z" id="path9257"/>
</clipPath>
<clipPath id="clipPath9243">
<path d="M0 1145.9h1366V0H0z" id="path9241"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 .61565 -.3002 0 844 120)" id="linearGradient9233">
<stop offset="0" id="stop9229" stop-color="#757575"/>
<stop offset="1" id="stop9231" stop-color="#393939"/>
</linearGradient>
<clipPath id="clipPath9191">
<path d="M0 1145.9h1366V0H0z" id="path9189"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 11.84237 -15.8829 0 844 104.6)" id="linearGradient9181">
<stop offset="0" id="stop9175" stop-color="#6a6a6a"/>
<stop offset=".5" id="stop9177" stop-color="#48e400"/>
<stop offset="1" id="stop9179" stop-color="#6a6a6a"/>
</linearGradient>
<clipPath id="clipPath9157">
<path d="M0 1145.9h1366V0H0z" id="path9155"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -1.22922 5.1724 0 844 95.3)" id="linearGradient9147">
<stop offset="0" id="stop9143" stop-color="#a9aba9"/>
<stop offset="1" id="stop9145" stop-color="#535453"/>
</linearGradient>
<clipPath id="clipPath9121">
<path d="M0 1145.9h1366V0H0z" id="path9119"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -.51809 .65506 0 844 120.5)" id="linearGradient9111">
<stop offset="0" id="stop9107" stop-color="#a9aba9"/>
<stop offset="1" id="stop9109" stop-color="#818181"/>
</linearGradient>
<clipPath id="clipPath9089">
<path d="M0 1145.9h1366V0H0z" id="path9087"/>
</clipPath>
<linearGradient x2="1" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0 -2.21578 2.29436 0 844 104.3)" id="linearGradient9079">
<stop offset="0" id="stop9075" stop-color="#f2f2f2"/>
<stop offset="1" id="stop9077" stop-color="#7a7a7a"/>
</linearGradient>
<clipPath id="clipPath9009">
<path d="M0 1145.9h1366V0H0z" id="path9007"/>
</clipPath>
<clipPath id="clipPath9041">
<path d="M779.5 134.7h16.7v-12.6h-16.7z" id="path9039"/>
</clipPath>
<clipPath id="clipPath9045">
<path d="M779.5 134.7h16.7v-12.6h-16.7z" id="path9043"/>
</clipPath>
</defs>
<g id="layer1" transform="translate(0 -268)">
<g id="g8999" transform="matrix(.35278 0 0 -.35278 40.2 289.4)">
<path d="M0 0h40" id="path9001" fill="none" stroke="#000" stroke-width="2"/>
</g>
<g id="g9011" transform="matrix(.35278 0 0 -.35278 10.4 271.7)">
<path d="M0 0h83a4 4 0 0 0 4-4v-52.5H-4V-4a4 4 0 0 0 4 4" id="path9013" fill="#e6e6e6"/>
</g>
<g id="g9015" transform="matrix(.35278 0 0 -.35278 10.4 272.3)">
<path d="M0 0h83c1.3 0 2.4-1.1 2.4-2.5V-52c0-.9-.6-1.5-1.5-1.5H-1c-.8 0-1.5.6-1.5 1.5v49.5C-2.5-1.1-1.4 0 0 0z" id="path9017" fill="none" stroke="#282828" stroke-width="3"/>
</g>
<g id="g9019" transform="matrix(.35278 0 0 -.35278 5.8 291.9)">
<path d="M0 0h108.8v-1.2a3 3 0 0 0-3-3H3a3 3 0 0 0-3 3z" id="path9021" fill="#626262"/>
</g>
<g id="g9023" transform="matrix(.35278 0 0 -.35278 21.6 291.9)">
<path d="M0 0h19.3c0-.8-.6-1.4-1.4-1.4H1.4C.6-1.4 0-.8 0 0" id="path9025" fill="#818181"/>
</g>
<g id="g9027" transform="matrix(.35278 0 0 -.35278 45 286.7)">
<path d="M0 0l-28-5.4-7.6 39 20 3.9c3.9-2.4 8-4.7 9.4-5.4z" id="path9029" fill="#fff"/>
</g>
<g id="g9031" transform="matrix(.35278 0 0 -.35278 45.4 287)">
<path d="M0 0l-30-5.8-8 41 21.5 4.1c4.7-2.8 10-5.7 10-5.7zm-2.3 1.6l-6 30.7c-1.6.8-5.2 2.8-8.6 4.9l-18.7-3.6 7.2-37 26 5" id="path9033" fill="#303030"/>
</g>
<g id="g9035" transform="matrix(.35278 0 0 -.35278 -239.7 326.4)">
<g id="g9061">
<g clip-path="url(#clipPath9041)" id="g9059">
<g id="g9057">
<g id="g9055">
<g clip-path="url(#clipPath9045)" id="g9053">
<g aria-label=".uf2" transform="scale(1 -1) rotate(-11 -255.3 -4117.6)" style="-inkscape-font-specification:LEGOChalet60-Bold" id="text9051" font-weight="700" font-size="9" font-family="LEGO Chalet 60" fill="#303030">
<path d="M2.4 0H.8v-1.7h1.6z" id="path12451"/>
<path d="M7.6 0H6.1v-.5l-.9.5-.8.1Q3.6.1 3-.3q-.4-.5-.4-1.4V-5h1.6v3l.1.4q0 .2.3.3h.9l.5-.2V-5h1.5z" id="path12453"/>
<path d="M11.1-5.7H9.7q-.2.2-.2.7h1.3v1.1H9.6V0H8v-3.9h-.7v-1H8v-.2q0-.9.5-1.3Q9-7 10-7h.6l.5.1z" id="path12455"/>
<path d="M16 0h-5.2v-1L12-2l1-.8q.5-.5.7-1 .2-.3.2-.7 0-.4-.3-.7-.3-.2-.8-.2l-.9.2-.8.4H11v-1.5l.9-.2 1.2-.2q1.2 0 1.9.5.6.6.6 1.5 0 .6-.3 1.2-.3.5-1 1.1l-.7.7-.6.4h3z" id="path12457"/>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9063">
<g id="g9065">
<g id="g9071">
<g id="g9073">
<path d="M829.4 131.8a.5.5 0 0 1-.5-.6v-28c0-.3.2-.6.5-.6h29.1c.3 0 .6.3.6.6v28c0 .3-.3.6-.6.6z" id="path9081" fill="url(#linearGradient9079)"/>
</g>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9083">
<g id="g9085" clip-path="url(#clipPath9089)">
<g id="g9091" transform="translate(831.1 105.6)">
<path d="M0 0h25.7c.3 0 .6-.2.6-.5V-11c0-.3-.3-.6-.6-.6H0c-.3 0-.5.3-.5.6V-.5c0 .3.2.5.5.5" id="path9093" fill="#f2f2f2"/>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9095">
<g id="g9097">
<g id="g9103">
<g id="g9105">
<path d="M830.9 140.4a.5.5 0 0 1-.6-.5v-20.5c0-.3.3-.6.6-.6H857c.3 0 .5.3.5.6v20.5c0 .3-.2.5-.5.5z" id="path9113" fill="url(#linearGradient9111)"/>
</g>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9115">
<g id="g9117" clip-path="url(#clipPath9121)">
<g id="g9123" transform="translate(833.9 137.6)">
<path d="M0 0h20.3c.6 0 1-.5 1-1v-11.4c0-.6-.4-1-1-1H0a1 1 0 0 0-1 1V-1c0 .5.4 1 1 1" id="path9125" fill="#393939"/>
</g>
<g id="g9127" transform="translate(835.4 137)">
<path d="M0 0h17.2c.5 0 .8-.3.8-.7v-11c0-.5-.3-.8-.8-.8H0c-.4 0-.7.3-.7.8v11c0 .4.3.7.7.7" id="path9129" fill="#98b6a7"/>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9131">
<g id="g9133">
<g id="g9139">
<g id="g9141">
<path d="M830.6 100.4v-5.8c0-.3.2-.5.5-.5h25.7c.3 0 .6.2.6.5v5.8z" id="path9149" fill="url(#linearGradient9147)"/>
</g>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9151">
<g id="g9153" clip-path="url(#clipPath9157)">
<g id="g9159" transform="translate(842.2 103.9)">
<path d="M0 0l-3.9 3.9v.5h-1a2.3 2.3 0 1 0 0 4.5h1v.5l3.9 4h3.8c1.7-1.9 3.9-4 3.9-4V9h.8a2.3 2.3 0 0 0 0-4.5h-.8V4L3.8 0z" id="path9161" fill="#6a6a6a"/>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9163">
<g id="g9165">
<g id="g9171">
<g id="g9173">
<path d="M842.1 117.2l-3.8-3.9v-.5h-1a2.3 2.3 0 1 1 0-4.5h1v-.5l3.9-3.9h3.8l3.8 3.9v.5h1c1.1 0 2 1 2.1 2.2 0 1.2-1 2.3-2.2 2.3h-.9v.6l-3.8 3.8z" id="path9183" fill="url(#linearGradient9181)"/>
</g>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9185">
<g id="g9187" clip-path="url(#clipPath9191)">
<g id="g9193" transform="translate(837.3 112.3)">
<path d="M0 0h2.8v-3.4H0A1.7 1.7 0 0 0 0 0" id="path9195" fill="#a9aba9"/>
</g>
<g id="g9197" transform="translate(850.7 109)">
<path d="M0 0h-2.8v3.4H0A1.7 1.7 0 0 0 0 0" id="path9199" fill="#a9aba9"/>
</g>
<g id="g9201" transform="translate(842.4 112.3)">
<path d="M0 0h3.3v-3.3H-.1V0H0" id="path9203" fill="#393939"/>
</g>
<g id="g9205" transform="translate(842.3 116.6)">
<path d="M0 0h3.5L6-2.6 5-3.7v-2H4v1.2c0 .4-.4.8-.8.8h-3a.7.7 0 0 1-.7-.7v-1.3h-1v2l-1.1 1z" id="path9207" fill="#a9aba9"/>
</g>
<g id="g9209" transform="translate(845.8 104.6)">
<path d="M0 0h-3.5L-6 2.7l1.1 1v2h1V4.6c0-.5.4-.9.8-.9h3a.7.7 0 0 1 .8.7v1.3h1v-2l1-1z" id="path9211" fill="#a9aba9"/>
</g>
<path d="M843.6 124.1h.8v-3.7h-.8z" id="path9213" fill="#393939"/>
<path d="M843.6 120.5h.8V119h-.8z" id="path9215" fill="#9b9b9b"/>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9217">
<g id="g9219">
<g id="g9225">
<g id="g9227">
<path d="M843.6 118.8h.8v1.7h-.8z" id="path9235" fill="url(#linearGradient9233)"/>
</g>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9237">
<g id="g9239" clip-path="url(#clipPath9243)">
<path d="M843.6 118.8h.8v-1.6h-.8z" id="path9245" fill="#818181"/>
<g id="g9247" transform="translate(832.5 118.8)">
<path d="M0 0h6.5v-1.6L4.8-3.2H.5c-.3 0-.5.3-.5.6z" id="path9249" fill="#a9aba9"/>
</g>
<path d="M852.5 99.6h3.3v-3.3h-3.3z" id="path9251" fill="#fff"/>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9253">
<g id="g9255" clip-path="url(#clipPath9259)">
<g id="g9261" transform="translate(855.6 98.2)">
<path d="M0 0v-.3C-.3-.7-.4-1-.7-1-.9-1-1-1-1-.8a.5.5 0 0 0-.5-.2l-.3.1h-.8l-.3.1c0 .4.2.6.3 1h.5l.4.2.3-.1h.6V.2h.1l.4.2.2-.1V0m-3-2H.2v3.4H-3z" id="path9263" fill="#fe0"/>
</g>
<g id="g9265" transform="translate(855.7 98.1)">
<path d="M0 0l-.1-.4C-.2-.7-.5-1-.7-1c-.2 0-.3 0-.4.2a.6.6 0 0 0-.4-.2l-.3.1a.6.6 0 0 0-.3 0h-.6c-.2 0-.4 0-.4.3l.3.9.4.2.2-.1.4.1h.6l.4-.1h.7L0 0m-3.2-1.8H.1v3.3h-3.3z" id="path9267" fill="#d52715"/>
</g>
<path d="M855.8 96.3h-3.3v3.3h3.3zm-3.3 0h3.3v3.3h-3.3z" id="path9269" fill="#171714"/>
<g id="g9271" transform="translate(855.7 98.7)">
<path d="M0 0v-.2.2m0 0v-.1m0 0zm0 0z" id="path9273" fill="#171714"/>
</g>
<g id="g9275" transform="translate(855.3 98.2)">
<path d="M0 0l-.2-.5h-.1c0 .2 0 .4.2.5H0m.2-.1L.1-.6l-.4-.2c-.1 0-.3 0-.3.2l.1.5c.1.2.2.4.5.4s.3-.3.2-.4m-1 .2l-.3-.6.2.1v.1l.1.1c.2 0 .2-.1.2-.2 0-.2-.2-.4-.5-.4-.1 0-.2 0-.2.2V0c.2.2.3.4.6.4.1 0 .2 0 .2-.2L-.6 0s-.2 0-.1.1m-1-.4v-.1h.3c0-.2-.2-.3-.3-.3-.1 0-.2 0-.3.2l.2.7.4.2.2-.1c0-.1 0-.2-.2-.2l-.2-.1.3-.1c0-.2-.2-.2-.3-.1m-.6-.2h.2c0-.3-.2-.3-.3-.3 0 0-.2 0-.2.2 0 .3.2.5.3.8h.2c0-.2 0-.5-.2-.7M0 .4C-.2.4-.3.4-.4.2c-.1.2-.2.2-.4.2L-1 .3l-.3.1c-.1 0-.3 0-.4-.2v.1h-.5l-.3-1s.1-.2.3-.2l.3.1.3-.1.3.1.3-.1c.2 0 .3 0 .4.2l.4-.2c.3 0 .5.2.6.6V0a.3.3 0 0 1-.3.4" id="path9277" fill="#171714"/>
</g>
</g>
</g>
<g transform="matrix(.35278 0 0 -.35278 -239.7 326.4)" id="g9279">
<g id="g9281" clip-path="url(#clipPath9285)">
<g id="g9287" transform="translate(838.7 98.2)">
<path d="M0 0v-.3h-.5l-.1-.1v-.4H0v-.3h-1v.2h-.4v-.6h2V.4h-2v-.5h.4V0h1z" id="path9289" fill="#f2f2f2"/>
</g>
<g id="g9291" transform="translate(836.9 98.7)">
<path d="M0 0h-.4l-.2-.1-.5-1.2-.6 1.2-.1.1h-.5v-.1l.8-1.8.2-.1h.5l.9 2H0" id="path9293" fill="#f2f2f2"/>
</g>
<g id="g9295" transform="translate(834.2 97.9)">
<path d="M0 0h.1v-.4h-1.5v-.4H0L.1-1v-.3H-2v2h2V.3h-1.5V0z" id="path9297" fill="#f2f2f2"/>
</g>
<g id="g9299" transform="translate(820.8 131.1)">
<path d="M0 0l-1.9-2.9 7.3-1C4.3 1.3 4 1.7 3.4 5.2l-2-3a39.5 39.5 0 0 1-4.1 3.2c-1.4.8-3 1.3-4.7 1.5-2.1 0-4.3-.2-6.4-.8l.1-3.3C-9 4.8-3.5 3.8 0 0" id="path9301" fill="#303030"/>
</g>
<g id="g9303" transform="translate(767 107.4)">
<path d="M0 0c1.6 2.3 3.8 4 6.4 5" id="path9305" fill="none" stroke="#303030"/>
</g>
<g id="g9307" transform="translate(766.2 110.4)">
<path d="M0 0c1.6 2.3 3.8 4 6.4 5" id="path9309" fill="none" stroke="#303030"/>
</g>
<g id="g9311" transform="translate(765.6 113.3)">
<path d="M0 0c1.6 2.3 3.8 4 6.4 5" id="path9313" fill="none" stroke="#303030"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 17 KiB

4
docs/static/filelogo.svg vendored Normal file
View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path fill="#aa278f" d="M32 15.994v-.011c0-.108-.005-.209-.016-.303h-.001c-.032-.285-.112-.504-.239-.656-.171-.204-.459-.435-.864-.691a4.275 4.275 0 0 1-.986-.827c-.252-.296-.442-.734-.57-1.316-.049-.227-.087-.719-.112-1.473V8.696c0-.38-.031-.723-.076-1.049a12.313 12.313 0 0 0-.004-.188c-.009-.782-.18-1.475-.513-2.078a3.462 3.462 0 0 0-1.416-1.401c-.611-.33-1.305-.495-2.081-.495H6.271s-.674.067-.962.201a4.021 4.021 0 0 0-.521.295 3.502 3.502 0 0 0-.798.59c-.693.688-1.061 1.601-1.113 2.734a9.172 9.172 0 0 0-.088 1.283v2.558a6.802 6.802 0 0 1-.183 1.373 2.311 2.311 0 0 1-.532 1.033 2.67 2.67 0 0 0-.202.196c-.265.238-.638.511-1.13.823-.404.262-.64.633-.715 1.108l-.002.023a2.195 2.195 0 0 0-.023.287L0 16.006v.011c0 .108.005.209.016.303h.001c.032.285.112.504.239.656.171.204.459.435.864.691.406.256.735.532.986.827.252.296.442.734.57 1.316.049.227.087.719.112 1.473v2.019c0 .38.031.723.076 1.049l.004.188c.009.782.18 1.475.513 2.078a3.462 3.462 0 0 0 1.416 1.401c.611.33 1.305.495 2.081.495H25.73c.35 0 .673-.067.961-.201.184-.085.356-.187.521-.296.291-.159.559-.353.798-.59.693-.688 1.061-1.601 1.113-2.734.056-.398.088-.823.088-1.283v-2.558c.019-.495.079-.953.183-1.373.104-.419.282-.762.532-1.033a2.67 2.67 0 0 0 .202-.196c.265-.238.638-.511 1.13-.823.404-.262.64-.633.715-1.108h.002l.002-.023c.013-.092.022-.187.023-.287v-.014z"/>
<path fill="#fff" d="M27.366 16.522l.819-.518-.821-.516a4.547 4.547 0 0 1-.927-.744 3.033 3.033 0 0 1-.554-.896 5.166 5.166 0 0 1-.328-1.339 16.319 16.319 0 0 1-.103-1.961c0-.781-.016-1.365-.05-1.786-.039-.489-.123-.852-.258-1.112a1.36 1.36 0 0 0-.718-.661c-.223-.089-.527-.154-.924-.199a.532.532 0 0 1-.356-.213c-.11-.133-.165-.344-.165-.627 0-.41.086-.811 1.121-.811.636 0 1.196.127 1.666.376.464.247.818.589 1.085 1.046.267.458.406.995.413 1.597.064 3.554.129 4.265.184 4.492.153.63.382 1.109.701 1.464.287.319.635.602 1.035.843.29.175.501.341.627.493.035.043.116.181.116.554 0 .383-.12.628-.39.794-.606.373-1.041.699-1.331.997a2.734 2.734 0 0 0-.678 1.24c-.112.437-.177 1.05-.198 1.875-.02.773-.042 1.741-.066 2.904-.021.941-.306 1.668-.873 2.222-.568.554-1.317.823-2.291.823-.409 0-.71-.077-.895-.23-.155-.128-.226-.32-.226-.604 0-.179.03-.336.093-.479a.682.682 0 0 1 .188-.268.463.463 0 0 1 .24-.094c.414-.055.725-.127.951-.219.317-.131.567-.378.723-.716.124-.269.2-.625.233-1.089.029-.402.044-.968.044-1.725.016-1.061.077-1.896.182-2.481.095-.53.274-.987.533-1.359.261-.375.665-.736 1.198-1.073zm-16.618 6.519h10.458a.75.75 0 0 0 .751-.751l-.001-3.709c-.134-.449-.518-.492-.878-.15-.033 0-.393.443-1.22.443a2.033 2.033 0 0 1-1.944-1.715h-.011a6.59 6.59 0 0 1 0-.526h.011a2.03 2.03 0 0 1 1.944-1.715c.827 0 1.187.443 1.22.443.35.332.738.252.879-.147l.001-3.432a.769.769 0 0 0-.562-.741c-.061.016-3.259 0-3.259 0-.786.065-1.063-.466-.624-.928 0-.033.443-.393.443-1.22a2.033 2.033 0 0 0-1.715-1.944v-.011a6.59 6.59 0 0 0-.526 0v.011A2.03 2.03 0 0 0 14 8.893c0 .827.443 1.187.443 1.22.439.462.254.97-.624.928 0 0-3.198.016-3.259 0a.77.77 0 0 0-.562.741V22.29a.75.75 0 0 0 .75.751zm-6.197-3.692c.055.227.12.938.184 4.492.007.602.146 1.138.413 1.597.267.458.622.8 1.085 1.046.47.25 1.03.376 1.666.376 1.035 0 1.121-.4 1.121-.811 0-.283-.056-.493-.165-.627a.537.537 0 0 0-.356-.213c-.397-.045-.701-.11-.925-.199a1.367 1.367 0 0 1-.718-.661c-.135-.259-.219-.623-.258-1.112a24.159 24.159 0 0 1-.05-1.786c0-.751-.035-1.41-.103-1.961a5.174 5.174 0 0 0-.329-1.339 3.028 3.028 0 0 0-.554-.896 4.52 4.52 0 0 0-.927-.744l-.821-.516.819-.518c.533-.337.936-.698 1.199-1.075.259-.372.438-.829.533-1.359.105-.585.166-1.419.182-2.481 0-.757.014-1.323.044-1.725.033-.464.109-.82.233-1.089.156-.337.406-.584.723-.715.226-.092.537-.163.951-.219a.463.463 0 0 0 .24-.094.662.662 0 0 0 .189-.267 1.18 1.18 0 0 0 .093-.479c0-.284-.072-.476-.226-.604-.186-.153-.487-.23-.895-.23-.974 0-1.723.269-2.291.823-.567.554-.852 1.281-.873 2.222a588.806 588.806 0 0 1-.065 2.904c-.021.825-.086 1.438-.198 1.875a2.731 2.731 0 0 1-.679 1.24c-.289.298-.725.624-1.331.997-.27.166-.39.41-.39.794 0 .373.081.511.116.554.127.153.338.319.627.493.4.24.748.524 1.035.843.319.355.548.834.701 1.464z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
docs/static/hero.png vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 585 KiB

BIN
docs/static/lessons/line-detection.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
docs/static/lessons/make-it-move.jpg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -8,7 +8,7 @@ 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.editor.initExtensionsAsync = function (opts: pxt.editor.ExtensionOptions): Promise<pxt.editor.ExtensionResult> {
pxt.debug('loading pxt-ev3 target extensions...')
updateBlocklyShape();
const res: pxt.editor.ExtensionResult = {
@ -28,7 +28,95 @@ pxt.editor.initExtensionsAsync = function(opts: pxt.editor.ExtensionOptions): Pr
selector: "turnratio",
editor: FieldTurnRatio
}],
deployCoreAsync
deployCoreAsync,
showUploadInstructionsAsync: (fn: string, url: string, confirmAsync: (options: any) => Promise<number>) => {
let resolve: (thenableOrResult?: void | PromiseLike<void>) => void;
let reject: (error: any) => void;
const deferred = new Promise<void>((res, rej) => {
resolve = res;
reject = rej;
});
const boardName = pxt.appTarget.appTheme.boardName || "???";
const boardDriveName = pxt.appTarget.appTheme.driveDisplayName || pxt.appTarget.compile.driveName || "???";
// https://msdn.microsoft.com/en-us/library/cc848897.aspx
// "For security reasons, data URIs are restricted to downloaded resources.
// Data URIs cannot be used for navigation, for scripting, or to populate frame or iframe elements"
const downloadAgain = !pxt.BrowserUtils.isIE() && !pxt.BrowserUtils.isEdge();
const docUrl = pxt.appTarget.appTheme.usbDocs;
const saveAs = pxt.BrowserUtils.hasSaveAs();
const htmlBody = `
<div class="ui three column grid stackable">
<div class="column">
<div class="ui">
<div class="image">
<img class="ui medium rounded image" src="./static/download/connect.svg" style="height:109px;width:261px;margin-bottom:1rem;">
</div>
<div class="content">
<div class="description">
<span class="ui yellow circular label">1</span>
<strong>${lf("Connect EV3 to computer with USB cable")}</strong>
<br/>
${lf("Use the miniUSB port on top of EV3 brick")}
</div>
</div>
</div>
</div>
<div class="column">
<div class="ui">
<div class="image">
<img class="ui medium rounded image" src="./static/download/firmware.svg" style="height:109px;width:261px;margin-bottom:1rem;">
</div>
<div class="content">
<div class="description">
<span class="ui blue circular label">2</span>
<strong>${lf("Make sure you have the latest EV3 firmware")}</strong>
<br/>
<a href="" target="_blank">${lf("Click here to update to latest firmware")}</a>
</div>
</div>
</div>
</div>
<div class="column">
<div class="ui">
<div class="image">
<img class="ui medium rounded image" src="./static/download/transfer.svg" style="height:109px;width:261px;margin-bottom:1rem;">
</div>
<div class="content">
<div class="description">
<span class="ui blue circular label">3</span>
${lf("Move the .uf2 file to EV3 brick")}
<br/>
${lf("Locate the downloaded .uf2 file and drag it to the EV3 drive")}
</div>
</div>
</div>
</div>
</div>`;
return confirmAsync({
header: lf("Download to your EV3"),
htmlBody,
hasCloseIcon: true,
hideCancel: true,
hideAgree: false,
agreeLbl: lf("I got it"),
buttons: [downloadAgain ? {
label: fn,
icon: "download",
class: "lightgrey focused",
url,
fileName: fn
} : undefined, docUrl ? {
label: lf("Help"),
icon: "help",
class: "lightgrey",
url: docUrl
} : undefined]
//timeout: 20000
}).then(() => { });
}
};
initAsync().catch(e => {
// probably no HID - we'll try this again upon deployment

View File

@ -0,0 +1,26 @@
{
"automation": "Automation, process control and robotic controllers",
"automation.Behavior": "A behavior",
"automation.Behavior.update": "Called on each behavior iteration even for suppresed behaviors",
"automation.Behavior.update|param|elapsed": "milli seconds since last call",
"automation.BehaviorManager": "A manager for behaviors",
"automation.BehaviorManager.add": "Adds a new behavior to the behavior manager",
"automation.BehaviorManager.add|param|behavior": "the behavior to add",
"automation.BehaviorManager.start": "Starts the behavior control loop",
"automation.BehaviorManager.stop": "Stops the execution loop",
"automation.PIDController": "A PID controller.\n* Reference: Feedback System, Karl Johan Astrom & Rickard M. Murry",
"automation.PIDController.compute": "Computes the output based on the system state",
"automation.PIDController.setControlSaturation": "Sets the control saturation values",
"automation.PIDController.setControlSaturation|param|high": "highest control value, eg: 100",
"automation.PIDController.setControlSaturation|param|low": "lowest control value, eg: -100",
"automation.PIDController.setDerivativeFilter": "Sets the derivative filter gain",
"automation.PIDController.setDerivativeFilter|param|N": "the filter gain, eg:10",
"automation.PIDController.setGains": "Sets the PID gains",
"automation.PIDController.setGains|param|b": "setpoint weight, eg: 0.9",
"automation.PIDController.setGains|param|kd": "derivative gain",
"automation.PIDController.setGains|param|ki": "integral gain",
"automation.PIDController.setGains|param|kp": "proportional gain",
"automation.PIDController.setPoint": "Updates the desired setpoint",
"automation.addBehavior": "Adds the behavior and starts it",
"automation.addBehavior|param|behavior": "a behavior"
}

View File

@ -0,0 +1,12 @@
{
"automation.PIDController.compute|block": "%pid|compute for timestep %timestep|(ms) at state %y",
"automation.PIDController.setControlSaturation|block": "set %pid|control saturation from %low|to %high",
"automation.PIDController.setDerivativeFilter|block": "set %pid|derivative filter %N",
"automation.PIDController.setGains|block": "set %pid|gains kp %kp|ki %ki|kd %kd",
"automation.PIDController.setPoint|block": "set %pid|point to %ysp",
"automation.addBehavior|block": "add behavior %behavior",
"automation|block": "automation",
"{id:category}Automation": "Automation",
"{id:group}Behaviors": "Behaviors",
"{id:group}PID": "PID"
}

View File

@ -1,6 +1,6 @@
{
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/behaviors",
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/automation",
"dependencies": {
"core": "file:../ev3"
"ev3": "file:../ev3"
}
}

View File

@ -134,7 +134,7 @@
"control.panic": "Display an error code and stop the program.",
"control.panic|param|code": "an error number to display. eg: 5",
"control.reset": "Reset the device.",
"control.runInBackground": "Run other code in the background.",
"control.runInParallel": "Run other code in the parallel.",
"control.waitForEvent": "Blocks the calling thread until the specified event is raised.",
"control.waitMicros": "Block the current fiber for the given microseconds",
"control.waitMicros|param|micros": "number of micro-seconds to wait. eg: 4",

View File

@ -25,10 +25,11 @@
"control.onEvent|block": "on event|from %src|with value %value",
"control.panic|block": "panic %code",
"control.reset|block": "reset",
"control.runInBackground|block": "run in background",
"control.runInParallel|block": "run in parallel",
"control.waitForEvent|block": "wait for event|from %src|with value %value",
"control.waitMicros|block": "wait (µs)%micros",
"control|block": "control",
"fieldeditors|block": "fieldeditors",
"loops.forever|block": "forever",
"loops.pause|block": "pause %pause=timePicker|ms",
"loops|block": "loops",

View File

@ -17,7 +17,8 @@
"control.cpp",
"control.ts",
"serial.cpp",
"serial.ts"
"serial.ts",
"fieldeditors.ts"
],
"testFiles": [
"test.ts"

View File

@ -118,11 +118,11 @@ declare namespace control {
function waitMicros(micros: int32): void;
/**
* Run other code in the background.
* Run other code in the parallel.
*/
//% help=control/run-in-background blockAllowMultiple=1 afterOnStart=true
//% blockId="control_run_in_background" block="run in background" blockGap=8 shim=control::runInBackground
function runInBackground(a: () => void): void;
//% help=control/run-in-parallel handlerStatement=1
//% blockId="control_run_in_parallel" block="run in parallel" blockGap=8 shim=control::runInParallel
function runInParallel(a: () => void): void;
/**
* Blocks the calling thread until the specified event is raised.

View File

@ -1,14 +0,0 @@
{
"behaviors": "Behavior drive blocks",
"behaviors.Behavior": "A behavior",
"behaviors.BehaviorManager": "A manager for behaviors",
"behaviors.BehaviorManager.add": "Adds a new behavior to the behavior manager",
"behaviors.BehaviorManager.add|param|behavior": "the behavior to add",
"behaviors.BehaviorManager.start": "Starts the behavior control loop",
"behaviors.BehaviorManager.stop": "Stops the execution loop",
"behaviors.addBehavior": "Adds the behavior and starts it",
"behaviors.addBehavior|param|behavior": "a behavior",
"behaviors.avoidCrash": "A behavior that stops all motors if the sensor distance get too short",
"behaviors.driveForward": "A behavior that turns on the motors to the specified speed",
"behaviors.driveForward|param|motors": "@param speed the desired speed, eg: 50"
}

View File

@ -1,7 +0,0 @@
{
"behaviors.addBehavior|block": "add behavior %behavior",
"behaviors.avoidCrash|block": "avoid crash using %ultrasonic",
"behaviors.driveForward|block": "drive %motors|forward at %speed=motorSpeedPicker|%",
"behaviors|block": "behaviors",
"{id:category}Behaviors": "Behaviors"
}

View File

@ -1,56 +0,0 @@
namespace behaviors {
class AvoidCrashBehavior extends behaviors.Behavior {
private ultrasonic: sensors.UltraSonicSensor;
constructor(ultrasonic: sensors.UltraSonicSensor) {
super();
this.ultrasonic = ultrasonic;
}
shouldRun(): boolean {
return this.ultrasonic.distance() < 5;
}
run(): void {
motors.stopAllMotors();
this.active = false;
}
}
/**
* A behavior that stops all motors if the sensor distance get too short
*/
//% blockId=behaviorsAvoidCrash block="avoid crash using %ultrasonic"
export function avoidCrash(ultrasonic: sensors.UltraSonicSensor) : behaviors.Behavior {
return new AvoidCrashBehavior(ultrasonic);
}
class DriveForwardBehavior extends behaviors.Behavior {
private motors: motors.MotorBase;
private speed: number;
constructor(motors: motors.MotorBase, speed: number) {
super();
this.motors = motors;
this.speed = speed;
}
shouldRun(): boolean {
return true;
}
run(): void {
this.motors.setSpeed(this.speed);
pauseUntil(() => !this.active);
this.motors.setSpeed(0);
}
}
/**
* A behavior that turns on the motors to the specified speed
* @param motors
* @param speed the desired speed, eg: 50
*/
//% blockId=behaviorsDriveForward block="drive %motors|forward at %speed=motorSpeedPicker|%"
export function driveForward(motors: motors.MotorBase, speed: number): behaviors.Behavior {
return new DriveForwardBehavior(motors, speed);
}
}

View File

@ -1,12 +1,9 @@
{
"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.driveFor": "Makes a differential drive robot move with a given speed (cm/s) and rotation rate (deg/s)\nusing a unicycle model.",
"chassis.Chassis.driveFor|param|rotationSpeed": "rotation of the robot around the center point, eg: 30",
"chassis.Chassis.driveFor|param|speed": "speed of the center point between motors, eg: 10",
"chassis.Chassis.driveFor|param|value": "the amount of movement, eg: 2",
"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",

View File

@ -1,7 +1,6 @@
{
"ChassisProperty.BaseLength|block": "base length (cm)",
"ChassisProperty.WheelRadius|block": "wheel radius (cm)",
"chassis.Chassis.driveFor|block": "drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s|for %value|%unit",
"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",

View File

@ -24,19 +24,6 @@ namespace chassis {
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
*/
//% blockId=motorDrive block="drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s"
//% inlineInputMode=inline
//% weight=99 blockGap=8
drive(speed: number, rotationSpeed: number) {
this.driveFor(speed, rotationSpeed, 0, MoveUnit.Degrees);
}
/**
* Makes a differential drive robot move with a given speed (cm/s) and rotation rate (deg/s)
* using a unicycle model.
@ -45,10 +32,10 @@ namespace chassis {
* @param value the amount of movement, eg: 2
* @param unit
*/
//% blockId=motorDriveFor block="drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s|for %value|%unit"
//% blockId=motorDrive block="drive %chassis|at %speed|cm/s|turning %rotationSpeed|deg/s"
//% inlineInputMode=inline
//% weight=95 blockGap=8
driveFor(speed: number, rotationSpeed: number, value: number, unit: MoveUnit) {
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
@ -65,7 +52,7 @@ namespace chassis {
const sr = vr / maxw * 100; // %
const sl = vl / maxw * 100; // %
this.motors.tankFor(sr, sl, value, unit)
this.motors.tank(sr, sl, value, unit)
}
/**

View File

@ -1,5 +1,6 @@
{
"sensors.ColorSensor": "The color sensor is a digital sensor that can detect the color or intensity\nof light that enters the small window on the face of the sensor.",
"sensors.ColorSensor.calibrateLight": "Collects measurement of the light condition and adjusts the threshold to 10% / 90%.",
"sensors.ColorSensor.color": "Get the current color from the color sensor.",
"sensors.ColorSensor.colorMode": "Gets the current color mode",
"sensors.ColorSensor.light": "Measures the ambient or reflected light value from 0 (darkest) to 100 (brightest).",
@ -14,5 +15,7 @@
"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"
"sensors.ColorSensor.setThreshold|param|value": "the value threshold",
"sensors.ColorSensor.threshold": "Gets the threshold value",
"sensors.ColorSensor.threshold|param|condition": "the light condition"
}

View File

@ -13,13 +13,15 @@
"LightCondition.Dark|block": "dark",
"LightIntensityMode.Ambient|block": "ambient light",
"LightIntensityMode.Reflected|block": "reflected light",
"sensors.ColorSensor.calibrateLight|block": "calibrate|%sensor|for %mode|light",
"sensors.ColorSensor.color|block": "%sensor| color",
"sensors.ColorSensor.light|block": "%sensor|%mode",
"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|%condition",
"sensors.ColorSensor.setThreshold|block": "set %condition|to %value",
"sensors.ColorSensor.setThreshold|block": "set %sensor|%condition|to %value",
"sensors.ColorSensor.threshold|block": "%sensor|%condition",
"sensors.color1|block": "color 1",
"sensors.color2|block": "color 2",
"sensors.color3|block": "color 3",

View File

@ -39,9 +39,9 @@ const enum ColorSensorColor {
enum LightCondition {
//% block="dark"
Dark = sensors.internal.ThresholdState.Low,
Dark = sensors.ThresholdState.Low,
//$ block="bright"
Bright = sensors.internal.ThresholdState.High
Bright = sensors.ThresholdState.High
}
namespace sensors {
@ -52,12 +52,14 @@ namespace sensors {
*/
//% fixedInstances
export class ColorSensor extends internal.UartSensor {
thresholdDetector: sensors.internal.ThresholdDetector;
thresholdDetector: sensors.ThresholdDetector;
calibrating: boolean;
constructor(port: number) {
super(port)
this._setMode(ColorSensorMode.None);
this.thresholdDetector = new sensors.internal.ThresholdDetector(this.id());
this.thresholdDetector = new sensors.ThresholdDetector(this.id());
this.calibrating = false;
}
_colorEventValue(value: number) {
@ -95,6 +97,7 @@ namespace sensors {
}
_update(prev: number, curr: number) {
if (this.calibrating) return; // simply ignore data updates while calibrating
if (this.mode == ColorSensorMode.Color)
control.raiseEvent(this._id, this._colorEventValue(curr));
else
@ -227,20 +230,79 @@ namespace sensors {
* @param condition the dark or bright light condition
* @param value the value threshold
*/
//% blockId=colorSetThreshold block="set %condition|to %value"
//% blockId=colorSetThreshold block="set %sensor|%condition|to %value"
//% group="Threshold" blockGap=8 weight=90
//% value.min=0 value.max=100
//% sensor.fieldEditor="ports"
setThreshold(condition: LightCondition, value: number) {
if (condition == LightCondition.Dark)
this.thresholdDetector.setLowThreshold(value)
else
this.thresholdDetector.setHighThreshold(value);
}
/**
* Gets the threshold value
* @param condition the light condition
*/
//% blockId=colorGetThreshold block="%sensor|%condition"
//% group="Threshold" blockGap=8 weight=89
//% sensor.fieldEditor="ports"
threshold(condition: LightCondition): number {
return this.thresholdDetector.threshold(<ThresholdState><number>LightCondition.Dark);
}
/**
* Collects measurement of the light condition and adjusts the threshold to 10% / 90%.
*/
//% blockId=colorCalibrateLight block="calibrate|%sensor|for %mode|light"
//% group="Threshold" weight=91 blockGap=8
//% sensor.fieldEditor="ports"
calibrateLight(mode: LightIntensityMode, deviation: number = 8) {
this.calibrating = true; // prevent events
this.light(mode); // trigger a read
pauseUntil(() => this.isActive()); // ensure sensor is live
let vold = 0;
let vcount = 0;
let min = 200;
let max = -200;
let k = 0;
while(k++ < 1000 && vcount < 50) {
let v = this.light(mode);
min = Math.min(min, v);
max = Math.max(max, v);
// detect if nothing has changed and stop calibration
if (Math.abs(v - vold) <= 2)
vcount ++;
else {
vold = v;
vcount = 1;
}
// wait a bit
loops.pause(50);
}
// apply tolerance
const minDist = 10;
min = Math.max(minDist / 2, Math.min(min + deviation / 2, max - deviation / 2 - minDist / 2));
max = Math.min(100 - minDist / 2, Math.max(min + minDist, max - deviation / 2));
// apply thresholds
this.thresholdDetector.setLowThreshold(min);
this.thresholdDetector.setHighThreshold(max);
this.calibrating = false;
}
}
//% whenUsed block="color 3" weight=90 fixedInstance jres=icons.port3
//% whenUsed block="color 3" weight=95 fixedInstance jres=icons.port3
export const color3: ColorSensor = new ColorSensor(3)
//% whenUsed block="color 1" weight=95 fixedInstance jres=icons.port1
//% whenUsed block="color 1" weight=90 fixedInstance jres=icons.port1
export const color1: ColorSensor = new ColorSensor(1)
//% whenUsed block="color 2" weight=90 fixedInstance jres=icons.port2

View File

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

View File

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

View File

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

View File

@ -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.",
@ -28,11 +30,9 @@
"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.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",
@ -52,6 +52,12 @@
"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": "A timer",
"control.Timer.millis": "Gets the elapsed time in millis since the last reset",
"control.Timer.pauseUntil": "Pauses until the timer reaches the given amount of milliseconds",
"control.Timer.pauseUntil|param|ms": "how long to pause for, eg: 5, 100, 200, 500, 1000, 2000",
"control.Timer.reset": "Resets the timer",
"control.Timer.seconds": "Gets the elapsed time in seconds since the last reset",
"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.",
@ -61,6 +67,8 @@
"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",

View File

@ -1,17 +1,17 @@
{
"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",
@ -30,15 +30,14 @@
"brick.Button.pauseUntil|block": "pause until %button|%event",
"brick.Button.wasPressed|block": "%button|was pressed",
"brick.batteryLevel|block": "battery level",
"brick.buttonDown|block": "down",
"brick.buttonEnter|block": "enter",
"brick.buttonLeft|block": "left",
"brick.buttonRight|block": "right",
"brick.buttonUp|block": "up",
"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.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",
@ -48,15 +47,29 @@
"console.log|block": "console|log %text",
"console.sendToScreen|block": "send console to screen",
"console|block": "console",
"control.Timer.millis|block": "%timer|millis",
"control.Timer.pauseUntil|block": "%timer|pause until (ms) %ms",
"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=toggleOnOff",
"motors.Motor.speed|block": "%motor|speed",
"motors.Motor.tacho|block": "%motor|tacho",
"motors.MotorBase.pauseUntilReady|block": "%motor|pause until ready",
"motors.MotorBase.setBrake|block": "set %motor|brake %brake",
"motors.MotorBase.setReversed|block": "set %motor|reversed %reversed",
"motors.MotorBase.reset|block": "%motors|reset",
"motors.MotorBase.setBrake|block": "set %motor|brake %brake=toggleOnOff",
"motors.MotorBase.setReversed|block": "set %motor|reversed %reversed=toggleOnOff",
"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|%",
@ -88,10 +101,10 @@
"{id:category}Motors": "Motors",
"{id:category}Output": "Output",
"{id:category}Screen": "Screen",
"{id:category}Sensors": "Sensors",
"{id:category}Serial": "Serial",
"{id:group}Buttons": "Buttons",
"{id:group}Counters": "Counters",
"{id:group}Light": "Light",
"{id:group}More": "More",
"{id:group}Move": "Move",
"{id:group}Screen": "Screen",

View File

@ -2,36 +2,26 @@
/**
* Patterns for lights under the buttons.
*/
const enum LightsPattern {
//% block=Off enumval=0
//% blockIdentity=brick.lightPattern
const enum BrickLight {
//% block=off enumval=0
Off = 0,
//% block=Green enumval=1
//% blockIdentity=brick.lightPattern
//% block=green enumval=1
Green = 1,
//% block=Red enumval=2
//% blockIdentity=brick.lightPattern
//% block=red enumval=2
Red = 2,
//% block=Orange enumval=3
//% blockIdentity=brick.lightPattern
//% block=orange enumval=3
Orange = 3,
//% block="Flashing Green" enumval=4
//% blockIdentity=brick.lightPattern
//% block="green flash" enumval=4
GreenFlash = 4,
//% block="Flashing Red" enumval=5
//% blockIdentity=brick.lightPattern
//% block="red flash" enumval=5
RedFlash = 5,
//% block="Flashing Orange" enumval=6
//% blockIdentity=brick.lightPattern
//% block="orange flash" enumval=6
OrangeFlash = 6,
//% block="Pulsing Green" enumval=7
//% blockIdentity=brick.lightPattern
//% block="green pulse" enumval=7
GreenPulse = 7,
//% block="Pulsing Red" enumval=8
//% blockIdentity=brick.lightPattern
//% block="red pulse" enumval=8
RedPulse = 8,
//% block="Pulsing Orange" enumval=9
//% blockIdentity=brick.lightPattern
//% block="orange pulse" enumval=9
OrangePulse = 9,
}
@ -170,6 +160,7 @@ namespace brick {
// 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
@ -203,31 +194,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)
}
@ -251,32 +242,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;
}
}

View File

@ -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
View File

@ -1,6 +1,17 @@
// Auto-generated. Do not edit.
/**
* Mode for lseek()
*/
declare const enum SeekWhence {
Set = 0,
Current = 1,
End = 2,
}
/**
* Drawing modes
*/

View File

@ -11,7 +11,7 @@ namespace sensors.internal {
// This is implementation for the simulator.
control.runInBackground(() => {
control.runInParallel(() => {
let prev = query()
changeHandler(prev, prev)
while (true) {
@ -93,7 +93,7 @@ namespace sensors.internal {
init();
return {
temp: analogMM.getNumber(NumberFormat.Int16LE, AnalogOff.BatteryTemp),
current: analogMM.getNumber(NumberFormat.Int16LE, AnalogOff.BatteryCurrent)
current: Math.round(analogMM.getNumber(NumberFormat.Int16LE, AnalogOff.BatteryCurrent) / 10)
}
}
@ -196,83 +196,6 @@ namespace sensors.internal {
}
}
export enum ThresholdState {
Normal = 1,
High = 2,
Low = 3,
}
export class ThresholdDetector {
public id: number;
private min: number;
private max: number;
private lowThreshold: number;
private highThreshold: number;
private level: number;
public state: ThresholdState;
constructor(id: number, min = 0, max = 100, lowThreshold = 20, highThreshold = 80) {
this.id = id;
this.min = min;
this.max = max;
this.lowThreshold = lowThreshold;
this.highThreshold = highThreshold;
this.level = Math.ceil((max - min) / 2);
this.state = ThresholdState.Normal;
}
public setLevel(level: number) {
if (this == null) return
this.level = this.clampValue(level);
if (this.level >= this.highThreshold) {
this.setState(ThresholdState.High);
}
else if (this.level <= this.lowThreshold) {
this.setState(ThresholdState.Low);
}
else {
this.setState(ThresholdState.Normal);
}
}
public setLowThreshold(value: number) {
this.lowThreshold = this.clampValue(value);
this.highThreshold = Math.max(this.lowThreshold + 1, this.highThreshold);
}
public setHighThreshold(value: number) {
this.highThreshold = this.clampValue(value);
this.lowThreshold = Math.min(this.highThreshold - 1, this.lowThreshold);
}
private clampValue(value: number) {
if (value < this.min) {
return this.min;
}
else if (value > this.max) {
return this.max;
}
return value;
}
private setState(state: ThresholdState) {
if (this.state == state) return;
this.state = state;
switch (state) {
case ThresholdState.High:
control.raiseEvent(this.id, ThresholdState.High);
break;
case ThresholdState.Low:
control.raiseEvent(this.id, ThresholdState.Low);
break;
case ThresholdState.Normal:
break;
}
}
}
export class UartSensor extends Sensor {
protected mode: number // the mode user asked for
protected realmode: number // the mode the hardware is in
@ -310,8 +233,9 @@ namespace sensors.internal {
return getUartNumber(fmt, off, this._port)
}
protected reset() {
reset() {
if (this.isActive()) uartReset(this._port);
this.realmode = 0;
}
}
@ -498,3 +422,91 @@ namespace sensors.internal {
TST_UART_WRITE = 0xc048740a,
}
}
namespace sensors {
export enum ThresholdState {
Normal = 1,
High = 2,
Low = 3,
}
export class ThresholdDetector {
public id: number;
public min: number;
public max: number;
public lowThreshold: number;
public highThreshold: number;
public level: number;
public state: ThresholdState;
constructor(id: number, min = 0, max = 100, lowThreshold = 20, highThreshold = 80) {
this.id = id;
this.min = min;
this.max = max;
this.lowThreshold = lowThreshold;
this.highThreshold = highThreshold;
this.level = Math.ceil((max - min) / 2);
this.state = ThresholdState.Normal;
}
public setLevel(level: number) {
if (this == null) return
this.level = this.clampValue(level);
if (this.level >= this.highThreshold) {
this.setState(ThresholdState.High);
}
else if (this.level <= this.lowThreshold) {
this.setState(ThresholdState.Low);
}
else {
const interval = (this.highThreshold - this.lowThreshold) / 6;
if ((this.state == ThresholdState.High && this.level < this.highThreshold - interval) ||
(this.state == ThresholdState.Low && this.level > this.lowThreshold + interval))
this.setState(ThresholdState.Normal);
}
}
public threshold(t: ThresholdState): number {
switch(t) {
case ThresholdState.High: return this.highThreshold;
case ThresholdState.Low: return this.lowThreshold;
default: return (this.max - this.min) / 2;
}
}
public setLowThreshold(value: number) {
this.lowThreshold = this.clampValue(value);
this.highThreshold = Math.max(this.lowThreshold + 1, this.highThreshold);
}
public setHighThreshold(value: number) {
this.highThreshold = this.clampValue(value);
this.lowThreshold = Math.min(this.highThreshold - 1, this.lowThreshold);
}
private clampValue(value: number) {
if (value < this.min) {
return this.min;
}
else if (value > this.max) {
return this.max;
}
return value;
}
private setState(state: ThresholdState) {
if (this.state == state) return;
this.state = state;
switch (state) {
case ThresholdState.High:
control.raiseEvent(this.id, ThresholdState.High);
break;
case ThresholdState.Low:
control.raiseEvent(this.id, ThresholdState.Low);
break;
}
}
}
}

View File

@ -271,7 +271,12 @@ void setupThread(Action a, TValue arg = 0, void (*runner)(Thread *) = NULL, TVal
}
}
void runInBackground(Action a) {
void releaseFiber() {
stopUser();
pthread_exit(NULL);
}
void runInParallel(Action a) {
setupThread(a);
}

View File

@ -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);
}
}

View File

@ -111,7 +111,7 @@ namespace motors {
* Stops all motors
*/
//% blockId=motorStopAll block="stop all motors"
//% weight=5
//% weight=1
//% group="Move"
export function stopAllMotors() {
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
@ -161,8 +161,7 @@ namespace motors {
* Sets the automatic brake on or off when the motor is off
* @param brake a value indicating if the motor should break when off
*/
//% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake"
//% brake.fieldEditor=toggleonoff
//% blockId=outputMotorSetBrakeMode block="set %motor|brake %brake=toggleOnOff"
//% weight=60 blockGap=8
//% group="Move"
setBrake(brake: boolean) {
@ -173,9 +172,8 @@ namespace motors {
/**
* Reverses the motor polarity
*/
//% blockId=motorSetReversed block="set %motor|reversed %reversed"
//% reversed.fieldEditor=toggleonoff
//% weight=59
//% blockId=motorSetReversed block="set %motor|reversed %reversed=toggleOnOff"
//% weight=59 blockGap=8
//% group="Move"
setReversed(reversed: boolean) {
this.init();
@ -193,12 +191,22 @@ namespace motors {
stop() {
this.init();
stop(this._port, this._brake);
this.settle();
}
private settle() {
// if we've recently completed a motor command with brake
// allow 500ms for robot to settle
if(this._brake)
loops.pause(500);
}
/**
* Resets the motor(s).
*/
//%
//% weight=5
//% group="Move"
//% blockId=motorReset block="%motors|reset"
reset() {
this.init();
reset(this._port);
@ -216,10 +224,17 @@ namespace motors {
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) {
@ -242,6 +257,10 @@ namespace motors {
}
this._move(useSteps, stepsOrTime, speed);
// wait till motor is done with this work
this.pauseUntilReady();
// allow robot to settle
this.settle();
}
/**
@ -271,10 +290,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();
}
@ -290,7 +311,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) {
@ -304,11 +325,23 @@ 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=toggleOnOff"
//% weight=58
//% group="Move"
setRegulated(value: boolean) {
this._regulated = value;
}
/**
* Gets motor actual speed.
* @param motor the port which connects to the motor

View File

@ -11,6 +11,7 @@
"mmap.cpp",
"control.cpp",
"console.ts",
"timer.ts",
"serialnumber.cpp",
"buttons.ts",
"png.cpp",

View File

@ -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 {

View File

@ -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())
})

64
libs/core/timer.ts Normal file
View File

@ -0,0 +1,64 @@
namespace control {
/**
* A timer
*/
//% fixedInstances
export class Timer {
start: number;
constructor() {
this.start = control.millis();
}
/**
* Gets the elapsed time in millis since the last reset
*/
//% blockId=timerMillis block="%timer|millis"
millis(): number {
return control.millis() - this.start;
}
/**
* Gets the elapsed time in seconds since the last reset
*/
//% blockId=timerSeconds block="%timer|seconds"
seconds(): number {
return this.millis() / 1000;
}
/**
* Resets the timer
*/
//% blockId=timerRest block="%timer|reset"
reset() {
this.start = control.millis();
}
/**
* Pauses until the timer reaches the given amount of milliseconds
* @param ms how long to pause for, eg: 5, 100, 200, 500, 1000, 2000
*/
//% blockId=timerPauseUntil block="%timer|pause until (ms) %ms"
pauseUntil(ms: number) {
const remaining = this.millis() - ms;
loops.pause(Math.max(0, remaining));
}
}
//% 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();
}

View File

@ -0,0 +1,15 @@
{
"datalog": "A data logging framework",
"datalog.DatalogStorage": "A storage for datalog data",
"datalog.DatalogStorage.appendHeaders": "Appends the headers in datalog",
"datalog.DatalogStorage.appendRow": "Appends a row of data",
"datalog.DatalogStorage.flush": "Flushes any buffered data",
"datalog.DatalogStorage.init": "Initializes the storage",
"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.flush": "Commits any buffered row to disk",
"datalog.setEnabled": "Turns on or off datalogging",
"datalog.setStorage": "* @param storage custom storage solution"
}

View File

@ -0,0 +1,7 @@
{
"datalog.addRow|block": "datalog add row",
"datalog.addValue|block": "datalog add %name|=%value",
"datalog.setEnabled|block": "datalog %enabled=toggleOnOff",
"datalog|block": "datalog",
"{id:category}Datalog": "Datalog"
}

7
libs/datalog/pxt.json Normal file
View File

@ -0,0 +1,7 @@
{
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/datalog",
"dependencies": {
"core": "file:../core",
"storage": "file:../storage"
}
}

View File

@ -0,0 +1,57 @@
namespace datalog.ev3 {
/**
* A datalog storage for the EV3
*/
export class EV3DatalogStorage extends DatalogStorage { // implements DatalogStorage {
private _filename: string;
private _buffer: string;
private _storage: storage.Storage;
/**
* Creates a new storage for the datalog
* @param storage
* @param filename
*/
constructor(storage: storage.Storage, filename: string) {
super();
this._filename = filename;
this._storage = storage;
}
/**
* Initializes the storage
*/
init(): void {
this._storage.remove(this._filename);
this._buffer = "";
}
/**
* Appends the headers in datalog
*/
appendHeaders(headers: string[]): void {
this._storage.appendCSVHeaders(this._filename, headers);
}
/**
* Appends a row of data
*/
appendRow(values: number[]): void {
// commit row data
this._buffer += storage.toCSV(values, this._storage.csvSeparator);
// buffered writes
if (this._buffer.length > 1024)
this.flush();
}
/**
* Flushes any buffered data
*/
flush(): void {
if (this._buffer) {
const b = this._buffer;
this._buffer = "";
this._storage.append(this._filename, b);
}
}
}
// automatic hook up
datalog.setStorage(new datalog.ev3.EV3DatalogStorage(storage.temporary, "datalog.csv"));
}

View File

@ -56,4 +56,9 @@ namespace loops {
//% color="#1E5AA8"
namespace light {
}
//% color="#b0b0b0" advanced=true weight=5
namespace storage {
}

View File

@ -13,7 +13,8 @@
"color-sensor": "file:../color-sensor",
"touch-sensor": "file:../touch-sensor",
"ultrasonic-sensor": "file:../ultrasonic-sensor",
"gyro-sensor": "file:../gyro-sensor"
"gyro-sensor": "file:../gyro-sensor",
"mood": "file:../mood"
},
"public": true
}

View File

@ -1,5 +1,7 @@
{
"sensors.GyroSensor.angle": "Get the current angle from the gyroscope.",
"sensors.GyroSensor.calibrate": "Forces a calibration of the gyro. Must be called when the sensor is completely still.",
"sensors.GyroSensor.rotationRate": "Get the current rotation rate from the gyroscope."
"sensors.GyroSensor.drift": "Gets the computed rate drift",
"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.",
"sensors.GyroSensor.setDriftCorrection": "Enables or disable drift correction"
}

View File

@ -1,7 +1,7 @@
{
"sensors.GyroSensor.angle|block": "%sensor|angle",
"sensors.GyroSensor.calibrate|block": "%sensor|calibrate",
"sensors.GyroSensor.rotationRate|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",

View File

@ -8,16 +8,27 @@ namespace sensors {
//% fixedInstances
export class GyroSensor extends internal.UartSensor {
private calibrating: boolean;
private _drift: number;
private _drifting: boolean;
constructor(port: number) {
super(port)
this.calibrating = false;
this._drift = 0;
this._drifting = true;
this.setMode(GyroSensorMode.Rate);
}
_deviceType() {
return DAL.DEVICE_TYPE_GYRO
}
_query(): number {
return this.getNumber(NumberFormat.Int16LE, 0);
}
setMode(m: GyroSensorMode) {
if (m == GyroSensorMode.Rate && this.mode != m)
this._drift = 0;
this._setMode(m)
}
@ -37,61 +48,91 @@ namespace sensors {
if (this.calibrating)
pauseUntil(() => !this.calibrating, 2000);
this.setMode(GyroSensorMode.Angle)
return this.getNumber(NumberFormat.Int16LE, 0)
this.setMode(GyroSensorMode.Angle);
return this._query();
}
/**
* Get the current rotation rate from the gyroscope.
* @param sensor the gyroscope to query the request
*/
//% help=input/gyro/rotation-rate
//% block="%sensor|rotation rate"
//% help=input/gyro/rate
//% block="%sensor|rate"
//% blockId=gyroGetRate
//% parts="gyroscope"
//% blockNamespace=sensors
//% sensor.fieldEditor="ports"
//% weight=65 blockGap=8
//% group="Gyro Sensor"
rotationRate(): number {
rate(): number {
if (this.calibrating)
pauseUntil(() => !this.calibrating, 2000);
this.setMode(GyroSensorMode.Rate)
return this.getNumber(NumberFormat.Int16LE, 0)
this.setMode(GyroSensorMode.Rate);
let curr = this._query();
if (Math.abs(curr) < 20) {
const p = 0.0005;
this._drift = (1 - p) * this._drift + p * curr;
curr -= this._drift;
}
return curr;
}
/**
* Forces a calibration of the gyro. Must be called when the sensor is completely still.
*/
//% help=input/gyro/calibrate
//% block="%sensor|calibrate"
//% blockId=gyroCalibrate
//% block="%sensor|reset"
//% blockId=gyroReset
//% parts="gyroscope"
//% blockNamespace=sensors
//% sensor.fieldEditor="ports"
//% weight=50 blockGap=8
//% group="Gyro Sensor"
calibrate(): void {
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);
// may be triggered by a button click,
// give time for robot to settle
loops.pause(700);
// send a reset command
this.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);
super.reset();
// switch back to the desired mode
this.setMode(this.mode);
// wait till sensor is live
pauseUntil(() => this.isActive());
// give it a bit of time to init
loops.pause(1000)
// compute drift
this._drift = 0;
if (this.mode == GyroSensorMode.Rate) {
for (let i = 0; i < 200; ++i) {
this._drift += this._query();
loops.pause(4);
}
this._drift /= 200;
}
// and we're done
this.calibrating = false;
}
/**
* Gets the computed rate drift
*/
//%
drift(): number {
return this._drift;
}
/**
* Enables or disable drift correction
* @param enabled
*/
//%
setDriftCorrection(enabled: boolean) {
this._drifting = enabled;
}
}
//% fixedInstance whenUsed block="gyro 2" weight=95 jres=icons.port2

View File

@ -7,6 +7,8 @@
"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.InfraredSensor.threshold": "Gets the threshold value",
"sensors.InfraredSensor.threshold|param|condition": "the proximity condition",
"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",

View File

@ -5,7 +5,8 @@
"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 %condition|to %value",
"sensors.InfraredSensor.setThreshold|block": "set %sensor|%condition|to %value",
"sensors.InfraredSensor.threshold|block": "%sensor|%condition",
"sensors.RemoteInfraredBeaconButton.isPressed|block": "%button|is pressed",
"sensors.RemoteInfraredBeaconButton.onEvent|block": "on %button|%event",
"sensors.RemoteInfraredBeaconButton.wasPressed|block": "%button|was pressed",

View File

@ -138,12 +138,12 @@ namespace sensors {
//% fixedInstances
export class InfraredSensor extends internal.UartSensor {
private channel: IrRemoteChannel;
private proximityThreshold: sensors.internal.ThresholdDetector;
private proximityThreshold: sensors.ThresholdDetector;
constructor(port: number) {
super(port)
this.channel = IrRemoteChannel.Ch0
this.proximityThreshold = new sensors.internal.ThresholdDetector(this._id, 0, 100, 10, 90);
this.proximityThreshold = new sensors.ThresholdDetector(this._id, 0, 100, 10, 90);
irButton(0) // make sure buttons array is initalized
// and set the mode, as otherwise button events won't work
@ -257,14 +257,26 @@ namespace sensors {
* @param condition the dark or bright light condition
* @param value the value threshold
*/
//% blockId=irSetThreshold block="set %condition|to %value"
//% group="Threshold" blockGap=8
//% blockId=irSetThreshold block="set %sensor|%condition|to %value"
//% group="Threshold" blockGap=8 weight=49
//% value.min=0 value.max=100
setThreshold(condition: InfraredSensorEvent, value: number) {
if (condition == InfraredSensorEvent.ObjectNear)
this.proximityThreshold.setLowThreshold(value)
else
this.proximityThreshold.setHighThreshold(value);
}
/**
* Gets the threshold value
* @param condition the proximity condition
*/
//% blockId=irGetThreshold block="%sensor|%condition"
//% group="Threshold" blockGap=8 weight=49
//% sensor.fieldEditor="ports"
threshold(condition: InfraredSensorEvent): number {
return this.proximityThreshold.threshold(<ThresholdState><number>LightCondition.Dark);
}
}
//% fixedInstance whenUsed block="infrared 1" jres=icons.port1

3
libs/mood/README.md Normal file
View File

@ -0,0 +1,3 @@
# mood
A package to put the EV3 in various moods.

View File

@ -0,0 +1,17 @@
{
"brick.Mood": "A mood",
"brick.Mood.show": "Shows the mood on the EV3",
"brick.showMood": "Shows a mood",
"moods.angry": "An angry mood",
"moods.awake": "A awake mood",
"moods.dizzy": "A dizzy mood",
"moods.knockedOut": "A knocked out mood",
"moods.love": "In love mood",
"moods.middleLeft": "Looking around left",
"moods.middleRight": "Looking around right",
"moods.neutral": "In a neutral mood",
"moods.sad": "A sad mood",
"moods.sleeping": "A sleeping mood",
"moods.tired": "A tired mood",
"moods.winking": "In laughing mood"
}

View File

@ -0,0 +1,8 @@
{
"brick.showMood|block": "show mood %mood=mood_image_picker",
"brick|block": "brick",
"moods|block": "moods",
"{id:category}Brick": "Brick",
"{id:category}Moods": "Moods",
"{id:group}Screen": "Screen"
}

125
libs/mood/mood.ts Normal file
View File

@ -0,0 +1,125 @@
namespace brick {
/**
* Shows a mood
*/
//% weight=90
//% blockId=moodShow block="show mood %mood=mood_image_picker"
//% weight=101 group="Screen" blockGap=8
export function showMood(mood: Mood) {
if(mood)
mood.show();
}
/**
* A mood
*/
//% fixedInstances
export class Mood {
private image: Image;
private sound: Sound;
private light: BrickLight;
constructor(image: Image, sound: Sound, light: BrickLight) {
this.image = image;
this.sound = sound;
this.light = light;
}
/**
* Shows the mood on the EV3
*/
show() {
brick.setLight(this.light);
brick.showImage(this.image);
music.playSoundEffectUntilDone(this.sound);
loops.pause(20);
}
}
/**
* An image
* @param image the image
*/
//% blockId=mood_image_picker block="%image" shim=TD_ID
//% image.fieldEditor="images"
//% image.fieldOptions.columns=4
//% image.fieldOptions.width=400
//% group="Screen" weight=0 blockHidden=1
export function __moodImagePicker(mood: Mood): Mood {
return mood;
}
}
namespace moods {
/**
* A sleeping mood
*/
//% fixedInstance jres=images.eyesSleeping
export const sleeping = new brick.Mood(images.eyesSleeping, sounds.expressionsSnoring, BrickLight.OrangePulse);
/**
* A awake mood
*/
//% fixedInstance jres=images.eyesAwake
export const awake = new brick.Mood(images.eyesAwake, sounds.informationActivate, BrickLight.Orange);
/**
* A tired mood
*/
//% fixedInstance jres=images.eyesTiredMiddle
export const tired = new brick.Mood(images.eyesTiredMiddle, sounds.expressionsSneezing, BrickLight.OrangeFlash);
/**
* An angry mood
*/
//% fixedInstance jres=images.eyesAngry
export const angry = new brick.Mood(images.eyesAngry, sounds.animalsDogGrowl, BrickLight.RedPulse);
/**
* A sad mood
*/
//% fixedInstance jres=images.eyesTear
export const sad = new brick.Mood(images.eyesTear, sounds.animalsDogWhine, BrickLight.Red);
/**
* A dizzy mood
*/
//% fixedInstance jres=images.eyesDizzy
export const dizzy = new brick.Mood(images.eyesDizzy, sounds.expressionsUhOh, BrickLight.OrangeFlash);
/**
* A knocked out mood
*/
//% fixedInstance jres=images.eyesKnockedOut
export const knockedOut = new brick.Mood(images.eyesKnockedOut, sounds.informationError, BrickLight.RedFlash);
/**
* Looking around left
*/
//% fixedInstance jres=images.eyesMiddleLeft
export const middleLeft = new brick.Mood(images.eyesMiddleLeft, sounds.informationAnalyze, BrickLight.Off);
/**
* Looking around right
*/
//% fixedInstance jres=images.eyesMiddleRight
export const middleRight = new brick.Mood(images.eyesMiddleRight, sounds.informationAnalyze, BrickLight.Off);
/**
* In love mood
*/
//% fixedInstance jres=images.eyesLove
export const love = new brick.Mood(images.eyesLove, sounds.expressionsMagicWand, BrickLight.GreenPulse);
/**
* In laughing mood
*/
//% fixedInstance jres=images.eyesWinking
export const winking = new brick.Mood(images.eyesWinking, sounds.expressionsLaughing1, BrickLight.GreenFlash);
/**
* In a neutral mood
*/
//% fixedInstance jres=images.eyesNeutral
export const neutral = new brick.Mood(images.eyesNeutral, undefined, BrickLight.Green);
}

15
libs/mood/pxt.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "mood",
"description": "The EV3 mood library",
"files": [
"README.md",
"mood.ts"
],
"testFiles": [
],
"public": true,
"dependencies": {
"core": "file:../core",
"music": "file:../music"
}
}

View File

@ -23,7 +23,7 @@
"music.setTempo": "Set the tempo a number of beats per minute (bpm).",
"music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
"music.setVolume": "Set the output volume of the sound synthesizer.",
"music.setVolume|param|volume": "the volume 0...256, eg: 128",
"music.setVolume|param|volume": "the volume 0...100, eg: 50",
"music.stopAllSounds": "Play a tone through the speaker for some amount of time.",
"music.tempo": "Return the tempo in beats per minute (bpm).\nTempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play."
}

View File

@ -121,7 +121,7 @@
"sounds.mechanicalMotorStart|block": "mechanical motor start",
"sounds.mechanicalMotorStop|block": "mechanical motor stop",
"sounds.mechanicalRatchet|block": "mechanical ratchet",
"sounds.mechanicalSonar|block": "\"mechanical sonar\"",
"sounds.mechanicalSonar|block": "mechanical sonar",
"sounds.mechanicalTickTack|block": "mechanical tick tack",
"sounds.mechanicalWalk|block": "mechanical walk",
"sounds.movementsArm1|block": "movements arm1",

View File

@ -13,7 +13,7 @@
namespace music {
uint8_t currVolume = 2;
uint8_t currVolume = 50;
uint8_t *lmsSoundMMap;
int writeDev(void *data, int size) {
@ -25,16 +25,16 @@ int writeDev(void *data, int size) {
/**
* Set the output volume of the sound synthesizer.
* @param volume the volume 0...256, eg: 128
* @param volume the volume 0...100, eg: 50
*/
//% weight=96
//% blockId=synth_set_volume block="set volume %volume"
//% parts="speaker" blockGap=8
//% volume.min=0 volume.max=256
//% volume.min=0 volume.max=100
//% help=music/set-volume
//% weight=1
void setVolume(int volume) {
currVolume = max(0, min(100, volume * 100 / 256));
currVolume = max(0, min(100, volume));
}
#define SOUND_CMD_BREAK 0

View File

@ -3,12 +3,12 @@ declare namespace music {
/**
* Set the output volume of the sound synthesizer.
* @param volume the volume 0...256, eg: 128
* @param volume the volume 0...100, eg: 50
*/
//% weight=96
//% blockId=synth_set_volume block="set volume %volume"
//% parts="speaker" blockGap=8
//% volume.min=0 volume.max=256
//% volume.min=0 volume.max=100
//% help=music/set-volume
//% weight=1 shim=music::setVolume
function setVolume(volume: int32): void;

View File

@ -175,7 +175,7 @@ namespace sounds {
export const mechanicalMotorStop = music.fromWAV(hex``);
//% fixedInstance jres block="mechanical ratchet"
export const mechanicalRatchet = music.fromWAV(hex``);
//% fixedInstance jres block='"mechanical sonar"'
//% fixedInstance jres block="mechanical sonar"
export const mechanicalSonar = music.fromWAV(hex``);
//% fixedInstance jres block="mechanical tick tack"
export const mechanicalTickTack = music.fromWAV(hex``);
@ -291,6 +291,9 @@ namespace music {
export function playSoundEffect(sound: Sound) {
if (!sound || numSoundsPlaying >= soundsLimit) return;
numSoundsPlaying++;
control.runInBackground(() => {sound.play(); numSoundsPlaying--;});
control.runInParallel(() => {
sound.play();
numSoundsPlaying--;
});
}
}

View 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."
}

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

View File

@ -0,0 +1,202 @@
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 = toCSV(data, this.csvSeparator);
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);
}
}
}
export function toCSV(data: number[], sep: string) {
let s = ""
for (const d of data) {
if (s) s += sep;
s = s + d;
}
s += "\r\n"
return s;
}
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
View 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
View 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);
})
}

View File

@ -1,11 +1,11 @@
# Touch Sensor
```cards
sensors.touchSensor1.onEvent(TouchSensorEvent.Pressed, function () {
sensors.touch1.onEvent(TouchSensorEvent.Pressed, function () {
brick.showImage(images.expressionsBigSmile)
})
sensors.touchSensor1.isPressed();
sensors.touchSensor1.wasPressed();
sensors.touch1.isPressed();
sensors.touch1.wasPressed();
```
## See Also

Some files were not shown because too many files have changed in this diff Show More