技术研究之大疆机场

标签: 无 分类: 未分类 创建时间:2023-12-09 07:55:45 更新时间:2024-11-15 10:49:44

1.前言

  • 在大疆开发者网站注册成为开发者(https://developer.dji.com/cn/user/apps/#all)
  • 在大疆开发者网站创建应用,拿到API交互所需的APP ID、APP 秘钥、APP License
  • 将官方Sample 跑起来:用来学习和理解(github地址:https://github.com/dji-sdk/Cloud-API-Demo-Web,https://github.com/dji-sdk/ DJI-Cloud-API-Demo)
  • 开发三方云平台(登录页面;http服务;mqtt服务;推拉流服务等)
  • 在pilot中配置第三方云平台登录地址,并登录,token会存储到pilot中
  • 在pilot中配置其它第三方云平台的信息
  • pilot和第三方云进行数据的传输和业务功能的处理;dock和第三方云进行数据的传输和业务功能的处理
  • pilot程序退出或者飞机下线,断开和第三方云的链接
  • 目前一个机场只能用一个飞机,当飞机下线后,dock和三方云平台的链接也将终止
参考文章:
【1】.大疆机场的那些问题,你都知道多少?
【2】.产品支持 通过 domain、type、sub_type 可以唯一地确定一款设备(可以为飞行器、负载、遥控器等)。
【3】.简述大疆无人机对接 上面的开发步骤基本上就是这个样子的。

2.机场上云

暂无设备,请使用USB数据线连接遥控器和机场后,Pilot 2自动进入机场部署流程,在云服务配置-司空2 绑定设备。根据我查看上云的视频展示,主要有几个步骤
(1)使用usb连接机场版手柄,然后进行自动配对,飞机对频和网络连接。

(2)配置好远程服务器的
在机场上云这个后端代码中,需要监听 thing/product/+/requests

  • MQTT 服务器地址,
  • 用户名
  • 密码:最好和绑定移动飞机的时候一个样,
  • 组织id:这里没有特别的说明,好像是可以随便填,
  • 绑定码:我查看了数据库,在 manage_workspace 中标的是 qwe
  • 机场的名称:这个没有特别的说明
  • 飞机的名称:这个也没有特别的说明

(3)配置好之后,就会显示设备已经绑定第三方云服务

参考文章:
【1】. Demo示例是否适用于对接大疆机场
【2】.上云API对接大疆机场开发板
【3】.机场上云
【4】.组织管理 这里有topic:thing/product/{gateway_sn}/requests,就是要配置request的东西。

3.执行航线

waylines.wpml是飞机直接执行的文件,它定义了明确的无人机飞行和负载动作指令,这些指令由 DJI Pilot 2、DJI Flighthub 2 或者其它软件生成,也可被开发者直接编辑开发。WPML 航线文件的字段介绍如下:

  • 仅用于 template.kml 文件的字段在template.kml
  • 仅用于 waylines.wpml 文件的字段在waylines.wpml 说明
  • template.kml 文件与 waylines.wpml 文件共用的字段在共用元素信息

在司空2上可以编辑航点动作和航线,然后导出 kmz 文件。kmz 文件其实是一个压缩文件,可以使用 WinRAR 文件打开,里面包含了两个文件,一个是 template.kml 一个是 waylines.wpml 文件。

参考文章:
1.怎么打开KMZ文件
2.waylines.wpml 说明 这是大疆官方对 wpml 文件的说明。

问题

1.视频录像和停止录像怎么会在指令飞行中呢?

答:当前协议的呈现为 按照 topic 类型(event、service等)划分的,不是按照功能模块划分的,后续有优化的计划

2.录像存储的位置在哪里呢?怎么读取和上传呢?

答:录像存储在无人机中,存储的位置是无人机中事先规定好的照片存储位置。无人机中sd卡存储位置上云API无法进行获取与设置。视频录像和停止录像只对机场上云生效,机场会向云端请求媒体文件上传临时凭证,拿到临时凭证后,机场会上传到云端指定的对象存储中。注意:无人机必须在空中执行的录像才会上传到云端。

3.STS service failed with HTTP status code 403

我用自定义的minio作为存储的时候,总是出现这个问题。

参考文章:
【1】.STS service failed with HTTP status code 403
【2】.HTTP status code 400 这里列举了一些常见的错误:InvalidBucketName、InvalidObjectName 等。

4.机场 314013

在执行机场任务的时候,发现报错 314013, 这个显示的就是:飞行任务下发失败,机场无法获取到本次飞行任务的航线,无法执行飞行任务,请稍后重试

【尝试方案】
1.检查机场和飞机的固件版本是否配套,具体配套版本可以查看机场的发布记录或者上云API 版本的发布记录。
2.检查下发任务中的 url 是否正确,在浏览器中输入该url,需要能够自动触发下载。
3.检查机场网络是否能够访问该下发任务中的url。
4.检查云端服务是否正常回复了机场请求的任务资源获取接口。

5.我还是尝试了重写 AbstractWaylineService 接口中的 flighttaskResourceGet,后来我发现原来在 SDKWaylineService 已经实现了相关的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
@Override
public TopicRequestsResponse<MqttReply<FlighttaskResourceGetResponse>> flighttaskResourceGet(TopicRequestsRequest<FlighttaskResourceGetRequest> response, MessageHeaders headers) {
String jobId = response.getData().getFlightId();

Optional<DeviceDTO> deviceOpt = deviceRedisService.getDeviceOnline(response.getGateway());
if (deviceOpt.isEmpty()) {
log.error("设备已离线,请稍后重试");
return new TopicRequestsResponse().setData(MqttReply.error(CommonErrorEnum.DEVICE_OFFLINE));
}
Optional<WaylineJobDTO> waylineJobOpt = waylineJobService.getJobByJobId(deviceOpt.get().getWorkspaceId(), jobId);
if (waylineJobOpt.isEmpty()) {
log.error("航线任务不存在");
return new TopicRequestsResponse().setData(MqttReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT));
}

WaylineJobDTO waylineJob = waylineJobOpt.get();

// get wayline file
Optional<GetWaylineListResponse> waylineFile = waylineFileService.getWaylineByWaylineId(waylineJob.getWorkspaceId(), waylineJob.getFileId());
if (waylineFile.isEmpty()) {
log.error("航线文件不存在");
return new TopicRequestsResponse().setData(MqttReply.error(CommonErrorEnum.ILLEGAL_ARGUMENT));
}
// get file url
try {
URL url = waylineFileService.getObjectUrl(waylineJob.getWorkspaceId(), waylineFile.get().getId());
log.error("航线文件地址:"+url);
TopicRequestsResponse<MqttReply<FlighttaskResourceGetResponse>> waylineResponse=new TopicRequestsResponse<>();
log.info("创建响应", JSONObject.toJSONString(waylineResponse));
waylineResponse.setData(MqttReply.success(new FlighttaskResourceGetResponse()
.setFile(new FlighttaskFile()
.setUrl(url.toString())
.setFingerprint(waylineFile.get().getSign()))));

log.info("获取航线文件接口返回的内容:{} ", JSONObject.toJSONString(waylineResponse));

return waylineResponse;
} catch (SQLException | NullPointerException e) {
e.printStackTrace();
log.error("获取航线任务出错",e);
return new TopicRequestsResponse().setData(MqttReply.error(CommonErrorEnum.SYSTEM_ERROR));
}
}

【解决方案】
我部署到服务器上的时候,就是无法获取航线文件,但是后来我在本地测试的时候,竟然可以获取航线文件了,也就可以正常的执行航线了。 基本的逻辑其实就是实现 thing/product/{gateway_sn}/requests 消息,但是如果同时部署两套系统,那么因为大家共用一个后端,就会导致有些可能是提前响应这个消息,但是这个时候获取到的资源也可能不存在。

参考文章:
【1】.上云API与大疆机场 执行任务 错误码:314013
【2】.错误码 这里是错误码的说明
【3】.机场下发航线任务时,报错314013 或者314004的解决方案 这里有几个尝试的方法,主要就是:检查云端服务是否正常回复了机场请求的任务资源获取接口、检查机场网络是否能够访问该下发任务中的url
【4】.机场航线任务一定会请求云端任务资源获取的接口吗? 会,不论下发任务(flighttask_prepare)中的文件url能够获取资源地址,机场一定会请求云端任务资源获取(flighttask_resource_get)获取资源。

5.负载控制-画面拖动控制

画面拖动控制,下发一次指令,云台动一次。如果想要实现持续控制,发送频率需要保证在0.3s/ 次。经过我尝试,因为给定的接口没有这个部分,我参考了相关的代码,最后还是搞定了这个东西。

参考文章:
【1】.负载控制-画面拖动控制
【2】.无人机小知识:Pitch Yaw Roll的经典解释 1.Pitch是围绕Y轴旋转,也叫做俯仰角。2.Yaw是围绕Z轴旋转,也叫偏航角。3.Roll是围绕X轴旋转,也叫翻滚角。
【3】.负载控制-分屏报错325003的解决方案

6.The 4G transmission of the aircraft fails to be enabled, and the 4G transmission cannot establish a connection. Please check the 4G signal strength, or consult the operator to check the package traffic and APN settings.

这个问题出现在我给无人机机场开启 4G 图传的时候,就是这个问题。 后来不知道怎么搞的,有些地方就可以直接开启。

参考文章:
【1】.4G增强模块

7.负载控制-缩放

8.负载控制-分屏

分屏控制,要在镜头处于红外相机的情况下才能有用,否则就会报错 325003:设备端命令响应错误,请重试。

参考文章:
【1】.负载控制-分屏 这个功能需要在使用红外镜头的情况下才能下发。
【2】.「负载控制—分屏」用途是什么? 分屏一边是红外画面一边是普通画面。 需要在使用红外镜头的情况下才能下发该指令

9.红外相机

切换红外相机之后,默认看到的就是黑白的颜色,问了官方回复,说是可以通过MQTT的 thermal_current_palette_style 字段设置调色板类型。通过 Topic:thing/product/{gateway_sn}/property/set 这个接口,设置相机的属性。

主要属性包括:{“0”:”白热”,”1”:”黑热”,”2”:”描红”,”3”:”医疗”,”5”:”彩虹 1”,”6”:”铁红”,”8”:”北极”,”11”:”熔岩”,”12”:”热铁”,”13”:”彩虹 2”}

在设置的时候,需要注意先把相机模式切换到红外模式,才能进行设置。

10.电池运行模式切换

  • 1.计划模式
    电池以较低电量存储(55% 至 60%),电池使用寿命较长,适合巡检等规律作业场景。电池电量可能较低,此时如果立即起飞,作业途中可能导致提前触发智能低电量返航 。

  • 2.待命模式
    电池以较高电量存储(85% 至 90%),起飞时电池电量较高,适合消防等应急作业场景.电池一直保持高电量存储状态,使用寿命将受影响。若无应急起飞的需求,推荐选择计划模式。

参考文章:
【1】.电池运行模式切换
【2】.用户手册

11.文件传输

参考文章:
【1】.大疆机场媒体文件回传的逻辑是什么? 1. 传输文件过程中,若有新的飞行任务,将中断传输,待结束任务后继续传输;2. 使用 4G 图传时,也需要飞行器降落后再传输,不支持飞行实时传输文件;3. 从飞行器传输到机场传输速度大概 3-4Mbps ,从机场上传到云端主要看网速情况。

11.问题

(1)2024-03-29 17:24:23.888 ERROR 27897 — [pool-3-thread-1] o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessageHandlingException: error occurred in message handler [ServiceActivator for [org.springframework.integration.handler.LambdaMessageProcessor@557ed49a] (osdRouterFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#1)]; nested exception is java.lang.IllegalArgumentException: Cannot construct instance of com.dji.sdk.cloudapi.control.LensStorageSettingsEnum, problem: com.dji.sdk.cloudapi.control.LensStorageSettingsEnum has unknown data: [vision]

在示例代码中,osdRouterFlow 函数中,有一个数据转换的地方,这里出现了一个 vision 属性无法识别,而且定位到了com.dji.sdk.cloudapi.control.LensStorageSettingsEnum has unknown data 这里。

参考文章:
【1】.M3D/M3TD 设备属性 这里有一个 cameras 属性,里面有一个 video_storage_settings 属性:视频存储设置集合,取值范围{current, vision, ir}。

(2)uom_real_name_state 属性
我在用大疆的后台接口的时候,总是报这个错误,后来我就求证了大疆的开发人员,他说:“我们与相关同事进行了确认,uom_real_name_state 属性暂未对外开放,您当前可以忽略该属性。” 回复的时间是 2024年04月03日

参考文章:
【1】.uom_real_name_state 是一个什么属性? 忽略这个属性就好了。

(3)problem: com.dji.sdk.cloudapi.debug.RemoteDebugStepKeyEnum has unknown data: [close_drone]

(4)RECV_VIDEO_DECODE_FAILED_RECOVER
这个是编解码问题。

(5)无人机无法关机
每次飞行任务完成之后,回到机舱之后,点击关闭无人机,命令执行成功了,但是过一会无人机就会自动开机,这个问题很不理解。后来官方给出的解释是:无人机的媒体文件没有拉取完成,无人机会自动开机,并继续媒体文件拉取。

【解决方案】
请订阅任务进度上报的消息,并检查关机时是否有报错。

1
2
3
Topic: thing/product/{gateway_sn}/events
Direction: up
Method: drone_close
参考文章:
【1】.机场无法关闭无人机

(6)错误码:211001
直播开启的时候,总是出现这个211001错误,但是在官方错误码的表格里面却没有这个东西。

我用的是声网的直播,在项目部署到服务器上之后,消息就可以正常的发出来了,但是在测试的时候,就是死活不行。

  • 检查前端配置文件中 rtmp 的参数是否为流媒体服务器地址。

  • 由于网页无法直接播放rtmp 流,所以需要将rtmp 流转换为 webrtc流进行播放。官方测试的流媒体服务器中做了流的转换,所以 demo 中没有做流的处理,需要第三方自己做处理。

  • 检查遥控器以及电脑的网络和流媒体服务的网络是否联通。

  • 检查发起直播的参数是否正确,遥控器是否回复启动直播成功的消息。

我在思考的一个问题那就是,为什么在有些程序中,这个 mqtt 消息就可以正常的接收,但是在另外的一些程序中就无法正常接收。

(7)Cannot deserialize value of type int from String “On the wayline segment”: not a valid int value at [Source: (byte[])”
这个错误是在写代码的时候出现的问题,主要就是测试代码中的bug问题,这个

1
2
3
4
5
6
7
8
public int getState() {
return state;
}
// 错误代码
@JsonValue
public String getMsg() {
return msg;
}

实际上这个 @JsonValue 应该标注在 getState 上,而不是其他的地方。包括 FlighttaskBreakReasonEnum 类中的 @JsonValue,应该标注在 getReason 上,而不是 getMsg 上。

(8) Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method ‘drcUpRouterFlow’ threw exception with message: org/springframework/integration/transformer/GenericTransformer

这个问题就特别的奇怪,就是无法实例化一个 IntegrationFlow ,

(7)大疆机场的示例代码集成 jeecgboot
这个也是我突发奇想的事情,就是为了代码编写方便,很多的功能已经有了,于是就想要要把两者捏合到一起,可是奈何自己的水平太低了,就算是把代码捏合到一起,也是废了我很长时间,很大的功夫。我主要用了 jeecgboot 的springboot3 版本的。

  • 创建父模块 drone
    创建父模块,然后修改 pom.xml,增加一些依赖。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <dependency>
    <groupId>org.jeecgframework.boot</groupId>
    <artifactId>jeecg-boot-base-core</artifactId>
    </dependency>

    <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    </dependency>


    <dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.1</version>
    </dependency>


    <dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
    </dependency>
  • 创建子模块
    将 sample 和 cloud-sdk 作为子模块 添加到父模块 drone 中,讲 cloud-sdk 中的依赖都删掉,将 sample 模块中的 一些依赖也都删掉 spring-boot-starter-test、mybatis-plus-boot-starter、mysql-connector-java、spring-boot-starter-web

  • 删除冲突的bean
    因为要是使用 jeecgboot 的框架,那么一些 springboot 的配置就已经有了,所以需要单独的处理下,要不就会导致Bean名称冲突,系统起不来。删除或者改造下面的一些文件:CorsFilter、MybatisPlusConfiguration、RedisConfiguration、OssConfiguration、SpringBeanConfiguration,运行的时候搞不定再说也可以

  • 修改启动类
    为了完成 bean 自动扫描,所以需要修改启动类,增加如下的配置。

    1
    2
    3
    @ComponentScan(basePackages = {"com.dji.*","org.jeecg.*"})
    @MapperScan(basePackages = {"com.dji.sample.*.dao"})
    @EnableScheduling
  • 修改配置文件
    为了将 mqtt 的配置文件引入,需要在 application-dev.yml 中引入配置

    1
    2
    3
    spring:
    config:
    import: classpath:application-drone-dev.yml

(8)DRC link is refused
执行航线任务的时候,出现了这个 514304,以前是好好的,现在就出现了这个问题,到底什么问题呢?

【解决方案】
我的原因是因为emqx的ssl证书过期了,重新换一个就可以了。

参考文章:
【1】.进入指令飞行控制drc模式报错514304 检查下发进入指令飞行控制的参数是否准确,可以使用mqtt客户端校验是否能连接上mqtt服务器
【2】.514304问题 大概率会是网络问题:目前DRC和普通MQTT是共用一条链路的,而DRC连接的网络质量要求比较高,且超时时间短,不会反复重试,很容易失败,所以使用DRC需要保证网络稳定
小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。