precision camera stuff

This commit is contained in:
legop3
2026-06-29 21:06:21 -04:00
parent 79be3e1583
commit 0cc40b7608
12 changed files with 129 additions and 28 deletions
@@ -12,6 +12,9 @@ import VerticalCameraTilt from './VerticalCameraTilt.jsx';
import { trackAnalyticsEvent } from '../../analytics/index.js';
import { useSessionSelector } from '../../context/SessionContext.jsx';
const CAMERA_TILT_STEP_DEGREES = 0.5;
const CAMERA_TILT_PRECISION_STEP_DEGREES = 0.1;
function AuxColumnContent() {
const roverId = useControlSelector((control) => control.state.roverId);
const roomLightsLockedOn = useSessionSelector((state) => Boolean(state.session?.homeAssistant?.lightPolicy?.lockedOn));
@@ -41,6 +44,14 @@ function AuxColumnContent() {
? cameraConfig.homeAngle
: (cameraMin + cameraMax) / 2;
const cameraDisabled = Boolean(disabled || dockAssist.cameraLocked);
/*
The mobile tilt track shares the same precision flag as desktop tilt. This
keeps the servo fine-step behavior tied to the selected movement mode rather
than inventing a separate mobile-only camera setting.
*/
const cameraTiltStep = camera?.precisionMode
? CAMERA_TILT_PRECISION_STEP_DEGREES
: CAMERA_TILT_STEP_DEGREES;
const handleHeadlightToggle = useCallback(
(nextOn) => {
@@ -101,7 +112,7 @@ function AuxColumnContent() {
value={cameraValue}
min={cameraMin}
max={cameraMax}
step={0.5}
step={cameraTiltStep}
disabled={cameraDisabled}
onChange={setServoAngle}
/>
@@ -30,7 +30,7 @@ function getSpeedModeConfig(speedMode) {
export default function ControlPadPanel({ disabled = false }) {
const rawKeymap = useControlSelector((control) => control.state.keymap);
const { setDriveVector, registerInputState } = useControlActions();
const { setCameraPrecisionMode, setDriveVector, registerInputState } = useControlActions();
const { value: inputSettings } = useSettingsNamespace('inputs', INPUT_SETTINGS_DEFAULTS);
const [speedMode, setSpeedMode] = useState('normal');
const [activeInputLabel, setActiveInputLabel] = useState('stop');
@@ -71,10 +71,18 @@ export default function ControlPadPanel({ disabled = false }) {
const tokens = buildVirtualKeyTokens(cell, modeId);
const vector = computeKeyboardDriveVector(tokens, keymap);
const speedOptions = getKeyboardDriveSpeedOptions(tokens, keymap, keyboardSpeeds);
const precisionActive = modeId === 'precision';
// Mobile deliberately routes through the keyboard vector/speed helpers. The
// thumb pad only chooses which virtual keys are down, so changes to keyboard
// drive behavior automatically stay matched here.
/*
The selected mobile speed mode is persistent, unlike the keyboard's held
Shift modifier. Publishing camera precision here makes the servo tilt
controls follow the mobile movement mode even before the driver starts
dragging on the pad.
*/
setCameraPrecisionMode(precisionActive);
setDriveVector(vector, { source: SOURCE, speedOptions });
registerInputState(SOURCE, {
keys: Array.from(tokens),
@@ -90,6 +98,7 @@ export default function ControlPadPanel({ disabled = false }) {
keyboardSpeeds,
keymap,
registerInputState,
setCameraPrecisionMode,
setDriveVector,
],
);
@@ -99,7 +108,7 @@ export default function ControlPadPanel({ disabled = false }) {
clearRepeatTimer();
activeCellRef.current = null;
setActiveInputLabel('stop');
sendDriveCell({ id: 'stop', actions: [] }, lastEvent, 'normal');
sendDriveCell({ id: 'stop', actions: [] }, lastEvent, speedModeRef.current);
},
[clearRepeatTimer, sendDriveCell],
);
@@ -127,21 +136,31 @@ export default function ControlPadPanel({ disabled = false }) {
(nextMode) => {
setSpeedMode(nextMode);
speedModeRef.current = nextMode;
setCameraPrecisionMode(nextMode === 'precision');
if (activeCellRef.current) {
sendDriveCell(activeCellRef.current, 'speed', nextMode);
}
},
[sendDriveCell],
[sendDriveCell, setCameraPrecisionMode],
);
useEffect(() => {
return () => clearRepeatTimer();
}, [clearRepeatTimer]);
return () => {
clearRepeatTimer();
/*
Mobile controls can unmount when layouts change or the driver leaves the
control surface. Clear the shared flag so a stale mobile precision choice
cannot leave desktop/keyboard camera tilt in fine-step mode.
*/
setCameraPrecisionMode(false);
};
}, [clearRepeatTimer, setCameraPrecisionMode]);
useEffect(() => {
if (!disabled) return;
stopDrivePad('disabled');
}, [disabled, stopDrivePad]);
setCameraPrecisionMode(false);
}, [disabled, setCameraPrecisionMode, stopDrivePad]);
return (
<div className="mobile-touch-control flex flex-1 min-h-0 flex-col overflow-hidden rounded-xl border-2 border-slate-700 bg-slate-900 text-slate-100 shadow-md">
+13 -2
View File
@@ -39,6 +39,8 @@ const CHAT_DOCK_INITIAL_HEIGHT = 224;
const CHAT_DOCK_MIN_HEIGHT = 144;
const CHAT_DOCK_MAX_HEIGHT = 300;
const CHAT_DOCK_BOTTOM_INSET = 8;
const CAMERA_TILT_STEP_DEGREES = 0.5;
const CAMERA_TILT_PRECISION_STEP_DEGREES = 0.1;
function TopDownMapPanel() {
const roverId = useControlSelector((control) => control.state.roverId);
@@ -90,6 +92,14 @@ function DriveDockPanel() {
const upLabel = formatKeyLabel(keymap?.cameraUp?.[0]);
const downLabel = formatKeyLabel(keymap?.cameraDown?.[0]);
const cameraDisabled = Boolean(!roverId || dockAssist.cameraLocked);
/*
Precision movement mode also tightens the servo slider step. The command
path still sends ordinary angle targets; only the UI increment changes while
precision mode is active.
*/
const cameraTiltStep = camera?.precisionMode
? CAMERA_TILT_PRECISION_STEP_DEGREES
: CAMERA_TILT_STEP_DEGREES;
const trackedControls = useMemo(
() => ({
setHeadlight: (nextOn) => {
@@ -156,6 +166,7 @@ function DriveDockPanel() {
value={value}
min={min}
max={max}
step={cameraTiltStep}
label="Camera tilt"
disabled={cameraDisabled}
onChange={setServoAngle}
@@ -388,9 +399,9 @@ export default function RightPaneTabs({ layout, onOpenHelpOverlay }) {
{/* activities tab */}
<TabPanel id="activities">
<div className={`flex flex-col ${themeGapClass}`}>
<BarcodeGamesPanel />
<LiftCard />
<NeatoCard />
<LiftCard />
<BarcodeGamesPanel />
<OdometerPanel />
<ButtonBoxPanel />
<KinectPanel />