Compare commits
38 Commits
Author | SHA1 | Date | |
---|---|---|---|
4e99cd3ef1 | |||
57647318c4 | |||
2720698864 | |||
c0bab4877a | |||
d2a1d10ada | |||
bcb68d937d | |||
05a8395028 | |||
3a1601a419 | |||
712c2178d2 | |||
12cdad72c8 | |||
95076f8f24 | |||
6391620373 | |||
86212e2153 | |||
98e430f3c1 | |||
5c7e856e7b | |||
a47988913e | |||
ea72dba6c7 | |||
215e846a54 | |||
21b34cb459 | |||
282134f5dc | |||
6b44352839 | |||
9a883d5672 | |||
59ce4338d3 | |||
90560050b8 | |||
2c72173bfe | |||
1a5992408b | |||
0e1a3b7e6b | |||
ea6bfa03bd | |||
20d584db2b | |||
0e4e0d8899 | |||
a18a690417 | |||
c9d57c5e8d | |||
7e9d42a571 | |||
1b51320edb | |||
4f44238237 | |||
c8ffa0ded7 | |||
6b07d5f716 | |||
8784e23b60 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -31,3 +31,4 @@ videos/**
|
||||
lib/
|
||||
.vscode/
|
||||
bin
|
||||
scripts/out.*
|
||||
|
@ -1,6 +1,6 @@
|
||||
# LEGO Mindstorms EV3 target for PXT
|
||||
|
||||
[](https://ci2.dot.net/job/Private/job/pxt_project_pink/job/master/job/pxt-ev3_Push/)
|
||||
[](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://d541eec2-1e96-4b7b-a223-da9d01d0337a.pxt.io/
|
||||
|
||||
|
47
docs/maker.md
Normal file
47
docs/maker.md
Normal file
@ -0,0 +1,47 @@
|
||||
# Maker Activites
|
||||
|
||||
These six activities require the LEGO® MINDSTORMS® Education EV3 Core Set (45544). Supporting materials for teachers and middle school students are provided, offering everything teachers and students need to explore their inner makers as they follow the design process to solve open-ended, themed challenges...
|
||||
|
||||
* [Download Curriculum Materials](https://education.lego.com/en-us/downloads/mindstorms-ev3)
|
||||
|
||||
## Activites
|
||||
|
||||
```codecard
|
||||
[
|
||||
{
|
||||
"name": "Sound Machine",
|
||||
"description": "Create instruments with your EV3 Brick!",
|
||||
"url":"/maker/sound-machine",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/sound-machine.png"
|
||||
},
|
||||
{
|
||||
"name": "Sound Of Color",
|
||||
"description": "Play different sounds based on the color",
|
||||
"url":"/maker/sound-of-color",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/sound-of-color.png"
|
||||
},
|
||||
{
|
||||
"name": "Security Gadget",
|
||||
"description": "Raise the alarm when your brick is lifted!",
|
||||
"url":"/maker/security-gadget",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/security-gadget.png"
|
||||
},
|
||||
{
|
||||
"name": "Intruder Detector",
|
||||
"description": "Raise the alarm when an intruder sneaks in",
|
||||
"url":"/maker/intruder-detector",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/intruder-detector.png"
|
||||
},
|
||||
{
|
||||
"name": "Puppet",
|
||||
"description": "Build an automated puppet",
|
||||
"url":"/maker/puppet",
|
||||
"cardType": "example",
|
||||
"imageUrl": "/static/maker/puppet.png"
|
||||
}
|
||||
]
|
||||
```
|
11
docs/maker/intruder-detector.md
Normal file
11
docs/maker/intruder-detector.md
Normal file
@ -0,0 +1,11 @@
|
||||
# Intruder Detector
|
||||
|
||||
This program will activate an alarm when an object moves in front of the Ultrasonic Sensor.
|
||||
|
||||
TODO support for event when value changes
|
||||
|
||||
```blocks
|
||||
input.ultrasonic4.onObjectNear(function () {
|
||||
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
|
||||
})
|
||||
```
|
17
docs/maker/puppet.md
Normal file
17
docs/maker/puppet.md
Normal file
@ -0,0 +1,17 @@
|
||||
# Puppet
|
||||
|
||||
Use this program with the Programmable Brick and Large Motor.
|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
output.largeMotorA.setPower(30)
|
||||
output.largeMotorA.on(true)
|
||||
loops.pause(100)
|
||||
output.largeMotorA.on(false)
|
||||
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
|
||||
output.largeMotorA.setPower(-30)
|
||||
output.largeMotorA.on(true)
|
||||
loops.pause(100)
|
||||
output.largeMotorA.on(false)
|
||||
})
|
||||
```
|
9
docs/maker/security-gadget.md
Normal file
9
docs/maker/security-gadget.md
Normal file
@ -0,0 +1,9 @@
|
||||
# Security Gadget
|
||||
|
||||
This program will activate an alarm when an object is lifted from the Touch Sensor.
|
||||
|
||||
```blocks
|
||||
input.touchSensor1.onEvent(TouchSensorEvent.Released, function () {
|
||||
music.playSoundUntilDone(music.sounds(Sounds.PowerUp))
|
||||
})
|
||||
```
|
12
docs/maker/sound-machine.md
Normal file
12
docs/maker/sound-machine.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Sound Machine
|
||||
|
||||
This example program combined with the small model will make a beat and rhythm on any surface when the program is run.
|
||||
|
||||
```blocks
|
||||
loops.forever(function () {
|
||||
output.motorA.on(50)
|
||||
loops.pause(200)
|
||||
output.motorA.on(100)
|
||||
loops.pause(200)
|
||||
})
|
||||
```
|
15
docs/maker/sound-of-color.md
Normal file
15
docs/maker/sound-of-color.md
Normal file
@ -0,0 +1,15 @@
|
||||
# Sound Of Color
|
||||
|
||||
This program will play different sounds when the wheel is rotated. The sound is determined by which color is placed in front of the color Sensor.
|
||||
|
||||
```blocks
|
||||
input.color3.onColorDetected(ColorSensorColor.Blue, function () {
|
||||
music.playTone(Note.G4, music.beat(BeatFraction.Half))
|
||||
})
|
||||
input.color3.onColorDetected(ColorSensorColor.Red, function () {
|
||||
music.playTone(Note.C5, music.beat(BeatFraction.Half))
|
||||
})
|
||||
input.color3.onColorDetected(ColorSensorColor.Green, function () {
|
||||
music.playTone(Note.D5, music.beat(BeatFraction.Half))
|
||||
})
|
||||
```
|
BIN
docs/static/hero.png
vendored
Normal file
BIN
docs/static/hero.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
BIN
docs/static/maker/intruder-detector.png
vendored
Normal file
BIN
docs/static/maker/intruder-detector.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
BIN
docs/static/maker/puppet.png
vendored
Normal file
BIN
docs/static/maker/puppet.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 377 KiB |
BIN
docs/static/maker/security-gadget.png
vendored
Normal file
BIN
docs/static/maker/security-gadget.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
BIN
docs/static/maker/sound-machine.png
vendored
Normal file
BIN
docs/static/maker/sound-machine.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 141 KiB |
BIN
docs/static/maker/sound-of-color.png
vendored
Normal file
BIN
docs/static/maker/sound-of-color.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 159 KiB |
@ -21,51 +21,59 @@
|
||||
"input": "Respond to and read data from buttons and sensors.",
|
||||
"input.Button": "Generic button class, for device buttons and sensors.",
|
||||
"input.Button.isPressed": "Check if button is currently pressed or not.",
|
||||
"input.Button.onEvent": "Do something when a button or sensor is clicked, double clicked, etc...",
|
||||
"input.Button.onEvent": "Do something when a button or sensor is clicked, up or down.",
|
||||
"input.Button.onEvent|param|body": "code to run when the event is raised",
|
||||
"input.Button.wasPressed": "See if the button was pressed again since the last time you checked.",
|
||||
"input.ColorSensor.ambientLight": "Get current ambient light value from the color sensor.",
|
||||
"input.ColorSensor.color": "Get the current color from the color sensor.",
|
||||
"input.ColorSensor.onColorDetected": "Registers code to run when the given color is detected",
|
||||
"input.ColorSensor.onColorDetected|param|color": "the color to dtect",
|
||||
"input.ColorSensor.onColorDetected|param|handler": "the code to run when detected",
|
||||
"input.ColorSensor.reflectedLight": "Get current reflected light value from the color sensor.",
|
||||
"input.GyroSensor.angle": "Get the current angle from the gyroscope.",
|
||||
"input.GyroSensor.rate": "Get the current rotation rate from the gyroscope.",
|
||||
"input.IrSensor.distance": "Get the distance measured by the infrared sensor.",
|
||||
"input.IrSensor.remoteCommand": "Get the remote commandreceived the infrared sensor.",
|
||||
"input.InfraredSensor.onObjectNear": "Registers code to run when an object is getting near.",
|
||||
"input.InfraredSensor.onObjectNear|param|handler": "the code to run when detected",
|
||||
"input.InfraredSensor.proximity": "Get the promixity measured by the infrared sensor, from ``0`` (close) to ``100`` (far)",
|
||||
"input.InfraredSensor.remoteCommand": "Get the remote commandreceived the infrared sensor.",
|
||||
"input.RemoteInfraredBeaconButton.isPressed": "Check if a remote button is currently pressed or not.",
|
||||
"input.RemoteInfraredBeaconButton.onEvent": "Do something when a button or sensor is clicked, up or down",
|
||||
"input.RemoteInfraredBeaconButton.onEvent|param|body": "code to run when the event is raised",
|
||||
"input.RemoteInfraredBeaconButton.wasPressed": "See if the remote button was pressed again since the last time you checked.",
|
||||
"input.TouchSensor.isTouched": "Check if touch sensor is touched.",
|
||||
"input.TouchSensor.onEvent": "Do something when a touch sensor is touched...",
|
||||
"input.TouchSensor.onEvent|param|body": "code to run when the event is raised",
|
||||
"input.UltraSonicSensor.distance": "Gets the distance from the sonar in millimeters",
|
||||
"input.UltraSonicSensor.onObjectNear": "Registers code to run when the given color is close",
|
||||
"input.UltraSonicSensor.onObjectNear|param|handler": "the code to run when detected",
|
||||
"input.buttonDown": "Down button on the EV3 Brick.",
|
||||
"input.buttonEnter": "Enter button on the EV3 Brick.",
|
||||
"input.buttonLeft": "Left button on the EV3 Brick.",
|
||||
"input.buttonRight": "Right button on the EV3 Brick.",
|
||||
"input.buttonUp": "Up button on the EV3 Brick.",
|
||||
"input.remoteBottomLeft": "Remote bottom-left button.",
|
||||
"input.remoteBottomRight": "Remote bottom-right button.",
|
||||
"input.remoteCenter": "Remote beacon (center) button.",
|
||||
"input.remoteTopLeft": "Remote top-left button.",
|
||||
"input.remoteTopRight": "Remote top-right button.",
|
||||
"input.remoteButtonBottomLeft": "Remote bottom-left button.",
|
||||
"input.remoteButtonBottomRight": "Remote bottom-right button.",
|
||||
"input.remoteButtonCenter": "Remote beacon (center) button.",
|
||||
"input.remoteButtonTopLeft": "Remote top-left button.",
|
||||
"input.remoteButtonTopRight": "Remote top-right button.",
|
||||
"output.Motor.clearCount": "Clears the motor count",
|
||||
"output.Motor.count": "Gets motor step count.",
|
||||
"output.Motor.on": "Power on or off the motor.",
|
||||
"output.Motor.reset": "Resets the motor.",
|
||||
"output.Motor.setBrake": "Sets the automatic brake on or off when the motor is off",
|
||||
"output.Motor.setBrake|param|brake": "a value indicating if the motor should break when off",
|
||||
"output.Motor.setPower": "Sets the motor power level from ``-100`` to ``100``.",
|
||||
"output.Motor.setPower|param|power": "the desired speed to use. eg: 50",
|
||||
"output.Motor.setReversed": "Reverses the motor polarity",
|
||||
"output.Motor.speed": "Gets motor actual speed.",
|
||||
"output.Motor.tachoCount": "Gets motor tacho count.",
|
||||
"output.createBuffer": "Create a new zero-initialized buffer.",
|
||||
"output.createBuffer|param|size": "number of bytes in the buffer",
|
||||
"output.getCurrentSpeed": "Get motor speed.",
|
||||
"output.getCurrentSpeed|param|out": "the output connection that the motor is connected to",
|
||||
"output.pattern": "Pattern block.",
|
||||
"output.pattern|param|pattern": "the lights pattern to use. eg: LightsPattern.Green",
|
||||
"output.powerMotor": "Switch the motor on or off.",
|
||||
"output.powerMotor|param|on": "1 to turn the motor on, 0 to turn it off",
|
||||
"output.powerMotor|param|out": "the output connection that the motor is connected to",
|
||||
"output.setPower": "Set motor power.",
|
||||
"output.setPower|param|out": "the output connection that the motor is connected to",
|
||||
"output.setPower|param|power": "the desired power to use. eg: 100",
|
||||
"output.setSpeed": "Set motor speed.",
|
||||
"output.setSpeed|param|out": "the output connection that the motor is connected to",
|
||||
"output.setSpeed|param|speed": "the desired speed to use. eg: 100",
|
||||
"output.setStatusLight": "Set lights.",
|
||||
"output.setStatusLight|param|pattern": "the lights pattern to use.",
|
||||
"output.turn": "Turn a motor on for a specified number of milliseconds.",
|
||||
"output.turn|param|ms": "the number of milliseconds to turn the motor on, eg: 500",
|
||||
"output.turn|param|out": "the output connection that the motor is connected to",
|
||||
"output.turn|param|useBrake": "whether or not to use the brake, defaults to false",
|
||||
"output.stopAllMotors": "Stops all motors",
|
||||
"screen.clear": "Clear screen and reset font to normal.",
|
||||
"screen.doubleIcon": "Double size of an icon.",
|
||||
"screen.drawIcon": "Draw an icon on the screen.",
|
||||
@ -73,6 +81,10 @@
|
||||
"screen.print|param|text": "the text to print on the screen, eg: \"Hello world\"",
|
||||
"screen.print|param|x": "the starting position's x coordinate, eg: 0",
|
||||
"screen.print|param|y": "the starting position's x coordinate, eg: 0",
|
||||
"screen.setPixel": "Sets a pixel on or off",
|
||||
"screen.setPixel|param|on": "a value indicating if the pixel should be on or off",
|
||||
"screen.setPixel|param|x": "the starting position's x coordinate, eg: 0",
|
||||
"screen.setPixel|param|y": "the starting position's x coordinate, eg: 0",
|
||||
"serial": "Reading and writing data over a serial connection.",
|
||||
"serial.writeDmesg": "Send DMESG debug buffer over serial."
|
||||
}
|
@ -2,6 +2,14 @@
|
||||
"ButtonEvent.Click|block": "click",
|
||||
"ButtonEvent.Down|block": "down",
|
||||
"ButtonEvent.Up|block": "up",
|
||||
"ColorSensorColor.Black|block": "black",
|
||||
"ColorSensorColor.Blue|block": "blue",
|
||||
"ColorSensorColor.Brown|block": "brown",
|
||||
"ColorSensorColor.Green|block": "green",
|
||||
"ColorSensorColor.None|block": "none",
|
||||
"ColorSensorColor.Red|block": "red",
|
||||
"ColorSensorColor.White|block": "white",
|
||||
"ColorSensorColor.Yellow|block": "yellow",
|
||||
"LightsPattern.GreenFlash|block": "Flashing Green",
|
||||
"LightsPattern.GreenPulse|block": "Pulsing Green",
|
||||
"LightsPattern.Green|block": "Green",
|
||||
@ -12,9 +20,16 @@
|
||||
"LightsPattern.RedFlash|block": "Flashing Red",
|
||||
"LightsPattern.RedPulse|block": "Pulsing Red",
|
||||
"LightsPattern.Red|block": "Red",
|
||||
"Output.ALL|block": "All",
|
||||
"Output.A|block": "A",
|
||||
"Output.B|block": "B",
|
||||
"Output.C|block": "C",
|
||||
"Output.D|block": "D",
|
||||
"PromixityEvent.ObjectDetected|block": "object detected",
|
||||
"PromixityEvent.ObjectNear|block": "object near",
|
||||
"TouchSensorEvent.Bumped|block": "bumped",
|
||||
"TouchSensorEvent.Pressed|block": "pressed",
|
||||
"TouchSensorEvent.Released|block": "released",
|
||||
"TouchSensorEvent.Touched|block": "touched",
|
||||
"control.raiseEvent|block": "raise event|from %src|with value %value",
|
||||
"control|block": "control",
|
||||
"input.Button.isPressed|block": "%button|is pressed",
|
||||
@ -22,14 +37,20 @@
|
||||
"input.Button.wasPressed|block": "%button|was pressed",
|
||||
"input.ColorSensor.ambientLight|block": "%color| ambient light",
|
||||
"input.ColorSensor.color|block": "%color| color",
|
||||
"input.ColorSensor.onColorDetected|block": "on %sensor|detected %color",
|
||||
"input.ColorSensor.reflectedLight|block": "%color| reflected light",
|
||||
"input.GyroSensor.angle|block": "%sensor|angle",
|
||||
"input.GyroSensor.rate|block": "%sensor|rotation rate",
|
||||
"input.IrSensor.distance|block": "%infrared|distance",
|
||||
"input.IrSensor.remoteCommand|block": "%infrared|remote command",
|
||||
"input.InfraredSensor.onObjectNear|block": "on %sensor|object near",
|
||||
"input.InfraredSensor.proximity|block": "%infrared|proximity",
|
||||
"input.InfraredSensor.remoteCommand|block": "%infrared|remote command",
|
||||
"input.RemoteInfraredBeaconButton.isPressed|block": "%button|is pressed",
|
||||
"input.RemoteInfraredBeaconButton.onEvent|block": "on %button|%event",
|
||||
"input.RemoteInfraredBeaconButton.wasPressed|block": "%button|was pressed",
|
||||
"input.TouchSensor.isTouched|block": "%sensor|is touched",
|
||||
"input.TouchSensor.onEvent|block": "on %sensor|%event",
|
||||
"input.UltraSonicSensor.distance|block": "%sensor|distance",
|
||||
"input.UltraSonicSensor.onObjectNear|block": "on %sensor|object near",
|
||||
"input.buttonDown|block": "brick button down",
|
||||
"input.buttonEnter|block": "brick button enter",
|
||||
"input.buttonLeft|block": "brick button left",
|
||||
@ -43,11 +64,15 @@
|
||||
"input.gyro2|block": "gyro sensor 2",
|
||||
"input.gyro3|block": "gyro sensor 3",
|
||||
"input.gyro4|block": "gyro sensor 4",
|
||||
"input.remoteBottomLeft|block": "remote bottom-left",
|
||||
"input.remoteBottomRight|block": "remote bottom-right",
|
||||
"input.remoteCenter|block": "remote center",
|
||||
"input.remoteTopLeft|block": "remote top-left",
|
||||
"input.remoteTopRight|block": "remote top-right",
|
||||
"input.infraredSensor1|block": "infrared sensor 1",
|
||||
"input.infraredSensor2|block": "infrared sensor 2",
|
||||
"input.infraredSensor3|block": "infrared sensor 3",
|
||||
"input.infraredSensor4|block": "infrared sensor 4",
|
||||
"input.remoteButtonBottomLeft|block": "remote button bottom-left",
|
||||
"input.remoteButtonBottomRight|block": "remote button bottom-right",
|
||||
"input.remoteButtonCenter|block": "remote button center",
|
||||
"input.remoteButtonTopLeft|block": "remote button top-left",
|
||||
"input.remoteButtonTopRight|block": "remote button top-right",
|
||||
"input.touchSensor1|block": "touch sensor 1",
|
||||
"input.touchSensor2|block": "touch sensor 2",
|
||||
"input.touchSensor3|block": "touch sensor 3",
|
||||
@ -57,15 +82,27 @@
|
||||
"input.ultrasonic3|block": "ultrasonic sensor 3",
|
||||
"input.ultrasonic4|block": "ultrasonic sensor 4",
|
||||
"input|block": "input",
|
||||
"output.getCurrentSpeed|block": "motor %out|speed",
|
||||
"output.Motor.count|block": "%motor|count",
|
||||
"output.Motor.on|block": "%motor|%onOrOff",
|
||||
"output.Motor.setBrake|block": "%motor|set brake %brake",
|
||||
"output.Motor.setPower|block": "%motor|set power to %speed",
|
||||
"output.Motor.setReversed|block": "%motor|set reversed %reversed",
|
||||
"output.Motor.speed|block": "%motor|speed",
|
||||
"output.Motor.tachoCount|block": "%motor|tacho count",
|
||||
"output.largeMotorA|block": "large motor A",
|
||||
"output.largeMotorB|block": "large motor B",
|
||||
"output.largeMotorC|block": "large motor C",
|
||||
"output.largeMotorD|block": "large motor D",
|
||||
"output.mediumMotorA|block": "medium motor A",
|
||||
"output.mediumMotorB|block": "medium motor B",
|
||||
"output.mediumMotorC|block": "medium motor C",
|
||||
"output.mediumMotorD|block": "medium motor D",
|
||||
"output.pattern|block": "%pattern",
|
||||
"output.powerMotor|block": "power motor %out|%on",
|
||||
"output.setPower|block": "set motor %out| power to %power",
|
||||
"output.setSpeed|block": "set motor %out| speed to %speed",
|
||||
"output.setStatusLight|block": "set status light %pattern=led_pattern",
|
||||
"output.turn|block": "turn motor %out| on for %ms=timePicker|milliseconds",
|
||||
"output.stopAllMotors|block": "stop all motors",
|
||||
"output|block": "output",
|
||||
"screen.print|block": "print %text| at x: %x| y: %y",
|
||||
"screen.setPixel|block": "set pixel %on| at x: %x| y: %y",
|
||||
"screen|block": "screen",
|
||||
"serial|block": "serial",
|
||||
"{id:category}Control": "Control",
|
||||
@ -79,6 +116,7 @@
|
||||
"{id:group}Gyro Sensor": "Gyro Sensor",
|
||||
"{id:group}Infrared Sensor": "Infrared Sensor",
|
||||
"{id:group}Motors": "Motors",
|
||||
"{id:group}Remote Infrared Beacon": "Remote Infrared Beacon",
|
||||
"{id:group}Touch Sensor": "Touch Sensor",
|
||||
"{id:group}Ultrasonic Sensor": "Ultrasonic Sensor"
|
||||
}
|
@ -65,7 +65,7 @@ namespace input {
|
||||
}
|
||||
|
||||
//% hidden
|
||||
update(curr: boolean) {
|
||||
_update(curr: boolean) {
|
||||
if (this._isPressed == curr) return
|
||||
this._isPressed = curr
|
||||
if (curr) {
|
||||
@ -112,7 +112,7 @@ namespace input {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a button or sensor is clicked, double clicked, etc...
|
||||
* Do something when a button or sensor is clicked, up or down.
|
||||
* @param button the button that needs to be clicked or used
|
||||
* @param event the kind of button gesture that needs to be detected
|
||||
* @param body code to run when the event is raised
|
||||
@ -159,7 +159,7 @@ namespace input {
|
||||
if (curr & DAL.BUTTON_ID_ESCAPE)
|
||||
control.reset()
|
||||
for (let b of buttons)
|
||||
b.update(!!(curr & b.mask))
|
||||
b._update(!!(curr & b.mask))
|
||||
})
|
||||
control.dmesg("runtime started, " + control.deviceFirmwareVersion())
|
||||
}
|
||||
|
@ -9,13 +9,21 @@ const enum ColorSensorMode {
|
||||
}
|
||||
|
||||
const enum ColorSensorColor {
|
||||
//% block="none"
|
||||
None,
|
||||
//% block="black"
|
||||
Black,
|
||||
//% block="blue"
|
||||
Blue,
|
||||
//% block="green"
|
||||
Green,
|
||||
//% block="yellow"
|
||||
Yellow,
|
||||
//% block="red"
|
||||
Red,
|
||||
//% block="white"
|
||||
White,
|
||||
//% block="brown"
|
||||
Brown,
|
||||
}
|
||||
|
||||
@ -35,6 +43,35 @@ namespace input {
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
_query() {
|
||||
if (this.mode == ColorSensorMode.Color)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
return 0
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
control.raiseEvent(this._id, curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when the given color is detected
|
||||
* @param color the color to dtect
|
||||
* @param handler the code to run when detected
|
||||
*/
|
||||
//% help=input/color/on-color-detected
|
||||
//% block="on %sensor|detected %color"
|
||||
//% blockId=colorOnColorDetected
|
||||
//% parts="colorsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
onColorDetected(color: ColorSensorColor, handler: () => void) {
|
||||
control.onEvent(this._id, <number>color, handler);
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
if (this.color() == color)
|
||||
control.runInBackground(handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current ambient light value from the color sensor.
|
||||
* @param color the color sensor to query the request
|
||||
|
@ -119,7 +119,8 @@ namespace input.internal {
|
||||
si.sensor = null
|
||||
}
|
||||
if (si.devType != DAL.DEVICE_TYPE_NONE) {
|
||||
si.sensor = si.sensors.filter(s => s._deviceType() == si.devType)[0] || null
|
||||
// TODO figure out compiler problem when '|| null' is added here!
|
||||
si.sensor = si.sensors.filter(s => s._deviceType() == si.devType)[0]
|
||||
if (si.sensor == null) {
|
||||
control.dmesg(`sensor not found for type=${si.devType} at ${si.port}`)
|
||||
} else {
|
||||
@ -139,6 +140,7 @@ namespace input.internal {
|
||||
control.panic(120)
|
||||
this.port = port_ - 1
|
||||
init()
|
||||
sensorInfos[this.port].sensors.push(this)
|
||||
}
|
||||
|
||||
_activated() { }
|
||||
|
210
libs/core/ir.ts
210
libs/core/ir.ts
@ -40,24 +40,24 @@ namespace input {
|
||||
}
|
||||
}
|
||||
|
||||
let buttons: Button[]
|
||||
let buttons: RemoteInfraredBeaconButton[]
|
||||
|
||||
function create(ir: IrSensor) {
|
||||
function create(ir: InfraredSensor) {
|
||||
// it's created by referencing it
|
||||
}
|
||||
|
||||
export function irButton(id: IrRemoteButton) {
|
||||
export function irButton(id: IrRemoteButton): RemoteInfraredBeaconButton {
|
||||
if (buttons == null) {
|
||||
buttons = []
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
buttons.push(new Button())
|
||||
buttons.push(new RemoteInfraredBeaconButton(new Button()))
|
||||
}
|
||||
|
||||
// make sure sensors are up
|
||||
create(ir1)
|
||||
create(ir2)
|
||||
create(ir3)
|
||||
create(ir4)
|
||||
create(infraredSensor1)
|
||||
create(infraredSensor2)
|
||||
create(infraredSensor3)
|
||||
create(infraredSensor4)
|
||||
}
|
||||
|
||||
let num = -1
|
||||
@ -69,29 +69,101 @@ namespace input {
|
||||
return buttons[num]
|
||||
}
|
||||
|
||||
//% fixedInstance
|
||||
export class IrSensor extends internal.UartSensor {
|
||||
private channel: IrRemoteChannel
|
||||
//% fixedInstances
|
||||
export class RemoteInfraredBeaconButton extends control.Component {
|
||||
private button: Button;
|
||||
constructor(button: Button) {
|
||||
super();
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
_update(curr: boolean) {
|
||||
this.button._update(curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a remote button is currently pressed or not.
|
||||
* @param button the remote button to query the request
|
||||
*/
|
||||
//% help=input/remote-infrared-beacon/is-pressed
|
||||
//% block="%button|is pressed"
|
||||
//% blockId=remoteButtonIsPressed
|
||||
//% parts="remote"
|
||||
//% blockNamespace=input
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Remote Infrared Beacon"
|
||||
isPressed() {
|
||||
return this.button.isPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the remote button was pressed again since the last time you checked.
|
||||
* @param button the remote button to query the request
|
||||
*/
|
||||
//% help=input/remote-infrared-beacon/was-pressed
|
||||
//% block="%button|was pressed"
|
||||
//% blockId=remotebuttonWasPressed
|
||||
//% parts="remote"
|
||||
//% blockNamespace=input
|
||||
//% weight=80 blockGap=8
|
||||
//% group="Remote Infrared Beacon"
|
||||
wasPressed() {
|
||||
return this.button.wasPressed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do something when a button or sensor is clicked, up or down
|
||||
* @param button the button that needs to be clicked or used
|
||||
* @param event the kind of button gesture that needs to be detected
|
||||
* @param body code to run when the event is raised
|
||||
*/
|
||||
//% help=input/remote-infrared-beacon/on-event
|
||||
//% blockId=remotebuttonEvent block="on %button|%event"
|
||||
//% parts="remote"
|
||||
//% blockNamespace=input
|
||||
//% weight=99 blockGap=8
|
||||
//% group="Remote Infrared Beacon"
|
||||
onEvent(ev: ButtonEvent, body: () => void) {
|
||||
this.button.onEvent(ev, body);
|
||||
}
|
||||
}
|
||||
|
||||
//% fixedInstances
|
||||
export class InfraredSensor extends internal.UartSensor {
|
||||
private channel: IrRemoteChannel;
|
||||
private proximityThreshold: number;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.channel = IrRemoteChannel.Ch0
|
||||
this.proximityThreshold = 10;
|
||||
irButton(0) // make sure buttons array is initalized
|
||||
|
||||
// and set the mode, as otherwise button events won't work
|
||||
this.mode = IrSensorMode.RemoteControl
|
||||
this.mode = IrSensorMode.RemoteControl;
|
||||
}
|
||||
|
||||
_query() {
|
||||
if (this.mode == IrSensorMode.RemoteControl)
|
||||
return mapButton(this.getNumber(NumberFormat.UInt8LE, this.channel))
|
||||
return mapButton(this.getNumber(NumberFormat.UInt8LE, this.channel));
|
||||
else if (this.mode == IrSensorMode.Proximity) {
|
||||
const d = this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
||||
return d < this.proximityThreshold ? PromixityEvent.ObjectNear
|
||||
: d > this.proximityThreshold + 5 ? PromixityEvent.ObjectDetected
|
||||
: 0;
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
for (let i = 0; i < buttons.length; ++i) {
|
||||
let v = !!(curr & (1 << i))
|
||||
buttons[i].update(v)
|
||||
if (this.mode == IrSensorMode.RemoteControl) {
|
||||
for (let i = 0; i < buttons.length; ++i) {
|
||||
let v = !!(curr & (1 << i))
|
||||
buttons[i]._update(v)
|
||||
}
|
||||
} else {
|
||||
if (curr)
|
||||
control.raiseEvent(this._id, curr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +174,7 @@ namespace input {
|
||||
setRemoteChannel(c: IrRemoteChannel) {
|
||||
c = Math.clamp(0, 3, c | 0)
|
||||
this.channel = c
|
||||
this.setMode(IrSensorMode.RemoteControl)
|
||||
this._setMode(IrSensorMode.RemoteControl)
|
||||
}
|
||||
|
||||
setMode(m: IrSensorMode) {
|
||||
@ -110,18 +182,39 @@ namespace input {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the distance measured by the infrared sensor.
|
||||
* Registers code to run when an object is getting near.
|
||||
* @param handler the code to run when detected
|
||||
*/
|
||||
//% help=input/infrared/on-object-near
|
||||
//% block="on %sensor|object near"
|
||||
//% blockId=infraredOnObjectNear
|
||||
//% parts="infraredsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
onObjectNear(handler: () => void) {
|
||||
control.onEvent(this._id, PromixityEvent.ObjectNear, handler);
|
||||
if (this.proximity() == PromixityEvent.ObjectNear)
|
||||
control.runInBackground(handler);
|
||||
}
|
||||
|
||||
setObjectNearThreshold(distance: number) {
|
||||
this.proximityThreshold = Math.max(1, Math.min(95, distance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the promixity measured by the infrared sensor, from ``0`` (close) to ``100`` (far)
|
||||
* @param ir the infrared sensor
|
||||
*/
|
||||
//% help=input/infrared/distance
|
||||
//% block="%infrared|distance"
|
||||
//% blockId=infraredGetDistance
|
||||
//% help=input/infrared/proximity
|
||||
//% block="%infrared|proximity"
|
||||
//% blockId=infraredGetProximity
|
||||
//% parts="infrared"
|
||||
//% blockNamespace=input
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
distance() {
|
||||
this.setMode(IrSensorMode.Proximity)
|
||||
proximity() {
|
||||
this._setMode(IrSensorMode.Proximity)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
|
||||
@ -137,56 +230,57 @@ namespace input {
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Infrared Sensor"
|
||||
remoteCommand() {
|
||||
this.setMode(IrSensorMode.RemoteControl)
|
||||
this._setMode(IrSensorMode.RemoteControl)
|
||||
return this.getNumber(NumberFormat.UInt8LE, this.channel)
|
||||
}
|
||||
|
||||
// TODO
|
||||
getDirectionAndDistance() {
|
||||
this.setMode(IrSensorMode.Seek)
|
||||
this._setMode(IrSensorMode.Seek)
|
||||
return this.getNumber(NumberFormat.UInt16LE, this.channel * 2)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed
|
||||
export const ir1: IrSensor = new IrSensor(1)
|
||||
//% fixedInstance whenUsed block="infrared sensor 1"
|
||||
export const infraredSensor1: InfraredSensor = new InfraredSensor(1)
|
||||
|
||||
//% whenUsed
|
||||
export const ir2: IrSensor = new IrSensor(2)
|
||||
//% fixedInstance whenUsed block="infrared sensor 2"
|
||||
export const infraredSensor2: InfraredSensor = new InfraredSensor(2)
|
||||
|
||||
//% whenUsed
|
||||
export const ir3: IrSensor = new IrSensor(3)
|
||||
//% fixedInstance whenUsed block="infrared sensor 3"
|
||||
export const infraredSensor3: InfraredSensor = new InfraredSensor(3)
|
||||
|
||||
//% whenUsed
|
||||
export const ir4: IrSensor = new IrSensor(4)
|
||||
//% fixedInstance whenUsed block="infrared sensor 4"
|
||||
export const infraredSensor4: InfraredSensor = new InfraredSensor(4)
|
||||
|
||||
/**
|
||||
* Remote top-left button.
|
||||
*/
|
||||
//% whenUsed block="remote top-left" weight=95 fixedInstance
|
||||
export const remoteTopLeft = irButton(IrRemoteButton.TopLeft)
|
||||
|
||||
/**
|
||||
* Remote top-right button.
|
||||
*/
|
||||
//% whenUsed block="remote top-right" weight=95 fixedInstance
|
||||
export const remoteTopRight = irButton(IrRemoteButton.TopRight)
|
||||
|
||||
/**
|
||||
* Remote bottom-left button.
|
||||
*/
|
||||
//% whenUsed block="remote bottom-left" weight=95 fixedInstance
|
||||
export const remoteBottomLeft = irButton(IrRemoteButton.BottomLeft)
|
||||
|
||||
/**
|
||||
* Remote bottom-right button.
|
||||
*/
|
||||
//% whenUsed block="remote bottom-right" weight=95 fixedInstance
|
||||
export const remoteBottomRight = irButton(IrRemoteButton.BottomRight)
|
||||
|
||||
/**
|
||||
* Remote beacon (center) button.
|
||||
*/
|
||||
//% whenUsed block="remote center" weight=95 fixedInstance
|
||||
export const remoteCenter = irButton(IrRemoteButton.CenterBeacon)
|
||||
//% whenUsed block="remote button center" weight=95 fixedInstance
|
||||
export const remoteButtonCenter = irButton(IrRemoteButton.CenterBeacon)
|
||||
|
||||
/**
|
||||
* Remote top-left button.
|
||||
*/
|
||||
//% whenUsed block="remote button top-left" weight=95 fixedInstance
|
||||
export const remoteButtonTopLeft = irButton(IrRemoteButton.TopLeft)
|
||||
|
||||
/**
|
||||
* Remote top-right button.
|
||||
*/
|
||||
//% whenUsed block="remote button top-right" weight=95 fixedInstance
|
||||
export const remoteButtonTopRight = irButton(IrRemoteButton.TopRight)
|
||||
|
||||
/**
|
||||
* Remote bottom-left button.
|
||||
*/
|
||||
//% whenUsed block="remote button bottom-left" weight=95 fixedInstance
|
||||
export const remoteButtonBottomLeft = irButton(IrRemoteButton.BottomLeft)
|
||||
|
||||
/**
|
||||
* Remote bottom-right button.
|
||||
*/
|
||||
//% whenUsed block="remote button bottom-right" weight=95 fixedInstance
|
||||
export const remoteButtonBottomRight = irButton(IrRemoteButton.BottomRight)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
//% color="#B4009E" weight=98 icon="\uf192"
|
||||
//% groups='["Touch Sensor", "Gyro Sensor", "Color Sensor", "Ultrasonic Sensor", "Infrared Sensor", "Remote", "Brick"]'
|
||||
//% groups='["Brick", "Touch Sensor", "Color Sensor", "Ultrasonic Sensor", "Infrared Sensor", "Remote Infrared Beacon", "Gyro Sensor"]'
|
||||
namespace input {
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
enum Output {
|
||||
//% block="A"
|
||||
A = 0x01,
|
||||
//% block="B"
|
||||
B = 0x02,
|
||||
//% block="C"
|
||||
C = 0x04,
|
||||
//% block="D"
|
||||
D = 0x08,
|
||||
//% block="All"
|
||||
ALL = 0x0f
|
||||
}
|
||||
|
||||
@ -15,7 +20,6 @@ enum OutputType {
|
||||
namespace output {
|
||||
let pwmMM: MMap
|
||||
let motorMM: MMap
|
||||
let currentSpeed: number[] = []
|
||||
|
||||
const enum MotorDataOff {
|
||||
TachoCounts = 0, // int32
|
||||
@ -31,13 +35,7 @@ namespace output {
|
||||
if (!pwmMM) control.fail("no PWM file")
|
||||
motorMM = control.mmap("/dev/lms_motor", MotorDataOff.Size * DAL.NUM_OUTPUTS, 0)
|
||||
|
||||
stop(Output.ALL)
|
||||
|
||||
currentSpeed[Output.A] = -1;
|
||||
currentSpeed[Output.B] = -1;
|
||||
currentSpeed[Output.C] = -1;
|
||||
currentSpeed[Output.D] = -1;
|
||||
currentSpeed[Output.ALL] = -1;
|
||||
resetMotors()
|
||||
|
||||
let buf = output.createBuffer(1)
|
||||
buf[0] = DAL.opProgramStart
|
||||
@ -55,88 +53,173 @@ namespace output {
|
||||
}
|
||||
|
||||
function mkCmd(out: Output, cmd: number, addSize: number) {
|
||||
let b = createBuffer(2 + addSize)
|
||||
const b = createBuffer(2 + addSize)
|
||||
b.setNumber(NumberFormat.UInt8LE, 0, cmd)
|
||||
b.setNumber(NumberFormat.UInt8LE, 1, out)
|
||||
return b
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a motor on for a specified number of milliseconds.
|
||||
* @param out the output connection that the motor is connected to
|
||||
* @param ms the number of milliseconds to turn the motor on, eg: 500
|
||||
* @param useBrake whether or not to use the brake, defaults to false
|
||||
*/
|
||||
//% blockId=output_turn block="turn motor %out| on for %ms=timePicker|milliseconds"
|
||||
//% weight=100 group="Motors"
|
||||
export function turn(out: Output, ms: number, useBrake = false) {
|
||||
// TODO: use current power / speed configuration
|
||||
output.step(out, {
|
||||
speed: 100,
|
||||
step1: 0,
|
||||
step2: ms,
|
||||
step3: 0,
|
||||
useSteps: false,
|
||||
useBrake: useBrake
|
||||
})
|
||||
function resetMotors() {
|
||||
reset(Output.ALL)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switch the motor on or off.
|
||||
* @param out the output connection that the motor is connected to
|
||||
* @param on 1 to turn the motor on, 0 to turn it off
|
||||
* Stops all motors
|
||||
*/
|
||||
//% blockId=outputMotorPowerOnOff block="power motor %out|%on"
|
||||
//% weight=90 group="Motors"
|
||||
//% on.fieldEditor="toggleonoff"
|
||||
export function powerMotor(out: Output, on: boolean, useBrake = false) {
|
||||
if (on) {
|
||||
output.start(out);
|
||||
} else {
|
||||
output.stop(out, useBrake);
|
||||
//% blockId=motorStopAll block="stop all motors"
|
||||
//% weight=10 group="Motors" blockGap=8
|
||||
export function stopAllMotors() {
|
||||
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
//% fixedInstances
|
||||
export class Motor extends control.Component {
|
||||
private port: Output;
|
||||
private large: boolean;
|
||||
private brake: boolean;
|
||||
|
||||
constructor(port: Output, large: boolean) {
|
||||
super();
|
||||
this.port = port;
|
||||
this.large = large;
|
||||
this.brake = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn motor off.
|
||||
* @param out the output connection that the motor is connected to
|
||||
*/
|
||||
//% blockId=output_stop block="turn motor %out|off"
|
||||
//% weight=90 group="Motors"
|
||||
//% deprecated=1
|
||||
export function stop(out: Output, useBrake = false) {
|
||||
let b = mkCmd(out, DAL.opOutputStop, 1)
|
||||
b.setNumber(NumberFormat.UInt8LE, 2, useBrake ? 1 : 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn motor on.
|
||||
* @param out the output connection that the motor is connected to
|
||||
*/
|
||||
//% blockId=output_start block="turn motor %out|on"
|
||||
//% weight=95 group="Motors"
|
||||
//% deprecated=1
|
||||
export function start(out: Output) {
|
||||
if (currentSpeed[out] == -1) setSpeed(out, 50)
|
||||
let b = mkCmd(out, DAL.opOutputStart, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
export function reset(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputReset, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
export function clearCount(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputClearCount, 0)
|
||||
writePWM(b)
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (out & (1 << i)) {
|
||||
motorMM.setNumber(NumberFormat.Int32LE, i * MotorDataOff.Size + MotorDataOff.TachoSensor, 0)
|
||||
/**
|
||||
* Power on or off the motor.
|
||||
* @param motor the motor to turn on
|
||||
* @param power the motor power level from ``-100`` to ``100``, eg: 50
|
||||
*/
|
||||
//% blockId=outputMotorOn block="%motor|%onOrOff"
|
||||
//% onOrOff.fieldEditor=toggleonoff
|
||||
//% weight=99 group="Motors" blockGap=8
|
||||
on(onOrOff: boolean = true) {
|
||||
if (onOrOff) {
|
||||
const b = mkCmd(this.port, DAL.opOutputStart, 0)
|
||||
writePWM(b);
|
||||
} else {
|
||||
const b = mkCmd(this.port, DAL.opOutputStop, 1)
|
||||
b.setNumber(NumberFormat.UInt8LE, 2, this.brake ? 1 : 0)
|
||||
writePWM(b)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the motor power level from ``-100`` to ``100``.
|
||||
* @param motor the output connection that the motor is connected to
|
||||
* @param power the desired speed to use. eg: 50
|
||||
*/
|
||||
//% blockId=motorSetPower block="%motor|set power to %speed"
|
||||
//% weight=62 group="Motors" blockGap=8
|
||||
//% speed.min=-100 speed.max=100
|
||||
setPower(power: number) {
|
||||
const b = mkCmd(this.port, DAL.opOutputPower, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, power))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the automatic brake on or off when the motor is off
|
||||
* @param brake a value indicating if the motor should break when off
|
||||
*/
|
||||
//% blockId=outputMotorSetBrakeMode block="%motor|set brake %brake"
|
||||
//% brake.fieldEditor=toggleonoff
|
||||
//% weight=60 group="Motors" blockGap=8
|
||||
setBrake(brake: boolean) {
|
||||
this.brake = brake;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses the motor polarity
|
||||
*/
|
||||
//% blockId=motorSetReversed block="%motor|set reversed %reversed"
|
||||
//% reversed.fieldEditor=toggleonoff
|
||||
//% weight=59 group="Motors"
|
||||
setReversed(reversed: boolean) {
|
||||
const b = mkCmd(this.port, DAL.opOutputPolarity, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, reversed ? -1 : 1);
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor actual speed.
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorSpeed block="%motor|speed"
|
||||
//% weight=50 group="Motors" blockGap=8
|
||||
speed(): number {
|
||||
return getMotorData(this.port).actualSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor step count.
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorCount block="%motor|count"
|
||||
//% weight=49 group="Motors" blockGap=8
|
||||
count(): number {
|
||||
return getMotorData(this.port).count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets motor tacho count.
|
||||
* @param motor the port which connects to the motor
|
||||
*/
|
||||
//% blockId=motorTachoCount block="%motor|tacho count"
|
||||
//% weight=48 group="Motors"
|
||||
tachoCount(): number {
|
||||
return getMotorData(this.port).tachoCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the motor count
|
||||
*/
|
||||
clearCount() {
|
||||
const b = mkCmd(this.port, DAL.opOutputClearCount, 0)
|
||||
writePWM(b)
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (this.port & (1 << i)) {
|
||||
motorMM.setNumber(NumberFormat.Int32LE, i * MotorDataOff.Size + MotorDataOff.TachoSensor, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the motor.
|
||||
*/
|
||||
reset() {
|
||||
reset(this.port);
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed fixedInstance block="large motor A"
|
||||
export const largeMotorA = new Motor(Output.A, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large motor B"
|
||||
export const largeMotorB = new Motor(Output.B, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large motor C"
|
||||
export const largeMotorC = new Motor(Output.C, true);
|
||||
|
||||
//% whenUsed fixedInstance block="large motor D"
|
||||
export const largeMotorD = new Motor(Output.D, true);
|
||||
|
||||
//% whenUsed fixedInstance block="medium motor A"
|
||||
export const mediumMotorA = new Motor(Output.A, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium motor B"
|
||||
export const mediumMotorB = new Motor(Output.B, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium motor C"
|
||||
export const mediumMotorC = new Motor(Output.C, false);
|
||||
|
||||
//% whenUsed fixedInstance block="medium motor D"
|
||||
export const mediumMotorD = new Motor(Output.D, false);
|
||||
|
||||
function reset(out: Output) {
|
||||
let b = mkCmd(out, DAL.opOutputReset, 0)
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
function outOffset(out: Output) {
|
||||
@ -147,14 +230,14 @@ namespace output {
|
||||
return 0
|
||||
}
|
||||
|
||||
export interface MotorData {
|
||||
interface MotorData {
|
||||
actualSpeed: number; // -100..+100
|
||||
tachoCount: number;
|
||||
count: number;
|
||||
}
|
||||
|
||||
// only a single output at a time
|
||||
export function getMotorData(out: Output): MotorData {
|
||||
function getMotorData(out: Output): MotorData {
|
||||
let buf = motorMM.slice(outOffset(out), MotorDataOff.Size)
|
||||
return {
|
||||
actualSpeed: buf.getNumber(NumberFormat.Int8LE, MotorDataOff.Speed),
|
||||
@ -163,52 +246,7 @@ namespace output {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get motor speed.
|
||||
* @param out the output connection that the motor is connected to
|
||||
*/
|
||||
//% blockId=output_getCurrentSpeed block="motor %out|speed"
|
||||
//% weight=70 group="Motors"
|
||||
export function getCurrentSpeed(out: Output) {
|
||||
return getMotorData(out).actualSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set motor speed.
|
||||
* @param out the output connection that the motor is connected to
|
||||
* @param speed the desired speed to use. eg: 100
|
||||
*/
|
||||
//% blockId=output_setSpeed block="set motor %out| speed to %speed"
|
||||
//% weight=81 group="Motors"
|
||||
//% speed.min=-100 speed.max=100
|
||||
export function setSpeed(out: Output, speed: number) {
|
||||
currentSpeed[out] = speed;
|
||||
let b = mkCmd(out, DAL.opOutputSpeed, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, speed))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set motor power.
|
||||
* @param out the output connection that the motor is connected to
|
||||
* @param power the desired power to use. eg: 100
|
||||
*/
|
||||
//% blockId=output_setPower block="set motor %out| power to %power"
|
||||
//% weight=80 group="Motors"
|
||||
//% power.min=-100 power.max=100
|
||||
export function setPower(out: Output, power: number) {
|
||||
let b = mkCmd(out, DAL.opOutputPower, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-100, 100, power))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
export function setPolarity(out: Output, polarity: number) {
|
||||
let b = mkCmd(out, DAL.opOutputPolarity, 1)
|
||||
b.setNumber(NumberFormat.Int8LE, 2, Math.clamp(-1, 1, polarity))
|
||||
writePWM(b)
|
||||
}
|
||||
|
||||
export interface StepOptions {
|
||||
interface StepOptions {
|
||||
power?: number;
|
||||
speed?: number; // either speed or power has to be present
|
||||
step1: number;
|
||||
@ -218,7 +256,7 @@ namespace output {
|
||||
useBrake?: boolean;
|
||||
}
|
||||
|
||||
export function step(out: Output, opts: StepOptions) {
|
||||
function step(out: Output, opts: StepOptions) {
|
||||
let op = opts.useSteps ? DAL.opOutputStepSpeed : DAL.opOutputTimeSpeed
|
||||
let speed = opts.speed
|
||||
if (speed == null) {
|
||||
|
@ -78,13 +78,21 @@ namespace screen {
|
||||
}
|
||||
}
|
||||
|
||||
export function setPixel(x: number, y: number, mode = Draw.Normal) {
|
||||
/**
|
||||
* Sets a pixel on or off
|
||||
* @param on a value indicating if the pixel should be on or off
|
||||
* @param x the starting position's x coordinate, eg: 0
|
||||
* @param y the starting position's x coordinate, eg: 0
|
||||
*/
|
||||
//% blockId=screen_setpixel block="set pixel %on| at x: %x| y: %y"
|
||||
//% weight=98 group="Brick" blockNamespace=output
|
||||
//% x.min=0 x.max=178 y.min=0 y.max=128 on.fieldEditor=toggleonoff
|
||||
export function setPixel(on: boolean, x: number, y: number) {
|
||||
x |= 0
|
||||
y |= 0
|
||||
if (0 <= x && x < DAL.LCD_WIDTH && 0 <= y && y < DAL.LCD_HEIGHT)
|
||||
_setPixel(x, y, mode)
|
||||
_setPixel(x, y, on ? Draw.Normal : Draw.Clear)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show text on the screen.
|
||||
|
@ -31,17 +31,17 @@ input.buttonUp.onEvent(ButtonEvent.Click, () => {
|
||||
|
||||
let num = 0
|
||||
|
||||
input.touchSensor1.onEvent(ButtonEvent.Click, () => {
|
||||
input.touchSensor1.onEvent(TouchSensorEvent.Bumped, () => {
|
||||
screen.print("Click! " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
input.remoteTopLeft.onEvent(ButtonEvent.Click, () => {
|
||||
input.remoteButtonTopLeft.onEvent(ButtonEvent.Click, () => {
|
||||
screen.print("TOPLEFT " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
||||
input.remoteTopRight.onEvent(ButtonEvent.Down, () => {
|
||||
input.remoteButtonTopRight.onEvent(ButtonEvent.Down, () => {
|
||||
screen.print("TOPRIGH " + num, 10, 60)
|
||||
num++
|
||||
})
|
||||
|
@ -4,8 +4,8 @@
|
||||
* Touch sensor interactions
|
||||
*/
|
||||
const enum TouchSensorEvent {
|
||||
//% block="touched"
|
||||
Touched = 4,
|
||||
//% block="pressed"
|
||||
Pressed = 4,
|
||||
//% block="bumped"
|
||||
Bumped = 1,
|
||||
//% block="released"
|
||||
@ -28,7 +28,7 @@ namespace input {
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
this.button.update(curr > 0)
|
||||
this.button._update(curr > 0)
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
|
@ -1,15 +1,58 @@
|
||||
const enum PromixityEvent {
|
||||
//% block="object near"
|
||||
ObjectNear = 1,
|
||||
//% block="object detected"
|
||||
ObjectDetected = 2
|
||||
}
|
||||
|
||||
namespace input {
|
||||
|
||||
//% fixedInstances
|
||||
export class UltraSonicSensor extends internal.UartSensor {
|
||||
private promixityThreshold: number;
|
||||
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.promixityThreshold = 10;
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
return DAL.DEVICE_TYPE_ULTRASONIC
|
||||
}
|
||||
|
||||
_query(): number {
|
||||
const d = this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
||||
return d < this.promixityThreshold ? PromixityEvent.ObjectNear
|
||||
: d > this.promixityThreshold + 5 ? PromixityEvent.ObjectDetected
|
||||
: 0;
|
||||
}
|
||||
|
||||
_update(prev: number, curr: number) {
|
||||
if (curr)
|
||||
control.raiseEvent(this._id, curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers code to run when the given color is close
|
||||
* @param handler the code to run when detected
|
||||
*/
|
||||
//% help=input/ultrasonic/on-object-near
|
||||
//% block="on %sensor|object near"
|
||||
//% blockId=ultrasonicOnObjectClose
|
||||
//% parts="infraredsensor"
|
||||
//% blockNamespace=input
|
||||
//% weight=100 blockGap=8
|
||||
//% group="Ultrasonic Sensor"
|
||||
onObjectNear(handler: () => void) {
|
||||
control.onEvent(this._id, PromixityEvent.ObjectNear, handler);
|
||||
if (this.distance() == PromixityEvent.ObjectNear)
|
||||
control.runInBackground(handler);
|
||||
}
|
||||
|
||||
setObjectNearThreshold(distance: number) {
|
||||
this.promixityThreshold = Math.max(1, Math.min(250, distance));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the distance from the sonar in millimeters
|
||||
* @param sensor the ultrasonic sensor port
|
||||
@ -24,7 +67,7 @@ namespace input {
|
||||
distance() {
|
||||
// it supposedly also has an inch mode, but we stick to mm
|
||||
this._setMode(0)
|
||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff
|
||||
return this.getNumber(NumberFormat.UInt16LE, 0) & 0x0fff;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "0.0.21",
|
||||
"version": "0.0.26",
|
||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
|
@ -89,10 +89,6 @@
|
||||
"name": "About",
|
||||
"path": "/about"
|
||||
},
|
||||
{
|
||||
"name": "Examples",
|
||||
"path": "#projects:Examples"
|
||||
},
|
||||
{
|
||||
"name": "Blocks",
|
||||
"path": "/blocks"
|
||||
@ -104,18 +100,14 @@
|
||||
{
|
||||
"name": "Reference",
|
||||
"path": "/reference"
|
||||
},
|
||||
{
|
||||
"name": "Buy",
|
||||
"path": "https://www.lego.com/en-us/mindstorms/products/mindstorms-ev3-31313"
|
||||
}
|
||||
],
|
||||
"useStartPage": true,
|
||||
"showHomeScreen": true,
|
||||
"homeScreenHero": "./static/hero.png",
|
||||
"invertedMenu": false,
|
||||
"invertedMonaco": false,
|
||||
"monacoToolbox": true,
|
||||
"invertedToolbox": true,
|
||||
"exampleGallery": "examples",
|
||||
"hasAudio": true,
|
||||
"usbHelp": [],
|
||||
"extendEditor": true,
|
||||
|
157
scripts/rgf2png.js
Executable file
157
scripts/rgf2png.js
Executable file
@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs")
|
||||
const zlib = require("zlib")
|
||||
|
||||
function compressImg(fn) {
|
||||
const rgf = fs.readFileSync(fn)
|
||||
|
||||
const width = rgf[0]
|
||||
const height = rgf[1]
|
||||
|
||||
const expSz = ((width + 7) >> 3) * height + 2
|
||||
|
||||
console.log(`w=${width} h=${height} sz=${rgf.length} exp=${expSz}`)
|
||||
|
||||
let crcTable
|
||||
|
||||
function crc32(buf) {
|
||||
if (!crcTable) {
|
||||
crcTable = []
|
||||
for (let i = 0; i < 256; i++) {
|
||||
let curr = i;
|
||||
for (let j = 0; j < 8; j++) {
|
||||
if (curr & 1) {
|
||||
curr = 0xedb88320 ^ (curr >>> 1);
|
||||
} else {
|
||||
curr = curr >>> 1;
|
||||
}
|
||||
}
|
||||
crcTable[i] = curr
|
||||
}
|
||||
}
|
||||
|
||||
let crc = -1;
|
||||
for (var i = 0; i < buf.length; i++) {
|
||||
crc = crcTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
|
||||
}
|
||||
return (crc ^ -1) >>> 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Width 4 bytes
|
||||
Height 4 bytes
|
||||
Bit depth 1 byte
|
||||
Colour type 1 byte
|
||||
Compression method 1 byte
|
||||
Filter method 1 byte
|
||||
Interlace method 1 byte
|
||||
*/
|
||||
|
||||
const chunks = []
|
||||
|
||||
function addChunk(mark, addsize) {
|
||||
const buf = Buffer.alloc(mark.length + addsize)
|
||||
for (let i = 0; i < mark.length; ++i) {
|
||||
buf[i] = mark.charCodeAt(i)
|
||||
}
|
||||
chunks.push(buf)
|
||||
return buf
|
||||
}
|
||||
|
||||
const hd = addChunk("IHDR", 4 + 4 + 5)
|
||||
hd.writeInt32BE(width, 4)
|
||||
hd.writeInt32BE(height, 8)
|
||||
hd[12] = 1 // bit depth
|
||||
hd[13] = 0 // color type - grayscale
|
||||
hd[14] = 0 // compression - deflate
|
||||
hd[15] = 0 // filter method
|
||||
hd[16] = 0 // interlace method - no interlace
|
||||
|
||||
const scanlines = []
|
||||
const scanlen = (width + 7) >> 3
|
||||
|
||||
let srcptr = 2
|
||||
let srcmask = 0x01
|
||||
for (let y = 0; y < height; ++y) {
|
||||
const scan = Buffer.alloc(1 + scanlen)
|
||||
scanlines.push(scan)
|
||||
let dstptr = 1
|
||||
let dstmask = 0x80
|
||||
for (let x = 0; x < width; ++x) {
|
||||
if (!(rgf[srcptr] & srcmask)) {
|
||||
scan[dstptr] |= dstmask
|
||||
}
|
||||
dstmask >>= 1;
|
||||
if (dstmask == 0) {
|
||||
dstmask = 0x80
|
||||
dstptr++
|
||||
}
|
||||
srcmask <<= 1;
|
||||
if (srcmask > 0x80) {
|
||||
srcmask = 0x01
|
||||
srcptr++
|
||||
}
|
||||
}
|
||||
if (srcmask != 0x01) {
|
||||
srcmask = 0x01
|
||||
srcptr++
|
||||
}
|
||||
|
||||
if (false) {
|
||||
// seems to increase file size
|
||||
scan[0] = 1 // sub
|
||||
let prev = 0
|
||||
for (let i = 1; i < scan.length; ++i) {
|
||||
let p = scan[i]
|
||||
scan[i] = (p - prev) & 0xff
|
||||
prev = p
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dat = zlib.deflateSync(Buffer.concat(scanlines), {
|
||||
level: 9
|
||||
})
|
||||
const idat = addChunk("IDAT", dat.length)
|
||||
dat.copy(idat, 4)
|
||||
addChunk("IEND", 0)
|
||||
|
||||
const output = [new Buffer([137, 80, 78, 71, 13, 10, 26, 10])]
|
||||
|
||||
function intBuf(v) {
|
||||
let b = new Buffer(4)
|
||||
b.writeUInt32BE(v, 0)
|
||||
return b
|
||||
}
|
||||
for (let ch of chunks) {
|
||||
output.push(intBuf(ch.length - 4))
|
||||
output.push(ch)
|
||||
output.push(intBuf(crc32(ch)))
|
||||
}
|
||||
|
||||
let outp = Buffer.concat(output)
|
||||
return outp
|
||||
}
|
||||
|
||||
let sz = 0
|
||||
let bf
|
||||
let out = {}
|
||||
for (let i = 2; i < process.argv.length; ++i) {
|
||||
let fn = process.argv[i]
|
||||
let m = /([^\/]+\/[^/]+)\.rgf$/.exec(fn)
|
||||
let bn = m[1]
|
||||
bf = compressImg(fn)
|
||||
out[bn] = "data:image/png;base64," + bf.toString("base64")
|
||||
sz += bf.length
|
||||
}
|
||||
|
||||
console.log("total " + sz)
|
||||
fs.writeFileSync("out.json", JSON.stringify(out, null, 4))
|
||||
fs.writeFileSync("out.png", bf)
|
||||
|
||||
//if (require("os").platform() == "darwin")
|
||||
// require('child_process').execSync("afplay out.wav")
|
||||
|
||||
// TODO also play on Windows
|
46
scripts/rsf2wav.js
Executable file
46
scripts/rsf2wav.js
Executable file
@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs")
|
||||
const rsf = fs.readFileSync(process.argv[2])
|
||||
|
||||
const fmt = rsf.readInt16BE(0) // 0x0100
|
||||
if (fmt != 0x0100) {
|
||||
throw new Error("Invalid input format: " + fmt)
|
||||
}
|
||||
const size = rsf.readInt16BE(2)
|
||||
const samplerate = rsf.readInt16BE(4)
|
||||
const repeat = rsf.readInt16BE(6)
|
||||
|
||||
const datasize = rsf.length - 8
|
||||
|
||||
const wavHd = new Buffer(44)
|
||||
|
||||
function writeMark(off, mark) {
|
||||
for (let i = 0; i < mark.length; ++i) {
|
||||
wavHd[off + i] = mark.charCodeAt(i)
|
||||
}
|
||||
}
|
||||
|
||||
writeMark(0, 'RIFF')
|
||||
wavHd.writeInt32LE(datasize + 36, 4)
|
||||
writeMark(8, 'WAVE')
|
||||
writeMark(12, 'fmt ')
|
||||
wavHd.writeInt32LE(16, 16) // fmt size
|
||||
wavHd.writeInt16LE(1, 20) // PCM
|
||||
wavHd.writeInt16LE(1, 22) // mono, 1ch
|
||||
wavHd.writeInt32LE(samplerate, 24)
|
||||
wavHd.writeInt32LE(samplerate, 28) // byterate
|
||||
wavHd.writeInt16LE(1, 32) // block align
|
||||
wavHd.writeInt16LE(8, 34) // bits per sample
|
||||
writeMark(36, 'data')
|
||||
wavHd.writeInt32LE(datasize, 40)
|
||||
|
||||
const wav = Buffer.concat([wavHd, rsf.slice(8)])
|
||||
|
||||
console.log("writing out.wav; " + samplerate + "Hz")
|
||||
fs.writeFileSync("out.wav", wav)
|
||||
|
||||
if (require("os").platform() == "darwin")
|
||||
require('child_process').execSync("afplay out.wav")
|
||||
|
||||
// TODO also play on Windows
|
@ -6,5 +6,8 @@
|
||||
],
|
||||
"approvedRepos": [
|
||||
]
|
||||
},
|
||||
"galleries": {
|
||||
"Maker Activities": "maker"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user