using RobotNet.RobotManager.Data; using RobotNet.RobotShares.Dtos; using RobotNet.RobotShares.Enums; using RobotNet.Shares; using System.Collections.Concurrent; namespace RobotNet.RobotManager.Services.Traffic; public class TrafficManager(MapManager Map, IServiceProvider ServiceProvider, PathPlanner PathPlannger, IConfiguration Configuration, LoggerController Logger) : IHostedService { private System.Threading.Timer? computeTimer; private const int intervalTime = 1000; private readonly double TrafficCheckingDistanceMax = Configuration.GetValue("TrafficConfig:CheckingDistanceMax", 5); private readonly double TrafficCheckingDistanceMin = Configuration.GetValue("TrafficConfig:CheckingDistanceMin", 3); private readonly int TrafficResolutionRepeat = Configuration.GetValue("TrafficConfig:ResolutionRepeat", 1); private readonly int TrafficAvoidableNodeMax = Configuration.GetValue("TrafficConfig:AvoidableNodeMax", 3); private readonly double TrafficOffsetLength = Configuration.GetValue("TrafficConfig:OffsetLength", 0.3); private readonly double TrafficOffsetWidth = Configuration.GetValue("TrafficConfig:OffsetWidth", 0.2); public bool Enable => Configuration.GetValue("TrafficConfig:Enable", false); private readonly SemaphoreSlim AgentSemaphore = new(1, 1); private readonly SemaphoreSlim UpdateSemaphore = new(1, 1); public ConcurrentDictionary TrafficMaps { get; set; } = []; private Agent NewAgent(Guid mapId, IRobotController robotController, AgentModel model, TrafficNodeDto[] nodes, TrafficEdgeDto[] edges) { model.TurningRadius = TrafficMath.CalTurningRadius(model, TrafficOffsetLength, TrafficOffsetWidth); foreach (var node in nodes) { node.AvoidablePaths = [.. Map.GetNegativePaths(mapId, new() { Id = node.Id, X = node.X, Y = node.Y, Name = node.Name }, model.TurningRadius) .Where(path => path.Length > 0) .Select(path => path.Select(n => new TrafficNodeDto { Id = n.Id, X = n.X, Y = n.Y, Name = n.Name }).ToArray())]; node.IsAvoidableNode = Map.GetNegativeNodes(mapId, node.Id).Length > 2 && node.AvoidablePaths.Length > 0; if (nodes.Length > 0 && node != nodes.Last() && model.NavigationType != NavigationType.Forklift) node.LockedShapes = new() { Type = TrafficLockedShapeType.Circle, Radius = model.TurningRadius, }; else node.LockedShapes = TrafficMath.CalRobotRectShape(model, TrafficOffsetLength, TrafficOffsetWidth, node.X, node.Y, node.Theta); } Agent agent = new() { Robot = robotController, AgentModel = model, Nodes = [.. nodes], InNodeIndex = 0, ReleaseNode = nodes[0], Edges = [.. edges], State = TrafficSolutionState.Complete, MapId = mapId, GoalNode = nodes[^1], }; return agent; } public MessageResult CreateAgent(Guid mapId, IRobotController robotController, AgentModel model, TrafficNodeDto[] nodes, TrafficEdgeDto[] edges) { if (AgentSemaphore.Wait(2000)) { try { if (TrafficMaps.TryGetValue(mapId, out TrafficMap? TrafficMap) && TrafficMap is not null) { if (TrafficMap.Agents.TryGetValue(robotController.SerialNumber, out _)) TrafficMap.Agents.Remove(robotController.SerialNumber); TrafficMap.Agents.Add(robotController.SerialNumber, NewAgent(mapId, robotController, model, nodes, edges)); } else { bool result = TrafficMaps.TryAdd(mapId, new TrafficMap() { MapId = mapId, Agents = new Dictionary() { { robotController.SerialNumber, NewAgent(mapId, robotController, model, nodes, edges) } }, }); if (!result) return new(false, $"Không thể tạo TrafficMap cho bản đồ {mapId} do đã tồn tại hoặc xảy ra lỗi khi thêm agent {robotController.SerialNumber}."); } //Logger.Info($"CreateAgent: Tạo Agent thành công - {robotController.SerialNumber} to {nodes[^1].Name}, nodes: [{string.Join(", ", nodes.Select(n => $"[({n.Name}) - ({n.Direction})]"))}]"); return new(true, ""); } catch (Exception ex) { Logger.Warning($"Tạo mới traffic Agent xảy ra lỗi - {ex.Message}"); return new(false, $"Tạo mới traffic Agent xảy ra lỗi - {ex.Message}"); } finally { AgentSemaphore.Release(); } } else return new(false, $"Không thể tạo trafficAgent do vượt quá thời gian chờ."); } public MessageResult DeleteAgent(string robotId) { if (AgentSemaphore.Wait(2000)) { try { using var scope = ServiceProvider.CreateScope(); var RobotDb = scope.ServiceProvider.GetRequiredService(); var robot = RobotDb.Robots.FirstOrDefault(r => r.RobotId == robotId); if (robot is null) return new(false, $"Không tìm thấy robot Id {robotId} trong kho dữ liệu."); if (TrafficMaps.TryGetValue(robot.MapId, out TrafficMap? TrafficMap) && TrafficMap is not null) { if (TrafficMap.Agents.TryGetValue(robotId, out _)) { var remove = TrafficMap.Agents.Remove(robotId); if (!remove) return new(false, $"Không thể xóa agent {robotId}."); } } //Logger.Info($"DeleteAgent: Xóa Agent thành công - {robotId}"); return new(true, ""); } catch (Exception ex) { Logger.Warning($"Xóa traffic Agent xảy ra lỗi - {ex.Message}"); return new(false, $"Xóa traffic Agent xảy ra lỗi - {ex.Message}"); } finally { AgentSemaphore.Release(); } } else return new(false, $"Không thể xóa trafficAgent do vượt quá thời gian chờ."); } public TrafficSolution GetTrafficNode(string robotId) { try { using var scope = ServiceProvider.CreateScope(); var RobotDb = scope.ServiceProvider.GetRequiredService(); var robot = RobotDb.Robots.FirstOrDefault(r => r.RobotId == robotId); if (robot is null) return new() { State = TrafficSolutionState.None }; if (TrafficMaps.TryGetValue(robot.MapId, out TrafficMap? trafficmap) && trafficmap is not null) { if (trafficmap.Agents.TryGetValue(robotId, out Agent? agent) && agent is not null) { TrafficSolution returnSolution = new() { State = agent.State, ReleaseNode = agent.ReleaseNode, GivewayEdges = agent.GivewayEdges, GivewayNodes = agent.GivewayNodes, Nodes = [.. agent.Nodes], Edges = [.. agent.Edges] }; ; switch (agent.State) { case TrafficSolutionState.GiveWay: if (agent.InNodeIndex != agent.ReleaseNodeIndex && (agent.GivewayNodes.Count > 0 && agent.ReleaseNode.Id != agent.GivewayNodes[^1].Id)) returnSolution.State = TrafficSolutionState.Waitting; else { if (agent.GivewayNodes.Count > 0 && agent.ReleaseNode.Id != agent.GivewayNodes[^1].Id) agent.ReleaseNode = agent.GivewayNodes[^1]; if (agent.GivewayNodes.Count == 0 && agent.RefreshPathState == RefreshPathState.Compeleted) { agent.State = TrafficSolutionState.RefreshPath; returnSolution.State = TrafficSolutionState.RefreshPath; } } break; case TrafficSolutionState.LoopResolve: returnSolution.State = TrafficSolutionState.Complete; break; }; // Console.WriteLine($"{robotId} Gettraffic: {returnSolution.State}, release: {returnSolution.ReleaseNode.Name}"); return returnSolution; } } return new() { State = TrafficSolutionState.None }; } catch (Exception ex) { Logger.Warning($"{robotId} Lấy thông tin traffic xảy ra lỗi: {ex.Message}"); return new() { State = TrafficSolutionState.None }; } } public MessageResult UpdateInNode(string robotId, Guid nodeId) { if (UpdateSemaphore.Wait(2000)) { try { using var scope = ServiceProvider.CreateScope(); var RobotDb = scope.ServiceProvider.GetRequiredService(); var robot = RobotDb.Robots.FirstOrDefault(r => r.RobotId == robotId); if (robot is null) return new(false, $"Không tìm thấy robot Id {robotId} trong kho dữ liệu."); if (TrafficMaps.TryGetValue(robot.MapId, out TrafficMap? trafficmap) && trafficmap is not null) { if (trafficmap.Agents.TryGetValue(robotId, out Agent? agent) && agent is not null) { if (agent.State == TrafficSolutionState.GiveWay) { if (agent.GivewayNodes.Count > 1 && nodeId == agent.GivewayNodes[^1].Id) { var giveWayResolution = trafficmap.GivewayResolution.FirstOrDefault(n => n.RobotGive == robotId); if (giveWayResolution is not null) { trafficmap.AddLocker(giveWayResolution.RobotReceive, [.. giveWayResolution.Nodes]); giveWayResolution.IsGiveway = true; } agent.Nodes = agent.SubNodes; agent.Edges = agent.SubEdges; agent.GivewayNodes = []; agent.GivewayEdges = []; } List lockedNodes = []; var nodeIndex = agent.Nodes.FindIndex(n => n.Id == nodeId); if (nodeIndex != -1) { agent.InNodeIndex = nodeIndex; if (agent.ReleaseNodeIndex != -1 && agent.InNodeIndex <= agent.ReleaseNodeIndex) lockedNodes = agent.Nodes.GetRange(agent.InNodeIndex, agent.ReleaseNodeIndex - agent.InNodeIndex + 1); lockedNodes.AddRange(agent.GivewayNodes.Where(n => !lockedNodes.Any(ln => ln.Id == n.Id))); } else { nodeIndex = agent.GivewayNodes.FindIndex(n => n.Id == nodeId); if (nodeIndex != -1) lockedNodes = agent.GivewayNodes.GetRange(nodeIndex, agent.GivewayNodes.Count - nodeIndex); } trafficmap.UpdateLocker(robotId, [.. lockedNodes]); } else { var nodeIndex = agent.Nodes.FindIndex(n => n.Id == nodeId); if (nodeIndex != -1) { agent.InNodeIndex = nodeIndex; if (agent.ReleaseNodeIndex != -1 && agent.InNodeIndex <= agent.ReleaseNodeIndex) { var lockedNodes = agent.Nodes.GetRange(agent.InNodeIndex, agent.ReleaseNodeIndex - agent.InNodeIndex + 1); trafficmap.UpdateLocker(robotId, [.. lockedNodes]); trafficmap.GivewayResolution.RemoveAll(s => s.RobotReceive == agent.Robot.SerialNumber && s.IsGiveway && !lockedNodes.Any(n => s.Nodes.Any(sn => sn.Id == n.Id))); } if (agent.State == TrafficSolutionState.LoopResolve && nodeId == agent.ReleaseNode.Id) { var giveWayResolution = trafficmap.GivewayResolution.FirstOrDefault(n => n.RobotGive == robotId); if (giveWayResolution is not null) { trafficmap.AddLocker(giveWayResolution.RobotReceive, [.. giveWayResolution.Nodes]); giveWayResolution.IsGiveway = true; } agent.State = TrafficSolutionState.Waitting; } } } } } return new(true, ""); } catch (Exception ex) { Logger.Warning($"{robotId} Cập nhật vị trí xảy ra lỗi: {ex.Message}"); return new(false, $"{robotId} Cập nhật vị trí xảy ra lỗi: {ex.Message}"); } finally { UpdateSemaphore.Release(); } } else return new(false, $"Không thể xóa cập nhật dữ liệu vào hệ thống traffic do vượt quá thời gian chờ."); } private static (TrafficConflictState state, string robotId, TrafficNodeDto? nodeId) FirstCheckingReleaseNodes(TrafficNodeDto[] releaseNodes, Agent agent, TrafficMap trafficMap) { if (releaseNodes.Length != 0) { foreach (var releaseNode in releaseNodes) { foreach (var locked in trafficMap.Locked) { if (locked.Key == agent.Robot.SerialNumber) continue; if (locked.Value.Any(n => n.Id == releaseNode.Id)) return (TrafficConflictState.Vertex, locked.Key, releaseNode); //foreach (var lockedNode in locked.Value) //{ // var distance = Math.Sqrt(Math.Pow(lockedNode.X - releaseNode.X, 2) + Math.Pow(lockedNode.Y - releaseNode.Y, 2)); // if(distance > (lockedNode.LockedShapes.Radius + releaseNode.LockedShapes.Radius)) continue; // if (lockedNode.LockedShapes.Type == TrafficLockedShapeType.Circle) // { // if (releaseNode.LockedShapes.Type == TrafficLockedShapeType.Circle) // { // if (distance < (lockedNode.LockedShapes.Radius + releaseNode.LockedShapes.Radius)) return (TrafficConflictState.Proximity, locked.Key, releaseNode); // } // else if (releaseNode.LockedShapes.Type == TrafficLockedShapeType.Rectangle) // { // if(TrafficMath.RectIntersectCircle(lockedNode, lockedNode.LockedShapes.Radius, // releaseNode.LockedShapes.X1, releaseNode.LockedShapes.Y1, // releaseNode.LockedShapes.X2, releaseNode.LockedShapes.Y2, // releaseNode.LockedShapes.X3, releaseNode.LockedShapes.Y3, // releaseNode.LockedShapes.X4, releaseNode.LockedShapes.Y4)) return (TrafficConflictState.Proximity, locked.Key, releaseNode); // } // } // else if (lockedNode.LockedShapes.Type == TrafficLockedShapeType.Rectangle) // { // if (releaseNode.LockedShapes.Type == TrafficLockedShapeType.Circle) // { // if(TrafficMath.RectIntersectRect(lockedNode.LockedShapes, releaseNode.LockedShapes)) return (TrafficConflictState.Proximity, locked.Key, releaseNode); // } // else if (releaseNode.LockedShapes.Type == TrafficLockedShapeType.Circle) // { // if (TrafficMath.RectIntersectCircle(releaseNode, releaseNode.LockedShapes.Radius, // lockedNode.LockedShapes.X1, lockedNode.LockedShapes.Y1, // lockedNode.LockedShapes.X2, lockedNode.LockedShapes.Y2, // lockedNode.LockedShapes.X3, lockedNode.LockedShapes.Y3, // lockedNode.LockedShapes.X4, lockedNode.LockedShapes.Y4)) return (TrafficConflictState.Proximity, locked.Key, releaseNode); // } // } //} } } } return (TrafficConflictState.None, string.Empty, null); } private static (bool IsSuccess, string robotId, TrafficNodeDto? nodeId) GivewayCheckingReleaseNodes(TrafficNodeDto[] releaseNodes, string robotId, TrafficMap trafficMap) { foreach (var node in releaseNodes) { foreach (var locked in trafficMap.Locked) { if (locked.Value.Any(n => (n.Id == node.Id)) && locked.Key != robotId) return (false, locked.Key, node); } } return (true, string.Empty, null); } private void CheckConflict(Agent agent, TrafficMap trafficMap) { if (agent.Checking(TrafficAvoidableNodeMax, TrafficCheckingDistanceMax) && !trafficMap.GivewayResolution.Any(s => s.RobotGive == agent.Robot.SerialNumber)) { var releaseNodes = agent.GetChekingNodes(TrafficAvoidableNodeMax, TrafficCheckingDistanceMin); if (releaseNodes.Length > 0) { (var state, string conflictRobotId, TrafficNodeDto? conflictNode) = FirstCheckingReleaseNodes(releaseNodes, agent, trafficMap); if (state == TrafficConflictState.None) { trafficMap.AddLocker(agent.Robot.SerialNumber, [.. releaseNodes]); agent.ReleaseNode = releaseNodes[^1]; agent.State = TrafficSolutionState.Complete; trafficMap.Conflicts.RemoveAll(conflict => conflict.AgentRequest.Robot.SerialNumber == agent.Robot.SerialNumber); } else { if (conflictNode is null) { Logger.Warning($"{agent.Robot.SerialNumber} kiểm tra xung đột có lỗi: xảy ra xung đột nhưng không tìm thấy node xung đột"); return; } if (trafficMap.Agents.TryGetValue(conflictRobotId, out Agent? conflictAgent) && conflictAgent is not null) { trafficMap.Conflicts.RemoveAll(c => c.AgentRequest.Robot.SerialNumber == agent.Robot.SerialNumber); var conflictState = GetConflictState(agent, conflictAgent, conflictNode); if (conflictState == TrafficConflictState.Confrontation || state == TrafficConflictState.Proximity) { Level1ConflictResolution(agent, conflictAgent, [.. releaseNodes], conflictNode, trafficMap); } else { trafficMap.Conflicts.Add(new() { AgentConflict = conflictAgent, AgentRequest = agent, NodeConflict = conflictNode, ReleaseNodes = [.. releaseNodes], State = TrafficConflictState.Vertex, }); agent.State = TrafficSolutionState.Waitting; } } else { // cần xử lí khi bị xung đột với robot đang không di chuyển } } } } } private static TrafficConflictState GetConflictState(Agent agent1, Agent agent2, TrafficNodeDto conflictNode) { var conflictNodeAgent2Index = agent2.Nodes.IndexOf(conflictNode); if (conflictNodeAgent2Index != -1) { var remainingNodes = agent2.Nodes.GetRange(conflictNodeAgent2Index, agent2.Nodes.Count - conflictNodeAgent2Index); if (remainingNodes.Any(n => n.Id == agent1.ReleaseNode.Id)) return TrafficConflictState.Confrontation; return TrafficConflictState.Vertex; } return TrafficConflictState.None; } private TrafficSolutionState Level1ConflictResolution(Agent agent1, Agent agent2, List releaseNodes, TrafficNodeDto conflictNode, TrafficMap trafficMap) { try { var remainingNodes = agent2.Nodes.GetRange(agent2.InNodeIndex, agent2.Nodes.Count - agent2.InNodeIndex); var conflictIndex = releaseNodes.IndexOf(conflictNode); if (conflictIndex != -1) { //double distance = 0; for (int i = conflictIndex - 1; i >= 0; i--) { //distance += Math.Sqrt(Math.Pow(releaseNodes[i].X - releaseNodes[i + 1].X, 2) + Math.Pow(releaseNodes[i].Y - releaseNodes[i + 1].Y, 2)); //if (distance < TrafficLockedCircle) continue; if (!remainingNodes.Any(n => n.Id == releaseNodes[i].Id)) { var givewayNodes = releaseNodes.GetRange(0, releaseNodes.Count - i); (var IsSuccess, string conflictRobotId, TrafficNodeDto? _) = GivewayCheckingReleaseNodes([.. givewayNodes], agent1.Robot.SerialNumber, trafficMap); if (IsSuccess) { trafficMap.AddLocker(agent1.Robot.SerialNumber, [.. givewayNodes]); agent1.State = TrafficSolutionState.Complete; agent1.ReleaseNode = givewayNodes[^1]; trafficMap.Conflicts.RemoveAll(conflict => conflict.AgentRequest.Robot.SerialNumber == agent1.Robot.SerialNumber); return TrafficSolutionState.Complete; } } if (!releaseNodes[i].IsAvoidableNode) continue; var state = Level2ConflictResolution(agent1, agent2, [.. releaseNodes[i].AvoidablePaths], [.. releaseNodes], [.. releaseNodes.GetRange(0, i + 1)], trafficMap); if (state != TrafficSolutionState.UnableResolve) return state; } if (!trafficMap.GivewayResolution.Any(s => s.RobotReceive == agent1.Robot.SerialNumber)) { trafficMap.Conflicts.Add(new() { AgentRequest = agent1, AgentConflict = agent2, NodeConflict = conflictNode, ReleaseNodes = releaseNodes, State = TrafficConflictState.Confrontation, }); } return TrafficSolutionState.UnableResolve; } else { Logger.Warning($"{agent1.Robot.SerialNumber} tìm kiếm giải pháp tránh xung đột bậc 1 xảy ra lỗi: confilct node không được tìm thấy trong release node {conflictNode.Name}, release list [{string.Join(", ", releaseNodes.Select(n => n.Name))}]"); } return TrafficSolutionState.UnableResolve; } catch (Exception ex) { Logger.Warning($"{agent1.Robot.SerialNumber} tìm kiếm giải pháp tránh xung đột bậc 1 xảy ra lỗi: {ex.Message}"); return TrafficSolutionState.UnableResolve; } } private TrafficSolutionState Level2ConflictResolution(Agent agent1, Agent agent2, TrafficNodeDto[][] avoidablePaths, TrafficNodeDto[] relaseNodes, TrafficNodeDto[] conflictNodes, TrafficMap trafficMap) { try { if (agent2.State == TrafficSolutionState.GiveWay) return TrafficSolutionState.Waitting; List<(Agent conflictAgent, TrafficNodeDto conflictNode)> bufferConflict = []; var remainingNodeAgent2 = agent2.Nodes.GetRange(agent2.InNodeIndex, agent2.Nodes.Count - agent2.InNodeIndex); var remainingReleaseNodeAgent2 = agent2.Nodes.GetRange(agent2.InNodeIndex, agent2.ReleaseNodeIndex - agent2.InNodeIndex + 1); foreach (var avoidablePath in avoidablePaths) { if (avoidablePath.Any(avoidableNode => remainingReleaseNodeAgent2.Any(n => n.Id == avoidableNode.Id)) || remainingNodeAgent2.Any(avoidableNode => avoidableNode.Id == avoidablePath[^1].Id)) continue; (var IsSuccess, string conflictRobotId, TrafficNodeDto? conflictNode) = GivewayCheckingReleaseNodes([.. conflictNodes, .. avoidablePath], agent1.Robot.SerialNumber, trafficMap); if (IsSuccess) { TrafficNodeDto[] givewayNodes = [.. conflictNodes, .. avoidablePath.Skip(1)]; trafficMap.AddLocker(agent1.Robot.SerialNumber, givewayNodes); var (state, message) = agent1.UpdateGiveWay(givewayNodes, PathPlannger, Map); Logger.Info($"{agent1.Robot.SerialNumber} tránh Robot {agent2.Robot.SerialNumber} tại Node {givewayNodes[^1].Name} {(state == TrafficSolutionState.Complete || state == TrafficSolutionState.GiveWay ? "thành công" : $"xảy ra lỗi: {message}")}"); if (state == TrafficSolutionState.GiveWay) trafficMap.GivewayResolution.Add(new() { RobotGive = agent1.Robot.SerialNumber, RobotReceive = agent2.Robot.SerialNumber, Nodes = [conflictNodes[^1]] }); return state; } else { if (conflictNode is null) { Logger.Warning($"{agent1.Robot.SerialNumber} tìm kiếm giải pháp tránh xung đột bậc 2 có lỗi: xảy ra xung đột nhưng không tìm thấy node xung đột"); } else { if (trafficMap.Agents.TryGetValue(conflictRobotId, out Agent? conflictAgent) && conflictAgent is not null) bufferConflict.Add((conflictAgent, conflictNode)); } } } foreach (var (conflictAgent, conflictNode) in bufferConflict) { var trafficState = Level3ConflictResolution(conflictAgent, agent1.Robot.SerialNumber, conflictNode, relaseNodes, trafficMap, 0); if (trafficState == TrafficSolutionState.Complete || trafficState == TrafficSolutionState.GiveWay) return trafficState; } //return FindAvoidableResolution(agent1, agent2, trafficMap) ; return TrafficSolutionState.UnableResolve; } catch (Exception ex) { Logger.Warning($"{agent1.Robot.SerialNumber} tìm kiếm giải pháp tránh xung đột bậc 2 xảy ra lỗi: {ex.Message}"); return TrafficSolutionState.UnableResolve; } } private TrafficSolutionState Level3ConflictResolution(Agent agent, string giveWayRobotId, TrafficNodeDto giveNode, TrafficNodeDto[] relaseNodes, TrafficMap trafficMap, int counter) { try { if (agent.State == TrafficSolutionState.GiveWay || agent.State == TrafficSolutionState.LoopResolve) return TrafficSolutionState.Waitting; List<(Agent conflictAgent, TrafficNodeDto conflictNode)> bufferConflict = []; var negativePaths = Map.GetNegativePaths(trafficMap.MapId, new() { Id = giveNode.Id, X = giveNode.X, Y = giveNode.Y, Name = giveNode.Name }, agent.AgentModel.TurningRadius) .Where(path => path.Length > 0) .Select(path => path.Select(n => new TrafficNodeDto { Id = n.Id, X = n.X, Y = n.Y, Name = n.Name }).ToArray()) .ToList(); foreach (var negativePath in negativePaths) { if (negativePath.Any(negativeNode => relaseNodes.Any(n => n.Id == negativeNode.Id) && negativeNode.Id != giveNode.Id)) continue; (var IsSuccess, string conflictRobotId, TrafficNodeDto? conflictNode) = GivewayCheckingReleaseNodes(negativePath, agent.Robot.SerialNumber, trafficMap); if (IsSuccess) { trafficMap.AddLocker(agent.Robot.SerialNumber, negativePath); var (state, message) = agent.UpdateGiveWay(negativePath, PathPlannger, Map); Logger.Info($"{agent.Robot.SerialNumber} tránh level3 Robot {giveWayRobotId} tại Node {negativePath[^1].Name} {(state == TrafficSolutionState.Complete || state == TrafficSolutionState.GiveWay ? "thành công" : $"xảy ra lỗi: {message}")}"); if (state == TrafficSolutionState.GiveWay) trafficMap.GivewayResolution.Add(new() { RobotGive = agent.Robot.SerialNumber, RobotReceive = giveWayRobotId, Nodes = [giveNode] }); return state; } else { if (conflictNode is null) { Logger.Warning($"{agent.Robot.SerialNumber} tìm kiếm giải pháp tránh xung đột bậc 3 có lỗi: xảy ra xung đột nhưng không tìm thấy node xung đột"); } else { if (trafficMap.Agents.TryGetValue(conflictRobotId, out Agent? conflictAgent) && conflictAgent is not null) bufferConflict.Add((conflictAgent, conflictNode)); } } } if (counter < TrafficResolutionRepeat) { foreach (var (conflictAgent, conflictNode) in bufferConflict) { var trafficState = Level3ConflictResolution(conflictAgent, agent.Robot.SerialNumber, conflictNode, [.. relaseNodes, giveNode], trafficMap, ++counter); if (trafficState == TrafficSolutionState.Complete || trafficState == TrafficSolutionState.GiveWay) return trafficState; } } return TrafficSolutionState.UnableResolve; } catch (Exception ex) { Logger.Warning($"{agent.Robot.SerialNumber} tìm kiếm giải pháp tránh xung đột bậc 3 xảy ra lỗi: {ex.Message}"); return TrafficSolutionState.UnableResolve; } } private TrafficSolutionState FindAvoidableResolution(Agent agent1, Agent agent2, TrafficMap trafficMap) { try { if (agent2.State == TrafficSolutionState.GiveWay || agent2.State == TrafficSolutionState.LoopResolve) return TrafficSolutionState.Waitting; if (agent2.ReleaseNodeIndex == -1 || agent1.ReleaseNodeIndex == -1) return TrafficSolutionState.Waitting; var conflictNodes = agent2.Nodes.GetRange(agent2.ReleaseNodeIndex, agent2.Nodes.Count - agent2.ReleaseNodeIndex); List<(Agent conflictAgent, TrafficNodeDto conflictNode)> bufferConflict = []; for (int i = 1; i < conflictNodes.Count; i++) { if (conflictNodes[i].IsAvoidableNode) { var remainingNodeAgent2 = agent2.Nodes.GetRange(agent2.ReleaseNodeIndex, agent2.Nodes.Count - agent2.ReleaseNodeIndex); foreach (var avoidablePath in conflictNodes[i].AvoidablePaths) { if (remainingNodeAgent2.Any(n => n.Id == avoidablePath[^1].Id)) continue; var givewayagent2 = conflictNodes.GetRange(1, i); var mergeNode = givewayagent2.LastOrDefault(n => agent1.Nodes.Any(a1 => a1.Id == n.Id)); if (mergeNode is not null) { var avoidableIndex = givewayagent2.FindIndex(n => n.Id == mergeNode.Id); if (avoidableIndex != -1) { var giveWayNodes = givewayagent2.GetRange(avoidableIndex, givewayagent2.Count - avoidableIndex - 1); giveWayNodes.AddRange(avoidablePath); (var IsSuccess, string conflictRobotId, TrafficNodeDto? conflictNode) = GivewayCheckingReleaseNodes([.. giveWayNodes], agent1.Robot.SerialNumber, trafficMap); if (IsSuccess) { trafficMap.AddLocker(agent1.Robot.SerialNumber, [.. giveWayNodes]); var (state, message) = agent1.UpdateGiveWay([.. giveWayNodes], PathPlannger, Map); Logger.Info($"{agent1.Robot.SerialNumber} giải quyết đối đầu với robot {agent2.Robot.SerialNumber} tại node {giveWayNodes[^1].Name} {(state == TrafficSolutionState.Complete || state == TrafficSolutionState.GiveWay ? "thành công" : $"xảy ra lỗi: {message}")}"); if (state == TrafficSolutionState.GiveWay) trafficMap.GivewayResolution.Add(new() { RobotGive = agent1.Robot.SerialNumber, RobotReceive = agent2.Robot.SerialNumber, Nodes = [conflictNodes[i]] }); return state; } else { if (conflictNode is null) { Logger.Warning($"{agent1.Robot.SerialNumber} tìm kiếm giải pháp tránh xung đột đối đầu có lỗi: xảy ra xung đột nhưng không tìm thấy node xung đột"); } else { if (trafficMap.Agents.TryGetValue(conflictRobotId, out Agent? conflictAgent) && conflictAgent is not null) bufferConflict.Add((conflictAgent, conflictNode)); } } } } } } } foreach (var (conflictAgent, conflictNode) in bufferConflict) { var trafficState = Level3ConflictResolution(conflictAgent, agent1.Robot.SerialNumber, conflictNode, [.. conflictNodes], trafficMap, 0); if (trafficState == TrafficSolutionState.Complete || trafficState == TrafficSolutionState.GiveWay) return trafficState; } return TrafficSolutionState.UnableResolve; } catch (Exception ex) { Logger.Warning($"{agent1.Robot.SerialNumber} tìm kiếm giải pháp tránh xung đột đối đầu xảy ra lỗi: {ex.Message}"); return TrafficSolutionState.UnableResolve; } } private TrafficSolutionState LoopConflictResolution(TrafficConflict[] conflicts, TrafficMap trafficMap) { try { for (int i = 0; i < conflicts.Length; i++) { var conflictAvoid = conflicts.FirstOrDefault(c => c.AgentConflict.Robot.SerialNumber == conflicts[i].AgentRequest.Robot.SerialNumber); if (conflictAvoid is null) continue; var conflictResolutionState = LoopConflictLevel1Resolution(conflicts[i], conflictAvoid, trafficMap); if (conflictResolutionState == TrafficSolutionState.Complete) return conflictResolutionState; } for (int i = 0; i < conflicts.Length; i++) { var conflictAvoid = conflicts.FirstOrDefault(c => c.AgentConflict.Robot.SerialNumber == conflicts[i].AgentRequest.Robot.SerialNumber); if (conflictAvoid is null) continue; var conflictResolutionState = LoopConflictLevel2Resolution(conflicts[i], conflictAvoid, trafficMap); if (conflictResolutionState == TrafficSolutionState.Complete) return conflictResolutionState; } return TrafficSolutionState.UnableResolve; } catch (Exception ex) { Logger.Warning($"LoopConflictResolution: Hệ thống xảy ra lỗi - {ex.Message}"); return TrafficSolutionState.UnableResolve; } } private TrafficSolutionState LoopConflictLevel1Resolution(TrafficConflict conflict1, TrafficConflict conflict2, TrafficMap trafficMap) { try { var agent1ConflictIndex = conflict1.ReleaseNodes.IndexOf(conflict1.NodeConflict); var agent2ConflictIndex = conflict2.ReleaseNodes.IndexOf(conflict2.NodeConflict); if (agent1ConflictIndex == -1 || agent2ConflictIndex == -1) return TrafficSolutionState.UnableResolve; var agent1ConflictNodes = conflict1.ReleaseNodes.GetRange(0, agent1ConflictIndex); var agent2ConflictNodes = conflict2.ReleaseNodes.GetRange(0, agent2ConflictIndex + 1); Logger.Info($"{conflict1.AgentRequest.Robot.SerialNumber} xung đột lặp lại với robot {conflict2.AgentRequest.Robot.SerialNumber} - release 1: [{conflict1.ReleaseNodes[0].Name} => {conflict1.ReleaseNodes[^1].Name} - {conflict1.NodeConflict.Name}] - release 2: [{conflict2.ReleaseNodes[0].Name} => {conflict2.ReleaseNodes[^1].Name} - {conflict2.NodeConflict.Name}]"); var avoidableNode = agent1ConflictNodes.FirstOrDefault(n => !agent2ConflictNodes.Any(n2 => n2.Id == n.Id)); if (avoidableNode is not null) { TrafficNodeDto[] releaseNodes = [.. conflict1.ReleaseNodes.GetRange(0, conflict1.ReleaseNodes.IndexOf(avoidableNode) + 1)]; (var conflictState, string conflictRobotId, TrafficNodeDto? conflictNode) = FirstCheckingReleaseNodes(releaseNodes, conflict1.AgentRequest, trafficMap); if (conflictState == TrafficConflictState.None) { Logger.Info($"{conflict1.AgentRequest.Robot.SerialNumber} giải quyết xung đột lặp lại với robot {conflict2.AgentRequest.Robot.SerialNumber} tại node {avoidableNode.Name} - release {releaseNodes[^1].Name} "); trafficMap.AddLocker(conflict1.AgentRequest.Robot.SerialNumber, [.. releaseNodes]); conflict1.AgentRequest.ReleaseNode = releaseNodes[^1]; conflict1.AgentRequest.State = TrafficSolutionState.LoopResolve; trafficMap.GivewayResolution.Add(new() { RobotGive = conflict1.AgentRequest.Robot.SerialNumber, RobotReceive = conflict2.AgentRequest.Robot.SerialNumber, Nodes = [.. agent2ConflictNodes] }); return TrafficSolutionState.Complete; } } return TrafficSolutionState.Waitting; } catch (Exception ex) { Logger.Warning($"LoopConflictLevel1Resolution: Hệ thống xảy ra lỗi - {ex.Message}"); return TrafficSolutionState.UnableResolve; } } private TrafficSolutionState LoopConflictLevel2Resolution(TrafficConflict conflict1, TrafficConflict conflict2, TrafficMap trafficMap) { try { var agent2ConflictIndex = conflict2.ReleaseNodes.IndexOf(conflict2.NodeConflict); if (agent2ConflictIndex == -1) return TrafficSolutionState.UnableResolve; var agent2ConflictNodes = conflict2.ReleaseNodes.GetRange(0, agent2ConflictIndex + 1); Logger.Info($"{conflict1.AgentRequest.Robot.SerialNumber} xung đột lặp lại với robot {conflict2.AgentRequest.Robot.SerialNumber} - release 1: [{conflict1.ReleaseNodes[0].Name} => {conflict1.ReleaseNodes[^1].Name} - {conflict1.NodeConflict.Name}] - release 2: [{conflict2.ReleaseNodes[0].Name} => {conflict2.ReleaseNodes[^1].Name} - {conflict2.NodeConflict.Name}]"); var avoidableNode = conflict1.ReleaseNodes.FirstOrDefault(n => !agent2ConflictNodes.Any(n2 => n2.Id == n.Id)); if (avoidableNode is not null) { TrafficNodeDto[] releaseNodes = [.. conflict1.ReleaseNodes.GetRange(0, conflict1.ReleaseNodes.IndexOf(avoidableNode) + 1)]; (var conflictState, string conflictRobotId, TrafficNodeDto? conflictNode) = FirstCheckingReleaseNodes(releaseNodes, conflict1.AgentRequest, trafficMap); if (conflictState == TrafficConflictState.None) { Logger.Info($"{conflict1.AgentRequest.Robot.SerialNumber} giải quyết xung đột lặp lại với robot {conflict2.AgentRequest.Robot.SerialNumber} tại node {avoidableNode.Name} - release {releaseNodes[^1].Name} "); trafficMap.AddLocker(conflict1.AgentRequest.Robot.SerialNumber, [.. releaseNodes]); conflict1.AgentRequest.ReleaseNode = releaseNodes[^1]; conflict1.AgentRequest.State = TrafficSolutionState.LoopResolve; trafficMap.GivewayResolution.Add(new() { RobotGive = conflict1.AgentRequest.Robot.SerialNumber, RobotReceive = conflict2.AgentRequest.Robot.SerialNumber, Nodes = [.. agent2ConflictNodes] }); return TrafficSolutionState.Complete; } else { if (trafficMap.Agents.TryGetValue(conflictRobotId, out Agent? conflictAgent) && conflictAgent is not null) { var state = Level3ConflictResolution(conflictAgent, conflict1.AgentRequest.Robot.SerialNumber, avoidableNode, [.. releaseNodes, .. agent2ConflictNodes], trafficMap, 0); if (state == TrafficSolutionState.Complete || state == TrafficSolutionState.GiveWay) { trafficMap.Conflicts.RemoveAll(c => c.AgentRequest.Robot.SerialNumber == conflictAgent.Robot.SerialNumber); return TrafficSolutionState.Complete; } return TrafficSolutionState.UnableResolve; } } } return TrafficSolutionState.Waitting; } catch (Exception ex) { Logger.Warning($"LoopConflictLevel2Resolution: Hệ thống xảy ra lỗi - {ex.Message}"); return TrafficSolutionState.UnableResolve; } } private void ComputeHandler(object? state) { try { foreach (var trafficmap in TrafficMaps) { var agents = trafficmap.Value.Agents.Values.ToList(); foreach (var agent in agents) { CheckConflict(agent, trafficmap.Value); } var conflicts = trafficmap.Value.Conflicts.ToList(); for (int i = 0; i < conflicts.Count; i++) { int repeat = 0; bool isProccessed = false; string agentConflict = conflicts[i].AgentConflict.Robot.SerialNumber; List loopConflicts = [conflicts[i]]; while (repeat++ <= TrafficResolutionRepeat) { var loopConflict = conflicts.FirstOrDefault(cl => cl.AgentRequest.Robot.SerialNumber == agentConflict); if (loopConflict is null) break; loopConflicts.Add(loopConflict); if (loopConflict.AgentConflict.Robot.SerialNumber == conflicts[i].AgentRequest.Robot.SerialNumber) { if (loopConflicts.Count > 2) { var resolutionstate = LoopConflictResolution([.. loopConflicts], trafficmap.Value); isProccessed = resolutionstate == TrafficSolutionState.Complete; } break; } else agentConflict = loopConflict.AgentConflict.Robot.SerialNumber; } if (isProccessed) break; if (conflicts[i].State == TrafficConflictState.Confrontation) { if (conflicts.Any(c => c.State == TrafficConflictState.Confrontation && c.AgentRequest.Robot.SerialNumber == conflicts[i].AgentConflict.Robot.SerialNumber)) { var resolutionstate = FindAvoidableResolution(conflicts[i].AgentRequest, conflicts[i].AgentConflict, trafficmap.Value); if (resolutionstate == TrafficSolutionState.Complete || resolutionstate == TrafficSolutionState.GiveWay) { trafficmap.Value.Conflicts.Remove(conflicts[i]); break; } } } } } computeTimer?.Change(intervalTime, 0); } catch (Exception ex) { Logger.Warning($"TrafficCompute: Hệ thống xảy ra lỗi - {ex.Message}"); computeTimer?.Change(intervalTime, 0); } } public async Task StartAsync(CancellationToken cancellationToken) { if (!Enable) return; computeTimer = new Timer(ComputeHandler, null, Timeout.Infinite, Timeout.Infinite); computeTimer.Change(intervalTime, 0); await Task.Yield(); } public async Task StopAsync(CancellationToken cancellationToken) { if (computeTimer != null) { computeTimer.Change(Timeout.Infinite, Timeout.Infinite); await computeTimer.DisposeAsync(); } } }