📐 Adds socket-service
This commit is contained in:
+4
-4
@@ -2,9 +2,9 @@
|
||||
import { Router, Route } from 'svelte-routing';
|
||||
import { onMount } from 'svelte';
|
||||
import TopBar from './components/TopBar.svelte';
|
||||
import { connect } from '$lib/socket';
|
||||
import socketService from '$lib/services/socket-service';
|
||||
import Controller from './routes/Controller.svelte';
|
||||
import FileService from '$lib/services/file-service';
|
||||
import fileService from '$lib/services/file-service';
|
||||
import Settings from './routes/Settings.svelte';
|
||||
import { jointNames, model } from '$lib/store';
|
||||
import { loadModelAsync } from '$lib/utilities';
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
export let url = window.location.pathname
|
||||
onMount(async () => {
|
||||
connect(socketLocation);
|
||||
socketService.connect(socketLocation);
|
||||
registerFetchIntercept()
|
||||
const [urdf, JOINT_NAME] = await loadModelAsync('/spot_micro.urdf.xacro')
|
||||
jointNames.set(JOINT_NAME)
|
||||
@@ -25,7 +25,7 @@
|
||||
window.fetch = async (...args) => {
|
||||
const [resource, config] = args;
|
||||
let file: Result<Uint8Array | undefined, string>;
|
||||
file = await FileService.getFile(resource.toString());
|
||||
file = await fileService.getFile(resource.toString());
|
||||
return file.isOk()
|
||||
? new Response(file.inner)
|
||||
: originalFetch(resource, config)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import nipplejs from 'nipplejs';
|
||||
import { onMount } from 'svelte';
|
||||
import { throttler } from '$lib/utilities';
|
||||
import { socket } from '$lib/socket';
|
||||
import socketService from '$lib/services/socket-service';
|
||||
import { emulateModel, input, outControllerData } from '$lib/store';
|
||||
|
||||
let throttle = new throttler();
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
outControllerData.set(data)
|
||||
|
||||
if(!$emulateModel) $socket.send(data);
|
||||
if(!$emulateModel) socketService.send(data);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { isConnected, status, socket } from '$lib/socket';
|
||||
import socketService from '$lib/services/socket-service';
|
||||
import { Icon, Bars3, XMark, Power, Battery100, Signal, SignalSlash } from 'svelte-hero-icons';
|
||||
import { emulateModel } from '$lib/store';
|
||||
import { Link, useLocation } from 'svelte-routing'
|
||||
@@ -12,13 +12,14 @@
|
||||
let selected_view = views[0];
|
||||
let selected_modes = modes[0];
|
||||
let settingOpen = window.location.pathname.includes('/settings')
|
||||
let isConnected = socketService.isConnected
|
||||
|
||||
$: emulateModel.set(selected_view === views[0])
|
||||
$: settingOpen = $location.pathname.includes('/settings')
|
||||
|
||||
const stop = () => {
|
||||
if ($isConnected) {
|
||||
$socket.send(JSON.stringify({type:"system/stop"}))
|
||||
socketService.send(JSON.stringify({type:"system/stop"}))
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { onDestroy, onMount } from 'svelte';
|
||||
import { CanvasTexture, CircleGeometry, Mesh, MeshBasicMaterial} from 'three';
|
||||
import {socket, angles, mpu } from '$lib/socket'
|
||||
import socketService from '$lib/services/socket-service';
|
||||
import { lerp } from '$lib/utilities';
|
||||
import uzip from 'uzip';
|
||||
import { model, outControllerData } from '$lib/store';
|
||||
@@ -10,6 +10,9 @@ import { location } from '$lib/utilities';
|
||||
import FileService from '$lib/services/file-service';
|
||||
import SceneBuilder from '$lib/sceneBuilder';
|
||||
|
||||
const angles = socketService.angles
|
||||
const mpu = socketService.mpu
|
||||
|
||||
let sceneManager:SceneBuilder
|
||||
let canvas: HTMLCanvasElement, streamCanvas: HTMLCanvasElement, stream: HTMLImageElement
|
||||
let context: CanvasRenderingContext2D, texture: CanvasTexture
|
||||
@@ -44,7 +47,7 @@ onMount(async () => {
|
||||
await createScene()
|
||||
|
||||
outControllerData.subscribe(data => {
|
||||
$socket.send(JSON.stringify({
|
||||
socketService.send(JSON.stringify({
|
||||
type: "kinematic/bodystate",
|
||||
angles:[0, (data[1]-128)/3, (data[2]-128) / 4],
|
||||
position:[(data[4]-128)/2, data[5], (data[3]-128)/2]}))
|
||||
@@ -59,7 +62,6 @@ const cacheModelFiles = async () => {
|
||||
let data = await fetch("/stl.zip").then(data => data.arrayBuffer())
|
||||
|
||||
var files = uzip.parse(data);
|
||||
await FileService.openDatabase()
|
||||
|
||||
for(const [path, data] of Object.entries(files) as [path:string, data:Uint8Array][]){
|
||||
const url = new URL(path, window.location.href)
|
||||
@@ -69,7 +71,7 @@ const cacheModelFiles = async () => {
|
||||
|
||||
const updateAngles = (name:string, angle:number) => {
|
||||
modelTargetAngles[servoNames.indexOf(name)] = angle * (180/Math.PI)
|
||||
$socket.send(JSON.stringify({type:"kinematic/angle", angle:angle * (180/Math.PI), id:servoNames.indexOf(name)}))
|
||||
socketService.send(JSON.stringify({type:"kinematic/angle", angle:angle * (180/Math.PI), id:servoNames.indexOf(name)}))
|
||||
}
|
||||
|
||||
const createScene = async () => {
|
||||
@@ -117,7 +119,7 @@ const render = () => {
|
||||
const points = forwardKinematics.calculateFootpoints(modelAngles.map(ang => degToRad(ang)) as number[])
|
||||
robot.position.y = Math.max(...points.map(coord => coord[0] / 100)) - 2.7
|
||||
robot.rotation.z = lerp(robot.rotation.z, degToRad($mpu.heading + 90), 0.1)
|
||||
modelTargetAngles = $angles
|
||||
modelTargetAngles = $angles
|
||||
|
||||
handleVideoStream()
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { socket, isConnected, settings } from "../../lib/socket";
|
||||
import socketService from "$lib/services/socket-service";
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let isConnected = socketService.isConnected
|
||||
let settings = socketService.settings
|
||||
|
||||
onMount(() => {
|
||||
if ($isConnected) {
|
||||
const message = JSON.stringify({type: 'system/settings'})
|
||||
$socket.send(message)
|
||||
socketService.send(message)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { socket, isConnected, systemInfo } from "../../lib/socket";
|
||||
import { onMount } from 'svelte'
|
||||
import { humanFileSize } from "$lib/utilities";
|
||||
import socketService from '$lib/services/socket-service';
|
||||
|
||||
let isConnected = socketService.isConnected
|
||||
let settings = socketService.settings
|
||||
let systemInfo = socketService.systemInfo
|
||||
|
||||
onMount(() => {
|
||||
if ($isConnected) {
|
||||
const message = JSON.stringify({type: 'system/info'})
|
||||
$socket.send(message)
|
||||
socketService.send(message)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { socket, isConnected, log } from "../../lib/socket";
|
||||
import socketService from "$lib/services/socket-service";
|
||||
import { onMount } from 'svelte'
|
||||
|
||||
let isConnected = socketService.isConnected
|
||||
let log = socketService.log
|
||||
|
||||
onMount(() => {
|
||||
if ($isConnected) {
|
||||
const message = JSON.stringify({type: 'system/logs'})
|
||||
$socket.send(message)
|
||||
socketService.send(message)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './file-service'
|
||||
export * from './socket-service'
|
||||
@@ -0,0 +1,89 @@
|
||||
import { Result, Ok } from '$lib/utilities';
|
||||
import { writable, type Writable } from 'svelte/store';
|
||||
|
||||
type WebsocketData = string | ArrayBufferLike | Blob | ArrayBufferView
|
||||
|
||||
class SocketService {
|
||||
|
||||
public isConnected = writable(false);
|
||||
public angles = writable(new Int16Array(12).fill(0));
|
||||
public log = writable([] as string[]);
|
||||
public battery = writable({});
|
||||
public mpu = writable({ heading: 0 });
|
||||
public distances = writable({});
|
||||
public settings = writable({});
|
||||
public systemInfo = writable({} as number);
|
||||
public dataBuffer = writable(new Float32Array(13));
|
||||
public servoBuffer: Writable<Int16Array | number[]> = writable(new Int16Array(12));
|
||||
public data = writable();
|
||||
private socket!: WebSocket;
|
||||
|
||||
constructor() {}
|
||||
|
||||
public connect(url: string): void {
|
||||
this.socket = new WebSocket(url);
|
||||
this.socket.binaryType = "arraybuffer";
|
||||
this.socket.onopen = () => this.handleConnected();
|
||||
this.socket.onclose = () => this.handleDisconnected();
|
||||
this.socket.onmessage = (event: unknown) => this.handleMessage(event);
|
||||
}
|
||||
|
||||
public send(data: WebsocketData): Result<void, string> {
|
||||
if (this.socket.readyState === WebSocket.OPEN){
|
||||
this.socket.send(data)
|
||||
return Ok.void()
|
||||
}
|
||||
return Result.err("The connection is not open")
|
||||
}
|
||||
|
||||
private handleConnected(): void {
|
||||
this.isConnected.set(true);
|
||||
}
|
||||
|
||||
private handleDisconnected(): void {
|
||||
this.isConnected.set(false);
|
||||
}
|
||||
|
||||
private handleMessage(event: any): void {
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
let buffer = new Int8Array(event.data);
|
||||
if (buffer.length === 44) {
|
||||
this.dataBuffer.set(new Float32Array(buffer.buffer));
|
||||
}
|
||||
} else {
|
||||
let data = event.data;
|
||||
try {
|
||||
data = JSON.parse(event.data);
|
||||
} catch (error) {
|
||||
console.warn(error);
|
||||
}
|
||||
switch (data.type) {
|
||||
case "angles":
|
||||
this.angles.set(data.angles);
|
||||
break;
|
||||
case "logs":
|
||||
this.log.set(data.logs);
|
||||
break;
|
||||
case "log":
|
||||
this.log.update(entries => { entries.push(data.log); return entries; });
|
||||
break;
|
||||
case "settings":
|
||||
this.settings.set(data.settings);
|
||||
case "info":
|
||||
this.systemInfo.set(data.info);
|
||||
break;
|
||||
case "mpu":
|
||||
this.mpu.set(data.mpu);
|
||||
break;
|
||||
case "distances":
|
||||
this.distances.set(data.distances);
|
||||
break;
|
||||
case "battery":
|
||||
this.battery.set(data.battery);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new SocketService();
|
||||
@@ -1,92 +0,0 @@
|
||||
import { writable, type Writable } from 'svelte/store';
|
||||
|
||||
export type WebSocketStatus = 'OPEN' | 'CONNECTING' | 'CLOSED'
|
||||
|
||||
export const isConnected = writable(false)
|
||||
|
||||
export const angles = writable(new Int16Array(12).fill(0))
|
||||
export const log = writable([])
|
||||
export const battery = writable({})
|
||||
export const mpu = writable({heading:0})
|
||||
export const distances = writable({})
|
||||
export const settings = writable({})
|
||||
export const systemInfo = writable({} as number)
|
||||
|
||||
export const dataBuffer = writable(new Float32Array(13))
|
||||
|
||||
export const servoBuffer:Writable<Int16Array|number[]> = writable(new Int16Array(12))
|
||||
|
||||
export const data = writable();
|
||||
|
||||
export const status:Writable<WebSocketStatus> = writable('CLOSED')
|
||||
|
||||
export const socket:Writable<WebSocket> = writable()
|
||||
|
||||
export const connect = (url:string) => {
|
||||
status.set('CONNECTING')
|
||||
let _socket = new WebSocket(url);
|
||||
_socket.binaryType = "arraybuffer";
|
||||
_socket.onopen = _connected;
|
||||
_socket.onclose = _disconnected;
|
||||
_socket.onmessage = _message;
|
||||
socket.set(_socket)
|
||||
|
||||
servoBuffer.subscribe(data => {
|
||||
if(_socket.readyState !== 1) return
|
||||
const buffer = []
|
||||
buffer[0] = 1
|
||||
buffer.push(...data)
|
||||
_socket.send(new Int16Array(buffer))
|
||||
})
|
||||
}
|
||||
|
||||
const _connected = () => {
|
||||
status.set('OPEN')
|
||||
isConnected.set(true)
|
||||
}
|
||||
|
||||
const _disconnected = () => {
|
||||
status.set('CLOSED')
|
||||
isConnected.set(false)
|
||||
}
|
||||
|
||||
const _message = (event:any) => {
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
let buffer = new Int8Array(event.data);
|
||||
if(buffer.length === 44) {
|
||||
dataBuffer.set(new Float32Array(buffer.buffer) )
|
||||
}
|
||||
} else {
|
||||
let data = event.data
|
||||
try {
|
||||
data = JSON.parse(event.data)
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
}
|
||||
switch (data.type) {
|
||||
case "angles":
|
||||
angles.set(data.angles)
|
||||
break
|
||||
case "logs":
|
||||
log.set(data.logs)
|
||||
break
|
||||
case "log":
|
||||
log.update(entries => {entries.push(data.log); return entries})
|
||||
break
|
||||
case "settings":
|
||||
settings.set(data.settings)
|
||||
case "info":
|
||||
systemInfo.set(data.info)
|
||||
break
|
||||
case "mpu":
|
||||
mpu.set(data.mpu)
|
||||
break
|
||||
case "distances":
|
||||
distances.set(data.distances)
|
||||
break
|
||||
case "battery":
|
||||
battery.set(data.battery)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,4 +33,12 @@ export class Ok<T> {
|
||||
static new<T>(inner: T): Ok<T> {
|
||||
return new Ok<T>(inner)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty `Ok`
|
||||
* @returns `Ok(void)`
|
||||
*/
|
||||
static void(): Ok<void> {
|
||||
return new Ok(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user