Initial commit

This commit is contained in:
2026-07-13 09:25:40 +07:00
parent c08ff54676
commit bccfb156d7
1938 changed files with 641646 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Represents a conflict between robots
/// </summary>
public class Conflict
{
/// <summary>
/// Type of conflict
/// </summary>
public ConflictType Type { get; set; }
/// <summary>
/// List of robot IDs involved in this conflict
/// </summary>
public List<string> InvolvedRobots { get; set; } = new();
/// <summary>
/// List of conflicting edge IDs
/// </summary>
public List<Guid> ConflictingEdges { get; set; } = new();
/// <summary>
/// List of conflicting node IDs
/// </summary>
public List<Guid> ConflictingNodes { get; set; } = new();
/// <summary>
/// When the conflict was detected
/// </summary>
public DateTime DetectedAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// Severity of the conflict
/// </summary>
public ConflictSeverity Severity { get; set; }
/// <summary>
/// Resolution strategy for this conflict
/// </summary>
public ConflictResolution? Resolution { get; set; }
/// <summary>
/// Additional details about the conflict
/// </summary>
public Dictionary<string, object> ConflictDetails { get; set; } = new();
/// <summary>
/// Estimated number of new conflicts that may arise from resolving this conflict
/// </summary>
public int EstimatedNewConflicts { get; set; }
/// <summary>
/// List of other conflict keys that can be resolved by resolving this conflict
/// </summary>
public List<string> CanResolveConflicts { get; set; } = new();
}

View File

@@ -0,0 +1,35 @@
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Represents a resolution strategy for a conflict
/// </summary>
public class ConflictResolution
{
/// <summary>
/// Resolution strategy (WaitAtNode or Reroute)
/// </summary>
public ResolutionStrategy Strategy { get; set; }
/// <summary>
/// Robot ID that needs to take action
/// </summary>
public string ActionRobotId { get; set; } = string.Empty;
/// <summary>
/// Specific action to take
/// </summary>
public ResolutionAction Action { get; set; }
/// <summary>
/// Wait until this time (if action is Wait)
/// </summary>
public DateTime? WaitUntil { get; set; }
/// <summary>
/// New route (if action is Reroute)
/// </summary>
public RobotRoute? NewRoute { get; set; }
}

View File

@@ -0,0 +1,55 @@
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Represents an edge reservation for a robot
/// </summary>
public class EdgeReservation
{
/// <summary>
/// Edge ID (Guid from database)
/// </summary>
public Guid EdgeId { get; set; }
/// <summary>
/// Edge ID string (VDMA LIF edgeId)
/// </summary>
public string EdgeIdString { get; set; } = string.Empty;
/// <summary>
/// Start Node ID of the edge
/// </summary>
public Guid StartNodeId { get; set; }
/// <summary>
/// End Node ID of the edge
/// </summary>
public Guid EndNodeId { get; set; }
/// <summary>
/// Robot ID that reserved this edge
/// </summary>
public string RobotId { get; set; } = string.Empty;
/// <summary>
/// Order ID associated with this reservation
/// </summary>
public string OrderId { get; set; } = string.Empty;
/// <summary>
/// When the reservation was created
/// </summary>
public DateTime ReservedAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// When the reservation expires (based on edge length and robot speed)
/// </summary>
public DateTime ReservedUntil { get; set; }
/// <summary>
/// Reservation status
/// </summary>
public ReservationStatus Status { get; set; } = ReservationStatus.Reserved;
}

View File

@@ -0,0 +1,76 @@
using RobotNet10.FleetManager.Services.TrafficControl.ACS;
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// State information for an order managed by ACS Order Control
/// </summary>
public class OrderACSState
{
/// <summary>
/// Robot ID
/// </summary>
public string RobotId { get; set; } = string.Empty;
/// <summary>
/// Order status
/// </summary>
public OrderStatus Status { get; set; } = OrderStatus.IsProccessing;
/// <summary>
/// Full route (Base + Horizon)
/// </summary>
public RobotRoute Route { get; set; } = new();
/// <summary>
/// Set of zone IDs that have been successfully requested (RequestIn completed)
/// </summary>
public HashSet<string> ZoneRequestInCompleted { get; set; } = [];
/// <summary>
/// Set of zone IDs that have been successfully requested (RequestOut completed)
/// </summary>
public HashSet<string> ZoneRequestOutCompleted { get; set; } = [];
/// <summary>
/// Set of region IDs needs to be successfully requested. (IN)
/// </summary>
public HashSet<string> ZoneRequestInCompleting { get; set; } = [];
/// <summary>
/// Set of region IDs needs to be successfully requested. (OUT)
/// </summary>
public HashSet<string> ZoneRequestOutCompleting { get; set; } = [];
/// <summary>
/// Error message if status is IsError
/// </summary>
public string? Error { get; set; }
/// <summary>
/// List of nodes that are mapped to ACS zones for RequestIn (in order of appearance in route)
/// Each entry contains: (NodeIdString, ZoneId)
/// </summary>
public List<(string NodeIdString, string ZoneId)> InMappedNodes { get; set; } = [];
/// <summary>
/// List of nodes that are mapped to ACS zones for RequestOut (in order of appearance in route)
/// Each entry contains: (NodeIdString, ZoneId)
/// </summary>
public List<(string NodeIdString, string ZoneId)> OutMappedNodes { get; set; } = [];
/// <summary>
/// Index of the current IN mapped node being processed
/// </summary>
public int CurrentInMappedNodeIndex { get; set; } = 0;
/// <summary>
/// Timestamp when order was created
/// </summary>
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// Last update timestamp
/// </summary>
public DateTime LastUpdated { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,27 @@
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Path planning method to use for IPathPlanner
/// </summary>
public enum PathPlanningMethod
{
/// <summary>
/// Basic path planning (PathPlanning) - No constraints
/// </summary>
Basic = 0,
/// <summary>
/// Path planning with start direction constraint (PathPlanningWithStartDirection)
/// </summary>
WithStartDirection = 1,
/// <summary>
/// Path planning with final direction constraint (PathPlanningWithFinalDirection)
/// </summary>
WithFinalDirection = 2,
/// <summary>
/// Path planning with final angle constraint (PathPlanningWithAngle)
/// </summary>
WithAngle = 3
}

View File

@@ -0,0 +1,55 @@
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Robot information needed for conflict detection
/// </summary>
public class RobotInfo
{
/// <summary>
/// Robot ID
/// </summary>
public string RobotId { get; set; } = string.Empty;
/// <summary>
/// Robot length in meters (from RobotModel)
/// </summary>
public double Length { get; set; }
/// <summary>
/// Robot width in meters (from RobotModel)
/// </summary>
public double Width { get; set; }
/// <summary>
/// Navigation point X offset in meters (from RobotModel)
/// </summary>
public double NavigationPointX { get; set; }
/// <summary>
/// Navigation point Y offset in meters (from RobotModel)
/// </summary>
public double NavigationPointY { get; set; }
/// <summary>
/// Current X position (from State message)
/// </summary>
public double CurrentX { get; set; }
/// <summary>
/// Current Y position (from State message)
/// </summary>
public double CurrentY { get; set; }
/// <summary>
/// Current orientation angle in radians (from State message)
/// </summary>
public double CurrentTheta { get; set; }
/// <summary>
/// Last node ID the robot passed through (from State message)
/// </summary>
public string LastNodeId { get; set; } = string.Empty;
}

View File

@@ -0,0 +1,30 @@
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Represents priority information for a robot
/// </summary>
public class RobotPriority
{
/// <summary>
/// Robot ID
/// </summary>
public string RobotId { get; set; } = string.Empty;
/// <summary>
/// Priority level (higher number = higher priority)
/// </summary>
public int PriorityLevel { get; set; }
/// <summary>
/// Reason for the priority
/// </summary>
public PriorityReason Reason { get; set; }
/// <summary>
/// Priority valid until this time (null if permanent)
/// </summary>
public DateTime? ValidUntil { get; set; }
}

View File

@@ -0,0 +1,70 @@
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Represents a complete route for a robot with Base and Horizon segments
/// </summary>
public class RobotRoute
{
/// <summary>
/// Robot ID (SerialNumber)
/// </summary>
public string RobotId { get; set; } = string.Empty;
/// <summary>
/// Order ID from VDA5050
/// </summary>
public string OrderId { get; set; } = string.Empty;
/// <summary>
/// Order Update ID from VDA5050
/// </summary>
public int OrderUpdateId { get; set; }
/// <summary>
/// Full route (Base + Horizon)
/// </summary>
public List<RouteSegment> FullRoute { get; set; } = [];
/// <summary>
/// Base: Released segments that robot is currently executing
/// </summary>
public List<RouteSegment> Base { get; set; } = [];
/// <summary>
/// Horizon: Unreleased segments waiting for conditions
/// </summary>
public List<RouteSegment> Horizon { get; set; } = [];
/// <summary>
/// Current position index in the route
/// </summary>
public int CurrentSegmentIndex { get; set; }
/// <summary>
/// Route creation timestamp
/// </summary>
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
/// <summary>
/// Last update timestamp
/// </summary>
public DateTime LastUpdated { get; set; } = DateTime.UtcNow;
/// <summary>
/// Number of reroute attempts for this route (to prevent infinite rerouting)
/// </summary>
public int RerouteAttempts { get; set; } = 0;
/// <summary>
/// Node ID where robot should wait (if WaitAtNode resolution is applied)
/// </summary>
public Guid? WaitNodeId { get; set; }
/// <summary>
/// Time until which robot should wait at WaitNodeId (if WaitAtNode resolution is applied)
/// </summary>
public DateTime? WaitUntil { get; set; }
}

View File

@@ -0,0 +1,71 @@
using RobotNet.VDA5050.Order;
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Represents a segment in a robot route (either a node or an edge)
/// Uses VDA5050.Order.Node and VDA5050.Order.Edge to store full information
/// </summary>
public class RouteSegment
{
// Internal properties needed for traffic control logic
/// <summary>
/// Node ID (Guid from database) - for conflict detection and edge reservation
/// </summary>
public Guid NodeId { get; set; }
/// <summary>
/// Edge ID (Guid from database) - Null if this is a node-only segment
/// </summary>
public Guid? EdgeId { get; set; }
/// <summary>
/// Start Node ID of the edge (Guid from database) - for conflict detection
/// </summary>
public Guid? StartNodeId { get; set; }
/// <summary>
/// End Node ID of the edge (Guid from database) - for conflict detection
/// </summary>
public Guid? EndNodeId { get; set; }
/// <summary>
/// Whether this segment has been released into base
/// </summary>
public bool Released { get; set; }
/// <summary>
/// Time until which this edge is reserved
/// </summary>
public DateTime? ReservedUntil { get; set; }
// VDA5050 Order objects containing full information from MapEditor
/// <summary>
/// VDA5050 Node with full information (NodeId, NodeDescription, NodePosition, Actions, etc.)
/// </summary>
public Node? VdaNode { get; set; }
/// <summary>
/// VDA5050 Edge with full information (EdgeId, EdgeDescription, MaxSpeed, Trajectory, Actions, etc.)
/// Null if this is a node-only segment
/// </summary>
public Edge? VdaEdge { get; set; }
/// <summary>
/// Get SequenceId from VdaNode or VdaEdge
/// </summary>
public int SequenceId => VdaNode?.SequenceId ?? VdaEdge?.SequenceId ?? 0;
/// <summary>
/// Check if this segment is a node segment
/// </summary>
public bool IsNode => VdaNode != null;
/// <summary>
/// Check if this segment is an edge segment
/// </summary>
public bool IsEdge => VdaEdge != null;
}

View File

@@ -0,0 +1,174 @@
using RobotNet10.FleetManager.Shared.Enums;
namespace RobotNet10.FleetManager.Services.TrafficControl.Models;
/// <summary>
/// Configuration for TrafficControl service
/// </summary>
public class TrafficControlConfig
{
/// <summary>
/// Conflict detection configuration
/// </summary>
public ConflictDetectionConfig ConflictDetection { get; set; } = new();
/// <summary>
/// Base/Horizon management configuration
/// </summary>
public BaseHorizonConfig BaseHorizon { get; set; } = new();
/// <summary>
/// Conflict resolution configuration
/// </summary>
public ConflictResolutionConfig ConflictResolution { get; set; } = new();
/// <summary>
/// Priority configuration
/// </summary>
public PriorityConfig Priority { get; set; } = new();
/// <summary>
/// Path planning configuration
/// </summary>
public PathPlanningConfig PathPlanning { get; set; } = new();
}
/// <summary>
/// Conflict detection configuration
/// </summary>
public class ConflictDetectionConfig
{
/// <summary>
/// Detection interval in milliseconds (default: 500ms = 2 Hz)
/// </summary>
public int IntervalMs { get; set; } = 500;
/// <summary>
/// Vertex conflict threshold in meters (default: 2.0m)
/// </summary>
public double VertexConflictThreshold { get; set; } = 2.0;
/// <summary>
/// Minimum safe distance for proximity conflict in meters (default: 1.0m)
/// </summary>
public double ProximityMinDistance { get; set; } = 1.0;
/// <summary>
/// Time conflict threshold in seconds (default: 5.0s)
/// </summary>
public double TimeConflictThreshold { get; set; } = 5.0;
/// <summary>
/// Rotation space radius in meters (default: 0.5m)
/// </summary>
public double RotationSpaceRadius { get; set; } = 0.5;
/// <summary>
/// Corridor width threshold in meters (default: 2.0m)
/// </summary>
public double CorridorWidthThreshold { get; set; } = 2.0;
}
/// <summary>
/// Base/Horizon management configuration
/// </summary>
public class BaseHorizonConfig
{
/// <summary>
/// Initial number of base segments (default: 2)
/// </summary>
public int InitialBaseSegments { get; set; } = 2;
/// <summary>
/// Number of segments to release ahead (default: 2)
/// </summary>
public int ReleaseAheadSegments { get; set; } = 2;
/// <summary>
/// Minimum number of horizon segments to keep (default: 1)
/// </summary>
public int MinHorizonSegments { get; set; } = 1;
}
/// <summary>
/// Conflict resolution configuration
/// </summary>
public class ConflictResolutionConfig
{
/// <summary>
/// Maximum wait time at node in seconds (default: 5.0s)
/// </summary>
public double WaitTimeAtNode { get; set; } = 5.0;
/// <summary>
/// Whether to allow reroute on conflict (default: true)
/// </summary>
public bool RerouteOnConflict { get; set; } = true;
/// <summary>
/// Maximum reroute attempts for one conflict (default: 3)
/// </summary>
public int MaxRerouteAttempts { get; set; } = 3;
/// <summary>
/// Enable resolution optimization (default: true)
/// </summary>
public bool ResolutionOptimization { get; set; } = true;
/// <summary>
/// Maximum simulation depth for resolution evaluation (default: 2)
/// </summary>
public int MaxResolutionSimulationDepth { get; set; } = 2;
}
/// <summary>
/// Priority configuration
/// </summary>
public class PriorityConfig
{
/// <summary>
/// Default priority level (default: 0)
/// </summary>
public int DefaultPriority { get; set; } = 0;
/// <summary>
/// Emergency priority level (default: 100)
/// </summary>
public int EmergencyPriority { get; set; } = 100;
/// <summary>
/// High value order priority level (default: 50)
/// </summary>
public int HighValueOrderPriority { get; set; } = 50;
/// <summary>
/// Time critical priority level (default: 30)
/// </summary>
public int TimeCriticalPriority { get; set; } = 30;
}
/// <summary>
/// Path planning configuration
/// </summary>
public class PathPlanningConfig
{
/// <summary>
/// Mapping from NavigationType to PathPlanningMethod
/// Defines which IPathPlanner method to use for each NavigationType
/// </summary>
public Dictionary<NavigationType, PathPlanningMethod> NavigationTypeMethodMapping { get; set; } = new()
{
// Default mappings
{ NavigationType.Differential, PathPlanningMethod.Basic },
{ NavigationType.Forklift, PathPlanningMethod.Basic },
{ NavigationType.OmniDrive, PathPlanningMethod.Basic }
};
/// <summary>
/// Default path planning method if NavigationType is not found in mapping (default: Basic)
/// </summary>
public PathPlanningMethod DefaultMethod { get; set; } = PathPlanningMethod.Basic;
}