liusuyi
2024-10-23 37aeda6f5a45a220955eafd55bf5154c71c2d705
优化
4 files added
7 files modified
36456 ■■■■■ changed files
ard-admin/src/main/resources/application-dev.yml 4 ●●●●● patch | view | raw | blame | history
ard-work/pom.xml 6 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/config/TyConfiguration.java 7 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/command/UavDataCommand.java 29 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/command/UavStateCommand.java 25 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/handler/ClientHandler.java 8 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java 41 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/protobuf/TelemetryDataBuf-new.proto 280 ●●●●● patch | view | raw | blame | history
ard-work/src/main/java/com/ard/tianyu/netty/protobuf/TelemetryDataPB.java 36013 ●●●●● 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 37 ●●●●● patch | view | raw | blame | history
ard-admin/src/main/resources/application-dev.yml
@@ -24,12 +24,12 @@
# 天宇服务器配置
tianyu:
  # 天宇http服务器地址
  endpoint: 112.98.106.22:12000
  endpoint: 112.98.106.22:22000
  accesskeyid: qmfmd3Ws7M4dMcylnrTU
  accesskeysecret: 5WBU2uEhHZaVefpZdaxpFh4LJW9fZZaa
  # 天宇tcp服务器地址
  tcpserver: 112.98.106.22
  tcpport: 13002
  tcpport: 23002
# netty配置
netty:
  tcp:
ard-work/pom.xml
@@ -49,6 +49,12 @@
            <scope>provided</scope>
        </dependency>
        <!--protobuf的依赖-->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.20.1</version>
        </dependency>
    </dependencies>
    <build>
ard-work/src/main/java/com/ard/tianyu/config/TyConfiguration.java
@@ -72,10 +72,13 @@
                .encryptStr(getEncryptStr())
                .timeStamp(timestamp)
                .build();
        try {
        TyHttpCommonReceiver<AccessTokenReceiver> getTokenRes = tyClient.getToken(gtd);
        //{"state":0,"content":{"companyId":4127,"accessToken":"sOONT0MMVdoKcMBibb40xxgrUrq0Hw9RFiajic3KOzoNtk"}}
        accessToken = getTokenRes.getContent();
        } catch (Exception e) {
            log.error("获取token失败:{}", e.getMessage());
        }
        //{"state":0,"content":{"companyId":4127,"accessToken":"sOONT0MMVdoKcMBibb40xxgrUrq0Hw9RFiajic3KOzoNtk"}}
        return accessToken;
    }
}
ard-work/src/main/java/com/ard/tianyu/netty/command/UavDataCommand.java
New file
@@ -0,0 +1,29 @@
package com.ard.tianyu.netty.command;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import io.netty.buffer.ByteBuf;
/**
 * UavDataCommand
 *
 * @author liusuyi
 * @date 2024年10月23日9:33
 **/
public class UavDataCommand extends BaseCommand{
    private TelemetryDataPB.TelemetryData telemetryData;
    // 构造函数
    public UavDataCommand(TelemetryDataPB.TelemetryData telemetryData) {
        this.telemetryData = telemetryData;
    }
    // 获取无人机状态数据
    public TelemetryDataPB.TelemetryData getTelemetryData() {
        return telemetryData;
    }
    // 实现 encode 方法,如果需要
    @Override
    public void encode(ByteBuf out) {
        // 根据需要实现编码
    }
}
ard-work/src/main/java/com/ard/tianyu/netty/command/UavStateCommand.java
New file
@@ -0,0 +1,25 @@
package com.ard.tianyu.netty.command;
import com.ard.tianyu.netty.command.BaseCommand;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import io.netty.buffer.ByteBuf;
public class UavStateCommand extends BaseCommand {
    private TelemetryDataPB.UavState uavState;  // ProtoBuf 数据类
    // 构造函数
    public UavStateCommand(TelemetryDataPB.UavState uavState) {
        this.uavState = uavState;
    }
    // 获取无人机状态数据
    public TelemetryDataPB.UavState getUavState() {
        return uavState;
    }
    // 实现 encode 方法,如果需要
    @Override
    public void encode(ByteBuf out) {
        // 根据需要实现编码
    }
}
ard-work/src/main/java/com/ard/tianyu/netty/handler/ClientHandler.java
@@ -29,10 +29,10 @@
    @Override
    public void channelRead0(ChannelHandlerContext ctx, BaseCommand command) {
        //InetSocketAddress ipSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        //String host = ipSocket.getHostString();
        //int port = ipSocket.getPort();
        //tyService.processMessage(host + "/" + port, msg);
        InetSocketAddress ipSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String host = ipSocket.getHostString();
        int port = ipSocket.getPort();
        tyService.processMessage(host + ":" + port, command);
    }
    @Override
ard-work/src/main/java/com/ard/tianyu/netty/handler/MessageProtocolDecoder.java
@@ -2,6 +2,9 @@
import com.ard.tianyu.netty.command.BaseCommand;
import com.ard.tianyu.netty.command.HeartbeatReplyCommand;
import com.ard.tianyu.netty.command.UavDataCommand;
import com.ard.tianyu.netty.command.UavStateCommand;
import com.ard.tianyu.netty.protobuf.TelemetryDataPB;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
@@ -30,22 +33,36 @@
            return;
        }
        byte cmdCode = in.readByte();
        BaseCommand command = null;
        // 根据 cmdCode 创建相应消息对象
        if (cmdCode == 0x01) { // 注册回复消息
        BaseCommand baseCommand = null;
        switch (cmdCode) {
            case 0x01:
            byte success = in.readByte(); // 读取是否成功
            log.warn("注册回复: {}", success == 0x01 ? "成功" : "失败");
        }
        if (cmdCode == 0x02) { // 注册回复消息
                break;
            case 0x02:
            long timestamp = in.readLong(); // 读取时间戳
            command = new HeartbeatReplyCommand(timestamp); // 创建心跳回复对象
            log.debug("心跳回复: 时间戳 {}", timestamp);
                baseCommand = new HeartbeatReplyCommand(timestamp);
                log.warn("心跳回复: 时间戳 {}", timestamp);
                break;
            case (byte) 0xA8:
                byte[] uavStatus = new byte[dataLength - 1];
                in.readBytes(uavStatus);  // 读取 ProtoBuf 数据
                TelemetryDataPB.UavState uavState = TelemetryDataPB.UavState.parseFrom(uavStatus);
                baseCommand = new UavStateCommand(uavState);
                log.warn("无人机状态数据: {}", uavState.getBoxSn());
                break;
            case (byte) 0xA9:
                byte[] uavData = new byte[dataLength - 1];
                in.readBytes(uavData);
                TelemetryDataPB.TelemetryData telemetryData = TelemetryDataPB.TelemetryData.parseFrom(uavData);
                baseCommand = new UavDataCommand(telemetryData);
                log.warn("无人机遥测数据: {}", telemetryData.getBoxSn());
                break;
            default:
                log.warn("无法识别的命令码: {}", String.format("0x%02X", cmdCode & 0xFF));//String.format("0x%02X", cmdCode & 0xFF)
        }
        if (command != null) {
            out.add(command); // 添加解码的命令对象到输出列表
        } else {
            log.warn("无法识别的命令码: {}", cmdCode);//String.format("0x%02X", cmdCode & 0xFF)
        if (baseCommand != null) {
            out.add(baseCommand);
        }
    }
}
ard-work/src/main/java/com/ard/tianyu/netty/protobuf/TelemetryDataBuf-new.proto
New file
@@ -0,0 +1,280 @@
syntax = "proto3";
option java_package = "com.ard.tianyu.netty.protobuf";
option java_outer_classname ="TelemetryDataPB";
//下行遥测
message TelemetryData{
    double lng=1;//经度
    double lat=2;//纬度
    float altitude=3;//海拔高度(椭球高)(单位:米)[与遥控器显示值不同源,可能不一致。会受周围气压湿度等环境影响,数据差异及误差比较大]
    float ultrasonic=4;//相对高度(单位:米)[飞行器距地面10米以下,此值为真实距地距离,大于10米时为距起飞点的相对高度]
    float pitch=5;//俯仰角
    float roll=6;//横滚角
    float yaw=7;//偏航角
    float airspeed=8;//空速(单位:米/秒)
    float velocity=9;//地速(单位:米/秒)
    uint64 timestamp=10;//时间戳
    float ptpitch=11;//载荷俯仰角
    float ptroll=12;//载荷横滚角
    float ptyaw=13;//载荷航向角
    float zoomfactor=14;//载荷当前倍数
    string boxSn=15;//云盒子编号
    string batteryPower=16;//电池电量,多个电池以下划线分割,如:80_60
    uint32 satelliteCount=17;//卫星计数
    uint64 taskId=18;//任务编号
    double rtkLng=19;//rtk经度
    double rtkLat=20;//rtk纬度
    float rtkHFSL=21;//rtk海拔高度(平均海平面高度)(单位:米)
    uint32 rtkPositionInfo=22;//rtk状态(值为50时[rtk数据fix固定解],rtk的经纬度及海拔高度值可用)
    uint32 airFlyTimes=23;//当前架次飞行时长(单位:秒) [起飞->落地 视为一个架次]
    float airFlyDistance=24;//当前架次飞行实际距离(单位:米)
    string uavSn=25;//无人机编号
    string uavModel=26;//无人机型号
    float homeRange=27;//距降落点水平直线距离(单位:米)
    uint32 flightMode=28;//飞行模式:1=手动控制模式,2=姿态模式,6=MODE_P_GPS,9=热点任务中,11=自动起飞中,12=降落中,14=航线中,15=返航中,17=虚拟摇杆控制中,33=强制降落中,41=解锁电机准备起飞中
    float targetDistance=29;//距目标点实际距离(单位:米) [适用于打点飞行和航线飞行]
    uint32 predictFlyTime=30;//预计剩余飞行时间[适用于打点飞行和航线飞行]
    float ultrasonicMax=31;//本架次最大相对高度值
    float ultrasonicMin=32;//本架次最小相对高度值
}
//飞行历史
message TelemetryList{
    repeated TelemetryData telemetryList = 1;
}
 //信道质量
message SignalInfo{
   string mode=1; //入网模式:NR5G-SA,NR5G-NSA,LTE
   string mcc=2; //NR5G-SA,NR5G-NSA,LTE
   string mnc=3; //NR5G-SA,NR5G-NSA,LTE
   string cellid=4; //NR5G-SA,LTE
   string pcid=5; //NR5G-SA,NR5G-NSA,LTE
   string tac=6; //NR5G-SA,LTE
   string arfcn=7; //NR5G-SA,NR5G-NSA
   string band=8; //NR5G-SA,NR5G-NSA
   string nr_dl_bandwidth=9; //NR5G-SA
   string rsrp=10; //NR5G-SA,NR5G-NSA,LTE
   string rsrq=11; //NR5G-SA,NR5G-NSA,LTE
   string sinr=12; //NR5G-SA,NR5G-NSA,LTE
   string tx_power=13; //NR5G-SA,LTE
   string srxlev=14; //NR5G-SA,LTE
   string cqi=15; //LTE
   string earfcn=16; //LTE
   string freq_band_ind=17; //LTE
   string ul_bandwidth=18; //LTE
   string dl_bandwidth=19; //LTE
   string is_tdd=20; //LTE
   string rssi=21; //LTE
   string duplex_mode=22; //NR5G-SA
   double lng=23;//经度
   double lat=24;//纬度
   float height=25;//高度(单位:米)
   uint32 timestamp=26;//时间戳(单位:秒)
   uint32 boxstate=27;//1=线缆故障,2=OSDK未激活,3=正常,4=云盒固件更新
   string isp=28;//运营商
   uint32 tempMax=29;//模组芯片温度(单位:摄氏度)
   string prx_rsrp=30;//prx路径的rsrp值
   string drx_rsrp=31;//drx路径的rsrp值
   string rx2_rsrp=32;//rx2路径的rsrp值
   string rx3_rsrp=33;//rx3路径的rsrp值
   string box_sn=34;//云盒编号
}
message SignalList{
    repeated SignalInfo signalInfo = 1;
}
//无人机状态对象
message UavState{
    FlightControllerState flightControllerState=1;//飞控状态
    BatteryState batteryState=2;//电池状态
    PtzState ptzState=3;//云台状态
    CameraState cameraState=4;//相机状态
    MissionState missionState=5;//任务状态
    string boxSn=6;//云盒编号
    AvoidanceData avoidanceData=7;//避障数据
    repeated HmsAlarmData hmsAlarmData=8;//Hms报警信息[飞机告警信息]
}
message FlightControllerState{
    uint32 satelliteCount=1;//卫星计数
    uint32 gpsSignalLevel=2;//GPS信号级别,0~5[4,5等级可以执行航线]
    uint32 flightMode=3;//飞行模式:1=手动控制模式,2=姿态模式,6=MODE_P_GPS,9=热点任务中,11=自动起飞中,12=降落中,14=航线中,15=返航中,17=虚拟摇杆控制中,33=强制降落中,41=解锁电机准备起飞中
    uint32 flightStatus=4;//飞行状态:0=电机未启动(地面),1=电机启动未起飞(地面),2=起飞在空中(空中)
    PointData startPoint=5;//起飞点(只包含lat和lng信息)
    PointData homePoint=6;//返航点(只包含lat和lng信息)
    int32 homeHeight=7;//返航高度(单位:米)
    uint32 safeLine=8;//打点飞行模式:0=节能模式【飞机直线飞到目标点,需飞机在空中并且有控制权】,1=安全模式【飞机飞行至目标点高度再平飞到目标点,飞机可以在地面】 默认为节能模式
    uint32 deviceStatus=9;//控制权状态:0=遥控器,1=msdk,4=云盒[此控制权只针对虚拟摇杆控制权,起飞、降落、强制降落、航线操作、返航不需要此控制权,但是遥控器断连情况下,如果云盒没有控制权,飞机会执行遥控器的失联策略]
    uint32 uwbNodeCount=10;//UWB星数(只有等于4时,才可以开启uwb精准降落模式)
    string rcMode=11;//遥控器档位模式(说明:1.遥控器与飞机正常连接:(M300:T-P-S/M30:F-S-N/M3:C-N-S),2.遥控器与飞机未连接:W,3.只有在M300-P挡、M30-N挡、M3-N挡下云盒才能正常控制无人机)
    uint32 isEmergencyBrakeing=12;//是否紧急制动中,0=否,1=是 【飞行器在地面限制起飞,飞行器在空中限制飞行.如果想操作飞行,请先解除紧急制动】
    uint32 outFlyAreaFlag=13;//飞行器是否在所有自定义电子围栏外,0=电子围栏内 1=电子围栏外
    uint32 inNoFlyAreaFlag=14;//飞行器是否在自定义禁飞区内,0=禁飞区外 1=禁飞区内
}
//电池状态
message BatteryState{
    uint32 batteryNum=1;//电池数量
    string batteryPower=2;//电池电量,多个电池以下划线分割,如:80_60
    string batteryVoltage=3;//电池电压,多个电池以下划线分割,如:40_30(单位:V)[注意:如果2块电池电压差大于0.7V,飞机限制起飞]
    BatteryStateInfo firstBatteryInfo=4;//第一块电池状态信息(安装在飞机左边电池槽)
    BatteryStateInfo secondBatteryInfo=5;//第二块电池状态信息(安装在飞机右边电池槽)
}
//电池状态信息
message BatteryStateInfo{
    uint32 isBatteryEmbed=1;//电池插入飞机状态(注意:如果未插入所有电池信息不可用):0=插入,1=未插入
    uint32 batteryCapacityPercent=2;//电池电量百分比
    int32 currentVoltage=3;//电池电压(单位:mV)
    int32 currentElectric=4;//当前电池电流(单位:mA)
    uint32 fullCapacity=5;//满电池容量(单位:mAh)
    uint32 remainedCapacity=6;//剩余电池容量(单位:mAh)
    float batteryTemperature=7;//电池温度(单位:摄氏度)
    uint32 cellCount=8;//电池组数(电池硬件型号有关)
    uint32 batSOHState=9;//电池循环健康状态:0=正常,1=警报,2=注意安全
    uint32 sop=10;//相对功率百分比(Relative power percentage)
    uint32 heatState=11;//电池加热状态:0=未加热,1=加热中,2=保持恒温
    uint32 socState=12;//电池SOC荷电状态: 0=SOC正常,1=SOC_ABNORMAL_HIGH,2=SOC_JUMP_DOWN,3=SOC_JUMP_UP,4=SOC_INVALID
    uint32 selfCheckError=13;//电池自检错误标志(注意:如果此值非0,就是电池损坏需要维修):0=正常,1=电池自检NTC异常,2=电池自检MOS异常,3=电池自检采样电阻异常,4=电池电芯损坏,5=电池未校准,6=电量计参数异常
}
//云台状态
message PtzState{
    float pitch=1;//俯仰角 范围:-120° ~ 30°
    float roll=2;//横滚角 范围:-90° ~ 60°
    float yaw=3;//偏航角  范围:-180° ~ 180°
    uint32 gimbalMode=4;//云台模式 1=自由模式,2=跟随模式,3=FPV模式
}
//相机状态
message CameraState{
    uint32 mode=1;//相机模式:1=拍照模式,2=录像模式,0=未知
    uint32 isRecording=2;//是否录制中:1=录制中,0=未录制
    uint32 recordDuration=3;//录制时长(单位:秒)
    uint32 source=4;//相机视源:0=可见,1=变焦,2=红外
    uint32 camera=5;//相机: 0=FPV,1=相机(1),2=相机(2)
    float  zoomfactor=6;//相机当前变焦倍数
    uint32 width=7;//水平像素(例如:1920)
    uint32 height=8;//垂直像素(例如:1080)
    uint32 frameRate=9;//帧率(例如:30)
    uint32 bitstream=10;//码率(单位:0.001)(例如:6兆设置值为6000)
    uint32 pointThermometrying=11;//单点测温状态:0=非单点测温中,1=单点测温中
    uint32 areaThermometrying=12;//区域测温状态:0=非区域测温中,1=区域测温中
    uint32 laserRanging=13;//激光测距状态:0=非激光测距中,1=激光测距中
}
//任务状态
message MissionState{
    uint32 isPause=1;//航线是否暂停中:0=未暂停,1=暂停中
    uint32 targetWaypointIndex=2;//目标航点下标(说明:开始成功到第一个航点之间此值为0,到达第一个航点此值为1,到达第二个航点此值为2,以此类推,航线结束后此值不清空直到下一次开始航线)
    uint32 isWaypointFinished=3;//是否航点完成:1完成、0未完成(此值废弃)
    uint32 pushVideo=4;//云盒是否发送视频数据:0=不发送,1=发送
    uint32 lock4g=5;//是否锁定4G:0=不锁定,1=锁定
    uint32 boxModel=6;//是否开通图片自动回传功能:0=未开通,1=已开通
    uint32 mapPlay=7;//自动拍照间隔:0未开始,3~255间隔时间
    uint32 loseAction=8;//网络失联后动作:0=返回HOME点,1=继续航线
    uint32 isPointControl=9;//是否打点飞行控制中:0=否,1=是
    uint32 isUwbLanding=10;//是否UWB精准降落中:0=不是,1=是
    uint32 isPushVideoing=11;//视频是否推流中:0=不是,1=是
    uint32 isDLanding=12;//是否二维码精准降落中:0=不是,1=是
    uint32 perceptionFlag=13;//二维码精准降落模式:0=载荷降落,1=下视降落
    uint32 isPositionControl=14;//是否指定距离飞行控制中:0=否,1=是
}
//避障数据
message AvoidanceData{
    uint32 downHealth=1;
    float down=2;//距下障碍物的距离(单位:米),downHealth为1时值有效
    uint32 frontHealth=3;
    float front=4;//距前障碍物的距离(单位:米),frontHealth为1时值有效
    uint32 rightHealth=5;
    float right=6;//距右障碍物的距离(单位:米),rightHealth为1时值有效
    uint32 backHealth=7;
    float back=8;//距后障碍物的距离(单位:米),backHealth为1时值有效
    uint32 leftHealth=9;
    float left=10;//距左障碍物的距离(单位:米),leftHealth为1时值有效
    uint32 upHealth=11;
    float up=12;//距上障碍物的距离(单位:米),upHealth为1时值有效
    uint32 avoidanceEnableStatusDown=13;//下视觉避障开关状态:0-关闭 1-打开
    uint32 avoidanceEnableStatusUp=14;//上视觉避障开关状态:0-关闭 1-打开
    uint32 avoidanceEnableStatusHorizontal=15;//水平视觉避障开关状态:0-关闭 1-打开
}
//Hms报警信息
message HmsAlarmData{
    uint32 alarmId=1;//报警信息ID
    uint32 reportLevel=2;//等级[1/2-警告 3/4/5-错误]
    string alarmMssInfo=3;//报警信息描述(说明:支持中文和英文版本,默认中文,如需切换请联系技术支持)
}
//航线
message PlanLineData{
    uint32 finishedAction=1;//结束航线后动作:1=返航,2=原地悬停,3=原地降落,4=原地绕飞[目前只osdk4.1版本支持,中心点为最后一个航点,飞机绕此点画圆飞行],5=返回至第一个航点并悬停[如果飞机到最后一个点时RC和飞机失联,飞机会在最后一个点悬停]
    float maxSpeed=2;//最大飞行速度(单位:米/秒,范围0~15),默认15
    float autoSpeed=3;//自动飞行速度(单位:米/秒,范围0~15),默认8
    repeated PointData points=4;//坐标点数组
    uint32 loseAction=5;//网络失联后动作:0=返回HOME点,1=继续航线,默认0
    uint32 homeHeight=6;//返航高度:(单位:米,范围20~1500),说明:此值为相对起飞点高度,如果太高会有失去网络覆盖风险。不同飞行器返航逻辑不一样,若飞行器距HOME点距离过近,可能不会升高再返航。具体逻辑请咨询大疆DJI
    uint32 isSaveEnergyMode=7;//是否开启节能模式:0=不是,1=是(说明:节能模式下,飞机沿最短直线距离由起飞点到航线第一个航点,非升高到第一个航点高度再飞往第一个航点)
    HangarPoint takePoint=8;//起飞点机库信息
    HangarPoint landPoint=9;//降落点机库信息
    repeated PointData interests=10;//兴趣点数组(对象只包含经纬高)
    NormalModel normalModel=11;//普通建模
    SurroundModel surroundModel=12;//环绕建模
    PointData takeOffPoint=13;//起飞点(对象只包含经纬高)
}
//航线点
message PointData{
    double lng=1;//经度
    double lat=2;//纬度
    float height=3;//高度(单位:米,范围0~遥控器限高),说明:此值为相对起飞点高度,如果太高会有失去网络覆盖风险
    float speed=4;//速度(单位:米/秒,范围0~15),默认8
    repeated PointAction actions=5;//动作数组
    uint32 flightPathMode=6;//航线飞行模式:1=直线飞行,2=协调转弯,3=曲线飞行(停),4=曲线飞行(不停)
    float dampingDistance=7;//转弯半径(仅协调转弯模式下有效),取值范围1~655.35单位:米,两点间距离要小于此值,此值要根据实际情况计算,切勿随便设此值[可能导致航线开始失败],具体计算方法可以咨询售后支持或者大疆DJI
    uint32 safeGohomeFlag=8;//是否为安全返航点 0=不是,1=是 (暂时未启用)
    uint32 headingMode=9;//偏航模式 0=自动,1=锁定,2=遥控器控制,3=云台依照航点方向旋转,4=朝向兴趣点,5=飞机和云台的偏航同时旋转
    float heading=10;//航点偏航 -180~180
    int32 interestIndex=11;//兴趣点下标,默认-1
    uint32 groupIndex=12;//组下标
}
//航线点动作
message PointAction{
    uint32 type=1;//类型:1.变焦 2.拍照 3.录像 4.停录 5.控制飞机机头偏航 6.控制云台俯仰 7.控制云台偏航 8.控制云台横滚 9.悬停 10.等距间隔拍照 11.等时间隔拍照 12.结束间隔拍照 13.单条喊话 14.开始循环喊话 15.结束循环喊话 16.对焦
    float param=2;//参数:[1.变焦]->变焦倍数(范围:2~200) 、 [5.控制飞机机头偏航(范围:-180~180)、6.控制云台俯仰(范围:-120~30)、7.控制云台偏航(范围:-180~180)、8.控制云台横滚(范围:-90~60)]->角度(按正北坐标系绝对值控制) 、[9.悬停]->时间(单位:秒,范围:1~25,如果想停留大于25秒时长,可以加多组悬停动作) [10.等距间隔拍照]->距离(单位:米,范围:1~100)  [11.等时间隔拍照]->时间(单位:秒,范围:1~30)  [13/14->喊话器俯仰角度,如果此值为0默认改成-90](范围:0~-90)
    int32 waitTime=3;//动作触发后等待时长(单位:秒) [此值如果不需要可以不传,如需悬停可添加类型9悬停动作] [13/14->喊话器声音,如果此值不传默认50](范围:0~100)
    string speakInfo=4;//喊话内容[type=13和type=14时生效]
}
//机库信息
message HangarPoint{
    string hangarId=1;//机库ID
    double hangarLng=2;//机库经度
    double hangarLat=3;//机库纬度
    double alternateLng=4;//备降点经度
    double alternateLat=5;//备降点纬度
}
//普通建模
message NormalModel{
   repeated PointData area=1;//作业区域
   uint32 serviceId=2;//建模平台编号:1=瞰景,2=大势,默认1
   uint32 cameraId=3;//相机编号
   uint32 isModeling=4;//是否实时建模:0=不,1=是
   uint32 mode=5;//作业模式:1=倾斜,2=正摄
   uint32 hOverlap=6;//横向重叠率
   uint32 vOverlap=7;//纵向重叠率
   uint32 mirror=8;//方向正反
}
//环绕建模
message SurroundModel{
   repeated PointData area=1;//作业区域
   uint32 serviceId=2;//建模平台编号:1=瞰景
   uint32 cameraId=3;//相机编号
   uint32 isModeling=4;//是否实时建模:0=不,1=是
}
ard-work/src/main/java/com/ard/tianyu/netty/protobuf/TelemetryDataPB.java
New file
Diff too large
ard-work/src/main/java/com/ard/tianyu/service/ITyService.java
@@ -4,6 +4,7 @@
import com.ard.tianyu.model.dto.BoxPhotosDTO;
import com.ard.tianyu.model.dto.BoxSettingsDTO;
import com.ard.tianyu.model.receiver.*;
import com.ard.tianyu.netty.command.BaseCommand;
import com.dtflys.forest.annotation.Var;
import java.util.List;
@@ -61,4 +62,9 @@
     * 云台转动(基于角度)
     */
    void controlAngle(String boxSn);
    /**
     * 解析天宇服务端发来的消息
     */
    void processMessage(String key, BaseCommand tyMessage);
}
ard-work/src/main/java/com/ard/tianyu/service/impl/TyServiceImpl.java
@@ -6,10 +6,7 @@
import com.ard.tianyu.model.dto.BoxPhotosDTO;
import com.ard.tianyu.model.dto.BoxSettingsDTO;
import com.ard.tianyu.model.receiver.*;
import com.ard.tianyu.netty.command.BaseCommand;
import com.ard.tianyu.netty.command.ControlAngleCommand;
import com.ard.tianyu.netty.command.HeartbeatCommand;
import com.ard.tianyu.netty.command.RegisterCommand;
import com.ard.tianyu.netty.command.*;
import com.ard.tianyu.netty.TyNettyTcpClient;
import com.ard.tianyu.service.ITyService;
import io.netty.buffer.ByteBuf;
@@ -22,6 +19,7 @@
import javax.annotation.Resource;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
/**
@@ -58,8 +56,13 @@
    @Override
    public List<BoxInfoReceiver> getBoxList() {
        //请求云盒列表
        try {
        TyHttpCommonReceiver<List<BoxInfoReceiver>> boxListReveiver = tyClient.getBoxList(tyConfiguration.getAccessToken().convertFromDTO());
        return boxListReveiver.getContent();
        } catch (Exception e) {
            log.error("获取云盒列表失败:{}", e.getMessage());
            return new ArrayList<>();
        }
    }
    /**
@@ -145,6 +148,32 @@
        this.sendMessage(tyConfiguration.getIpPort(), controlAngleCommand);
    }
    @Override
    public void processMessage(String key, BaseCommand tyCommand) {
        byte cmdCode = tyCommand.getCmdCode();
        switch (cmdCode) {
            case 0x01:
                // 处理心跳消息
                log.info("收到心跳消息-->处理心跳消息");
                break;
            case 0x02:
                // 处理注册消息
                HeartbeatReplyCommand heartbeatReplyCommand = (HeartbeatReplyCommand) tyCommand;
                log.info("收到心跳消息-->处理心跳消息{}", heartbeatReplyCommand.getTimestamp());
                break;
            case (byte) 0xA8:
                // 处理无人机状态消息
                log.info("收到无人机状态消息-->无人机状态消息");
                break;
            case (byte) 0xA9:
                // 处理无人机遥测消息
                log.info("收到无人机遥测消息-->无人机遥测消息");
                break;
            default:
                // 处理其他消息
        }
    }
    @Scheduled(fixedRate = 5000)
    public void sendHeartBeat() {
        long timestamp = System.currentTimeMillis();