From 19ebceb9599e8c9c86c051604a20955738b13674 Mon Sep 17 00:00:00 2001 From: Niklas Jensen Date: Thu, 1 Jan 2026 22:39:06 +0100 Subject: [PATCH] Redoing input data and modes, --- .../lib/platform_shared/websocket_message.ts | 329 +++++++++++++++++- app/src/lib/stores/model-store.ts | 20 +- app/src/routes/+layout.svelte | 7 +- app/src/routes/controller/Controls.svelte | 22 +- platform_shared/websocket_message.proto | 16 +- 5 files changed, 352 insertions(+), 42 deletions(-) diff --git a/app/src/lib/platform_shared/websocket_message.ts b/app/src/lib/platform_shared/websocket_message.ts index ca53c00..b6e586c 100644 --- a/app/src/lib/platform_shared/websocket_message.ts +++ b/app/src/lib/platform_shared/websocket_message.ts @@ -10,6 +10,63 @@ import type { FileDescriptorProto } from "ts-proto-descriptors"; export const protobufPackage = ""; +export enum ModesEnum { + DEACTIVATED = 0, + IDLE = 1, + CALIBRATION = 2, + REST = 3, + STAND = 4, + WALK = 5, + UNRECOGNIZED = -1, +} + +export function modesEnumFromJSON(object: any): ModesEnum { + switch (object) { + case 0: + case "DEACTIVATED": + return ModesEnum.DEACTIVATED; + case 1: + case "IDLE": + return ModesEnum.IDLE; + case 2: + case "CALIBRATION": + return ModesEnum.CALIBRATION; + case 3: + case "REST": + return ModesEnum.REST; + case 4: + case "STAND": + return ModesEnum.STAND; + case 5: + case "WALK": + return ModesEnum.WALK; + case -1: + case "UNRECOGNIZED": + default: + return ModesEnum.UNRECOGNIZED; + } +} + +export function modesEnumToJSON(object: ModesEnum): string { + switch (object) { + case ModesEnum.DEACTIVATED: + return "DEACTIVATED"; + case ModesEnum.IDLE: + return "IDLE"; + case ModesEnum.CALIBRATION: + return "CALIBRATION"; + case ModesEnum.REST: + return "REST"; + case ModesEnum.STAND: + return "STAND"; + case ModesEnum.WALK: + return "WALK"; + case ModesEnum.UNRECOGNIZED: + default: + return "UNRECOGNIZED"; + } +} + export interface Vector { x: number; y: number; @@ -52,7 +109,7 @@ export interface IMUCalibrateData { } export interface ModeData { - mode: number; + mode: ModesEnum; } export interface ControllerInputData { @@ -114,6 +171,14 @@ export interface SonarData { dummyField: string; } +export interface HumanInputData { + left: Vector | undefined; + right: Vector | undefined; + height: number; + speed: number; + s1: number; +} + export interface SubscribeNotification { tag: number; } @@ -146,6 +211,7 @@ export interface WebsocketMessage { i2cScan?: I2CScanData | undefined; peripheralSettings?: PeripheralSettingsData | undefined; wifiSettings?: WifiSettingsData | undefined; + humanInputData?: HumanInputData | undefined; rssi?: RSSIData | undefined; } @@ -796,7 +862,7 @@ export const ModeData: MessageFns = { break; } - message.mode = reader.int32(); + message.mode = reader.int32() as any; continue; } } @@ -809,13 +875,13 @@ export const ModeData: MessageFns = { }, fromJSON(object: any): ModeData { - return { mode: isSet(object.mode) ? globalThis.Number(object.mode) : 0 }; + return { mode: isSet(object.mode) ? modesEnumFromJSON(object.mode) : 0 }; }, toJSON(message: ModeData): unknown { const obj: any = {}; if (message.mode !== 0) { - obj.mode = Math.round(message.mode); + obj.mode = modesEnumToJSON(message.mode); } return obj; }, @@ -1764,6 +1830,132 @@ export const SonarData: MessageFns = { }, }; +function createBaseHumanInputData(): HumanInputData { + return { left: undefined, right: undefined, height: 0, speed: 0, s1: 0 }; +} + +export const HumanInputData: MessageFns = { + encode(message: HumanInputData, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.left !== undefined) { + Vector.encode(message.left, writer.uint32(82).fork()).join(); + } + if (message.right !== undefined) { + Vector.encode(message.right, writer.uint32(90).fork()).join(); + } + if (message.height !== 0) { + writer.uint32(165).float(message.height); + } + if (message.speed !== 0) { + writer.uint32(173).float(message.speed); + } + if (message.s1 !== 0) { + writer.uint32(181).float(message.s1); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): HumanInputData { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseHumanInputData(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 10: { + if (tag !== 82) { + break; + } + + message.left = Vector.decode(reader, reader.uint32()); + continue; + } + case 11: { + if (tag !== 90) { + break; + } + + message.right = Vector.decode(reader, reader.uint32()); + continue; + } + case 20: { + if (tag !== 165) { + break; + } + + message.height = reader.float(); + continue; + } + case 21: { + if (tag !== 173) { + break; + } + + message.speed = reader.float(); + continue; + } + case 22: { + if (tag !== 181) { + break; + } + + message.s1 = reader.float(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): HumanInputData { + return { + left: isSet(object.left) ? Vector.fromJSON(object.left) : undefined, + right: isSet(object.right) ? Vector.fromJSON(object.right) : undefined, + height: isSet(object.height) ? globalThis.Number(object.height) : 0, + speed: isSet(object.speed) ? globalThis.Number(object.speed) : 0, + s1: isSet(object.s1) ? globalThis.Number(object.s1) : 0, + }; + }, + + toJSON(message: HumanInputData): unknown { + const obj: any = {}; + if (message.left !== undefined) { + obj.left = Vector.toJSON(message.left); + } + if (message.right !== undefined) { + obj.right = Vector.toJSON(message.right); + } + if (message.height !== 0) { + obj.height = message.height; + } + if (message.speed !== 0) { + obj.speed = message.speed; + } + if (message.s1 !== 0) { + obj.s1 = message.s1; + } + return obj; + }, + + create, I>>(base?: I): HumanInputData { + return HumanInputData.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): HumanInputData { + const message = createBaseHumanInputData(); + message.left = (object.left !== undefined && object.left !== null) ? Vector.fromPartial(object.left) : undefined; + message.right = (object.right !== undefined && object.right !== null) + ? Vector.fromPartial(object.right) + : undefined; + message.height = object.height ?? 0; + message.speed = object.speed ?? 0; + message.s1 = object.s1 ?? 0; + return message; + }, +}; + function createBaseSubscribeNotification(): SubscribeNotification { return { tag: 0 }; } @@ -1981,6 +2173,7 @@ function createBaseWebsocketMessage(): WebsocketMessage { i2cScan: undefined, peripheralSettings: undefined, wifiSettings: undefined, + humanInputData: undefined, rssi: undefined, }; } @@ -2026,6 +2219,9 @@ export const WebsocketMessage: MessageFns = { if (message.wifiSettings !== undefined) { WifiSettingsData.encode(message.wifiSettings, writer.uint32(1922).fork()).join(); } + if (message.humanInputData !== undefined) { + HumanInputData.encode(message.humanInputData, writer.uint32(2002).fork()).join(); + } if (message.rssi !== undefined) { RSSIData.encode(message.rssi, writer.uint32(2082).fork()).join(); } @@ -2143,6 +2339,14 @@ export const WebsocketMessage: MessageFns = { message.wifiSettings = WifiSettingsData.decode(reader, reader.uint32()); continue; } + case 250: { + if (tag !== 2002) { + break; + } + + message.humanInputData = HumanInputData.decode(reader, reader.uint32()); + continue; + } case 260: { if (tag !== 2082) { break; @@ -2177,6 +2381,7 @@ export const WebsocketMessage: MessageFns = { ? PeripheralSettingsData.fromJSON(object.peripheralSettings) : undefined, wifiSettings: isSet(object.wifiSettings) ? WifiSettingsData.fromJSON(object.wifiSettings) : undefined, + humanInputData: isSet(object.humanInputData) ? HumanInputData.fromJSON(object.humanInputData) : undefined, rssi: isSet(object.rssi) ? RSSIData.fromJSON(object.rssi) : undefined, }; }, @@ -2222,6 +2427,9 @@ export const WebsocketMessage: MessageFns = { if (message.wifiSettings !== undefined) { obj.wifiSettings = WifiSettingsData.toJSON(message.wifiSettings); } + if (message.humanInputData !== undefined) { + obj.humanInputData = HumanInputData.toJSON(message.humanInputData); + } if (message.rssi !== undefined) { obj.rssi = RSSIData.toJSON(message.rssi); } @@ -2268,6 +2476,9 @@ export const WebsocketMessage: MessageFns = { message.wifiSettings = (object.wifiSettings !== undefined && object.wifiSettings !== null) ? WifiSettingsData.fromPartial(object.wifiSettings) : undefined; + message.humanInputData = (object.humanInputData !== undefined && object.humanInputData !== null) + ? HumanInputData.fromPartial(object.humanInputData) + : undefined; message.rssi = (object.rssi !== undefined && object.rssi !== null) ? RSSIData.fromPartial(object.rssi) : undefined; return message; }, @@ -2650,8 +2861,8 @@ export const protoMetadata: ProtoMetadata = { "name": "mode", "number": 1, "label": 1, - "type": 5, - "typeName": "", + "type": 14, + "typeName": ".ModesEnum", "extendee": "", "defaultValue": "", "oneofIndex": 0, @@ -3160,6 +3371,78 @@ export const protoMetadata: ProtoMetadata = { "reservedRange": [], "reservedName": [], "visibility": 0, + }, { + "name": "HumanInputData", + "field": [{ + "name": "left", + "number": 10, + "label": 1, + "type": 11, + "typeName": ".Vector", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "left", + "options": undefined, + "proto3Optional": false, + }, { + "name": "right", + "number": 11, + "label": 1, + "type": 11, + "typeName": ".Vector", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "right", + "options": undefined, + "proto3Optional": false, + }, { + "name": "height", + "number": 20, + "label": 1, + "type": 2, + "typeName": "", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "height", + "options": undefined, + "proto3Optional": false, + }, { + "name": "speed", + "number": 21, + "label": 1, + "type": 2, + "typeName": "", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "speed", + "options": undefined, + "proto3Optional": false, + }, { + "name": "s1", + "number": 22, + "label": 1, + "type": 2, + "typeName": "", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "s1", + "options": undefined, + "proto3Optional": false, + }], + "extension": [], + "nestedType": [], + "enumType": [], + "extensionRange": [], + "oneofDecl": [], + "options": undefined, + "reservedRange": [], + "reservedName": [], + "visibility": 0, }, { "name": "SubscribeNotification", "field": [{ @@ -3390,6 +3673,18 @@ export const protoMetadata: ProtoMetadata = { "jsonName": "wifiSettings", "options": undefined, "proto3Optional": false, + }, { + "name": "human_input_data", + "number": 250, + "label": 1, + "type": 11, + "typeName": ".HumanInputData", + "extendee": "", + "defaultValue": "", + "oneofIndex": 0, + "jsonName": "humanInputData", + "options": undefined, + "proto3Optional": false, }, { "name": "rssi", "number": 260, @@ -3413,7 +3708,21 @@ export const protoMetadata: ProtoMetadata = { "reservedName": [], "visibility": 0, }], - "enumType": [], + "enumType": [{ + "name": "ModesEnum", + "value": [ + { "name": "DEACTIVATED", "number": 0, "options": undefined }, + { "name": "IDLE", "number": 1, "options": undefined }, + { "name": "CALIBRATION", "number": 2, "options": undefined }, + { "name": "REST", "number": 3, "options": undefined }, + { "name": "STAND", "number": 4, "options": undefined }, + { "name": "WALK", "number": 5, "options": undefined }, + ], + "options": undefined, + "reservedRange": [], + "reservedName": [], + "visibility": 0, + }], "service": [], "extension": [], "options": undefined, @@ -3425,8 +3734,8 @@ export const protoMetadata: ProtoMetadata = { "trailingComments": "", "leadingDetachedComments": [], }, { - "path": [4, 20], - "span": [56, 0, 73, 1], + "path": [4, 21], + "span": [69, 0, 87, 1], "leadingComments": " WebSocket message wrapper\n Only ONE field will be set at a time (oneof ensures this)\n", "trailingComments": "", "leadingDetachedComments": [], @@ -3436,6 +3745,7 @@ export const protoMetadata: ProtoMetadata = { "edition": 0, }, references: { + ".ModesEnum": ModesEnum, ".Vector": Vector, ".I2CDevice": I2CDevice, ".PinConfig": PinConfig, @@ -3452,6 +3762,7 @@ export const protoMetadata: ProtoMetadata = { ".RSSIData": RSSIData, ".DownloadOTAData": DownloadOTAData, ".SonarData": SonarData, + ".HumanInputData": HumanInputData, ".SubscribeNotification": SubscribeNotification, ".UnsubscribeNotification": UnsubscribeNotification, ".PingMsg": PingMsg, diff --git a/app/src/lib/stores/model-store.ts b/app/src/lib/stores/model-store.ts index 1c14b76..e33a34d 100644 --- a/app/src/lib/stores/model-store.ts +++ b/app/src/lib/stores/model-store.ts @@ -1,3 +1,4 @@ +import { HumanInputData, ModeData, ModesEnum } from '$lib/platform_shared/websocket_message' import type { ControllerInput } from '$lib/types/models' import { persistentStore } from '$lib/utilities/svelte-utilities' import { writable, type Writable } from 'svelte/store' @@ -12,14 +13,7 @@ export const modes = ['deactivated', 'idle', 'calibration', 'rest', 'stand', 'wa export type Modes = (typeof modes)[number] -export enum ModesEnum { - Deactivated = 0, - Idle = 1, - Calibration = 2, - Rest = 3, - Stand = 4, - Walk = 5 -} + export enum WalkGaits { Trot = 0, @@ -37,7 +31,7 @@ export const walkGaitToMode = (gait: WalkGaits): 'trot' | 'crawl' => { return gait === WalkGaits.Trot ? 'trot' : 'crawl' } -export const mode: Writable = writable(ModesEnum.Deactivated) +export const mode: Writable = writable(ModeData.create({ mode: ModesEnum.DEACTIVATED })) export const walkGait: Writable = writable(WalkGaits.Trot) @@ -45,10 +39,4 @@ export const outControllerData = writable([0, 0, 0, 0, 0, 1, 0]) export const kinematicData = writable([0, 0, 0, 0, 1, 0]) -export const input: Writable = writable({ - left: { x: 0, y: 0 }, - right: { x: 0, y: 0 }, - height: 0.5, - speed: 0.5, - s1: 0.5 -}) +export const input: Writable = writable( HumanInputData.create( {left: {x:0,y:0}, right: {x:0,y:0}, height:0, s1:0, speed:0} ) ) diff --git a/app/src/routes/+layout.svelte b/app/src/routes/+layout.svelte index 0484f21..b5650a1 100644 --- a/app/src/routes/+layout.svelte +++ b/app/src/routes/+layout.svelte @@ -11,7 +11,6 @@ import { telemetry, analytics, - ModesEnum, kinematicData, mode, input, @@ -22,7 +21,7 @@ useFeatureFlags, walkGait } from '$lib/stores' - import { AnalyticsData, AnglesData, DownloadOTAData, ModeData, RSSIData, SonarData } from '$lib/platform_shared/websocket_message' + import { AnalyticsData, AnglesData, DownloadOTAData, ModesEnum, RSSIData, SonarData } from '$lib/platform_shared/websocket_message' import { Throttler } from '$lib/utilities' interface Props { @@ -41,7 +40,7 @@ addEventListeners() input.subscribe(data => socket.sendEvent(InputData, InputData.create())) - mode.subscribe(data => socket.sendEvent(ModeData, data)) + mode.subscribe(data => socket.sendEvent(ModesD, data)) walkGait.subscribe(data => socket.sendEvent(GaitData, data)) servoAnglesOut.subscribe(data => socket.sendEvent(AnglesData, data)) kinematicData.subscribe(data => socket.sendEvent(PositionData, data)) @@ -58,7 +57,7 @@ socket.onEvent('close', handleClose), socket.onEvent('error', handleError), socket.on(RSSIData, (data) => telemetry.setRSSI(data)), - socket.on(ModeData, (data) => mode.set(data.mode)), + socket.on(ModesEnum, (data) => mode.set(data)), socket.on(AnalyticsData, (data) => {analytics.addData(data)}), socket.on(AnglesData, (data) => {servoAngles.set(data.angles)}) ]) diff --git a/app/src/routes/controller/Controls.svelte b/app/src/routes/controller/Controls.svelte index 4f6f6af..5a1b317 100644 --- a/app/src/routes/controller/Controls.svelte +++ b/app/src/routes/controller/Controls.svelte @@ -86,19 +86,17 @@ const handleKeyup = (event: KeyboardEvent) => { const down = event.type === 'keydown' input.update(data => { - if (event.key === 'w') data.left.y = down ? 1 : 0 - if (event.key === 'a') data.left.x = down ? -1 : 0 - if (event.key === 's') data.left.y = down ? -1 : 0 - if (event.key === 'd') data.left.x = down ? 1 : 0 - if (event.key === 'ArrowLeft') data.right.x = down ? 1 : 0 - if (event.key === 'ArrowRight') data.right.x = down ? -1 : 0 + if (event.key === 'w') data.left!.y = down ? 1 : 0 + if (event.key === 'a') data.left!.x = down ? -1 : 0 + if (event.key === 's') data.left!.y = down ? -1 : 0 + if (event.key === 'd') data.left!.x = down ? 1 : 0 + if (event.key === 'ArrowLeft') data.right!.x = down ? 1 : 0 + if (event.key === 'ArrowRight') data.right!.x = down ? -1 : 0 return data }) } - const handleRange = (event: Event, key: 'speed' | 'height' | 's1') => { - const value: number = Number((event.target as HTMLInputElement).value) - + const handleRange = (value: number, key: 'speed' | 'height' | 's1') => { input.update(inputData => { inputData[key] = value return inputData @@ -140,7 +138,7 @@ min={0} max={1} step={0.01} - oninput={(e: Event) => handleRange(e, 'height')} + oninput={(v: number) => handleRange(v, 'height')} /> @@ -183,7 +181,7 @@ min="0" step="0.01" max="1" - oninput={e => handleRange(e, 's1')} + oninput={e => handleRange(Number((e.target as HTMLInputElement).value), 's1')} class="range range-xs range-primary" /> @@ -195,7 +193,7 @@ min="0" step="0.01" max="1" - oninput={e => handleRange(e, 'speed')} + oninput={e => handleRange(Number((e.target as HTMLInputElement).value), 'speed')} class="range range-xs range-primary" /> diff --git a/platform_shared/websocket_message.proto b/platform_shared/websocket_message.proto index 0a73504..7c489de 100644 --- a/platform_shared/websocket_message.proto +++ b/platform_shared/websocket_message.proto @@ -13,8 +13,17 @@ message IMUData { float temp = 4; } +enum ModesEnum { + DEACTIVATED = 0; + IDLE = 1; + CALIBRATION = 2; + REST = 3; + STAND = 4; + WALK = 5; +} + message IMUCalibrateData { bool success = 1; } -message ModeData { int32 mode = 1; } +message ModeData { ModesEnum mode = 1; } message ControllerInputData { Vector left = 1; Vector right = 2; @@ -44,6 +53,10 @@ message WifiSettingsData { string hostname = 1; bool priority_rssi = 2; repeated message RSSIData { int32 rssi = 1; } message DownloadOTAData { string status = 1; int32 progress = 2; string error = 3; } message SonarData { string dummy_field = 1; } +message HumanInputData { + Vector left = 10; Vector right = 11; float height = 20; float speed = 21; float s1 = 22; +} + message SubscribeNotification { int32 tag = 1; } message UnsubscribeNotification {int32 tag = 1; } @@ -69,6 +82,7 @@ message WebsocketMessage { I2CScanData i2c_scan = 180; PeripheralSettingsData peripheral_settings = 190; WifiSettingsData wifi_settings = 240; + HumanInputData human_input_data = 250; RSSIData rssi = 260; } }