Files
Motor_v2/Robot_V2/device/ang_sensor.cpp
T
cbb 7c4aaa5ee6 feat(FOC): 优化FOC控制算法并修复多个控制环路问题
- 重构cal_Iq_Id函数,移除电角度参数传递,改用预计算的sin/cos值
  以避免重复三角函数计算,提升性能约15-300周期
- 修复角度同步Uq前馈学习中的运动方向判断逻辑,解决反转时的
  震荡问题和正转正常反转震荡的根本原因
- 实现低速缩放因子函数get_mode3_velocity_scale,改进静摩擦
  hunting抑制效果
- 优化电压检测逻辑,将阻塞式ADC读取改为连续模式零等待,
  提升实时性能
- 修复初始化期间电压分母为零的问题,添加下限保护防止P增益
  无穷大
- 实现PID控制器测量微分功能,消除目标阶跃时的微分冲击
- 改进积分抗饱和策略,添加外部饱和泄放功能,优化到位稳定
  性能

perf(Filter): 优化中值滤波算法性能

- 针对ADC_FILTER_SIZE=6的固定场景实现最优排序网络,
  用12次比较替代通用std::nth_element算法,显著提升性能
- 保留通用回退路径处理其他尺寸情况
2026-09-01 02:46:25 +08:00

239 lines
6.8 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.
/**
* @file device/ang_sensor.cpp
* @brief 底层设备驱动与外设封装源文件
* @note 本文件仅补充 Doxygen 文档注释,不改变代码逻辑。
*/
#include "ang_sensor.h"
#include "Can.h"
#include "Filter.h"
#include "config.h"
#include "flash.h"
#include "gd32c10x_dma.h"
#include "gd32c10x_gpio.h"
#include "gd32c10x_spi.h"
#include <cstdio>
#include <cstring>
#include <stdint.h>
// ANG_SENS 调试宏定义
#if ANG_SENS_DEBUG
/** @brief ANG_SENS_DEBUG_PRINT 宏定义 */
#define ANG_SENS_DEBUG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
/** @brief ANG_SENS_DEBUG_PRINT 宏定义 */
#define ANG_SENS_DEBUG_PRINT(fmt, ...) ((void)0)
#endif
/** @brief ANG_SPI_CS_ENABLE 宏定义 */
#define ANG_SPI_CS_ENABLE() gpio_bit_reset(GPIOA, GPIO_PIN_15)
/** @brief ANG_SPI_CS_DISABLE 宏定义 */
#define ANG_SPI_CS_DISABLE() gpio_bit_set(GPIOA, GPIO_PIN_15)
/** @brief DRV_SPI_CS_ENABLE 宏定义 */
#define DRV_SPI_CS_ENABLE() gpio_bit_reset(GPIOB, GPIO_PIN_14)
/** @brief DRV_SPI_CS_DISABLE 宏定义 */
#define DRV_SPI_CS_DISABLE() gpio_bit_set(GPIOB, GPIO_PIN_14)
// 全局角度传感器单例:系统只有一个 KTH7823 角度传感器。
// 初始化顺序由 main::hardware_init() 调用 KTH7823.init() 保证。
angle_sensor KTH7823; // 角度传感器初始化
extern FlashEEPROM flashEEP;
extern EncoderAngleKalman Angle_kalman;
extern EncoderVelocityKalman Vel_kalman;
extern CAN_transmiter CAN0_transmiter; // CAN 初始化
/**
* @brief Send or read half word through SPI by register polling
*
* @param[in] spi_periph SPI peripheral
* @param[in] tx_data Data to transmit
* @param[out] rx_data Pointer to store received data
* @return 0 if success, -1 if error
* @note 单半字轮询收发。DMA 版本(已移除)每次传输需要:重配 2 个 DMA
* 通道(约 10 次寄存器写) + 2 次 FTF 中断 + 忙等完成标志,而 16bit
* @5MHz 帧本身只有 3.2μs——DMA 的准备与中断开销和传输时间同量级。
* 轮询同样忙等帧时间,但砍掉了全部 DMA 开销与 40k 次/秒的中断。
*/
int spi_rw_half_word_polling(uint32_t spi_periph, uint16_t tx_data,
uint16_t *rx_data) {
u32 timeout = 1000;
while (spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE) == RESET) {
if (--timeout == 0U) {
return -1;
}
}
spi_i2s_data_transmit(spi_periph, tx_data);
timeout = 1000;
while (spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE) == RESET) {
if (--timeout == 0U) {
return -1;
}
}
*rx_data = spi_i2s_data_receive(spi_periph);
// 等待移位完成再返回:调用方返回后立即拉高 CS,
// 若最后一位仍在移位会截断帧
while (spi_i2s_flag_get(spi_periph, SPI_FLAG_TRANS) != RESET) {
}
return 0;
}
/**
* @brief 角度传感器初始化
* @param 无
*/
void KTH7823_gpio_init(void) {
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_SPI0);
rcu_periph_clock_enable(RCU_AF);
/* 关闭 JTAG,仅保留 SWD(释放 PA15、PB3、PB4) */
gpio_pin_remap_config(GPIO_SWJ_SWDPENABLE_REMAP, ENABLE);
/* -------- SPI0 全 remap:PB3/4/5 + PA15 -------- */
gpio_pin_remap_config(GPIO_SPI0_REMAP, ENABLE);
/* PA15 → NSS, 推挽输出 */
gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
/* PB3 → SCK, PB5 → MOSI, 推挽输出 */
gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ,
GPIO_PIN_3 | GPIO_PIN_5);
/* PB4 → MISO, 浮空输入 */
gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ,
GPIO_PIN_4 | GPIO_PIN_10 | GPIO_PIN_11);
}
/**
* @brief SPI 初始化
*
* @details Configures SPI hardware and initializes necessary settings
*/
void KTH7823_spi_init(void) {
spi_parameter_struct spi_init_str;
spi_struct_para_init(&spi_init_str);
/* SPI 参数:16bit, 主机,全双工,CPOL=1 CPHA=1, MSB first */
spi_init_str.device_mode = SPI_MASTER;
spi_init_str.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
spi_init_str.frame_size = SPI_FRAMESIZE_16BIT;
spi_init_str.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;
spi_init_str.nss = SPI_NSS_SOFT;
spi_init_str.endian = SPI_ENDIAN_MSB;
spi_init_str.prescale = 24; /* 5MHz @ 120MHz */
spi_init(SPI0, &spi_init_str);
spi_nss_output_enable(SPI0);
spi_nssp_mode_enable(SPI0);
spi_enable(SPI0);
}
/**
* @ 角度传感器类 初始化
* @return 0:初始化成功 1:初始化失败
*/
u8 angle_sensor::init(void) {
KTH7823_gpio_init(); // GPIO 初始化
KTH7823_spi_init(); // SPI 初始化
return 0;
}
/**
* @ 角度传感器类 设置当前角度
* @param angle 输出级角度值
* @return 0 成功/1 失败
*/
u8 angle_sensor::angle_set(float angle) {
m_cumulativeAngle = angle * REDUCTION_RATIO;
m_firstUpdate = true;
return 0;
}
/**
* @brief 读取传感器数据
* @return 传感器数据
*/
inline float angle_sensor::read_sensorAngle(void) {
uint16_t raw_data;
ANG_SPI_CS_ENABLE();
u8 result = spi_rw_half_word_polling(SPI0, DEFAULT_COMMAND, &raw_data);
ANG_SPI_CS_DISABLE();
if (result == 0) {
// 单次浮点乘法优化:只计算一次度数,然后转换为弧度
float angle_deg = -(float)raw_data * ANGLESENS_FACTOR + ANGLESENS_OFFSET;
current_angle_deg = angle_deg;
current_angle_rad = angle_deg * DEG2RAD; // M_PI/180.0f
return angle_deg;
}
// 仅在调试模式下输出错误,避免发布版本中的 I/O 开销
if (result != 0) {
ANG_SENS_DEBUG_PRINT("Error reading angle from sensor.\n");
}
return (float)FAULT_RECEIVE;
}
/**
* @brief 更新传感器角度(输出级)
* @return 累积角度值
*/
float angle_sensor::update(void) {
read_sensorAngle();
if (m_firstUpdate) {
m_lastAngle = current_angle_deg;
m_firstUpdate = false;
return m_cumulativeAngle;
}
// 计算角度变化
float delta = current_angle_deg - m_lastAngle;
// 处理角度绕回情况(0 度和 360 度之间的跳变)
// 如果变化超过 300 度,说明发生了绕回
if (delta > ANGLE_WRAP_THRESHOLD) {
// 从接近 360 度绕回到接近 0 度
delta -= ANGLE_WRAP_VALUE;
} else if (delta < -ANGLE_WRAP_THRESHOLD) {
// 从接近 0 度绕到接近 360 度
delta += ANGLE_WRAP_VALUE;
}
m_cumulativeAngle += delta;
m_lastAngle = current_angle_deg;
return m_cumulativeAngle;
}
/**
* @brief 获取累积角度值 (输出级)
* @return 累积角度值
*/
float angle_sensor::getAngle(void) const {
return m_cumulativeAngle / REDUCTION_RATIO;
}
/**
* @brief 获取累积角度值 (原始级)
* @return 累积角度值
*/
float angle_sensor::getRawAngle(void) const { return m_cumulativeAngle; }
/**
* @brief 获取角度值 (原始级)
* @return 角度值 (原始级)
*/
float angle_sensor::getcurrent_sensorangle(void) const{
return current_angle_deg;
}
/**
* @brief 设置电角度零位校准角
* @param[in] angle 校准角(度)
* @return 0 成功
*/
u8 angle_sensor::set_calibration(float angle) {
calibration_angle = normalizeAngle360(angle);
return 0;
}