数据传输
概述
负载设备和无人机使用数据传输模块,在控制命令传输通道上以透传的方式在PSDK和MSDK间传输控制指令。在高速数据传输通道上以透传的方式在PSDK和MSDK间传输数据信息以及用户自定义的数据。使用数据传输功能,不仅可以设置不同类型的数据占用高速数据传输通道带宽的比例,还能够查看不同数据传输通道的状态。
说明: PSDK 的数据传输模块以透传的方式在负载设备、机载计算机和无人机间传输数据,支持用户根据实际的使用需求设计数据传输协议,使基于PSDK 开发的负载设备能够与移动端App 或机载计算机间实现复杂通信。 兼容性说明: 若视频流格式设置为DJI H264 格式,数据流传输功能将无法使用,建议切换到SDK 互联互通功能使用。
基础概念
通道的分类
根据实际传输的数据类型和数据的作用,PSDK 的数据传输通道可分为命令信号传输通道和高速数据传输通道,如 图1.信号传输通道 所示。
- 命令信号传输通道:可靠性强,专用于传输对可靠性要求较高的信号,如控制指令和状态信息等。
- 高速数据传输通道:带宽较大,主要用于传输数据量较大且对实时性要求较高的数据,如雷达信号和点云数据等。
图1.信号传输通道
通道的带宽
- 通道带宽:数据通道在理论状态下可传输的数据量
- 实时带宽:数据通道在工作状态下理论上可传输的数据量
- 实际带宽:数据通道实际传输的数据量
通道带宽限制
数据传输通道的带宽限制,是指在单位时间内,通道最大能够传输的数据量(byte/s)。
受制于接口部件的物理特性和实际的使用环境,命令信号传输通道和高速数据传输通道的带宽可分为静态带宽限制和动态带宽限制。
静态带宽限制
静态带宽限制是指命令信号传输通道固定的带宽大小,受制于材料的物理特性和固有的电气特性而无法被改变,有关数据传输通道静态带宽的详细参数,请参见 表1 静态带宽。
通道类型 | 传输方向 | M30 | M30T | M300 RTK | M350 RTK | 搭配飞行器的 Dock 1 | 搭配飞行器的 Dock 2 |
---|---|---|---|---|---|---|---|
命令信号传输通道 | 移动端App ➟ 负载设备 | 4 KB/s | - | ||||
负载设备 ➟ 移动端App | |||||||
机载计算机 ➟ 负载设备 | |||||||
负载设备 ➟ 机载计算机 | |||||||
负载设备 ➟ 云端服务器 | - | 4 KB/s,最大发送频率为 20 Hz | |||||
云端服务器 ➟ 负载设备 | |||||||
高速数据传输通道 | 负载设备 ➟ 移动端App | - | 4Mbps | - |
动态带宽限制
动态带宽限制是指高速数据传输通道受链路状态和电磁环境等因素的影响,通道最大能够传输的数据量会动态变化,因此,高速数据传输通道的实际带宽应低于实时带宽。
设置带宽占用比例
PSDK 支持用户为不同的数据类型设置高速数据传输通道带宽使用比例,实现对高速数据传输通道带宽占用的精准控制。 某类数据的实际带宽=高速数据传输通道的动态带宽 ✕ 带宽分配比例。
说明: 命令信号传输通道的动态带宽限制等于静态带宽限制。
流量控制
PSDK 的数据传输模块通过使用流量阈值和缓冲区,限制负载设备向移动端App 或机载计算机发送的数据量,实现流量控制功能,如 图2.流量控制 所示。
PSDK 的流量控制过程如下所示:
- 负载设备通过数据通道向机载计算机或移动端App 传输数据信息;
- 当负载设备发送的数据大于流量控制功能的阈值时,流量控制功能将超出流量阈值的数据暂存入缓冲区中;
- 当缓冲区已存满数据时,负载设备发送的超出流量阈值的数据将被丢弃;
- 当数据通道空闲时,流量控制模块将发送暂存在缓冲区的数据。
说明
- 数据传输模块的流量控制周期为 1s,在每个控制周期内,负载设备传输的数据量应小于用户设置的流量阈值。
- 流量阈值决定当前数据传输通道最大可传输的数据,该阈值由静态带宽限制、动态带宽限制及高速数据传输通道的带宽占用比例等因素共同决定。
图2.流量控制
通道状态
使用PSDK 开发的负载设备能够获取到如下信息:
- 信息数据传输通道在用户使用流量控制功能前实际的带宽;
- 信息数据传输通道在用户使用流量控制功能后实际的带宽;
- 通道的繁忙状态:当对应通道的数据被存入缓冲区或被丢弃时,数据传输模块的通道状态为“繁忙”。
使用数据传输功能
使用PSDK 的数据传输功能,需要在创建工程文件并完成PSDK 的初始化后,初始化数据传输模块,设置不同类型的数据占用高速数据传输通道的比例;再实现数据传输功能和监控数据通道状态的功能。
1. 数据传输功能模块初始化
使用“数据传输”功能前,需要使用如下代码初始化数据传输功能模块,确保负载设备能够正常传输数据。
djiStat = DjiLowSpeedDataChannel_Init();
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("init data transmission module error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
2. 设置带宽占用比例
用户通过使用基于MSDK 开发的移动端App 或使用PSDK 开发的无人机控制程序,为不同类型的数据设置高速数据传输通道带宽的占用比例后,使用PSDK 开发的负载设备通过调用DjiHighSpeedDataChannel_SetBandwidthProportion
接口,能够设置如下载视频流等类型的数据占用高速数据传输通道带宽的比例。
djiStat = DjiHighSpeedDataChannel_SetBandwidthProportion(bandwidthProportionOfHighspeedChannel);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Set data channel bandwidth width proportion error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
说明
- 仅Linux 系统支持使用“设置高速数据传输通道带宽占用比例”的功能;
- 未使用流量控制功能时,视频、数据和媒体下载类型的数据占高速数据传输通道带宽的默认比例分别为33%,33%和34%。
3. 实现数据发送功能
使用PSDK 开发的负载设备通过命令信号传输通道和高速数据传输通道向移动端App 或机载计算机发送测试数据。
- 向移动端App 发送控制命令
使用PSDK 开发的负载设备在命令信号传输通道上向移动端App 发送控制命令。
channelAddress = DJI_CHANNEL_ADDRESS_MASTER_RC_APP;
djiStat = DjiLowSpeedDataChannel_SendData(channelAddress, dataToBeSent, sizeof(dataToBeSent));
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS)
USER_LOG_ERROR("send data to mobile error.");
移动端App 接收负载设备通过命令信号传输通道发送的控制命令,如 图3.APP 数据接收(1) 所示。
图3.移动端App 数据接收(1)
- 向移动端App 发送数据信息
使用PSDK 开发的负载设备在高速数据传输通道上向移动端App 发送数据信息。
djiStat = DjiHighSpeedDataChannel_SendDataStreamData(dataToBeSent, sizeof(dataToBeSent));
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS)
USER_LOG_ERROR("send data to data stream error.");
移动端App 接收负载设备通过高速数据传输通道发送的数据信息,如 图4. 移动端App 数据接收(2) 所示。
图4. 移动端App 数据接收(2)
- 向机载计算机发送控制命令
使用PSDK 开发的负载设备在命令信号传输通道上向机载计算机发送控制命令。
djiStat = DjiLowSpeedDataChannel_SendData(channelAddress, dataToBeSent, sizeof(dataToBeSent));
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS)
USER_LOG_ERROR("send data to onboard computer error.");
机载计算机接收负载设备通过命令信号传输通道发送的控制命令,如 图5.机载计算机数据接收 所示。
图5. 机载计算机数据接收
4. 实现数据接收功能
构造并注册数据接收函数后,使用PSDK 开发的负载设备能够通过命令信号传输通道接收从移动端设备和机载计算机发送的控制命令。
4.1 构造回调函数
构造回调函数获取并打印从移动端App 和机载计算机上发送的控制命令。
static T_DjiReturnCode ReceiveDataFromMobile(const uint8_t *data, uint16_t len)
{
char *printData = NULL;
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
printData = osalHandler->Malloc(len + 1);
if (printData == NULL) {
USER_LOG_ERROR("malloc memory for printData fail.");
return DJI_ERROR_SYSTEM_MODULE_CODE_MEMORY_ALLOC_FAILED;
}
strncpy(printData, (const char *) data, len);
printData[len] = '\0';
USER_LOG_INFO("receive data from mobile: %s, len:%d.", printData, len);
DjiTest_WidgetLogAppend("receive data: %s, len:%d.", printData, len);
osalHandler->Free(printData);
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
static T_DjiReturnCode ReceiveDataFromOnboardComputer(const uint8_t *data, uint16_t len)
{
char *printData = NULL;
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
printData = osalHandler->Malloc(len + 1);
if (printData == NULL) {
USER_LOG_ERROR("malloc memory for printData fail.");
return DJI_ERROR_SYSTEM_MODULE_CODE_MEMORY_ALLOC_FAILED;
}
strncpy(printData, (const char *) data, len);
printData[len] = '\0';
USER_LOG_INFO("receive data from onboard computer: %s, len:%d.", printData, len);
DjiTest_WidgetLogAppend("receive data: %s, len:%d.", printData, len);
osalHandler->Free(printData);
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
4.2 注册回调函数
通过注册回调函数,负载设备能够接收从移动端App 和机载计算机发送的控制命令。
channelAddress = DJI_CHANNEL_ADDRESS_MASTER_RC_APP;
djiStat = DjiLowSpeedDataChannel_RegRecvDataCallback(channelAddress, ReceiveDataFromMobile);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("register receive data from mobile error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
if (s_aircraftInfoBaseInfo.mountPosition == DJI_MOUNT_POSITION_PAYLOAD_PORT_NO1 ||
s_aircraftInfoBaseInfo.mountPosition == DJI_MOUNT_POSITION_PAYLOAD_PORT_NO2 ||
s_aircraftInfoBaseInfo.mountPosition == DJI_MOUNT_POSITION_PAYLOAD_PORT_NO3) {
channelAddress = DJI_CHANNEL_ADDRESS_EXTENSION_PORT;
djiStat = DjiLowSpeedDataChannel_RegRecvDataCallback(channelAddress, ReceiveDataFromOnboardComputer);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("register receive data from onboard coputer error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
djiStat = DjiHighSpeedDataChannel_SetBandwidthProportion(bandwidthProportionOfHighspeedChannel);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Set data channel bandwidth width proportion error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
djiStat = DjiHighSpeedDataChannel_GetDataStreamRemoteAddress(ipAddr, &port);
if (djiStat == DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_DEBUG("Get data stream remote address: %s, port: %d", ipAddr, port);
} else {
USER_LOG_ERROR("get data stream remote address error.");
}
} else if (s_aircraftInfoBaseInfo.mountPosition == DJI_MOUNT_POSITION_EXTENSION_PORT) {
channelAddress = DJI_CHANNEL_ADDRESS_PAYLOAD_PORT_NO1;
djiStat = DjiLowSpeedDataChannel_RegRecvDataCallback(channelAddress, ReceiveDataFromPayload);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("register receive data from payload NO1 error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
} else {
return DJI_ERROR_SYSTEM_MODULE_CODE_NONSUPPORT;
}
负载设备接收移动端App 和机载计算机从命令信号传输通道发送的测试数据,如 图6.负载设备数据接收 所示。
图6.负载设备数据接收
5. 监控数据传输通道的状态
在数据传输线程中获取数据通道的状态并打印到终端。
- 获取命令信号传输通道的状态信息
获取负载设备向移动端App 和机载计算机发送控制命令的命令信号传输通道的状态。
djiStat = DjiLowSpeedDataChannel_GetSendDataState(channelAddress, &state);
if (djiStat == DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_DEBUG(
"send to onboard computer state: realtimeBandwidthBeforeFlowController: %d, realtimeBandwidthAfterFlowController: %d, busyState: %d.",
state.realtimeBandwidthBeforeFlowController, state.realtimeBandwidthAfterFlowController,
state.busyState);
} else {
USER_LOG_ERROR("get send to onboard computer channel state error.");
}
- 获取高速数据传输通道的状态信息
说明: 仅基于Linux 开发的负载设备能获取高速数据传输通道的状态信息。
djiStat = DjiHighSpeedDataChannel_GetDataStreamState(&state);
if (djiStat == DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_DEBUG(
"data stream state: realtimeBandwidthLimit: %d, realtimeBandwidthBeforeFlowController: %d, busyState: %d.",
state.realtimeBandwidthLimit, state.realtimeBandwidthBeforeFlowController, state.busyState);
} else {
USER_LOG_ERROR("get data stream state error.");
}
高速数据传输通道状态如 图7.数据传输 所示。
说明: 实时带宽统计周期为 1s。
图7.数据传输