Implement ACS Command Handlers (PickOn, PickOff, Charge), Manual Mode Safety, and Map UI Commands

This commit is contained in:
2025-12-13 02:40:55 +09:00
parent 703e1387bf
commit 34b038c4be
25 changed files with 1992 additions and 295 deletions

View File

@@ -88,17 +88,18 @@ namespace AGVNavigationCore.Models
private bool _disablecross = false;
/// <summary>
/// 해당 노드 통과 시 제한 속도 (기본값: M - Normal)
/// Predict 단계에서 이 값을 참조하여 속도 명령을 생성합니다.
/// </summary>
public SpeedLevel SpeedLimit { get; set; } = SpeedLevel.M;
/// <summary>
/// 장비 ID (도킹/충전 스테이션인 경우)
/// 예: "LOADER1", "CLEANER1", "BUFFER1", "CHARGER1"
/// </summary>
public string NodeAlias { get; set; } = string.Empty;
/// <summary>
/// 장비 타입 (도킹/충전 스테이션인 경우)
/// </summary>
// public StationType? StationType { get; set; } = null;
/// <summary>
/// 노드 생성 일자
/// </summary>
@@ -109,7 +110,6 @@ namespace AGVNavigationCore.Models
/// </summary>
public DateTime ModifiedDate { get; set; } = DateTime.Now;
/// <summary>
/// 노드 활성화 여부
/// </summary>

View File

@@ -188,6 +188,11 @@ namespace AGVNavigationCore.Models
/// </summary>
public int DetectedRfidCount => _detectedRfids.Count;
/// <summary>
/// 배터리 부족 경고 임계값 (%)
/// </summary>
public float LowBatteryThreshold { get; set; } = 20.0f;
#endregion
#region Constructor
@@ -262,9 +267,9 @@ namespace AGVNavigationCore.Models
BatteryLevel = Math.Max(0, Math.Min(100, percentage));
// 배터리 부족 경고
if (BatteryLevel < 20.0f && _currentState != AGVState.Charging)
if (BatteryLevel < LowBatteryThreshold && _currentState != AGVState.Charging)
{
OnError($"배터리 부족: {BatteryLevel:F1}%");
OnError($"배터리 부족: {BatteryLevel:F1}% (기준: {LowBatteryThreshold}%)");
}
}
@@ -586,6 +591,15 @@ namespace AGVNavigationCore.Models
var item = CurrentPath.DetailedPath.FirstOrDefault(t => t.NodeId == node.NodeId && t.IsPass == false);
if (item != null)
{
// [PathJump Check] 점프한 노드 개수 확인
// 현재 노드(item)보다 이전인데 아직 IsPass가 안 된 노드의 개수
int skippedCount = CurrentPath.DetailedPath.Count(t => t.seq < item.seq && t.IsPass == false);
if (skippedCount > 2)
{
OnError($"PathJump: {skippedCount}개의 노드를 건너뛰었습니다. (허용: 2개, 현재노드: {node.NodeId})");
return;
}
//item.IsPass = true;
//이전노드는 모두 지나친걸로 한다
CurrentPath.DetailedPath.Where(t => t.seq < item.seq).ToList().ForEach(t => t.IsPass = true);
@@ -633,14 +647,11 @@ namespace AGVNavigationCore.Models
// DetailedPath가 없으면 기본 명령 반환
if (_currentPath == null || _currentPath.DetailedPath == null || _currentPath.DetailedPath.Count == 0)
{
var defaultMotor = _currentDirection == AgvDirection.Forward
? MotorCommand.Forward
: MotorCommand.Backward;
// [Refactor] Predict와 일관성 유지: 경로가 없으면 정지
return new AGVCommand(
defaultMotor,
MotorCommand.Stop,
MagnetPosition.S,
SpeedLevel.M,
SpeedLevel.L,
eAGVCommandReason.NoPath,
$"{actionDescription} (DetailedPath 없음)"
);
@@ -697,10 +708,13 @@ namespace AGVNavigationCore.Models
break;
}
// 속도 결정 (회전 노드면 저속, 일반 이동은 중속)
SpeedLevel speed = nodeInfo.CanRotate || nodeInfo.IsDirectionChangePoint
? SpeedLevel.L
: SpeedLevel.M;
// [Speed Control] NodeMotorInfo에 설정된 속도 사용
// 단, 회전 구간 등에서 안전을 위해 강제 감속이 필요한 경우 로직 추가 가능
// 현재는 사용자 설정 우선
SpeedLevel speed = nodeInfo.Speed;
// Optional: 회전 시 강제 감속 로직 (사용자 요청에 따라 주석 처리 또는 제거 가능)
// if (nodeInfo.CanRotate || nodeInfo.IsDirectionChangePoint) speed = SpeedLevel.L;
return new AGVCommand(
motorCmd,

View File

@@ -445,7 +445,12 @@ namespace AGVNavigationCore.PathFinding.Planning
MagnetDirection.Straight
);
detailedPath1.Add(nodeInfo);
// [Speed Control] MapNode의 속도 설정 적용
var mapNode = _mapNodes.FirstOrDefault(n => n.NodeId == nodeId);
if (mapNode != null)
{
nodeInfo.Speed = mapNode.SpeedLimit;
}
}
// path1에 상세 경로 정보 설정

View File

@@ -47,6 +47,11 @@ namespace AGVNavigationCore.PathFinding.Planning
/// </summary>
public AgvDirection MotorDirection { get; set; }
/// <summary>
/// 해당 노드에서의 제한 속도
/// </summary>
public SpeedLevel Speed { get; set; } = SpeedLevel.M;
/// <summary>
/// 마그넷 센서 방향 제어 (갈림길 처리용)
/// </summary>