@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.
- package/README.md +60 -50
- package/dist/{AutoReconnectingWebsocket-BI1ckzP8.d.ts → AutoReconnectingWebsocket-CoU4ZyD2.d.cts} +1 -3
- package/dist/AutoReconnectingWebsocket-CoU4ZyD2.d.cts.map +1 -0
- package/dist/{AutoReconnectingWebsocket-Cr7f9016.d.cts → AutoReconnectingWebsocket-D0gTrkzu.d.ts} +1 -3
- package/dist/AutoReconnectingWebsocket-D0gTrkzu.d.ts.map +1 -0
- package/dist/{LoginWithAuth0-0g0wWRUC.js → LoginWithAuth0-CaX7yo7d.js} +58 -5
- package/dist/LoginWithAuth0-CaX7yo7d.js.map +1 -0
- package/dist/{LoginWithAuth0-C82OCyDy.cjs → LoginWithAuth0-DaPnTz2I.cjs} +99 -4
- package/dist/LoginWithAuth0-DaPnTz2I.cjs.map +1 -0
- package/dist/index.cjs +11 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -8
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +11 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/lib/v1/index.cjs +17 -19
- package/dist/lib/v1/index.cjs.map +1 -1
- package/dist/lib/v1/index.d.cts +4 -2
- package/dist/lib/v1/index.d.cts.map +1 -1
- package/dist/lib/v1/index.d.ts +4 -2
- package/dist/lib/v1/index.d.ts.map +1 -1
- package/dist/lib/v1/index.js +7 -10
- package/dist/lib/v1/index.js.map +1 -1
- package/dist/lib/v2/index.cjs +1087 -11
- package/dist/lib/v2/index.cjs.map +1 -1
- package/dist/lib/v2/index.d.cts +256 -7
- package/dist/lib/v2/index.d.cts.map +1 -1
- package/dist/lib/v2/index.d.ts +256 -7
- package/dist/lib/v2/index.d.ts.map +1 -1
- package/dist/lib/v2/index.js +1082 -12
- package/dist/lib/v2/index.js.map +1 -1
- package/dist/wandelscriptUtils-CO5GYRij.js +24 -0
- package/dist/wandelscriptUtils-CO5GYRij.js.map +1 -0
- package/dist/wandelscriptUtils-COHpTIme.d.cts +12 -0
- package/dist/wandelscriptUtils-COHpTIme.d.cts.map +1 -0
- package/dist/wandelscriptUtils-Cl3GBxOp.d.ts +12 -0
- package/dist/wandelscriptUtils-Cl3GBxOp.d.ts.map +1 -0
- package/dist/wandelscriptUtils-DwpJ4jCy.cjs +30 -0
- package/dist/wandelscriptUtils-DwpJ4jCy.cjs.map +1 -0
- package/package.json +2 -2
- package/src/LoginWithAuth0.ts +3 -3
- package/src/index.ts +1 -0
- package/src/lib/converters.ts +5 -23
- package/src/lib/v1/MotionStreamConnection.ts +1 -1
- package/src/lib/v1/NovaClient.ts +6 -0
- package/src/lib/v1/index.ts +6 -0
- package/src/lib/v1/mock/MockNovaInstance.ts +0 -1
- package/src/lib/v1/wandelscriptUtils.ts +22 -0
- package/src/lib/v2/ConnectedMotionGroup.ts +415 -0
- package/src/lib/v2/JoggerConnection.ts +647 -0
- package/src/lib/v2/MotionStreamConnection.ts +222 -0
- package/src/lib/v2/NovaClient.ts +43 -8
- package/src/lib/v2/index.ts +5 -0
- package/src/lib/v2/mock/MockNovaInstance.ts +385 -1
- package/src/lib/v2/motionStateUpdate.ts +76 -0
- package/src/lib/v2/types/vector3.ts +1 -0
- package/src/lib/v2/wandelscriptUtils.ts +27 -0
- package/dist/AutoReconnectingWebsocket-BI1ckzP8.d.ts.map +0 -1
- package/dist/AutoReconnectingWebsocket-Cr7f9016.d.cts.map +0 -1
- package/dist/LoginWithAuth0-0g0wWRUC.js.map +0 -1
- package/dist/LoginWithAuth0-C82OCyDy.cjs.map +0 -1
- package/dist/converters-DP2EIVv6.cjs +0 -108
- package/dist/converters-DP2EIVv6.cjs.map +0 -1
- package/dist/converters-DY6Lf7mb.js +0 -66
- package/dist/converters-DY6Lf7mb.js.map +0 -1
package/dist/lib/v2/index.cjs
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
const require_LoginWithAuth0 = require('../../LoginWithAuth0-
|
|
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/
|
|
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/
|
|
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,
|