Commit be279abb sunke

包装料机器人逻辑

1 个父辈 57191c57
......@@ -26,6 +26,16 @@ public class InquiryShelfBean {
public static Map<String,Map<String,ShelfInfo>> hSerialShelfMap = new ConcurrentHashMap<>();
/**
* 清理使用过的料架
*/
public static void clearShelf(String hSerial){
if(hSerial != null){
log.info("清理["+hSerial+"]使用的过料架");
hSerialShelfMap.remove(hSerial);
}
}
/**
* 添加限制库位(即库位中只能放入某个条码)
* @param task
* @param outItem
......@@ -241,12 +251,15 @@ public class InquiryShelfBean {
* @param packageRfid
* @return
*/
public ShelfInfo findPackageShelf(String packageRfid){
public ShelfInfo findPackageShelf(String hSerial, String packageRfid){
if(packageRfid == null){
return null;
}
for (Map<String, ShelfInfo> shelfInfoMap : hSerialShelfMap.values()) {
for (ShelfInfo shelf : shelfInfoMap.values()) {
Map<String, ShelfInfo> shSerialShelfInfoMap = hSerialShelfMap.get(hSerial);
if(shSerialShelfInfoMap == null ){
return null;
}
for (ShelfInfo shelf : shSerialShelfInfoMap.values()) {
String shelfRFID = shelf.getRealRfid();
if(shelfRFID != null){
if(shelfRFID.equals(packageRfid)){
......@@ -255,7 +268,6 @@ public class InquiryShelfBean {
}
}
}
}
return null;
}
......@@ -284,6 +296,28 @@ public class InquiryShelfBean {
return null;
}
public ShelfInfo findMaxUsedShelf(String hSerial, String shelfType){
Map<String, ShelfInfo> shelfMap = hSerialShelfMap.get(hSerial);
ShelfInfo maxLocShelf = null;
for (ShelfInfo shelf : shelfMap.values()) {
if(StorageConstants.SHEFL_TYPE.judgeType(shelfType, shelf.getShelfType())){
//同一种料架
if(maxLocShelf == null){
maxLocShelf = shelf;
}
if(shelf.getUsedLocCount() > maxLocShelf.getUsedLocCount()){
maxLocShelf = shelf;
}
}
}
if(maxLocShelf != null){
log.info("找到类型为["+shelfType+"]库位最多的同种料架["+maxLocShelf.tempRfid()+"]");
}else{
log.info("已没有与["+shelfType+"]类型相同的料架");;
}
return maxLocShelf;
}
/**
* 锁定架位
*/
......
......@@ -177,6 +177,14 @@ public class OutInfo extends BaseMongoBean {
return getAction().contains("首盘");
}
/**
* 补料需求单
*/
public boolean isTailAction(){
return getAction().contains("补料");
}
public int getTaskFinishNum() {
return taskFinishNum;
}
......
......@@ -26,6 +26,22 @@ public class OutInfoCache {
//定时查询未完成的需求单
private static Map<String,OutInfo> outInfoMap = new ConcurrentHashMap<>();
/**
* 当前正在执行的工单需求单(首盘,补料),未完成时,其他工单需求单不可执行
*/
private static String currentOrderHSerial = "";
public static void setCurrentOrderHSerial(String currentOrderHSerial) {
if(currentOrderHSerial == null){
currentOrderHSerial = "";
}
OutInfoCache.currentOrderHSerial = currentOrderHSerial;
}
public String getCurrentOrderHSerial() {
return currentOrderHSerial;
}
@Autowired
private IOutInfoDao outInfoDao;
......
......@@ -429,17 +429,17 @@ public class QisdaApiController extends BaseController {
private void realBindReel(OutItem outItem){
if(!outItem.isCutMaterial()){
//先从预绑定料盘中进行绑定,如果还有缺料的,从未使用的物料中查找,如果还缺料,从预绑定的物料中查找
log.info("绑定非分盘料:So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]+refno=["+outItem.getRefno()+"]的slotLoction"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]当前绑定数量["+outItem.getRealLockQty()+"/"+outItem.getQty()+"]");
log.info("绑定非分盘料:So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]+refno=["+outItem.getRefno()+"]的slotLoction"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]当前绑定数量["+outItem.getRealLockQty()+"/"+outItem.getQty()+"]当前出库/发料数量["+outItem.getOutQty()+"/"+outItem.getSendQty()+"]");
List<StoragePos> preBindPosList = storagePosDao.findPreBindList(outItem.getSo(), outItem.getSlotlocation());
for (StoragePos pos : preBindPosList) {
outItem = tryRealBind(pos, outItem);
}
log.info("将预绑定转为真实绑定结束,当前数量:"+ outItem.getRealLockQty() +"/" + outItem.getQty());
int needNum = outItem.getQty() - outItem.getRealLockQty();
//所需数量=需求单数量-已发料数量-真实绑定数量
int needNum = outItem.getQty() - outItem.getSendQty() - outItem.getRealLockQty();
log.info("将预绑定转为真实绑定结束,所需数量("+needNum+")=需求单数量("+outItem.getQty()+")-已发料数量("+ outItem.getSendQty()+")-真实绑定数量"+ outItem.getRealLockQty() +")");
if(needNum >= 0){
log.info("预绑定数量不足,查找未绑定料盘进行真实绑定结束,当前数量:"+ outItem.getRealLockQty() +"/" + outItem.getQty());
log.info("预绑定数量不足,查找未绑定料盘进行真实绑定结束,当前数量:"+outItem.getSendQty()+"+"+ outItem.getRealLockQty() +"/" + outItem.getQty());
while(needNum >= 0){
StoragePos pos = storagePosDao.findNoBindMinQty(outItem.getPn(), outItem.getFacility());
OutItem resultOutItem = tryRealBind(pos, outItem);
......@@ -455,9 +455,9 @@ public class QisdaApiController extends BaseController {
}
needNum = outItem.getQty() - outItem.getRealLockQty();
needNum = outItem.getQty() - outItem.getSendQty() - outItem.getRealLockQty();
if(needNum >= 0 ){
log.info("未绑定料盘数量不足,开始抢其他工单的预绑定物料进行真实绑定,当前数量:"+ outItem.getRealLockQty() +"/" + outItem.getQty());
log.info("未绑定料盘数量不足,开始抢其他工单的预绑定物料进行真实绑定,当前数量:"+outItem.getSendQty()+"+"+ outItem.getRealLockQty() +"/" + outItem.getQty());
//抢其他工单的预绑定
while(needNum >= 0){
StoragePos pos = storagePosDao.findOtherPreBindMinQty(outItem.getPn(), outItem.getFacility());
......@@ -466,13 +466,13 @@ public class QisdaApiController extends BaseController {
break;
}
outItem = resultOutItem;
if(outItem.getRealLockQty() > outItem.getQty()){
if(outItem.getRealLockQty() + outItem.getSendQty() > outItem.getQty()){
//已经满足需求了,直接跳出
break;
}
}
}
log.info("So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]+refno=["+outItem.getRefno()+"]的slot"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]真实绑定结束,当前数量:"+ outItem.getRealLockQty() +"/" + outItem.getQty());
log.info("So=["+outItem.getSo()+"]hSerial=["+outItem.gethSerial()+"]+refno=["+outItem.getRefno()+"]的slot"+outItem.getSlotlocation()+"]pn=["+outItem.getPn()+"]真实绑定结束,当前数量:"+outItem.getSendQty()+"+"+ outItem.getRealLockQty() +"/" + outItem.getQty());
}
}
......@@ -993,9 +993,10 @@ public class QisdaApiController extends BaseController {
tasks.add(task);
}
}else{
int needNum = outItem.getQty() - outItem.getRealLockQty();
//紧急料,未绑定数量=需求单数量-已出库数量-已绑数量
int needNum = outItem.getQty() - outItem.getOutQty() - outItem.getRealLockQty();
if(needNum >= 0){
log.info("紧急料,查找未绑定料盘进行出库,当前数量:"+ outItem.getRealLockQty() +"/" + outItem.getQty());
log.info("紧急料,查找未绑定料盘进行出库,未绑数量为"+needNum+"=(需求单"+ outItem.getQty() + ") - (已出" + outItem.getOutQty() + ")-已绑(" + outItem.getRealLockQty()+")");
while(needNum >= 0){
StoragePos pos = storagePosDao.findNoBindMinQty(outItem.getPn(), outItem.getFacility());
if(pos != null){
......@@ -1139,25 +1140,15 @@ public class QisdaApiController extends BaseController {
}
}
//清理掉已经完成的需求单的料架
// Set<String> hserialSet = InquiryShelfBean.hSerialShelfMap.keySet();
// for (String hserial : hserialSet) {
// OutInfo out = outInfoDao.findByHSerial(hSerial);
// if(!outInfo.isReelCutAction() && !outInfo.isUrgentAction()){
// log.info("清理需求单["+out.gethSerial()+"]占用的料架");
// InquiryShelfBean.hSerialShelfMap.remove(hserial);
// }
// }
//TODO:可以出的时候把之前的料架信息清空
outInfo.setTaskNum(0);
outInfo.setTaskFinishNum(0);
outInfo.setOutReelNum(0);
outInfo = outInfoDao.save(outInfo);
//如果是工单需求单,设置当前正在执行的工单需求单
if(outInfo.isFirstReelAction() || outInfo.isTailAction()){
String oldHSerial = outInfoCache.getCurrentOrderHSerial();
log.info("设置当前正在执行的工单料需求为:" + outInfo.gethSerial()+"清理之前["+oldHSerial+"]出库使用的料架");
InquiryShelfBean.clearShelf(oldHSerial);
outInfoCache.setCurrentOrderHSerial(outInfo.gethSerial());
}
List<DataLog> tasks = new ArrayList<>();
......@@ -1186,8 +1177,12 @@ public class QisdaApiController extends BaseController {
int outReelNum = tasks.size();
if(outReelNum > 0){
log.info("需求单"+outInfo.gethSerial()+"已出("+outInfo.getOutReelNum()+")/已发("+outInfo.getTaskFinishNum()+") 本次出库料盘数量:" + outReelNum);
outInfo.setOutReelNum(0);
outInfo.setTaskFinishNum(0);
outInfo.setTaskNum(outReelNum);
outInfo = outInfoDao.save(outInfo);
//先出小料盘,再出大料盘
for (DataLog task : tasks) {
if(task.isSmallReel()){
......@@ -1201,7 +1196,6 @@ public class QisdaApiController extends BaseController {
}
}
log.info("需求单"+outInfo.gethSerial()+" 出库料盘数量:" + outReelNum);
if(outInfo.isReelCutAction() || outInfo.isFirstReelAction()){
if(outReelNum == 0){
......
......@@ -199,10 +199,23 @@ public class QisdaDeviceController extends BaseController {
String bigRfid = request.getParameter("bigRfid");
//包装料RFID
String packageRfid = request.getParameter("packageRfid");
log.info("收到包装料摆放位置信息请求:[packageRfid=" + packageRfid + "]bigRfid=" + bigRfid);
ShelfInfo packageShelf = inquiryShelfBean.findPackageShelf(packageRfid);
String hSerial = outInfoCache.getCurrentOrderHSerial();
log.info("收到包装料摆放位置信息请求:[packageRfid=" + packageRfid + "]bigRfid=" + bigRfid + "当前工单料需求:["+hSerial+"]");
ShelfInfo packageShelf = inquiryShelfBean.findPackageShelf(hSerial, packageRfid);
ShelfInfo bigShelf = inquiryShelfBean.findSameShelf(hSerial,bigRfid);
//未找到,说明是未绑定过的新料架,找相同类型的进行绑定
//未找到已经有实际RFID的料架,查找库位最多的料架
if(bigShelf == null){
log.info("未找到实际绑定的["+bigRfid+"]料架,开始查找库位最多的C型料架");
ShelfInfo maxLocShelf = inquiryShelfBean.findMaxUsedShelf(hSerial, StorageConstants.SHEFL_TYPE.C);
if(maxLocShelf != null){
bigShelf = maxLocShelf;
}else{
log.info(hSerial + "已没有C型料架");
}
}
ShelfInfo bigShelf = inquiryShelfBean.findBigShelf(bigRfid);
if(bigShelf != null){
Collection<DataLog> queueTasks = taskService.getQueueTasks();
List<DataLog> allTasks = taskService.getFinishedTasks();
......@@ -293,7 +306,8 @@ public class QisdaDeviceController extends BaseController {
resultMap.put("packageTask", packageTask +"");
resultMap.put("packageRfid", packageRfid);
resultMap.put("packageLoc", packageLoc);
resultMap.put("bigRfid", bigRfid);
resultMap.put("bigRfid", bigShelf.tempRfid());
resultMap.put("realBigRfid",bigShelf.getRealRfid());
resultMap.put("bigLoc", bigLoc);
log.info("大料架信息返回:"+resultMap);
......@@ -303,8 +317,6 @@ public class QisdaDeviceController extends BaseController {
}
}catch(Exception e){
log.error("包装料摆放位置信息获取出错",e);
return ResultBean.newErrorResult(-1,"包装料摆放位置信息获取出错:" + e.getMessage());
......@@ -457,11 +469,13 @@ public class QisdaDeviceController extends BaseController {
* @param rfid 料架RFID
* @param rfidLoc 料架位置
*/
private void reelPutInFinished(DataLog cacheTask, String rfid, String rfidLoc){
private boolean reelPutInFinished(DataLog cacheTask, String rfid, String rfidLoc){
if(cacheTask != null){
AppendInfo appendInfo = cacheTask.getAppendInfo();
boolean putResult = inquiryShelfBean.putInShelf(cacheTask,rfid, Integer.valueOf(rfidLoc));
if(!putResult){
//紧急料和分盘料放入失败不影响
boolean isCutTask = cacheTask.isUrgentReel() || cacheTask.isCutReel();
if(!isCutTask && !putResult){
//记录日志
String errorMsg = "料盘["+cacheTask.getBarcode()+"]放入位置"+rfid+"["+rfidLoc+"],原分配位置"+appendInfo.getTempRfid()+"["+appendInfo.getRfidLoc()+"],不更改状态,不进行发料";
log.error(errorMsg);
......@@ -475,8 +489,9 @@ public class QisdaDeviceController extends BaseController {
alarmInfo.setEndTime(date);
alarmInfo.setAlarmMsg(errorMsg);
alarmInfoDao.save(alarmInfo);
return;
}
return putResult;
}else{
log.info("料盘["+cacheTask.getBarcode()+"]放入位置"+rfid+"["+rfidLoc+"]成功");
cacheTask.setStatus(StorageConstants.OP_STATUS.FINISHED.name());
appendInfo.setRfid(rfid);
appendInfo.setRfidLoc(Integer.valueOf(rfidLoc));
......@@ -484,8 +499,6 @@ public class QisdaDeviceController extends BaseController {
cacheTask = dataLogDao.save(cacheTask);
taskService.updateFinishedTask(cacheTask);
String hSerial = appendInfo.gethSerial();
if(Strings.isNotBlank(hSerial)){
OutInfo outInfo = outInfoDao.findByHSerial(hSerial);
......@@ -520,6 +533,10 @@ public class QisdaDeviceController extends BaseController {
}
}
}
return putResult;
}
return false;
}
/**
* 包装线机器人从A包装料架放到C大料架上barcode
......@@ -539,9 +556,10 @@ public class QisdaDeviceController extends BaseController {
if (cacheTask == null) {
return ResultBean.newErrorResult(501,"料盘[" + barcode + "]的任务不存在");
} else {
reelPutInFinished(cacheTask,bigRfid, bigLoc);
boolean putInResult = reelPutInFinished(cacheTask,bigRfid, bigLoc);
if(putInResult){
//清理包装料架的位置
ShelfInfo packageShelf = inquiryShelfBean.findPackageShelf(packageRfid);
ShelfInfo packageShelf = inquiryShelfBean.findPackageShelf(cacheTask.getAppendInfo().gethSerial(), packageRfid);
if(packageShelf != null){
Map<Integer, ShelfLoc> packageLocMap = packageShelf.getLocMap();
for (ShelfLoc shelfLoc : packageLocMap.values()) {
......@@ -558,6 +576,7 @@ public class QisdaDeviceController extends BaseController {
}
}
}
}
String msg = "包装线机器人放置料盘["+barcode+"]从"+packageRfid+"["+packageLoc+"]=>"+bigRfid+"["+bigLoc+"]失败";
return ResultBean.newErrorResult(501,msg);
......@@ -576,8 +595,6 @@ public class QisdaDeviceController extends BaseController {
try{
DataLog cacheTask = null;
if(Strings.isNotBlank(barcode)) {
cacheTask = taskService.getFinishedTask(barcode);
......
......@@ -584,9 +584,9 @@ public class StorageDataController extends BaseController {
}else {
StoragePos pos = null;
try {
log.info("条码["+barcode.getBarcode()+"]入库,清空Facility入库信息");
barcode.setAppendInfo(null);
barcode = barcodeManager.save(barcode);
// log.info("条码["+barcode.getBarcode()+"]入库,清空Facility入库信息");
// barcode.setAppendInfo(null);
// barcode = barcodeManager.save(barcode);
pos = taskService.findEmptyPosForPutIn(storageList,barcode, rfid);
if(pos != null){
......
......@@ -559,30 +559,28 @@ public class TaskService implements ITaskService {
}
}
//按任务数量从小到大排序
// List<Map.Entry<String, Integer>> list = new ArrayList<>(countMap.entrySet());
// Collections.sort(list, new Comparator<Map.Entry<String, Integer>>()
// {
// @Override
// public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2)
// {
// //按照value值,用compareTo()方法默认是从小到大排序
// return o1.getValue().compareTo(o2.getValue());
// }
// });
//可用的料仓(在线,且可以放入)
List<Storage> availbleStorageList = new ArrayList<>();
for(Storage storage : storageList){
StatusBean status = getStatus(storage.getCid());
if(status.timeOut()){
continue;
}
if(storage.canPutIn(barcode.getPlateSize(),barcode.getHeight())){
availbleStorageList.add(storage);
}
}
//
for (Storage storage : storageList) {
for (Storage storage : availbleStorageList) {
String storageId = storage.getId();
Integer taskCount = countMap.get(storageId);
if(taskCount >= 2){
continue;
}
StatusBean status = getStatus(storage.getCid());
if(status.timeOut()){
continue;
}
try{
log.info("尝试从"+storage.getName()+"["+storage.getCid()+"]查找空位,当前料仓任务数:" + taskCount);
return findLineEmptyPosForPutIn(storage,barcode);
......@@ -591,6 +589,17 @@ public class TaskService implements ITaskService {
}
}
//只有一个料仓可以入时,只能继续往里面放
log.info("可用料仓太少,不按任务数分配,重新查找...");
for (Storage storage : availbleStorageList) {
try{
log.info("尝试从"+storage.getName()+"["+storage.getCid()+"]查找空位,当前料仓任务数");
return findLineEmptyPosForPutIn(storage,barcode);
}catch(Exception e){
log.info("从"+storage.getName()+"["+storage.getCid()+"]查找空位失败:" + e.getMessage());
}
}
return null;
}
......@@ -1027,6 +1036,11 @@ public class TaskService implements ITaskService {
}
}
if(!shelfNameList.contains(storageTask.getAppendInfo().getTempRfid())){
if(storageTask.getAppendInfo().isCShelfTask()){
//大料(C料架)只能同时出一个架子,不然到包装料工位时无法切换
log.info("未完成的工单料架为:["+String.join(",",shelfNameList)+ "]大料架任务["+storageTask.getBarcode()+"]暂停出库,以免包装工位无法切换");
return null;
}
//未完成的工单任务料架数量>2,且未包含此任务,任务先不出,等到只有一个料架时再说
if(shelfNameList.size() >= 2){
log.info("未完成的工单任务料架为:["+String.join(",",shelfNameList)+ "]任务"+storageTask.getBarcode()+"暂停出库");
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!