rm_balance/User/device/gimbal_imu.c
2026-01-11 23:22:12 +08:00

169 lines
6.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Gimbal IMU Device - 接收来自云台的CAN IMU数据
*/
/* Includes ----------------------------------------------------------------- */
#include "gimbal_imu.h"
#include <string.h>
#include "bsp/can.h"
#include "bsp/time.h"
/* Private function prototypes ---------------------------------------------- */
/**
* @brief 无符号整数转换为浮点数
*
* @param x_int 输入的整数值
* @param x_min 最小值
* @param x_max 最大值
* @param bits 位数
* @return float 转换后的浮点数
*/
static float uint_to_float(uint16_t x_int, float x_min, float x_max, int bits) {
float span = x_max - x_min;
float offset = x_min;
return ((float)x_int) * span / ((float)((1 << bits) - 1)) + offset;
}
/**
* @brief 解析CAN消息中的IMU数据
*/
static void GIMBAL_IMU_ParseMessage(GIMBAL_IMU_t *gimbal_imu, uint32_t id, const uint8_t *data) {
if (gimbal_imu == NULL || data == NULL) {
return;
}
/* 判断是哪个ID的数据 */
if (id == gimbal_imu->param.accl_id) {
/* 解析加速度计数据 */
uint16_t acc_x = (uint16_t)data[2] | ((uint16_t)data[3] << 8);
uint16_t acc_y = (uint16_t)data[4] | ((uint16_t)data[5] << 8);
uint16_t acc_z = (uint16_t)data[6] | ((uint16_t)data[7] << 8);
gimbal_imu->data.accl.x = uint_to_float(acc_x, GIMBAL_IMU_ACCEL_MIN, GIMBAL_IMU_ACCEL_MAX, 16);
gimbal_imu->data.accl.y = uint_to_float(acc_y, GIMBAL_IMU_ACCEL_MIN, GIMBAL_IMU_ACCEL_MAX, 16);
gimbal_imu->data.accl.z = uint_to_float(acc_z, GIMBAL_IMU_ACCEL_MIN, GIMBAL_IMU_ACCEL_MAX, 16);
/* 温度数据 */
gimbal_imu->data.temp = (float)data[1];
} else if (id == gimbal_imu->param.gyro_id) {
/* 解析陀螺仪数据 */
uint16_t gyro_x = (uint16_t)data[2] | ((uint16_t)data[3] << 8);
uint16_t gyro_y = (uint16_t)data[4] | ((uint16_t)data[5] << 8);
uint16_t gyro_z = (uint16_t)data[6] | ((uint16_t)data[7] << 8);
gimbal_imu->data.gyro.x = uint_to_float(gyro_x, GIMBAL_IMU_GYRO_MIN, GIMBAL_IMU_GYRO_MAX, 16);
gimbal_imu->data.gyro.y = uint_to_float(gyro_y, GIMBAL_IMU_GYRO_MIN, GIMBAL_IMU_GYRO_MAX, 16);
gimbal_imu->data.gyro.z = uint_to_float(gyro_z, GIMBAL_IMU_GYRO_MIN, GIMBAL_IMU_GYRO_MAX, 16);
} else if (id == gimbal_imu->param.eulr_id) {
/* 解析欧拉角数据 */
uint16_t pit = (uint16_t)data[2] | ((uint16_t)data[3] << 8);
uint16_t yaw = (uint16_t)data[4] | ((uint16_t)data[5] << 8);
uint16_t rol = (uint16_t)data[6] | ((uint16_t)data[7] << 8);
gimbal_imu->data.eulr.pit = uint_to_float(pit, GIMBAL_IMU_PITCH_MIN, GIMBAL_IMU_PITCH_MAX, 16);
gimbal_imu->data.eulr.yaw = uint_to_float(yaw, GIMBAL_IMU_YAW_MIN, GIMBAL_IMU_YAW_MAX, 16);
gimbal_imu->data.eulr.rol = uint_to_float(rol, GIMBAL_IMU_ROLL_MIN, GIMBAL_IMU_ROLL_MAX, 16);
} else if (id == gimbal_imu->param.quat_id) {
/* 解析四元数数据 - 使用14位精度解包 */
uint16_t q0 = ((uint16_t)data[1] << 6) | ((uint16_t)data[2] >> 2);
uint16_t q1 = (((uint16_t)data[2] & 0x03) << 12) | ((uint16_t)data[3] << 4) | ((uint16_t)data[4] >> 4);
uint16_t q2 = (((uint16_t)data[4] & 0x0F) << 10) | ((uint16_t)data[5] << 2) | ((uint16_t)data[6] >> 6);
uint16_t q3 = (((uint16_t)data[6] & 0x3F) << 8) | (uint16_t)data[7];
gimbal_imu->data.quat.q0 = uint_to_float(q0, GIMBAL_IMU_QUAT_MIN, GIMBAL_IMU_QUAT_MAX, 14);
gimbal_imu->data.quat.q1 = uint_to_float(q1, GIMBAL_IMU_QUAT_MIN, GIMBAL_IMU_QUAT_MAX, 14);
gimbal_imu->data.quat.q2 = uint_to_float(q2, GIMBAL_IMU_QUAT_MIN, GIMBAL_IMU_QUAT_MAX, 14);
gimbal_imu->data.quat.q3 = uint_to_float(q3, GIMBAL_IMU_QUAT_MIN, GIMBAL_IMU_QUAT_MAX, 14);
}
}
/* Exported functions ------------------------------------------------------- */
/**
* @brief 初始化Gimbal IMU设备
* @param gimbal_imu Gimbal IMU结构体指针
* @param param 参数配置
* @return 初始化结果
* - DEVICE_OK: 成功
* - DEVICE_ERR_NULL: 参数为空
*/
int8_t GIMBAL_IMU_Init(GIMBAL_IMU_t *gimbal_imu, const GIMBAL_IMU_Param_t *param) {
if (gimbal_imu == NULL || param == NULL) {
return DEVICE_ERR_NULL;
}
/* 清空数据 */
memset(gimbal_imu, 0, sizeof(GIMBAL_IMU_t));
/* 复制参数 */
gimbal_imu->param = *param;
/* 设置设备类型 */
gimbal_imu->header.online = false;
/* 注册CAN ID到消息队列 */
BSP_CAN_RegisterId(param->can, param->accl_id, BSP_CAN_DEFAULT_QUEUE_SIZE);
BSP_CAN_RegisterId(param->can, param->gyro_id, BSP_CAN_DEFAULT_QUEUE_SIZE);
BSP_CAN_RegisterId(param->can, param->eulr_id, BSP_CAN_DEFAULT_QUEUE_SIZE);
BSP_CAN_RegisterId(param->can, param->quat_id, BSP_CAN_DEFAULT_QUEUE_SIZE);
return DEVICE_OK;
}
/**
* @brief 更新Gimbal IMU设备状态 - 从CAN队列读取并解析数据
* @param gimbal_imu Gimbal IMU结构体指针
* @return 更新结果
* - DEVICE_OK: 成功
* - DEVICE_ERR_NULL: 参数为空
*/
int8_t GIMBAL_IMU_Update(GIMBAL_IMU_t *gimbal_imu) {
if (gimbal_imu == NULL) {
return DEVICE_ERR_NULL;
}
BSP_CAN_Message_t msg;
bool received = false;
/* 读取所有可用的CAN消息 */
while (BSP_CAN_GetMessage(gimbal_imu->param.can, gimbal_imu->param.accl_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) {
GIMBAL_IMU_ParseMessage(gimbal_imu, gimbal_imu->param.accl_id, msg.data);
received = true;
}
while (BSP_CAN_GetMessage(gimbal_imu->param.can, gimbal_imu->param.gyro_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) {
GIMBAL_IMU_ParseMessage(gimbal_imu, gimbal_imu->param.gyro_id, msg.data);
received = true;
}
while (BSP_CAN_GetMessage(gimbal_imu->param.can, gimbal_imu->param.eulr_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) {
GIMBAL_IMU_ParseMessage(gimbal_imu, gimbal_imu->param.eulr_id, msg.data);
received = true;
}
while (BSP_CAN_GetMessage(gimbal_imu->param.can, gimbal_imu->param.quat_id, &msg, BSP_CAN_TIMEOUT_IMMEDIATE) == BSP_OK) {
GIMBAL_IMU_ParseMessage(gimbal_imu, gimbal_imu->param.quat_id, msg.data);
received = true;
}
/* 更新在线状态和时间戳 */
if (received) {
gimbal_imu->header.online = true;
gimbal_imu->header.last_online_time = BSP_TIME_Get();
} else {
/* 超时检测 - 100ms */
uint64_t now_time = BSP_TIME_Get();
if (now_time - gimbal_imu->header.last_online_time > 100000) { /* 100ms超时单位微秒 */
gimbal_imu->header.online = false;
}
}
return DEVICE_OK;
}