📦 Moves all model loading to model-utilities

This commit is contained in:
Rune Harlyk
2024-08-18 16:26:42 +02:00
parent 296adfee51
commit a86b2fa50e
5 changed files with 70 additions and 62 deletions
+2 -15
View File
@@ -1,10 +1,8 @@
<script lang="ts"> <script lang="ts">
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { BufferGeometry, Line, LineBasicMaterial, Mesh, MeshBasicMaterial, Object3D, SphereGeometry, Vector3, type NormalBufferAttributes, type Object3DEventMap } from 'three'; import { BufferGeometry, Line, LineBasicMaterial, Mesh, MeshBasicMaterial, Object3D, SphereGeometry, Vector3, type NormalBufferAttributes, type Object3DEventMap } from 'three';
import uzip from 'uzip';
import { ModesEnum, kinematicData, mode, model, outControllerData, servoAnglesOut, servoAngles, mpu, jointNames } from '$lib/stores'; import { ModesEnum, kinematicData, mode, model, outControllerData, servoAnglesOut, servoAngles, mpu, jointNames } from '$lib/stores';
import { footColor, isEmbeddedApp, throttler, toeWorldPositions } from '$lib/utilities'; import { footColor, isEmbeddedApp, populateModelCache, throttler, toeWorldPositions } from '$lib/utilities';
import { fileService } from '$lib/services';
import SceneBuilder from '$lib/sceneBuilder'; import SceneBuilder from '$lib/sceneBuilder';
import { lerp, degToRad } from 'three/src/math/MathUtils'; import { lerp, degToRad } from 'three/src/math/MathUtils';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
@@ -76,7 +74,7 @@
} }
onMount(async () => { onMount(async () => {
await cacheModelFiles() await populateModelCache();
await createScene(); await createScene();
if (!isEmbeddedApp && panel) createPanel(); if (!isEmbeddedApp && panel) createPanel();
servoAngles.subscribe(updateAnglesFromStore) servoAngles.subscribe(updateAnglesFromStore)
@@ -130,17 +128,6 @@
]) ])
} }
const cacheModelFiles = async () => {
let data = await fetch('/stl.zip').then((data) => data.arrayBuffer());
var files = uzip.parse(data);
for (const [path, data] of Object.entries(files) as [path: string, data: Uint8Array][]) {
const url = new URL(path, window.location.href);
fileService.saveFile(url.toString(), data);
}
};
const updateAngles = (name: string, angle: number) => { const updateAngles = (name: string, angle: number) => {
modelTargetAngles[$jointNames.indexOf(name)] = angle * (180 / Math.PI); modelTargetAngles[$jointNames.indexOf(name)] = angle * (180 / Math.PI);
Throttler.throttle(() => servoAnglesOut.set(modelTargetAngles.map(num => Math.round(num))), 100) Throttler.throttle(() => servoAnglesOut.set(modelTargetAngles.map(num => Math.round(num))), 100)
+3
View File
@@ -3,3 +3,6 @@ export * from './logging-store';
export * from './model-store'; export * from './model-store';
export * from './socket'; export * from './socket';
export * from './fullscreen'; export * from './fullscreen';
export * from './telemetry';
export * from './analytics';
export * from './user';
+26
View File
@@ -2,9 +2,35 @@ import { Color, LoaderUtils, Vector3 } from 'three';
import URDFLoader, { type URDFRobot } from 'urdf-loader'; import URDFLoader, { type URDFRobot } from 'urdf-loader';
import { XacroLoader } from 'xacro-parser'; import { XacroLoader } from 'xacro-parser';
import { Result } from '$lib/utilities'; import { Result } from '$lib/utilities';
import { jointNames, model } from '$lib/stores';
import uzip from 'uzip';
import { fileService } from '$lib/services';
let model_xml: XMLDocument; let model_xml: XMLDocument;
export const populateModelCache = async () => {
await cacheModelFiles();
const modelRes = await loadModelAsync('/spot_micro.urdf.xacro');
if (modelRes.isOk()) {
const [urdf, JOINT_NAME] = modelRes.inner;
jointNames.set(JOINT_NAME);
model.set(urdf);
} else {
console.error(modelRes.inner, { exception: modelRes.exception });
}
};
export const cacheModelFiles = async () => {
let data = await fetch('/stl.zip');
var files = uzip.parse(await data.arrayBuffer());
for (const [path, data] of Object.entries(files) as [path: string, data: Uint8Array][]) {
const url = new URL(path, window.location.href);
fileService.saveFile(url.toString(), data);
}
};
export const loadModelAsync = async ( export const loadModelAsync = async (
url: string url: string
): Promise<Result<[URDFRobot, string[]], string>> => { ): Promise<Result<[URDFRobot, string[]], string>> => {
+37 -30
View File
@@ -1,9 +1,5 @@
<script lang="ts"> <script lang="ts">
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
import { user } from '$lib/stores/user';
import { telemetry } from '$lib/stores/telemetry';
import { analytics } from '$lib/stores/analytics';
import type { userProfile } from '$lib/stores/user';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { Modals, closeModal } from 'svelte-modals'; import { Modals, closeModal } from 'svelte-modals';
import Toast from '$lib/components/toasts/Toast.svelte'; import Toast from '$lib/components/toasts/Toast.svelte';
@@ -13,7 +9,19 @@
import Menu from './menu.svelte'; import Menu from './menu.svelte';
import Statusbar from './statusbar.svelte'; import Statusbar from './statusbar.svelte';
import Login from './login.svelte'; import Login from './login.svelte';
import { ModesEnum, kinematicData, mode, outControllerData, servoAngles, servoAnglesOut, socket } from '$lib/stores'; import {
telemetry,
analytics,
user,
type userProfile,
ModesEnum,
kinematicData,
mode,
outControllerData,
servoAngles,
servoAnglesOut,
socket
} from '$lib/stores';
import type { Analytics, Battery, DownloadOTA } from '$lib/types/models'; import type { Analytics, Battery, DownloadOTA } from '$lib/types/models';
import { api } from '$lib/api'; import { api } from '$lib/api';
@@ -21,35 +29,37 @@
if ($user.bearer_token !== '') { if ($user.bearer_token !== '') {
await validateUser($user); await validateUser($user);
} }
const ws_token = $page.data.features.security ? '?access_token=' + $user.bearer_token : ''; const ws_token = $page.data.features.security ? '?access_token=' + $user.bearer_token : '';
socket.init(`ws://${window.location.host}/ws/events${ws_token}`); socket.init(`ws://${window.location.host}/ws/events${ws_token}`);
addEventListeners(); addEventListeners();
outControllerData.subscribe((data) => socket.sendEvent("input", {data})); outControllerData.subscribe((data) => socket.sendEvent('input', { data }));
mode.subscribe((data) => socket.sendEvent("mode", {data})); mode.subscribe((data) => socket.sendEvent('mode', { data }));
servoAnglesOut.subscribe((data) => socket.sendEvent("angles", {data})); servoAnglesOut.subscribe((data) => socket.sendEvent('angles', { data }));
kinematicData.subscribe((data) => socket.sendEvent("position", {data})); kinematicData.subscribe((data) => socket.sendEvent('position', { data }));
}); });
onDestroy(() => { onDestroy(() => {
removeEventListeners(); removeEventListeners();
}); });
const addEventListeners = () => { const addEventListeners = () => {
socket.on('open', handleOpen); socket.on('open', handleOpen);
socket.on('close', handleClose); socket.on('close', handleClose);
socket.on('error', handleError); socket.on('error', handleError);
socket.on('rssi', handleNetworkStatus); socket.on('rssi', handleNetworkStatus);
socket.on('mode', (data:ModesEnum) => mode.set(data)); socket.on('mode', (data: ModesEnum) => mode.set(data));
socket.on('angles', (angles:number[]) => { if (angles.length) servoAngles.set(angles)}); socket.on('angles', (angles: number[]) => {
if (angles.length) servoAngles.set(angles);
});
if ($page.data.features.analytics) socket.on('analytics', handleAnalytics); if ($page.data.features.analytics) socket.on('analytics', handleAnalytics);
if ($page.data.features.battery) socket.on('battery', handleBattery); if ($page.data.features.battery) socket.on('battery', handleBattery);
if ($page.data.features.download_firmware) socket.on('otastatus', handleOAT); if ($page.data.features.download_firmware) socket.on('otastatus', handleOAT);
if ($page.data.features.sonar) socket.on('sonar', data => console.log(data)) if ($page.data.features.sonar) socket.on('sonar', (data) => console.log(data));
}; };
const removeEventListeners = () => { const removeEventListeners = () => {
socket.off('analytics', handleAnalytics); socket.off('analytics', handleAnalytics);
socket.off('open', handleOpen); socket.off('open', handleOpen);
socket.off('close', handleClose); socket.off('close', handleClose);
@@ -58,12 +68,12 @@
socket.off('otastatus', handleOAT); socket.off('otastatus', handleOAT);
}; };
async function validateUser(userdata: userProfile) { async function validateUser(userdata: userProfile) {
const result = await api.get('/api/verifyAuthorization') const result = await api.get('/api/verifyAuthorization');
if (result.isErr()){ if (result.isErr()) {
user.invalidate(); user.invalidate();
console.error('Error:', result.inner); console.error('Error:', result.inner);
} }
} }
const handleOpen = () => { const handleOpen = () => {
@@ -71,7 +81,7 @@
}; };
const handleClose = () => { const handleClose = () => {
notifications.error('Connection to device lost', 5000); // notifications.error('Connection to device lost', 5000);
telemetry.setRSSI(0); telemetry.setRSSI(0);
}; };
@@ -86,7 +96,6 @@
const handleOAT = (data: DownloadOTA) => telemetry.setDownloadOTA(data); const handleOAT = (data: DownloadOTA) => telemetry.setDownloadOTA(data);
let menuOpen = false; let menuOpen = false;
</script> </script>
<svelte:head> <svelte:head>
@@ -103,14 +112,12 @@
<Statusbar /> <Statusbar />
<!-- Main page content here --> <!-- Main page content here -->
<slot /> <slot />
</div> </div>
<!-- Side Navigation --> <!-- Side Navigation -->
<div class="drawer-side z-30 shadow-lg"> <div class="drawer-side z-30 shadow-lg">
<label for="main-menu" class="drawer-overlay" /> <label for="main-menu" class="drawer-overlay" />
<Menu <Menu on:menuClicked={() => (menuOpen = false)} />
on:menuClicked={() => menuOpen = false}
/>
</div> </div>
</div> </div>
{/if} {/if}
+2 -17
View File
@@ -1,7 +1,4 @@
import { jointNames, model } from '$lib/stores'; export const prerender = false;
import { loadModelAsync } from '$lib/utilities/model-utilities';
export const prerender = true;
export const ssr = false; export const ssr = false;
const registerFetchIntercept = async () => { const registerFetchIntercept = async () => {
@@ -14,20 +11,8 @@ const registerFetchIntercept = async () => {
}; };
}; };
const loadModelFiles = async () => { export const load = async () => {
const modelRes = await loadModelAsync('/spot_micro.urdf.xacro');
if (modelRes.isOk()) {
const [urdf, JOINT_NAME] = modelRes.inner;
jointNames.set(JOINT_NAME);
model.set(urdf);
} else {
console.error(modelRes.inner, { exception: modelRes.exception });
}
};
export const load = async ({ fetch }) => {
await registerFetchIntercept(); await registerFetchIntercept();
await loadModelFiles();
const result = await fetch('/api/features'); const result = await fetch('/api/features');
const features = await result.json(); const features = await result.json();
return { return {