| | |
| | | |
| | | var state = _stateManager.GetState(ipAddress); |
| | | |
| | | // 换盘任务使用批次格式 |
| | | // 换盘任务批次模式 |
| | | if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()) |
| | | { |
| | | int targetNormalCount = task.RobotTaskTotalNum; |
| | |
| | | |
| | | bool isFlowA = task.RobotSourceAddressLineCode is "11001" or "11010"; |
| | | |
| | | // 流向A Phase 2:放假电芯到目标托盘 |
| | | if (isFlowA && state?.ChangePalletPhase == 2) |
| | | // ==================== Phase 2: 放正常电芯到目标托盘(两流向相同)==================== |
| | | // PickFinished 到达:Phase 1 的 Pick 命令完成,现在下发 Put 命令放正常电芯 |
| | | if (state?.ChangePalletPhase == 2) |
| | | { |
| | | int remaining = 48 - currentCompletedCount; |
| | | if (remaining <= 0) return; |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) |
| | | { |
| | | // 正常电芯全部放完,等待 HandlePutFinishedAsync 切换到 Phase 3 |
| | | return; |
| | | } |
| | | |
| | | int batchStart = targetNormalCount + 1 + (state.CurrentBatchIndex - 1); |
| | | int putCount = Math.Min(4, remaining); |
| | | int batchStart = (currentCompletedCount / 4) * 4 + 1; |
| | | int putCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end); |
| | | |
| | | // Phase 保持为 2,等 HandlePutFinishedAsync 处理完放货计数后再切回 Phase 1 |
| | | _stateManager.TryUpdateStateSafely(ipAddress, state); |
| | | return; |
| | | } |
| | | |
| | | // 流向B Phase 4:放假电芯到5号位 |
| | | if (!isFlowA && state?.ChangePalletPhase == 4) |
| | | // ==================== Phase 4: 放假电芯(两流向分叉)==================== |
| | | // PickFinished 到达:Phase 3 的 Pick 命令完成,现在下发 Put 命令放假电芯 |
| | | if (state?.ChangePalletPhase == 4) |
| | | { |
| | | int fakeCount = 48 - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) return; |
| | | |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake)); |
| | | if (positions.Count == 0) |
| | | if (remainingFake <= 0) |
| | | { |
| | | _logger.LogError("HandlePickFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum); |
| | | // 假电芯全部放完,等待 allputfinished 触发 Phase 5 入库 |
| | | return; |
| | | } |
| | | |
| | | int start = positions.Min(); |
| | | int end = positions.Max(); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, "5", start, end); |
| | | return; |
| | | } |
| | | |
| | | // 流向B Phase 2:放正常电芯到目标托盘 |
| | | if (!isFlowA && state?.ChangePalletPhase == 2) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) return; |
| | | |
| | | int batchStart = ((currentCompletedCount - 1) / 4) * 4 + 1; |
| | | int putCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end); |
| | | return; |
| | | } |
| | | |
| | | // 默认:使用原有格式 |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | } |
| | | else |
| | | { |
| | | // 非换盘任务:使用原有格式 |
| | | if (state != null && state.IsGroupPallet && task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode()) |
| | | { |
| | | // 组盘任务:放货需判断是否NG,如果NG则放到NG口 |
| | | if (state.IsScanNG) |
| | | if (isFlowA) |
| | | { |
| | | taskString = $"Putbattery,4"; |
| | | // 流向A:放假电芯到目标托盘 |
| | | int batchStart = targetNormalCount + 1 + (state.CurrentBatchIndex - 1); |
| | | int putCount = Math.Min(4, remainingFake); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, task.RobotTargetAddress, start, end); |
| | | |
| | | state.CurrentBatchIndex += putCount; |
| | | // Phase 保持为 4,等 HandlePutFinishedAsync 处理完后再切回 Phase 3 |
| | | _stateManager.TryUpdateStateSafely(ipAddress, state); |
| | | } |
| | | else |
| | | { |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | // 流向B:放假电芯到5号位 |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake)); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePickFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int start = positions.Min(); |
| | | int end = positions.Max(); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, state, "5", start, end); |
| | | |
| | | // Phase 保持为 4,等 HandlePutFinishedAsync 处理完后再切回 Phase 3 |
| | | _stateManager.TryUpdateStateSafely(ipAddress, state); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | // 非批次模式或其他阶段不下发指令 |
| | | return; |
| | | } |
| | | |
| | | // 非换盘任务:使用原有格式 |
| | | if (state != null && state.IsGroupPallet && task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode()) |
| | | { |
| | | if (state.IsScanNG) |
| | | { |
| | | taskString = $"Putbattery,1"; |
| | | } |
| | | else |
| | | { |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | } |
| | | } |
| | | else |
| | | taskString = $"Putbattery,{task.RobotTargetAddress}"; |
| | | |
| | | bool result = await _clientManager.SendToClientAsync(ipAddress, taskString); |
| | | |
| | |
| | | // 如果是组盘任务 |
| | | if (task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode()) |
| | | { |
| | | |
| | | //if (!stateForUpdate.BatteryArrived) |
| | | //{ |
| | | // return; |
| | | //} |
| | | // 检查电池是否已到位 |
| | | if (!stateForUpdate.BatteryArrived) |
| | | { |
| | | return; |
| | | } |
| | | // 读取线体电芯条码 |
| | | string trayBarcode1 = RobotBarcodeGenerator.GenerateTrayBarcode("DB40.990"); |
| | | string trayBarcode2 = RobotBarcodeGenerator.GenerateTrayBarcode("DB40.1020"); |
| | |
| | | // 条码重复,记录错误日志并停止后续操作(后续放货时会用到这些条码信息,供后续放货时使用,调试后可能会取消此逻辑) |
| | | |
| | | // 发送取货指令 标记扫码NG,放货时不使用这些条码,并放入NG口 |
| | | //await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, true); |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, true); |
| | | return; |
| | | } |
| | | else |
| | | { |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:读取的托盘条码唯一,继续执行,任务号: {TaskNum}", task.RobotTaskNum); |
| | | QuartzLogger.Info($"读取的托盘条码唯一,继续执行", stateForUpdate.RobotCrane.DeviceName); |
| | | |
| | | // 将条码添加到状态中,供后续放货时使用 |
| | | stateForUpdate.CellBarcode = new List<string>() |
| | | { |
| | | trayBarcode1,trayBarcode2 |
| | | }; |
| | | |
| | | // 将条码添加到状态中,供后续放货时使用 |
| | | //stateForUpdate.CellBarcode.Add(trayBarcode1); |
| | | //stateForUpdate.CellBarcode.Add(trayBarcode2); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | // 发送取货指令 标记扫码NG,放货时不使用这些条码,并放入NG口 |
| | | //await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, true); |
| | | await _taskProcessor.SendSocketRobotPickAsync(task, stateForUpdate, true); |
| | | return; |
| | | } |
| | | } |
| | | else if (task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()) |
| | | { |
| | | const int targetTotal = 48; |
| | | // 换盘任务进入批次模式,分阶段处理正常电芯和假电芯 (机器人任务总数) |
| | | int targetNormalCount = task.RobotTaskTotalNum; |
| | | // 当前已完成数量(取货完成的数量),初始为状态中的 RobotTaskTotalNum,后续根据取货完成的数量动态更新 |
| | | int currentCompletedCount = stateForUpdate.RobotTaskTotalNum; |
| | | |
| | | // 判断流向(null-safe) |
| | |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:换盘任务进入批次模式,任务号: {TaskNum},流向: {Flow}", |
| | | task.RobotTaskNum, isFlowA ? "A" : "B"); |
| | | _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate); |
| | | } |
| | | |
| | | // ==================== 流向A:补假电芯到目标托盘 ==================== |
| | | if (isFlowA) |
| | | // ==================== Phase 1: 取正常电芯(两流向相同)==================== |
| | | if (stateForUpdate.ChangePalletPhase == 1) |
| | | { |
| | | // Phase 1: 取假电芯(从5号位,使用 PositionIndex) |
| | | if (stateForUpdate.ChangePalletPhase == 1) |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) |
| | | { |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:流向A完成,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int pickCount = Math.Min(4, remaining); |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(pickCount); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePutFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | await _taskProcessor.SendSocketRobotFakeBatteryPickAsync(task, stateForUpdate, positions); |
| | | stateForUpdate.ChangePalletPhase = 2; |
| | | // 正常电芯取完,切换到 Phase 3 取假电芯 |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | stateForUpdate.CurrentBatchIndex = 1; // 假电芯批次从头开始 |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:正常电芯取完,切换到Phase 3取假电芯,任务号: {TaskNum}", task.RobotTaskNum); |
| | | _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate); |
| | | return; |
| | | } |
| | | // Phase 2: 放假电芯到目标托盘(从 targetNormalCount+1 开始递增) |
| | | else if (stateForUpdate.ChangePalletPhase == 2) |
| | | { |
| | | int remaining = targetTotal - currentCompletedCount; |
| | | if (remaining <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:流向A完成,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // 计算放货批次编号:从 targetNormalCount + 1 开始 |
| | | int batchStart = targetNormalCount + 1 + (stateForUpdate.CurrentBatchIndex - 1); |
| | | int putCount = Math.Min(4, remaining); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | int pickCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, task.RobotTargetAddress, start, end); |
| | | await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end); |
| | | |
| | | stateForUpdate.CurrentBatchIndex += putCount; |
| | | stateForUpdate.ChangePalletPhase = 1; |
| | | } |
| | | stateForUpdate.CurrentBatchIndex += pickCount; |
| | | // 发完 Pick 后切换到 Phase=2,等 PickFinished 触发 HandlePickFinishedStateAsync 下发放货指令 |
| | | stateForUpdate.ChangePalletPhase = 2; |
| | | _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate); |
| | | return; |
| | | } |
| | | // ==================== 流向B:取正常电芯 + 回收假电芯 ==================== |
| | | else |
| | | |
| | | // ==================== Phase 3: 处理假电芯(流向A/B 分叉),自己循环 ==================== |
| | | if (stateForUpdate.ChangePalletPhase == 3) |
| | | { |
| | | // Phase 1: 取正常电芯(从源地址,从1开始递增) |
| | | if (stateForUpdate.ChangePalletPhase == 1) |
| | | int fakeCount = targetTotal - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) |
| | | { |
| | | // 正常电芯取完,切换到 Phase 3 |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | stateForUpdate.CurrentBatchIndex = targetNormalCount + 1; |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:正常电芯全部取完,进入Phase 3回收假电芯,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int pickCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount); |
| | | |
| | | await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end); |
| | | |
| | | stateForUpdate.CurrentBatchIndex += pickCount; |
| | | stateForUpdate.ChangePalletPhase = 2; |
| | | // 假电芯全部处理完,切换到 Phase 5 等待入库 |
| | | stateForUpdate.ChangePalletPhase = 5; |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:假电芯处理完毕,切换到Phase 5等待入库,任务号: {TaskNum}", task.RobotTaskNum); |
| | | _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate); |
| | | return; |
| | | } |
| | | // Phase 2: 放正常电芯到目标托盘(放货编号与取货编号一致) |
| | | else if (stateForUpdate.ChangePalletPhase == 2) |
| | | |
| | | if (isFlowA) |
| | | { |
| | | int remainingNormal = targetNormalCount - currentCompletedCount; |
| | | if (remainingNormal <= 0) |
| | | { |
| | | // 正常电芯放完,切换到 Phase 3 |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | stateForUpdate.CurrentBatchIndex = targetNormalCount + 1; |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:正常电芯全部放完,进入Phase 3回收假电芯,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // 计算本批放货编号:基于 currentCompletedCount 推导批次起始 |
| | | int batchStart = ((currentCompletedCount - 1) / 4) * 4 + 1; |
| | | int putCount = Math.Min(4, remainingNormal); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(batchStart, putCount); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, task.RobotTargetAddress, start, end); |
| | | |
| | | stateForUpdate.ChangePalletPhase = 1; |
| | | } |
| | | // Phase 3: 取假电芯(从源地址,从 targetNormalCount+1 开始递增) |
| | | else if (stateForUpdate.ChangePalletPhase == 3) |
| | | { |
| | | int fakeCount = targetTotal - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:流向B完成,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int pickCount = Math.Min(4, remainingFake); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount); |
| | | |
| | | await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end); |
| | | |
| | | stateForUpdate.CurrentBatchIndex += pickCount; |
| | | stateForUpdate.ChangePalletPhase = 4; |
| | | } |
| | | // Phase 4: 放假电芯到5号位(使用 PositionIndex) |
| | | else if (stateForUpdate.ChangePalletPhase == 4) |
| | | { |
| | | int fakeCount = targetTotal - targetNormalCount; |
| | | int completedFake = Math.Max(0, currentCompletedCount - targetNormalCount); |
| | | int remainingFake = fakeCount - completedFake; |
| | | |
| | | if (remainingFake <= 0) |
| | | { |
| | | stateForUpdate.ChangePalletPhase = 0; |
| | | stateForUpdate.CurrentBatchIndex = 1; |
| | | stateForUpdate.IsInFakeBatteryMode = false; |
| | | _logger.LogInformation("HandlePutFinishedStateAsync:流向B完成,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // 流向A:从5号位取假电芯 |
| | | var positions = _taskProcessor.GetNextAvailableFakeBatteryPositions(Math.Min(4, remainingFake)); |
| | | if (positions.Count == 0) |
| | | { |
| | | _logger.LogError("HandlePutFinishedStateAsync:无可用假电芯点位,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | int start = positions.Min(); |
| | | int end = positions.Max(); |
| | | |
| | | await _taskProcessor.SendPutWithBatchAsync(task, stateForUpdate, "5", start, end); |
| | | |
| | | stateForUpdate.ChangePalletPhase = 3; |
| | | await _taskProcessor.SendSocketRobotFakeBatteryPickAsync(task, stateForUpdate, positions); |
| | | } |
| | | else |
| | | { |
| | | // 流向B:从源地址取假电芯 |
| | | int pickCount = Math.Min(4, remainingFake); |
| | | var (start, end) = _taskProcessor.BuildBatchRange(stateForUpdate.CurrentBatchIndex, pickCount); |
| | | await _taskProcessor.SendPickWithBatchAsync(task, stateForUpdate, task.RobotSourceAddress, start, end); |
| | | stateForUpdate.CurrentBatchIndex += pickCount; |
| | | } |
| | | |
| | | // 发完 Pick 后切换到 Phase=4,等 PickFinished 触发 HandlePickFinishedStateAsync 下发放货指令 |
| | | stateForUpdate.ChangePalletPhase = 4; |
| | | _stateManager.TryUpdateStateSafely(ipAddress, stateForUpdate); |
| | | return; |
| | | } |
| | | |
| | | // ==================== Phase 5: 完成入库(allputfinished / allpickfinished 触发)==================== |
| | | if (stateForUpdate.ChangePalletPhase == 5) |
| | | { |
| | | // Phase 5 由 allpickfinished/allputfinished 触发入库,本方法不再下发指令 |
| | | return; |
| | | } |
| | | } |
| | | else |