This commit is contained in:
aikai 2025-04-07 15:55:46 +08:00
commit fd814aad58
28 changed files with 415 additions and 52 deletions

View File

@ -145,12 +145,16 @@ public class MqttFactory {
return BeanUtils.getBean(RobotWorkStatusServiceImpl.class);
case ROBOT_UPDATE_PALLET_HEIGHT:
return BeanUtils.getBean(RobotUpdatePalletHeightServiceImpl.class);
case ROBOT_OBSTACLES_STATUS:
return BeanUtils.getBean(RobotObstaclesStatusServiceImpl.class);
case PLANNING_INIT_DATA:
return BeanUtils.getBean(PathPlanningInitDataServiceImpl.class);
case PLANNING_DISTRIBUTION_TASK:
return BeanUtils.getBean(PathPlanningDistributionTaskServiceImpl.class);
case PLANNING_DISTRIBUTION_FAIL:
return BeanUtils.getBean(PathPlanningDistributionFailServiceImpl.class);
case PLANNING_SIMULATION_ROBOT_POSE_REQUEST:
return BeanUtils.getBean(PlanningSimulationRobotPoseRequestServiceImpl.class);
case PLANNING_MOVE:
return BeanUtils.getBean(PathPlanningMoveServiceImpl.class);
case PLANNING_ROUTE_DISPLAY:

View File

@ -21,9 +21,11 @@ public enum DefineSubTopicEnum {
ROBOT_PATH_STATUS("ROBOT_PATH_STATUS", 2,"导航实时行为上报"),
ROBOT_WORK_STATUS("ROBOT_WORK_STATUS", 2,"作业实时行为上报"),
ROBOT_UPDATE_PALLET_HEIGHT("UPDATE_PALLET_HEIGHT", 2,"放货后货物高度反馈和取货后货物高度反馈"),
ROBOT_OBSTACLES_STATUS("ROBOT_OBSTACLES_STATUS", 2,"障碍物状态上报"),
PLANNING_INIT_DATA("SYNCHRONOUS_ALL_MAP_REQUEST", 2,"路径规划需要初始数据上报"),
PLANNING_DISTRIBUTION_TASK("TASK_ASSIGNMENT_FEEDBACK", 2,"路径规划任务分配上报"),
PLANNING_DISTRIBUTION_FAIL("TASK_ASSIGNMENT_FAIL", 2,"路径规划失败上报"),
PLANNING_SIMULATION_ROBOT_POSE_REQUEST("SIMULATION_ROBOT_POSE_REQUEST", 2,"仿真初始化点位信息"),
PLANNING_MOVE("UPDATE_ROUTE_DISPLAY_PLANNING", 2,"车辆即将走的点位"),
PLANNING_ROUTE_DISPLAY("ROBOT_MOVE_POSE_PLANNING", 2,"路径规划上报实时路径");

View File

@ -6,6 +6,6 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = {RobotGenericsStatusApi.class, RobotTaskStatusApi.class, RobotStatusApi.class, RobotReactiveStatusApi.class,
RobotPathStatusApi.class,RobotWorkStatusApi.class,RobotUpdatePalletHeightApi.class})
RobotPathStatusApi.class,RobotWorkStatusApi.class,RobotUpdatePalletHeightApi.class,RobotObstaclesStatusApi.class})
public class SystemConfiguration {
}

View File

@ -0,0 +1,22 @@
package cn.iododer.yudao.module.mqtt.service;
import cn.iocoder.yudao.module.system.api.path.PathApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
@Slf4j
public class PlanningSimulationRobotPoseRequestServiceImpl implements MqttService{
@Resource
private PathApi pathApi;
@Override
public void analysisMessage(String message) {
log.info("收到仿真初始化点位的消息 :{}",message);
pathApi.simulationRobotPoseRequest(message);
}
}

View File

@ -0,0 +1,20 @@
package cn.iododer.yudao.module.mqtt.service;
import cn.iocoder.yudao.module.system.api.robot.RobotObstaclesStatusApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class RobotObstaclesStatusServiceImpl implements MqttService{
@Autowired
private RobotObstaclesStatusApi robotObstaclesStatusApi;
@Override
public void analysisMessage(String message) {
log.info("障碍物状态上报 :{}", message);
robotObstaclesStatusApi.robotObstaclesStatus(message);
}
}

View File

@ -32,4 +32,8 @@ public interface PathApi {
@PostMapping(PREFIX + "/pathPlanningMovePose")
@Operation(summary = "路径规划要走的点位信息")
void pathPlanningMovePose(@RequestParam("message") String message);
@PostMapping(PREFIX + "/simulationRobotPose")
@Operation(summary = "仿真初始化点位信息")
void simulationRobotPoseRequest(@RequestParam("message") String message);
}

View File

@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.system.api.robot;
import cn.iocoder.yudao.module.system.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = ApiConstants.NAME)
@Tag(name = "RPC 服务 - 障碍物状态上报")
public interface RobotObstaclesStatusApi {
String PREFIX = ApiConstants.PREFIX + "/task";
@PostMapping(PREFIX + "/robotObstaclesStatus")
@Operation(summary = "障碍物状态上报")
void robotObstaclesStatus(@RequestParam("message") String message);
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.system.api.robot.dto;
import lombok.Data;
@Data
public class RobotObstaclesStatusDTO {
/**
* mac地址
*/
public String mac;
/**
* true表示有障碍物false表示没有障碍物
*/
public Boolean obstacles;
}

View File

@ -167,6 +167,7 @@ public interface ErrorCodeConstants {
ErrorCode INFORMATION_NOT_EXISTS = new ErrorCode(1_002_029_001, "设备信息不存在");
ErrorCode INFORMATION_MAC_EXIST = new ErrorCode(1_002_029_002, "此Mac地址已经存在");
ErrorCode INFORMATION_MAC_INPUT = new ErrorCode(1_002_029_003, "请输入Mac地址");
ErrorCode INFORMATION_BIND_MAP = new ErrorCode(1_002_029_004, "设备已经绑定在地图上,请先在地图上解绑");
// ========== 线库/巷道 1-002-030-000 ==========
ErrorCode HOUSE_LANE_NOT_EXISTS = new ErrorCode(1-002-030-001, "线库不存在");
@ -201,9 +202,9 @@ public interface ErrorCodeConstants {
ErrorCode TASK_CHECK_EXCEPTION = new ErrorCode(1-002-035-005, "任务下发失败");
ErrorCode TASK_CHECK_ID_EXCEPTION = new ErrorCode(1-002-035-006, "请输入ID");
ErrorCode TASK_CHECK_TASK_PRIORITY = new ErrorCode(1-002-035-007, "非新单据不能修改优先级");
ErrorCode TASK_CHECK_TASK_STATUS = new ErrorCode(1-002-035-100, "订单已完成");
ErrorCode TASK_CHECK_UPDATE_STATUS = new ErrorCode(1-002-035-101, "订单更新失败");
ErrorCode TASK_CHECK_EXIST_NO = new ErrorCode(1-002-035-102, "订单号已存在");
ErrorCode TASK_CHECK_TASK_STATUS = new ErrorCode(1-002-035-100, "任务已完成");
ErrorCode TASK_CHECK_UPDATE_STATUS = new ErrorCode(1-002-035-101, "任务更新失败");
ErrorCode TASK_CHECK_EXIST_NO = new ErrorCode(1-002-035-102, "任务号已存在");
ErrorCode TASK_TYPE_UN_EXIST = new ErrorCode(1-002-035-103, "找不到对应的任务类型");
ErrorCode TASK_TAKE_LOCATION_EMPTY = new ErrorCode(1-002-035-104, "取货库位没有库存");
ErrorCode TASK_TAKE_LOCATION_UPPER_LEVELS_NOT_EMPTY = new ErrorCode(1-002-035-105, "取货库位上层不为空");
@ -211,6 +212,7 @@ public interface ErrorCodeConstants {
ErrorCode TASK_RELEASE_LOCATION_LOWER_LEVELS_EMPTY = new ErrorCode(1-002-035-107, "放货库位下层为空");
ErrorCode TASK_TAKE_LOCATION_HAVE_OTHER_TASK = new ErrorCode(1-002-035-108, "取货库位已经分配了其他任务");
ErrorCode TASK_RELEASE_LOCATION_HAVE_OTHER_TASK = new ErrorCode(1-002-035-109, "放货库位已经分配了其他任务");
ErrorCode TASK_CREATE_FAIL = new ErrorCode(1-002-035-110, "任务创建失败:");
// ========== 机器人任务明细 1-002-036-000 ==========
ErrorCode TASK_DETAIL_NOT_EXISTS = new ErrorCode(1-002-036-001, "机器人任务明细不存在");

View File

@ -104,5 +104,15 @@ public class PathApiImpl implements PathApi {
pathPlanningService.pathPlanningMovePose(message);
}
/**
* 仿真点位信息
* @param message
*/
@Override
public void simulationRobotPoseRequest(String message) {
TenantContextHolder.setTenantId(1L);
pathPlanningService.simulationRobotPoseRequest();
}
}

View File

@ -0,0 +1,67 @@
package cn.iocoder.yudao.module.system.api.robot;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi;
import cn.iocoder.yudao.module.system.api.robot.dto.FloorZoneDTO;
import cn.iocoder.yudao.module.system.api.robot.dto.RobotObstaclesStatusDTO;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotUpdatePalletHeightDTO;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.constant.webSocket.WebSocketConstant;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotWarnMsgSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotWarnMsgDO;
import cn.iocoder.yudao.module.system.enums.robot.RobotWarnType;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Slf4j
@RestController // 提供 RESTful API 接口 Feign 调用
@Validated
public class RobotObstaclesStatusApiImpl implements RobotObstaclesStatusApi{
@Resource
private RedisUtil redisUtil;
@Resource
public WebSocketSenderApi webSocketSenderApi;
@Resource
private RobotWarnMsgService warnMsgService;
@Autowired
private RobotInformationService robotInformationService;
@Override
public void robotObstaclesStatus(String message) {
log.info("障碍物状态上报 :{}" ,message);
RobotObstaclesStatusDTO data = JSON.parseObject(message, RobotObstaclesStatusDTO.class);
if (!data.getObstacles()) {
return;
}
String floorAreaKey = RobotTaskChcheConstant.ROBOT_FLOOR_AREA + data.getMac();
Object floorAreaObject = redisUtil.get(floorAreaKey);
FloorZoneDTO floorZoneDTO = JSONUtil.toBean((String) floorAreaObject, FloorZoneDTO.class);
String robotNo = robotInformationService.getRobotNoByMac(data.getMac());
RobotWarnMsgSaveReqVO warnMsg = new RobotWarnMsgSaveReqVO();
warnMsg.setWarnLevel(4);
warnMsg.setRobotNo(robotNo);
warnMsg.setWarnType(RobotWarnType.ROBOT_WARN.getType());
warnMsg.setWarnMsg(robotNo +" 机器人遇到障碍物");
warnMsgService.createWarnMsg(warnMsg);
webSocketSenderApi.sendObject(floorZoneDTO.getFloor() + "_" + floorZoneDTO.getArea(),
WebSocketConstant.AGV_WARN, warnMsg.getWarnMsg());
}
}

View File

@ -64,6 +64,10 @@ public class PathPlanningTopicConstant {
* 发送车辆编号对应的车宽中心与车头距离中心与车尾距离给PP
*/
public static String SEND_ROBOT_DIMENSIONS = "SEND_ROBOT_DIMENSIONS";
/**
* 仿真车辆信息
*/
public static String INIT_ROBOT_POSE = "INIT_ROBOT_POSE";
/**
* 车辆当前位置给给PP

View File

@ -20,4 +20,8 @@ public class RobotTopicConstant {
* 让机器人同步告警码值映射的topic 拼接mac地址
*/
public static String UPDATE_ERROR_TOPIC = "UPDATE_ERROR_";
/**
* 让机器人同步告警码值映射的topic 拼接mac地址
*/
public static String WARN_WAIT_TIME_TOPIC = "WARN_WAIT_TIME";
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.system.controller.admin.information.dto;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.Data;
@Data
public class DeviceInformationDataJsonDTO {
private Long id;
private Long positionMapId;
private Long positionMapItemId;
private String locationX;
private String locationY;
private String actualLocationX;
private String actualLocationY;
private Integer locationWide;
private Integer locationDeep;
private Integer deviceType;
private String deviceNo;
private String mapImageUrl;
}

View File

@ -107,4 +107,11 @@ public class PathPlanningController {
pathPlanningService.robotDimensions();
return success("同步完成");
}
@PostMapping("/robot/simulationRobotPoseRequest")
@Operation(summary = "发送车辆数据给--仿真")
public CommonResult<String> simulationRobotPoseRequest() {
pathPlanningService.simulationRobotPoseRequest();
return success("同步完成");
}
}

View File

@ -0,0 +1,32 @@
package cn.iocoder.yudao.module.system.controller.admin.path.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
@Data
public class SimulationRobotPoseDTO {
private String mac;
@Schema(description = "坐标x轴")
private String locationX;
@Schema(description = "坐标y轴")
private String locationY;
@Schema(description = "实际坐标x轴")
private String actualLocationX;
@Schema(description = "实际坐标y轴")
private String actualLocationY;
@Schema(description = "地图所在楼")
public String floor;
@Schema(description = "地图所在区")
public String area;
@Schema(description = "弧度")
private String locationYaw;
}

View File

@ -13,7 +13,8 @@ public enum CommandConfigTypeEnum {
CHARG_CONFIG(1,"充电设置(页面)"),
PP_CONFIG_PRIORITY(2,"优先级>时间>路径"),
PP_CONFIG_TIME(3,"优先级=时间>路径"),
PP_CONFIG_PATH(4,"优先级=时间=路径");
PP_CONFIG_PATH(4,"优先级=时间=路径"),
SIMULATION_CONFIG(13,"仿真初始化地图");
/**
* 类型
*/

View File

@ -72,18 +72,20 @@ public class HouseLocationServiceImpl extends ServiceImpl<WareHouseLocationMappe
// 更新
WareHouseLocationDO updateObj = BeanUtils.toBean(updateReqVO, WareHouseLocationDO.class);
houseLocationMapper.updateById(updateObj);
String str = getChangeInfo(wareHouseLocationDO, updateObj);
if (ObjectUtil.isNotEmpty(str)) {
str = "修改库位信息:" + updateReqVO.getLocationNo() + "_" + str;
if(ObjectUtil.isEmpty(str)) {
return;
}
str = "修改库位信息:" + updateReqVO.getLocationNo() + "_" + str;
UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
.operateAction(str)
.nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
userOperationLogService.createUserOperationLog(operationLog);
houseLocationMapper.updateById(updateObj);
}
public String getChangeInfo(WareHouseLocationDO wareHouseLocationDO, WareHouseLocationDO updateReqVO) {
@ -123,7 +125,6 @@ public class HouseLocationServiceImpl extends ServiceImpl<WareHouseLocationMappe
str = str + " 设置库位锁定状态为正常" ;
}
return str;
}

View File

@ -5,8 +5,10 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotPathStatusDTO;
import cn.iocoder.yudao.module.system.constant.device.DeviceChcheConstant;
import cn.iocoder.yudao.module.system.controller.admin.information.dto.DeviceInformationDTO;
import cn.iocoder.yudao.module.system.controller.admin.information.dto.DeviceInformationDataJsonDTO;
import cn.iocoder.yudao.module.system.controller.admin.information.dto.MapBindDeviceInfoDTO;
import cn.iocoder.yudao.module.system.controller.admin.information.dto.StatisticsInformationDTO;
import cn.iocoder.yudao.module.system.controller.admin.information.vo.DeviceInformationPageReqVO;
@ -32,6 +34,7 @@ import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService
import cn.iocoder.yudao.module.system.service.robot.RobotWarnMsgService;
import cn.iocoder.yudao.module.system.util.modbus3.ModbusUtils;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.serotonin.modbus4j.ModbusMaster;
@ -52,8 +55,7 @@ import java.util.stream.Collectors;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.INFORMATION_MAC_EXIST;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.INFORMATION_NOT_EXISTS;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
/**
* 设备信息 Service 实现类
@ -121,6 +123,7 @@ public class DeviceInformationServiceImpl extends ServiceImpl<DeviceInformationM
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateInformation(DeviceInformationSaveReqVO updateReqVO) {
// 校验存在
validateInformationExists(updateReqVO.getId());
@ -137,6 +140,17 @@ public class DeviceInformationServiceImpl extends ServiceImpl<DeviceInformationM
DeviceInformationDO updateObj = BeanUtils.toBean(updateReqVO, DeviceInformationDO.class);
informationMapper.updateById(updateObj);
if (ObjectUtil.isNotEmpty(updateObj.getPositionMapItemId())) {
PositionMapItemDO positionMapItem = positionMapItemService.getPositionMapItem(updateObj.getPositionMapItemId());
String dataJson = positionMapItem.getDataJson();
DeviceInformationDataJsonDTO data = JSON.parseObject(dataJson, DeviceInformationDataJsonDTO.class);
data.setDeviceType(updateObj.getDeviceType());
data.setDeviceNo(updateObj.getDeviceNo());
data.setMapImageUrl(updateObj.getMapImageUrl());
positionMapItem.setDataJson(JSON.toJSONString(data));
positionMapItemService.updateById(positionMapItem);
}
UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
.operateAction("更新设备信息 " + updateReqVO.getDeviceNo())
.nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
@ -149,19 +163,16 @@ public class DeviceInformationServiceImpl extends ServiceImpl<DeviceInformationM
// 校验存在
validateInformationExists(id);
DeviceInformationDO deviceInformationDO = informationMapper.selectById(id);
if (ObjectUtil.isNotEmpty(deviceInformationDO.getPositionMapItemId())) {
throw exception(INFORMATION_BIND_MAP);
}
UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder()
.operateAction("删除设备 " + deviceInformationDO.getDeviceNo())
.nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
// 删除
informationMapper.deleteById(id);
if (ObjectUtil.isNotEmpty(deviceInformationDO.getPositionMapItemId())) {
PositionMapItemDO positionMapItem = positionMapItemService.getPositionMapItem(deviceInformationDO.getPositionMapItemId());
positionMapItem.setType(PositionMapItemEnum.PATH.getType());
positionMapItem.setDataJson(null);
positionMapItemService.updateById(positionMapItem);
}
userOperationLogService.createUserOperationLog(operationLog);
}
@ -208,7 +219,10 @@ public class DeviceInformationServiceImpl extends ServiceImpl<DeviceInformationM
editList.addAll(list.get(1));
}
if (isNotEmpty(list.get(2))) {
list.get(2).forEach(a -> a.setPositionMapItemId(null));
list.get(2).forEach( a -> {
a.setPositionMapItemId(null);
a.setPositionMapId(null);
});
editList.addAll(list.get(2));
}
if (isNotEmpty(editList)) {

View File

@ -44,4 +44,9 @@ public interface PathPlanningService {
* @param message
*/
void pathPlanningMovePose(String message);
/**
* 仿真点位信息
*/
void simulationRobotPoseRequest();
}

View File

@ -18,19 +18,27 @@ import cn.iocoder.yudao.module.system.constant.path.PathPlanningTopicConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTaskChcheConstant;
import cn.iocoder.yudao.module.system.constant.robot.RobotTopicConstant;
import cn.iocoder.yudao.module.system.constant.webSocket.WebSocketConstant;
import cn.iocoder.yudao.module.system.controller.admin.path.dto.SimulationRobotPoseDTO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapItemSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapLineSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.vo.PositionMapSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.task.TaskAssignDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.config.CommonConfigDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapLineDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotInformationDO;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapItemMapper;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapLineMapper;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotInformationMapper;
import cn.iocoder.yudao.module.system.enums.config.CommandConfigTypeEnum;
import cn.iocoder.yudao.module.system.enums.item.PositionMapItemEnum;
import cn.iocoder.yudao.module.system.enums.line.DirectionEnum;
import cn.iocoder.yudao.module.system.enums.path.PathTypeEnum;
import cn.iocoder.yudao.module.system.service.config.CommonConfigService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapService;
import cn.iocoder.yudao.module.system.service.robot.RobotInformationService;
import cn.iocoder.yudao.module.system.util.redis.RedisUtil;
import com.alibaba.fastjson.JSON;
@ -80,15 +88,21 @@ public class PathPlanningServiceImpl implements PathPlanningService {
@Resource
private CommonApi commonApi;
@Resource
private RequestProcessor processor;
@Resource
private RedisUtil redisUtil;
@Resource
public WebSocketSenderApi webSocketSenderApi;
@Resource
private CommonConfigService configService;
@Resource
private PositionMapService positionMapService;
@Resource
private PositionMapItemService positionMapItemService;
/**
* 同步ware_position_map_line的点位信息
*/
@ -444,6 +458,64 @@ public class PathPlanningServiceImpl implements PathPlanningService {
WebSocketConstant.PLANNING_MOVE_POSE, message);
}
/**
* 仿真点位信息
*/
@Override
public void simulationRobotPoseRequest() {
CommonConfigDO config = configService.getConfig(CommandConfigTypeEnum.SIMULATION_CONFIG.getType().longValue());
PositionMapDO positionMap = null;
if (ObjectUtil.isEmpty(config) || ObjectUtil.isEmpty(config.getConfigStr())) {
List<PositionMapDO> maps = positionMapService.getAllMap();
if (ObjectUtil.isEmpty(maps)) {
return;
}
positionMap = maps.get(0);
}else {
positionMap = positionMapService.getPositionMap(Long.valueOf(config.getConfigStr()));
}
if (ObjectUtil.isEmpty(positionMap)) {
log.info("仿真环境没有地图信息");
return;
}
List<RobotInformationDO> robots = robotInformationService.getAllRobot();
if (ObjectUtil.isEmpty(robots)) {
log.info("仿真环境没有机器人信息");
return;
}
List<PositionMapItemDO> itemDOList = new ArrayList<>();
List<PositionMapItemDO> items = positionMapItemService.getPositionMapItemByMapAndType(positionMap.getId(), PositionMapItemEnum.WAIT.getType());
if (ObjectUtil.isEmpty(items) || items.size() < robots.size()) {
List<PositionMapItemDO> itemPoses = positionMapItemService.getPositionMapItemByMapAndType(positionMap.getId(), PositionMapItemEnum.PATH.getType());
itemDOList.addAll(itemPoses);
} else {
itemDOList = items;
}
List<SimulationRobotPoseDTO> simulationList = new ArrayList<>();
int i = 0;
for (RobotInformationDO robot : robots) {
SimulationRobotPoseDTO simulationRobotPoseDTO = new SimulationRobotPoseDTO();
simulationRobotPoseDTO.setMac(robot.getMacAddress());
if (itemDOList.size() <= i) {
continue;
}
simulationRobotPoseDTO.setLocationX(itemDOList.get(i).getLocationX());
simulationRobotPoseDTO.setLocationY(itemDOList.get(i).getLocationY());
simulationRobotPoseDTO.setActualLocationX(itemDOList.get(i).getActualLocationX());
simulationRobotPoseDTO.setActualLocationY(itemDOList.get(i).getActualLocationY());
simulationRobotPoseDTO.setLocationYaw(itemDOList.get(i).getLocationYaw());
simulationRobotPoseDTO.setFloor(positionMap.getFloor()+"");
simulationRobotPoseDTO.setArea(positionMap.getArea());
simulationList.add(simulationRobotPoseDTO);
i++;
}
commonApi.commonMethod(simulationList, PathPlanningTopicConstant.INIT_ROBOT_POSE);
}
public PositionMapLineDTO setPositionMapLineDTOData(PositionMapLineDTO positionMapLineDO) {
PositionMapLineDTO build = PositionMapLineDTO.builder()
.id(positionMapLineDO.getId())

View File

@ -103,4 +103,12 @@ public interface PositionMapItemService extends IService<PositionMapItemDO> {
Object getAGVPointInformation(String macAddress);
void setMapItemIdle(Long id);
/**
* 查询地图对应的类型数据
* @param id 地图id
* @param type 类型
* @return
*/
List<PositionMapItemDO> getPositionMapItemByMapAndType(Long id, Integer type);
}

View File

@ -17,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
@ -130,4 +131,11 @@ public class PositionMapItemServiceImpl extends ServiceImpl<PositionMapItemMappe
positionMapItemMapper.updateById(item);
}
@Override
public List<PositionMapItemDO> getPositionMapItemByMapAndType(Long mapId, Integer type) {
return positionMapItemMapper.selectList(new LambdaQueryWrapperX<PositionMapItemDO>()
.eq(PositionMapItemDO::getPositionMapId, mapId)
.eq(PositionMapItemDO::getType, type));
}
}

View File

@ -10,6 +10,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
/**
* 仓库点位地图 Service 接口
@ -94,4 +95,10 @@ public interface PositionMapService extends IService<PositionMapDO> {
* @param id
*/
void emergencyStopOrRecovery(Long id);
/**
* 获取所有地图
* @return
*/
List<PositionMapDO> getAllMap();
}

View File

@ -305,4 +305,9 @@ public class PositionMapServiceImpl extends ServiceImpl<PositionMapMapper, Posit
}
@Override
public List<PositionMapDO> getAllMap() {
return positionMapMapper.selectList(new LambdaQueryWrapperX<PositionMapDO>().orderByDesc(PositionMapDO::getId));
}
}

View File

@ -181,15 +181,6 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
String addResult = "";
if (lock.tryLock(60l, TimeUnit.MINUTES)) {
/*try {
addResult = addTask(createReqVO);
} catch (Exception e) {
log.error("下发任务出现异常 :{}", e);
addResult = ObjectUtil.isNotEmpty(e.getMessage()) ? e.getMessage(): "创建任务失败";
} finally {
lock.unlock();
}*/
try {
addResult = addTask(createReqVO);
} finally {
@ -203,7 +194,7 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
throw exception0(TASK_CHECK_EXCEPTION.getCode(), addResult);
}
UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder().operateAction("创建订单 " + createReqVO.getTaskNo())
UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder().operateAction("创建任务 " + createReqVO.getTaskNo())
.nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
userOperationLogService.createUserOperationLog(operationLog);
@ -386,7 +377,7 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
List<Long> detailIds = new ArrayList<>();
Set<String> robotNos = new HashSet<>();
UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder().operateAction("关闭订单 " + robotTaskDO.getTaskNo())
UserOperationLogSaveReqVO operationLog = UserOperationLogSaveReqVO.builder().operateAction("关闭任务 " + robotTaskDO.getTaskNo())
.nickName(SecurityFrameworkUtils.getLoginUserNickname()).build();
userOperationLogService.createUserOperationLog(operationLog);
@ -726,20 +717,21 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
if (ObjectUtil.isEmpty(stockList)) {
log.error("取货线库/区域为空或者已锁定或者机器人取放货区域受限制 :{}", robotTaskVo.toString());
throw new RuntimeException("取货线库/区域为空或者已锁定或者机器人取放货区域受限制");
throw exception0(TASK_CREATE_FAIL.getCode(), "取货线库/区域为空或者已锁定或者机器人取放货区域受限制" );
}
//判断取货库位是否存在未完成的任务
Set<Long> stockLocationIds = stockList.stream().map(WareHouseLocationDO::getId).collect(Collectors.toSet());
List<RobotTaskDetailDO> doingTasks = taskDetailMapper.queryDoingTaskByIds(stockLocationIds);
if (ObjectUtil.isNotEmpty(doingTasks)) {
throw new RuntimeException("取货线库/区域,存在未完成的任务");
log.error("取货线库/区域,存在未完成的任务 :{}", JSON.toJSONString(doingTasks));
throw exception0(TASK_CREATE_FAIL.getCode(), "取货线库/区域,存在未完成的任务" );
}
//查找空库位
WareHouseLocationDO releaseQuery = null;
if (ReleaseTakeEnum.TO_LANE.getType().equals(robotTaskVo.getReleaseType())) {
if (ObjectUtil.isEmpty(laneIds) && ObjectUtil.isNotEmpty(skuInfo)) {
log.error("查不到此物料对应的线库区域 :{}", robotTaskVo.getReleaseId());
throw new RuntimeException("查不到此物料对应的线库区域 " + skuInfo);
throw exception0(TASK_CREATE_FAIL.getCode(), "查不到此物料对应的线库区域" );
}
releaseQuery = WareHouseLocationDO.builder()
.laneId(robotTaskVo.getReleaseId())
@ -750,7 +742,7 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
} else if (ReleaseTakeEnum.TO_AREA.getType().equals(robotTaskVo.getReleaseType())) {
if (ObjectUtil.isEmpty(areaIds) && ObjectUtil.isNotEmpty(skuInfo)) {
log.error("查不到此物料对应的区域库位 :{}", robotTaskVo.getReleaseId());
throw new RuntimeException("查不到此物料对应的区域库位 " + skuInfo);
throw exception0(TASK_CREATE_FAIL.getCode(), "查不到此物料对应的区域库位" );
}
releaseQuery = WareHouseLocationDO.builder()
.areaId(robotTaskVo.getReleaseId())
@ -764,7 +756,7 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
laneIds, areaIds, mapItemIds);
if (ObjectUtil.isEmpty(releaseStockList) || releaseStockList.size() < stockList.size()) {
log.error("放货线库/区域库位数量不足或者机器人取放货区域受限制 :{}", robotTaskVo.toString());
throw new RuntimeException("放货线库/区域库位数量不足或者机器人取放货区域受限制");
throw exception0(TASK_CREATE_FAIL.getCode(), "放货线库/区域库位数量不足或者机器人取放货区域受限制" );
}
Collections.reverse(releaseStockList);
//赋值数据
@ -896,7 +888,7 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
break;
default:
log.error("任务类型不存在 ");
throw new RuntimeException("任务类型不存在");
throw exception0(TASK_CREATE_FAIL.getCode(), "任务类型不存在" );
}
}
return locationIds;
@ -1028,30 +1020,30 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
robotTaskVo.setToMapItemId(locationDO.getMapItemId());
if (ObjectUtil.isNotEmpty(mapIds) && !mapIds.contains(locationDO.getMapId())) {
log.error("机器人不能在此放货库位放货 :{}, 机器人编号 :{}", locationDO.getLocationNo(), robotTaskVo.getRobotNo());
throw new RuntimeException("机器人不能在此放货库位放货 " + robotTaskVo.getReleaseId());
throw exception0(TASK_CREATE_FAIL.getCode(), "机器人不能在此放货库位放货 " + robotTaskVo.getReleaseId());
}
if (ObjectUtil.isNotEmpty(takeMapItemIds) && takeMapItemIds.contains(locationDO.getMapItemId())) {
log.error("此点位存在取货任务 :{}", locationDO.getLocationNo());
throw new RuntimeException("此库位存在取货任务 " + locationDO.getLocationNo());
throw exception0(TASK_CREATE_FAIL.getCode(), "此库位存在取货任务 " + locationDO.getLocationNo());
}
releaseMapItemIds.add(locationDO.getMapItemId());
} else {
if (ReleaseTakeEnum.TO_LANE.getType().equals(robotTaskVo.getReleaseType()) && ObjectUtil.isEmpty(laneIds)
&& ObjectUtil.isNotEmpty(skuInfo)) {
log.error("查不到此物料对应的线库区域 :{}", robotTaskVo.getReleaseId());
throw new RuntimeException("查不到此物料对应的线库区域 " + skuInfo);
throw exception0(TASK_CREATE_FAIL.getCode(), "查不到此物料对应的线库区域 " + skuInfo);
}
if (ReleaseTakeEnum.TO_AREA.getType().equals(robotTaskVo.getReleaseType()) && ObjectUtil.isEmpty(areaIds)
&& ObjectUtil.isNotEmpty(skuInfo)) {
log.error("查不到此物料对应的区域库位 :{}", robotTaskVo.getReleaseId());
throw new RuntimeException("查不到此物料对应的区域库位 " + skuInfo);
throw exception0(TASK_CREATE_FAIL.getCode(), "查不到此物料对应的区域库位 " + skuInfo);
}
WareHouseLocationDO wareHouseLocationDO =
locationMapper.selectByTypeAndId(LocationUseStatusEnum.NO.getType(), robotTaskVo.getReleaseType()
, robotTaskVo.getReleaseId(), locationIds, mapIds, takeMapItemIds, laneIds, areaIds);
if (ObjectUtil.isEmpty(wareHouseLocationDO)) {
log.error("放货库位为空或者已锁定或者机器人取放货区域受限制 :{}", robotTaskVo.getReleaseId());
throw new RuntimeException("放货库位为空或者已锁定或者机器人取放货区域受限制 " + robotTaskVo.getReleaseId());
throw exception0(TASK_CREATE_FAIL.getCode(), "放货库位为空或者已锁定或者机器人取放货区域受限制 " + robotTaskVo.getReleaseId());
}
robotTaskVo.setToLocationNo(wareHouseLocationDO.getLocationNo());
robotTaskVo.setToLocationId(wareHouseLocationDO.getId());
@ -1084,15 +1076,15 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
robotTaskVo.setFromMapItemId(locationDO.getMapItemId());
if (ObjectUtil.isNotEmpty(mapIds) && !mapIds.contains(locationDO.getMapId())) {
log.error("机器人不能在此取货库位取货 :{}, 机器人编号 :{}", locationDO.getLocationNo(), robotTaskVo.getRobotNo());
throw new RuntimeException("机器人不能在此取货库位取货 " + robotTaskVo.getTakeId());
throw exception0(TASK_CREATE_FAIL.getCode(), "机器人不能在此取货库位取货 " + robotTaskVo.getTakeId());
}
if (ObjectUtil.isNotEmpty(releaseMapItemIds) && releaseMapItemIds.contains(locationDO.getMapItemId())) {
log.error("此取货库位存在放货任务 :{}", locationDO.getLocationNo());
throw new RuntimeException("此取货库位存在放货任务 " + locationDO.getLocationNo());
throw exception0(TASK_CREATE_FAIL.getCode(), "此取货库位存在放货任务 " + locationDO.getLocationNo());
}
if (LocationUseStatusEnum.NO.getType().equals(locationDO.getLocationUseStatus())) {
log.error("此取货库位没库存 :{}", locationDO.getLocationNo());
throw new RuntimeException("此取货库位没库存 " + locationDO.getLocationNo());
throw exception0(TASK_CREATE_FAIL.getCode(), "此取货库位没库存 " + locationDO.getLocationNo());
}
takeMapItemIds.add(locationDO.getMapItemId());
} else {
@ -1101,7 +1093,7 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
robotTaskVo.getTakeId(), locationIds, mapIds, releaseMapItemIds, new ArrayList<>(), new ArrayList<>());
if (ObjectUtil.isEmpty(wareHouseLocationDO)) {
log.error("取货库位为空或者已锁定或者机器人取放货区域受限制 :{}", robotTaskVo.getTakeId());
throw new RuntimeException("取货库位为空或者已锁定或者机器人取放货区域受限制 " + robotTaskVo.getTakeId());
throw exception0(TASK_CREATE_FAIL.getCode(), "取货库位为空或者已锁定或者机器人取放货区域受限制 " + robotTaskVo.getTakeId());
}
robotTaskVo.setFromLocationNo(wareHouseLocationDO.getLocationNo());
robotTaskVo.setFromLocationId(wareHouseLocationDO.getId());
@ -1141,7 +1133,7 @@ public class RobotTaskServiceImpl extends ServiceImpl<RobotTaskMapper, RobotTask
List<RobotTaskDetailDO> doingTasks = taskDetailMapper.queryDoingTaskByIds(set);
if (ObjectUtil.isNotEmpty(doingTasks)) {
log.error("取货库位,存在未完成的任务 :{}", robotTaskVo.getTakeId());
throw new RuntimeException("取货库位,存在未完成的任务 ");
throw exception0(TASK_CREATE_FAIL.getCode(), "取货库位,存在未完成的任务" );
}
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.service.robot;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.system.api.robot.vo.RobotInformationVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotWarnCodeMappingPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotWarnCodeMappingSaveReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.warn.RobotWarnCodeMappingVO;
@ -32,6 +33,9 @@ import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@ -108,7 +112,8 @@ public class RobotWarnCodeMappingServiceImpl implements RobotWarnCodeMappingServ
if (ObjectUtil.isEmpty(list)) {
return;
}
exportJson(response,list,"warn.json",warnUploadPath);
Map<String, RobotWarnCodeMappingVO> map = list.stream().collect(Collectors.toMap(RobotWarnCodeMappingVO::getWarnCode, Function.identity(), (v1, v2) -> v1));
exportJson(response,map,"warn.json",warnUploadPath);
}
public void exportJson(HttpServletResponse response, Object obj, String fileName, String uploadPath) {

View File

@ -71,6 +71,17 @@ public class ToolsServiceImpl implements ToolsService {
}
CommonConfigVO chargeConfig = JSONUtil.toBean(commonConfigDO.getConfigStr(), CommonConfigVO.class);
if (ObjectUtil.isNotEmpty(chargeConfig.getWarnWaitTime())) {
List<RobotInformationDO> robots = informationService.getAllRobot();
if (ObjectUtil.isNotEmpty(robots)) {
for (RobotInformationDO robot : robots) {
commonApi.commonMethodStr(String.valueOf(chargeConfig.getWarnWaitTime()),
RobotTopicConstant.WARN_WAIT_TIME_TOPIC+robot.getMacAddress());
}
}
}
if (ObjectUtil.isEmpty(chargeConfig.getPathSortConfig())) {
addWarnMsg();
return "没有配置路径规划权重";