| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- package com.jeesite.modules.scheduling;
- import com.github.xingshuangs.iot.protocol.common.buff.EByteBuffFormat;
- import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
- import com.jeesite.common.config.Global;
- import com.jeesite.common.lang.ObjectUtils;
- import com.jeesite.common.lang.StringUtils;
- import com.jeesite.modules.mes.entity.MesLine;
- import com.jeesite.modules.mes.entity.MesProduct;
- import com.jeesite.modules.mes.entity.MesProductFsw;
- import com.jeesite.modules.mes.resp.BindMaterialResp;
- import com.jeesite.modules.mes.resp.ParamsResp;
- import com.jeesite.modules.mes.service.MesLineService;
- import com.jeesite.modules.mes.service.MesProductFswService;
- import com.jeesite.modules.mes.service.MesProductRecordService;
- import com.jeesite.modules.mes.service.MesProductService;
- import com.jeesite.modules.mes.web.MesProductRecordController;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.scheduling.annotation.EnableScheduling;
- import org.springframework.scheduling.annotation.Scheduled;
- import java.nio.charset.StandardCharsets;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.concurrent.atomic.AtomicBoolean;
- /**
- * FSW 设备 Modbus TCP 握手与过程参数采集。
- * <pre>
- * 寄存器约定:
- * 4740 总使能(1=执行整套逻辑,其它值跳过)
- * 3600 数据采集触发(1=请求采集,MES读完后置0)
- * 3610 质量校验结果(1=合格,2=不合格)
- * 3620~3649 工件码(30个字,ASCII拼接)
- * 3740 进给速度 → feedSpeed
- * 3780 进给倍率 → feedRate
- * 3820 主轴转速 → spindleSpeed
- * 3860 主轴倍率 → spindleRate
- * 4040 指定焊接点压力 → pressure
- * 4590 指定焊接点偏移量 → pyl
- * 4742 B轴角度 → jd
- *
- * 配置(application.yml):
- * mes.fsw.modbus.enabled 是否启用(默认 false)
- * mes.fsw.modbus.host PLC IP
- * mes.fsw.modbus.port 端口,默认 502
- * mes.fsw.modbus.unitId 从站号,默认 1
- * mes.fsw.modbus.oprno 工位号
- * mes.fsw.modbus.lineSn 产线编号(可空,空则按工件类型自动解析)
- * </pre>
- */
- @Configuration
- @EnableScheduling
- public class FswModbusScheduling {
- private static final Logger logger = LoggerFactory.getLogger(FswModbusScheduling.class);
- /** 总开关:为 1 时才执行质量校验与过程采集 */
- private static final int ADDR_ENABLE_FLAG = 4740;
- private static final int ADDR_COLLECT_FLAG = 3600;
- private static final int ADDR_QUALITY_RESULT = 3610;
- private static final int ADDR_SN_START = 3620;
- private static final int SN_REGISTER_COUNT = 60;
- private static final int ADDR_FEED_SPEED = 3740;
- private static final int ADDR_FEED_RATE = 3780;
- private static final int ADDR_SPINDLE_SPEED = 3820;
- private static final int ADDR_SPINDLE_RATE = 3860;
- private static final int ADDR_WELD_PRESSURE = 4040;
- private static final int ADDR_WELD_OFFSET = 4590;
- private static final int ADDR_B_AXIS_ANGLE = 4742;
- private static final String DEFAULT_HOST = "10.0.20.220";
- private static final int DEFAULT_PORT = 502;
- private static final int DEFAULT_UNIT_ID = 1;
- /** 过程参数落库固定产线 / 工位 */
- private static final String FIXED_LINE_SN = "XT";
- private static final String FIXED_OPRNO = "OP230B";
- @Autowired
- private MesProductRecordController mesProductRecordController;
- @Autowired
- private MesProductService mesProductService;
- @Autowired
- private MesLineService mesLineService;
- @Autowired
- private MesProductFswService mesProductFswService;
- @Autowired
- private MesProductRecordService mesProductRecordService;
- private final AtomicBoolean running = new AtomicBoolean(false);
- private volatile ModbusTcp modbusTcp;
- private volatile String lastCheckedSn;
- /**
- * 每秒执行:工件码质量校验 + 过程参数采集握手
- */
- @Scheduled(fixedRate = 1000)
- public void collect() {
- String enabled = Global.getConfig("mes.fsw.modbus.enabled");
- if (StringUtils.isBlank(enabled) || !"true".equalsIgnoreCase(enabled.trim())) {
- return;
- }
- runOnce();
- }
- /**
- * 直接执行一轮完整逻辑(供测试 / 手工触发)。
- * 不受 mes.fsw.modbus.enabled 开关限制,仍会检查 4740 使能点位。
- */
- public void runOnce() {
- if (!running.compareAndSet(false, true)) {
- logger.warn("FSW Modbus上一轮尚未结束,跳过本次调用");
- return;
- }
- try {
- ModbusTcp plc = getClient();
- Short enable = plc.readInt16(ADDR_ENABLE_FLAG);
- if (enable == null || enable != 1) {
- logger.info("FSW Modbus 4740={},未使能,跳过", enable);
- return;
- }
- handleQualityCheck(plc);
- handleCollectTrigger(plc);
- } catch (Exception e) {
- logger.error("FSW Modbus任务失败:{}", e.getMessage());
- closeClient();
- } finally {
- running.set(false);
- }
- }
- /**
- * 读取工件码 → 质量校验 → 写回 3610(1合格 / 2不合格)
- */
- private void handleQualityCheck(ModbusTcp plc) {
- String sn = readWorkpieceCode(plc);
- if (StringUtils.isBlank(sn)) {
- lastCheckedSn = null;
- return;
- }
- if (sn.equals(lastCheckedSn)) {
- return;
- }
- boolean pass = doQualityCheck(sn);
- plc.writeInt16(ADDR_QUALITY_RESULT, pass ? (short) 1 : (short) 2);
- lastCheckedSn = sn;
- logger.info("FSW质量校验 sn={} result={}", sn, pass ? 1 : 2);
- }
- /**
- * 3600=1 时采集过程参数,完成后置 0
- */
- private void handleCollectTrigger(ModbusTcp plc) {
- Short flag = plc.readInt16(ADDR_COLLECT_FLAG);
- if (flag == null || flag != 1) {
- return;
- }
- String sn = readWorkpieceCode(plc);
- float feedSpeed = plc.readFloat32(ADDR_FEED_SPEED, EByteBuffFormat.BA_DC);
- float feedRate = plc.readFloat32(ADDR_FEED_RATE, EByteBuffFormat.BA_DC);
- float spindleSpeed = plc.readFloat32(ADDR_SPINDLE_SPEED, EByteBuffFormat.BA_DC);
- float spindleRate = plc.readFloat32(ADDR_SPINDLE_RATE, EByteBuffFormat.BA_DC);
- float weldPressure = plc.readFloat32(ADDR_WELD_PRESSURE, EByteBuffFormat.BA_DC);
- float weldOffset = plc.readFloat32(ADDR_WELD_OFFSET, EByteBuffFormat.BA_DC);
- float bAxisAngle = plc.readFloat32(ADDR_B_AXIS_ANGLE, EByteBuffFormat.BA_DC);
- logger.info("FSW过程采集 sn={} 进给速度={} 进给倍率={} 主轴转速={} 主轴倍率={} 焊接压力={} 偏移量={} B轴角度={}",
- sn, feedSpeed, feedRate, spindleSpeed, spindleRate, weldPressure, weldOffset, bAxisAngle);
- saveProcessData(sn, feedSpeed, feedRate, spindleSpeed, spindleRate, weldPressure, weldOffset, bAxisAngle);
- plc.writeInt16(ADDR_COLLECT_FLAG, (short) 0);
- }
- private boolean doQualityCheck(String sn) {
- String oprno = Global.getConfig("mes.fsw.modbus.oprno");
- if (StringUtils.isBlank(oprno)) {
- logger.warn("FSW质量校验失败:未配置 mes.fsw.modbus.oprno");
- return false;
- }
- String oldOprno = oprno;
- if (oldOprno.length() == 5) {
- oldOprno = oldOprno + "A";
- }
- String lineSn = Global.getConfig("mes.fsw.modbus.lineSn");
- if (StringUtils.isBlank(lineSn)) {
- lineSn = resolveLineSn(sn);
- }
- if (StringUtils.isBlank(lineSn)) {
- logger.warn("FSW质量校验失败:无法解析产线编号 sn={}", sn);
- return false;
- }
- try {
- String ret = mesProductRecordController.checkQualityCommon(oldOprno, sn, lineSn, "");
- if (StringUtils.isBlank(ret) || ret.length() < 5) {
- return false;
- }
- return "UD".equals(ret.substring(3, 5));
- } catch (Exception e) {
- logger.error("FSW质量校验异常 sn={}:{}", sn, e.getMessage());
- return false;
- }
- }
- private String resolveLineSn(String sn) {
- MesProduct product = mesProductService.findBySn(sn);
- if (ObjectUtils.isEmpty(product) || StringUtils.isBlank(product.getCate())) {
- return null;
- }
- MesLine query = new MesLine();
- query.setProductCate(product.getCate());
- query.setStatus("0");
- MesLine line = mesLineService.findInfo(query);
- if (ObjectUtils.isEmpty(line)) {
- return null;
- }
- return line.getSn();
- }
- private void saveProcessData(String sn, float feedSpeed, float feedRate,
- float spindleSpeed, float spindleRate, float weldPressure, float weldOffset, float bAxisAngle) {
- if (StringUtils.isBlank(sn)) {
- return;
- }
- try {
- MesProductFsw entity = new MesProductFsw();
- entity.setSn(sn);
- entity.setOprno(FIXED_OPRNO);
- entity.setLineSn(FIXED_LINE_SN);
- entity.setFeedSpeed(fmt(feedSpeed));
- entity.setFeedRate(fmt(feedRate));
- entity.setSpindleSpeed(fmt(spindleSpeed));
- entity.setSpindleRate(fmt(spindleRate));
- entity.setPressure(fmt(weldPressure));
- entity.setPyl(fmt(weldOffset));
- entity.setJd(fmt(bAxisAngle));
- mesProductFswService.save(entity);
- // 保存完成后提交工位总结果为 OK
- List<ParamsResp> params = new ArrayList<>();
- List<BindMaterialResp> bmlists = new ArrayList<>();
- mesProductRecordService.updateRecordResult(sn, FIXED_OPRNO, "100000", "", "OK",
- "", params, FIXED_LINE_SN, true, bmlists, null);
- logger.info("FSW过程参数已保存并更新工位结果 OK sn={} oprno={}", sn, FIXED_OPRNO);
- } catch (Exception e) {
- logger.error("FSW过程参数保存失败 sn={}:{}", sn, e.getMessage());
- }
- }
- /**
- * 3620 起连续 30 个保持寄存器,按 ASCII 拼接工件码
- */
- private String readWorkpieceCode(ModbusTcp plc) {
- byte[] bytes = plc.readHoldRegister(ADDR_SN_START, SN_REGISTER_COUNT);
- if (bytes == null || bytes.length == 0) {
- return null;
- }
- String raw = new String(bytes, StandardCharsets.US_ASCII);
- StringBuilder sb = new StringBuilder(raw.length());
- for (int i = 0; i < raw.length(); i++) {
- char c = raw.charAt(i);
- if (c == 0 || c == ' ') {
- continue;
- }
- if (c >= 32 && c < 127) {
- sb.append(c);
- }
- }
- return sb.toString().trim();
- }
- private ModbusTcp getClient() {
- ModbusTcp client = modbusTcp;
- if (client != null) {
- return client;
- }
- synchronized (this) {
- if (modbusTcp == null) {
- String host = Global.getConfig("mes.fsw.modbus.host");
- if (StringUtils.isBlank(host)) {
- host = DEFAULT_HOST;
- }
- int port = parseInt(Global.getConfig("mes.fsw.modbus.port"), DEFAULT_PORT);
- int unitId = parseInt(Global.getConfig("mes.fsw.modbus.unitId"), DEFAULT_UNIT_ID);
- modbusTcp = new ModbusTcp(unitId, host, port);
- logger.info("FSW Modbus已连接 {}:{} unitId={}", host, port, unitId);
- }
- return modbusTcp;
- }
- }
- private void closeClient() {
- synchronized (this) {
- if (modbusTcp != null) {
- try {
- modbusTcp.close();
- } catch (Exception ignore) {
- }
- modbusTcp = null;
- }
- }
- }
- private static int parseInt(String val, int defaultVal) {
- if (StringUtils.isBlank(val)) {
- return defaultVal;
- }
- try {
- return Integer.parseInt(val.trim());
- } catch (Exception e) {
- return defaultVal;
- }
- }
- private static String fmt(float val) {
- return String.format("%.3f", val);
- }
- }
|