tpmkms_4wp 9.5.1-beta.9 → 9.6.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/common/animals.instance.json +130 -0
  2. package/common/animals.js +3 -5
  3. package/common/asking.js +12 -4
  4. package/common/avatar.test.json +1001 -860
  5. package/common/can.instance.json +2182 -5
  6. package/common/can.js +102 -39
  7. package/common/can.test.json +51307 -0
  8. package/common/colors.instance.json +142 -30
  9. package/common/colors.js +3 -6
  10. package/common/comparable.instance.json +31 -1
  11. package/common/comparable.js +3 -6
  12. package/common/concept.js +25 -27
  13. package/common/concept.test.json +142 -120
  14. package/common/conjunction.test.json +32 -42
  15. package/common/crew.instance.json +400 -126
  16. package/common/crew.js +3 -6
  17. package/common/dateTimeSelectors.instance.json +2 -2
  18. package/common/dateTimeSelectors.js +6 -9
  19. package/common/dateTimeSelectors.test.json +76935 -35739
  20. package/common/dates.instance.json +50 -84
  21. package/common/dates.js +3 -6
  22. package/common/dates.test.json +284 -287
  23. package/common/dialogues.js +33 -115
  24. package/common/dialogues.test.json +1248 -1152
  25. package/common/dimension.instance.json +21498 -566
  26. package/common/dimension.js +147 -52
  27. package/common/dimension.test.json +10979 -4625
  28. package/common/drone.instance.json +24709 -0
  29. package/common/drone.js +662 -0
  30. package/common/drone.test.json +30522 -0
  31. package/common/drone_v1.instance.json +24703 -0
  32. package/common/drone_v1.js +596 -0
  33. package/common/drone_v1.test.json +115538 -0
  34. package/common/edible.instance.json +365 -65
  35. package/common/edible.js +3 -5
  36. package/common/emotions.instance.json +57 -70
  37. package/common/emotions.js +3 -6
  38. package/common/errors.js +3 -3
  39. package/common/fastfood.instance.json +1270 -244
  40. package/common/fastfood.js +10 -12
  41. package/common/fastfood.test.json +6970 -6829
  42. package/common/formulas.instance.json +10 -0
  43. package/common/formulas.js +2 -1
  44. package/common/gdefaults.js +58 -13
  45. package/common/help.js +9 -9
  46. package/common/help.test.json +65 -11
  47. package/common/helpers/dialogues.js +9 -1
  48. package/common/helpers/properties.js +37 -18
  49. package/common/helpers.js +32 -2
  50. package/common/hierarchy.js +10 -8
  51. package/common/kirk.instance.json +10 -0
  52. package/common/kirk.js +4 -6
  53. package/common/kirk.test.json +600 -424
  54. package/common/latin.instance.json +10 -10
  55. package/common/latin.js +8 -10
  56. package/common/length.instance.json +34659 -3157
  57. package/common/length.js +11 -6
  58. package/common/length.test.json +54357 -2557
  59. package/common/math.instance.json +11 -1
  60. package/common/math.js +2 -1
  61. package/common/menus.instance.json +74 -7
  62. package/common/menus.js +3 -12
  63. package/common/meta.js +4 -5
  64. package/common/nameable.js +29 -15
  65. package/common/nameable.test.json +436 -0
  66. package/common/numbers.js +1 -1
  67. package/common/ordering.instance.json +24 -2
  68. package/common/ordering.js +3 -5
  69. package/common/ordering.test.json +104 -174
  70. package/common/people.instance.json +140 -315
  71. package/common/people.js +3 -5
  72. package/common/pipboy.instance.json +171 -57
  73. package/common/pipboy.js +2 -1
  74. package/common/pokemon.instance.json +135 -5
  75. package/common/pokemon.js +3 -5
  76. package/common/pressure.instance.json +3990 -1981
  77. package/common/pressure.js +3 -5
  78. package/common/pressure.test.json +433 -477
  79. package/common/properties.instance.json +15 -16
  80. package/common/properties.js +10 -9
  81. package/common/properties.test.json +9565 -6951
  82. package/common/rates.instance.json +59 -0
  83. package/common/rates.js +95 -0
  84. package/common/rates.test.json +27702 -0
  85. package/common/reminders.js +5 -8
  86. package/common/reminders.test.json +64635 -25787
  87. package/common/reports.instance.json +22 -2
  88. package/common/reports.js +3 -5
  89. package/common/scorekeeper.js +3 -6
  90. package/common/spock.instance.json +10 -0
  91. package/common/spock.js +4 -7
  92. package/common/spock.test.json +606 -430
  93. package/common/stm.js +37 -20
  94. package/common/temperature.instance.json +3162 -1153
  95. package/common/temperature.js +3 -5
  96. package/common/temperature.test.json +433 -477
  97. package/common/time.instance.json +24852 -0
  98. package/common/time.js +136 -139
  99. package/common/time.test.json +31876 -3757
  100. package/common/ui.instance.json +12 -5
  101. package/common/ui.js +4 -13
  102. package/common/weight.instance.json +10500 -4098
  103. package/common/weight.js +3 -5
  104. package/common/weight.test.json +2601 -2263
  105. package/common/words.instance.json +9 -0
  106. package/common/words.js +50 -0
  107. package/common/words.test.json +2 -0
  108. package/common/wp.instance.json +470 -58
  109. package/common/wp.js +6 -4
  110. package/common/wp.test.json +7385 -6906
  111. package/main.js +6 -2
  112. package/package.json +21 -6
  113. package/common/listener.js +0 -50
  114. package/common/listener.test.json +0 -142
@@ -0,0 +1,662 @@
1
+ const { knowledgeModule, where } = require('./runtime').theprogrammablemind
2
+ const { defaultContextCheck, getValue, setValue } = require('./helpers')
3
+ const drone_tests = require('./drone.test.json')
4
+ const instance = require('./drone.instance.json')
5
+ const hierarchy = require('./hierarchy')
6
+ const ordinals = require('./ordinals')
7
+ const nameable = require('./nameable')
8
+ const rates = require('./rates')
9
+ const help = require('./help')
10
+ const { degreesToRadians, radiansToDegrees, cartesianToPolar } = require('./helpers/drone')
11
+
12
+ /*
13
+ todo
14
+
15
+ VOSK
16
+
17
+ https://alphacephei.com/vosk/
18
+
19
+ FreeNode Tank
20
+
21
+ https://docs.freenove.com/projects/fnk0077/en/latest/fnk0077/codes/tutorial/3_Module_test_%28necessary%29.html
22
+ https://www.amazon.ca/Freenove-Raspberry-Tracking-Avoidance-Ultrasonic/dp/B0BNDQFRP1/ref=sr_1_1_sspa?crid=1JT788RT84O8C&dib=eyJ2IjoiMSJ9.1W6XTWnHwPcqZTD8iRfmF7hHwiVycHjB02NHKEcqGfQSUKyJfN0OLyaaoCcypQug_C9CGah-7wLgfAtJRs_JKiwDsqYXqFfvvoU5ETBk_Le-S9Qt4kwh92r0w19bzA5my7aQpT52ssw8-f8Xpzjbqm1uFsLh82jF4V7P8xMKobjVHHILXalReEPuJz2OlF6y_ihwtUuVLDjMkuvNPoK-M7YLntLqKQy229XKjtDSUV4J0YT1L8uLVWHZ-ySs_MmG_w-oyZ9QFIe0a9hJEMuiu_BcaDmxFkwMeGBro2uczAU.NlqF_FH_6PvflZKozPylFlIyKuwx7mAB-jAggC1aPFk&dib_tag=se&keywords=Freenove+Tank+Robot+Kit&qid=1766258114&sprefix=freenove+drone+robot+kit%2Caps%2C130&sr=8-1-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&psc=1
23
+
24
+
25
+ send commands to arduino from another computer:
26
+
27
+ https://www.npmjs.com/package/johnny-five
28
+
29
+ KEYESTUDIO Mini Tank Robot V2 Smart Car Kit for Arduino
30
+
31
+ https://www.amazon.ca/KEYESTUDIO-Infrared-Ultrasonic-Obstacle-Avoidance/dp/B07X4W7SZ5/ref=sr_1_10?crid=2A71NHZNTAION&dib=eyJ2IjoiMSJ9.W-I4I_tfyGdGt2UrNlNrlFeKnfIwppniNSX5FJndx77Ht944f9RylJD9me0PiqV5V_b185b17BsrPdKxmYYHnJ-Odb7hbdVzKs019mag1nCL-Wqe4aR0IYrEOzJkKTnR4YbXGYwriLd26OBYjhNvgaCFyE5uwsYkAK-qJXI2Xiui19oLiLYrmJvBz0bCHe4s7U6OdmaumYhhfxpVErk1E1zAwxE8kdq_YD7ZCMRjKS9Tr6cbayIh9GKDwMLuW-LCdzOW2eQx-dTB7yXV53rpV34IBAcCE1IgmwwNIIW7E6Y.fdaAuj4qvXq-67f5ktOq7Coo8lggrMiB_TFFtluqDtI&dib_tag=se&keywords=Adafruit+Mini+Round+Robot+Chassis+Kit&qid=1766256581&sprefix=adafruit+mini+round+robot+chassis+kit+%2Caps%2C123&sr=8-10
32
+ https://github.com/ericmend/mini-drone/blob/master/README.md
33
+
34
+
35
+
36
+
37
+ vosk
38
+
39
+ https://github.com/sunfounder/picar-x/tree/v2.0/gpt_examples
40
+ https://github.com/sunfounder/picar-x/tree/v2.0/example
41
+ VOSK: https://docs.sunfounder.com/projects/picar-x-v20/en/latest/ai_interaction/python_voice_control.html
42
+
43
+ DONE why is 3 meters not marker: length its marker dimension
44
+ DONE how to handle time in the testing
45
+ repeat that/what/say again/say that again
46
+ make it say the howToCalibrate right from the start. maybe have some prime it call?!?!?!
47
+ convert from length to a some kind of standard number
48
+ shut up/dont talk/be quiet -> stop saying responses
49
+
50
+ use it to measure distances -> go forward. stop. how far was that
51
+
52
+ call this point a
53
+ move 5 feet
54
+ call this point b
55
+ moving between a and b is called patrol 1
56
+ do patrol 1 every 3 minutes
57
+
58
+ what is patrol 1
59
+
60
+ calibrate distance
61
+ stop
62
+
63
+ go forward slowly
64
+ stop
65
+ that was 2 feet
66
+
67
+ do a circle 2 feet in diameter every 2 minutes
68
+
69
+ this is jeff
70
+ say hi
71
+
72
+
73
+ say your names
74
+ car 1 do patrol one
75
+ car 1 and 2 go to point a
76
+
77
+ who car 1
78
+
79
+ just say the speed
80
+
81
+ go forward 2 meters
82
+
83
+ pan camera left slowly
84
+ do the cylon every 30 seconds
85
+
86
+ patrol one is forward 10 feet left 2 feet right 3 feet and back to the start
87
+ go forward 10 feet then go back to the start
88
+
89
+ go to the last point
90
+ go back 2 positions
91
+
92
+ call the first point start
93
+ call the second point fred
94
+ call the last point june
95
+ call the next point albert
96
+
97
+ pause for 4 seconds
98
+
99
+ this way is north
100
+ turn west
101
+ go three meters
102
+ turn south
103
+ go 1 foot
104
+
105
+ forward for 4 seconds
106
+
107
+ you are facing north. patrol between here and 100 feet to the west
108
+ */
109
+
110
+ function expectDirection(args) {
111
+ args.config.addSemantic({
112
+ match: ({context, isA}) => isA(context.marker, 'direction'),
113
+ apply: ({objects, context}) => {
114
+ objects.runCommand = true
115
+ objects.current.direction = context.marker
116
+ }
117
+ })
118
+ }
119
+
120
+ function expectDistanceForMove(args) {
121
+ // TODO save id for recalibration
122
+ args.config.addSemantic({
123
+ match: ({context, isA}) => isA(context.marker, 'quantity') && !isA(context.unit.marker, 'unitPerUnit'),
124
+ apply: async ({context, objects, fragments, e}) => {
125
+ const instantiation = await fragments("quantity in meters", { quantity: context })
126
+ const result = await e(instantiation)
127
+ objects.runCommand = true
128
+ objects.current.distance = result.evalue.amount.evalue.evalue
129
+ }
130
+ })
131
+ }
132
+
133
+ /*
134
+ ^
135
+ y
136
+ |
137
+ 90
138
+ |
139
+ -180/180 <--^--> 0 -- x ->
140
+ |
141
+ -90
142
+ */
143
+
144
+ class OverrideCheck {
145
+ constructor(base, checks) {
146
+ this.base = base
147
+ this.checks = checks
148
+ }
149
+
150
+ check(obj) {
151
+ for (const check of this.checks) {
152
+ if (obj[check] == this.base.prototype[check]) {
153
+ throw new Error(`For ${obj.constructor.name} you need to override ${check}`)
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ /*
160
+ L = track separation width (distance between the centers of the two tracks, measured side-to-side, in meters or whatever unit you like)
161
+
162
+ v = ground speed of each track (in m/s) — assume same magnitude but opposite directionsleft track forward at +v
163
+ right track backward at -v (or vice versa for the other direction)
164
+
165
+ θ = desired turn angle in radians (convert degrees to radians with θ_rad = θ_deg × π / 180)
166
+
167
+ The angular velocity ω (how fast the tank rotates, in rad/s) is:
168
+
169
+ ω = 2v / L
170
+
171
+ The time t needed to turn by angle θ is:
172
+
173
+ t = θ / ω = (θ × L) / (2v)
174
+ */
175
+ class API {
176
+ constructor() {
177
+ this.overrideCheck = new OverrideCheck(API, ['forwardDrone', 'backwardDrone', 'rotateDrone', 'sonicDrone', 'tiltAngleDrone', 'panAngleDrone', 'stopDrone', 'saveCalibration'])
178
+ this.overriden = this.constructor !== API
179
+ }
180
+
181
+ initialize({ objects }) {
182
+ if (this.overriden) {
183
+ this.overrideCheck.check(this)
184
+ }
185
+ this._objects = objects
186
+ this._objects.defaultTime = { hour: 9, minute: 0, second: 0, millisecond: 0 }
187
+ this._objects.ordinal = 0
188
+ delete this.testDate
189
+
190
+ objects.calibration = {
191
+ speed: undefined, // meters per second
192
+ widthOfTankInMM: 188,
193
+ widthOfTreadInMM: 44,
194
+ }
195
+ objects.current = {
196
+ angleInRadians: 0
197
+ // direction: undefined, // direction to go if going
198
+ // power: undefined, // power
199
+ // ordinal // ordinal of the current point or the current point that the recent movement started at
200
+ }
201
+ objects.history = []
202
+ objects.calibration.isCalibrated = false
203
+ objects.sonicTest = 5
204
+ }
205
+
206
+ isCalibrated() {
207
+ return this._objects.calibration.isCalibrated
208
+ }
209
+
210
+ nextOrdinal() {
211
+ return this._objects.ordinal += 1
212
+ }
213
+
214
+ currentPoint() {
215
+ if (!this._objects.current.endTime) {
216
+ return null // in motion
217
+ }
218
+ const ordinal = this._objects.current.ordinal
219
+ const lastPoint = this.args.mentions({ context: { marker: 'point' }, condition: (context) => context.ordinal == ordinal })
220
+
221
+ const durationInSeconds = (this._objects.current.endTime - this._objects.current.startTime) / 1000
222
+ const speedInMetersPerSecond = (this._objects.current.power / this._objects.calibration.power) * this._objects.calibration.speedForward
223
+ const direction = this._objects.current.direction
224
+ const distanceInMeters = speedInMetersPerSecond * durationInSeconds * (direction == 'forward' ? 1 : -1)
225
+ const angleInRadians = this._objects.current.angleInRadians
226
+ const yPrime = lastPoint.point.y + distanceInMeters * Math.sin(angleInRadians)
227
+ const xPrime = lastPoint.point.x + distanceInMeters * Math.cos(angleInRadians)
228
+ return { x: xPrime, y: yPrime }
229
+ }
230
+
231
+ markCurrentPoint() {
232
+ const ordinal = this.nextOrdinal()
233
+ const point = this.currentPoint()
234
+ this.args.mentioned({ marker: 'point', ordinal, point })
235
+ this._objects.current.ordinal = ordinal
236
+ this._objects.current.endTime = null
237
+ this._objects.current.startTime = null
238
+ }
239
+
240
+ async sendCommand() {
241
+ const stopAtDistance = async (direction, distanceMeters) => {
242
+ const speed_meters_per_second = direction == 'forward' ? this._objects.calibration.speedForward : this._objects.calibration.speedBackward
243
+ const duration_seconds = distanceMeters / speed_meters_per_second
244
+ await this.pause(duration_seconds, { batched: true })
245
+ await this.stop()
246
+ this.markCurrentPoint()
247
+ }
248
+
249
+ if (this._objects.current.destination) {
250
+ const currentPoint = this.args.mentions({ context: { marker: 'point' } })
251
+ const polar = cartesianToPolar(currentPoint.point, this._objects.current.destination.point)
252
+ const destinationAngleInDegrees = radiansToDegrees(polar.angle)
253
+ let angleDelta = destinationAngleInRadians - this._objects.current.angleInRadians
254
+ if (angleDelta > 180) {
255
+ angleDelta -= 360
256
+ } else if (angleDelta < -180) {
257
+ angleDelta += 360
258
+ }
259
+ await this.rotate(angleDelta)
260
+ await this.forward(this._objects.current.power)
261
+ await stopAtDistance(polar.radius)
262
+ return
263
+ }
264
+
265
+ const command = { power: this._objects.current.power, ...this._objects.current }
266
+ switch (command.direction) {
267
+ case 'forward':
268
+ await this.forward(command.power, { batched: command.distance })
269
+ break
270
+ case 'backward':
271
+ await this.backward(command.power, { batched: command.distance })
272
+ break
273
+ case 'right':
274
+ await this.rotate(-Math.PI/2)
275
+ break
276
+ case 'left':
277
+ await this.rotate(Math.PI/2)
278
+ break
279
+ case 'around':
280
+ await this.rotate(180)
281
+ break
282
+ }
283
+
284
+ if (command.distance) {
285
+ const distanceMeters = command.distance
286
+ await stopAtDistance(command.direction, distanceMeters)
287
+ }
288
+ }
289
+
290
+ loadCalibration(calibration) {
291
+ Object.assign(this._objects.calibration, calibration)
292
+ this._objects.current.power = this._objects.calibration.minPower
293
+ }
294
+
295
+ // override this to save the calibration to not have to run it over and over again and be annoing.
296
+ async saveCalibration(calibration) {
297
+ this._objects.history.push({ marker: 'history', saveCalibration: true })
298
+ }
299
+
300
+ async forward(power, options) {
301
+ const time = await this.forwardDrone(power, options)
302
+ this._objects.current.startTime = time
303
+ this._objects.current.endTime = null
304
+ return time
305
+ }
306
+
307
+ async backward(power, options) {
308
+ const time = await this.backwardDrone(power, options)
309
+ this._objects.current.startTime = time
310
+ this._objects.current.endTime = null
311
+ return time
312
+ }
313
+
314
+ async sonic() {
315
+ return await this.sonicDrone()
316
+ }
317
+
318
+ // TODO allow saying turn while its moving and make that one moves so you can go back wiggly?
319
+ async rotate(angleInRadians) {
320
+ await this.rotateDrone(angleInRadians)
321
+ this._objects.current.angleInRadians = (this._objects.current.angleInRadians + angleInRadians) % Math.PI
322
+ }
323
+
324
+ async tiltAngle(angle) {
325
+ await tiltAngleDrone(angle)
326
+ }
327
+
328
+ async panAngle(angle) {
329
+ await panAngleDrone(angle)
330
+ }
331
+
332
+ async stop(options) {
333
+ const time = await this.stopDrone(options)
334
+ this._objects.current.endTime = time
335
+ return time
336
+ }
337
+
338
+ async pause(durationInSeconds, options) {
339
+ await this.pauseDrone(durationInSeconds, options)
340
+ }
341
+
342
+ // subclass and override the remaining to call the drone
343
+
344
+ // this is for testing
345
+ async pauseDrone(durationInSeconds, options) {
346
+ this._objects.history.push({ marker: 'history', pause: durationInSeconds, ...options })
347
+ this.testDate = new Date(this.testDate.getTime() + (durationInSeconds-1)*1000)
348
+ }
349
+
350
+ now() {
351
+ if (this.args.isProcess || this.args.isTest) {
352
+ if (!this.testDate) {
353
+ this.testDate = new Date(2025, 5, 29, 14, 52, 0)
354
+ }
355
+ this.testDate = new Date(this.testDate.getTime() + 1000)
356
+ return this.testDate
357
+ } else {
358
+ return new Date()
359
+ }
360
+ }
361
+
362
+ // CMD_MOTOR#1000#1000#
363
+ async forwardDrone(power, options) {
364
+ const time = this.now()
365
+ this._objects.sonicTest -= 1
366
+ this._objects.history.push({ marker: 'history', direction: 'forward', power, time, ...options })
367
+ return time
368
+ }
369
+
370
+ async backwardDrone(power, options) {
371
+ const time = this.now()
372
+ this._objects.sonicTest += 1
373
+ this._objects.history.push({ marker: 'history', direction: 'backward', power, time, ...options })
374
+ return time
375
+ }
376
+
377
+ // -angle is counterclockwise
378
+ // +angle is clockwise
379
+
380
+ async rotateDrone(angleInRadians) {
381
+ this._objects.history.push({ marker: 'history', turn: angleInRadians })
382
+ }
383
+
384
+ // distance in cm
385
+ async sonicDrone() {
386
+ this._objects.history.push({ marker: 'history', sonic: this._objects.sonicTest })
387
+ return this._objects.sonicTest
388
+ }
389
+
390
+ async tiltAngleDrone(angle) {
391
+ }
392
+
393
+ async panAngleDrone(angle) {
394
+ }
395
+
396
+ async stopDrone(options) {
397
+ const time = this.now()
398
+ this._objects.history.push({ marker: 'history', power: 0, time, ...options })
399
+ return time
400
+ }
401
+ }
402
+
403
+ const howToCalibrate = "Put an object in front of the drone. When you are ready say calibrate."
404
+
405
+ function askForProperty({
406
+ ask,
407
+ propertyPath,
408
+ contextPath=[],
409
+ query,
410
+ matchr,
411
+ oneShot=false,
412
+ }) {
413
+ ask({
414
+ where: where(),
415
+ oneShot,
416
+
417
+ matchq: ({ api, context, objects }) => !getValue(propertyPath, objects) && context.marker == 'controlEnd',
418
+ applyq: async ({ say, objects }) => {
419
+ return query
420
+ },
421
+
422
+ matchr,
423
+ applyr: async ({objects, context}) => {
424
+ setValue(propertyPath, objects, getValue(contextPath, context))
425
+ },
426
+ })
427
+ }
428
+
429
+ // expectProperty
430
+ /*
431
+ function expectDirection(args) {
432
+ args.config.addSemantic({
433
+ match: ({context, isA}) => isA(context.marker, 'direction'),
434
+ apply: ({objects, context}) => {
435
+ objects.runCommand = true
436
+ objects.current.direction = context.marker
437
+ }
438
+ })
439
+ }
440
+
441
+ function expectDistanceForMove(args) {
442
+ // TODO save id for recalibration
443
+ args.config.addSemantic({
444
+ match: ({context, isA}) => isA(context.marker, 'quantity') && !isA(context.unit.marker, 'unitPerUnit'),
445
+ apply: async ({context, objects, fragments, e}) => {
446
+ const instantiation = await fragments("quantity in meters", { quantity: context })
447
+ const result = await e(instantiation)
448
+ objects.runCommand = true
449
+ objects.current.distance = result.evalue.amount.evalue.evalue
450
+ }
451
+ })
452
+ }
453
+ */
454
+
455
+ const template = {
456
+ fragments: [
457
+ "quantity in meters",
458
+ "quantity in meters per second",
459
+ ],
460
+ configs: [
461
+ "drone is a concept",
462
+ //TODO "forward left, right, backward are directions",
463
+ "around, forward, left, right, and backward are directions",
464
+ "speed and power are properties",
465
+ "point is a concept",
466
+ // TODO fix/add this "position means point",
467
+ "points are nameable orderable and memorable",
468
+ (args) => {
469
+ expectDirection(args)
470
+ expectDistanceForMove(args)
471
+
472
+ args.config.addSemantic({
473
+ match: ({context, isA}) => isA(context.marker, 'quantity') && isA(context.unit.marker, 'unitPerUnit'),
474
+ apply: async ({context, objects, api, fragments, e}) => {
475
+ // send a command to the drone
476
+ const instantiation = await fragments("quantity in meters per second", { quantity: context })
477
+ const result = await e(instantiation)
478
+ const desired_speed = result.evalue.amount.evalue.evalue
479
+ const desired_power = objects.current.power * (desired_speed / objects.calibration.speedForward)
480
+ objects.runCommand = true
481
+ objects.current.power = desired_power
482
+ }
483
+ })
484
+
485
+ args.config.addSemantic({
486
+ match: ({context, objects, isA}) => objects.current.direction && objects.calibration.isCalibrated && context.marker == 'controlStart',
487
+ apply: ({context, objects, api}) => {
488
+ objects.runCommand = false
489
+ }
490
+ })
491
+
492
+ args.config.addSemantic({
493
+ // match: ({context, objects, isA}) => objects.current.direction && objects.calibration.isCalibrated && (context.marker == 'controlEnd' || context.marker == 'controlBetween'),
494
+ match: ({context, objects, isA}) => objects.current.direction && objects.calibration.isCalibrated && context.marker == 'controlEnd',
495
+ apply: async ({context, objects, api}) => {
496
+ // send a command to the drone
497
+ if (objects.runCommand) {
498
+ await api.sendCommand()
499
+ }
500
+ }
501
+ })
502
+ },
503
+ {
504
+ operators: [
505
+ "([calibrate])",
506
+ "([turn] (direction))",
507
+ "([pause] ([number]))",
508
+ "([stop] ([drone|])?)",
509
+ "([go])",
510
+ "([toPoint|to] (point))",
511
+ ],
512
+ bridges: [
513
+ {
514
+ id: "toPoint",
515
+ isA: ['preposition'],
516
+ bridge: "{ ...next(operator), operator: operator, point: after[0], interpolate: [{ property: 'operator' }, { property: 'point' }] }",
517
+ semantic: async ({objects, api, e, context}) => {
518
+ if (api.isCalibrated()) {
519
+ objects.runCommand = true
520
+ const point = await e(context.point)
521
+ objects.current.destination = point.evalue
522
+ }
523
+ }
524
+ },
525
+ { id: "go" },
526
+ {
527
+ id: 'turn',
528
+ isA: ['verb'],
529
+ bridge: "{ ...next(operator), direction: after[0], interpolate: [{ context: operator }, { property: 'direction' }] }",
530
+ semantic: ({context, objects, api}) => {
531
+ objects.runCommand = true
532
+ objects.current.direction = context.direction.marker
533
+ },
534
+ // check: { marker: 'turn', exported: true, extra: ['direction'] }
535
+ },
536
+ {
537
+ id: 'calibrate',
538
+ words: ['configure'],
539
+ isA: ['verb'],
540
+ bridge: "{ ...next(operator), interpolate: [{ context: operator }] }",
541
+ semantic: async ({context, objects, api, mentioned}) => {
542
+ let power = 20
543
+ const moveTimeInSeconds = 0.5
544
+ let distanceInCM = 0
545
+ let startBackward
546
+ for (; power < 30; ++power) {
547
+ const start = await api.sonic();
548
+ await api.forward(power, { batched: true })
549
+ await api.pause(moveTimeInSeconds, { batched: true })
550
+ await api.stop()
551
+ const end = await api.sonic();
552
+ if (end !== start) {
553
+ distanceInCM = start - end
554
+ startBackward = end
555
+ break;
556
+ }
557
+ }
558
+
559
+ const metersPerSecondForward = (distanceInCM/100)/moveTimeInSeconds
560
+
561
+ // reset
562
+
563
+ await api.backward(power, { batched: true })
564
+ await api.pause(moveTimeInSeconds, { batched: true })
565
+ await api.stop()
566
+ const endBackward = await api.sonic();
567
+
568
+ const metersPerSecondBackward = ((endBackward-startBackward)/100)/moveTimeInSeconds
569
+
570
+ // console.log(`Distance ${distance} cm`)
571
+ // console.log(`Time ${moveTime} ms`)
572
+ // console.log(`M/S ${metersPerSecond}`)
573
+
574
+ objects.calibration.minPower = power
575
+ objects.calibration.power = power
576
+ objects.current.power = power
577
+ objects.calibration.speedForward = metersPerSecondForward
578
+ objects.calibration.speedBackward = metersPerSecondBackward
579
+ objects.calibration.isCalibrated = true
580
+
581
+ const ordinal = api.nextOrdinal()
582
+ mentioned({ marker: 'point', ordinal, point: { x: 0, y: 0 }, description: "start" })
583
+ objects.current.ordinal = ordinal
584
+
585
+ api.saveCalibration(objects.calibration)
586
+ }
587
+ },
588
+ {
589
+ id: 'pause',
590
+ isA: ['verb'],
591
+ bridge: "{ ...operator, time: after[0], interpolate: [{ context: operator }, { property: 'time' }] }",
592
+ semantic: async ({context}) => {
593
+ // why doesn't nodejs add a sleep function. I always have to look up how to do this because its not fucking memorable.
594
+ // function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
595
+ // await sleep(context.time.value*1000)
596
+ }
597
+ },
598
+ {
599
+ id: 'stop',
600
+ isA: ['verb'],
601
+ optional: {
602
+ 1: "{ marker: 'drone' }",
603
+ },
604
+ bridge: "{ ...next(operator), object: after[0], interpolate: [{ context: operator }, { property: 'object' }] }",
605
+ semantic: async ({mentioned, context, objects, api, say}) => {
606
+ if (!objects.calibration.startTime) {
607
+ return // ignore
608
+ }
609
+ if (objects.calibration.speedForward) {
610
+ await api.stop()
611
+ api.markCurrentPoint()
612
+ } else {
613
+ const stopTime = await api.stop()
614
+ objects.calibration.endTime = stopTime
615
+ objects.calibration.duration = (objects.calibration.endTime - objects.calibration.startTime)/1000
616
+ }
617
+ }
618
+ },
619
+ ],
620
+ generators: [
621
+ {
622
+ match: ({context}) => context.marker == 'help' && !context.paraphrase && context.isResponse,
623
+ apply: () => ''
624
+ },
625
+ ],
626
+ semantics: [
627
+
628
+ ],
629
+ },
630
+ ],
631
+ }
632
+
633
+ knowledgeModule( {
634
+ config: { name: 'drone' },
635
+ includes: [nameable, ordinals, hierarchy, rates, help],
636
+ api: () => new API(),
637
+
638
+ module,
639
+ description: 'controlling a drone',
640
+ test: {
641
+ name: './drone.test.json',
642
+ contents: drone_tests,
643
+ checks: {
644
+ context: [
645
+ defaultContextCheck({ marker: 'point', exported: true, extra: ['ordinal', { property: 'point', check: ['x', 'y'] }, 'description', { property: 'stm', check: ['id', 'names'] }] }),
646
+ defaultContextCheck({ marker: 'turn', exported: true, extra: ['direction'] }),
647
+ defaultContextCheck({ marker: 'history', exported: true, extra: ['pause', 'direction', 'power', 'turn', 'time', 'sonic', 'saveCalibration', 'batched'] }),
648
+ defaultContextCheck(),
649
+ ],
650
+ objects: [
651
+ { km: 'stm' },
652
+ { path: ['isCalibrated'] },
653
+ { path: ['calibration'] },
654
+ { path: ['history'] },
655
+ { path: ['current'] },
656
+ { path: ['runCommand'] },
657
+ ],
658
+ }
659
+ },
660
+ instance,
661
+ template,
662
+ })