horn pass

This commit is contained in:
legop3
2026-01-31 13:44:35 -05:00
parent 92ab763b27
commit b7d636c70a
26 changed files with 676 additions and 128 deletions
+31
View File
@@ -6,6 +6,7 @@ import { DEFAULT_KEYMAP, DEFAULT_MACROS, SONG_DEFAULT_NOTE } from './constants.j
import { canonicalizeKeyInput } from './keymapUtils.js';
import { useSettingsNamespace } from '../settings/index.js';
import { useSession } from '../context/SessionContext.jsx';
import { HORN_SETTINGS_DEFAULTS } from '../settings/namespaces.js';
import {
applyAuxOvercurrentScale,
applyDriveOvercurrentScale,
@@ -36,6 +37,7 @@ export function ControlSystemProvider({ children }) {
value: controlSettings,
save: saveControlSettings,
} = useSettingsNamespace('controls', { keymap: DEFAULT_KEYMAP, macros: DEFAULT_MACROS });
const { value: hornSettings } = useSettingsNamespace('horn', HORN_SETTINGS_DEFAULTS);
const { session, homeAssistantSetState } = useSession();
const roverId = session?.assignment?.roverId ?? null;
const overcurrentLimiter = useOvercurrentLimiter(roverId);
@@ -346,6 +348,31 @@ export function ControlSystemProvider({ children }) {
[pipeline],
);
const normalizedHornSettings = useMemo(() => {
const base = hornSettings ?? HORN_SETTINGS_DEFAULTS;
const waveform = base.waveform === 'sine' ? 'sine' : 'saw';
const freqs = Array.isArray(base.freqs) ? base.freqs : HORN_SETTINGS_DEFAULTS.freqs;
const normalized = [...freqs, 0, 0, 0, 0]
.slice(0, 4)
.map((value) => {
const num = Number(value);
if (!Number.isFinite(num)) return 0;
return num <= 0 ? 0 : Math.min(5000, Math.round(num));
});
return { waveform, freqs: normalized };
}, [hornSettings]);
const startHorn = useCallback(() => {
if (!pipeline.horn) return;
pipeline.sendHorn({ action: 'start', ...normalizedHornSettings });
recordControlIntent();
}, [normalizedHornSettings, pipeline, recordControlIntent]);
const stopHorn = useCallback(() => {
if (!pipeline.horn) return;
pipeline.sendHorn({ action: 'stop' });
}, [pipeline]);
const registerInputState = useCallback((source, data) => {
dispatch({ type: 'control/register-input-state', payload: { source, state: data } });
}, []);
@@ -374,6 +401,8 @@ export function ControlSystemProvider({ children }) {
registerInputState,
setSongNote,
sendSong,
startHorn,
stopHorn,
},
}),
[
@@ -397,6 +426,8 @@ export function ControlSystemProvider({ children }) {
registerInputState,
setSongNote,
sendSong,
startHorn,
stopHorn,
],
);
+21
View File
@@ -32,6 +32,11 @@ export function useCommandPipeline(options = {}) {
return rosterEntry.nightVision;
}, [rosterEntry]);
const horn = useMemo(() => {
if (!rosterEntry?.horn || !rosterEntry.horn.enabled) return null;
return rosterEntry.horn;
}, [rosterEntry]);
const nightVisionState = useMemo(() => rosterEntry?.nightVision?.state ?? null, [rosterEntry]);
const emitCommand = useCallback(
@@ -172,6 +177,18 @@ export function useCommandPipeline(options = {}) {
[emitCommand, nightVision, roverId],
);
const sendHorn = useCallback(
(payload) => {
if (!roverId) return null;
emitCommand({
type: 'horn',
data: { horn: payload },
});
return payload;
},
[emitCommand, roverId],
);
const sendSong = useCallback(
(notes = [], options = {}) => {
if (!roverId) return null;
@@ -205,6 +222,7 @@ export function useCommandPipeline(options = {}) {
servoConfig,
nightVision,
nightVisionState,
horn,
emitCommand,
enableSensorStream,
sendDriveDirect,
@@ -212,6 +230,7 @@ export function useCommandPipeline(options = {}) {
sendServoAngle,
sendOiCommand,
sendNightVision,
sendHorn,
sendSong,
runMacroSteps,
}),
@@ -221,6 +240,7 @@ export function useCommandPipeline(options = {}) {
servoConfig,
nightVision,
nightVisionState,
horn,
emitCommand,
enableSensorStream,
sendDriveDirect,
@@ -228,6 +248,7 @@ export function useCommandPipeline(options = {}) {
sendServoAngle,
sendOiCommand,
sendNightVision,
sendHorn,
runMacroSteps,
],
);
+1
View File
@@ -42,6 +42,7 @@ export const DEFAULT_KEYMAP = {
cameraUp: ['u'],
cameraDown: ['j'],
nightVisionToggle: ['e'],
hornHonk: ['h'],
driveMacro: ['f'],
dockMacro: ['g'],
chatFocus: ['enter'],
@@ -126,6 +126,8 @@ export default function KeyboardInputManager() {
stopAllMotion,
registerInputState,
toggleNightVision,
startHorn,
stopHorn,
setSongNote,
sendSong,
},
@@ -174,6 +176,7 @@ export default function KeyboardInputManager() {
const lastAuxRef = useRef(ZERO_AUX);
const servoIntervalRef = useRef(null);
const songIntervalRef = useRef(null);
const hornActiveRef = useRef(false);
const driveFromKeys = useCallback(() => {
const tokensSnapshot = new Set(activeTokensRef.current);
@@ -299,9 +302,13 @@ export default function KeyboardInputManager() {
lastAuxRef.current = ZERO_AUX;
stopServoLoop();
stopSongLoop();
if (hornActiveRef.current) {
hornActiveRef.current = false;
stopHorn();
}
stopAllMotion();
registerInputState(SOURCE, { keys: [], vector: ZERO_VECTOR, aux: ZERO_AUX });
}, [registerInputState, stopAllMotion, stopServoLoop, stopSongLoop]);
}, [registerInputState, stopAllMotion, stopHorn, stopServoLoop, stopSongLoop]);
const triggerHomeAssistantCycle = useCallback(
(targetState) => {
@@ -364,6 +371,11 @@ export default function KeyboardInputManager() {
runMacro('seek-dock');
} else if (newlyPressed.some((token) => keymap.nightVisionToggle?.has(token))) {
toggleNightVision();
} else if (newlyPressed.some((token) => keymap.hornHonk?.has(token))) {
if (!hornActiveRef.current) {
hornActiveRef.current = true;
startHorn();
}
} else if (newlyPressed.some((token) => keymap.homeAssistantOn?.has(token))) {
triggerHomeAssistantCycle('on');
} else if (newlyPressed.some((token) => keymap.homeAssistantOff?.has(token))) {
@@ -379,6 +391,10 @@ export default function KeyboardInputManager() {
function handleKeyUp(event) {
const tokens = tokensForEvent(event);
tokens.forEach((token) => activeTokensRef.current.delete(token));
if (hornActiveRef.current && !bindingActive(keymap.hornHonk, activeTokensRef.current)) {
hornActiveRef.current = false;
stopHorn();
}
ensureServoLoop();
ensureSongLoop();
driveFromKeys();
@@ -407,11 +423,14 @@ export default function KeyboardInputManager() {
keymap.chatFocus,
keymap.dockMacro,
keymap.driveMacro,
keymap.hornHonk,
resetAll,
runMacro,
setMode,
stopAllMotion,
stopSongLoop,
startHorn,
stopHorn,
triggerHomeAssistantCycle,
]);