@wandelbots/nova-js 3.2.0 → 3.3.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 (104) hide show
  1. package/README.md +32 -136
  2. package/dist/AutoReconnectingWebsocket-Qcrbm3Kb.d.cts +69 -0
  3. package/dist/AutoReconnectingWebsocket-Qcrbm3Kb.d.cts.map +1 -0
  4. package/dist/AutoReconnectingWebsocket-dHe-kceU.d.mts +69 -0
  5. package/dist/AutoReconnectingWebsocket-dHe-kceU.d.mts.map +1 -0
  6. package/dist/LoginWithAuth0-CBD9BXXz.cjs +264 -0
  7. package/dist/LoginWithAuth0-CBD9BXXz.cjs.map +1 -0
  8. package/dist/LoginWithAuth0-wQB-Sol1.mjs +217 -0
  9. package/dist/LoginWithAuth0-wQB-Sol1.mjs.map +1 -0
  10. package/dist/NovaClient-B8XM3OPO.mjs +2057 -0
  11. package/dist/NovaClient-B8XM3OPO.mjs.map +1 -0
  12. package/dist/NovaClient-CV7ooIkD.d.cts +349 -0
  13. package/dist/NovaClient-CV7ooIkD.d.cts.map +1 -0
  14. package/dist/NovaClient-D2EItmiH.cjs +2137 -0
  15. package/dist/NovaClient-D2EItmiH.cjs.map +1 -0
  16. package/dist/NovaClient-qJnHcx2s.d.mts +349 -0
  17. package/dist/NovaClient-qJnHcx2s.d.mts.map +1 -0
  18. package/dist/index.cjs +42 -386
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.d.cts +73 -0
  21. package/dist/index.d.cts.map +1 -0
  22. package/dist/index.d.mts +73 -0
  23. package/dist/index.d.mts.map +1 -0
  24. package/dist/index.mjs +36 -0
  25. package/dist/index.mjs.map +1 -0
  26. package/dist/lib/v1/index.cjs +190 -2940
  27. package/dist/lib/v1/index.cjs.map +1 -1
  28. package/dist/lib/v1/index.d.cts +62 -0
  29. package/dist/lib/v1/index.d.cts.map +1 -0
  30. package/dist/lib/v1/index.d.mts +62 -0
  31. package/dist/lib/v1/index.d.mts.map +1 -0
  32. package/dist/lib/v1/index.mjs +182 -0
  33. package/dist/lib/v1/index.mjs.map +1 -0
  34. package/dist/lib/v2/index.cjs +1821 -1468
  35. package/dist/lib/v2/index.cjs.map +1 -1
  36. package/dist/lib/v2/index.d.cts +118 -0
  37. package/dist/lib/v2/index.d.cts.map +1 -0
  38. package/dist/lib/v2/index.d.mts +118 -0
  39. package/dist/lib/v2/index.d.mts.map +1 -0
  40. package/dist/lib/v2/index.mjs +1822 -0
  41. package/dist/lib/v2/index.mjs.map +1 -0
  42. package/package.json +21 -19
  43. package/src/LoginWithAuth0.ts +12 -12
  44. package/src/index.ts +2 -0
  45. package/src/lib/converters.ts +5 -23
  46. package/src/lib/v1/MotionStreamConnection.ts +0 -1
  47. package/src/lib/v1/NovaClient.ts +18 -0
  48. package/src/lib/v1/index.ts +6 -0
  49. package/src/lib/v1/mock/MockNovaInstance.ts +0 -1
  50. package/src/lib/v1/wandelscriptUtils.ts +22 -0
  51. package/src/lib/v2/NovaClient.ts +14 -7
  52. package/src/lib/v2/index.ts +1 -0
  53. package/src/lib/v2/mock/MockNovaInstance.ts +411 -21
  54. package/src/lib/v2/wandelscriptUtils.ts +27 -0
  55. package/dist/LoginWithAuth0.d.ts +0 -7
  56. package/dist/LoginWithAuth0.d.ts.map +0 -1
  57. package/dist/chunk-B2C22PTK.js +0 -53
  58. package/dist/chunk-B2C22PTK.js.map +0 -1
  59. package/dist/chunk-I3PUV6ZD.js +0 -286
  60. package/dist/chunk-I3PUV6ZD.js.map +0 -1
  61. package/dist/index.d.ts +0 -6
  62. package/dist/index.d.ts.map +0 -1
  63. package/dist/index.js +0 -60
  64. package/dist/index.js.map +0 -1
  65. package/dist/lib/AutoReconnectingWebsocket.d.ts +0 -43
  66. package/dist/lib/AutoReconnectingWebsocket.d.ts.map +0 -1
  67. package/dist/lib/availableStorage.d.ts +0 -15
  68. package/dist/lib/availableStorage.d.ts.map +0 -1
  69. package/dist/lib/converters.d.ts +0 -26
  70. package/dist/lib/converters.d.ts.map +0 -1
  71. package/dist/lib/errorHandling.d.ts +0 -15
  72. package/dist/lib/errorHandling.d.ts.map +0 -1
  73. package/dist/lib/v1/ConnectedMotionGroup.d.ts +0 -77
  74. package/dist/lib/v1/ConnectedMotionGroup.d.ts.map +0 -1
  75. package/dist/lib/v1/JoggerConnection.d.ts +0 -94
  76. package/dist/lib/v1/JoggerConnection.d.ts.map +0 -1
  77. package/dist/lib/v1/MotionStreamConnection.d.ts +0 -26
  78. package/dist/lib/v1/MotionStreamConnection.d.ts.map +0 -1
  79. package/dist/lib/v1/NovaCellAPIClient.d.ts +0 -68
  80. package/dist/lib/v1/NovaCellAPIClient.d.ts.map +0 -1
  81. package/dist/lib/v1/NovaClient.d.ts +0 -67
  82. package/dist/lib/v1/NovaClient.d.ts.map +0 -1
  83. package/dist/lib/v1/ProgramStateConnection.d.ts +0 -57
  84. package/dist/lib/v1/ProgramStateConnection.d.ts.map +0 -1
  85. package/dist/lib/v1/getLatestTrajectories.d.ts +0 -4
  86. package/dist/lib/v1/getLatestTrajectories.d.ts.map +0 -1
  87. package/dist/lib/v1/index.d.ts +0 -9
  88. package/dist/lib/v1/index.d.ts.map +0 -1
  89. package/dist/lib/v1/index.js +0 -2653
  90. package/dist/lib/v1/index.js.map +0 -1
  91. package/dist/lib/v1/mock/MockNovaInstance.d.ts +0 -13
  92. package/dist/lib/v1/mock/MockNovaInstance.d.ts.map +0 -1
  93. package/dist/lib/v1/motionStateUpdate.d.ts +0 -4
  94. package/dist/lib/v1/motionStateUpdate.d.ts.map +0 -1
  95. package/dist/lib/v2/NovaCellAPIClient.d.ts +0 -62
  96. package/dist/lib/v2/NovaCellAPIClient.d.ts.map +0 -1
  97. package/dist/lib/v2/NovaClient.d.ts +0 -60
  98. package/dist/lib/v2/NovaClient.d.ts.map +0 -1
  99. package/dist/lib/v2/index.d.ts +0 -4
  100. package/dist/lib/v2/index.d.ts.map +0 -1
  101. package/dist/lib/v2/index.js +0 -1196
  102. package/dist/lib/v2/index.js.map +0 -1
  103. package/dist/lib/v2/mock/MockNovaInstance.d.ts +0 -13
  104. package/dist/lib/v2/mock/MockNovaInstance.d.ts.map +0 -1
@@ -0,0 +1,2057 @@
1
+ import { n as availableStorage, r as AutoReconnectingWebsocket, t as loginWithAuth0 } from "./LoginWithAuth0-wQB-Sol1.mjs";
2
+ import axios, { AxiosError, isAxiosError } from "axios";
3
+ import urlJoin from "url-join";
4
+ import { makeAutoObservable, runInAction } from "mobx";
5
+ import * as THREE from "three";
6
+ import { Vector3 } from "three";
7
+ import { Vector3 as Vector3$1 } from "three/src/math/Vector3.js";
8
+ import { ApplicationApi, CellApi, ControllerApi, ControllerIOsApi, CoordinateSystemsApi, DeviceConfigurationApi, LibraryProgramApi, LibraryProgramMetadataApi, LibraryRecipeApi, LibraryRecipeMetadataApi, MotionApi, MotionGroupApi, MotionGroupInfosApi, MotionGroupJoggingApi, MotionGroupKinematicApi, ProgramApi, ProgramValuesApi, StoreCollisionComponentsApi, StoreCollisionScenesApi, StoreObjectApi, SystemApi, VirtualRobotApi, VirtualRobotBehaviorApi, VirtualRobotModeApi, VirtualRobotSetupApi } from "@wandelbots/nova-api/v1";
9
+ import * as pathToRegexp from "path-to-regexp";
10
+
11
+ //#region src/lib/converters.ts
12
+ /** Try to parse something as JSON; return undefined if we can't */
13
+ function tryParseJson(json) {
14
+ try {
15
+ return JSON.parse(json);
16
+ } catch {
17
+ return;
18
+ }
19
+ }
20
+ /** Try to turn something into JSON; return undefined if we can't */
21
+ function tryStringifyJson(json) {
22
+ try {
23
+ return JSON.stringify(json);
24
+ } catch {
25
+ return;
26
+ }
27
+ }
28
+ /**
29
+ * Converts object parameters to query string.
30
+ * e.g. { a: "1", b: "2" } => "?a=1&b=2"
31
+ * {} => ""
32
+ */
33
+ function makeUrlQueryString(obj) {
34
+ const str = new URLSearchParams(obj).toString();
35
+ return str ? `?${str}` : "";
36
+ }
37
+ /** Convert radians to degrees */
38
+ function radiansToDegrees(radians) {
39
+ return radians * (180 / Math.PI);
40
+ }
41
+ /** Convert degrees to radians */
42
+ function degreesToRadians(degrees) {
43
+ return degrees * (Math.PI / 180);
44
+ }
45
+ /**
46
+ * Check for coordinate system id equivalence, accounting for the "world" default
47
+ * on empty/undefined values.
48
+ */
49
+ function isSameCoordinateSystem(firstCoordSystem, secondCoordSystem) {
50
+ if (!firstCoordSystem) firstCoordSystem = "world";
51
+ if (!secondCoordSystem) secondCoordSystem = "world";
52
+ return firstCoordSystem === secondCoordSystem;
53
+ }
54
+ /**
55
+ * Helpful const for converting {x, y, z} to [x, y, z] and vice versa
56
+ */
57
+ const XYZ_TO_VECTOR = {
58
+ x: 0,
59
+ y: 1,
60
+ z: 2
61
+ };
62
+
63
+ //#endregion
64
+ //#region src/lib/v1/wandelscriptUtils.ts
65
+ /**
66
+ * Convert a Pose object representing a motion group position
67
+ * into a string which represents that pose in Wandelscript.
68
+ */
69
+ function poseToWandelscriptString(pose) {
70
+ const position = [
71
+ pose.position.x,
72
+ pose.position.y,
73
+ pose.position.z
74
+ ];
75
+ const orientation = [
76
+ pose.orientation?.x ?? 0,
77
+ pose.orientation?.y ?? 0,
78
+ pose.orientation?.z ?? 0
79
+ ];
80
+ const positionValues = position.map((v) => v.toFixed(1));
81
+ const rotationValues = orientation.map((v) => v.toFixed(4));
82
+ return `(${positionValues.concat(rotationValues).join(", ")})`;
83
+ }
84
+
85
+ //#endregion
86
+ //#region src/lib/v1/motionStateUpdate.ts
87
+ function jointValuesEqual(oldJointValues, newJointValues, changeDeltaThreshold) {
88
+ if (newJointValues.length !== oldJointValues.length) return true;
89
+ for (let jointIndex = 0; jointIndex < newJointValues.length; jointIndex++) if (Math.abs(newJointValues[jointIndex] - oldJointValues[jointIndex]) > changeDeltaThreshold) return false;
90
+ return true;
91
+ }
92
+ function tcpPoseEqual(oldTcp, newTcp, changeDeltaThreshold) {
93
+ if (oldTcp === void 0 && newTcp || oldTcp && newTcp === void 0) return false;
94
+ if (oldTcp === void 0 || newTcp === void 0) return true;
95
+ let changedDelta = 0;
96
+ changedDelta += Math.abs(oldTcp.orientation.x - newTcp.orientation.x);
97
+ changedDelta += Math.abs(oldTcp.orientation.y - newTcp.orientation.y);
98
+ changedDelta += Math.abs(oldTcp.orientation.z - newTcp.orientation.z);
99
+ changedDelta += Math.abs(oldTcp.position.x - newTcp.position.x);
100
+ changedDelta += Math.abs(oldTcp.position.y - newTcp.position.y);
101
+ changedDelta += Math.abs(oldTcp.position.z - newTcp.position.z);
102
+ if (changedDelta > changeDeltaThreshold) return false;
103
+ return oldTcp.coordinate_system === newTcp.coordinate_system && oldTcp.tcp === newTcp.tcp;
104
+ }
105
+
106
+ //#endregion
107
+ //#region src/lib/v1/ConnectedMotionGroup.ts
108
+ const MOTION_DELTA_THRESHOLD$1 = 1e-4;
109
+ /**
110
+ * Store representing the current state of a connected motion group.
111
+ */
112
+ var ConnectedMotionGroup = class ConnectedMotionGroup {
113
+ static async connect(nova, motionGroupId, controllers) {
114
+ const [_motionGroupIndex, controllerId] = motionGroupId.split("@");
115
+ const controller = controllers.find((c) => c.controller === controllerId);
116
+ const motionGroup = controller?.physical_motion_groups.find((mg) => mg.motion_group === motionGroupId);
117
+ if (!controller || !motionGroup) throw new Error(`Controller ${controllerId} or motion group ${motionGroupId} not found`);
118
+ const motionStateSocket = nova.openReconnectingWebsocket(`/motion-groups/${motionGroupId}/state-stream`);
119
+ const firstMessage = await motionStateSocket.firstMessage();
120
+ const initialMotionState = tryParseJson(firstMessage.data)?.result;
121
+ if (!initialMotionState) throw new Error(`Unable to parse initial motion state message ${firstMessage.data}`);
122
+ console.log(`Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state:\n `, initialMotionState);
123
+ const isVirtual = (await nova.api.controller.getRobotController(controller.controller)).configuration.kind === "VirtualController";
124
+ const mounting = await (async () => {
125
+ try {
126
+ return await nova.api.motionGroupInfos.getMounting(motionGroup.motion_group);
127
+ } catch (err) {
128
+ console.error(`Error fetching mounting for ${motionGroup.motion_group}`, err);
129
+ return null;
130
+ }
131
+ })();
132
+ const controllerStateSocket = nova.openReconnectingWebsocket(`/controllers/${controller.controller}/state-stream?response_rate=1000`);
133
+ const firstControllerMessage = await controllerStateSocket.firstMessage();
134
+ const initialControllerState = tryParseJson(firstControllerMessage.data)?.result;
135
+ if (!initialControllerState) throw new Error(`Unable to parse initial controller state message ${firstControllerMessage.data}`);
136
+ console.log(`Connected controller state websocket to controller ${controller.controller}. Initial state:\n `, initialControllerState);
137
+ const { tcps } = await nova.api.motionGroupInfos.listTcps(motionGroupId);
138
+ return new ConnectedMotionGroup(nova, controller, motionGroup, initialMotionState, motionStateSocket, isVirtual, tcps, await nova.api.motionGroupInfos.getMotionGroupSpecification(motionGroupId), await nova.api.motionGroupInfos.getSafetySetup(motionGroupId), mounting, initialControllerState, controllerStateSocket);
139
+ }
140
+ constructor(nova, controller, motionGroup, initialMotionState, motionStateSocket, isVirtual, tcps, motionGroupSpecification, safetySetup, mounting, initialControllerState, controllerStateSocket) {
141
+ this.nova = nova;
142
+ this.controller = controller;
143
+ this.motionGroup = motionGroup;
144
+ this.initialMotionState = initialMotionState;
145
+ this.motionStateSocket = motionStateSocket;
146
+ this.isVirtual = isVirtual;
147
+ this.tcps = tcps;
148
+ this.motionGroupSpecification = motionGroupSpecification;
149
+ this.safetySetup = safetySetup;
150
+ this.mounting = mounting;
151
+ this.initialControllerState = initialControllerState;
152
+ this.controllerStateSocket = controllerStateSocket;
153
+ this.connectedJoggingCartesianSocket = null;
154
+ this.connectedJoggingJointsSocket = null;
155
+ this.joggingVelocity = 10;
156
+ this.activationState = "inactive";
157
+ this.rapidlyChangingMotionState = initialMotionState;
158
+ this.controllerState = initialControllerState;
159
+ controllerStateSocket.addEventListener("message", (event) => {
160
+ const data = tryParseJson(event.data)?.result;
161
+ if (!data) return;
162
+ runInAction(() => {
163
+ this.controllerState = data;
164
+ });
165
+ });
166
+ motionStateSocket.addEventListener("message", (event) => {
167
+ const motionStateResponse = tryParseJson(event.data)?.result;
168
+ if (!motionStateResponse) throw new Error(`Failed to get motion state for ${this.motionGroupId}: ${event.data}`);
169
+ if (!jointValuesEqual(this.rapidlyChangingMotionState.state.joint_position.joints, motionStateResponse.state.joint_position.joints, MOTION_DELTA_THRESHOLD$1)) runInAction(() => {
170
+ this.rapidlyChangingMotionState.state = motionStateResponse.state;
171
+ });
172
+ if (!tcpPoseEqual(this.rapidlyChangingMotionState.tcp_pose, motionStateResponse.tcp_pose, MOTION_DELTA_THRESHOLD$1)) runInAction(() => {
173
+ this.rapidlyChangingMotionState.tcp_pose = motionStateResponse.tcp_pose;
174
+ });
175
+ });
176
+ makeAutoObservable(this);
177
+ }
178
+ get motionGroupId() {
179
+ return this.motionGroup.motion_group;
180
+ }
181
+ get controllerId() {
182
+ return this.controller.controller;
183
+ }
184
+ get modelFromController() {
185
+ return this.motionGroup.model_from_controller;
186
+ }
187
+ get wandelscriptIdentifier() {
188
+ const num = this.motionGroupId.split("@")[0];
189
+ return `${this.controllerId.replaceAll("-", "_")}_${num}`;
190
+ }
191
+ /** Jogging velocity in radians for rotation and joint movement */
192
+ get joggingVelocityRads() {
193
+ return this.joggingVelocity * Math.PI / 180;
194
+ }
195
+ get joints() {
196
+ return this.initialMotionState.state.joint_position.joints.map((_, i) => {
197
+ return { index: i };
198
+ });
199
+ }
200
+ get dhParameters() {
201
+ return this.motionGroupSpecification.dh_parameters;
202
+ }
203
+ get safetyZones() {
204
+ return this.safetySetup.safety_zones;
205
+ }
206
+ /** Gets the robot mounting position offset in 3D viz coordinates */
207
+ get mountingPosition() {
208
+ if (!this.mounting) return [
209
+ 0,
210
+ 0,
211
+ 0
212
+ ];
213
+ return [
214
+ this.mounting.pose.position.x / 1e3,
215
+ this.mounting.pose.position.y / 1e3,
216
+ this.mounting.pose.position.z / 1e3
217
+ ];
218
+ }
219
+ /** Gets the robot mounting position rotation in 3D viz coordinates */
220
+ get mountingQuaternion() {
221
+ const rotationVector = new THREE.Vector3(this.mounting?.pose.orientation?.x || 0, this.mounting?.pose.orientation?.y || 0, this.mounting?.pose.orientation?.z || 0);
222
+ const magnitude = rotationVector.length();
223
+ const axis = rotationVector.normalize();
224
+ return new THREE.Quaternion().setFromAxisAngle(axis, magnitude);
225
+ }
226
+ /**
227
+ * Whether the controller is currently in a safety state
228
+ * corresponding to an emergency stop
229
+ */
230
+ get isEstopActive() {
231
+ return ["SAFETY_STATE_ROBOT_EMERGENCY_STOP", "SAFETY_STATE_DEVICE_EMERGENCY_STOP"].includes(this.controllerState.safety_state);
232
+ }
233
+ /**
234
+ * Whether the controller is in a safety state
235
+ * that may be non-functional for robot pad purposes
236
+ */
237
+ get isMoveableSafetyState() {
238
+ return ["SAFETY_STATE_NORMAL", "SAFETY_STATE_REDUCED"].includes(this.controllerState.safety_state);
239
+ }
240
+ /**
241
+ * Whether the controller is in an operation mode that allows movement
242
+ */
243
+ get isMoveableOperationMode() {
244
+ return [
245
+ "OPERATION_MODE_AUTO",
246
+ "OPERATION_MODE_MANUAL",
247
+ "OPERATION_MODE_MANUAL_T1",
248
+ "OPERATION_MODE_MANUAL_T2"
249
+ ].includes(this.controllerState.operation_mode);
250
+ }
251
+ /**
252
+ * Whether the robot is currently active and can be moved, based on the
253
+ * safety state, operation mode and servo toggle activation state.
254
+ */
255
+ get canBeMoved() {
256
+ return this.isMoveableSafetyState && this.isMoveableOperationMode && this.activationState === "active";
257
+ }
258
+ async deactivate() {
259
+ if (this.activationState !== "active") {
260
+ console.error("Tried to deactivate while already deactivating");
261
+ return;
262
+ }
263
+ runInAction(() => {
264
+ this.activationState = "deactivating";
265
+ });
266
+ try {
267
+ await this.nova.api.controller.setDefaultMode(this.controllerId, "MODE_MONITOR");
268
+ runInAction(() => {
269
+ this.activationState = "inactive";
270
+ });
271
+ } catch (err) {
272
+ runInAction(() => {
273
+ this.activationState = "active";
274
+ });
275
+ throw err;
276
+ }
277
+ }
278
+ async activate() {
279
+ if (this.activationState !== "inactive") {
280
+ console.error("Tried to activate while already activating");
281
+ return;
282
+ }
283
+ runInAction(() => {
284
+ this.activationState = "activating";
285
+ });
286
+ try {
287
+ await this.nova.api.controller.setDefaultMode(this.controllerId, "MODE_CONTROL");
288
+ runInAction(() => {
289
+ this.activationState = "active";
290
+ });
291
+ } catch (err) {
292
+ runInAction(() => {
293
+ this.activationState = "inactive";
294
+ });
295
+ throw err;
296
+ }
297
+ }
298
+ toggleActivation() {
299
+ if (this.activationState === "inactive") this.activate();
300
+ else if (this.activationState === "active") this.deactivate();
301
+ }
302
+ dispose() {
303
+ this.motionStateSocket.close();
304
+ if (this.connectedJoggingCartesianSocket) this.connectedJoggingCartesianSocket.close();
305
+ if (this.connectedJoggingJointsSocket) this.connectedJoggingJointsSocket.close();
306
+ }
307
+ setJoggingVelocity(velocity) {
308
+ this.joggingVelocity = velocity;
309
+ }
310
+ };
311
+
312
+ //#endregion
313
+ //#region src/lib/v1/JoggerConnection.ts
314
+ var JoggerConnection = class JoggerConnection {
315
+ static async open(nova, motionGroupId, opts = {}) {
316
+ return new JoggerConnection(await nova.connectMotionStream(motionGroupId), opts);
317
+ }
318
+ constructor(motionStream, opts = {}) {
319
+ this.motionStream = motionStream;
320
+ this.opts = opts;
321
+ this.cartesianWebsocket = null;
322
+ this.jointWebsocket = null;
323
+ this.cartesianJoggingOpts = {};
324
+ }
325
+ get motionGroupId() {
326
+ return this.motionStream.motionGroupId;
327
+ }
328
+ get nova() {
329
+ return this.motionStream.nova;
330
+ }
331
+ get numJoints() {
332
+ return this.motionStream.joints.length;
333
+ }
334
+ get activeJoggingMode() {
335
+ if (this.cartesianWebsocket) return "cartesian";
336
+ if (this.jointWebsocket) return "joint";
337
+ return "increment";
338
+ }
339
+ get activeWebsocket() {
340
+ return this.cartesianWebsocket || this.jointWebsocket;
341
+ }
342
+ async stop() {
343
+ if (this.cartesianWebsocket) this.cartesianWebsocket.sendJson({
344
+ motion_group: this.motionGroupId,
345
+ position_direction: {
346
+ x: 0,
347
+ y: 0,
348
+ z: 0
349
+ },
350
+ rotation_direction: {
351
+ x: 0,
352
+ y: 0,
353
+ z: 0
354
+ },
355
+ position_velocity: 0,
356
+ rotation_velocity: 0,
357
+ tcp: this.cartesianJoggingOpts.tcpId,
358
+ coordinate_system: this.cartesianJoggingOpts.coordSystemId
359
+ });
360
+ if (this.jointWebsocket) this.jointWebsocket.sendJson({
361
+ motion_group: this.motionGroupId,
362
+ joint_velocities: new Array(this.numJoints).fill(0)
363
+ });
364
+ }
365
+ dispose() {
366
+ if (this.cartesianWebsocket) this.cartesianWebsocket.dispose();
367
+ if (this.jointWebsocket) this.jointWebsocket.dispose();
368
+ }
369
+ setJoggingMode(mode, cartesianJoggingOpts) {
370
+ console.log("Setting jogging mode to", mode);
371
+ if (cartesianJoggingOpts) {
372
+ if (JSON.stringify(this.cartesianJoggingOpts) !== JSON.stringify(cartesianJoggingOpts)) {
373
+ if (this.cartesianWebsocket) {
374
+ this.cartesianWebsocket.dispose();
375
+ this.cartesianWebsocket = null;
376
+ }
377
+ }
378
+ this.cartesianJoggingOpts = cartesianJoggingOpts;
379
+ }
380
+ if (mode !== "cartesian" && this.cartesianWebsocket) {
381
+ this.cartesianWebsocket.dispose();
382
+ this.cartesianWebsocket = null;
383
+ }
384
+ if (mode !== "joint" && this.jointWebsocket) {
385
+ this.jointWebsocket.dispose();
386
+ this.jointWebsocket = null;
387
+ }
388
+ if (mode === "cartesian" && !this.cartesianWebsocket) {
389
+ this.cartesianWebsocket = this.nova.openReconnectingWebsocket(`/motion-groups/move-tcp`);
390
+ this.cartesianWebsocket.addEventListener("message", (ev) => {
391
+ const data = tryParseJson(ev.data);
392
+ if (data && "error" in data) if (this.opts.onError) this.opts.onError(ev.data);
393
+ else throw new Error(ev.data);
394
+ });
395
+ }
396
+ if (mode === "joint" && !this.jointWebsocket) {
397
+ this.jointWebsocket = this.nova.openReconnectingWebsocket(`/motion-groups/move-joint`);
398
+ this.jointWebsocket.addEventListener("message", (ev) => {
399
+ const data = tryParseJson(ev.data);
400
+ if (data && "error" in data) if (this.opts.onError) this.opts.onError(ev.data);
401
+ else throw new Error(ev.data);
402
+ });
403
+ }
404
+ }
405
+ /**
406
+ * Start rotation of a single robot joint at the specified velocity
407
+ */
408
+ async startJointRotation({ joint, direction, velocityRadsPerSec }) {
409
+ if (!this.jointWebsocket) throw new Error("Joint jogging websocket not connected; call setJoggingMode first");
410
+ const jointVelocities = new Array(this.numJoints).fill(0);
411
+ jointVelocities[joint] = direction === "-" ? -velocityRadsPerSec : velocityRadsPerSec;
412
+ this.jointWebsocket.sendJson({
413
+ motion_group: this.motionGroupId,
414
+ joint_velocities: jointVelocities
415
+ });
416
+ }
417
+ /**
418
+ * Start the TCP moving along a specified axis at a given velocity
419
+ */
420
+ async startTCPTranslation({ axis, direction, velocityMmPerSec }) {
421
+ if (!this.cartesianWebsocket) throw new Error("Cartesian jogging websocket not connected; call setJoggingMode first");
422
+ const zeroVector = {
423
+ x: 0,
424
+ y: 0,
425
+ z: 0
426
+ };
427
+ const joggingVector = Object.assign({}, zeroVector);
428
+ joggingVector[axis] = direction === "-" ? -1 : 1;
429
+ this.cartesianWebsocket.sendJson({
430
+ motion_group: this.motionGroupId,
431
+ position_direction: joggingVector,
432
+ rotation_direction: zeroVector,
433
+ position_velocity: velocityMmPerSec,
434
+ rotation_velocity: 0,
435
+ tcp: this.cartesianJoggingOpts.tcpId,
436
+ coordinate_system: this.cartesianJoggingOpts.coordSystemId
437
+ });
438
+ }
439
+ /**
440
+ * Start the TCP rotating around a specified axis at a given velocity
441
+ */
442
+ async startTCPRotation({ axis, direction, velocityRadsPerSec }) {
443
+ if (!this.cartesianWebsocket) throw new Error("Cartesian jogging websocket not connected; call setJoggingMode first");
444
+ const zeroVector = {
445
+ x: 0,
446
+ y: 0,
447
+ z: 0
448
+ };
449
+ const joggingVector = Object.assign({}, zeroVector);
450
+ joggingVector[axis] = direction === "-" ? -1 : 1;
451
+ this.cartesianWebsocket.sendJson({
452
+ motion_group: this.motionGroupId,
453
+ position_direction: zeroVector,
454
+ rotation_direction: joggingVector,
455
+ position_velocity: 0,
456
+ rotation_velocity: velocityRadsPerSec,
457
+ tcp: this.cartesianJoggingOpts.tcpId,
458
+ coordinate_system: this.cartesianJoggingOpts.coordSystemId
459
+ });
460
+ }
461
+ /**
462
+ * Move the robot by a fixed distance in a single cartesian
463
+ * axis, either rotating or translating relative to the TCP.
464
+ * Promise resolves only after the motion has completed.
465
+ */
466
+ async runIncrementalCartesianMotion({ currentTcpPose, currentJoints, coordSystemId, velocityInRelevantUnits, axis, direction, motion }) {
467
+ const commands = [];
468
+ if (!isSameCoordinateSystem(currentTcpPose.coordinate_system, coordSystemId)) throw new Error(`Current TCP pose coordinate system ${currentTcpPose.coordinate_system} does not match target coordinate system ${coordSystemId}`);
469
+ if (motion.type === "translate") {
470
+ const targetTcpPosition = Object.assign({}, currentTcpPose.position);
471
+ targetTcpPosition[axis] += motion.distanceMm * (direction === "-" ? -1 : 1);
472
+ commands.push({
473
+ settings: { limits_override: { tcp_velocity_limit: velocityInRelevantUnits } },
474
+ line: {
475
+ position: targetTcpPosition,
476
+ orientation: currentTcpPose.orientation,
477
+ coordinate_system: coordSystemId
478
+ }
479
+ });
480
+ } else if (motion.type === "rotate") {
481
+ const currentRotationVector = new Vector3$1(currentTcpPose.orientation.x, currentTcpPose.orientation.y, currentTcpPose.orientation.z);
482
+ const currentRotationRad = currentRotationVector.length();
483
+ const currentRotationDirection = currentRotationVector.clone().normalize();
484
+ const differenceRotationRad = motion.distanceRads * (direction === "-" ? -1 : 1);
485
+ const differenceRotationDirection = new Vector3$1(0, 0, 0);
486
+ differenceRotationDirection[axis] = 1;
487
+ const f1 = Math.cos(.5 * differenceRotationRad) * Math.cos(.5 * currentRotationRad);
488
+ const f2 = Math.sin(.5 * differenceRotationRad) * Math.sin(.5 * currentRotationRad);
489
+ const f3 = Math.sin(.5 * differenceRotationRad) * Math.cos(.5 * currentRotationRad);
490
+ const f4 = Math.cos(.5 * differenceRotationRad) * Math.sin(.5 * currentRotationRad);
491
+ const dotProduct = differenceRotationDirection.dot(currentRotationDirection);
492
+ const crossProduct = differenceRotationDirection.clone().cross(currentRotationDirection);
493
+ const newRotationRad = 2 * Math.acos(f1 - f2 * dotProduct);
494
+ const f5 = newRotationRad / Math.sin(.5 * newRotationRad);
495
+ const targetTcpOrientation = new Vector3$1().addScaledVector(crossProduct, f2).addScaledVector(differenceRotationDirection, f3).addScaledVector(currentRotationDirection, f4).multiplyScalar(f5);
496
+ commands.push({
497
+ settings: { limits_override: { tcp_orientation_velocity_limit: velocityInRelevantUnits } },
498
+ line: {
499
+ position: currentTcpPose.position,
500
+ orientation: targetTcpOrientation,
501
+ coordinate_system: coordSystemId
502
+ }
503
+ });
504
+ }
505
+ const motionPlanRes = await this.nova.api.motion.planMotion({
506
+ motion_group: this.motionGroupId,
507
+ start_joint_position: currentJoints,
508
+ tcp: this.cartesianJoggingOpts.tcpId,
509
+ commands
510
+ });
511
+ const plannedMotion = motionPlanRes.plan_successful_response?.motion;
512
+ if (!plannedMotion) throw new Error(`Failed to plan jogging increment motion ${JSON.stringify(motionPlanRes)}`);
513
+ await this.nova.api.motion.streamMoveForward(plannedMotion, 100, void 0, void 0, void 0, { timeout: 1e3 * 60 });
514
+ }
515
+ /**
516
+ * Rotate a single robot joint by a fixed number of radians
517
+ * Promise resolves only after the motion has completed.
518
+ */
519
+ async runIncrementalJointRotation({ joint, currentJoints, velocityRadsPerSec, direction, distanceRads }) {
520
+ const targetJoints = [...currentJoints.joints];
521
+ targetJoints[joint] += distanceRads * (direction === "-" ? -1 : 1);
522
+ const jointVelocityLimits = new Array(currentJoints.joints.length).fill(velocityRadsPerSec);
523
+ const motionPlanRes = await this.nova.api.motion.planMotion({
524
+ motion_group: this.motionGroupId,
525
+ start_joint_position: currentJoints,
526
+ commands: [{
527
+ settings: { limits_override: { joint_velocity_limits: { joints: jointVelocityLimits } } },
528
+ joint_ptp: { joints: targetJoints }
529
+ }]
530
+ });
531
+ const plannedMotion = motionPlanRes.plan_successful_response?.motion;
532
+ if (!plannedMotion) {
533
+ console.error("Failed to plan jogging increment motion", motionPlanRes);
534
+ return;
535
+ }
536
+ await this.nova.api.motion.streamMoveForward(plannedMotion, 100, void 0, void 0, void 0, { timeout: 1e3 * 60 });
537
+ }
538
+ };
539
+
540
+ //#endregion
541
+ //#region src/lib/v1/MotionStreamConnection.ts
542
+ const MOTION_DELTA_THRESHOLD = 1e-4;
543
+ function unwrapRotationVector(newRotationVectorApi, currentRotationVectorApi) {
544
+ const currentRotationVector = new Vector3(currentRotationVectorApi.x, currentRotationVectorApi.y, currentRotationVectorApi.z);
545
+ const newRotationVector = new Vector3(newRotationVectorApi.x, newRotationVectorApi.y, newRotationVectorApi.z);
546
+ const currentAngle = currentRotationVector.length();
547
+ const currentAxis = currentRotationVector.normalize();
548
+ let newAngle = newRotationVector.length();
549
+ let newAxis = newRotationVector.normalize();
550
+ if (newAxis.dot(currentAxis) < 0) {
551
+ newAngle = -newAngle;
552
+ newAxis = newAxis.multiplyScalar(-1);
553
+ }
554
+ let angleDifference = newAngle - currentAngle;
555
+ angleDifference -= 2 * Math.PI * Math.floor((angleDifference + Math.PI) / (2 * Math.PI));
556
+ newAngle = currentAngle + angleDifference;
557
+ return newAxis.multiplyScalar(newAngle);
558
+ }
559
+ /**
560
+ * Store representing the current state of a connected motion group.
561
+ */
562
+ var MotionStreamConnection = class MotionStreamConnection {
563
+ static async open(nova, motionGroupId) {
564
+ const { instances: controllers } = await nova.api.controller.listControllers();
565
+ const [_motionGroupIndex, controllerId] = motionGroupId.split("@");
566
+ const controller = controllers.find((c) => c.controller === controllerId);
567
+ const motionGroup = controller?.physical_motion_groups.find((mg) => mg.motion_group === motionGroupId);
568
+ if (!controller || !motionGroup) throw new Error(`Controller ${controllerId} or motion group ${motionGroupId} not found`);
569
+ const motionStateSocket = nova.openReconnectingWebsocket(`/motion-groups/${motionGroupId}/state-stream`);
570
+ const firstMessage = await motionStateSocket.firstMessage();
571
+ const initialMotionState = tryParseJson(firstMessage.data)?.result;
572
+ if (!initialMotionState) throw new Error(`Unable to parse initial motion state message ${firstMessage.data}`);
573
+ console.log(`Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state:\n `, initialMotionState);
574
+ return new MotionStreamConnection(nova, controller, motionGroup, initialMotionState, motionStateSocket);
575
+ }
576
+ constructor(nova, controller, motionGroup, initialMotionState, motionStateSocket) {
577
+ this.nova = nova;
578
+ this.controller = controller;
579
+ this.motionGroup = motionGroup;
580
+ this.initialMotionState = initialMotionState;
581
+ this.motionStateSocket = motionStateSocket;
582
+ this.rapidlyChangingMotionState = initialMotionState;
583
+ motionStateSocket.addEventListener("message", (event) => {
584
+ const motionStateResponse = tryParseJson(event.data)?.result;
585
+ if (!motionStateResponse) throw new Error(`Failed to get motion state for ${this.motionGroupId}: ${event.data}`);
586
+ if (!jointValuesEqual(this.rapidlyChangingMotionState.state.joint_position.joints, motionStateResponse.state.joint_position.joints, MOTION_DELTA_THRESHOLD)) runInAction(() => {
587
+ this.rapidlyChangingMotionState.state = motionStateResponse.state;
588
+ });
589
+ if (!tcpPoseEqual(this.rapidlyChangingMotionState.tcp_pose, motionStateResponse.tcp_pose, MOTION_DELTA_THRESHOLD)) runInAction(() => {
590
+ if (this.rapidlyChangingMotionState.tcp_pose == null) this.rapidlyChangingMotionState.tcp_pose = motionStateResponse.tcp_pose;
591
+ else this.rapidlyChangingMotionState.tcp_pose = {
592
+ position: motionStateResponse.tcp_pose.position,
593
+ orientation: unwrapRotationVector(motionStateResponse.tcp_pose.orientation, this.rapidlyChangingMotionState.tcp_pose.orientation),
594
+ tcp: motionStateResponse.tcp_pose.tcp,
595
+ coordinate_system: motionStateResponse.tcp_pose.coordinate_system
596
+ };
597
+ });
598
+ });
599
+ makeAutoObservable(this);
600
+ }
601
+ get motionGroupId() {
602
+ return this.motionGroup.motion_group;
603
+ }
604
+ get controllerId() {
605
+ return this.controller.controller;
606
+ }
607
+ get modelFromController() {
608
+ return this.motionGroup.model_from_controller;
609
+ }
610
+ get wandelscriptIdentifier() {
611
+ const num = this.motionGroupId.split("@")[0];
612
+ return `${this.controllerId.replaceAll("-", "_")}_${num}`;
613
+ }
614
+ get joints() {
615
+ return this.initialMotionState.state.joint_position.joints.map((_, i) => {
616
+ return { index: i };
617
+ });
618
+ }
619
+ dispose() {
620
+ this.motionStateSocket.close();
621
+ }
622
+ };
623
+
624
+ //#endregion
625
+ //#region src/lib/v1/NovaCellAPIClient.ts
626
+ /**
627
+ * API client providing type-safe access to all the Nova API REST endpoints
628
+ * associated with a specific cell id.
629
+ */
630
+ var NovaCellAPIClient = class {
631
+ constructor(cellId, opts) {
632
+ this.cellId = cellId;
633
+ this.opts = opts;
634
+ this.system = this.withUnwrappedResponsesOnly(SystemApi);
635
+ this.cell = this.withUnwrappedResponsesOnly(CellApi);
636
+ this.deviceConfig = this.withCellId(DeviceConfigurationApi);
637
+ this.motionGroup = this.withCellId(MotionGroupApi);
638
+ this.motionGroupInfos = this.withCellId(MotionGroupInfosApi);
639
+ this.controller = this.withCellId(ControllerApi);
640
+ this.program = this.withCellId(ProgramApi);
641
+ this.programValues = this.withCellId(ProgramValuesApi);
642
+ this.controllerIOs = this.withCellId(ControllerIOsApi);
643
+ this.motionGroupKinematic = this.withCellId(MotionGroupKinematicApi);
644
+ this.motion = this.withCellId(MotionApi);
645
+ this.coordinateSystems = this.withCellId(CoordinateSystemsApi);
646
+ this.application = this.withCellId(ApplicationApi);
647
+ this.applicationGlobal = this.withUnwrappedResponsesOnly(ApplicationApi);
648
+ this.motionGroupJogging = this.withCellId(MotionGroupJoggingApi);
649
+ this.virtualRobot = this.withCellId(VirtualRobotApi);
650
+ this.virtualRobotSetup = this.withCellId(VirtualRobotSetupApi);
651
+ this.virtualRobotMode = this.withCellId(VirtualRobotModeApi);
652
+ this.virtualRobotBehavior = this.withCellId(VirtualRobotBehaviorApi);
653
+ this.libraryProgramMetadata = this.withCellId(LibraryProgramMetadataApi);
654
+ this.libraryProgram = this.withCellId(LibraryProgramApi);
655
+ this.libraryRecipeMetadata = this.withCellId(LibraryRecipeMetadataApi);
656
+ this.libraryRecipe = this.withCellId(LibraryRecipeApi);
657
+ this.storeObject = this.withCellId(StoreObjectApi);
658
+ this.storeCollisionComponents = this.withCellId(StoreCollisionComponentsApi);
659
+ this.storeCollisionScenes = this.withCellId(StoreCollisionScenesApi);
660
+ }
661
+ /**
662
+ * Some TypeScript sorcery which alters the API class methods so you don't
663
+ * have to pass the cell id to every single one, and de-encapsulates the
664
+ * response data
665
+ */
666
+ withCellId(ApiConstructor) {
667
+ const apiClient = new ApiConstructor({
668
+ ...this.opts,
669
+ isJsonMime: (mime) => {
670
+ return mime === "application/json";
671
+ }
672
+ }, this.opts.basePath ?? "", this.opts.axiosInstance ?? axios.create());
673
+ for (const key of Reflect.ownKeys(Reflect.getPrototypeOf(apiClient))) if (key !== "constructor" && typeof apiClient[key] === "function") {
674
+ const originalFunction = apiClient[key];
675
+ apiClient[key] = (...args) => {
676
+ return originalFunction.apply(apiClient, [this.cellId, ...args]).then((res) => res.data);
677
+ };
678
+ }
679
+ return apiClient;
680
+ }
681
+ /**
682
+ * As withCellId, but only does the response unwrapping
683
+ */
684
+ withUnwrappedResponsesOnly(ApiConstructor) {
685
+ const apiClient = new ApiConstructor({
686
+ ...this.opts,
687
+ isJsonMime: (mime) => {
688
+ return mime === "application/json";
689
+ }
690
+ }, this.opts.basePath ?? "", this.opts.axiosInstance ?? axios.create());
691
+ for (const key of Reflect.ownKeys(Reflect.getPrototypeOf(apiClient))) if (key !== "constructor" && typeof apiClient[key] === "function") {
692
+ const originalFunction = apiClient[key];
693
+ apiClient[key] = (...args) => {
694
+ return originalFunction.apply(apiClient, args).then((res) => res.data);
695
+ };
696
+ }
697
+ return apiClient;
698
+ }
699
+ };
700
+
701
+ //#endregion
702
+ //#region src/lib/v1/mock/MockNovaInstance.ts
703
+ /**
704
+ * Ultra-simplified mock Nova server for testing stuff
705
+ */
706
+ var MockNovaInstance = class {
707
+ constructor() {
708
+ this.connections = [];
709
+ }
710
+ async handleAPIRequest(config) {
711
+ const apiHandlers = [
712
+ {
713
+ method: "GET",
714
+ path: "/cells/:cellId/controllers",
715
+ handle() {
716
+ return { instances: [{
717
+ controller: "mock-ur5e",
718
+ model_name: "UniversalRobots::Controller",
719
+ host: "mock-ur5e",
720
+ allow_software_install_on_controller: true,
721
+ physical_motion_groups: [{
722
+ motion_group: "0@mock-ur5e",
723
+ name_from_controller: "UR5e",
724
+ active: false,
725
+ model_from_controller: "UniversalRobots_UR5e"
726
+ }],
727
+ has_error: false,
728
+ error_details: ""
729
+ }] };
730
+ }
731
+ },
732
+ {
733
+ method: "GET",
734
+ path: "/cells/:cellId/controllers/:controllerId",
735
+ handle() {
736
+ return {
737
+ configuration: {
738
+ kind: "VirtualController",
739
+ manufacturer: "universalrobots",
740
+ position: "[0,-1.571,-1.571,-1.571,1.571,-1.571,0]",
741
+ type: "universalrobots-ur5e"
742
+ },
743
+ name: "mock-ur5"
744
+ };
745
+ }
746
+ },
747
+ {
748
+ method: "GET",
749
+ path: "/cells/:cellId/motion-groups/:motionGroupId/specification",
750
+ handle() {
751
+ return {
752
+ dh_parameters: [
753
+ {
754
+ alpha: 1.5707963267948966,
755
+ theta: 0,
756
+ a: 0,
757
+ d: 162.25,
758
+ reverse_rotation_direction: false
759
+ },
760
+ {
761
+ alpha: 0,
762
+ theta: 0,
763
+ a: -425,
764
+ d: 0,
765
+ reverse_rotation_direction: false
766
+ },
767
+ {
768
+ alpha: 0,
769
+ theta: 0,
770
+ a: -392.2,
771
+ d: 0,
772
+ reverse_rotation_direction: false
773
+ },
774
+ {
775
+ alpha: 1.5707963267948966,
776
+ theta: 0,
777
+ a: 0,
778
+ d: 133.3,
779
+ reverse_rotation_direction: false
780
+ },
781
+ {
782
+ alpha: -1.5707963267948966,
783
+ theta: 0,
784
+ a: 0,
785
+ d: 99.7,
786
+ reverse_rotation_direction: false
787
+ },
788
+ {
789
+ alpha: 0,
790
+ theta: 0,
791
+ a: 0,
792
+ d: 99.6,
793
+ reverse_rotation_direction: false
794
+ }
795
+ ],
796
+ mechanical_joint_limits: [
797
+ {
798
+ joint: "JOINTNAME_AXIS_1",
799
+ lower_limit: -6.335545063018799,
800
+ upper_limit: 6.335545063018799,
801
+ unlimited: false
802
+ },
803
+ {
804
+ joint: "JOINTNAME_AXIS_2",
805
+ lower_limit: -6.335545063018799,
806
+ upper_limit: 6.335545063018799,
807
+ unlimited: false
808
+ },
809
+ {
810
+ joint: "JOINTNAME_AXIS_3",
811
+ lower_limit: -6.335545063018799,
812
+ upper_limit: 6.335545063018799,
813
+ unlimited: false
814
+ },
815
+ {
816
+ joint: "JOINTNAME_AXIS_4",
817
+ lower_limit: -6.335545063018799,
818
+ upper_limit: 6.335545063018799,
819
+ unlimited: false
820
+ },
821
+ {
822
+ joint: "JOINTNAME_AXIS_5",
823
+ lower_limit: -6.335545063018799,
824
+ upper_limit: 6.335545063018799,
825
+ unlimited: false
826
+ },
827
+ {
828
+ joint: "JOINTNAME_AXIS_6",
829
+ lower_limit: -6.335545063018799,
830
+ upper_limit: 6.335545063018799,
831
+ unlimited: false
832
+ }
833
+ ]
834
+ };
835
+ }
836
+ },
837
+ {
838
+ method: "GET",
839
+ path: "/cells/:cellId/motion-groups/:motionGroupId/safety-setup",
840
+ handle() {
841
+ return {
842
+ safety_settings: [{
843
+ safety_state: "SAFETY_NORMAL",
844
+ settings: {
845
+ joint_position_limits: [
846
+ {
847
+ joint: "JOINTNAME_AXIS_1",
848
+ lower_limit: -2.96705961227417,
849
+ upper_limit: 2.96705961227417,
850
+ unlimited: false
851
+ },
852
+ {
853
+ joint: "JOINTNAME_AXIS_2",
854
+ lower_limit: -1.7453292608261108,
855
+ upper_limit: 2.7925267219543457,
856
+ unlimited: false
857
+ },
858
+ {
859
+ joint: "JOINTNAME_AXIS_3",
860
+ lower_limit: -3.3161256313323975,
861
+ upper_limit: .40142571926116943,
862
+ unlimited: false
863
+ },
864
+ {
865
+ joint: "JOINTNAME_AXIS_4",
866
+ lower_limit: -3.4906585216522217,
867
+ upper_limit: 3.4906585216522217,
868
+ unlimited: false
869
+ },
870
+ {
871
+ joint: "JOINTNAME_AXIS_5",
872
+ lower_limit: -2.4434609413146973,
873
+ upper_limit: 2.4434609413146973,
874
+ unlimited: false
875
+ },
876
+ {
877
+ joint: "JOINTNAME_AXIS_6",
878
+ lower_limit: -4.71238899230957,
879
+ upper_limit: 4.71238899230957,
880
+ unlimited: false
881
+ }
882
+ ],
883
+ joint_velocity_limits: [
884
+ {
885
+ joint: "JOINTNAME_AXIS_1",
886
+ limit: 3.1415927410125732
887
+ },
888
+ {
889
+ joint: "JOINTNAME_AXIS_2",
890
+ limit: 3.1415927410125732
891
+ },
892
+ {
893
+ joint: "JOINTNAME_AXIS_3",
894
+ limit: 3.4906585216522217
895
+ },
896
+ {
897
+ joint: "JOINTNAME_AXIS_4",
898
+ limit: 6.108652591705322
899
+ },
900
+ {
901
+ joint: "JOINTNAME_AXIS_5",
902
+ limit: 6.108652591705322
903
+ },
904
+ {
905
+ joint: "JOINTNAME_AXIS_6",
906
+ limit: 6.981317043304443
907
+ }
908
+ ],
909
+ joint_acceleration_limits: [],
910
+ joint_torque_limits: [],
911
+ tcp_velocity_limit: 1800
912
+ }
913
+ }],
914
+ safety_zones: [
915
+ {
916
+ id: 1,
917
+ priority: 0,
918
+ geometry: {
919
+ compound: { child_geometries: [
920
+ {
921
+ convex_hull: { vertices: [
922
+ {
923
+ x: -800,
924
+ y: -1330,
925
+ z: -1820
926
+ },
927
+ {
928
+ x: 1650,
929
+ y: -1330,
930
+ z: -1820
931
+ },
932
+ {
933
+ x: 1650,
934
+ y: 1330,
935
+ z: -1820
936
+ },
937
+ {
938
+ x: -800,
939
+ y: 1330,
940
+ z: -1820
941
+ }
942
+ ] },
943
+ init_pose: {
944
+ position: {
945
+ x: 0,
946
+ y: 0,
947
+ z: 0
948
+ },
949
+ orientation: {
950
+ x: 0,
951
+ y: 0,
952
+ z: 0,
953
+ w: 1
954
+ }
955
+ },
956
+ id: "box"
957
+ },
958
+ {
959
+ convex_hull: { vertices: [
960
+ {
961
+ x: -800,
962
+ y: -1330,
963
+ z: -1820
964
+ },
965
+ {
966
+ x: 1650,
967
+ y: -1330,
968
+ z: -1820
969
+ },
970
+ {
971
+ x: 1650,
972
+ y: -1330,
973
+ z: 1500
974
+ },
975
+ {
976
+ x: -800,
977
+ y: -1330,
978
+ z: 1500
979
+ }
980
+ ] },
981
+ init_pose: {
982
+ position: {
983
+ x: 0,
984
+ y: 0,
985
+ z: 0
986
+ },
987
+ orientation: {
988
+ x: 0,
989
+ y: 0,
990
+ z: 0,
991
+ w: 1
992
+ }
993
+ },
994
+ id: "box"
995
+ },
996
+ {
997
+ convex_hull: { vertices: [
998
+ {
999
+ x: -800,
1000
+ y: -1330,
1001
+ z: -1820
1002
+ },
1003
+ {
1004
+ x: -800,
1005
+ y: 1330,
1006
+ z: -1820
1007
+ },
1008
+ {
1009
+ x: -800,
1010
+ y: 1330,
1011
+ z: 1500
1012
+ },
1013
+ {
1014
+ x: -800,
1015
+ y: -1330,
1016
+ z: 1500
1017
+ }
1018
+ ] },
1019
+ init_pose: {
1020
+ position: {
1021
+ x: 0,
1022
+ y: 0,
1023
+ z: 0
1024
+ },
1025
+ orientation: {
1026
+ x: 0,
1027
+ y: 0,
1028
+ z: 0,
1029
+ w: 1
1030
+ }
1031
+ },
1032
+ id: "box"
1033
+ },
1034
+ {
1035
+ convex_hull: { vertices: [
1036
+ {
1037
+ x: 1650,
1038
+ y: 1330,
1039
+ z: 1500
1040
+ },
1041
+ {
1042
+ x: -800,
1043
+ y: 1330,
1044
+ z: 1500
1045
+ },
1046
+ {
1047
+ x: -800,
1048
+ y: -1330,
1049
+ z: 1500
1050
+ },
1051
+ {
1052
+ x: 1650,
1053
+ y: -1330,
1054
+ z: 1500
1055
+ }
1056
+ ] },
1057
+ init_pose: {
1058
+ position: {
1059
+ x: 0,
1060
+ y: 0,
1061
+ z: 0
1062
+ },
1063
+ orientation: {
1064
+ x: 0,
1065
+ y: 0,
1066
+ z: 0,
1067
+ w: 1
1068
+ }
1069
+ },
1070
+ id: "box"
1071
+ },
1072
+ {
1073
+ convex_hull: { vertices: [
1074
+ {
1075
+ x: 1650,
1076
+ y: 1330,
1077
+ z: 1500
1078
+ },
1079
+ {
1080
+ x: -800,
1081
+ y: 1330,
1082
+ z: 1500
1083
+ },
1084
+ {
1085
+ x: -800,
1086
+ y: 1330,
1087
+ z: -1820
1088
+ },
1089
+ {
1090
+ x: 1650,
1091
+ y: 1330,
1092
+ z: -1820
1093
+ }
1094
+ ] },
1095
+ init_pose: {
1096
+ position: {
1097
+ x: 0,
1098
+ y: 0,
1099
+ z: 0
1100
+ },
1101
+ orientation: {
1102
+ x: 0,
1103
+ y: 0,
1104
+ z: 0,
1105
+ w: 1
1106
+ }
1107
+ },
1108
+ id: "box"
1109
+ },
1110
+ {
1111
+ convex_hull: { vertices: [
1112
+ {
1113
+ x: 1650,
1114
+ y: 1330,
1115
+ z: 1500
1116
+ },
1117
+ {
1118
+ x: 1650,
1119
+ y: -1330,
1120
+ z: 1500
1121
+ },
1122
+ {
1123
+ x: 1650,
1124
+ y: -1330,
1125
+ z: -1820
1126
+ },
1127
+ {
1128
+ x: 1650,
1129
+ y: 1330,
1130
+ z: -1820
1131
+ }
1132
+ ] },
1133
+ init_pose: {
1134
+ position: {
1135
+ x: 0,
1136
+ y: 0,
1137
+ z: 0
1138
+ },
1139
+ orientation: {
1140
+ x: 0,
1141
+ y: 0,
1142
+ z: 0,
1143
+ w: 1
1144
+ }
1145
+ },
1146
+ id: "box"
1147
+ }
1148
+ ] },
1149
+ init_pose: {
1150
+ position: {
1151
+ x: 0,
1152
+ y: 0,
1153
+ z: 0
1154
+ },
1155
+ orientation: {
1156
+ x: 0,
1157
+ y: 0,
1158
+ z: 0,
1159
+ w: 1
1160
+ }
1161
+ },
1162
+ id: "Cell workzone"
1163
+ },
1164
+ motion_group_uid: 1
1165
+ },
1166
+ {
1167
+ id: 2,
1168
+ priority: 0,
1169
+ geometry: {
1170
+ convex_hull: { vertices: [
1171
+ {
1172
+ x: 1650,
1173
+ y: 1330,
1174
+ z: -1850
1175
+ },
1176
+ {
1177
+ x: 865,
1178
+ y: 1330,
1179
+ z: -1850
1180
+ },
1181
+ {
1182
+ x: 865,
1183
+ y: -720,
1184
+ z: -1850
1185
+ },
1186
+ {
1187
+ x: 1650,
1188
+ y: -720,
1189
+ z: -1850
1190
+ },
1191
+ {
1192
+ x: 1650,
1193
+ y: 1330,
1194
+ z: -920
1195
+ },
1196
+ {
1197
+ x: 865,
1198
+ y: 1330,
1199
+ z: -920
1200
+ },
1201
+ {
1202
+ x: 865,
1203
+ y: -720,
1204
+ z: -920
1205
+ },
1206
+ {
1207
+ x: 1650,
1208
+ y: -720,
1209
+ z: -920
1210
+ }
1211
+ ] },
1212
+ init_pose: {
1213
+ position: {
1214
+ x: 0,
1215
+ y: 0,
1216
+ z: 0
1217
+ },
1218
+ orientation: {
1219
+ x: 0,
1220
+ y: 0,
1221
+ z: 0,
1222
+ w: 1
1223
+ }
1224
+ },
1225
+ id: "Transport"
1226
+ },
1227
+ motion_group_uid: 1
1228
+ },
1229
+ {
1230
+ id: 3,
1231
+ priority: 0,
1232
+ geometry: {
1233
+ convex_hull: { vertices: [
1234
+ {
1235
+ x: 1650,
1236
+ y: 1330,
1237
+ z: -600
1238
+ },
1239
+ {
1240
+ x: 865,
1241
+ y: 1330,
1242
+ z: -600
1243
+ },
1244
+ {
1245
+ x: 865,
1246
+ y: 430,
1247
+ z: -600
1248
+ },
1249
+ {
1250
+ x: 1650,
1251
+ y: 430,
1252
+ z: -600
1253
+ },
1254
+ {
1255
+ x: 1650,
1256
+ y: 1330,
1257
+ z: -1250
1258
+ },
1259
+ {
1260
+ x: 865,
1261
+ y: 1330,
1262
+ z: -1250
1263
+ },
1264
+ {
1265
+ x: 865,
1266
+ y: 430,
1267
+ z: -1250
1268
+ },
1269
+ {
1270
+ x: 1650,
1271
+ y: 430,
1272
+ z: -1250
1273
+ }
1274
+ ] },
1275
+ init_pose: {
1276
+ position: {
1277
+ x: 0,
1278
+ y: 0,
1279
+ z: 0
1280
+ },
1281
+ orientation: {
1282
+ x: 0,
1283
+ y: 0,
1284
+ z: 0,
1285
+ w: 1
1286
+ }
1287
+ },
1288
+ id: "Tunel"
1289
+ },
1290
+ motion_group_uid: 1
1291
+ },
1292
+ {
1293
+ id: 4,
1294
+ priority: 0,
1295
+ geometry: {
1296
+ convex_hull: { vertices: [
1297
+ {
1298
+ x: 1650,
1299
+ y: -760,
1300
+ z: -440
1301
+ },
1302
+ {
1303
+ x: 900,
1304
+ y: -760,
1305
+ z: -440
1306
+ },
1307
+ {
1308
+ x: 900,
1309
+ y: -1330,
1310
+ z: -440
1311
+ },
1312
+ {
1313
+ x: 1650,
1314
+ y: -1330,
1315
+ z: -440
1316
+ },
1317
+ {
1318
+ x: 1650,
1319
+ y: -760,
1320
+ z: -1800
1321
+ },
1322
+ {
1323
+ x: 900,
1324
+ y: -760,
1325
+ z: -1800
1326
+ },
1327
+ {
1328
+ x: 900,
1329
+ y: -1330,
1330
+ z: -1800
1331
+ },
1332
+ {
1333
+ x: 1650,
1334
+ y: -1330,
1335
+ z: -1800
1336
+ }
1337
+ ] },
1338
+ init_pose: {
1339
+ position: {
1340
+ x: 0,
1341
+ y: 0,
1342
+ z: 0
1343
+ },
1344
+ orientation: {
1345
+ x: 0,
1346
+ y: 0,
1347
+ z: 0,
1348
+ w: 1
1349
+ }
1350
+ },
1351
+ id: "Fanuc controller"
1352
+ },
1353
+ motion_group_uid: 1
1354
+ },
1355
+ {
1356
+ id: 6,
1357
+ priority: 0,
1358
+ geometry: {
1359
+ convex_hull: { vertices: [
1360
+ {
1361
+ x: -200,
1362
+ y: -200,
1363
+ z: -1900
1364
+ },
1365
+ {
1366
+ x: 200,
1367
+ y: -200,
1368
+ z: -1900
1369
+ },
1370
+ {
1371
+ x: 200,
1372
+ y: 200,
1373
+ z: -1900
1374
+ },
1375
+ {
1376
+ x: -200,
1377
+ y: 200,
1378
+ z: -1900
1379
+ },
1380
+ {
1381
+ x: -200,
1382
+ y: -200,
1383
+ z: -350
1384
+ },
1385
+ {
1386
+ x: 200,
1387
+ y: -200,
1388
+ z: -350
1389
+ },
1390
+ {
1391
+ x: 200,
1392
+ y: 200,
1393
+ z: -350
1394
+ },
1395
+ {
1396
+ x: -200,
1397
+ y: 200,
1398
+ z: -350
1399
+ }
1400
+ ] },
1401
+ init_pose: {
1402
+ position: {
1403
+ x: 0,
1404
+ y: 0,
1405
+ z: 0
1406
+ },
1407
+ orientation: {
1408
+ x: 0,
1409
+ y: 0,
1410
+ z: 0,
1411
+ w: 1
1412
+ }
1413
+ },
1414
+ id: "Robot base"
1415
+ },
1416
+ motion_group_uid: 1
1417
+ }
1418
+ ],
1419
+ robot_model_geometries: [
1420
+ {
1421
+ link_index: 1,
1422
+ geometry: {
1423
+ sphere: { radius: 270 },
1424
+ init_pose: {
1425
+ position: {
1426
+ x: -70,
1427
+ y: -70,
1428
+ z: -50
1429
+ },
1430
+ orientation: {
1431
+ x: 0,
1432
+ y: 0,
1433
+ z: 0,
1434
+ w: 1
1435
+ }
1436
+ },
1437
+ id: "link1_sphere"
1438
+ }
1439
+ },
1440
+ {
1441
+ link_index: 2,
1442
+ geometry: {
1443
+ capsule: {
1444
+ radius: 160,
1445
+ cylinder_height: 800
1446
+ },
1447
+ init_pose: {
1448
+ position: {
1449
+ x: -450,
1450
+ y: 40,
1451
+ z: 170
1452
+ },
1453
+ orientation: {
1454
+ x: 0,
1455
+ y: -Math.SQRT1_2,
1456
+ z: 0,
1457
+ w: Math.SQRT1_2
1458
+ }
1459
+ },
1460
+ id: "link2_capsule"
1461
+ }
1462
+ },
1463
+ {
1464
+ link_index: 3,
1465
+ geometry: {
1466
+ sphere: { radius: 270 },
1467
+ init_pose: {
1468
+ position: {
1469
+ x: -110,
1470
+ y: 10,
1471
+ z: -100
1472
+ },
1473
+ orientation: {
1474
+ x: 0,
1475
+ y: 0,
1476
+ z: 0,
1477
+ w: 1
1478
+ }
1479
+ },
1480
+ id: "link3_sphere"
1481
+ }
1482
+ },
1483
+ {
1484
+ link_index: 4,
1485
+ geometry: {
1486
+ capsule: {
1487
+ radius: 110,
1488
+ cylinder_height: 600
1489
+ },
1490
+ init_pose: {
1491
+ position: {
1492
+ x: 0,
1493
+ y: 300,
1494
+ z: 40
1495
+ },
1496
+ orientation: {
1497
+ x: -Math.SQRT1_2,
1498
+ y: 0,
1499
+ z: 0,
1500
+ w: Math.SQRT1_2
1501
+ }
1502
+ },
1503
+ id: "link4_capsule"
1504
+ }
1505
+ },
1506
+ {
1507
+ link_index: 5,
1508
+ geometry: {
1509
+ sphere: { radius: 75 },
1510
+ init_pose: {
1511
+ position: {
1512
+ x: 0,
1513
+ y: 0,
1514
+ z: -50
1515
+ },
1516
+ orientation: {
1517
+ x: 0,
1518
+ y: 0,
1519
+ z: 0,
1520
+ w: 1
1521
+ }
1522
+ },
1523
+ id: "link5_sphere"
1524
+ }
1525
+ }
1526
+ ],
1527
+ tool_geometries: []
1528
+ };
1529
+ }
1530
+ },
1531
+ {
1532
+ method: "GET",
1533
+ path: "/cells/:cellId/coordinate-systems",
1534
+ handle() {
1535
+ return { coordinatesystems: [{
1536
+ coordinate_system: "",
1537
+ name: "world",
1538
+ reference_uid: "",
1539
+ position: {
1540
+ x: 0,
1541
+ y: 0,
1542
+ z: 0
1543
+ },
1544
+ rotation: {
1545
+ angles: [
1546
+ 0,
1547
+ 0,
1548
+ 0
1549
+ ],
1550
+ type: "ROTATION_VECTOR"
1551
+ }
1552
+ }] };
1553
+ }
1554
+ },
1555
+ {
1556
+ method: "GET",
1557
+ path: "/cells/:cellId/motion-groups/:motionGroupId/tcps",
1558
+ handle() {
1559
+ return { tcps: [{
1560
+ id: "Flange",
1561
+ readable_name: "Default-Flange",
1562
+ position: {
1563
+ x: 0,
1564
+ y: 0,
1565
+ z: 0
1566
+ },
1567
+ rotation: {
1568
+ angles: [
1569
+ 0,
1570
+ 0,
1571
+ 0,
1572
+ 0
1573
+ ],
1574
+ type: "ROTATION_VECTOR"
1575
+ }
1576
+ }, {
1577
+ id: "complex-tcp-position",
1578
+ readable_name: "Complex TCP Position",
1579
+ position: {
1580
+ x: -200,
1581
+ y: 300,
1582
+ z: 150
1583
+ },
1584
+ rotation: {
1585
+ angles: [
1586
+ -.12139440409113832,
1587
+ -.06356210998212003,
1588
+ -.2023240068185639,
1589
+ 0
1590
+ ],
1591
+ type: "ROTATION_VECTOR"
1592
+ }
1593
+ }] };
1594
+ }
1595
+ }
1596
+ ];
1597
+ const method = config.method?.toUpperCase() || "GET";
1598
+ const path = `/cells${config.url?.split("/cells")[1]?.split("?")[0]}`;
1599
+ for (const handler of apiHandlers) {
1600
+ const match = pathToRegexp.match(handler.path)(path || "");
1601
+ if (method === handler.method && match) {
1602
+ const json = handler.handle();
1603
+ return {
1604
+ status: 200,
1605
+ statusText: "Success",
1606
+ data: JSON.stringify(json),
1607
+ headers: {},
1608
+ config,
1609
+ request: { responseURL: config.url }
1610
+ };
1611
+ }
1612
+ }
1613
+ throw new AxiosError(`No mock handler matched this request: ${method} ${path}`, "404", config);
1614
+ }
1615
+ handleWebsocketConnection(socket) {
1616
+ this.connections.push(socket);
1617
+ setTimeout(() => {
1618
+ socket.dispatchEvent(new Event("open"));
1619
+ console.log("Websocket connection opened from", socket.url);
1620
+ if (socket.url.includes("/state-stream")) socket.dispatchEvent(new MessageEvent("message", { data: JSON.stringify(defaultMotionState) }));
1621
+ if (socket.url.includes("/move-joint")) socket.dispatchEvent(new MessageEvent("message", { data: JSON.stringify({ result: {
1622
+ motion_group: "0@ur",
1623
+ state: {
1624
+ controller: "ur",
1625
+ operation_mode: "OPERATION_MODE_AUTO",
1626
+ safety_state: "SAFETY_STATE_NORMAL",
1627
+ timestamp: "2024-09-18T12:48:26.096266444Z",
1628
+ velocity_override: 100,
1629
+ motion_groups: [{
1630
+ motion_group: "0@ur",
1631
+ controller: "ur",
1632
+ joint_position: { joints: [
1633
+ 1.3492152690887451,
1634
+ -1.5659207105636597,
1635
+ 1.6653711795806885,
1636
+ -1.0991662740707397,
1637
+ -1.829018235206604,
1638
+ 1.264623761177063
1639
+ ] },
1640
+ joint_velocity: { joints: [
1641
+ 0,
1642
+ 0,
1643
+ 0,
1644
+ 0,
1645
+ 0,
1646
+ 0
1647
+ ] },
1648
+ flange_pose: {
1649
+ position: {
1650
+ x: 6.437331889439328,
1651
+ y: -628.4123774830913,
1652
+ z: 577.0569957147832
1653
+ },
1654
+ orientation: {
1655
+ x: -1.683333649797158,
1656
+ y: -1.9783363827298732,
1657
+ z: -.4928031860165713
1658
+ },
1659
+ coordinate_system: ""
1660
+ },
1661
+ tcp_pose: {
1662
+ position: {
1663
+ x: 6.437331889439328,
1664
+ y: -628.4123774830913,
1665
+ z: 577.0569957147832
1666
+ },
1667
+ orientation: {
1668
+ x: -1.683333649797158,
1669
+ y: -1.9783363827298732,
1670
+ z: -.4928031860165713
1671
+ },
1672
+ coordinate_system: "",
1673
+ tcp: "Flange"
1674
+ },
1675
+ velocity: {
1676
+ linear: {
1677
+ x: 0,
1678
+ y: 0,
1679
+ z: 0
1680
+ },
1681
+ angular: {
1682
+ x: -0,
1683
+ y: 0,
1684
+ z: 0
1685
+ },
1686
+ coordinate_system: ""
1687
+ },
1688
+ force: {
1689
+ force: {
1690
+ x: 0,
1691
+ y: 0,
1692
+ z: 0
1693
+ },
1694
+ moment: {
1695
+ x: 0,
1696
+ y: 0,
1697
+ z: 0
1698
+ },
1699
+ coordinate_system: ""
1700
+ },
1701
+ joint_limit_reached: { limit_reached: [
1702
+ false,
1703
+ false,
1704
+ false,
1705
+ false,
1706
+ false,
1707
+ false
1708
+ ] },
1709
+ joint_current: { joints: [
1710
+ 0,
1711
+ 0,
1712
+ 0,
1713
+ 0,
1714
+ 0,
1715
+ 0
1716
+ ] },
1717
+ sequence_number: "671259"
1718
+ }],
1719
+ sequence_number: "671259"
1720
+ },
1721
+ movement_state: "MOVEMENT_STATE_MOVING"
1722
+ } }) }));
1723
+ if (socket.url.includes("/move-tcp")) socket.dispatchEvent(new MessageEvent("message", { data: JSON.stringify({ result: {
1724
+ motion_group: "0@ur",
1725
+ state: {
1726
+ controller: "ur",
1727
+ operation_mode: "OPERATION_MODE_AUTO",
1728
+ safety_state: "SAFETY_STATE_NORMAL",
1729
+ timestamp: "2024-09-18T12:43:12.188335774Z",
1730
+ velocity_override: 100,
1731
+ motion_groups: [{
1732
+ motion_group: "0@ur",
1733
+ controller: "ur",
1734
+ joint_position: { joints: [
1735
+ 1.3352527618408203,
1736
+ -1.5659207105636597,
1737
+ 1.6653711795806885,
1738
+ -1.110615611076355,
1739
+ -1.829018235206604,
1740
+ 1.264623761177063
1741
+ ] },
1742
+ joint_velocity: { joints: [
1743
+ 0,
1744
+ 0,
1745
+ 0,
1746
+ 0,
1747
+ 0,
1748
+ 0
1749
+ ] },
1750
+ flange_pose: {
1751
+ position: {
1752
+ x: -2.763015284002938,
1753
+ y: -630.2151479701106,
1754
+ z: 577.524509114342
1755
+ },
1756
+ orientation: {
1757
+ x: -1.704794877102097,
1758
+ y: -1.9722372952861567,
1759
+ z: -.4852079204210754
1760
+ },
1761
+ coordinate_system: ""
1762
+ },
1763
+ tcp_pose: {
1764
+ position: {
1765
+ x: -2.763015284002938,
1766
+ y: -630.2151479701106,
1767
+ z: 577.524509114342
1768
+ },
1769
+ orientation: {
1770
+ x: -1.704794877102097,
1771
+ y: -1.9722372952861567,
1772
+ z: -.4852079204210754
1773
+ },
1774
+ coordinate_system: "",
1775
+ tcp: "Flange"
1776
+ },
1777
+ velocity: {
1778
+ linear: {
1779
+ x: 0,
1780
+ y: 0,
1781
+ z: 0
1782
+ },
1783
+ angular: {
1784
+ x: -0,
1785
+ y: 0,
1786
+ z: 0
1787
+ },
1788
+ coordinate_system: ""
1789
+ },
1790
+ force: {
1791
+ force: {
1792
+ x: 0,
1793
+ y: 0,
1794
+ z: 0
1795
+ },
1796
+ moment: {
1797
+ x: 0,
1798
+ y: 0,
1799
+ z: 0
1800
+ },
1801
+ coordinate_system: ""
1802
+ },
1803
+ joint_limit_reached: { limit_reached: [
1804
+ false,
1805
+ false,
1806
+ false,
1807
+ false,
1808
+ false,
1809
+ false
1810
+ ] },
1811
+ joint_current: { joints: [
1812
+ 0,
1813
+ 0,
1814
+ 0,
1815
+ 0,
1816
+ 0,
1817
+ 0
1818
+ ] },
1819
+ sequence_number: "627897"
1820
+ }],
1821
+ sequence_number: "627897"
1822
+ },
1823
+ movement_state: "MOVEMENT_STATE_MOVING"
1824
+ } }) }));
1825
+ }, 10);
1826
+ }
1827
+ handleWebsocketMessage(socket, message) {
1828
+ console.log(`Received message on ${socket.url}`, message);
1829
+ }
1830
+ };
1831
+ const defaultMotionState = { result: {
1832
+ state: {
1833
+ motion_group: "0@universalrobots-ur5e",
1834
+ controller: "universalrobots-ur5e",
1835
+ joint_position: { joints: [
1836
+ 1.1699999570846558,
1837
+ -1.5700000524520874,
1838
+ 1.3600000143051147,
1839
+ 1.0299999713897705,
1840
+ 1.2899999618530273,
1841
+ 1.2799999713897705
1842
+ ] },
1843
+ joint_velocity: { joints: [
1844
+ 0,
1845
+ 0,
1846
+ 0,
1847
+ 0,
1848
+ 0,
1849
+ 0
1850
+ ] },
1851
+ flange_pose: {
1852
+ position: {
1853
+ x: 1.3300010259703043,
1854
+ y: -409.2680714682808,
1855
+ z: 531.0203477065281
1856
+ },
1857
+ orientation: {
1858
+ x: 1.7564919306270736,
1859
+ y: -1.7542521568325058,
1860
+ z: .7326972590614671
1861
+ },
1862
+ coordinate_system: ""
1863
+ },
1864
+ tcp_pose: {
1865
+ position: {
1866
+ x: 1.3300010259703043,
1867
+ y: -409.2680714682808,
1868
+ z: 531.0203477065281
1869
+ },
1870
+ orientation: {
1871
+ x: 1.7564919306270736,
1872
+ y: -1.7542521568325058,
1873
+ z: .7326972590614671
1874
+ },
1875
+ coordinate_system: "",
1876
+ tcp: "Flange"
1877
+ },
1878
+ velocity: {
1879
+ linear: {
1880
+ x: 0,
1881
+ y: 0,
1882
+ z: 0
1883
+ },
1884
+ angular: {
1885
+ x: 0,
1886
+ y: 0,
1887
+ z: 0
1888
+ },
1889
+ coordinate_system: ""
1890
+ },
1891
+ force: {
1892
+ force: {
1893
+ x: 0,
1894
+ y: 0,
1895
+ z: 0
1896
+ },
1897
+ moment: {
1898
+ x: 0,
1899
+ y: 0,
1900
+ z: 0
1901
+ },
1902
+ coordinate_system: ""
1903
+ },
1904
+ joint_limit_reached: { limit_reached: [
1905
+ false,
1906
+ false,
1907
+ false,
1908
+ false,
1909
+ false,
1910
+ false
1911
+ ] },
1912
+ joint_current: { joints: [
1913
+ 0,
1914
+ 0,
1915
+ 0,
1916
+ 0,
1917
+ 0,
1918
+ 0
1919
+ ] },
1920
+ sequence_number: "1"
1921
+ },
1922
+ tcp_pose: {
1923
+ position: {
1924
+ x: 302.90748476115556,
1925
+ y: -152.87065869452337,
1926
+ z: 424.0454619321661
1927
+ },
1928
+ orientation: {
1929
+ x: 2.3403056115045353,
1930
+ y: -1.1706836379431356,
1931
+ z: .9772511964246311
1932
+ },
1933
+ coordinate_system: "",
1934
+ tcp: "Flange"
1935
+ }
1936
+ } };
1937
+
1938
+ //#endregion
1939
+ //#region src/lib/v1/NovaClient.ts
1940
+ function permissiveInstanceUrlParse(url) {
1941
+ if (!url.startsWith("http")) url = `http://${url}`;
1942
+ return new URL(url).toString();
1943
+ }
1944
+ /**
1945
+ * Client for connecting to a Nova instance and controlling robots.
1946
+ * @deprecated The nova v1 client is deprecated. Please use the v2 client from `@wandelbots/nova-js/v2` instead.
1947
+ */
1948
+ var NovaClient = class {
1949
+ constructor(config) {
1950
+ this.authPromise = null;
1951
+ this.accessToken = null;
1952
+ const cellId = config.cellId ?? "cell";
1953
+ this.config = {
1954
+ cellId,
1955
+ ...config
1956
+ };
1957
+ this.accessToken = config.accessToken || availableStorage.getString("wbjs.access_token") || null;
1958
+ if (this.config.instanceUrl === "https://mock.example.com") this.mock = new MockNovaInstance();
1959
+ else this.config.instanceUrl = permissiveInstanceUrlParse(this.config.instanceUrl);
1960
+ const axiosInstance = axios.create({
1961
+ baseURL: urlJoin(this.config.instanceUrl, "/api/v1"),
1962
+ headers: typeof window !== "undefined" && window.location.origin.includes("localhost") ? {} : { "X-Wandelbots-Client": "Wandelbots-Nova-JS-SDK" }
1963
+ });
1964
+ axiosInstance.interceptors.request.use(async (request) => {
1965
+ if (!request.headers.Authorization) {
1966
+ if (this.accessToken) request.headers.Authorization = `Bearer ${this.accessToken}`;
1967
+ else if (this.config.username && this.config.password) request.headers.Authorization = `Basic ${btoa(`${config.username}:${config.password}`)}`;
1968
+ }
1969
+ return request;
1970
+ });
1971
+ if (typeof window !== "undefined") axiosInstance.interceptors.response.use((r) => r, async (error) => {
1972
+ if (isAxiosError(error)) {
1973
+ if (error.response?.status === 401) try {
1974
+ await this.renewAuthentication();
1975
+ if (error.config) {
1976
+ if (this.accessToken) error.config.headers.Authorization = `Bearer ${this.accessToken}`;
1977
+ else delete error.config.headers.Authorization;
1978
+ return axiosInstance.request(error.config);
1979
+ }
1980
+ } catch (err) {
1981
+ return Promise.reject(err);
1982
+ }
1983
+ else if (error.response?.status === 503) {
1984
+ if ((await fetch(window.location.href)).status === 503) window.location.reload();
1985
+ }
1986
+ }
1987
+ return Promise.reject(error);
1988
+ });
1989
+ this.api = new NovaCellAPIClient(cellId, {
1990
+ ...config,
1991
+ basePath: urlJoin(this.config.instanceUrl, "/api/v1"),
1992
+ isJsonMime: (mime) => {
1993
+ return mime === "application/json";
1994
+ },
1995
+ baseOptions: {
1996
+ ...this.mock ? { adapter: (config$1) => {
1997
+ return this.mock.handleAPIRequest(config$1);
1998
+ } } : {},
1999
+ ...config.baseOptions
2000
+ },
2001
+ axiosInstance
2002
+ });
2003
+ }
2004
+ async renewAuthentication() {
2005
+ if (this.authPromise) return;
2006
+ this.authPromise = loginWithAuth0(this.config.instanceUrl);
2007
+ try {
2008
+ this.accessToken = await this.authPromise;
2009
+ if (this.accessToken) availableStorage.setString("wbjs.access_token", this.accessToken);
2010
+ else availableStorage.delete("wbjs.access_token");
2011
+ } finally {
2012
+ this.authPromise = null;
2013
+ }
2014
+ }
2015
+ makeWebsocketURL(path) {
2016
+ const url = new URL(urlJoin(this.config.instanceUrl, `/api/v1/cells/${this.config.cellId}`, path));
2017
+ url.protocol = url.protocol.replace("http", "ws");
2018
+ url.protocol = url.protocol.replace("https", "wss");
2019
+ if (this.accessToken) url.searchParams.append("token", this.accessToken);
2020
+ else if (this.config.username && this.config.password) {
2021
+ url.username = this.config.username;
2022
+ url.password = this.config.password;
2023
+ }
2024
+ return url.toString();
2025
+ }
2026
+ /**
2027
+ * Retrieve an AutoReconnectingWebsocket to the given path on the Nova instance.
2028
+ * If you explicitly want to reconnect an existing websocket, call `reconnect`
2029
+ * on the returned object.
2030
+ */
2031
+ openReconnectingWebsocket(path) {
2032
+ return new AutoReconnectingWebsocket(this.makeWebsocketURL(path), { mock: this.mock });
2033
+ }
2034
+ /**
2035
+ * Connect to the motion state websocket(s) for a given motion group
2036
+ */
2037
+ async connectMotionStream(motionGroupId) {
2038
+ return await MotionStreamConnection.open(this, motionGroupId);
2039
+ }
2040
+ /**
2041
+ * Connect to the jogging websocket(s) for a given motion group
2042
+ */
2043
+ async connectJogger(motionGroupId) {
2044
+ return await JoggerConnection.open(this, motionGroupId);
2045
+ }
2046
+ async connectMotionGroups(motionGroupIds) {
2047
+ const { instances } = await this.api.controller.listControllers();
2048
+ return Promise.all(motionGroupIds.map((motionGroupId) => ConnectedMotionGroup.connect(this, motionGroupId, instances)));
2049
+ }
2050
+ async connectMotionGroup(motionGroupId) {
2051
+ return (await this.connectMotionGroups([motionGroupId]))[0];
2052
+ }
2053
+ };
2054
+
2055
+ //#endregion
2056
+ export { ConnectedMotionGroup as a, degreesToRadians as c, radiansToDegrees as d, tryParseJson as f, JoggerConnection as i, isSameCoordinateSystem as l, NovaCellAPIClient as n, poseToWandelscriptString as o, tryStringifyJson as p, MotionStreamConnection as r, XYZ_TO_VECTOR as s, NovaClient as t, makeUrlQueryString as u };
2057
+ //# sourceMappingURL=NovaClient-B8XM3OPO.mjs.map