Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
ad48ee12ca | |||
83aeb24a98 | |||
fc5ecd9f10 | |||
0b3b840ac1 | |||
60c09809e7 | |||
148067a143 | |||
6f34887c94 | |||
64a9930c2e | |||
5815e16647 | |||
c4f5e425c2 | |||
361ae7a2d2 | |||
3769402ade | |||
5c3c83eb52 | |||
0f07a89981 | |||
11d887a213 | |||
8150b2dbb0 |
@ -19,6 +19,7 @@ If you found a bug, please try if it hasn't been fixed yet! Go to https://makeco
|
||||
* You will need to install the latest EV3 firmware on your brick. Instructions on how to do that are located here: https://makecode.mindstorms.com/troubleshoot.
|
||||
* You will need a computer with a USB port to connect to the EV3 in order to download your programs.
|
||||
* You will need internet access and a browser on your computer to get to https://makecode.mindstorms.com.
|
||||
* You can [install the app](/offline-app) to use the editor offline.
|
||||
|
||||
### I know LabView, how is MakeCode different?
|
||||
|
||||
@ -28,12 +29,16 @@ We have compiled a guide for EV3 LabView users at https://makecode.mindstorms.co
|
||||
|
||||
Go to https://makecode.mindstorms.com. The home screen is filled with videos, tutorials and examples that might be relevant for your missions.
|
||||
|
||||
On the home page, scroll down to the **FLL / City Shaper / Crane Mission** section for specific lessons related to Mission 2.
|
||||
On the home page, scroll down to the **FLL / City Shaper** section for specific lessons related to Mission 2.
|
||||
|
||||
### Can I load both LEGO MINDSTORMS EV3 Software and MakeCode programs onto my EV3?
|
||||
|
||||
Yes.
|
||||
|
||||
### Does it work without internet?
|
||||
|
||||
No, the editor is cached in your browser cache. However, you can also download the [offline app](/offline-app) in case you need to install it on a computer.
|
||||
|
||||
### How do I figure out what a block does?
|
||||
|
||||
You can right-click on any block and select “Help” in the context menu to open the documentation page describing what that block does.
|
||||
|
@ -388,12 +388,12 @@
|
||||
}
|
||||
function downloadWin64() {
|
||||
// TODO: Keep this link up-to-date with the desired release version
|
||||
window.open("https://makecode.com/api/release/ev3/v1.0.11/win64");
|
||||
window.open("https://makecode.com/api/release/ev3/v1.1.20/win64");
|
||||
tickEvent("offlineapp.download", { "target": "ev3", "platform": "win64" });
|
||||
}
|
||||
function downloadMac64() {
|
||||
// TODO: Keep this link up-to-date with the desired release version
|
||||
window.open("https://makecode.com/api/release/ev3/v1.0.11/mac64");
|
||||
window.open("https://makecode.com/api/release/ev3/v1.1.20/mac64");
|
||||
tickEvent("offlineapp.download", { "target": "ev3", "platform": "mac64" });
|
||||
}
|
||||
</script>
|
||||
|
@ -3,9 +3,3 @@
|
||||
## Offline app #target-app
|
||||
|
||||
The MakeCode editor is available as app which you can install on a computer with Windows or Mac OS. Once installed, the **[MakeCode Offline App](/offline-app)** lets you create, run, and download your projects to the @boardname@. It works the same as the Web application does in your browser but it's a stand-alone application that will work when a connection to the internet is restricted or not available.
|
||||
|
||||
### ~ hint
|
||||
|
||||
The [MakeCode Offline App](/offline-app) is currently in development and is made available as a **pre-release** version.
|
||||
|
||||
### ~
|
||||
|
BIN
docs/static/tutorials/pause-on-start.png
vendored
Normal file
BIN
docs/static/tutorials/pause-on-start.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
@ -27,6 +27,12 @@
|
||||
"cardType": "tutorial",
|
||||
"url":"/tutorials/music-brick",
|
||||
"imageUrl":"/static/tutorials/music-brick.png"
|
||||
}, {
|
||||
"name": "Pause On Start",
|
||||
"description": "Don't start running immediately!",
|
||||
"cardType": "tutorial",
|
||||
"url":"/tutorials/pause-on-start",
|
||||
"imageUrl":"/static/tutorials/pause-on-start.png"
|
||||
}]
|
||||
```
|
||||
|
||||
|
25
docs/tutorials/city-shaper.md
Normal file
25
docs/tutorials/city-shaper.md
Normal file
@ -0,0 +1,25 @@
|
||||
# City Shaper
|
||||
|
||||
## Tutorials
|
||||
|
||||
```codecard
|
||||
[
|
||||
{
|
||||
"name": "Crane Mission / Robot 1",
|
||||
"description": "Learn the basics and build your first robot driving base.",
|
||||
"cardType": "tutorial",
|
||||
"url":"/tutorials/city-shaper/robot-1"
|
||||
}, {
|
||||
"name": "Crane Mission / Robot 2",
|
||||
"description": "Program your robot to move in different ways.",
|
||||
"cardType": "tutorial",
|
||||
"url":"/tutorials/city-shaper/robot-2"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## See Also
|
||||
|
||||
[Robot 1](/tutorials/city-shaper/robot-1),
|
||||
[Robot 2](/tutorials/city-shaper/robot-2)
|
||||
|
@ -42,7 +42,7 @@
|
||||
}, {
|
||||
"name": "Turtle",
|
||||
"description": "Encode moves and run them on a driving base",
|
||||
"url":"/examples/turtle",
|
||||
"url":"/tutorials/turtle",
|
||||
"cardType": "example"
|
||||
}]
|
||||
```
|
||||
|
33
docs/tutorials/pause-on-start.md
Normal file
33
docs/tutorials/pause-on-start.md
Normal file
@ -0,0 +1,33 @@
|
||||
# Pause On Start
|
||||
|
||||
## Introduction @unplugged
|
||||
|
||||
Sometimes you don't want your program to run right away... you can use a button to wait before moving the motors.
|
||||
|
||||
## Step 1
|
||||
|
||||
Let's start by showing an image on the screen so the user knows that the robot is ready and waiting.
|
||||
|
||||
```blocks
|
||||
brick.showImage(images.informationStop1)
|
||||
```
|
||||
|
||||
## Step 2
|
||||
|
||||
Drag the ``||brick:pause until enter pressed||`` button to wait for the user to press the Enter button.
|
||||
|
||||
```blocks
|
||||
brick.showImage(images.informationStop1)
|
||||
brick.buttonEnter.pauseUntil(ButtonEvent.Pressed)
|
||||
```
|
||||
|
||||
## Step 3
|
||||
|
||||
Add all the motor and sensor code you want after those blocks!
|
||||
|
||||
```blocks
|
||||
brick.showImage(images.informationStop1)
|
||||
brick.buttonEnter.pauseUntil(ButtonEvent.Pressed)
|
||||
brick.showImage(images.expressionsBigSmile)
|
||||
motors.largeBC.tank(50, 50, 1, MoveUnit.Seconds)
|
||||
```
|
66
libs/broadcast/broadcast.ts
Normal file
66
libs/broadcast/broadcast.ts
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Message broadcasting
|
||||
*/
|
||||
//% weight=70
|
||||
//% color="#58AB41"
|
||||
namespace broadcast {
|
||||
const broadcastEventId = control.allocateNotifyEvent();
|
||||
const broadcastDoneEventId = control.allocateNotifyEvent();
|
||||
|
||||
function normalizeId(id: number) {
|
||||
// upper ids are reserved for answer
|
||||
return ((id + 1) | 0) & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* An enum shim
|
||||
*/
|
||||
//% shim=ENUM_GET
|
||||
//% blockId=msg_enum_shim
|
||||
//% block="$arg"
|
||||
//% enumName="Messages"
|
||||
//% enumMemberName="message"
|
||||
//% enumPromptHint="e.g. Move, Turn, ..."
|
||||
//% enumInitialMembers="message1"
|
||||
//% blockHidden=1
|
||||
//% enumIsHash=1
|
||||
export function __messageShim(arg: number) {
|
||||
// This function should do nothing, but must take in a single
|
||||
// argument of type number and return a number value.
|
||||
return arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register code to run when a message is received
|
||||
*/
|
||||
//% block="on %id=msg_enum_shim|received"
|
||||
//% blockId=broadcastonreceived draggableParameters
|
||||
export function onMessageReceived(message: number, body: () => void) {
|
||||
const messageid = normalizeId(message);
|
||||
control.onEvent(broadcastEventId, messageid, function () {
|
||||
body();
|
||||
control.raiseEvent(broadcastDoneEventId, messageid);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to activate code
|
||||
*/
|
||||
//% block="send %id=msg_enum_shim"
|
||||
//% blockId=broadcastsend draggableParameters
|
||||
export function sendMessage(message: number) {
|
||||
const messageid = normalizeId(message);
|
||||
control.raiseEvent(broadcastEventId, messageid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message and pauses until the handler to finishes.
|
||||
*/
|
||||
//% block="send %id=msg_enum_shim| and pause"
|
||||
//% blockId=broadcastsendpause
|
||||
export function sendMessageAndPause(message: number) {
|
||||
const messageid = normalizeId(message);
|
||||
control.raiseEvent(broadcastEventId, messageid);
|
||||
control.waitForEvent(broadcastDoneEventId, messageid);
|
||||
}
|
||||
}
|
11
libs/broadcast/pxt.json
Normal file
11
libs/broadcast/pxt.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "broadcast",
|
||||
"description": "Broadcasting messages - beta",
|
||||
"files": [
|
||||
"broadcast.ts"
|
||||
],
|
||||
"public": true,
|
||||
"dependencies": {
|
||||
"core": "file:../core"
|
||||
}
|
||||
}
|
@ -179,6 +179,7 @@ namespace sensors {
|
||||
//% group="Color Sensor"
|
||||
//% blockGap=8
|
||||
color(): ColorSensorColor {
|
||||
this.poke();
|
||||
this.setMode(ColorSensorMode.Color)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
@ -196,6 +197,7 @@ namespace sensors {
|
||||
//% group="Color Sensor"
|
||||
//% blockGap=8
|
||||
rgbRaw(): number[] {
|
||||
this.poke();
|
||||
this.setMode(ColorSensorMode.RgbRaw);
|
||||
return [this.getNumber(NumberFormat.UInt16LE, 0), this.getNumber(NumberFormat.UInt16LE, 2), this.getNumber(NumberFormat.UInt16LE, 4)];
|
||||
}
|
||||
@ -249,6 +251,7 @@ namespace sensors {
|
||||
//% weight=87 blockGap=8
|
||||
//% group="Color Sensor"
|
||||
light(mode: LightIntensityMode) {
|
||||
this.poke();
|
||||
this.setMode(<ColorSensorMode><number>mode)
|
||||
switch(mode) {
|
||||
case LightIntensityMode.ReflectedRaw:
|
||||
@ -279,6 +282,7 @@ namespace sensors {
|
||||
*/
|
||||
//%
|
||||
reflectedLightRaw(): number {
|
||||
this.poke();
|
||||
this.setMode(ColorSensorMode.RefRaw);
|
||||
return this.getNumber(NumberFormat.UInt16LE, 0);
|
||||
}
|
||||
|
@ -55,6 +55,10 @@ namespace brick {
|
||||
this._wasPressed = false
|
||||
}
|
||||
|
||||
protected poke() {
|
||||
|
||||
}
|
||||
|
||||
//% hidden
|
||||
_update(curr: boolean) {
|
||||
if (this == null) return
|
||||
@ -85,6 +89,7 @@ namespace brick {
|
||||
//% group="Buttons"
|
||||
//% button.fieldEditor="brickbuttons"
|
||||
isPressed() {
|
||||
this.poke();
|
||||
return this._isPressed
|
||||
}
|
||||
|
||||
@ -102,6 +107,7 @@ namespace brick {
|
||||
//% group="Buttons"
|
||||
//% button.fieldEditor="brickbuttons"
|
||||
wasPressed() {
|
||||
this.poke();
|
||||
const r = this._wasPressed
|
||||
this._wasPressed = false
|
||||
return r
|
||||
@ -144,6 +150,7 @@ namespace brick {
|
||||
namespace brick {
|
||||
let btnsMM: MMap
|
||||
let buttons: DevButton[]
|
||||
let buttonPoller: sensors.internal.Poller;
|
||||
|
||||
export namespace internal {
|
||||
export function getBtnsMM() {
|
||||
@ -167,7 +174,7 @@ namespace brick {
|
||||
btnsMM = control.mmap("/dev/lms_ui", DAL.NUM_BUTTONS, 0)
|
||||
if (!btnsMM) control.fail("no buttons?")
|
||||
buttons = []
|
||||
sensors.internal.unsafePollForChanges(50, readButtons, (prev, curr) => {
|
||||
buttonPoller = new sensors.internal.Poller(50, readButtons, (prev, curr) => {
|
||||
for (let b of buttons)
|
||||
b._update(!!(curr & b.mask))
|
||||
})
|
||||
@ -182,6 +189,10 @@ namespace brick {
|
||||
initBtns()
|
||||
buttons.push(this)
|
||||
}
|
||||
|
||||
protected poke() {
|
||||
buttonPoller.poke();
|
||||
}
|
||||
}
|
||||
|
||||
initBtns() // always ON as it handles ESCAPE button
|
||||
|
@ -1,28 +1,51 @@
|
||||
namespace sensors.internal {
|
||||
//% shim=pxt::unsafePollForChanges
|
||||
export function unsafePollForChanges(
|
||||
periodMs: number,
|
||||
query: () => number,
|
||||
changeHandler: (prev: number, curr: number) => void
|
||||
) {
|
||||
// This is implemented in C++ without blocking the regular JS when query() is runnning
|
||||
// which is generally unsafe. Query should not update globally visible state, and cannot
|
||||
// call any yielding functions, like sleep().
|
||||
export class Poller {
|
||||
private query: () => number;
|
||||
private update: (previous: number, current: number) => void;
|
||||
public interval: number;
|
||||
|
||||
// This is implementation for the simulator.
|
||||
private previousValue: number;
|
||||
private currentValue: number;
|
||||
private lastQuery: number; // track down the last time we did a query/update cycle
|
||||
private lastPause: number; // track down the last time we pause in the sensor polling loop
|
||||
|
||||
control.runInParallel(() => {
|
||||
let prev = query()
|
||||
changeHandler(prev, prev)
|
||||
while (true) {
|
||||
pause(periodMs)
|
||||
let curr = query()
|
||||
if (prev !== curr) {
|
||||
changeHandler(prev, curr)
|
||||
prev = curr
|
||||
}
|
||||
constructor(interval: number, query: () => number, update: (previous: number, current: number) => void) {
|
||||
this.interval = interval | 0;
|
||||
this.query = query;
|
||||
this.update = update;
|
||||
|
||||
this.poll();
|
||||
}
|
||||
|
||||
poke(): void {
|
||||
const now = control.millis();
|
||||
if (now - this.lastQuery >= this.interval * 2)
|
||||
this.queryAndUpdate(); // sensor poller is not allowed to run
|
||||
if (now - this.lastPause >= this.interval * 5)
|
||||
pause(1); // allow events to trigger
|
||||
}
|
||||
|
||||
private queryAndUpdate() {
|
||||
this.lastQuery = control.millis();
|
||||
this.currentValue = this.query();
|
||||
if (this.previousValue != this.currentValue) {
|
||||
this.update(this.previousValue, this.currentValue);
|
||||
this.previousValue = this.currentValue;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private poll() {
|
||||
control.runInBackground(() => {
|
||||
this.lastQuery = this.lastPause = control.millis();
|
||||
this.previousValue = this.currentValue = this.query();
|
||||
this.update(this.previousValue, this.currentValue);
|
||||
while (true) {
|
||||
this.lastPause = control.millis();
|
||||
pause(this.interval);
|
||||
this.queryAndUpdate();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function bufferToString(buf: Buffer): string {
|
||||
@ -38,6 +61,7 @@ namespace sensors.internal {
|
||||
let IICMM: MMap
|
||||
let powerMM: MMap
|
||||
let devcon: Buffer
|
||||
let devPoller: Poller
|
||||
let sensorInfos: SensorInfo[];
|
||||
|
||||
let batteryInfo: {
|
||||
@ -55,6 +79,7 @@ namespace sensors.internal {
|
||||
connType: number
|
||||
devType: number
|
||||
iicid: string
|
||||
poller: Poller;
|
||||
|
||||
constructor(p: number) {
|
||||
this.port = p
|
||||
@ -62,6 +87,20 @@ namespace sensors.internal {
|
||||
this.devType = DAL.DEVICE_TYPE_NONE
|
||||
this.iicid = ''
|
||||
this.sensors = []
|
||||
this.poller = new Poller(50, () => this.query(), (prev, curr) => this.update(prev, curr));
|
||||
}
|
||||
|
||||
poke() {
|
||||
this.poller.poke();
|
||||
}
|
||||
|
||||
private query() {
|
||||
if (this.sensor) return this.sensor._query();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private update(prev: number, curr: number) {
|
||||
if (this.sensor) this.sensor._update(prev, curr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,20 +121,11 @@ namespace sensors.internal {
|
||||
|
||||
powerMM = control.mmap("/dev/lms_power", 2, 0)
|
||||
|
||||
unsafePollForChanges(500,
|
||||
() => { return hashDevices(); },
|
||||
devPoller = new Poller(500, () => { return hashDevices(); },
|
||||
(prev, curr) => {
|
||||
detectDevices();
|
||||
});
|
||||
sensorInfos.forEach(info => {
|
||||
unsafePollForChanges(50, () => {
|
||||
if (info.sensor) return info.sensor._query()
|
||||
return 0
|
||||
}, (prev, curr) => {
|
||||
if (info.sensor) info.sensor._update(prev, curr)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function getActiveSensors(): Sensor[] {
|
||||
init();
|
||||
@ -164,13 +194,13 @@ namespace sensors.internal {
|
||||
batteryVMax = ACCU_INDICATOR_HIGH;
|
||||
}
|
||||
}
|
||||
batteryInfo = {
|
||||
CinCnt: CinCnt,
|
||||
batteryInfo = {
|
||||
CinCnt: CinCnt,
|
||||
CoutCnt: CoutCnt,
|
||||
VinCnt: VinCnt
|
||||
};
|
||||
// update in background
|
||||
control.runInParallel(() => forever(updateBatteryInfo));
|
||||
control.runInParallel(() => forever(updateBatteryInfo));
|
||||
} else {
|
||||
CinCnt = batteryInfo.CinCnt = ((batteryInfo.CinCnt * (AVR_CIN - 1)) + CinCnt) / AVR_CIN;
|
||||
CoutCnt = batteryInfo.CoutCnt = ((batteryInfo.CoutCnt * (AVR_COUT - 1)) + CoutCnt) / AVR_COUT;
|
||||
@ -178,11 +208,11 @@ namespace sensors.internal {
|
||||
}
|
||||
}
|
||||
|
||||
export function getBatteryInfo(): {
|
||||
level: number;
|
||||
Ibatt: number,
|
||||
Vbatt: number,
|
||||
Imotor: number
|
||||
export function getBatteryInfo(): {
|
||||
level: number;
|
||||
Ibatt: number,
|
||||
Vbatt: number,
|
||||
Imotor: number
|
||||
} {
|
||||
init();
|
||||
if (!batteryInfo) updateBatteryInfo();
|
||||
@ -225,13 +255,13 @@ void cUiUpdatePower(void)
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
const CinV = CNT_V(CinCnt) / AMP_CIN;
|
||||
const Vbatt = CNT_V(VinCnt) / AMP_VIN + CinV + VCE;
|
||||
const Ibatt = CinV / SHUNT_IN;
|
||||
const CoutV = CNT_V(CoutCnt) / AMP_COUT;
|
||||
const Imotor = CoutV / SHUNT_OUT;
|
||||
const level = Math.max(0, Math.min(100, Math.floor((Vbatt * 1000.0 - batteryVMin)
|
||||
/ (batteryVMax - batteryVMin) * 100)));
|
||||
const CinV = CNT_V(CinCnt) / AMP_CIN;
|
||||
const Vbatt = CNT_V(VinCnt) / AMP_VIN + CinV + VCE;
|
||||
const Ibatt = CinV / SHUNT_IN;
|
||||
const CoutV = CNT_V(CoutCnt) / AMP_COUT;
|
||||
const Imotor = CoutV / SHUNT_OUT;
|
||||
const level = Math.max(0, Math.min(100, Math.floor((Vbatt * 1000.0 - batteryVMin)
|
||||
/ (batteryVMax - batteryVMin) * 100)));
|
||||
|
||||
return {
|
||||
level: level,
|
||||
@ -337,6 +367,11 @@ void cUiUpdatePower(void)
|
||||
this.markUsed();
|
||||
}
|
||||
|
||||
poke() {
|
||||
if (this.isActive())
|
||||
sensorInfos[this._port].poke();
|
||||
}
|
||||
|
||||
markUsed() {
|
||||
sensors.__sensorUsed(this._port, this._deviceType());
|
||||
}
|
||||
|
@ -446,11 +446,6 @@ static void runPoller(Thread *thr) {
|
||||
// disposeThread(thr);
|
||||
}
|
||||
|
||||
//%
|
||||
void unsafePollForChanges(int ms, Action query, Action handler) {
|
||||
setupThread(handler, 0, runPoller, query, fromInt(ms));
|
||||
}
|
||||
|
||||
uint32_t afterProgramPage() {
|
||||
return 0;
|
||||
}
|
||||
|
@ -123,7 +123,8 @@ namespace motors {
|
||||
//% help=motors/stop-all
|
||||
export function stopAll() {
|
||||
const b = mkCmd(Output.ALL, DAL.opOutputStop, 0)
|
||||
writePWM(b)
|
||||
writePWM(b);
|
||||
pause(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,6 +133,7 @@ namespace motors {
|
||||
//% group="Move"
|
||||
export function resetAllMotors() {
|
||||
reset(Output.ALL)
|
||||
pause(1);
|
||||
}
|
||||
|
||||
interface MoveSchedule {
|
||||
@ -259,6 +261,8 @@ namespace motors {
|
||||
// allow 500ms for robot to settle
|
||||
if (this._brake && this._brakeSettleTime > 0)
|
||||
pause(this._brakeSettleTime);
|
||||
else
|
||||
pause(1); // give a tiny breather
|
||||
}
|
||||
|
||||
protected pauseOnRun(stepsOrTime: number) {
|
||||
@ -267,6 +271,9 @@ namespace motors {
|
||||
this.pauseUntilReady();
|
||||
// allow robot to settle
|
||||
this.settle();
|
||||
} else {
|
||||
// give a breather to the event system in tight loops
|
||||
pause(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,6 +341,7 @@ namespace motors {
|
||||
// special: 0 is infinity
|
||||
if (schedule.steps[0] + schedule.steps[1] + schedule.steps[2] == 0) {
|
||||
this._run(schedule.speed);
|
||||
pause(1);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -494,7 +502,7 @@ namespace motors {
|
||||
*/
|
||||
//% blockId=motorPauseUntilRead block="pause until %motor|ready"
|
||||
//% motor.fieldEditor="motors"
|
||||
//% weight=90
|
||||
//% weight=90 blockGap=8
|
||||
//% group="Move"
|
||||
pauseUntilReady(timeOut?: number) {
|
||||
pauseUntil(() => this.isReady(), timeOut);
|
||||
@ -602,6 +610,33 @@ namespace motors {
|
||||
toString(): string {
|
||||
return `${this._large ? "" : "M"}${this._portName} ${this.speed()}% ${this.angle()}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the program until the motor is stalled.
|
||||
*/
|
||||
//% blockId=motorPauseUntilStall block="pause until %motor|stalled"
|
||||
//% motor.fieldEditor="motors"
|
||||
//% weight=89
|
||||
//% group="Move"
|
||||
//% help=motors/motor/pause-until-stalled
|
||||
pauseUntilStalled(timeOut?: number): void {
|
||||
// let it start
|
||||
pause(50);
|
||||
let previous = this.angle();
|
||||
let stall = 0;
|
||||
pauseUntil(() => {
|
||||
let current = this.angle();
|
||||
if (Math.abs(current - previous) < 1) {
|
||||
if (stall++ > 2) {
|
||||
return true; // not moving
|
||||
}
|
||||
} else {
|
||||
stall = 0;
|
||||
previous = current;
|
||||
}
|
||||
return false;
|
||||
}, timeOut)
|
||||
}
|
||||
}
|
||||
|
||||
//% whenUsed fixedInstance block="large motor A" jres=icons.portA
|
||||
@ -697,7 +732,7 @@ namespace motors {
|
||||
this.init();
|
||||
speed = Math.clamp(-100, 100, speed >> 0);
|
||||
if (!speed) {
|
||||
stop(this._port, this._brake);
|
||||
this.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ namespace sensors {
|
||||
//% weight=64 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
angle(): number {
|
||||
this.poke();
|
||||
if (this.calibrating)
|
||||
pauseUntil(() => !this.calibrating, 2000);
|
||||
|
||||
@ -65,6 +66,7 @@ namespace sensors {
|
||||
//% weight=65 blockGap=8
|
||||
//% group="Gyro Sensor"
|
||||
rate(): number {
|
||||
this.poke();
|
||||
if (this.calibrating)
|
||||
pauseUntil(() => !this.calibrating, 2000);
|
||||
|
||||
|
@ -235,6 +235,7 @@ namespace sensors {
|
||||
//% group="Infrared Sensor"
|
||||
//% this.fieldEditor="ports"
|
||||
proximity(): number {
|
||||
this.poke();
|
||||
this._setMode(InfraredSensorMode.Proximity)
|
||||
return this.getNumber(NumberFormat.UInt8LE, 0)
|
||||
}
|
||||
@ -284,6 +285,7 @@ namespace sensors {
|
||||
|
||||
// TODO
|
||||
private getDirectionAndDistance() {
|
||||
this.poke();
|
||||
this._setMode(InfraredSensorMode.Seek)
|
||||
return this.getNumber(NumberFormat.UInt16LE, this._channel * 2)
|
||||
}
|
||||
|
@ -73,6 +73,7 @@ namespace sensors {
|
||||
//% weight=81 blockGap=8
|
||||
//% group="Touch Sensor"
|
||||
isPressed() {
|
||||
this.poke();
|
||||
return this.button.isPressed();
|
||||
}
|
||||
|
||||
@ -90,6 +91,7 @@ namespace sensors {
|
||||
//% weight=81
|
||||
//% group="Touch Sensor"
|
||||
wasPressed() {
|
||||
this.poke();
|
||||
return this.button.wasPressed();
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +84,7 @@ namespace sensors {
|
||||
//% weight=65
|
||||
//% group="Ultrasonic Sensor"
|
||||
distance(): number {
|
||||
this.poke();
|
||||
// it supposedly also has an inch mode, but we stick to cm
|
||||
this._setMode(0)
|
||||
return this._query();
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pxt-ev3",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.7",
|
||||
"description": "LEGO MINDSTORMS EV3 for Microsoft MakeCode",
|
||||
"private": false,
|
||||
"keywords": [
|
||||
@ -40,7 +40,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"pxt-common-packages": "0.23.61",
|
||||
"pxt-core": "4.0.9"
|
||||
"pxt-core": "4.0.10"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node node_modules/pxt-core/built/pxt.js travis"
|
||||
|
@ -17,7 +17,8 @@
|
||||
"libs/gyro-sensor",
|
||||
"libs/screen",
|
||||
"libs/ev3",
|
||||
"libs/storage"
|
||||
"libs/storage",
|
||||
"libs/broadcast"
|
||||
],
|
||||
"simulator": {
|
||||
"autoRun": true,
|
||||
|
@ -15,13 +15,13 @@
|
||||
"Color Sensor Tutorials": "tutorials/color-sensor",
|
||||
"Ultrasonic Sensor Tutorials": "tutorials/ultrasonic-sensor",
|
||||
"Infrared Sensor Tutorials": "tutorials/infrared-sensor",
|
||||
"FLL / City Shaper / Crane Mission": "tutorials/city-shaper/crane-mission",
|
||||
"FLL / City Shaper": "tutorials/city-shaper",
|
||||
"Design Engineering": "design-engineering",
|
||||
"Coding": "coding",
|
||||
"Maker": "maker",
|
||||
"Videos": "videos"
|
||||
},
|
||||
"electronManifest": {
|
||||
"latest": "v1.0.11"
|
||||
"latest": "v1.1.20"
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user