\"feat_Enhance_BMS_Simulation_SystemLog_UI_and_ACS_Controls\"
This commit is contained in:
79
App.tsx
79
App.tsx
@@ -71,7 +71,8 @@ const App: React.FC = () => {
|
||||
// Lift & Magnet
|
||||
magnetOn: false,
|
||||
liftStatus: 'IDLE',
|
||||
lidarEnabled: true, // Default ON
|
||||
lidarEnabled: false,
|
||||
isCharging: false, // Initial state
|
||||
|
||||
// Protocol Flags Initial State
|
||||
system0: 0,
|
||||
@@ -80,8 +81,8 @@ const App: React.FC = () => {
|
||||
signalFlags: 0, // Will be updated by useEffect
|
||||
|
||||
batteryLevel: 95,
|
||||
maxCapacity: 100, // 100Ah
|
||||
batteryTemp: 25,
|
||||
maxCapacity: 100,
|
||||
batteryTemps: [25.0, 26.5],
|
||||
cellVoltages: Array(8).fill(3.2),
|
||||
});
|
||||
|
||||
@@ -607,6 +608,26 @@ const App: React.FC = () => {
|
||||
const totalV = Math.floor(s.cellVoltages.reduce((a, b) => a + b, 0) * 100);
|
||||
resp[4] = (totalV >> 8) & 0xFF; resp[5] = totalV & 0xFF;
|
||||
|
||||
// 6, 7: Current (mA)
|
||||
// Power (W) = (mA / 1000) * V => mA = (W / V) * 1000.
|
||||
// Discharging: ~50W, Charging: ~-450W.
|
||||
const isCharging = s.isCharging; // Use manual state
|
||||
const powerW = isCharging ? -450 : 50;
|
||||
|
||||
let currentMA = 0;
|
||||
if (totalV > 0) {
|
||||
const realV = totalV / 100; // Convert 0.01V to Volts
|
||||
currentMA = Math.floor((powerW / totalV) * 10);
|
||||
}
|
||||
|
||||
// Write Int16 (Little Endian or Big Endian? BMS usually Big Endian for these usually?
|
||||
// Code above uses Big Endian for Voltage (resp[4] = high, resp[5] = low).
|
||||
// Standard BMS protocols often BE. I will follow the pattern of Voltage.
|
||||
// Handle negative numbers via Two's Complement for manual byte splitting if needed,
|
||||
// but bitwise ops on standard JS numbers (treated as 32bit int) work fine for & 0xFF.
|
||||
resp[6] = (currentMA >> 8) & 0xFF;
|
||||
resp[7] = currentMA & 0xFF;
|
||||
|
||||
const remainAh = Math.floor(s.maxCapacity * (s.batteryLevel / 100));
|
||||
resp[8] = (remainAh >> 8) & 0xFF; resp[9] = remainAh & 0xFF;
|
||||
const maxAh = s.maxCapacity;
|
||||
@@ -614,8 +635,8 @@ const App: React.FC = () => {
|
||||
|
||||
resp[23] = Math.floor(s.batteryLevel);
|
||||
|
||||
const t1 = Math.floor((s.batteryTemp * 10) + 2731);
|
||||
const t2 = Math.floor((s.batteryTemp * 10) + 2731);
|
||||
const t1 = Math.floor((s.batteryTemps[0] * 10) + 2731);
|
||||
const t2 = Math.floor((s.batteryTemps[1] * 10) + 2731);
|
||||
|
||||
resp[27] = (t1 >> 8) & 0xFF; resp[28] = t1 & 0xFF;
|
||||
resp[29] = (t2 >> 8) & 0xFF; resp[30] = t2 & 0xFF;
|
||||
@@ -1145,6 +1166,40 @@ const App: React.FC = () => {
|
||||
};
|
||||
}, [agvState, agvConnected, sendTag]);
|
||||
|
||||
// BMS Simulation
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setAgvState(s => {
|
||||
const isCharging = s.isCharging;
|
||||
let newLevel = s.batteryLevel;
|
||||
|
||||
if (isCharging) {
|
||||
// Charge: 1% per min (faster than discharge)
|
||||
newLevel = Math.min(100, s.batteryLevel + (1.0 / 60));
|
||||
} else {
|
||||
// Discharge: 5% per 10 min = 0.5% per min = 0.5 / 60 per sec
|
||||
newLevel = Math.max(0, s.batteryLevel - (0.5 / 60));
|
||||
}
|
||||
|
||||
// Fluctuate Voltages (+- 0.01V)
|
||||
const newVoltages = s.cellVoltages.map(v => {
|
||||
const delta = (Math.random() - 0.5) * 0.02;
|
||||
let val = v + delta;
|
||||
if (val < 2.8) val = 2.8;
|
||||
if (val > 3.6) val = 3.6;
|
||||
return val;
|
||||
});
|
||||
|
||||
return {
|
||||
...s,
|
||||
batteryLevel: newLevel,
|
||||
cellVoltages: newVoltages
|
||||
};
|
||||
});
|
||||
}, 1000);
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex h-screen w-screen bg-gray-950 text-white overflow-hidden"
|
||||
@@ -1162,14 +1217,14 @@ const App: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* 2. Inner Left: Protocol Flags (Separated Sidebar) - Removed BMS from here */}
|
||||
<div className="w-80 border-r border-gray-800 bg-gray-900 flex flex-col shrink-0">
|
||||
<div className="w-60 border-r border-gray-800 bg-gray-900 flex flex-col shrink-0">
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<AgvStatusPanel agvState={agvState} />
|
||||
|
||||
</div>
|
||||
|
||||
{/* Auto Run Controls (Left Sidebar) */}
|
||||
<div className="w-80 border-r border-gray-800 bg-gray-900 flex flex-col shrink-0">
|
||||
<div className="w-60 border-r border-gray-800 bg-gray-900 flex flex-col shrink-0">
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<AgvAutoRunControls
|
||||
agvState={agvState}
|
||||
@@ -1267,7 +1322,7 @@ const App: React.FC = () => {
|
||||
</div>
|
||||
|
||||
{/* 4. Right: Controls & BMS & ACS */}
|
||||
<div className="w-80 border-l border-gray-800 bg-gray-900 flex flex-col shrink-0">
|
||||
<div className="w-72 border-l border-gray-800 bg-gray-900 flex flex-col shrink-0">
|
||||
|
||||
{/* Top: Controls (Scrollable if needed) */}
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
@@ -1286,7 +1341,13 @@ const App: React.FC = () => {
|
||||
|
||||
{/* Middle 1: BMS Panel (Fixed) */}
|
||||
<div className="flex-shrink-0">
|
||||
<BmsPanel state={agvState} setBatteryLevel={(l) => setAgvState(s => ({ ...s, batteryLevel: l }))} />
|
||||
<BmsPanel
|
||||
state={agvState}
|
||||
setBatteryLevel={(l) => setAgvState(s => ({ ...s, batteryLevel: l }))}
|
||||
setIsCharging={(isConnected) => {
|
||||
setAgvState(s => ({ ...s, isCharging: isConnected }));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Bottom: System Logs (Fixed Height) */}
|
||||
|
||||
Reference in New Issue
Block a user