📦 Moves all model loading to model-utilities
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
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 { footColor, isEmbeddedApp, throttler, toeWorldPositions } from '$lib/utilities';
|
||||
import { fileService } from '$lib/services';
|
||||
import { footColor, isEmbeddedApp, populateModelCache, throttler, toeWorldPositions } from '$lib/utilities';
|
||||
import SceneBuilder from '$lib/sceneBuilder';
|
||||
import { lerp, degToRad } from 'three/src/math/MathUtils';
|
||||
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
|
||||
@@ -76,7 +74,7 @@
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await cacheModelFiles()
|
||||
await populateModelCache();
|
||||
await createScene();
|
||||
if (!isEmbeddedApp && panel) createPanel();
|
||||
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) => {
|
||||
modelTargetAngles[$jointNames.indexOf(name)] = angle * (180 / Math.PI);
|
||||
Throttler.throttle(() => servoAnglesOut.set(modelTargetAngles.map(num => Math.round(num))), 100)
|
||||
|
||||
@@ -3,3 +3,6 @@ export * from './logging-store';
|
||||
export * from './model-store';
|
||||
export * from './socket';
|
||||
export * from './fullscreen';
|
||||
export * from './telemetry';
|
||||
export * from './analytics';
|
||||
export * from './user';
|
||||
|
||||
@@ -2,9 +2,35 @@ import { Color, LoaderUtils, Vector3 } from 'three';
|
||||
import URDFLoader, { type URDFRobot } from 'urdf-loader';
|
||||
import { XacroLoader } from 'xacro-parser';
|
||||
import { Result } from '$lib/utilities';
|
||||
import { jointNames, model } from '$lib/stores';
|
||||
import uzip from 'uzip';
|
||||
import { fileService } from '$lib/services';
|
||||
|
||||
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 (
|
||||
url: string
|
||||
): Promise<Result<[URDFRobot, string[]], string>> => {
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<script lang="ts">
|
||||
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 { Modals, closeModal } from 'svelte-modals';
|
||||
import Toast from '$lib/components/toasts/Toast.svelte';
|
||||
@@ -13,7 +9,19 @@
|
||||
import Menu from './menu.svelte';
|
||||
import Statusbar from './statusbar.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 { api } from '$lib/api';
|
||||
|
||||
@@ -21,35 +29,37 @@
|
||||
if ($user.bearer_token !== '') {
|
||||
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}`);
|
||||
|
||||
addEventListeners();
|
||||
|
||||
outControllerData.subscribe((data) => socket.sendEvent("input", {data}));
|
||||
mode.subscribe((data) => socket.sendEvent("mode", {data}));
|
||||
servoAnglesOut.subscribe((data) => socket.sendEvent("angles", {data}));
|
||||
kinematicData.subscribe((data) => socket.sendEvent("position", {data}));
|
||||
outControllerData.subscribe((data) => socket.sendEvent('input', { data }));
|
||||
mode.subscribe((data) => socket.sendEvent('mode', { data }));
|
||||
servoAnglesOut.subscribe((data) => socket.sendEvent('angles', { data }));
|
||||
kinematicData.subscribe((data) => socket.sendEvent('position', { data }));
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
removeEventListeners();
|
||||
});
|
||||
onDestroy(() => {
|
||||
removeEventListeners();
|
||||
});
|
||||
|
||||
const addEventListeners = () => {
|
||||
const addEventListeners = () => {
|
||||
socket.on('open', handleOpen);
|
||||
socket.on('close', handleClose);
|
||||
socket.on('error', handleError);
|
||||
socket.on('rssi', handleNetworkStatus);
|
||||
socket.on('mode', (data:ModesEnum) => mode.set(data));
|
||||
socket.on('angles', (angles:number[]) => { if (angles.length) servoAngles.set(angles)});
|
||||
socket.on('mode', (data: ModesEnum) => mode.set(data));
|
||||
socket.on('angles', (angles: number[]) => {
|
||||
if (angles.length) servoAngles.set(angles);
|
||||
});
|
||||
if ($page.data.features.analytics) socket.on('analytics', handleAnalytics);
|
||||
if ($page.data.features.battery) socket.on('battery', handleBattery);
|
||||
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('open', handleOpen);
|
||||
socket.off('close', handleClose);
|
||||
@@ -58,12 +68,12 @@
|
||||
socket.off('otastatus', handleOAT);
|
||||
};
|
||||
|
||||
async function validateUser(userdata: userProfile) {
|
||||
const result = await api.get('/api/verifyAuthorization')
|
||||
if (result.isErr()){
|
||||
user.invalidate();
|
||||
console.error('Error:', result.inner);
|
||||
}
|
||||
async function validateUser(userdata: userProfile) {
|
||||
const result = await api.get('/api/verifyAuthorization');
|
||||
if (result.isErr()) {
|
||||
user.invalidate();
|
||||
console.error('Error:', result.inner);
|
||||
}
|
||||
}
|
||||
|
||||
const handleOpen = () => {
|
||||
@@ -71,7 +81,7 @@
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
notifications.error('Connection to device lost', 5000);
|
||||
// notifications.error('Connection to device lost', 5000);
|
||||
telemetry.setRSSI(0);
|
||||
};
|
||||
|
||||
@@ -86,7 +96,6 @@
|
||||
const handleOAT = (data: DownloadOTA) => telemetry.setDownloadOTA(data);
|
||||
|
||||
let menuOpen = false;
|
||||
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -103,14 +112,12 @@
|
||||
<Statusbar />
|
||||
|
||||
<!-- Main page content here -->
|
||||
<slot />
|
||||
<slot />
|
||||
</div>
|
||||
<!-- Side Navigation -->
|
||||
<div class="drawer-side z-30 shadow-lg">
|
||||
<label for="main-menu" class="drawer-overlay" />
|
||||
<Menu
|
||||
on:menuClicked={() => menuOpen = false}
|
||||
/>
|
||||
<Menu on:menuClicked={() => (menuOpen = false)} />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { jointNames, model } from '$lib/stores';
|
||||
import { loadModelAsync } from '$lib/utilities/model-utilities';
|
||||
|
||||
export const prerender = true;
|
||||
export const prerender = false;
|
||||
export const ssr = false;
|
||||
|
||||
const registerFetchIntercept = async () => {
|
||||
@@ -14,20 +11,8 @@ const registerFetchIntercept = async () => {
|
||||
};
|
||||
};
|
||||
|
||||
const loadModelFiles = 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 }) => {
|
||||
export const load = async () => {
|
||||
await registerFetchIntercept();
|
||||
await loadModelFiles();
|
||||
const result = await fetch('/api/features');
|
||||
const features = await result.json();
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user