@viamrobotics/test-widgets 0.6.1 → 0.7.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/README.md +1 -1
- package/dist/api-docs-href.d.ts +8 -0
- package/dist/api-docs-href.js +17 -0
- package/dist/components/angle-unit-toggle.svelte +1 -4
- package/dist/components/api-section.svelte +21 -23
- package/dist/components/api-section.svelte.d.ts +2 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/is-moving.svelte +3 -1
- package/dist/components/is-moving.svelte.d.ts +1 -0
- package/dist/components/mutation-section.svelte +19 -22
- package/dist/components/mutation-section.svelte.d.ts +2 -0
- package/dist/components/section-title.svelte +63 -0
- package/dist/components/section-title.svelte.d.ts +14 -0
- package/dist/components/widgets/arm/arm.svelte +17 -24
- package/dist/components/widgets/arm/joint-position-editor.svelte +89 -0
- package/dist/components/widgets/arm/joint-position-editor.svelte.d.ts +11 -0
- package/dist/components/widgets/arm/joint-position-quick-move.svelte +85 -0
- package/dist/components/widgets/arm/joint-position-quick-move.svelte.d.ts +9 -0
- package/dist/components/widgets/arm/joint-position-slider.svelte +36 -0
- package/dist/components/widgets/arm/joint-position-slider.svelte.d.ts +9 -0
- package/dist/components/widgets/arm/move-to-joint-positions.svelte +73 -127
- package/dist/components/widgets/arm/move-to-joint-positions.svelte.d.ts +1 -0
- package/dist/components/widgets/audio-input/audio-input.svelte +2 -0
- package/dist/components/widgets/audio-output/audio-output.svelte +2 -0
- package/dist/components/widgets/base/base.svelte +9 -1
- package/dist/components/widgets/camera/camera.svelte +156 -142
- package/dist/components/widgets/camera/live-or-polling-video.svelte +1 -0
- package/dist/components/widgets/discovery/discovery.svelte +1 -0
- package/dist/components/widgets/encoder/encoder.svelte +2 -0
- package/dist/components/widgets/gantry/gantry.svelte +28 -5
- package/dist/components/widgets/generic/generic.svelte +8 -1
- package/dist/components/widgets/gripper/gripper.svelte +11 -5
- package/dist/components/widgets/gripper/is-holding-something.svelte +1 -0
- package/dist/components/widgets/input-controller/input-controller.svelte +2 -1
- package/dist/components/widgets/motor/motor.svelte +11 -1
- package/dist/components/widgets/movement-sensor/movement-sensor.svelte +53 -26
- package/dist/components/widgets/power-sensor/power-sensor.svelte +4 -0
- package/dist/components/widgets/sensor/sensor.svelte +1 -0
- package/dist/components/widgets/servo/servo.svelte +10 -2
- package/dist/components/widgets/slam/move-on-map.svelte +4 -1
- package/dist/components/widgets/slam/slam.svelte +4 -1
- package/dist/components/widgets/vision-service/context.svelte.d.ts +1 -0
- package/dist/components/widgets/vision-service/context.svelte.js +7 -0
- package/dist/components/widgets/vision-service/detection-row.svelte +38 -0
- package/dist/components/widgets/vision-service/detection-row.svelte.d.ts +8 -0
- package/dist/components/widgets/vision-service/detection.svelte +7 -4
- package/dist/components/widgets/vision-service/legend.svelte +14 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +5 -2
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Slider, ThemeUtils } from 'svelte-tweakpane-ui'
|
|
3
|
+
|
|
4
|
+
import { degreesToRadians, formatNumeric, radiansToDegrees } from '../../../format'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
value: number
|
|
8
|
+
minDegrees: number
|
|
9
|
+
maxDegrees: number
|
|
10
|
+
useRadians: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let { value = $bindable(), minDegrees, maxDegrees, useRadians }: Props = $props()
|
|
14
|
+
|
|
15
|
+
const min = $derived(useRadians ? degreesToRadians(minDegrees) : minDegrees)
|
|
16
|
+
const max = $derived(useRadians ? degreesToRadians(maxDegrees) : maxDegrees)
|
|
17
|
+
const step = $derived(useRadians ? 0.01 : 0.1)
|
|
18
|
+
|
|
19
|
+
const sliderFormat = (v: number) => formatNumeric(v, useRadians ? 3 : 1)
|
|
20
|
+
const toDisplay = (degrees: number) => (useRadians ? degreesToRadians(degrees) : degrees)
|
|
21
|
+
const toDegrees = (display: number) => (useRadians ? radiansToDegrees(display) : display)
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<div class="joint-slider min-w-0">
|
|
25
|
+
<Slider
|
|
26
|
+
value={toDisplay(value)}
|
|
27
|
+
on:change={(event) => {
|
|
28
|
+
value = toDegrees(event.detail.value)
|
|
29
|
+
}}
|
|
30
|
+
{min}
|
|
31
|
+
{max}
|
|
32
|
+
{step}
|
|
33
|
+
format={sliderFormat}
|
|
34
|
+
theme={ThemeUtils.presets.light}
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
value: number;
|
|
3
|
+
minDegrees: number;
|
|
4
|
+
maxDegrees: number;
|
|
5
|
+
useRadians: boolean;
|
|
6
|
+
}
|
|
7
|
+
declare const JointPositionSlider: import("svelte").Component<Props, {}, "value">;
|
|
8
|
+
type JointPositionSlider = ReturnType<typeof JointPositionSlider>;
|
|
9
|
+
export default JointPositionSlider;
|
|
@@ -1,93 +1,68 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import { Icon, Tooltip } from '@viamrobotics/prime-core'
|
|
3
3
|
|
|
4
4
|
import AngleUnitToggle from '../../angle-unit-toggle.svelte'
|
|
5
5
|
import CopyButton from '../../copy-button.svelte'
|
|
6
6
|
import ErrorDisplay from '../../error.svelte'
|
|
7
7
|
import PasteButton from '../../paste-button.svelte'
|
|
8
|
-
import Table from '../../table.svelte'
|
|
9
|
-
import { numberValueFromEvent } from '../../../event-handlers'
|
|
10
8
|
import { degreesToRadians, formatNumeric, radiansToDegrees } from '../../../format'
|
|
11
9
|
|
|
12
|
-
import
|
|
10
|
+
import JointPositionEditor from './joint-position-editor.svelte'
|
|
11
|
+
import { type JointLimit } from './joint-position-limits'
|
|
12
|
+
import JointPositionQuickMove from './joint-position-quick-move.svelte'
|
|
13
|
+
|
|
14
|
+
type ControlMode = 'jointPositions' | 'quickMove'
|
|
13
15
|
|
|
14
16
|
interface Props {
|
|
15
17
|
positions: number[]
|
|
16
18
|
moveToJointPositions: (jointPositions: number[]) => void
|
|
17
19
|
lastError: Error | null
|
|
18
20
|
jointLimitsDegrees: JointLimit[]
|
|
21
|
+
isMoving?: boolean
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
const {
|
|
24
|
+
const {
|
|
25
|
+
positions,
|
|
26
|
+
moveToJointPositions,
|
|
27
|
+
lastError,
|
|
28
|
+
jointLimitsDegrees,
|
|
29
|
+
isMoving = false,
|
|
30
|
+
}: Props = $props()
|
|
22
31
|
|
|
23
32
|
// svelte-ignore state_referenced_locally
|
|
24
|
-
let desiredPositions = $state([...positions])
|
|
33
|
+
let desiredPositions = $state([...positions]) // in degrees
|
|
25
34
|
let useRadians = $state(false)
|
|
35
|
+
let controlMode = $state<ControlMode>('jointPositions')
|
|
26
36
|
|
|
27
|
-
const
|
|
28
|
-
desiredPositions = [...desiredPositions].fill(0)
|
|
29
|
-
}
|
|
37
|
+
const isQuickMoveMode = $derived(controlMode === 'quickMove')
|
|
30
38
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
39
|
+
const getJointMin = (index: number): number => jointLimitsDegrees[index]?.minDegrees ?? -180
|
|
40
|
+
const getJointMax = (index: number): number => jointLimitsDegrees[index]?.maxDegrees ?? 180
|
|
41
|
+
|
|
42
|
+
const toDisplayAngle = (degrees: number) => (useRadians ? degreesToRadians(degrees) : degrees)
|
|
34
43
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
const displayPositions = $derived(desiredPositions.map((degrees) => toDisplayAngle(degrees)))
|
|
45
|
+
const copyData = $derived(`[${displayPositions.map((v) => formatNumeric(v)).join(', ')}]`)
|
|
46
|
+
|
|
47
|
+
const toggleMode = () => {
|
|
48
|
+
controlMode = isQuickMoveMode ? 'jointPositions' : 'quickMove'
|
|
39
49
|
}
|
|
40
50
|
|
|
41
51
|
const handlePaste = (data: string): boolean => {
|
|
42
52
|
try {
|
|
43
|
-
|
|
53
|
+
const parsed = JSON.parse(data) as number[]
|
|
54
|
+
desiredPositions = parsed.map((pos, i) => {
|
|
55
|
+
const degrees = useRadians ? radiansToDegrees(pos) : pos
|
|
56
|
+
return Math.min(Math.max(degrees, getJointMin(i)), getJointMax(i))
|
|
57
|
+
})
|
|
44
58
|
} catch {
|
|
45
59
|
return false
|
|
46
60
|
}
|
|
47
61
|
return true
|
|
48
62
|
}
|
|
49
|
-
const degreesToDisplayAngle = (degrees: number) => {
|
|
50
|
-
return useRadians ? degreesToRadians(degrees) : degrees
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const outOfBoundsMessage = (displayValue: number, limit: JointLimit) => {
|
|
54
|
-
const min = degreesToDisplayAngle(limit.minDegrees)
|
|
55
|
-
const max = degreesToDisplayAngle(limit.maxDegrees)
|
|
56
|
-
const unit = useRadians ? 'rad' : 'deg'
|
|
57
|
-
const side = getOutOfBoundsSide(displayValue, min, max)
|
|
58
|
-
|
|
59
|
-
if (side === 'below-min') {
|
|
60
|
-
return `Min value is ${formatNumeric(min)} ${unit}`
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (side === 'above-max') {
|
|
64
|
-
return `Max value is ${formatNumeric(max)} ${unit}`
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const displayPositions = $derived(desiredPositions.map((pos) => degreesToDisplayAngle(pos)))
|
|
69
|
-
|
|
70
|
-
const copyData = $derived(`[${displayPositions.join(', ')}]`)
|
|
71
|
-
|
|
72
|
-
const outOfBoundsByIndex = $derived(
|
|
73
|
-
displayPositions.map((displayValue, index) => {
|
|
74
|
-
const limit = jointLimitsDegrees[index]
|
|
75
|
-
if (!limit) {
|
|
76
|
-
return false
|
|
77
|
-
}
|
|
78
|
-
return isOutsideJointLimit(
|
|
79
|
-
displayValue,
|
|
80
|
-
degreesToDisplayAngle(limit.minDegrees),
|
|
81
|
-
degreesToDisplayAngle(limit.maxDegrees)
|
|
82
|
-
)
|
|
83
|
-
})
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
const hasOutOfBoundsPositions = $derived(outOfBoundsByIndex.some(Boolean))
|
|
87
63
|
</script>
|
|
88
64
|
|
|
89
65
|
<div class="flex min-w-0 flex-col gap-4">
|
|
90
|
-
<!-- Controls Header -->
|
|
91
66
|
<div class="flex items-center justify-between">
|
|
92
67
|
<span class="flex flex-row items-center gap-1 text-sm">
|
|
93
68
|
Joint Positions
|
|
@@ -96,88 +71,59 @@
|
|
|
96
71
|
name="information-outline"
|
|
97
72
|
cx="text-gray-6"
|
|
98
73
|
/>
|
|
99
|
-
|
|
100
74
|
<span slot="description">
|
|
101
75
|
Joint position limits are based solely on the arm kinematics and do not take into account
|
|
102
76
|
motion service limit overrides.
|
|
103
77
|
</span>
|
|
104
78
|
</Tooltip>
|
|
105
79
|
</span>
|
|
106
|
-
<div class="flex gap-1">
|
|
107
|
-
<
|
|
108
|
-
{
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
<Table>
|
|
119
|
-
<thead>
|
|
120
|
-
<tr>
|
|
121
|
-
<th> Joint </th>
|
|
122
|
-
<th>Move ({useRadians ? 'radians' : 'degrees'})</th>
|
|
123
|
-
</tr>
|
|
124
|
-
</thead>
|
|
125
|
-
<tbody>
|
|
126
|
-
{#each { length: positions.length }, index}
|
|
127
|
-
{@const limit = jointLimitsDegrees[index]}
|
|
128
|
-
{@const value = Number.parseFloat(formatNumeric(displayPositions[index]))}
|
|
129
|
-
{@const outOfBounds = outOfBoundsByIndex[index]}
|
|
130
|
-
<tr>
|
|
131
|
-
<th>{index}</th>
|
|
132
|
-
<th>
|
|
133
|
-
<div class="flex flex-col items-center gap-0.5 py-0.5">
|
|
134
|
-
<NumericInput
|
|
135
|
-
cx="max-w-[76px]"
|
|
136
|
-
{value}
|
|
137
|
-
on:change={(event) => {
|
|
138
|
-
const inputValue = numberValueFromEvent(event) ?? 0
|
|
139
|
-
handleJointInputChange(index, inputValue)
|
|
140
|
-
}}
|
|
141
|
-
/>
|
|
142
|
-
{#if limit && outOfBounds}
|
|
143
|
-
<p class="text-danger-dark text-center text-[10px] leading-snug whitespace-normal">
|
|
144
|
-
{outOfBoundsMessage(displayPositions[index], limit)}
|
|
145
|
-
</p>
|
|
146
|
-
{/if}
|
|
147
|
-
</div>
|
|
148
|
-
</th>
|
|
149
|
-
</tr>
|
|
150
|
-
{/each}
|
|
151
|
-
</tbody>
|
|
152
|
-
</Table>
|
|
153
|
-
|
|
154
|
-
<div class="mb-2 flex flex-col gap-2">
|
|
155
|
-
<span class="flex flex-row gap-2">
|
|
156
|
-
<h4 class="text-xs font-semibold">Quick set</h4>
|
|
157
|
-
<Tooltip>
|
|
158
|
-
<Icon
|
|
159
|
-
name="information-outline"
|
|
160
|
-
cx="text-gray-6"
|
|
80
|
+
<div class="flex items-center gap-1">
|
|
81
|
+
<div class="flex gap-1">
|
|
82
|
+
{#if !isQuickMoveMode}
|
|
83
|
+
<CopyButton data={copyData} />
|
|
84
|
+
<PasteButton onPaste={handlePaste} />
|
|
85
|
+
{/if}
|
|
86
|
+
<AngleUnitToggle
|
|
87
|
+
{useRadians}
|
|
88
|
+
onToggle={() => {
|
|
89
|
+
useRadians = !useRadians
|
|
90
|
+
}}
|
|
161
91
|
/>
|
|
162
|
-
|
|
92
|
+
</div>
|
|
93
|
+
<Tooltip>
|
|
94
|
+
<button
|
|
95
|
+
onclick={toggleMode}
|
|
96
|
+
aria-label={isQuickMoveMode ? 'Exit quick move mode' : 'Enter quick move mode'}
|
|
97
|
+
class={[
|
|
98
|
+
'hover:border-medium hover:bg-medium active:bg-gray-2 rounded p-0.5',
|
|
99
|
+
isQuickMoveMode ? 'text-amber-600' : 'text-gray-6',
|
|
100
|
+
]}
|
|
101
|
+
>
|
|
102
|
+
<Icon name="lightning-bolt-outline" />
|
|
103
|
+
</button>
|
|
163
104
|
<span slot="description">
|
|
164
|
-
|
|
105
|
+
{isQuickMoveMode ? 'Exit quick move mode' : 'Enter quick move mode'}
|
|
165
106
|
</span>
|
|
166
107
|
</Tooltip>
|
|
167
|
-
</span>
|
|
168
|
-
<div class="flex flex-col gap-2 sm:flex-row">
|
|
169
|
-
<Button onclick={resetToZero}>Zero</Button>
|
|
170
|
-
<Button onclick={resetToCurrent}>Current position</Button>
|
|
171
108
|
</div>
|
|
172
109
|
</div>
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
110
|
+
|
|
111
|
+
{#if isQuickMoveMode}
|
|
112
|
+
<JointPositionQuickMove
|
|
113
|
+
{positions}
|
|
114
|
+
{moveToJointPositions}
|
|
115
|
+
{useRadians}
|
|
116
|
+
{isMoving}
|
|
117
|
+
/>
|
|
118
|
+
{:else}
|
|
119
|
+
<JointPositionEditor
|
|
120
|
+
bind:desiredPositions
|
|
121
|
+
{positions}
|
|
122
|
+
{moveToJointPositions}
|
|
123
|
+
{useRadians}
|
|
124
|
+
{jointLimitsDegrees}
|
|
125
|
+
/>
|
|
126
|
+
{/if}
|
|
127
|
+
|
|
182
128
|
<ErrorDisplay {lastError} />
|
|
183
129
|
</div>
|
|
@@ -4,6 +4,7 @@ interface Props {
|
|
|
4
4
|
moveToJointPositions: (jointPositions: number[]) => void;
|
|
5
5
|
lastError: Error | null;
|
|
6
6
|
jointLimitsDegrees: JointLimit[];
|
|
7
|
+
isMoving?: boolean;
|
|
7
8
|
}
|
|
8
9
|
declare const MoveToJointPositions: import("svelte").Component<Props, {}, "">;
|
|
9
10
|
type MoveToJointPositions = ReturnType<typeof MoveToJointPositions>;
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
<div class="flex w-full flex-col divide-y">
|
|
63
63
|
<MutationSection
|
|
64
64
|
title="GetAudio"
|
|
65
|
+
api="rdk:component:audio_input"
|
|
65
66
|
description="Capture audio from the device"
|
|
66
67
|
lastError={capture.error}
|
|
67
68
|
>
|
|
@@ -131,6 +132,7 @@
|
|
|
131
132
|
<div class="ml-auto flex w-full max-w-1/2 flex-col divide-y sm:max-w-1/3">
|
|
132
133
|
<ApiSection
|
|
133
134
|
title="GetProperties"
|
|
135
|
+
api="rdk:component:audio_input"
|
|
134
136
|
description="Audio input properties"
|
|
135
137
|
class="relative"
|
|
136
138
|
>
|
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
<div class="flex w-full flex-col divide-y">
|
|
108
108
|
<MutationSection
|
|
109
109
|
title="Play"
|
|
110
|
+
api="rdk:component:audio_output"
|
|
110
111
|
description="Send audio data to the device"
|
|
111
112
|
lastError={playContext.error}
|
|
112
113
|
>
|
|
@@ -178,6 +179,7 @@
|
|
|
178
179
|
<div class="ml-auto flex w-full max-w-1/2 flex-col divide-y sm:max-w-1/3">
|
|
179
180
|
<ApiSection
|
|
180
181
|
title="GetProperties"
|
|
182
|
+
api="rdk:component:audio_output"
|
|
181
183
|
description="Audio output properties"
|
|
182
184
|
class="relative"
|
|
183
185
|
>
|
|
@@ -83,7 +83,10 @@
|
|
|
83
83
|
/>
|
|
84
84
|
</MutationSection>
|
|
85
85
|
<div class="ml-auto flex w-full max-w-40 grow flex-col divide-y">
|
|
86
|
-
<ApiSection
|
|
86
|
+
<ApiSection
|
|
87
|
+
title="Stop"
|
|
88
|
+
api="rdk:component:base"
|
|
89
|
+
>
|
|
87
90
|
<StopButton
|
|
88
91
|
error={stopMutation.error}
|
|
89
92
|
onStop={() => {
|
|
@@ -93,6 +96,7 @@
|
|
|
93
96
|
</ApiSection>
|
|
94
97
|
<IsMoving
|
|
95
98
|
client={BaseClient}
|
|
99
|
+
api="rdk:component:base"
|
|
96
100
|
{partID}
|
|
97
101
|
{resourceName}
|
|
98
102
|
/>
|
|
@@ -100,6 +104,7 @@
|
|
|
100
104
|
</div>
|
|
101
105
|
<MutationSection
|
|
102
106
|
title="MoveStraight"
|
|
107
|
+
api="rdk:component:base"
|
|
103
108
|
description="Move across a given distance at a given velocity"
|
|
104
109
|
lastError={moveStraightMutation.error}
|
|
105
110
|
>
|
|
@@ -107,6 +112,7 @@
|
|
|
107
112
|
</MutationSection>
|
|
108
113
|
<MutationSection
|
|
109
114
|
title="Spin"
|
|
115
|
+
api="rdk:component:base"
|
|
110
116
|
description="Turn to a given angle at a given velocity"
|
|
111
117
|
lastError={spinMutation.error}
|
|
112
118
|
>
|
|
@@ -114,6 +120,7 @@
|
|
|
114
120
|
</MutationSection>
|
|
115
121
|
<MutationSection
|
|
116
122
|
title="SetPower"
|
|
123
|
+
api="rdk:component:base"
|
|
117
124
|
description="Move continuously at a given amount of power"
|
|
118
125
|
lastError={setPowerMutation.error}
|
|
119
126
|
>
|
|
@@ -121,6 +128,7 @@
|
|
|
121
128
|
</MutationSection>
|
|
122
129
|
<MutationSection
|
|
123
130
|
title="SetVelocity"
|
|
131
|
+
api="rdk:component:base"
|
|
124
132
|
description="Move continually at a given velocity"
|
|
125
133
|
lastError={setVelocityMutation.error}
|
|
126
134
|
>
|