@viamrobotics/motion-tools 0.17.0 → 0.18.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 +8 -0
- package/dist/components/RefreshRate.svelte +73 -32
- package/dist/components/RefreshRate.svelte.d.ts +12 -0
- package/dist/components/Tree/Settings.svelte +8 -0
- package/dist/hooks/useGeometries.svelte.js +4 -3
- package/dist/hooks/usePointclouds.svelte.js +4 -3
- package/dist/hooks/usePose.svelte.js +4 -3
- package/dist/hooks/useWeblabs.svelte.js +8 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,3 +72,11 @@ VITE_CONFIGS='
|
|
|
72
72
|
The visualizer includes a golang package that allows executing commands to the visualizer.
|
|
73
73
|
|
|
74
74
|
The list of available commands [can be found here](https://pkg.go.dev/github.com/viam-labs/motion-tools@v0.9.0/client/client).
|
|
75
|
+
|
|
76
|
+
### Programmatic camera control
|
|
77
|
+
|
|
78
|
+
It is possible to programmatically move the viewer camera and even modify the camera settings during runtime.
|
|
79
|
+
|
|
80
|
+
To do this, open the Javascript console while using the visualizer and call methods or set properties on the `cameraControls` object.
|
|
81
|
+
|
|
82
|
+
The following APIs are available: https://github.com/yomotsu/camera-controls?tab=readme-ov-file#properties
|
|
@@ -1,5 +1,22 @@
|
|
|
1
|
+
<script
|
|
2
|
+
module
|
|
3
|
+
lang="ts"
|
|
4
|
+
>
|
|
5
|
+
export const RefetchRates = {
|
|
6
|
+
OFF: -1,
|
|
7
|
+
MANUAL: 0,
|
|
8
|
+
FPS_60: 17,
|
|
9
|
+
FPS_30: 33,
|
|
10
|
+
MS_500: 500,
|
|
11
|
+
MS_1000: 1000,
|
|
12
|
+
MS_2000: 2000,
|
|
13
|
+
MS_5000: 5000,
|
|
14
|
+
MS_10000: 10_000,
|
|
15
|
+
} as const
|
|
16
|
+
</script>
|
|
17
|
+
|
|
1
18
|
<script lang="ts">
|
|
2
|
-
import { Select } from '@viamrobotics/prime-core'
|
|
19
|
+
import { Select, IconButton } from '@viamrobotics/prime-core'
|
|
3
20
|
import { useMachineSettings } from '../hooks/useMachineSettings.svelte'
|
|
4
21
|
import type { Snippet } from 'svelte'
|
|
5
22
|
|
|
@@ -7,46 +24,70 @@
|
|
|
7
24
|
id: string
|
|
8
25
|
label: string
|
|
9
26
|
allowLive?: boolean
|
|
27
|
+
onManualRefetch: () => void
|
|
10
28
|
children?: Snippet
|
|
11
29
|
}
|
|
12
30
|
|
|
13
|
-
let { id, label, allowLive = false, children }: Props = $props()
|
|
31
|
+
let { id, label, allowLive = false, onManualRefetch, children }: Props = $props()
|
|
14
32
|
|
|
15
33
|
const { refreshRates } = useMachineSettings()
|
|
16
|
-
const rate = $derived(refreshRates.get(id))
|
|
34
|
+
const rate = $derived(refreshRates.get(id) ?? RefetchRates.MANUAL)
|
|
17
35
|
</script>
|
|
18
36
|
|
|
19
37
|
<label class="flex flex-col gap-1">
|
|
20
38
|
{label}
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
<div class="flex items-center gap-1">
|
|
40
|
+
<Select
|
|
41
|
+
style="
|
|
42
|
+
-webkit-appearance: none;
|
|
43
|
+
-moz-appearance: none;
|
|
44
|
+
appearance: none;
|
|
45
|
+
"
|
|
46
|
+
onchange={(event: InputEvent) => {
|
|
47
|
+
if (event.target instanceof HTMLSelectElement) {
|
|
48
|
+
const { value } = event.target
|
|
49
|
+
refreshRates.set(id, Number.parseInt(value, 10))
|
|
50
|
+
}
|
|
51
|
+
}}
|
|
52
|
+
value={String(rate)}
|
|
53
|
+
>
|
|
54
|
+
{#if children}
|
|
55
|
+
{@render children()}
|
|
56
|
+
{:else}
|
|
57
|
+
<option value={String(RefetchRates.OFF)}>Do not fetch</option>
|
|
58
|
+
<option value={String(RefetchRates.MANUAL)}>Manual</option>
|
|
59
|
+
{#if allowLive}
|
|
60
|
+
<option value={String(RefetchRates.FPS_60)}>60fps</option>
|
|
61
|
+
<option value={String(RefetchRates.FPS_30)}>30fps</option>
|
|
62
|
+
{/if}
|
|
63
|
+
<option value={String(RefetchRates.MS_500)}>Refresh every 0.5 second</option>
|
|
64
|
+
<option value={String(RefetchRates.MS_1000)}>Refresh every second</option>
|
|
65
|
+
<option value={String(RefetchRates.MS_2000)}>Refresh every 2 seconds</option>
|
|
66
|
+
<option value={String(RefetchRates.MS_5000)}>Refresh every 5 seconds</option>
|
|
67
|
+
<option value={String(RefetchRates.MS_10000)}>Refresh every 10 seconds</option>
|
|
38
68
|
{/if}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<
|
|
43
|
-
|
|
69
|
+
</Select>
|
|
70
|
+
|
|
71
|
+
{#if rate === RefetchRates.MANUAL}
|
|
72
|
+
<IconButton
|
|
73
|
+
icon="refresh"
|
|
74
|
+
label="refetch"
|
|
75
|
+
variant="secondary"
|
|
76
|
+
cx="border-light border"
|
|
77
|
+
onclick={() => {
|
|
78
|
+
onManualRefetch()
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
{:else}
|
|
82
|
+
<IconButton
|
|
83
|
+
icon={rate === RefetchRates.OFF ? 'play-circle-outline' : 'pause'}
|
|
84
|
+
label="pause"
|
|
85
|
+
variant="secondary"
|
|
86
|
+
cx="border-light border"
|
|
87
|
+
onclick={() => {
|
|
88
|
+
refreshRates.set(id, RefetchRates.MANUAL)
|
|
89
|
+
}}
|
|
90
|
+
/>
|
|
44
91
|
{/if}
|
|
45
|
-
</
|
|
92
|
+
</div>
|
|
46
93
|
</label>
|
|
47
|
-
|
|
48
|
-
<style>
|
|
49
|
-
label :global svg {
|
|
50
|
-
display: none;
|
|
51
|
-
}
|
|
52
|
-
</style>
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
+
export declare const RefetchRates: {
|
|
2
|
+
readonly OFF: -1;
|
|
3
|
+
readonly MANUAL: 0;
|
|
4
|
+
readonly FPS_60: 17;
|
|
5
|
+
readonly FPS_30: 33;
|
|
6
|
+
readonly MS_500: 500;
|
|
7
|
+
readonly MS_1000: 1000;
|
|
8
|
+
readonly MS_2000: 2000;
|
|
9
|
+
readonly MS_5000: 5000;
|
|
10
|
+
readonly MS_10000: 10000;
|
|
11
|
+
};
|
|
1
12
|
import type { Snippet } from 'svelte';
|
|
2
13
|
interface Props {
|
|
3
14
|
id: string;
|
|
4
15
|
label: string;
|
|
5
16
|
allowLive?: boolean;
|
|
17
|
+
onManualRefetch: () => void;
|
|
6
18
|
children?: Snippet;
|
|
7
19
|
}
|
|
8
20
|
declare const RefreshRate: import("svelte").Component<Props, {}, "">;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Select, Switch, Input } from '@viamrobotics/prime-core'
|
|
3
|
+
import { useQueryClient } from '@tanstack/svelte-query'
|
|
3
4
|
import RefreshRate from '../RefreshRate.svelte'
|
|
4
5
|
import { useMotionClient } from '../../hooks/useMotionClient.svelte'
|
|
5
6
|
import Drawer from './Drawer.svelte'
|
|
@@ -10,6 +11,7 @@
|
|
|
10
11
|
import WeblabActive from '../weblab/WeblabActive.svelte'
|
|
11
12
|
import { WEBLABS_EXPERIMENTS } from '../../hooks/useWeblabs.svelte'
|
|
12
13
|
|
|
14
|
+
const queryClient = useQueryClient()
|
|
13
15
|
const partID = usePartID()
|
|
14
16
|
const cameras = useResourceNames(() => partID.current, 'camera')
|
|
15
17
|
const settings = useSettings()
|
|
@@ -28,10 +30,16 @@
|
|
|
28
30
|
id={RefreshRates.poses}
|
|
29
31
|
label="Poses"
|
|
30
32
|
allowLive
|
|
33
|
+
onManualRefetch={() => {
|
|
34
|
+
queryClient.refetchQueries({ queryKey: ['getPose', 'getGeometries'], exact: false })
|
|
35
|
+
}}
|
|
31
36
|
/>
|
|
32
37
|
<RefreshRate
|
|
33
38
|
id={RefreshRates.pointclouds}
|
|
34
39
|
label="Pointclouds"
|
|
40
|
+
onManualRefetch={() => {
|
|
41
|
+
queryClient.refetchQueries({ queryKey: ['getPointCloud'], exact: false })
|
|
42
|
+
}}
|
|
35
43
|
/>
|
|
36
44
|
<div>
|
|
37
45
|
<div>Enabled pointcloud cameras</div>
|
|
@@ -10,6 +10,7 @@ import { useLogs } from './useLogs.svelte';
|
|
|
10
10
|
import { resourceColors } from '../color';
|
|
11
11
|
import { Color } from 'three';
|
|
12
12
|
import { useFrames } from './useFrames.svelte';
|
|
13
|
+
import { RefetchRates } from '../components/RefreshRate.svelte';
|
|
13
14
|
const key = Symbol('geometries-context');
|
|
14
15
|
export const provideGeometries = (partID) => {
|
|
15
16
|
const frames = useFrames();
|
|
@@ -32,9 +33,9 @@ export const provideGeometries = (partID) => {
|
|
|
32
33
|
const results = [];
|
|
33
34
|
for (const client of clients) {
|
|
34
35
|
const options = queryOptions({
|
|
35
|
-
enabled: interval !==
|
|
36
|
-
refetchInterval: interval ===
|
|
37
|
-
queryKey: ['partID', partID(), client.current?.name
|
|
36
|
+
enabled: interval !== RefetchRates.OFF && client.current !== undefined,
|
|
37
|
+
refetchInterval: interval === RefetchRates.MANUAL ? false : interval,
|
|
38
|
+
queryKey: ['getGeometries', 'partID', partID(), client.current?.name],
|
|
38
39
|
queryFn: async () => {
|
|
39
40
|
if (!client.current) {
|
|
40
41
|
throw new Error('No client');
|
|
@@ -8,6 +8,7 @@ import { RefreshRates, useMachineSettings } from './useMachineSettings.svelte';
|
|
|
8
8
|
import { WorldObject } from '../WorldObject.svelte';
|
|
9
9
|
import { usePersistentUUIDs } from './usePersistentUUIDs.svelte';
|
|
10
10
|
import { useLogs } from './useLogs.svelte';
|
|
11
|
+
import { RefetchRates } from '../components/RefreshRate.svelte';
|
|
11
12
|
const key = Symbol('pointcloud-context');
|
|
12
13
|
export const providePointclouds = (partID) => {
|
|
13
14
|
const logs = useLogs();
|
|
@@ -20,11 +21,11 @@ export const providePointclouds = (partID) => {
|
|
|
20
21
|
for (const cameraClient of clients) {
|
|
21
22
|
const name = cameraClient.current?.name ?? '';
|
|
22
23
|
const options = queryOptions({
|
|
23
|
-
enabled: interval !==
|
|
24
|
+
enabled: interval !== RefetchRates.OFF &&
|
|
24
25
|
cameraClient.current !== undefined &&
|
|
25
26
|
disabledCameras.get(name) !== true,
|
|
26
|
-
refetchInterval: interval ===
|
|
27
|
-
queryKey: ['partID', partID(), name
|
|
27
|
+
refetchInterval: interval === RefetchRates.MANUAL ? false : interval,
|
|
28
|
+
queryKey: ['getPointCloud', 'partID', partID(), name],
|
|
28
29
|
queryFn: async () => {
|
|
29
30
|
if (!cameraClient.current) {
|
|
30
31
|
throw new Error('No camera client');
|
|
@@ -9,6 +9,7 @@ import { useEnvironment } from './useEnvironment.svelte';
|
|
|
9
9
|
import { observe } from '@threlte/core';
|
|
10
10
|
import { untrack } from 'svelte';
|
|
11
11
|
import { useFrames } from './useFrames.svelte';
|
|
12
|
+
import { RefetchRates } from '../components/RefreshRate.svelte';
|
|
12
13
|
export const usePose = (name, parent) => {
|
|
13
14
|
const { refreshRates } = useMachineSettings();
|
|
14
15
|
const partID = usePartID();
|
|
@@ -21,11 +22,11 @@ export const usePose = (name, parent) => {
|
|
|
21
22
|
const client = createResourceClient(MotionClient, () => partID.current, () => motionClient.current ?? '');
|
|
22
23
|
const interval = $derived(refreshRates.get(RefreshRates.poses));
|
|
23
24
|
const options = $derived(queryOptions({
|
|
24
|
-
enabled: interval !==
|
|
25
|
+
enabled: interval !== RefetchRates.OFF &&
|
|
25
26
|
client.current !== undefined &&
|
|
26
27
|
environment.current.viewerMode === 'monitor',
|
|
27
|
-
refetchInterval: interval ===
|
|
28
|
-
queryKey: ['partID', partID.current, client.current?.name,
|
|
28
|
+
refetchInterval: interval === RefetchRates.MANUAL ? false : interval,
|
|
29
|
+
queryKey: ['getPose', 'partID', partID.current, client.current?.name, name(), parent()],
|
|
29
30
|
queryFn: async () => {
|
|
30
31
|
if (!client.current) {
|
|
31
32
|
throw new Error('No client');
|
|
@@ -55,5 +55,12 @@ export const provideWeblabs = () => {
|
|
|
55
55
|
setContext(WEBLABS_CONTEXT_KEY, createWeblabs());
|
|
56
56
|
};
|
|
57
57
|
export const useWeblabs = () => {
|
|
58
|
-
|
|
58
|
+
const context = getContext(WEBLABS_CONTEXT_KEY);
|
|
59
|
+
if (!context) {
|
|
60
|
+
return {
|
|
61
|
+
load: () => { },
|
|
62
|
+
isActive: () => false,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return context;
|
|
59
66
|
};
|