UNPKG

@wandelbots/nova-js

Version:

Official JS client for the Wandelbots API

1,444 lines (1,433 loc) 87.8 kB
import { isEqual_default } from "../../chunk-6WCKJOFL.js"; import { AutoReconnectingWebsocket, __async, __spreadProps, __spreadValues, availableStorage, isSameCoordinateSystem, loginWithAuth0, tryParseJson } from "../../chunk-V3NJLR6P.js"; // src/lib/v1/index.ts export * from "@wandelbots/nova-api/v1"; // src/lib/v1/ConnectedMotionGroup.ts import { makeAutoObservable, runInAction } from "mobx"; import * as THREE from "three"; // src/lib/v1/motionStateUpdate.ts function jointValuesEqual(oldJointValues, newJointValues, changeDeltaThreshold) { if (newJointValues.length !== oldJointValues.length) { return true; } for (let jointIndex = 0; jointIndex < newJointValues.length; jointIndex++) { if (Math.abs(newJointValues[jointIndex] - oldJointValues[jointIndex]) > changeDeltaThreshold) { return false; } } return true; } function tcpPoseEqual(oldTcp, newTcp, changeDeltaThreshold) { if (oldTcp === void 0 && newTcp || oldTcp && newTcp === void 0) { return false; } if (oldTcp === void 0 || newTcp === void 0) { return true; } let changedDelta = 0; changedDelta += Math.abs(oldTcp.orientation.x - newTcp.orientation.x); changedDelta += Math.abs(oldTcp.orientation.y - newTcp.orientation.y); changedDelta += Math.abs(oldTcp.orientation.z - newTcp.orientation.z); changedDelta += Math.abs(oldTcp.position.x - newTcp.position.x); changedDelta += Math.abs(oldTcp.position.y - newTcp.position.y); changedDelta += Math.abs(oldTcp.position.z - newTcp.position.z); if (changedDelta > changeDeltaThreshold) { return false; } return oldTcp.coordinate_system === newTcp.coordinate_system && oldTcp.tcp === newTcp.tcp; } // src/lib/v1/ConnectedMotionGroup.ts var MOTION_DELTA_THRESHOLD = 1e-4; var ConnectedMotionGroup = class _ConnectedMotionGroup { constructor(nova, controller, motionGroup, initialMotionState, motionStateSocket, isVirtual, tcps, motionGroupSpecification, safetySetup, mounting, initialControllerState, controllerStateSocket) { this.nova = nova; this.controller = controller; this.motionGroup = motionGroup; this.initialMotionState = initialMotionState; this.motionStateSocket = motionStateSocket; this.isVirtual = isVirtual; this.tcps = tcps; this.motionGroupSpecification = motionGroupSpecification; this.safetySetup = safetySetup; this.mounting = mounting; this.initialControllerState = initialControllerState; this.controllerStateSocket = controllerStateSocket; this.connectedJoggingCartesianSocket = null; this.connectedJoggingJointsSocket = null; // tmp this.joggingVelocity = 10; /** * Reflects activation state of the motion group / robot servos. The * movement controls in the UI should only be enabled in the "active" state */ this.activationState = "inactive"; this.rapidlyChangingMotionState = initialMotionState; this.controllerState = initialControllerState; controllerStateSocket.addEventListener("message", (event) => { var _a; const data = (_a = tryParseJson(event.data)) == null ? void 0 : _a.result; if (!data) { return; } runInAction(() => { this.controllerState = data; }); }); motionStateSocket.addEventListener("message", (event) => { var _a; const motionStateResponse = (_a = tryParseJson(event.data)) == null ? void 0 : _a.result; if (!motionStateResponse) { throw new Error( `Failed to get motion state for ${this.motionGroupId}: ${event.data}` ); } if (!jointValuesEqual( this.rapidlyChangingMotionState.state.joint_position.joints, motionStateResponse.state.joint_position.joints, MOTION_DELTA_THRESHOLD )) { runInAction(() => { this.rapidlyChangingMotionState.state = motionStateResponse.state; }); } if (!tcpPoseEqual( this.rapidlyChangingMotionState.tcp_pose, motionStateResponse.tcp_pose, MOTION_DELTA_THRESHOLD )) { runInAction(() => { this.rapidlyChangingMotionState.tcp_pose = motionStateResponse.tcp_pose; }); } }); makeAutoObservable(this); } static connect(nova, motionGroupId, controllers) { return __async(this, null, function* () { var _a, _b; const [_motionGroupIndex, controllerId] = motionGroupId.split("@"); const controller = controllers.find((c) => c.controller === controllerId); const motionGroup = controller == null ? void 0 : controller.physical_motion_groups.find( (mg) => mg.motion_group === motionGroupId ); if (!controller || !motionGroup) { throw new Error( `Controller ${controllerId} or motion group ${motionGroupId} not found` ); } const motionStateSocket = nova.openReconnectingWebsocket( `/motion-groups/${motionGroupId}/state-stream` ); const firstMessage = yield motionStateSocket.firstMessage(); const initialMotionState = (_a = tryParseJson(firstMessage.data)) == null ? void 0 : _a.result; if (!initialMotionState) { throw new Error( `Unable to parse initial motion state message ${firstMessage.data}` ); } console.log( `Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state: `, initialMotionState ); const config = yield nova.api.controller.getRobotController( controller.controller ); const isVirtual = config.configuration.kind === "VirtualController"; const mounting = yield (() => __async(this, null, function* () { try { const mounting2 = yield nova.api.motionGroupInfos.getMounting( motionGroup.motion_group ); return mounting2; } catch (err) { console.error( `Error fetching mounting for ${motionGroup.motion_group}`, err ); return null; } }))(); const controllerStateSocket = nova.openReconnectingWebsocket( `/controllers/${controller.controller}/state-stream?response_rate=1000` ); const firstControllerMessage = yield controllerStateSocket.firstMessage(); const initialControllerState = (_b = tryParseJson(firstControllerMessage.data)) == null ? void 0 : _b.result; if (!initialControllerState) { throw new Error( `Unable to parse initial controller state message ${firstControllerMessage.data}` ); } console.log( `Connected controller state websocket to controller ${controller.controller}. Initial state: `, initialControllerState ); const { tcps } = yield nova.api.motionGroupInfos.listTcps(motionGroupId); const motionGroupSpecification = yield nova.api.motionGroupInfos.getMotionGroupSpecification(motionGroupId); const safetySetup = yield nova.api.motionGroupInfos.getSafetySetup(motionGroupId); return new _ConnectedMotionGroup( nova, controller, motionGroup, initialMotionState, motionStateSocket, isVirtual, tcps, motionGroupSpecification, safetySetup, mounting, initialControllerState, controllerStateSocket ); }); } get motionGroupId() { return this.motionGroup.motion_group; } get controllerId() { return this.controller.controller; } get modelFromController() { return this.motionGroup.model_from_controller; } get wandelscriptIdentifier() { const num = this.motionGroupId.split("@")[0]; return `${this.controllerId.replaceAll("-", "_")}_${num}`; } /** Jogging velocity in radians for rotation and joint movement */ get joggingVelocityRads() { return this.joggingVelocity * Math.PI / 180; } get joints() { return this.initialMotionState.state.joint_position.joints.map((_, i) => { return { index: i }; }); } get dhParameters() { return this.motionGroupSpecification.dh_parameters; } get safetyZones() { return this.safetySetup.safety_zones; } /** Gets the robot mounting position offset in 3D viz coordinates */ get mountingPosition() { if (!this.mounting) { return [0, 0, 0]; } return [ this.mounting.pose.position.x / 1e3, this.mounting.pose.position.y / 1e3, this.mounting.pose.position.z / 1e3 ]; } /** Gets the robot mounting position rotation in 3D viz coordinates */ get mountingQuaternion() { var _a, _b, _c, _d, _e, _f; const rotationVector = new THREE.Vector3( ((_b = (_a = this.mounting) == null ? void 0 : _a.pose.orientation) == null ? void 0 : _b.x) || 0, ((_d = (_c = this.mounting) == null ? void 0 : _c.pose.orientation) == null ? void 0 : _d.y) || 0, ((_f = (_e = this.mounting) == null ? void 0 : _e.pose.orientation) == null ? void 0 : _f.z) || 0 ); const magnitude = rotationVector.length(); const axis = rotationVector.normalize(); return new THREE.Quaternion().setFromAxisAngle(axis, magnitude); } /** * Whether the controller is currently in a safety state * corresponding to an emergency stop */ get isEstopActive() { const estopStates = [ "SAFETY_STATE_ROBOT_EMERGENCY_STOP", "SAFETY_STATE_DEVICE_EMERGENCY_STOP" ]; return estopStates.includes(this.controllerState.safety_state); } /** * Whether the controller is in a safety state * that may be non-functional for robot pad purposes */ get isMoveableSafetyState() { const goodSafetyStates = [ "SAFETY_STATE_NORMAL", "SAFETY_STATE_REDUCED" ]; return goodSafetyStates.includes(this.controllerState.safety_state); } /** * Whether the controller is in an operation mode that allows movement */ get isMoveableOperationMode() { const goodOperationModes = [ "OPERATION_MODE_AUTO", "OPERATION_MODE_MANUAL", "OPERATION_MODE_MANUAL_T1", "OPERATION_MODE_MANUAL_T2" ]; return goodOperationModes.includes(this.controllerState.operation_mode); } /** * Whether the robot is currently active and can be moved, based on the * safety state, operation mode and servo toggle activation state. */ get canBeMoved() { return this.isMoveableSafetyState && this.isMoveableOperationMode && this.activationState === "active"; } deactivate() { return __async(this, null, function* () { if (this.activationState !== "active") { console.error("Tried to deactivate while already deactivating"); return; } runInAction(() => { this.activationState = "deactivating"; }); try { yield this.nova.api.controller.setDefaultMode( this.controllerId, "MODE_MONITOR" ); runInAction(() => { this.activationState = "inactive"; }); } catch (err) { runInAction(() => { this.activationState = "active"; }); throw err; } }); } activate() { return __async(this, null, function* () { if (this.activationState !== "inactive") { console.error("Tried to activate while already activating"); return; } runInAction(() => { this.activationState = "activating"; }); try { yield this.nova.api.controller.setDefaultMode( this.controllerId, "MODE_CONTROL" ); runInAction(() => { this.activationState = "active"; }); } catch (err) { runInAction(() => { this.activationState = "inactive"; }); throw err; } }); } toggleActivation() { if (this.activationState === "inactive") { this.activate(); } else if (this.activationState === "active") { this.deactivate(); } } dispose() { this.motionStateSocket.close(); if (this.connectedJoggingCartesianSocket) this.connectedJoggingCartesianSocket.close(); if (this.connectedJoggingJointsSocket) this.connectedJoggingJointsSocket.close(); } setJoggingVelocity(velocity) { this.joggingVelocity = velocity; } }; // src/lib/v1/getLatestTrajectories.ts var lastMotionIds = /* @__PURE__ */ new Set(); function getLatestTrajectories(apiClient, sampleTime = 50, responsesCoordinateSystem) { return __async(this, null, function* () { const newTrajectories = []; try { const motions = yield apiClient.motion.listMotions(); const currentMotionIds = new Set(motions.motions); const newMotionIds = Array.from(currentMotionIds).filter( (id) => !lastMotionIds.has(id) ); for (const motionId of newMotionIds) { const trajectory = yield apiClient.motion.getMotionTrajectory( motionId, sampleTime, responsesCoordinateSystem ); newTrajectories.push(trajectory); } lastMotionIds = currentMotionIds; } catch (error) { console.error("Failed to get latest trajectories:", error); } return newTrajectories; }); } // src/lib/v1/JoggerConnection.ts import { Vector3 as Vector32 } from "three/src/math/Vector3.js"; var JoggerConnection = class _JoggerConnection { constructor(motionStream, opts = {}) { this.motionStream = motionStream; this.opts = opts; // Currently a separate websocket is needed for each mode, pester API people // to merge these for simplicity this.cartesianWebsocket = null; this.jointWebsocket = null; this.cartesianJoggingOpts = {}; } static open(_0, _1) { return __async(this, arguments, function* (nova, motionGroupId, opts = {}) { const motionStream = yield nova.connectMotionStream(motionGroupId); return new _JoggerConnection(motionStream, opts); }); } get motionGroupId() { return this.motionStream.motionGroupId; } get nova() { return this.motionStream.nova; } get numJoints() { return this.motionStream.joints.length; } get activeJoggingMode() { if (this.cartesianWebsocket) return "cartesian"; if (this.jointWebsocket) return "joint"; return "increment"; } get activeWebsocket() { return this.cartesianWebsocket || this.jointWebsocket; } stop() { return __async(this, null, function* () { if (this.cartesianWebsocket) { this.cartesianWebsocket.sendJson({ motion_group: this.motionGroupId, position_direction: { x: 0, y: 0, z: 0 }, rotation_direction: { x: 0, y: 0, z: 0 }, position_velocity: 0, rotation_velocity: 0, tcp: this.cartesianJoggingOpts.tcpId, coordinate_system: this.cartesianJoggingOpts.coordSystemId }); } if (this.jointWebsocket) { this.jointWebsocket.sendJson({ motion_group: this.motionGroupId, joint_velocities: new Array(this.numJoints).fill(0) }); } }); } dispose() { if (this.cartesianWebsocket) { this.cartesianWebsocket.dispose(); } if (this.jointWebsocket) { this.jointWebsocket.dispose(); } } setJoggingMode(mode, cartesianJoggingOpts) { console.log("Setting jogging mode to", mode); if (cartesianJoggingOpts) { if (!isEqual_default(this.cartesianJoggingOpts, cartesianJoggingOpts)) { if (this.cartesianWebsocket) { this.cartesianWebsocket.dispose(); this.cartesianWebsocket = null; } } this.cartesianJoggingOpts = cartesianJoggingOpts; } if (mode !== "cartesian" && this.cartesianWebsocket) { this.cartesianWebsocket.dispose(); this.cartesianWebsocket = null; } if (mode !== "joint" && this.jointWebsocket) { this.jointWebsocket.dispose(); this.jointWebsocket = null; } if (mode === "cartesian" && !this.cartesianWebsocket) { this.cartesianWebsocket = this.nova.openReconnectingWebsocket( `/motion-groups/move-tcp` ); this.cartesianWebsocket.addEventListener( "message", (ev) => { const data = tryParseJson(ev.data); if (data && "error" in data) { if (this.opts.onError) { this.opts.onError(ev.data); } else { throw new Error(ev.data); } } } ); } if (mode === "joint" && !this.jointWebsocket) { this.jointWebsocket = this.nova.openReconnectingWebsocket( `/motion-groups/move-joint` ); this.jointWebsocket.addEventListener("message", (ev) => { const data = tryParseJson(ev.data); if (data && "error" in data) { if (this.opts.onError) { this.opts.onError(ev.data); } else { throw new Error(ev.data); } } }); } } /** * Start rotation of a single robot joint at the specified velocity */ startJointRotation(_0) { return __async(this, arguments, function* ({ joint, direction, velocityRadsPerSec }) { if (!this.jointWebsocket) { throw new Error( "Joint jogging websocket not connected; call setJoggingMode first" ); } const jointVelocities = new Array(this.numJoints).fill(0); jointVelocities[joint] = direction === "-" ? -velocityRadsPerSec : velocityRadsPerSec; this.jointWebsocket.sendJson({ motion_group: this.motionGroupId, joint_velocities: jointVelocities }); }); } /** * Start the TCP moving along a specified axis at a given velocity */ startTCPTranslation(_0) { return __async(this, arguments, function* ({ axis, direction, velocityMmPerSec }) { if (!this.cartesianWebsocket) { throw new Error( "Cartesian jogging websocket not connected; call setJoggingMode first" ); } const zeroVector = { x: 0, y: 0, z: 0 }; const joggingVector = Object.assign({}, zeroVector); joggingVector[axis] = direction === "-" ? -1 : 1; this.cartesianWebsocket.sendJson({ motion_group: this.motionGroupId, position_direction: joggingVector, rotation_direction: zeroVector, position_velocity: velocityMmPerSec, rotation_velocity: 0, tcp: this.cartesianJoggingOpts.tcpId, coordinate_system: this.cartesianJoggingOpts.coordSystemId }); }); } /** * Start the TCP rotating around a specified axis at a given velocity */ startTCPRotation(_0) { return __async(this, arguments, function* ({ axis, direction, velocityRadsPerSec }) { if (!this.cartesianWebsocket) { throw new Error( "Cartesian jogging websocket not connected; call setJoggingMode first" ); } const zeroVector = { x: 0, y: 0, z: 0 }; const joggingVector = Object.assign({}, zeroVector); joggingVector[axis] = direction === "-" ? -1 : 1; this.cartesianWebsocket.sendJson({ motion_group: this.motionGroupId, position_direction: zeroVector, rotation_direction: joggingVector, position_velocity: 0, rotation_velocity: velocityRadsPerSec, tcp: this.cartesianJoggingOpts.tcpId, coordinate_system: this.cartesianJoggingOpts.coordSystemId }); }); } /** * Move the robot by a fixed distance in a single cartesian * axis, either rotating or translating relative to the TCP. * Promise resolves only after the motion has completed. */ runIncrementalCartesianMotion(_0) { return __async(this, arguments, function* ({ currentTcpPose, currentJoints, coordSystemId, velocityInRelevantUnits, axis, direction, motion }) { var _a; const commands = []; if (!isSameCoordinateSystem(currentTcpPose.coordinate_system, coordSystemId)) { throw new Error( `Current TCP pose coordinate system ${currentTcpPose.coordinate_system} does not match target coordinate system ${coordSystemId}` ); } if (motion.type === "translate") { const targetTcpPosition = Object.assign({}, currentTcpPose.position); targetTcpPosition[axis] += motion.distanceMm * (direction === "-" ? -1 : 1); commands.push({ settings: { limits_override: { tcp_velocity_limit: velocityInRelevantUnits } }, line: { position: targetTcpPosition, orientation: currentTcpPose.orientation, coordinate_system: coordSystemId } }); } else if (motion.type === "rotate") { const currentRotationVector = new Vector32( currentTcpPose.orientation["x"], currentTcpPose.orientation["y"], currentTcpPose.orientation["z"] ); const currentRotationRad = currentRotationVector.length(); const currentRotationDirection = currentRotationVector.clone().normalize(); const differenceRotationRad = motion.distanceRads * (direction === "-" ? -1 : 1); const differenceRotationDirection = new Vector32(0, 0, 0); differenceRotationDirection[axis] = 1; const f1 = Math.cos(0.5 * differenceRotationRad) * Math.cos(0.5 * currentRotationRad); const f2 = Math.sin(0.5 * differenceRotationRad) * Math.sin(0.5 * currentRotationRad); const f3 = Math.sin(0.5 * differenceRotationRad) * Math.cos(0.5 * currentRotationRad); const f4 = Math.cos(0.5 * differenceRotationRad) * Math.sin(0.5 * currentRotationRad); const dotProduct = differenceRotationDirection.dot( currentRotationDirection ); const crossProduct = differenceRotationDirection.clone().cross(currentRotationDirection); const newRotationRad = 2 * Math.acos(f1 - f2 * dotProduct); const f5 = newRotationRad / Math.sin(0.5 * newRotationRad); const targetTcpOrientation = new Vector32().addScaledVector(crossProduct, f2).addScaledVector(differenceRotationDirection, f3).addScaledVector(currentRotationDirection, f4).multiplyScalar(f5); commands.push({ settings: { limits_override: { tcp_orientation_velocity_limit: velocityInRelevantUnits } }, line: { position: currentTcpPose.position, orientation: targetTcpOrientation, coordinate_system: coordSystemId } }); } const motionPlanRes = yield this.nova.api.motion.planMotion({ motion_group: this.motionGroupId, start_joint_position: currentJoints, tcp: this.cartesianJoggingOpts.tcpId, commands }); const plannedMotion = (_a = motionPlanRes.plan_successful_response) == null ? void 0 : _a.motion; if (!plannedMotion) { throw new Error( `Failed to plan jogging increment motion ${JSON.stringify(motionPlanRes)}` ); } yield this.nova.api.motion.streamMoveForward( plannedMotion, 100, void 0, void 0, void 0, { // Might take a while at low velocity timeout: 1e3 * 60 } ); }); } /** * Rotate a single robot joint by a fixed number of radians * Promise resolves only after the motion has completed. */ runIncrementalJointRotation(_0) { return __async(this, arguments, function* ({ joint, currentJoints, velocityRadsPerSec, direction, distanceRads }) { var _a; const targetJoints = [...currentJoints.joints]; targetJoints[joint] += distanceRads * (direction === "-" ? -1 : 1); const jointVelocityLimits = new Array( currentJoints.joints.length ).fill(velocityRadsPerSec); const motionPlanRes = yield this.nova.api.motion.planMotion({ motion_group: this.motionGroupId, start_joint_position: currentJoints, commands: [ { settings: { limits_override: { joint_velocity_limits: { joints: jointVelocityLimits } } }, joint_ptp: { joints: targetJoints } } ] }); const plannedMotion = (_a = motionPlanRes.plan_successful_response) == null ? void 0 : _a.motion; if (!plannedMotion) { console.error("Failed to plan jogging increment motion", motionPlanRes); return; } yield this.nova.api.motion.streamMoveForward( plannedMotion, 100, void 0, void 0, void 0, { // Might take a while at low velocity timeout: 1e3 * 60 } ); }); } }; // src/lib/v1/MotionStreamConnection.ts import { makeAutoObservable as makeAutoObservable2, runInAction as runInAction2 } from "mobx"; import { Vector3 as Vector33 } from "three"; var MOTION_DELTA_THRESHOLD2 = 1e-4; function unwrapRotationVector(newRotationVectorApi, currentRotationVectorApi) { const currentRotationVector = new Vector33( currentRotationVectorApi.x, currentRotationVectorApi.y, currentRotationVectorApi.z ); const newRotationVector = new Vector33( newRotationVectorApi.x, newRotationVectorApi.y, newRotationVectorApi.z ); const currentAngle = currentRotationVector.length(); const currentAxis = currentRotationVector.normalize(); let newAngle = newRotationVector.length(); let newAxis = newRotationVector.normalize(); if (newAxis.dot(currentAxis) < 0) { newAngle = -newAngle; newAxis = newAxis.multiplyScalar(-1); } let angleDifference = newAngle - currentAngle; angleDifference -= 2 * Math.PI * Math.floor((angleDifference + Math.PI) / (2 * Math.PI)); newAngle = currentAngle + angleDifference; return newAxis.multiplyScalar(newAngle); } var MotionStreamConnection = class _MotionStreamConnection { constructor(nova, controller, motionGroup, initialMotionState, motionStateSocket) { this.nova = nova; this.controller = controller; this.motionGroup = motionGroup; this.initialMotionState = initialMotionState; this.motionStateSocket = motionStateSocket; this.rapidlyChangingMotionState = initialMotionState; motionStateSocket.addEventListener("message", (event) => { var _a; const motionStateResponse = (_a = tryParseJson(event.data)) == null ? void 0 : _a.result; if (!motionStateResponse) { throw new Error( `Failed to get motion state for ${this.motionGroupId}: ${event.data}` ); } if (!jointValuesEqual( this.rapidlyChangingMotionState.state.joint_position.joints, motionStateResponse.state.joint_position.joints, MOTION_DELTA_THRESHOLD2 )) { runInAction2(() => { this.rapidlyChangingMotionState.state = motionStateResponse.state; }); } if (!tcpPoseEqual( this.rapidlyChangingMotionState.tcp_pose, motionStateResponse.tcp_pose, MOTION_DELTA_THRESHOLD2 )) { runInAction2(() => { if (this.rapidlyChangingMotionState.tcp_pose == void 0) { this.rapidlyChangingMotionState.tcp_pose = motionStateResponse.tcp_pose; } else { this.rapidlyChangingMotionState.tcp_pose = { position: motionStateResponse.tcp_pose.position, orientation: unwrapRotationVector( motionStateResponse.tcp_pose.orientation, this.rapidlyChangingMotionState.tcp_pose.orientation ), tcp: motionStateResponse.tcp_pose.tcp, coordinate_system: motionStateResponse.tcp_pose.coordinate_system }; } }); } }); makeAutoObservable2(this); } static open(nova, motionGroupId) { return __async(this, null, function* () { var _a; const { instances: controllers } = yield nova.api.controller.listControllers(); const [_motionGroupIndex, controllerId] = motionGroupId.split("@"); const controller = controllers.find((c) => c.controller === controllerId); const motionGroup = controller == null ? void 0 : controller.physical_motion_groups.find( (mg) => mg.motion_group === motionGroupId ); if (!controller || !motionGroup) { throw new Error( `Controller ${controllerId} or motion group ${motionGroupId} not found` ); } const motionStateSocket = nova.openReconnectingWebsocket( `/motion-groups/${motionGroupId}/state-stream` ); const firstMessage = yield motionStateSocket.firstMessage(); console.log("got first message", firstMessage); const initialMotionState = (_a = tryParseJson(firstMessage.data)) == null ? void 0 : _a.result; if (!initialMotionState) { throw new Error( `Unable to parse initial motion state message ${firstMessage.data}` ); } console.log( `Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state: `, initialMotionState ); return new _MotionStreamConnection( nova, controller, motionGroup, initialMotionState, motionStateSocket ); }); } get motionGroupId() { return this.motionGroup.motion_group; } get controllerId() { return this.controller.controller; } get modelFromController() { return this.motionGroup.model_from_controller; } get wandelscriptIdentifier() { const num = this.motionGroupId.split("@")[0]; return `${this.controllerId.replaceAll("-", "_")}_${num}`; } get joints() { return this.initialMotionState.state.joint_position.joints.map((_, i) => { return { index: i }; }); } dispose() { this.motionStateSocket.close(); } }; // src/lib/v1/NovaCellAPIClient.ts 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"; import axios from "axios"; var NovaCellAPIClient = class { constructor(cellId, opts) { this.cellId = cellId; this.opts = opts; this.system = this.withUnwrappedResponsesOnly(SystemApi); this.cell = this.withUnwrappedResponsesOnly(CellApi); this.deviceConfig = this.withCellId(DeviceConfigurationApi); this.motionGroup = this.withCellId(MotionGroupApi); this.motionGroupInfos = this.withCellId(MotionGroupInfosApi); this.controller = this.withCellId(ControllerApi); this.program = this.withCellId(ProgramApi); this.programValues = this.withCellId(ProgramValuesApi); this.controllerIOs = this.withCellId(ControllerIOsApi); this.motionGroupKinematic = this.withCellId(MotionGroupKinematicApi); this.motion = this.withCellId(MotionApi); this.coordinateSystems = this.withCellId(CoordinateSystemsApi); this.application = this.withCellId(ApplicationApi); this.applicationGlobal = this.withUnwrappedResponsesOnly(ApplicationApi); this.motionGroupJogging = this.withCellId(MotionGroupJoggingApi); this.virtualRobot = this.withCellId(VirtualRobotApi); this.virtualRobotSetup = this.withCellId(VirtualRobotSetupApi); this.virtualRobotMode = this.withCellId(VirtualRobotModeApi); this.virtualRobotBehavior = this.withCellId(VirtualRobotBehaviorApi); this.libraryProgramMetadata = this.withCellId(LibraryProgramMetadataApi); this.libraryProgram = this.withCellId(LibraryProgramApi); this.libraryRecipeMetadata = this.withCellId(LibraryRecipeMetadataApi); this.libraryRecipe = this.withCellId(LibraryRecipeApi); this.storeObject = this.withCellId(StoreObjectApi); this.storeCollisionComponents = this.withCellId( StoreCollisionComponentsApi ); this.storeCollisionScenes = this.withCellId(StoreCollisionScenesApi); } /** * Some TypeScript sorcery which alters the API class methods so you don't * have to pass the cell id to every single one, and de-encapsulates the * response data */ withCellId(ApiConstructor) { var _a, _b; const apiClient = new ApiConstructor( __spreadProps(__spreadValues({}, this.opts), { isJsonMime: (mime) => { return mime === "application/json"; } }), (_a = this.opts.basePath) != null ? _a : "", (_b = this.opts.axiosInstance) != null ? _b : axios.create() ); for (const key of Reflect.ownKeys(Reflect.getPrototypeOf(apiClient))) { if (key !== "constructor" && typeof apiClient[key] === "function") { const originalFunction = apiClient[key]; apiClient[key] = (...args) => { return originalFunction.apply(apiClient, [this.cellId, ...args]).then((res) => res.data); }; } } return apiClient; } /** * As withCellId, but only does the response unwrapping */ withUnwrappedResponsesOnly(ApiConstructor) { var _a, _b; const apiClient = new ApiConstructor( __spreadProps(__spreadValues({}, this.opts), { isJsonMime: (mime) => { return mime === "application/json"; } }), (_a = this.opts.basePath) != null ? _a : "", (_b = this.opts.axiosInstance) != null ? _b : axios.create() ); for (const key of Reflect.ownKeys(Reflect.getPrototypeOf(apiClient))) { if (key !== "constructor" && typeof apiClient[key] === "function") { const originalFunction = apiClient[key]; apiClient[key] = (...args) => { return originalFunction.apply(apiClient, args).then((res) => res.data); }; } } return apiClient; } }; // src/lib/v1/NovaClient.ts import axios2, { isAxiosError } from "axios"; import urlJoin from "url-join"; // src/lib/v1/mock/MockNovaInstance.ts import { AxiosError } from "axios"; import * as pathToRegexp from "path-to-regexp"; var MockNovaInstance = class { constructor() { this.connections = []; } handleAPIRequest(config) { return __async(this, null, function* () { var _a, _b, _c; const apiHandlers = [ { method: "GET", path: "/cells/:cellId/controllers", handle() { return { instances: [ { controller: "mock-ur5e", model_name: "UniversalRobots::Controller", host: "mock-ur5e", allow_software_install_on_controller: true, physical_motion_groups: [ { motion_group: "0@mock-ur5e", name_from_controller: "UR5e", active: false, model_from_controller: "UniversalRobots_UR5e" } ], has_error: false, error_details: "" } ] }; } }, { method: "GET", path: "/cells/:cellId/controllers/:controllerId", handle() { return { configuration: { kind: "VirtualController", manufacturer: "universalrobots", position: "[0,-1.571,-1.571,-1.571,1.571,-1.571,0]", type: "universalrobots-ur5e" }, name: "mock-ur5" }; } }, { method: "GET", path: "/cells/:cellId/motion-groups/:motionGroupId/specification", handle() { return { dh_parameters: [ { alpha: 1.5707963267948966, theta: 0, a: 0, d: 162.25, reverse_rotation_direction: false }, { alpha: 0, theta: 0, a: -425, d: 0, reverse_rotation_direction: false }, { alpha: 0, theta: 0, a: -392.2, d: 0, reverse_rotation_direction: false }, { alpha: 1.5707963267948966, theta: 0, a: 0, d: 133.3, reverse_rotation_direction: false }, { alpha: -1.5707963267948966, theta: 0, a: 0, d: 99.7, reverse_rotation_direction: false }, { alpha: 0, theta: 0, a: 0, d: 99.6, reverse_rotation_direction: false } ], mechanical_joint_limits: [ { joint: "JOINTNAME_AXIS_1", lower_limit: -6.335545063018799, upper_limit: 6.335545063018799, unlimited: false }, { joint: "JOINTNAME_AXIS_2", lower_limit: -6.335545063018799, upper_limit: 6.335545063018799, unlimited: false }, { joint: "JOINTNAME_AXIS_3", lower_limit: -6.335545063018799, upper_limit: 6.335545063018799, unlimited: false }, { joint: "JOINTNAME_AXIS_4", lower_limit: -6.335545063018799, upper_limit: 6.335545063018799, unlimited: false }, { joint: "JOINTNAME_AXIS_5", lower_limit: -6.335545063018799, upper_limit: 6.335545063018799, unlimited: false }, { joint: "JOINTNAME_AXIS_6", lower_limit: -6.335545063018799, upper_limit: 6.335545063018799, unlimited: false } ] }; } }, { method: "GET", path: "/cells/:cellId/motion-groups/:motionGroupId/safety-setup", handle() { return { safety_settings: [ { safety_state: "SAFETY_NORMAL", settings: { joint_position_limits: [ { joint: "JOINTNAME_AXIS_1", lower_limit: -2.96705961227417, upper_limit: 2.96705961227417, unlimited: false }, { joint: "JOINTNAME_AXIS_2", lower_limit: -1.7453292608261108, upper_limit: 2.7925267219543457, unlimited: false }, { joint: "JOINTNAME_AXIS_3", lower_limit: -3.3161256313323975, upper_limit: 0.40142571926116943, unlimited: false }, { joint: "JOINTNAME_AXIS_4", lower_limit: -3.4906585216522217, upper_limit: 3.4906585216522217, unlimited: false }, { joint: "JOINTNAME_AXIS_5", lower_limit: -2.4434609413146973, upper_limit: 2.4434609413146973, unlimited: false }, { joint: "JOINTNAME_AXIS_6", lower_limit: -4.71238899230957, upper_limit: 4.71238899230957, unlimited: false } ], joint_velocity_limits: [ { joint: "JOINTNAME_AXIS_1", limit: 3.1415927410125732 }, { joint: "JOINTNAME_AXIS_2", limit: 3.1415927410125732 }, { joint: "JOINTNAME_AXIS_3", limit: 3.4906585216522217 }, { joint: "JOINTNAME_AXIS_4", limit: 6.108652591705322 }, { joint: "JOINTNAME_AXIS_5", limit: 6.108652591705322 }, { joint: "JOINTNAME_AXIS_6", limit: 6.981317043304443 } ], joint_acceleration_limits: [], joint_torque_limits: [], tcp_velocity_limit: 1800 } } ], safety_zones: [ { id: 1, priority: 0, geometry: { compound: { child_geometries: [ { convex_hull: { vertices: [ { x: -800, y: -1330, z: -1820 }, { x: 1650, y: -1330, z: -1820 }, { x: 1650, y: 1330, z: -1820 }, { x: -800, y: 1330, z: -1820 } ] }, init_pose: { position: { x: 0, y: 0, z: 0 }, orientation: { x: 0, y: 0, z: 0, w: 1 } }, id: "box" }, { convex_hull: { vertices: [ { x: -800, y: -1330, z: -1820 }, { x: 1650, y: -1330, z: -1820 }, { x: 1650, y: -1330, z: 1500 }, { x: -800, y: -1330, z: 1500 } ] }, init_pose: { position: { x: 0, y: 0, z: 0 }, orientation: { x: 0, y: 0, z: 0, w: 1 } }, id: "box" }, { convex_hull: { vertices: [ { x: -800, y: -1330, z: -1820 }, { x: -800, y: 1330, z: -1820 }, { x: -800, y: 1330, z: 1500 }, { x: -800, y: -1330, z: 1500 } ] }, init_pose: { position: { x: 0, y: 0, z: 0 }, orientation: { x: 0, y: 0, z: 0, w: 1 } }, id: "box" }, { convex_hull: { vertices: [ { x: 1650, y: 1330, z: 1500 }, { x: -800, y: 1330, z: 1500 }, { x: -800, y: -1330, z: 1500 }, { x: 1650, y: -1330, z: 1500 } ] }, init_pose: { position: { x: 0, y: 0, z: 0 }, orientation: { x: 0, y: 0, z: 0, w: 1 } }, id: "box" }, { convex_hull: { vertices: [ { x: 1650, y: 1330, z: 1500 }, { x: -800, y: 1330, z: 1500 }, { x: -800, y: 1330, z: -1820 }, { x: 1650, y: 1330, z: -1820 } ] }, init_pose: { position: { x: 0, y: 0, z: 0 }, orientation: { x: 0, y: 0, z: 0, w: 1 } }, id: "box" }, { convex_hull: { vertices: [ { x: 1650, y: 1330, z: 1500 }, { x: 1650, y: -1330, z: 1500 }, { x: 1650, y: -1330, z: -1820 }, {