liusuyi
2024-11-01 dc4d96ff05b50617c685d90d625c6e2617c81dde
增加:航线
关闭:流媒体拉流
16 files added
7 files modified
729 ■■■■■ changed files
ard-work/src/main/java/com/ard/tianyu/controller/UavWayLineController.java 39 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/cache/TyTcpServerCache.java 31 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/HangarPointConverter.java 29 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/NormalModelConverter.java 48 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/PlanLineDataConverter.java 128 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/PointActionConverter.java 27 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/PointDataConverter.java 53 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/SurroundModelConverter.java 47 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/state/PointData.java 14 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/HangarPoint.java 23 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/NormalModel.java 30 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/PlanLineData.java 34 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/PointAction.java 22 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/SurroundModel.java 14 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/WayLineUploadDTO.java 22 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/TyNettyTcpClient.java 3 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/command/wayline/WayLineUploadCmd.java 40 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/command/wayline/WayLineUploadReplyCmd.java 37 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/handler/ClientHandler.java 3 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java 3 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/service/ITyService.java 6 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/service/impl/TyServiceImpl.java 67 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/vtdu/service/impl/MediaServiceImpl.java 9 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/controller/UavWayLineController.java
New file
@@ -0,0 +1,39 @@
package com.ard.tianyu.controller;
import com.ard.common.core.domain.AjaxResult;
import com.ard.tianyu.model.dto.speaker.SpeakModeSwitchDTO;
import com.ard.tianyu.model.dto.speaker.StopSpeakDTO;
import com.ard.tianyu.model.dto.speaker.TextSpeakDTO;
import com.ard.tianyu.model.dto.wayline.WayLineUploadDTO;
import com.ard.tianyu.service.ITyService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
 * UavSpeakerController
 *
 * @author liusuyi
 * @date 2024年10月21日13:52
 **/
@Api(tags = "无人机航线飞行接口")
@RequestMapping("/uav/wayline")
@RestController
public class UavWayLineController {
    @Resource
    private ITyService tyService;
    @ApiOperation("上传航线")
    @PostMapping("/wayLineUpload")
    public AjaxResult wayLineUpload(@RequestBody WayLineUploadDTO wayLineUploadDTO) {
        tyService.wayLineUpload(wayLineUploadDTO);
        return AjaxResult.success();
    }
}
ard-work/src/main/java/com/ard/tianyu/model/cache/TyTcpServerCache.java
New file
@@ -0,0 +1,31 @@
package com.ard.tianyu.model.cache;
import com.ard.tianyu.model.dto.signal.SignalInfo;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 天宇tcp服务器缓存
 *
 * @author liusuyi
 * @date 2024年11月01日13:53
 **/
public class TyTcpServerCache {
    // 使用 ConcurrentHashMap 来缓存TCP服务连接状态,key 是 ip:port(服务器地址) value 是连接状态
    private static final ConcurrentHashMap<String, Boolean> tcpServerCache = new ConcurrentHashMap<>();
    // 存储TCP服务连接状态到缓存
    public static void putTcpServerCache(String tcpServer,Boolean state) {
        tcpServerCache.put(tcpServer, state);
    }
    // 从缓存中获取TCP服务连接状态
    public static Boolean getTcpServerCache(String tcpServer) {
        return tcpServerCache.getOrDefault(tcpServer,false);
    }
    // 删除缓存中的TCP服务连接状态
    public static void removeTcpServerCache(String tcpServer) {
        tcpServerCache.remove(tcpServer);
    }
}
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/HangarPointConverter.java
New file
@@ -0,0 +1,29 @@
package com.ard.tianyu.model.dto.converter.wayline;
import com.ard.common.utils.bean.BeanUtils;
import com.ard.tianyu.model.dto.wayline.HangarPoint;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
public class HangarPointConverter {
    public static TelemetryDataPB.HangarPoint convertEntityToProto(HangarPoint hangarPoint) {
        // 使用 Protobuf 的构建器创建 HangarPoint 对象
        TelemetryDataPB.HangarPoint.Builder builder = TelemetryDataPB.HangarPoint.newBuilder();
        // 从 HangarPoint 实体中获取值并设置到 Protobuf 对象
        builder.setHangarId(hangarPoint.getHangarId());
        builder.setHangarLng(hangarPoint.getHangarLng());
        builder.setHangarLat(hangarPoint.getHangarLat());
        builder.setAlternateLng(hangarPoint.getAlternateLng());
        builder.setAlternateLat(hangarPoint.getAlternateLat());
        // 构建并返回 Protobuf 对象
        return builder.build();
    }
    // 将 Protobuf 对象转换为实体对象
    public static HangarPoint convertProtoToEntity(TelemetryDataPB.HangarPoint proto) {
        HangarPoint hangarPoint = new HangarPoint();
        // 从 Protobuf 对象中获取值并设置到实体对象
        BeanUtils.copyProperties(proto, hangarPoint);
        return hangarPoint;
    }
}
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/NormalModelConverter.java
New file
@@ -0,0 +1,48 @@
package com.ard.tianyu.model.dto.converter.wayline;
import com.ard.common.utils.bean.BeanUtils;
import com.ard.tianyu.model.dto.wayline.NormalModel;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
public class NormalModelConverter {
    public static TelemetryDataPB.NormalModel convertEntityToProto(NormalModel normalModel) {
        // 使用构建器来创建 Protobuf 对象
        TelemetryDataPB.NormalModel.Builder builder = TelemetryDataPB.NormalModel.newBuilder();
        // 复制基本属性
        builder.setServiceId(normalModel.getServiceId());
        builder.setCameraId(normalModel.getCameraId());
        builder.setIsModeling(normalModel.getIsModeling());
        builder.setMode(normalModel.getMode());
        builder.setHOverlap(normalModel.getHOverlap());
        builder.setVOverlap(normalModel.getVOverlap());
        builder.setMirror(normalModel.getMirror());
        // 处理 repeated fields
        if (normalModel.getArea() != null) {
            normalModel.getArea().forEach(pointData -> {
                builder.addArea(PointDataConverter.convertEntityToProto(pointData));
            });
        }
        // 构建并返回 Protobuf 对象
        return builder.build();
    }
    // 将 Protobuf 对象转换为实体对象
    public static NormalModel convertProtoToEntity(TelemetryDataPB.NormalModel proto) {
        NormalModel normalModel = new NormalModel();
        // 复制基本属性
        BeanUtils.copyProperties(proto, normalModel);
        // 处理 repeated fields
        if (proto.getAreaCount() > 0) {
            proto.getAreaList().forEach(pointDataProto -> {
                normalModel.getArea().add(PointDataConverter.convertProtoToEntity(pointDataProto));
            });
        }
        return normalModel;
    }
}
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/PlanLineDataConverter.java
New file
@@ -0,0 +1,128 @@
package com.ard.tianyu.model.dto.converter.wayline;
import com.ard.common.utils.bean.BeanUtils;
import com.ard.tianyu.model.dto.state.PointData;
import com.ard.tianyu.model.dto.wayline.HangarPoint;
import com.ard.tianyu.model.dto.wayline.NormalModel;
import com.ard.tianyu.model.dto.wayline.PlanLineData;
import com.ard.tianyu.model.dto.wayline.SurroundModel;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import java.util.List;
import java.util.stream.Collectors;
public class PlanLineDataConverter {
    // 将 Protobuf 对象转换为实体对象
    public static PlanLineData convertProtoToEntity(TelemetryDataPB.PlanLineData proto) {
        PlanLineData planLineData = new PlanLineData();
        // 使用 BeanUtils 复制属性
        BeanUtils.copyProperties(proto, planLineData);
        // 处理 repeated fields
        if (proto.getPointsCount() > 0) {
            List<PointData> points = proto.getPointsList().stream()
                .map(PointDataConverter::convertProtoToEntity)
                .collect(Collectors.toList());
            planLineData.setPoints(points);
        }
        if (proto.getInterestsCount() > 0) {
            List<PointData> interests = proto.getInterestsList().stream()
                .map(PointDataConverter::convertProtoToEntity)
                .collect(Collectors.toList());
            planLineData.setInterests(interests);
        }
        // 处理 HangarPoint
        if (proto.hasTakePoint()) {
            HangarPoint takePoint = HangarPointConverter.convertProtoToEntity(proto.getTakePoint());
            planLineData.setTakePoint(takePoint);
        }
        if (proto.hasLandPoint()) {
            HangarPoint landPoint = HangarPointConverter.convertProtoToEntity(proto.getLandPoint());
            planLineData.setLandPoint(landPoint);
        }
        // 处理 NormalModel 和 SurroundModel
        if (proto.hasNormalModel()) {
            NormalModel normalModel = NormalModelConverter.convertProtoToEntity(proto.getNormalModel());
            planLineData.setNormalModel(normalModel);
        }
        if (proto.hasSurroundModel()) {
            SurroundModel surroundModel = SurroundModelConverter.convertProtoToEntity(proto.getSurroundModel());
            planLineData.setSurroundModel(surroundModel);
        }
        // 处理起飞点
        if (proto.hasTakeOffPoint()) {
            PointData takeOffPoint = PointDataConverter.convertProtoToEntity(proto.getTakeOffPoint());
            planLineData.setTakeOffPoint(takeOffPoint);
        }
        return planLineData;
    }
    // 将实体对象转换为 Protobuf 对象
    public static TelemetryDataPB.PlanLineData convertEntityToProto(PlanLineData planLineData) {
        // 创建 Protobuf 的构建器
        TelemetryDataPB.PlanLineData.Builder builder = TelemetryDataPB.PlanLineData.newBuilder();
        // 复制基本属性
        builder.setFinishedAction(planLineData.getFinishedAction());
        builder.setMaxSpeed(planLineData.getMaxSpeed());
        builder.setAutoSpeed(planLineData.getAutoSpeed());
        builder.setLoseAction(planLineData.getLoseAction());
        builder.setHomeHeight(planLineData.getHomeHeight());
        builder.setIsSaveEnergyMode(planLineData.getIsSaveEnergyMode());
        // 处理 repeated fields
        if (planLineData.getPoints() != null) {
            List<TelemetryDataPB.PointData> points = planLineData.getPoints().stream()
                .map(PointDataConverter::convertEntityToProto)
                .collect(Collectors.toList());
            builder.addAllPoints(points);
        }
        if (planLineData.getInterests() != null) {
            List<TelemetryDataPB.PointData> interests = planLineData.getInterests().stream()
                .map(PointDataConverter::convertEntityToProto)
                .collect(Collectors.toList());
            builder.addAllInterests(interests);
        }
        // 处理 HangarPoint
        if (planLineData.getTakePoint() != null) {
            TelemetryDataPB.HangarPoint takePoint = HangarPointConverter.convertEntityToProto(planLineData.getTakePoint());
            builder.setTakePoint(takePoint);
        }
        if (planLineData.getLandPoint() != null) {
            TelemetryDataPB.HangarPoint landPoint = HangarPointConverter.convertEntityToProto(planLineData.getLandPoint());
            builder.setLandPoint(landPoint);
        }
        // 处理 NormalModel 和 SurroundModel
        if (planLineData.getNormalModel() != null) {
            TelemetryDataPB.NormalModel normalModel = NormalModelConverter.convertEntityToProto(planLineData.getNormalModel());
            builder.setNormalModel(normalModel);
        }
        if (planLineData.getSurroundModel() != null) {
            TelemetryDataPB.SurroundModel surroundModel = SurroundModelConverter.convertEntityToProto(planLineData.getSurroundModel());
            builder.setSurroundModel(surroundModel);
        }
        // 处理起飞点
        if (planLineData.getTakeOffPoint() != null) {
            TelemetryDataPB.PointData takeOffPoint = PointDataConverter.convertEntityToProto(planLineData.getTakeOffPoint());
            builder.setTakeOffPoint(takeOffPoint);
        }
        // 构建并返回 Protobuf 对象
        return builder.build();
    }
}
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/PointActionConverter.java
New file
@@ -0,0 +1,27 @@
package com.ard.tianyu.model.dto.converter.wayline;
import com.ard.common.utils.bean.BeanUtils;
import com.ard.tianyu.model.dto.wayline.PointAction;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
public class PointActionConverter {
    public static TelemetryDataPB.PointAction convertEntityToProto(PointAction pointAction) {
        // 使用构建器来创建 Protobuf 对象
        TelemetryDataPB.PointAction.Builder builder = TelemetryDataPB.PointAction.newBuilder();
        // 复制基本属性
        builder.setType(pointAction.getType());
        builder.setParam(pointAction.getParam());
        builder.setWaitTime(pointAction.getWaitTime());
        builder.setSpeakInfo(pointAction.getSpeakInfo());
        // 构建并返回 Protobuf 对象
        return builder.build();
    }
    public static PointAction convertProtoToEntity(TelemetryDataPB.PointAction proto) {
        PointAction pointAction = new PointAction();
        BeanUtils.copyProperties(proto, pointAction);
        return pointAction;
    }
}
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/PointDataConverter.java
New file
@@ -0,0 +1,53 @@
package com.ard.tianyu.model.dto.converter.wayline;
import com.ard.common.utils.bean.BeanUtils;
import com.ard.tianyu.model.dto.state.PointData;
import com.ard.tianyu.model.dto.wayline.PointAction;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import java.util.List;
import java.util.stream.Collectors;
public class PointDataConverter {
    public static TelemetryDataPB.PointData convertEntityToProto(PointData pointData) {
        // 使用构建器来创建 Protobuf 对象
        TelemetryDataPB.PointData.Builder builder = TelemetryDataPB.PointData.newBuilder();
        // 复制基本属性
        builder.setLng(pointData.getLng());
        builder.setLat(pointData.getLat());
        builder.setHeight(pointData.getHeight());
        builder.setSpeed(pointData.getSpeed());
        builder.setFlightPathMode(pointData.getFlightPathMode());
        builder.setDampingDistance(pointData.getDampingDistance());
        builder.setSafeGohomeFlag(pointData.getSafeGohomeFlag());
        builder.setHeadingMode(pointData.getHeadingMode());
        builder.setHeading(pointData.getHeading());
        builder.setInterestIndex(pointData.getInterestIndex());
        builder.setGroupIndex(pointData.getGroupIndex());
        // 处理动作数组
        if (pointData.getActions() != null && !pointData.getActions().isEmpty()) {
            List<TelemetryDataPB.PointAction> actions = pointData.getActions().stream()
                    .map(PointActionConverter::convertEntityToProto)
                    .collect(Collectors.toList());
            builder.addAllActions(actions);
        }
        // 构建并返回 Protobuf 对象
        return builder.build();
    }
    public static PointData convertProtoToEntity(TelemetryDataPB.PointData proto) {
        PointData pointData = new PointData();
        BeanUtils.copyProperties(proto, pointData);
        // 处理 repeated fields
        if (proto.getActionsCount() > 0) {
            List<PointAction> actions = proto.getActionsList().stream()
                    .map(PointActionConverter::convertProtoToEntity)
                    .collect(Collectors.toList());
            pointData.setActions(actions);
        }
        return pointData;
    }
}
ard-work/src/main/java/com/ard/tianyu/model/dto/converter/wayline/SurroundModelConverter.java
New file
@@ -0,0 +1,47 @@
package com.ard.tianyu.model.dto.converter.wayline;
import com.ard.common.utils.bean.BeanUtils;
import com.ard.tianyu.model.dto.state.PointData;
import com.ard.tianyu.model.dto.wayline.SurroundModel;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import java.util.List;
import java.util.stream.Collectors;
public class SurroundModelConverter {
    public static TelemetryDataPB.SurroundModel convertEntityToProto(SurroundModel surroundModel) {
        // 使用构建器来创建 Protobuf 对象
        TelemetryDataPB.SurroundModel.Builder builder = TelemetryDataPB.SurroundModel.newBuilder();
        // 复制基本属性
        builder.setServiceId(surroundModel.getServiceId());
        builder.setCameraId(surroundModel.getCameraId());
        builder.setIsModeling(surroundModel.getIsModeling());
        // 处理 repeated fields
        if (surroundModel.getArea() != null && !surroundModel.getArea().isEmpty()) {
            List<TelemetryDataPB.PointData> area = surroundModel.getArea().stream()
                    .map(PointDataConverter::convertEntityToProto)
                    .collect(Collectors.toList());
            builder.addAllArea(area);
        }
        // 构建并返回 Protobuf 对象
        return builder.build();
    }
    public static SurroundModel convertProtoToEntity(TelemetryDataPB.SurroundModel proto) {
        SurroundModel surroundModel = new SurroundModel();
        BeanUtils.copyProperties(proto, surroundModel);
        // 处理 repeated fields
        if (proto.getAreaCount() > 0) {
            List<PointData> area = proto.getAreaList().stream()
                    .map(PointDataConverter::convertProtoToEntity)
                    .collect(Collectors.toList());
            surroundModel.setArea(area);
        }
        return surroundModel;
    }
}
ard-work/src/main/java/com/ard/tianyu/model/dto/state/PointData.java
@@ -1,10 +1,24 @@
package com.ard.tianyu.model.dto.state;
import com.ard.tianyu.model.dto.wayline.PointAction;
import lombok.Data;
import java.util.List;
// 假设 PointData 类定义如下
@Data
public class PointData {
    private double lat; // 纬度
    private double lng; // 经度
    private float height; // 高度(单位:米,范围0~遥控器限高)
    private float speed; // 速度(单位:米/秒,范围0~15),默认8
    private List<PointAction> actions; // 动作数组
    private int flightPathMode; // 航线飞行模式:1=直线飞行,2=协调转弯,3=曲线飞行(停),4=曲线飞行(不停)
    private float dampingDistance; // 转弯半径(仅协调转弯模式下有效),取值范围1~655.35单位:米
    private int safeGohomeFlag; // 是否为安全返航点 0=不是,1=是
    private int headingMode; // 偏航模式 0=自动,1=锁定,2=遥控器控制,3=云台依照航点方向旋转,4=朝向兴趣点,5=飞机和云台的偏航同时旋转
    private float heading; // 航点偏航 -180~180
    private int interestIndex; // 兴趣点下标,默认-1
    private int groupIndex; // 组下标
}
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/HangarPoint.java
New file
@@ -0,0 +1,23 @@
package com.ard.tianyu.model.dto.wayline;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * 机库信息实体对象
 *
 * @author liusuyi
 * @date 2024年11月01日10:55
 **/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class HangarPoint {
    private String hangarId; // 机库ID
    private double hangarLng; // 机库经度
    private double hangarLat; // 机库纬度
    private double alternateLng; // 备降点经度
    private double alternateLat; // 备降点纬度
}
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/NormalModel.java
New file
@@ -0,0 +1,30 @@
package com.ard.tianyu.model.dto.wayline;
import com.ard.tianyu.model.dto.state.PointData;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
 * 普通建模实体对象
 *
 * @author liusuyi
 * @date 2024年11月01日10:55
 **/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class NormalModel {
    private List<PointData> area; // 作业区域
    private int serviceId; // 建模平台编号:1=瞰景,2=大势,默认1
    private int cameraId; // 相机编号
    private int isModeling; // 是否实时建模:0=不,1=是
    private int mode; // 作业模式:1=倾斜,2=正摄
    private int hOverlap; // 横向重叠率
    private int vOverlap; // 纵向重叠率
    private int mirror; // 方向正反
}
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/PlanLineData.java
New file
@@ -0,0 +1,34 @@
package com.ard.tianyu.model.dto.wayline;
import com.ard.tianyu.model.dto.state.PointData;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
 * 航线实体对象
 *
 * @author liusuyi
 * @date 2024年11月01日10:55
 **/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PlanLineData {
    private int finishedAction; // 结束航线后动作
    private float maxSpeed; // 最大飞行速度(单位:米/秒)
    private float autoSpeed; // 自动飞行速度(单位:米/秒)
    private List<PointData> points; // 坐标点数组
    private int loseAction; // 网络失联后动作
    private int homeHeight; // 返航高度
    private int isSaveEnergyMode; // 是否开启节能模式
    private HangarPoint takePoint; // 起飞点机库信息
    private HangarPoint landPoint; // 降落点机库信息
    private List<PointData> interests; // 兴趣点数组
    private NormalModel normalModel; // 普通建模
    private SurroundModel surroundModel; // 环绕建模
    private PointData takeOffPoint; // 起飞点
}
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/PointAction.java
New file
@@ -0,0 +1,22 @@
package com.ard.tianyu.model.dto.wayline;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * 航点动作实体对象
 *
 * @author liusuyi
 * @date 2024年11月01日10:55
 **/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PointAction {
    private int type; // 类型:1-变焦 2-拍照 3-录像 4-停录 5-控制飞机机头偏航 6-控制云台俯仰 7-控制云台偏航 8-控制云台横滚 9-悬停 10-等距间隔拍照 11-等时间隔拍照 12-结束间隔拍照 13-单条喊话 14-开始循环喊话 15-结束循环喊话 16-对焦
    private float param; // 参数,根据类型不同含义不同
    private int waitTime; // 动作触发后等待时长(单位:秒)
    private String speakInfo; // 喊话内容[type=13和type=14时生效]
}
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/SurroundModel.java
New file
@@ -0,0 +1,14 @@
package com.ard.tianyu.model.dto.wayline;
import com.ard.tianyu.model.dto.state.PointData;
import lombok.Data;
import java.util.List;
@Data
public class SurroundModel {
    private List<PointData> area; // 作业区域
    private int serviceId; // 建模平台编号:1=瞰景
    private int cameraId; // 相机编号
    private int isModeling; // 是否实时建模:0=不,1=是
}
ard-work/src/main/java/com/ard/tianyu/model/dto/wayline/WayLineUploadDTO.java
New file
@@ -0,0 +1,22 @@
package com.ard.tianyu.model.dto.wayline;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * 上传航线实体对象
 *
 * @author liusuyi
 * @date 2024年11月01日10:55
 **/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class WayLineUploadDTO {
    private String boxSn;
    private PlanLineData wayLineData;
}
ard-work/src/main/java/com/ard/tianyu/netty/TyNettyTcpClient.java
@@ -1,6 +1,7 @@
package com.ard.tianyu.netty;
import com.ard.tianyu.config.TyConfiguration;
import com.ard.tianyu.model.cache.TyTcpServerCache;
import com.ard.tianyu.netty.handler.ClientHandler;
import com.ard.tianyu.netty.handler.MessageProtocolDecoder;
import com.ard.tianyu.netty.handler.MessageProtocolEncoder;
@@ -72,10 +73,12 @@
        ChannelFuture future = bootstrap.connect(host, port).addListener((ChannelFuture futureListener) -> {
            if (futureListener.isSuccess()) {
                log.info("连接天宇TCP服务器成功【{}:{}】", host, port);
                TyTcpServerCache.putTcpServerCache(host + ":" + port, true);
            } else {
                final EventLoop eventLoop = futureListener.channel().eventLoop();
                eventLoop.schedule(() -> {
                    log.info("连接天宇TCP服务器失败【{}:{}】,正尝试重连...", host, port);
                    TyTcpServerCache.putTcpServerCache(host + ":" + port, false);
                    try {
                        initConnection(host, port);
                    } catch (Exception e) {
ard-work/src/main/java/com/ard/tianyu/netty/command/wayline/WayLineUploadCmd.java
New file
@@ -0,0 +1,40 @@
package com.ard.tianyu.netty.command.wayline;
import com.ard.tianyu.model.dto.converter.wayline.PlanLineDataConverter;
import com.ard.tianyu.model.dto.wayline.PlanLineData;
import com.ard.tianyu.model.dto.wayline.WayLineUploadDTO;
import com.ard.tianyu.netty.command.BaseCmd;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import io.netty.buffer.ByteBuf;
/**
 * 上传航线指令
 *
 * @author liusuyi
 * @date 2024年10月30日16:20
 **/
public class WayLineUploadCmd extends BaseCmd {
    private final byte[] wayLineData;         //动作参数
    public WayLineUploadCmd(WayLineUploadDTO wayLineUploadDTO) {
        PlanLineData planLineData = wayLineUploadDTO.getWayLineData();
        TelemetryDataPB.PlanLineData planLineDataPB = PlanLineDataConverter.convertEntityToProto(planLineData);
        this.wayLineData = planLineDataPB.toByteArray();
        setDataHeader((short) 0x7479);
        setDataLength((short) (18 + wayLineData.length));
        setBoxSn(wayLineUploadDTO.getBoxSn().getBytes());
        setCmdCode((byte) 0xD1);
    }
    public void encode(ByteBuf out) {
        out.writeShort(getDataHeader());    // 写入数据头
        out.writeShort(getDataLength());    // 写入数据长度
        out.writeBytes(getBoxSn());         // 写入盒子SN
        out.writeByte(getCmdCode());        // 写入命令码
        out.writeByte(0x00);          // 写入加密标志
        out.writeByte(0x10);          // 写入动作编号
        out.writeBytes(this.wayLineData);   // 写入航线数据
    }
}
ard-work/src/main/java/com/ard/tianyu/netty/command/wayline/WayLineUploadReplyCmd.java
New file
@@ -0,0 +1,37 @@
package com.ard.tianyu.netty.command.wayline;
import com.ard.tianyu.model.dto.converter.wayline.PlanLineDataConverter;
import com.ard.tianyu.model.dto.wayline.PlanLineData;
import com.ard.tianyu.model.dto.wayline.WayLineUploadDTO;
import com.ard.tianyu.netty.command.BaseCmd;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import io.netty.buffer.ByteBuf;
import lombok.Data;
/**
 * 上传航线回复指令
 *
 * @author liusuyi
 * @date 2024年10月30日16:20
 **/
@Data
public class WayLineUploadReplyCmd extends BaseCmd {
    private final byte encryptFlag = 0x00; // 加密标志
    private final byte actionCode = 0x10;  // 动作编号
    private final byte result;             // 执行结果
    private final Integer errorCode;       // 错误码
    public WayLineUploadReplyCmd(String boxSn, Byte result, Integer errorCode) {
        setDataHeader((short) 0x6A77);
        //setDataLength((short) 18);
        setCmdCode((byte) 0xD1);
        setBoxSn(boxSn.getBytes());
        this.result = result;
        this.errorCode = errorCode;
    }
    public void encode(ByteBuf out) {
    }
}
ard-work/src/main/java/com/ard/tianyu/netty/handler/ClientHandler.java
@@ -1,5 +1,6 @@
package com.ard.tianyu.netty.handler;
import com.ard.tianyu.model.cache.TyTcpServerCache;
import com.ard.tianyu.netty.TyNettyTcpClient;
import com.ard.tianyu.netty.command.BaseCmd;
import com.ard.tianyu.service.ITyService;
@@ -70,7 +71,7 @@
        int port = ipSocket.getPort();
        String host = ipSocket.getHostString();
        log.error("与天宇服务{}:{}连接断开!", host, port);
        TyTcpServerCache.putTcpServerCache(host + ":" + port, false);
        ctx.channel().eventLoop().schedule(() -> {
            log.error("天宇服务端链接不上,开始重连操作...");
            try {
ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java
@@ -16,6 +16,7 @@
import com.ard.tianyu.netty.command.register.HeartbeatReplyCmd;
import com.ard.tianyu.netty.command.register.RegisterReplyCmd;
import com.ard.tianyu.netty.command.register.UavInitReplyCmd;
import com.ard.tianyu.netty.command.wayline.WayLineUploadReplyCmd;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import com.google.protobuf.InvalidProtocolBufferException;
import io.netty.buffer.ByteBuf;
@@ -113,6 +114,8 @@
        in.readBytes(uavData);
        String boxSn = new String(uavData);
        switch (actionCode) {
            case 0x10:
                return new WayLineUploadReplyCmd(boxSn, result, errorCode);
            case 0x11:
                return new TakeOffReplyCmd(boxSn, result, errorCode);
            case 0x12:
ard-work/src/main/java/com/ard/tianyu/service/ITyService.java
@@ -12,6 +12,7 @@
import com.ard.tianyu.model.dto.speaker.*;
import com.ard.tianyu.model.dto.state.UavState;
import com.ard.tianyu.model.dto.telemetry.TelemetryData;
import com.ard.tianyu.model.dto.wayline.WayLineUploadDTO;
import com.ard.tianyu.model.receiver.*;
import com.ard.tianyu.netty.command.BaseCmd;
import com.dtflys.forest.annotation.Var;
@@ -229,6 +230,11 @@
    void stopSpeak(StopSpeakDTO stopSpeakDTO);
    /**
     * 上传航线
     */
    void wayLineUpload(WayLineUploadDTO wayLineUploadDTO);
    /**
     * 处理回复消息
     */
    void processReplyMessage(String key, BaseCmd tyMessage);
ard-work/src/main/java/com/ard/tianyu/service/impl/TyServiceImpl.java
@@ -3,6 +3,7 @@
import com.ard.common.utils.ByteUtils;
import com.ard.tianyu.config.TyConfiguration;
import com.ard.tianyu.http.TyClient;
import com.ard.tianyu.model.cache.TyTcpServerCache;
import com.ard.tianyu.model.cache.UavSignalInfoCache;
import com.ard.tianyu.model.cache.UavStateCache;
import com.ard.tianyu.model.cache.UavTelemetryDataCache;
@@ -16,11 +17,14 @@
import com.ard.tianyu.model.dto.converter.UavSignalInfoConverter;
import com.ard.tianyu.model.dto.converter.UavStateConverter;
import com.ard.tianyu.model.dto.converter.UavTelemetryDataConverter;
import com.ard.tianyu.model.dto.converter.wayline.PlanLineDataConverter;
import com.ard.tianyu.model.dto.manual.*;
import com.ard.tianyu.model.dto.signal.SignalInfo;
import com.ard.tianyu.model.dto.speaker.*;
import com.ard.tianyu.model.dto.state.UavState;
import com.ard.tianyu.model.dto.telemetry.TelemetryData;
import com.ard.tianyu.model.dto.wayline.PlanLineData;
import com.ard.tianyu.model.dto.wayline.WayLineUploadDTO;
import com.ard.tianyu.model.receiver.*;
import com.ard.tianyu.netty.command.*;
import com.ard.tianyu.netty.TyNettyTcpClient;
@@ -37,7 +41,10 @@
import com.ard.tianyu.netty.command.real.UavTelemetryDataCmd;
import com.ard.tianyu.netty.command.register.*;
import com.ard.tianyu.netty.command.speaker.*;
import com.ard.tianyu.netty.command.wayline.WayLineUploadCmd;
import com.ard.tianyu.netty.command.wayline.WayLineUploadReplyCmd;
import com.ard.tianyu.netty.handler.ErrorCodeEnum;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import com.ard.tianyu.service.ITyService;
import com.ard.tianyu.websocket.utils.WebSocketUtil;
import io.netty.channel.Channel;
@@ -49,6 +56,7 @@
import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -420,6 +428,7 @@
        RecordSpeakCmd recordSpeakCmd = new RecordSpeakCmd(recordSpeakDTO);
        this.sendMessage(tyConfiguration.getIpPort(), recordSpeakCmd);
    }
    /**
     * 设置音量
     */
@@ -437,13 +446,58 @@
        LoopSettingCmd loopSettingCmd = new LoopSettingCmd(loopSettingDTO);
        this.sendMessage(tyConfiguration.getIpPort(), loopSettingCmd);
    }
    /**
     * 停止喊话
     */
    @Override
    public void stopSpeak(StopSpeakDTO stopSpeakDTO) {
        StopSpeakCmd stopSpeakCmd=new StopSpeakCmd(stopSpeakDTO);
        StopSpeakCmd stopSpeakCmd = new StopSpeakCmd(stopSpeakDTO);
        this.sendMessage(tyConfiguration.getIpPort(), stopSpeakCmd);
    }
    /**
     * 航线上传
     */
    @Override
    public void wayLineUpload(WayLineUploadDTO wayLineUploadDTO) {
        wayLineUploadDTO.setWayLineData(this.CreatePlanLineData());//设置航线数据
        WayLineUploadCmd wayLineUploadCmd = new WayLineUploadCmd(wayLineUploadDTO);
        this.sendMessage(tyConfiguration.getIpPort(), wayLineUploadCmd);
    }
    //创建航线
    private PlanLineData CreatePlanLineData() {
        TelemetryDataPB.PointData pointData1 = TelemetryDataPB.PointData.newBuilder()
                .setLng(124.12345).setLat(45.12345).setHeight(80).setSpeed(10)
                .setFlightPathMode(1)//航线飞行模式:1=直线飞行,2=协调转弯,3=曲线飞行(停),4=曲线飞行(不停)
                .setSafeGohomeFlag(0)//是否为安全返航点 0=不是,1=是
                .build();
        TelemetryDataPB.PointData pointData2 = TelemetryDataPB.PointData.newBuilder()
                .setLng(124.22222).setLat(45.22222).setHeight(80).setSpeed(10)
                .setFlightPathMode(1)//航线飞行模式:1=直线飞行,2=协调转弯,3=曲线飞行(停),4=曲线飞行(不停)
                .setSafeGohomeFlag(0)//是否为安全返航点 0=不是,1=是
                .build();
        TelemetryDataPB.PointData pointData3 = TelemetryDataPB.PointData.newBuilder()
                .setLng(124.33333).setLat(45.33333).setHeight(80).setSpeed(10)
                .setFlightPathMode(1)//航线飞行模式:1=直线飞行,2=协调转弯,3=曲线飞行(停),4=曲线飞行(不停)
                .setSafeGohomeFlag(0)//是否为安全返航点 0=不是,1=是
                .build();
        //创建航线
        TelemetryDataPB.PlanLineData PlanLineDataPB = TelemetryDataPB.PlanLineData.newBuilder()
                .setFinishedAction(2)//结束航线后动作:1=返航,2=原地悬停,3=原地降落,4=原地绕飞
                .setMaxSpeed(10)//最大飞行速度
                .setAutoSpeed(10)//自动飞行速度
                .addPoints(pointData1)//航线点1
                .addPoints(pointData2)//航线点2
                .addPoints(pointData3)//航线点3
                .setLoseAction(1)//网络失联后动作:0=返回HOME点,1=继续航线,默认0
                .setHomeHeight(6)//返航高度:(单位:米,范围20~1500)
                .setIsSaveEnergyMode(0)////是否开启节能模式:0=不是,1=是(说明:节能模式下,飞机沿最短直线距离由起飞点到航线第一个航点,非升高到第一个航点高度再飞往第一个航点)
                .build();
        return PlanLineDataConverter.convertProtoToEntity(PlanLineDataPB);
    }
    /**
@@ -589,7 +643,12 @@
                //紧急制动回复
                if (tyCommand instanceof EmergencyBrakeReplyCmd) {
                    EmergencyBrakeReplyCmd emergencyBrakeReplyCmd = (EmergencyBrakeReplyCmd) tyCommand;
                    logPrint("紧急制动回复", emergencyBrakeReplyCmd.getResult(), emergencyBrakeReplyCmd.getErrorCode());
                    logPrint("紧急制动", emergencyBrakeReplyCmd.getResult(), emergencyBrakeReplyCmd.getErrorCode());
                }
                //上传航线回复
                if (tyCommand instanceof WayLineUploadReplyCmd) {
                    WayLineUploadReplyCmd wayLineUploadReplyCmd = (WayLineUploadReplyCmd) tyCommand;
                    logPrint("上传航线", wayLineUploadReplyCmd.getResult(), wayLineUploadReplyCmd.getErrorCode());
                }
                break;
            default:
@@ -617,6 +676,10 @@
     */
    @Scheduled(fixedRate = 3000)
    public void sendHeartBeat() {
        if(!TyTcpServerCache.getTcpServerCache(tyConfiguration.getTcpserver() + ":" + tyConfiguration.getTcpport()))
        {
            return;
        }
        long timestamp = System.currentTimeMillis();
        log.debug("定时向天宇发送⼼跳,时间戳{}", timestamp);
        HeartbeatCmd heartbeatMessage = new HeartbeatCmd(timestamp);
ard-work/src/main/java/com/ard/vtdu/service/impl/MediaServiceImpl.java
@@ -2,6 +2,8 @@
import com.ard.common.constant.HttpStatus;
import com.ard.common.core.page.TableDataInfo;
import com.ard.tianyu.config.TyConfiguration;
import com.ard.tianyu.model.cache.TyTcpServerCache;
import com.ard.tianyu.model.receiver.BoxInfoReceiver;
import com.ard.tianyu.model.receiver.BoxStreamUrlReceiver;
import com.ard.tianyu.service.ITyService;
@@ -42,6 +44,8 @@
    private MediaClient mediaClient;
    @Resource
    private ITyService tyService;
    @Resource
    private TyConfiguration tyConfiguration;
    @Value("${mediamtx.host}")
    private String mediamtxHost;
@@ -566,8 +570,11 @@
    }
    //同步无人机推流到流媒体
    @Scheduled(cron = "0/20 * * * * ?")
   // @Scheduled(cron = "0/20 * * * * ?")
    public void syncVtdu() {
        if (!TyTcpServerCache.getTcpServerCache(tyConfiguration.getTcpserver() + ":" + tyConfiguration.getTcpport())) {
            return;
        }
        log.info("定时同步MediaMTX任务开始");
        List<String> nameList = getNameList();
        List<BoxInfoReceiver> boxList = tyService.getBoxList();