小车调度
This commit is contained in:
@@ -9,30 +9,26 @@ import java.util.Map;
|
|||||||
|
|
||||||
public interface RoadCacheService {
|
public interface RoadCacheService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定楼层的缓存
|
||||||
|
* @param floor 楼层
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Map<String,WcsSrgvMap> getArrByRoadSite(Integer floor);
|
||||||
|
|
||||||
int[][] updateRoadCache(int floor, List<int[]> grid ,int value);
|
/**
|
||||||
|
* 处理地图
|
||||||
List<int[]> findFullPath(int floor, int startX, int startY, int endX, int endY);
|
* @param arrByRoadSite
|
||||||
int[][] findFullMap(int floor, int startX, int startY, int endX, int endY);
|
* @param deviceSrgv
|
||||||
int[][] findFullMap(int floor, int startX, int startY, int endX, int endY, DeviceSrgv srgvPlc);
|
* @return
|
||||||
|
*/
|
||||||
List<int[]> findEmptyPath(int floor, int startX, int startY, int endX, int endY);
|
int[][] handleMap(Map<String, WcsSrgvMap> arrByRoadSite, DeviceSrgv deviceSrgv);
|
||||||
|
/**
|
||||||
int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY);
|
* 根据x y z 获取指定位置的缓存
|
||||||
int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY, DeviceSrgv splc);
|
* @param x
|
||||||
|
* @param y
|
||||||
Map<String, String> getRoadSiteByArr(int floor);
|
* @param z
|
||||||
|
* @return
|
||||||
int[][] getRoadCache(int floor);
|
*/
|
||||||
|
WcsSrgvMap selectRoadSiteByArr(int x, int y, int z);
|
||||||
Map<String, int[]> getArrByRoadSite(int floor);
|
|
||||||
|
|
||||||
List<WcsSrgvMap> getRoadDataCache(int floor);
|
|
||||||
|
|
||||||
|
|
||||||
int[][] findMap(int floor);
|
|
||||||
|
|
||||||
int[][] findFullMap(int floor, int startX, int startY, int endX, int endY,DeviceSrgv srgvPlc,List<String> noSite);
|
|
||||||
|
|
||||||
Map<String, String> getSpaceDataCache();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
package com.ruoyi.bas.srgvmap.service.impl;
|
package com.ruoyi.bas.srgvmap.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap;
|
import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap;
|
||||||
import com.ruoyi.bas.srgvmap.service.IWcsSrgvMapService;
|
import com.ruoyi.bas.srgvmap.service.IWcsSrgvMapService;
|
||||||
import com.ruoyi.bas.srgvmap.service.RoadCacheService;
|
import com.ruoyi.bas.srgvmap.service.RoadCacheService;
|
||||||
import com.ruoyi.device.srgv.domain.DeviceSrgv;
|
import com.ruoyi.device.srgv.domain.DeviceSrgv;
|
||||||
import com.ruoyi.device.srgv.service.IDeviceSrgvService;
|
import com.ruoyi.device.srgv.service.IDeviceSrgvService;
|
||||||
|
import com.ruoyi.queue.srgv.domain.WcsSrgvQueue;
|
||||||
import com.ruoyi.queue.srgv.service.IWcsSrgvQueueService;
|
import com.ruoyi.queue.srgv.service.IWcsSrgvQueueService;
|
||||||
|
import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -31,14 +32,76 @@ public class AgvPathProcessor {
|
|||||||
public void processNoSites(int[][] roadCache, int floor, List<String> noSite) {
|
public void processNoSites(int[][] roadCache, int floor, List<String> noSite) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processAgvPathInfo(int[][] ints, int floor) {
|
public void processAgvPathInfo(Map<String, WcsSrgvMap> maps,Integer agvId) {
|
||||||
|
List<WcsSrgvQueue> wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(new WcsSrgvQueue());
|
||||||
|
if (CollUtil.isNotEmpty(wcsSrgvQueues)) {
|
||||||
|
//筛选其他小车队列
|
||||||
|
wcsSrgvQueues = wcsSrgvQueues.stream().filter(x -> x.getAgvId().equals(Convert.toStr(agvId))).collect(Collectors.toList());
|
||||||
|
|
||||||
|
//获取其他小车占用点位列表
|
||||||
|
HashSet<String> siteList = new HashSet<>();
|
||||||
|
for (WcsSrgvQueue wcsSrgvQueue : wcsSrgvQueues) {
|
||||||
|
String[] split = wcsSrgvQueue.getPathInfo().split(",");
|
||||||
|
siteList.addAll(Arrays.asList(split));
|
||||||
|
}
|
||||||
|
|
||||||
|
//设置其他小车占用点位
|
||||||
|
for (String site : siteList) {
|
||||||
|
if (maps.containsKey(site)){
|
||||||
|
maps.get(site).setValue(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processOnlineAgvSites(int[][] ints, int floor) {
|
/**
|
||||||
|
* 更新AGV路径映射,只保留当前站点及以后的路径
|
||||||
|
*/
|
||||||
|
private void updateAgvPathMap(Map<String, String> agvPathMap, List<SRGVPlc> srgvPlcs) {
|
||||||
|
for (SRGVPlc plc : srgvPlcs) {
|
||||||
|
com.ruoyi.plc.sagv.SRGVData agvData = plc.getAgvData();
|
||||||
|
if (agvData != null && agvData.getAgvId() != null) {
|
||||||
|
String agvId = agvData.getAgvId();
|
||||||
|
String currSite = agvData.getCurrSite();
|
||||||
|
|
||||||
|
// 如果这个agvId在agvPathMap中存在,且currSite不为空
|
||||||
|
if (agvPathMap.containsKey(agvId) && currSite != null) {
|
||||||
|
String pathInfo = agvPathMap.get(agvId);
|
||||||
|
|
||||||
|
// 处理路径信息,只保留当前站点及以后的路径
|
||||||
|
if (pathInfo != null && !pathInfo.isEmpty()) {
|
||||||
|
String[] pathArray = pathInfo.split(",");
|
||||||
|
StringBuilder newPathBuilder = new StringBuilder();
|
||||||
|
|
||||||
|
boolean foundCurrentSite = false;
|
||||||
|
for (String site : pathArray) {
|
||||||
|
if (site.trim().equals(currSite.trim())) {
|
||||||
|
foundCurrentSite = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundCurrentSite) {
|
||||||
|
if (newPathBuilder.length() > 0) {
|
||||||
|
newPathBuilder.append(",");
|
||||||
|
}
|
||||||
|
newPathBuilder.append(site);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果找到了当前站点,更新路径信息
|
||||||
|
if (foundCurrentSite) {
|
||||||
|
agvPathMap.put(agvId, newPathBuilder.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processOfflineAgvSites(int[][] ints, int floor) {
|
public void processOnlineAgvSites(Map<String, WcsSrgvMap> maps) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processOfflineAgvSites(Map<String, WcsSrgvMap> maps) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,311 +1,150 @@
|
|||||||
package com.ruoyi.bas.srgvmap.service.impl;
|
package com.ruoyi.bas.srgvmap.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap;
|
import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap;
|
||||||
import com.ruoyi.bas.srgvmap.mapper.WcsSrgvMapMapper;
|
import com.ruoyi.bas.srgvmap.mapper.WcsSrgvMapMapper;
|
||||||
import com.ruoyi.bas.srgvmap.service.RoadCacheService;
|
import com.ruoyi.bas.srgvmap.service.RoadCacheService;
|
||||||
import com.ruoyi.device.srgv.domain.DeviceSrgv;
|
import com.ruoyi.device.srgv.domain.DeviceSrgv;
|
||||||
import com.ruoyi.schedule.plcRead.srgv.roadUtil.PathFinder;
|
import com.ruoyi.device.srgv.service.IDeviceSrgvService;
|
||||||
import org.slf4j.Logger;
|
import com.ruoyi.queue.srgv.domain.WcsSrgvQueue;
|
||||||
import org.slf4j.LoggerFactory;
|
import com.ruoyi.queue.srgv.service.IWcsSrgvQueueService;
|
||||||
|
import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.cache.CacheManager;
|
|
||||||
import org.springframework.cache.annotation.CachePut;
|
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
|
@Slf4j
|
||||||
public class RoadCacheServiceImpl implements RoadCacheService {
|
public class RoadCacheServiceImpl implements RoadCacheService {
|
||||||
|
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private WcsSrgvMapMapper wcsSrgvMapMapper;
|
private WcsSrgvMapMapper wcsSrgvMapMapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CacheManager cacheManager;
|
private IWcsSrgvQueueService wcsSrgvQueueService;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private RoadCacheService selfProxy; // 注入代理对象
|
private IDeviceSrgvService deviceSrgvService;
|
||||||
|
|
||||||
|
|
||||||
@Autowired
|
@Override
|
||||||
private AgvPathProcessor agvPathProcessor;
|
public Map<String, WcsSrgvMap> getArrByRoadSite(Integer floor) {
|
||||||
|
WcsSrgvMap param = new WcsSrgvMap();
|
||||||
|
param.setZ(floor);
|
||||||
|
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(param);
|
||||||
|
|
||||||
|
HashMap<String, WcsSrgvMap> maps = new HashMap<>();
|
||||||
|
for (WcsSrgvMap wcsSrgvMap : wcsSrgvMaps) {
|
||||||
|
maps.put(wcsSrgvMap.getSiteId(), wcsSrgvMap);
|
||||||
|
}
|
||||||
|
return maps;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
@Override
|
||||||
*
|
public int[][] handleMap(Map<String, WcsSrgvMap> maps, DeviceSrgv deviceSrgv) {
|
||||||
*
|
|
||||||
* */
|
|
||||||
@Autowired
|
|
||||||
@Cacheable(value = "CSpaceDataCache" ,key = "'CSpaceDataCacheKey_'")
|
|
||||||
public Map<String,String> getSpaceDataCache() {
|
|
||||||
log.info("从数据库获取初始化地图数据");
|
|
||||||
|
|
||||||
WcsSrgvMap wcsSrgvMap = new WcsSrgvMap();
|
//1.锁定其他车任务路径
|
||||||
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(wcsSrgvMap);
|
lockedOtherCarQueuePath(maps, deviceSrgv);
|
||||||
//将集合转为map,
|
//2.锁定无任务小车当前位置
|
||||||
Map<String, String> siteMap = new HashMap<>();
|
lockedOtherCarCurrSite(maps, deviceSrgv);
|
||||||
|
//3.锁定离线小车当前位置
|
||||||
|
lockedOfflineCarCurrSite(maps, deviceSrgv);
|
||||||
|
|
||||||
for (WcsSrgvMap srgvMap : wcsSrgvMaps) {
|
int[][] mapsInt = new int[29][11];
|
||||||
String siteId = srgvMap.getSiteId();
|
for (String site : maps.keySet()) {
|
||||||
String warehouse = srgvMap.getWarehouse();
|
WcsSrgvMap wcsSrgvMap = maps.get(site);
|
||||||
if(!Objects.equals(siteId,"000")){
|
mapsInt[wcsSrgvMap.getX()][wcsSrgvMap.getY()] = wcsSrgvMap.getValue();
|
||||||
siteMap.put(siteId,warehouse);
|
}
|
||||||
|
return mapsInt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WcsSrgvMap selectRoadSiteByArr(int x, int y, int z) {
|
||||||
|
WcsSrgvMap param = new WcsSrgvMap();
|
||||||
|
param.setX(x);
|
||||||
|
param.setY(y);
|
||||||
|
param.setZ(z);
|
||||||
|
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(param);
|
||||||
|
if (CollUtil.isNotEmpty(wcsSrgvMaps)){
|
||||||
|
return wcsSrgvMaps.get(0);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 锁定离线小车当前位置
|
||||||
|
*
|
||||||
|
* @param maps
|
||||||
|
* @param deviceSrgv
|
||||||
|
*/
|
||||||
|
private void lockedOfflineCarCurrSite(Map<String, WcsSrgvMap> maps, DeviceSrgv deviceSrgv) {
|
||||||
|
//获取所有小车状态
|
||||||
|
List<DeviceSrgv> deviceSrgvs = deviceSrgvService.selectDeviceSrgvList(new DeviceSrgv());
|
||||||
|
//获取其他小车离线站点
|
||||||
|
List<DeviceSrgv> offlineSrgvList = deviceSrgvs.stream().filter(x ->
|
||||||
|
!x.getDeviceId().equals(deviceSrgv.getDeviceId()) &&
|
||||||
|
StrUtil.isNotEmpty(x.getOfflineSite())
|
||||||
|
).collect(Collectors.toList());
|
||||||
|
//锁定离线小车站点
|
||||||
|
if (CollUtil.isNotEmpty(offlineSrgvList)) {
|
||||||
|
for (DeviceSrgv offlineSrgv : offlineSrgvList) {
|
||||||
|
if (maps.containsKey(offlineSrgv.getOfflineSite())) {
|
||||||
|
maps.get(offlineSrgv.getOfflineSite()).setValue(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return siteMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
@Cacheable(value = "RoadDataCache" ,key = "'RoadDataCacheKey_floor_' +#floor")
|
* 锁定无任务小车当前位置
|
||||||
@Override
|
*
|
||||||
public List<WcsSrgvMap> getRoadDataCache(int floor) {
|
* @param arrByRoadSite
|
||||||
log.info("从数据库获取初始化地图");
|
* @param deviceSrgv
|
||||||
|
*/
|
||||||
WcsSrgvMap wcsSrgvMap1 = new WcsSrgvMap();
|
private void lockedOtherCarCurrSite(Map<String, WcsSrgvMap> arrByRoadSite, DeviceSrgv deviceSrgv) {
|
||||||
wcsSrgvMap1.setUz(floor);
|
//锁定其他车当前位置
|
||||||
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(wcsSrgvMap1);
|
for (String sRgv : PlcSrgvRead.deviceSrgvMap.keySet()) {
|
||||||
|
if (!sRgv.equals(deviceSrgv.getDeviceId().toString())) {
|
||||||
return wcsSrgvMaps;
|
DeviceSrgv otherCar = PlcSrgvRead.deviceSrgvMap.get(sRgv);
|
||||||
}
|
String currSite = otherCar.getCurrSite();
|
||||||
|
if (arrByRoadSite.containsKey(currSite)) {
|
||||||
/*
|
arrByRoadSite.get(currSite).setValue(0);
|
||||||
*
|
}
|
||||||
* 每层二维地图
|
}
|
||||||
* */
|
|
||||||
@Override
|
|
||||||
@Cacheable(value = "RoadCache" ,key = "'RoadCacheKey_floor_' +#floor")
|
|
||||||
public int[][] getRoadCache(int floor) {
|
|
||||||
|
|
||||||
List<WcsSrgvMap> roadDataCache = selfProxy.getRoadDataCache(floor);
|
|
||||||
|
|
||||||
//集合转为二维数组
|
|
||||||
int[][] grid = new int[30][137];
|
|
||||||
for (WcsSrgvMap roadMap : roadDataCache) {
|
|
||||||
grid[roadMap.getX().intValue()][roadMap.getY().intValue()] = roadMap.getValue().intValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return grid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
* 锁定其他车任务路径
|
||||||
*
|
*
|
||||||
* 每层 站点与二维数组关系
|
* @param maps
|
||||||
* */
|
* @param deviceSrgv
|
||||||
@Override
|
*/
|
||||||
@CachePut(value = "SiteCache" ,key = "'SiteKey_floor_' +#floor")
|
private void lockedOtherCarQueuePath(Map<String, WcsSrgvMap> maps, DeviceSrgv deviceSrgv) {
|
||||||
public Map<String, int[]> getArrByRoadSite(int floor) {
|
//查询所有小车作业
|
||||||
List<WcsSrgvMap> roadDataCache = selfProxy.getRoadDataCache(floor);
|
List<WcsSrgvQueue> wcsSrgvQueues = wcsSrgvQueueService.selectWcsSrgvQueueList(new WcsSrgvQueue());
|
||||||
|
if (CollUtil.isNotEmpty(wcsSrgvQueues)) {
|
||||||
//将集合转为map,key为siteId,value为x,y
|
//筛选其他小车队列
|
||||||
Map<String, int[]> siteMap = new HashMap<>();
|
List<WcsSrgvQueue> otherCarQueue = wcsSrgvQueues.stream().filter(x -> !x.getAgvId().equals(deviceSrgv.getDeviceId().toString())).collect(Collectors.toList());
|
||||||
for (WcsSrgvMap map : roadDataCache) {
|
if (CollUtil.isNotEmpty(otherCarQueue)) {
|
||||||
siteMap.put(map.getSiteId(), new int[]{map.getX(), map.getY(),floor});
|
//添加其他小车路径列表
|
||||||
|
HashSet<String> otherCarSiteList = new HashSet<>();
|
||||||
|
for (WcsSrgvQueue wcsSrgvQueue : otherCarQueue) {
|
||||||
|
otherCarSiteList.addAll(Arrays.asList(wcsSrgvQueue.getPathInfo().split(",")));
|
||||||
|
}
|
||||||
|
//锁定其他小车路径
|
||||||
|
if (CollUtil.isNotEmpty(otherCarSiteList)) {
|
||||||
|
for (String siteId : otherCarSiteList) {
|
||||||
|
if (maps.containsKey(siteId)) {
|
||||||
|
maps.get(siteId).setValue(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return siteMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
@Override
|
|
||||||
@CachePut(value = "ArrCache" ,key = "'ArrKey_floor_' +#floor")
|
|
||||||
public Map<String, String> getRoadSiteByArr(int floor) {
|
|
||||||
List<WcsSrgvMap> roadDataCache = selfProxy.getRoadDataCache(floor);
|
|
||||||
|
|
||||||
//将集合转为map,key为x,y,value为siteId
|
|
||||||
Map<String, String> siteMap = new HashMap<>();
|
|
||||||
for (WcsSrgvMap map : roadDataCache) {
|
|
||||||
siteMap.put(map.getX()+","+map.getY(), map.getSiteId());
|
|
||||||
}
|
|
||||||
|
|
||||||
return siteMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//更新地图
|
|
||||||
@Override
|
|
||||||
@CachePut(value = "RoadCache" ,key = "'RoadCacheKey_floor_' +#floor")
|
|
||||||
public int[][] updateRoadCache(int floor, List<int[]> grid,int value) {
|
|
||||||
|
|
||||||
|
|
||||||
int[][] roadCache = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
for (int[] ints : grid) {
|
|
||||||
roadCache[ints[0]][ints[1]] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return roadCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//获取载货路径
|
|
||||||
@Override
|
|
||||||
public List<int[]> findFullPath(int floor, int startX, int startY, int endX, int endY) {
|
|
||||||
|
|
||||||
int[][] grid = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
//对二维数组 进行深拷贝
|
|
||||||
int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new);
|
|
||||||
|
|
||||||
//剔除不允许站点
|
|
||||||
extractInflectionPoints(roadCache,floor);
|
|
||||||
|
|
||||||
// 调用路径规划算法
|
|
||||||
return PathFinder.findShortestPathFrom2To2Or1(roadCache,startX,startY,endX,endY);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[][] findFullMap(int floor, int startX, int startY, int endX, int endY) {
|
|
||||||
|
|
||||||
int[][] grid = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
//对二维数组 进行深拷贝
|
|
||||||
int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new);
|
|
||||||
|
|
||||||
//剔除不允许站点
|
|
||||||
extractInflectionPoints(roadCache,floor);
|
|
||||||
|
|
||||||
// 调用路径规划算法
|
|
||||||
return roadCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[][] findFullMap(int floor, int startX, int startY, int endX, int endY,DeviceSrgv splc) {
|
|
||||||
|
|
||||||
int[][] grid = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
//对二维数组 进行深拷贝
|
|
||||||
int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new);
|
|
||||||
|
|
||||||
//剔除不允许站点(不包含自己)
|
|
||||||
extractInflectionPoints(roadCache,floor,splc);
|
|
||||||
|
|
||||||
// 调用路径规划算法
|
|
||||||
return roadCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[][] findFullMap(int floor, int startX, int startY, int endX, int endY,DeviceSrgv splc,List<String> noSite) {
|
|
||||||
|
|
||||||
int[][] grid = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
//对二维数组 进行深拷贝
|
|
||||||
int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new);
|
|
||||||
|
|
||||||
//剔除不允许站点(不包含自己)
|
|
||||||
extractInflectionPoints(roadCache,floor,splc);
|
|
||||||
|
|
||||||
//将地图 roadCache 中的 所有站点noSite排除掉
|
|
||||||
agvPathProcessor.processNoSites(roadCache,floor,noSite);
|
|
||||||
|
|
||||||
// 调用路径规划算法
|
|
||||||
return roadCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//获取空载路径
|
|
||||||
@Override
|
|
||||||
public List<int[]> findEmptyPath(int floor, int startX, int startY, int endX, int endY) {
|
|
||||||
|
|
||||||
|
|
||||||
int[][] grid = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
//对二维数组 进行深拷贝
|
|
||||||
int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new);
|
|
||||||
|
|
||||||
//剔除不允许站点
|
|
||||||
extractInflectionPoints(roadCache,floor);
|
|
||||||
|
|
||||||
List<int[]> shortestPath = PathFinder.findShortestPath(grid, startX, startY, endX, endY);
|
|
||||||
return shortestPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY, DeviceSrgv splc) {
|
|
||||||
|
|
||||||
|
|
||||||
int[][] grid = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
//对二维数组 进行深拷贝
|
|
||||||
int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new);
|
|
||||||
|
|
||||||
//剔除不允许站点(不包含自己)
|
|
||||||
extractInflectionPoints(roadCache,floor,splc);
|
|
||||||
|
|
||||||
|
|
||||||
return roadCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY) {
|
|
||||||
|
|
||||||
|
|
||||||
int[][] grid = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
//对二维数组 进行深拷贝
|
|
||||||
int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new);
|
|
||||||
|
|
||||||
//剔除不允许站点
|
|
||||||
extractInflectionPoints(roadCache,floor);
|
|
||||||
|
|
||||||
|
|
||||||
return roadCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 剔除不可用站点,并返回新地图
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
private int[][] extractInflectionPoints(int[][] ints,int floor){
|
|
||||||
|
|
||||||
|
|
||||||
//所有车锁定路径
|
|
||||||
agvPathProcessor.processAgvPathInfo(ints,floor);
|
|
||||||
//所有在线车当前站点
|
|
||||||
agvPathProcessor.processOnlineAgvSites(ints,floor);
|
|
||||||
//所有离线车站点
|
|
||||||
agvPathProcessor.processOfflineAgvSites(ints,floor);
|
|
||||||
|
|
||||||
return ints;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int[][] extractInflectionPoints(int[][] ints, int floor, DeviceSrgv splc){
|
|
||||||
|
|
||||||
String agvId = String.valueOf(splc.getDeviceId());
|
|
||||||
String currSite = splc.getCurrSite();
|
|
||||||
//所有车锁定路径
|
|
||||||
agvPathProcessor.processAgvPathInfo(ints,floor);
|
|
||||||
//所有在线车当前站点
|
|
||||||
agvPathProcessor.processOnlineAgvSites(ints,floor);
|
|
||||||
//所有离线车站点
|
|
||||||
agvPathProcessor.processOfflineAgvSites(ints,floor);
|
|
||||||
|
|
||||||
return ints;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int[][] findMap(int floor) {
|
|
||||||
int[][] grid = selfProxy.getRoadCache(floor);
|
|
||||||
|
|
||||||
//对二维数组 进行深拷贝
|
|
||||||
int[][] roadCache = Arrays.stream(grid).map(int[]::clone).toArray(int[][]::new);
|
|
||||||
|
|
||||||
return roadCache;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ public class PathFinder {
|
|||||||
int[][] gCost = new int[rows][cols];
|
int[][] gCost = new int[rows][cols];
|
||||||
// fCost: gCost + 启发式估计成本(从当前节点到终点)
|
// fCost: gCost + 启发式估计成本(从当前节点到终点)
|
||||||
int[][] fCost = new int[rows][cols];
|
int[][] fCost = new int[rows][cols];
|
||||||
// prev: 记录路径回溯信息
|
// prev: 记录路径回溯信息,初始化为无效值
|
||||||
int[][][] prev = new int[rows][cols][2];
|
int[][][] prev = new int[rows][cols][2];
|
||||||
// closedSet: 记录已访问的节点
|
// closedSet: 记录已访问的节点
|
||||||
boolean[][] closedSet = new boolean[rows][cols];
|
boolean[][] closedSet = new boolean[rows][cols];
|
||||||
@@ -137,6 +137,10 @@ public class PathFinder {
|
|||||||
for (int i = 0; i < rows; i++) {
|
for (int i = 0; i < rows; i++) {
|
||||||
Arrays.fill(gCost[i], Integer.MAX_VALUE);
|
Arrays.fill(gCost[i], Integer.MAX_VALUE);
|
||||||
Arrays.fill(fCost[i], Integer.MAX_VALUE);
|
Arrays.fill(fCost[i], Integer.MAX_VALUE);
|
||||||
|
// 初始化 prev 数组为无效值 [-1, -1]
|
||||||
|
for (int j = 0; j < cols; j++) {
|
||||||
|
prev[i][j] = new int[]{-1, -1};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 优先队列,按fCost排序
|
// 优先队列,按fCost排序
|
||||||
@@ -211,8 +215,8 @@ public class PathFinder {
|
|||||||
path.add(new int[]{currX, currY});
|
path.add(new int[]{currX, currY});
|
||||||
int[] p = prev[currX][currY];
|
int[] p = prev[currX][currY];
|
||||||
|
|
||||||
// 检查路径有效性
|
// 检查路径有效性,使用 -1,-1 作为无效值判断
|
||||||
if (p[0] == 0 && p[1] == 0 && (currX != startX || currY != startY)) {
|
if (p[0] == -1 && p[1] == -1 && (currX != startX || currY != startY)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,32 +407,13 @@ public class PathFinder {
|
|||||||
* - 方向变化点(水平转垂直 / 垂直转水平)
|
* - 方向变化点(水平转垂直 / 垂直转水平)
|
||||||
*
|
*
|
||||||
* @param path 路径坐标列表(逻辑坐标)
|
* @param path 路径坐标列表(逻辑坐标)
|
||||||
* @param grid 网格数据
|
|
||||||
* @return 拐点坐标列表(逻辑坐标)
|
* @return 拐点坐标列表(逻辑坐标)
|
||||||
*/
|
*/
|
||||||
public static List<int[]> extractInflectionPoints2(List<int[]> path, int[][] grid) {
|
public static List<int[]> extractInflectionPoints2(List<int[]> path) {
|
||||||
List<int[]> inflectionPoints = new ArrayList<>();
|
List<int[]> inflectionPoints = new ArrayList<>();
|
||||||
|
|
||||||
// 记录类型转换点和方向变化点
|
// 记录类型转换点和方向变化点
|
||||||
Set<String> seen = new HashSet<>();
|
Set<String> seen = new HashSet<>();
|
||||||
|
|
||||||
// 检测类型转换点(1 ↔ 2)
|
|
||||||
/*for (int i = 0; i < path.size() - 1; i++) {
|
|
||||||
int[] current = path.get(i);
|
|
||||||
int[] next = path.get(i + 1);
|
|
||||||
int currentValue = grid[current[0]][current[1]];
|
|
||||||
int nextValue = grid[next[0]][next[1]];
|
|
||||||
|
|
||||||
if ((currentValue == 1 && nextValue == 2) || (currentValue == 2 && nextValue == 1)) {
|
|
||||||
int[] point = currentValue == 2 ? current : next;
|
|
||||||
String key = point[0] + "," + point[1];
|
|
||||||
if (!seen.contains(key)) {
|
|
||||||
seen.add(key);
|
|
||||||
inflectionPoints.add(point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// 检测方向变化点(连续三点的方向变化)
|
// 检测方向变化点(连续三点的方向变化)
|
||||||
for (int i = 1; i < path.size() - 1; i++) {
|
for (int i = 1; i < path.size() - 1; i++) {
|
||||||
int[] prev = path.get(i - 1);
|
int[] prev = path.get(i - 1);
|
||||||
@@ -448,9 +433,7 @@ public class PathFinder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 排序后返回(可选)
|
// 排序后返回(可选)
|
||||||
return inflectionPoints; /*.stream()
|
return inflectionPoints;
|
||||||
.sorted(Comparator.comparingInt(a -> a[0] * 1000 + a[1]))
|
|
||||||
.collect(Collectors.toList());*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import cn.hutool.core.collection.CollUtil;
|
|||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import com.ruoyi.bas.port.domain.WcsPort;
|
|
||||||
import com.ruoyi.bas.port.service.IWcsPortService;
|
import com.ruoyi.bas.port.service.IWcsPortService;
|
||||||
import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap;
|
import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap;
|
||||||
import com.ruoyi.bas.srgvmap.service.IWcsSrgvMapService;
|
import com.ruoyi.bas.srgvmap.service.IWcsSrgvMapService;
|
||||||
@@ -75,17 +74,14 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
if (ObjUtil.isNotNull(PlcSrgvRead.deviceSrgvMap.get(code))) {
|
if (ObjUtil.isNotNull(PlcSrgvRead.deviceSrgvMap.get(code))) {
|
||||||
|
|
||||||
DeviceSrgv deviceSrgv = PlcSrgvRead.deviceSrgvMap.get(code);
|
DeviceSrgv deviceSrgv = PlcSrgvRead.deviceSrgvMap.get(code);
|
||||||
//循环所有楼层
|
sRgvTask(deviceSrgv);
|
||||||
for (int i = 1; i <= 8; i++) {
|
|
||||||
sRgvTask(deviceSrgv, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
createCarInQueue();
|
createCarInQueue();
|
||||||
|
|
||||||
createCarOutQueue();
|
createCarOutQueue();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
log.error("堆垛机设备为空");
|
log.error("小车设备为空");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
@@ -107,15 +103,15 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
/**
|
/**
|
||||||
* 四向小车任务处理
|
* 四向小车任务处理
|
||||||
*/
|
*/
|
||||||
private void sRgvTask(DeviceSrgv deviceSrgv, int floor) {
|
private void sRgvTask(DeviceSrgv deviceSrgv) {
|
||||||
//处理队列下发
|
//处理队列下发
|
||||||
resQueue(deviceSrgv, floor);
|
resQueue(deviceSrgv);
|
||||||
|
|
||||||
//小车完成队列
|
//小车完成队列
|
||||||
completeCarTask(deviceSrgv, floor);
|
completeCarTask(deviceSrgv);
|
||||||
|
|
||||||
//小车发送任务
|
//小车发送任务
|
||||||
sendTask(deviceSrgv, floor);
|
sendTask(deviceSrgv);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,10 +209,10 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
/**
|
/**
|
||||||
* 小车发送任务
|
* 小车发送任务
|
||||||
*/
|
*/
|
||||||
private void sendTask(DeviceSrgv deviceSrgv, int floor) {
|
private void sendTask(DeviceSrgv deviceSrgv) {
|
||||||
WcsSrgvQueue param = new WcsSrgvQueue();
|
WcsSrgvQueue param = new WcsSrgvQueue();
|
||||||
param.setIssued("0");
|
param.setIssued("0");
|
||||||
param.setTheFloor(Convert.toStr(floor));
|
param.setAgvId(deviceSrgv.getDeviceId().toString());
|
||||||
List<WcsSrgvQueue> wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(param);
|
List<WcsSrgvQueue> wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(param);
|
||||||
if (CollUtil.isEmpty(wcsSrgvQueues)) {
|
if (CollUtil.isEmpty(wcsSrgvQueues)) {
|
||||||
return;
|
return;
|
||||||
@@ -232,10 +228,10 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
//判断小车是否在起始点
|
//判断小车是否在起始点
|
||||||
if (currSite.equals(startSite)) {
|
if (currSite.equals(startSite)) {
|
||||||
//小车在起始点
|
//小车在起始点
|
||||||
sendMainTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor);
|
sendMainTask(deviceSrgv, wcsSrgvQueue, currSite, endSite);
|
||||||
} else {
|
} else {
|
||||||
//小车不在起始点
|
//小车不在起始点
|
||||||
sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, startSite, floor);
|
sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, startSite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,51 +242,58 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
/**
|
/**
|
||||||
* 小车发送点对点任务
|
* 小车发送点对点任务
|
||||||
*/
|
*/
|
||||||
private void sendPointToPointTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String startSite, String endSite, int floor) {
|
private boolean sendPointToPointTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String startSite, String endSite) {
|
||||||
|
Integer floor = deviceSrgv.getCurrFloor();
|
||||||
//获取当前地图
|
//获取当前地图
|
||||||
Map<String, int[]> arrByRoadSite = roadCacheService.getArrByRoadSite(floor);
|
Map<String, WcsSrgvMap> arrByRoadSite = roadCacheService.getArrByRoadSite(floor);
|
||||||
|
|
||||||
|
//处理地图
|
||||||
|
int[][] emptyMap = roadCacheService.handleMap(arrByRoadSite, deviceSrgv);
|
||||||
|
|
||||||
//获取空载地图
|
|
||||||
int[][] emptyMap = roadCacheService.findEmptyMap(floor, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1], deviceSrgv);
|
|
||||||
//计算最短路径
|
//计算最短路径
|
||||||
List<int[]> shortestPath = PathFinder.findShortestPath(emptyMap, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1]);
|
List<int[]> shortestPath = PathFinder.findShortestPath(emptyMap, arrByRoadSite.get(startSite).getX(), arrByRoadSite.get(startSite).getY(), arrByRoadSite.get(endSite).getX(), arrByRoadSite.get(endSite).getY());
|
||||||
|
|
||||||
//判断是否能规划出最短路径
|
//判断是否能规划出最短路径
|
||||||
if (shortestPath == null || shortestPath.isEmpty()) {
|
if (shortestPath == null || shortestPath.isEmpty()) {
|
||||||
return;
|
log.error("无最短路径 taskNo:{}", wcsSrgvQueue.getTaskNo());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取拐点路径
|
//获取拐点路径
|
||||||
List<int[]> trun = PathFinder.extractInflectionPoints2(shortestPath, emptyMap);
|
List<int[]> trun = PathFinder.extractInflectionPoints2(shortestPath);
|
||||||
|
|
||||||
// 路径点拼接
|
// 路径点拼接
|
||||||
StringBuilder pathBuilder = new StringBuilder();
|
StringBuilder pathBuilder = new StringBuilder();
|
||||||
Map<String, String> roadSiteByArr = roadCacheService.getRoadSiteByArr(floor);
|
if (!shortestPath.isEmpty()) {
|
||||||
for (int[] point : shortestPath) {
|
for (int[] ints : shortestPath) {
|
||||||
String site = roadSiteByArr.get(point[0] + "," + point[1]);
|
WcsSrgvMap roadSiteByArr = roadCacheService.selectRoadSiteByArr(ints[0], ints[1], floor);
|
||||||
if (!"000".equals(site)) {
|
if (roadSiteByArr == null) {
|
||||||
|
log.error("无此站点 x y z :{},{},{}", ints[0], ints[1], floor);
|
||||||
|
throw new RuntimeException("点位信息错误");
|
||||||
|
}
|
||||||
|
String site = roadSiteByArr.getSiteId();
|
||||||
pathBuilder.append(site).append(",");
|
pathBuilder.append(site).append(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (pathBuilder.length() > 0) {
|
|
||||||
pathBuilder.setLength(pathBuilder.length() - 1); // 移除最后一个逗号
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拐点拼接
|
// 拐点拼接
|
||||||
StringBuilder inflectionBuilder = new StringBuilder();
|
StringBuilder turnBuilder = new StringBuilder();
|
||||||
if (!trun.isEmpty()) {
|
if (!trun.isEmpty()) {
|
||||||
for (int[] ints : trun) {
|
for (int[] ints : trun) {
|
||||||
String site = roadSiteByArr.get(ints[0] + "," + ints[1]);//获取站点
|
WcsSrgvMap roadSiteByArr = roadCacheService.selectRoadSiteByArr(ints[0], ints[1], floor);
|
||||||
inflectionBuilder.append(site).append(",");
|
if (roadSiteByArr == null) {
|
||||||
|
log.error("无此站点 x y z :{},{},{}", ints[0], ints[1], floor);
|
||||||
|
throw new RuntimeException("点位信息错误");
|
||||||
|
}
|
||||||
|
String site = roadSiteByArr.getSiteId();
|
||||||
|
turnBuilder.append(site).append(",");
|
||||||
}
|
}
|
||||||
if (inflectionBuilder.length() > 0) {
|
if (turnBuilder.length() > 0) {
|
||||||
inflectionBuilder.setLength(inflectionBuilder.length() - 1);
|
turnBuilder.setLength(turnBuilder.length() - 1);
|
||||||
}
|
}
|
||||||
// 当trun长度小于6时,后面用0拼接
|
// 当trun长度小于6时,后面用0拼接
|
||||||
if (trun.size() < 6) {
|
if (trun.size() < 6) {
|
||||||
for (int i = trun.size(); i < 6; i++) {
|
for (int i = trun.size(); i < 6; i++) {
|
||||||
inflectionBuilder.append(",0");
|
turnBuilder.append(",0");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,7 +302,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
if (!trun.isEmpty()) {
|
if (!trun.isEmpty()) {
|
||||||
SendData2 path = new SendData2();
|
SendData2 path = new SendData2();
|
||||||
path.setAddress("4000");//地址
|
path.setAddress("4000");//地址
|
||||||
path.setData(startSite + "," + endSite + "," + inflectionBuilder.toString());
|
path.setData(startSite + "," + endSite + "," + turnBuilder);
|
||||||
path.setType(2);
|
path.setType(2);
|
||||||
sendDataList.add(path);
|
sendDataList.add(path);
|
||||||
} else {
|
} else {
|
||||||
@@ -335,23 +338,32 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
|
|
||||||
//下发数据
|
//下发数据
|
||||||
boolean b = sendCarTask(sendDataList, deviceSrgv);
|
boolean b = sendCarTask(sendDataList, deviceSrgv);
|
||||||
|
if (b) {
|
||||||
|
wcsSrgvQueue.setPathInfo(pathBuilder.toString());
|
||||||
|
wcsSrgvQueue.setTrunPath(turnBuilder.toString());
|
||||||
|
wcsSagvQueueMapper.updateWcsSrgvQueue(wcsSrgvQueue);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
log.error("小车下发失败 taskNo:{}", wcsSrgvQueue.getTaskNo());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小车发送点对点主任务
|
* 小车发送点对点主任务
|
||||||
*/
|
*/
|
||||||
private void sendMainTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String currSite, String endSite, int floor) {
|
private void sendMainTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String currSite, String endSite) {
|
||||||
String taskType = wcsSrgvQueue.getTaskType();
|
String taskType = wcsSrgvQueue.getDefault02();
|
||||||
boolean sendFlag = false;
|
boolean sendFlag = false;
|
||||||
switch (taskType) {
|
switch (taskType) {
|
||||||
case "1":
|
case "4":
|
||||||
// 空车任务(充电、换层、手动点到点、除尘等)
|
// 空车任务(充电、换层、手动点到点、除尘等)
|
||||||
sendFlag = sendEmptyCarTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor);
|
sendFlag = sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, endSite);
|
||||||
break;
|
break;
|
||||||
|
case "1":
|
||||||
case "2":
|
case "2":
|
||||||
// 载货任务(出库、入库、移库等)
|
// 载货任务(出库、入库、移库等)
|
||||||
sendFlag = sendFullCarTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor);
|
sendFlag = sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, endSite);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,253 +372,6 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 小车发送载货任务
|
|
||||||
*/
|
|
||||||
private boolean sendFullCarTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String startSite, String endSite, int floor) {
|
|
||||||
|
|
||||||
//0 待机 1去向原站 2 到达原站托盘定位 3 上升至中位顶取货物 4生成去向目标站路径
|
|
||||||
// 5去向目标站 6下降至低位放货,工作完成,将阶段设置为0. 20:执行点到点命令运行中 21:到达点到目标位置 22:小车充电中
|
|
||||||
int workPhase = deviceSrgv.getWorkPhase();
|
|
||||||
int status = deviceSrgv.getStatus();// 0:未知 1:待机 2:运行 3:报警
|
|
||||||
int workMode = deviceSrgv.getWorkMode();
|
|
||||||
|
|
||||||
|
|
||||||
//取货规划路径和下发,在货底下,并且待机,任务未被下发
|
|
||||||
if ((workPhase == 0) && status == 1 && workMode == 5) {
|
|
||||||
//查找载货路径
|
|
||||||
Map<String, int[]> arrByRoadSite = roadCacheService.getArrByRoadSite(floor);
|
|
||||||
//获取空载地图(剔除不包含自己的障碍)(250919,排除其他站点)
|
|
||||||
|
|
||||||
String noTar0 = null;
|
|
||||||
String noTar1 = null;
|
|
||||||
|
|
||||||
if ("3".equals(wcsSrgvQueue.getCargo())) {
|
|
||||||
noTar0 = getNoTar(startSite);
|
|
||||||
noTar1 = getNoTar(endSite);
|
|
||||||
} else if ("1".equals(wcsSrgvQueue.getCargo())) {
|
|
||||||
noTar1 = getNoTar(endSite);
|
|
||||||
} else if ("2".equals(wcsSrgvQueue.getCargo())) {
|
|
||||||
noTar0 = getNoTar(startSite);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int[][] fullMap = null;
|
|
||||||
if (noTar0 == null && noTar1 == null) {
|
|
||||||
fullMap = roadCacheService.findFullMap(floor, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1], deviceSrgv);
|
|
||||||
} else {
|
|
||||||
List<String> strings = new ArrayList<>();//排除站点
|
|
||||||
if (noTar0 != null) {
|
|
||||||
strings.add(noTar0);
|
|
||||||
}
|
|
||||||
if (noTar1 != null) {
|
|
||||||
strings.add(noTar1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fullMap = roadCacheService.findFullMap(floor, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1], deviceSrgv, strings);
|
|
||||||
}
|
|
||||||
|
|
||||||
//计算最短路径
|
|
||||||
List<int[]> shortestPath = PathFinder.findShortestPathFrom2To2Or1(fullMap, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1]);
|
|
||||||
//判断是否能规划出最短路径
|
|
||||||
if (shortestPath == null || shortestPath.isEmpty()) {
|
|
||||||
//空车从当前点去目标点没有可以路径,校验是否是同层其他车影响,要上次其他车避让任务
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取拐点路径
|
|
||||||
List<int[]> trun = PathFinder.extractInflectionPoints2(shortestPath, fullMap);
|
|
||||||
|
|
||||||
// 路径点拼接
|
|
||||||
StringBuilder pathBuilder = new StringBuilder();
|
|
||||||
Map<String, String> roadSiteByArr = roadCacheService.getRoadSiteByArr(Integer.parseInt(wcsSrgvQueue.getTheFloor()));
|
|
||||||
for (int[] point : shortestPath) {
|
|
||||||
String site = roadSiteByArr.get(point[0] + "," + point[1]);
|
|
||||||
if (!"000".equals(site)) {
|
|
||||||
pathBuilder.append(site).append(",");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pathBuilder.length() > 0) {
|
|
||||||
pathBuilder.setLength(pathBuilder.length() - 1); // 移除最后一个逗号
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拐点拼接
|
|
||||||
StringBuilder inflectionBuilder = new StringBuilder();
|
|
||||||
if (!trun.isEmpty()) {
|
|
||||||
for (int[] ints : trun) {
|
|
||||||
String site = roadSiteByArr.get(ints[0] + "," + ints[1]);//获取站点
|
|
||||||
inflectionBuilder.append(site).append(",");
|
|
||||||
}
|
|
||||||
if (inflectionBuilder.length() > 0) {
|
|
||||||
inflectionBuilder.setLength(inflectionBuilder.length() - 1);
|
|
||||||
}
|
|
||||||
// 当trun长度小于6时,后面用0拼接
|
|
||||||
if (trun.size() < 6) {
|
|
||||||
for (int i = trun.size(); i < 6; i++) {
|
|
||||||
inflectionBuilder.append(",0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<SendData2> sendDataList = new ArrayList<>();
|
|
||||||
|
|
||||||
|
|
||||||
if (!trun.isEmpty()) {
|
|
||||||
SendData2 path = new SendData2();
|
|
||||||
path.setAddress("4000");//地址
|
|
||||||
path.setData(startSite + "," + endSite + "," + inflectionBuilder);
|
|
||||||
path.setType(2);
|
|
||||||
sendDataList.add(path);
|
|
||||||
} else {
|
|
||||||
SendData2 path = new SendData2();
|
|
||||||
path.setAddress("4000");//地址
|
|
||||||
path.setData(startSite + "," + endSite);
|
|
||||||
path.setType(2);
|
|
||||||
sendDataList.add(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
String siteId = wcsSrgvQueue.getTaskNo();//+ "," + startSite + "," + endSite;
|
|
||||||
SendData2 site = new SendData2();
|
|
||||||
site.setAddress("4400");
|
|
||||||
site.setData(siteId);
|
|
||||||
site.setType(2);
|
|
||||||
sendDataList.add(site);
|
|
||||||
//下发类型
|
|
||||||
SendData2 taskType = new SendData2();
|
|
||||||
taskType.setAddress("2200");
|
|
||||||
taskType.setData(wcsSrgvQueue.getTaskType());
|
|
||||||
taskType.setType(1);
|
|
||||||
sendDataList.add(taskType);
|
|
||||||
//下发标志转换
|
|
||||||
SendData2 flag = new SendData2();
|
|
||||||
flag.setAddress("2202");
|
|
||||||
flag.setData("1");
|
|
||||||
flag.setType(1);
|
|
||||||
sendDataList.add(flag);
|
|
||||||
|
|
||||||
//boolean write = true;
|
|
||||||
return sendCarTask(sendDataList, deviceSrgv);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 获取特俗区域的母通道排除站点
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
private String getNoTar(String site) {
|
|
||||||
|
|
||||||
String s = site.substring(site.length() - 4);
|
|
||||||
|
|
||||||
String p = site.substring(0, 2);
|
|
||||||
int pi = Integer.parseInt(p);
|
|
||||||
|
|
||||||
String l = site.substring(2, 4);
|
|
||||||
int li = Integer.parseInt(l);//排
|
|
||||||
|
|
||||||
String tarSite = null;
|
|
||||||
if (pi > 4 && pi < 15 && li > 30) {
|
|
||||||
tarSite = "16" + s;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
return tarSite;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 小车发送空车任务
|
|
||||||
*/
|
|
||||||
private boolean sendEmptyCarTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String startSite, String endSite, int floor) {
|
|
||||||
//获取当前地图
|
|
||||||
Map<String, int[]> arrByRoadSite = roadCacheService.getArrByRoadSite(floor);
|
|
||||||
//获取空载地图
|
|
||||||
int[][] emptyMap = roadCacheService.findEmptyMap(floor, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1], deviceSrgv);
|
|
||||||
//计算最短路径
|
|
||||||
List<int[]> shortestPath = PathFinder.findShortestPath(emptyMap, arrByRoadSite.get(startSite)[0], arrByRoadSite.get(startSite)[1], arrByRoadSite.get(endSite)[0], arrByRoadSite.get(endSite)[1]);
|
|
||||||
|
|
||||||
//判断是否能规划出最短路径
|
|
||||||
if (shortestPath == null || shortestPath.isEmpty()) {
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//获取拐点路径
|
|
||||||
List<int[]> trun = PathFinder.extractInflectionPoints2(shortestPath, emptyMap);
|
|
||||||
|
|
||||||
// 路径点拼接
|
|
||||||
StringBuilder pathBuilder = new StringBuilder();
|
|
||||||
Map<String, String> roadSiteByArr = roadCacheService.getRoadSiteByArr(floor);
|
|
||||||
for (int[] point : shortestPath) {
|
|
||||||
String site = roadSiteByArr.get(point[0] + "," + point[1]);
|
|
||||||
if (!"000".equals(site)) {
|
|
||||||
pathBuilder.append(site).append(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (pathBuilder.length() > 0) {
|
|
||||||
pathBuilder.setLength(pathBuilder.length() - 1); // 移除最后一个逗号
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拐点拼接
|
|
||||||
StringBuilder inflectionBuilder = new StringBuilder();
|
|
||||||
if (!trun.isEmpty()) {
|
|
||||||
for (int[] ints : trun) {
|
|
||||||
String site = roadSiteByArr.get(ints[0] + "," + ints[1]);//获取站点
|
|
||||||
inflectionBuilder.append(site).append(",");
|
|
||||||
}
|
|
||||||
if (inflectionBuilder.length() > 0) {
|
|
||||||
inflectionBuilder.setLength(inflectionBuilder.length() - 1);
|
|
||||||
}
|
|
||||||
// 当trun长度小于6时,后面用0拼接
|
|
||||||
if (trun.size() < 6) {
|
|
||||||
for (int i = trun.size(); i < 6; i++) {
|
|
||||||
inflectionBuilder.append(",0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<SendData2> sendDataList = new ArrayList<>();
|
|
||||||
if (!trun.isEmpty()) {
|
|
||||||
SendData2 path = new SendData2();
|
|
||||||
path.setAddress("4000");//地址
|
|
||||||
path.setData(startSite + "," + endSite + "," + inflectionBuilder.toString());
|
|
||||||
path.setType(2);
|
|
||||||
sendDataList.add(path);
|
|
||||||
} else {
|
|
||||||
SendData2 path = new SendData2();
|
|
||||||
path.setAddress("4000");//地址
|
|
||||||
path.setData(startSite + "," + endSite);
|
|
||||||
path.setType(2);
|
|
||||||
sendDataList.add(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//任务号、原、目标数据转换
|
|
||||||
String siteId = wcsSrgvQueue.getTaskNo();//+ "," + startSite + "," + endSite;
|
|
||||||
SendData2 site = new SendData2();
|
|
||||||
site.setAddress("4400");
|
|
||||||
site.setData(siteId);
|
|
||||||
site.setType(2);
|
|
||||||
sendDataList.add(site);
|
|
||||||
|
|
||||||
//任务类型转换
|
|
||||||
SendData2 taskType = new SendData2();
|
|
||||||
taskType.setAddress("2200");
|
|
||||||
taskType.setData(wcsSrgvQueue.getDefault02());
|
|
||||||
taskType.setType(1);
|
|
||||||
sendDataList.add(taskType);
|
|
||||||
|
|
||||||
//下发标志转换
|
|
||||||
SendData2 flag = new SendData2();
|
|
||||||
flag.setAddress("2202");
|
|
||||||
flag.setData("1");
|
|
||||||
flag.setType(1);
|
|
||||||
sendDataList.add(flag);
|
|
||||||
|
|
||||||
return sendCarTask(sendDataList, deviceSrgv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小车发送任务
|
* 小车发送任务
|
||||||
*/
|
*/
|
||||||
@@ -667,37 +432,10 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理未指定目的地的任务
|
|
||||||
*/
|
|
||||||
private void handleUnspecifiedDestination(WcsSrgvQueue wcsSrgvQueue, String startSite, int floor, DeviceSrgv deviceSrgv) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断站点是否是同一层
|
|
||||||
*
|
|
||||||
* @param startSite
|
|
||||||
* @param endSite
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isSameFloor(String startSite, String endSite) {
|
|
||||||
// 参数校验
|
|
||||||
if (startSite == null || endSite == null || startSite.length() < 2 || endSite.length() < 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 正确提取起始和结束站点的楼层信息
|
|
||||||
String startFloor = startSite.substring(startSite.length() - 2);
|
|
||||||
String endFloor = endSite.substring(endSite.length() - 2);
|
|
||||||
|
|
||||||
// 比较是否在同一层
|
|
||||||
return Objects.equals(startFloor, endFloor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 小车完成队列
|
* 小车完成队列
|
||||||
*/
|
*/
|
||||||
private void completeCarTask(DeviceSrgv deviceSrgv, int floor) {
|
private void completeCarTask(DeviceSrgv deviceSrgv) {
|
||||||
//联机自动
|
//联机自动
|
||||||
if (deviceSrgv.getWorkMode() == 4) {
|
if (deviceSrgv.getWorkMode() == 4) {
|
||||||
//22到达充电位置 23到达换层目标
|
//22到达充电位置 23到达换层目标
|
||||||
@@ -715,7 +453,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
* 1、不处理终点是提升机站点的四向车
|
* 1、不处理终点是提升机站点的四向车
|
||||||
* 2、处理终点不是提升机站点的
|
* 2、处理终点不是提升机站点的
|
||||||
* */
|
* */
|
||||||
boolean taskFinishFlag = finishTaskByQueue(deviceSrgv.getCurrSite(), wcsSrgvQueue, floor);
|
boolean taskFinishFlag = finishTaskByQueue(deviceSrgv.getCurrSite(), wcsSrgvQueue);
|
||||||
|
|
||||||
if (taskFinishFlag) {
|
if (taskFinishFlag) {
|
||||||
String spare2 = deviceSrgv.getSpare2();
|
String spare2 = deviceSrgv.getSpare2();
|
||||||
@@ -741,10 +479,9 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
*
|
*
|
||||||
* @param currSite
|
* @param currSite
|
||||||
* @param wcsSrgvQueue
|
* @param wcsSrgvQueue
|
||||||
* @param floor
|
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private boolean finishTaskByQueue(String currSite, WcsSrgvQueue wcsSrgvQueue, int floor) {
|
private boolean finishTaskByQueue(String currSite, WcsSrgvQueue wcsSrgvQueue) {
|
||||||
|
|
||||||
|
|
||||||
//当前在放货站点
|
//当前在放货站点
|
||||||
@@ -825,14 +562,13 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
|
|||||||
*
|
*
|
||||||
* @param deviceSrgv
|
* @param deviceSrgv
|
||||||
*/
|
*/
|
||||||
private void resQueue(DeviceSrgv deviceSrgv, int floor) {
|
private void resQueue(DeviceSrgv deviceSrgv) {
|
||||||
int taskNo = deviceSrgv.getTaskNo();
|
int taskNo = deviceSrgv.getTaskNo();
|
||||||
String currSite = deviceSrgv.getCurrSite();
|
String currSite = deviceSrgv.getCurrSite();
|
||||||
Integer deviceId = deviceSrgv.getDeviceId();
|
Integer deviceId = deviceSrgv.getDeviceId();
|
||||||
|
|
||||||
if (taskNo > 999 && !"000000".equals(currSite)) {
|
if (taskNo > 999 && !"000000".equals(currSite)) {
|
||||||
WcsSrgvQueue param = new WcsSrgvQueue();
|
WcsSrgvQueue param = new WcsSrgvQueue();
|
||||||
param.setTheFloor(Convert.toStr(floor));
|
|
||||||
param.setTaskNo(Convert.toStr(taskNo));
|
param.setTaskNo(Convert.toStr(taskNo));
|
||||||
param.setIssued("0");
|
param.setIssued("0");
|
||||||
param.setAgvId(String.valueOf(deviceId));
|
param.setAgvId(String.valueOf(deviceId));
|
||||||
|
|||||||
Reference in New Issue
Block a user