Compare commits
44 Commits
Author | SHA1 | Date | |
---|---|---|---|
12b1eb349b | |||
68dc195ea4 | |||
0251b914f2 | |||
1fc818767c | |||
9aeaec477f | |||
7fc796d2cb | |||
cb1cd2a4b4 | |||
39bd7aa0eb | |||
140ba64462 | |||
42fe96aa5a | |||
1a5b42026d | |||
9fe649aa3c | |||
a97dfb17b2 | |||
277c9903bb | |||
0de8a84de2 | |||
a302bbfc2b | |||
bcb682b602 | |||
e4a7531541 | |||
348964c888 | |||
8b3461bebd | |||
e511630c2e | |||
db156d5df0 | |||
93c6975400 | |||
abc93dd7da | |||
85cfc86bf8 | |||
b66d4f2d64 | |||
5843deab11 | |||
8d5edc38bb | |||
0309e50058 | |||
aa40e7b169 | |||
75cf8da396 | |||
db9b6a995b | |||
fb255edafe | |||
f4c39f74e8 | |||
3e56e2c3e2 | |||
79b5f8cc88 | |||
312729142f | |||
5bd4aed0e1 | |||
cfaa4ae3ef | |||
faa839d59f | |||
630687bfce | |||
2b300a4094 | |||
5fb8c0de6e | |||
1f65cd59a8 |
9
.travis.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "8.9.0"
|
||||||
|
script:
|
||||||
|
- "node node_modules/pxt-core/built/pxt.js travis"
|
||||||
|
sudo: false
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- node_modules
|
25
README.md
@ -1,10 +1,8 @@
|
|||||||
# LEGO® MINDSTORMS® Education EV3 for Microsoft MakeCode
|
# LEGO® MINDSTORMS® Education EV3 for Microsoft MakeCode [](https://travis-ci.org/microsoft/pxt-ev3)
|
||||||
|
|
||||||
[](https://ci2.dot.net/job/Private/job/pxt_project_rainbow/job/master/job/pxt-ev3_Push/)
|
|
||||||
|
|
||||||
This repo contains the editor target hosted at https://makecode.mindstorms.com
|
This repo contains the editor target hosted at https://makecode.mindstorms.com
|
||||||
|
|
||||||
## Local Dev setup
|
## Local setup
|
||||||
|
|
||||||
These instructions assume familiarity with dev tools and languages.
|
These instructions assume familiarity with dev tools and languages.
|
||||||
|
|
||||||
@ -12,10 +10,6 @@ These instructions assume familiarity with dev tools and languages.
|
|||||||
* install Docker; make sure `docker` command is in your `PATH`
|
* install Docker; make sure `docker` command is in your `PATH`
|
||||||
* (optional) install [Visual Studio Code](https://code.visualstudio.com/)
|
* (optional) install [Visual Studio Code](https://code.visualstudio.com/)
|
||||||
|
|
||||||
In a common folder,
|
|
||||||
|
|
||||||
* clone https://github.com/Microsoft/pxt to ``pxt`` folder
|
|
||||||
* clone https://github.com/Microsoft/pxt-common-packages to ``pxt-common-packages`` folder
|
|
||||||
* clone https://github.com/Microsoft/pxt-ev3 to ``pxt-ev3`` folder
|
* clone https://github.com/Microsoft/pxt-ev3 to ``pxt-ev3`` folder
|
||||||
* go to ``pxt`` and run
|
* go to ``pxt`` and run
|
||||||
|
|
||||||
@ -23,6 +17,18 @@ In a common folder,
|
|||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* to run the local server,
|
||||||
|
```
|
||||||
|
pxt serve --cloud
|
||||||
|
```
|
||||||
|
|
||||||
|
## Local Dev setup
|
||||||
|
|
||||||
|
In the common folder,
|
||||||
|
|
||||||
|
* clone https://github.com/Microsoft/pxt to ``pxt`` folder
|
||||||
|
* clone https://github.com/Microsoft/pxt-common-packages to ``pxt-common-packages`` folder
|
||||||
|
|
||||||
* go to ``pxt-common-packages`` and run
|
* go to ``pxt-common-packages`` and run
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -54,9 +60,6 @@ cd libs/core
|
|||||||
pxt deploy
|
pxt deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
### Jenkins build
|
|
||||||
https://ci2.dot.net/job/Private/job/pxt_project_rainbow/job/master/
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
MIT
|
MIT
|
||||||
|
|
||||||
|
@ -19,11 +19,14 @@
|
|||||||
* [What Animal Am I?](/tutorials/what-animal-am-i)
|
* [What Animal Am I?](/tutorials/what-animal-am-i)
|
||||||
* [Music Brick](/tutorials/music-brick)
|
* [Music Brick](/tutorials/music-brick)
|
||||||
* [Run Motors](/tutorials/run-motors)
|
* [Run Motors](/tutorials/run-motors)
|
||||||
|
* [Tank ZigZag](/tutorials/tank-zigzag)
|
||||||
* [Touch to Run](/tutorials/touch-to-run)
|
* [Touch to Run](/tutorials/touch-to-run)
|
||||||
* [Touch Sensor Values](/tutorials/touch-sensor-values)
|
* [Touch Sensor Values](/tutorials/touch-sensor-values)
|
||||||
* [What Color?](/tutorials/what-color)
|
* [What Color?](/tutorials/what-color)
|
||||||
* [Line Following](/tutorials/line-following)
|
* [Line Following](/tutorials/line-following)
|
||||||
* [Red Light, Green Light](/tutorials/redlight-greenlight)
|
* [Red Light, Green Light](/tutorials/redlight-greenlight)
|
||||||
|
* [Reflected Light Measure](/tutorials/reflected-light-measure)
|
||||||
|
* [Reflected Light Calibration](/tutorials/reflected-light-calibration)
|
||||||
* [Object Near?](/tutorials/object-near)
|
* [Object Near?](/tutorials/object-near)
|
||||||
* [Security Alert](/tutorials/security-alert)
|
* [Security Alert](/tutorials/security-alert)
|
||||||
|
|
||||||
|
@ -190,12 +190,10 @@ if (true) {
|
|||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
forever(function () {
|
forever(function () {
|
||||||
while (true) {
|
while (sensors.color3.color() == ColorSensorColor.Black) {
|
||||||
sensors.color3.pauseUntilColorDetected(ColorSensorColor.Black)
|
|
||||||
motors.largeBC.steer(-30, 50)
|
motors.largeBC.steer(-30, 50)
|
||||||
}
|
}
|
||||||
while (true) {
|
while (sensors.color3.color() == ColorSensorColor.White) {
|
||||||
sensors.color3.pauseUntilColorDetected(ColorSensorColor.White)
|
|
||||||
motors.largeBC.steer(30, 50)
|
motors.largeBC.steer(30, 50)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -209,11 +207,9 @@ Else the Color Sensor detects the color white, start motors ``B`` and ``C`` (dri
|
|||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
forever(function () {
|
forever(function () {
|
||||||
if (true) {
|
if (sensors.color3.color() == ColorSensorColor.Black) {
|
||||||
sensors.color3.pauseUntilColorDetected(ColorSensorColor.Black)
|
|
||||||
motors.largeBC.steer(-30, 50)
|
motors.largeBC.steer(-30, 50)
|
||||||
} else {
|
} else {
|
||||||
sensors.color3.pauseUntilColorDetected(ColorSensorColor.White)
|
|
||||||
motors.largeBC.steer(30, 50)
|
motors.largeBC.steer(30, 50)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
18
docs/extensions.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Extensions
|
||||||
|
|
||||||
|
## #gallery
|
||||||
|
|
||||||
|
## Using Extensions
|
||||||
|
|
||||||
|
In the web editor, click on ``Settings`` then ``Extensions`` to search and add extensions to the project.
|
||||||
|
The Blocks and JavaScript definitions will be automatically loaded in the editor.
|
||||||
|
|
||||||
|
## Custom extensions
|
||||||
|
|
||||||
|
The [Build Your Own Extension](https://makecode.com/extensions/getting-started) manual is for advanced users who want to publish their own extension.
|
||||||
|
|
||||||
|
## ~ hint
|
||||||
|
|
||||||
|
**Extensions** were previously called **Packages** in MakeCode.
|
||||||
|
|
||||||
|
## ~
|
14
docs/fll.md
@ -2,10 +2,16 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
For teams participating in the Open Software Platform Pilot utilizing MakeCode, we’ve compiled a list of resources and information that we hope will be helpful for you.
|
**For teams participating in the Open Software Platform Pilot utilizing MakeCode**, we’ve compiled a list of resources and information that we hope will be helpful for you.
|
||||||
|
|
||||||
|
* **Got a question? Post it on the forums** at https://forum.makecode.com/
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
|
### I found a bug what do I do?
|
||||||
|
|
||||||
|
If you found a bug, please try if it hasn't been fixed yet! Go to https://makecode.mindstorms.com/beta and try if the bug is corrected. Otherwise, please tell us at https://forum.makecode.com/.
|
||||||
|
|
||||||
### How do I use MakeCode with my EV3?
|
### How do I use MakeCode with my EV3?
|
||||||
|
|
||||||
* You will need to install the latest EV3 firmware on your brick. Instructions on how to do that are located here: https://makecode.mindstorms.com/troubleshoot.
|
* You will need to install the latest EV3 firmware on your brick. Instructions on how to do that are located here: https://makecode.mindstorms.com/troubleshoot.
|
||||||
@ -104,9 +110,3 @@ For other common questions, try the FAQ page https://makecode.mindstorms.com/faq
|
|||||||
|
|
||||||
>* Description: Unable to delete program files from the EV3 brick after downloading them
|
>* Description: Unable to delete program files from the EV3 brick after downloading them
|
||||||
>* Status: LEGO Education team is working on a fix, no estimated date yet
|
>* Status: LEGO Education team is working on a fix, no estimated date yet
|
||||||
|
|
||||||
## Community connection
|
|
||||||
|
|
||||||
For questions, issues, feedback and community for the Open Software Platform Pilot:
|
|
||||||
|
|
||||||
We are using a messaging service called **Slack**. Slack can be accessed via an app you download to your computer or mobile device, and via a web interface. For more information about Slack, click [here](https://slack.com/). Anyone in the pilot can participate by signing up with Slack first, and then clicking this [FIRST LEGO League Robot SW](https://fllrobotsw.slack.com/join/shared_invite/enQtNDgxOTQ5MDc2OTkyLTg2ZTRkYzQ4OGMyZTg1OTZmMDFhMWNlOTQ1OWRlNDdmNzNmMjlhMmZiM2M3OWUxYjU1ODEwY2FmODJkNjZkOTA) link to join the Slack workspace.
|
|
||||||
|
@ -25,6 +25,12 @@
|
|||||||
"description": "Build a robot and drive into the world of robotics!",
|
"description": "Build a robot and drive into the world of robotics!",
|
||||||
"url": "/getting-started/use",
|
"url": "/getting-started/use",
|
||||||
"cardType": "side"
|
"cardType": "side"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "First LEGO League",
|
||||||
|
"imageUrl": "/static/fll/fll-big.png",
|
||||||
|
"description": "Information about using MakeCode in FLL competitions",
|
||||||
|
"url": "/fll"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
3
docs/packages-ref.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"redirect": "/extensions"
|
||||||
|
}
|
3
docs/packages/approval-ref.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"redirect": "https://makecode.com/extensions/approval"
|
||||||
|
}
|
3
docs/packages/build-your-own-ref.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"redirect": "https://makecode.com/extensions/getting-started"
|
||||||
|
}
|
3
docs/packages/versioning-ref.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"redirect": "https://makecode.com/extensions/versioning"
|
||||||
|
}
|
@ -39,6 +39,13 @@ motors.largeBC.steer(-15, -75)
|
|||||||
|
|
||||||
## ~
|
## ~
|
||||||
|
|
||||||
|
## ~ hint
|
||||||
|
|
||||||
|
Only one set of synchronized motors will run at the same time. Once you launch tank/steer, it will cancel any existing synchronized speed command.
|
||||||
|
|
||||||
|
## ~
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Make a slight right
|
### Make a slight right
|
||||||
@ -79,6 +86,51 @@ for (let i = 0; i < 4; i++) {
|
|||||||
motors.stopAll()
|
motors.stopAll()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Steer tester
|
||||||
|
|
||||||
|
This program lets you change the values of speed and turn ratio with the buttons.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
let speed = 0;
|
||||||
|
let turnRatio = 0;
|
||||||
|
|
||||||
|
brick.showString(`steer tester`, 1)
|
||||||
|
brick.showString(`connect motors BC`, 7)
|
||||||
|
brick.showString(`up/down for speed`, 8)
|
||||||
|
brick.showString(`left/right for turn ratio`, 9)
|
||||||
|
|
||||||
|
forever(function () {
|
||||||
|
brick.showString(`motor B speed ${motors.largeB.speed()}%`, 4)
|
||||||
|
brick.showString(`motor C speed ${motors.largeC.speed()}%`, 5)
|
||||||
|
pause(100)
|
||||||
|
})
|
||||||
|
|
||||||
|
function updateSteer() {
|
||||||
|
motors.largeBC.steer(turnRatio, speed);
|
||||||
|
brick.showString(`speed ${speed}%`, 2)
|
||||||
|
brick.showString(`turnRatio ${turnRatio}`, 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
brick.buttonUp.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
speed += 10
|
||||||
|
updateSteer()
|
||||||
|
})
|
||||||
|
brick.buttonDown.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
speed -= 10
|
||||||
|
updateSteer()
|
||||||
|
})
|
||||||
|
brick.buttonLeft.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
turnRatio -= 10
|
||||||
|
updateSteer()
|
||||||
|
})
|
||||||
|
brick.buttonRight.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
turnRatio += 10
|
||||||
|
updateSteer()
|
||||||
|
})
|
||||||
|
|
||||||
|
updateSteer()
|
||||||
|
```
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
[tank](/reference/motors/synced/tank), [run](/reference/motors/motor/run)
|
[tank](/reference/motors/synced/tank), [run](/reference/motors/motor/run)
|
@ -35,6 +35,12 @@ motors.largeBC.tank(-75, -75)
|
|||||||
|
|
||||||
## ~
|
## ~
|
||||||
|
|
||||||
|
## ~ hint
|
||||||
|
|
||||||
|
Only one set of synchronized motors will run at the same time. Once you launch tank/steer, it will cancel any existing synchronized speed command.
|
||||||
|
|
||||||
|
## ~
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Tank forward and backward
|
### Tank forward and backward
|
||||||
@ -76,6 +82,51 @@ pause(5000)
|
|||||||
motors.stopAll()
|
motors.stopAll()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Tank tester
|
||||||
|
|
||||||
|
This program lets you change the tank values using the brick buttons
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
let tankB = 0;
|
||||||
|
let tankC = 0;
|
||||||
|
|
||||||
|
brick.showString(`tank tester`, 1)
|
||||||
|
brick.showString(`connect motors BC`, 7)
|
||||||
|
brick.showString(`up/down for tank B`, 8)
|
||||||
|
brick.showString(`left/right for tank C`, 9)
|
||||||
|
|
||||||
|
forever(function () {
|
||||||
|
brick.showString(`motor B speed ${motors.largeB.speed()}%`, 4)
|
||||||
|
brick.showString(`motor C speed ${motors.largeC.speed()}%`, 5)
|
||||||
|
pause(100)
|
||||||
|
})
|
||||||
|
|
||||||
|
function updateTank() {
|
||||||
|
brick.showString(`tank A: ${tankB}%`, 2)
|
||||||
|
brick.showString(`tank B: ${tankC}%`, 3)
|
||||||
|
motors.largeBC.tank(tankB, tankC);
|
||||||
|
}
|
||||||
|
|
||||||
|
brick.buttonUp.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
tankB += 10
|
||||||
|
updateTank();
|
||||||
|
})
|
||||||
|
brick.buttonDown.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
tankB -= 10
|
||||||
|
updateTank();
|
||||||
|
})
|
||||||
|
brick.buttonRight.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
tankC += 10
|
||||||
|
updateTank();
|
||||||
|
})
|
||||||
|
brick.buttonLeft.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
tankC -= 10
|
||||||
|
updateTank();
|
||||||
|
})
|
||||||
|
|
||||||
|
updateTank();
|
||||||
|
```
|
||||||
|
|
||||||
## See also
|
## See also
|
||||||
|
|
||||||
[steer](/reference/motors/synced/steer), [run](/reference/motors/motor/run)
|
[steer](/reference/motors/synced/steer), [run](/reference/motors/motor/run)
|
BIN
docs/static/fll/fll-big.png
vendored
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
docs/static/tutorials/pivot-turn.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
docs/static/tutorials/reflected-light-calibration.png
vendored
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
docs/static/tutorials/reflected-light-measure.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
docs/static/tutorials/smooth-turn.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
docs/static/tutorials/spin-turn.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
docs/static/tutorials/tank-zigzag.png
vendored
Normal file
After Width: | Height: | Size: 19 KiB |
@ -2,113 +2,41 @@
|
|||||||
|
|
||||||
Step by step guides to coding your @boardname@.
|
Step by step guides to coding your @boardname@.
|
||||||
|
|
||||||
## Brick
|
## Tutorials
|
||||||
|
|
||||||
```codecard
|
```codecard
|
||||||
[{
|
[{
|
||||||
"name": "Wake Up!",
|
"name": "Brick",
|
||||||
"description": "Show different moods on the screen. Is it tired, sleepy, or awake?",
|
"description": "Learn how to use the screen and the buttons",
|
||||||
"cardType": "tutorial",
|
"url":"/tutorials/brick",
|
||||||
"url":"/tutorials/wake-up",
|
|
||||||
"imageUrl":"/static/tutorials/wake-up.png"
|
"imageUrl":"/static/tutorials/wake-up.png"
|
||||||
}, {
|
}, {
|
||||||
"name": "Make an Animation",
|
"name": "Motors",
|
||||||
"description": "Create a custom animation on your EV3 Brick Display.",
|
"description": "User motors to move the brick.",
|
||||||
"cardType": "tutorial",
|
"url":"/tutorials/motors",
|
||||||
"url":"/tutorials/make-an-animation",
|
|
||||||
"imageUrl":"/static/tutorials/make-an-animation.png"
|
|
||||||
}, {
|
|
||||||
"name": "What Animal Am I?",
|
|
||||||
"description": "Create different animal effects and have someone guess what the animal is.",
|
|
||||||
"cardType": "tutorial",
|
|
||||||
"url":"/tutorials/what-animal-am-i",
|
|
||||||
"imageUrl":"/static/tutorials/what-animal-am-i.png"
|
|
||||||
}, {
|
|
||||||
"name": "Music Brick",
|
|
||||||
"description": "Transform the brick into a musical instrument!",
|
|
||||||
"cardType": "tutorial",
|
|
||||||
"url":"/tutorials/music-brick",
|
|
||||||
"imageUrl":"/static/tutorials/music-brick.png"
|
|
||||||
}]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Motors
|
|
||||||
|
|
||||||
```codecard
|
|
||||||
[{
|
|
||||||
"name": "Run Motors",
|
|
||||||
"description": "Use the EV3 Brick buttons to start and stop the Large Motor and Medium Motor.",
|
|
||||||
"cardType": "tutorial",
|
|
||||||
"url":"/tutorials/run-motors",
|
|
||||||
"imageUrl":"/static/tutorials/run-motors.png"
|
"imageUrl":"/static/tutorials/run-motors.png"
|
||||||
}]
|
}, {
|
||||||
```
|
"name": "Touch Sensor",
|
||||||
|
"description": "Use touch sensors in your robot.",
|
||||||
## Touch Sensor
|
"url":"/tutorials/touch-sensor",
|
||||||
|
|
||||||
```codecard
|
|
||||||
[{
|
|
||||||
"name": "Touch to Run",
|
|
||||||
"description": "Press the Touch Sensor and run a motor.",
|
|
||||||
"cardType": "tutorial",
|
|
||||||
"url":"/tutorials/touch-to-run",
|
|
||||||
"imageUrl":"/static/tutorials/touch-to-run.png"
|
"imageUrl":"/static/tutorials/touch-to-run.png"
|
||||||
}, {
|
}, {
|
||||||
"name": "Touch Sensor Values",
|
"name": "Color Sensor",
|
||||||
"description": "Check the value of a Touch Sensor and stop a motor if pressed.",
|
"description": "Use the color sensor to follow line or detect colors",
|
||||||
"cardType": "tutorial",
|
"url":"/tutorials/color-sensor",
|
||||||
"url":"/tutorials/touch-sensor-values",
|
|
||||||
"imageUrl":"/static/tutorials/touch-sensor-values.png"
|
|
||||||
}]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Color Sensor
|
|
||||||
|
|
||||||
```codecard
|
|
||||||
[{
|
|
||||||
"name": "What Color?",
|
|
||||||
"description": "Use the Color Sensor to detect different colors.",
|
|
||||||
"cardType": "tutorial",
|
|
||||||
"url":"/tutorials/what-color",
|
|
||||||
"imageUrl":"/static/tutorials/what-color.png"
|
"imageUrl":"/static/tutorials/what-color.png"
|
||||||
}, {
|
}, {
|
||||||
"name": "Line Following",
|
"name": "Infrared Sensor",
|
||||||
"description": "Use the Color Sensor to make a robot follow a line.",
|
"description": "Use the infrared sensor to detect objects",
|
||||||
"cardType": "tutorial",
|
"url":"/tutorials/infrared-sensor",
|
||||||
"url":"/tutorials/line-following",
|
|
||||||
"imageUrl":"/static/tutorials/line-following.png"
|
|
||||||
}, {
|
|
||||||
"name": "Red Light, Green Light",
|
|
||||||
"description": "Play Red Light, Green Light using the Color Sensor and the robot.",
|
|
||||||
"cardType": "tutorial",
|
|
||||||
"url":"/tutorials/redlight-greenlight",
|
|
||||||
"imageUrl":"/static/tutorials/redlight-greenlight.png"
|
|
||||||
}]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Infrared Sensor
|
|
||||||
|
|
||||||
```codecard
|
|
||||||
[{
|
|
||||||
"name": "Security Alert",
|
|
||||||
"description": "Build an security alert using the Infrared Sensor.",
|
|
||||||
"cardType": "tutorial",
|
|
||||||
"url":"/tutorials/security-alert",
|
|
||||||
"imageUrl":"/static/tutorials/security-alert.png"
|
"imageUrl":"/static/tutorials/security-alert.png"
|
||||||
}]
|
}]
|
||||||
```
|
```
|
||||||
|
|
||||||
## See Also
|
## See Also
|
||||||
|
|
||||||
[Wake Up!](/tutorials/wake-up),
|
[Brick tutorials](/tutorials/brick),
|
||||||
[Make An Animation](/tutorials/make-an-animation),
|
[Motors tutorials](/tutorials/motors),
|
||||||
[What Animal Am I?](/tutorials/what-animal-am-i),
|
[Touch sensor tutorials](/tutorials/touch-sensor),
|
||||||
[Music Brick](/tutorials/music-brick),
|
[Color sensor tutorials](/tutorials/color-sensor),
|
||||||
[Run Motors](/tutorials/run-motors),
|
[Infrared sensor tutorials](/tutorials/infrared-sensor)
|
||||||
[Touch to Run](/tutorials/touch-to-run),
|
|
||||||
[Touch Sensor Values](/tutorials/touch-sensor-values),
|
|
||||||
[What Color?](/tutorials/what-color),
|
|
||||||
[Line Following](/tutorials/line-following),
|
|
||||||
[Red Light, Green Light](/tutorials/redlight-greenlight),
|
|
||||||
[Object Near?](/tutorials/object-near),
|
|
||||||
[Security Alert](/tutorials/security-alert)
|
|
||||||
|
38
docs/tutorials/brick.md
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# Brick Tutorials
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
|
```codecard
|
||||||
|
[{
|
||||||
|
"name": "Wake Up!",
|
||||||
|
"description": "Show different moods on the screen. Is it tired, sleepy, or awake?",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/wake-up",
|
||||||
|
"imageUrl":"/static/tutorials/wake-up.png"
|
||||||
|
}, {
|
||||||
|
"name": "Make an Animation",
|
||||||
|
"description": "Create a custom animation on your EV3 Brick Display.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/make-an-animation",
|
||||||
|
"imageUrl":"/static/tutorials/make-an-animation.png"
|
||||||
|
}, {
|
||||||
|
"name": "What Animal Am I?",
|
||||||
|
"description": "Create different animal effects and have someone guess what the animal is.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/what-animal-am-i",
|
||||||
|
"imageUrl":"/static/tutorials/what-animal-am-i.png"
|
||||||
|
}, {
|
||||||
|
"name": "Music Brick",
|
||||||
|
"description": "Transform the brick into a musical instrument!",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/music-brick",
|
||||||
|
"imageUrl":"/static/tutorials/music-brick.png"
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
[Wake Up!](/tutorials/wake-up),
|
||||||
|
[Make An Animation](/tutorials/make-an-animation),
|
||||||
|
[What Animal Am I?](/tutorials/what-animal-am-i),
|
||||||
|
[Music Brick](/tutorials/music-brick),
|
43
docs/tutorials/color-sensor.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# Color Sensor
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
|
```codecard
|
||||||
|
[{
|
||||||
|
"name": "What Color?",
|
||||||
|
"description": "Use the Color Sensor to detect different colors.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/what-color",
|
||||||
|
"imageUrl":"/static/tutorials/what-color.png"
|
||||||
|
}, {
|
||||||
|
"name": "Line Following",
|
||||||
|
"description": "Use the Color Sensor to make a robot follow a line.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/line-following",
|
||||||
|
"imageUrl":"/static/tutorials/line-following.png"
|
||||||
|
}, {
|
||||||
|
"name": "Red Light, Green Light",
|
||||||
|
"description": "Play Red Light, Green Light using the Color Sensor and the robot.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/redlight-greenlight",
|
||||||
|
"imageUrl":"/static/tutorials/redlight-greenlight.png"
|
||||||
|
}, {
|
||||||
|
"name": "Reflected Light Measure",
|
||||||
|
"description": "Teach the sensor what light or dark is.",
|
||||||
|
"cardType": "example",
|
||||||
|
"url":"/tutorials/reflected-light-measure",
|
||||||
|
"imageUrl":"/static/tutorials/reflected-light-measure.png"
|
||||||
|
}, {
|
||||||
|
"name": "Reflected Light Calibration",
|
||||||
|
"description": "Use the auto-calibration feature to setup the dark and bright values.",
|
||||||
|
"cardType": "example",
|
||||||
|
"url":"/tutorials/reflected-light-calibration",
|
||||||
|
"imageUrl":"/static/tutorials/reflected-light-calibration.png"
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
[What Color?](/tutorials/what-color),
|
||||||
|
[Line Following](/tutorials/line-following),
|
||||||
|
[Red Light, Green Light](/tutorials/redlight-greenlight),
|
24
docs/tutorials/infrared-sensor.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Infrared sensor
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
|
```codecard
|
||||||
|
[{
|
||||||
|
"name": "Object Near",
|
||||||
|
"description": "Detect if objects are near.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/object-near",
|
||||||
|
"imageUrl":"/static/tutorials/object-near.png"
|
||||||
|
}, {
|
||||||
|
"name": "Security Alert",
|
||||||
|
"description": "Build an security alert using the Infrared Sensor.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/security-alert",
|
||||||
|
"imageUrl":"/static/tutorials/security-alert.png"
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
[Object Near?](/tutorials/object-near),
|
||||||
|
[Security Alert](/tutorials/security-alert)
|
45
docs/tutorials/motors.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# Motors
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
|
```codecard
|
||||||
|
[{
|
||||||
|
"name": "Run Motors",
|
||||||
|
"description": "Use the EV3 Brick buttons to start and stop the Large Motor and Medium Motor.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/run-motors",
|
||||||
|
"imageUrl":"/static/tutorials/run-motors.png"
|
||||||
|
}, {
|
||||||
|
"name": "Spin Turn",
|
||||||
|
"description": "Turn the driving base around its center.",
|
||||||
|
"cardType": "example",
|
||||||
|
"url":"/tutorials/spin-turn",
|
||||||
|
"imageUrl":"/static/tutorials/spin-turn.png"
|
||||||
|
}, {
|
||||||
|
"name": "Pivot Turn",
|
||||||
|
"description": "Turn the driving base around a wheel.",
|
||||||
|
"cardType": "example",
|
||||||
|
"url":"/tutorials/pivot-turn",
|
||||||
|
"imageUrl":"/static/tutorials/pivot-turn.png"
|
||||||
|
}, {
|
||||||
|
"name": "Smooth Turn",
|
||||||
|
"description": "Turn the driving base in a smooth motion.",
|
||||||
|
"cardType": "example",
|
||||||
|
"url":"/tutorials/smooth-turn",
|
||||||
|
"imageUrl":"/static/tutorials/smooth-turn.png"
|
||||||
|
}, {
|
||||||
|
"name": "Tank ZigZag",
|
||||||
|
"description": "Use the tank block to keep motors in sync.",
|
||||||
|
"cardType": "example",
|
||||||
|
"url":"/tutorials/tank-zigzag",
|
||||||
|
"imageUrl":"/static/tutorials/tank-zigzag.png"
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
[Run Motors](/tutorials/run-motors),
|
||||||
|
[Spin Turn](/tutorials/spin-turn),
|
||||||
|
[Pivot Turn](/tutorials/pivot-turn),
|
||||||
|
[Smooth Turn](/tutorials/smooth-turn),
|
||||||
|
[Tank ZigZag](/tutorials/tank-zigzag),
|
12
docs/tutorials/pivot-turn.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Pivot Turn
|
||||||
|
|
||||||
|
A **pivot turn** happens when a [EV3 Driving Base](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/building-instructions/ev3-rem-driving-base-79bebfc16bd491186ea9c9069842155e.pdf) turns around a wheel by spinning a single wheel.
|
||||||
|
|
||||||
|
You can achieve turn with a ``tank`` or a ``steer`` block.
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
forever(function() {
|
||||||
|
motors.largeBC.tank(50, 0, 2, MoveUnit.Rotations)
|
||||||
|
motors.largeBC.tank(0, 50, 2, MoveUnit.Rotations)
|
||||||
|
})
|
||||||
|
```
|
24
docs/tutorials/reflected-light-calibration.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Reflected light calibration
|
||||||
|
|
||||||
|
The ``calibrateLight`` blocks allows you to calibrate the reflected light of the color sensor in one block. Start the block and move the sensor over the dark and bright surface; then stop moving it.
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
sensors.color3.onLightDetected(LightIntensityMode.Reflected, Light.Dark, function () {
|
||||||
|
brick.showString("dark", 2)
|
||||||
|
})
|
||||||
|
sensors.color3.onLightDetected(LightIntensityMode.Reflected, Light.Bright, function () {
|
||||||
|
brick.showString("bright", 2)
|
||||||
|
})
|
||||||
|
console.sendToScreen()
|
||||||
|
console.log("move color sensor")
|
||||||
|
console.log("over DARK and BRIGHT color")
|
||||||
|
console.log("and stop moving when done")
|
||||||
|
console.log("press ENTER when ready")
|
||||||
|
brick.buttonEnter.pauseUntil(ButtonEvent.Pressed)
|
||||||
|
sensors.color3.calibrateLight(LightIntensityMode.Reflected)
|
||||||
|
brick.showValue("dark", sensors.color3.threshold(Light.Dark), 4)
|
||||||
|
brick.showValue("bright", sensors.color3.threshold(Light.Bright), 5)
|
||||||
|
forever(function () {
|
||||||
|
brick.showValue("reflected light", sensors.color3.light(LightIntensityMode.Reflected), 1)
|
||||||
|
})
|
||||||
|
```
|
29
docs/tutorials/reflected-light-measure.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Reflected light measure
|
||||||
|
|
||||||
|
This example uses a color sensor to measure the reflected light on the dark and light surface
|
||||||
|
and set the light/dark thresholds.
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
sensors.color3.onLightDetected(LightIntensityMode.Reflected, Light.Dark, function () {
|
||||||
|
brick.showString("dark", 2)
|
||||||
|
})
|
||||||
|
sensors.color3.onLightDetected(LightIntensityMode.Reflected, Light.Bright, function () {
|
||||||
|
brick.showString("bright", 2)
|
||||||
|
})
|
||||||
|
console.sendToScreen()
|
||||||
|
console.log("move color sensor")
|
||||||
|
console.log("over DARK color")
|
||||||
|
console.log("press ENTER when ready")
|
||||||
|
brick.buttonEnter.pauseUntil(ButtonEvent.Pressed)
|
||||||
|
sensors.color3.setThreshold(Light.Dark, sensors.color3.light(LightIntensityMode.Reflected) + 5)
|
||||||
|
console.logValue("dark", sensors.color3.threshold(Light.Dark))
|
||||||
|
console.log("move color sensor")
|
||||||
|
console.log("over BRIGHT color")
|
||||||
|
console.log("press ENTER when ready")
|
||||||
|
brick.buttonEnter.pauseUntil(ButtonEvent.Pressed)
|
||||||
|
sensors.color3.setThreshold(Light.Bright, sensors.color3.light(LightIntensityMode.Reflected) - 5)
|
||||||
|
console.logValue("bright", sensors.color3.threshold(Light.Bright))
|
||||||
|
forever(function () {
|
||||||
|
brick.showValue("reflected light", sensors.color3.light(LightIntensityMode.Reflected), 1)
|
||||||
|
})
|
||||||
|
```
|
12
docs/tutorials/smooth-turn.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Smooth Turn
|
||||||
|
|
||||||
|
A **smooth turn** happens when a [EV3 Driving Base](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/building-instructions/ev3-rem-driving-base-79bebfc16bd491186ea9c9069842155e.pdf) turns around both wheels at a different speed.
|
||||||
|
|
||||||
|
You can achieve turn with a ``tank`` or a ``steer`` block.
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
forever(function() {
|
||||||
|
motors.largeBC.tank(50, 20, 2, MoveUnit.Rotations)
|
||||||
|
motors.largeBC.tank(20, 50, 2, MoveUnit.Rotations)
|
||||||
|
})
|
||||||
|
```
|
12
docs/tutorials/spin-turn.md
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Spin Turn
|
||||||
|
|
||||||
|
A **spin turn** happens when a [EV3 Driving Base](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/building-instructions/ev3-rem-driving-base-79bebfc16bd491186ea9c9069842155e.pdf) turns on the spot, by spinning both wheels in opposite directions.
|
||||||
|
|
||||||
|
You can achieve turn with a ``tank`` or a ``steer`` block.
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
forever(function() {
|
||||||
|
motors.largeBC.tank(50, -50, 2, MoveUnit.Rotations)
|
||||||
|
motors.largeBC.tank(-50, 50, 2, MoveUnit.Rotations)
|
||||||
|
})
|
||||||
|
```
|
17
docs/tutorials/tank-zigzag.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Tank ZigZag
|
||||||
|
|
||||||
|
This example shows how to use the [tank](/reference/motors/tank) block to keep the speed of 2 large motors synchronized. In this example, a [EV3 Driving Base](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/building-instructions/ev3-rem-driving-base-79bebfc16bd491186ea9c9069842155e.pdf)
|
||||||
|
) will move on a zig zag pattern.
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
/**
|
||||||
|
* Use the tank block to keep large motors synched.
|
||||||
|
Use this code with a EV3 driving base.
|
||||||
|
*/
|
||||||
|
forever(function () {
|
||||||
|
brick.showImage(images.eyesMiddleRight)
|
||||||
|
motors.largeBC.tank(50, 10, 2, MoveUnit.Rotations)
|
||||||
|
brick.showImage(images.eyesMiddleLeft)
|
||||||
|
motors.largeBC.tank(10, 50, 2, MoveUnit.Rotations)
|
||||||
|
})
|
||||||
|
```
|
24
docs/tutorials/touch-sensor.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Touch Sensor
|
||||||
|
|
||||||
|
## Tutorials
|
||||||
|
|
||||||
|
```codecard
|
||||||
|
[{
|
||||||
|
"name": "Touch to Run",
|
||||||
|
"description": "Press the Touch Sensor and run a motor.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/touch-to-run",
|
||||||
|
"imageUrl":"/static/tutorials/touch-to-run.png"
|
||||||
|
}, {
|
||||||
|
"name": "Touch Sensor Values",
|
||||||
|
"description": "Check the value of a Touch Sensor and stop a motor if pressed.",
|
||||||
|
"cardType": "tutorial",
|
||||||
|
"url":"/tutorials/touch-sensor-values",
|
||||||
|
"imageUrl":"/static/tutorials/touch-sensor-values.png"
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
[Touch to Run](/tutorials/touch-to-run),
|
||||||
|
[Touch Sensor Values](/tutorials/touch-sensor-values),
|
13
ev3.code-workspace
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../pxt-common-packages"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../pxt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,41 +0,0 @@
|
|||||||
import jobs.generation.Utilities;
|
|
||||||
import jobs.generation.InternalUtilities;
|
|
||||||
|
|
||||||
def project = GithubProject
|
|
||||||
def projectName = "pxt-ev3"
|
|
||||||
|
|
||||||
[true, false].each { isPR ->
|
|
||||||
def newJobName = projectName
|
|
||||||
|
|
||||||
if (isPR) {
|
|
||||||
newJobName += "_PR"
|
|
||||||
} else {
|
|
||||||
newJobName += "_Push"
|
|
||||||
}
|
|
||||||
|
|
||||||
def newJob = job(newJobName) {
|
|
||||||
steps {
|
|
||||||
shell("chmod +x ./jenkins.sh")
|
|
||||||
shell("./jenkins.sh ${isPR}")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isPR) {
|
|
||||||
wrappers {
|
|
||||||
credentialsBinding {
|
|
||||||
string("PXT_ACCESS_TOKEN", "pxt_access_token")
|
|
||||||
string("PXT_RELEASE_REPO", "pxt_release_repo_ev3")
|
|
||||||
string("CROWDIN_KEY", "pxt_crowdin_key")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Utilities.setMachineAffinity(newJob, "Ubuntu", "20161020")
|
|
||||||
InternalUtilities.standardJobSetup(newJob, project, isPR, "*/*")
|
|
||||||
|
|
||||||
if (isPR) {
|
|
||||||
Utilities.addGithubPRTrigger(newJob, "Default Testing")
|
|
||||||
} else {
|
|
||||||
Utilities.addGithubPushTrigger(newJob)
|
|
||||||
}
|
|
||||||
}
|
|
56
jenkins.sh
@ -1,56 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
# Set up NVM
|
|
||||||
export NVM_DIR="/home/dotnet-bot/.nvm"
|
|
||||||
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
|
|
||||||
|
|
||||||
nvm install 8
|
|
||||||
|
|
||||||
# Set up build environment variables
|
|
||||||
echo ---------- Setting build environment variables
|
|
||||||
echo Git branch: $GIT_BRANCH
|
|
||||||
echo isPR: $1
|
|
||||||
|
|
||||||
originRegex="^origin/.*"
|
|
||||||
branchRegex="^origin/\K.*(?=$)"
|
|
||||||
releaseBranchRegex="^(master|v\d+)$"
|
|
||||||
|
|
||||||
if [[ "$GIT_BRANCH" =~ $originRegex ]]; then
|
|
||||||
branchName=$(echo ${GIT_BRANCH} | grep -oP $branchRegex)
|
|
||||||
echo Setting TRAVIS_BRANCH to ${branchName}
|
|
||||||
export TRAVIS_BRANCH=${branchName}
|
|
||||||
else
|
|
||||||
echo Setting TRAVIS_BRANCH to $GIT_BRANCH
|
|
||||||
export TRAVIS_BRANCH=$GIT_BRANCH
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$1" == "false" ]; then
|
|
||||||
echo Setting TRAVIS_PULL_REQUEST to false
|
|
||||||
export TRAVIS_PULL_REQUEST=false
|
|
||||||
|
|
||||||
if [[ "$TRAVIS_BRANCH" =~ $releaseBranchRegex ]]; then
|
|
||||||
if [[ -z $PXT_RELEASE_REPO ]]; then
|
|
||||||
echo Cannot find release repo\; skipping tag checks
|
|
||||||
else
|
|
||||||
gitTag=$(git describe --tags --exact-match 2> /dev/null)
|
|
||||||
builtTag=$(git ls-remote --tags $PXT_RELEASE_REPO | grep -o "refs/tags/$gitTag$")
|
|
||||||
|
|
||||||
echo Current tag: $gitTag
|
|
||||||
echo Built tag: $builtTag
|
|
||||||
|
|
||||||
if [[ ! -z $gitTag && -z $builtTag ]]; then
|
|
||||||
echo Built tag not found\; building tag
|
|
||||||
echo Setting TRAVIS_BRANCH to $gitTag
|
|
||||||
export TRAVIS_BRANCH=$gitTag
|
|
||||||
echo Setting TRAVIS_TAG to $gitTag
|
|
||||||
export TRAVIS_TAG=$gitTag
|
|
||||||
else
|
|
||||||
echo Not a tag build
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Perform build
|
|
||||||
npm install
|
|
||||||
npm test
|
|
@ -1,5 +1,5 @@
|
|||||||
const enum ColorSensorMode {
|
const enum ColorSensorMode {
|
||||||
None = -1,
|
None = 0,
|
||||||
//% block="reflected light intensity"
|
//% block="reflected light intensity"
|
||||||
ReflectedLightIntensity = 0,
|
ReflectedLightIntensity = 0,
|
||||||
//% block="ambient light intensity"
|
//% block="ambient light intensity"
|
||||||
@ -15,7 +15,9 @@ enum LightIntensityMode {
|
|||||||
//% block="reflected light"
|
//% block="reflected light"
|
||||||
Reflected = ColorSensorMode.ReflectedLightIntensity,
|
Reflected = ColorSensorMode.ReflectedLightIntensity,
|
||||||
//% block="ambient light"
|
//% block="ambient light"
|
||||||
Ambient = ColorSensorMode.AmbientLightIntensity
|
Ambient = ColorSensorMode.AmbientLightIntensity,
|
||||||
|
//% block="reflected light (raw)"
|
||||||
|
ReflectedRaw = ColorSensorMode.RefRaw
|
||||||
}
|
}
|
||||||
|
|
||||||
const enum ColorSensorColor {
|
const enum ColorSensorColor {
|
||||||
@ -93,6 +95,8 @@ namespace sensors {
|
|||||||
|| this.mode == ColorSensorMode.AmbientLightIntensity
|
|| this.mode == ColorSensorMode.AmbientLightIntensity
|
||||||
|| this.mode == ColorSensorMode.ReflectedLightIntensity)
|
|| this.mode == ColorSensorMode.ReflectedLightIntensity)
|
||||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||||
|
if (this.mode == ColorSensorMode.RefRaw || this.mode == ColorSensorMode.RgbRaw)
|
||||||
|
return this.getNumber(NumberFormat.UInt16LE, 0)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +118,7 @@ namespace sensors {
|
|||||||
|
|
||||||
_update(prev: number, curr: number) {
|
_update(prev: number, curr: number) {
|
||||||
if (this.calibrating) return; // simply ignore data updates while calibrating
|
if (this.calibrating) return; // simply ignore data updates while calibrating
|
||||||
if (this.mode == ColorSensorMode.Color)
|
if (this.mode == ColorSensorMode.Color || this.mode == ColorSensorMode.RgbRaw || this.mode == ColorSensorMode.RefRaw)
|
||||||
control.raiseEvent(this._id, this._colorEventValue(curr));
|
control.raiseEvent(this._id, this._colorEventValue(curr));
|
||||||
else
|
else
|
||||||
this.thresholdDetector.setLevel(curr);
|
this.thresholdDetector.setLevel(curr);
|
||||||
@ -179,6 +183,23 @@ namespace sensors {
|
|||||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current raw rgb values as an array from the color sensor.
|
||||||
|
* @param sensor the color sensor to query the request
|
||||||
|
*/
|
||||||
|
//% help=sensors/color-sensor/rgbraw
|
||||||
|
//% blockId=colorRgbRaw block="**color sensor** %this| RGB raw"
|
||||||
|
//% parts="colorsensor"
|
||||||
|
//% blockNamespace=sensors
|
||||||
|
//% this.fieldEditor="ports"
|
||||||
|
//% weight=1
|
||||||
|
//% group="Color Sensor"
|
||||||
|
//% blockGap=8
|
||||||
|
rgbRaw(): number[] {
|
||||||
|
this.setMode(ColorSensorMode.RgbRaw);
|
||||||
|
return [this.getNumber(NumberFormat.UInt16LE, 0), this.getNumber(NumberFormat.UInt16LE, 2), this.getNumber(NumberFormat.UInt16LE, 4)];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers code to run when the ambient light changes.
|
* Registers code to run when the ambient light changes.
|
||||||
* @param condition the light condition
|
* @param condition the light condition
|
||||||
@ -225,11 +246,16 @@ namespace sensors {
|
|||||||
//% parts="colorsensor"
|
//% parts="colorsensor"
|
||||||
//% blockNamespace=sensors
|
//% blockNamespace=sensors
|
||||||
//% this.fieldEditor="ports"
|
//% this.fieldEditor="ports"
|
||||||
//% weight=87
|
//% weight=87 blockGap=8
|
||||||
//% group="Color Sensor"
|
//% group="Color Sensor"
|
||||||
light(mode: LightIntensityMode) {
|
light(mode: LightIntensityMode) {
|
||||||
this.setMode(<ColorSensorMode><number>mode)
|
this.setMode(<ColorSensorMode><number>mode)
|
||||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
switch(mode) {
|
||||||
|
case LightIntensityMode.ReflectedRaw:
|
||||||
|
return this.reflectedLightRaw();
|
||||||
|
default:
|
||||||
|
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,6 +274,15 @@ namespace sensors {
|
|||||||
return this.light(LightIntensityMode.Reflected);
|
return this.light(LightIntensityMode.Reflected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the raw reflection light value
|
||||||
|
*/
|
||||||
|
//%
|
||||||
|
reflectedLightRaw(): number {
|
||||||
|
this.setMode(ColorSensorMode.RefRaw);
|
||||||
|
return this.getNumber(NumberFormat.UInt16LE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a threshold value
|
* Set a threshold value
|
||||||
* @param condition the dark or bright light condition
|
* @param condition the dark or bright light condition
|
||||||
|
@ -159,12 +159,6 @@ namespace brick {
|
|||||||
if (sl[i])
|
if (sl[i])
|
||||||
ret |= 1 << i
|
ret |= 1 << i
|
||||||
}
|
}
|
||||||
// this needs to be done in query(), which is run without the main JS execution mutex
|
|
||||||
// otherwise, while(true){} will lock the device
|
|
||||||
if (ret & DAL.BUTTON_ID_ESCAPE) {
|
|
||||||
motors.stopAll(); // ensuring that all motors are off
|
|
||||||
control.reset()
|
|
||||||
}
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +25,17 @@ namespace sensors.internal {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function bufferToString(buf: Buffer): string {
|
||||||
|
let s = ''
|
||||||
|
for (let i = 0; i < buf.length; i++)
|
||||||
|
s += String.fromCharCode(buf[i])
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
let analogMM: MMap
|
let analogMM: MMap
|
||||||
let uartMM: MMap
|
let uartMM: MMap
|
||||||
|
let IICMM: MMap
|
||||||
let devcon: Buffer
|
let devcon: Buffer
|
||||||
let sensorInfos: SensorInfo[]
|
let sensorInfos: SensorInfo[]
|
||||||
|
|
||||||
@ -36,11 +45,13 @@ namespace sensors.internal {
|
|||||||
sensors: Sensor[]
|
sensors: Sensor[]
|
||||||
connType: number
|
connType: number
|
||||||
devType: number
|
devType: number
|
||||||
|
iicid: string
|
||||||
|
|
||||||
constructor(p: number) {
|
constructor(p: number) {
|
||||||
this.port = p
|
this.port = p
|
||||||
this.connType = DAL.CONN_NONE
|
this.connType = DAL.CONN_NONE
|
||||||
this.devType = DAL.DEVICE_TYPE_NONE
|
this.devType = DAL.DEVICE_TYPE_NONE
|
||||||
|
this.iicid = ''
|
||||||
this.sensors = []
|
this.sensors = []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,20 +68,21 @@ namespace sensors.internal {
|
|||||||
uartMM = control.mmap("/dev/lms_uart", UartOff.Size, 0)
|
uartMM = control.mmap("/dev/lms_uart", UartOff.Size, 0)
|
||||||
if (!uartMM) control.fail("no uart sensor")
|
if (!uartMM) control.fail("no uart sensor")
|
||||||
|
|
||||||
forever(() => {
|
IICMM = control.mmap("/dev/lms_iic", IICOff.Size, 0)
|
||||||
detectDevices()
|
if (!IICMM) control.fail("no iic sensor")
|
||||||
pause(500)
|
|
||||||
})
|
|
||||||
|
|
||||||
for (let info_ of sensorInfos) {
|
unsafePollForChanges(500,
|
||||||
let info = info_
|
() => { return hashDevices(); },
|
||||||
|
(prev, curr) => { detectDevices();
|
||||||
|
});
|
||||||
|
sensorInfos.forEach(info => {
|
||||||
unsafePollForChanges(50, () => {
|
unsafePollForChanges(50, () => {
|
||||||
if (info.sensor) return info.sensor._query()
|
if (info.sensor) return info.sensor._query()
|
||||||
return 0
|
return 0
|
||||||
}, (prev, curr) => {
|
}, (prev, curr) => {
|
||||||
if (info.sensor) info.sensor._update(prev, curr)
|
if (info.sensor) info.sensor._update(prev, curr)
|
||||||
})
|
})
|
||||||
}
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +101,15 @@ namespace sensors.internal {
|
|||||||
//serial.writeLine("UART " + port + " / " + mode + " - " + info)
|
//serial.writeLine("UART " + port + " / " + mode + " - " + info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function readIICID(port: number) {
|
||||||
|
const buf = output.createBuffer(IICStr.Size)
|
||||||
|
buf[IICStr.Port] = port
|
||||||
|
IICMM.ioctl(IO.IIC_READ_TYPE_INFO, buf)
|
||||||
|
const manufacturer = bufferToString(buf.slice(IICStr.Manufacturer, 8))
|
||||||
|
const sensorType = bufferToString(buf.slice(IICStr.SensorType, 8))
|
||||||
|
return manufacturer + sensorType;
|
||||||
|
}
|
||||||
|
|
||||||
export function getBatteryInfo(): { temp: number; current: number } {
|
export function getBatteryInfo(): { temp: number; current: number } {
|
||||||
init();
|
init();
|
||||||
return {
|
return {
|
||||||
@ -97,52 +118,87 @@ namespace sensors.internal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectDevices() {
|
function hashDevices(): number {
|
||||||
let conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
|
const conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
|
||||||
let numChanged = 0
|
let r = 0;
|
||||||
|
for(let i = 0; i < conns.length; ++i) {
|
||||||
|
r = (r << 8 | conns[i]);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
for (let info of sensorInfos) {
|
let nonActivated = 0;
|
||||||
let newConn = conns[info.port]
|
function detectDevices() {
|
||||||
if (newConn == info.connType)
|
//control.dmesg(`detect devices (${nonActivated} na)`)
|
||||||
continue
|
const conns = analogMM.slice(AnalogOff.InConn, DAL.NUM_INPUTS)
|
||||||
|
let numChanged = 0;
|
||||||
|
const uartSensors: SensorInfo[] = [];
|
||||||
|
|
||||||
|
for (const sensorInfo of sensorInfos) {
|
||||||
|
const newConn = conns[sensorInfo.port]
|
||||||
|
if (newConn == sensorInfo.connType) {
|
||||||
|
// control.dmesg(`connection unchanged ${newConn} at ${sensorInfo.port}`)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
numChanged++
|
numChanged++
|
||||||
info.connType = newConn
|
sensorInfo.connType = newConn
|
||||||
info.devType = DAL.DEVICE_TYPE_NONE
|
sensorInfo.devType = DAL.DEVICE_TYPE_NONE
|
||||||
if (newConn == DAL.CONN_INPUT_UART) {
|
if (newConn == DAL.CONN_INPUT_UART) {
|
||||||
control.dmesg(`new UART connection at ${info.port}`)
|
control.dmesg(`new UART connection at ${sensorInfo.port}`)
|
||||||
setUartMode(info.port, 0)
|
updateUartMode(sensorInfo.port, 0);
|
||||||
let uinfo = readUartInfo(info.port, 0)
|
uartSensors.push(sensorInfo);
|
||||||
info.devType = uinfo[TypesOff.Type]
|
} else if (newConn == DAL.CONN_NXT_IIC) {
|
||||||
control.dmesg(`UART type ${info.devType}`)
|
control.dmesg(`new IIC connection at ${sensorInfo.port}`)
|
||||||
|
sensorInfo.devType = DAL.DEVICE_TYPE_IIC_UNKNOWN
|
||||||
|
sensorInfo.iicid = readIICID(sensorInfo.port)
|
||||||
|
control.dmesg(`IIC ID ${sensorInfo.iicid.length}`)
|
||||||
} else if (newConn == DAL.CONN_INPUT_DUMB) {
|
} else if (newConn == DAL.CONN_INPUT_DUMB) {
|
||||||
control.dmesg(`new DUMB connection at ${info.port}`)
|
control.dmesg(`new DUMB connection at ${sensorInfo.port}`)
|
||||||
// TODO? for now assume touch
|
// TODO? for now assume touch
|
||||||
info.devType = DAL.DEVICE_TYPE_TOUCH
|
sensorInfo.devType = DAL.DEVICE_TYPE_TOUCH
|
||||||
} else if (newConn == DAL.CONN_NONE || newConn == 0) {
|
} else if (newConn == DAL.CONN_NONE || newConn == 0) {
|
||||||
control.dmesg(`disconnect at ${info.port}`)
|
control.dmesg(`disconnect at port ${sensorInfo.port}`)
|
||||||
} else {
|
} else {
|
||||||
control.dmesg(`unknown connection type: ${newConn} at ${info.port}`)
|
control.dmesg(`unknown connection type: ${newConn} at ${sensorInfo.port}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numChanged == 0)
|
if (uartSensors.length > 0) {
|
||||||
|
setUartModes();
|
||||||
|
for (const sensorInfo of uartSensors) {
|
||||||
|
let uinfo = readUartInfo(sensorInfo.port, 0)
|
||||||
|
sensorInfo.devType = uinfo[TypesOff.Type]
|
||||||
|
control.dmesg(`UART type ${sensorInfo.devType}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numChanged == 0 && nonActivated == 0)
|
||||||
return
|
return
|
||||||
|
|
||||||
for (let si of sensorInfos) {
|
control.dmesg(`updating sensor status`)
|
||||||
if (si.sensor && si.sensor._deviceType() != si.devType) {
|
nonActivated = 0;
|
||||||
si.sensor = null
|
for (const sensorInfo of sensorInfos) {
|
||||||
}
|
if (sensorInfo.devType == DAL.DEVICE_TYPE_IIC_UNKNOWN) {
|
||||||
if (si.devType != DAL.DEVICE_TYPE_NONE) {
|
sensorInfo.sensor = sensorInfo.sensors.filter(s => s._IICId() == sensorInfo.iicid)[0]
|
||||||
// TODO figure out compiler problem when '|| null' is added here!
|
if (!sensorInfo.sensor) {
|
||||||
si.sensor = si.sensors.filter(s => s._deviceType() == si.devType)[0]
|
control.dmesg(`sensor not found for iicid=${sensorInfo.iicid} at ${sensorInfo.port}`)
|
||||||
if (si.sensor == null) {
|
nonActivated++;
|
||||||
control.dmesg(`sensor not found for type=${si.devType} at ${si.port}`)
|
|
||||||
} else {
|
} else {
|
||||||
control.dmesg(`sensor connected type=${si.devType} at ${si.port}`)
|
control.dmesg(`sensor connected iicid=${sensorInfo.iicid} at ${sensorInfo.port}`)
|
||||||
si.sensor._activated()
|
sensorInfo.sensor._activated()
|
||||||
|
}
|
||||||
|
} else if (sensorInfo.devType != DAL.DEVICE_TYPE_NONE) {
|
||||||
|
sensorInfo.sensor = sensorInfo.sensors.filter(s => s._deviceType() == sensorInfo.devType)[0]
|
||||||
|
if (!sensorInfo.sensor) {
|
||||||
|
control.dmesg(`sensor not found for type=${sensorInfo.devType} at ${sensorInfo.port}`)
|
||||||
|
nonActivated++;
|
||||||
|
} else {
|
||||||
|
control.dmesg(`sensor connected type=${sensorInfo.devType} at ${sensorInfo.port}`)
|
||||||
|
sensorInfo.sensor._activated()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//control.dmesg(`detect devices done`)
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Sensor extends control.Component {
|
export class Sensor extends control.Component {
|
||||||
@ -187,6 +243,10 @@ namespace sensors.internal {
|
|||||||
_deviceType() {
|
_deviceType() {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_IICId() {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AnalogSensor extends Sensor {
|
export class AnalogSensor extends Sensor {
|
||||||
@ -212,7 +272,6 @@ namespace sensors.internal {
|
|||||||
|
|
||||||
_activated() {
|
_activated() {
|
||||||
this.realmode = 0
|
this.realmode = 0
|
||||||
// uartReset(this.port) // TODO is it ever needed?
|
|
||||||
this._setMode(this.mode)
|
this._setMode(this.mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,6 +302,55 @@ namespace sensors.internal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class IICSensor extends Sensor {
|
||||||
|
protected mode: number // the mode user asked for
|
||||||
|
protected realmode: number // the mode the hardware is in
|
||||||
|
private readLength: number
|
||||||
|
|
||||||
|
constructor(port: number) {
|
||||||
|
super(port)
|
||||||
|
this.mode = 0
|
||||||
|
this.realmode = 0
|
||||||
|
this.readLength = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_activated() {
|
||||||
|
this.realmode = 0
|
||||||
|
this._setMode(this.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _setMode(m: number) {
|
||||||
|
let v = m | 0
|
||||||
|
this.mode = v
|
||||||
|
if (!this.isActive()) return
|
||||||
|
if (this.realmode != this.mode) {
|
||||||
|
this.realmode = v
|
||||||
|
setIICMode(this._port, this._deviceType(), v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getBytes(): Buffer {
|
||||||
|
return getIICBytes(this.isActive() ? this._port : -1, this.readLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
getNumber(fmt: NumberFormat, off: number) {
|
||||||
|
if (!this.isActive())
|
||||||
|
return 0
|
||||||
|
return getIICNumber(this.readLength, fmt, off, this._port)
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction(deviceAddress: number, write: number[], read: number) {
|
||||||
|
this.readLength = read;
|
||||||
|
transactionIIC(this._port, deviceAddress, write, read)
|
||||||
|
}
|
||||||
|
|
||||||
|
_deviceType() {
|
||||||
|
return DAL.DEVICE_TYPE_IIC_UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const iicsensor = new IICSensor(3)
|
||||||
|
|
||||||
function uartReset(port: number) {
|
function uartReset(port: number) {
|
||||||
if (port < 0) return
|
if (port < 0) return
|
||||||
control.dmesg(`UART reset at ${port}`)
|
control.dmesg(`UART reset at ${port}`)
|
||||||
@ -267,6 +375,7 @@ namespace sensors.internal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function uartClearChange(port: number) {
|
function uartClearChange(port: number) {
|
||||||
|
control.dmesg(`UART clear change`);
|
||||||
const UART_DATA_READY = 8
|
const UART_DATA_READY = 8
|
||||||
const UART_PORT_CHANGED = 1
|
const UART_PORT_CHANGED = 1
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -288,20 +397,43 @@ namespace sensors.internal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setUartModes() {
|
||||||
|
control.dmesg(`UART set modes`)
|
||||||
|
uartMM.ioctl(IO.UART_SET_CONN, devcon)
|
||||||
|
const ports: number[] = [];
|
||||||
|
for (let port = 0; port < DAL.NUM_INPUTS; ++port) {
|
||||||
|
if (devcon.getNumber(NumberFormat.Int8LE, DevConOff.Connection + port) == DAL.CONN_INPUT_UART) {
|
||||||
|
ports.push(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ports.length) {
|
||||||
|
const port = ports.pop();
|
||||||
|
const status = waitNonZeroUartStatus(port)
|
||||||
|
control.dmesg(`UART set mode ${status} at ${port}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateUartMode(port: number, mode: number) {
|
||||||
|
control.dmesg(`UART set mode to ${mode} at ${port}`)
|
||||||
|
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_INPUT_UART)
|
||||||
|
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, 33)
|
||||||
|
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode)
|
||||||
|
}
|
||||||
|
|
||||||
function setUartMode(port: number, mode: number) {
|
function setUartMode(port: number, mode: number) {
|
||||||
const UART_PORT_CHANGED = 1
|
const UART_PORT_CHANGED = 1
|
||||||
while (true) {
|
while (true) {
|
||||||
if (port < 0) return
|
if (port < 0) return
|
||||||
control.dmesg(`UART set mode to ${mode} at ${port}`)
|
updateUartMode(port, mode);
|
||||||
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_INPUT_UART)
|
|
||||||
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, 33)
|
|
||||||
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode)
|
|
||||||
uartMM.ioctl(IO.UART_SET_CONN, devcon)
|
uartMM.ioctl(IO.UART_SET_CONN, devcon)
|
||||||
let status = waitNonZeroUartStatus(port)
|
let status = waitNonZeroUartStatus(port)
|
||||||
if (status & UART_PORT_CHANGED) {
|
if (status & UART_PORT_CHANGED) {
|
||||||
|
control.dmesg(`UART clear changed at ${port}`)
|
||||||
uartClearChange(port)
|
uartClearChange(port)
|
||||||
} else {
|
} else {
|
||||||
break
|
control.dmesg(`UART status ${status}`);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
pause(10)
|
pause(10)
|
||||||
}
|
}
|
||||||
@ -322,6 +454,48 @@ namespace sensors.internal {
|
|||||||
UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index + off)
|
UartOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index + off)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setIICMode(port: number, type: number, mode: number) {
|
||||||
|
if (port < 0) return;
|
||||||
|
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Connection + port, DAL.CONN_NXT_IIC)
|
||||||
|
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Type + port, type)
|
||||||
|
devcon.setNumber(NumberFormat.Int8LE, DevConOff.Mode + port, mode)
|
||||||
|
IICMM.ioctl(IO.IIC_SET_CONN, devcon)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transactionIIC(port: number, deviceAddress: number, writeBuf: number[], readLen: number) {
|
||||||
|
if (port < 0) return;
|
||||||
|
let iicdata = output.createBuffer(IICDat.Size)
|
||||||
|
iicdata.setNumber(NumberFormat.Int8LE, IICDat.Port, port)
|
||||||
|
iicdata.setNumber(NumberFormat.Int8LE, IICDat.Repeat, 0)
|
||||||
|
iicdata.setNumber(NumberFormat.Int16LE, IICDat.Time, 0)
|
||||||
|
iicdata.setNumber(NumberFormat.Int8LE, IICDat.WrLng, writeBuf.length + 1)
|
||||||
|
for (let i = 0; i < writeBuf.length; i++)
|
||||||
|
iicdata.setNumber(NumberFormat.Int8LE, IICDat.WrData + i + 1, writeBuf[i])
|
||||||
|
iicdata.setNumber(NumberFormat.Int8LE, IICDat.WrData, deviceAddress)
|
||||||
|
iicdata.setNumber(NumberFormat.Int8LE, IICDat.RdLng, readLen)
|
||||||
|
IICMM.ioctl(IO.IIC_SETUP, iicdata)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIICBytes(port: number, length: number) {
|
||||||
|
if (port < 0) return output.createBuffer(length);
|
||||||
|
let index = IICMM.getNumber(NumberFormat.UInt16LE, IICOff.Actual + port * 2);
|
||||||
|
let buf = IICMM.slice(
|
||||||
|
IICOff.Raw + DAL.MAX_DEVICE_DATALENGTH * 300 * port + DAL.MAX_DEVICE_DATALENGTH * index,
|
||||||
|
length
|
||||||
|
);
|
||||||
|
|
||||||
|
// Reverse
|
||||||
|
for (let i = 0; i < length / 2; i++) {
|
||||||
|
let c = buf[i]
|
||||||
|
buf[i] = buf[length - i - 1]
|
||||||
|
buf[length - i - 1] = c
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getIICNumber(length: number, format: NumberFormat, off: number, port: number) {
|
||||||
|
return getIICBytes(port, length).getNumber(format, off)
|
||||||
|
}
|
||||||
|
|
||||||
const enum NxtColOff {
|
const enum NxtColOff {
|
||||||
Calibration = 0, // uint32[4][3]
|
Calibration = 0, // uint32[4][3]
|
||||||
@ -405,6 +579,52 @@ namespace sensors.internal {
|
|||||||
Size = 58
|
Size = 58
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const enum IICOff {
|
||||||
|
TypeData = 0, // Types[8][4]
|
||||||
|
Repeat = 1792, // uint16[300][4]
|
||||||
|
Raw = 4192, // int8[32][300][4]
|
||||||
|
Actual = 42592, // uint16[4]
|
||||||
|
LogIn = 42600, // uint16[4]
|
||||||
|
Status = 42608, // int8[4]
|
||||||
|
Output = 42612, // int8[32][4]
|
||||||
|
OutputLength = 42740, // int8[4]
|
||||||
|
Size = 42744
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum IICCtlOff {
|
||||||
|
TypeData = 0, // Types
|
||||||
|
Port = 56, // int8
|
||||||
|
Mode = 57, // int8
|
||||||
|
Size = 58
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum IICDat {
|
||||||
|
Result = 0, // result
|
||||||
|
Port = 4, // int8
|
||||||
|
Repeat = 5, // int8
|
||||||
|
Time = 6, // int16
|
||||||
|
WrLng = 8, // int8
|
||||||
|
WrData = 9, // int8[32]
|
||||||
|
RdLng = 41, // int8
|
||||||
|
RdData = 42, //int8[32]
|
||||||
|
Size = 74,
|
||||||
|
}
|
||||||
|
|
||||||
|
const enum IICStr {
|
||||||
|
Port = 0, // int8
|
||||||
|
Time = 2, // int16
|
||||||
|
Type = 4, // int8
|
||||||
|
Mode = 5, // int8
|
||||||
|
Manufacturer = 6, // int8[9]
|
||||||
|
SensorType = 15, // int[9]
|
||||||
|
SetupLng = 24, // int8
|
||||||
|
SetupString = 28, // ulong
|
||||||
|
PollLng = 32, // int8
|
||||||
|
PollString = 36, // ulong
|
||||||
|
ReadLng = 40, // int8
|
||||||
|
Size = 44
|
||||||
|
}
|
||||||
|
|
||||||
const enum IO {
|
const enum IO {
|
||||||
UART_SET_CONN = 0xc00c7500,
|
UART_SET_CONN = 0xc00c7500,
|
||||||
UART_READ_MODE_INFO = 0xc03c7501,
|
UART_READ_MODE_INFO = 0xc03c7501,
|
||||||
@ -472,7 +692,7 @@ namespace sensors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public threshold(t: ThresholdState): number {
|
public threshold(t: ThresholdState): number {
|
||||||
switch(t) {
|
switch (t) {
|
||||||
case ThresholdState.High: return this.highThreshold;
|
case ThresholdState.High: return this.highThreshold;
|
||||||
case ThresholdState.Low: return this.lowThreshold;
|
case ThresholdState.Low: return this.lowThreshold;
|
||||||
default: return (this.max - this.min) / 2;
|
default: return (this.max - this.min) / 2;
|
||||||
@ -512,5 +732,5 @@ namespace sensors {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include "ev3const.h"
|
||||||
|
|
||||||
#define THREAD_DBG(...)
|
#define THREAD_DBG(...)
|
||||||
|
|
||||||
@ -144,6 +147,29 @@ static void startUsb() {
|
|||||||
pthread_detach(pid);
|
pthread_detach(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *exitThread(void *) {
|
||||||
|
int fd = open("/dev/lms_ui", O_RDWR, 0666);
|
||||||
|
if (fd < 0)
|
||||||
|
return 0;
|
||||||
|
uint8_t *data =
|
||||||
|
(uint8_t *)mmap(NULL, NUM_BUTTONS, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (data == MAP_FAILED) {
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
if (data[5])
|
||||||
|
target_reset();
|
||||||
|
sleep_core_us(50000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startExitThread() {
|
||||||
|
pthread_t pid;
|
||||||
|
pthread_create(&pid, NULL, exitThread, NULL);
|
||||||
|
pthread_detach(pid);
|
||||||
|
}
|
||||||
|
|
||||||
void sendUsb(uint16_t code, const char *data, int len) {
|
void sendUsb(uint16_t code, const char *data, int len) {
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
int sz = len;
|
int sz = len;
|
||||||
@ -489,14 +515,22 @@ void runLMS() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void stopMotors() {
|
void stopMotors() {
|
||||||
uint8_t cmd[2] = { 0xA3, 0x0F };
|
uint8_t cmd[3] = {opOutputStop, 0x0F, 0};
|
||||||
int fd = open("/dev/lms_pwm", O_RDWR);
|
int fd = open("/dev/lms_pwm", O_RDWR);
|
||||||
write(fd, cmd, 2);
|
write(fd, cmd, 3);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopProgram() {
|
||||||
|
uint8_t cmd[1] = {opOutputProgramStop};
|
||||||
|
int fd = open("/dev/lms_pwm", O_RDWR);
|
||||||
|
write(fd, cmd, 1);
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void target_reset() {
|
extern "C" void target_reset() {
|
||||||
stopMotors();
|
stopMotors();
|
||||||
|
stopProgram();
|
||||||
if (lmsPid)
|
if (lmsPid)
|
||||||
runLMS();
|
runLMS();
|
||||||
else
|
else
|
||||||
@ -510,6 +544,7 @@ void initRuntime() {
|
|||||||
DMESG("runtime starting...");
|
DMESG("runtime starting...");
|
||||||
stopLMS();
|
stopLMS();
|
||||||
startUsb();
|
startUsb();
|
||||||
|
startExitThread();
|
||||||
pthread_t disp;
|
pthread_t disp;
|
||||||
pthread_create(&disp, NULL, evtDispatcher, NULL);
|
pthread_create(&disp, NULL, evtDispatcher, NULL);
|
||||||
pthread_detach(disp);
|
pthread_detach(disp);
|
||||||
|
@ -134,6 +134,7 @@ namespace motors {
|
|||||||
protected _brake: boolean;
|
protected _brake: boolean;
|
||||||
private _pauseOnRun: boolean;
|
private _pauseOnRun: boolean;
|
||||||
private _initialized: boolean;
|
private _initialized: boolean;
|
||||||
|
private _brakeSettleTime: number;
|
||||||
private _init: () => void;
|
private _init: () => void;
|
||||||
private _run: (speed: number) => void;
|
private _run: (speed: number) => void;
|
||||||
private _move: (steps: boolean, stepsOrTime: number, speed: number) => void;
|
private _move: (steps: boolean, stepsOrTime: number, speed: number) => void;
|
||||||
@ -147,6 +148,7 @@ namespace motors {
|
|||||||
this._brake = false;
|
this._brake = false;
|
||||||
this._pauseOnRun = true;
|
this._pauseOnRun = true;
|
||||||
this._initialized = false;
|
this._initialized = false;
|
||||||
|
this._brakeSettleTime = 10;
|
||||||
this._init = init;
|
this._init = init;
|
||||||
this._run = run;
|
this._run = run;
|
||||||
this._move = move;
|
this._move = move;
|
||||||
@ -204,6 +206,20 @@ namespace motors {
|
|||||||
writePWM(b)
|
writePWM(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the settle time after braking in milliseconds (default is 10ms).
|
||||||
|
*/
|
||||||
|
//% blockId=motorSetBrakeSettleTime block="set %motor|brake settle time %millis|ms"
|
||||||
|
//% motor.fieldEditor="motors"
|
||||||
|
//% weight=1 blockGap=8
|
||||||
|
//% group="Properties"
|
||||||
|
//% millis.defl=200 millis.min=0 millis.max=500
|
||||||
|
setBrakeSettleTime(millis: number) {
|
||||||
|
this.init();
|
||||||
|
// ensure in [0,500]
|
||||||
|
this._brakeSettleTime = Math.max(0, Math.min(500, millis | 0))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the motor(s).
|
* Stops the motor(s).
|
||||||
*/
|
*/
|
||||||
@ -221,8 +237,8 @@ namespace motors {
|
|||||||
protected settle() {
|
protected settle() {
|
||||||
// if we've recently completed a motor command with brake
|
// if we've recently completed a motor command with brake
|
||||||
// allow 500ms for robot to settle
|
// allow 500ms for robot to settle
|
||||||
if (this._brake)
|
if (this._brake && this._brakeSettleTime > 0)
|
||||||
pause(500);
|
pause(this._brakeSettleTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected pauseOnRun(stepsOrTime: number) {
|
protected pauseOnRun(stepsOrTime: number) {
|
||||||
@ -323,7 +339,7 @@ namespace motors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected setOutputType(large: boolean) {
|
protected setOutputType(large: boolean) {
|
||||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||||
if (this._port & (1 << i)) {
|
if (this._port & (1 << i)) {
|
||||||
// (0x07: Large motor, Medium motor = 0x08)
|
// (0x07: Large motor, Medium motor = 0x08)
|
||||||
MotorBase.output_types[i] = large ? 0x07 : 0x08;
|
MotorBase.output_types[i] = large ? 0x07 : 0x08;
|
||||||
@ -396,7 +412,7 @@ namespace motors {
|
|||||||
*/
|
*/
|
||||||
//% blockId=outputMotorSetRegulated block="set %motor|regulated %value=toggleOnOff"
|
//% blockId=outputMotorSetRegulated block="set %motor|regulated %value=toggleOnOff"
|
||||||
//% motor.fieldEditor="motors"
|
//% motor.fieldEditor="motors"
|
||||||
//% weight=58
|
//% weight=58 blockGap=8
|
||||||
//% group="Properties"
|
//% group="Properties"
|
||||||
//% help=motors/motor/set-regulated
|
//% help=motors/motor/set-regulated
|
||||||
setRegulated(value: boolean) {
|
setRegulated(value: boolean) {
|
||||||
@ -545,10 +561,12 @@ namespace motors {
|
|||||||
speedRight = Math.clamp(-100, 100, speedRight >> 0);
|
speedRight = Math.clamp(-100, 100, speedRight >> 0);
|
||||||
|
|
||||||
const speed = Math.abs(speedLeft) > Math.abs(speedRight) ? speedLeft : speedRight;
|
const speed = Math.abs(speedLeft) > Math.abs(speedRight) ? speedLeft : speedRight;
|
||||||
const turnRatio = speedLeft == speed
|
let turnRatio = speedLeft == speed
|
||||||
? (100 - speedRight / speedLeft * 100)
|
? speedLeft == 0 ? 0 : (100 - speedRight / speedLeft * 100)
|
||||||
: (speedLeft / speedRight * 100 - 100);
|
: speedRight == 0 ? 0 : (speedLeft / speedRight * 100 - 100);
|
||||||
|
turnRatio = Math.floor(turnRatio);
|
||||||
|
|
||||||
|
//control.dmesg(`tank ${speedLeft} ${speedRight} => ${turnRatio} ${speed}`)
|
||||||
this.steer(turnRatio, speed, value, unit);
|
this.steer(turnRatio, speed, value, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
```cards
|
```cards
|
||||||
sensors.gyro1.angle();
|
sensors.gyro1.angle();
|
||||||
sensors.gyro1.rate();
|
sensors.gyro1.rate();
|
||||||
|
sensors.gyro1.calibrate();
|
||||||
sensors.gyro1.reset();
|
sensors.gyro1.reset();
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -10,4 +11,6 @@ sensors.gyro1.reset();
|
|||||||
|
|
||||||
[angle](/reference/sensors/gyro/angle),
|
[angle](/reference/sensors/gyro/angle),
|
||||||
[rate](/reference/sensors/gyro/rate),
|
[rate](/reference/sensors/gyro/rate),
|
||||||
|
[reset](/reference/sensors/gyro/calibrate),
|
||||||
[reset](/reference/sensors/gyro/reset)
|
[reset](/reference/sensors/gyro/reset)
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ When the brick changes its position, it's moved in the direction of one of the a
|
|||||||
|
|
||||||
## Accuracy and calibration
|
## Accuracy and calibration
|
||||||
|
|
||||||
Gyro sensors aren't perfectly accurate. Sometimes, because of temperature and changes in the way elecricity behaves in the sensor, the gyro returns a small error in it's measurement. This causes the gyro sensor to return an incorrect value for the amount of angle it detected. This might make your robot drive off course and not go to where you want it to.
|
Gyro sensors aren't perfectly accurate. Sometimes, because of temperature and changes in the way electricity behaves in the sensor, the gyro returns a small error in it's measurement. This causes the gyro sensor to return an incorrect value for the amount of angle it detected. This might make your robot drive off course and not go to where you want it to.
|
||||||
|
|
||||||
### Drift
|
### Drift
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ If you want to turn the tank or robot you built to the left by 45 degrees, you m
|
|||||||
|
|
||||||
The problem is that when you need to read the angle measurement frequently, the amount of error in the angle measurement may continue to increase. If the sensor thought it moved by 45 degrees the first time instead of really 49 degrees, your second turn will put you at 98 degrees when the sensor said 90 degrees. If you want a robot to turn right 90 degrees and drive for 5 meters, it might actually turn 98 degrees and drive 0.7 meters off course before it stops. This error in the sensor's measurement is called _drift_.
|
The problem is that when you need to read the angle measurement frequently, the amount of error in the angle measurement may continue to increase. If the sensor thought it moved by 45 degrees the first time instead of really 49 degrees, your second turn will put you at 98 degrees when the sensor said 90 degrees. If you want a robot to turn right 90 degrees and drive for 5 meters, it might actually turn 98 degrees and drive 0.7 meters off course before it stops. This error in the sensor's measurement is called _drift_.
|
||||||
|
|
||||||
### Time to reset
|
### Calibration
|
||||||
|
|
||||||
If errors in the angle values returned by the gyro sensor are making your project not work right, then it's time to **[reset](/reference/sensors/gyro/reset)**. A reset will return the gyro sensor's current angle value back to `0` and _calibrate_ for drift. Calibration is the process of finding out how much error there is in a sensor's measurement and then removing the error from the value returned to your program.
|
If errors in the angle values returned by the gyro sensor are making your project not work right, then it's time to **[reset](/reference/sensors/gyro/reset)**. A reset will return the gyro sensor's current angle value back to `0` and _calibrate_ for drift. Calibration is the process of finding out how much error there is in a sensor's measurement and then removing the error from the value returned to your program.
|
||||||
|
|
||||||
@ -42,7 +42,14 @@ Turn the brick and press ENTER to see the current rotation angle of `gyro 2`.
|
|||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
|
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
|
||||||
brick.showNumber(sensors.gyro2.angle(), 1)
|
sensors.gyro2.reset()
|
||||||
|
})
|
||||||
|
brick.buttonLeft.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
sensors.gyro2.calibrate()
|
||||||
|
})
|
||||||
|
forever(function () {
|
||||||
|
brick.showNumber(control.millis(), 1)
|
||||||
|
brick.showNumber(sensors.gyro2.angle(), 2)
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
51
libs/gyro-sensor/docs/reference/sensors/gyro/calibrate.md
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# calibrate
|
||||||
|
|
||||||
|
Reset the zero reference for the gyro to current position of the brick.
|
||||||
|
|
||||||
|
```sig
|
||||||
|
sensors.gyro2.calibrate()
|
||||||
|
```
|
||||||
|
|
||||||
|
To make the gyro measure rotation angle from the current position of the brick, it is recalibrated. That is, the brick's current position is set to `0` degrees and rotation angle measurements start from there.
|
||||||
|
|
||||||
|
This function adds a few pauses to ensure that the robot is still. If you only want to reset the sensor, use [reset](/reference/gyro-sensor/reset).
|
||||||
|
|
||||||
|
|
||||||
|
## ~hint
|
||||||
|
|
||||||
|
The current position is considered to be the [_horizon_](https://en.wikipedia.org/wiki/Attitude_indicator) or a place that is the _plane of reference_ (this is possibly someplace that's flat for a horizontal reference).
|
||||||
|
|
||||||
|
## ~
|
||||||
|
|
||||||
|
## ~hint
|
||||||
|
|
||||||
|
**Important**
|
||||||
|
|
||||||
|
To properly reset the gyro, the brick must remain still (undisturbed) while the reset operation takes place.
|
||||||
|
|
||||||
|
## ~
|
||||||
|
|
||||||
|
## Calibration states
|
||||||
|
|
||||||
|
Calibration happens in the following phases and each phase is tracked by the brick status light.
|
||||||
|
|
||||||
|
* **orange**: sensor initialization. This phase ensures that the sensor is in the desired mode and ready to collect data.
|
||||||
|
* **orange pulse**: data collection. Light information is being collected, move the sensor over the various light sources to detect.
|
||||||
|
* **green**: calibration success. The calibration data has been saved.
|
||||||
|
* **red flash**: sensor failure. We were unable to connect to the sensor.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Set the brick on a flat surface. Reset `gyro 2` and tilt the brick slightly. Reset it again while it's still tilted. Lay the brick down flat again and display the angle measurement.
|
||||||
|
|
||||||
|
```blocks
|
||||||
|
brick.buttonLeft.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
sensors.gyro2.calibrate()
|
||||||
|
})
|
||||||
|
forever(function() {
|
||||||
|
brick.showNumber(sensors.gyro2.angle(), 1)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## See also
|
||||||
|
|
||||||
|
[angle](/reference/sensors/gyro/angle), [rate](/reference/sensors/gyro/rate)
|
@ -13,12 +13,39 @@ When the brick is in motion, it moves in the direction of one of axes used to me
|
|||||||
|
|
||||||
* a [number](/types/number) that is the current rate of rotation in degrees per second.
|
* a [number](/types/number) that is the current rate of rotation in degrees per second.
|
||||||
|
|
||||||
|
## ~hint
|
||||||
|
|
||||||
|
## Accuracy and calibration
|
||||||
|
|
||||||
|
Gyro sensors aren't perfectly accurate. Sometimes, because of temperature and changes in the way electricity behaves in the sensor, the gyro returns a small error in it's measurement. This causes the gyro sensor to return an incorrect value for the amount of angle it detected. This might make your robot drive off course and not go to where you want it to.
|
||||||
|
|
||||||
|
### Drift
|
||||||
|
|
||||||
|
If you want to turn the tank or robot you built to the left by 45 degrees, you might run the motor on the right side until the gyro reported that you turned by 45 degrees. What if the gyro was getting an error of 4 degrees every time it measured an angle? You may have actually turned 49 degrees when you expected to turn 45 degrees. Well, that might not be too bad if you use the gyro's angle value only once. It's fine if you just wanted to turn and stop or drive a short distance in only that direction.
|
||||||
|
|
||||||
|
The problem is that when you need to read the angle measurement frequently, the amount of error in the angle measurement may continue to increase. If the sensor thought it moved by 45 degrees the first time instead of really 49 degrees, your second turn will put you at 98 degrees when the sensor said 90 degrees. If you want a robot to turn right 90 degrees and drive for 5 meters, it might actually turn 98 degrees and drive 0.7 meters off course before it stops. This error in the sensor's measurement is called _drift_.
|
||||||
|
|
||||||
|
### Calibration
|
||||||
|
|
||||||
|
If errors in the angle values returned by the gyro sensor are making your project not work right, then it's time to **[reset](/reference/sensors/gyro/reset)**. A reset will return the gyro sensor's current angle value back to `0` and _calibrate_ for drift. Calibration is the process of finding out how much error there is in a sensor's measurement and then removing the error from the value returned to your program.
|
||||||
|
|
||||||
|
Are you using a gyro sensor in your project and need accuracy for your angle values? You should reset the gyro sensor at a regular intervals to improve precision in the values reported to your program.
|
||||||
|
|
||||||
|
## ~
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
Flash the status light to red if the roll rate of `gyro 2` is more that `30` degrees per second.
|
Flash the status light to red if the roll rate of `gyro 2` is more that `30` degrees per second.
|
||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
|
brick.buttonEnter.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
sensors.gyro2.reset()
|
||||||
|
})
|
||||||
|
brick.buttonLeft.onEvent(ButtonEvent.Pressed, function () {
|
||||||
|
sensors.gyro2.calibrate()
|
||||||
|
})
|
||||||
forever(function () {
|
forever(function () {
|
||||||
|
brick.showNumber(sensors.gyro2.rate(), 2)
|
||||||
if (sensors.gyro2.rate() > 30) {
|
if (sensors.gyro2.rate() > 30) {
|
||||||
brick.setStatusLight(StatusLight.RedFlash)
|
brick.setStatusLight(StatusLight.RedFlash)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# reset
|
# reset
|
||||||
|
|
||||||
Reset the zero reference for the gyro to current position of the brick.
|
Reset the gyro sensor.
|
||||||
|
|
||||||
```sig
|
```sig
|
||||||
sensors.gyro2.reset()
|
sensors.gyro2.reset()
|
||||||
@ -8,6 +8,8 @@ sensors.gyro2.reset()
|
|||||||
|
|
||||||
To make the gyro measure rotation angle from the current position of the brick, it is recalibrated. That is, the brick's current position is set to `0` degrees and rotation angle measurements start from there.
|
To make the gyro measure rotation angle from the current position of the brick, it is recalibrated. That is, the brick's current position is set to `0` degrees and rotation angle measurements start from there.
|
||||||
|
|
||||||
|
This function only resets the sensor; if you wish to have progress indication and a more robust calibration sequence, use [calibrate](/reference/gyro-sensor/calibrate).
|
||||||
|
|
||||||
## ~hint
|
## ~hint
|
||||||
|
|
||||||
The current position is considered to be the [_horizon_](https://en.wikipedia.org/wiki/Attitude_indicator) or a place that is the _plane of reference_ (this is possibly someplace that's flat for a horizontal reference).
|
The current position is considered to be the [_horizon_](https://en.wikipedia.org/wiki/Attitude_indicator) or a place that is the _plane of reference_ (this is possibly someplace that's flat for a horizontal reference).
|
||||||
@ -18,27 +20,18 @@ The current position is considered to be the [_horizon_](https://en.wikipedia.or
|
|||||||
|
|
||||||
**Important**
|
**Important**
|
||||||
|
|
||||||
To properly reset the gyro, the brick must remain still (undistrurbed) while the reset operation takes place.
|
To properly reset the gyro, the brick must remain still (undisturbed) while the reset operation takes place.
|
||||||
|
|
||||||
## ~
|
## ~
|
||||||
|
|
||||||
## Calibration states
|
|
||||||
|
|
||||||
Calibration happens in the following phases and each phase is tracked by the brick status light.
|
|
||||||
|
|
||||||
* **orange**: sensor initialization. This phase ensures that the sensor is in the desired mode and ready to collect data.
|
|
||||||
* **orange pulse**: data collection. Light information is being collected, move the sensor over the various light sources to detect.
|
|
||||||
* **green**: calibration success. The calibration data has been saved.
|
|
||||||
* **red flash**: sensor failure. We were unable to connect to the sensor.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
Set the brick on a flat surface. Reset `gyro 2` and tilt the brick slighly. Reset it again while it's still tilted. Lay the brick down flat again and display the angle measurement.
|
Set the brick on a flat surface. Reset `gyro 2` and tilt the brick slightly. Reset it again while it's still tilted. Lay the brick down flat again and display the angle measurement.
|
||||||
|
|
||||||
```blocks
|
```blocks
|
||||||
brick.buttonLeft.onEvent(ButtonEvent.Pressed, function () {
|
brick.buttonLeft.onEvent(ButtonEvent.Pressed, function () {
|
||||||
sensors.gyro2.reset()
|
sensors.gyro2.reset()
|
||||||
})
|
})
|
||||||
brick.buttonRight.onEvent(ButtonEvent.Pressed, function () {
|
forever(function() {
|
||||||
brick.showNumber(sensors.gyro2.angle(), 1)
|
brick.showNumber(sensors.gyro2.angle(), 1)
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const enum GyroSensorMode {
|
const enum GyroSensorMode {
|
||||||
None = -1,
|
None = 0,
|
||||||
Angle = 0,
|
Angle = 0,
|
||||||
Rate = 1,
|
Rate = 1,
|
||||||
}
|
}
|
||||||
@ -9,12 +9,12 @@ namespace sensors {
|
|||||||
export class GyroSensor extends internal.UartSensor {
|
export class GyroSensor extends internal.UartSensor {
|
||||||
private calibrating: boolean;
|
private calibrating: boolean;
|
||||||
private _drift: number;
|
private _drift: number;
|
||||||
private _drifting: boolean;
|
private _driftCorrection: boolean;
|
||||||
constructor(port: number) {
|
constructor(port: number) {
|
||||||
super(port)
|
super(port)
|
||||||
this.calibrating = false;
|
this.calibrating = false;
|
||||||
this._drift = 0;
|
this._drift = 0;
|
||||||
this._drifting = true;
|
this._driftCorrection = false;
|
||||||
this.setMode(GyroSensorMode.Rate);
|
this.setMode(GyroSensorMode.Rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,14 +70,78 @@ namespace sensors {
|
|||||||
|
|
||||||
this.setMode(GyroSensorMode.Rate);
|
this.setMode(GyroSensorMode.Rate);
|
||||||
let curr = this._query();
|
let curr = this._query();
|
||||||
if (Math.abs(curr) < 20) {
|
if (Math.abs(curr) < 4 && this._driftCorrection) {
|
||||||
const p = 0.0005;
|
const p = 0.01;
|
||||||
this._drift = (1 - p) * this._drift + p * curr;
|
this._drift = (1 - p) * this._drift + p * curr;
|
||||||
curr -= this._drift;
|
curr = Math.round(curr - this._drift);
|
||||||
}
|
}
|
||||||
return curr;
|
return curr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forces a calibration of the with light progress indicators.
|
||||||
|
* Must be called when the sensor is completely still.
|
||||||
|
*/
|
||||||
|
//% help=sensors/gyro/calibrate
|
||||||
|
//% block="calibrate **gyro** %this|"
|
||||||
|
//% blockId=gyroCalibrate
|
||||||
|
//% parts="gyroscope"
|
||||||
|
//% blockNamespace=sensors
|
||||||
|
//% this.fieldEditor="ports"
|
||||||
|
//% weight=51 blockGap=8
|
||||||
|
//% group="Gyro Sensor"
|
||||||
|
calibrate(): void {
|
||||||
|
if (this.calibrating) return; // already in calibration mode
|
||||||
|
|
||||||
|
const statusLight = brick.statusLight(); // save current status light
|
||||||
|
brick.setStatusLight(StatusLight.Orange);
|
||||||
|
|
||||||
|
this.calibrating = true;
|
||||||
|
// may be triggered by a button click,
|
||||||
|
// give time for robot to settle
|
||||||
|
pause(700);
|
||||||
|
|
||||||
|
// calibrating
|
||||||
|
brick.setStatusLight(StatusLight.OrangePulse);
|
||||||
|
|
||||||
|
// send a reset command
|
||||||
|
super.reset();
|
||||||
|
// wait till sensor is live
|
||||||
|
pauseUntil(() => this.isActive(), 7000);
|
||||||
|
// mode toggling
|
||||||
|
this.setMode(GyroSensorMode.Rate);
|
||||||
|
this.setMode(GyroSensorMode.Angle);
|
||||||
|
// switch back to the desired mode
|
||||||
|
this.setMode(this.mode);
|
||||||
|
|
||||||
|
// check sensor is ready
|
||||||
|
if (!this.isActive()) {
|
||||||
|
brick.setStatusLight(StatusLight.RedFlash); // didn't work
|
||||||
|
pause(2000);
|
||||||
|
brick.setStatusLight(statusLight); // restore previous light
|
||||||
|
this.calibrating = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute drift
|
||||||
|
this._drift = 0;
|
||||||
|
if (this._driftCorrection && this.mode == GyroSensorMode.Rate) {
|
||||||
|
const n = 100;
|
||||||
|
for (let i = 0; i < n; ++i) {
|
||||||
|
this._drift += this._query();
|
||||||
|
pause(4);
|
||||||
|
}
|
||||||
|
this._drift /= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
brick.setStatusLight(StatusLight.Green); // success
|
||||||
|
pause(1000);
|
||||||
|
brick.setStatusLight(statusLight); // resture previous light
|
||||||
|
|
||||||
|
// and we're done
|
||||||
|
this.calibrating = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Forces a calibration of the gyro. Must be called when the sensor is completely still.
|
* Forces a calibration of the gyro. Must be called when the sensor is completely still.
|
||||||
*/
|
*/
|
||||||
@ -92,49 +156,10 @@ namespace sensors {
|
|||||||
reset(): void {
|
reset(): void {
|
||||||
if (this.calibrating) return; // already in calibration mode
|
if (this.calibrating) return; // already in calibration mode
|
||||||
|
|
||||||
const statusLight = brick.statusLight(); // save current status light
|
|
||||||
brick.setStatusLight(StatusLight.Orange);
|
|
||||||
|
|
||||||
this.calibrating = true;
|
this.calibrating = true;
|
||||||
// may be triggered by a button click,
|
|
||||||
// give time for robot to settle
|
|
||||||
pause(700);
|
|
||||||
// send a reset command
|
// send a reset command
|
||||||
super.reset();
|
super.reset();
|
||||||
// switch back to the desired mode
|
// and done
|
||||||
this.setMode(this.mode);
|
|
||||||
// wait till sensor is live
|
|
||||||
pauseUntil(() => this.isActive(), 5000);
|
|
||||||
|
|
||||||
// check sensor is ready
|
|
||||||
if (!this.isActive()) {
|
|
||||||
brick.setStatusLight(StatusLight.RedFlash); // didn't work
|
|
||||||
pause(2000);
|
|
||||||
brick.setStatusLight(statusLight); // restore previous light
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// give it a bit of time to init
|
|
||||||
pause(1000)
|
|
||||||
|
|
||||||
// calibrating
|
|
||||||
brick.setStatusLight(StatusLight.OrangePulse);
|
|
||||||
|
|
||||||
// compute drift
|
|
||||||
this._drift = 0;
|
|
||||||
if (this.mode == GyroSensorMode.Rate) {
|
|
||||||
for (let i = 0; i < 200; ++i) {
|
|
||||||
this._drift += this._query();
|
|
||||||
pause(4);
|
|
||||||
}
|
|
||||||
this._drift /= 200;
|
|
||||||
}
|
|
||||||
|
|
||||||
brick.setStatusLight(StatusLight.Green); // success
|
|
||||||
pause(1000);
|
|
||||||
brick.setStatusLight(statusLight); // resture previous light
|
|
||||||
|
|
||||||
// and we're done
|
|
||||||
this.calibrating = false;
|
this.calibrating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +177,8 @@ namespace sensors {
|
|||||||
*/
|
*/
|
||||||
//%
|
//%
|
||||||
setDriftCorrection(enabled: boolean) {
|
setDriftCorrection(enabled: boolean) {
|
||||||
this._drifting = enabled;
|
this._driftCorrection = enabled;
|
||||||
|
this._drift = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const enum InfraredSensorMode {
|
const enum InfraredSensorMode {
|
||||||
None = -1,
|
None = 0,
|
||||||
Proximity = 0,
|
Proximity = 0,
|
||||||
Seek = 1,
|
Seek = 1,
|
||||||
RemoteControl = 2,
|
RemoteControl = 2,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "storage",
|
"name": "storage",
|
||||||
"description": "USB Pen-drive support and flash storage",
|
"description": "USB Pen-drive support and flash storage - beta",
|
||||||
"files": [
|
"files": [
|
||||||
"storage.cpp",
|
"storage.cpp",
|
||||||
"storage-core.ts",
|
"storage-core.ts",
|
||||||
|
4670
package-lock.json
generated
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "pxt-ev3",
|
"name": "pxt-ev3",
|
||||||
"version": "1.0.11",
|
"version": "1.1.16",
|
||||||
"description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode",
|
"description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode",
|
||||||
"private": true,
|
"private": false,
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"JavaScript",
|
"JavaScript",
|
||||||
"education",
|
"education",
|
||||||
@ -39,7 +39,7 @@
|
|||||||
"webfonts-generator": "^0.4.0"
|
"webfonts-generator": "^0.4.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pxt-common-packages": "0.23.56",
|
"pxt-common-packages": "0.23.61",
|
||||||
"pxt-core": "4.0.9"
|
"pxt-core": "4.0.9"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
"libs/infrared-sensor",
|
"libs/infrared-sensor",
|
||||||
"libs/gyro-sensor",
|
"libs/gyro-sensor",
|
||||||
"libs/screen",
|
"libs/screen",
|
||||||
"libs/ev3"
|
"libs/ev3",
|
||||||
|
"libs/storage"
|
||||||
],
|
],
|
||||||
"simulator": {
|
"simulator": {
|
||||||
"autoRun": true,
|
"autoRun": true,
|
||||||
@ -112,7 +113,7 @@
|
|||||||
"docMenu": [
|
"docMenu": [
|
||||||
{
|
{
|
||||||
"name": "Support",
|
"name": "Support",
|
||||||
"path": "https://www.lego.com/service/"
|
"path": "https://forum.makecode.com/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Troubleshoot",
|
"name": "Troubleshoot",
|
||||||
|
@ -27,6 +27,7 @@ namespace pxsim.sensors {
|
|||||||
|
|
||||||
export function __sensorUsed(port: number, type: number) {
|
export function __sensorUsed(port: number, type: number) {
|
||||||
//console.log("SENSOR INIT " + port + ", type: " + type);
|
//console.log("SENSOR INIT " + port + ", type: " + type);
|
||||||
|
if (type == DAL.DEVICE_TYPE_IIC_UNKNOWN) return; // Ignore IIC
|
||||||
if (!ev3board().hasSensor(port)) {
|
if (!ev3board().hasSensor(port)) {
|
||||||
const sensor = ev3board().getSensor(port, type);
|
const sensor = ev3board().getSensor(port, type);
|
||||||
runtime.queueDisplayUpdate();
|
runtime.queueDisplayUpdate();
|
||||||
|
@ -63,6 +63,12 @@ namespace pxsim {
|
|||||||
delete this.speedCmd;
|
delete this.speedCmd;
|
||||||
delete this.speedCmdValues;
|
delete this.speedCmdValues;
|
||||||
delete this._synchedMotor;
|
delete this._synchedMotor;
|
||||||
|
this.setChangedState();
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSyncCmd() {
|
||||||
|
if (this._synchedMotor)
|
||||||
|
this.clearSpeedCmd();
|
||||||
}
|
}
|
||||||
|
|
||||||
setLarge(large: boolean) {
|
setLarge(large: boolean) {
|
||||||
@ -179,11 +185,13 @@ namespace pxsim {
|
|||||||
case DAL.opOutputStepSync:
|
case DAL.opOutputStepSync:
|
||||||
case DAL.opOutputTimeSync: {
|
case DAL.opOutputTimeSync: {
|
||||||
const otherMotor = this._synchedMotor;
|
const otherMotor = this._synchedMotor;
|
||||||
if (otherMotor.port < this.port) // handled in other motor code
|
|
||||||
break;
|
|
||||||
|
|
||||||
const speed = this.speedCmdValues[0];
|
const speed = this.speedCmdValues[0];
|
||||||
const turnRatio = this.speedCmdValues[1];
|
const turnRatio = this.speedCmdValues[1];
|
||||||
|
// if turnratio is negative, right motor at power level
|
||||||
|
// right motor -> this.port > otherMotor.port
|
||||||
|
if (Math.sign(this.port - otherMotor.port)
|
||||||
|
== Math.sign(turnRatio))
|
||||||
|
break; // handled in other motor code
|
||||||
const stepsOrTime = this.speedCmdValues[2];
|
const stepsOrTime = this.speedCmdValues[2];
|
||||||
const brake = this.speedCmdValues[3];
|
const brake = this.speedCmdValues[3];
|
||||||
const dstep = this.speedCmd == DAL.opOutputTimeSync
|
const dstep = this.speedCmd == DAL.opOutputTimeSync
|
||||||
@ -199,12 +207,7 @@ namespace pxsim {
|
|||||||
|
|
||||||
// turn ratio is a bit weird to interpret
|
// turn ratio is a bit weird to interpret
|
||||||
// see https://communities.theiet.org/blogs/698/1706
|
// see https://communities.theiet.org/blogs/698/1706
|
||||||
if (turnRatio < 0) {
|
otherMotor.speed = this.speed * (100 - Math.abs(turnRatio)) / 100;
|
||||||
otherMotor.speed = speed;
|
|
||||||
this.speed *= (100 + turnRatio) / 100;
|
|
||||||
} else {
|
|
||||||
otherMotor.speed = this.speed * (100 - turnRatio) / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
// clamp
|
// clamp
|
||||||
this.speed = Math.max(-100, Math.min(100, this.speed >> 0));
|
this.speed = Math.max(-100, Math.min(100, this.speed >> 0));
|
||||||
|
@ -80,6 +80,12 @@ namespace pxsim {
|
|||||||
const brake = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 12);
|
const brake = pxsim.BufferMethods.getNumber(buf, BufferMethods.NumberFormat.Int8LE, 12);
|
||||||
|
|
||||||
const motors = ev3board().getMotor(port);
|
const motors = ev3board().getMotor(port);
|
||||||
|
// cancel any other sync command
|
||||||
|
for(const motor of ev3board().getMotors().filter(motor => motors.indexOf(motor) < 0)) {
|
||||||
|
motor.clearSyncCmd()
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply commands to all motors
|
||||||
for (const motor of motors) {
|
for (const motor of motors) {
|
||||||
const otherMotor = motors.filter(m => m.port != motor.port)[0];
|
const otherMotor = motors.filter(m => m.port != motor.port)[0];
|
||||||
motor.setSyncCmd(
|
motor.setSyncCmd(
|
||||||
|
@ -9,7 +9,11 @@
|
|||||||
},
|
},
|
||||||
"galleries": {
|
"galleries": {
|
||||||
"Getting Started": "getting-started",
|
"Getting Started": "getting-started",
|
||||||
"Tutorials": "tutorials",
|
"Brick Tutorials": "tutorials/brick",
|
||||||
|
"Motor Tutorials": "tutorials/motors",
|
||||||
|
"Touch Sensor Tutorials": "tutorials/touch-sensor",
|
||||||
|
"Color Sensor Tutorials": "tutorials/color-sensor",
|
||||||
|
"Infrared Sensor Tutorials": "tutorials/infrared-sensor",
|
||||||
"Design Engineering": "design-engineering",
|
"Design Engineering": "design-engineering",
|
||||||
"Coding": "coding",
|
"Coding": "coding",
|
||||||
"Maker": "maker",
|
"Maker": "maker",
|
||||||
|