Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
7baf7cfede | |||
efd6718ea3 | |||
057a1d66dc | |||
5ddfcd5508 | |||
00f0922189 | |||
41f4b64087 | |||
ea5ee1c007 | |||
603e4c0fc1 | |||
e50c88008a | |||
f057964a50 | |||
2eda2061cf | |||
a4ebf4c746 | |||
f1880897d4 | |||
ad2e82060d | |||
d1bb19e30e | |||
280963d1eb | |||
9fadf49b0e | |||
3c2be25384 | |||
e1f623a94d | |||
cb5f9648f5 | |||
9158cfe4f6 | |||
0b763978f2 |
@ -1,5 +1,11 @@
|
||||
# @extends
|
||||
|
||||
## Lessons #Lessons
|
||||
|
||||
* [Lessons](/lessons)
|
||||
* [Make it move](/lessons/make-it-move)
|
||||
* [Line detection](/lessons/line-detection)
|
||||
|
||||
## Reference #reference
|
||||
|
||||
* [Reference](/reference)
|
||||
|
178
docs/examples/core-set/gyroboy-blocks.md
Normal file
178
docs/examples/core-set/gyroboy-blocks.md
Normal file
@ -0,0 +1,178 @@
|
||||
# Gyroboy
|
||||
|
||||
Work in progress
|
||||
|
||||
```blocks
|
||||
let motorSpeed1 = 0
|
||||
let motorSpeed2 = 0
|
||||
let motorSpeed3 = 0
|
||||
let motorSpeed = 0
|
||||
let fallen = false
|
||||
let motorSpeed0 = 0
|
||||
let oldControlDrive = 0
|
||||
let controlDrive = 0
|
||||
let power = 0
|
||||
let motorAngle = 0
|
||||
let gyroAngle = 0
|
||||
let controlSteering = 0
|
||||
let state = 0
|
||||
let motorPosition = 0
|
||||
let temp = 0
|
||||
let gyroRate = 0
|
||||
let timestep = 0
|
||||
sensors.color1.onColorDetected(ColorSensorColor.Red, function () {
|
||||
music.playTone(2000, 100)
|
||||
controlDrive = 0
|
||||
controlSteering = 0
|
||||
})
|
||||
// reads the motor angle and computes the motor speed,
|
||||
// position
|
||||
function computeMotors() {
|
||||
temp = motorAngle
|
||||
// read angle on both motors
|
||||
motorAngle = motors.largeD.angle() + motors.largeA.angle()
|
||||
// and estimate speed as angle difference
|
||||
motorSpeed0 = motorAngle - temp
|
||||
// average last 4 speed readings
|
||||
motorSpeed = (motorSpeed0 + motorSpeed1 + motorSpeed2 + motorSpeed3) / 4 / timestep
|
||||
// shift all previous recorded speeds by one
|
||||
motorSpeed3 = motorSpeed2
|
||||
motorSpeed2 = motorSpeed1
|
||||
motorSpeed1 = motorSpeed0
|
||||
// compute position from speed
|
||||
motorPosition = motorPosition + timestep * motorSpeed
|
||||
}
|
||||
// read the gyro rate and computes the angle
|
||||
function computeGyro() {
|
||||
gyroRate = sensors.gyro2.rate()
|
||||
gyroAngle = gyroAngle + timestep * gyroRate
|
||||
}
|
||||
function reset() {
|
||||
state = 0
|
||||
// sleeping
|
||||
moods.sleeping.show();
|
||||
// reset counters
|
||||
motors.largeA.reset()
|
||||
motors.largeD.reset()
|
||||
// motors are unregulated
|
||||
motors.largeA.setRegulated(false)
|
||||
motors.largeD.setRegulated(false)
|
||||
// clear the gyro sensor to remove drift
|
||||
sensors.gyro2.reset()
|
||||
// fall detection timer
|
||||
control.timer2.reset()
|
||||
// timestep computation timer
|
||||
control.timer3.reset()
|
||||
motorAngle = 0
|
||||
motorPosition = 0
|
||||
motorSpeed = 0
|
||||
motorSpeed0 = 0
|
||||
motorSpeed1 = 0
|
||||
motorSpeed2 = 0
|
||||
motorSpeed3 = 0
|
||||
gyroRate = 0
|
||||
gyroAngle = 0
|
||||
fallen = false
|
||||
power = 0
|
||||
controlSteering = 0
|
||||
controlDrive = 0
|
||||
// awake
|
||||
moods.awake.show();
|
||||
gyroAngle = -0.25
|
||||
state = 1;
|
||||
}
|
||||
// compute set point for motor position and required
|
||||
// motor power
|
||||
function computePower() {
|
||||
// apply control and compute desired motor position
|
||||
motorPosition -= timestep * controlDrive;
|
||||
// estimate power based on sensor readings and control
|
||||
// values
|
||||
power = 0.8 * gyroRate + 15 * gyroAngle + (0.08 * motorSpeed + 0.12 * motorPosition) - 0.01 * controlDrive
|
||||
// ensure that power stays within -100, 100
|
||||
if (power > 100) {
|
||||
power = 100
|
||||
} else if (power < -100) {
|
||||
power = -100
|
||||
}
|
||||
}
|
||||
// test if the robot has fallen off
|
||||
function checkFallen() {
|
||||
if (Math.abs(power) < 100) {
|
||||
control.timer2.reset()
|
||||
}
|
||||
if (control.timer2.seconds() > 2) {
|
||||
fallen = true
|
||||
}
|
||||
}
|
||||
// stop all motors and wait for touch button to be
|
||||
// pressed
|
||||
function stop() {
|
||||
motors.stopAllMotors()
|
||||
state = 0
|
||||
moods.knockedOut.show();
|
||||
sensors.touch3.pauseUntil(TouchSensorEvent.Pressed)
|
||||
moods.neutral.show();
|
||||
}
|
||||
sensors.ultrasonic4.onEvent(UltrasonicSensorEvent.ObjectNear, function () {
|
||||
moods.dizzy.show()
|
||||
controlSteering = 0
|
||||
oldControlDrive = controlDrive
|
||||
controlDrive = -10
|
||||
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
|
||||
motors.mediumC.setSpeed(-30, 60, MoveUnit.Degrees);
|
||||
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
|
||||
if (Math.randomRange(-1, 1) >= 1) {
|
||||
controlSteering = 70
|
||||
} else {
|
||||
controlSteering = -70
|
||||
}
|
||||
loops.pause(4000)
|
||||
music.playTone(2000, 100)
|
||||
controlSteering = 0
|
||||
controlDrive = oldControlDrive
|
||||
moods.neutral.show()
|
||||
})
|
||||
// compute the elapsed time since the last iteration
|
||||
function computeTimestep() {
|
||||
timestep = control.timer3.seconds()
|
||||
control.timer3.reset()
|
||||
}
|
||||
sensors.color1.onColorDetected(ColorSensorColor.Green, function () {
|
||||
moods.winking.show()
|
||||
controlDrive = 150
|
||||
controlSteering = 0
|
||||
})
|
||||
sensors.color1.onColorDetected(ColorSensorColor.Blue, function () {
|
||||
moods.middleRight.show()
|
||||
controlSteering = 70
|
||||
})
|
||||
// apply power to motors
|
||||
function controlMotors() {
|
||||
motors.largeA.setSpeed(power + controlSteering * 0.1)
|
||||
motors.largeD.setSpeed(power - controlSteering * 0.1)
|
||||
}
|
||||
sensors.color1.onColorDetected(ColorSensorColor.Yellow, function () {
|
||||
moods.middleLeft.show()
|
||||
controlSteering = -70
|
||||
})
|
||||
sensors.color1.onColorDetected(ColorSensorColor.White, function () {
|
||||
moods.sad.show();
|
||||
controlDrive = -75
|
||||
})
|
||||
timestep = 0.014
|
||||
// main loop
|
||||
loops.forever(function () {
|
||||
reset()
|
||||
while (!fallen) {
|
||||
control.timer3.pauseUntil(5)
|
||||
computeTimestep()
|
||||
computeGyro()
|
||||
computeMotors()
|
||||
computePower()
|
||||
controlMotors()
|
||||
checkFallen()
|
||||
}
|
||||
stop()
|
||||
})
|
||||
```
|
215
docs/examples/core-set/gyroboy-labview.md
Normal file
215
docs/examples/core-set/gyroboy-labview.md
Normal file
@ -0,0 +1,215 @@
|
||||
# Gyroboy LabView
|
||||
|
||||
```typescript
|
||||
let mSum = 0;
|
||||
let mPos = 0;
|
||||
let mSpd = 0;
|
||||
let mD = 0;
|
||||
let mDP1 = 0;
|
||||
let mDP2 = 0;
|
||||
let mDP3 = 0;
|
||||
let Crdv = 0;
|
||||
let cLo = 0;
|
||||
let gAng = 0;
|
||||
let ok = false;
|
||||
let pwr = 0;
|
||||
let Cstr = 0;
|
||||
let Cdrv = 0;
|
||||
let gMn = 0;
|
||||
let gMx = 0;
|
||||
let gSum = 0;
|
||||
let gyro = 0;
|
||||
let gOS = 0;
|
||||
let gSpd = 0;
|
||||
let tInt = 0.014;
|
||||
let lpwr = 0
|
||||
let rpwr = 0
|
||||
let tStart = 0
|
||||
let st = 0
|
||||
let oldDr = 0
|
||||
|
||||
function RST() {
|
||||
motors.largeA.reset()
|
||||
motors.largeD.reset()
|
||||
motors.largeA.setRegulated(false)
|
||||
motors.largeD.setRegulated(false)
|
||||
sensors.gyro2.reset()
|
||||
sensors.gyro2.rate()
|
||||
control.timer2.reset()
|
||||
loops.pause(5000)
|
||||
mSum = 0;
|
||||
mPos = 0;
|
||||
mD = 0;
|
||||
mDP1 = 0;
|
||||
mDP2 = 0;
|
||||
mDP3 = 0;
|
||||
Crdv = 0;
|
||||
cLo = 0;
|
||||
gAng = 0;
|
||||
ok = false;
|
||||
pwr = 0;
|
||||
st = 0;
|
||||
Cstr = 0;
|
||||
Cdrv = 0;
|
||||
}
|
||||
|
||||
function OS() {
|
||||
// OSL
|
||||
do {
|
||||
gMn = 1000;
|
||||
gMx = -100;
|
||||
gSum = 0;
|
||||
// gChk
|
||||
for (let i = 0; i < 200; i++) {
|
||||
gyro = sensors.gyro2.rate()
|
||||
gSum = gyro;
|
||||
gMx = Math.max(gMx, gyro)
|
||||
gMn = Math.min(gMn, gyro)
|
||||
loops.pause(4);
|
||||
}
|
||||
} while (gMx - gMn > 2);
|
||||
gOS = gSum / 200;
|
||||
}
|
||||
|
||||
function GT() {
|
||||
if (cLo == 0) {
|
||||
tInt = 0.014;
|
||||
control.timer1.reset();
|
||||
} else {
|
||||
tInt = control.timer1.seconds() / cLo;
|
||||
}
|
||||
cLo++;
|
||||
}
|
||||
|
||||
function GG() {
|
||||
gyro = sensors.gyro2.rate();
|
||||
gOS = 0.0005 * gyro + (1 - 0.0005) * gOS
|
||||
gSpd = gyro - gOS;
|
||||
gAng = gAng + tInt * gSpd;
|
||||
}
|
||||
|
||||
function GM() {
|
||||
let temp = mSum
|
||||
mSum = motors.largeD.angle() + motors.largeA.angle();
|
||||
mD = mSum - temp;
|
||||
mPos = mPos + mD;
|
||||
mSpd = ((mDP1 + mDP2 + mDP3 + mD) / 4) / tInt;
|
||||
mDP3 = mDP2;
|
||||
mDP2 = mDP1;
|
||||
mDP1 = mD;
|
||||
}
|
||||
|
||||
function EQ() {
|
||||
mPos = mPos - Cdrv * tInt;
|
||||
pwr = (0.8 * gSpd + 15 * gAng) + (0.08 * mSpd + 0.12 * mPos) - 0.01 * Cdrv
|
||||
if (pwr > 100) pwr = 100
|
||||
else if (pwr < -100) pwr = -100
|
||||
}
|
||||
|
||||
function cntrl() {
|
||||
mPos = mPos - tInt * Cdrv
|
||||
lpwr = (pwr + Cstr * 0.1)
|
||||
rpwr = (pwr - Cstr * 0.1)
|
||||
}
|
||||
|
||||
function CHK() {
|
||||
if (Math.abs(pwr) < 100)
|
||||
control.timer2.reset();
|
||||
if (control.timer2.seconds() > 2) {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// M
|
||||
loops.forever(function () {
|
||||
RST();
|
||||
brick.showImage(images.eyesSleeping)
|
||||
OS()
|
||||
gAng = -0.25;
|
||||
music.playSoundEffect(sounds.movementsSpeedUp)
|
||||
brick.showImage(images.eyesAwake)
|
||||
st = 1;
|
||||
// BALANCE
|
||||
while (!ok) {
|
||||
GT();
|
||||
let t1 = control.timer1.millis()
|
||||
GG();
|
||||
GM();
|
||||
EQ();
|
||||
cntrl();
|
||||
motors.largeA.setSpeed(lpwr)
|
||||
motors.largeD.setSpeed(rpwr)
|
||||
CHK()
|
||||
let t2 = control.timer1.millis();
|
||||
let p = 5 - (t2 - t1);
|
||||
loops.pause(Math.max(1, p))
|
||||
}
|
||||
motors.stopAllMotors()
|
||||
st = 0;
|
||||
brick.setLight(BrickLight.RedPulse);
|
||||
brick.showImage(images.eyesKnockedOut)
|
||||
music.playSoundEffect(sounds.movementsSpeedDown)
|
||||
sensors.touch3.pauseUntil(TouchSensorEvent.Pressed)
|
||||
brick.setLight(BrickLight.Off);
|
||||
})
|
||||
|
||||
// BHV
|
||||
loops.forever(function () {
|
||||
switch (st) {
|
||||
case 0:
|
||||
Cdrv = 0;
|
||||
Cstr = 0;
|
||||
break;
|
||||
case 1:
|
||||
Cdrv = 40;
|
||||
loops.pause(4000);
|
||||
Cdrv = 0;
|
||||
music.playTone(1000, 100);
|
||||
st = 2;
|
||||
break;
|
||||
case 2:
|
||||
switch (sensors.color1.color()) {
|
||||
case ColorSensorColor.Red:
|
||||
music.playTone(2000, 100);
|
||||
Cdrv = 0;
|
||||
Cstr = 0;
|
||||
break;
|
||||
case ColorSensorColor.Green:
|
||||
music.playTone(2000, 100);
|
||||
Cdrv = 150;
|
||||
Cstr = 0;
|
||||
break;
|
||||
case ColorSensorColor.Blue:
|
||||
music.playTone(2000, 100);
|
||||
Cstr = 70;
|
||||
break;
|
||||
case ColorSensorColor.Yellow:
|
||||
music.playTone(2000, 100);
|
||||
Cstr = -70;
|
||||
break;
|
||||
case ColorSensorColor.White:
|
||||
music.playTone(2000, 100);
|
||||
Cdrv = -75;
|
||||
break;
|
||||
}
|
||||
if (sensors.ultrasonic4.distance() < 25) {
|
||||
Cstr = 0;
|
||||
oldDr = Cdrv;
|
||||
Cdrv = -10;
|
||||
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
|
||||
motors.mediumC.setSpeed(-30, 60, MoveUnit.Degrees);
|
||||
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
|
||||
if (Math.randomRange(-1, 1) >= 1)
|
||||
Cstr = 70;
|
||||
else
|
||||
Cstr = -70;
|
||||
loops.pause(4000);
|
||||
music.playTone(2000, 100)
|
||||
Cstr = 0;
|
||||
Cdrv = oldDr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
loops.pause(80);
|
||||
})
|
||||
```
|
390
docs/examples/core-set/puppy-labview.md
Normal file
390
docs/examples/core-set/puppy-labview.md
Normal file
@ -0,0 +1,390 @@
|
||||
# Puppy
|
||||
|
||||
```typescript
|
||||
let P_T = 0;
|
||||
let ISS = 0;
|
||||
let F_T = 0;
|
||||
let P_C = 0;
|
||||
let F_C = 0;
|
||||
let DB_S = 0;
|
||||
let NS = false;
|
||||
let IBP = 0;
|
||||
let IAP = 0;
|
||||
let C = false;
|
||||
let TC = false;
|
||||
let OTC = false;
|
||||
let COL = 0;
|
||||
let OCOL = 0;
|
||||
let _C = false;
|
||||
let GTO = 0;
|
||||
|
||||
function DN() {
|
||||
motors.largeAD.setBrake(true);
|
||||
motors.largeAD.tank(50, 50, 1, MoveUnit.Seconds);
|
||||
loops.pause(100);
|
||||
motors.largeA.clearCounts()
|
||||
motors.largeD.clearCounts()
|
||||
}
|
||||
|
||||
function MNRH() {
|
||||
motors.mediumC.setBrake(true)
|
||||
brick.showImage(images.legoEv3icon)
|
||||
brick.setLight(BrickLight.OrangePulse)
|
||||
while (!brick.buttonEnter.wasPressed()) {
|
||||
if (brick.buttonUp.wasPressed()) {
|
||||
motors.mediumC.setSpeed(-100);
|
||||
} else if (brick.buttonDown.wasPressed()) {
|
||||
motors.mediumC.setSpeed(100);
|
||||
} else {
|
||||
motors.mediumC.stop();
|
||||
}
|
||||
}
|
||||
motors.mediumC.stop();
|
||||
motors.mediumC.clearCounts();
|
||||
brick.setLight(BrickLight.Green);
|
||||
}
|
||||
|
||||
function IS(t: number) {
|
||||
ISS = t;
|
||||
switch (t) {
|
||||
case 0:
|
||||
brick.showImage(images.eyesNeutral);
|
||||
break;
|
||||
case 1:
|
||||
brick.showImage(images.eyesSleeping);
|
||||
break;
|
||||
case 2:
|
||||
brick.showImage(images.eyesTear);
|
||||
// draw rect...
|
||||
break;
|
||||
case 3:
|
||||
brick.showImage(images.eyesHurt);
|
||||
break;
|
||||
case 4:
|
||||
brick.showImage(images.eyesAngry);
|
||||
break;
|
||||
case 5:
|
||||
brick.showImage(images.eyesTiredMiddle);
|
||||
break;
|
||||
case 6:
|
||||
brick.showImage(images.eyesTiredRight);
|
||||
break;
|
||||
case 7:
|
||||
brick.showImage(images.eyesTiredLeft);
|
||||
break;
|
||||
case 8:
|
||||
brick.showImage(images.eyesLove);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function UP() {
|
||||
if (motors.largeA.angle() > -50) {
|
||||
control.runInBackground(function () {
|
||||
motors.largeD.clearCounts()
|
||||
motors.largeD.setSpeed(-35);
|
||||
pauseUntil(() => motors.largeD.angle() < -25);
|
||||
motors.largeD.stop();
|
||||
motors.largeD.setRegulated(false)
|
||||
motors.largeD.setSpeed(-15)
|
||||
pauseUntil(() => motors.largeD.angle() < -65);
|
||||
motors.largeD.stop();
|
||||
})
|
||||
motors.largeA.clearCounts()
|
||||
motors.largeA.setSpeed(-35);
|
||||
pauseUntil(() => motors.largeA.angle() < -25);
|
||||
motors.largeA.stop();
|
||||
motors.largeA.setRegulated(false)
|
||||
motors.largeA.setSpeed(-15)
|
||||
pauseUntil(() => motors.largeA.angle() < -65);
|
||||
motors.largeA.stop();
|
||||
|
||||
loops.pause(500);
|
||||
}
|
||||
}
|
||||
|
||||
function RST() {
|
||||
P_T = Math.randomRange(3, 6);
|
||||
F_T = Math.randomRange(2, 4);
|
||||
P_C = 1;
|
||||
F_C = 1;
|
||||
control.timer1.reset();
|
||||
control.timer2.reset();
|
||||
control.timer3.reset();
|
||||
CS(0);
|
||||
}
|
||||
|
||||
function CS(db: number) {
|
||||
if (DB_S != db) {
|
||||
DB_S = db;
|
||||
NS = true;
|
||||
}
|
||||
}
|
||||
|
||||
function MON() {
|
||||
if (control.timer2.seconds() > 10) {
|
||||
control.timer2.reset();
|
||||
P_C--;
|
||||
if (P_C < 0) {
|
||||
P_C = 0;
|
||||
}
|
||||
}
|
||||
if (control.timer1.seconds() > 20) {
|
||||
control.timer1.reset()
|
||||
F_C--;
|
||||
if (F_C < 0) {
|
||||
F_C = 0;
|
||||
}
|
||||
}
|
||||
if (control.timer3.seconds() > 30) {
|
||||
control.timer3.reset();
|
||||
CS(1);
|
||||
}
|
||||
}
|
||||
|
||||
function UIS() {
|
||||
if (control.timer5.seconds() > IBP) {
|
||||
control.timer5.reset();
|
||||
if (ISS == 1) {
|
||||
ISS = 6;
|
||||
IBP = Math.randomRange(1, 5);
|
||||
} else {
|
||||
ISS = 1;
|
||||
IBP = 0.25;
|
||||
}
|
||||
IS(ISS);
|
||||
}
|
||||
if (control.timer6.seconds() > IAP) {
|
||||
if (ISS != 1) {
|
||||
control.timer6.reset();
|
||||
IAP = Math.randomRange(1, 10)
|
||||
if (ISS != 7) {
|
||||
ISS = 7
|
||||
} else {
|
||||
ISS = 6;
|
||||
}
|
||||
IS(ISS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function UPDB() {
|
||||
if ((P_T == P_C) && (F_T == F_C)) {
|
||||
CS(6);
|
||||
}
|
||||
if ((P_T > P_C) && (F_T < F_C)) {
|
||||
CS(3);
|
||||
}
|
||||
if ((P_T < P_C) && (F_T > F_C)) {
|
||||
CS(5);
|
||||
}
|
||||
if ((P_C == 0) && (F_C > 0)) {
|
||||
CS(2)
|
||||
}
|
||||
if (F_C == 0) {
|
||||
CS(4)
|
||||
}
|
||||
}
|
||||
|
||||
function PTC() {
|
||||
C = false;
|
||||
OTC = TC;
|
||||
TC = sensors.touch1.isPressed()
|
||||
if (TC != OTC && TC) {
|
||||
P_C++;
|
||||
control.timer3.reset();
|
||||
if (DB_S != 4) {
|
||||
IS(2);
|
||||
music.playSoundEffect(sounds.animalsDogSniff);
|
||||
C = true;
|
||||
}
|
||||
}
|
||||
return C;
|
||||
}
|
||||
|
||||
function FDC() {
|
||||
OCOL = COL;
|
||||
COL = sensors.color4.color();
|
||||
_C = false;
|
||||
if ((COL != 0) && (OCOL != COL)) {
|
||||
F_C++;
|
||||
_C = true;
|
||||
control.timer3.reset();
|
||||
IS(2);
|
||||
music.playSoundEffect(sounds.expressionsCrunching)
|
||||
}
|
||||
return _C;
|
||||
}
|
||||
|
||||
function IDL() {
|
||||
if (NS) {
|
||||
NS = false;
|
||||
UP();
|
||||
}
|
||||
UIS();
|
||||
UPDB();
|
||||
PTC();
|
||||
FDC();
|
||||
}
|
||||
|
||||
function MHT(Pos: number) {
|
||||
let _R = Pos - motors.mediumC.angle();
|
||||
if (_R >= 0) {
|
||||
motors.mediumC.setSpeed(100, _R, MoveUnit.Degrees);
|
||||
} else {
|
||||
motors.mediumC.setSpeed(-100, Math.abs(_R), MoveUnit.Degrees);
|
||||
}
|
||||
}
|
||||
|
||||
function SLP() {
|
||||
if (NS) {
|
||||
NS = false;
|
||||
IS(5)
|
||||
DN()
|
||||
MHT(3000)
|
||||
IS(1)
|
||||
music.playSoundEffect(sounds.expressionsSnoring)
|
||||
}
|
||||
if (sensors.touch1.isPressed() || brick.buttonEnter.isPressed()) {
|
||||
music.stopAllSounds();
|
||||
control.timer3.reset();
|
||||
CS(7);
|
||||
}
|
||||
}
|
||||
|
||||
function PLF() {
|
||||
if (NS) {
|
||||
NS = false
|
||||
IS(0)
|
||||
UP()
|
||||
music.playSoundEffect(sounds.animalsDogBark2)
|
||||
control.timer4.reset()
|
||||
GTO = Math.randomRange(4, 8);
|
||||
}
|
||||
if(PTC()) {
|
||||
CS(0);
|
||||
}
|
||||
if (control.timer4.seconds() > GTO) {
|
||||
music.playSoundEffect(sounds.animalsDogBark2)
|
||||
control.timer4.reset();
|
||||
GTO = Math.randomRange(4, 8);
|
||||
}
|
||||
}
|
||||
|
||||
function NGR() {
|
||||
NS = false
|
||||
IS(4)
|
||||
music.playSoundEffect(sounds.animalsDogGrowl);
|
||||
UP();
|
||||
loops.pause(1500);
|
||||
music.stopAllSounds()
|
||||
music.playSoundEffect(sounds.animalsDogBark1)
|
||||
P_C--;
|
||||
CS(0);
|
||||
}
|
||||
|
||||
function HNG() {
|
||||
if (NS) {
|
||||
NS = false;
|
||||
IS(3)
|
||||
DN();
|
||||
music.playSoundEffect(sounds.animalsDogWhine);
|
||||
}
|
||||
if(FDC()) {
|
||||
CS(0)
|
||||
}
|
||||
if (PTC()) {
|
||||
CS(3);
|
||||
}
|
||||
}
|
||||
|
||||
function PPP() {
|
||||
NS = false;
|
||||
IS(2);
|
||||
UP();
|
||||
loops.pause(100)
|
||||
motors.largeA.setSpeed(-30, 70, MoveUnit.Degrees);
|
||||
loops.pause(800);
|
||||
music.playSoundEffect(sounds.mechanicalHorn1);
|
||||
loops.pause(1000);
|
||||
for(let i = 0; i < 3; ++i) {
|
||||
motors.largeA.setSpeed(-30, 20, MoveUnit.Degrees);
|
||||
motors.largeA.setSpeed(30, 20, MoveUnit.Degrees);
|
||||
}
|
||||
motors.largeA.setSpeed(30, 70, MoveUnit.Degrees);
|
||||
F_C = 1;
|
||||
CS(0);
|
||||
}
|
||||
|
||||
function HPY() {
|
||||
IS(8)
|
||||
MHT(0);
|
||||
motors.largeAD.setSpeed(10, 0.8, MoveUnit.Seconds);
|
||||
for(let i = 0; i < 3; ++i) {
|
||||
music.playSoundEffect(sounds.animalsDogBark1);
|
||||
motors.largeAD.setSpeed(-100, 0.2, MoveUnit.Seconds);
|
||||
loops.pause(300)
|
||||
motors.largeAD.setSpeed(10, 0.3, MoveUnit.Seconds)
|
||||
}
|
||||
loops.pause(500);
|
||||
music.stopAllSounds();
|
||||
DN();
|
||||
RST();
|
||||
}
|
||||
|
||||
function STL() {
|
||||
UP();
|
||||
motors.largeAD.setSpeed(-20, 60, MoveUnit.Degrees);
|
||||
music.playSoundEffect(sounds.animalsDogWhine);
|
||||
motors.largeAD.setSpeed(20, 60, MoveUnit.Degrees);
|
||||
}
|
||||
|
||||
function WKU() {
|
||||
let stateC = false;
|
||||
IS(5);
|
||||
music.playSoundEffect(sounds.animalsDogWhine)
|
||||
MHT(0)
|
||||
DN()
|
||||
STL()
|
||||
loops.pause(1000);
|
||||
UP()
|
||||
CS(0;)
|
||||
}
|
||||
|
||||
DN();
|
||||
MNRH();
|
||||
// compare button state???
|
||||
IS(1);
|
||||
UP();
|
||||
RST();
|
||||
loops.forever(function () {
|
||||
MON();
|
||||
switch (DB_S) {
|
||||
case 0:
|
||||
IDL();
|
||||
break;
|
||||
case 1:
|
||||
SLP();
|
||||
break;
|
||||
case 2:
|
||||
PLF();
|
||||
break;
|
||||
case 3:
|
||||
NGR();
|
||||
break;
|
||||
case 4:
|
||||
HNG();
|
||||
break;
|
||||
case 5:
|
||||
PPP();
|
||||
break;
|
||||
case 6:
|
||||
HPY();
|
||||
break;
|
||||
case 7:
|
||||
WKU();
|
||||
break;
|
||||
}
|
||||
})
|
||||
```
|
51
docs/examples/core-set/robotarm-labview.md
Normal file
51
docs/examples/core-set/robotarm-labview.md
Normal file
@ -0,0 +1,51 @@
|
||||
# Robot Arm
|
||||
|
||||
```typescript
|
||||
function INI() {
|
||||
motors.largeB.setBrake(true)
|
||||
motors.largeC.setBrake(true)
|
||||
motors.mediumA.setBrake(true)
|
||||
motors.largeB.setSpeed(-50)
|
||||
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
|
||||
motors.largeB.stop();
|
||||
motors.mediumA.setSpeed(30, 1, MoveUnit.Seconds);
|
||||
motors.mediumA.setSpeed(-50, 90, MoveUnit.Degrees);
|
||||
motors.largeC.setSpeed(50)
|
||||
sensors.touch1.pauseUntil(TouchSensorEvent.Pressed);
|
||||
motors.largeC.setSpeed(-50, 0.86, MoveUnit.Rotations);
|
||||
}
|
||||
|
||||
INI()
|
||||
|
||||
let down = false;
|
||||
loops.forever(function () {
|
||||
brick.showImage(images.informationQuestionMark)
|
||||
brick.setLight(BrickLight.OrangePulse);
|
||||
pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed())
|
||||
brick.setLight(BrickLight.Off)
|
||||
music.playSoundEffect(sounds.mechanicalAirRelease)
|
||||
brick.showImage(images.informationAccept)
|
||||
if (down) {
|
||||
brick.showImage(images.informationForward)
|
||||
motors.largeC.setSpeed(65, 0.85, MoveUnit.Rotations);
|
||||
} else {
|
||||
brick.showImage(images.informationBackward)
|
||||
motors.largeC.setSpeed(-65, 0.85, MoveUnit.Rotations);
|
||||
}
|
||||
motors.largeB.setSpeed(20, 275, MoveUnit.Degrees)
|
||||
motors.mediumA.setSpeed(30, 1, MoveUnit.Seconds)
|
||||
motors.largeB.setSpeed(-55)
|
||||
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
|
||||
motors.largeB.stop();
|
||||
if (down) {
|
||||
motors.largeC.setSpeed(-65, 0.86, MoveUnit.Rotations);
|
||||
} else {
|
||||
motors.largeC.setSpeed(65, 0.85, MoveUnit.Rotations);
|
||||
}
|
||||
motors.largeB.setSpeed(20, 275, MoveUnit.Degrees);
|
||||
motors.mediumA.setSpeed(-30, 90, MoveUnit.Degrees);
|
||||
motors.largeB.setSpeed(-55)
|
||||
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
|
||||
motors.largeB.stop()
|
||||
})
|
||||
```
|
51
docs/examples/crane-labview.md
Normal file
51
docs/examples/crane-labview.md
Normal file
@ -0,0 +1,51 @@
|
||||
# Crane LabView
|
||||
|
||||
```blocks
|
||||
function INI() {
|
||||
motors.largeB.setBrake(true)
|
||||
motors.largeC.setBrake(true)
|
||||
motors.mediumA.setBrake(true)
|
||||
motors.largeB.setSpeed(-50)
|
||||
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
|
||||
motors.largeB.stop();
|
||||
motors.mediumA.setSpeed(30, 1, MoveUnit.Seconds);
|
||||
motors.mediumA.setSpeed(-50, 90, MoveUnit.Degrees);
|
||||
motors.largeC.setSpeed(50)
|
||||
sensors.touch1.pauseUntil(TouchSensorEvent.Pressed);
|
||||
motors.largeC.setSpeed(-50, 0.86, MoveUnit.Rotations);
|
||||
}
|
||||
|
||||
INI()
|
||||
|
||||
let down = false;
|
||||
loops.forever(function () {
|
||||
brick.showImage(images.informationQuestionMark)
|
||||
brick.setLight(BrickLight.OrangePulse);
|
||||
pauseUntil(() => (down = brick.buttonDown.wasPressed()) || brick.buttonUp.wasPressed())
|
||||
brick.setLight(BrickLight.Off)
|
||||
music.playSoundEffect(sounds.mechanicalAirRelease)
|
||||
brick.showImage(images.informationAccept)
|
||||
if (down) {
|
||||
brick.showImage(images.informationForward)
|
||||
motors.largeC.setSpeed(65, 0.85, MoveUnit.Rotations);
|
||||
} else {
|
||||
brick.showImage(images.informationBackward)
|
||||
motors.largeC.setSpeed(-65, 0.85, MoveUnit.Rotations);
|
||||
}
|
||||
motors.largeB.setSpeed(20, 275, MoveUnit.Degrees)
|
||||
motors.mediumA.setSpeed(30, 1, MoveUnit.Seconds)
|
||||
motors.largeB.setSpeed(-55)
|
||||
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
|
||||
motors.largeB.stop();
|
||||
if (down) {
|
||||
motors.largeC.setSpeed(-65, 0.86, MoveUnit.Rotations);
|
||||
} else {
|
||||
motors.largeC.setSpeed(65, 0.85, MoveUnit.Rotations);
|
||||
}
|
||||
motors.largeB.setSpeed(20, 275, MoveUnit.Degrees);
|
||||
motors.mediumA.setSpeed(-30, 90, MoveUnit.Degrees);
|
||||
motors.largeB.setSpeed(-55)
|
||||
pauseUntil(() => sensors.color3.light(LightIntensityMode.Reflected) > 25);
|
||||
motors.largeB.stop()
|
||||
})
|
||||
```
|
215
docs/examples/gyro-boy-labview.md
Normal file
215
docs/examples/gyro-boy-labview.md
Normal file
@ -0,0 +1,215 @@
|
||||
# Gyro Boy LabView
|
||||
|
||||
```blocks
|
||||
let mSum = 0;
|
||||
let mPos = 0;
|
||||
let mSpd = 0;
|
||||
let mD = 0;
|
||||
let mDP1 = 0;
|
||||
let mDP2 = 0;
|
||||
let mDP3 = 0;
|
||||
let Crdv = 0;
|
||||
let cLo = 0;
|
||||
let gAng = 0;
|
||||
let ok = false;
|
||||
let pwr = 0;
|
||||
let Cstr = 0;
|
||||
let Cdrv = 0;
|
||||
let gMn = 0;
|
||||
let gMx = 0;
|
||||
let gSum = 0;
|
||||
let gyro = 0;
|
||||
let gOS = 0;
|
||||
let gSpd = 0;
|
||||
let tInt = 0.014;
|
||||
let lpwr = 0
|
||||
let rpwr = 0
|
||||
let tStart = 0
|
||||
let st = 0
|
||||
let oldDr = 0
|
||||
|
||||
function RST() {
|
||||
motors.largeA.reset()
|
||||
motors.largeD.reset()
|
||||
motors.largeA.setRegulated(false)
|
||||
motors.largeD.setRegulated(false)
|
||||
sensors.gyro2.reset()
|
||||
sensors.gyro2.rate()
|
||||
control.timer2.reset()
|
||||
loops.pause(5000)
|
||||
mSum = 0;
|
||||
mPos = 0;
|
||||
mD = 0;
|
||||
mDP1 = 0;
|
||||
mDP2 = 0;
|
||||
mDP3 = 0;
|
||||
Crdv = 0;
|
||||
cLo = 0;
|
||||
gAng = 0;
|
||||
ok = false;
|
||||
pwr = 0;
|
||||
st = 0;
|
||||
Cstr = 0;
|
||||
Cdrv = 0;
|
||||
}
|
||||
|
||||
function OS() {
|
||||
// OSL
|
||||
do {
|
||||
gMn = 1000;
|
||||
gMx = -100;
|
||||
gSum = 0;
|
||||
// gChk
|
||||
for (let i = 0; i < 200; i++) {
|
||||
gyro = sensors.gyro2.rate()
|
||||
gSum = gyro;
|
||||
gMx = Math.max(gMx, gyro)
|
||||
gMn = Math.min(gMn, gyro)
|
||||
loops.pause(4);
|
||||
}
|
||||
} while (gMx - gMn > 2);
|
||||
gOS = gSum / 200;
|
||||
}
|
||||
|
||||
function GT() {
|
||||
if (cLo == 0) {
|
||||
tInt = 0.014;
|
||||
control.timer1.reset();
|
||||
} else {
|
||||
tInt = control.timer1.seconds() / cLo;
|
||||
}
|
||||
cLo++;
|
||||
}
|
||||
|
||||
function GG() {
|
||||
gyro = sensors.gyro2.rate();
|
||||
gOS = 0.0005 * gyro + (1 - 0.0005) * gOS
|
||||
gSpd = gyro - gOS;
|
||||
gAng = gAng + tInt * gSpd;
|
||||
}
|
||||
|
||||
function GM() {
|
||||
let temp = mSum
|
||||
mSum = motors.largeD.angle() + motors.largeA.angle();
|
||||
mD = mSum - temp;
|
||||
mPos = mPos + mD;
|
||||
mSpd = ((mDP1 + mDP2 + mDP3 + mD) / 4) / tInt;
|
||||
mDP3 = mDP2;
|
||||
mDP2 = mDP1;
|
||||
mDP1 = mD;
|
||||
}
|
||||
|
||||
function EQ() {
|
||||
mPos = mPos - Cdrv * tInt;
|
||||
pwr = (0.8 * gSpd + 15 * gAng) + (0.095 * mSpd + 0.13 * mPos) - 0.01 * Cdrv
|
||||
if (pwr > 100) pwr = 100
|
||||
else if (pwr < -100) pwr = -100
|
||||
}
|
||||
|
||||
function cntrl() {
|
||||
mPos = mPos - tInt * Cdrv
|
||||
lpwr = (pwr + Cstr * 0.1)
|
||||
rpwr = (pwr - Cstr * 0.1)
|
||||
}
|
||||
|
||||
function CHK() {
|
||||
if (Math.abs(pwr) < 100)
|
||||
control.timer2.reset();
|
||||
if (control.timer2.seconds() > 2) {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
// M
|
||||
loops.forever(function () {
|
||||
RST();
|
||||
brick.showImage(images.eyesSleeping)
|
||||
OS()
|
||||
gAng = -0.25;
|
||||
music.playSoundEffect(sounds.movementsSpeedUp)
|
||||
brick.showImage(images.eyesAwake)
|
||||
st = 1;
|
||||
// BALANCE
|
||||
while (!ok) {
|
||||
GT();
|
||||
let t1 = control.timer1.millis()
|
||||
GG();
|
||||
GM();
|
||||
EQ();
|
||||
cntrl();
|
||||
motors.largeA.setSpeed(lpwr)
|
||||
motors.largeD.setSpeed(rpwr)
|
||||
CHK()
|
||||
let t2 = control.timer1.millis();
|
||||
let p = 5 - (t2 - t1);
|
||||
loops.pause(Math.max(1, p))
|
||||
}
|
||||
motors.stopAllMotors()
|
||||
st = 0;
|
||||
brick.setLight(BrickLight.RedPulse);
|
||||
brick.showImage(images.eyesKnockedOut)
|
||||
music.playSoundEffect(sounds.movementsSpeedDown)
|
||||
sensors.touch3.pauseUntil(TouchSensorEvent.Pressed)
|
||||
brick.setLight(BrickLight.Off);
|
||||
})
|
||||
|
||||
// BHV
|
||||
loops.forever(function () {
|
||||
switch (st) {
|
||||
case 0:
|
||||
Cdrv = 0;
|
||||
Cstr = 0;
|
||||
break;
|
||||
case 1:
|
||||
Cdrv = 40;
|
||||
loops.pause(4000);
|
||||
Cdrv = 0;
|
||||
music.playTone(1000, 100);
|
||||
st = 2;
|
||||
break;
|
||||
case 2:
|
||||
switch (sensors.color1.color()) {
|
||||
case ColorSensorColor.Red:
|
||||
music.playTone(2000, 100);
|
||||
Cdrv = 0;
|
||||
Cstr = 0;
|
||||
break;
|
||||
case ColorSensorColor.Green:
|
||||
music.playTone(2000, 100);
|
||||
Cdrv = 150;
|
||||
Cstr = 0;
|
||||
break;
|
||||
case ColorSensorColor.Blue:
|
||||
music.playTone(2000, 100);
|
||||
Cstr = 70;
|
||||
break;
|
||||
case ColorSensorColor.Yellow:
|
||||
music.playTone(2000, 100);
|
||||
Cstr = -70;
|
||||
break;
|
||||
case ColorSensorColor.White:
|
||||
music.playTone(2000, 100);
|
||||
Cdrv = -75;
|
||||
break;
|
||||
}
|
||||
if (sensors.ultrasonic4.distance() < 25) {
|
||||
Cstr = 0;
|
||||
oldDr = Cdrv;
|
||||
Cdrv = -10;
|
||||
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
|
||||
motors.mediumC.setSpeed(-30, 60, MoveUnit.Degrees);
|
||||
motors.mediumC.setSpeed(30, 30, MoveUnit.Degrees);
|
||||
if (Math.randomRange(-1, 1) >= 1)
|
||||
Cstr = 70;
|
||||
else
|
||||
Cstr = -70;
|
||||
loops.pause(4000);
|
||||
music.playTone(2000, 100)
|
||||
Cstr = 0;
|
||||
Cdrv = oldDr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
loops.pause(80);
|
||||
})
|
||||
```
|
27
docs/lessons.md
Normal file
27
docs/lessons.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Lessons
|
||||
|
||||
Learning activities for LEGO Mindstorms with MakeCode.
|
||||
|
||||
## Motors and motion
|
||||
|
||||
```codecard
|
||||
[{
|
||||
"name": "Make it Move",
|
||||
"imageUrl":"/static/lessons/make-it-move.jpg",
|
||||
"url": "/lessons/make-it-move",
|
||||
"cardType": "project",
|
||||
"description": "Make a robot that moves itself without wheels."
|
||||
}, {
|
||||
"name": "Make it Move TUTORIAL",
|
||||
"imageUrl":"/static/lessons/make-it-move.jpg",
|
||||
"url": "/lessons/make-it-move-tutorial",
|
||||
"cardType": "tutorial",
|
||||
"description": "Make a robot that moves itself without wheels."
|
||||
}, {
|
||||
"name": "Line Detection",
|
||||
"imageUrl":"/static/lessons/line-detection.jpg",
|
||||
"url": "/lessons/line-detection",
|
||||
"cardType": "project",
|
||||
"description": "Make your robot drive itself by following lines."
|
||||
}]
|
||||
```
|
266
docs/lessons/line-detection.md
Normal file
266
docs/lessons/line-detection.md
Normal file
@ -0,0 +1,266 @@
|
||||
# Line Detection
|
||||
|
||||
## Objective
|
||||
|
||||
Design ways to improve driving safety by helping to prevent drivers from falling asleep and causing an accident.
|
||||
|
||||

|
||||
|
||||
## Connect
|
||||
|
||||
Make sure that you can answer the following questions:
|
||||
|
||||
* Can autonomous cars react to different traffic light signals?
|
||||
* What can happen if a driver falls asleep while driving?
|
||||
* How can we detect when a driver is falling asleep?
|
||||
|
||||
Think about what you have learned, then document it. Describe the problem in your own words. Creatively record your ideas and findings.
|
||||
|
||||
## Construct
|
||||
|
||||
Start by constructing this model. Read the building instructions [here](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/building-instructions/ev3-rem-color-sensor-down-driving-base-d30ed30610c3d6647d56e17bc64cf6e2.pdf) first.
|
||||
|
||||

|
||||
|
||||
## Program
|
||||
|
||||
Autonomous cars need to recognize and respond to traffic lights automatically.
|
||||
First, create a program that will make your robot stop at red lights.
|
||||
Make sure your robot is only responding to the color red.
|
||||
Once you have succeeded, program your robot to drive forward again when the light changes from red to green.
|
||||
|
||||
There are two coding tasks for this lesson:
|
||||
|
||||
1. Create a program that will make your robot stop at red lights.
|
||||
2. Create a program that drives the robot forward until the Color Sensor sees red. The robot then stops.
|
||||
|
||||
## Coding task 1 - Stop at red lights
|
||||
|
||||
**Goal:** Create a program that will make your robot stop at red lights.
|
||||
|
||||
### Step 1
|
||||
|
||||
Create a program that drives the robot forward until the Color Sensor sees red. The robot then stops.
|
||||
|
||||
Place a ``||motors:steer large B+C||`` block from ``||motors:Motors||`` under ``||loops:on start||``. Change the speed to 20%.
|
||||
|
||||
```blocks
|
||||
motors.largeBC.steer(0, 20)
|
||||
```
|
||||
|
||||
### Step 2
|
||||
|
||||
Place a ``||loops:while||`` loop block under ``||motors:steer large B+C||``.
|
||||
|
||||
```blocks
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3
|
||||
|
||||
Place a ``||sensors:pause for color||`` from ``||sensors:Sensors||`` inside the ``||loops:while||`` loop block. Change the color to red.
|
||||
|
||||
```blocks
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Red)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4
|
||||
|
||||
Place a ``||motors:stop all motors||`` block under the ``||sensors:pause for color||`` block.
|
||||
|
||||
Study the program...what do you think the program will do?
|
||||
|
||||
**Hint:** The motors will run until the Color Sensor senses the color red, then all motors will stop. The motors will run until the sensor reading in the while block is true.
|
||||
|
||||
```blocks
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Red)
|
||||
motors.stopAllMotors()
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5
|
||||
|
||||
Click `|Download|` and follow the instructions to get your code onto your EV3 Brick. Press the **center** button on the EV3 Brick to run the program.
|
||||
|
||||
## Coding task 2 - Detect light changes
|
||||
|
||||
**Goal:** Program your robot to drive forward again when the light changes from red to green.
|
||||
|
||||
### Step 1
|
||||
|
||||
Place a ``||loops:while||`` loop block under ``||loops:on start||``.
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2
|
||||
|
||||
Place a ``||motors:steer large B+C||`` block from ``||motors:Motors||`` inside the ``||loops:while||`` loop block. Change the speed to 20%.
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
motors.largeBC.steer(0, 20)
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4
|
||||
|
||||
Place a ``||loops:while||`` loop block under the ``||motors:steer large B+C||`` block.
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 5
|
||||
|
||||
Place a ``||sensors:pause for color||`` block from ``||sensors:Sensors||`` inside the ``||loops:while||`` loop block. Change the color to red.
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Red)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 6
|
||||
|
||||
Place a ``||motors:stop all motors||`` block under the ``||sensors:pause for color||`` block.
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Red)
|
||||
motors.stopAllMotors()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 7
|
||||
|
||||
Place a ``||loops:while||`` loop block under the second ``||loops:while||`` loop block.
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Red)
|
||||
motors.stopAllMotors()
|
||||
}
|
||||
while (true) {
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 8
|
||||
|
||||
Place a ``||sensors:pause for color||`` block inside the new ``||loops:while||`` loop block. Change the color to red.
|
||||
|
||||
What do you think the program will do?
|
||||
|
||||
**Hint:** The motors will run until the Color Sensor detects the color red, then it will stop all motors. The motors will also run and not stop when the color sensor detects the color green.
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Red)
|
||||
motors.stopAllMotors()
|
||||
}
|
||||
while (true) {
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Red)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 9
|
||||
|
||||
Click `|Download|` and follow the instructions to get your code onto your EV3 Brick. Press the **center** button on the EV3 Brick to run the program.
|
||||
|
||||
## Contemplate
|
||||
|
||||
To simulate what could happen if a driver falls asleep while driving, your robot could sound an alarm signal when it crosses the line. This feature is often available in new cars.
|
||||
|
||||
Program your robot to perform this function.
|
||||
|
||||
Think about what you have learned, then document it. Describe your pseudocode for this task. Creatively record your ideas, and findings.
|
||||
|
||||
### Programming hint
|
||||
|
||||
```blocks
|
||||
motors.largeBC.steer(0, 20)
|
||||
while (true) {
|
||||
sensors.color3.pauseForColor(ColorSensorColor.Yellow)
|
||||
music.playSoundEffect(sounds.systemGeneralAlert)
|
||||
}
|
||||
while (true) {
|
||||
while (true) { sensors.color3.pauseForLight(LightIntensityMode.Reflected, LightCondition.Bright)
|
||||
motors.largeB.setSpeed(10)
|
||||
motors.largeC.setSpeed(-10)
|
||||
}
|
||||
while (true) {
|
||||
sensors.color3.pauseForLight(LightIntensityMode.Reflected, LightCondition.Bright)
|
||||
motors.largeA.setSpeed(-10)
|
||||
motors.largeA.setSpeed(10)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Continue
|
||||
|
||||
Program your robot to drive on “autopilot” along a given route. You will need to create a program that recognizes and responds to a dark line (or white line). You will create a line-following program and your robot will need to travel along the line without losing contact with it.
|
||||
|
||||
You will need to constantly debug your program in order to make your robot travel as smoothly as possible along the line.
|
||||
|
||||
### Programming hint
|
||||
|
||||
```blocks
|
||||
while (true) {
|
||||
while (true) { sensors.color3.pauseForLight(LightIntensityMode.Reflected, LightCondition.Bright)
|
||||
motors.largeB.setSpeed(10)
|
||||
motors.largeC.setSpeed(-10)
|
||||
}
|
||||
while (true) {
|
||||
sensors.color3.pauseForLight(LightIntensityMode.Reflected, LightCondition.Bright)
|
||||
motors.largeB.setSpeed(-10)
|
||||
motors.largeC.setSpeed(10)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Share
|
||||
|
||||
Consider the following questions:
|
||||
|
||||
1. What challenged you?
|
||||
2. Where there any surprises?
|
||||
3. How could you improve your program?
|
||||
4. Could your program have been more streamlined?
|
||||
5. Have you used too many blocks?
|
||||
6. Is there a more efficient way of building your program?
|
||||
7. How could your program be used in real-world scenarios?
|
||||
|
||||
Think about what you have learned, then document it. Creatively record and present your ideas, creations, and findings.
|
||||
|
||||
|
||||
|
||||
|
||||
|
72
docs/lessons/make-it-move-tutorial.md
Normal file
72
docs/lessons/make-it-move-tutorial.md
Normal file
@ -0,0 +1,72 @@
|
||||
# Make It Move Without Wheels
|
||||
|
||||
## Objective @fullscreen
|
||||
|
||||
Design, build and program a robot that can move itself:
|
||||
|
||||
Your robot will:
|
||||
|
||||
* Go a distance of at least 30cm
|
||||
* Use at least one motor
|
||||
* Use NO wheels for locomotion
|
||||
|
||||

|
||||
|
||||
|
||||
## Construct @fullscreen
|
||||
|
||||
Build a Walker Bot!
|
||||
|
||||
The Walker Bot is one example of many possible solutions for making a robot move without wheels.
|
||||
|
||||
The Walker Bot combines an EV3 Frame and two legs that are mirror-images to create left and right legs.
|
||||
|
||||
The legs in the Walker Bot are designed to show how to change the rotary motion of a motor to reciprocating motion.
|
||||
|
||||
Start by reading [these](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/ev3-dep/building%20instructions/walker-bot-bi-180fc24f9298e1dd6201099627d43903.pdf) instructions first.
|
||||
|
||||

|
||||
|
||||
|
||||
## Program 1 @fullscreen
|
||||
|
||||
In nature, creatures use many methods to get around. None of them, however, use wheels to move. Can we copy the method of animal locomotion with our robot? Using motors and legs, make the robot move without using any wheels.
|
||||
|
||||
Place a ``||motors:tank large B+C||`` block from ``||motors:Motors||`` under ``||loops:on start||``.
|
||||
|
||||
Change the speed to `-60%` (for motor B) and `+60%` (for motor C).
|
||||
Change the rotations to `9`.
|
||||
|
||||
The ``||motors:tank large B+C||`` block will run for `9` rotations when the **center** button is pressed on the EV3 brick. The motors are set for the reverse direction because they are mounted upside down in this model.
|
||||
|
||||
```blocks
|
||||
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
|
||||
```
|
||||
|
||||
## Program 2 @fullscreen
|
||||
|
||||
Place a ``||motors:stop all motors||`` block under ``||motors:tank large B+C||``.
|
||||
|
||||
The ``||motors:tank large B+C||`` block will run for `9` rotations when the **center** button is pressed on the EV3 brick then stop.
|
||||
|
||||
```blocks
|
||||
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
|
||||
motors.stopAllMotors()
|
||||
```
|
||||
|
||||
## Program 3 @fullscreen
|
||||
|
||||
Place a ``||brick:show string||`` block under ``||motors:stop all motors||``.
|
||||
Change the `"Hello World"` text to `"30 cm"`.
|
||||
|
||||
The ``||motors:tank large B+C||`` will run for `9` rotations when the **center** button is pressed on the EV3 brick then stop and display "30 cm" on the EV3 Brick’s screen.
|
||||
|
||||
```blocks
|
||||
motors.largeBC.tank(-60, 60, 9, MoveUnit.Rotations)
|
||||
motors.stopAllMotors()
|
||||
brick.showString("30 cm", 1)
|
||||
```
|
||||
|
||||
## Program 4 @fullscreen
|
||||
|
||||
Click `|Download|` and follow the instructions to get your code onto your EV3 Brick. Press the **center** button on the EV3 Brick to run the program.
|
73
docs/lessons/make-it-move.md
Normal file
73
docs/lessons/make-it-move.md
Normal file
@ -0,0 +1,73 @@
|
||||
# Make It Move Without Wheels
|
||||
|
||||
## Objective
|
||||
|
||||
Design, build and program a robot that can move itself:
|
||||
|
||||
Your robot will:
|
||||
|
||||
* Go a distance of at least 30cm
|
||||
* Use at least one motor
|
||||
* Use NO wheels for locomotion
|
||||
|
||||

|
||||
|
||||
## Construct
|
||||
|
||||
Build a Walker Bot!
|
||||
|
||||
The Walker Bot is one example of many possible solutions for making a robot move without wheels.
|
||||
|
||||
The Walker Bot combines an EV3 Frame and two legs that are mirror-images to create left and right legs.
|
||||
|
||||
The legs in the Walker Bot are designed to show how to change the rotary motion of a motor to reciprocating motion.
|
||||
|
||||
Start by reading [these](https://le-www-live-s.legocdn.com/sc/media/lessons/mindstorms-ev3/ev3-dep/building%20instructions/walker-bot-bi-180fc24f9298e1dd6201099627d43903.pdf) instructions first.
|
||||
|
||||

|
||||
|
||||
|
||||
## Program
|
||||
|
||||
In nature, creatures use many methods to get around. None of them, however, use wheels to move. Can we copy the method of animal locomotion with our robot? Using motors and legs, make the robot move without using any wheels.
|
||||
|
||||
### Step 1
|
||||
|
||||
Place a ``||motors:tank large B+C||`` block from ``||motors:Motors||`` under ``||loops:on start||``.
|
||||
|
||||
Change the speed to `-60%` (for motor B) and `+60%` (for motor C).
|
||||
Change the rotations to `9`.
|
||||
|
||||
The ``||motors:tank large B+C||`` block will run for `9` rotations when the **center** button is pressed on the EV3 brick. The motors are set for the reverse direction because they are mounted upside down in this model.
|
||||
|
||||
```typescript-ignore
|
||||
motors.largeBC.tankFor(-60, 60, 9, MoveUnit.Rotations)
|
||||
```
|
||||
|
||||
### Step 2
|
||||
|
||||
Place a ``||motors:stop all motors||`` block under ``||motors:tank large B+C||``.
|
||||
|
||||
The ``||motors:tank large B+C||`` block will run for `9` rotations when the **center** button is pressed on the EV3 brick then stop.
|
||||
|
||||
```typescript-ignore
|
||||
motors.largeBC.tankFor(-60, 60, 9, MoveUnit.Rotations)
|
||||
motors.stopAllMotors()
|
||||
```
|
||||
|
||||
### Step 3
|
||||
|
||||
Place a ``||brick:show string||`` block under ``||motors:stop all motors||``.
|
||||
Change the `"Hello World"` text to `"30 cm"`.
|
||||
|
||||
The ``||motors:tank large B+C||`` will run for `9` rotations when the **center** button is pressed on the EV3 brick then stop and display "30 cm" on the EV3 Brick’s screen.
|
||||
|
||||
```typescript-ignore
|
||||
motors.largeBC.tankFor(-60, 60, 9, MoveUnit.Rotations)
|
||||
motors.stopAllMotors()
|
||||
brick.showString("30 cm", 1)
|
||||
```
|
||||
|
||||
### Step 4
|
||||
|
||||
Click `|Download|` and follow the instructions to get your code onto your EV3 Brick. Press the **center** button on the EV3 Brick to run the program.
|
BIN
docs/static/lessons/line-detection.jpg
vendored
Normal file
BIN
docs/static/lessons/line-detection.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
docs/static/lessons/line-detection/car-driving.jpg
vendored
Normal file
BIN
docs/static/lessons/line-detection/car-driving.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
BIN
docs/static/lessons/line-detection/color-sensor-driving.jpg
vendored
Normal file
BIN
docs/static/lessons/line-detection/color-sensor-driving.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
docs/static/lessons/make-it-move.jpg
vendored
Normal file
BIN
docs/static/lessons/make-it-move.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
docs/static/lessons/make-it-move/locomotion-no-wheels.jpg
vendored
Normal file
BIN
docs/static/lessons/make-it-move/locomotion-no-wheels.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
BIN
docs/static/lessons/make-it-move/walker-bot.jpg
vendored
Normal file
BIN
docs/static/lessons/make-it-move/walker-bot.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
25
libs/automation/_locales/automation-jsdoc-strings.json
Normal file
25
libs/automation/_locales/automation-jsdoc-strings.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"automation": "Automation, process control and robotic controllers\n\nProcess control, automation, robotics AI",
|
||||
"automation.Behavior": "A behavior",
|
||||
"automation.Behavior.update": "Called on each behavior iteration even for suppresed behaviors",
|
||||
"automation.Behavior.update|param|elapsed": "milli seconds since last call",
|
||||
"automation.BehaviorManager": "A manager for behaviors",
|
||||
"automation.BehaviorManager.add": "Adds a new behavior to the behavior manager",
|
||||
"automation.BehaviorManager.add|param|behavior": "the behavior to add",
|
||||
"automation.BehaviorManager.start": "Starts the behavior control loop",
|
||||
"automation.BehaviorManager.stop": "Stops the execution loop",
|
||||
"automation.PIDController.compute": "Computes the output based on the system state",
|
||||
"automation.PIDController.setControlSaturation": "Sets the control saturation values",
|
||||
"automation.PIDController.setControlSaturation|param|high": "highest control value, eg: 100",
|
||||
"automation.PIDController.setControlSaturation|param|low": "lowest control value, eg: -100",
|
||||
"automation.PIDController.setDerivativeFilter": "Sets the derivative filter gain",
|
||||
"automation.PIDController.setDerivativeFilter|param|N": "the filter gain, eg:10",
|
||||
"automation.PIDController.setGains": "Sets the PID gains",
|
||||
"automation.PIDController.setGains|param|b": "setpoint weight, eg: 0.9",
|
||||
"automation.PIDController.setGains|param|kd": "derivative gain",
|
||||
"automation.PIDController.setGains|param|ki": "integral gain",
|
||||
"automation.PIDController.setGains|param|kp": "proportional gain",
|
||||
"automation.PIDController.setPoint": "Updates the desired setpoint",
|
||||
"automation.addBehavior": "Adds the behavior and starts it",
|
||||
"automation.addBehavior|param|behavior": "a behavior"
|
||||
}
|
12
libs/automation/_locales/automation-strings.json
Normal file
12
libs/automation/_locales/automation-strings.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"automation.PIDController.compute|block": "%pid|compute for timestep %timestep|(s) at state %y",
|
||||
"automation.PIDController.setControlSaturation|block": "set %pid|control saturation from %low|to %high",
|
||||
"automation.PIDController.setDerivativeFilter|block": "set %pid|derivative filter %N",
|
||||
"automation.PIDController.setGains|block": "set %pid|gains kp %kp|ki %ki|kd %kd",
|
||||
"automation.PIDController.setPoint|block": "set %pid|point to %ysp",
|
||||
"automation.addBehavior|block": "add behavior %behavior",
|
||||
"automation|block": "automation",
|
||||
"{id:category}Automation": "Automation",
|
||||
"{id:group}Behaviors": "Behaviors",
|
||||
"{id:group}PID": "PID"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/behaviors",
|
||||
"additionalFilePath": "../../node_modules/pxt-common-packages/libs/automation",
|
||||
"dependencies": {
|
||||
"core": "file:../ev3"
|
||||
"ev3": "file:../ev3"
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"behaviors": "Behavior drive blocks",
|
||||
"behaviors.Behavior": "A behavior",
|
||||
"behaviors.BehaviorManager": "A manager for behaviors",
|
||||
"behaviors.BehaviorManager.add": "Adds a new behavior to the behavior manager",
|
||||
"behaviors.BehaviorManager.add|param|behavior": "the behavior to add",
|
||||
"behaviors.BehaviorManager.start": "Starts the behavior control loop",
|
||||
"behaviors.BehaviorManager.stop": "Stops the execution loop",
|
||||
"behaviors.addBehavior": "Adds the behavior and starts it",
|
||||
"behaviors.addBehavior|param|behavior": "a behavior",
|
||||
"behaviors.avoidCrash": "A behavior that stops all motors if the sensor distance get too short",
|
||||
"behaviors.driveForward": "A behavior that turns on the motors to the specified speed",
|
||||
"behaviors.driveForward|param|motors": "@param speed the desired speed, eg: 50"
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"behaviors.addBehavior|block": "add behavior %behavior",
|
||||
"behaviors.avoidCrash|block": "avoid crash using %ultrasonic",
|
||||
"behaviors.driveForward|block": "drive %motors|forward at %speed=motorSpeedPicker|%",
|
||||
"behaviors|block": "behaviors",
|
||||
"{id:category}Behaviors": "Behaviors"
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
namespace behaviors {
|
||||
class AvoidCrashBehavior extends behaviors.Behavior {
|
||||
private ultrasonic: sensors.UltraSonicSensor;
|
||||
constructor(ultrasonic: sensors.UltraSonicSensor) {
|
||||
super();
|
||||
this.ultrasonic = ultrasonic;
|
||||
}
|
||||
|
||||
shouldRun(): boolean {
|
||||
return this.ultrasonic.distance() < 5;
|
||||
}
|
||||
|
||||
run(): void {
|
||||
motors.stopAllMotors();
|
||||
this.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A behavior that stops all motors if the sensor distance get too short
|
||||
*/
|
||||
//% blockId=behaviorsAvoidCrash block="avoid crash using %ultrasonic"
|
||||
export function avoidCrash(ultrasonic: sensors.UltraSonicSensor) : behaviors.Behavior {
|
||||
return new AvoidCrashBehavior(ultrasonic);
|
||||
}
|
||||
|
||||
class DriveForwardBehavior extends behaviors.Behavior {
|
||||
private motors: motors.MotorBase;
|
||||
private speed: number;
|
||||
constructor(motors: motors.MotorBase, speed: number) {
|
||||
super();
|
||||
this.motors = motors;
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
shouldRun(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
run(): void {
|
||||
this.motors.setSpeed(this.speed);
|
||||
pauseUntil(() => !this.active);
|
||||
this.motors.setSpeed(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A behavior that turns on the motors to the specified speed
|
||||
* @param motors
|
||||
* @param speed the desired speed, eg: 50
|
||||
*/
|
||||
//% blockId=behaviorsDriveForward block="drive %motors|forward at %speed=motorSpeedPicker|%"
|
||||
export function driveForward(motors: motors.MotorBase, speed: number): behaviors.Behavior {
|
||||
return new DriveForwardBehavior(motors, speed);
|
||||
}
|
||||
}
|
@ -52,9 +52,12 @@
|
||||
"console.logValue|param|value": "to write",
|
||||
"console.sendToScreen": "Sends the log messages to the brick screen and uses the brick up and down buttons to scroll.",
|
||||
"control": "Program controls and events.",
|
||||
"control.Timer.millis": "Gets the elapsed time in millis",
|
||||
"control.Timer": "A timer",
|
||||
"control.Timer.millis": "Gets the elapsed time in millis since the last reset",
|
||||
"control.Timer.pauseUntil": "Pauses until the timer reaches the given amount of milliseconds",
|
||||
"control.Timer.pauseUntil|param|ms": "how long to pause for, eg: 5, 100, 200, 500, 1000, 2000",
|
||||
"control.Timer.reset": "Resets the timer",
|
||||
"control.Timer.seconds": "Gets the elapsed time in seconds",
|
||||
"control.Timer.seconds": "Gets the elapsed time in seconds since the last reset",
|
||||
"control.allocateNotifyEvent": "Allocates the next user notification event",
|
||||
"control.deviceFirmwareVersion": "Determine the version of system software currently running.",
|
||||
"control.dmesg": "Write data to DMESG debugging buffer.",
|
||||
|
@ -48,6 +48,7 @@
|
||||
"console.sendToScreen|block": "send console to screen",
|
||||
"console|block": "console",
|
||||
"control.Timer.millis|block": "%timer|millis",
|
||||
"control.Timer.pauseUntil|block": "%timer|pause until (ms) %ms",
|
||||
"control.Timer.reset|block": "%timer|reset",
|
||||
"control.Timer.seconds|block": "%timer|seconds",
|
||||
"control.raiseEvent|block": "raise event|from %src|with value %value",
|
||||
|
@ -4,34 +4,24 @@
|
||||
*/
|
||||
const enum BrickLight {
|
||||
//% block=off enumval=0
|
||||
//% blockIdentity=brick.lightPattern
|
||||
Off = 0,
|
||||
//% block=green enumval=1
|
||||
//% blockIdentity=brick.lightPattern
|
||||
Green = 1,
|
||||
//% block=red enumval=2
|
||||
//% blockIdentity=brick.lightPattern
|
||||
Red = 2,
|
||||
//% block=orange enumval=3
|
||||
//% blockIdentity=brick.lightPattern
|
||||
Orange = 3,
|
||||
//% block="green flash" enumval=4
|
||||
//% blockIdentity=brick.lightPattern
|
||||
GreenFlash = 4,
|
||||
//% block="red flash" enumval=5
|
||||
//% blockIdentity=brick.lightPattern
|
||||
RedFlash = 5,
|
||||
//% block="orange flash" enumval=6
|
||||
//% blockIdentity=brick.lightPattern
|
||||
OrangeFlash = 6,
|
||||
//% block="green pulse" enumval=7
|
||||
//% blockIdentity=brick.lightPattern
|
||||
GreenPulse = 7,
|
||||
//% block="red pulse" enumval=8
|
||||
//% blockIdentity=brick.lightPattern
|
||||
RedPulse = 8,
|
||||
//% block="orange pulse" enumval=9
|
||||
//% blockIdentity=brick.lightPattern
|
||||
OrangePulse = 9,
|
||||
}
|
||||
|
||||
|
@ -312,6 +312,7 @@ namespace sensors.internal {
|
||||
|
||||
reset() {
|
||||
if (this.isActive()) uartReset(this._port);
|
||||
this.realmode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
namespace control {
|
||||
/**
|
||||
* A timer
|
||||
*/
|
||||
//% fixedInstances
|
||||
export class Timer {
|
||||
start: number;
|
||||
@ -8,7 +11,7 @@ namespace control {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the elapsed time in millis
|
||||
* Gets the elapsed time in millis since the last reset
|
||||
*/
|
||||
//% blockId=timerMillis block="%timer|millis"
|
||||
millis(): number {
|
||||
@ -16,7 +19,7 @@ namespace control {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the elapsed time in seconds
|
||||
* Gets the elapsed time in seconds since the last reset
|
||||
*/
|
||||
//% blockId=timerSeconds block="%timer|seconds"
|
||||
seconds(): number {
|
||||
@ -30,6 +33,16 @@ namespace control {
|
||||
reset() {
|
||||
this.start = control.millis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses until the timer reaches the given amount of milliseconds
|
||||
* @param ms how long to pause for, eg: 5, 100, 200, 500, 1000, 2000
|
||||
*/
|
||||
//% blockId=timerPauseUntil block="%timer|pause until (ms) %ms"
|
||||
pauseUntil(ms: number) {
|
||||
const remaining = this.millis() - ms;
|
||||
loops.pause(Math.max(0, remaining));
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed fixedInstance block="timer 1"
|
||||
|
@ -3,6 +3,9 @@
|
||||
"datalog.addValue": "Adds a cell to the row of data",
|
||||
"datalog.addValue|param|name": "name of the cell, eg: \"x\"",
|
||||
"datalog.addValue|param|value": "value of the cell, eg: 0",
|
||||
"datalog.flush": "Commits any buffered row to disk",
|
||||
"datalog.setEnabled": "Turns on or off datalogging",
|
||||
"datalog.setFile": "Starts a new data logger for the given file",
|
||||
"datalog.setFile|param|filename": "the filename, eg: \"datalog.csv\"",
|
||||
"datalog.setStorage": "* @param storage custom storage solution"
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"datalog.addRow|block": "datalog add row",
|
||||
"datalog.addValue|block": "datalog add %name|=%value",
|
||||
"datalog.setEnabled|block": "datalog %enabled",
|
||||
"datalog|block": "datalog",
|
||||
"{id:category}Datalog": "Datalog"
|
||||
}
|
@ -3,13 +3,16 @@ namespace datalog {
|
||||
let _headers: string[] = undefined;
|
||||
let _headersLength: number;
|
||||
let _values: number[];
|
||||
let _buffer: string = "";
|
||||
let _start: number;
|
||||
let _filename = "data.csv";
|
||||
let _filename = "datalog.csv";
|
||||
let _storage: storage.Storage = storage.temporary;
|
||||
let _enabled = true;
|
||||
|
||||
function clear() {
|
||||
_headers = undefined;
|
||||
_values = undefined;
|
||||
_buffer = "";
|
||||
}
|
||||
|
||||
function init() {
|
||||
@ -31,7 +34,10 @@ namespace datalog {
|
||||
_headersLength = _storage.size(_filename);
|
||||
}
|
||||
// commit row data
|
||||
_storage.appendCSV(_filename, _values);
|
||||
_buffer += storage.toCSV(_values, _storage.csvSeparator);
|
||||
// buffered writes
|
||||
if (_buffer.length > 1024)
|
||||
flush();
|
||||
}
|
||||
|
||||
// clear values
|
||||
@ -44,6 +50,8 @@ namespace datalog {
|
||||
//% weight=100
|
||||
//% blockId=datalogAddRow block="datalog add row"
|
||||
export function addRow(): void {
|
||||
if (!_enabled) return;
|
||||
|
||||
commit();
|
||||
init();
|
||||
const s = (control.millis() - _start) / 1000;
|
||||
@ -65,16 +73,16 @@ namespace datalog {
|
||||
i = _headers.length - 1;
|
||||
}
|
||||
_values[i] = value;
|
||||
if (i > 0) // 0 is time
|
||||
console.logValue(name, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new data logger for the given file
|
||||
* @param filename the filename, eg: "datalog.csv"
|
||||
*/
|
||||
//%
|
||||
export function setFile(fn: string) {
|
||||
_filename = fn;
|
||||
export function setFile(filename: string) {
|
||||
flush();
|
||||
_filename = filename;
|
||||
clear();
|
||||
}
|
||||
|
||||
@ -84,7 +92,31 @@ namespace datalog {
|
||||
*/
|
||||
//%
|
||||
export function setStorage(storage: storage.Storage) {
|
||||
flush();
|
||||
_storage = storage;
|
||||
clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits any buffered row to disk
|
||||
*/
|
||||
//%
|
||||
export function flush() {
|
||||
if (_buffer) {
|
||||
const b = _buffer;
|
||||
_buffer = "";
|
||||
_storage.append(_filename, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns on or off datalogging
|
||||
* @param enabled
|
||||
*/
|
||||
//% blockId=datalogEnabled block="datalog %enabled"
|
||||
//% enabled.fieldEditor=fieldonoff
|
||||
export function setEnabled(enabled: boolean) {
|
||||
flush();
|
||||
_enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,8 @@
|
||||
"color-sensor": "file:../color-sensor",
|
||||
"touch-sensor": "file:../touch-sensor",
|
||||
"ultrasonic-sensor": "file:../ultrasonic-sensor",
|
||||
"gyro-sensor": "file:../gyro-sensor"
|
||||
"gyro-sensor": "file:../gyro-sensor",
|
||||
"mood": "file:../mood"
|
||||
},
|
||||
"public": true
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
{
|
||||
"sensors.GyroSensor.angle": "Get the current angle from the gyroscope.",
|
||||
"sensors.GyroSensor.drift": "Gets the computed rate drift",
|
||||
"sensors.GyroSensor.rate": "Get the current rotation rate from the gyroscope.",
|
||||
"sensors.GyroSensor.reset": "Forces a calibration of the gyro. Must be called when the sensor is completely still."
|
||||
"sensors.GyroSensor.reset": "Forces a calibration of the gyro. Must be called when the sensor is completely still.",
|
||||
"sensors.GyroSensor.setDriftCorrection": "Enables or disable drift correction"
|
||||
}
|
@ -8,16 +8,27 @@ namespace sensors {
|
||||
//% fixedInstances
|
||||
export class GyroSensor extends internal.UartSensor {
|
||||
private calibrating: boolean;
|
||||
private _drift: number;
|
||||
private _drifting: boolean;
|
||||
constructor(port: number) {
|
||||
super(port)
|
||||
this.calibrating = false;
|
||||
this._drift = 0;
|
||||
this._drifting = true;
|
||||
this.setMode(GyroSensorMode.Rate);
|
||||
}
|
||||
|
||||
_deviceType() {
|
||||
return DAL.DEVICE_TYPE_GYRO
|
||||
}
|
||||
|
||||
_query(): number {
|
||||
return this.getNumber(NumberFormat.Int16LE, 0);
|
||||
}
|
||||
|
||||
setMode(m: GyroSensorMode) {
|
||||
if (m == GyroSensorMode.Rate && this.mode != m)
|
||||
this._drift = 0;
|
||||
this._setMode(m)
|
||||
}
|
||||
|
||||
@ -37,8 +48,8 @@ namespace sensors {
|
||||
if (this.calibrating)
|
||||
pauseUntil(() => !this.calibrating, 2000);
|
||||
|
||||
this.setMode(GyroSensorMode.Angle)
|
||||
return this.getNumber(NumberFormat.Int16LE, 0)
|
||||
this.setMode(GyroSensorMode.Angle);
|
||||
return this._query();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,8 +68,14 @@ namespace sensors {
|
||||
if (this.calibrating)
|
||||
pauseUntil(() => !this.calibrating, 2000);
|
||||
|
||||
this.setMode(GyroSensorMode.Rate)
|
||||
return this.getNumber(NumberFormat.Int16LE, 0)
|
||||
this.setMode(GyroSensorMode.Rate);
|
||||
let curr = this._query();
|
||||
if (Math.abs(curr) < 20) {
|
||||
const p = 0.0005;
|
||||
this._drift = (1 - p) * this._drift + p * curr;
|
||||
curr -= this._drift;
|
||||
}
|
||||
return curr;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,23 +93,45 @@ namespace sensors {
|
||||
if (this.calibrating) return; // already in calibration mode
|
||||
|
||||
this.calibrating = true;
|
||||
// may be triggered by a button click, give time to settle
|
||||
loops.pause(500);
|
||||
// may be triggered by a button click,
|
||||
// give time for robot to settle
|
||||
loops.pause(700);
|
||||
// send a reset command
|
||||
super.reset();
|
||||
// we need to switch mode twice to perform a calibration
|
||||
if (this.mode == GyroSensorMode.Rate)
|
||||
this.setMode(GyroSensorMode.Angle);
|
||||
else
|
||||
this.setMode(GyroSensorMode.Rate);
|
||||
// switch back and wait
|
||||
if (this.mode == GyroSensorMode.Rate)
|
||||
this.setMode(GyroSensorMode.Angle);
|
||||
else
|
||||
this.setMode(GyroSensorMode.Rate);
|
||||
// give it more time to settle
|
||||
loops.pause(500);
|
||||
this.calibrating = false;
|
||||
// switch back to the desired mode
|
||||
this.setMode(this.mode);
|
||||
// wait till sensor is live
|
||||
pauseUntil(() => this.isActive());
|
||||
// give it a bit of time to init
|
||||
loops.pause(1000)
|
||||
// compute drift
|
||||
this._drift = 0;
|
||||
if (this.mode == GyroSensorMode.Rate) {
|
||||
for (let i = 0; i < 200; ++i) {
|
||||
this._drift += this._query();
|
||||
loops.pause(4);
|
||||
}
|
||||
this._drift /= 200;
|
||||
}
|
||||
// and we're done
|
||||
this.calibrating = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the computed rate drift
|
||||
*/
|
||||
//%
|
||||
drift(): number {
|
||||
return this._drift;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disable drift correction
|
||||
* @param enabled
|
||||
*/
|
||||
//%
|
||||
setDriftCorrection(enabled: boolean) {
|
||||
this._drifting = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
3
libs/mood/README.md
Normal file
3
libs/mood/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# mood
|
||||
|
||||
A package to put the EV3 in various moods.
|
17
libs/mood/_locales/mood-jsdoc-strings.json
Normal file
17
libs/mood/_locales/mood-jsdoc-strings.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"brick.Mood": "A mood",
|
||||
"brick.Mood.show": "Shows the mood on the EV3",
|
||||
"brick.showMood": "Shows a mood",
|
||||
"moods.angry": "An angry mood",
|
||||
"moods.awake": "A awake mood",
|
||||
"moods.dizzy": "A dizzy mood",
|
||||
"moods.knockedOut": "A knocked out mood",
|
||||
"moods.love": "In love mood",
|
||||
"moods.middleLeft": "Looking around left",
|
||||
"moods.middleRight": "Looking around right",
|
||||
"moods.neutral": "In a neutral mood",
|
||||
"moods.sad": "A sad mood",
|
||||
"moods.sleeping": "A sleeping mood",
|
||||
"moods.tired": "A tired mood",
|
||||
"moods.winking": "In laughing mood"
|
||||
}
|
8
libs/mood/_locales/mood-strings.json
Normal file
8
libs/mood/_locales/mood-strings.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"brick.showMood|block": "show mood %mood=mood_image_picker",
|
||||
"brick|block": "brick",
|
||||
"moods|block": "moods",
|
||||
"{id:category}Brick": "Brick",
|
||||
"{id:category}Moods": "Moods",
|
||||
"{id:group}Screen": "Screen"
|
||||
}
|
125
libs/mood/mood.ts
Normal file
125
libs/mood/mood.ts
Normal file
@ -0,0 +1,125 @@
|
||||
namespace brick {
|
||||
/**
|
||||
* Shows a mood
|
||||
*/
|
||||
//% weight=90
|
||||
//% blockId=moodShow block="show mood %mood=mood_image_picker"
|
||||
//% weight=101 group="Screen" blockGap=8
|
||||
export function showMood(mood: Mood) {
|
||||
if(mood)
|
||||
mood.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* A mood
|
||||
*/
|
||||
//% fixedInstances
|
||||
export class Mood {
|
||||
private image: Image;
|
||||
private sound: Sound;
|
||||
private light: BrickLight;
|
||||
|
||||
constructor(image: Image, sound: Sound, light: BrickLight) {
|
||||
this.image = image;
|
||||
this.sound = sound;
|
||||
this.light = light;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the mood on the EV3
|
||||
*/
|
||||
show() {
|
||||
brick.setLight(this.light);
|
||||
brick.showImage(this.image);
|
||||
music.playSoundEffectUntilDone(this.sound);
|
||||
loops.pause(20);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An image
|
||||
* @param image the image
|
||||
*/
|
||||
//% blockId=mood_image_picker block="%image" shim=TD_ID
|
||||
//% image.fieldEditor="images"
|
||||
//% image.fieldOptions.columns=4
|
||||
//% image.fieldOptions.width=400
|
||||
//% group="Screen" weight=0 blockHidden=1
|
||||
export function __moodImagePicker(mood: Mood): Mood {
|
||||
return mood;
|
||||
}
|
||||
}
|
||||
|
||||
namespace moods {
|
||||
/**
|
||||
* A sleeping mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesSleeping
|
||||
export const sleeping = new brick.Mood(images.eyesSleeping, sounds.expressionsSnoring, BrickLight.OrangePulse);
|
||||
|
||||
/**
|
||||
* A awake mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesAwake
|
||||
export const awake = new brick.Mood(images.eyesAwake, sounds.informationActivate, BrickLight.Orange);
|
||||
|
||||
/**
|
||||
* A tired mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesTiredMiddle
|
||||
export const tired = new brick.Mood(images.eyesTiredMiddle, sounds.expressionsSneezing, BrickLight.OrangeFlash);
|
||||
|
||||
/**
|
||||
* An angry mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesAngry
|
||||
export const angry = new brick.Mood(images.eyesAngry, sounds.animalsDogGrowl, BrickLight.RedPulse);
|
||||
|
||||
/**
|
||||
* A sad mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesTear
|
||||
export const sad = new brick.Mood(images.eyesTear, sounds.animalsDogWhine, BrickLight.Red);
|
||||
|
||||
/**
|
||||
* A dizzy mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesDizzy
|
||||
export const dizzy = new brick.Mood(images.eyesDizzy, sounds.expressionsUhOh, BrickLight.OrangeFlash);
|
||||
|
||||
/**
|
||||
* A knocked out mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesKnockedOut
|
||||
export const knockedOut = new brick.Mood(images.eyesKnockedOut, sounds.informationError, BrickLight.RedFlash);
|
||||
|
||||
/**
|
||||
* Looking around left
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesMiddleLeft
|
||||
export const middleLeft = new brick.Mood(images.eyesMiddleLeft, sounds.informationAnalyze, BrickLight.Off);
|
||||
|
||||
/**
|
||||
* Looking around right
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesMiddleRight
|
||||
export const middleRight = new brick.Mood(images.eyesMiddleRight, sounds.informationAnalyze, BrickLight.Off);
|
||||
|
||||
/**
|
||||
* In love mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesLove
|
||||
export const love = new brick.Mood(images.eyesLove, sounds.expressionsMagicWand, BrickLight.GreenPulse);
|
||||
|
||||
/**
|
||||
* In laughing mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesWinking
|
||||
export const winking = new brick.Mood(images.eyesWinking, sounds.expressionsLaughing1, BrickLight.GreenFlash);
|
||||
|
||||
/**
|
||||
* In a neutral mood
|
||||
*/
|
||||
//% fixedInstance jres=images.eyesNeutral
|
||||
export const neutral = new brick.Mood(images.eyesNeutral, undefined, BrickLight.Green);
|
||||
}
|
15
libs/mood/pxt.json
Normal file
15
libs/mood/pxt.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "mood",
|
||||
"description": "The EV3 mood library",
|
||||
"files": [
|
||||
"README.md",
|
||||
"mood.ts"
|
||||
],
|
||||
"testFiles": [
|
||||
],
|
||||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core",
|
||||
"music": "file:../music"
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
"music.setTempo": "Set the tempo a number of beats per minute (bpm).",
|
||||
"music.setTempo|param|bpm": "The new tempo in beats per minute, eg: 120",
|
||||
"music.setVolume": "Set the output volume of the sound synthesizer.",
|
||||
"music.setVolume|param|volume": "the volume 0...256, eg: 128",
|
||||
"music.setVolume|param|volume": "the volume 0...100, eg: 50",
|
||||
"music.stopAllSounds": "Play a tone through the speaker for some amount of time.",
|
||||
"music.tempo": "Return the tempo in beats per minute (bpm).\nTempo is the speed (bpm = beats per minute) at which notes play. The larger the tempo value, the faster the notes will play."
|
||||
}
|
@ -121,7 +121,7 @@
|
||||
"sounds.mechanicalMotorStart|block": "mechanical motor start",
|
||||
"sounds.mechanicalMotorStop|block": "mechanical motor stop",
|
||||
"sounds.mechanicalRatchet|block": "mechanical ratchet",
|
||||
"sounds.mechanicalSonar|block": "\"mechanical sonar\"",
|
||||
"sounds.mechanicalSonar|block": "mechanical sonar",
|
||||
"sounds.mechanicalTickTack|block": "mechanical tick tack",
|
||||
"sounds.mechanicalWalk|block": "mechanical walk",
|
||||
"sounds.movementsArm1|block": "movements arm1",
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
namespace music {
|
||||
|
||||
uint8_t currVolume = 2;
|
||||
uint8_t currVolume = 50;
|
||||
uint8_t *lmsSoundMMap;
|
||||
|
||||
int writeDev(void *data, int size) {
|
||||
@ -25,16 +25,16 @@ int writeDev(void *data, int size) {
|
||||
|
||||
/**
|
||||
* Set the output volume of the sound synthesizer.
|
||||
* @param volume the volume 0...256, eg: 128
|
||||
* @param volume the volume 0...100, eg: 50
|
||||
*/
|
||||
//% weight=96
|
||||
//% blockId=synth_set_volume block="set volume %volume"
|
||||
//% parts="speaker" blockGap=8
|
||||
//% volume.min=0 volume.max=256
|
||||
//% volume.min=0 volume.max=100
|
||||
//% help=music/set-volume
|
||||
//% weight=1
|
||||
void setVolume(int volume) {
|
||||
currVolume = max(0, min(100, volume * 100 / 256));
|
||||
currVolume = max(0, min(100, volume));
|
||||
}
|
||||
|
||||
#define SOUND_CMD_BREAK 0
|
||||
|
4
libs/music/shims.d.ts
vendored
4
libs/music/shims.d.ts
vendored
@ -3,12 +3,12 @@ declare namespace music {
|
||||
|
||||
/**
|
||||
* Set the output volume of the sound synthesizer.
|
||||
* @param volume the volume 0...256, eg: 128
|
||||
* @param volume the volume 0...100, eg: 50
|
||||
*/
|
||||
//% weight=96
|
||||
//% blockId=synth_set_volume block="set volume %volume"
|
||||
//% parts="speaker" blockGap=8
|
||||
//% volume.min=0 volume.max=256
|
||||
//% volume.min=0 volume.max=100
|
||||
//% help=music/set-volume
|
||||
//% weight=1 shim=music::setVolume
|
||||
function setVolume(volume: int32): void;
|
||||
|
@ -175,7 +175,7 @@ namespace sounds {
|
||||
export const mechanicalMotorStop = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="mechanical ratchet"
|
||||
export const mechanicalRatchet = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block='"mechanical sonar"'
|
||||
//% fixedInstance jres block="mechanical sonar"
|
||||
export const mechanicalSonar = music.fromWAV(hex``);
|
||||
//% fixedInstance jres block="mechanical tick tack"
|
||||
export const mechanicalTickTack = music.fromWAV(hex``);
|
||||
|
@ -7,7 +7,7 @@ namespace storage {
|
||||
//% fixedInstances
|
||||
export class Storage {
|
||||
csvSeparator: string;
|
||||
constructor() {
|
||||
constructor() {
|
||||
this.csvSeparator = ",";
|
||||
}
|
||||
|
||||
@ -80,18 +80,13 @@ namespace storage {
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a row of CSV data
|
||||
* @param filename the file name to append data, eg: "data.csv"
|
||||
* @param data the data to append
|
||||
*/
|
||||
* Append a row of CSV data
|
||||
* @param filename the file name to append data, eg: "data.csv"
|
||||
* @param data the data to append
|
||||
*/
|
||||
//% blockId=storageAppendCSV block="storage %source|%filename|append CSV %data"
|
||||
appendCSV(filename: string, data: number[]) {
|
||||
let s = ""
|
||||
for (const d of data) {
|
||||
if (s) s += this.csvSeparator;
|
||||
s = s + d;
|
||||
}
|
||||
s += "\r\n"
|
||||
let s = toCSV(data, this.csvSeparator);
|
||||
this.append(filename, s)
|
||||
}
|
||||
|
||||
@ -167,6 +162,16 @@ namespace storage {
|
||||
}
|
||||
}
|
||||
|
||||
export function toCSV(data: number[], sep: string) {
|
||||
let s = ""
|
||||
for (const d of data) {
|
||||
if (s) s += sep;
|
||||
s = s + d;
|
||||
}
|
||||
s += "\r\n"
|
||||
return s;
|
||||
}
|
||||
|
||||
class TemporaryStorage extends Storage {
|
||||
constructor() {
|
||||
super();
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "0.0.65",
|
||||
"version": "0.0.70",
|
||||
"description": "LEGO Mindstorms EV3 for Microsoft MakeCode",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
@ -44,7 +44,7 @@
|
||||
"webfonts-generator": "^0.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-common-packages": "0.15.5",
|
||||
"pxt-common-packages": "0.15.7",
|
||||
"pxt-core": "3.0.11"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -16,11 +16,12 @@
|
||||
"libs/infrared-sensor",
|
||||
"libs/gyro-sensor",
|
||||
"libs/chassis",
|
||||
"libs/mood",
|
||||
"libs/ev3",
|
||||
"libs/storage",
|
||||
"libs/datalog",
|
||||
"libs/tests",
|
||||
"libs/behaviors"
|
||||
"libs/automation"
|
||||
],
|
||||
"simulator": {
|
||||
"autoRun": true,
|
||||
|
@ -97,28 +97,21 @@ namespace pxsim {
|
||||
return this.brickNode;
|
||||
}
|
||||
|
||||
motorUsed(port: number, large: boolean) {
|
||||
motorUsed(ports: number, large: boolean): boolean {
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
const p = 1 << i;
|
||||
if (port & p) {
|
||||
const motorPort = this.motorMap[p];
|
||||
if (!this.outputNodes[motorPort])
|
||||
this.outputNodes[motorPort] = new MotorNode(motorPort, large);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hasMotor(port: number) {
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
const p = 1 << i;
|
||||
if (port & p) {
|
||||
if (ports & p) {
|
||||
const motorPort = this.motorMap[p];
|
||||
const outputNode = this.outputNodes[motorPort];
|
||||
if (outputNode)
|
||||
return true;
|
||||
if (!outputNode) {
|
||||
this.outputNodes[motorPort] = new MotorNode(motorPort, large);
|
||||
continue;
|
||||
}
|
||||
if (outputNode && outputNode.isLarge() != large)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
getMotor(port: number, large?: boolean): MotorNode[] {
|
||||
|
@ -3,15 +3,23 @@
|
||||
import lf = pxsim.localization.lf;
|
||||
|
||||
namespace pxsim.motors {
|
||||
|
||||
export function __motorUsed(port: number, large: boolean) {
|
||||
//console.log("MOTOR INIT " + port);
|
||||
if (!ev3board().hasMotor(port)) {
|
||||
ev3board().motorUsed(port, large);
|
||||
runtime.queueDisplayUpdate();
|
||||
} else {
|
||||
U.userError(`${lf("Multiple motors are connected to Port")} ${String.fromCharCode('A'.charCodeAt(0) + ev3board().motorMap[port])}`);
|
||||
function portsToString(out: number): string {
|
||||
let r = "";
|
||||
for (let i = 0; i < DAL.NUM_OUTPUTS; ++i) {
|
||||
if (out & (1 << i)) {
|
||||
if (r.length > 0) r += "+";
|
||||
r += "ABCD"[i];
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
export function __motorUsed(ports: number, large: boolean) {
|
||||
//console.log("MOTOR INIT " + port);
|
||||
if (ev3board().motorUsed(ports, large))
|
||||
runtime.queueDisplayUpdate();
|
||||
else
|
||||
U.userError(`${lf("Multiple motors are connected to Port")} ${portsToString(ports)}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,10 @@ namespace pxsim {
|
||||
this.rotationsPerMilliSecond = (large ? 170 : 250) / 60000;
|
||||
}
|
||||
|
||||
isLarge(): boolean {
|
||||
return this.id == NodeType.LargeMotor;
|
||||
}
|
||||
|
||||
setPolarity(polarity: number) {
|
||||
// Either 1 or 255 (reverse)
|
||||
/*
|
||||
|
@ -9,6 +9,7 @@
|
||||
},
|
||||
"galleries": {
|
||||
"Maker Activities": "maker",
|
||||
"Coding Activites": "coding"
|
||||
"Coding Activites": "coding",
|
||||
"Lessons": "lessons"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user