@wandelbots/nova-js 3.2.0-pr.dev-e2e-jogging-test.143.4f02caf → 3.2.0-pr.feat-v2.155.e91b019

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 (66) hide show
  1. package/README.md +60 -50
  2. package/dist/{AutoReconnectingWebsocket-BI1ckzP8.d.ts → AutoReconnectingWebsocket-CoU4ZyD2.d.cts} +1 -3
  3. package/dist/AutoReconnectingWebsocket-CoU4ZyD2.d.cts.map +1 -0
  4. package/dist/{AutoReconnectingWebsocket-Cr7f9016.d.cts → AutoReconnectingWebsocket-D0gTrkzu.d.ts} +1 -3
  5. package/dist/AutoReconnectingWebsocket-D0gTrkzu.d.ts.map +1 -0
  6. package/dist/{LoginWithAuth0-0g0wWRUC.js → LoginWithAuth0-CaX7yo7d.js} +58 -5
  7. package/dist/LoginWithAuth0-CaX7yo7d.js.map +1 -0
  8. package/dist/{LoginWithAuth0-C82OCyDy.cjs → LoginWithAuth0-DaPnTz2I.cjs} +99 -4
  9. package/dist/LoginWithAuth0-DaPnTz2I.cjs.map +1 -0
  10. package/dist/index.cjs +11 -10
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +11 -8
  13. package/dist/index.d.cts.map +1 -1
  14. package/dist/index.d.ts +11 -8
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -3
  17. package/dist/lib/v1/index.cjs +17 -19
  18. package/dist/lib/v1/index.cjs.map +1 -1
  19. package/dist/lib/v1/index.d.cts +4 -2
  20. package/dist/lib/v1/index.d.cts.map +1 -1
  21. package/dist/lib/v1/index.d.ts +4 -2
  22. package/dist/lib/v1/index.d.ts.map +1 -1
  23. package/dist/lib/v1/index.js +7 -10
  24. package/dist/lib/v1/index.js.map +1 -1
  25. package/dist/lib/v2/index.cjs +1087 -11
  26. package/dist/lib/v2/index.cjs.map +1 -1
  27. package/dist/lib/v2/index.d.cts +256 -7
  28. package/dist/lib/v2/index.d.cts.map +1 -1
  29. package/dist/lib/v2/index.d.ts +256 -7
  30. package/dist/lib/v2/index.d.ts.map +1 -1
  31. package/dist/lib/v2/index.js +1082 -12
  32. package/dist/lib/v2/index.js.map +1 -1
  33. package/dist/wandelscriptUtils-CO5GYRij.js +24 -0
  34. package/dist/wandelscriptUtils-CO5GYRij.js.map +1 -0
  35. package/dist/wandelscriptUtils-COHpTIme.d.cts +12 -0
  36. package/dist/wandelscriptUtils-COHpTIme.d.cts.map +1 -0
  37. package/dist/wandelscriptUtils-Cl3GBxOp.d.ts +12 -0
  38. package/dist/wandelscriptUtils-Cl3GBxOp.d.ts.map +1 -0
  39. package/dist/wandelscriptUtils-DwpJ4jCy.cjs +30 -0
  40. package/dist/wandelscriptUtils-DwpJ4jCy.cjs.map +1 -0
  41. package/package.json +2 -2
  42. package/src/LoginWithAuth0.ts +3 -3
  43. package/src/index.ts +1 -0
  44. package/src/lib/converters.ts +5 -23
  45. package/src/lib/v1/MotionStreamConnection.ts +1 -1
  46. package/src/lib/v1/NovaClient.ts +6 -0
  47. package/src/lib/v1/index.ts +6 -0
  48. package/src/lib/v1/mock/MockNovaInstance.ts +0 -1
  49. package/src/lib/v1/wandelscriptUtils.ts +22 -0
  50. package/src/lib/v2/ConnectedMotionGroup.ts +415 -0
  51. package/src/lib/v2/JoggerConnection.ts +647 -0
  52. package/src/lib/v2/MotionStreamConnection.ts +222 -0
  53. package/src/lib/v2/NovaClient.ts +43 -8
  54. package/src/lib/v2/index.ts +5 -0
  55. package/src/lib/v2/mock/MockNovaInstance.ts +385 -1
  56. package/src/lib/v2/motionStateUpdate.ts +76 -0
  57. package/src/lib/v2/types/vector3.ts +1 -0
  58. package/src/lib/v2/wandelscriptUtils.ts +27 -0
  59. package/dist/AutoReconnectingWebsocket-BI1ckzP8.d.ts.map +0 -1
  60. package/dist/AutoReconnectingWebsocket-Cr7f9016.d.cts.map +0 -1
  61. package/dist/LoginWithAuth0-0g0wWRUC.js.map +0 -1
  62. package/dist/LoginWithAuth0-C82OCyDy.cjs.map +0 -1
  63. package/dist/converters-DP2EIVv6.cjs +0 -108
  64. package/dist/converters-DP2EIVv6.cjs.map +0 -1
  65. package/dist/converters-DY6Lf7mb.js +0 -66
  66. package/dist/converters-DY6Lf7mb.js.map +0 -1
@@ -1,6 +1,12 @@
1
- const require_LoginWithAuth0 = require('../../LoginWithAuth0-C82OCyDy.cjs');
1
+ const require_LoginWithAuth0 = require('../../LoginWithAuth0-DaPnTz2I.cjs');
2
2
  let axios = require("axios");
3
3
  axios = require_LoginWithAuth0.__toESM(axios);
4
+ let mobx = require("mobx");
5
+ mobx = require_LoginWithAuth0.__toESM(mobx);
6
+ let three = require("three");
7
+ three = require_LoginWithAuth0.__toESM(three);
8
+ let three_src_math_Vector3_js = require("three/src/math/Vector3.js");
9
+ three_src_math_Vector3_js = require_LoginWithAuth0.__toESM(three_src_math_Vector3_js);
4
10
  let url_join = require("url-join");
5
11
  url_join = require_LoginWithAuth0.__toESM(url_join);
6
12
  let path_to_regexp = require("path-to-regexp");
@@ -8,6 +14,233 @@ path_to_regexp = require_LoginWithAuth0.__toESM(path_to_regexp);
8
14
  let __wandelbots_nova_api_v2 = require("@wandelbots/nova-api/v2");
9
15
  __wandelbots_nova_api_v2 = require_LoginWithAuth0.__toESM(__wandelbots_nova_api_v2);
10
16
 
17
+ //#region src/lib/v2/motionStateUpdate.ts
18
+ function jointValuesEqual(oldJointValues, newJointValues, changeDeltaThreshold) {
19
+ if (newJointValues.length !== oldJointValues.length) return true;
20
+ for (let jointIndex = 0; jointIndex < newJointValues.length; jointIndex++) if (Math.abs(newJointValues[jointIndex] - oldJointValues[jointIndex]) > changeDeltaThreshold) return false;
21
+ return true;
22
+ }
23
+ function poseEqual(oldTcp, newTcp, changeDeltaThreshold) {
24
+ if (oldTcp === void 0 && newTcp || oldTcp && newTcp === void 0) return false;
25
+ if (oldTcp?.orientation === void 0 || newTcp?.orientation === void 0 || oldTcp?.position === void 0 || newTcp?.position === void 0) return false;
26
+ if (oldTcp === void 0 || newTcp === void 0) return true;
27
+ let changedDelta = 0;
28
+ changedDelta += Math.abs(oldTcp.orientation[0] - newTcp.orientation[0]);
29
+ changedDelta += Math.abs(oldTcp.orientation[1] - newTcp.orientation[1]);
30
+ changedDelta += Math.abs(oldTcp.orientation[2] - newTcp.orientation[2]);
31
+ changedDelta += Math.abs(oldTcp.position[0] - newTcp.position[0]);
32
+ changedDelta += Math.abs(oldTcp.position[1] - newTcp.position[1]);
33
+ changedDelta += Math.abs(oldTcp.position[2] - newTcp.position[2]);
34
+ return changedDelta <= changeDeltaThreshold;
35
+ }
36
+ function tcpMotionEqual(oldMotionState, newMotionState, changeDeltaThreshold) {
37
+ return oldMotionState.coordinate_system === newMotionState.coordinate_system && oldMotionState.tcp === newMotionState.tcp && poseEqual(oldMotionState.tcp_pose, newMotionState.tcp_pose, changeDeltaThreshold);
38
+ }
39
+
40
+ //#endregion
41
+ //#region src/lib/v2/ConnectedMotionGroup.ts
42
+ const MOTION_DELTA_THRESHOLD$1 = 1e-4;
43
+ /**
44
+ * Store representing the current state of a connected motion group.
45
+ */
46
+ var ConnectedMotionGroup = class ConnectedMotionGroup {
47
+ static async connect(nova, motionGroupId) {
48
+ const [_motionGroupIndex, controllerId] = motionGroupId.split("@");
49
+ const controller = await nova.api.controller.getCurrentRobotControllerState(controllerId);
50
+ const motionGroup = controller?.motion_groups.find((mg) => mg.motion_group === motionGroupId);
51
+ if (!controller || !motionGroup) throw new Error(`Controller ${controllerId} or motion group ${motionGroupId} not found`);
52
+ const motionStateSocket = nova.openReconnectingWebsocket(`/controllers/${controllerId}/motion-groups/${motionGroupId}/state-stream`);
53
+ const firstMessage = await motionStateSocket.firstMessage();
54
+ const initialMotionState = require_LoginWithAuth0.tryParseJson(firstMessage.data)?.result;
55
+ if (!initialMotionState) throw new Error(`Unable to parse initial motion state message ${firstMessage.data}`);
56
+ console.log(`Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state:\n `, initialMotionState);
57
+ const isVirtual = (await nova.api.controller.getRobotController(controller.controller)).configuration.kind === "VirtualController";
58
+ const description = await nova.api.motionGroup.getMotionGroupDescription(controllerId, motionGroup.motion_group);
59
+ const tcps = Object.entries(description.tcps || {}).map(([id, tcp]) => ({
60
+ id,
61
+ readable_name: tcp.name,
62
+ position: tcp.pose.position,
63
+ orientation: tcp.pose.orientation
64
+ }));
65
+ const controllerStateSocket = nova.openReconnectingWebsocket(`/controllers/${controller.controller}/state-stream?response_rate=1000`);
66
+ const firstControllerMessage = await controllerStateSocket.firstMessage();
67
+ const initialControllerState = require_LoginWithAuth0.tryParseJson(firstControllerMessage.data)?.result;
68
+ if (!initialControllerState) throw new Error(`Unable to parse initial controller state message ${firstControllerMessage.data}`);
69
+ console.log(`Connected controller state websocket to controller ${controller.controller}. Initial state:\n `, initialControllerState);
70
+ return new ConnectedMotionGroup(nova, controller, motionGroup, initialMotionState, motionStateSocket, isVirtual, tcps, description, initialControllerState, controllerStateSocket);
71
+ }
72
+ constructor(nova, controller, motionGroup, initialMotionState, motionStateSocket, isVirtual, tcps, description, initialControllerState, controllerStateSocket) {
73
+ this.nova = nova;
74
+ this.controller = controller;
75
+ this.motionGroup = motionGroup;
76
+ this.initialMotionState = initialMotionState;
77
+ this.motionStateSocket = motionStateSocket;
78
+ this.isVirtual = isVirtual;
79
+ this.tcps = tcps;
80
+ this.description = description;
81
+ this.initialControllerState = initialControllerState;
82
+ this.controllerStateSocket = controllerStateSocket;
83
+ this.connectedJoggingSocket = null;
84
+ this.joggingVelocity = 10;
85
+ this.activationState = "inactive";
86
+ this.rapidlyChangingMotionState = initialMotionState;
87
+ this.controllerState = initialControllerState;
88
+ controllerStateSocket.addEventListener("message", (event) => {
89
+ const data = require_LoginWithAuth0.tryParseJson(event.data)?.result;
90
+ if (!data) return;
91
+ (0, mobx.runInAction)(() => {
92
+ this.controllerState = data;
93
+ });
94
+ });
95
+ motionStateSocket.addEventListener("message", (event) => {
96
+ const latestMotionState = require_LoginWithAuth0.tryParseJson(event.data)?.result;
97
+ if (!latestMotionState) throw new Error(`Failed to get motion state for ${this.motionGroupId}: ${event.data}`);
98
+ if (!jointValuesEqual(this.rapidlyChangingMotionState.joint_position, latestMotionState.joint_position, MOTION_DELTA_THRESHOLD$1)) (0, mobx.runInAction)(() => {
99
+ this.rapidlyChangingMotionState = latestMotionState;
100
+ });
101
+ if (!tcpMotionEqual(this.rapidlyChangingMotionState, latestMotionState, MOTION_DELTA_THRESHOLD$1)) (0, mobx.runInAction)(() => {
102
+ this.rapidlyChangingMotionState.tcp_pose = latestMotionState.tcp_pose;
103
+ });
104
+ if (this.rapidlyChangingMotionState.standstill !== latestMotionState.standstill) (0, mobx.runInAction)(() => {
105
+ this.rapidlyChangingMotionState.standstill = latestMotionState.standstill;
106
+ });
107
+ });
108
+ (0, mobx.makeAutoObservable)(this);
109
+ }
110
+ get motionGroupId() {
111
+ return this.motionGroup.motion_group;
112
+ }
113
+ get controllerId() {
114
+ return this.controller.controller;
115
+ }
116
+ get modelFromController() {
117
+ return this.description.motion_group_model;
118
+ }
119
+ get wandelscriptIdentifier() {
120
+ const num = this.motionGroupId.split("@")[0];
121
+ return `${this.controllerId.replaceAll("-", "_")}_${num}`;
122
+ }
123
+ /** Jogging velocity in radians for rotation and joint movement */
124
+ get joggingVelocityRads() {
125
+ return this.joggingVelocity * Math.PI / 180;
126
+ }
127
+ get joints() {
128
+ return this.initialMotionState.joint_position.map((_, i) => {
129
+ return { index: i };
130
+ });
131
+ }
132
+ get dhParameters() {
133
+ return this.description.dh_parameters;
134
+ }
135
+ get safetyZones() {
136
+ return this.description.safety_zones;
137
+ }
138
+ /** Gets the robot mounting position offset in 3D viz coordinates */
139
+ get mountingPosition() {
140
+ if (!this.description.mounting) return [
141
+ 0,
142
+ 0,
143
+ 0
144
+ ];
145
+ return [
146
+ (this.description.mounting.position?.[0] || 0) / 1e3,
147
+ (this.description.mounting.position?.[1] || 0) / 1e3,
148
+ (this.description.mounting.position?.[2] || 0) / 1e3
149
+ ];
150
+ }
151
+ /** Gets the robot mounting position rotation in 3D viz coordinates */
152
+ get mountingQuaternion() {
153
+ const rotationVector = new three.Vector3(this.description.mounting?.orientation?.[0] || 0, this.description.mounting?.orientation?.[1] || 0, this.description.mounting?.orientation?.[2] || 0);
154
+ const magnitude = rotationVector.length();
155
+ const axis = rotationVector.normalize();
156
+ return new three.Quaternion().setFromAxisAngle(axis, magnitude);
157
+ }
158
+ /**
159
+ * Whether the controller is currently in a safety state
160
+ * corresponding to an emergency stop
161
+ */
162
+ get isEstopActive() {
163
+ return ["SAFETY_STATE_ROBOT_EMERGENCY_STOP", "SAFETY_STATE_DEVICE_EMERGENCY_STOP"].includes(this.controllerState.safety_state);
164
+ }
165
+ /**
166
+ * Whether the controller is in a safety state
167
+ * that may be non-functional for robot pad purposes
168
+ */
169
+ get isMoveableSafetyState() {
170
+ return ["SAFETY_STATE_NORMAL", "SAFETY_STATE_REDUCED"].includes(this.controllerState.safety_state);
171
+ }
172
+ /**
173
+ * Whether the controller is in an operation mode that allows movement
174
+ */
175
+ get isMoveableOperationMode() {
176
+ return [
177
+ "OPERATION_MODE_AUTO",
178
+ "OPERATION_MODE_MANUAL",
179
+ "OPERATION_MODE_MANUAL_T1",
180
+ "OPERATION_MODE_MANUAL_T2"
181
+ ].includes(this.controllerState.operation_mode);
182
+ }
183
+ /**
184
+ * Whether the robot is currently active and can be moved, based on the
185
+ * safety state, operation mode and servo toggle activation state.
186
+ */
187
+ get canBeMoved() {
188
+ return this.isMoveableSafetyState && this.isMoveableOperationMode && this.activationState === "active";
189
+ }
190
+ async deactivate() {
191
+ if (this.activationState !== "active") {
192
+ console.error("Tried to deactivate while already deactivating");
193
+ return;
194
+ }
195
+ (0, mobx.runInAction)(() => {
196
+ this.activationState = "deactivating";
197
+ });
198
+ try {
199
+ await this.nova.api.controller.setDefaultMode(this.controllerId, "ROBOT_SYSTEM_MODE_MONITOR");
200
+ (0, mobx.runInAction)(() => {
201
+ this.activationState = "inactive";
202
+ });
203
+ } catch (err) {
204
+ (0, mobx.runInAction)(() => {
205
+ this.activationState = "active";
206
+ });
207
+ throw err;
208
+ }
209
+ }
210
+ async activate() {
211
+ if (this.activationState !== "inactive") {
212
+ console.error("Tried to activate while already activating");
213
+ return;
214
+ }
215
+ (0, mobx.runInAction)(() => {
216
+ this.activationState = "activating";
217
+ });
218
+ try {
219
+ await this.nova.api.controller.setDefaultMode(this.controllerId, "ROBOT_SYSTEM_MODE_CONTROL");
220
+ (0, mobx.runInAction)(() => {
221
+ this.activationState = "active";
222
+ });
223
+ } catch (err) {
224
+ (0, mobx.runInAction)(() => {
225
+ this.activationState = "inactive";
226
+ });
227
+ throw err;
228
+ }
229
+ }
230
+ toggleActivation() {
231
+ if (this.activationState === "inactive") this.activate();
232
+ else if (this.activationState === "active") this.deactivate();
233
+ }
234
+ dispose() {
235
+ this.motionStateSocket.close();
236
+ if (this.connectedJoggingSocket) this.connectedJoggingSocket.close();
237
+ }
238
+ setJoggingVelocity(velocity) {
239
+ this.joggingVelocity = velocity;
240
+ }
241
+ };
242
+
243
+ //#endregion
11
244
  //#region src/lib/v2/NovaCellAPIClient.ts
12
245
  /**
13
246
  * API client providing type-safe access to all the Nova API REST endpoints
@@ -81,7 +314,6 @@ var NovaCellAPIClient = class {
81
314
  //#endregion
82
315
  //#region src/lib/v2/mock/MockNovaInstance.ts
83
316
  /**
84
- * EXPERIMENTAL
85
317
  * Ultra-simplified mock Nova server for testing stuff
86
318
  */
87
319
  var MockNovaInstance = class {
@@ -90,6 +322,437 @@ var MockNovaInstance = class {
90
322
  }
91
323
  async handleAPIRequest(config) {
92
324
  const apiHandlers = [
325
+ {
326
+ method: "GET",
327
+ path: "/cells/:cellId/controllers/:controllerId/state",
328
+ handle() {
329
+ return {
330
+ mode: "MODE_CONTROL",
331
+ last_error: [],
332
+ timestamp: "2025-10-16T09:19:26.634534092Z",
333
+ sequence_number: 1054764,
334
+ controller: "mock-ur5e",
335
+ operation_mode: "OPERATION_MODE_AUTO",
336
+ safety_state: "SAFETY_STATE_NORMAL",
337
+ velocity_override: 100,
338
+ motion_groups: [{
339
+ timestamp: "2025-10-16T09:19:26.634534092Z",
340
+ sequence_number: 1054764,
341
+ motion_group: "0@mock-ur5e",
342
+ controller: "mock-ur5e",
343
+ joint_position: [
344
+ 1.487959623336792,
345
+ -1.8501918315887451,
346
+ 1.8003005981445312,
347
+ 6.034560203552246,
348
+ 1.4921919107437134,
349
+ 1.593459963798523
350
+ ],
351
+ joint_limit_reached: { limit_reached: [
352
+ false,
353
+ false,
354
+ false,
355
+ false,
356
+ false,
357
+ false
358
+ ] },
359
+ joint_torque: [],
360
+ joint_current: [
361
+ 0,
362
+ 0,
363
+ 0,
364
+ 0,
365
+ 0,
366
+ 0
367
+ ],
368
+ flange_pose: {
369
+ position: [
370
+ 107.6452433732927,
371
+ -409.0402987746852,
372
+ 524.2402132330305
373
+ ],
374
+ orientation: [
375
+ .9874434028353319,
376
+ -.986571714997442,
377
+ 1.3336589451098142
378
+ ]
379
+ },
380
+ tcp: "Flange",
381
+ tcp_pose: {
382
+ position: [
383
+ 107.6452433732927,
384
+ -409.0402987746852,
385
+ 524.2402132330305
386
+ ],
387
+ orientation: [
388
+ .9874434028353319,
389
+ -.986571714997442,
390
+ 1.3336589451098142
391
+ ]
392
+ },
393
+ payload: "",
394
+ coordinate_system: "",
395
+ standstill: true
396
+ }]
397
+ };
398
+ }
399
+ },
400
+ {
401
+ method: "GET",
402
+ path: "/cells/:cellId/controllers/:controllerId/motion-groups/:motionGroupId/description",
403
+ handle() {
404
+ return {
405
+ motion_group_model: "UniversalRobots_UR5e",
406
+ mounting: {
407
+ position: [
408
+ 0,
409
+ 0,
410
+ 0
411
+ ],
412
+ orientation: [
413
+ 0,
414
+ 0,
415
+ 0
416
+ ]
417
+ },
418
+ tcps: {
419
+ Flange: {
420
+ name: "Default-Flange",
421
+ pose: {
422
+ position: [
423
+ 0,
424
+ 0,
425
+ 0
426
+ ],
427
+ orientation: [
428
+ 0,
429
+ 0,
430
+ 0
431
+ ]
432
+ }
433
+ },
434
+ "complex-tcp-position": {
435
+ name: "Complex TCP Position",
436
+ pose: {
437
+ position: [
438
+ -200,
439
+ 300,
440
+ 150
441
+ ],
442
+ orientation: [
443
+ -.12139440409113832,
444
+ -.06356210998212003,
445
+ -.2023240068185639
446
+ ]
447
+ }
448
+ },
449
+ "offset-150mm-xy": {
450
+ name: "-150mm XY Offset",
451
+ pose: {
452
+ position: [
453
+ -150,
454
+ -150,
455
+ 0
456
+ ],
457
+ orientation: [
458
+ 0,
459
+ 0,
460
+ 0
461
+ ]
462
+ }
463
+ },
464
+ "rotated-90deg-z": {
465
+ name: "90° Z Axis Rotation",
466
+ pose: {
467
+ position: [
468
+ 0,
469
+ 0,
470
+ 0
471
+ ],
472
+ orientation: [
473
+ 0,
474
+ 0,
475
+ 1.5708
476
+ ]
477
+ }
478
+ }
479
+ },
480
+ payloads: { "FPay-0": {
481
+ name: "FPay-0",
482
+ payload: 0,
483
+ center_of_mass: [
484
+ 0,
485
+ 0,
486
+ 0
487
+ ],
488
+ moment_of_inertia: [
489
+ 0,
490
+ 0,
491
+ 0
492
+ ]
493
+ } },
494
+ cycle_time: 8,
495
+ dh_parameters: [
496
+ {
497
+ alpha: 1.5707963267948966,
498
+ d: 162.25
499
+ },
500
+ { a: -425 },
501
+ { a: -392.2 },
502
+ {
503
+ alpha: 1.5707963267948966,
504
+ d: 133.3
505
+ },
506
+ {
507
+ alpha: -1.5707963267948966,
508
+ d: 99.7
509
+ },
510
+ { d: 99.6 }
511
+ ],
512
+ operation_limits: {
513
+ auto_limits: {
514
+ joints: [
515
+ {
516
+ position: {
517
+ lower_limit: -6.283185307179586,
518
+ upper_limit: 6.283185307179586
519
+ },
520
+ velocity: 3.34159255027771,
521
+ acceleration: 40,
522
+ torque: 150
523
+ },
524
+ {
525
+ position: {
526
+ lower_limit: -6.283185307179586,
527
+ upper_limit: 6.283185307179586
528
+ },
529
+ velocity: 3.34159255027771,
530
+ acceleration: 40,
531
+ torque: 150
532
+ },
533
+ {
534
+ position: {
535
+ lower_limit: -6.283185307179586,
536
+ upper_limit: 6.283185307179586
537
+ },
538
+ velocity: 3.34159255027771,
539
+ acceleration: 40,
540
+ torque: 150
541
+ },
542
+ {
543
+ position: {
544
+ lower_limit: -6.283185307179586,
545
+ upper_limit: 6.283185307179586
546
+ },
547
+ velocity: 3.34159255027771,
548
+ acceleration: 40,
549
+ torque: 28
550
+ },
551
+ {
552
+ position: {
553
+ lower_limit: -6.283185307179586,
554
+ upper_limit: 6.283185307179586
555
+ },
556
+ velocity: 3.34159255027771,
557
+ acceleration: 40,
558
+ torque: 28
559
+ },
560
+ {
561
+ position: {
562
+ lower_limit: -6.283185307179586,
563
+ upper_limit: 6.283185307179586
564
+ },
565
+ velocity: 3.34159255027771,
566
+ acceleration: 40,
567
+ torque: 28
568
+ }
569
+ ],
570
+ tcp: { velocity: 5e3 },
571
+ elbow: { velocity: 5e3 },
572
+ flange: { velocity: 5e3 }
573
+ },
574
+ manual_limits: {
575
+ joints: [
576
+ {
577
+ position: {
578
+ lower_limit: -6.283185307179586,
579
+ upper_limit: 6.283185307179586
580
+ },
581
+ velocity: 3.34159255027771,
582
+ acceleration: 40,
583
+ torque: 150
584
+ },
585
+ {
586
+ position: {
587
+ lower_limit: -6.283185307179586,
588
+ upper_limit: 6.283185307179586
589
+ },
590
+ velocity: 3.34159255027771,
591
+ acceleration: 40,
592
+ torque: 150
593
+ },
594
+ {
595
+ position: {
596
+ lower_limit: -6.283185307179586,
597
+ upper_limit: 6.283185307179586
598
+ },
599
+ velocity: 3.34159255027771,
600
+ acceleration: 40,
601
+ torque: 150
602
+ },
603
+ {
604
+ position: {
605
+ lower_limit: -6.283185307179586,
606
+ upper_limit: 6.283185307179586
607
+ },
608
+ velocity: 3.34159255027771,
609
+ acceleration: 40,
610
+ torque: 28
611
+ },
612
+ {
613
+ position: {
614
+ lower_limit: -6.283185307179586,
615
+ upper_limit: 6.283185307179586
616
+ },
617
+ velocity: 3.34159255027771,
618
+ acceleration: 40,
619
+ torque: 28
620
+ },
621
+ {
622
+ position: {
623
+ lower_limit: -6.283185307179586,
624
+ upper_limit: 6.283185307179586
625
+ },
626
+ velocity: 3.34159255027771,
627
+ acceleration: 40,
628
+ torque: 28
629
+ }
630
+ ],
631
+ tcp: { velocity: 5e3 }
632
+ },
633
+ manual_t1_limits: {
634
+ joints: [
635
+ {
636
+ position: {
637
+ lower_limit: -6.283185307179586,
638
+ upper_limit: 6.283185307179586
639
+ },
640
+ velocity: 3.34159255027771,
641
+ acceleration: 40,
642
+ torque: 150
643
+ },
644
+ {
645
+ position: {
646
+ lower_limit: -6.283185307179586,
647
+ upper_limit: 6.283185307179586
648
+ },
649
+ velocity: 3.34159255027771,
650
+ acceleration: 40,
651
+ torque: 150
652
+ },
653
+ {
654
+ position: {
655
+ lower_limit: -6.283185307179586,
656
+ upper_limit: 6.283185307179586
657
+ },
658
+ velocity: 3.34159255027771,
659
+ acceleration: 40,
660
+ torque: 150
661
+ },
662
+ {
663
+ position: {
664
+ lower_limit: -6.283185307179586,
665
+ upper_limit: 6.283185307179586
666
+ },
667
+ velocity: 3.34159255027771,
668
+ acceleration: 40,
669
+ torque: 28
670
+ },
671
+ {
672
+ position: {
673
+ lower_limit: -6.283185307179586,
674
+ upper_limit: 6.283185307179586
675
+ },
676
+ velocity: 3.34159255027771,
677
+ acceleration: 40,
678
+ torque: 28
679
+ },
680
+ {
681
+ position: {
682
+ lower_limit: -6.283185307179586,
683
+ upper_limit: 6.283185307179586
684
+ },
685
+ velocity: 3.34159255027771,
686
+ acceleration: 40,
687
+ torque: 28
688
+ }
689
+ ],
690
+ tcp: { velocity: 5e3 }
691
+ },
692
+ manual_t2_limits: {
693
+ joints: [
694
+ {
695
+ position: {
696
+ lower_limit: -6.283185307179586,
697
+ upper_limit: 6.283185307179586
698
+ },
699
+ velocity: 3.34159255027771,
700
+ acceleration: 40,
701
+ torque: 150
702
+ },
703
+ {
704
+ position: {
705
+ lower_limit: -6.283185307179586,
706
+ upper_limit: 6.283185307179586
707
+ },
708
+ velocity: 3.34159255027771,
709
+ acceleration: 40,
710
+ torque: 150
711
+ },
712
+ {
713
+ position: {
714
+ lower_limit: -6.283185307179586,
715
+ upper_limit: 6.283185307179586
716
+ },
717
+ velocity: 3.34159255027771,
718
+ acceleration: 40,
719
+ torque: 150
720
+ },
721
+ {
722
+ position: {
723
+ lower_limit: -6.283185307179586,
724
+ upper_limit: 6.283185307179586
725
+ },
726
+ velocity: 3.34159255027771,
727
+ acceleration: 40,
728
+ torque: 28
729
+ },
730
+ {
731
+ position: {
732
+ lower_limit: -6.283185307179586,
733
+ upper_limit: 6.283185307179586
734
+ },
735
+ velocity: 3.34159255027771,
736
+ acceleration: 40,
737
+ torque: 28
738
+ },
739
+ {
740
+ position: {
741
+ lower_limit: -6.283185307179586,
742
+ upper_limit: 6.283185307179586
743
+ },
744
+ velocity: 3.34159255027771,
745
+ acceleration: 40,
746
+ torque: 28
747
+ }
748
+ ],
749
+ tcp: { velocity: 5e3 }
750
+ }
751
+ },
752
+ serial_number: "WBVirtualRobot"
753
+ };
754
+ }
755
+ },
93
756
  {
94
757
  method: "GET",
95
758
  path: "/cells/:cellId/controllers",
@@ -1256,6 +1919,380 @@ const defaultMotionState = { result: {
1256
1919
  }
1257
1920
  } };
1258
1921
 
1922
+ //#endregion
1923
+ //#region src/lib/v2/MotionStreamConnection.ts
1924
+ const MOTION_DELTA_THRESHOLD = 1e-4;
1925
+ function unwrapRotationVector(newRotationVectorApi, currentRotationVectorApi) {
1926
+ const currentRotationVector = new three.Vector3(currentRotationVectorApi[0], currentRotationVectorApi[1], currentRotationVectorApi[2]);
1927
+ const newRotationVector = new three.Vector3(newRotationVectorApi[0], newRotationVectorApi[1], newRotationVectorApi[2]);
1928
+ const currentAngle = currentRotationVector.length();
1929
+ const currentAxis = currentRotationVector.normalize();
1930
+ let newAngle = newRotationVector.length();
1931
+ let newAxis = newRotationVector.normalize();
1932
+ if (newAxis.dot(currentAxis) < 0) {
1933
+ newAngle = -newAngle;
1934
+ newAxis = newAxis.multiplyScalar(-1);
1935
+ }
1936
+ let angleDifference = newAngle - currentAngle;
1937
+ angleDifference -= 2 * Math.PI * Math.floor((angleDifference + Math.PI) / (2 * Math.PI));
1938
+ newAngle = currentAngle + angleDifference;
1939
+ return [...newAxis.multiplyScalar(newAngle)];
1940
+ }
1941
+ /**
1942
+ * Store representing the current state of a connected motion group.
1943
+ */
1944
+ var MotionStreamConnection = class MotionStreamConnection {
1945
+ static async open(nova, motionGroupId) {
1946
+ const [_motionGroupIndex, controllerId] = motionGroupId.split("@");
1947
+ const controller = await nova.api.controller.getCurrentRobotControllerState(controllerId);
1948
+ const motionGroup = controller?.motion_groups.find((mg) => mg.motion_group === motionGroupId);
1949
+ if (!controller || !motionGroup) throw new Error(`Controller ${controllerId} or motion group ${motionGroupId} not found`);
1950
+ const motionStateSocket = nova.openReconnectingWebsocket(`/controllers/${controllerId}/motion-groups/${motionGroupId}/state-stream`);
1951
+ const firstMessage = await motionStateSocket.firstMessage();
1952
+ const initialMotionState = require_LoginWithAuth0.tryParseJson(firstMessage.data)?.result;
1953
+ if (!initialMotionState) throw new Error(`Unable to parse initial motion state message ${firstMessage.data}`);
1954
+ console.log(`Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state:\n `, initialMotionState);
1955
+ return new MotionStreamConnection(nova, controller, motionGroup, await nova.api.motionGroup.getMotionGroupDescription(controllerId, motionGroup.motion_group), initialMotionState, motionStateSocket);
1956
+ }
1957
+ constructor(nova, controller, motionGroup, description, initialMotionState, motionStateSocket) {
1958
+ this.nova = nova;
1959
+ this.controller = controller;
1960
+ this.motionGroup = motionGroup;
1961
+ this.description = description;
1962
+ this.initialMotionState = initialMotionState;
1963
+ this.motionStateSocket = motionStateSocket;
1964
+ this.rapidlyChangingMotionState = initialMotionState;
1965
+ motionStateSocket.addEventListener("message", (event) => {
1966
+ const latestMotionState = require_LoginWithAuth0.tryParseJson(event.data)?.result;
1967
+ if (!latestMotionState) throw new Error(`Failed to get motion state for ${this.motionGroupId}: ${event.data}`);
1968
+ if (!jointValuesEqual(this.rapidlyChangingMotionState.joint_position, latestMotionState.joint_position, MOTION_DELTA_THRESHOLD)) (0, mobx.runInAction)(() => {
1969
+ this.rapidlyChangingMotionState = latestMotionState;
1970
+ });
1971
+ if (!tcpMotionEqual(this.rapidlyChangingMotionState, latestMotionState, MOTION_DELTA_THRESHOLD)) (0, mobx.runInAction)(() => {
1972
+ if (this.rapidlyChangingMotionState.tcp_pose == null) this.rapidlyChangingMotionState.tcp_pose = latestMotionState.tcp_pose;
1973
+ else if (latestMotionState.tcp_pose?.orientation && latestMotionState.tcp_pose?.position && this.rapidlyChangingMotionState.tcp_pose?.orientation) this.rapidlyChangingMotionState.tcp_pose = {
1974
+ position: latestMotionState.tcp_pose.position,
1975
+ orientation: unwrapRotationVector(latestMotionState.tcp_pose.orientation, this.rapidlyChangingMotionState.tcp_pose.orientation)
1976
+ };
1977
+ else console.warn("Received incomplete tcp_pose, ignoring", latestMotionState.tcp_pose);
1978
+ });
1979
+ if (this.rapidlyChangingMotionState.standstill !== latestMotionState.standstill) (0, mobx.runInAction)(() => {
1980
+ this.rapidlyChangingMotionState.standstill = latestMotionState.standstill;
1981
+ });
1982
+ });
1983
+ (0, mobx.makeAutoObservable)(this);
1984
+ }
1985
+ get motionGroupId() {
1986
+ return this.motionGroup.motion_group;
1987
+ }
1988
+ get controllerId() {
1989
+ return this.controller.controller;
1990
+ }
1991
+ get wandelscriptIdentifier() {
1992
+ const num = this.motionGroupId.split("@")[0];
1993
+ return `${this.controllerId.replaceAll("-", "_")}_${num}`;
1994
+ }
1995
+ get joints() {
1996
+ return this.initialMotionState.joint_position.map((_, i) => {
1997
+ return { index: i };
1998
+ });
1999
+ }
2000
+ dispose() {
2001
+ this.motionStateSocket.close();
2002
+ }
2003
+ };
2004
+
2005
+ //#endregion
2006
+ //#region src/lib/v2/JoggerConnection.ts
2007
+ var JoggerConnection = class JoggerConnection {
2008
+ /**
2009
+ * Initialize the jogging connection using jogging endpoint or trajectory endpoint depending on the selected mode.
2010
+ *
2011
+ * @param nova - The Nova client instance
2012
+ * @param motionGroupId - The ID of the motion group to connect to
2013
+ * @param options - Configuration options for the jogger connection
2014
+ * @param options.mode - The jogging mode to initialize:
2015
+ * - "jogging": Continuous jogging mode with persistent websocket for real-time velocity commands
2016
+ * - "trajectory": Incremental jogging mode for fixed-distance motions via trajectory planning
2017
+ * - "off": No jogging enabled, all websockets closed (default)
2018
+ * @param options.timeout - Timeout in milliseconds for websocket initialization (default: 5000ms)
2019
+ * @param options.tcp - TCP frame to use for motions (default: from motion group)
2020
+ * //param options.coordinateSystem - Coordinate system for jogging commands (default: "world"). Please note: Currently not implemented
2021
+ * @param options.orientation - If set to "tool", jogging TcpVelocityRequest will use `use_tool_coordinate_system` option (default: "world")
2022
+ * @param options.onError - Error handler for websocket errors
2023
+ * @returns Promise resolving to initialized JoggerConnection instance
2024
+ */
2025
+ static async open(nova, motionGroupId, options = {}) {
2026
+ const jogger = new JoggerConnection(await nova.connectMotionStream(motionGroupId), options);
2027
+ await jogger.setJoggingMode(jogger.mode);
2028
+ return jogger;
2029
+ }
2030
+ constructor(motionStream, options = {}) {
2031
+ this.motionStream = motionStream;
2032
+ this.options = options;
2033
+ this.ENDPOINT_JOGGING = "/execution/jogging";
2034
+ this.ENDPOINT_TRAJECTORY = "/execution/trajectory";
2035
+ this.DEFAULT_MODE = "off";
2036
+ this.DEFAULT_TCP = "Flange";
2037
+ this.DEFAULT_INIT_TIMEOUT = 5e3;
2038
+ this.DEFAULT_ORIENTATION = "world";
2039
+ this.mode = "off";
2040
+ this.joggingSocket = null;
2041
+ this.trajectorySocket = null;
2042
+ this.timeout = this.DEFAULT_INIT_TIMEOUT;
2043
+ this.tcp = options?.tcp || motionStream.motionGroup.tcp || this.DEFAULT_TCP;
2044
+ this.orientation = options?.orientation || this.DEFAULT_ORIENTATION;
2045
+ this.timeout = options?.timeout || this.DEFAULT_INIT_TIMEOUT;
2046
+ this.mode = options?.mode || this.DEFAULT_MODE;
2047
+ this.onError = options?.onError;
2048
+ }
2049
+ async updateOptions(options) {
2050
+ if (options.tcp) this.tcp = options.tcp;
2051
+ if (options.timeout) this.timeout = options.timeout;
2052
+ if (options.mode) this.mode = options.mode;
2053
+ if (options.orientation) this.orientation = options.orientation;
2054
+ if (options.onError) this.onError = options.onError;
2055
+ this.setJoggingMode(this.mode, false);
2056
+ }
2057
+ get motionGroupId() {
2058
+ return this.motionStream.motionGroupId;
2059
+ }
2060
+ get nova() {
2061
+ return this.motionStream.nova;
2062
+ }
2063
+ get numJoints() {
2064
+ return this.motionStream.joints.length;
2065
+ }
2066
+ async stop() {
2067
+ if (this.joggingSocket) {
2068
+ const velocity = new Array(this.numJoints).fill(0);
2069
+ this.joggingSocket.sendJson({
2070
+ message_type: "JointVelocityRequest",
2071
+ velocity
2072
+ });
2073
+ }
2074
+ if (this.trajectorySocket) this.trajectorySocket.sendJson({ message_type: "PauseMovementRequest" });
2075
+ }
2076
+ async dispose() {
2077
+ const sockets = [this.joggingSocket, this.trajectorySocket].filter((s) => s !== null);
2078
+ sockets.forEach((s) => {
2079
+ s.dispose();
2080
+ });
2081
+ this.joggingSocket = null;
2082
+ this.trajectorySocket = null;
2083
+ return Promise.all(sockets.map((s) => s.closed()));
2084
+ }
2085
+ async setJoggingMode(mode, skipReinitializeIfSameMode = true) {
2086
+ if (this.mode === mode && skipReinitializeIfSameMode) return;
2087
+ this.dispose();
2088
+ this.mode = mode;
2089
+ if (this.mode === "jogging") return this.initializeJoggingWebsocket();
2090
+ }
2091
+ async initializeJoggingWebsocket() {
2092
+ return new Promise((resolve, reject) => {
2093
+ const connectionFailedTimeout = setTimeout(() => {
2094
+ reject(/* @__PURE__ */ new Error(`Jogging initialization timeout after ${this.timeout} seconds`));
2095
+ }, this.timeout);
2096
+ this.joggingSocket = this.nova.openReconnectingWebsocket(this.ENDPOINT_JOGGING);
2097
+ this.joggingSocket.addEventListener("message", (ev) => {
2098
+ const data = require_LoginWithAuth0.tryParseJson(ev.data);
2099
+ if (data?.result?.kind === "INITIALIZE_RECEIVED") {
2100
+ clearTimeout(connectionFailedTimeout);
2101
+ resolve();
2102
+ return;
2103
+ }
2104
+ if (data && "error" in data || data?.result?.kind === "MOTION_ERROR") {
2105
+ clearTimeout(connectionFailedTimeout);
2106
+ if (this.onError) this.onError(ev.data);
2107
+ else reject(new Error(ev.data));
2108
+ }
2109
+ });
2110
+ this.joggingSocket.sendJson({
2111
+ message_type: "InitializeJoggingRequest",
2112
+ motion_group: this.motionGroupId,
2113
+ tcp: this.tcp
2114
+ });
2115
+ });
2116
+ }
2117
+ /**
2118
+ * Jogging: Start rotation of a single robot joint at the specified velocity
2119
+ */
2120
+ async rotateJoints({ joint, direction, velocityRadsPerSec }) {
2121
+ if (!this.joggingSocket || this.mode !== "jogging") throw new Error("Joint jogging websocket not connected; create one by setting jogging mode to 'jogging'");
2122
+ const velocity = new Array(this.numJoints).fill(0);
2123
+ velocity[joint] = direction === "-" ? -velocityRadsPerSec : velocityRadsPerSec;
2124
+ this.joggingSocket.sendJson({
2125
+ message_type: "JointVelocityRequest",
2126
+ velocity
2127
+ });
2128
+ }
2129
+ /**
2130
+ * Jogging: Start the TCP moving along a specified axis at a given velocity
2131
+ */
2132
+ async translateTCP({ axis, direction, velocityMmPerSec }) {
2133
+ if (!this.joggingSocket || this.mode !== "jogging") throw new Error("Continuous jogging websocket not connected; create one by setting jogging mode to 'jogging'");
2134
+ const rotation = [
2135
+ 0,
2136
+ 0,
2137
+ 0
2138
+ ];
2139
+ const translation = [
2140
+ 0,
2141
+ 0,
2142
+ 0
2143
+ ];
2144
+ translation[require_LoginWithAuth0.XYZ_TO_VECTOR[axis]] = direction === "-" ? -velocityMmPerSec : velocityMmPerSec;
2145
+ this.joggingSocket.sendJson({
2146
+ message_type: "TcpVelocityRequest",
2147
+ translation,
2148
+ rotation,
2149
+ use_tool_coordinate_system: this.orientation === "tool"
2150
+ });
2151
+ }
2152
+ /**
2153
+ * Jogging: Start the TCP rotating around a specified axis at a given velocity
2154
+ */
2155
+ async rotateTCP({ axis, direction, velocityRadsPerSec }) {
2156
+ if (!this.joggingSocket || this.mode !== "jogging") throw new Error("Continuous jogging websocket not connected; create one by setting jogging mode to 'jogging'");
2157
+ const rotation = [
2158
+ 0,
2159
+ 0,
2160
+ 0
2161
+ ];
2162
+ const translation = [
2163
+ 0,
2164
+ 0,
2165
+ 0
2166
+ ];
2167
+ rotation[require_LoginWithAuth0.XYZ_TO_VECTOR[axis]] = direction === "-" ? -velocityRadsPerSec : velocityRadsPerSec;
2168
+ this.joggingSocket.sendJson({
2169
+ message_type: "TcpVelocityRequest",
2170
+ translation,
2171
+ rotation
2172
+ });
2173
+ }
2174
+ /**
2175
+ * Trajectory jogging:
2176
+ *
2177
+ * Move the robot by a fixed distance in a single cartesian
2178
+ * axis, either rotating or translating relative to the TCP.
2179
+ * Promise resolves only after the motion has completed.
2180
+ */
2181
+ async runIncrementalCartesianMotion({ currentTcpPose, currentJoints, coordSystemId, velocityInRelevantUnits, axis, direction, motion }) {
2182
+ const commands = [];
2183
+ if (this.mode !== "trajectory") throw new Error("Set jogging mode to 'trajectory' to run incremental cartesian motions");
2184
+ if (motion.type === "translate") {
2185
+ if (!currentTcpPose.position) throw new Error("Current pose has no position, cannot perform translation");
2186
+ const targetTcpPosition = [...currentTcpPose.position];
2187
+ targetTcpPosition[require_LoginWithAuth0.XYZ_TO_VECTOR[axis]] += motion.distanceMm * (direction === "-" ? -1 : 1);
2188
+ commands.push({
2189
+ limits_override: { tcp_velocity_limit: velocityInRelevantUnits },
2190
+ path: {
2191
+ path_definition_name: "PathLine",
2192
+ target_pose: {
2193
+ position: targetTcpPosition,
2194
+ orientation: currentTcpPose.orientation
2195
+ }
2196
+ }
2197
+ });
2198
+ } else if (motion.type === "rotate") {
2199
+ if (!currentTcpPose.orientation) throw new Error("Current pose has no orientation, cannot perform rotation");
2200
+ const currentRotationVector = new three_src_math_Vector3_js.Vector3(currentTcpPose.orientation[0], currentTcpPose.orientation[1], currentTcpPose.orientation[2]);
2201
+ const currentRotationRad = currentRotationVector.length();
2202
+ const currentRotationDirection = currentRotationVector.clone().normalize();
2203
+ const differenceRotationRad = motion.distanceRads * (direction === "-" ? -1 : 1);
2204
+ const differenceRotationDirection = new three_src_math_Vector3_js.Vector3(0, 0, 0);
2205
+ differenceRotationDirection[axis] = 1;
2206
+ const f1 = Math.cos(.5 * differenceRotationRad) * Math.cos(.5 * currentRotationRad);
2207
+ const f2 = Math.sin(.5 * differenceRotationRad) * Math.sin(.5 * currentRotationRad);
2208
+ const f3 = Math.sin(.5 * differenceRotationRad) * Math.cos(.5 * currentRotationRad);
2209
+ const f4 = Math.cos(.5 * differenceRotationRad) * Math.sin(.5 * currentRotationRad);
2210
+ const dotProduct = differenceRotationDirection.dot(currentRotationDirection);
2211
+ const crossProduct = differenceRotationDirection.clone().cross(currentRotationDirection);
2212
+ const newRotationRad = 2 * Math.acos(f1 - f2 * dotProduct);
2213
+ const f5 = newRotationRad / Math.sin(.5 * newRotationRad);
2214
+ const targetTcpOrientation = new three_src_math_Vector3_js.Vector3().addScaledVector(crossProduct, f2).addScaledVector(differenceRotationDirection, f3).addScaledVector(currentRotationDirection, f4).multiplyScalar(f5);
2215
+ commands.push({
2216
+ limits_override: { tcp_orientation_velocity_limit: velocityInRelevantUnits },
2217
+ path: {
2218
+ path_definition_name: "PathLine",
2219
+ target_pose: {
2220
+ position: currentTcpPose.position,
2221
+ orientation: [...targetTcpOrientation]
2222
+ }
2223
+ }
2224
+ });
2225
+ }
2226
+ const description = this.motionStream.description;
2227
+ if (description.cycle_time === void 0) {
2228
+ console.warn("Current motion group has no cycle time, cannot plan jogging motion");
2229
+ return;
2230
+ }
2231
+ const motion_group_setup = {
2232
+ motion_group_model: description.motion_group_model,
2233
+ cycle_time: description.cycle_time,
2234
+ mounting: description.mounting,
2235
+ global: description.operation_limits.auto_limits
2236
+ };
2237
+ const motionPlanRes = await this.nova.api.trajectoryPlanning.planTrajectory({
2238
+ motion_group_setup,
2239
+ start_joint_position: currentJoints,
2240
+ motion_commands: commands
2241
+ });
2242
+ const trajectoryData = motionPlanRes.response;
2243
+ if (!trajectoryData) throw new Error(`Failed to plan jogging increment motion ${JSON.stringify(motionPlanRes)}`);
2244
+ if (this.trajectorySocket) {
2245
+ console.warn("Trajectory jogging websocket already open; will close");
2246
+ this.trajectorySocket.dispose();
2247
+ }
2248
+ this.trajectorySocket = this.nova.openReconnectingWebsocket(this.ENDPOINT_TRAJECTORY);
2249
+ const messageInitializeMovementResponse = (result) => {
2250
+ if (!result || result.add_trajectory_error || result.message) if (this.onError) this.onError(result);
2251
+ else throw new Error(result?.add_trajectory_error?.message || result?.message || "Failed to execute trajectory, unknown error");
2252
+ if (!this.trajectorySocket) throw new Error(`Failed to execute trajectory, websocket not available anymore`);
2253
+ this.trajectorySocket.sendJson({
2254
+ message_type: "StartMovementRequest",
2255
+ direction: "DIRECTION_FORWARD"
2256
+ });
2257
+ };
2258
+ const waitForMovementToStartAndFinish = async () => {
2259
+ await (0, mobx.when)(() => !this.motionStream.rapidlyChangingMotionState.standstill);
2260
+ await (0, mobx.when)(() => this.motionStream.rapidlyChangingMotionState.standstill);
2261
+ this.trajectorySocket?.dispose();
2262
+ this.trajectorySocket = null;
2263
+ };
2264
+ const waitForMovementToFinish = async () => {
2265
+ await (0, mobx.when)(() => this.motionStream.rapidlyChangingMotionState.standstill);
2266
+ this.trajectorySocket?.dispose();
2267
+ this.trajectorySocket = null;
2268
+ };
2269
+ const messageStartMovementResponse = async (data) => {
2270
+ if (data?.message) if (this.onError) {
2271
+ this.onError(data);
2272
+ return;
2273
+ } else throw new Error(data.message || "Failed to execute trajectory, unknown error");
2274
+ if (this.motionStream.rapidlyChangingMotionState.standstill) await waitForMovementToStartAndFinish();
2275
+ else await waitForMovementToFinish();
2276
+ };
2277
+ this.trajectorySocket.addEventListener("message", (ev) => {
2278
+ const data = require_LoginWithAuth0.tryParseJson(ev.data);
2279
+ if (!data?.result?.kind) throw new Error(`Failed to execute trajectory: Received invalid message ${ev.data}`);
2280
+ if (data.result.kind === "INITIALIZE_RECEIVED") messageInitializeMovementResponse(data.result);
2281
+ else if (data.result.kind === "START_RECEIVED") messageStartMovementResponse(data);
2282
+ else throw new Error(`Failed to execute trajectory, cannot handle message type "${data.result.kind}"`);
2283
+ });
2284
+ this.trajectorySocket.sendJson({
2285
+ message_type: "InitializeMovementRequest",
2286
+ trajectory: {
2287
+ message_type: "TrajectoryData",
2288
+ motion_group: this.motionGroupId,
2289
+ data: trajectoryData,
2290
+ tcp: this.tcp
2291
+ }
2292
+ });
2293
+ }
2294
+ };
2295
+
1259
2296
  //#endregion
1260
2297
  //#region src/lib/v2/NovaClient.ts
1261
2298
  function permissiveInstanceUrlParse(url) {
@@ -1263,10 +2300,6 @@ function permissiveInstanceUrlParse(url) {
1263
2300
  return new URL(url).toString();
1264
2301
  }
1265
2302
  /**
1266
- * EXPERIMENTAL
1267
- *
1268
- * This client provides a starting point to migrate NOVA api v2.
1269
- * As v2 is still in development, this client has to be considered unstable
1270
2303
  *
1271
2304
  * Client for connecting to a Nova instance and controlling robots.
1272
2305
  */
@@ -1274,15 +2307,14 @@ var NovaClient = class {
1274
2307
  constructor(config) {
1275
2308
  this.authPromise = null;
1276
2309
  this.accessToken = null;
1277
- console.warn("Using experimental NOVA v2 client");
1278
2310
  const cellId = config.cellId ?? "cell";
1279
2311
  this.config = {
1280
2312
  cellId,
1281
- ...config,
1282
- instanceUrl: permissiveInstanceUrlParse(config.instanceUrl)
2313
+ ...config
1283
2314
  };
1284
2315
  this.accessToken = config.accessToken || require_LoginWithAuth0.availableStorage.getString("wbjs.access_token") || null;
1285
2316
  if (this.config.instanceUrl === "https://mock.example.com") this.mock = new MockNovaInstance();
2317
+ else this.config.instanceUrl = permissiveInstanceUrlParse(this.config.instanceUrl);
1286
2318
  const axiosInstance = axios.default.create({
1287
2319
  baseURL: (0, url_join.default)(this.config.instanceUrl, "/api/v2"),
1288
2320
  headers: typeof window !== "undefined" && window.location.origin.includes("localhost") ? {} : { "X-Wandelbots-Client": "Wandelbots-Nova-JS-SDK" }
@@ -1314,7 +2346,7 @@ var NovaClient = class {
1314
2346
  });
1315
2347
  this.api = new NovaCellAPIClient(cellId, {
1316
2348
  ...config,
1317
- basePath: (0, url_join.default)(this.config.instanceUrl, "/api/v1"),
2349
+ basePath: (0, url_join.default)(this.config.instanceUrl, "/api/v2"),
1318
2350
  isJsonMime: (mime) => {
1319
2351
  return mime === "application/json";
1320
2352
  },
@@ -1339,7 +2371,7 @@ var NovaClient = class {
1339
2371
  }
1340
2372
  }
1341
2373
  makeWebsocketURL(path) {
1342
- const url = new URL((0, url_join.default)(this.config.instanceUrl, `/api/v1/cells/${this.config.cellId}`, path));
2374
+ const url = new URL((0, url_join.default)(this.config.instanceUrl, `/api/v2/cells/${this.config.cellId}`, path));
1343
2375
  url.protocol = url.protocol.replace("http", "ws");
1344
2376
  url.protocol = url.protocol.replace("https", "wss");
1345
2377
  if (this.accessToken) url.searchParams.append("token", this.accessToken);
@@ -1357,11 +2389,55 @@ var NovaClient = class {
1357
2389
  openReconnectingWebsocket(path) {
1358
2390
  return new require_LoginWithAuth0.AutoReconnectingWebsocket(this.makeWebsocketURL(path), { mock: this.mock });
1359
2391
  }
2392
+ /**
2393
+ * Connect to the motion state websocket(s) for a given motion group
2394
+ */
2395
+ async connectMotionStream(motionGroupId) {
2396
+ return await MotionStreamConnection.open(this, motionGroupId);
2397
+ }
2398
+ /**
2399
+ * Connect to the jogging websocket(s) for a given motion group
2400
+ */
2401
+ async connectJogger(motionGroupId, options = {}) {
2402
+ return await JoggerConnection.open(this, motionGroupId, options);
2403
+ }
2404
+ async connectMotionGroups(motionGroupIds) {
2405
+ return Promise.all(motionGroupIds.map((motionGroupId) => ConnectedMotionGroup.connect(this, motionGroupId)));
2406
+ }
2407
+ async connectMotionGroup(motionGroupId) {
2408
+ return (await this.connectMotionGroups([motionGroupId]))[0];
2409
+ }
1360
2410
  };
1361
2411
 
1362
2412
  //#endregion
2413
+ //#region src/lib/v2/wandelscriptUtils.ts
2414
+ /**
2415
+ * Convert a Pose object representing a motion group position
2416
+ * into a string which represents that pose in Wandelscript.
2417
+ */
2418
+ function poseToWandelscriptString(pose) {
2419
+ const position = [
2420
+ pose.position?.[0] ?? 0,
2421
+ pose.position?.[1] ?? 0,
2422
+ pose.position?.[2] ?? 0
2423
+ ];
2424
+ const orientation = [
2425
+ pose.orientation?.[0] ?? 0,
2426
+ pose.orientation?.[1] ?? 0,
2427
+ pose.orientation?.[2] ?? 0
2428
+ ];
2429
+ const positionValues = position.map((v) => v.toFixed(1));
2430
+ const rotationValues = orientation.map((v) => v.toFixed(4));
2431
+ return `(${positionValues.concat(rotationValues).join(", ")})`;
2432
+ }
2433
+
2434
+ //#endregion
2435
+ exports.ConnectedMotionGroup = ConnectedMotionGroup;
2436
+ exports.JoggerConnection = JoggerConnection;
2437
+ exports.MotionStreamConnection = MotionStreamConnection;
1363
2438
  exports.NovaCellAPIClient = NovaCellAPIClient;
1364
2439
  exports.NovaClient = NovaClient;
2440
+ exports.poseToWandelscriptString = poseToWandelscriptString;
1365
2441
  Object.keys(__wandelbots_nova_api_v2).forEach(function (k) {
1366
2442
  if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1367
2443
  enumerable: true,