@viamrobotics/test-widgets 0.11.3 → 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.
@@ -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 MoveToPosition from './move-to-position.svelte'
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
- <Query query={endPositionQuery}>
98
- {#if endPositionQuery.data}
99
- <MoveToPosition
100
- endPosition={endPositionQuery.data}
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
+ };
@@ -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>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ partID: string;
3
+ resourceName: string;
4
+ }
5
+ declare const MoveToPositionControl: import("svelte").Component<Props, {}, "">;
6
+ type MoveToPositionControl = ReturnType<typeof MoveToPositionControl>;
7
+ export default MoveToPositionControl;
@@ -1,14 +1,5 @@
1
1
  <script lang="ts">
2
- import { ArmClient, type Pose } from '@viamrobotics/sdk'
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
- <Query query={endPositionQuery}>
36
- {#if endPositionQuery.data}
37
- <MoveToPosition
38
- endPosition={endPositionQuery.data}
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 { endPosition, moveToPosition, lastError }: Props = $props()
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="Pose is with respect to the arm origin and does not take into account the motion service or frame system."
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 { useResourceNames } from '@viamrobotics/svelte-sdk'
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 resourceNames = useResourceNames(() => partID)
13
+ const statuses = useResourceStatuses(() => partID)
14
14
  const resource = $derived(
15
- resourceNames.current.find((candidate) => candidate.name === resourceName)
15
+ statuses.current.find((status) => status.name?.name === resourceName)?.name
16
16
  )
17
17
  </script>
18
18
 
@@ -4,7 +4,7 @@
4
4
  import {
5
5
  createResourceClient,
6
6
  createResourceQuery,
7
- useResourceNames,
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 cameras = useResourceNames(() => partID, 'camera')
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.current.length > 0 && !initialFetchComplete) {
58
+ if (cameras.length > 0 && !initialFetchComplete) {
53
59
  initialFetchComplete = true
54
- cameraName = cameras.current[0]?.name ?? ''
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.current as { name } (name)}
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.11.3",
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.2.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",