rain
2024-07-26 086ef5ab15ebd71f8e454868503c6d29b6c5eb98
src/main/java/com/dji/sample/control/service/impl/ControlServiceImpl.java
@@ -1,7 +1,9 @@
package com.dji.sample.control.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.dji.sample.common.error.CommonErrorEnum;
import com.dji.sample.common.model.ResponseResult;
import com.dji.sample.common.util.SpringBeanUtils;
import com.dji.sample.component.mqtt.model.*;
import com.dji.sample.component.mqtt.service.IMessageSenderService;
import com.dji.sample.component.redis.RedisConst;
@@ -9,11 +11,10 @@
import com.dji.sample.component.websocket.model.BizCodeEnum;
import com.dji.sample.component.websocket.service.ISendMessageService;
import com.dji.sample.control.model.dto.FlyToProgressReceiver;
import com.dji.sample.control.model.dto.PointDTO;
import com.dji.sample.control.model.dto.ResultNotifyDTO;
import com.dji.sample.control.model.dto.TakeoffProgressReceiver;
import com.dji.sample.control.model.enums.DroneAuthorityEnum;
import com.dji.sample.control.model.enums.DroneControlMethodEnum;
import com.dji.sample.control.model.enums.RemoteDebugMethodEnum;
import com.dji.sample.control.model.enums.*;
import com.dji.sample.control.model.param.*;
import com.dji.sample.control.service.IControlService;
import com.dji.sample.manage.model.dto.DeviceDTO;
@@ -24,6 +25,7 @@
import com.dji.sample.manage.service.IDeviceRedisService;
import com.dji.sample.manage.service.IDeviceService;
import com.dji.sample.wayline.model.enums.WaylineErrorCodeEnum;
import com.dji.sample.wayline.model.param.PointPOJO;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
@@ -31,10 +33,9 @@
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
/**
 * @author sean
@@ -97,14 +98,25 @@
                    "error: " + serviceIdentifier + serviceReply.getResult());
        }
        if (controlMethodEnum.getProgress()) {
            RedisOpsUtils.setWithExpire(serviceIdentifier + RedisConst.DELIMITER +  bid, sn,
            RedisOpsUtils.setWithExpire(serviceIdentifier + RedisConst.DELIMITER + bid, sn,
                    RedisConst.DEVICE_ALIVE_SECOND * RedisConst.DEVICE_ALIVE_SECOND);
        }
        //当执行返航指令时,删除图斑redis
        if (serviceIdentifier == "return_home"){
            if (RedisOpsUtils.checkExist("tuban:" + sn)){
                RedisOpsUtils.del("tuban:" + sn);
            }
        }
        return ResponseResult.success();
    }
    /**
     * Handles multi-state command progress information.
     *
     * @param receiver
     * @param headers
     * @return
@@ -118,7 +130,8 @@
        String sn = RedisOpsUtils.get(key).toString();
        EventsReceiver<EventsOutputProgressReceiver> eventsReceiver = mapper.convertValue(receiver.getData(),
                new TypeReference<EventsReceiver<EventsOutputProgressReceiver>>(){});
                new TypeReference<EventsReceiver<EventsOutputProgressReceiver>>() {
                });
        eventsReceiver.setBid(receiver.getBid());
        eventsReceiver.setSn(sn);
@@ -137,7 +150,7 @@
        Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(sn);
        if (deviceOpt.isEmpty()) {
            throw new RuntimeException("The device is offline.");
            throw new RuntimeException("设备离线.");
        }
        DeviceDTO device = deviceOpt.get();
@@ -151,12 +164,12 @@
        // TODO 设备固件版本不兼容情况
        Optional<DeviceDTO> dockOpt = deviceRedisService.getDeviceOnline(dockSn);
        if (dockOpt.isEmpty()) {
            throw new RuntimeException("The dock is offline, please restart the dock.");
            throw new RuntimeException("机场离线请重启机场");
        }
        DeviceModeCodeEnum deviceMode = deviceService.getDeviceMode(dockOpt.get().getChildDeviceSn());
        if (DeviceModeCodeEnum.MANUAL != deviceMode) {
            throw new RuntimeException("The current state of the drone does not support this function, please try again later.");
            throw new RuntimeException("无人机当前状态不支持此功能,请稍后再试");
        }
        ResponseResult result = seizeAuthority(dockSn, DroneAuthorityEnum.FLIGHT, null);
@@ -172,7 +185,7 @@
        param.setFlyToId(UUID.randomUUID().toString());
        ServiceReply reply = messageSenderService.publishServicesTopic(sn, DroneControlMethodEnum.FLY_TO_POINT.getMethod(), param, param.getFlyToId());
        return ResponseResult.CODE_SUCCESS != reply.getResult() ?
                ResponseResult.error("Flying to the target point failed." + reply.getResult())
                ResponseResult.error("飞向目标点失败。" + reply.getResult())
                : ResponseResult.success();
    }
@@ -180,21 +193,22 @@
    public ResponseResult flyToPointStop(String sn) {
        ServiceReply reply = messageSenderService.publishServicesTopic(sn, DroneControlMethodEnum.FLY_TO_POINT_STOP.getMethod(), null);
        return ResponseResult.CODE_SUCCESS != reply.getResult() ?
                ResponseResult.error("The drone flying to the target point failed to stop. " + reply.getResult())
                ResponseResult.error("飞向目标点的无人机停止失败" + reply.getResult())
                : ResponseResult.success();
    }
    @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_FLY_TO_POINT_PROGRESS, outputChannel = ChannelName.OUTBOUND_EVENTS)
    public CommonTopicReceiver handleFlyToPointProgress(CommonTopicReceiver receiver, MessageHeaders headers) {
        String dockSn  = receiver.getGateway();
    public CommonTopicReceiver handleFlyToPointProgress(CommonTopicReceiver receiver, MessageHeaders headers) throws Exception {
        String dockSn = receiver.getGateway();
        Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(dockSn);
        if (deviceOpt.isEmpty()) {
            log.error("The dock is offline.");
            log.error("机场离线");
            return null;
        }
        FlyToProgressReceiver eventsReceiver = mapper.convertValue(receiver.getData(), new TypeReference<FlyToProgressReceiver>(){});
        FlyToProgressReceiver eventsReceiver = mapper.convertValue(receiver.getData(), new TypeReference<FlyToProgressReceiver>() {
        });
        webSocketMessageService.sendBatch(deviceOpt.get().getWorkspaceId(), UserTypeEnum.WEB.getVal(),
                BizCodeEnum.FLY_TO_POINT_PROGRESS.getCode(),
                ResultNotifyDTO.builder().sn(dockSn)
@@ -202,13 +216,115 @@
                                eventsReceiver.getStatus().getMessage() : eventsReceiver.getResult().getErrorMsg())
                        .result(eventsReceiver.getResult().getErrorCode())
                        .build());
        //当飞向目标点成功后
        if (eventsReceiver.getStatus().equals(FlyToStatusEnum.WAYLINE_OK)) {
            JSONObject jsonObject = (JSONObject) RedisOpsUtils.get("tuban:" + dockSn);
            if (jsonObject != null) {
                List<PointPOJO> targetList = (List<PointPOJO>) jsonObject.get("targetList");
                int curIndex = (Integer) jsonObject.get("curIndex");
                String payloadIndex = jsonObject.getString("payloadIndex");
                flyToNextPoint(targetList, curIndex+1, dockSn, payloadIndex);
            }
        }
        return receiver;
    }
    @Override
    public ResponseResult flyToNextPoint(List<PointPOJO> targetList, int curIndex, String sn, String payloadIndex) throws Exception {
        //当无人机状态为人工时再发布下一个命令
        while (true) {
            Optional<DeviceDTO> dockOpt = deviceRedisService.getDeviceOnline(sn);
            DeviceModeCodeEnum deviceMode = deviceService.getDeviceMode(dockOpt.get().getChildDeviceSn());
            if (DeviceModeCodeEnum.MANUAL == deviceMode) {
                //执行拍照
                ResponseResult responseResult = takePhoto(sn, payloadIndex);
                //发布飞行指令
                if (curIndex == targetList.size()) {
                    //当前是最后一个点,返航
                    ResponseResult returnHome = controlDockDebug(sn, "return_home", null);
                    RedisOpsUtils.del("tuban:" + sn);
                    return returnHome;
                } else {
                    //当前不是最后一个点,飞行到下一个点
                    FlyToPointParam flyToPointParam = new FlyToPointParam();
                    flyToPointParam.setMaxSpeed(14);
                    List<PointDTO> pointDTOS = new ArrayList<>();
                    PointDTO pointDTO = new PointDTO();
                    pointDTO.setHeight(150.0);
                    pointDTO.setLongitude(targetList.get(curIndex).getLon());
                    pointDTO.setLatitude(targetList.get(curIndex).getLat());
                    pointDTOS.add(pointDTO);
                    flyToPointParam.setPoints(pointDTOS);
                    //发布下一个飞行指令
                    ResponseResult flyToRes = flyToPoint(sn, flyToPointParam);
                    if (flyToRes.getCode() == ResponseResult.CODE_SUCCESS) {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("targetList", targetList);
                        jsonObject.put("curIndex", curIndex);
                        jsonObject.put("payloadIndex",payloadIndex);
                        RedisOpsUtils.set("tuban:" + sn, jsonObject);
                    }
                    return flyToRes;
                }
            }
        }
    }
    @Override
    public ResponseResult takePhoto(String sn, String payloadIndex) throws Exception {
        //获取负载控制权
        DronePayloadParam dronePayloadParam = new DronePayloadParam();
        dronePayloadParam.setPayloadIndex(payloadIndex);
        ResponseResult seizeAuthorityRes = seizeAuthority(sn, DroneAuthorityEnum.PAYLOAD, dronePayloadParam);
        //切换为相机模式
        if (seizeAuthorityRes.getCode() != ResponseResult.CODE_SUCCESS) {
            return seizeAuthorityRes;
        }
        PayloadCommandsParam payloadCommandsParam = new PayloadCommandsParam();
//            DronePayloadParam switchParam = new DronePayloadParam();
//            switchParam.setCameraMode(CameraModeEnum.PHOTO);
//            switchParam.setPayloadIndex(payloadIndex);
//            payloadCommandsParam.setSn(sn);
//            payloadCommandsParam.setCmd(PayloadCommandsEnum.CAMERA_MODE_SWitCH);
//            payloadCommandsParam.setData(switchParam);
//
//            ResponseResult switchModeRes = payloadCommands(payloadCommandsParam);
//            if (switchModeRes.getCode() != ResponseResult.CODE_SUCCESS){
//                return  switchModeRes;
//            }
        //拍照
        payloadCommandsParam.setCmd(PayloadCommandsEnum.CAMERA_PHOTO_TAKE);
        DronePayloadParam takePhotoParam = new DronePayloadParam();
        takePhotoParam.setPayloadIndex(payloadIndex);
        payloadCommandsParam.setData(takePhotoParam);
        payloadCommandsParam.setSn(sn);
        ResponseResult responseResult = payloadCommands(payloadCommandsParam);
        return responseResult;
    }
    private void checkTakeoffCondition(String dockSn) {
        Optional<DeviceDTO> dockOpt = deviceRedisService.getDeviceOnline(dockSn);
        if (dockOpt.isEmpty() || DockModeCodeEnum.IDLE != deviceService.getDockMode(dockSn)) {
            throw new RuntimeException("The current state does not support takeoff.");
            throw new RuntimeException("当前状态不支持起飞");
        }
        ResponseResult result = seizeAuthority(dockSn, DroneAuthorityEnum.FLIGHT, null);
@@ -221,24 +337,26 @@
    @Override
    public ResponseResult takeoffToPoint(String sn, TakeoffToPointParam param) {
        checkTakeoffCondition(sn);
        param.setFlightId(UUID.randomUUID().toString());
        if (!StringUtils.hasText(param.getFlightId())){
            param.setFlightId(UUID.randomUUID().toString());
        }
        ServiceReply reply = messageSenderService.publishServicesTopic(sn, DroneControlMethodEnum.TAKE_OFF_TO_POINT.getMethod(), param, param.getFlightId());
        return ResponseResult.CODE_SUCCESS != reply.getResult() ?
                ResponseResult.error("The drone failed to take off. " + reply.getResult())
                ResponseResult.error("无人机起飞失败 " + reply.getResult())
                : ResponseResult.success();
    }
    @ServiceActivator(inputChannel = ChannelName.INBOUND_EVENTS_TAKE_OFF_TO_POINT_PROGRESS, outputChannel = ChannelName.OUTBOUND_EVENTS)
    public CommonTopicReceiver handleTakeoffToPointProgress(CommonTopicReceiver receiver, MessageHeaders headers) {
        String dockSn  = receiver.getGateway();
        String dockSn = receiver.getGateway();
        Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(dockSn);
        if (deviceOpt.isEmpty()) {
            log.error("The dock is offline.");
            log.error("机场离线");
            return null;
        }
        TakeoffProgressReceiver eventsReceiver = mapper.convertValue(receiver.getData(), new TypeReference<TakeoffProgressReceiver>(){});
        TakeoffProgressReceiver eventsReceiver = mapper.convertValue(receiver.getData(), new TypeReference<TakeoffProgressReceiver>() {
        });
        webSocketMessageService.sendBatch(deviceOpt.get().getWorkspaceId(), UserTypeEnum.WEB.getVal(),
                BizCodeEnum.TAKE_OFF_TO_POINT_PROGRESS.getCode(),
@@ -272,14 +390,14 @@
        }
        ServiceReply serviceReply = messageSenderService.publishServicesTopic(sn, method, param);
        return ResponseResult.CODE_SUCCESS != serviceReply.getResult() ?
                ResponseResult.error(serviceReply.getResult(), "Method: " + method + " Error Code:" + serviceReply.getResult())
                ResponseResult.error(serviceReply.getResult(), "方法: " + method + " 错误码:" + serviceReply.getResult())
                : ResponseResult.success();
    }
    private Boolean checkPayloadAuthority(String sn, String payloadIndex) {
        Optional<DeviceDTO> dockOpt = deviceRedisService.getDeviceOnline(sn);
        if (dockOpt.isEmpty()) {
            throw new RuntimeException("The dock is offline, please restart the dock.");
            throw new RuntimeException("机场离线请重启机场");
        }
        return devicePayloadService.checkAuthorityPayload(dockOpt.get().getChildDeviceSn(), payloadIndex);
    }
@@ -294,7 +412,15 @@
        ServiceReply serviceReply = messageSenderService.publishServicesTopic(param.getSn(), param.getCmd().getCmd(), param.getData());
        return ResponseResult.CODE_SUCCESS != serviceReply.getResult() ?
                ResponseResult.error(serviceReply.getResult(), " Error Code:" + serviceReply.getResult())
                ResponseResult.error(serviceReply.getResult(), "错误码:" + serviceReply.getResult())
                : ResponseResult.success();
    }
    @Override
    public ResponseResult requestsConfig(String sn, String method, RequestsParam param) {
        ServiceReply serviceReply = messageSenderService.publishRequestsTopic(sn, method, param);
        return ResponseResult.CODE_SUCCESS != serviceReply.getResult() ?
                ResponseResult.error(serviceReply.getResult(), "错误码:" + serviceReply.getResult())
                : ResponseResult.success();
    }