|  |  |  | 
|---|
|  |  |  | package com.zy.acs.manager.core.service; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | 
|---|
|  |  |  | import com.zy.acs.framework.common.Cools; | 
|---|
|  |  |  | import com.zy.acs.common.utils.Utils; | 
|---|
|  |  |  | import com.zy.acs.framework.common.Cools; | 
|---|
|  |  |  | import com.zy.acs.manager.common.config.RedisProperties; | 
|---|
|  |  |  | import com.zy.acs.manager.common.utils.MapDataUtils; | 
|---|
|  |  |  | import com.zy.acs.manager.core.constant.MapDataConstant; | 
|---|
|  |  |  | import com.zy.acs.manager.core.service.astart.DynamicNodeType; | 
|---|
|  |  |  | 
|---|
|  |  |  | import com.zy.acs.manager.manager.entity.AgvDetail; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.entity.AgvModel; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.entity.Code; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.enums.AgvModelType; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.service.AgvDetailService; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.service.AgvModelService; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.service.AgvService; | 
|---|
|  |  |  | import com.zy.acs.manager.manager.service.CodeService; | 
|---|
|  |  |  | import lombok.extern.slf4j.Slf4j; | 
|---|
|  |  |  | import org.apache.commons.lang.time.StopWatch; | 
|---|
|  |  |  | import org.springframework.beans.factory.annotation.Autowired; | 
|---|
|  |  |  | import org.springframework.context.annotation.DependsOn; | 
|---|
|  |  |  | import org.springframework.core.io.ClassPathResource; | 
|---|
|  |  |  | import org.springframework.core.io.Resource; | 
|---|
|  |  |  | import org.springframework.stereotype.Component; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import javax.annotation.PostConstruct; | 
|---|
|  |  |  | import javax.annotation.PreDestroy; | 
|---|
|  |  |  | import java.io.BufferedReader; | 
|---|
|  |  |  | import java.io.File; | 
|---|
|  |  |  | import java.io.InputStream; | 
|---|
|  |  |  | import java.io.InputStreamReader; | 
|---|
|  |  |  | import java.nio.file.Files; | 
|---|
|  |  |  | import java.nio.file.StandardCopyOption; | 
|---|
|  |  |  | import java.util.List; | 
|---|
|  |  |  | import java.util.concurrent.ExecutorService; | 
|---|
|  |  |  | import java.util.concurrent.Executors; | 
|---|
|  |  |  | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | @Slf4j | 
|---|
|  |  |  | @Component | 
|---|
|  |  |  | @DependsOn("getMapDataDispatcher") | 
|---|
|  |  |  | public class AvoidWaveCalculator { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static final ReentrantLock lock = new ReentrantLock(Boolean.TRUE); | 
|---|
|  |  |  | 
|---|
|  |  |  | private static final int LOCK_TIMEOUT = 5; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private ExecutorService singleThreadExecutor; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private File pythonFile = null; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private MapDataDispatcher mapDataDispatcher; | 
|---|
|  |  |  | 
|---|
|  |  |  | private CodeService codeService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private MapService mapService; | 
|---|
|  |  |  | @Autowired | 
|---|
|  |  |  | private RedisProperties redisProperties; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | @PostConstruct | 
|---|
|  |  |  | @SuppressWarnings("all") | 
|---|
|  |  |  | public void execute() { | 
|---|
|  |  |  | this.singleThreadExecutor = Executors.newSingleThreadExecutor(); | 
|---|
|  |  |  | this.singleThreadExecutor.execute(() -> { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | try { Thread.sleep(200); } catch (InterruptedException ignore) {} | 
|---|
|  |  |  | try { Thread.sleep(500); } catch (InterruptedException ignore) {} | 
|---|
|  |  |  |  | 
|---|
|  |  |  | this.calcDynamicNodeWhenBoot(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | while (!Thread.currentThread().isInterrupted()) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | this.calcWaveScope(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | try { Thread.sleep(500); } catch (InterruptedException ignore) {} | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | }); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void calcWaveScope() { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public boolean calcWaveScope() { | 
|---|
|  |  |  | Integer lev = MapDataDispatcher.MAP_DEFAULT_LEV; | 
|---|
|  |  |  | boolean lockAcquired = false; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | StopWatch stopWatch = new StopWatch(); | 
|---|
|  |  |  | stopWatch.start(); | 
|---|
|  |  |  | long startTime = System.currentTimeMillis(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (!(lockAcquired = lock.tryLock(LOCK_TIMEOUT, TimeUnit.SECONDS))) { | 
|---|
|  |  |  | log.warn("AvoidWaveCalculator execute fail, cause can not acquire lock ..."); | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(lev); | 
|---|
|  |  |  | String[][] waveMatrix = mapDataDispatcher.initWaveMatrix(lev); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // vehicle | 
|---|
|  |  |  | //            for (Agv agv : agvService.list(new LambdaQueryWrapper<>())) { | 
|---|
|  |  |  | //                AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId()); | 
|---|
|  |  |  | //                AgvModel agvModel = agvModelService.getById(agv.getAgvModel()); | 
|---|
|  |  |  | //                Code code = codeService.getById(agvDetail.getRecentCode()); | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //                Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getDiameter(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); | 
|---|
|  |  |  | //                List<NavigateNode> includeList = mapService.getWaveScopeByCode(lev, code.getData(), avoidDistance); | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //                for (NavigateNode navigateNode : includeList) { | 
|---|
|  |  |  | //                    String waveNode = waveMatrix[navigateNode.getX()][navigateNode.getY()]; | 
|---|
|  |  |  | //                    waveMatrix[navigateNode.getX()][navigateNode.getY()] = MapDataUtils.generateWaveNode(waveNode, agv.getUuid()); | 
|---|
|  |  |  | //                } | 
|---|
|  |  |  | // | 
|---|
|  |  |  | //            } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // lock path | 
|---|
|  |  |  | DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(lev); | 
|---|
|  |  |  | for (int i = 0; i < dynamicMatrix.length; i++) { | 
|---|
|  |  |  | for (int j = 0; j < dynamicMatrix[i].length; j++) { | 
|---|
|  |  |  | DynamicNode dynamicNode = dynamicMatrix[i][j]; | 
|---|
|  |  |  | String vehicle = dynamicNode.getVehicle(); | 
|---|
|  |  |  | if (!DynamicNodeType.ACCESS.val.equals(vehicle) && !DynamicNodeType.BLOCK.val.equals(vehicle)) { | 
|---|
|  |  |  | AgvModel agvModel = agvModelService.getById(agvService.selectByUuid(vehicle).getAgvModel());    // can be optimized | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getDiameter(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); | 
|---|
|  |  |  | List<NavigateNode> includeList = mapService.getWaveScopeByCode(lev, codeMatrix[i][j], avoidDistance); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | for (NavigateNode navigateNode : includeList) { | 
|---|
|  |  |  | String waveNode = waveMatrix[navigateNode.getX()][navigateNode.getY()]; // overlay | 
|---|
|  |  |  | waveMatrix[navigateNode.getX()][navigateNode.getY()] = MapDataUtils.generateWaveNode(waveNode, vehicle); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //            mapDataDispatcher.printMatrix(waveMatrix); | 
|---|
|  |  |  | mapDataDispatcher.setWaveMatrix(lev, waveMatrix); | 
|---|
|  |  |  | //            return this.calcWaveScopeByPython(lev); | 
|---|
|  |  |  | return this.calcWaveScopeByJava(lev); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | log.error(this.getClass().getSimpleName(), e); | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } finally { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (lockAcquired) { | 
|---|
|  |  |  | lock.unlock(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | stopWatch.stop(); | 
|---|
|  |  |  | if (stopWatch.getTime() > 100) { | 
|---|
|  |  |  | log.info("滤波函数花费时间为:{}毫秒......", stopWatch.getTime()); | 
|---|
|  |  |  | long during = System.currentTimeMillis() - startTime; | 
|---|
|  |  |  | if (during > 50) { | 
|---|
|  |  |  | log.info("滤波函数花费时间为:{}毫秒......", during); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void syncWaveBySingleVeh(String agvNo, String codeData) { | 
|---|
|  |  |  | if (Cools.isEmpty(agvNo, codeData)) { | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | private boolean calcWaveScopeByPython(Integer lev) throws Exception { | 
|---|
|  |  |  | // python | 
|---|
|  |  |  | AgvModel agvModel = agvModelService.selectByType(AgvModelType.CTU_BOX_TRANSPORT_AGV.toString());    // can be optimized | 
|---|
|  |  |  | Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getDiameter(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (null == pythonFile) { | 
|---|
|  |  |  | pythonFile = loadPythonFile(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | boolean lockAcquired = false; | 
|---|
|  |  |  | Integer lev = MapDataDispatcher.MAP_DEFAULT_LEV; | 
|---|
|  |  |  | ProcessBuilder processBuilder = new ProcessBuilder( | 
|---|
|  |  |  | "python" // 或者 "python3" 取决于系统配置 | 
|---|
|  |  |  | , pythonFile.getAbsolutePath() | 
|---|
|  |  |  | , String.valueOf(avoidDistance) | 
|---|
|  |  |  | , redisProperties.getHost() | 
|---|
|  |  |  | , redisProperties.getPassword() | 
|---|
|  |  |  | , String.valueOf(redisProperties.getPort()) | 
|---|
|  |  |  | , String.valueOf(redisProperties.getIndex()) | 
|---|
|  |  |  | ); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | processBuilder.redirectErrorStream(true); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Process process = processBuilder.start(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); | 
|---|
|  |  |  | String line; | 
|---|
|  |  |  | StringBuilder builder = new StringBuilder(); | 
|---|
|  |  |  | while ((line = reader.readLine()) != null) { | 
|---|
|  |  |  | builder.append(line); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | int exitCode = process.waitFor(); | 
|---|
|  |  |  | if (exitCode != 0) { | 
|---|
|  |  |  | log.error("Python script exited with error code: {}", exitCode); | 
|---|
|  |  |  | log.error("python error:{}", builder.toString()); | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | reader.close(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (builder.length() <= 0) { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String result = builder.toString(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (Cools.isEmpty(result)) { | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | if (!"1".equals(result)) { | 
|---|
|  |  |  | log.error("Failed to call python"); | 
|---|
|  |  |  | return false; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return true; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private boolean calcWaveScopeByJava(Integer lev) throws Exception { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | AgvModel agvModel = agvModelService.selectByType(AgvModelType.CTU_BOX_TRANSPORT_AGV.toString());    // can be optimized | 
|---|
|  |  |  | Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getDiameter(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // java | 
|---|
|  |  |  | String[][] codeMatrix = mapDataDispatcher.getCodeMatrix(lev); | 
|---|
|  |  |  | String[][] waveMatrix = mapDataDispatcher.initWaveMatrix(lev); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | // lock path | 
|---|
|  |  |  | DynamicNode[][] dynamicMatrix = mapDataDispatcher.getDynamicMatrix(lev); | 
|---|
|  |  |  | for (int i = 0; i < dynamicMatrix.length; i++) { | 
|---|
|  |  |  | for (int j = 0; j < dynamicMatrix[i].length; j++) { | 
|---|
|  |  |  | DynamicNode dynamicNode = dynamicMatrix[i][j]; | 
|---|
|  |  |  | String vehicle = dynamicNode.getVehicle(); | 
|---|
|  |  |  | if (!DynamicNodeType.ACCESS.val.equals(vehicle) && !DynamicNodeType.BLOCK.val.equals(vehicle)) { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<NavigateNode> includeList = mapService.getWaveScopeByCode(lev, codeMatrix[i][j], avoidDistance); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | for (NavigateNode navigateNode : includeList) { | 
|---|
|  |  |  | String waveNode = waveMatrix[navigateNode.getX()][navigateNode.getY()]; // overlay | 
|---|
|  |  |  | waveMatrix[navigateNode.getX()][navigateNode.getY()] = MapDataUtils.generateWaveNode(waveNode, vehicle); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | //            mapDataDispatcher.printMatrix(waveMatrix); | 
|---|
|  |  |  | mapDataDispatcher.setWaveMatrix(lev, waveMatrix); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | return true; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private File loadPythonFile() { | 
|---|
|  |  |  | File scriptFile = null; | 
|---|
|  |  |  | try { | 
|---|
|  |  |  | if (!(lockAcquired = lock.tryLock(LOCK_TIMEOUT, TimeUnit.SECONDS))) { | 
|---|
|  |  |  | log.warn("AvoidWaveCalculator syncWaveBySingleVeh fail, cause can not acquire lock ..."); | 
|---|
|  |  |  | return; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | Resource resource = new ClassPathResource("agv.py"); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | Agv agv = agvService.selectByUuid(agvNo); | 
|---|
|  |  |  | AgvModel agvModel = agvModelService.getById(agv.getAgvModel()); | 
|---|
|  |  |  | Double avoidDistance = MapDataUtils.getVehicleWaveSafeDistance(agvModel.getDiameter(), MapDataConstant.MAX_DISTANCE_BETWEEN_ADJACENT_AGV_FACTOR); | 
|---|
|  |  |  | InputStream is = resource.getInputStream(); | 
|---|
|  |  |  | scriptFile = File.createTempFile("agv", ".py"); | 
|---|
|  |  |  | scriptFile.deleteOnExit(); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | String[][] waveMatrix = mapDataDispatcher.getWaveMatrix(lev); | 
|---|
|  |  |  | Files.copy(is, scriptFile.toPath(), StandardCopyOption.REPLACE_EXISTING); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | List<NavigateNode> includeList = mapService.getWaveScopeByCode(lev, codeData, avoidDistance); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | for (NavigateNode navigateNode : includeList) { | 
|---|
|  |  |  | String waveNode = waveMatrix[navigateNode.getX()][navigateNode.getY()]; | 
|---|
|  |  |  | waveMatrix[navigateNode.getX()][navigateNode.getY()] = MapDataUtils.generateWaveNode(waveNode, agv.getUuid()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | mapDataDispatcher.setWaveMatrix(lev, waveMatrix); | 
|---|
|  |  |  |  | 
|---|
|  |  |  | boolean executable = scriptFile.setExecutable(true); | 
|---|
|  |  |  | } catch (Exception e) { | 
|---|
|  |  |  | log.error("AvoidWaveCalculator.syncWaveBySingleVeh fail", e); | 
|---|
|  |  |  | } finally { | 
|---|
|  |  |  |  | 
|---|
|  |  |  | if (lockAcquired) { | 
|---|
|  |  |  | lock.unlock(); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | throw new RuntimeException(e); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return scriptFile; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public void calcDynamicNodeWhenBoot() { | 
|---|
|  |  |  | 
|---|
|  |  |  | DynamicNode dynamicNode = dynamicMatrix[codeMatrixIdx[0]][codeMatrixIdx[1]]; | 
|---|
|  |  |  | String vehicle = dynamicNode.getVehicle(); | 
|---|
|  |  |  | if (vehicle.equals(DynamicNodeType.ACCESS.val)) { | 
|---|
|  |  |  | mapDataDispatcher.modifyDynamicMatrix(null, Utils.singletonList(code.getData()), agv.getUuid()); | 
|---|
|  |  |  | mapDataDispatcher.modifyDynamicMatrix(null, Utils.singletonList(codeMatrixIdx), agv.getUuid()); | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|