wanshenmean
2026-02-28 c3de7bb2097aa347a1f92c2f640d18753aff633a
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/RobotJob/RobotJob.cs
@@ -5,6 +5,7 @@
using System.Net.Sockets;
using System.Text.Json;
using WIDESEAWCS_Common.HttpEnum;
using WIDESEAWCS_Common.TaskEnum;
using WIDESEAWCS_Core;
using WIDESEAWCS_Core.Helper;
using WIDESEAWCS_Core.Http;
@@ -22,18 +23,26 @@
    [DisallowConcurrentExecution]
    public class RobotJob : IJob
    {
        private const int MaxTaskTotalNum = 48;
        private readonly TcpSocketServer _TcpSocket;
        private static readonly ConcurrentDictionary<string, RobotSocketState> _socketStates = new();
        private static int _eventSubscribedFlag;
        private readonly IRobotTaskService _taskService;
        private readonly ITaskExecuteDetailService _taskExecuteDetailService;
        private readonly ITaskRepository _taskRepository;
        private readonly IRouterService _routerService;
        public RobotJob(TcpSocketServer TcpSocket, IRobotTaskService taskService)
        private readonly ITaskService _taskService;
        private readonly IRobotTaskService _robotTaskService;
        private static IRobotTaskService _latestRobotTaskService = null!;
        private static ITaskService _latestTaskService = null!;
        public RobotJob(TcpSocketServer TcpSocket, IRobotTaskService RobottaskService, ITaskService TaskService)
        {
            _TcpSocket = TcpSocket;
            _taskService = taskService;
            _robotTaskService = RobottaskService;
            _taskService = TaskService;
            _latestRobotTaskService = RobottaskService;
            _latestTaskService = TaskService;
        }
        public async Task Execute(IJobExecutionContext context)
@@ -73,40 +82,91 @@
            if (!state.IsEventSubscribed)
            {
                _TcpSocket._clients.TryGetValue(ipAddress, out TcpClient client);
                Task clientTask = _TcpSocket.HandleClientAsync(client, robotCrane.IPAddress, _TcpSocket._cts.Token, state);
                state.IsEventSubscribed = true;
                if (_TcpSocket._clients.TryGetValue(ipAddress, out TcpClient client))
                {
                    _ = _TcpSocket.HandleClientAsync(client, robotCrane.IPAddress, _TcpSocket._cts.Token, state)
                        .ContinueWith(t =>
                        {
                            if (t.IsFaulted)
                                Console.WriteLine($"HandleClientAsync error: {t.Exception?.GetBaseException().Message}");
                        }, TaskContinuationOptions.OnlyOnFaulted);
                    state.IsEventSubscribed = true;
                }
            }
            // 获取任务并缓存到状态中
            Dt_RobotTask? task = GetTask(robotCrane);
            if (task != null)
            {
                state.IsSplitPallet = task.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode();
                state.IsGroupPallet = task.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() || task.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode();
                state.CurrentTask = task;
                if (task.RobotTaskTotalNum != 48)
                if (task.RobotTaskTotalNum <= MaxTaskTotalNum)
                {
                    // 处理正在执行的任务
                    if (state.RobotRunMode == 1 && state.RobotControlMode == 1)
                    if (state.RobotRunMode == 2 && state.RobotControlMode == 1 && state.OperStatus != "Running")
                    {
                        await Task.Delay(1000);
                        if ((state.CurrentAction == "Homed" || state.CurrentAction == "PickFinished" || state.CurrentAction == "PutFinished") && state.OperStatus == "Running")
                        if (state.CurrentAction == "PickFinished" && state.RobotArmObject == 1 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
                        {
                            string taskString = $"Putbattery,{task.RobotTargetAddress}";
                            bool result = await _TcpSocket.SendToClientAsync(ipAddress, taskString);
                            if (result)
                            {
                                task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
                                await _robotTaskService.UpdateRobotTaskAsync(task);
                            }
                        }
                        else if (state.CurrentAction == "PutFinished" && state.RobotArmObject == 0 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
                        {
                            task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
                            await _robotTaskService.UpdateRobotTaskAsync(task);
                        }
                        else if (state.OperStatus == "Homed" && state.RobotArmObject == 0 && task.RobotTaskState != TaskRobotStatusEnum.RobotExecuting.GetHashCode())
                        {
                            // TODO 读取线体电池条码,发送取电池指令
                            if (true)
                            {
                                // 模拟读取条码
                                state.CellBarcode = new string[] { "CellBarcode1", "CellBarcode2", "CellBarcode3", "CellBarcode4" };
                            // 随机生成两天托盘条码存放到两个变量里面
                            // 定义前缀(例如:TRAY代表托盘)
                            string prefix = "TRAY";
                            // 生成两个托盘条码
                            string trayBarcode1 = GenerateTrayBarcode(state, prefix);
                            string trayBarcode2 = GenerateTrayBarcode(state, prefix);
                            if (!trayBarcode1.IsNullOrEmpty() && !trayBarcode2.IsNullOrEmpty())
                            {
                                string taskString = $"Pickbattery,{task.RobotSourceAddress}";
                                // 发送任务指令
                                bool result = await _TcpSocket.SendToClientAsync(ipAddress, taskString);
                                if (result)
                                {
                                    // TODO 处理成功发送任务指令后的逻辑
                                    task.RobotTaskState = TaskRobotStatusEnum.RobotExecuting.GetHashCode();
                                    result = await _robotTaskService.UpdateRobotTaskAsync(task);
                                }
                            }
                        }
                    }
                }
            }
        }
            return;
        //临时测试用
        private static string GenerateTrayBarcode(RobotSocketState state, string prefix = "")
        {
            // 当前日期
            string datePart = DateTime.Now.ToString("yyyyMMdd");
            // 时间戳(时分秒)
            string timePart = DateTime.Now.ToString("HHmmss");
            // 随机数
            string randomPart = Random.Shared.Next(100, 1000).ToString();
            // 组合:前缀 + 日期 + 时间 + 随机数
            var barCode = prefix + datePart + timePart + randomPart;
            state.CellBarcode.Add(randomPart);
            return barCode;
        }
        /// <summary>
@@ -130,11 +190,11 @@
        /// <returns></returns>
        private async Task<string?> _TcpSocket_MessageReceived(string message, bool isJson, TcpClient client, RobotSocketState state)
        {
            WebResponseContent content = new WebResponseContent();
            string messageLower = message.ToLowerInvariant();
            if (IsSimpleCommand(messageLower, state))
            if (await IsSimpleCommandAsync(messageLower, state))
            {
                await _TcpSocket.SendMessageAsync(client, message);
                return null;
            }
@@ -143,79 +203,70 @@
                try
                {
                    var parts = message.Split(',');
                    if (parts.Length >= 1)
                    if (parts.Length >= 1 && state.CurrentTask != null)
                    {
                        var cmd = parts[0].ToLowerInvariant();
                        int[] positions = new int[4];
                        for (int i = 1; i <= 4 && i < parts.Length; i++)
                        {
                            int.TryParse(parts[i], out positions[i - 1]);
                        }
                        int[] positions = parts.Skip(1)
                           .Select(p => int.TryParse(p, out int value) ? value : (int?)null)
                           .Where(v => v.HasValue && v.Value != 0)
                           .Select(v => v!.Value)
                           .ToArray();
                        var task = await _latestRobotTaskService.Repository.QueryFirstAsync(x => x.RobotTaskId == state.CurrentTask.RobotTaskId);
                        if (cmd.StartsWith("pickfinished"))
                        {
                            StockDTO stockDTO = new StockDTO
                            if (state.IsSplitPallet)
                            {
                                SourceLineNo = state.CurrentTask?.RobotSourceAddressLineCode,
                                SourcePalletNo = state.CurrentTask?.RobotSourceAddressPalletCode,
                                TargetPalletNo = state.CurrentTask?.RobotTargetAddressPalletCode,
                                TargetLineNo = state.CurrentTask?.RobotTargetAddressLineCode,
                                Details = positions
                                        .Where(x => x > 0)
                                        .OrderBy(x => x)
                                        .Select((x, idx) => new StockDetailDTO
                                        {
                                            Quantity = state.CurrentTask?.RobotTaskTotalNum ?? 1,
                                            Channel = x > 0 ? x : throw new ArgumentOutOfRangeException(nameof(x), "Channel must be positive"),
                                            CellBarcode = state.CellBarcode[idx]
                                        })
                                        .ToList()
                            };
                            state.LastPickPositions = positions;
                                var stockDTO = BuildStockDTO(state, positions);
                                state.LastPickPositions = positions;
                            var result = await HttpRequestHelper.HTTPPostAsync(nameof(Category.WMS), stockDTO.ToJsonString(), state.CurrentTask?.RobotTaskType == 2 ? nameof(ConfigKey.ChangePalletAsync) : nameof(ConfigKey.SplitPalletAsync));
                            content = JsonConvert.DeserializeObject<WebResponseContent>(result);
                                var result = await HttpRequestHelper.HTTPPostAsync(nameof(Category.WMS), stockDTO.ToJsonString(), nameof(ConfigKey.SplitPalletAsync));
                            if (content.Status)
                                if (result.Status)
                                {
                                    state.CurrentAction = "PickFinished";
                                }
                            }
                            else
                            {
                                state.CurrentAction = "PickFinished";
                            }
                            task.RobotTaskState = TaskRobotStatusEnum.RobotPickFinish.GetHashCode();
                            await _latestRobotTaskService.Repository.UpdateDataAsync(task);
                        }
                        else if (cmd.StartsWith("putfinished"))
                        {
                            state.LastPutPositions = positions;
                            if (state.CurrentTask?.RobotTaskType == 1)
                            bool putSuccess = true;
                            if (state.IsGroupPallet)
                            {
                                // 发送数据给WMS组盘/换盘
                                StockDTO stockDTO = new StockDTO
                                {
                                    SourceLineNo = state.CurrentTask?.RobotSourceAddressLineCode,
                                    SourcePalletNo = state.CurrentTask?.RobotSourceAddressPalletCode,
                                    TargetPalletNo = state.CurrentTask?.RobotTargetAddressPalletCode,
                                    TargetLineNo = state.CurrentTask?.RobotTargetAddressLineCode,
                                    Details = positions
                                        .Where(x => x > 0)
                                        .OrderBy(x => x)
                                        .Select((x, idx) => new StockDetailDTO
                                        {
                                            Quantity = state.CurrentTask?.RobotTaskTotalNum ?? 1,
                                            Channel = x > 0 ? x : throw new ArgumentOutOfRangeException(nameof(x), "Channel must be positive"),
                                            CellBarcode = state.CellBarcode[idx]
                                        })
                                        .ToList()
                                };
                                var result = await HttpRequestHelper.HTTPPostAsync(nameof(Category.WMS), stockDTO.ToJsonString(), nameof(ConfigKey.GroupPalletAsync));
                                content = JsonConvert.DeserializeObject<WebResponseContent>(result);
                                if (content.Status)
                                {
                                    state.CurrentAction = "PutFinished";
                                }
                                state.LastPutPositions = positions;
                                var stockDTO = BuildStockDTO(state, positions);
                                var configKey = state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode()
                                    ? nameof(ConfigKey.ChangePalletAsync) : nameof(ConfigKey.GroupPalletAsync);
                                var result = await HttpRequestHelper.HTTPPostAsync(nameof(Category.WMS), stockDTO.ToJsonString(), configKey);
                                putSuccess = result.Status;
                            }
                            if (putSuccess)
                            {
                                state.CurrentAction = "PutFinished";
                                state.RobotTaskTotalNum += positions.Length;
                                task.RobotTaskTotalNum += positions.Length;
                            }
                            task.RobotTaskState = TaskRobotStatusEnum.RobotPutFinish.GetHashCode();
                            await _latestRobotTaskService.Repository.UpdateDataAsync(task);
                        }
                    }
                }
                catch { }
                catch (Exception ex)
                {
                    Console.WriteLine($"RobotJob MessageReceived Error: {ex.Message}");
                }
                await _TcpSocket.SendMessageAsync(client, message);
                return null;
            }
@@ -229,16 +280,16 @@
        /// <param name="message"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private bool IsSimpleCommand(string message, RobotSocketState state)
        private static async Task<bool> IsSimpleCommandAsync(string message, RobotSocketState state)
        {
            switch (message)
            {
                case "homing":
                    state.CurrentAction = "Homing";
                    state.OperStatus = "Homing";
                    return true;
                case "homed":
                    state.CurrentAction = "Homed";
                    state.OperStatus = "Homed";
                    return true;
                case "picking":
@@ -249,29 +300,19 @@
                    state.CurrentAction = "Putting";
                    return true;
                case "allpickfinished":
                case "allpickfinished": // 取货完成
                    state.CurrentAction = "AllPickFinished";
                    if (state.CurrentTask?.RobotTaskType == 2 || state.CurrentTask?.RobotTaskType == 3)
                    if (state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.SplitPallet.GetHashCode() || state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())
                    {
                        // TODO 机械手取货完成,判断是否换盘、拆盘任务,创建空托盘回库任务
                        await HandleInboundTaskAsync(state, useSourceAddress: true);
                    }
                    return true;
                case "allputfinished":
                case "allputfinished": // 放货完成
                    state.CurrentAction = "AllPutFinished";
                    if (state.CurrentTask?.RobotTaskType == 1)
                    if (state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.GroupPallet.GetHashCode() || state.CurrentTask?.RobotTaskType == RobotTaskTypeEnum.ChangePallet.GetHashCode())
                    {
                        // TODO 机械手取货完成,判断是否组盘任务,创建组盘入库任务
                        CreateTaskDto taskDto = new CreateTaskDto()
                        {
                            PalletCode = state.CurrentTask?.RobotTargetAddressPalletCode ?? string.Empty,
                            SourceAddress = state.CurrentTask?.RobotTargetAddress ?? string.Empty,
                            TargetAddress = state.CurrentTask?.RobotTargetAddress ?? string.Empty,
                            Roadway = state.CurrentTask?.RobotRoadway == "1" ? "GWSC001" : state.CurrentTask?.RobotRoadway == "2" ? "HCSC001" : "SC001" ?? string.Empty,
                            WarehouseId = state.CurrentTask?.RobotRoadway == "1" ? 1 : state.CurrentTask?.RobotRoadway == "2" ? 2 : 3,
                            PalletType = 1,
                            TaskType = 4
                        };
                        await HandleInboundTaskAsync(state, useSourceAddress: false);
                    }
                    return true;
@@ -320,6 +361,49 @@
            }
        }
        private static async Task HandleInboundTaskAsync(RobotSocketState state, bool useSourceAddress)
        {
            var currentTask = state.CurrentTask;
            if (currentTask == null)
            {
                return;
            }
            string roadway = currentTask.RobotRoadway == "1" ? "GWSC001" : currentTask.RobotRoadway == "2" ? "HCSC001" : "SC001";
            int warehouseId = currentTask.RobotRoadway == "1" ? 1 : currentTask.RobotRoadway == "2" ? 2 : 3;
            CreateTaskDto taskDto = new CreateTaskDto
            {
                PalletCode = currentTask.RobotTargetAddressPalletCode ?? string.Empty,
                SourceAddress = currentTask.RobotSourceAddress ?? string.Empty,
                TargetAddress = currentTask.RobotTargetAddress ?? string.Empty,
                Roadway = roadway,
                WarehouseId = warehouseId,
                PalletType = 1,
                TaskType = 4
            };
            var result = await HttpRequestHelper.HTTPPostAsync(nameof(Category.WMS), taskDto.ToJsonString(), nameof(ConfigKey.CreateTaskInboundAsync));
            if (!result.Status)
            {
                return;
            }
            WMSTaskDTO taskDTO = JsonConvert.DeserializeObject<WMSTaskDTO>(result.Data.ToString() ?? string.Empty) ?? new WMSTaskDTO();
            var content = _latestTaskService.ReceiveWMSTask(new List<WMSTaskDTO> { taskDTO });
            if (!content.Status) return;
            var taskInfo = _latestTaskService.QueryByTaskNum(taskDTO.TaskNum);
            if (taskInfo == null) return;
            string targetAddress = useSourceAddress ? taskDTO.SourceAddress : taskDTO.TargetAddress;
            IDevice? device = Storage.Devices.FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == targetAddress));
            device?.Communicator.Write(nameof(ConveyorLineDBNameNew.Target), taskInfo.NextAddress);
            device?.Communicator.Write(nameof(ConveyorLineDBNameNew.TaskNo), taskDTO.TaskNum);
            device?.Communicator.Write(nameof(ConveyorLineDBNameNew.WCS_STB), 1);
        }
        /// <summary>
        /// 机械手前缀命令处理
        /// </summary>
@@ -330,9 +414,30 @@
            return message.StartsWith("pickfinished") || message.StartsWith("putfinished");
        }
        private static StockDTO BuildStockDTO(RobotSocketState state, int[] positions)
        {
            return new StockDTO
            {
                SourceLineNo = state.CurrentTask?.RobotSourceAddressLineCode,
                SourcePalletNo = state.CurrentTask?.RobotSourceAddressPalletCode,
                TargetPalletNo = state.CurrentTask?.RobotTargetAddressPalletCode,
                TargetLineNo = state.CurrentTask?.RobotTargetAddressLineCode,
                Details = positions
                    .Where(x => x > 0)
                    .OrderBy(x => x)
                    .Select((x, idx) => new StockDetailDTO
                    {
                        Quantity = state.CurrentTask?.RobotTaskTotalNum ?? 1,
                        Channel = x,
                        CellBarcode = !state.CellBarcode.IsNullOrEmpty() ? state.CellBarcode[idx] : ""
                    })
                    .ToList()
            };
        }
        private Dt_RobotTask? GetTask(RobotCraneDevice robotCrane)
        {
            return _taskService.QueryRobotCraneTask(robotCrane.DeviceCode);
            return _robotTaskService.QueryRobotCraneTask(robotCrane.DeviceCode);
        }
    }
@@ -356,7 +461,7 @@
        public int? RobotControlMode { get; set; }
        /// <summary>
        /// 机械手抓取对象
        /// 机械手是否抓取物料,0-无物料,1-有物料
        /// </summary>
        public int? RobotArmObject { get; set; }
@@ -388,11 +493,26 @@
        /// <summary>
        /// 抓取位置条码
        /// </summary>
        public string[] CellBarcode { get; set; }
        public List<string> CellBarcode { get; set; } = new();
        /// <summary>
        /// 当前抓取任务
        /// </summary>
        public Dt_RobotTask? CurrentTask { get; set; }
        /// <summary>
        /// 是否需要拆盘
        /// </summary>
        public bool IsSplitPallet { get; set; }
        /// <summary>
        /// 是否需要组盘
        /// </summary>
        public bool IsGroupPallet { get; set; }
        /// <summary>
        /// 任务总数
        /// </summary>
        public int RobotTaskTotalNum { get; set; }
    }
}