From b39af89e2eef90bfaed1454fc933d440685a352b Mon Sep 17 00:00:00 2001 From: lsymicc Date: Tue, 1 Jul 2025 17:41:59 +0800 Subject: [PATCH] =?UTF-8?q?AGV=E4=BB=BB=E5=8A=A1=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E8=AF=B7=E6=B1=82=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/ruoyi/common/TaskType.java | 24 ++++ .../device/agv/controller/AgvController.java | 91 +++++++++++++ .../agvCallback/AgvCallbackRequest.java | 126 ++++++++++++++++++ .../agvCallback/AgvCallbackResponse.java | 24 ++++ .../schedule/scheduleTask/Execution.java | 75 ++++++++--- .../schedule/scheduleTask/StatusUpdate.java | 1 - .../ruoyi/schedule/scheduleTask/Timer.java | 4 +- 7 files changed, 322 insertions(+), 23 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/common/TaskType.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/device/agv/controller/AgvController.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/device/agv/domain/agvCallback/AgvCallbackRequest.java create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/device/agv/domain/agvCallback/AgvCallbackResponse.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/common/TaskType.java b/ruoyi-admin/src/main/java/com/ruoyi/common/TaskType.java new file mode 100644 index 0000000..0569a3e --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/common/TaskType.java @@ -0,0 +1,24 @@ +package com.ruoyi.common; + +public class TaskType { + + /** + * 输送线入库(PTL出口) + */ + public static final String CONV_STOCKIN = "1"; + + /** + * 出库至输送线(PTL入口)---单个或组出库 + */ + public static final String CONV_STOCKOUT_SINGLE_GROUP = "21"; + + /** + * 出库至输送线(PTL入口)---顺序出 + */ + public static final String CONV_STOCKOUT_SEQUENCE = "22"; + + /** + * AGV点到点搬运 + */ + public static final String AGV_MOVE = "3"; +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/device/agv/controller/AgvController.java b/ruoyi-admin/src/main/java/com/ruoyi/device/agv/controller/AgvController.java new file mode 100644 index 0000000..33665c8 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/device/agv/controller/AgvController.java @@ -0,0 +1,91 @@ +package com.ruoyi.device.agv.controller; + +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson2.JSON; +import com.ruoyi.common.Constant; +import com.ruoyi.common.TaskStatusCode; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.device.DeviceCar.domain.DeviceCar; +import com.ruoyi.device.agv.domain.ResponseBase; +import com.ruoyi.device.agv.domain.agvCallback.AgvCallbackRequest; +import com.ruoyi.device.agv.domain.agvCallback.AgvCallbackResponse; +import com.ruoyi.device.agv.domain.genAgvSchedulingTask.GenAgvSchedulingTaskRequest; +import com.ruoyi.device.agv.domain.genAgvSchedulingTask.GenAgvSchedulingTaskResponse; +import com.ruoyi.device.api.domain.RequestLog; +import com.ruoyi.schedule.plc.domain.AgvRead; +import com.ruoyi.schedule.task.domain.WcsTask; +import com.ruoyi.schedule.task.mapper.WcsTaskMapper; +import com.ruoyi.schedule.task.service.IWcsTaskService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * Agv操作请求 + */ +@RestController +@RequestMapping("/agv/api") +@Slf4j +public class AgvController extends BaseController { + + + @Autowired + WcsTaskMapper wcsTaskMapper; + + @PostMapping("/agvCallback") + public AgvCallbackResponse agvCallback(@RequestBody AgvCallbackRequest request) { + + AgvCallbackResponse response = new AgvCallbackResponse(); + + response.setCode(0); + response.setMessage("success"); + response.setReqCode(request.getReqCode()); + + //请求字符串空校验 + if (request == null || + StringUtils.isBlank(request.getReqCode()) || + StringUtils.isBlank(request.getReqTime()) || + StringUtils.isBlank(request.getCurrentPositionCode()) || + StringUtils.isBlank(request.getMethod()) || + StringUtils.isBlank(request.getRobotCode()) || + StringUtils.isBlank(request.getTaskCode()) + ) { + response.setCode(1); + response.setMessage("failed"); + log.error("【设备执行任务回调接口异常】:{}", JSON.toJSONString(request)); + } + + //根据回调参数更新任务状态 + WcsTask task = wcsTaskMapper.selectWcsTaskByTaskId(request.getTaskCode()); + switch (request.getMethod()){ + case "start": + case "outbin": + task.setTaskStatus(TaskStatusCode.TASK_RUNNING); + log.info("【更新任务状态】任务号:{},任务执行中",task.getTaskId()); + break; + case "end": + task.setTaskStatus(TaskStatusCode.TASK_FINISH); + log.info("【更新任务状态】任务号:{},任务自动完成",task.getTaskId()); + break; + case "cancel": + task.setTaskStatus(TaskStatusCode.TASK_CANCEL); + log.info("【更新任务状态】任务号:{},任务已取消",task.getTaskId()); + break; + case "apply": + //task.setTaskStatus(TaskStatusCode.TASK_RUNNING); + break; + } + task.setDeviceId(request.getRobotCode()); + + wcsTaskMapper.updateWcsTask(task); + + return response; + } + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/device/agv/domain/agvCallback/AgvCallbackRequest.java b/ruoyi-admin/src/main/java/com/ruoyi/device/agv/domain/agvCallback/AgvCallbackRequest.java new file mode 100644 index 0000000..1512117 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/device/agv/domain/agvCallback/AgvCallbackRequest.java @@ -0,0 +1,126 @@ +package com.ruoyi.device.agv.domain.agvCallback; + +import lombok.Data; + +@Data +public class AgvCallbackRequest { + + /** + * 请求编号,每个请求都要一个唯一编号,同一个请求重复提交,使用同一编号 + */ + private String reqCode; + + /** + * 请求时间戳,格式: “yyyy-MM-dd HH:mm:ss” + */ + private String reqTime; + + /** + * 地码 X 坐标(mm):任务完成时有值 + */ + private Number cooX; + + /** + * 地码 Y 坐标(mm):任务完成时有值 + */ + private Number cooY; + + /** + * 当前位置编号 + * 任务开始:该位置为任务起点 + * 走出储位:该位置为任务起点 + * 任务单取消:该位置为工作位编号 + * 任务结束:该位置为任务终点 + * 取放申请:取放料箱的点 + */ + private String currentPositionCode; + + /** + * 自定义字段,不超过2000个字符 + */ + private String data; + + /** + * 地图编号 + */ + private String mapCode; + + /** + * 地码编号:任务完成时有值 + */ + private String mapDataCode; + + /** + * 仓位编号:叉车与CTU任务时有值 + */ + private String stgBinCode; + + /** + * 方法名, 可使用任务类型做为方法名 + * 默认使用方式: + * start : 任务开始 + * outbin : 走出储位 + * end : 任务结束 + * cancel : 任务单取消 + * apply:CTU料箱取放申请 + */ + private String method; + + /** + * 货架编号:背货架时有值 + */ + private String podCode; + + /** + * 方向:“180”,”0”,”90”,”-90” 分别对应地图的”左”,”右”,”上”,”下”:任务完成时有值 + */ + private String podDir; + + /** + * 物料编号 + */ + private String materialLot; + + /** + * AGV编号(同 agvCode ) + */ + private String robotCode; + + /** + * 当前任务单号 + */ + private String taskCode; + + /** + * 工作位,与RCS-2000端配置的位置名称一致。任务完成时有值,与生成任务单接口中的wbCode一致。 + */ + private String wbCode; + + /** + * 容器编号 + */ + private String ctnrCode; + + /** + * 容器类型 + */ + private String ctnrType; + + /** + * 巷道编号 + */ + private String roadWayCode; + + /** + * 巷道内顺序号 + * 巷道尾是0,到巷道头依次递增1 + */ + private String seq; + + /** + * 设备编号,如梳齿式工作站、输送线等,一般使用于CTU场景。 + * 系统根据仓位定位到关联的设备编号。 + */ + private String eqpCode; + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/device/agv/domain/agvCallback/AgvCallbackResponse.java b/ruoyi-admin/src/main/java/com/ruoyi/device/agv/domain/agvCallback/AgvCallbackResponse.java new file mode 100644 index 0000000..9e1cea3 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/device/agv/domain/agvCallback/AgvCallbackResponse.java @@ -0,0 +1,24 @@ +package com.ruoyi.device.agv.domain.agvCallback; + +import com.ruoyi.device.agv.domain.ResponseBase; +import lombok.Data; + +@Data +public class AgvCallbackResponse { + + /** + * 响应码 + */ + private Integer code; + + /** + * 响应信息 + */ + private String message; + + /** + * 请求编号 + */ + private String reqCode; + +} diff --git a/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/Execution.java b/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/Execution.java index 1b9e478..7cba7ba 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/Execution.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/Execution.java @@ -7,6 +7,7 @@ import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.Constant; import com.ruoyi.common.TaskStatusCode; +import com.ruoyi.common.TaskType; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.uuid.UUID; import com.ruoyi.device.agv.domain.ResponseBase; @@ -64,33 +65,67 @@ public class Execution { //无【待执行】任务 if (tasks.size() == 0) return; + //请求agv/ctu下发指令 + GenAgvSchedulingTaskRequest request = new GenAgvSchedulingTaskRequest(); + for (int i = 0; i < tasks.size(); i++) { - //请求agv/ctu下发指令 - GenAgvSchedulingTaskRequest request = new GenAgvSchedulingTaskRequest(); - request.setReqCode(UUID.randomUUID().toString().replace("-", "")); - - //入库类型 + //判断任务类型 switch (tasks.get(i).getTaskType()) { - case "1": - request.setTaskTyp("F12"); + case TaskType.CONV_STOCKIN: + //todo 是否要处理输送线取货工位有多个料箱的情况 + //todo 是否要处理输送线取货工位有多个料箱的情况 + + + request.setReqCode(UUID.randomUUID().toString().replace("-", "")); + + //设备执行任务内置任务类型初始化 + switch (tasks.get(i).getTaskType()) { + case "1": + request.setTaskTyp("F12"); + break; + case "2": + request.setTaskTyp("F11"); + break; + default: + log.warn("【向设备下发任务请求】TaskTyp:{},生成任务的请求参数错误,异常的任务类型!", request.getTaskTyp()); + return; + } + + //todo 了解CTU货架与工作台输送过程中是否需要另外下发取放料箱的任务 + //todo 了解CTU货架与工作台输送过程中是否需要另外下发取放料箱的任务 + + //添加路径(未测试) + //todo 了解AGV/CTU路径的格式/规则 + //todo 了解AGV/CTU路径的格式/规则 + List path = new ArrayList<>(); + path.add(new PositionCodeData(tasks.get(i).getSourceLocation(),"05")); + path.add(new PositionCodeData(tasks.get(i).getTargetLocation(),"05")); + request.setPositionCodePath(path); + + //wcs任务号---设备任务编号 + request.setTaskCode(tasks.get(i).getTaskId()); + + + //todo 上层平台是否有【校验料箱是否可入库】接口可用 + //todo 上层平台是否有【校验料箱是否可入库】接口可用 + + + //todo 是否需要单独请求取放料箱接口 + //todo 是否需要单独请求取放料箱接口 + break; - case "2": - request.setTaskTyp("F11"); + case TaskType.CONV_STOCKOUT_SINGLE_GROUP: + + break; + case TaskType.CONV_STOCKOUT_SEQUENCE: + + break; + case TaskType.AGV_MOVE: + break; - default: - log.warn("【向设备下发任务请求】TaskTyp:{},生成任务的请求参数错误,异常的任务类型!", request.getTaskTyp()); - return; } - //添加路径(未测试) - List path = new ArrayList<>(); - path.add(new PositionCodeData(tasks.get(i).getSourceLocation(),"05")); - path.add(new PositionCodeData(tasks.get(i).getTargetLocation(),"05")); - request.setPositionCodePath(path); - - //wcs任务号---设备任务编号 - request.setTaskCode(tasks.get(i).getTaskId()); //下发成功---更新【任务状态】为下发成功 if (sendCommand(request)){ diff --git a/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/StatusUpdate.java b/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/StatusUpdate.java index 1fb84a1..d2dfc45 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/StatusUpdate.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/StatusUpdate.java @@ -13,7 +13,6 @@ import com.ruoyi.schedule.task.domain.WcsTask; import com.ruoyi.schedule.task.mapper.WcsTaskMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.LocalDateTime; diff --git a/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/Timer.java b/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/Timer.java index 32c4218..e3a24c1 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/Timer.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/schedule/scheduleTask/Timer.java @@ -34,8 +34,8 @@ public class Timer { execution.executeTask(); Thread.sleep(200); - statusUpdate.statusUpdate(); - Thread.sleep(200); + //statusUpdate.statusUpdate(); + //Thread.sleep(200); taskFinish.taskFinish(); Thread.sleep(200);