@viamrobotics/test-widgets 0.11.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/widgets/arm/arm.svelte +5 -18
- package/dist/components/widgets/arm/move-control-mode.d.ts +19 -0
- package/dist/components/widgets/arm/move-control-mode.js +22 -0
- package/dist/components/widgets/arm/move-to-joint-positions.svelte +39 -47
- package/dist/components/widgets/arm/move-to-position-control.svelte +164 -0
- package/dist/components/widgets/arm/move-to-position-control.svelte.d.ts +7 -0
- package/dist/components/widgets/arm/move-to-position-widget.svelte +5 -33
- package/dist/components/widgets/arm/move-to-position.svelte +8 -2
- package/dist/components/widgets/arm/move-to-position.svelte.d.ts +1 -0
- package/dist/components/widgets/do-command/create-do-command-client.svelte.d.ts +2 -3
- package/dist/components/widgets/do-command/create-do-command-client.svelte.js +7 -1
- package/dist/components/widgets/do-command/resource-do-command.svelte +3 -3
- package/dist/components/widgets/movement-sensor/map.svelte +1 -1
- package/dist/components/widgets/movement-sensor/movement-sensor.svelte +129 -127
- package/dist/components/widgets/navigation/navigation.svelte +79 -75
- package/dist/components/widgets/slam/move-on-map.svelte +1 -1
- package/dist/components/widgets/slam/slam.svelte +72 -64
- package/dist/components/widgets/vision-service/vision-service.svelte +11 -5
- package/package.json +2 -2
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type { Pose } from '@viamrobotics/sdk'
|
|
3
|
-
|
|
4
2
|
import { ArmClient } from '@viamrobotics/sdk'
|
|
5
3
|
import {
|
|
6
4
|
createResourceClient,
|
|
@@ -17,7 +15,7 @@
|
|
|
17
15
|
import GetJointPositions from './get-joint-positions.svelte'
|
|
18
16
|
import { getJointPositionLimits, type KinematicsJSON } from './joint-position-limits'
|
|
19
17
|
import MoveToJointPositions from './move-to-joint-positions.svelte'
|
|
20
|
-
import
|
|
18
|
+
import MoveToPositionControl from './move-to-position-control.svelte'
|
|
21
19
|
|
|
22
20
|
interface Props {
|
|
23
21
|
partID: string
|
|
@@ -34,22 +32,16 @@
|
|
|
34
32
|
|
|
35
33
|
const options = { refetchInterval: 500 }
|
|
36
34
|
const jointPositionsQuery = createResourceQuery(client, 'getJointPositions', options)
|
|
37
|
-
const endPositionQuery = createResourceQuery(client, 'getEndPosition', options)
|
|
38
35
|
const kinematicsQuery = createResourceQuery(client, 'getKinematics', options)
|
|
39
36
|
const isMovingQuery = createResourceQuery(client, 'isMoving', options)
|
|
40
37
|
|
|
41
38
|
const moveToJointPosMutation = createResourceMutation(client, 'moveToJointPositions')
|
|
42
39
|
const stopMutation = createResourceMutation(client, 'stop')
|
|
43
|
-
const moveToPosMutation = createResourceMutation(client, 'moveToPosition')
|
|
44
40
|
|
|
45
41
|
const moveToJointPositions = (jointPositionsList: number[]) => {
|
|
46
42
|
moveToJointPosMutation.mutate([jointPositionsList], {})
|
|
47
43
|
}
|
|
48
44
|
|
|
49
|
-
const moveToPosition = (position: Pose) => {
|
|
50
|
-
moveToPosMutation.mutate([position], {})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
45
|
const jointLimitsDegrees = $derived(
|
|
54
46
|
kinematicsQuery.data ? getJointPositionLimits(kinematicsQuery.data as KinematicsJSON) : []
|
|
55
47
|
)
|
|
@@ -94,15 +86,10 @@
|
|
|
94
86
|
title="MoveToPosition"
|
|
95
87
|
api="rdk:component:arm"
|
|
96
88
|
>
|
|
97
|
-
<
|
|
98
|
-
{
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
{moveToPosition}
|
|
102
|
-
lastError={moveToPosMutation.error}
|
|
103
|
-
/>
|
|
104
|
-
{/if}
|
|
105
|
-
</Query>
|
|
89
|
+
<MoveToPositionControl
|
|
90
|
+
{partID}
|
|
91
|
+
{resourceName}
|
|
92
|
+
/>
|
|
106
93
|
</ApiSection>
|
|
107
94
|
</div>
|
|
108
95
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** How the arm MoveToPosition widget executes a move. */
|
|
2
|
+
export type MoveControlMode = 'motion' | 'direct';
|
|
3
|
+
/**
|
|
4
|
+
* The mode the widget starts in: motion planning whenever the machine has a
|
|
5
|
+
* motion service, direct arm control only when it has none.
|
|
6
|
+
*/
|
|
7
|
+
export declare const defaultMoveControlMode: (motionServiceNames: string[]) => MoveControlMode;
|
|
8
|
+
/**
|
|
9
|
+
* The motion service a `Move` call targets: `builtin` when present, otherwise
|
|
10
|
+
* the first discovered service.
|
|
11
|
+
*
|
|
12
|
+
* @returns The service name, or `undefined` when the machine has no motion service.
|
|
13
|
+
*/
|
|
14
|
+
export declare const moveMotionServiceName: (motionServiceNames: string[]) => string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* The selectable motion services for the service select: `builtin` first when
|
|
17
|
+
* present, the rest alphabetical.
|
|
18
|
+
*/
|
|
19
|
+
export declare const motionServiceOptions: (motionServiceNames: string[]) => string[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The mode the widget starts in: motion planning whenever the machine has a
|
|
3
|
+
* motion service, direct arm control only when it has none.
|
|
4
|
+
*/
|
|
5
|
+
export const defaultMoveControlMode = (motionServiceNames) => motionServiceNames.length > 0 ? 'motion' : 'direct';
|
|
6
|
+
/**
|
|
7
|
+
* The motion service a `Move` call targets: `builtin` when present, otherwise
|
|
8
|
+
* the first discovered service.
|
|
9
|
+
*
|
|
10
|
+
* @returns The service name, or `undefined` when the machine has no motion service.
|
|
11
|
+
*/
|
|
12
|
+
export const moveMotionServiceName = (motionServiceNames) => motionServiceNames.includes('builtin') ? 'builtin' : motionServiceNames[0];
|
|
13
|
+
/**
|
|
14
|
+
* The selectable motion services for the service select: `builtin` first when
|
|
15
|
+
* present, the rest alphabetical.
|
|
16
|
+
*/
|
|
17
|
+
export const motionServiceOptions = (motionServiceNames) => {
|
|
18
|
+
const others = motionServiceNames
|
|
19
|
+
.filter((name) => name !== 'builtin')
|
|
20
|
+
.toSorted((a, b) => a.localeCompare(b));
|
|
21
|
+
return motionServiceNames.includes('builtin') ? ['builtin', ...others] : others;
|
|
22
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { Icon, Tooltip } from '@viamrobotics/prime-core'
|
|
2
|
+
import { Icon, ToggleButtons, Tooltip } from '@viamrobotics/prime-core'
|
|
3
3
|
|
|
4
4
|
import AngleUnitToggle from '../../angle-unit-toggle.svelte'
|
|
5
5
|
import CopyButton from '../../copy-button.svelte'
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
import { type JointLimit } from './joint-position-limits'
|
|
12
12
|
import JointPositionQuickMove from './joint-position-quick-move.svelte'
|
|
13
13
|
|
|
14
|
-
type ControlMode = '
|
|
14
|
+
type ControlMode = 'Joint Positions' | 'Quick Move'
|
|
15
|
+
|
|
16
|
+
const CONTROL_MODES: ControlMode[] = ['Joint Positions', 'Quick Move']
|
|
15
17
|
|
|
16
18
|
interface Props {
|
|
17
19
|
positions: number[]
|
|
@@ -32,9 +34,9 @@
|
|
|
32
34
|
// svelte-ignore state_referenced_locally
|
|
33
35
|
let desiredPositions = $state([...positions]) // in degrees
|
|
34
36
|
let useRadians = $state(false)
|
|
35
|
-
let controlMode = $state<ControlMode>('
|
|
37
|
+
let controlMode = $state<ControlMode>('Joint Positions')
|
|
36
38
|
|
|
37
|
-
const isQuickMoveMode = $derived(controlMode === '
|
|
39
|
+
const isQuickMoveMode = $derived(controlMode === 'Quick Move')
|
|
38
40
|
|
|
39
41
|
const getJointMin = (index: number): number => jointLimitsDegrees[index]?.minDegrees ?? -180
|
|
40
42
|
const getJointMax = (index: number): number => jointLimitsDegrees[index]?.maxDegrees ?? 180
|
|
@@ -44,8 +46,11 @@
|
|
|
44
46
|
const displayPositions = $derived(desiredPositions.map((degrees) => toDisplayAngle(degrees)))
|
|
45
47
|
const copyData = $derived(`[${displayPositions.map((v) => formatNumeric(v)).join(', ')}]`)
|
|
46
48
|
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
+
const handleModeChange = ({ detail }: CustomEvent<string>) => {
|
|
50
|
+
const nextMode = CONTROL_MODES.find((mode) => mode === detail)
|
|
51
|
+
if (nextMode) {
|
|
52
|
+
controlMode = nextMode
|
|
53
|
+
}
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
const handlePaste = (data: string): boolean => {
|
|
@@ -63,48 +68,35 @@
|
|
|
63
68
|
</script>
|
|
64
69
|
|
|
65
70
|
<div class="flex min-w-0 flex-col gap-4">
|
|
66
|
-
<div class="flex items-center justify-between">
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<span slot="description">
|
|
75
|
-
Joint position limits are based solely on the arm kinematics and do not take into account
|
|
76
|
-
motion service limit overrides.
|
|
77
|
-
</span>
|
|
78
|
-
</Tooltip>
|
|
79
|
-
</span>
|
|
71
|
+
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
72
|
+
<ToggleButtons
|
|
73
|
+
role="group"
|
|
74
|
+
aria-label="Control mode"
|
|
75
|
+
options={CONTROL_MODES}
|
|
76
|
+
selected={controlMode}
|
|
77
|
+
on:input={handleModeChange}
|
|
78
|
+
/>
|
|
80
79
|
<div class="flex items-center gap-1">
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
>
|
|
102
|
-
<Icon name="lightning-bolt-outline" />
|
|
103
|
-
</button>
|
|
104
|
-
<span slot="description">
|
|
105
|
-
{isQuickMoveMode ? 'Exit quick move mode' : 'Enter quick move mode'}
|
|
106
|
-
</span>
|
|
107
|
-
</Tooltip>
|
|
80
|
+
{#if !isQuickMoveMode}
|
|
81
|
+
<Tooltip>
|
|
82
|
+
<Icon
|
|
83
|
+
name="information-outline"
|
|
84
|
+
cx="text-gray-6"
|
|
85
|
+
/>
|
|
86
|
+
<span slot="description">
|
|
87
|
+
Joint position limits are based solely on the arm kinematics and do not take into
|
|
88
|
+
account motion service limit overrides.
|
|
89
|
+
</span>
|
|
90
|
+
</Tooltip>
|
|
91
|
+
<CopyButton data={copyData} />
|
|
92
|
+
<PasteButton onPaste={handlePaste} />
|
|
93
|
+
{/if}
|
|
94
|
+
<AngleUnitToggle
|
|
95
|
+
{useRadians}
|
|
96
|
+
onToggle={() => {
|
|
97
|
+
useRadians = !useRadians
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
108
100
|
</div>
|
|
109
101
|
</div>
|
|
110
102
|
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Banner, Icon, Label, Select, ToggleButtons, Tooltip } from '@viamrobotics/prime-core'
|
|
3
|
+
import { ArmClient, MotionClient, type Pose, type RobotClient } from '@viamrobotics/sdk'
|
|
4
|
+
import {
|
|
5
|
+
createResourceClient,
|
|
6
|
+
createResourceMutation,
|
|
7
|
+
createResourceQuery,
|
|
8
|
+
createRobotQuery,
|
|
9
|
+
useResourceStatuses,
|
|
10
|
+
useRobotClient,
|
|
11
|
+
} from '@viamrobotics/svelte-sdk'
|
|
12
|
+
|
|
13
|
+
import Query from '../../query.svelte'
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
defaultMoveControlMode,
|
|
17
|
+
motionServiceOptions,
|
|
18
|
+
type MoveControlMode,
|
|
19
|
+
moveMotionServiceName,
|
|
20
|
+
} from './move-control-mode'
|
|
21
|
+
import MoveToPosition from './move-to-position.svelte'
|
|
22
|
+
|
|
23
|
+
interface Props {
|
|
24
|
+
partID: string
|
|
25
|
+
resourceName: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const { partID, resourceName }: Props = $props()
|
|
29
|
+
|
|
30
|
+
const motionServices = useResourceStatuses(() => partID, 'motion')
|
|
31
|
+
const motionServiceNames = $derived(
|
|
32
|
+
motionServices.current
|
|
33
|
+
.map((service) => service.name?.name)
|
|
34
|
+
.filter((name): name is string => name !== undefined)
|
|
35
|
+
)
|
|
36
|
+
const hasMotionService = $derived(motionServiceNames.length > 0)
|
|
37
|
+
|
|
38
|
+
let userChoice = $state<MoveControlMode>()
|
|
39
|
+
const mode = $derived(userChoice ?? defaultMoveControlMode(motionServiceNames))
|
|
40
|
+
|
|
41
|
+
let userServiceChoice = $state<string>()
|
|
42
|
+
const activeMotionServiceName = $derived(
|
|
43
|
+
userServiceChoice ?? moveMotionServiceName(motionServiceNames)
|
|
44
|
+
)
|
|
45
|
+
const serviceOptions = $derived(motionServiceOptions(motionServiceNames))
|
|
46
|
+
const showServiceSelect = $derived(mode === 'motion' && serviceOptions.length > 1)
|
|
47
|
+
|
|
48
|
+
const robotClient = useRobotClient(() => partID)
|
|
49
|
+
const armClient = createResourceClient(
|
|
50
|
+
ArmClient,
|
|
51
|
+
() => partID,
|
|
52
|
+
() => resourceName
|
|
53
|
+
)
|
|
54
|
+
const motionClient = createResourceClient(
|
|
55
|
+
MotionClient,
|
|
56
|
+
() => partID,
|
|
57
|
+
() => activeMotionServiceName ?? ''
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
// Pre-fill the editor with the arm's current pose, in the frame the active mode sends to.
|
|
61
|
+
const poseArgs = $derived<Parameters<RobotClient['getPose']>>([resourceName, 'world', []])
|
|
62
|
+
const poseQuery = createRobotQuery(
|
|
63
|
+
robotClient,
|
|
64
|
+
'getPose',
|
|
65
|
+
() => poseArgs,
|
|
66
|
+
() => ({ enabled: mode === 'motion' })
|
|
67
|
+
)
|
|
68
|
+
const endPositionQuery = createResourceQuery(armClient, 'getEndPosition', () => ({
|
|
69
|
+
refetchInterval: 500,
|
|
70
|
+
enabled: mode === 'direct',
|
|
71
|
+
}))
|
|
72
|
+
|
|
73
|
+
const activeQuery = $derived(mode === 'motion' ? poseQuery : endPositionQuery)
|
|
74
|
+
const endPosition = $derived(mode === 'motion' ? poseQuery.data?.pose : endPositionQuery.data)
|
|
75
|
+
|
|
76
|
+
const moveMutation = createResourceMutation(motionClient, 'move')
|
|
77
|
+
const moveToPosMutation = createResourceMutation(armClient, 'moveToPosition')
|
|
78
|
+
const lastError = $derived(mode === 'motion' ? moveMutation.error : moveToPosMutation.error)
|
|
79
|
+
|
|
80
|
+
const description = $derived(
|
|
81
|
+
mode === 'motion'
|
|
82
|
+
? 'Pose is in the world frame, as required by the motion service.'
|
|
83
|
+
: 'Pose is with respect to the arm origin and does not take into account the motion service or frame system.'
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
const handleModeInput = (event: CustomEvent<string>) => {
|
|
87
|
+
userChoice = event.detail === 'Motion service' ? 'motion' : 'direct'
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const handleServiceChange = (event: Event) => {
|
|
91
|
+
if (event.target instanceof HTMLSelectElement) {
|
|
92
|
+
userServiceChoice = event.target.value
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const moveToPosition = (position: Pose) => {
|
|
97
|
+
if (mode === 'motion') {
|
|
98
|
+
moveMutation.mutate([{ referenceFrame: 'world', pose: position }, resourceName], {})
|
|
99
|
+
} else {
|
|
100
|
+
moveToPosMutation.mutate([position], {})
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<div class="flex flex-col gap-4">
|
|
106
|
+
{#if hasMotionService}
|
|
107
|
+
<Label position="top">
|
|
108
|
+
<span class="flex items-center gap-1 text-xs">
|
|
109
|
+
Control mode
|
|
110
|
+
<Tooltip>
|
|
111
|
+
<Icon
|
|
112
|
+
name="information-outline"
|
|
113
|
+
size="sm"
|
|
114
|
+
/>
|
|
115
|
+
<span slot="description">
|
|
116
|
+
Using a motion service will include motion planning and obstacle avoidance. Direct arm
|
|
117
|
+
control will move the arm without any planning and regardless of obstacles.
|
|
118
|
+
</span>
|
|
119
|
+
</Tooltip>
|
|
120
|
+
</span>
|
|
121
|
+
|
|
122
|
+
<ToggleButtons
|
|
123
|
+
slot="input"
|
|
124
|
+
options={['Motion service', 'Arm']}
|
|
125
|
+
selected={mode === 'motion' ? 'Motion service' : 'Arm'}
|
|
126
|
+
on:input={handleModeInput}
|
|
127
|
+
/>
|
|
128
|
+
</Label>
|
|
129
|
+
{/if}
|
|
130
|
+
{#if showServiceSelect}
|
|
131
|
+
<Label>
|
|
132
|
+
Motion service name
|
|
133
|
+
|
|
134
|
+
<Select
|
|
135
|
+
slot="input"
|
|
136
|
+
value={activeMotionServiceName ?? ''}
|
|
137
|
+
on:change={handleServiceChange}
|
|
138
|
+
>
|
|
139
|
+
{#each serviceOptions as name (name)}
|
|
140
|
+
<option value={name}>{name}</option>
|
|
141
|
+
{/each}
|
|
142
|
+
</Select>
|
|
143
|
+
</Label>
|
|
144
|
+
{/if}
|
|
145
|
+
<Banner variant={mode === 'motion' ? 'info' : 'danger'}>
|
|
146
|
+
{#snippet subtitle()}
|
|
147
|
+
{#if mode === 'motion'}
|
|
148
|
+
Movement goes through motion planning and attempts to avoid obstacles.
|
|
149
|
+
{:else}
|
|
150
|
+
The arm will not avoid obstacles when moving. Use with caution.
|
|
151
|
+
{/if}
|
|
152
|
+
{/snippet}
|
|
153
|
+
</Banner>
|
|
154
|
+
<Query query={activeQuery}>
|
|
155
|
+
{#if endPosition}
|
|
156
|
+
<MoveToPosition
|
|
157
|
+
{endPosition}
|
|
158
|
+
{moveToPosition}
|
|
159
|
+
{lastError}
|
|
160
|
+
{description}
|
|
161
|
+
/>
|
|
162
|
+
{/if}
|
|
163
|
+
</Query>
|
|
164
|
+
</div>
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
createResourceClient,
|
|
5
|
-
createResourceMutation,
|
|
6
|
-
createResourceQuery,
|
|
7
|
-
} from '@viamrobotics/svelte-sdk'
|
|
8
|
-
|
|
9
|
-
import Query from '../../query.svelte'
|
|
10
|
-
|
|
11
|
-
import MoveToPosition from './move-to-position.svelte'
|
|
2
|
+
import MoveToPositionControl from './move-to-position-control.svelte'
|
|
12
3
|
|
|
13
4
|
interface Props {
|
|
14
5
|
partID: string
|
|
@@ -16,28 +7,9 @@
|
|
|
16
7
|
}
|
|
17
8
|
|
|
18
9
|
const { partID, resourceName }: Props = $props()
|
|
19
|
-
|
|
20
|
-
const client = createResourceClient(
|
|
21
|
-
ArmClient,
|
|
22
|
-
() => partID,
|
|
23
|
-
() => resourceName
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
const endPositionQuery = createResourceQuery(client, 'getEndPosition', {
|
|
27
|
-
refetchInterval: 500,
|
|
28
|
-
})
|
|
29
|
-
const moveToPosMutation = createResourceMutation(client, 'moveToPosition')
|
|
30
|
-
const moveToPosition = (position: Pose) => {
|
|
31
|
-
moveToPosMutation.mutate([position], {})
|
|
32
|
-
}
|
|
33
10
|
</script>
|
|
34
11
|
|
|
35
|
-
<
|
|
36
|
-
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
{moveToPosition}
|
|
40
|
-
lastError={moveToPosMutation.error}
|
|
41
|
-
/>
|
|
42
|
-
{/if}
|
|
43
|
-
</Query>
|
|
12
|
+
<MoveToPositionControl
|
|
13
|
+
{partID}
|
|
14
|
+
{resourceName}
|
|
15
|
+
/>
|
|
@@ -10,9 +10,15 @@
|
|
|
10
10
|
endPosition: Pose
|
|
11
11
|
moveToPosition: (position: Pose) => void
|
|
12
12
|
lastError: Error | null
|
|
13
|
+
description?: string
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
const {
|
|
16
|
+
const {
|
|
17
|
+
endPosition,
|
|
18
|
+
moveToPosition,
|
|
19
|
+
lastError,
|
|
20
|
+
description = 'Pose is with respect to the arm origin and does not take into account the motion service or frame system.',
|
|
21
|
+
}: Props = $props()
|
|
16
22
|
|
|
17
23
|
// svelte-ignore state_referenced_locally
|
|
18
24
|
let desiredPosition = $state({ ...endPosition })
|
|
@@ -41,7 +47,7 @@
|
|
|
41
47
|
desiredPosition = next
|
|
42
48
|
}}
|
|
43
49
|
title="Pose Values"
|
|
44
|
-
description
|
|
50
|
+
{description}
|
|
45
51
|
/>
|
|
46
52
|
|
|
47
53
|
<div class="mb-2 flex flex-col gap-2">
|
|
@@ -3,6 +3,7 @@ interface Props {
|
|
|
3
3
|
endPosition: Pose;
|
|
4
4
|
moveToPosition: (position: Pose) => void;
|
|
5
5
|
lastError: Error | null;
|
|
6
|
+
description?: string;
|
|
6
7
|
}
|
|
7
8
|
declare const MoveToPosition: import("svelte").Component<Props, {}, "">;
|
|
8
9
|
type MoveToPosition = ReturnType<typeof MoveToPosition>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { MLModelClient, ResourceName } from '@viamrobotics/sdk';
|
|
2
|
+
import { type ResourceClientContext } from '@viamrobotics/svelte-sdk';
|
|
2
3
|
import { clientMap } from '../../../client-map';
|
|
3
4
|
type DoCommandable = InstanceType<Exclude<(typeof clientMap)[keyof typeof clientMap], typeof MLModelClient>>;
|
|
4
|
-
export declare const createDoCommandClient: (resource: () => ResourceName, partID: () => string, resourceName: () => string) =>
|
|
5
|
-
current: DoCommandable | undefined;
|
|
6
|
-
};
|
|
5
|
+
export declare const createDoCommandClient: (resource: () => ResourceName, partID: () => string, resourceName: () => string) => ResourceClientContext<DoCommandable>;
|
|
7
6
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { MachineConnectionEvent, MLModelClient, ResourceName } from '@viamrobotics/sdk';
|
|
2
|
-
import { useConnectionStatus, useRobotClient } from '@viamrobotics/svelte-sdk';
|
|
2
|
+
import { useConnectionStatus, useRobotClient, } from '@viamrobotics/svelte-sdk';
|
|
3
3
|
import { clientForResource, clientMap } from '../../../client-map';
|
|
4
4
|
export const createDoCommandClient = (resource, partID, resourceName) => {
|
|
5
5
|
const robotClient = useRobotClient(partID);
|
|
@@ -22,5 +22,11 @@ export const createDoCommandClient = (resource, partID, resourceName) => {
|
|
|
22
22
|
get current() {
|
|
23
23
|
return resourceClient;
|
|
24
24
|
},
|
|
25
|
+
get partID() {
|
|
26
|
+
return partID();
|
|
27
|
+
},
|
|
28
|
+
get name() {
|
|
29
|
+
return resourceName();
|
|
30
|
+
},
|
|
25
31
|
};
|
|
26
32
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { useResourceStatuses } from '@viamrobotics/svelte-sdk'
|
|
3
3
|
|
|
4
4
|
import DoCommand from './do-command.svelte'
|
|
5
5
|
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
const { partID, resourceName }: Props = $props()
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const statuses = useResourceStatuses(() => partID)
|
|
14
14
|
const resource = $derived(
|
|
15
|
-
|
|
15
|
+
statuses.current.find((status) => status.name?.name === resourceName)?.name
|
|
16
16
|
)
|
|
17
17
|
</script>
|
|
18
18
|
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
const lng = $derived(safeReadCoordinate(coordinate?.longitude))
|
|
25
25
|
</script>
|
|
26
26
|
|
|
27
|
-
<div class="relative h-[300px] w-full
|
|
27
|
+
<div class="relative h-[300px] w-full @4xl:h-auto @4xl:w-1/2">
|
|
28
28
|
<MapLibre
|
|
29
29
|
zoom={15}
|
|
30
30
|
options={{ attributionControl: { compact: false } }}
|
|
@@ -103,150 +103,152 @@
|
|
|
103
103
|
query={propertiesQuery}
|
|
104
104
|
contentCx="p-4 h-14"
|
|
105
105
|
>
|
|
106
|
-
<div class="
|
|
107
|
-
<div class="flex
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
106
|
+
<div class="@container">
|
|
107
|
+
<div class="flex flex-wrap text-xs @4xl:flex-nowrap">
|
|
108
|
+
<div class="flex w-full flex-col gap-5 py-4 pr-6 pl-4 @4xl:w-1/4">
|
|
109
|
+
{#if propertiesQuery.data?.positionSupported}
|
|
110
|
+
<div class="flex flex-col gap-2">
|
|
111
|
+
<SectionTitle
|
|
112
|
+
title="GetPosition"
|
|
113
|
+
api={MS_API}
|
|
114
|
+
/>
|
|
115
|
+
<Query
|
|
116
|
+
query={positionQuery}
|
|
117
|
+
contentCx="h-6"
|
|
118
|
+
>
|
|
119
|
+
{#if positionQuery.data !== undefined}
|
|
120
|
+
<Position data={positionQuery.data} />
|
|
121
|
+
{/if}
|
|
122
|
+
</Query>
|
|
123
|
+
</div>
|
|
124
|
+
{/if}
|
|
124
125
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
126
|
+
{#if propertiesQuery.data?.orientationSupported}
|
|
127
|
+
<div class="flex flex-col gap-2">
|
|
128
|
+
<SectionTitle
|
|
129
|
+
title="GetOrientation"
|
|
130
|
+
api={MS_API}
|
|
131
|
+
>
|
|
132
|
+
{#snippet suffix()}<span class="text-subtle-2 text-xs font-normal">(º)</span
|
|
133
|
+
>{/snippet}
|
|
134
|
+
</SectionTitle>
|
|
135
|
+
<Query
|
|
136
|
+
query={orientationQuery}
|
|
137
|
+
contentCx="h-6"
|
|
138
|
+
>
|
|
139
|
+
{#if orientationQuery.data !== undefined}
|
|
140
|
+
<Orientation data={orientationQuery.data} />
|
|
141
|
+
{/if}
|
|
142
|
+
</Query>
|
|
143
|
+
</div>
|
|
144
|
+
{/if}
|
|
144
145
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
146
|
+
{#if propertiesQuery.data?.compassHeadingSupported}
|
|
147
|
+
<div class="flex flex-col gap-2">
|
|
148
|
+
<SectionTitle
|
|
149
|
+
title="GetCompassHeading"
|
|
150
|
+
api={MS_API}
|
|
151
|
+
>
|
|
152
|
+
{#snippet suffix()}<span class="text-subtle-2 text-xs font-normal">(º)</span
|
|
153
|
+
>{/snippet}
|
|
154
|
+
</SectionTitle>
|
|
155
|
+
<Query
|
|
156
|
+
query={compassHeadingQuery}
|
|
157
|
+
contentCx="h-6"
|
|
158
|
+
>
|
|
159
|
+
{#if compassHeadingQuery.data !== undefined}
|
|
160
|
+
<CompassHeading data={compassHeadingQuery.data} />
|
|
161
|
+
{/if}
|
|
162
|
+
</Query>
|
|
163
|
+
</div>
|
|
164
|
+
{/if}
|
|
165
|
+
</div>
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
167
|
+
<div class="flex w-full flex-col gap-5 p-4 @4xl:w-1/4">
|
|
168
|
+
{#if propertiesQuery.data?.angularVelocitySupported}
|
|
169
|
+
<div class="flex flex-col gap-2">
|
|
170
|
+
<SectionTitle
|
|
171
|
+
title="GetAngularVelocity"
|
|
172
|
+
api={MS_API}
|
|
173
|
+
>
|
|
174
|
+
{#snippet suffix()}<span class="text-subtle-2 text-xs font-normal">(º/s)</span
|
|
175
|
+
>{/snippet}
|
|
176
|
+
</SectionTitle>
|
|
177
|
+
<Query
|
|
178
|
+
query={angularVelocityQuery}
|
|
179
|
+
contentCx="h-6"
|
|
180
|
+
>
|
|
181
|
+
{#if angularVelocityQuery.data !== undefined}
|
|
182
|
+
<Vector3 data={angularVelocityQuery.data} />
|
|
183
|
+
{/if}
|
|
184
|
+
</Query>
|
|
185
|
+
</div>
|
|
186
|
+
{/if}
|
|
186
187
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
188
|
+
{#if propertiesQuery.data?.linearVelocitySupported}
|
|
189
|
+
<div class="flex flex-col gap-2">
|
|
190
|
+
<SectionTitle
|
|
191
|
+
title="GetLinearVelocity"
|
|
192
|
+
api={MS_API}
|
|
193
|
+
>
|
|
194
|
+
{#snippet suffix()}<span class="text-subtle-2 text-xs font-normal">(m/s)</span
|
|
195
|
+
>{/snippet}
|
|
196
|
+
</SectionTitle>
|
|
197
|
+
<Query
|
|
198
|
+
query={linearVelocityQuery}
|
|
199
|
+
contentCx="h-6"
|
|
200
|
+
>
|
|
201
|
+
{#if linearVelocityQuery.data !== undefined}
|
|
202
|
+
<Vector3 data={linearVelocityQuery.data} />
|
|
203
|
+
{/if}
|
|
204
|
+
</Query>
|
|
205
|
+
</div>
|
|
206
|
+
{/if}
|
|
207
|
+
|
|
208
|
+
{#if propertiesQuery.data?.linearAccelerationSupported}
|
|
209
|
+
<div class="flex flex-col gap-2">
|
|
210
|
+
<SectionTitle
|
|
211
|
+
title="GetLinearAcceleration"
|
|
212
|
+
api={MS_API}
|
|
213
|
+
>
|
|
214
|
+
{#snippet suffix()}<span class="text-subtle-2 text-xs font-normal"
|
|
215
|
+
>(m/s<sup>2</sup>)</span
|
|
216
|
+
>{/snippet}
|
|
217
|
+
</SectionTitle>
|
|
218
|
+
<Query
|
|
219
|
+
query={linearAccelerationQuery}
|
|
220
|
+
contentCx="h-6"
|
|
221
|
+
>
|
|
222
|
+
{#if linearAccelerationQuery.data !== undefined}
|
|
223
|
+
<Vector3 data={linearAccelerationQuery.data} />
|
|
224
|
+
{/if}
|
|
225
|
+
</Query>
|
|
226
|
+
</div>
|
|
227
|
+
{/if}
|
|
206
228
|
|
|
207
|
-
{#if propertiesQuery.data?.linearAccelerationSupported}
|
|
208
229
|
<div class="flex flex-col gap-2">
|
|
209
230
|
<SectionTitle
|
|
210
|
-
title="
|
|
231
|
+
title="GetAccuracy"
|
|
211
232
|
api={MS_API}
|
|
212
|
-
|
|
213
|
-
{#snippet suffix()}<span class="text-subtle-2 text-xs font-normal"
|
|
214
|
-
>(m/s<sup>2</sup>)</span
|
|
215
|
-
>{/snippet}
|
|
216
|
-
</SectionTitle>
|
|
233
|
+
/>
|
|
217
234
|
<Query
|
|
218
|
-
query={
|
|
235
|
+
query={accuracyQuery}
|
|
219
236
|
contentCx="h-6"
|
|
220
237
|
>
|
|
221
|
-
{#if
|
|
222
|
-
<
|
|
238
|
+
{#if accuracyQuery.data !== undefined}
|
|
239
|
+
<Accuracy data={accuracyQuery.data} />
|
|
223
240
|
{/if}
|
|
224
241
|
</Query>
|
|
225
242
|
</div>
|
|
226
|
-
|
|
243
|
+
</div>
|
|
227
244
|
|
|
228
|
-
|
|
229
|
-
<
|
|
230
|
-
|
|
231
|
-
|
|
245
|
+
{#if propertiesQuery.data?.positionSupported}
|
|
246
|
+
<Map
|
|
247
|
+
coordinate={positionQuery.data?.coordinate}
|
|
248
|
+
rotation={orientationQuery.data?.oZ}
|
|
232
249
|
/>
|
|
233
|
-
|
|
234
|
-
query={accuracyQuery}
|
|
235
|
-
contentCx="h-6"
|
|
236
|
-
>
|
|
237
|
-
{#if accuracyQuery.data !== undefined}
|
|
238
|
-
<Accuracy data={accuracyQuery.data} />
|
|
239
|
-
{/if}
|
|
240
|
-
</Query>
|
|
241
|
-
</div>
|
|
250
|
+
{/if}
|
|
242
251
|
</div>
|
|
243
|
-
|
|
244
|
-
{#if propertiesQuery.data?.positionSupported}
|
|
245
|
-
<Map
|
|
246
|
-
coordinate={positionQuery.data?.coordinate}
|
|
247
|
-
rotation={orientationQuery.data?.oZ}
|
|
248
|
-
/>
|
|
249
|
-
{/if}
|
|
250
252
|
</div>
|
|
251
253
|
</Query>
|
|
252
254
|
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
|
|
135
135
|
<ConnectionStatus {partID}>
|
|
136
136
|
{#snippet connected()}
|
|
137
|
-
<div class="flex w-full justify-between p-4">
|
|
137
|
+
<div class="flex w-full flex-wrap justify-between gap-2 p-4">
|
|
138
138
|
<RefetchController
|
|
139
139
|
{refetchInterval}
|
|
140
140
|
queries={[locationQuery, obstaclesQuery, waypointsQuery]}
|
|
@@ -152,85 +152,89 @@
|
|
|
152
152
|
</div>
|
|
153
153
|
</div>
|
|
154
154
|
|
|
155
|
-
<div class="
|
|
156
|
-
<div class="w-full
|
|
157
|
-
<
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
<Tab
|
|
164
|
-
title="Waypoints"
|
|
165
|
-
selected={tab.current === 'waypoints'}
|
|
166
|
-
selectTab={() => (tab.current = 'waypoints')}
|
|
167
|
-
/>
|
|
168
|
-
</TabsBar>
|
|
169
|
-
|
|
170
|
-
<ul class="h-[calc(100%-32px)] overflow-auto">
|
|
171
|
-
{#if tab.current === 'obstacles'}
|
|
172
|
-
<ObstaclesLegend
|
|
173
|
-
{map}
|
|
174
|
-
{hovered}
|
|
175
|
-
{obstacles}
|
|
176
|
-
onEnter={setHovered}
|
|
177
|
-
onLeave={setHovered}
|
|
155
|
+
<div class="@container">
|
|
156
|
+
<div class="relative flex w-full flex-col items-stretch p-2 @2xl:h-120 @2xl:flex-row">
|
|
157
|
+
<div class="w-full p-2 @2xl:max-w-62.5">
|
|
158
|
+
<TabsBar variant="secondary">
|
|
159
|
+
<Tab
|
|
160
|
+
title="Obstacles"
|
|
161
|
+
selected={tab.current === 'obstacles'}
|
|
162
|
+
selectTab={() => (tab.current = 'obstacles')}
|
|
178
163
|
/>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
{
|
|
182
|
-
{
|
|
183
|
-
{waypoints}
|
|
184
|
-
onEnter={setHovered}
|
|
185
|
-
onLeave={setHovered}
|
|
186
|
-
onRemove={async (id) => {
|
|
187
|
-
await removeWaypointMutation.mutateAsync([id])
|
|
188
|
-
await waypointsQuery.refetch()
|
|
189
|
-
}}
|
|
164
|
+
<Tab
|
|
165
|
+
title="Waypoints"
|
|
166
|
+
selected={tab.current === 'waypoints'}
|
|
167
|
+
selectTab={() => (tab.current = 'waypoints')}
|
|
190
168
|
/>
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
169
|
+
</TabsBar>
|
|
170
|
+
|
|
171
|
+
<ul class="max-h-60 overflow-auto @2xl:h-[calc(100%-32px)] @2xl:max-h-none">
|
|
172
|
+
{#if tab.current === 'obstacles'}
|
|
173
|
+
<ObstaclesLegend
|
|
174
|
+
{map}
|
|
175
|
+
{hovered}
|
|
176
|
+
{obstacles}
|
|
177
|
+
onEnter={setHovered}
|
|
178
|
+
onLeave={setHovered}
|
|
179
|
+
/>
|
|
180
|
+
{:else if tab.current === 'waypoints'}
|
|
181
|
+
<WaypointsLegend
|
|
182
|
+
{map}
|
|
183
|
+
{hovered}
|
|
184
|
+
{waypoints}
|
|
185
|
+
onEnter={setHovered}
|
|
186
|
+
onLeave={setHovered}
|
|
187
|
+
onRemove={async (id) => {
|
|
188
|
+
await removeWaypointMutation.mutateAsync([id])
|
|
189
|
+
await waypointsQuery.refetch()
|
|
190
|
+
}}
|
|
191
|
+
/>
|
|
192
|
+
{/if}
|
|
193
|
+
</ul>
|
|
194
|
+
</div>
|
|
194
195
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
196
|
+
<div class="relative h-80 @2xl:h-auto @2xl:grow">
|
|
197
|
+
<MapLibre
|
|
198
|
+
class="relative"
|
|
199
|
+
maxPitch={view === '3D' ? 60 : 0}
|
|
200
|
+
mapProvider={MapProviders.googleMaps}
|
|
201
|
+
mapProviderKey={import.meta.env.VITE_GOOGLE_MAPS_API_KEY}
|
|
202
|
+
bind:map
|
|
203
|
+
>
|
|
204
|
+
<NavigationControls showZoom={false} />
|
|
205
|
+
|
|
206
|
+
<div class="absolute top-5 right-14 z-10 flex items-center gap-2">
|
|
207
|
+
<ToggleButtons
|
|
208
|
+
options={['2D', '3D']}
|
|
209
|
+
selected={view}
|
|
210
|
+
on:input={handleViewSelect}
|
|
211
|
+
/>
|
|
212
|
+
<SatelliteControls />
|
|
213
|
+
<CenterControls />
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
{#if locationQuery.data}
|
|
217
|
+
<DirectionalMarker position={locationQuery.data} />
|
|
218
|
+
{/if}
|
|
219
|
+
|
|
220
|
+
<Waypoints
|
|
221
|
+
{waypoints}
|
|
222
|
+
{addWayPoint}
|
|
223
|
+
tab={tab.current ?? 'obstacles'}
|
|
224
|
+
{hovered}
|
|
225
|
+
/>
|
|
203
226
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
227
|
+
{#snippet layer()}
|
|
228
|
+
<Obstacles
|
|
229
|
+
{obstacles}
|
|
230
|
+
{hovered}
|
|
231
|
+
{setHovered}
|
|
232
|
+
{view}
|
|
233
|
+
/>
|
|
234
|
+
{/snippet}
|
|
235
|
+
</MapLibre>
|
|
212
236
|
</div>
|
|
213
|
-
|
|
214
|
-
{#if locationQuery.data}
|
|
215
|
-
<DirectionalMarker position={locationQuery.data} />
|
|
216
|
-
{/if}
|
|
217
|
-
|
|
218
|
-
<Waypoints
|
|
219
|
-
{waypoints}
|
|
220
|
-
{addWayPoint}
|
|
221
|
-
tab={tab.current ?? 'obstacles'}
|
|
222
|
-
{hovered}
|
|
223
|
-
/>
|
|
224
|
-
|
|
225
|
-
{#snippet layer()}
|
|
226
|
-
<Obstacles
|
|
227
|
-
{obstacles}
|
|
228
|
-
{hovered}
|
|
229
|
-
{setHovered}
|
|
230
|
-
{view}
|
|
231
|
-
/>
|
|
232
|
-
{/snippet}
|
|
233
|
-
</MapLibre>
|
|
237
|
+
</div>
|
|
234
238
|
</div>
|
|
235
239
|
{/snippet}
|
|
236
240
|
</ConnectionStatus>
|
|
@@ -191,78 +191,86 @@
|
|
|
191
191
|
>.
|
|
192
192
|
</div>
|
|
193
193
|
{:else}
|
|
194
|
-
<div class="
|
|
195
|
-
<div class="divide-
|
|
196
|
-
<div class="
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
194
|
+
<div class="@container">
|
|
195
|
+
<div class="flex flex-col @2xl:flex-row @2xl:divide-x">
|
|
196
|
+
<div class="divide-y">
|
|
197
|
+
<div class="m-4">
|
|
198
|
+
<RefetchController
|
|
199
|
+
{refetchInterval}
|
|
200
|
+
queries={[positionQuery, pointCloudMapQuery]}
|
|
201
|
+
/>
|
|
202
|
+
</div>
|
|
203
|
+
|
|
204
|
+
<ApiSection
|
|
205
|
+
title="GetPosition"
|
|
206
|
+
api="rdk:service:slam"
|
|
207
|
+
>
|
|
208
|
+
<Queries
|
|
209
|
+
queries={[propertiesQuery, positionQuery]}
|
|
210
|
+
contentCx="h-6"
|
|
211
|
+
>
|
|
212
|
+
{#if positionQuery.data !== undefined}
|
|
213
|
+
<Position position={positionQuery.data} />
|
|
214
|
+
{/if}
|
|
215
|
+
</Queries>
|
|
216
|
+
</ApiSection>
|
|
217
|
+
|
|
218
|
+
<ApiSection title="Motion">
|
|
219
|
+
<Label>
|
|
220
|
+
Base name
|
|
221
|
+
|
|
222
|
+
<Input
|
|
223
|
+
slot="input"
|
|
224
|
+
bind:value={baseName}
|
|
225
|
+
/>
|
|
226
|
+
</Label>
|
|
227
|
+
<Label>
|
|
228
|
+
Motion name
|
|
229
|
+
|
|
230
|
+
<Input
|
|
231
|
+
slot="input"
|
|
232
|
+
placeholder="builtin"
|
|
233
|
+
bind:value={motionName}
|
|
234
|
+
/>
|
|
235
|
+
</Label>
|
|
236
|
+
</ApiSection>
|
|
237
|
+
|
|
238
|
+
<MoveOnMap
|
|
239
|
+
{destination}
|
|
240
|
+
{updateDestination}
|
|
241
|
+
{moveOnMap}
|
|
242
|
+
{stopPlan}
|
|
243
|
+
lastError={moveOnMapMutation.error ?? stopPlanMutation.error}
|
|
200
244
|
/>
|
|
201
245
|
</div>
|
|
202
246
|
|
|
203
|
-
<
|
|
204
|
-
title="GetPosition"
|
|
205
|
-
api="rdk:service:slam"
|
|
206
|
-
>
|
|
247
|
+
<div class="flex w-full">
|
|
207
248
|
<Queries
|
|
208
|
-
queries={[propertiesQuery, positionQuery]}
|
|
209
|
-
contentCx="h-
|
|
249
|
+
queries={[propertiesQuery, positionQuery, pointCloudMapQuery]}
|
|
250
|
+
contentCx="p-4 h-auto"
|
|
210
251
|
>
|
|
211
|
-
{#if positionQuery.data !== undefined}
|
|
212
|
-
<
|
|
252
|
+
{#if positionQuery.data?.pose !== undefined && pointCloudMapQuery.data !== undefined}
|
|
253
|
+
<div class="h-80 w-full @2xl:h-full">
|
|
254
|
+
<SlamMap2D
|
|
255
|
+
pointcloud={pointCloudMapQuery.data}
|
|
256
|
+
basePose={{
|
|
257
|
+
// Position is returned in millimeters, but the map uses meters
|
|
258
|
+
x: positionQuery.data.pose.x / 1000,
|
|
259
|
+
y: positionQuery.data.pose.y / 1000,
|
|
260
|
+
theta: positionQuery.data.pose.theta,
|
|
261
|
+
}}
|
|
262
|
+
{motionPath}
|
|
263
|
+
destination={destination
|
|
264
|
+
? new Vector2(destination.x, destination.y)
|
|
265
|
+
: undefined}
|
|
266
|
+
helpers={true}
|
|
267
|
+
onClick={handleClick}
|
|
268
|
+
/>
|
|
269
|
+
</div>
|
|
213
270
|
{/if}
|
|
214
271
|
</Queries>
|
|
215
|
-
</
|
|
216
|
-
|
|
217
|
-
<ApiSection title="Motion">
|
|
218
|
-
<Label>
|
|
219
|
-
Base name
|
|
220
|
-
|
|
221
|
-
<Input
|
|
222
|
-
slot="input"
|
|
223
|
-
bind:value={baseName}
|
|
224
|
-
/>
|
|
225
|
-
</Label>
|
|
226
|
-
<Label>
|
|
227
|
-
Motion name
|
|
228
|
-
|
|
229
|
-
<Input
|
|
230
|
-
slot="input"
|
|
231
|
-
placeholder="builtin"
|
|
232
|
-
bind:value={motionName}
|
|
233
|
-
/>
|
|
234
|
-
</Label>
|
|
235
|
-
</ApiSection>
|
|
236
|
-
|
|
237
|
-
<MoveOnMap
|
|
238
|
-
{destination}
|
|
239
|
-
{updateDestination}
|
|
240
|
-
{moveOnMap}
|
|
241
|
-
{stopPlan}
|
|
242
|
-
lastError={moveOnMapMutation.error ?? stopPlanMutation.error}
|
|
243
|
-
/>
|
|
272
|
+
</div>
|
|
244
273
|
</div>
|
|
245
|
-
|
|
246
|
-
<Queries
|
|
247
|
-
queries={[propertiesQuery, positionQuery, pointCloudMapQuery]}
|
|
248
|
-
contentCx="p-4 h-auto"
|
|
249
|
-
>
|
|
250
|
-
{#if positionQuery.data?.pose !== undefined && pointCloudMapQuery.data !== undefined}
|
|
251
|
-
<SlamMap2D
|
|
252
|
-
pointcloud={pointCloudMapQuery.data}
|
|
253
|
-
basePose={{
|
|
254
|
-
// Position is returned in millimeters, but the map uses meters
|
|
255
|
-
x: positionQuery.data.pose.x / 1000,
|
|
256
|
-
y: positionQuery.data.pose.y / 1000,
|
|
257
|
-
theta: positionQuery.data.pose.theta,
|
|
258
|
-
}}
|
|
259
|
-
{motionPath}
|
|
260
|
-
destination={destination ? new Vector2(destination.x, destination.y) : undefined}
|
|
261
|
-
helpers={true}
|
|
262
|
-
onClick={handleClick}
|
|
263
|
-
/>
|
|
264
|
-
{/if}
|
|
265
|
-
</Queries>
|
|
266
274
|
</div>
|
|
267
275
|
{/if}
|
|
268
276
|
</Query>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import {
|
|
5
5
|
createResourceClient,
|
|
6
6
|
createResourceQuery,
|
|
7
|
-
|
|
7
|
+
useResourceStatuses,
|
|
8
8
|
} from '@viamrobotics/svelte-sdk'
|
|
9
9
|
|
|
10
10
|
import { useAddImageToDataset } from '../../../add-image-to-dataset'
|
|
@@ -46,12 +46,18 @@
|
|
|
46
46
|
let showObjectPointClouds = $state(false)
|
|
47
47
|
let isRemote = $state(false)
|
|
48
48
|
|
|
49
|
-
const
|
|
49
|
+
const cameraStatuses = useResourceStatuses(() => partID, 'camera')
|
|
50
|
+
|
|
51
|
+
const cameras = $derived(
|
|
52
|
+
cameraStatuses.current
|
|
53
|
+
.map((status) => status.name?.name)
|
|
54
|
+
.filter((name): name is string => name !== undefined)
|
|
55
|
+
)
|
|
50
56
|
|
|
51
57
|
$effect.pre(() => {
|
|
52
|
-
if (cameras.
|
|
58
|
+
if (cameras.length > 0 && !initialFetchComplete) {
|
|
53
59
|
initialFetchComplete = true
|
|
54
|
-
cameraName = cameras
|
|
60
|
+
cameraName = cameras[0] ?? ''
|
|
55
61
|
}
|
|
56
62
|
})
|
|
57
63
|
|
|
@@ -136,7 +142,7 @@
|
|
|
136
142
|
>
|
|
137
143
|
Default camera
|
|
138
144
|
</option>
|
|
139
|
-
{#each cameras
|
|
145
|
+
{#each cameras as name (name)}
|
|
140
146
|
<option
|
|
141
147
|
selected={cameraName === name}
|
|
142
148
|
value={name}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/test-widgets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"wireit": {
|
|
@@ -249,7 +249,7 @@
|
|
|
249
249
|
"@types/three": "^0.183.1",
|
|
250
250
|
"@viamrobotics/prime-core": "^0.1.22",
|
|
251
251
|
"@viamrobotics/sdk": "^0.69.0",
|
|
252
|
-
"@viamrobotics/svelte-sdk": "^1.
|
|
252
|
+
"@viamrobotics/svelte-sdk": "^1.5.1",
|
|
253
253
|
"@viamrobotics/tailwind-config": "^1.2.0",
|
|
254
254
|
"@vitest/browser": "^4.1.10",
|
|
255
255
|
"@vitest/browser-playwright": "^4.1.5",
|