mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-17 01:50:47 -04:00
output rate limit and override gating
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -11,7 +11,7 @@
|
|||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||||
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
||||||
<title>Multi Roomba Rover</title>
|
<title>Multi Roomba Rover</title>
|
||||||
<script type="module" crossorigin src="/assets/index-BU08RP3S.js"></script>
|
<script type="module" crossorigin src="/assets/index-DlZ3NGp7.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-BBEWYgmH.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-BBEWYgmH.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ export default function OvercurrentLimiterPanel() {
|
|||||||
<div className="surface text-[0.7rem] text-slate-400">
|
<div className="surface text-[0.7rem] text-slate-400">
|
||||||
<div>{`A charge ${overcurrentLimiter?.config?.meterAChargeSec}s · A decay ${overcurrentLimiter?.config?.meterADecaySec}s`}</div>
|
<div>{`A charge ${overcurrentLimiter?.config?.meterAChargeSec}s · A decay ${overcurrentLimiter?.config?.meterADecaySec}s`}</div>
|
||||||
<div>{`B charge ${overcurrentLimiter?.config?.meterBChargeSec}s · B decay ${overcurrentLimiter?.config?.meterBDecaySec}s`}</div>
|
<div>{`B charge ${overcurrentLimiter?.config?.meterBChargeSec}s · B decay ${overcurrentLimiter?.config?.meterBDecaySec}s`}</div>
|
||||||
|
<div>{`Output rate ${overcurrentLimiter?.config?.outputRateMs}ms`}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -142,6 +142,8 @@ export function ControlSystemProvider({ children }) {
|
|||||||
const driveSpeedsRef = useRef(state.drive.speeds);
|
const driveSpeedsRef = useRef(state.drive.speeds);
|
||||||
const auxValuesRef = useRef(state.aux);
|
const auxValuesRef = useRef(state.aux);
|
||||||
const limiterScaleToken = useMemo(() => JSON.stringify(overcurrentLimiter.scales), [overcurrentLimiter.scales]);
|
const limiterScaleToken = useMemo(() => JSON.stringify(overcurrentLimiter.scales), [overcurrentLimiter.scales]);
|
||||||
|
const limiterDriveSentAtRef = useRef(0);
|
||||||
|
const limiterAuxSentAtRef = useRef(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
driveSpeedsRef.current = state.drive.speeds;
|
driveSpeedsRef.current = state.drive.speeds;
|
||||||
@@ -152,19 +154,23 @@ export function ControlSystemProvider({ children }) {
|
|||||||
}, [state.aux]);
|
}, [state.aux]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!pipeline.roverId || overcurrentLimiter.adminImmune) return;
|
if (!pipeline.roverId || overcurrentLimiter.adminImmune || !overcurrentLimiter.isActive) return;
|
||||||
|
const outputRateMs = Math.max(0, Number(overcurrentLimiter?.config?.outputRateMs) || 0);
|
||||||
|
const now = typeof performance !== 'undefined' ? performance.now() : Date.now();
|
||||||
const drive = driveSpeedsRef.current || { left: 0, right: 0 };
|
const drive = driveSpeedsRef.current || { left: 0, right: 0 };
|
||||||
const aux = auxValuesRef.current || { main: 0, side: 0, vacuum: 0 };
|
const aux = auxValuesRef.current || { main: 0, side: 0, vacuum: 0 };
|
||||||
const driveActive = Boolean(drive.left || drive.right);
|
const driveActive = Boolean(drive.left || drive.right);
|
||||||
const auxActive = Boolean(aux.main || aux.side || aux.vacuum);
|
const auxActive = Boolean(aux.main || aux.side || aux.vacuum);
|
||||||
if (!driveActive && !auxActive) return;
|
if (!driveActive && !auxActive) return;
|
||||||
if (driveActive) {
|
if (driveActive && now - limiterDriveSentAtRef.current >= outputRateMs) {
|
||||||
|
limiterDriveSentAtRef.current = now;
|
||||||
pipeline.sendDriveDirect(drive);
|
pipeline.sendDriveDirect(drive);
|
||||||
}
|
}
|
||||||
if (auxActive) {
|
if (auxActive && now - limiterAuxSentAtRef.current >= outputRateMs) {
|
||||||
|
limiterAuxSentAtRef.current = now;
|
||||||
pipeline.sendAuxMotors(aux);
|
pipeline.sendAuxMotors(aux);
|
||||||
}
|
}
|
||||||
}, [limiterScaleToken, overcurrentLimiter.adminImmune, pipeline]);
|
}, [limiterScaleToken, overcurrentLimiter.adminImmune, overcurrentLimiter.config, overcurrentLimiter.isActive, pipeline]);
|
||||||
|
|
||||||
const setDriveVector = useCallback(
|
const setDriveVector = useCallback(
|
||||||
(vector, meta = {}) => {
|
(vector, meta = {}) => {
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ export const OVERCURRENT_GROUPS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const DEFAULT_OVERCURRENT_LIMITS = {
|
export const DEFAULT_OVERCURRENT_LIMITS = {
|
||||||
meterAChargeSec: 3,
|
meterAChargeSec: 9,
|
||||||
meterADecaySec: 9,
|
meterADecaySec: 9,
|
||||||
meterBChargeSec: 1,
|
meterBChargeSec: 5,
|
||||||
meterBDecaySec: 10,
|
meterBDecaySec: 5,
|
||||||
|
outputRateMs: 250,
|
||||||
};
|
};
|
||||||
|
|
||||||
function createInitialMeters() {
|
function createInitialMeters() {
|
||||||
@@ -139,6 +140,7 @@ export function useOvercurrentLimiter(roverId, options = {}) {
|
|||||||
meters,
|
meters,
|
||||||
overcurrent,
|
overcurrent,
|
||||||
scales,
|
scales,
|
||||||
|
isActive: (scales?.drive?.left ?? 1) < 1 || (scales?.drive?.right ?? 1) < 1 || (scales?.aux?.main ?? 1) < 1 || (scales?.aux?.side ?? 1) < 1,
|
||||||
config,
|
config,
|
||||||
adminImmune,
|
adminImmune,
|
||||||
}),
|
}),
|
||||||
@@ -150,6 +152,7 @@ export function applyDriveOvercurrentScale(speeds = {}, scales, adminImmune = fa
|
|||||||
if (adminImmune || !scales?.drive) return speeds;
|
if (adminImmune || !scales?.drive) return speeds;
|
||||||
const leftScale = typeof scales.drive.left === 'number' ? scales.drive.left : 1;
|
const leftScale = typeof scales.drive.left === 'number' ? scales.drive.left : 1;
|
||||||
const rightScale = typeof scales.drive.right === 'number' ? scales.drive.right : 1;
|
const rightScale = typeof scales.drive.right === 'number' ? scales.drive.right : 1;
|
||||||
|
if (leftScale >= 0.999 && rightScale >= 0.999) return speeds;
|
||||||
return {
|
return {
|
||||||
left: Math.round((speeds.left ?? 0) * leftScale),
|
left: Math.round((speeds.left ?? 0) * leftScale),
|
||||||
right: Math.round((speeds.right ?? 0) * rightScale),
|
right: Math.round((speeds.right ?? 0) * rightScale),
|
||||||
@@ -161,6 +164,7 @@ export function applyAuxOvercurrentScale(values = {}, scales, adminImmune = fals
|
|||||||
const mainScale = typeof scales.aux.main === 'number' ? scales.aux.main : 1;
|
const mainScale = typeof scales.aux.main === 'number' ? scales.aux.main : 1;
|
||||||
const sideScale = typeof scales.aux.side === 'number' ? scales.aux.side : 1;
|
const sideScale = typeof scales.aux.side === 'number' ? scales.aux.side : 1;
|
||||||
const vacuumScale = typeof scales.aux.vacuum === 'number' ? scales.aux.vacuum : 1;
|
const vacuumScale = typeof scales.aux.vacuum === 'number' ? scales.aux.vacuum : 1;
|
||||||
|
if (mainScale >= 0.999 && sideScale >= 0.999 && vacuumScale >= 0.999) return values;
|
||||||
return {
|
return {
|
||||||
main: Math.round((values.main ?? 0) * mainScale),
|
main: Math.round((values.main ?? 0) * mainScale),
|
||||||
side: Math.round((values.side ?? 0) * sideScale),
|
side: Math.round((values.side ?? 0) * sideScale),
|
||||||
|
|||||||
Reference in New Issue
Block a user