Update: Relocate AutoRun controls and cleanup
This commit is contained in:
73
App.tsx
73
App.tsx
@@ -8,6 +8,7 @@ import AgvControls from './components/AgvControls';
|
|||||||
import BmsPanel from './components/BmsPanel';
|
import BmsPanel from './components/BmsPanel';
|
||||||
import AcsControls from './components/AcsControls';
|
import AcsControls from './components/AcsControls';
|
||||||
import AgvStatusPanel from './components/AgvStatusPanel';
|
import AgvStatusPanel from './components/AgvStatusPanel';
|
||||||
|
import AgvAutoRunControls from './components/AgvAutoRunControls';
|
||||||
import SystemLogPanel from './components/SystemLogPanel';
|
import SystemLogPanel from './components/SystemLogPanel';
|
||||||
import { SerialPortHandler } from './services/serialService';
|
import { SerialPortHandler } from './services/serialService';
|
||||||
|
|
||||||
@@ -184,12 +185,12 @@ const App: React.FC = () => {
|
|||||||
}, [addLog]);
|
}, [addLog]);
|
||||||
|
|
||||||
const handleAgvData = useCallback((data: Uint8Array) => {
|
const handleAgvData = useCallback((data: Uint8Array) => {
|
||||||
for(let i=0; i<data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
agvBufferRef.current.push(data[i]);
|
agvBufferRef.current.push(data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const buf = agvBufferRef.current;
|
const buf = agvBufferRef.current;
|
||||||
while(true) {
|
while (true) {
|
||||||
const stxIdx = buf.indexOf(0x02);
|
const stxIdx = buf.indexOf(0x02);
|
||||||
if (stxIdx === -1) {
|
if (stxIdx === -1) {
|
||||||
agvBufferRef.current = [];
|
agvBufferRef.current = [];
|
||||||
@@ -232,7 +233,7 @@ const App: React.FC = () => {
|
|||||||
|
|
||||||
setAgvState(s => {
|
setAgvState(s => {
|
||||||
const newBranch = (bunki === 'L' ? 'LEFT' : bunki === 'R' ? 'RIGHT' : bunki === 'S' ? 'STRAIGHT' : s.runConfig.branch);
|
const newBranch = (bunki === 'L' ? 'LEFT' : bunki === 'R' ? 'RIGHT' : bunki === 'S' ? 'STRAIGHT' : s.runConfig.branch);
|
||||||
const newSpeed = (['L','M','H'].includes(speed) ? speed : s.runConfig.speedLevel) as any;
|
const newSpeed = (['L', 'M', 'H'].includes(speed) ? speed : s.runConfig.speedLevel) as any;
|
||||||
|
|
||||||
// Treat '0' as placeholder for sensor if we want to preserve CBR logic,
|
// Treat '0' as placeholder for sensor if we want to preserve CBR logic,
|
||||||
// BUT allow manual toggle via UI to override later.
|
// BUT allow manual toggle via UI to override later.
|
||||||
@@ -298,7 +299,7 @@ const App: React.FC = () => {
|
|||||||
setAgvState(s => {
|
setAgvState(s => {
|
||||||
// Logic: Update if specific char provided, else keep existing
|
// Logic: Update if specific char provided, else keep existing
|
||||||
const newBranch = (bunki === 'L' ? 'LEFT' : bunki === 'R' ? 'RIGHT' : bunki === 'S' ? 'STRAIGHT' : s.runConfig.branch);
|
const newBranch = (bunki === 'L' ? 'LEFT' : bunki === 'R' ? 'RIGHT' : bunki === 'S' ? 'STRAIGHT' : s.runConfig.branch);
|
||||||
const newSpeed = (['L','M','H'].includes(speed) ? speed : s.runConfig.speedLevel) as any;
|
const newSpeed = (['L', 'M', 'H'].includes(speed) ? speed : s.runConfig.speedLevel) as any;
|
||||||
|
|
||||||
const newLidar = sensor !== '0';
|
const newLidar = sensor !== '0';
|
||||||
|
|
||||||
@@ -603,7 +604,7 @@ const App: React.FC = () => {
|
|||||||
const resp = new Uint8Array(34);
|
const resp = new Uint8Array(34);
|
||||||
resp[0] = 0xDD; resp[1] = 0x03; resp[2] = 0x00; resp[3] = 0x1b; //arrary 3value 0->1b
|
resp[0] = 0xDD; resp[1] = 0x03; resp[2] = 0x00; resp[3] = 0x1b; //arrary 3value 0->1b
|
||||||
|
|
||||||
const totalV = Math.floor(s.cellVoltages.reduce((a,b)=>a+b, 0) * 100);
|
const totalV = Math.floor(s.cellVoltages.reduce((a, b) => a + b, 0) * 100);
|
||||||
resp[4] = (totalV >> 8) & 0xFF; resp[5] = totalV & 0xFF;
|
resp[4] = (totalV >> 8) & 0xFF; resp[5] = totalV & 0xFF;
|
||||||
|
|
||||||
const remainAh = Math.floor(s.maxCapacity * (s.batteryLevel / 100));
|
const remainAh = Math.floor(s.maxCapacity * (s.batteryLevel / 100));
|
||||||
@@ -675,7 +676,7 @@ const App: React.FC = () => {
|
|||||||
|
|
||||||
acsSerialRef.current.send(new Uint8Array(buffer));
|
acsSerialRef.current.send(new Uint8Array(buffer));
|
||||||
|
|
||||||
const hex = buffer.map(b => b.toString(16).padStart(2,'0').toUpperCase()).join(' ');
|
const hex = buffer.map(b => b.toString(16).padStart(2, '0').toUpperCase()).join(' ');
|
||||||
addLog('ACS', 'TX', `CMD:${cmd.toString(16).toUpperCase()} [${hex}]`);
|
addLog('ACS', 'TX', `CMD:${cmd.toString(16).toUpperCase()} [${hex}]`);
|
||||||
}, [addLog]);
|
}, [addLog]);
|
||||||
|
|
||||||
@@ -735,7 +736,7 @@ const App: React.FC = () => {
|
|||||||
// Default Little Endian. So index len-3 is Low, len-2 is High.
|
// Default Little Endian. So index len-3 is Low, len-2 is High.
|
||||||
|
|
||||||
if (receivedCrc !== 0xFFFF && calcCrc !== receivedCrc) {
|
if (receivedCrc !== 0xFFFF && calcCrc !== receivedCrc) {
|
||||||
const hex = packetData.map(b => b.toString(16).padStart(2,'0').toUpperCase()).join(' ');
|
const hex = packetData.map(b => b.toString(16).padStart(2, '0').toUpperCase()).join(' ');
|
||||||
addLog('ACS', 'ERROR', `CRC Fail: ${hex}`);
|
addLog('ACS', 'ERROR', `CRC Fail: ${hex}`);
|
||||||
acsParseErrorsRef.current++;
|
acsParseErrorsRef.current++;
|
||||||
if (acsParseErrorsRef.current > 3) buf.length = 0; // Reset on too many errors
|
if (acsParseErrorsRef.current > 3) buf.length = 0; // Reset on too many errors
|
||||||
@@ -750,7 +751,7 @@ const App: React.FC = () => {
|
|||||||
const cmd = packetData[3];
|
const cmd = packetData[3];
|
||||||
const payload = packetData.slice(4, totalPacketSize - 3);
|
const payload = packetData.slice(4, totalPacketSize - 3);
|
||||||
|
|
||||||
const hexStr = packetData.map(b => b.toString(16).padStart(2,'0').toUpperCase()).join(' ');
|
const hexStr = packetData.map(b => b.toString(16).padStart(2, '0').toUpperCase()).join(' ');
|
||||||
addLog('ACS', 'RX', `[ID:${id} CMD:${cmd}] ${hexStr}`);
|
addLog('ACS', 'RX', `[ID:${id} CMD:${cmd}] ${hexStr}`);
|
||||||
|
|
||||||
// Consume buffer
|
// Consume buffer
|
||||||
@@ -890,7 +891,7 @@ const App: React.FC = () => {
|
|||||||
const [xStr, yStr] = l.Position.split(',').map(s => s.trim());
|
const [xStr, yStr] = l.Position.split(',').map(s => s.trim());
|
||||||
newNodes.push({
|
newNodes.push({
|
||||||
id: l.Id,
|
id: l.Id,
|
||||||
x: parseFloat(xStr)||0, y: parseFloat(yStr)||0,
|
x: parseFloat(xStr) || 0, y: parseFloat(yStr) || 0,
|
||||||
type: NodeType.Label,
|
type: NodeType.Label,
|
||||||
name: "",
|
name: "",
|
||||||
rfidId: "",
|
rfidId: "",
|
||||||
@@ -909,7 +910,7 @@ const App: React.FC = () => {
|
|||||||
const [xStr, yStr] = img.Position.split(',').map(s => s.trim());
|
const [xStr, yStr] = img.Position.split(',').map(s => s.trim());
|
||||||
newNodes.push({
|
newNodes.push({
|
||||||
id: img.Id,
|
id: img.Id,
|
||||||
x: parseFloat(xStr)||0, y: parseFloat(yStr)||0,
|
x: parseFloat(xStr) || 0, y: parseFloat(yStr) || 0,
|
||||||
type: NodeType.Image,
|
type: NodeType.Image,
|
||||||
name: img.Name,
|
name: img.Name,
|
||||||
rfidId: "",
|
rfidId: "",
|
||||||
@@ -1047,7 +1048,7 @@ const App: React.FC = () => {
|
|||||||
NodeTextFontSize: n.fontSize || 7.0,
|
NodeTextFontSize: n.fontSize || 7.0,
|
||||||
AliasName: "",
|
AliasName: "",
|
||||||
SpeedLimit: 0,
|
SpeedLimit: 0,
|
||||||
CanDocking: [1,2,3,4,5].includes(n.type),
|
CanDocking: [1, 2, 3, 4, 5].includes(n.type),
|
||||||
DockDirection: n.type === NodeType.Charging || n.type === NodeType.ChargerStation ? 1 : 0,
|
DockDirection: n.type === NodeType.Charging || n.type === NodeType.ChargerStation ? 1 : 0,
|
||||||
CanTurnLeft: true,
|
CanTurnLeft: true,
|
||||||
CanTurnRight: true,
|
CanTurnRight: true,
|
||||||
@@ -1126,7 +1127,7 @@ const App: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// --- Real-time updates to Serial (AGV Events) ---
|
// --- Real-time updates to Serial (AGV Events) ---
|
||||||
const prevSensors = useRef({ rfid: null as string|null, mark: false, line: false });
|
const prevSensors = useRef({ rfid: null as string | null, mark: false, line: false });
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!agvConnected || !agvSerialRef.current) return;
|
if (!agvConnected || !agvSerialRef.current) return;
|
||||||
|
|
||||||
@@ -1164,8 +1165,38 @@ const App: React.FC = () => {
|
|||||||
<div className="w-80 border-r border-gray-800 bg-gray-900 flex flex-col shrink-0">
|
<div className="w-80 border-r border-gray-800 bg-gray-900 flex flex-col shrink-0">
|
||||||
<div className="flex-1 overflow-hidden">
|
<div className="flex-1 overflow-hidden">
|
||||||
<AgvStatusPanel agvState={agvState} />
|
<AgvStatusPanel agvState={agvState} />
|
||||||
|
|
||||||
</div>
|
</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="flex-1 overflow-hidden">
|
||||||
|
<AgvAutoRunControls
|
||||||
|
agvState={agvState}
|
||||||
|
updateRunConfig={(key, value) => {
|
||||||
|
if (agvState.error) return;
|
||||||
|
setAgvState(s => ({ ...s, runConfig: { ...s.runConfig, [key]: value } }));
|
||||||
|
}}
|
||||||
|
toggleRun={() => {
|
||||||
|
if (agvState.error) return;
|
||||||
|
if (agvState.motionState === AgvMotionState.RUNNING || agvState.motionState === AgvMotionState.MARK_STOPPING) {
|
||||||
|
setAgvState(s => ({ ...s, motionState: AgvMotionState.IDLE }));
|
||||||
|
} else {
|
||||||
|
const isFwd = agvState.runConfig.direction === 'FWD';
|
||||||
|
const hasLine = isFwd ? agvState.sensorLineFront : agvState.sensorLineRear;
|
||||||
|
if (!hasLine) {
|
||||||
|
setAgvState(s => ({ ...s, error: 'LINE_OUT' }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setAgvState(s => ({ ...s, motionState: AgvMotionState.RUNNING }));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
isRunning={agvState.motionState === AgvMotionState.RUNNING || agvState.motionState === AgvMotionState.MARK_STOPPING}
|
||||||
|
isError={agvState.error !== null}
|
||||||
|
setLidar={(isOn) => setAgvState(s => ({ ...s, lidarEnabled: isOn, sensorStatus: isOn ? '1' : '0' }))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Middle 2: ACS Panel (Fixed) */}
|
{/* Middle 2: ACS Panel (Fixed) */}
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
@@ -1242,20 +1273,20 @@ const App: React.FC = () => {
|
|||||||
<div className="flex-1 overflow-y-auto">
|
<div className="flex-1 overflow-y-auto">
|
||||||
<AgvControls
|
<AgvControls
|
||||||
agvState={agvState}
|
agvState={agvState}
|
||||||
setMotion={(m) => setAgvState(s => ({...s, motionState: m}))}
|
setMotion={(m) => setAgvState(s => ({ ...s, motionState: m }))}
|
||||||
setLift={(h) => setAgvState(s => ({...s, liftHeight: h}))}
|
setLift={(h) => setAgvState(s => ({ ...s, liftHeight: h }))}
|
||||||
setRunConfig={(c) => setAgvState(s => ({...s, runConfig: c}))}
|
setRunConfig={(c) => setAgvState(s => ({ ...s, runConfig: c }))}
|
||||||
setError={(e) => setAgvState(s => ({...s, error: e}))}
|
setError={(e) => setAgvState(s => ({ ...s, error: e }))}
|
||||||
onTurn180={handleTurn180}
|
onTurn180={handleTurn180}
|
||||||
setMagnet={(isOn) => setAgvState(s => ({...s, magnetOn: isOn}))}
|
setMagnet={(isOn) => setAgvState(s => ({ ...s, magnetOn: isOn }))}
|
||||||
setLiftStatus={(status) => setAgvState(s => ({...s, liftStatus: status}))}
|
setLiftStatus={(status) => setAgvState(s => ({ ...s, liftStatus: status }))}
|
||||||
setLidar={(isOn) => setAgvState(s => ({...s, lidarEnabled: isOn, sensorStatus: isOn ? '1' : '0'}))}
|
setLidar={(isOn) => setAgvState(s => ({ ...s, lidarEnabled: isOn, sensorStatus: isOn ? '1' : '0' }))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Middle 1: BMS Panel (Fixed) */}
|
{/* Middle 1: BMS Panel (Fixed) */}
|
||||||
<div className="flex-shrink-0">
|
<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 }))} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bottom: System Logs (Fixed Height) */}
|
{/* Bottom: System Logs (Fixed Height) */}
|
||||||
@@ -1263,7 +1294,7 @@ const App: React.FC = () => {
|
|||||||
<SystemLogPanel logs={logs.filter(l => l.source === 'SYSTEM')} onClear={() => clearLogs('SYSTEM')} />
|
<SystemLogPanel logs={logs.filter(l => l.source === 'SYSTEM')} onClear={() => clearLogs('SYSTEM')} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
1
commit_msg_2.txt
Normal file
1
commit_msg_2.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Update: Relocate AutoRun controls and cleanup
|
||||||
@@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
import { StopCircle, Play, Square, AlertTriangle, ChevronsUp, ChevronsDown, Magnet, Radar, ArrowLeft, ArrowRight } from 'lucide-react';
|
import { StopCircle, Play, Square, AlertTriangle, ChevronsUp, ChevronsDown, Magnet, Radar, ArrowLeft, ArrowRight } from 'lucide-react';
|
||||||
import { AgvState, AgvMotionState, AgvRunConfig } from '../types';
|
import { AgvState, AgvMotionState, AgvRunConfig } from '../types';
|
||||||
import AgvManualControls from './AgvManualControls';
|
import AgvManualControls from './AgvManualControls';
|
||||||
import AgvAutoRunControls from './AgvAutoRunControls';
|
|
||||||
|
|
||||||
interface AgvControlsProps {
|
interface AgvControlsProps {
|
||||||
agvState: AgvState;
|
agvState: AgvState;
|
||||||
@@ -29,22 +29,7 @@ const AgvControls: React.FC<AgvControlsProps> = ({ agvState, setMotion, setLift,
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleRun = () => {
|
|
||||||
if (isError) return;
|
|
||||||
|
|
||||||
if (isRunning) {
|
|
||||||
setMotion(AgvMotionState.IDLE);
|
|
||||||
} else {
|
|
||||||
const isFwd = agvState.runConfig.direction === 'FWD';
|
|
||||||
const hasLine = isFwd ? agvState.sensorLineFront : agvState.sensorLineRear;
|
|
||||||
|
|
||||||
if (!hasLine) {
|
|
||||||
setError('LINE_OUT');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setMotion(AgvMotionState.RUNNING);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMarkStop = () => {
|
const handleMarkStop = () => {
|
||||||
if (agvState.motionState === AgvMotionState.RUNNING) {
|
if (agvState.motionState === AgvMotionState.RUNNING) {
|
||||||
@@ -152,14 +137,7 @@ const AgvControls: React.FC<AgvControlsProps> = ({ agvState, setMotion, setLift,
|
|||||||
|
|
||||||
{/* Auto Run Controls */}
|
{/* Auto Run Controls */}
|
||||||
{/* Auto Run Controls (분리된 콤포넌트) */}
|
{/* Auto Run Controls (분리된 콤포넌트) */}
|
||||||
<AgvAutoRunControls
|
|
||||||
agvState={agvState}
|
|
||||||
updateRunConfig={updateRunConfig}
|
|
||||||
toggleRun={toggleRun}
|
|
||||||
isRunning={isRunning}
|
|
||||||
isError={isError}
|
|
||||||
setLidar={setLidar}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user