@wandelbots/nova-js 3.13.0 → 4.0.0-pr.309.02b99fd

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 (72) hide show
  1. package/dist/{AutoReconnectingWebsocket-1K2J1NA4.d.cts → AutoReconnectingWebsocket-BSt-vnzX.d.mts} +4 -16
  2. package/dist/AutoReconnectingWebsocket-BSt-vnzX.d.mts.map +1 -0
  3. package/dist/{context-ffr5Q2dc.mjs → LoginWithAuth0-D92HnzHq.mjs} +3 -13
  4. package/dist/LoginWithAuth0-D92HnzHq.mjs.map +1 -0
  5. package/dist/{Nova--8gozkLR.d.mts → Nova-C8nDNSCa.d.mts} +2 -2
  6. package/dist/{Nova--8gozkLR.d.mts.map → Nova-C8nDNSCa.d.mts.map} +1 -1
  7. package/dist/experimental/nats/index.d.mts +1 -1
  8. package/dist/index.d.mts +2 -7
  9. package/dist/index.d.mts.map +1 -1
  10. package/dist/index.mjs +2 -3
  11. package/dist/v2/index.d.mts +2 -130
  12. package/dist/v2/index.mjs +4 -231
  13. package/dist/v2/index.mjs.map +1 -1
  14. package/package.json +13 -17
  15. package/src/index.ts +0 -2
  16. package/src/lib/AutoReconnectingWebsocket.ts +3 -4
  17. package/src/lib/LoginWithAuth0.ts +1 -1
  18. package/src/lib/context.ts +1 -1
  19. package/src/lib/errorHandling.ts +0 -7
  20. package/src/v2/index.ts +0 -3
  21. package/dist/AutoReconnectingWebsocket-1K2J1NA4.d.cts.map +0 -1
  22. package/dist/AutoReconnectingWebsocket-1K2J1NA4.d.mts +0 -69
  23. package/dist/AutoReconnectingWebsocket-1K2J1NA4.d.mts.map +0 -1
  24. package/dist/Nova-B1o5iTQ6.d.cts +0 -85
  25. package/dist/Nova-B1o5iTQ6.d.cts.map +0 -1
  26. package/dist/context-BZELA2eh.cjs +0 -348
  27. package/dist/context-BZELA2eh.cjs.map +0 -1
  28. package/dist/context-ffr5Q2dc.mjs.map +0 -1
  29. package/dist/converters-EYS27XJE.cjs +0 -146
  30. package/dist/converters-EYS27XJE.cjs.map +0 -1
  31. package/dist/experimental/nats/index.cjs +0 -158
  32. package/dist/experimental/nats/index.cjs.map +0 -1
  33. package/dist/experimental/nats/index.d.cts +0 -3235
  34. package/dist/experimental/nats/index.d.cts.map +0 -1
  35. package/dist/index.cjs +0 -24
  36. package/dist/index.d.cts +0 -110
  37. package/dist/index.d.cts.map +0 -1
  38. package/dist/v1/index.cjs +0 -201
  39. package/dist/v1/index.cjs.map +0 -1
  40. package/dist/v1/index.d.cts +0 -67
  41. package/dist/v1/index.d.cts.map +0 -1
  42. package/dist/v1/index.d.mts +0 -67
  43. package/dist/v1/index.d.mts.map +0 -1
  44. package/dist/v1/index.mjs +0 -184
  45. package/dist/v1/index.mjs.map +0 -1
  46. package/dist/v2/index.cjs +0 -1038
  47. package/dist/v2/index.cjs.map +0 -1
  48. package/dist/v2/index.d.cts +0 -131
  49. package/dist/v2/index.d.cts.map +0 -1
  50. package/dist/v2/index.d.mts.map +0 -1
  51. package/dist/wandelscriptUtils-CpUXdLVc.mjs +0 -2062
  52. package/dist/wandelscriptUtils-CpUXdLVc.mjs.map +0 -1
  53. package/dist/wandelscriptUtils-DY3WsiuB.d.cts +0 -356
  54. package/dist/wandelscriptUtils-DY3WsiuB.d.cts.map +0 -1
  55. package/dist/wandelscriptUtils-DcY1aLWu.cjs +0 -2099
  56. package/dist/wandelscriptUtils-DcY1aLWu.cjs.map +0 -1
  57. package/dist/wandelscriptUtils-YHTxn_p9.d.mts +0 -356
  58. package/dist/wandelscriptUtils-YHTxn_p9.d.mts.map +0 -1
  59. package/src/lib/deprecated/v1/ConnectedMotionGroup.ts +0 -449
  60. package/src/lib/deprecated/v1/JoggerConnection.ts +0 -491
  61. package/src/lib/deprecated/v1/MotionStreamConnection.ts +0 -215
  62. package/src/lib/deprecated/v1/NovaCellAPIClient.ts +0 -208
  63. package/src/lib/deprecated/v1/NovaClient.ts +0 -260
  64. package/src/lib/deprecated/v1/ProgramStateConnection.ts +0 -277
  65. package/src/lib/deprecated/v1/getLatestTrajectories.ts +0 -37
  66. package/src/lib/deprecated/v1/mock/MockNovaInstance.ts +0 -1303
  67. package/src/lib/deprecated/v1/motionStateUpdate.ts +0 -58
  68. package/src/lib/deprecated/v1/wandelscriptUtils.ts +0 -23
  69. package/src/lib/deprecated/v2/NovaCellAPIClient.ts +0 -215
  70. package/src/lib/deprecated/v2/NovaClient.ts +0 -218
  71. package/src/lib/deprecated/v2/wandelscriptUtils.ts +0 -28
  72. package/src/v1/index.ts +0 -14
@@ -1,491 +0,0 @@
1
- import type { Command, Joints, TcpPose } from "@wandelbots/nova-api/v1"
2
- import { Vector3 } from "three/src/math/Vector3.js"
3
- import type { AutoReconnectingWebsocket } from "../../AutoReconnectingWebsocket.ts"
4
- import { isSameCoordinateSystem, tryParseJson } from "../../converters.ts"
5
- import type { MotionStreamConnection } from "./MotionStreamConnection.ts"
6
- import type { NovaClient } from "./NovaClient.ts"
7
-
8
- /** @deprecated */
9
- export type JoggerConnectionOpts = {
10
- /**
11
- * When an error message is received from the jogging websocket, it
12
- * will be passed here. If this handler is not provided, the error will
13
- * instead be thrown as an unhandled error.
14
- */
15
- onError?: (err: unknown) => void
16
- }
17
-
18
- /** @deprecated */
19
- export class JoggerConnection {
20
- // Currently a separate websocket is needed for each mode, pester API people
21
- // to merge these for simplicity
22
- cartesianWebsocket: AutoReconnectingWebsocket | null = null
23
- jointWebsocket: AutoReconnectingWebsocket | null = null
24
- cartesianJoggingOpts: {
25
- tcpId?: string
26
- coordSystemId?: string
27
- } = {}
28
-
29
- static async open(
30
- nova: NovaClient,
31
- motionGroupId: string,
32
- opts: JoggerConnectionOpts = {},
33
- ) {
34
- const motionStream = await nova.connectMotionStream(motionGroupId)
35
-
36
- return new JoggerConnection(motionStream, opts)
37
- }
38
-
39
- readonly motionStream: MotionStreamConnection
40
- readonly opts: JoggerConnectionOpts
41
-
42
- constructor(
43
- motionStream: MotionStreamConnection,
44
- opts: JoggerConnectionOpts = {},
45
- ) {
46
- this.motionStream = motionStream
47
- this.opts = opts
48
- }
49
-
50
- get motionGroupId() {
51
- return this.motionStream.motionGroupId
52
- }
53
-
54
- get nova() {
55
- return this.motionStream.nova
56
- }
57
-
58
- get numJoints() {
59
- return this.motionStream.joints.length
60
- }
61
-
62
- get activeJoggingMode() {
63
- if (this.cartesianWebsocket) return "cartesian"
64
- if (this.jointWebsocket) return "joint"
65
- return "increment"
66
- }
67
-
68
- get activeWebsocket() {
69
- return this.cartesianWebsocket || this.jointWebsocket
70
- }
71
-
72
- async stop() {
73
- // Why not call the stopJogging API endpoint?
74
- // Because this results in the websocket closing and we
75
- // would like to keep it open for now.
76
-
77
- if (this.cartesianWebsocket) {
78
- this.cartesianWebsocket.sendJson({
79
- motion_group: this.motionGroupId,
80
- position_direction: { x: 0, y: 0, z: 0 },
81
- rotation_direction: { x: 0, y: 0, z: 0 },
82
- position_velocity: 0,
83
- rotation_velocity: 0,
84
- tcp: this.cartesianJoggingOpts.tcpId,
85
- coordinate_system: this.cartesianJoggingOpts.coordSystemId,
86
- })
87
- }
88
-
89
- if (this.jointWebsocket) {
90
- this.jointWebsocket.sendJson({
91
- motion_group: this.motionGroupId,
92
- joint_velocities: new Array(this.numJoints).fill(0),
93
- })
94
- }
95
- }
96
-
97
- dispose() {
98
- if (this.cartesianWebsocket) {
99
- this.cartesianWebsocket.dispose()
100
- }
101
-
102
- if (this.jointWebsocket) {
103
- this.jointWebsocket.dispose()
104
- }
105
- }
106
-
107
- setJoggingMode(
108
- mode: "cartesian" | "joint" | "increment",
109
- cartesianJoggingOpts?: {
110
- tcpId?: string
111
- coordSystemId?: string
112
- },
113
- ) {
114
- console.log("Setting jogging mode to", mode)
115
- if (cartesianJoggingOpts) {
116
- // Websocket needs to be reopened to change options
117
- if (
118
- JSON.stringify(this.cartesianJoggingOpts) !==
119
- JSON.stringify(cartesianJoggingOpts)
120
- ) {
121
- if (this.cartesianWebsocket) {
122
- this.cartesianWebsocket.dispose()
123
- this.cartesianWebsocket = null
124
- }
125
- }
126
-
127
- this.cartesianJoggingOpts = cartesianJoggingOpts
128
- }
129
-
130
- if (mode !== "cartesian" && this.cartesianWebsocket) {
131
- this.cartesianWebsocket.dispose()
132
- this.cartesianWebsocket = null
133
- }
134
-
135
- if (mode !== "joint" && this.jointWebsocket) {
136
- this.jointWebsocket.dispose()
137
- this.jointWebsocket = null
138
- }
139
-
140
- if (mode === "cartesian" && !this.cartesianWebsocket) {
141
- this.cartesianWebsocket = this.nova.openReconnectingWebsocket(
142
- `/motion-groups/move-tcp`,
143
- )
144
-
145
- this.cartesianWebsocket.addEventListener(
146
- "message",
147
- (ev: MessageEvent) => {
148
- const data = tryParseJson(ev.data)
149
- if (data && "error" in data) {
150
- if (this.opts.onError) {
151
- this.opts.onError(ev.data)
152
- } else {
153
- throw new Error(ev.data)
154
- }
155
- }
156
- },
157
- )
158
- }
159
-
160
- if (mode === "joint" && !this.jointWebsocket) {
161
- this.jointWebsocket = this.nova.openReconnectingWebsocket(
162
- `/motion-groups/move-joint`,
163
- )
164
-
165
- this.jointWebsocket.addEventListener("message", (ev: MessageEvent) => {
166
- const data = tryParseJson(ev.data)
167
- if (data && "error" in data) {
168
- if (this.opts.onError) {
169
- this.opts.onError(ev.data)
170
- } else {
171
- throw new Error(ev.data)
172
- }
173
- }
174
- })
175
- }
176
- }
177
-
178
- /**
179
- * Start rotation of a single robot joint at the specified velocity
180
- */
181
- async startJointRotation({
182
- joint,
183
- direction,
184
- velocityRadsPerSec,
185
- }: {
186
- /** Index of the joint to rotate */
187
- joint: number
188
- /** Direction of rotation ("+" or "-") */
189
- direction: "+" | "-"
190
- /** Speed of the rotation in radians per second */
191
- velocityRadsPerSec: number
192
- }) {
193
- if (!this.jointWebsocket) {
194
- throw new Error(
195
- "Joint jogging websocket not connected; call setJoggingMode first",
196
- )
197
- }
198
-
199
- const jointVelocities = new Array(this.numJoints).fill(0)
200
-
201
- jointVelocities[joint] =
202
- direction === "-" ? -velocityRadsPerSec : velocityRadsPerSec
203
-
204
- this.jointWebsocket.sendJson({
205
- motion_group: this.motionGroupId,
206
- joint_velocities: jointVelocities,
207
- })
208
- }
209
-
210
- /**
211
- * Start the TCP moving along a specified axis at a given velocity
212
- */
213
- async startTCPTranslation({
214
- axis,
215
- direction,
216
- velocityMmPerSec,
217
- }: {
218
- axis: "x" | "y" | "z"
219
- direction: "-" | "+"
220
- velocityMmPerSec: number
221
- }) {
222
- if (!this.cartesianWebsocket) {
223
- throw new Error(
224
- "Cartesian jogging websocket not connected; call setJoggingMode first",
225
- )
226
- }
227
-
228
- const zeroVector = { x: 0, y: 0, z: 0 }
229
- const joggingVector = Object.assign({}, zeroVector)
230
- joggingVector[axis] = direction === "-" ? -1 : 1
231
-
232
- this.cartesianWebsocket.sendJson({
233
- motion_group: this.motionGroupId,
234
- position_direction: joggingVector,
235
- rotation_direction: zeroVector,
236
- position_velocity: velocityMmPerSec,
237
- rotation_velocity: 0,
238
- tcp: this.cartesianJoggingOpts.tcpId,
239
- coordinate_system: this.cartesianJoggingOpts.coordSystemId,
240
- })
241
- }
242
-
243
- /**
244
- * Start the TCP rotating around a specified axis at a given velocity
245
- */
246
- async startTCPRotation({
247
- axis,
248
- direction,
249
- velocityRadsPerSec,
250
- }: {
251
- axis: "x" | "y" | "z"
252
- direction: "-" | "+"
253
- velocityRadsPerSec: number
254
- }) {
255
- if (!this.cartesianWebsocket) {
256
- throw new Error(
257
- "Cartesian jogging websocket not connected; call setJoggingMode first",
258
- )
259
- }
260
-
261
- const zeroVector = { x: 0, y: 0, z: 0 }
262
- const joggingVector = Object.assign({}, zeroVector)
263
- joggingVector[axis] = direction === "-" ? -1 : 1
264
-
265
- this.cartesianWebsocket.sendJson({
266
- motion_group: this.motionGroupId,
267
- position_direction: zeroVector,
268
- rotation_direction: joggingVector,
269
- position_velocity: 0,
270
- rotation_velocity: velocityRadsPerSec,
271
- tcp: this.cartesianJoggingOpts.tcpId,
272
- coordinate_system: this.cartesianJoggingOpts.coordSystemId,
273
- })
274
- }
275
-
276
- /**
277
- * Move the robot by a fixed distance in a single cartesian
278
- * axis, either rotating or translating relative to the TCP.
279
- * Promise resolves only after the motion has completed.
280
- */
281
- async runIncrementalCartesianMotion({
282
- currentTcpPose,
283
- currentJoints,
284
- coordSystemId,
285
- velocityInRelevantUnits,
286
- axis,
287
- direction,
288
- motion,
289
- }: {
290
- currentTcpPose: TcpPose
291
- currentJoints: Joints
292
- coordSystemId: string
293
- velocityInRelevantUnits: number
294
- axis: "x" | "y" | "z"
295
- direction: "-" | "+"
296
- motion:
297
- | {
298
- type: "rotate"
299
- distanceRads: number
300
- }
301
- | {
302
- type: "translate"
303
- distanceMm: number
304
- }
305
- }) {
306
- const commands: Command[] = []
307
-
308
- if (
309
- !isSameCoordinateSystem(currentTcpPose.coordinate_system, coordSystemId)
310
- ) {
311
- throw new Error(
312
- `Current TCP pose coordinate system ${currentTcpPose.coordinate_system} does not match target coordinate system ${coordSystemId}`,
313
- )
314
- }
315
-
316
- if (motion.type === "translate") {
317
- const targetTcpPosition = Object.assign({}, currentTcpPose.position)
318
- targetTcpPosition[axis] +=
319
- motion.distanceMm * (direction === "-" ? -1 : 1)
320
-
321
- commands.push({
322
- settings: {
323
- limits_override: {
324
- tcp_velocity_limit: velocityInRelevantUnits,
325
- },
326
- },
327
- line: {
328
- position: targetTcpPosition,
329
- orientation: currentTcpPose.orientation,
330
- coordinate_system: coordSystemId,
331
- },
332
- })
333
- } else if (motion.type === "rotate") {
334
- // Concatenate rotations expressed by rotation vectors
335
- // Equations taken from https://physics.stackexchange.com/a/287819
336
-
337
- // Compute axis and angle of current rotation vector
338
- const currentRotationVector = new Vector3(
339
- currentTcpPose.orientation.x,
340
- currentTcpPose.orientation.y,
341
- currentTcpPose.orientation.z,
342
- )
343
-
344
- const currentRotationRad = currentRotationVector.length()
345
- const currentRotationDirection = currentRotationVector.clone().normalize()
346
-
347
- // Compute axis and angle of difference rotation vector
348
- const differenceRotationRad =
349
- motion.distanceRads * (direction === "-" ? -1 : 1)
350
-
351
- const differenceRotationDirection = new Vector3(0.0, 0.0, 0.0)
352
- differenceRotationDirection[axis] = 1.0
353
-
354
- // Some abbreviations to make the following equations more readable
355
- const f1 =
356
- Math.cos(0.5 * differenceRotationRad) *
357
- Math.cos(0.5 * currentRotationRad)
358
- const f2 =
359
- Math.sin(0.5 * differenceRotationRad) *
360
- Math.sin(0.5 * currentRotationRad)
361
- const f3 =
362
- Math.sin(0.5 * differenceRotationRad) *
363
- Math.cos(0.5 * currentRotationRad)
364
- const f4 =
365
- Math.cos(0.5 * differenceRotationRad) *
366
- Math.sin(0.5 * currentRotationRad)
367
-
368
- const dotProduct = differenceRotationDirection.dot(
369
- currentRotationDirection,
370
- )
371
-
372
- const crossProduct = differenceRotationDirection
373
- .clone()
374
- .cross(currentRotationDirection)
375
-
376
- // Compute angle of concatenated rotation
377
- const newRotationRad = 2.0 * Math.acos(f1 - f2 * dotProduct)
378
-
379
- // Compute rotation vector of concatenated rotation
380
- const f5 = newRotationRad / Math.sin(0.5 * newRotationRad)
381
-
382
- const targetTcpOrientation = new Vector3()
383
- .addScaledVector(crossProduct, f2)
384
- .addScaledVector(differenceRotationDirection, f3)
385
- .addScaledVector(currentRotationDirection, f4)
386
- .multiplyScalar(f5)
387
-
388
- commands.push({
389
- settings: {
390
- limits_override: {
391
- tcp_orientation_velocity_limit: velocityInRelevantUnits,
392
- },
393
- },
394
- line: {
395
- position: currentTcpPose.position,
396
- orientation: targetTcpOrientation,
397
- coordinate_system: coordSystemId,
398
- },
399
- })
400
- }
401
-
402
- const motionPlanRes = await this.nova.api.motion.planMotion({
403
- motion_group: this.motionGroupId,
404
- start_joint_position: currentJoints,
405
- tcp: this.cartesianJoggingOpts.tcpId,
406
- commands,
407
- })
408
-
409
- const plannedMotion = motionPlanRes.plan_successful_response?.motion
410
- if (!plannedMotion) {
411
- throw new Error(
412
- `Failed to plan jogging increment motion ${JSON.stringify(motionPlanRes)}`,
413
- )
414
- }
415
-
416
- await this.nova.api.motion.streamMoveForward(
417
- plannedMotion,
418
- 100,
419
- undefined,
420
- undefined,
421
- undefined,
422
- {
423
- // Might take a while at low velocity
424
- timeout: 1000 * 60,
425
- },
426
- )
427
- }
428
-
429
- /**
430
- * Rotate a single robot joint by a fixed number of radians
431
- * Promise resolves only after the motion has completed.
432
- */
433
- async runIncrementalJointRotation({
434
- joint,
435
- currentJoints,
436
- velocityRadsPerSec,
437
- direction,
438
- distanceRads,
439
- }: {
440
- joint: number
441
- currentJoints: Joints
442
- velocityRadsPerSec: number
443
- direction: "-" | "+"
444
- distanceRads: number
445
- }) {
446
- const targetJoints = [...currentJoints.joints]
447
- // biome-ignore lint/style/noNonNullAssertion: legacy code
448
- targetJoints[joint]! += distanceRads * (direction === "-" ? -1 : 1)
449
-
450
- const jointVelocityLimits: number[] = new Array(
451
- currentJoints.joints.length,
452
- ).fill(velocityRadsPerSec)
453
-
454
- const motionPlanRes = await this.nova.api.motion.planMotion({
455
- motion_group: this.motionGroupId,
456
- start_joint_position: currentJoints,
457
- commands: [
458
- {
459
- settings: {
460
- limits_override: {
461
- joint_velocity_limits: {
462
- joints: jointVelocityLimits,
463
- },
464
- },
465
- },
466
- joint_ptp: {
467
- joints: targetJoints,
468
- },
469
- },
470
- ],
471
- })
472
-
473
- const plannedMotion = motionPlanRes.plan_successful_response?.motion
474
- if (!plannedMotion) {
475
- console.error("Failed to plan jogging increment motion", motionPlanRes)
476
- return
477
- }
478
-
479
- await this.nova.api.motion.streamMoveForward(
480
- plannedMotion,
481
- 100,
482
- undefined,
483
- undefined,
484
- undefined,
485
- {
486
- // Might take a while at low velocity
487
- timeout: 1000 * 60,
488
- },
489
- )
490
- }
491
- }
@@ -1,215 +0,0 @@
1
- /** biome-ignore-all lint/style/noNonNullAssertion: legacy code */
2
- import type {
3
- ControllerInstance,
4
- MotionGroupPhysical,
5
- MotionGroupStateResponse,
6
- Vector3d,
7
- } from "@wandelbots/nova-api/v1"
8
- import { makeAutoObservable, runInAction } from "mobx"
9
- import { Vector3 } from "three"
10
- import type { AutoReconnectingWebsocket } from "../../AutoReconnectingWebsocket.ts"
11
- import { tryParseJson } from "../../converters.ts"
12
- import { jointValuesEqual, tcpPoseEqual } from "./motionStateUpdate.ts"
13
- import type { NovaClient } from "./NovaClient.ts"
14
-
15
- const MOTION_DELTA_THRESHOLD = 0.0001
16
-
17
- function unwrapRotationVector(
18
- newRotationVectorApi: Vector3d,
19
- currentRotationVectorApi: Vector3d,
20
- ): Vector3d {
21
- const currentRotationVector = new Vector3(
22
- currentRotationVectorApi.x,
23
- currentRotationVectorApi.y,
24
- currentRotationVectorApi.z,
25
- )
26
-
27
- const newRotationVector = new Vector3(
28
- newRotationVectorApi.x,
29
- newRotationVectorApi.y,
30
- newRotationVectorApi.z,
31
- )
32
-
33
- const currentAngle = currentRotationVector.length()
34
- const currentAxis = currentRotationVector.normalize()
35
-
36
- let newAngle = newRotationVector.length()
37
- let newAxis = newRotationVector.normalize()
38
-
39
- // Align rotation axes
40
- if (newAxis.dot(currentAxis) < 0) {
41
- newAngle = -newAngle
42
- newAxis = newAxis.multiplyScalar(-1.0)
43
- }
44
-
45
- // Shift rotation angle close to previous one to extend domain of rotation angles beyond [0, pi]
46
- // - this simplifies interpolation and prevents abruptly changing signs of the rotation angles
47
- let angleDifference = newAngle - currentAngle
48
- angleDifference -=
49
- 2.0 * Math.PI * Math.floor((angleDifference + Math.PI) / (2.0 * Math.PI))
50
-
51
- newAngle = currentAngle + angleDifference
52
-
53
- return newAxis.multiplyScalar(newAngle)
54
- }
55
-
56
- /**
57
- * Store representing the current state of a connected motion group.
58
- * @deprecated
59
- */
60
- export class MotionStreamConnection {
61
- static async open(nova: NovaClient, motionGroupId: string) {
62
- const { instances: controllers } =
63
- await nova.api.controller.listControllers()
64
-
65
- const [_motionGroupIndex, controllerId] = motionGroupId.split("@") as [
66
- string,
67
- string,
68
- ]
69
- const controller = controllers.find((c) => c.controller === controllerId)
70
- const motionGroup = controller?.physical_motion_groups.find(
71
- (mg) => mg.motion_group === motionGroupId,
72
- )
73
- if (!controller || !motionGroup) {
74
- throw new Error(
75
- `Controller ${controllerId} or motion group ${motionGroupId} not found`,
76
- )
77
- }
78
-
79
- const motionStateSocket = nova.openReconnectingWebsocket(
80
- `/motion-groups/${motionGroupId}/state-stream`,
81
- )
82
-
83
- // Wait for the first message to get the initial state
84
- const firstMessage = await motionStateSocket.firstMessage()
85
- const initialMotionState = tryParseJson(firstMessage.data)
86
- ?.result as MotionGroupStateResponse
87
-
88
- if (!initialMotionState) {
89
- throw new Error(
90
- `Unable to parse initial motion state message ${firstMessage.data}`,
91
- )
92
- }
93
-
94
- console.log(
95
- `Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state:\n `,
96
- initialMotionState,
97
- )
98
-
99
- return new MotionStreamConnection(
100
- nova,
101
- controller,
102
- motionGroup,
103
- initialMotionState,
104
- motionStateSocket,
105
- )
106
- }
107
-
108
- // Not mobx-observable as this changes very fast; should be observed
109
- // using animation frames
110
- rapidlyChangingMotionState: MotionGroupStateResponse
111
-
112
- readonly nova: NovaClient
113
- readonly controller: ControllerInstance
114
- readonly motionGroup: MotionGroupPhysical
115
- readonly initialMotionState: MotionGroupStateResponse
116
- readonly motionStateSocket: AutoReconnectingWebsocket
117
-
118
- constructor(
119
- nova: NovaClient,
120
- controller: ControllerInstance,
121
- motionGroup: MotionGroupPhysical,
122
- initialMotionState: MotionGroupStateResponse,
123
- motionStateSocket: AutoReconnectingWebsocket,
124
- ) {
125
- this.nova = nova
126
- this.controller = controller
127
- this.motionGroup = motionGroup
128
- this.initialMotionState = initialMotionState
129
- this.motionStateSocket = motionStateSocket
130
-
131
- this.rapidlyChangingMotionState = initialMotionState
132
-
133
- motionStateSocket.addEventListener("message", (event) => {
134
- const motionStateResponse = tryParseJson(event.data)?.result as
135
- | MotionGroupStateResponse
136
- | undefined
137
-
138
- if (!motionStateResponse) {
139
- throw new Error(
140
- `Failed to get motion state for ${this.motionGroupId}: ${event.data}`,
141
- )
142
- }
143
-
144
- // handle motionState message
145
- if (
146
- !jointValuesEqual(
147
- this.rapidlyChangingMotionState.state.joint_position.joints,
148
- motionStateResponse.state.joint_position.joints,
149
- MOTION_DELTA_THRESHOLD,
150
- )
151
- ) {
152
- runInAction(() => {
153
- this.rapidlyChangingMotionState.state = motionStateResponse.state
154
- })
155
- }
156
-
157
- // handle tcpPose message
158
- if (
159
- !tcpPoseEqual(
160
- this.rapidlyChangingMotionState.tcp_pose,
161
- motionStateResponse.tcp_pose,
162
- MOTION_DELTA_THRESHOLD,
163
- )
164
- ) {
165
- runInAction(() => {
166
- if (this.rapidlyChangingMotionState.tcp_pose == null) {
167
- this.rapidlyChangingMotionState.tcp_pose =
168
- motionStateResponse.tcp_pose
169
- } else {
170
- this.rapidlyChangingMotionState.tcp_pose = {
171
- position: motionStateResponse.tcp_pose!.position,
172
- orientation: unwrapRotationVector(
173
- motionStateResponse.tcp_pose!.orientation,
174
- this.rapidlyChangingMotionState.tcp_pose!.orientation,
175
- ),
176
- tcp: motionStateResponse.tcp_pose!.tcp,
177
- coordinate_system:
178
- motionStateResponse.tcp_pose!.coordinate_system,
179
- }
180
- }
181
- })
182
- }
183
- })
184
- makeAutoObservable(this)
185
- }
186
-
187
- get motionGroupId() {
188
- return this.motionGroup.motion_group
189
- }
190
-
191
- get controllerId() {
192
- return this.controller.controller
193
- }
194
-
195
- get modelFromController() {
196
- return this.motionGroup.model_from_controller
197
- }
198
-
199
- get wandelscriptIdentifier() {
200
- const num = this.motionGroupId.split("@")[0]
201
- return `${this.controllerId.replaceAll("-", "_")}_${num}`
202
- }
203
-
204
- get joints() {
205
- return this.initialMotionState.state.joint_position.joints.map((_, i) => {
206
- return {
207
- index: i,
208
- }
209
- })
210
- }
211
-
212
- dispose() {
213
- this.motionStateSocket.close()
214
- }
215
- }