小车调度

This commit is contained in:
liuhanqing
2025-11-27 15:40:53 +08:00
parent ea85539f06
commit 548f55109a
5 changed files with 273 additions and 656 deletions

View File

@@ -9,30 +9,26 @@ import java.util.Map;
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);
int[][] findFullMap(int floor, int startX, int startY, int endX, int endY);
int[][] findFullMap(int floor, int startX, int startY, int endX, int endY, DeviceSrgv srgvPlc);
List<int[]> findEmptyPath(int floor, int startX, int startY, int endX, int endY);
int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY);
int[][] findEmptyMap(int floor, int startX, int startY, int endX, int endY, DeviceSrgv splc);
Map<String, String> getRoadSiteByArr(int floor);
int[][] getRoadCache(int floor);
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();
/**
* 处理地图
* @param arrByRoadSite
* @param deviceSrgv
* @return
*/
int[][] handleMap(Map<String, WcsSrgvMap> arrByRoadSite, DeviceSrgv deviceSrgv);
/**
* 根据x y z 获取指定位置的缓存
* @param x
* @param y
* @param z
* @return
*/
WcsSrgvMap selectRoadSiteByArr(int x, int y, int z);
}

View File

@@ -1,18 +1,19 @@
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.service.IWcsSrgvMapService;
import com.ruoyi.bas.srgvmap.service.RoadCacheService;
import com.ruoyi.device.srgv.domain.DeviceSrgv;
import com.ruoyi.device.srgv.service.IDeviceSrgvService;
import com.ruoyi.queue.srgv.domain.WcsSrgvQueue;
import com.ruoyi.queue.srgv.service.IWcsSrgvQueueService;
import com.ruoyi.schedule.plcRead.srgv.PlcSrgvRead;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;
@Component
@@ -31,14 +32,76 @@ public class AgvPathProcessor {
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) {
}
/**

View File

@@ -1,311 +1,150 @@
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.mapper.WcsSrgvMapMapper;
import com.ruoyi.bas.srgvmap.service.RoadCacheService;
import com.ruoyi.device.srgv.domain.DeviceSrgv;
import com.ruoyi.schedule.plcRead.srgv.roadUtil.PathFinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.device.srgv.service.IDeviceSrgvService;
import com.ruoyi.queue.srgv.domain.WcsSrgvQueue;
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.cache.CacheManager;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
public class RoadCacheServiceImpl implements RoadCacheService {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private WcsSrgvMapMapper wcsSrgvMapMapper;
@Autowired
private CacheManager cacheManager;
private IWcsSrgvQueueService wcsSrgvQueueService;
@Autowired
private RoadCacheService selfProxy; // 注入代理对象
private IDeviceSrgvService deviceSrgvService;
@Autowired
private AgvPathProcessor agvPathProcessor;
@Override
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;
}
/*
*
*
* */
@Autowired
@Cacheable(value = "CSpaceDataCache" ,key = "'CSpaceDataCacheKey_'")
public Map<String,String> getSpaceDataCache() {
log.info("从数据库获取初始化地图数据");
@Override
public int[][] handleMap(Map<String, WcsSrgvMap> maps, DeviceSrgv deviceSrgv) {
WcsSrgvMap wcsSrgvMap = new WcsSrgvMap();
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(wcsSrgvMap);
//将集合转为map,
Map<String, String> siteMap = new HashMap<>();
//1.锁定其他车任务路径
lockedOtherCarQueuePath(maps, deviceSrgv);
//2.锁定无任务小车当前位置
lockedOtherCarCurrSite(maps, deviceSrgv);
//3.锁定离线小车当前位置
lockedOfflineCarCurrSite(maps, deviceSrgv);
for (WcsSrgvMap srgvMap : wcsSrgvMaps) {
String siteId = srgvMap.getSiteId();
String warehouse = srgvMap.getWarehouse();
if(!Objects.equals(siteId,"000")){
siteMap.put(siteId,warehouse);
int[][] mapsInt = new int[29][11];
for (String site : maps.keySet()) {
WcsSrgvMap wcsSrgvMap = maps.get(site);
mapsInt[wcsSrgvMap.getX()][wcsSrgvMap.getY()] = wcsSrgvMap.getValue();
}
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) {
log.info("从数据库获取初始化地图");
WcsSrgvMap wcsSrgvMap1 = new WcsSrgvMap();
wcsSrgvMap1.setUz(floor);
List<WcsSrgvMap> wcsSrgvMaps = wcsSrgvMapMapper.selectWcsSrgvMapList(wcsSrgvMap1);
return wcsSrgvMaps;
}
/*
*
* 每层二维地图
* */
@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();
/**
* 锁定无任务小车当前位置
*
* @param arrByRoadSite
* @param deviceSrgv
*/
private void lockedOtherCarCurrSite(Map<String, WcsSrgvMap> arrByRoadSite, DeviceSrgv deviceSrgv) {
//锁定其他车当前位置
for (String sRgv : PlcSrgvRead.deviceSrgvMap.keySet()) {
if (!sRgv.equals(deviceSrgv.getDeviceId().toString())) {
DeviceSrgv otherCar = PlcSrgvRead.deviceSrgvMap.get(sRgv);
String currSite = otherCar.getCurrSite();
if (arrByRoadSite.containsKey(currSite)) {
arrByRoadSite.get(currSite).setValue(0);
}
}
}
return grid;
}
/*
*
* 每层 站点与二维数组关系
* */
@Override
@CachePut(value = "SiteCache" ,key = "'SiteKey_floor_' +#floor")
public Map<String, int[]> getArrByRoadSite(int floor) {
List<WcsSrgvMap> roadDataCache = selfProxy.getRoadDataCache(floor);
//将集合转为map,key为siteId,value为x,y
Map<String, int[]> siteMap = new HashMap<>();
for (WcsSrgvMap map : roadDataCache) {
siteMap.put(map.getSiteId(), new int[]{map.getX(), map.getY(),floor});
/**
* 锁定其他车任务路径
*
* @param maps
* @param deviceSrgv
*/
private void lockedOtherCarQueuePath(Map<String, WcsSrgvMap> maps, DeviceSrgv deviceSrgv) {
//查询所有小车作业
List<WcsSrgvQueue> wcsSrgvQueues = wcsSrgvQueueService.selectWcsSrgvQueueList(new WcsSrgvQueue());
if (CollUtil.isNotEmpty(wcsSrgvQueues)) {
//筛选其他小车队列
List<WcsSrgvQueue> otherCarQueue = wcsSrgvQueues.stream().filter(x -> !x.getAgvId().equals(deviceSrgv.getDeviceId().toString())).collect(Collectors.toList());
if (CollUtil.isNotEmpty(otherCarQueue)) {
//添加其他小车路径列表
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;
}
}

View File

@@ -128,7 +128,7 @@ public class PathFinder {
int[][] gCost = new int[rows][cols];
// fCost: gCost + 启发式估计成本(从当前节点到终点)
int[][] fCost = new int[rows][cols];
// prev: 记录路径回溯信息
// prev: 记录路径回溯信息,初始化为无效值
int[][][] prev = new int[rows][cols][2];
// closedSet: 记录已访问的节点
boolean[][] closedSet = new boolean[rows][cols];
@@ -137,6 +137,10 @@ public class PathFinder {
for (int i = 0; i < rows; i++) {
Arrays.fill(gCost[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排序
@@ -211,8 +215,8 @@ public class PathFinder {
path.add(new int[]{currX, currY});
int[] p = prev[currX][currY];
// 检查路径有效性
if (p[0] == 0 && p[1] == 0 && (currX != startX || currY != startY)) {
// 检查路径有效性,使用 -1,-1 作为无效值判断
if (p[0] == -1 && p[1] == -1 && (currX != startX || currY != startY)) {
return null;
}
@@ -403,32 +407,13 @@ public class PathFinder {
* - 方向变化点(水平转垂直 / 垂直转水平)
*
* @param path 路径坐标列表(逻辑坐标)
* @param grid 网格数据
* @return 拐点坐标列表(逻辑坐标)
*/
public static List<int[]> extractInflectionPoints2(List<int[]> path, int[][] grid) {
public static List<int[]> extractInflectionPoints2(List<int[]> path) {
List<int[]> inflectionPoints = new ArrayList<>();
// 记录类型转换点和方向变化点
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++) {
int[] prev = path.get(i - 1);
@@ -448,9 +433,7 @@ public class PathFinder {
}
// 排序后返回(可选)
return inflectionPoints; /*.stream()
.sorted(Comparator.comparingInt(a -> a[0] * 1000 + a[1]))
.collect(Collectors.toList());*/
return inflectionPoints;
}
/*

View File

@@ -5,7 +5,6 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjUtil;
import com.ruoyi.bas.port.domain.WcsPort;
import com.ruoyi.bas.port.service.IWcsPortService;
import com.ruoyi.bas.srgvmap.domain.WcsSrgvMap;
import com.ruoyi.bas.srgvmap.service.IWcsSrgvMapService;
@@ -75,17 +74,14 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
if (ObjUtil.isNotNull(PlcSrgvRead.deviceSrgvMap.get(code))) {
DeviceSrgv deviceSrgv = PlcSrgvRead.deviceSrgvMap.get(code);
//循环所有楼层
for (int i = 1; i <= 8; i++) {
sRgvTask(deviceSrgv, i);
}
sRgvTask(deviceSrgv);
createCarInQueue();
createCarOutQueue();
} else {
log.error("堆垛机设备为空");
log.error("小车设备为空");
}
}
} 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();
param.setIssued("0");
param.setTheFloor(Convert.toStr(floor));
param.setAgvId(deviceSrgv.getDeviceId().toString());
List<WcsSrgvQueue> wcsSrgvQueues = wcsSagvQueueMapper.selectWcsSrgvQueueList(param);
if (CollUtil.isEmpty(wcsSrgvQueues)) {
return;
@@ -232,10 +228,10 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
//判断小车是否在起始点
if (currSite.equals(startSite)) {
//小车在起始点
sendMainTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor);
sendMainTask(deviceSrgv, wcsSrgvQueue, currSite, endSite);
} 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()) {
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();
Map<String, String> roadSiteByArr = roadCacheService.getRoadSiteByArr(floor);
for (int[] point : shortestPath) {
String site = roadSiteByArr.get(point[0] + "," + point[1]);
if (!"000".equals(site)) {
if (!shortestPath.isEmpty()) {
for (int[] ints : shortestPath) {
WcsSrgvMap roadSiteByArr = roadCacheService.selectRoadSiteByArr(ints[0], ints[1], floor);
if (roadSiteByArr == null) {
log.error("无此站点 x y z :{},{},{}", ints[0], ints[1], floor);
throw new RuntimeException("点位信息错误");
}
String site = roadSiteByArr.getSiteId();
pathBuilder.append(site).append(",");
}
}
if (pathBuilder.length() > 0) {
pathBuilder.setLength(pathBuilder.length() - 1); // 移除最后一个逗号
}
// 拐点拼接
StringBuilder inflectionBuilder = new StringBuilder();
StringBuilder turnBuilder = new StringBuilder();
if (!trun.isEmpty()) {
for (int[] ints : trun) {
String site = roadSiteByArr.get(ints[0] + "," + ints[1]);//获取站点
inflectionBuilder.append(site).append(",");
WcsSrgvMap roadSiteByArr = roadCacheService.selectRoadSiteByArr(ints[0], ints[1], floor);
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) {
inflectionBuilder.setLength(inflectionBuilder.length() - 1);
if (turnBuilder.length() > 0) {
turnBuilder.setLength(turnBuilder.length() - 1);
}
// 当trun长度小于6时,后面用0拼接
if (trun.size() < 6) {
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()) {
SendData2 path = new SendData2();
path.setAddress("4000");//地址
path.setData(startSite + "," + endSite + "," + inflectionBuilder.toString());
path.setData(startSite + "," + endSite + "," + turnBuilder);
path.setType(2);
sendDataList.add(path);
} else {
@@ -335,23 +338,32 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
//下发数据
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) {
String taskType = wcsSrgvQueue.getTaskType();
private void sendMainTask(DeviceSrgv deviceSrgv, WcsSrgvQueue wcsSrgvQueue, String currSite, String endSite) {
String taskType = wcsSrgvQueue.getDefault02();
boolean sendFlag = false;
switch (taskType) {
case "1":
case "4":
// 空车任务(充电、换层、手动点到点、除尘等)
sendFlag = sendEmptyCarTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor);
sendFlag = sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, endSite);
break;
case "1":
case "2":
// 载货任务(出库、入库、移库等)
sendFlag = sendFullCarTask(deviceSrgv, wcsSrgvQueue, currSite, endSite, floor);
sendFlag = sendPointToPointTask(deviceSrgv, wcsSrgvQueue, currSite, endSite);
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;
}
/**
* 处理未指定目的地的任务
*/
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) {
//22到达充电位置 23到达换层目标
@@ -715,7 +453,7 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
* 1、不处理终点是提升机站点的四向车
* 2、处理终点不是提升机站点的
* */
boolean taskFinishFlag = finishTaskByQueue(deviceSrgv.getCurrSite(), wcsSrgvQueue, floor);
boolean taskFinishFlag = finishTaskByQueue(deviceSrgv.getCurrSite(), wcsSrgvQueue);
if (taskFinishFlag) {
String spare2 = deviceSrgv.getSpare2();
@@ -741,10 +479,9 @@ public class BaseSRgvThread implements Runnable, SRgvThreadInterface {
*
* @param currSite
* @param wcsSrgvQueue
* @param floor
* @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
*/
private void resQueue(DeviceSrgv deviceSrgv, int floor) {
private void resQueue(DeviceSrgv deviceSrgv) {
int taskNo = deviceSrgv.getTaskNo();
String currSite = deviceSrgv.getCurrSite();
Integer deviceId = deviceSrgv.getDeviceId();
if (taskNo > 999 && !"000000".equals(currSite)) {
WcsSrgvQueue param = new WcsSrgvQueue();
param.setTheFloor(Convert.toStr(floor));
param.setTaskNo(Convert.toStr(taskNo));
param.setIssued("0");
param.setAgvId(String.valueOf(deviceId));