@wandelbots/nova-js 2.1.4 → 3.0.0-pr.bugfix-compatible-with-non-dom-envs.115.33da73d
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 +29 -1
- package/dist/LoginWithAuth0.d.ts.map +1 -1
- package/dist/{chunk-6WCKJOFL.js → chunk-4FP7NTKS.js} +51 -1
- package/dist/chunk-4FP7NTKS.js.map +1 -0
- package/dist/{chunk-V3NJLR6P.js → chunk-GVLDRXDW.js} +2 -52
- package/dist/chunk-GVLDRXDW.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +8 -8
- package/dist/lib/AutoReconnectingWebsocket.d.ts +2 -2
- package/dist/lib/AutoReconnectingWebsocket.d.ts.map +1 -1
- package/dist/lib/availableStorage.d.ts +1 -1
- package/dist/lib/availableStorage.d.ts.map +1 -1
- package/dist/lib/v1/NovaClient.d.ts +1 -1
- package/dist/lib/v1/NovaClient.d.ts.map +1 -1
- package/dist/lib/v1/index.cjs +1 -1
- package/dist/lib/v1/index.cjs.map +1 -1
- package/dist/lib/v1/index.js +6 -6
- package/dist/lib/v1/index.js.map +1 -1
- package/dist/lib/v2/NovaCellAPIClient.d.ts +9 -11
- package/dist/lib/v2/NovaCellAPIClient.d.ts.map +1 -1
- package/dist/lib/v2/NovaClient.d.ts +0 -8
- package/dist/lib/v2/NovaClient.d.ts.map +1 -1
- package/dist/lib/v2/index.cjs +29 -772
- package/dist/lib/v2/index.cjs.map +1 -1
- package/dist/lib/v2/index.d.ts +0 -4
- package/dist/lib/v2/index.d.ts.map +1 -1
- package/dist/lib/v2/index.js +32 -764
- package/dist/lib/v2/index.js.map +1 -1
- package/dist/lib/v2/mock/MockNovaInstance.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/LoginWithAuth0.ts +5 -0
- package/src/lib/AutoReconnectingWebsocket.ts +6 -2
- package/src/lib/availableStorage.ts +5 -2
- package/src/lib/v1/NovaClient.ts +7 -1
- package/src/lib/v2/NovaCellAPIClient.ts +22 -22
- package/src/lib/v2/NovaClient.ts +7 -28
- package/src/lib/v2/index.ts +0 -4
- package/src/lib/v2/mock/MockNovaInstance.ts +9 -32
- package/src/types/non-dom.d.ts +118 -0
- package/dist/chunk-6WCKJOFL.js.map +0 -1
- package/dist/chunk-V3NJLR6P.js.map +0 -1
- package/dist/lib/v2/ConnectedMotionGroup.d.ts +0 -41
- package/dist/lib/v2/ConnectedMotionGroup.d.ts.map +0 -1
- package/dist/lib/v2/JoggerConnection.d.ts +0 -53
- package/dist/lib/v2/JoggerConnection.d.ts.map +0 -1
- package/dist/lib/v2/MotionStreamConnection.d.ts +0 -25
- package/dist/lib/v2/MotionStreamConnection.d.ts.map +0 -1
- package/dist/lib/v2/ProgramStateConnection.d.ts +0 -53
- package/dist/lib/v2/ProgramStateConnection.d.ts.map +0 -1
- package/dist/lib/v2/motionStateUpdate.d.ts +0 -4
- package/dist/lib/v2/motionStateUpdate.d.ts.map +0 -1
- package/src/lib/v2/ConnectedMotionGroup.ts +0 -216
- package/src/lib/v2/JoggerConnection.ts +0 -207
- package/src/lib/v2/MotionStreamConnection.ts +0 -201
- package/src/lib/v2/ProgramStateConnection.ts +0 -249
- package/src/lib/v2/motionStateUpdate.ts +0 -55
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Controller,
|
|
3
|
-
MotionGroupPhysical,
|
|
4
|
-
MotionGroupState,
|
|
5
|
-
} from "@wandelbots/nova-api/v2"
|
|
6
|
-
import { makeAutoObservable, runInAction } from "mobx"
|
|
7
|
-
import * as THREE from "three"
|
|
8
|
-
import type { AutoReconnectingWebsocket } from "../AutoReconnectingWebsocket"
|
|
9
|
-
import { tryParseJson } from "../converters"
|
|
10
|
-
import { jointValuesEqual, tcpPoseEqual } from "./motionStateUpdate"
|
|
11
|
-
import type { NovaClient } from "./NovaClient"
|
|
12
|
-
import { Vector3d, vector3ToArray } from "./vectorUtils"
|
|
13
|
-
|
|
14
|
-
const MOTION_DELTA_THRESHOLD = 0.0001
|
|
15
|
-
|
|
16
|
-
function unwrapRotationVector(
|
|
17
|
-
newRotationVectorApi: Vector3d,
|
|
18
|
-
currentRotationVectorApi: Vector3d,
|
|
19
|
-
): Vector3d {
|
|
20
|
-
const currentRotationVector = new THREE.Vector3(
|
|
21
|
-
currentRotationVectorApi[0],
|
|
22
|
-
currentRotationVectorApi[1],
|
|
23
|
-
currentRotationVectorApi[2],
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
const newRotationVector = new THREE.Vector3(
|
|
27
|
-
newRotationVectorApi[0],
|
|
28
|
-
newRotationVectorApi[1],
|
|
29
|
-
newRotationVectorApi[2],
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
const currentAngle = currentRotationVector.length()
|
|
33
|
-
const currentAxis = currentRotationVector.normalize()
|
|
34
|
-
|
|
35
|
-
let newAngle = newRotationVector.length()
|
|
36
|
-
let newAxis = newRotationVector.normalize()
|
|
37
|
-
|
|
38
|
-
// Align rotation axes
|
|
39
|
-
if (newAxis.dot(currentAxis) < 0) {
|
|
40
|
-
newAngle = -newAngle
|
|
41
|
-
newAxis = newAxis.multiplyScalar(-1.0)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Shift rotation angle close to previous one to extend domain of rotation angles beyond [0, pi]
|
|
45
|
-
// - this simplifies interpolation and prevents abruptly changing signs of the rotation angles
|
|
46
|
-
let angleDifference = newAngle - currentAngle
|
|
47
|
-
angleDifference -=
|
|
48
|
-
2.0 * Math.PI * Math.floor((angleDifference + Math.PI) / (2.0 * Math.PI))
|
|
49
|
-
|
|
50
|
-
newAngle = currentAngle + angleDifference
|
|
51
|
-
|
|
52
|
-
return vector3ToArray(newAxis.multiplyScalar(newAngle))
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Store representing the current state of a connected motion group.
|
|
57
|
-
*/
|
|
58
|
-
export class MotionStreamConnection {
|
|
59
|
-
static async open(nova: NovaClient, motionGroupId: string) {
|
|
60
|
-
const { controllers: controllers } =
|
|
61
|
-
await nova.api.controller.listControllers()
|
|
62
|
-
|
|
63
|
-
const [_motionGroupIndex, controllerId] = motionGroupId.split("@") as [
|
|
64
|
-
string,
|
|
65
|
-
string,
|
|
66
|
-
]
|
|
67
|
-
const controller = controllers.find((c) => c.controller === controllerId)
|
|
68
|
-
const motionGroup = controller?.motion_groups.find(
|
|
69
|
-
(mg) => mg.motion_group === motionGroupId,
|
|
70
|
-
)
|
|
71
|
-
if (!controller || !motionGroup) {
|
|
72
|
-
throw new Error(
|
|
73
|
-
`Controller ${controllerId} or motion group ${motionGroupId} not found`,
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const motionStateSocket = nova.openReconnectingWebsocket(
|
|
78
|
-
`/motion-groups/${motionGroupId}/state-stream`,
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
// Wait for the first message to get the initial state
|
|
82
|
-
const firstMessage = await motionStateSocket.firstMessage()
|
|
83
|
-
console.log("got first message", firstMessage)
|
|
84
|
-
const initialMotionState = tryParseJson(firstMessage.data)
|
|
85
|
-
?.result as MotionGroupState
|
|
86
|
-
|
|
87
|
-
if (!initialMotionState) {
|
|
88
|
-
throw new Error(
|
|
89
|
-
`Unable to parse initial motion state message ${firstMessage.data}`,
|
|
90
|
-
)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
console.log(
|
|
94
|
-
`Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state:\n `,
|
|
95
|
-
initialMotionState,
|
|
96
|
-
)
|
|
97
|
-
|
|
98
|
-
return new MotionStreamConnection(
|
|
99
|
-
nova,
|
|
100
|
-
controller,
|
|
101
|
-
motionGroup,
|
|
102
|
-
initialMotionState,
|
|
103
|
-
motionStateSocket,
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Not mobx-observable as this changes very fast; should be observed
|
|
108
|
-
// using animation frames
|
|
109
|
-
rapidlyChangingMotionState: MotionGroupState
|
|
110
|
-
|
|
111
|
-
constructor(
|
|
112
|
-
readonly nova: NovaClient,
|
|
113
|
-
readonly controller: Controller,
|
|
114
|
-
readonly motionGroup: MotionGroupPhysical,
|
|
115
|
-
readonly initialMotionState: MotionGroupState,
|
|
116
|
-
readonly motionStateSocket: AutoReconnectingWebsocket,
|
|
117
|
-
) {
|
|
118
|
-
this.rapidlyChangingMotionState = initialMotionState
|
|
119
|
-
|
|
120
|
-
motionStateSocket.addEventListener("message", (event) => {
|
|
121
|
-
const motionState = tryParseJson(event.data)?.result as
|
|
122
|
-
| MotionGroupState
|
|
123
|
-
| undefined
|
|
124
|
-
|
|
125
|
-
if (!motionState) {
|
|
126
|
-
throw new Error(
|
|
127
|
-
`Failed to get motion state for ${this.motionGroupId}: ${event.data}`,
|
|
128
|
-
)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// handle motionState message
|
|
132
|
-
if (
|
|
133
|
-
!jointValuesEqual(
|
|
134
|
-
this.rapidlyChangingMotionState.joint_position.joints,
|
|
135
|
-
motionState.joint_position.joints,
|
|
136
|
-
MOTION_DELTA_THRESHOLD,
|
|
137
|
-
)
|
|
138
|
-
) {
|
|
139
|
-
runInAction(() => {
|
|
140
|
-
this.rapidlyChangingMotionState = motionState
|
|
141
|
-
})
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// handle tcpPose message
|
|
145
|
-
if (
|
|
146
|
-
!tcpPoseEqual(
|
|
147
|
-
this.rapidlyChangingMotionState.tcp_pose,
|
|
148
|
-
motionState.tcp_pose,
|
|
149
|
-
MOTION_DELTA_THRESHOLD,
|
|
150
|
-
)
|
|
151
|
-
) {
|
|
152
|
-
runInAction(() => {
|
|
153
|
-
if (this.rapidlyChangingMotionState.tcp_pose == undefined) {
|
|
154
|
-
this.rapidlyChangingMotionState.tcp_pose = motionState.tcp_pose
|
|
155
|
-
} else {
|
|
156
|
-
this.rapidlyChangingMotionState.tcp_pose = {
|
|
157
|
-
position: motionState.tcp_pose!.position,
|
|
158
|
-
orientation: unwrapRotationVector(
|
|
159
|
-
motionState.tcp_pose!.orientation as Vector3d,
|
|
160
|
-
this.rapidlyChangingMotionState.tcp_pose!
|
|
161
|
-
.orientation as Vector3d,
|
|
162
|
-
),
|
|
163
|
-
tcp: motionState.tcp_pose!.tcp,
|
|
164
|
-
coordinate_system: motionState.tcp_pose!.coordinate_system,
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
})
|
|
168
|
-
}
|
|
169
|
-
})
|
|
170
|
-
makeAutoObservable(this)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
get motionGroupId() {
|
|
174
|
-
return this.motionGroup.motion_group
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
get controllerId() {
|
|
178
|
-
return this.controller.controller
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
get modelFromController() {
|
|
182
|
-
return this.motionGroup.model_from_controller
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
get wandelscriptIdentifier() {
|
|
186
|
-
const num = this.motionGroupId.split("@")[0]
|
|
187
|
-
return `${this.controllerId.replaceAll("-", "_")}_${num}`
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
get joints() {
|
|
191
|
-
return this.initialMotionState.joint_position.joints.map((_, i) => {
|
|
192
|
-
return {
|
|
193
|
-
index: i,
|
|
194
|
-
}
|
|
195
|
-
})
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
dispose() {
|
|
199
|
-
this.motionStateSocket.close()
|
|
200
|
-
}
|
|
201
|
-
}
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
import { AxiosError } from "axios"
|
|
2
|
-
import { makeAutoObservable, runInAction } from "mobx"
|
|
3
|
-
import { AutoReconnectingWebsocket } from "../AutoReconnectingWebsocket"
|
|
4
|
-
import { tryParseJson } from "../converters"
|
|
5
|
-
import type { MotionStreamConnection } from "./MotionStreamConnection"
|
|
6
|
-
import type { NovaClient } from "./NovaClient"
|
|
7
|
-
|
|
8
|
-
export type ProgramRunnerLogEntry = {
|
|
9
|
-
timestamp: number
|
|
10
|
-
message: string
|
|
11
|
-
level?: "warn" | "error"
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export enum ProgramState {
|
|
15
|
-
NotStarted = "not started",
|
|
16
|
-
Running = "running",
|
|
17
|
-
Stopped = "stopped",
|
|
18
|
-
Failed = "failed",
|
|
19
|
-
Completed = "completed",
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export type CurrentProgram = {
|
|
23
|
-
id?: string
|
|
24
|
-
wandelscript?: string
|
|
25
|
-
state?: ProgramState
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
type ProgramStateMessage = {
|
|
29
|
-
type: string
|
|
30
|
-
runner: {
|
|
31
|
-
id: string
|
|
32
|
-
state: ProgramState
|
|
33
|
-
start_time?: number | null
|
|
34
|
-
execution_time?: number | null
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Interface for running Wandelscript programs on the Nova instance and
|
|
40
|
-
* tracking their progress and output
|
|
41
|
-
*/
|
|
42
|
-
export class ProgramStateConnection {
|
|
43
|
-
currentProgram: CurrentProgram = {}
|
|
44
|
-
logs: ProgramRunnerLogEntry[] = []
|
|
45
|
-
|
|
46
|
-
executionState = "idle" as "idle" | "starting" | "executing" | "stopping"
|
|
47
|
-
currentlyExecutingProgramRunnerId = null as string | null
|
|
48
|
-
|
|
49
|
-
programStateSocket: AutoReconnectingWebsocket
|
|
50
|
-
|
|
51
|
-
constructor(readonly nova: NovaClient) {
|
|
52
|
-
makeAutoObservable(this, {}, { autoBind: true })
|
|
53
|
-
|
|
54
|
-
this.programStateSocket = nova.openReconnectingWebsocket(`/programs/state`)
|
|
55
|
-
|
|
56
|
-
this.programStateSocket.addEventListener("message", (ev) => {
|
|
57
|
-
const msg = tryParseJson(ev.data)
|
|
58
|
-
|
|
59
|
-
if (!msg) {
|
|
60
|
-
console.error("Failed to parse program state message", ev.data)
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
if (msg.type === "update") {
|
|
64
|
-
this.handleProgramStateMessage(msg)
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/** Handle a program state update from the backend */
|
|
70
|
-
async handleProgramStateMessage(msg: ProgramStateMessage) {
|
|
71
|
-
const { runner } = msg
|
|
72
|
-
|
|
73
|
-
// Ignoring other programs for now
|
|
74
|
-
// TODO - show if execution state is busy from another source
|
|
75
|
-
if (runner.id !== this.currentlyExecutingProgramRunnerId) return
|
|
76
|
-
|
|
77
|
-
if (runner.state === ProgramState.Failed) {
|
|
78
|
-
try {
|
|
79
|
-
const runnerState = await this.nova.api.program.getProgramRun(runner.id)
|
|
80
|
-
|
|
81
|
-
// TODO - wandelengine should send print statements in real time over
|
|
82
|
-
// websocket as well, rather than at the end
|
|
83
|
-
const stdout = (runnerState as any).stdout
|
|
84
|
-
if (stdout) {
|
|
85
|
-
this.log(stdout)
|
|
86
|
-
}
|
|
87
|
-
this.logError(
|
|
88
|
-
`Program runner ${runner.id} failed with error: ${runnerState.error}\n${runnerState.traceback}`,
|
|
89
|
-
)
|
|
90
|
-
} catch (err) {
|
|
91
|
-
this.logError(
|
|
92
|
-
`Failed to retrieve results for program ${runner.id}: ${err}`,
|
|
93
|
-
)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
this.currentProgram.state = ProgramState.Failed
|
|
97
|
-
|
|
98
|
-
this.gotoIdleState()
|
|
99
|
-
} else if (runner.state === ProgramState.Stopped) {
|
|
100
|
-
try {
|
|
101
|
-
const runnerState = await this.nova.api.program.getProgramRun(runner.id)
|
|
102
|
-
|
|
103
|
-
const stdout = (runnerState as any).stdout
|
|
104
|
-
if (stdout) {
|
|
105
|
-
this.log(stdout)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this.currentProgram.state = ProgramState.Stopped
|
|
109
|
-
this.log(`Program runner ${runner.id} stopped`)
|
|
110
|
-
} catch (err) {
|
|
111
|
-
this.logError(
|
|
112
|
-
`Failed to retrieve results for program ${runner.id}: ${err}`,
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
this.gotoIdleState()
|
|
117
|
-
} else if (runner.state === ProgramState.Completed) {
|
|
118
|
-
try {
|
|
119
|
-
const runnerState = await this.nova.api.program.getProgramRun(runner.id)
|
|
120
|
-
|
|
121
|
-
const stdout = (runnerState as any).stdout
|
|
122
|
-
if (stdout) {
|
|
123
|
-
this.log(stdout)
|
|
124
|
-
}
|
|
125
|
-
this.log(
|
|
126
|
-
`Program runner ${runner.id} finished successfully in ${runner.execution_time?.toFixed(2)} seconds`,
|
|
127
|
-
)
|
|
128
|
-
|
|
129
|
-
this.currentProgram.state = ProgramState.Completed
|
|
130
|
-
} catch (err) {
|
|
131
|
-
this.logError(
|
|
132
|
-
`Failed to retrieve results for program ${runner.id}: ${err}`,
|
|
133
|
-
)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
this.gotoIdleState()
|
|
137
|
-
} else if (runner.state === ProgramState.Running) {
|
|
138
|
-
this.currentProgram.state = ProgramState.Running
|
|
139
|
-
this.log(`Program runner ${runner.id} now running`)
|
|
140
|
-
} else if (runner.state !== ProgramState.NotStarted) {
|
|
141
|
-
console.error(runner)
|
|
142
|
-
this.logError(
|
|
143
|
-
`Program runner ${runner.id} entered unexpected state: ${runner.state}`,
|
|
144
|
-
)
|
|
145
|
-
this.currentProgram.state = ProgramState.NotStarted
|
|
146
|
-
this.gotoIdleState()
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/** Call when a program is no longer executing */
|
|
151
|
-
gotoIdleState() {
|
|
152
|
-
runInAction(() => {
|
|
153
|
-
this.executionState = "idle"
|
|
154
|
-
})
|
|
155
|
-
this.currentlyExecutingProgramRunnerId = null
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
async executeProgram(
|
|
159
|
-
wandelscript: string,
|
|
160
|
-
initial_state?: Object,
|
|
161
|
-
activeRobot?: MotionStreamConnection,
|
|
162
|
-
) {
|
|
163
|
-
this.currentProgram = {
|
|
164
|
-
wandelscript: wandelscript,
|
|
165
|
-
state: ProgramState.NotStarted,
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
const { currentProgram: openProgram } = this
|
|
169
|
-
if (!openProgram) return
|
|
170
|
-
runInAction(() => {
|
|
171
|
-
this.executionState = "starting"
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
// WOS-1539: Wandelengine parser currently breaks if there are empty lines with indentation
|
|
175
|
-
const trimmedCode = openProgram.wandelscript!.replaceAll(/^\s*$/gm, "")
|
|
176
|
-
|
|
177
|
-
try {
|
|
178
|
-
const programRunnerRef = await this.nova.api.program.createProgramRun(
|
|
179
|
-
{
|
|
180
|
-
code: trimmedCode,
|
|
181
|
-
initial_state: initial_state,
|
|
182
|
-
default_robot: activeRobot?.wandelscriptIdentifier,
|
|
183
|
-
} as any,
|
|
184
|
-
{
|
|
185
|
-
headers: {
|
|
186
|
-
"Content-Type": "application/json",
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
)
|
|
190
|
-
|
|
191
|
-
this.log(`Created program runner ${programRunnerRef.id}"`)
|
|
192
|
-
runInAction(() => {
|
|
193
|
-
this.executionState = "executing"
|
|
194
|
-
})
|
|
195
|
-
this.currentlyExecutingProgramRunnerId = programRunnerRef.id
|
|
196
|
-
} catch (error) {
|
|
197
|
-
if (error instanceof AxiosError && error.response && error.request) {
|
|
198
|
-
this.logError(
|
|
199
|
-
`${error.response.status} ${error.response.statusText} from ${error.response.config.url} ${JSON.stringify(error.response.data)}`,
|
|
200
|
-
)
|
|
201
|
-
} else {
|
|
202
|
-
this.logError(JSON.stringify(error))
|
|
203
|
-
}
|
|
204
|
-
runInAction(() => {
|
|
205
|
-
this.executionState = "idle"
|
|
206
|
-
})
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async stopProgram() {
|
|
211
|
-
if (!this.currentlyExecutingProgramRunnerId) return
|
|
212
|
-
runInAction(() => {
|
|
213
|
-
this.executionState = "stopping"
|
|
214
|
-
})
|
|
215
|
-
|
|
216
|
-
try {
|
|
217
|
-
await this.nova.api.program.stopProgramRun(
|
|
218
|
-
this.currentlyExecutingProgramRunnerId,
|
|
219
|
-
)
|
|
220
|
-
} catch (err) {
|
|
221
|
-
// Reactivate the stop button so user can try again
|
|
222
|
-
runInAction(() => {
|
|
223
|
-
this.executionState = "executing"
|
|
224
|
-
})
|
|
225
|
-
throw err
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
reset() {
|
|
230
|
-
this.currentProgram = {}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
log(message: string) {
|
|
234
|
-
console.log(message)
|
|
235
|
-
this.logs.push({
|
|
236
|
-
timestamp: Date.now(),
|
|
237
|
-
message,
|
|
238
|
-
})
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
logError(message: string) {
|
|
242
|
-
console.log(message)
|
|
243
|
-
this.logs.push({
|
|
244
|
-
timestamp: Date.now(),
|
|
245
|
-
message,
|
|
246
|
-
level: "error",
|
|
247
|
-
})
|
|
248
|
-
}
|
|
249
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import type { TcpPose } from "@wandelbots/nova-api/v2"
|
|
2
|
-
|
|
3
|
-
export function jointValuesEqual(
|
|
4
|
-
oldJointValues: number[],
|
|
5
|
-
newJointValues: number[],
|
|
6
|
-
changeDeltaThreshold: number,
|
|
7
|
-
): boolean {
|
|
8
|
-
if (newJointValues.length !== oldJointValues.length) {
|
|
9
|
-
return true
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
for (let jointIndex = 0; jointIndex < newJointValues.length; jointIndex++) {
|
|
13
|
-
if (
|
|
14
|
-
Math.abs(newJointValues[jointIndex]! - oldJointValues[jointIndex]!) >
|
|
15
|
-
changeDeltaThreshold
|
|
16
|
-
) {
|
|
17
|
-
return false
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return true
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function tcpPoseEqual(
|
|
25
|
-
oldTcp: TcpPose | undefined,
|
|
26
|
-
newTcp: TcpPose | undefined,
|
|
27
|
-
changeDeltaThreshold: number,
|
|
28
|
-
): boolean {
|
|
29
|
-
// undefined -> defined (+reverse) transition
|
|
30
|
-
if ((oldTcp === undefined && newTcp) || (oldTcp && newTcp === undefined)) {
|
|
31
|
-
return false
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// the typechecker cannot resolve states to "!= undefined" if "&&" is used
|
|
35
|
-
if (oldTcp === undefined || newTcp === undefined) {
|
|
36
|
-
return true
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
let changedDelta = 0
|
|
40
|
-
changedDelta += Math.abs(oldTcp.orientation[0] - newTcp.orientation[0])
|
|
41
|
-
changedDelta += Math.abs(oldTcp.orientation[1] - newTcp.orientation[1])
|
|
42
|
-
changedDelta += Math.abs(oldTcp.orientation[2] - newTcp.orientation[2])
|
|
43
|
-
changedDelta += Math.abs(oldTcp.position[0] - newTcp.position[0])
|
|
44
|
-
changedDelta += Math.abs(oldTcp.position[1] - newTcp.position[1])
|
|
45
|
-
changedDelta += Math.abs(oldTcp.position[2] - newTcp.position[2])
|
|
46
|
-
|
|
47
|
-
if (changedDelta > changeDeltaThreshold) {
|
|
48
|
-
return false
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
oldTcp.coordinate_system === newTcp.coordinate_system &&
|
|
53
|
-
oldTcp.tcp === newTcp.tcp
|
|
54
|
-
)
|
|
55
|
-
}
|