wanshenmean
5 小时以前 ad64840cc04dac2278ca02f22ddc02b1a218e9cf
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/Workflow/RobotWorkflowOrchestrator.cs
@@ -1,5 +1,7 @@
using Microsoft.Extensions.Logging;
using WIDESEA_Core;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_ITaskInfoService;
using WIDESEAWCS_Model.Models;
@@ -58,22 +60,30 @@
        private readonly IRobotTaskService _robotTaskService;
        /// <summary>
        /// 日志记录器
        /// </summary>
        private readonly ILogger _logger;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="stateManager">状态管理器</param>
        /// <param name="clientManager">客户端管理器</param>
        /// <param name="taskProcessor">任务处理器</param>
        /// <param name="robotTaskService">任务服务</param>
        /// <param name="logger">日志记录器</param>
        public RobotWorkflowOrchestrator(
            RobotStateManager stateManager,
            RobotClientManager clientManager,
            RobotTaskProcessor taskProcessor,
            IRobotTaskService robotTaskService)
            IRobotTaskService robotTaskService,
            ILogger logger)
        {
            _stateManager = stateManager;
            _clientManager = clientManager;
            _taskProcessor = taskProcessor;
            _robotTaskService = robotTaskService;
            _logger = logger;
        }
        /// <summary>
@@ -100,8 +110,8 @@
            // 检查是否满足自动控制条件:
            // 1. 运行模式为自动(2)
            // 2. 控制模式为客户端控制(1)
            // 3. 运行状态不是 Running(说明已完成当前动作)
            if (latestState.RobotRunMode == 2 && latestState.RobotControlMode == 1 && latestState.OperStatus != "Running")
            // 3. 运行状态是 Running
            if (latestState.RobotRunMode == 2 /*&& latestState.RobotControlMode == 1*/ && latestState.OperStatus == "Running" && latestState.Homed == "Homed")
            {
                // ========== 取货完成后的放货处理 ==========
                // 条件:
@@ -112,21 +122,25 @@
                    && latestState.RobotArmObject == 1
                    && task.RobotTaskState == TaskRobotStatusEnum.RobotPickFinish.GetHashCode())
                {
                    _logger.LogInformation("ExecuteAsync:满足放货条件,开始处理取货完成,任务号: {TaskNum}", task.RobotTaskNum);
                    QuartzLogger.Info($"ExecuteAsync:满足放货条件,开始处理取货完成", latestState.RobotCrane?.DeviceName ?? ipAddress);
                    // 发送放货指令
                    await HandlePickFinishedStateAsync(task, ipAddress);
                }
                // ========== 放货完成后的取货处理 ==========
                // ========== 初始化或者放货完成后的取货处理 ==========
                // 条件:
                // - 当前动作是 PutFinished、AllPutFinished 或 null(放货完成)
                // - 运行状态为 Homed(已归位)
                // - 手臂上无物料(RobotArmObject == 0)
                // - 任务状态为 RobotPutFinish 或不是 RobotExecuting
                else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished" || latestState.CurrentAction == null)
                    && latestState.OperStatus == "Homed"
                else if ((latestState.CurrentAction == "PutFinished" || latestState.CurrentAction == "AllPutFinished" || latestState.CurrentAction.IsNullOrEmpty())
                    && latestState.RobotArmObject == 0
                    && (task.RobotTaskState == TaskRobotStatusEnum.RobotPutFinish.GetHashCode()
                    || task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode()))
                {
                    _logger.LogInformation("ExecuteAsync:满足取货条件,开始处理放货完成,任务号: {TaskNum}", task.RobotTaskNum);
                    QuartzLogger.Info($"ExecuteAsync:满足取货条件,开始处理放货完成", latestState.RobotCrane?.DeviceName ?? ipAddress);
                    // 发送取货指令
                    await HandlePutFinishedStateAsync(task, ipAddress);
                }
@@ -155,8 +169,9 @@
            if (result)
            {
                // 发送成功,记录日志
                QuartzLogger.Error($"下发放货指令,指�?: {taskString}", task.RobotRoadway);
                // 发送成功,记录 Info 日志
                _logger.LogInformation("HandlePickFinishedStateAsync:下发放货指令成功,指令: {TaskString},任务号: {TaskNum}", taskString, task.RobotTaskNum);
                QuartzLogger.Info($"下发放货指令成功,指令: {taskString}", task.RobotRoadway);
                // 更新任务状态为"机器人执行中"
                task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
@@ -174,6 +189,12 @@
                        await _robotTaskService.UpdateRobotTaskAsync(task);
                    }
                }
            }
            else
            {
                // 发送失败,记录 Error 日志
                _logger.LogError("HandlePickFinishedStateAsync:下发放货指令失败,指令: {TaskString},任务号: {TaskNum}", taskString, task.RobotTaskNum);
                QuartzLogger.Error($"下发放货指令失败,指令: {taskString}", task.RobotRoadway);
            }
        }
@@ -202,6 +223,8 @@
            var stateForUpdate = _stateManager.GetState(ipAddress);
            if (stateForUpdate == null)
            {
                _logger.LogWarning("HandlePutFinishedStateAsync:获取状态失败,IP: {IpAddress}", ipAddress);
                QuartzLogger.Warn($"HandlePutFinishedStateAsync:获取状态失败,IP: {ipAddress}", ipAddress);
                return;
            }
@@ -214,29 +237,110 @@
                    || task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode();
            }
            // 如果是组盘任务(包括换盘)
            // 如果是组盘任务
            if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode())
            {
                // 生成托盘条码前缀
                const string prefix = "TRAY";
                // 生成两个托盘条码(用于组盘操作)
                // 生成两个托盘条码(用于组盘操作)(测试用,后续读取线体条码)
                string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix);
                string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode(prefix);
                // 如果条码生成成功
                if (!string.IsNullOrEmpty(trayBarcode1) && !string.IsNullOrEmpty(trayBarcode2))
                {
                    // 将条码添加到状态中,供后续放货时使用
                    stateForUpdate.CellBarcode.Add(trayBarcode1);
                    stateForUpdate.CellBarcode.Add(trayBarcode2);
                    if(stateForUpdate.CellBarcode.Contains(trayBarcode1)|| stateForUpdate.CellBarcode.Contains(trayBarcode2))
                    {
                        _logger.LogError("HandlePutFinishedStateAsync:生成的托盘条码已存在,可能存在重复,任务号: {TaskNum}", task.RobotTaskNum);
                        QuartzLogger.Error($"生成的托盘条码已存在,可能存在重复", stateForUpdate.RobotCrane.DeviceName);
                    // 记录日志
                    QuartzLogger.Error($"ȡ�������о�ţ���о: {trayBarcode1}+{trayBarcode2}", stateForUpdate.RobotCrane.DeviceName);
                        // 条码重复,记录错误日志并停止后续操作(后续放货时会用到这些条码信息,供后续放货时使用,调试后可能会取消此逻辑)
                        return;
                    }
                    else
                    {
                        _logger.LogInformation("HandlePutFinishedStateAsync:生成的托盘条码唯一,继续执行,任务号: {TaskNum}", task.RobotTaskNum);
                        QuartzLogger.Info($"生成的托盘条码唯一,继续执行", stateForUpdate.RobotCrane.DeviceName);
                        // 将条码添加到状态中,供后续放货时使用
                        stateForUpdate.CellBarcode.Add(trayBarcode1);
                        stateForUpdate.CellBarcode.Add(trayBarcode2);
                    }
                    // 记录日志:生成托盘条码成功
                    _logger.LogInformation("HandlePutFinishedStateAsync:生成托盘条码成功: {Barcode1}+{Barcode2},任务号: {TaskNum}", trayBarcode1, trayBarcode2, task.RobotTaskNum);
                    QuartzLogger.Info($"生成托盘条码成功: {trayBarcode1}+{trayBarcode2}", stateForUpdate.RobotCrane.DeviceName);
                    // 发送取货指令
                    await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate);
                }
                else
                {
                    // 条码生成失败,记录错误日志
                    _logger.LogError("HandlePutFinishedStateAsync:生成托盘条码失败,任务号: {TaskNum}", task.RobotTaskNum);
                    QuartzLogger.Error($"生成托盘条码失败", stateForUpdate.RobotCrane.DeviceName);
                }
            }
            else if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())
            {
                // 换盘任务
                // 目标:正常电芯抓取完成后,补充假电芯至48个
                const int targetTotal = 48;
                const int fakeBatteryPickPosition = 5;  // 假电芯抓取位置
                const int pickCountPerExecution = 4;     // 每次抓取数量
                int targetNormalCount = task.RobotTaskTotalNum;  // 正常电芯目标数量
                int currentCompletedCount = stateForUpdate.RobotTaskTotalNum;  // 已完成数量
                // 如果目标数量为48,直接下发正常任务
                if (targetNormalCount == targetTotal)
                {
                    await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate);
                }
                // 如果已完成数量小于目标数量,继续抓取正常电芯
                else if (currentCompletedCount < targetNormalCount)
                {
                    await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate);
                }
                // 正常电芯已完成,进入假电芯补充模式
                else if (currentCompletedCount == targetNormalCount && !stateForUpdate.IsInFakeBatteryMode)
                {
                    // 首次进入假电芯模式,设置标志
                    stateForUpdate.IsInFakeBatteryMode = true;
                    _logger.LogInformation("HandlePutFinishedStateAsync:正常电芯抓取完成,进入假电芯补充模式,任务号: {TaskNum}", task.RobotTaskNum);
                    QuartzLogger.Info($"正常电芯抓取完成,进入假电芯补充模式", stateForUpdate.RobotCrane?.DeviceName);
                }
                // 如果处于假电芯补充模式,计算并下发补数任务
                if (stateForUpdate.IsInFakeBatteryMode)
                {
                    int remaining = targetTotal - currentCompletedCount;
                    if (remaining > 0)
                    {
                        // 计算每次抓取的数量(最多4个)
                        int pickCount = Math.Min(pickCountPerExecution, remaining);
                        // 获取可用的假电芯平面点位
                        var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(pickCount);
                        if (positions.Count == 0)
                        {
                            _logger.LogError("HandlePutFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum);
                            QuartzLogger.Error($"无可用假电芯点位", stateForUpdate.RobotCrane?.DeviceName);
                            return;
                        }
                        // 下发假电芯取货指令
                        await _taskProcessor.SendSocketRobotFakeBatteryPickAsync(task, stateForUpdate, positions);
                    }
                    else
                    {
                        // 假电芯补充完成,重置标志
                        stateForUpdate.IsInFakeBatteryMode = false;
                        _logger.LogInformation("HandlePutFinishedStateAsync:换盘任务完成,任务号: {TaskNum}", task.RobotTaskNum);
                        QuartzLogger.Info($"换盘任务完成", stateForUpdate.RobotCrane?.DeviceName);
                    }
                }
            }
            else
            {