From 98af101f00d6650315f31e600b79c021c8d30809 Mon Sep 17 00:00:00 2001 From: liejiu946 Date: Thu, 12 Feb 2026 15:00:01 +0800 Subject: [PATCH] =?UTF-8?q?add:1.=E5=A2=9E=E5=8A=A0=E6=A0=87=E5=AE=9A?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 7 + .../controller/AnomalyInfoController.java | 17 +- .../apt/anomalyInfo/dao/ExceptionRecord.java | 56 ++++ .../param/QueryExceptionRecordParam.java | 20 ++ .../service/AnomalyInfoService.java | 37 +++ .../service/ExceptionRecordService.java | 15 + .../service/impl/AnomalyInfoServiceImpl.java | 199 ++++++++++++- .../impl/ExceptionRecordServiceImpl.java | 40 +++ .../service/mapper/ExceptionRecordMapper.java | 14 + .../controller/CalibrationController.java | 61 ++++ .../calibration/enums/CalibrationResult.java | 29 ++ .../calibration/enums/LaserAndCameraType.java | 102 +++++++ .../param/CalibrationLaserParam.java | 24 ++ .../service/CalibrationService.java | 52 ++++ .../service/impl/CalibrationServiceImpl.java | 277 ++++++++++++++++++ .../qrobot/apt/vehicle/dao/VehicleInfo.java | 9 + .../qrobot/apt/vehicle/dao/VehicleSpeed.java | 26 ++ .../vehicle/rest/VehicleInfoController.java | 12 + .../vehicle/service/VehicleInfoService.java | 11 + .../service/impl/VehicleInfoServiceImpl.java | 63 +++- .../nl/qrobot/config/MybatisPlusConfig.java | 22 ++ .../thread/ProtobufWebSocketHandler.java | 21 +- src/main/resources/config/application-dev.yml | 2 +- src/main/resources/config/application.yml | 1 + .../resources/language/error/error.properties | 4 +- .../language/error/error_en_US.properties | 4 +- .../language/error/error_zh_CN.properties | 4 +- 27 files changed, 1117 insertions(+), 12 deletions(-) create mode 100644 src/main/java/org/nl/qrobot/apt/anomalyInfo/dao/ExceptionRecord.java create mode 100644 src/main/java/org/nl/qrobot/apt/anomalyInfo/param/QueryExceptionRecordParam.java create mode 100644 src/main/java/org/nl/qrobot/apt/anomalyInfo/service/ExceptionRecordService.java create mode 100644 src/main/java/org/nl/qrobot/apt/anomalyInfo/service/impl/ExceptionRecordServiceImpl.java create mode 100644 src/main/java/org/nl/qrobot/apt/anomalyInfo/service/mapper/ExceptionRecordMapper.java create mode 100644 src/main/java/org/nl/qrobot/apt/calibration/controller/CalibrationController.java create mode 100644 src/main/java/org/nl/qrobot/apt/calibration/enums/CalibrationResult.java create mode 100644 src/main/java/org/nl/qrobot/apt/calibration/enums/LaserAndCameraType.java create mode 100644 src/main/java/org/nl/qrobot/apt/calibration/param/CalibrationLaserParam.java create mode 100644 src/main/java/org/nl/qrobot/apt/calibration/service/CalibrationService.java create mode 100644 src/main/java/org/nl/qrobot/apt/calibration/service/impl/CalibrationServiceImpl.java create mode 100644 src/main/java/org/nl/qrobot/apt/vehicle/dao/VehicleSpeed.java create mode 100644 src/main/java/org/nl/qrobot/config/MybatisPlusConfig.java diff --git a/pom.xml b/pom.xml index db3b4c4..7baf482 100644 --- a/pom.xml +++ b/pom.xml @@ -104,6 +104,13 @@ 1.2.3 + + + org.springframework.boot + spring-boot-starter-validation + 3.0.0 + + com.alibaba diff --git a/src/main/java/org/nl/qrobot/apt/anomalyInfo/controller/AnomalyInfoController.java b/src/main/java/org/nl/qrobot/apt/anomalyInfo/controller/AnomalyInfoController.java index 203f124..3a59806 100644 --- a/src/main/java/org/nl/qrobot/apt/anomalyInfo/controller/AnomalyInfoController.java +++ b/src/main/java/org/nl/qrobot/apt/anomalyInfo/controller/AnomalyInfoController.java @@ -4,22 +4,22 @@ import cn.dev33.satoken.annotation.SaIgnore; import com.alibaba.excel.EasyExcel; import org.nl.qrobot.apt.anomalyInfo.dao.ErrorHandling; import org.nl.qrobot.apt.anomalyInfo.dao.ErrorInfo; +import org.nl.qrobot.apt.anomalyInfo.param.QueryExceptionRecordParam; import org.nl.qrobot.apt.anomalyInfo.service.AnomalyInfoService; import org.nl.qrobot.apt.anomalyInfo.service.ErrorHandlingService; import org.nl.qrobot.apt.anomalyInfo.service.ErrorInfoService; +import org.nl.qrobot.apt.anomalyInfo.service.ExceptionRecordService; import org.nl.qrobot.apt.vehicle.ProcessZip; import org.nl.qrobot.common.BadRequestException; import org.nl.qrobot.common.excel.ErrorHandlingListener; import org.nl.qrobot.common.excel.ErrorInfoListener; +import org.nl.qrobot.common.logging.annotation.Log; import org.nl.qrobot.config.file.FileProperties; import org.nl.qrobot.config.language.LangProcess; import org.nl.qrobot.util.FileConstant; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; @@ -44,7 +44,7 @@ public class AnomalyInfoController { private ErrorHandlingService errorHandlingService; @Resource - private FileProperties properties; + private ExceptionRecordService exceptionRecordService; @Resource private ProcessZip processZip; @@ -55,6 +55,13 @@ public class AnomalyInfoController { return new ResponseEntity<>(anomalyInfoService.queryErrorDataByCode(code), HttpStatus.OK); } + @SaIgnore + @Log("查询异常记录分页") + @PostMapping("/queryExceptionRecordPage") + public ResponseEntity queryExceptionRecordPage(@RequestBody QueryExceptionRecordParam param) { + return new ResponseEntity<>(exceptionRecordService.queryExceptionRecordPage(param), HttpStatus.OK); + } + @PostMapping("/importErrorInfoExcel") public ResponseEntity importErrorInfoExcel(@RequestParam("file") MultipartFile file) throws IOException { if (file.isEmpty()) { diff --git a/src/main/java/org/nl/qrobot/apt/anomalyInfo/dao/ExceptionRecord.java b/src/main/java/org/nl/qrobot/apt/anomalyInfo/dao/ExceptionRecord.java new file mode 100644 index 0000000..ae091b6 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/anomalyInfo/dao/ExceptionRecord.java @@ -0,0 +1,56 @@ +package org.nl.qrobot.apt.anomalyInfo.dao; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +/** + * @author dsh + * 2026/1/5 + */ +@Data +@TableName("exception_record") +public class ExceptionRecord { + + /** + * 异常标识 + */ + @TableId + private String id; + + /** + * 异常编码 + */ + private String exceptionCode; + + /** + * 异常消息 + */ + private String exceptionMessage; + + /** + * 异常消息(中文) + */ + private String zh_exceptionMessage; + + /** + * 异常消息(英文) + */ + private String en_exceptionMessage; + + /** + * 是否活跃 + */ + private String active; + + /** + * 创建时间 + */ + private String createdAt; + + /** + * 解决时间 + */ + private String resolvedAt; + +} diff --git a/src/main/java/org/nl/qrobot/apt/anomalyInfo/param/QueryExceptionRecordParam.java b/src/main/java/org/nl/qrobot/apt/anomalyInfo/param/QueryExceptionRecordParam.java new file mode 100644 index 0000000..e10134a --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/anomalyInfo/param/QueryExceptionRecordParam.java @@ -0,0 +1,20 @@ +package org.nl.qrobot.apt.anomalyInfo.param; + +import lombok.Data; + +/** + * @author dsh + * 2026/1/13 + */ +@Data +public class QueryExceptionRecordParam { + + private int pageNum; + + private int pageSize; + + private String startTime; + + private String endTime; + +} diff --git a/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/AnomalyInfoService.java b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/AnomalyInfoService.java index 3c7316e..985d318 100644 --- a/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/AnomalyInfoService.java +++ b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/AnomalyInfoService.java @@ -1,6 +1,12 @@ package org.nl.qrobot.apt.anomalyInfo.service; +import org.nl.qrobot.apt.anomalyInfo.dao.ErrorInfo; +import org.nl.qrobot.apt.anomalyInfo.dao.ExceptionRecord; import org.nl.qrobot.apt.anomalyInfo.dto.ErrorDataDto; +import org.nl.qrobot.apt.dto.WebResponse; +import org.nl.qrobot.apt.vehicle.dao.VehicleException; + +import java.util.List; /** * @author dsh @@ -14,4 +20,35 @@ public interface AnomalyInfoService { * @return */ ErrorDataDto queryErrorDataByCode(String code); + + /** + * 处理异常数据 + */ + void processExceptions(List errorInfos); + + /** + * 标记为已解决 + * @param code + * @param resolvedAt + * @return + */ + boolean markAsResolved(String code,String resolvedAt); + + /** + * 删除cutoffDate之前的异常记录 + * @param cutoffDate + * @return + */ + int deleteRecordsOlderThan(String cutoffDate); + + /** + * 查找所有活跃异常记录 + * @return + */ + List findByActiveTrue(); + + /** + * 清除缓存 + */ + void cleanInactiveCache(); } diff --git a/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/ExceptionRecordService.java b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/ExceptionRecordService.java new file mode 100644 index 0000000..21efe80 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/ExceptionRecordService.java @@ -0,0 +1,15 @@ +package org.nl.qrobot.apt.anomalyInfo.service; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import org.nl.qrobot.apt.anomalyInfo.dao.ExceptionRecord; +import org.nl.qrobot.apt.anomalyInfo.param.QueryExceptionRecordParam; + +/** + * @author dsh + * 2026/1/13 + */ +public interface ExceptionRecordService extends IService { + + IPage queryExceptionRecordPage(QueryExceptionRecordParam param); +} diff --git a/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/impl/AnomalyInfoServiceImpl.java b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/impl/AnomalyInfoServiceImpl.java index a8f62d1..902c2d1 100644 --- a/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/impl/AnomalyInfoServiceImpl.java +++ b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/impl/AnomalyInfoServiceImpl.java @@ -1,17 +1,36 @@ package org.nl.qrobot.apt.anomalyInfo.service.impl; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.sun.jndi.cosnaming.ExceptionMapper; import org.nl.qrobot.apt.anomalyInfo.dao.ErrorHandling; import org.nl.qrobot.apt.anomalyInfo.dao.ErrorInfo; +import org.nl.qrobot.apt.anomalyInfo.dao.ExceptionRecord; import org.nl.qrobot.apt.anomalyInfo.dto.ErrorDataDto; import org.nl.qrobot.apt.anomalyInfo.service.AnomalyInfoService; import org.nl.qrobot.apt.anomalyInfo.service.mapper.ErrorHandlingMapper; import org.nl.qrobot.apt.anomalyInfo.service.mapper.ErrorInfoMapper; +import org.nl.qrobot.apt.anomalyInfo.service.mapper.ExceptionRecordMapper; +import org.nl.qrobot.apt.dto.WebResponse; +import org.nl.qrobot.apt.vehicle.dao.VehicleException; +import org.nl.qrobot.common.BadRequestException; +import org.nl.qrobot.config.language.LangProcess; +import org.nl.qrobot.util.IdUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import javax.annotation.PostConstruct; import javax.annotation.Resource; -import java.util.List; +import java.time.LocalDateTime; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** @@ -21,12 +40,20 @@ import java.util.stream.Collectors; @Service public class AnomalyInfoServiceImpl implements AnomalyInfoService { + private static final Logger log = LoggerFactory.getLogger(AnomalyInfoServiceImpl.class); + + // 内存缓存:记录当前活跃的异常码 + private final Map activeExceptionCache = new ConcurrentHashMap<>(); + @Resource private ErrorHandlingMapper errorHandlingMapper; @Resource private ErrorInfoMapper errorInfoMapper; + @Resource + private ExceptionRecordMapper exceptionRecordMapper; + @Override public ErrorDataDto queryErrorDataByCode(String code) { @@ -44,4 +71,174 @@ public class AnomalyInfoServiceImpl implements AnomalyInfoService { errorDataDto.setVideoDescription(videoDescription); return errorDataDto; } + + @Override + public void processExceptions(List errorInfos) { + + if (errorInfos == null || errorInfos.isEmpty()) { + // 没有异常,将当前活跃的异常标记为已解决 + resolveCurrentExceptions(); + return; + } + + // 处理每个异常 + for (ErrorInfo errorInfo : errorInfos) { + String code = errorInfo.getError_code(); + String message = errorInfo.getEn_error_name(); + String zh_message = errorInfo.getZh_error_name(); + String en_message = errorInfo.getEn_error_name(); + + // 检查异常是否已经记录过且为活跃状态 + if (activeExceptionCache.containsKey(code)) { + log.info("异常已存在,异常码:{}",code); + } else { + // 新异常或重新出现的异常 + ExceptionRecord errorRecord = new ExceptionRecord(); + String id = IdUtil.getStringId(); + errorRecord.setId(id); + errorRecord.setExceptionCode(code); + errorRecord.setExceptionMessage(message); + errorRecord.setZh_exceptionMessage(zh_message); + errorRecord.setEn_exceptionMessage(en_message); + errorRecord.setActive("1"); + errorRecord.setCreatedAt(DateUtil.now()); + exceptionRecordMapper.insert(errorRecord); + + activeExceptionCache.put(code, id); + } + } + + //处理已经消失的异常 + Set currentCodeSet = errorInfos.stream().map(ErrorInfo::getError_code).collect(Collectors.toSet()); + List disappearedCodes = new ArrayList<>(); + + // 找出内存中有但当前不存在的异常 + for (String code : activeExceptionCache.keySet()) { + if (!currentCodeSet.contains(code)) { + disappearedCodes.add(code); + } + } + + // 标记已消失的异常为完成 + if (!disappearedCodes.isEmpty()) { + this.markExceptionsAsResolved(disappearedCodes); + log.info("标记 {} 个消失的异常为完成", disappearedCodes.size()); + } + + } + + /** + * 标记指定异常为已解决 + */ + private void markExceptionsAsResolved(List exceptionCodes) { + String now = DateUtil.now(); + + for (String code : exceptionCodes) { + String recordId = activeExceptionCache.get(code); + if (recordId != null) { + try { + this.markAsResolved(recordId, now); + activeExceptionCache.remove(code); + log.info("异常消失,标记为完成: {}", code); + } catch (Exception e) { + log.info("标记异常完成失败: {}", code, e); + } + } + } + } + + /** + * 解决当前不存在的异常(异常消失) + */ + private void resolveCurrentExceptions() { + List resolvedCodes = new ArrayList<>(); + String now = DateUtil.now(); + for (Map.Entry entry: activeExceptionCache.entrySet()) { + String exceptionCode = entry.getKey(); + String recordId = entry.getValue(); + try { + // 标记异常为已解决 + this.markAsResolved(recordId,now); + resolvedCodes.add(exceptionCode); + log.debug("标记异常为完成: {}", exceptionCode); + } catch (Exception e) { + log.error("标记异常完成失败: {}", exceptionCode, e); + } + } + // 从内存中移除已解决的异常 + resolvedCodes.forEach(activeExceptionCache::remove); + log.info("完成标记 {} 个异常为已完成", resolvedCodes.size()); + } + + @Override + public boolean markAsResolved(String id,String resolvedAt) { + if (StrUtil.isBlank(id)){ + log.info("修改异常记录,异常标识不能为空"); + return false; + } + return exceptionRecordMapper.update(null,new LambdaUpdateWrapper<>(ExceptionRecord.class) + .set(ExceptionRecord::getResolvedAt, resolvedAt) + .set(ExceptionRecord::getActive,"0") + .eq(ExceptionRecord::getId,id) + ) >0 ; + } + + @Override + public int deleteRecordsOlderThan(String cutoffDate) { + if (StrUtil.isBlank(cutoffDate)){ + log.info("清除cutoffDate之前的异常记录,异常编号不能为空"); + return 0; + } + return exceptionRecordMapper.delete(new LambdaQueryWrapper<>(ExceptionRecord.class).lt(ExceptionRecord::getCreatedAt,cutoffDate)); + } + + @Override + public List findByActiveTrue() { + return exceptionRecordMapper.selectList(new LambdaQueryWrapper() + .eq(ExceptionRecord::getActive,"1") + ); + } + + @Override + public void cleanInactiveCache() { + + } + + /** + * 每天凌晨清理一个月前的记录 + */ + @Scheduled(cron = "0 0 0 * * ?") + @Transactional + public void cleanupOldRecords() { + String oneMonthAgo = String.valueOf(DateUtil.offsetMonth(DateUtil.date(),-1)); + int deletedCount = this.deleteRecordsOlderThan(oneMonthAgo); + log.info("清理了 {} 条一个月前的异常记录", deletedCount); + + // 重新加载活跃异常到缓存 + reloadActiveExceptions(); + } + + @PostConstruct + public void init(){ + String oneMonthAgo = String.valueOf(DateUtil.offsetMonth(DateUtil.date(),-1)); + int deletedCount = this.deleteRecordsOlderThan(oneMonthAgo); + log.info("程序初始化,清理了 {} 条一个月前的异常记录", deletedCount); + + // 重新加载活跃异常到缓存 + reloadActiveExceptions(); + } + + /** + * 重新加载活跃异常到缓存 + */ + private void reloadActiveExceptions() { + activeExceptionCache.clear(); + this.findByActiveTrue() + .forEach(record -> + activeExceptionCache.put(record.getExceptionCode(), record.getId()) + ); + log.info("重新加载了 {} 个活跃异常到缓存", activeExceptionCache.size()); + } + + } diff --git a/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/impl/ExceptionRecordServiceImpl.java b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/impl/ExceptionRecordServiceImpl.java new file mode 100644 index 0000000..14e1904 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/impl/ExceptionRecordServiceImpl.java @@ -0,0 +1,40 @@ +package org.nl.qrobot.apt.anomalyInfo.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.extern.slf4j.Slf4j; +import org.nl.qrobot.apt.anomalyInfo.dao.ExceptionRecord; +import org.nl.qrobot.apt.anomalyInfo.param.QueryExceptionRecordParam; +import org.nl.qrobot.apt.anomalyInfo.service.ExceptionRecordService; +import org.nl.qrobot.apt.anomalyInfo.service.mapper.ExceptionRecordMapper; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * @author dsh + * 2026/1/13 + */ +@Slf4j +@Service +public class ExceptionRecordServiceImpl extends ServiceImpl implements ExceptionRecordService { + + @Resource + private ExceptionRecordMapper exceptionRecordMapper; + + @Override + public IPage queryExceptionRecordPage(QueryExceptionRecordParam param) { + Page page = new Page<>(param.getPageNum(), param.getPageSize()); + return exceptionRecordMapper.selectPage(page,new LambdaQueryWrapper<>(ExceptionRecord.class) + .gt(StrUtil.isNotBlank(param.getStartTime()),ExceptionRecord::getCreatedAt,param.getStartTime()) + .lt(StrUtil.isNotBlank(param.getEndTime()),ExceptionRecord::getCreatedAt,param.getEndTime()) + .orderByDesc(ExceptionRecord::getCreatedAt) + ); + } + + +} diff --git a/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/mapper/ExceptionRecordMapper.java b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/mapper/ExceptionRecordMapper.java new file mode 100644 index 0000000..8826b88 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/anomalyInfo/service/mapper/ExceptionRecordMapper.java @@ -0,0 +1,14 @@ +package org.nl.qrobot.apt.anomalyInfo.service.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.nl.qrobot.apt.anomalyInfo.dao.ExceptionRecord; + +/** + * @author dsh + * 2026/1/5 + */ +@Mapper +public interface ExceptionRecordMapper extends BaseMapper { + +} diff --git a/src/main/java/org/nl/qrobot/apt/calibration/controller/CalibrationController.java b/src/main/java/org/nl/qrobot/apt/calibration/controller/CalibrationController.java new file mode 100644 index 0000000..8a90ba9 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/calibration/controller/CalibrationController.java @@ -0,0 +1,61 @@ +package org.nl.qrobot.apt.calibration.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import org.nl.qrobot.apt.calibration.param.CalibrationLaserParam; +import org.nl.qrobot.apt.calibration.service.CalibrationService; +import org.nl.qrobot.common.logging.annotation.Log; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; + +/** + * @author dsh + * 2026/1/6 + */ +@RestController +@RequestMapping("/calibration") +public class CalibrationController { + + @Resource + private CalibrationService calibrationService; + + @GetMapping("/getCalibrationConfigInfo") + @Log("获取车辆相机和激光配置信息") + public ResponseEntity getCalibrationConfigInfo() { + return new ResponseEntity<>(calibrationService.getCalibrationConfigInfo(), HttpStatus.OK); + } + + @PostMapping("/calibrationLaser") + @Log("一键标定激光") + public ResponseEntity calibrationLaser(@RequestBody CalibrationLaserParam param){ + return new ResponseEntity<>(calibrationService.calibrationLaser(param), HttpStatus.OK); + } + + @PostMapping("/startCalibrationCamera") + @Log("开始标定顶部相机") + public ResponseEntity startCalibrationCamera(@RequestParam String location){ + return new ResponseEntity<>(calibrationService.startCalibrationCamera(location), HttpStatus.OK); + } + + @PostMapping("/endCalibrationCamera") + @Log("结束标定顶部相机") + public ResponseEntity endCalibrationCamera(@RequestParam String location,@RequestParam String params){ + return new ResponseEntity<>(calibrationService.endCalibrationCamera(location,params), HttpStatus.OK); + } + + @PostMapping("/calibrationDepthcamera") + @Log("一键标定相机") + public ResponseEntity calibrationDepthcamera(@RequestParam String location){ + return new ResponseEntity<>(calibrationService.calibrationDepthcamera(location), HttpStatus.OK); + } + + @GetMapping("/getCalibrationByTaskId") + @Log("根据task_id查询对应的标定结果") + public ResponseEntity getCalibrationByTaskId(@RequestParam String task_id){ + return new ResponseEntity<>(calibrationService.getCalibrationByTaskId(task_id), HttpStatus.OK); + } +} diff --git a/src/main/java/org/nl/qrobot/apt/calibration/enums/CalibrationResult.java b/src/main/java/org/nl/qrobot/apt/calibration/enums/CalibrationResult.java new file mode 100644 index 0000000..08fcb12 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/calibration/enums/CalibrationResult.java @@ -0,0 +1,29 @@ +package org.nl.qrobot.apt.calibration.enums; + +import lombok.Getter; + +/** + * @author dsh + * 2026/1/7 + */ +@Getter +public enum CalibrationResult { + + COLLECTING("1","采集数据中"), + FAILED("2","标定失败"), + RESULT_ABNORMAL("3","标定结果异常"), + PROCEDURE_ABNORMAL("999","标定程序异常"), + SUCCESSFUL("0","标定成功"); + + + + + private String code; + + private String name; + + CalibrationResult(String code, String name) { + this.code = code; + this.name = name; + } +} diff --git a/src/main/java/org/nl/qrobot/apt/calibration/enums/LaserAndCameraType.java b/src/main/java/org/nl/qrobot/apt/calibration/enums/LaserAndCameraType.java new file mode 100644 index 0000000..21e86a5 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/calibration/enums/LaserAndCameraType.java @@ -0,0 +1,102 @@ +package org.nl.qrobot.apt.calibration.enums; + +import lombok.Data; +import lombok.Getter; + +/** + * @author dsh + * 2026/1/6 + */ +@Getter +public enum LaserAndCameraType { + + /** + * 前 + */ + FRONT("1", "前", "前","Front"), + /** + * 后 + */ + REAR("2", "后", "后","Rear"), + /** + * 左 + */ + LEFT("3", "左", "左","Left"), + /** + * 左前 + */ + FRONT_LEFT("4", "左前", "左前","Front left"), + /** + * 左后 + */ + LEFT_BACK("5", "左后", "左后","Left rear"), + /** + * 右 + */ + RIGHT("6", "右", "右","Right"), + /** + * 右前 + */ + RIGHT_FRONT("7", "右前", "右前","Right front"), + /** + * 右后 + */ + RIGHT_BACK("8", "右后", "右后","Right rear"), + + /** + * 顶部前 + */ + TOP_FRONT("9", "顶部前", "顶部前","Top front"), + /** + * 顶部后 + */ + TOP_REAR("10", "顶部后", "顶部后","Top rear"), + /** + * 顶部左 + */ + TOP_LEFT("11", "顶部左", "顶部左","Top left"), + /** + * 顶部左前 + */ + TOP_FRONT_LEFT("12", "顶部左前", "顶部左前","Top front left"), + /** + * 顶部左后 + */ + TOP_LEFT_BACK("13", "顶部左后", "顶部左后","Top left rear"), + /** + * 顶部右 + */ + TOP_RIGHT("14", "顶部右", "顶部右","Top right"), + /** + * 顶部右前 + */ + TOP_RIGHT_FRONT("15", "顶部右前", "顶部右前","Top right front"), + /** + * 顶部右后 + */ + TOP_RIGHT_BACK("16", "顶部右后", "顶部右后","Top right rear"); + + private String location; + + private String name; + + private String zh_name; + + private String en_name; + + LaserAndCameraType(String location, String name, String zh_name, String en_name) { + this.location = location; + this.name = name; + this.zh_name = zh_name; + this.en_name = en_name; + } + + public static LaserAndCameraType getByLocation(String code) { + for (LaserAndCameraType e : LaserAndCameraType.values()) { + if (e.location.equals(code)) { + return e; + } + } + return null; + } +} diff --git a/src/main/java/org/nl/qrobot/apt/calibration/param/CalibrationLaserParam.java b/src/main/java/org/nl/qrobot/apt/calibration/param/CalibrationLaserParam.java new file mode 100644 index 0000000..6bb80e9 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/calibration/param/CalibrationLaserParam.java @@ -0,0 +1,24 @@ +package org.nl.qrobot.apt.calibration.param; + +import lombok.Data; +import org.nl.qrobot.config.language.LangProcess; + +import javax.validation.constraints.NotBlank; + +/** + * @author dsh + * 2026/1/7 + */ +@Data +public class CalibrationLaserParam { + + /** + * 设备ID + */ + private String location; + + /** + * 指令 + */ + private int cmd; +} diff --git a/src/main/java/org/nl/qrobot/apt/calibration/service/CalibrationService.java b/src/main/java/org/nl/qrobot/apt/calibration/service/CalibrationService.java new file mode 100644 index 0000000..9bb30b1 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/calibration/service/CalibrationService.java @@ -0,0 +1,52 @@ +package org.nl.qrobot.apt.calibration.service; + +import org.nl.qrobot.apt.calibration.param.CalibrationLaserParam; +import org.nl.qrobot.apt.dto.WebResponse; + +/** + * @author dsh + * 2026/1/6 + */ +public interface CalibrationService { + + /** + * 获取车辆相机和激光配置信息 + * @return + */ + WebResponse getCalibrationConfigInfo(); + + /** + * 标定激光 + * @param param + * @return + */ + WebResponse calibrationLaser(CalibrationLaserParam param); + + /** + * 开始标定顶部相机 + * @param location + * @return + */ + WebResponse startCalibrationCamera(String location); + + /** + * 结束标定顶部相机 + * @param location + * @return + */ + WebResponse endCalibrationCamera(String location,String params); + + /** + * 标定深度相机 + * @param location + * @return + */ + WebResponse calibrationDepthcamera(String location); + + /** + * 根据task_id查询对应的标定结果 + * @param task_id + * @return + */ + WebResponse getCalibrationByTaskId(String task_id); +} diff --git a/src/main/java/org/nl/qrobot/apt/calibration/service/impl/CalibrationServiceImpl.java b/src/main/java/org/nl/qrobot/apt/calibration/service/impl/CalibrationServiceImpl.java new file mode 100644 index 0000000..e432965 --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/calibration/service/impl/CalibrationServiceImpl.java @@ -0,0 +1,277 @@ +package org.nl.qrobot.apt.calibration.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.nl.qrobot.apt.calibration.enums.CalibrationResult; +import org.nl.qrobot.apt.calibration.enums.LaserAndCameraType; +import org.nl.qrobot.apt.calibration.param.CalibrationLaserParam; +import org.nl.qrobot.apt.calibration.service.CalibrationService; +import org.nl.qrobot.apt.dto.WebResponse; +import org.nl.qrobot.common.BadRequestException; +import org.nl.qrobot.config.language.LangProcess; +import org.nl.qrobot.util.HTTPUtil; +import org.nl.qrobot.util.URLConstant; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * @author dsh + * 2026/1/6 + */ +@Slf4j +@Service +public class CalibrationServiceImpl implements CalibrationService { + + public static Map currentCalibration = new ConcurrentHashMap<>(); + + @Override + public WebResponse getCalibrationConfigInfo() { + HttpResponse response = null; + try { + response = HTTPUtil.post(URLConstant.VEHICLE_IP_PORT,"/tool/rob/getInstallConfig", new JSONObject()); + } catch (Exception e) { + log.info("访问车辆相机和激光配置接口报错:{}",e.getMessage()); + throw new BadRequestException(LangProcess.msg("failed")); + } + // 检查响应状态码 + if (response.isOk() && response.body() != null) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("获取车辆相机和激光配置:{}",body); + return WebResponse.requestParamOk(this.analyzeLaserAndCamera(body)); + } + log.info("获取车辆相机和激光配置失败"); + throw new BadRequestException(LangProcess.msg("failed")); + } + + @Override + public WebResponse calibrationLaser(CalibrationLaserParam param) { + if (ObjectUtil.isEmpty(param)){ + throw new BadRequestException(LangProcess.msg("param_is_null")); + } + JSONObject params = new JSONObject(); + String task_id = DateUtil.format(new Date(), "yyyyMMddHHmmssSSS"); + String attach = "{"+ + "'init_pose':{'pose':{'x':0,'y':0,'angle':0}},'params':'','sub_command':"+param.getLocation()+",'target_pose':{'pose':{'x':0,'y':0,'angle':0}},"+ + "'task_id':'"+task_id+"',"+ + "'need_response':true"+ + "}"; + params.put("cmd", param.getCmd()); + params.put("attach", JSON.parseObject(attach)); + HttpResponse response = null; + try { + response = HTTPUtil.post(URLConstant.VEHICLE_IP_PORT,"/tool/rob/sendCMD", params); + } catch (Exception e) { + log.info("访问车体激光标定接口报错:{}",e.getMessage()); + throw new BadRequestException(LangProcess.msg("failed")); + } + // 检查响应状态码 + if (response.isOk() && response.body() != null) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("激光标定:{}",body); + if ("200".equals(body.getString("code"))){ + currentCalibration.put(task_id, CalibrationResult.COLLECTING.getCode()); + JSONObject result = new JSONObject(); + result.put("task_id", task_id); + return WebResponse.requestParamOk(result); + } + } + log.info("激光标定失败"); + throw new BadRequestException(LangProcess.msg("failed")); + } + + @Override + public WebResponse endCalibrationCamera(String location,String param) { + if (StrUtil.isBlank(location)){ + throw new BadRequestException(LangProcess.msg("param_is_null")); + } + JSONObject params = new JSONObject(); + String task_id = DateUtil.format(new Date(), "yyyyMMddHHmmssSSS"); + String attach = "{"+ + "'init_pose':{'pose':{'x':0,'y':0,'angle':0}},'params':'"+param+"','sub_command':"+location+",'target_pose':{'pose':{'x':0,'y':0,'angle':0}},"+ + "'task_id':"+task_id+","+ + "'need_response':true"+ + "}"; + params.put("cmd", 1822); + params.put("attach", JSON.parseObject(attach)); + HttpResponse response = null; + try { + response = HTTPUtil.post(URLConstant.VEHICLE_IP_PORT,"/tool/rob/sendCMD", params); + } catch (Exception e) { + log.info("访问车体顶部相机结束标定接口报错:{}",e.getMessage()); + throw new BadRequestException(LangProcess.msg("failed")); + } + // 检查响应状态码 + if (response.isOk() && response.body() != null) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("结束顶部相机标定:{}",body); + if ("200".equals(body.getString("code"))){ + currentCalibration.put(task_id, CalibrationResult.COLLECTING.getCode()); + JSONObject result = new JSONObject(); + result.put("task_id", task_id); + return WebResponse.requestParamOk(result); + } + } + log.info("结束顶部相机标定失败"); + throw new BadRequestException(LangProcess.msg("failed")); + } + + @Override + public WebResponse startCalibrationCamera(String location) { + if (StrUtil.isBlank(location)){ + throw new BadRequestException(LangProcess.msg("param_is_null")); + } + JSONObject params = new JSONObject(); + String task_id = DateUtil.format(new Date(), "yyyyMMddHHmmssSSS"); + String attach = "{"+ + "'init_pose':{'pose':{'x':0,'y':0,'angle':0}},'params':'','sub_command':"+location+",'target_pose':{'pose':{'x':0,'y':0,'angle':0}},"+ + "'task_id':"+task_id+","+ + "'need_response':true"+ + "}"; + params.put("cmd", 1821); + params.put("attach", JSON.parseObject(attach)); + HttpResponse response = null; + try { + response = HTTPUtil.post(URLConstant.VEHICLE_IP_PORT,"/tool/rob/sendCMD", params); + } catch (Exception e) { + log.info("访问车体顶部相机开始标定接口报错:{}",e.getMessage()); + throw new BadRequestException(LangProcess.msg("failed")); + } + // 检查响应状态码 + if (response.isOk() && response.body() != null) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("开始顶部相机标定:{}",body); + if ("200".equals(body.getString("code"))){ + return WebResponse.requestOk(); + } + } + log.info("开始顶部相机标定失败"); + throw new BadRequestException(LangProcess.msg("failed")); + } + + @Override + public WebResponse calibrationDepthcamera(String location) { + if (StrUtil.isBlank(location)){ + throw new BadRequestException(LangProcess.msg("param_is_null")); + } + JSONObject params = new JSONObject(); + String task_id = DateUtil.format(new Date(), "yyyyMMddHHmmssSSS"); + String attach = "{"+ + "'init_pose':{'pose':{'x':0,'y':0,'angle':0}},'params':'','sub_command':"+location+",'target_pose':{'pose':{'x':0,'y':0,'angle':0}},"+ + "'task_id':"+task_id+","+ + "'need_response':true"+ + "}"; + params.put("cmd", 1815); + params.put("attach", JSON.parseObject(attach)); + HttpResponse response = null; + try { + response = HTTPUtil.post(URLConstant.VEHICLE_IP_PORT,"/tool/rob/sendCMD", params); + } catch (Exception e) { + log.info("访问车体深度相机标定接口报错:{}",e.getMessage()); + throw new BadRequestException(LangProcess.msg("failed")); + } + // 检查响应状态码 + if (response.isOk() && response.body() != null) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("深度相机标定:{}",body); + if ("200".equals(body.getString("code"))){ + currentCalibration.put(task_id, CalibrationResult.COLLECTING.getCode()); + JSONObject result = new JSONObject(); + result.put("task_id", task_id); + return WebResponse.requestParamOk(result); + } + } + log.info("深度相机标定失败"); + throw new BadRequestException(LangProcess.msg("failed")); + } + + @Override + public WebResponse getCalibrationByTaskId(String task_id) { + if (StrUtil.isBlank(task_id)){ + throw new BadRequestException(LangProcess.msg("param_is_null")); + } + return WebResponse.requestParamOk(currentCalibration.get(task_id)); + } + + public JSONObject analyzeLaserAndCamera(JSONObject body) { + //激光 + JSONObject Laser = body.getJSONObject("Laser"); + //相机 + JSONObject Camera = body.getJSONObject("camera"); + //深度相机 + JSONObject Depthcamera = body.getJSONObject("depthcamera"); + + JSONObject result = new JSONObject(); + JSONArray LaserArray = new JSONArray(); + JSONArray CameraArray = new JSONArray(); + JSONArray DepthcameraArray = new JSONArray(); + if (Laser != null){ + for (String key : Laser.keySet()) { + JSONObject laser = Laser.getJSONObject(key); + String location = laser.getString("location"); + JSONObject value = new JSONObject(); + value.put("location", location); + LaserAndCameraType settingCodeEnum = LaserAndCameraType.getByLocation(location); + if (settingCodeEnum != null) { + value.put("name", settingCodeEnum.getName()); + value.put("zh_name", settingCodeEnum.getZh_name()); + value.put("en_name", settingCodeEnum.getEn_name()); + } + LaserArray.add(value); + } + } + result.put("Laser", LaserArray); + if (Camera != null){ + for (String key : Camera.keySet()) { + JSONObject camera = Camera.getJSONObject(key); + String location = camera.getString("location"); + JSONObject value = new JSONObject(); + value.put("location", location); + LaserAndCameraType settingCodeEnum = LaserAndCameraType.getByLocation(location); + if (settingCodeEnum != null) { + value.put("name", settingCodeEnum.getName()); + value.put("zh_name", settingCodeEnum.getZh_name()); + value.put("en_name", settingCodeEnum.getEn_name()); + } + CameraArray.add(value); + } + } + + result.put("camera", CameraArray); + if (Depthcamera != null){ + for (String key : Depthcamera.keySet()) { + JSONObject depthcamera = Depthcamera.getJSONObject(key); + String location = depthcamera.getString("location"); + JSONObject value = new JSONObject(); + value.put("location", location); + // 深度相机的location是负数,需要做转换。 + int new_location = Integer.parseInt(location); + LaserAndCameraType settingCodeEnum = LaserAndCameraType.getByLocation(String.valueOf(Math.abs(new_location))); + if (settingCodeEnum != null) { + value.put("name", settingCodeEnum.getName()); + value.put("zh_name", settingCodeEnum.getZh_name()); + value.put("en_name", settingCodeEnum.getEn_name()); + } + DepthcameraArray.add(value); + } + } + + result.put("depthcamera", DepthcameraArray); + return result; + } + +} diff --git a/src/main/java/org/nl/qrobot/apt/vehicle/dao/VehicleInfo.java b/src/main/java/org/nl/qrobot/apt/vehicle/dao/VehicleInfo.java index 29c08cc..cb76005 100644 --- a/src/main/java/org/nl/qrobot/apt/vehicle/dao/VehicleInfo.java +++ b/src/main/java/org/nl/qrobot/apt/vehicle/dao/VehicleInfo.java @@ -144,4 +144,13 @@ public class VehicleInfo implements Serializable { */ private String vehiclePayloads; + /** + * 车辆速度 + */ + private VehicleSpeed vehicleSpeed; + + /** + * 激光状态 + */ + private double laserState; } diff --git a/src/main/java/org/nl/qrobot/apt/vehicle/dao/VehicleSpeed.java b/src/main/java/org/nl/qrobot/apt/vehicle/dao/VehicleSpeed.java new file mode 100644 index 0000000..90b9fec --- /dev/null +++ b/src/main/java/org/nl/qrobot/apt/vehicle/dao/VehicleSpeed.java @@ -0,0 +1,26 @@ +package org.nl.qrobot.apt.vehicle.dao; + +import lombok.Data; + +/** + * @author dsh + * 2026/1/9 + */ +@Data +public class VehicleSpeed { + + /** + * x方向速度 + */ + private double vx; + + /** + * y方向速度 + */ + private double vy; + + /** + * w角速度 + */ + private double w; +} diff --git a/src/main/java/org/nl/qrobot/apt/vehicle/rest/VehicleInfoController.java b/src/main/java/org/nl/qrobot/apt/vehicle/rest/VehicleInfoController.java index bbdfe1f..7f9b722 100644 --- a/src/main/java/org/nl/qrobot/apt/vehicle/rest/VehicleInfoController.java +++ b/src/main/java/org/nl/qrobot/apt/vehicle/rest/VehicleInfoController.java @@ -40,4 +40,16 @@ public class VehicleInfoController { return new ResponseEntity<>(vehicleInfoService.setForkLegsObstacles(backIoStatus), HttpStatus.OK); } + @PostMapping("/pauseVehicle") + @Log("暂停车辆") + public ResponseEntity pauseVehicle(@RequestParam("amrId") Integer amrId) { + return new ResponseEntity<>(vehicleInfoService.pauseVehicle(amrId), HttpStatus.OK); + } + + @PostMapping("/resumeVehicle") + @Log("恢复车辆") + public ResponseEntity resumeVehicle(@RequestParam("amrId") Integer amrId) { + return new ResponseEntity<>(vehicleInfoService.resumeVehicle(amrId), HttpStatus.OK); + } + } diff --git a/src/main/java/org/nl/qrobot/apt/vehicle/service/VehicleInfoService.java b/src/main/java/org/nl/qrobot/apt/vehicle/service/VehicleInfoService.java index 7e1a1ad..7612025 100644 --- a/src/main/java/org/nl/qrobot/apt/vehicle/service/VehicleInfoService.java +++ b/src/main/java/org/nl/qrobot/apt/vehicle/service/VehicleInfoService.java @@ -1,5 +1,6 @@ package org.nl.qrobot.apt.vehicle.service; +import org.nl.qrobot.apt.dto.WebResponse; import org.nl.qrobot.apt.vehicle.dao.VehicleInfo; import java.util.Map; @@ -32,4 +33,14 @@ public interface VehicleInfoService { * 设置叉尖避障 */ Map setForkLegsObstacles(String backIoStatus); + + /** + * 暂停车辆 + */ + WebResponse pauseVehicle(Integer amrId); + + /** + * 暂停车辆 + */ + WebResponse resumeVehicle(Integer amrId); } diff --git a/src/main/java/org/nl/qrobot/apt/vehicle/service/impl/VehicleInfoServiceImpl.java b/src/main/java/org/nl/qrobot/apt/vehicle/service/impl/VehicleInfoServiceImpl.java index 147235a..b656dba 100644 --- a/src/main/java/org/nl/qrobot/apt/vehicle/service/impl/VehicleInfoServiceImpl.java +++ b/src/main/java/org/nl/qrobot/apt/vehicle/service/impl/VehicleInfoServiceImpl.java @@ -8,7 +8,9 @@ import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.extern.slf4j.Slf4j; import org.nl.qrobot.apt.anomalyInfo.dao.ErrorInfo; +import org.nl.qrobot.apt.anomalyInfo.service.AnomalyInfoService; import org.nl.qrobot.apt.anomalyInfo.service.ErrorInfoService; +import org.nl.qrobot.apt.dto.WebResponse; import org.nl.qrobot.apt.map.dto.PointCloudDataDto; import org.nl.qrobot.apt.map.service.MapInfoService; import org.nl.qrobot.apt.route.service.RouteInfoService; @@ -67,6 +69,9 @@ public class VehicleInfoServiceImpl implements VehicleInfoService { @Resource private ErrorInfoService errorInfoService; + @Resource + private AnomalyInfoService anomalyInfoService; + @Resource private ParamService paramService; @@ -151,6 +156,55 @@ public class VehicleInfoServiceImpl implements VehicleInfoService { throw new BadRequestException(LangProcess.msg("error_set_forkLegs")); } + @Override + public WebResponse pauseVehicle(Integer amrId) { + JSONObject params = new JSONObject(); + params.put("amrId", amrId); + // stopNow true立即停车 false 停到点位上 + params.put("stopNow", true); + HttpResponse response = null; + try { + response = HTTPUtil.post(URLConstant.RCS_IP_PORT,"/amr/taskCommand/pause/"+amrId, params); + } catch (Exception e) { + log.info("访问调度暂停车辆接口报错:{}",e.getMessage()); + throw new BadRequestException(LangProcess.msg("error_pause_vehicle")); + } + // 检查响应状态码 + if (response.isOk() && response.body() != null) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("暂停车辆:{}",body); + if ("true".equals(body.getString("state"))){ + WebResponse.requestOk(); + } + } + log.info("暂停车辆失败"); + throw new BadRequestException(LangProcess.msg("error_pause_vehicle")); + } + + @Override + public WebResponse resumeVehicle(Integer amrId) { + JSONObject params = new JSONObject(); + HttpResponse response = null; + try { + response = HTTPUtil.post(URLConstant.RCS_IP_PORT,"/amr/taskCommand/resume/"+amrId, params); + } catch (Exception e) { + log.info("访问调度恢复车辆接口报错:{}",e.getMessage()); + throw new BadRequestException(LangProcess.msg("error_resume_vehicle")); + } + // 检查响应状态码 + if (response.isOk() && response.body() != null) { + // 获取响应体内容 + JSONObject body = JSON.parseObject(response.body()); + log.info("恢复车辆:{}",body); + if ("true".equals(body.getString("state"))){ + WebResponse.requestOk(); + } + } + log.info("恢复车辆失败"); + throw new BadRequestException(LangProcess.msg("error_resume_vehicle")); + } + @Async("asynchronousTasks") public void queryVehicleInfo() { HttpResponse response = null; @@ -183,11 +237,18 @@ public class VehicleInfoServiceImpl implements VehicleInfoService { JSONObject amrException = data.getJSONObject("amrException"); VehicleException vehicleException = JSONObject.toJavaObject(amrException, VehicleException.class); vehicleInfo.setExceptionInfo(vehicleException); - List errorInfoList = new ArrayList<>(); + List errorInfoList = null; // 消息列表 if (ObjectUtil.isNotEmpty(vehicleException.getExceptionCodes())){ errorInfoList = errorInfoService.list(new LambdaQueryWrapper().in(ErrorInfo::getError_code,vehicleException.getExceptionCodes())); } + //处理异常记录 + anomalyInfoService.processExceptions(errorInfoList); + //清除异常记录缓存 +// anomalyInfoService.cleanInactiveCache(); + if (ObjectUtil.isEmpty(errorInfoList)) { + errorInfoList = new ArrayList<>(); + } // 异常等级 0无异常 1普通异常 2严重异常 OptionalInt maxLevel = errorInfoList.stream().mapToInt(ErrorInfo::getError_category).max(); int anomalyLevel = 0; diff --git a/src/main/java/org/nl/qrobot/config/MybatisPlusConfig.java b/src/main/java/org/nl/qrobot/config/MybatisPlusConfig.java new file mode 100644 index 0000000..9682ff2 --- /dev/null +++ b/src/main/java/org/nl/qrobot/config/MybatisPlusConfig.java @@ -0,0 +1,22 @@ +package org.nl.qrobot.config; + +import com.baomidou.mybatisplus.annotation.DbType; +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @author dsh + * 2026/1/13 + */ +@Configuration +public class MybatisPlusConfig { + + @Bean + public MybatisPlusInterceptor mybatisPlusInterceptor() { + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; + } +} diff --git a/src/main/java/org/nl/qrobot/config/thread/ProtobufWebSocketHandler.java b/src/main/java/org/nl/qrobot/config/thread/ProtobufWebSocketHandler.java index cd29afe..781d79c 100644 --- a/src/main/java/org/nl/qrobot/config/thread/ProtobufWebSocketHandler.java +++ b/src/main/java/org/nl/qrobot/config/thread/ProtobufWebSocketHandler.java @@ -4,8 +4,10 @@ import com.alibaba.fastjson.JSONObject; import comm_protocol.Robottype; import comm_protocol.Uidata; import lombok.extern.slf4j.Slf4j; +import org.nl.qrobot.apt.calibration.service.impl.CalibrationServiceImpl; import org.nl.qrobot.apt.map.dto.PointCloudDataDto; import org.nl.qrobot.apt.teaching.service.impl.TeachingServiceImpl; +import org.nl.qrobot.apt.vehicle.dao.VehicleSpeed; import org.nl.qrobot.apt.vehicle.service.impl.VehicleInfoServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.EnableScheduling; @@ -52,7 +54,14 @@ public class ProtobufWebSocketHandler extends BinaryWebSocketHandler { JSONObject data_pool = JSONObject.parseObject(robotBase.getDataPool()); String mapping_return = data_pool.getString("mapping_return"); String mapping_percent = data_pool.getString("mapping_percent"); - + // 判断data_pool里面是否有标定结果 key=task_id,value=1是采集数据中 2是标定失败 3是标定结果异常 999是标定程序异常 0是标定成功 + for (String key:data_pool.keySet()){ + if (CalibrationServiceImpl.currentCalibration.containsKey(key)){ + CalibrationServiceImpl.currentCalibration.put(key,data_pool.getString(key)); + } + } + //激光状态 + VehicleInfoServiceImpl.vehicleInfo.setLaserState(Double.parseDouble(data_pool.getString("loc_weight"))); //打点后是否可以自动沿着路线开出来(0计算中 1失败 2成功) VehicleInfoServiceImpl.vehicleInfo.setAuto_back_enable(data_pool.getString("auto_back_enable")); //起点终点是否重叠,结束建图 @@ -133,6 +142,16 @@ public class ProtobufWebSocketHandler extends BinaryWebSocketHandler { } // System.out.println("Received laser_scan: " + list); break; + case CURRENT_STATE: + Robottype.RobotState taskResult = datagram.getCurrentState(); + Robottype.RobotSpeed robotSpeed = taskResult.getSpeed(); + VehicleSpeed vehicleSpeed = new VehicleSpeed(); + vehicleSpeed.setVx(robotSpeed.getVx()); + vehicleSpeed.setVy(robotSpeed.getVy()); + vehicleSpeed.setW(robotSpeed.getW()); + //车辆行驶速度 + VehicleInfoServiceImpl.vehicleInfo.setVehicleSpeed(vehicleSpeed); + break; } } catch (Exception e) { log.error("Error processing protobuf message", e); diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index f486f02..e494c98 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -8,7 +8,7 @@ spring: druid: db-type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://localhost:3306/nl_apt15e?serverTimezone=GMT%2B8&characterEncoding=utf-8&userSSL=false + url: jdbc:mysql://localhost:3306/nl_qrobot?serverTimezone=GMT%2B8&characterEncoding=utf-8&userSSL=false username: root password: 123456 # 初始连接数 diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index d7c3ce3..cd7cdd5 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -46,6 +46,7 @@ security: - /mapInfo/** - /api/operate/** - /teaching/** + - /calibration/** - /vehicle/** - /vehicles/** - /webSocket/** diff --git a/src/main/resources/language/error/error.properties b/src/main/resources/language/error/error.properties index ac7746d..7fae9de 100644 --- a/src/main/resources/language/error/error.properties +++ b/src/main/resources/language/error/error.properties @@ -26,4 +26,6 @@ error_abandon_mapping = 放弃建图失败 error_auto_back = 自动返回上一个点失败 error_restart_system = 重启系统失败 error_initializing_system = 初始化底层系统失败 -error_set_forkLegs= 操作叉腿避障失败 \ No newline at end of file +error_set_forkLegs= 操作叉腿避障失败 +error_pause_vehicle= 暂停车辆失败 +error_resume_vehicle= 恢复车辆失败 \ No newline at end of file diff --git a/src/main/resources/language/error/error_en_US.properties b/src/main/resources/language/error/error_en_US.properties index 96d4e2e..cfea9b1 100644 --- a/src/main/resources/language/error/error_en_US.properties +++ b/src/main/resources/language/error/error_en_US.properties @@ -25,4 +25,6 @@ error_abandon_mapping = Abandoned mapping failed error_auto_back = Automatically returning to the previous point failed error_restart_system = Rebooting the system failed error_initializing_system = Initializing the underlying system failed -error_set_forkLegs= The operation of the fork leg to avoid obstacles failed \ No newline at end of file +error_set_forkLegs= The operation of the fork leg to avoid obstacles failed +error_pause_vehicle= Failed to suspend the vehicle +error_resume_vehicle= Vehicle recovery failed \ No newline at end of file diff --git a/src/main/resources/language/error/error_zh_CN.properties b/src/main/resources/language/error/error_zh_CN.properties index 438c3c3..ec1706e 100644 --- a/src/main/resources/language/error/error_zh_CN.properties +++ b/src/main/resources/language/error/error_zh_CN.properties @@ -25,4 +25,6 @@ error_abandon_mapping = 放弃建图失败 error_auto_back = 自动返回上一个点失败 error_restart_system = 重启系统失败 error_initializing_system = 初始化底层系统失败 -error_set_forkLegs= 操作叉腿避障失败 \ No newline at end of file +error_set_forkLegs= 操作叉腿避障失败 +error_pause_vehicle= 暂停车辆失败 +error_resume_vehicle= 恢复车辆失败 \ No newline at end of file