4.DJI-PSDK云台x-port控制:
DJI-PSDK云台x-port控制:
X-Port 功能控制,即控制 X-Port 云台,头文件为 dji_xport.h
使用PSDK 的“云台控制”功能,开发者需要先设计负载设备的云台并开发出控制云台的程序,将云台的控制函数注册到PSDK 指定的接口后,用户通过使用DJI Pilot、基于MSDK 开发的移动端App 及遥控器即可控制基于PSDK 开发的具有云台功能的负载设备,同时获得负载设备的相关信息,如姿态等。
参考文章:
https://developer.dji.com/doc/payload-sdk-tutorial/cn/function-set/advanced-function/x-port-function.html
https://developer.dji.com/doc/payload-sdk-tutorial/cn/function-set/basic-function/gimbal-function.html
https://developer.dji.com/doc/payload-sdk-api-reference/cn/practice/xport.html#10
1.基础概念:
1.1:云台关节和云台关节角:
云台的关节如 图1.云台关节 所示,云台关节是云台上带动负载设备转动的结构件:云台电机,云台关节角即云台电机转动的角度。本教程使用机体坐标系描述云台的关节角。
1.2:云台姿态和云台姿态角:
云台的姿态如 图2.云台姿态 所示,根据用户的控制指令,云台能够调整姿态;云台姿态角即使用大地坐标系(NED,北东地坐标系)描述云台上负载设备的角度,该角度也称为欧拉角。
2. xport云台模式:
云台模式决定了云台跟随无人机运动时的转动方式:
自由模式:当无人机的姿态改变时,云台将不会转动。
FPV 模式:当无人机的姿态发生改变时,云台会转动航向轴与横滚轴,确保负载设备当前的视场角不会发生改变。
YAW 跟随模式:在该模式下,云台的航向轴会跟随无人机的航向轴转动。
typedef enum {DJI_GIMBAL_MODE_FREE = 0, /*!< Free mode, fix gimbal attitude in the ground coordinate, ignoring movement of aircraft. */DJI_GIMBAL_MODE_FPV = 1, /*!< FPV (First Person View) mode, only control roll and yaw angle of gimbal in the ground coordinate to follow aircraft. */DJI_GIMBAL_MODE_YAW_FOLLOW = 2, /*!< Yaw follow mode, only control yaw angle of gimbal in the ground coordinate to follow aircraft. */
} E_DjiGimbalMode;
//设置云台飞行模式,自由模式/FPV模式/yaw模式djiStat = DjiXPort_SetGimbalModeSync(DJI_GIMBAL_MODE_FREE);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("set XPort gimbal mode error: 0x%08llX.", djiStat);return djiStat;}
3. 云台限位角及控制权限说明:
4.云台复位:
云台复位接口参数结构体:
typedef enum {/*! 仅重置云台的偏航轴。将偏航轴的角度重置为飞行器的偏航角与云台的微调偏航角之和。 */DJI_GIMBAL_RESET_MODE_YAW = 1,/*! 重置云台的偏航轴和俯仰轴。将偏航轴的角度重置为飞行器的偏航角与云台的微调偏航角之和,并将俯仰轴的角度重置为微调角度。 */DJI_GIMBAL_RESET_MODE_PITCH_AND_YAW = 3,/*! 仅重置云台的俯仰轴。 */DJI_GIMBAL_RESET_MODE_PITCH_ONLY = 4,/*! 仅重置云台的滚转轴。 */DJI_GIMBAL_RESET_MODE_ROLL_ONLY = 5,/*! 仅重置云台的偏航轴。 */DJI_GIMBAL_RESET_MODE_YAW_ONLY = 6,/*! 重置云台的偏航轴和俯仰轴。将偏航轴的角度重置为飞行器的偏航角与云台的微调偏航角之和,并且如果云台向下,则将俯仰轴的角度重置为-90度与微调角度之和;如果向上,则重置为90度与微调角度之和。 */DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD_AND_YAW = 11,/*! 重置云台的俯仰轴。如果云台向下,则将俯仰轴的角度重置为-90度与微调角度之和;如果向上,则重置为90度与微调角度之和。 */DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD = 12,
} E_DjiGimbalResetMode;
使用:
//以阻塞的方式控制X-Port 复位(大地坐标系)。// djiStat = DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_AND_YAW);djiStat = DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD);// DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD_AND_YAWif (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("reset XPort gimbal error: 0x%08llX.", djiStat);return djiStat;}
5.云台旋转控制:
接口说明:
T_DjiReturnCode DjiXPort_RotateSync(E_DjiGimbalRotationMode rotationMode,T_DjiGimbalRotationProperty rotationProperty, T_DjiAttitude3d rotationValue);
参数:
rotationMode:X-Port 的控制方式
rotationProperty:X-Port 旋转命令的属性
rotationValue:云台转动命令的值,当X-Port 的转动模式为 PSDK_GIMBAL_ROTATION_MODE_RELATIVE_ANGLE 或 PSDK_GIMBAL_ROTATION_MODE_ABSOLUTE_ANGLE 时,单位为0.1°;当X-Port 的转动模式为PSDK_GIMBAL_ROTATION_MODE_SPEED 时,单位为0.1°/s
返回值
根据程序执行的情况输出对应的返回值,详情请参见:DjiErrorCode
typedef enum {DJI_GIMBAL_ROTATION_MODE_RELATIVE_ANGLE = 0, /*!< 相对角度旋转模式,表示基于当前角度旋转云台指定的角度。 */DJI_GIMBAL_ROTATION_MODE_ABSOLUTE_ANGLE = 1, /*!< 绝对角度旋转模式,表示将云台旋转到地面坐标系中的指定角度。 */DJI_GIMBAL_ROTATION_MODE_SPEED = 2, /*!< 速度旋转模式,指定云台在地面坐标系中的旋转速度。 */
} E_DjiGimbalRotationMode;
相对角度旋转模式:在此模式下,云台将根据其当前的角度进行旋转。即,如果当前偏航角为30度,用户指定旋转10度,云台将转到40度。这种模式适用于希望基于当前状态进行增量调整的场景。
绝对角度旋转模式:此模式下,云台将旋转到地面坐标系中指定的绝对角度。例如,用户设定云台的偏航角为90度,无论其当前角度如何,云台都会调整到90度位置。这种模式非常适合需要精确定位的应用。
速度旋转模式:在此模式中,用户可以指定云台的旋转速度。与具体的角度无关,此模式下云台会以设定的速度进行旋转,这对于需要快速调整拍摄角度的场景非常有用,比如:遥控手柄
typedef struct {struct {bool pitch; /*!< 指定是否忽略俯仰轴的旋转命令,true 表示忽略。 */bool roll; /*!< 指定是否忽略滚转轴的旋转命令,true 表示忽略。 */bool yaw; /*!< 指定是否忽略偏航轴的旋转命令,true 表示忽略。 */} rotationValueInvalidFlag; /*!< 指定是否忽略某些轴的旋转命令,包括俯仰、滚转和偏航。 */union {struct {uint16_t actionTime; /*!< 在目标角度之间移动的动作时间,单位:0.01秒。 */} relativeAngleRotation; /*!< 相对角度旋转命令的属性。 */struct {uint16_t actionTime; /*!< 在目标角度之间移动的动作时间,单位:0.01秒。 *//*! 联动角度有效标志,指定在绝对角度控制时* T_DjiGimbalRotationProperty::absoluteAngleRotation::jointAngle 是否有效。 */bool jointAngleValid;/*! 云台的联动角度,单位:0.1度。如果* T_DjiGimbalRotationProperty::absoluteAngleRotation::jointAngleValid 为 false,则此处指定的联动角度无效,请忽略联动角度。如果联动角度有效,用户应确保* 云台的目标联动角度与指定值大致相同。 */T_DjiAttitude3d jointAngle;} absoluteAngleRotation; /*!< 绝对角度旋转命令的属性。 */};
} T_DjiGimbalRotationProperty;
rotationValueInvalidFlag: 每个布尔值表明是否忽略该轴的旋转命令:
relativeAngleRotation:含相对角度旋转命令的属性:actionTime: 表示在目标角度之间移动的时间,单位为 0.01 秒。例如,如果 actionTime 为 100,则表示移动时间为 1 秒。
absoluteAngleRotation:包含绝对角度旋转命令的属性:actionTime: 同样表示在目标角度之间移动的时间,单位为 0.01 秒。
jointAngleValid: 指定联动角度(即多个轴的联合运动)是否有效。如果为 true,则联动角度有效;如果为 false,则忽略该角度。
jointAngle: 表示云台的联动角度,单位为 0.1 度。如果 jointAngleValid 为 false,则此角度无效。用户在使用时应确保目标联动角度与指定值大致相同,以避免不必要的误差。
typedef struct {int32_t pitch; /*!< 指定俯仰角的 int32 值。 */int32_t roll; /*!< 指定滚转角的 int32 值。 */int32_t yaw; /*!< 指定偏航角的 int32 值。 */
} T_DjiAttitude3d;
T_DjiAttitude3d 结构体是用于表示三维空间中云台姿态的一个数据结构,其中包含俯仰、滚转和偏航三个角度的值。该结构体可以用于需要精确控制云台方向和姿态的应用场景,如无人机的相机稳定器、航拍设备等。通过设置这三个角度,用户可以实现对云台的准确定位和调整。
以阻塞的方式转动X-Port。
说明:
该接口执行的最大时间可能会大于600ms; 在PSDK_GIMBAL_ROTATION_MODE_RELATIVE_ANGLE
或PSDK_GIMBAL_ROTATION_MODE_ABSOLUTE_ANGLE 模式下,偏航轴的转动范围为[-1800,
1800]。X-Port 转动角度的符号不决定X-Port 旋转的方向; X-Port 可到达的角度主要受X-Port
转动角度的限制和限位缓冲区的影响; X-Port 安装在无人机顶部时,可转动的角度范围与安装在无人机下置云台架上的范围可能会有较大的差异;
当X-Port 超出限位角角度时,X-Port 将会返回错误值,或停留在限位缓冲区内; X-Port
转动的速度和转动区间受最大转动速度和最大加速度的限制;X-Port 转动的最大加速度受云台转动平滑度的限制;X-Port
转动的最大速度受X-Port
默认最大速度(90°/s)和最大速度百分比的限制详情请参见:SetControllerSmoothFactor() 和
SetControllerMaxSpeedPercentage() ; PSDK 仅支持开发者控制X-Port 的俯仰轴和偏航轴;
为防止中断X-Port 的旋转,X-Port 在控制参数自动调整、同轴度检测过程、平衡检测和重置的过程中不会响应用户发送的旋转命令;
X-Port 的有效控制时间为500ms,若X-Port 在500ms 内未收到转动命令,X-Port 将无法转动。
6. 案例:实现云台画圈方案:
示例代码参考如下:
payload_xport.h:
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef TEST_XPORT_H
#define TEST_XPORT_H/* Includes ------------------------------------------------------------------*/
#include "dji_typedef.h"
#include "dji_xport.h"#ifdef __cplusplus
extern "C" {
#endif/* Exported constants --------------------------------------------------------*//* Exported types ------------------------------------------------------------*//* Exported functions --------------------------------------------------------*/
T_DjiReturnCode DjiTest_XPortStartService(void);
T_DjiReturnCode DjiTest_XPortDeInit(void);
T_DjiReturnCode DjiTest_XPortGetSystemState(T_DjiGimbalSystemState *systemState);T_DjiReturnCode DjiXPort_ResetGimbal(void);
#ifdef __cplusplus
}
#endif#endif // TEST_XPORT_H/************************ (C) COPYRIGHT DJI Innovations *******END OF FILE******/
payload_xport.c:
/* Includes ------------------------------------------------------------------*/
#include <dji_gimbal.h>
#include "payload_xport.h"
#include "dji_logger.h"
#include "dji_platform.h"
#include "utils/util_misc.h"
#include "dji_aircraft_info.h"
#include "psdk_gimbal.h"
#include "subscription.h"
// #include "camera_emu/test_payload_cam_emu_base.h"
#include <math.h> // 加入 math.h#ifndef M_PI
#define M_PI 3.14159265358979323846 // 定义 M_PI
#define RADIUS 300 // 定义圆的半径
#define CIRCLE_POINTS 10 // 圆的分割点数量
#endif/* Private constants ---------------------------------------------------------*/
#define XPORT_TASK_FREQ (10) //设置xport任务频率,每s执行10次
#define XPORT_TASK_STACK_SIZE (2048) //为任务分配2048字节的栈空间extern dji_f32_t height; // 声明在其他文件中定义的变量
extern bool s_isXortOn;/* Private types -------------------------------------------------------------*//* Private functions declaration ---------------------------------------------*/
static void *UserXPort_Task(void *arg); //任务函数,在循环中执行xport的相关操作
static T_DjiReturnCode ReceiveXPortSystemState(T_DjiGimbalSystemState systemState); //回调函数,用于接收xport系统状态
static T_DjiReturnCode ReceiveXPortAttitudeInformation(T_DjiGimbalAttitudeInformation attitudeInformation); //回调函数,接收xport姿态信息/* Private variables ---------------------------------------------------------*/
static T_DjiTaskHandle s_userXPortThread;
static T_DjiMutexHandle s_userXPortMutex;
static T_DjiGimbalSystemState s_userXPortSystemState = {0};
static bool s_isUserXPortInited = false;
static bool s_isUserXPortSystemStateVaild = false;/* Exported functions definition ---------------------------------------------*/
//初始化和启动xport服务
T_DjiReturnCode DjiTest_XPortStartService(void)
{USER_LOG_ERROR("set serial number 22222222222222");T_DjiReturnCode djiStat;T_DjiXPortLimitAngle limitAngle = {0};T_DjiAircraftInfoBaseInfo aircraftInfoBaseInfo = {0};T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();//初始化xport模块djiStat = DjiXPort_Init();if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("XPort init error: 0x%08llX.", djiStat);return djiStat;}s_isUserXPortInited = true;//创建互斥锁djiStat = osalHandler->MutexCreate(&s_userXPortMutex);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("user XPort mutex create error: 0x%08llX.", djiStat);return djiStat;}//注册回调函数djiStat = DjiXPort_RegReceiveSystemStateCallback(ReceiveXPortSystemState);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("register receive XPort system state callback function error: 0x%08llX.", djiStat);return djiStat;}djiStat = DjiXPort_RegReceiveAttitudeInformationCallback(ReceiveXPortAttitudeInformation);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("register receive XPort attitude information callback function error: 0x%08llX.",djiStat);return djiStat;}//设置云台俯仰轴关节角角度限制limitAngle.upperLimit = 300;limitAngle.lowerLimit = -1000;djiStat = DjiXPort_SetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_PITCH_JOINT_ANGLE, limitAngle);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("set pitch joint angle limit angle for XPort error: 0x%08llX.", djiStat);return djiStat;}//设置云台俯仰轴欧拉角角度限制(在大地坐标系下)limitAngle.upperLimit = 300;limitAngle.lowerLimit = -900;djiStat = DjiXPort_SetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_PITCH_EULER_ANGLE, limitAngle);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("set pitch euler angle limit angle for XPort error: 0x%08llX.", djiStat);return djiStat;}//扩展俯仰轴欧拉角限制(在大地坐标系下),使用该功能时,请开启扩展俯仰轴角度限制功能limitAngle.upperLimit = 300;limitAngle.lowerLimit = -1200;djiStat = DjiXPort_SetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_PITCH_EULER_ANGLE_EXTENSION, limitAngle);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("set pitch extension euler angle limit angle for XPort error: 0x%08llX.", djiStat);return djiStat;}//获取飞行器的基本信息,以此决定角度限制的具体值djiStat = DjiAircraftInfo_GetBaseInfo(&aircraftInfoBaseInfo);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("get aircraft base information error: 0x%08llX.", djiStat);return djiStat;}if (aircraftInfoBaseInfo.mountPosition == DJI_MOUNT_POSITION_PAYLOAD_PORT_NO1) {limitAngle.upperLimit = 1500;limitAngle.lowerLimit = -1500;} else if (aircraftInfoBaseInfo.mountPosition == DJI_MOUNT_POSITION_PAYLOAD_PORT_NO2) {limitAngle.upperLimit = 1500;limitAngle.lowerLimit = -1500;} else if (aircraftInfoBaseInfo.mountPosition == DJI_MOUNT_POSITION_PAYLOAD_PORT_NO3) {limitAngle.upperLimit = 1500;limitAngle.lowerLimit = -1500;} else {USER_LOG_WARN("payload mount position is unknown.");return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;}//偏航轴关节角限制djiStat = DjiXPort_SetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_YAW_JOINT_ANGLE, limitAngle);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("set yaw joint angle limit angle for XPort error: 0x%08llX.", djiStat);return djiStat;}//设置云台飞行模式,自由模式/FPV模式/yaw模式djiStat = DjiXPort_SetGimbalModeSync(DJI_GIMBAL_MODE_FREE);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("set XPort gimbal mode error: 0x%08llX.", djiStat);return djiStat;}//以阻塞的方式控制X-Port 复位(大地坐标系)。// djiStat = DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_AND_YAW);djiStat = DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD);// DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD_AND_YAWif (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("reset XPort gimbal error: 0x%08llX.", djiStat);return djiStat;}USER_LOG_ERROR("set serial number 33333333333333");//开启用户任务函数if (osalHandler->TaskCreate("user_xport_task", UserXPort_Task, XPORT_TASK_STACK_SIZE, NULL, &s_userXPortThread) !=DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("user XPort task create error.");return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;}return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
//销毁和反初始化
T_DjiReturnCode DjiTest_XPortDeInit(void)
{T_DjiReturnCode djiStat;T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();djiStat = osalHandler->TaskDestroy(s_userXPortThread);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("Destroy test xport thread error: 0x%08llX.", djiStat);return djiStat;}djiStat = osalHandler->MutexDestroy(s_userXPortMutex);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("Destroy test xport mutex error: 0x%08llX.", djiStat);return djiStat;}djiStat = DjiXPort_DeInit();if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("XPort de-init error: 0x%08llX.", djiStat);return djiStat;}s_isUserXPortInited = false;return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
//获取系统状态信息
T_DjiReturnCode DjiTest_XPortGetSystemState(T_DjiGimbalSystemState *systemState)
{T_DjiReturnCode returnCode;T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();if (s_isUserXPortInited != true || s_isUserXPortSystemStateVaild != true) {USER_LOG_ERROR("user XPort has not inited.");return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;}returnCode = osalHandler->MutexLock(s_userXPortMutex);if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("user XPort mutex lock error: 0x%08llX.", returnCode);return returnCode;}memcpy(systemState, &s_userXPortSystemState, sizeof(T_DjiGimbalSystemState));returnCode = osalHandler->MutexUnlock(s_userXPortMutex);if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("user XPort mutex unlock error: 0x%08llX.", returnCode);return returnCode;}return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}static int flag_status = 0;
static void *UserXPort_Task(void *arg)
{T_DjiReturnCode djiStat;T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();USER_UTIL_UNUSED(arg);// 初始化旋转值和属性T_DjiAttitude3d rotationValue = {0};T_DjiGimbalRotationProperty rotationProperty = {0};// 设置无效标志rotationProperty.rotationValueInvalidFlag.pitch = false; rotationProperty.rotationValueInvalidFlag.roll = false; rotationProperty.rotationValueInvalidFlag.yaw = true; rotationProperty.relativeAngleRotation.actionTime = 100; // 单位是0.01srotationProperty.absoluteAngleRotation.actionTime = 100; rotationProperty.absoluteAngleRotation.jointAngleValid = false; osalHandler->TaskSleepMs(500);int loopCounter = 0; // 循环计数器float theta = 0.0f; // 角度变量// const float step = 0.628f; // 每次增加的角度步长const float step = 1.256f; // 每次增加的角度步长const int radius = 300; // 圆的半径while (1) {if (s_isXortOn) {if(flag_status == 0){DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD_AND_YAW);flag_status = 1;osalHandler->TaskSleepMs(500);}// 计算俯仰和滚转值rotationValue.pitch = radius * sin(theta); // 俯仰值rotationValue.roll = radius * cos(theta); // 滚转值// 调用 API 旋转云台djiStat = DjiXPort_RotateSync(DJI_GIMBAL_ROTATION_MODE_SPEED, rotationProperty, rotationValue);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("set XPort gimbal angle error: 0x%08llX.", djiStat);}// 更新角度theta += step;if (theta > 2 * M_PI) { // 如果超过 2π,回到 0theta -= 2 * M_PI;}// 每循环一定次数调用一次重置loopCounter++;if (loopCounter >= 180) { // 每 100 次循环重置一次DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD_AND_YAW);loopCounter = 0; // 重置计数器}}else if (!s_isXortOn && flag_status == 1){DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_DOWNWARD_UPWARD_AND_YAW);flag_status = 0;osalHandler->TaskSleepMs(250);DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_ROLL_ONLY);osalHandler->TaskSleepMs(250);}osalHandler->TaskSleepMs(100);}
}#ifndef __CC_ARM
#pragma GCC diagnostic pop
#endif
//接收系统状态回调函数
static T_DjiReturnCode ReceiveXPortSystemState(T_DjiGimbalSystemState systemState)
{T_DjiReturnCode returnCode;T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();returnCode = osalHandler->MutexLock(s_userXPortMutex);if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("user XPort mutex lock error: 0x%08llX.", returnCode);return returnCode;}s_isUserXPortSystemStateVaild = true;memcpy(&s_userXPortSystemState, &systemState, sizeof(T_DjiGimbalSystemState));returnCode = osalHandler->MutexUnlock(s_userXPortMutex);if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("user XPort mutex unlock error: 0x%08llX.", returnCode);return returnCode;}USER_LOG_DEBUG("receive XPort system state: mounted upward flag %d, gimbal mode %d.",systemState.mountedUpward, systemState.gimbalMode);USER_LOG_DEBUG("XPort fine tune: %d %d %d.", systemState.fineTuneAngle.pitch,systemState.fineTuneAngle.roll, systemState.fineTuneAngle.yaw);return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
//接收姿态信息回调函数
static T_DjiReturnCode ReceiveXPortAttitudeInformation(T_DjiGimbalAttitudeInformation attitudeInformation)
{USER_LOG_DEBUG("receive XPort attitude information:");USER_LOG_DEBUG("XPort attitude: pitch %d, roll %d, yaw %d.", attitudeInformation.attitude.pitch,attitudeInformation.attitude.roll, attitudeInformation.attitude.yaw);return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}//新添加的复位云台接口
T_DjiReturnCode DjiXPort_ResetGimbal(void) {T_DjiReturnCode djiStat;// 以阻塞的方式控制X-Port 复位(大地坐标系)djiStat = DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_AND_YAW);if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {USER_LOG_ERROR("reset XPort gimbal error: 0x%08llX.", djiStat);return djiStat;}USER_LOG_ERROR("XPort gimbal reset successfully.");return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}/****************** (C) COPYRIGHT DJI Innovations *****END OF FILE****/
相关文章:
4.DJI-PSDK云台x-port控制:
DJI-PSDK云台x-port控制: X-Port 功能控制,即控制 X-Port 云台,头文件为 dji_xport.h 使用PSDK 的“云台控制”功能,开发者需要先设计负载设备的云台并开发出控制云台的程序,将云台的控制函数注册到PSDK 指定的接口后…...
大语言模型中的幻觉现象深度解析
一、幻觉的定义及出现的原因 1. 基本定义 幻觉(Hallucination) 指大语言模型在自然语言处理过程中产生的与客观事实或既定输入相悖的响应,主要表现为信息失准与逻辑矛盾。 2. 幻觉类型与机制 2.1 事实性幻觉 定义:生成内容与可验证…...
衣橱管理助手系统(衣服推荐系统)(springboot+ssm+vue+mysql)含运行文档
衣橱管理助手系统(衣服推荐系统)(springbootssmvuemysql)含运行文档 该系统名为衣橱管理助手,是一个衣物搭配管理系统,主要功能包括衣物档案管理、衣物搭配推荐、搭配收藏以及套装智能推荐。用户可以通过系统进行衣物的搭配和收藏管理,系统提…...
视觉对象 - 数据可视化解读
Power BI 提供了丰富的视觉对象(Visuals),帮助用户以直观的方式呈现和分析数据。以下是 32 个常用视觉对象的解读及案例分享,涵盖核心功能、适用场景和注意事项。内容基于实际应用场景整理,便于快速理解。 一、数据比较类视觉对象 这类视觉对象主要用于比较不同类别、组别…...
使用物联网卡的烟感(NB-IoT/4G烟感)详解
基于物联网卡(NB-IoT/4G)的智能烟感是一种无线联网型火灾报警设备,相比传统烟感,它能够实时上报火警信息,适用于无人值守场所、智慧消防、远程监控等场景。 1. 物联网卡烟感的核心功能 功能说明实时报警探测到烟雾后&…...
(2)网络学习之堡垒机
堡垒机和防火墙的区别: 1.功能定位 防火墙主要负责抵御外部攻击,就像一道坚固的城墙,防止黑客进入内部网络。堡垒机则专注于内部管理,监控和记录运维人员的操作行为,确保内部网络的安全。 2.部署位置与作用范围 防…...
FlinkSQL的常用语言
FlinkSQL 常用语言指南 FlinkSQL 是 Apache Flink 提供的 SQL 接口,允许用户使用标准 SQL 或扩展的 SQL 语法来处理流式和批式数据。以下是 FlinkSQL 的常用语言元素和操作: 基本查询 -- 选择查询 SELECT * FROM table_name;-- 带条件的查询 SELECT c…...
Go语言编写一个进销存Web软件的demo
Go语言编写一个进销存Web软件的demo 用户现在要求用。之前他们已经讨论了用Django实现的方案,现在突然切换到Go,可能有几个原因。首先,用户可能对Go语言感兴趣,或者他们公司的技术栈转向了Go。其次,用户可能希望比较不…...
架构设计之Redisson分布式锁-可重入同步锁(一)
架构设计之Redisson分布式锁-可重入同步锁(一) Redisson分布式锁官方博客地址 1、Redisson是什么 Redisson 是一个基于 Redis 的 Java 分布式工具库,它提供了 分布式锁、集合、队列、缓存、Map、限流、任务调度 等高级数据结构和功能,极大地简化了 Ja…...
使用libcurl编写爬虫程序指南
用户想知道用Curl库编写的爬虫程序是什么样的。首先,我需要明确Curl本身是一个命令行工具和库,用于传输数据,支持多种协议。而用户提到的“Curl库”可能指的是libcurl,这是一个客户端URL传输库,可以用在C、C等编程语言…...
【数据结构】排序算法(下篇·终结)·解析数据难点
前引:归并排序作为一种高效排序方法,掌握起来还是有点困难的,何况需要先接受递归的熏陶,这正是编程的浪漫之处,我们不断探索出新的可能,如果给你一串数据让其变得有序?是选择简单的冒泡、插入排…...
Django 使用 Celery 完成异步任务或定时任务
1 介绍 Celery是一个分布式任务队列,由三个主要组件组成:Celery worker、Celery beat 和消息代理(例如 Redis 或 RabbitMQ)。这些组件一起协作,让开发者能够轻松地执行异步任务和定时任务。 Celery worker࿱…...
Excel 自动执行全局宏
Excel 自动执行全局宏 25.04.09 步骤 1:创建个人宏工作簿(Personal.xlsb) 生成Personal.xlsb (如尚未存在): 打开Excel → 开发工具 → 录制宏 → 选择“保存到个人宏工作簿” → 停止录制。按 Alt F11 进…...
【前缀和】矩阵区域和(medium)
矩阵区域和(medium) 题⽬描述:解法:代码Java 算法代码:C 算法代码: 题⽬描述: 题⽬链接:1314. 矩阵区域和 给你⼀个 m x n 的矩阵 mat 和⼀个整数 k ,请你返回⼀个矩阵 …...
Android ViewStub显示VISIBLE与消失GONE,Kotlin
Android ViewStub显示VISIBLE与消失GONE,Kotlin import android.os.Bundle import android.util.Log import android.view.View import android.view.ViewStub import android.widget.Button import androidx.appcompat.app.AppCompatActivity import androidx.trac…...
【愚公系列】《高效使用DeepSeek》063-海关数据获取和管理
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! 👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"…...
探索 OSPF 协议:构建高效网络的基石
文章目录 目录 文章目录 前言 一.OSPF协议概述 二.OSPF相关概念 🕤 2.1 基本思想 🕤 2.2 SPF算法 🕤 2.3 区域划分编辑 三.OSPF工作原理 编辑 🕤 3.1 DR/BDR选举 四.OSPF网络类型 🕤4.1 BMA 🕤4.2 P2P …...
深入剖析C++单例模式的八种实现演进与工程实践
深入剖析C单例模式的八种实现演进与工程实践 一、从基础到工业级:单例模式的演进图谱 1.1 基础实现的致命缺陷分析 // 初级版(非线程安全) class NaiveSingleton { public:static NaiveSingleton* getInstance() {if (!instance) {instanc…...
手游防DDoS攻击SDK接入
在手游中集成防DDoS攻击SDK是抵御流量型和应用层攻击的核心手段之一。以下从SDK选型、接入流程、防护策略优化三个维度提供完整指南,并附关键代码示例: 一、SDK选型与核心能力对比 服务商优势劣势适用场景…...
【C++进阶】关联容器:multimap类型
目录 一、multimap 基础概念与底层实现 1.1 定义与核心特性 1.2 底层数据结构 1.3 类模板定义 1.4 与其他容器的对比 二、multimap 核心操作详解 2.1 定义与初始化 2.2 插入元素 2.3 查找元素 2.4 删除元素 2.5 遍历元素 三、性能分析与适用场景 3.1 时间复杂度分…...
学习threejs,使用EffectComposer后期处理组合器(采用RenderPass、FilmPass渲染通道)
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️THREE.EffectComposer 后期…...
用Django和AJAX创建一个待办事项应用
用Django和AJAX创建一个待办事项应用 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 用Django和AJAX创建一个待办事项应用让我们创建一个简单的 Django 项目,其中包含不同类型的 A…...
【微调大模型】使用LLaMA-Factory进行监督微调 Qwen2.5
本文使用LLaMA-Factory进行监督微调 Qwen2.5。 此监督微调(SFT)脚本具有以下特点: 支持单GPU和多GPU训练;支持全参数调优,LoRA,Q-LoRA,Dora。 下面详细介绍一下该脚本的使用方法。 目录 安装…...
前端 react+ant design ,后端 springboot +mysql+redis 全栈项目零基础小白从服务器初始化开始部署上线超详细保姆级教程
哈喽小伙伴们,好久不见,我是小李,今天,来电干货,希望对大家有帮助。 去年12月底的时候心血来潮,正好赶上腾讯云在做活动,就买了一台服务器,说是后面打算上线一两个项目,体验体验云服务器究竟是怎么玩的。后来由于实习和“冬招”,实在忙不过来了,就放在文件夹吃灰了…...
[Windows] OfficeAI 助手 v0.3.20(长期免费,2025-03-18 本地支持WPS_Word联动)
OfficeAI助手,作为Microsoft Office与WPS的得力智能插件,集文档自动生成、内容精准校对与润色、公式智能推荐等多功能于一体。它凭借强大的数据分析能力,深度融入Office/WPS办公生态,一键简化复杂流程,让办公效率倍增&…...
3DGS之光栅化
光栅化(Rasterization)是计算机图形学中将连续的几何图形(如三角形、直线等)转换为离散像素的过程,最终在屏幕上形成图像。 一、光栅化的核心比喻 像画家在画布上作画 假设你是一个画家,要把一个3D立方体画…...
可发1区的超级创新思路(python 、MATLAB实现):基于SAM+Informer+2DCNN的功率预测模型
首先声明,该模型为原创!原创!原创!且该思路还未有成果发表,感兴趣的小伙伴可以借鉴! 目录 首先声明,该模型为原创!原创!原创!且该思路还未有成果发表,感兴趣的小伙伴可以借鉴! 一、模型背景与核心创新 二、模型组件详解 1. SAM时空注意力模块 原理说明 代码实…...
【Java面试系列】Spring Boot微服务架构下的分布式事务解决方案与性能优化详解 - 3-5年Java开发必备知识
【Java面试系列】Spring Boot微服务架构下的分布式事务解决方案与性能优化详解 - 3-5年Java开发必备知识 1. 引言 在当今的微服务架构中,分布式事务是一个不可避免的话题。随着业务复杂度的提升,如何保证跨服务的数据一致性成为开发者和架构师必须面对…...
【MATLAB第114期】基于MATLAB的SHAP可解释神经网络分类模型(敏感性分析方法)
【MATLAB第114期】基于MATLAB的SHAP可解释神经网络分类模型(敏感性分析方法) 引言 该文章实现了一个可解释的神经网络分类模型,使用BP神经网络(BPNN)来预测特征输出。该模型利用12个变量参数作为输入特征进行训练。为…...
WPS免费使用宏(安装VBA插件)
WPS提示要开会员才能使用宏,多次搜索发现其实可以直接安装VBA插件就行,Mark一下 插件下载地址: https://www.onlinedown.net/soft/10044362.htm ‘’’ WPS插件软件介绍 wps vba是一款wps office插件,安装wps vba 7.1就可以让of…...
让测试飞起来——DevOps中的自动化测试实践指南
让测试飞起来——DevOps中的自动化测试实践指南 近年来,DevOps理念已经成为现代软件开发和运维的“最佳拍档”。它倡导“开发”和“运维”的协作,核心目标是加速交付,同时保障软件质量。而在这一过程中,测试自动化扮演了不可替代的角色。今天,我们就一起来聊聊测试自动化…...
开源AI大模型AI智能名片S2B2C商城小程序:科技浪潮下的商业新引擎
摘要: 本文聚焦于科技迅猛发展背景下,开源AI大模型、AI智能名片与S2B2C商城小程序的融合应用。通过分析元宇宙、人工智能、区块链、5G等前沿科技带来的商业变革,阐述开源AI大模型AI智能名片S2B2C商城小程序在整合资源、优化服务、提升用户体验…...
webpack配置导致浏览器自动刷新
文章目录 关键配置 - liveReload 关键配置 - liveReload const dev_config {devtool: source-map,// watch: true,devServer: {contentBase: path.resolve(__dirname, bin),port: 8005,host:192.168.xx.xx,inline: true,hot: false,liveReload: false //关键这一行【false不会…...
OPEX baota 2024.02.26
OPEX baota 2024.02.26 运维集成软件宝塔2024.02.26作废例子: 最重要的两个地方:上传文件 网站,重启应用服务器(tomcat) 其他很少用的...
【Pandas】pandas DataFrame to_numpy
Pandas2.2 DataFrame Conversion 方法描述DataFrame.astype(dtype[, copy, errors])用于将 DataFrame 中的数据转换为指定的数据类型DataFrame.convert_dtypes([infer_objects, …])用于将 DataFrame 中的数据类型转换为更合适的类型DataFrame.infer_objects([copy])用于尝试…...
Tensorflow2实现: LSTM-火灾温度预测
- **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/rnFa-IeY93EpjVu0yzzjkw) 中的学习记录博客** - **🍖 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)** 一:理论知识基础 1.LSTM原理 一句话介…...
【降尺度】AI+CMIP6数据分析与可视化、降尺度技术与气候变化的区域影响、极端气候分析
气候变化已成为全球性挑战,对农业、生态系统、水资源、人类健康和社会经济系统产生深远影响。科学研究表明,自工业革命以来,人类活动导致的温室气体排放与全球气温上升、极端天气事件增加、冰川融化和海平面上升等现象密切相关。为科学理解和…...
粒子系统优化完成
按计划对幻世(OurDream)2D图形引擎的粒子系统进行了加强和优化,重点强化了粒子运动的控制和颜色混合效果的功能,目前优化过后的粒子系统的整体效果是令人满意的。...
spark-core编程
RDD转换算子 RDD 的两种算子:转换算子和行动算子。 RDD 根据数据处理方式的不同将算子整体上分为 Value 类型、双 Value 类型和 Key-Value 类型。 算子实际上是一些函数,用于数据处理。 Value类型 map 将处理的数据逐条进行映射转换,…...
智慧班牌系统解决方案,SaaS智慧电子班牌云平台
智慧班牌系统解决方案 系统概述 智慧班牌是智慧校园建设不断发展的产物,是教育信息化改革的载体。通过智慧班牌可以高效便捷传递各种知识信息和通知信息、及时反馈课堂信息、实现班级的透明化管理。智慧班牌将学生平安考勤、异常出勤情况及时反馈至家长、老师&…...
Flutter 2025 Roadmap
2025 这个路线图是有抱负的。它主要代表了我们这些在谷歌工作的人收集的内容。到目前为止,非Google贡献者的数量超过了谷歌雇佣的贡献者,所以这并不是一个详尽的列表,列出了我们希望今年Flutter能够出现的所有令人兴奋的新事物!在…...
【开发工具】科研开发中的主流AI工具整理及如何使用GPT润色英文论文
一、主流AI工具 AI技术发展至今已经逐渐成熟,并可以取代一部分科研和开发中的简单工作,并为复杂工作提高辅助,除此之外也是更高级的信息检索工具。熟练掌握 AI 工具在当前市场理应具有竞争优势,目前笔者在科研和开发中接触过AI工…...
用excel做九乘九乘法表
公式: IF($A2>B 1 , 1, 1,A2 & “" & B$1 & “” & $A2B$1,”")...
nacos配置达梦数据库驱动源代码步骤
1.在父工程pom.xml添加依赖: <dependency><groupId>com.dameng</groupId><artifactId>DmJdbcDriver18</artifactId><version>8.1.1.193</version> </dependency> 2.在nacos-config模块pom.xml添加依赖࿱…...
Spring Boot 线程池配置详解
Spring Boot 线程池配置详解 一、核心配置参数及作用 基础参数核心线程数 (corePoolSize) 作用:线程池中始终保持存活的线程数量,即使空闲也不回收。 建议:根据任务类型设定(如 I/O 密集型任务可设为 CPU 核心数 2)。 最大线程数 (maxPoolSize) 作用:…...
如何使用 qrcode.react生成二维码
qrcode.react(查看官网) 是一个用于 React 应用的 QR 码生成组件。下面是如何使用它的详细指南: 1、安装 npm install qrcode.react # 或者 yarn add qrcode.react2、基本用法 import {QRCodeSVG} from qrcode.react;const myPage () >…...
用VScode来编写前后端——构建基础框架
前言 我写这一个板块的原因是我参加了我们学校的新生项目课,需要创立一个系统,我们小组选的标题的基于计算机视觉的商品识别系统,那么我们需要一个网站来展示我们的功能,故写这些来记录一下自己,大家如果有什么问题的话…...
23.OpenCV轮廓逼近与拟合
OpenCV轮廓逼近与拟合 在计算机视觉中,轮廓是图像中边界或形状的重要表达形式。然而,直接从图像中提取的轮廓常常包含大量冗余点,且噪声较多。为了更好地描述图像中的形状,我们通常需要对轮廓进行逼近和拟合,从而降低…...
Flutter Row / Column 组件详解
1. 引言 在 Flutter 中,Row 和 Column 是最常用的布局组件,用于在水平方向 (Row) 或垂直方向 (Column) 排列子组件。它们提供了强大的对齐方式、空间分配策略,适用于各种 UI 设计需求。本文将详细介绍它们的基本用法、主要属性及自定义样式。…...
WHAT - 表单场景 - 依赖联动
目录 示例场景技术栈示例代码功能点总结详情场景 - 依赖联动初始化示例说明:详情页场景(含回显、联动)修改点说明示例代码(详情页)总结一下关键点 下面是一个基于 React TypeScript Ant Design (antd) 的表单联动示例…...