Skip to content

Commit f369e1e

Browse files
Track duration of an ML action until it changes to a different one. (#10)
- Add on action stop block with duration for callback - Update tsconfig to ignore example datasets - Rename test.ts to main.ts & add empty main.blocks so that we import the GH repo to MakeCode and it loads by default the test code into the project as the main entry point. --------- Co-authored-by: Robert Knight <[email protected]>
1 parent 7411542 commit f369e1e

File tree

7 files changed

+77
-40
lines changed

7 files changed

+77
-40
lines changed

autogenerated.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,19 @@ namespace mlrunner {
99
//% fixedInstance
1010
export const Circle = new MlEvent(4, "Circle");
1111

12-
actions = [None,Shake,Still,Circle];
12+
actions = [None, Shake, Still, Circle];
1313

1414
control.onEvent(MlRunnerIds.MlRunnerInference, 1, () => {
15-
prevAction = 1;
15+
maybeUpdateActionStats(None);
1616
});
1717
control.onEvent(MlRunnerIds.MlRunnerInference, 2, () => {
18-
prevAction = 2;
18+
maybeUpdateActionStats(Shake);
1919
});
2020
control.onEvent(MlRunnerIds.MlRunnerInference, 3, () => {
21-
prevAction = 3;
21+
maybeUpdateActionStats(Still);
2222
});
2323
control.onEvent(MlRunnerIds.MlRunnerInference, 4, () => {
24-
prevAction = 4;
24+
maybeUpdateActionStats(Circle);
2525
});
2626
}
2727
}

main.blocks

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<xml xmlns="https://developers.google.com/blockly/xml"></xml>

test.ts renamed to main.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
let timeStill = 0
12
input.onButtonPressed(Button.A, function () {
23
basic.clearScreen()
4+
serial.writeLine("Total time still: " + timeStill + "\n")
35
})
46
input.onButtonPressed(Button.B, function () {
57
if (mlrunner.isRunning()) {
@@ -14,12 +16,15 @@ mlrunner.Action.Shake.onEvent(function () {
1416
mlrunner.Action.Still.onEvent(function () {
1517
basic.showIcon(IconNames.Asleep)
1618
})
17-
mlrunner.Action.Circle.onEvent( function () {
19+
mlrunner.Action.Circle.onEvent(function () {
1820
basic.showString("C")
1921
})
2022
mlrunner.Action.None.onEvent(function () {
2123
basic.clearScreen()
2224
})
25+
mlrunner.Action.Still.onStop(function (duration) {
26+
timeStill += duration
27+
})
2328
basic.forever(function () {
2429
serial.writeLine("Is Shake: " + mlrunner.Action.Shake.isEvent() + "\n")
2530
basic.pause(10000)

pxt.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
],
1616
"testFiles": [
1717
"autogenerated.ts",
18-
"test.ts"
18+
"main.ts",
19+
"main.blocks"
1920
],
2021
"targetVersions": {
2122
"branch": "v6.0.26",
@@ -28,7 +29,7 @@
2829
"supportedTargets": [
2930
"microbit"
3031
],
31-
"preferredEditor": "blocksprj",
32+
"preferredEditor": "tsprj",
3233
"yotta": {
3334
"config": {
3435
"ML_INFERENCE_PERIOD_MS": 250,

pxtextension.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ namespace mlrunner {
294294
mlDataProcessor.deinit();
295295
free(actions);
296296
free(predictions);
297+
actions = NULL;
298+
predictions = NULL;
297299
mlSampleCountsPerInference = 0;
298300
lastPredictionEventId = -1;
299301

pxtextension.ts

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ function mlRunnerCustomOnEvent(
1616
class MlEvent {
1717
eventValue: number;
1818
eventLabel: string;
19-
hasOnEventHandler: boolean;
19+
lastDuration: number;
20+
onStopHandler: (duration: number) => void;
2021

2122
constructor(value: number, label: string) {
2223
this.eventValue = value;
2324
this.eventLabel = label;
24-
this.hasOnEventHandler = false;
25+
this.lastDuration = 0;
2526
}
2627

2728
/**
@@ -35,13 +36,21 @@ class MlEvent {
3536
* @param body The code to run when the model predicts the label.
3637
*/
3738
//% blockId=mlrunner_on_ml_event
38-
//% block="on ML event $this"
39+
//% block="on $this start"
3940
onEvent(body: () => void): void {
40-
this.hasOnEventHandler = true;
4141
const wrappedBody = () => {
42-
if (mlrunner.Action.prevAction !== this.eventValue) {
42+
if (
43+
mlrunner.Action.prevActionInstance !== this ||
44+
mlrunner.deviceIsSim()
45+
) {
4346
body();
4447
}
48+
if (
49+
mlrunner.Action.prevActionInstance !== this &&
50+
mlrunner.deviceIsSim()
51+
) {
52+
mlrunner.Action.maybeUpdateActionStats(this);
53+
}
4554
};
4655
if (!mlrunner.isRunning()) {
4756
mlrunner.startRunning();
@@ -54,14 +63,21 @@ class MlEvent {
5463
}
5564

5665
//% blockId=mlrunner_is_ml_event
57-
//% block="is %this action"
66+
//% block="is $this action"
5867
isEvent(): boolean {
5968
if (!mlrunner.isRunning()) {
6069
mlrunner.startRunning();
6170
return false;
6271
}
6372
return this.eventValue == mlrunner.currentActionId();
6473
}
74+
75+
//% blockId=mlrunner_on_ml_event_stop
76+
//% block="on $this stop $duration"
77+
//% draggableParameters="reporter"
78+
onStop(body: (duration: number) => void): void {
79+
this.onStopHandler = body;
80+
}
6581
}
6682

6783
//% color=#2b64c3 weight=100 icon="\uf108" block="ML Runner" advanced=false
@@ -70,12 +86,31 @@ namespace mlrunner {
7086
//% fixedInstance
7187
export const None = new MlEvent(1, "None");
7288
export let actions = [None];
73-
export let prevAction: number = 0;
74-
export let currentAction: number = 1;
89+
export let prevActionInstance: MlEvent = None;
90+
export let currentAction: MlEvent = None;
91+
export let lastActionTimestamp: number = 0;
92+
93+
export function maybeUpdateActionStats(currentAction: MlEvent) {
94+
if (currentAction !== prevActionInstance) {
95+
let now = input.runningTime();
96+
prevActionInstance.lastDuration = now - lastActionTimestamp;
97+
98+
if (prevActionInstance.onStopHandler) {
99+
prevActionInstance.onStopHandler(prevActionInstance.lastDuration);
100+
}
101+
102+
lastActionTimestamp = now;
103+
prevActionInstance = currentAction;
104+
}
105+
}
75106
}
76107

77108
let simIsRunning = false;
78109

110+
export function deviceIsSim() {
111+
return control.deviceName().slice(0, 3) === "sim";
112+
}
113+
79114
/**
80115
* TS shim for C++ function init(), which initialize the ML model with
81116
* an address to a model blob.
@@ -127,7 +162,7 @@ namespace mlrunner {
127162

128163
//% shim=mlrunner::currentEventId
129164
export function currentActionId(): number {
130-
return Action.currentAction;
165+
return Action.currentAction.eventValue;
131166
}
132167

133168
// Start simulator code.
@@ -174,21 +209,13 @@ namespace mlrunner {
174209
}
175210

176211
function simulateAction(eventValue: number) {
177-
// Set prevAction to 0 so that re-triggering the same action in the
178-
// sim still runs the code in the action event handler.
179-
Action.prevAction = 0;
180-
Action.currentAction = eventValue;
181212
const simulatedAction = Action.actions.find(
182213
(action) => action.eventValue === eventValue
183214
);
184-
if (simulatedAction.hasOnEventHandler) {
185-
control.raiseEvent(MlRunnerIds.MlRunnerInference, eventValue);
186-
} else {
187-
Action.prevAction = simulatedAction.eventValue;
188-
}
189-
basic.pause(500);
190-
Action.prevAction = 0;
191-
Action.currentAction = 1;
215+
Action.currentAction = simulatedAction;
216+
// This will run the MLEvent onEvent block if it exists in the user's code.
217+
// Otherwise, control.onEvent in autogenerated.ts is fired.
218+
control.raiseEvent(MlRunnerIds.MlRunnerInference, eventValue);
192219
}
193220

194221
function handleMessage(buffer: Buffer) {

tsconfig.json

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
{
2-
"compilerOptions": {
3-
"target": "ES5",
4-
"noImplicitAny": true,
5-
"outDir": "built",
6-
"rootDir": "."
7-
},
8-
"exclude": [
9-
"pxt_modules/**/*test.ts",
10-
"pxt_modules/**/autogenerated.ts",
11-
"pxt_modules/**/testextension.ts"
12-
]
2+
"compilerOptions": {
3+
"target": "ES5",
4+
"noImplicitAny": true,
5+
"outDir": "built",
6+
"rootDir": "."
7+
},
8+
"exclude": [
9+
"pxt_modules/**/*test.ts",
10+
"pxt_modules/**/autogenerated.ts",
11+
"pxt_modules/**/testextension.ts",
12+
"example-datasets/"
13+
]
1314
}

0 commit comments

Comments
 (0)