| | |
| | | using Quartz; |
| | | using Quartz; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Core.Caches; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_Tasks.Workflow.Abstractions; |
| | | using WIDESEAWCS_Tasks.Workflow; |
| | | using WIDESEAWCS_Tasks.SocketServer; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | | /// <summary> |
| | | /// 机械手任务作业 - 负责协调机械手客户端连接、消息处理和任务执行 |
| | | /// 机器人任务作业:负责调度与生命周期管理,具体状态机流程交给编排器。 |
| | | /// </summary> |
| | | [DisallowConcurrentExecution] |
| | | public class RobotJob : IJob |
| | |
| | | |
| | | private readonly RobotClientManager _clientManager; |
| | | private readonly RobotStateManager _stateManager; |
| | | private readonly RobotMessageHandler _messageHandler; |
| | | private readonly IRobotMessageRouter _messageRouter; |
| | | private readonly RobotTaskProcessor _taskProcessor; |
| | | private readonly IRobotTaskService _robotTaskService; |
| | | private readonly IRobotWorkflowOrchestrator _workflowOrchestrator; |
| | | |
| | | public RobotJob( |
| | | TcpSocketServer tcpSocket, |
| | |
| | | ICacheService cache, |
| | | HttpClientHelper httpClientHelper) |
| | | { |
| | | _robotTaskService = robotTaskService; |
| | | |
| | | // 初始化管理器 |
| | | _stateManager = new RobotStateManager(cache); |
| | | _taskProcessor = new RobotTaskProcessor(tcpSocket, _stateManager, robotTaskService, taskService, httpClientHelper); |
| | | _clientManager = new RobotClientManager(tcpSocket, _stateManager); |
| | | _messageHandler = new RobotMessageHandler(tcpSocket, _stateManager, cache, robotTaskService, _taskProcessor); |
| | | |
| | | // 订阅客户端管理器的事件 |
| | | // 收口 Socket 访问,后续若替换通信实现只需替换网关层。 |
| | | ISocketClientGateway socketGateway = new SocketClientGateway(tcpSocket); |
| | | |
| | | _taskProcessor = new RobotTaskProcessor(socketGateway, _stateManager, robotTaskService, taskService, httpClientHelper); |
| | | _clientManager = new RobotClientManager(tcpSocket, _stateManager); |
| | | |
| | | var simpleCommandHandler = new RobotSimpleCommandHandler(_taskProcessor); |
| | | var prefixCommandHandler = new RobotPrefixCommandHandler(robotTaskService, _taskProcessor, _stateManager, socketGateway); |
| | | _messageRouter = new RobotMessageHandler(socketGateway, _stateManager, cache, simpleCommandHandler, prefixCommandHandler); |
| | | |
| | | _workflowOrchestrator = new RobotWorkflowOrchestrator(_stateManager, _clientManager, _taskProcessor, robotTaskService); |
| | | |
| | | _clientManager.OnClientDisconnected += OnClientDisconnected; |
| | | |
| | | // 订阅TCP服务器的消息事件(全局只订阅一次) |
| | | // 全局只订阅一次消息事件,保持原有行为。 |
| | | if (System.Threading.Interlocked.CompareExchange(ref _messageSubscribedFlag, 1, 0) == 0) |
| | | { |
| | | tcpSocket.MessageReceived += _messageHandler.HandleMessageReceivedAsync; |
| | | Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 机器人TCP消息事件已订阅"); |
| | | tcpSocket.MessageReceived += _messageRouter.HandleMessageReceivedAsync; |
| | | Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 机器手TCP消息事件已订阅"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 客户端断开连接时的处理 |
| | | /// </summary> |
| | | private void OnClientDisconnected(object? sender, RobotSocketState state) |
| | | { |
| | | // 可以在这里添加断开连接后的处理逻辑 |
| | | Console.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 客户端已断开连接: {state.IPAddress}"); |
| | | } |
| | | |
| | |
| | | |
| | | string ipAddress = robotCrane.IPAddress; |
| | | |
| | | // 获取或创建状态 |
| | | RobotSocketState state = _stateManager.GetOrCreateState(ipAddress, robotCrane); |
| | | state.RobotCrane = robotCrane; |
| | | |
| | | try |
| | | { |
| | | // 确保客户端已连接并订阅消息事件 |
| | | if (!_clientManager.EnsureClientSubscribed(ipAddress, robotCrane)) |
| | | { |
| | | return; // 客户端未连接或订阅失败,跳过本次执行 |
| | | return; |
| | | } |
| | | |
| | | // 获取任务并处理 |
| | | Dt_RobotTask? task = _taskProcessor.GetTask(robotCrane); |
| | | var task = _taskProcessor.GetTask(robotCrane); |
| | | if (task != null) |
| | | { |
| | | // 每次判断前重新从缓存获取最新状态 |
| | | var latestState = _stateManager.GetState(ipAddress); |
| | | if (latestState == null) return; |
| | | if (latestState == null) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | if (latestState.RobotTaskTotalNum < MaxTaskTotalNum) |
| | | { |
| | | await ProcessTaskAsync(latestState, task, ipAddress); |
| | | await _workflowOrchestrator.ExecuteAsync(latestState, task, ipAddress); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception) |
| | | { |
| | | // 异常处理已在各组件中处理 |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 处理机械手任务 |
| | | /// </summary> |
| | | private async Task ProcessTaskAsync(RobotSocketState latestState, Dt_RobotTask task, string ipAddress) |
| | | { |
| | | // 处理正在执行的任务 |
| | | if (latestState.RobotRunMode == 2 && latestState.RobotControlMode == 1 && latestState.OperStatus != "Running") |
| | | { |
| | | // 取货完成状态处理 |
| | | if ((latestState.CurrentAction == "PickFinished" || latestState.CurrentAction == "AllPickFinished") && latestState.RobotArmObject == 1 && |
| | | task.RobotTaskState == TaskRobotStatusEnum.RobotPickFinish.GetHashCode()) |
| | | { |
| | | await HandlePickFinishedStateAsync(latestState, task, ipAddress); |
| | | } |
| | | // 放货完成状态处理 |
| | | else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished") && latestState.OperStatus == "Homed" && |
| | | latestState.RobotArmObject == 0 && |
| | | (task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode() || |
| | | task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())) |
| | | { |
| | | await HandlePutFinishedStateAsync(latestState, task, ipAddress); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 处理取货完成状态 |
| | | /// </summary> |
| | | private async Task HandlePickFinishedStateAsync(RobotSocketState latestState, Dt_RobotTask task, string ipAddress) |
| | | { |
| | | string taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | bool result = await _clientManager.SendToClientAsync(ipAddress, taskString); |
| | | if (result) |
| | | { |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | |
| | | // 重新获取最新状态并更新 |
| | | var stateToUpdate = _stateManager.GetState(ipAddress); |
| | | if (stateToUpdate != null) |
| | | { |
| | | stateToUpdate.CurrentTask = task; |
| | | if (_stateManager.TryUpdateStateSafely(ipAddress, stateToUpdate)) |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 处理放货完成状态 |
| | | /// </summary> |
| | | private async Task HandlePutFinishedStateAsync(RobotSocketState latestState, Dt_RobotTask task, string ipAddress) |
| | | { |
| | | // 重新获取最新状态 |
| | | var stateForUpdate = _stateManager.GetState(ipAddress); |
| | | if (stateForUpdate == null) return; |
| | | |
| | | if (!stateForUpdate.IsSplitPallet && !stateForUpdate.IsGroupPallet) |
| | | { |
| | | stateForUpdate.IsSplitPallet = task.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode(); |
| | | stateForUpdate.IsGroupPallet = task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() || |
| | | task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode(); |
| | | } |
| | | |
| | | if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode()) |
| | | { |
| | | string prefix = "TRAY"; |
| | | |
| | | // 生成两个托盘条码 |
| | | string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix); |
| | | string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix); |
| | | if (!trayBarcode1.IsNullOrEmpty() && !trayBarcode2.IsNullOrEmpty()) |
| | | { |
| | | stateForUpdate.CellBarcode.Add(trayBarcode1); |
| | | stateForUpdate.CellBarcode.Add(trayBarcode2); |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | } |
| | | } |
| | | else // 任务开始执行直接发送取货地址 |
| | | { |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate); |
| | | // 异常处理已在组件内部进行,Job 层保持兜底吞吐语义。 |
| | | } |
| | | } |
| | | } |