package com.zy.acs.manager.fake;
|
|
import com.zy.acs.common.constant.RedisConstant;
|
import com.zy.acs.common.domain.AgvProtocol;
|
import com.zy.acs.common.domain.protocol.AGV_11_UP;
|
import com.zy.acs.common.enums.AgvCompleteType;
|
import com.zy.acs.common.hk.state.HkState;
|
import com.zy.acs.common.hk.state.HkStateActionState;
|
import com.zy.acs.common.hk.state.HkStateAgvPosition;
|
import com.zy.acs.common.hk.state.HkStateBatteryState;
|
import com.zy.acs.common.hk.state.HkStateVelocity;
|
import com.zy.acs.common.hk.state.type.HkActionStatusType;
|
import com.zy.acs.common.utils.RedisSupport;
|
import com.zy.acs.manager.core.cache.CoreCache;
|
import com.zy.acs.manager.common.config.HikOrderProperties;
|
import com.zy.acs.manager.core.domain.CodeStepDto;
|
import com.zy.acs.manager.core.domain.type.JobType;
|
import com.zy.acs.manager.core.scheduler.MapDataWsScheduler;
|
import com.zy.acs.manager.core.service.MainService;
|
import com.zy.acs.manager.core.service.MapService;
|
import com.zy.acs.manager.core.utils.AgvAngleUtils;
|
import com.zy.acs.manager.manager.entity.Action;
|
import com.zy.acs.manager.manager.entity.Agv;
|
import com.zy.acs.manager.manager.entity.AgvDetail;
|
import com.zy.acs.manager.manager.entity.AgvModel;
|
import com.zy.acs.manager.manager.entity.Code;
|
import com.zy.acs.manager.manager.enums.ActionStsType;
|
import com.zy.acs.manager.manager.enums.ActionTypeType;
|
import com.zy.acs.manager.manager.service.*;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.util.StringUtils;
|
|
import java.time.Instant;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.List;
|
import java.util.Locale;
|
import java.util.Objects;
|
|
/**
|
* Created by vincent on 11/11/2024
|
*/
|
@Slf4j
|
public class AgvSimulatorTask implements Runnable {
|
|
private final Agv agv;
|
private final AgvDetailService agvDetailService;
|
private final AgvModelService agvModelService;
|
private final ActionService actionService;
|
private final CodeService codeService;
|
private final MapService mapService;
|
private final JamService jamService;
|
private final MainService mainService;
|
private final List<Action> actionList;
|
private final HikOrderProperties hikOrderProperties;
|
|
private final RedisSupport redis;
|
|
private final String groupId;
|
|
public AgvSimulatorTask(
|
Agv agv
|
, RedisSupport redis
|
, AgvDetailService agvDetailService
|
, AgvModelService agvModelService
|
, ActionService actionService
|
, CodeService codeService
|
, MapService mapService
|
, JamService jamService
|
, MainService mainService
|
, HikOrderProperties hikOrderProperties
|
, List<Action> actionList
|
) {
|
this.agv = agv;
|
this.redis = redis;
|
this.agvDetailService = agvDetailService;
|
this.agvModelService = agvModelService;
|
this.actionService = actionService;
|
this.codeService = codeService;
|
this.mapService = mapService;
|
this.jamService = jamService;
|
this.mainService = mainService;
|
this.hikOrderProperties = hikOrderProperties;
|
this.actionList = actionList;
|
|
this.groupId = actionList.get(0).getGroupId();
|
}
|
|
@Override
|
public void run() {
|
try {
|
String qrCode = null;
|
for (Action action : actionList) {
|
processAction(agv, action);
|
qrCode = action.getCode();
|
}
|
this.finishActionList(qrCode);
|
} catch (Exception e) {
|
log.error("AgvSimulatorTask AGV[{}]", agv.getUuid(), e);
|
} finally {
|
FakeProcessor.AGV_PROCESSING_MAP.put(agv.getId(), false);
|
}
|
}
|
|
private void processAction(Agv agv, Action action) throws InterruptedException {
|
|
switch (Objects.requireNonNull(ActionTypeType.get(action.getActionTypeEl()))) {
|
case TurnCorner:
|
simulateWalking(agv, action);
|
simulateRotating(agv, action);
|
break;
|
case StraightBackUnturnable:
|
case StraightBackTurnable:
|
case StraightAheadUnturnable:
|
case StraightAheadTurnable:
|
case FinishPath:
|
case DockingCharge:
|
simulateWalking(agv, action);
|
break;
|
case ReadyTakeFromShelvesLoc:
|
case ReadyReleaseToShelvesLoc:
|
break;
|
default:
|
log.warn("Unknown action type {} for AGV ID {}.", action.getActionType(), agv.getId());
|
break;
|
}
|
}
|
|
|
private void simulateWalking(Agv agv, Action action) throws InterruptedException {
|
Code code = codeService.getCacheByData(action.getCode());
|
// agvDetail.setPos(1);
|
// agvDetail.setCode(code.getId());
|
// 模拟电量消耗
|
// agvDetail.setVol(agvDetail.getVol() - 0.1 * distanceToMove); // 根据距离消耗电量
|
|
Thread.sleep(MapDataWsScheduler.WEBSOCKET_BROADCAST_INTERVAL);
|
|
agvDetailService.updatePosCodeByAgvId(agv.getId(), code.getId());
|
// agvDetailService.updateById(agvDetail);
|
|
mapService.unlockPath(agv.getUuid(), code.getData());
|
jamService.checkIfFinish(agv.getId(), code.getData());
|
|
action.setActionSts(ActionStsType.FINISH.val());
|
actionService.updateById(action);
|
}
|
|
/**
|
* 模拟AGV旋转
|
*
|
* @param agv 当前AGV
|
* @param action 当前动作
|
*/
|
private void simulateRotating(Agv agv, Action action) throws InterruptedException {
|
double actionAngle = Double.parseDouble(action.getParams());
|
// agvDetail.setAgvAngle(actionAngle);
|
// 模拟电量消耗?
|
// agvDetail.setVol(agvDetail.getVol() - 0.05 * (angleToRotate / 15.0)); // 根据角度消耗电量
|
|
Thread.sleep(MapDataWsScheduler.WEBSOCKET_BROADCAST_INTERVAL);
|
agvDetailService.updateAngleByAgvId(agv.getId(), actionAngle);
|
action.setActionSts(ActionStsType.FINISH.val());
|
actionService.updateById(action);
|
}
|
|
private void finishActionList(String qrCode) {
|
Long agvId = this.agv.getId();
|
String agvNo = this.agv.getUuid();
|
// 1.show effect
|
CodeStepDto codeStepDto = CoreCache.AGV_MOCK_STEP_CACHE.get(agvId);
|
if (null != codeStepDto && qrCode.equals(codeStepDto.getCodeData())) {
|
// Code currentCode = agvDetailService.getCurrentCode(this.agv.getId());
|
try { Thread.sleep(codeStepDto.getJobType().waitTime); } catch (InterruptedException ignore) {}
|
CoreCache.AGV_MOCK_STEP_CACHE.remove(this.agv.getId());
|
|
JobType jobType = CoreCache.AGV_MOCK_JOB_CACHE.get(this.agv.getUuid());
|
switch (jobType) {
|
case LOC_PICK:
|
Integer usedSlotsByLocPick = CoreCache.AGV_BACKPACK_USED_CACHE.get(agvId);
|
usedSlotsByLocPick++;
|
CoreCache.AGV_BACKPACK_USED_CACHE.put(agvId, usedSlotsByLocPick);
|
|
if (Objects.equals(agvModelService.getByAgvId(agvId).getBackpack(), usedSlotsByLocPick)) {
|
CoreCache.AGV_MOCK_JOB_CACHE.put(agvNo, JobType.CONVEYOR_DROP);
|
}
|
break;
|
case CONVEYOR_DROP:
|
CoreCache.AGV_BACKPACK_USED_CACHE.put(agvId, 0);
|
|
CoreCache.AGV_MOCK_JOB_CACHE.put(agvNo, JobType.CONVEYOR_PICK);
|
break;
|
case CONVEYOR_PICK:
|
CoreCache.AGV_BACKPACK_USED_CACHE.put(agvId, agvModelService.getByAgvId(agvId).getBackpack());
|
|
CoreCache.AGV_MOCK_JOB_CACHE.put(agvNo, JobType.LOCK_DROP);
|
break;
|
case LOCK_DROP:
|
Integer usedSlotsByLocDrop = CoreCache.AGV_BACKPACK_USED_CACHE.get(agvId);
|
usedSlotsByLocDrop--;
|
CoreCache.AGV_BACKPACK_USED_CACHE.put(agvId, usedSlotsByLocDrop);
|
|
if (usedSlotsByLocDrop == 0) {
|
CoreCache.AGV_MOCK_JOB_CACHE.put(agvNo, JobType.LOC_PICK);
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
|
// 2.complete data
|
if (isHikAgv()) {
|
finishHikActionList();
|
return;
|
}
|
|
AGV_11_UP agv_11_up = new AGV_11_UP();
|
agv_11_up.setSerialNo(groupId);
|
agv_11_up.setCompleteCode(AgvCompleteType.ENTIRE_PATH_COMPLETE.getCode());
|
agv_11_up.setCompleteType(AgvCompleteType.ENTIRE_PATH_COMPLETE);
|
agv_11_up.setQrCode(qrCode);
|
|
AgvProtocol agvProtocol = AgvProtocol.build(this.agv.getUuid()).setMessageBody(agv_11_up);
|
mainService.upDataSubscribe(agvProtocol);
|
// redis.push(RedisConstant.AGV_COMPLETE_FLAG, agvProtocol);
|
}
|
|
private void finishHikActionList() {
|
HkState state = new HkState();
|
state.setTimestamp(Instant.now().toString());
|
state.setSerialNumber(agv.getUuid());
|
state.setManufacturer(hikOrderProperties.getManufacturer());
|
state.setVersion(hikOrderProperties.getMajorVersion());
|
state.setOrderId(groupId);
|
state.setOrderUpdateId(0L);
|
state.setZoneSetId(hikOrderProperties.getZoneSetId());
|
state.setDriving(Boolean.FALSE);
|
state.setPaused(Boolean.FALSE);
|
state.setNodeStates(Collections.emptyList());
|
state.setEdgeStates(Collections.emptyList());
|
state.setActionStates(buildFinishedActionStates());
|
state.setLastNodeSequenceId(actionList.size() * 2L);
|
|
Code code = codeService.getCacheByData(actionList.get(actionList.size() - 1).getCode());
|
if (code != null) {
|
state.setLastNodeId(code.getData());
|
state.setAgvPosition(buildAgvPosition(code));
|
}
|
|
AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId());
|
state.setVelocity(new HkStateVelocity());
|
state.setBatteryState(buildBatteryState(agvDetail));
|
|
redis.push(RedisConstant.HK_AGV_DATA_FLAG, state);
|
}
|
|
private List<HkStateActionState> buildFinishedActionStates() {
|
List<HkStateActionState> actionStates = new ArrayList<>();
|
for (Action action : actionList) {
|
HkStateActionState actionState = new HkStateActionState();
|
actionState.setActionId("A" + action.getId());
|
actionState.setActionStatus(HkActionStatusType.FINISHED);
|
ActionTypeType actionType = ActionTypeType.get(action.getActionTypeEl());
|
actionState.setActionType(actionType == null ? String.valueOf(action.getActionType()) : actionType.name());
|
actionStates.add(actionState);
|
}
|
return actionStates;
|
}
|
|
private HkStateAgvPosition buildAgvPosition(Code code) {
|
HkStateAgvPosition position = new HkStateAgvPosition();
|
position.setPositionInitialized(Boolean.TRUE);
|
position.setLocalizationScore(1.0);
|
position.setX(code.getX() * hikOrderProperties.getCoordinateScale());
|
position.setY(code.getY() * hikOrderProperties.getCoordinateScale());
|
position.setMapId(hikOrderProperties.getMapId());
|
|
AgvDetail agvDetail = agvDetailService.selectByAgvId(agv.getId());
|
if (agvDetail != null && agvDetail.getAgvAngle() != null) {
|
position.setTheta(AgvAngleUtils.toRadians(agvDetail.getAgvAngle()));
|
}
|
return position;
|
}
|
|
private HkStateBatteryState buildBatteryState(AgvDetail agvDetail) {
|
HkStateBatteryState batteryState = new HkStateBatteryState();
|
if (agvDetail == null) {
|
return batteryState;
|
}
|
if (agvDetail.getSoc() != null) {
|
batteryState.setBatteryCharge(agvDetail.getSoc().doubleValue());
|
}
|
if (agvDetail.getVol() != null) {
|
batteryState.setBatteryVoltage(agvDetail.getVol().doubleValue());
|
}
|
return batteryState;
|
}
|
|
private boolean isHikAgv() {
|
AgvModel agvModel = agvModelService.getByAgvId(agv.getId());
|
if (agvModel == null) {
|
return false;
|
}
|
String protocol = agvModel.getProtocol();
|
return StringUtils.hasText(protocol) && protocol.toLowerCase(Locale.ROOT).contains("hik");
|
}
|
}
|