| | |
| | | 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("mapDataDispatcher") |
| | | 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() { |
| | |
| | | if (null == agvDetail) { |
| | | return; |
| | | } |
| | | if (agvDetail.getPos() == null || agvDetail.getPos() != 1) { |
| | | if (agvDetail.getPos() == null) { |
| | | return; |
| | | } |
| | | Long recentCode = agvDetail.getRecentCode(); |
| | |
| | | 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()); |
| | | } |
| | | } |
| | | |