\"feat_Enhance_BMS_Simulation_SystemLog_UI_and_ACS_Controls\"

This commit is contained in:
2025-12-19 00:52:33 +09:00
parent 051138489b
commit b2a26bc67d
7 changed files with 396 additions and 241 deletions

79
App.tsx
View File

@@ -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) */}