| | |
| | | private readonly HttpClientHelper _httpClientHelper; |
| | | |
| | | /// <summary> |
| | | /// 假电芯平面点位服务 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 用于管理假电芯平面点位的分配和状态。 |
| | | /// </remarks> |
| | | private readonly IFakeBatteryPositionService _fakeBatteryPositionService; |
| | | |
| | | /// <summary> |
| | | /// 日志记录器 |
| | | /// </summary> |
| | | private readonly ILogger _logger; |
| | |
| | | IRobotTaskService robotTaskService, |
| | | ITaskService taskService, |
| | | HttpClientHelper httpClientHelper, |
| | | ILogger logger) |
| | | ILogger logger, |
| | | IFakeBatteryPositionService fakeBatteryPositionService) |
| | | { |
| | | _socketClientGateway = socketClientGateway; |
| | | _stateManager = stateManager; |
| | |
| | | _taskService = taskService; |
| | | _httpClientHelper = httpClientHelper; |
| | | _logger = logger; |
| | | _fakeBatteryPositionService = fakeBatteryPositionService; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 下发假电芯取货指令到机器人客户端 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 发送格式:Pickbattery,5,{startPosition}-{endPosition} |
| | | /// 例如:Pickbattery,5,1-3 表示从假电芯位置5抓取,平面点位1到3 |
| | | /// |
| | | /// 下发成功后: |
| | | /// 1. 标记点位为已使用 |
| | | /// 2. 更新任务状态为"机器人执行中" |
| | | /// 3. 安全更新状态到 Redis |
| | | /// </remarks> |
| | | /// <param name="task">要下发的任务对象</param> |
| | | /// <param name="state">机器人当前状态</param> |
| | | /// <param name="positions">要抓取的平面点位列表</param> |
| | | public async Task SendSocketRobotFakeBatteryPickAsync(Dt_RobotTask task, RobotSocketState state, List<int> positions) |
| | | { |
| | | if (positions == null || positions.Count == 0) |
| | | { |
| | | _logger.LogWarning("SendSocketRobotFakeBatteryPickAsync:平面点位列表为空,任务号: {TaskNum}", task.RobotTaskNum); |
| | | return; |
| | | } |
| | | |
| | | // 计算点位范围,格式:1-3 |
| | | int startPos = positions.Min(); |
| | | int endPos = positions.Max(); |
| | | string taskString = $"Pickbattery,5,{startPos}-{endPos}"; |
| | | |
| | | // 标记点位为已使用 |
| | | _fakeBatteryPositionService.MarkAsUsed(positions); |
| | | |
| | | // 通过 Socket 网关发送指令到机器人客户端 |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("下发假电芯取货指令成功,指令: {TaskString},点位: {Positions},设备: {DeviceName}", |
| | | taskString, string.Join(",", positions), state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"下发假电芯取货指令成功,指令: {taskString}", state.RobotCrane?.DeviceName); |
| | | |
| | | // 更新任务状态为"机器人执行中" |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | |
| | | // 将任务关联到状态对象 |
| | | state.CurrentTask = task; |
| | | |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogError("下发假电芯取货指令失败,指令: {TaskString},设备: {DeviceName}", taskString, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Error($"下发假电芯取货指令失败,指令: {taskString}", state.RobotCrane?.DeviceName); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取下N个可用的假电芯平面点位 |
| | | /// </summary> |
| | | /// <param name="count">需要获取的点位数量</param> |
| | | /// <returns>可用点位列表</returns> |
| | | public List<int> GetNextAvailableFakeBatteryPositions(int count) |
| | | { |
| | | return _fakeBatteryPositionService.GetNextAvailable(count); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 计算批次编号范围 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 返回格式:(start, end) |
| | | /// - remaining >= 4: (currentIndex, currentIndex + 3) |
| | | /// - remaining > 1: (currentIndex, currentIndex + remaining - 1) |
| | | /// - remaining == 1: (currentIndex, 0) -- 单个物品用 0 表示 end |
| | | /// </remarks> |
| | | /// <param name="currentIndex">当前批次起始编号</param> |
| | | /// <param name="remaining">剩余数量</param> |
| | | /// <returns>(start, end) 元组</returns> |
| | | public (int Start, int End) BuildBatchRange(int currentIndex, int remaining) |
| | | { |
| | | if (remaining >= 4) |
| | | return (currentIndex, currentIndex + 3); |
| | | else if (remaining > 1) |
| | | return (currentIndex, currentIndex + remaining - 1); |
| | | else // remaining == 1 |
| | | return (currentIndex, 0); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 下发取货指令(带批次格式和总数) |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 发送顺序: |
| | | /// 1. PickTotalNum,{N} -- 真实电芯总数 |
| | | /// 2. Pickbattery,{位置},{start}-{end} -- 批次取货指令 |
| | | /// |
| | | /// 下发成功后更新任务状态为"机器人执行中"。 |
| | | /// </remarks> |
| | | /// <param name="task">要下发的任务对象</param> |
| | | /// <param name="state">机器人当前状态</param> |
| | | /// <param name="position">取货位置</param> |
| | | /// <param name="batchStart">批次起始编号</param> |
| | | /// <param name="batchEnd">批次结束编号</param> |
| | | public async Task SendPickWithBatchAsync(Dt_RobotTask task, RobotSocketState state, string position, int batchStart, int batchEnd) |
| | | { |
| | | // 先发送总数指令 |
| | | string totalNumCmd = $"PickTotalNum,{task.RobotTaskTotalNum}"; |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, totalNumCmd); |
| | | |
| | | // 再发送批次取货指令 |
| | | string range = batchEnd == 0 ? $"{batchStart}-0" : $"{batchStart}-{batchEnd}"; |
| | | string taskString = $"Pickbattery,{position},{range}"; |
| | | |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("下发批次取货指令成功,指令: {TaskString},批次: {Range},设备: {DeviceName}", |
| | | taskString, range, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"下发批次取货指令成功,指令: {taskString},批次: {range}", state.RobotCrane?.DeviceName); |
| | | |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | state.CurrentTask = task; |
| | | |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogError("下发批次取货指令失败,指令: {TaskString},设备: {DeviceName}", taskString, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Error($"下发批次取货指令失败,指令: {taskString}", state.RobotCrane?.DeviceName); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 下发放货指令(带批次格式和总数) |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 发送顺序: |
| | | /// 1. PutTotalNum,{N} -- 真实电芯总数 |
| | | /// 2. Putbattery,{位置},{start}-{end} -- 批次放货指令 |
| | | /// |
| | | /// 下发成功后更新任务状态为"机器人执行中"。 |
| | | /// </remarks> |
| | | /// <param name="task">要下发的任务对象</param> |
| | | /// <param name="state">机器人当前状态</param> |
| | | /// <param name="position">放货位置</param> |
| | | /// <param name="batchStart">批次起始编号</param> |
| | | /// <param name="batchEnd">批次结束编号</param> |
| | | public async Task SendPutWithBatchAsync(Dt_RobotTask task, RobotSocketState state, string position, int batchStart, int batchEnd) |
| | | { |
| | | // 先发送总数指令 |
| | | string totalNumCmd = $"PutTotalNum,{task.RobotTaskTotalNum}"; |
| | | await _socketClientGateway.SendToClientAsync(state.IPAddress, totalNumCmd); |
| | | |
| | | // 再发送批次放货指令 |
| | | string range = batchEnd == 0 ? $"{batchStart}-0" : $"{batchStart}-{batchEnd}"; |
| | | string taskString = $"Putbattery,{position},{range}"; |
| | | |
| | | bool result = await _socketClientGateway.SendToClientAsync(state.IPAddress, taskString); |
| | | |
| | | if (result) |
| | | { |
| | | _logger.LogInformation("下发放货指令成功,指令: {TaskString},批次: {Range},设备: {DeviceName}", |
| | | taskString, range, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Info($"下发放货指令成功,指令: {taskString},批次: {range}", state.RobotCrane?.DeviceName); |
| | | |
| | | task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode(); |
| | | state.CurrentTask = task; |
| | | |
| | | if (_stateManager.TryUpdateStateSafely(state.IPAddress, state)) |
| | | { |
| | | await _robotTaskService.UpdateRobotTaskAsync(task); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | _logger.LogError("下发放货指令失败,指令: {TaskString},设备: {DeviceName}", |
| | | taskString, state.RobotCrane?.DeviceName); |
| | | QuartzLogger.Error($"下发放货指令失败,指令: {taskString}", state.RobotCrane?.DeviceName); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 处理入库任务回传(拆盘/组盘/换盘场景) |
| | | /// </summary> |
| | | /// <remarks> |