自动化立体仓库 - WMS系统
zyh
2 天以前 b26b26e7170f4b86642176ac62955e57e1dc74a9
src/main/java/com/zy/asrs/service/impl/RcsServiceImpl.java
@@ -6,16 +6,19 @@
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zy.asrs.entity.*;
import com.zy.asrs.entity.mes.TransArrivalStation;
import com.zy.asrs.entity.mes.TransInOutStationAllow;
import com.zy.asrs.entity.mes.TransParent;
import com.zy.asrs.entity.rcs.*;
import com.zy.asrs.enums.RcsRetMethodEnum;
import com.zy.asrs.mapper.BasDevpMapper;
import com.zy.asrs.mapper.BlockStationMapper;
import com.zy.asrs.mapper.BlockTaskMapper;
import com.zy.asrs.service.*;
import com.zy.common.utils.HttpHandler;
import com.zy.common.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@@ -29,13 +32,15 @@
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@Service
public class RcsServiceImpl implements RcsService {
    @Value("${wms.address}")
    private String WMS_ADDRESS;
    @Value("${personIn.url}")
    private String PERSON_URL;
    // 海康RCS地址
    @Value("${hik.url}")
    private String HIK_URL;
@@ -63,8 +68,15 @@
    @Resource
    private WrkMastService wrkMastService;
    @Autowired
    private RedisUtil redisUtil;
    @Resource
    private ApiLogService apiLogService;
    private static final String IS_START_CHECK_INTRUSION = "intrusion:check";
    private static final String IS_PERSON_INTRUSION = "intrusion:person";
    private static final String LAST_INTRUSION_TIME = "intrusion:lastTime";
    private static final String IS_BLOCK_AREA = "intrusion:block";
    // region 封锁区逻辑,目前只有一个大封锁区,任务全部转到滑块库处理,或直接写到滑块库
@@ -95,40 +107,40 @@
     */
    public void managerBlock() {
       try {
           BlockTask firstTask = blockTaskMapper.findTop();
           if (firstTask == null) {
               return;
           }
           EntityWrapper<BlockStation> wrapper = new EntityWrapper<>();
           wrapper.eq("block_no", firstTask.getBlockNo());
           List<BlockStation> stations = blockStationMapper.selectList(wrapper);
           if (!stations.isEmpty()) {
               boolean locked = false;
               for (BlockStation station : stations) {
                   // 只允许1个厂家设备进入封锁区,status状态:0 空闲;1 海康封锁中;2 华晓封锁中;-1 异常;
                   if (station.getStatus() > 0 && !station.getStatus().equals(firstTask.getAgvFactory())) {
                       locked = true;
                       break;
                   }
               }
        try {
            BlockTask firstTask = blockTaskMapper.findTop();
            if (firstTask == null) {
                return;
            }
            EntityWrapper<BlockStation> wrapper = new EntityWrapper<>();
            wrapper.eq("block_no", firstTask.getBlockNo());
            List<BlockStation> stations = blockStationMapper.selectList(wrapper);
            if (!stations.isEmpty()) {
                boolean locked = false;
                for (BlockStation station : stations) {
                    // 只允许1个厂家设备进入封锁区,status状态:0 空闲;1 海康封锁中;2 华晓封锁中;-1 异常;
                    if (station.getStatus() > 0 && !station.getStatus().equals(firstTask.getAgvFactory())) {
                        locked = true;
                        break;
                    }
                }
               if (!locked) {
                   // 封锁状态
                   int success = blockStationMapper.addByBlockNo(firstTask.getBlockNo(), firstTask.getAgvFactory());
                   if (success > 0) {
                       // 通知RCS
                       RcsEqptNotify notify = new RcsEqptNotify();
                       notify.setEqptCode(firstTask.getBlockNo());
                       notify.setTaskCode(firstTask.getTaskCode());
                       notify.setActionStatus("1");
                       notifyEqpt(notify, firstTask.getAgvFactory());
                   }
               }
           }
       } catch (Exception e) {
           log.error("管理封锁区异常", e);
       }
                if (!locked) {
                    // 封锁状态
                    int success = blockStationMapper.addByBlockNo(firstTask.getBlockNo(), firstTask.getAgvFactory());
                    if (success > 0) {
                        // 通知RCS
                        RcsEqptNotify notify = new RcsEqptNotify();
                        notify.setEqptCode(firstTask.getBlockNo());
                        notify.setTaskCode(firstTask.getTaskCode());
                        notify.setActionStatus("1");
                        notifyEqpt(notify, firstTask.getAgvFactory());
                    }
                }
            }
        } catch (Exception e) {
            log.error("管理封锁区异常", e);
        }
    }
    /**
@@ -339,6 +351,9 @@
        return 0;
    }
    @Resource
    private BasDevpMapper basDevpMapper;
    /**
     * 2.2.1任务执行回馈
     * 厂家:海量、华晓
@@ -387,6 +402,100 @@
//                        JSONObject taskMemo = JSONObject.parseObject(task.getMemo());
//                        mesService.outFeedbackByTuo(taskMemo.getString("OrderNo"), task);
                    } break;
                    case APPLY_PUT: { // 放货申请
                        String staNo = task.getStaNo();
                        BasDevp basDevp = basDevpMapper.selectById(staNo);
                        if(basDevp.getAutoing().equals("Y") && basDevp.getLoading().equals("N") && basDevp.getWrkNo() == 0) {
                            // 205 触发条码扫描
                            if (staNo.equals("205")) {
                                Map<String,Object> params = new HashMap<>();
                                params.put("siteId",staNo);
                                String response = new HttpHandler.Builder()
                                        .setUri(WCS_URL)
                                        .setPath("/site/startScan")
                                        .setParams(params)
                                        .build()
                                        .doPost();
                                log.info("{}放货申请给wcs下发条码扫描原始返回:{}",staNo,response);
                            }
                            // 满足放货条件,调用RCS任务继续执行
                            RcsTaskContinue rcsTaskContinue = new RcsTaskContinue();
                            rcsTaskContinue.setRobotTaskCode(robotTaskCode);
                            rcsTaskContinue.setTriggerType("TASK");
                            rcsTaskContinue.setTriggerCode(robotTaskCode);
                            int success = continueTask(rcsTaskContinue, 1);
                            if(success != 1) {
                                rcsReturn.setCode("Err_RobotCodeNotMatch");
                                rcsReturn.setMessage("继续执行失败");
                                JSONObject data = new JSONObject();
                                data.put("robotTaskCode", robotTaskCode);
                                rcsReturn.setData(data);
                                return rcsReturn;
                            }
                        }else {
                            log.warn("站点:{},不满足放货条件,自动:{},无物:{},任务号:{}",staNo,basDevp.getAutoing(),basDevp.getLoading(),basDevp.getWrkNo());
                            rcsReturn.setCode("Err_RobotCodeNotMatch");
                            rcsReturn.setMessage("站点不满足放货条件");
                            JSONObject data = new JSONObject();
                            data.put("robotTaskCode", robotTaskCode);
                            rcsReturn.setData(data);
                            return rcsReturn;
                        }
                    } break;
                    case APPLY_PICK: { // 取货申请
                        String staNo = task.getSourceStaNo();
                        BasDevp basDevp = basDevpMapper.selectById(staNo);
                        if(basDevp.getAutoing().equals("Y") && basDevp.getLoading().equals("Y")
                                && basDevp.getWrkNo()  > 0 && basDevp.getWrkNo() <= 9990) {
                            // 满足放货条件,调用RCS任务继续执行
                            RcsTaskContinue rcsTaskContinue = new RcsTaskContinue();
                            rcsTaskContinue.setRobotTaskCode(robotTaskCode);
                            rcsTaskContinue.setTriggerType("TASK");
                            rcsTaskContinue.setTriggerCode(robotTaskCode);
                            int success = continueTask(rcsTaskContinue, 1);
                            if(success != 1) {
                                rcsReturn.setCode("Err_RobotCodeNotMatch");
                                rcsReturn.setMessage("继续执行失败");
                                JSONObject data = new JSONObject();
                                data.put("robotTaskCode", robotTaskCode);
                                rcsReturn.setData(data);
                                return rcsReturn;
                            }
                        }else {
                            log.warn("站点:{},不满足取货条件,自动:{},无物:{},任务号:{}",staNo,basDevp.getAutoing(),basDevp.getLoading(),basDevp.getWrkNo());
                            rcsReturn.setCode("Err_RobotCodeNotMatch");
                            rcsReturn.setMessage("站点不满足放货条件");
                            JSONObject data = new JSONObject();
                            data.put("robotTaskCode", robotTaskCode);
                            rcsReturn.setData(data);
                            return rcsReturn;
                        }
                    } break;
                    case PICK_COMPLETE: { // 取货完成
                        String staNo = task.getSourceStaNo();
                        // 清除输送线任务号
                        Map<String,Object> params = new HashMap<>();
                        params.put("siteId",staNo);
                        params.put("workNo",0);
                        params.put("staNo", 0);
                        params.put("pakMk","Y");
                        String response = new HttpHandler.Builder()
                                .setUri(WCS_URL)
                                .setPath("/site/detl/update")
                                .setParams(params)
                                .build()
                                .doPost();
                        log.info("agv反馈pickComplete给wcs发命令:{},返回:{}",JSONObject.toJSONString(params),response);
                        // agv继续执行
//                        TransInOutStationAllow inOutStationAllow = new TransInOutStationAllow();
//                        inOutStationAllow.setTaskno(robotTaskCode);
//                        inOutStationAllow.setStatus("Y");
//                        inOutStationAllow.setAgvCode("agv001");
//                        mesService.allowOutStation(inOutStationAllow);
                    } break;
                    case TASK_END: {
                        // 更新任务状态等内部逻辑
                        task.setWrkSts(304L);   // 301 任务下发、302 任务执行、303 任务中断、304 任务结束
@@ -394,9 +503,10 @@
                        task.setModiUser(defaultUserId);
                        taskService.updateById(task);
                        // 任务完成
                        mesService.reporterTask(rcsReporterTask);
//                        mesService.reporterTask(rcsReporterTask);
                        // 入立库时,区分是空托还是满托,给输送线下发命令9990 空,9995满
                        // 侧面205 9996空,9997满
                        String transType = memo.getString("TransType");
                        if("02".equals(transType) || "04".equals(transType)) {
                            int wrkNo = 9995;
@@ -409,11 +519,14 @@
                                }
                            }
                            int staNo = Integer.parseInt(task.getStaNo());
                            if(staNo == 205) { // 侧面任务号转换
                                wrkNo = wrkNo == 9990 ? 9996 : 9997;
                            }
                            Map<String,Object> params = new HashMap<>();
                            params.put("siteId",staNo);
                            params.put("workNo",wrkNo);
                            params.put("staNo", staNo == 205 ? 205 : (staNo-1) );
                            params.put("String","Y");
                            params.put("pakMk","Y");
                            String response = new HttpHandler.Builder()
                                    .setUri(WCS_URL)
                                    .setPath("/site/detl/update")
@@ -451,20 +564,52 @@
                        } else {
                            apply.setStationId(task.getStaNo());
                        }
                        if (RcsRetMethodEnum.APPLY_IN_STATION.getCode().equals(method)) {
                            JSONObject personRequest = new JSONObject();
                            personRequest.put("TaskType", 2);
                            personRequest.put("callback", WMS_ADDRESS+"/api/robot/personIn");
                            List<String> areaCodes = new ArrayList<>(Arrays.asList("03-H01", "03-H02", "03-M01"));
                            int i = 0;
                            for (String areaCode : areaCodes){
                                personRequest.put("AreaCode", areaCode);
                                int j = PersonRequest(personRequest, "IN");
                                if (j == 0){
                                    log.error("人员入侵系统调用失败");
                                }
                            }
                            redisUtil.set(IS_START_CHECK_INTRUSION, "T");
                            // 延迟处理,确保人员入侵系统信号优先处理
                            try {
                                Thread.sleep(10000); // 睡眠10秒
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                            }
                            mesService.applyInStation(apply);
                        } else if (RcsRetMethodEnum.APPLY_OFF_STATION.getCode().equals(method)) {
                            mesService.applyOutStation(apply);
                        } else if (RcsRetMethodEnum.ARRIVE_OFF_STATION.getCode().equals(method)) {
                            JSONObject personRequest = new JSONObject();
                            personRequest.put("TaskType", 2);
                            personRequest.put("callback", WMS_ADDRESS+"/api/robot/personIn");
                            List<String> areaCodes = new ArrayList<>(Arrays.asList("03-H01", "03-H02", "03-M01"));
                            int i = 0;
                            for (String areaCode:areaCodes){
                                personRequest.put("AreaCode", areaCode);
                                int j = PersonRequest(personRequest, "OUT");
                                if (j == 0){
                                    log.error("人员入侵系统调用失败");
                                }
                            }
                            redisUtil.set(IS_START_CHECK_INTRUSION, "F");
                            mesService.outStation(apply);
                            // agv继续执行
                            TransInOutStationAllow inOutStationAllow = new TransInOutStationAllow();
                            inOutStationAllow.setTaskno(robotTaskCode);
                            inOutStationAllow.setStatus("Y");
                            inOutStationAllow.setAgvCode("agv001");
                            mesService.allowOutStation(inOutStationAllow);
//                            TransInOutStationAllow inOutStationAllow = new TransInOutStationAllow();
//                            inOutStationAllow.setTaskno(robotTaskCode);
//                            inOutStationAllow.setStatus("Y");
//                            inOutStationAllow.setAgvCode("agv001");
//                            mesService.allowOutStation(inOutStationAllow);
                        }
                    } break;
                    case ARRIVE_ON_STATION: {
@@ -476,7 +621,7 @@
                        TransArrivalStation arrivalStation = new TransArrivalStation();
                        arrivalStation.setTaskno(robotTaskCode);
                        arrivalStation.setTaskname(memo.getString("taskName"));
                        arrivalStation.setTuoPanId(taskDetl == null ? "":taskDetl.getZpallet());  // memo.getString("TuoPanId")
                        arrivalStation.setTuoPanId(task.getBarcode());  // memo.getString("TuoPanId")
                        arrivalStation.setProductLineId(memo.getString("ProductLineId"));
                        String transType = memo.getString("TransType");
                        arrivalStation.setDaotype(transType);
@@ -737,5 +882,139 @@
        return result.toString();
    }
    @Override
    public RcsReturn siteBind(SiteBind siteBind) {
        RcsReturn rcsReturn = new RcsReturn();
        String url = HIK_URL + "api/robot/controller/site/bind";
        String response = sendPost(url, JSONObject.toJSONString(siteBind));
        if (!StringUtils.isEmpty(response) && response.contains("code")){
            rcsReturn = JSONObject.parseObject(response, RcsReturn.class);
        } else {
            rcsReturn.setCode("ERROR");
            rcsReturn.setMessage("调用绑定接口RCS无返回");
        }
        return rcsReturn;
    }
    int PersonRequest(JSONObject personRequest, String Type){
        String url;
        if (Type.equals("IN")){
            url = "/detect/start";
        }else{
            url = "/detect/stop";
        }
        String URL = PERSON_URL + url;
        String blockResponse = RcsServiceImpl.sendPost(URL, JSONObject.toJSONString(personRequest));
        JSONObject jsonObject = JSON.parseObject(blockResponse);
        if (!StringUtils.isEmpty(blockResponse) && (jsonObject.getInteger("code") == 200)) {
            return 1;
        }
        return 0;
    }
    @Scheduled(fixedDelay = 1000)
    public void personOut(){
        Object lastTimeObj = redisUtil.get(LAST_INTRUSION_TIME);
        if (lastTimeObj == null) {
            return;  // 没有记录,直接返回
        }
        long lastTime = Long.parseLong(lastTimeObj.toString());  // 先转String再转long
        long now = System.currentTimeMillis();
        long waitTime = now - lastTime;
        //循环检测是否有超过10秒没有更新有人信号
        if (waitTime > 10000){
            JSONObject personReturn = new JSONObject();
            String hik_blockUrl = "api/robot/controller/zone/blockade";
            String hik_pauseUrl = "api/robot/controller/zone/pause";
            String BLOCK_URL = HIK_URL + hik_blockUrl;
            String PAUSE_URL = HIK_URL + hik_pauseUrl;
            // 三个AGV区域
            List<String> areaCodes = new ArrayList<>(Arrays.asList("oprs1", "oprs2", "oprs3"));
            for (String areaCode:areaCodes){
                JSONObject rcsBlock = new JSONObject();
                JSONObject rcsPause = new JSONObject();
                rcsBlock.put("mapCode", "AA");
                rcsPause.put("mapCode", "AA");
                rcsBlock.put("invoke", "OPENUP");
                rcsPause.put("invoke","RUN");
                rcsBlock.put("zoneCode", areaCode);
                rcsPause.put("zoneCode", areaCode);
                // 解除AGV锁定区域与解除暂停
                String blockResponse = RcsServiceImpl.sendPost(BLOCK_URL, JSONObject.toJSONString(rcsBlock));
                String PauseResponse = RcsServiceImpl.sendPost(PAUSE_URL, JSONObject.toJSONString(rcsPause));
                JSONObject blockJsonObject = JSON.parseObject(blockResponse);
                JSONObject pauseJsonObject = JSON.parseObject(PauseResponse);
                if (!StringUtils.isEmpty(blockResponse) && (blockJsonObject.getString("code").equals("SUCCESS"))) {
                    if (!StringUtils.isEmpty(PauseResponse) && (pauseJsonObject.getString("code").equals("SUCCESS"))) {
                        personReturn.put("code", 200);
                        personReturn.put("message", "success");
                    }
                }
            }
            //重置封锁状态
            redisUtil.set(IS_BLOCK_AREA, "F");
        }
    }
    @Override
    //人员入侵系统回调接口实现方法
    public int personIn(JSONObject param) {
        //人员入侵系统检测到有人
        if (param.getString("AlarmValue").equals("1")){
            long date = new Date().getTime();
            //重置redis计时
            redisUtil.set(LAST_INTRUSION_TIME, String.valueOf(date));
            //如果已经封锁区域就直接返回,避免多次调用agv接口
            Object blockArea = redisUtil.get(IS_BLOCK_AREA);
            if (blockArea != null && "T".equals(blockArea)) {
                return 1;
            }
            redisUtil.set(IS_PERSON_INTRUSION, "T");
        }
        JSONObject personReturn = new JSONObject();
        String hik_blockUrl = "api/robot/controller/zone/blockade";
        String hik_pauseUrl = "api/robot/controller/zone/pause";
        String BLOCK_URL = HIK_URL + hik_blockUrl;
        String PAUSE_URL = HIK_URL + hik_pauseUrl;
        JSONObject rcsBlock = new JSONObject();
        JSONObject rcsPause = new JSONObject();
        rcsBlock.put("mapCode", "AA");
        rcsPause.put("mapCode", "AA");
        List<String> areaCodes = new ArrayList<>(Arrays.asList("oprs1", "oprs2", "oprs3"));
        for (String areaCode:areaCodes){
            rcsBlock.put("zoneCode", areaCode);
            rcsPause.put("zoneCode", areaCode);
            rcsBlock.put("invoke", "BLOCKADE");
            rcsPause.put("invoke","FREEZE");
            String blockResponse = RcsServiceImpl.sendPost(BLOCK_URL, JSONObject.toJSONString(rcsBlock));
            String PauseResponse = RcsServiceImpl.sendPost(PAUSE_URL, JSONObject.toJSONString(rcsPause));
            JSONObject blockJsonObject = JSON.parseObject(blockResponse);
            JSONObject pauseJsonObject = JSON.parseObject(PauseResponse);
            if (!StringUtils.isEmpty(blockResponse) && (blockJsonObject.getString("code").equals("SUCCESS"))) {
                if (!StringUtils.isEmpty(PauseResponse) && (pauseJsonObject.getString("code").equals("SUCCESS"))) {
                    personReturn.put("code", 200);
                    personReturn.put("message", "success");
                }
            }
        }
        // 更新存储封锁信息
        redisUtil.set(IS_BLOCK_AREA, "T");
        //直接返回,不需要信息
        return 1;
    }
    // endregion
}