package com.mes.plcTaskThread;
|
|
import com.mes.common.S7objectMachine;
|
import com.mes.device.PlcParameterInfo;
|
import com.mes.device.PlcParameterObject;
|
import com.mes.md.entity.RotatingRack;
|
import com.mes.md.service.RotatingRackService;
|
import com.mes.utils.Result;
|
import com.mes.utils.ResultCodeEnum;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Component;
|
import org.springframework.util.StringUtils;
|
|
import java.util.*;
|
|
@Slf4j
|
@Component
|
public class PlcRotingRack extends Thread {
|
// 默认值
|
public static double defaultWidth = 40.0;
|
public static double defaultHeight = 40.0;
|
public static double defaultThickness = 10.0;
|
public static int defaultPcs = 10;
|
|
private RotatingRackService rotatingRackService;
|
private S7objectMachine s7objectMachine;
|
|
// 设备名称标识
|
private String deviceName;
|
|
// 变量定义
|
private Map<Integer, RotatingRack> currentTasks = new HashMap<>();
|
private Map<Integer, Long> currentTaskIds = new HashMap<>();
|
|
private List<PlcParameterObject> plcMesObjectList=new ArrayList<>();
|
|
// 查询输入参数
|
private PlcParameterInfo[] doInputs = new PlcParameterInfo[7];
|
private PlcParameterInfo[] skuInputs = new PlcParameterInfo[7];
|
|
// 新增查询返回参数
|
// private PlcParameterInfo[] doReturns = new PlcParameterInfo[7];
|
// private PlcParameterInfo[] skuReturns = new PlcParameterInfo[7];
|
|
// 查询结果参数
|
private Map<Integer, PlcParameterInfo[]> doInputResults = new HashMap<>();
|
private Map<Integer, PlcParameterInfo[]> skuInputResults = new HashMap<>();
|
|
// 料架参数
|
private PlcParameterInfo[] taskStatus = new PlcParameterInfo[6];
|
private PlcParameterInfo[] doCode = new PlcParameterInfo[6];
|
private PlcParameterInfo[] skuCode = new PlcParameterInfo[6];
|
private PlcParameterInfo[] width = new PlcParameterInfo[7];
|
private PlcParameterInfo[] height = new PlcParameterInfo[7];
|
private PlcParameterInfo[] thickness = new PlcParameterInfo[7];
|
private PlcParameterInfo[] targetPcs = new PlcParameterInfo[7];
|
private PlcParameterInfo[] completedPcs = new PlcParameterInfo[7];
|
private PlcParameterInfo electricUsage;
|
private PlcParameterInfo downTime;
|
private PlcParameterInfo operatorName;
|
|
private PlcParameterInfo[] plcRequestParams = new PlcParameterInfo[7];
|
private PlcParameterInfo[] mesConfirmParams = new PlcParameterInfo[7];
|
private boolean[] plcRequest = new boolean[7];
|
private boolean[] mesConfirm = new boolean[7];
|
|
// 添加连接状态变量
|
private boolean connected = false;
|
|
// ROBOT固定值
|
private static final String DEFAULT_ROBOT_NO = "robot";
|
|
public PlcRotingRack(RotatingRackService rotatingRackService) {
|
log.info("---------------");
|
this.rotatingRackService = rotatingRackService;
|
log.info("--------结束-------");
|
}
|
|
/**
|
* 设置设备名称
|
* @param deviceName 设备名称
|
*/
|
public void setDeviceName(String deviceName) {
|
this.deviceName = deviceName;
|
}
|
|
/**
|
* 设置S7objectMachine
|
* @param s7objectMachine S7objectMachine实例
|
*/
|
public void setS7objectMachine(S7objectMachine s7objectMachine) {
|
this.s7objectMachine = s7objectMachine;
|
}
|
|
/**
|
* 获取设备名称
|
* @return 设备名称
|
*/
|
public String getDeviceName() {
|
return deviceName;
|
}
|
|
public void plcStart() {
|
try {
|
// 初始化S7通信
|
if (s7objectMachine == null) {
|
log.error("未设置S7objectMachine,无法启动PLC通信");
|
return;
|
}
|
|
if (!s7objectMachine.isAlive()) {
|
s7objectMachine.start();
|
Thread.sleep(2000); // 给连接一些时间
|
}
|
|
// 检查实际连接状态
|
boolean actuallyConnected = false;
|
try {
|
if (s7objectMachine.plccontrol != null) {
|
actuallyConnected = s7objectMachine.plccontrol.checkConnected();
|
}
|
} catch (Exception e) {
|
log.error("检查PLC连接状态失败: {}", e.getMessage());
|
}
|
|
connected = actuallyConnected;
|
if (connected) {
|
log.info("{}机械手PLC连接已建立", deviceName);
|
} else {
|
log.error("{}机械手PLC连接失败", deviceName);
|
}
|
|
} catch (Exception e) {
|
connected = false;
|
log.error("{}机械手PLC通信异常: {}", deviceName, e.getMessage(), e);
|
}
|
}
|
|
// 初始化PLC参数
|
private void initParameters() {
|
plcMesObjectList=s7objectMachine.plcMesObjectList;
|
PlcParameterObject plcParameterObject = plcMesObjectList.get(0);
|
PlcParameterObject plcParameterObjectDB7 = plcMesObjectList.get(1);
|
PlcParameterObject plcParameterObjectDB4 = plcMesObjectList.get(2);
|
PlcParameterObject plcParameterObjectDB42 = plcMesObjectList.get(3);
|
|
for (int i = 1; i <= 6; i++) {
|
plcRequestParams[i] = plcParameterObjectDB4.getPlcParameter("plcRequest" + i);
|
mesConfirmParams[i] = plcParameterObjectDB42.getPlcParameter("mesConfirm" + i);
|
|
if(plcRequestParams[i].getValue() != null && mesConfirmParams[i].getValue() != null) {
|
plcRequest[i] = plcRequestParams[i].getValue().equals("0") ? false : true;
|
mesConfirm[i] = mesConfirmParams[i].getValue().equals("0") ? false : true;
|
}
|
}
|
// 初始化查询输入参数
|
for (int i = 1; i <= 6; i++) {
|
doInputs[i] = plcParameterObject.getPlcParameter("DO_input_" + i);
|
skuInputs[i] = plcParameterObject.getPlcParameter("SKU_input_" + i);
|
|
// 初始化查询结果数组
|
PlcParameterInfo[] doResults = new PlcParameterInfo[11]; // 0-10
|
PlcParameterInfo[] skuResults = new PlcParameterInfo[11]; // 0-10
|
|
for (int j = 1; j <= 10; j++) {
|
doResults[j] = plcParameterObject.getPlcParameter("DO" + i + "_select_" + j);
|
skuResults[j] = plcParameterObject.getPlcParameter("SKU" + i + "_select_" + j);
|
}
|
|
doInputResults.put(i, doResults);
|
skuInputResults.put(i, skuResults);
|
}
|
|
// 初始化新的查询返回参数
|
// for (int i = 1; i <= 6; i++) {
|
// doReturns[i] = plcParameterObject.getPlcParameter("DO_return_" + i);
|
// skuReturns[i] = plcParameterObject.getPlcParameter("SKU_return_" + i);
|
// }
|
|
// 初始化操作员姓名参数
|
this.operatorName = plcParameterObject.getPlcParameter("operatorName");
|
|
// 初始化料架参数
|
for (int i = 1; i <= 6; i++) {
|
taskStatus[i-1] = plcParameterObject.getPlcParameter("taskStatus" + i);
|
doCode[i-1] = plcParameterObject.getPlcParameter("doCode" + i);
|
skuCode[i-1] = plcParameterObject.getPlcParameter("skuCode" + i);
|
|
// 从DB7获取尺寸和数量参数
|
width[i] = plcParameterObjectDB7.getPlcParameter("width" + i);
|
height[i] = plcParameterObjectDB7.getPlcParameter("height" + i);
|
thickness[i] = plcParameterObjectDB7.getPlcParameter("thickness" + i);
|
targetPcs[i] = plcParameterObjectDB7.getPlcParameter("targetPcs" + i);
|
completedPcs[i] = plcParameterObjectDB7.getPlcParameter("completedPcs" + i);
|
|
try {
|
this.electricUsage = plcParameterObjectDB7.getPlcParameter("electricUsage");
|
this.downTime = plcParameterObjectDB7.getPlcParameter("downTime");
|
} catch (Exception e) {
|
log.warn("参数electricUsage或downTime不存在");
|
}
|
}
|
}
|
|
// 处理查询请求
|
private void processQueryRequests() {
|
try {
|
// 遍历6个任务位
|
for (int i = 1; i <= 6; i++) {
|
// 检查对应位置的plcRequest是否为1
|
if (plcRequest[i]) {
|
int rackNumber = i;
|
|
// 获取对应料架的DO和SKU输入值
|
String doValue = doInputs[i].getValue();
|
String skuValue = skuInputs[i].getValue();
|
|
boolean doProcessed = false;
|
boolean skuProcessed = false;
|
|
// 检查输入值长度
|
if ((StringUtils.hasText(doValue) && doValue.length() > 20) ||
|
(StringUtils.hasText(skuValue) && skuValue.length() > 20)) {
|
log.warn("料架{}的输入值长度超过20个字符,不符合要求。DO:{}, SKU:{}",
|
rackNumber, doValue, skuValue);
|
s7objectMachine.plccontrol.writeBit(mesConfirmParams[i].getBitAddress(), true);
|
continue;
|
}
|
|
// 处理DO查询
|
if (StringUtils.hasText(doValue)) {
|
if (processSearchRequest(rackNumber, doValue, true)) {
|
doProcessed = true;
|
log.info("处理料架{}的DO查询: {}", rackNumber, doValue);
|
}
|
}
|
|
// 处理SKU查询
|
if (StringUtils.hasText(skuValue)) {
|
if (processSearchRequest(rackNumber, skuValue, false)) {
|
skuProcessed = true;
|
log.info("处理料架{}的SKU查询: {}", rackNumber, skuValue);
|
}
|
}
|
|
// 如果所有需要的查询都处理完成,发送确认信号
|
boolean allProcessed = true;
|
if (StringUtils.hasText(doValue) && !doProcessed) allProcessed = false;
|
if (StringUtils.hasText(skuValue) && !skuProcessed) allProcessed = false;
|
|
if (allProcessed) {
|
s7objectMachine.plccontrol.writeBit(mesConfirmParams[i].getBitAddress(), true);
|
log.info("料架{}所有查询处理完成,发送确认信号", rackNumber);
|
}
|
}
|
}
|
} catch (Exception e) {
|
log.error("处理查询请求异常: {}", e.getMessage(), e);
|
}
|
}
|
|
// 处理单个查询请求
|
private boolean processSearchRequest(int rackNumber, String keyword, boolean isDOQuery) {
|
try {
|
log.info("接收到料架{}的{}查询请求,关键字:{}", rackNumber, isDOQuery ? "DO" : "SKU", keyword);
|
|
// 验证rackNumber的有效性
|
if (rackNumber < 1 || rackNumber > 6) {
|
log.error("无效的料架号: {}", rackNumber);
|
return false;
|
}
|
|
// 获取结果数组
|
PlcParameterInfo[] resultArray = isDOQuery ?
|
doInputResults.get(rackNumber) :
|
skuInputResults.get(rackNumber);
|
|
// 验证结果数组
|
if (resultArray == null) {
|
log.error("料架{}的{}结果数组未初始化", rackNumber, isDOQuery ? "DO" : "SKU");
|
return false;
|
}
|
|
// 调用查询服务
|
Result result = isDOQuery ?
|
rotatingRackService.searchDO(keyword) :
|
rotatingRackService.searchSKU(keyword);
|
|
// 验证查询结果
|
if (result == null || !ResultCodeEnum.SUCCESS.getCode().equals(result.getCode()) || result.getData() == null) {
|
log.warn("料架{}的{}查询未返回有效结果", rackNumber, isDOQuery ? "DO" : "SKU");
|
return false;
|
}
|
|
// 处理查询结果
|
try {
|
List<?> list = (List<?>) result.getData();
|
int count = Math.min(list.size(), 10); // 最多10条结果
|
|
// 写入新结果
|
for (int j = 0; j < count; j++) {
|
if (j + 1 >= resultArray.length) {
|
log.warn("结果数量超过数组大小,停止写入");
|
break;
|
}
|
|
Object item = list.get(j);
|
String value = "";
|
|
if (item instanceof Map) {
|
Map<String, Object> itemMap = (Map<String, Object>) item;
|
Object fieldValue = isDOQuery ?
|
itemMap.get("strCode") :
|
itemMap.get("SKU_Code");
|
|
if (fieldValue != null) {
|
value = fieldValue.toString();
|
}
|
}
|
|
if (resultArray[j + 1] != null && resultArray[j + 1].getAddress() != null) {
|
s7objectMachine.plccontrol.writeString(resultArray[j + 1].getAddress(), value);
|
log.debug("写入第{}个结果: {}", j + 1, value);
|
} else {
|
log.warn("结果数组索引{}的地址无效", j + 1);
|
}
|
}
|
|
log.info("为料架{}写入{}条{}结果", rackNumber, count, isDOQuery ? "DO" : "SKU");
|
return true;
|
} catch (Exception e) {
|
log.error("处理料架{}的查询结果时出错: {}", rackNumber, e.getMessage());
|
return false;
|
}
|
} catch (Exception e) {
|
log.error("处理料架{}的{}查询请求时发生异常: {}", rackNumber, isDOQuery ? "DO" : "SKU", e.getMessage());
|
return false;
|
}
|
}
|
|
// 处理任务开始
|
private void processTaskStart(int rackNumber, int index) {
|
// 判断是否已有任务在进行
|
if (currentTaskIds.get(rackNumber) != null) {
|
log.info("料架{}已有任务在进行,ID: {}", rackNumber, currentTaskIds.get(rackNumber));
|
return;
|
}
|
|
log.info("接收到料架{}任务开始指令", rackNumber);
|
|
RotatingRack newTask = new RotatingRack();
|
|
newTask.setRobotNo(StringUtils.hasText(deviceName) ? deviceName : DEFAULT_ROBOT_NO);
|
newTask.setRackName("任务" + rackNumber);
|
newTask.setDoCode(doInputs[rackNumber].getValue());
|
log.info("DO输入: {}", doInputs[rackNumber].getValue());
|
newTask.setSkuCode(skuInputs[rackNumber].getValue());
|
log.info("sku输入: {}", skuInputs[rackNumber].getValue());
|
newTask.setTaskStatus(1); // 进行中
|
newTask.setStartDate(new Date());
|
// 尺寸参数
|
try {
|
newTask.setWidth(Double.parseDouble(width[index].getValue()));
|
log.info("宽度: {}", width[index].getValue());
|
} catch (Exception e) {
|
newTask.setWidth(defaultWidth);
|
log.warn("无法读取料架{}的宽度,使用默认值: {}", rackNumber, defaultWidth);
|
}
|
|
try {
|
newTask.setHeight(Double.parseDouble(height[index].getValue()));
|
log.info("高度: {}", height[index].getValue());
|
} catch (Exception e) {
|
newTask.setHeight(defaultHeight);
|
log.warn("无法读取料架{}的高度,使用默认值: {}", rackNumber, defaultHeight);
|
}
|
|
try {
|
newTask.setThickness(Double.parseDouble(thickness[index].getValue()));
|
log.info("厚度: {}", thickness[index].getValue());
|
} catch (Exception e) {
|
newTask.setThickness(defaultThickness);
|
log.warn("无法读取料架{}的厚度,使用默认值: {}", rackNumber, defaultThickness);
|
}
|
|
// 目标数量
|
try {
|
newTask.setTargetPcs(Integer.parseInt(targetPcs[index].getValue()));
|
log.info("目标数量: {}", targetPcs[index].getValue());
|
} catch (Exception e) {
|
newTask.setTargetPcs(defaultPcs);
|
log.warn("无法读取料架{}的目标数量,使用默认值: {}", rackNumber, defaultPcs);
|
}
|
|
// 操作员信息
|
try {
|
newTask.setOperatorName(operatorName.getValue());
|
log.info("操作员信息: {}", operatorName.getValue());
|
} catch (Exception e) {
|
log.error("无法读取料架{}的操作员信息: {}", rackNumber, e.getMessage());
|
}
|
|
// 保存任务
|
Long taskId = (long) rackNumber; // 使用料架号作为任务ID
|
newTask.setId(taskId);
|
currentTaskIds.put(rackNumber, taskId);
|
currentTasks.put(rackNumber, newTask);
|
log.info("成功创建料架{}任务,ID: {}", rackNumber, taskId);
|
}
|
|
// 处理任务完成
|
private void processTaskComplete(int rackNumber, int index) {
|
log.info("料架{}任务完成指令,任务ID: {}", rackNumber, currentTaskIds.get(rackNumber));
|
|
RotatingRack task = currentTasks.get(rackNumber);
|
|
// 设置结束时间
|
task.setEndDate(new Date());
|
|
// 完成数量
|
try {
|
task.setCompletedPcs(Integer.parseInt(completedPcs[index].getValue()));
|
log.info("完成数量: {}", completedPcs[index].getValue());
|
} catch (Exception e) {
|
log.error("无法读取料架{}的完成数量: {}", rackNumber, e.getMessage());
|
}
|
|
// 记录停机时间
|
if (downTime != null) {
|
try {
|
task.setDownTime((int)Double.parseDouble(downTime.getValue()));
|
} catch (Exception e) {
|
task.setDownTime(0);
|
}
|
}
|
|
// 保存任务完成数据
|
boolean success = rotatingRackService.completeTask(task);
|
|
if (success) {
|
log.info("成功完成料架{}任务,ID: {}", rackNumber, currentTaskIds.get(rackNumber));
|
// 重置当前任务
|
currentTaskIds.remove(rackNumber);
|
currentTasks.remove(rackNumber);
|
} else {
|
log.error("更新料架{}任务失败,ID: {}", rackNumber, currentTaskIds.get(rackNumber));
|
}
|
|
// 发送确认
|
//s7objectMachine.plccontrol.writeWord(mesConfirm.getAddress(), 1);
|
}
|
|
// 处理多个任务状态
|
private void processTaskStatuses() {
|
try {
|
// 循环处理6个料架
|
for (int i = 0; i < 6; i++) {
|
int rackNumber = i + 1;
|
try {
|
String taskStatusValue = taskStatus[i].getValue();
|
|
// 任务开始 (状态为1)
|
if ("1".equals(taskStatusValue)) {
|
// 如果是新任务,则处理开始
|
if (currentTaskIds.get(rackNumber) == null) {
|
log.info("料架{}开始新任务", rackNumber);
|
processTaskStart(rackNumber, i+1);
|
}
|
}
|
// 任务完成 (状态为2)
|
else if ("2".equals(taskStatusValue) && currentTaskIds.get(rackNumber) != null) {
|
log.info("料架{}完成任务", rackNumber);
|
processTaskComplete(rackNumber, i+1);
|
// 完成后清除当前任务ID
|
currentTaskIds.remove(rackNumber);
|
currentTasks.remove(rackNumber);
|
}
|
|
} catch (Exception e) {
|
log.error("处理料架{}状态异常: {}", rackNumber, e.getMessage());
|
}
|
}
|
} catch (Exception e) {
|
log.error("处理任务状态异常: {}", e.getMessage(), e);
|
}
|
}
|
|
@Override
|
public void run() {
|
plcStart();
|
String threadName = StringUtils.hasText(deviceName) ? deviceName : "未命名设备";
|
setName(threadName); // 设置线程名称
|
|
while (!Thread.currentThread().isInterrupted()) {
|
try {
|
Thread.sleep(1000); // 每秒读取一次状态
|
|
// 检查连接状态
|
if (!connected) {
|
log.warn("{}PLC连接已断开,尝试重新连接...", threadName);
|
plcStart();
|
continue;
|
}
|
initParameters();
|
//List<Boolean> booleanList = s7objectMachine.plccontrol.readBits(plcRequest.getBitAddress(), 2);
|
//log.info("{}设备: {},{}", threadName, this.plcRequest, this.mesConfirm);
|
// 处理查询请求
|
processQueryRequests();
|
|
// 重置确认信号
|
for (int i = 1; i <= 6; i++) {
|
//log.info("{}设备:{} {},{}",i,threadName, this.plcRequest[i], this.mesConfirm[i]);
|
if(!plcRequest[i]) {
|
s7objectMachine.plccontrol.writeBit(mesConfirmParams[i].getBitAddress(), false);
|
}
|
}
|
|
// 处理任务状态
|
processTaskStatuses();
|
|
} catch (InterruptedException e) {
|
connected = false;
|
log.error("{}机械手PLC线程中断,退出运行", threadName);
|
Thread.currentThread().interrupt(); // 恢复中断状态
|
break;
|
} catch (Exception e) {
|
log.error("{}机械手PLC通信异常: {}", threadName, e.getMessage(), e);
|
connected = false;
|
try {
|
Thread.sleep(5000); // 发生异常时等待5秒后重试
|
} catch (InterruptedException ie) {
|
Thread.currentThread().interrupt();
|
break;
|
}
|
}
|
}
|
|
log.info("{}机械手PLC线程已结束", threadName);
|
}
|
}
|