AGV任务执行通知请求接口

This commit is contained in:
lsymicc
2025-07-01 17:41:59 +08:00
parent f3a7bf26d1
commit b39af89e2e
7 changed files with 322 additions and 23 deletions

View File

@@ -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";
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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,13 +65,21 @@ public class Execution {
//无【待执行】任务
if (tasks.size() == 0) return;
for (int i = 0; i < tasks.size(); i++) {
//请求agv/ctu下发指令
GenAgvSchedulingTaskRequest request = new GenAgvSchedulingTaskRequest();
for (int i = 0; i < tasks.size(); i++) {
//判断任务类型
switch (tasks.get(i).getTaskType()) {
case TaskType.CONV_STOCKIN:
//todo 是否要处理输送线取货工位有多个料箱的情况
//todo 是否要处理输送线取货工位有多个料箱的情况
request.setReqCode(UUID.randomUUID().toString().replace("-", ""));
//入库类型
//设备执行任务内置任务类型初始化
switch (tasks.get(i).getTaskType()) {
case "1":
request.setTaskTyp("F12");
@@ -83,7 +92,12 @@ public class Execution {
return;
}
//todo 了解CTU货架与工作台输送过程中是否需要另外下发取放料箱的任务
//todo 了解CTU货架与工作台输送过程中是否需要另外下发取放料箱的任务
//添加路径(未测试)
//todo 了解AGV/CTU路径的格式/规则
//todo 了解AGV/CTU路径的格式/规则
List<PositionCodeData> path = new ArrayList<>();
path.add(new PositionCodeData(tasks.get(i).getSourceLocation(),"05"));
path.add(new PositionCodeData(tasks.get(i).getTargetLocation(),"05"));
@@ -92,6 +106,27 @@ public class Execution {
//wcs任务号---设备任务编号
request.setTaskCode(tasks.get(i).getTaskId());
//todo 上层平台是否有【校验料箱是否可入库】接口可用
//todo 上层平台是否有【校验料箱是否可入库】接口可用
//todo 是否需要单独请求取放料箱接口
//todo 是否需要单独请求取放料箱接口
break;
case TaskType.CONV_STOCKOUT_SINGLE_GROUP:
break;
case TaskType.CONV_STOCKOUT_SEQUENCE:
break;
case TaskType.AGV_MOVE:
break;
}
//下发成功---更新【任务状态】为下发成功
if (sendCommand(request)){
tasks.get(i).setTaskStatus(TaskStatusCode.TASK_SEND_SUCCESS);

View File

@@ -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;

View File

@@ -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);