Files
Motor_v2/Robot_V2/device/ang_sensor.cpp
T
cbb c0b5f6902b docs(config): 新增软件和硬件版本号定义
- 定义SOFTWARE_VERSION 26.1.19.1
- 定义HARDWARE_VERSION 25.12.01.0
- 定义BOOT_VERSION 26.1.12.0

feat(motor-control): 实现FOC控制算法速度环优化

refactor(can-protocol): 升级CANFD通信协议支持版本管理
- 实现版本号管理和CANFD_VERSION_ID协议
- 扩展CMD_ID消息解析支持PID参数动态配置
- 添加版本管理器实例并实现版本信息发送功能
- 优化CANFD异步发送数据长度判断逻辑

fix(angle-sensor): 修正角度传感器方向和偏移校准
- 添加ANGLESENS_OFFSET补偿参数
- 反转角度传感器读数方向(DIR = -1.0f)
- 在角度计算中应用负向因子和偏移量

chore(memory-layout): 调整Flash存储布局和版本配置
- 扩展BOOTLOADER_SIZE从16KB到24KB
- 更新APPLATEST_START_ADDR和APPBACK_START_ADDR偏移
- 重新分配OTA配置参数存储区域
- 增加EEP_DEBUG调试开关

refactor(pid-controller): 增强PID控制器功能接口
- 添加set_P_percent方法支持百分比参数设置
- 格式化PID计算代码提升可读性
- 保留积分和微分环节的约束保护机制
2026-01-20 01:28:52 +08:00

293 lines
8.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.
#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>
#define ANG_SENS_DEBUG 1
#define ANG_SPI_CS_ENABLE() gpio_bit_reset(GPIOA, GPIO_PIN_15)
#define ANG_SPI_CS_DISABLE() gpio_bit_set(GPIOA, GPIO_PIN_15)
#define DRV_SPI_CS_ENABLE() gpio_bit_reset(GPIOB, GPIO_PIN_14)
#define DRV_SPI_CS_DISABLE() gpio_bit_set(GPIOB, GPIO_PIN_14)
// DMA传输完成标志
volatile bool spi_dma_tx_complete = false;
volatile bool spi_dma_rx_complete = false;
angle_sensor KTH7823; // 角度传感器初始化
extern FlashEEPROM flashEEP;
extern EncoderAngleKalman Angle_kalman;
extern EncoderVelocityKalman Vel_kalman;
extern CAN_transmiter CAN0_transmiter; // CAN初始化
/**
* @brief SPI DMA initialization
*/
void spi_dma_init(void) {
dma_parameter_struct dma_init_struct;
// 使能DMA时钟
rcu_periph_clock_enable(RCU_DMA0);
// 初始化发送DMA通道
dma_deinit(DMA0, DMA_CH2);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr = (uint32_t)0; // 实际地址将在传输时设置
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_init_struct.number = 1;
dma_init_struct.periph_addr = (uint32_t)(&SPI_DATA(SPI0));
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_init(DMA0, DMA_CH2, &dma_init_struct);
// 初始化接收DMA通道
dma_deinit(DMA0, DMA_CH1);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)0; // 实际地址将在传输时设置
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
dma_init_struct.number = 1;
dma_init_struct.periph_addr = (uint32_t)(&SPI_DATA(SPI0));
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_init(DMA0, DMA_CH1, &dma_init_struct);
// 使能SPI的DMA发送和接收功能
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
// 配置DMA中断
nvic_irq_enable(DMA0_Channel2_IRQn, 0, 1);
nvic_irq_enable(DMA0_Channel1_IRQn, 0, 1);
// 使能DMA传输完成中断
dma_interrupt_enable(DMA0, DMA_CH2, DMA_INT_FTF);
dma_interrupt_enable(DMA0, DMA_CH1, DMA_INT_FTF);
}
/**
* @brief Send or read half word through SPI using DMA
*
* @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
*/
int spi_rw_half_word_dma(uint32_t spi_periph, uint16_t tx_data,
uint16_t *rx_data) {
// 重置完成标志
spi_dma_tx_complete = false;
spi_dma_rx_complete = false;
// 配置发送DMA
dma_channel_disable(DMA0, DMA_CH2);
dma_memory_address_config(DMA0, DMA_CH2, (uint32_t)&tx_data);
dma_transfer_number_config(DMA0, DMA_CH2, 1);
dma_channel_enable(DMA0, DMA_CH2);
// 配置接收DMA
dma_channel_disable(DMA0, DMA_CH1);
dma_memory_address_config(DMA0, DMA_CH1, (uint32_t)rx_data);
dma_transfer_number_config(DMA0, DMA_CH1, 1);
dma_channel_enable(DMA0, DMA_CH1);
// 等待传输完成,超时时间为100个循环
uint32_t timeout = 100;
while ((!spi_dma_tx_complete || !spi_dma_rx_complete) && --timeout) {
// 空循环等待DMA传输完成
}
// 检查是否超时
if (timeout == 0) {
// 禁用DMA通道
dma_channel_disable(DMA0, DMA_CH2);
dma_channel_disable(DMA0, DMA_CH1);
printf("SPI DMA transfer timeout\r\n");
return -1;
}
return 0;
}
/**
* @brief DMA0_Channel2中断处理函数
* @param 无
*/
extern "C" void DMA0_Channel2_IRQHandler(void) {
if (dma_interrupt_flag_get(DMA0, DMA_CH2, DMA_INT_FLAG_FTF)) {
dma_interrupt_flag_clear(DMA0, DMA_CH2, DMA_INT_FLAG_FTF);
spi_dma_tx_complete = true;
}
}
/**
* @brief DMA0_Channel1中断处理函数
* @param 无
*/
extern "C" void DMA0_Channel1_IRQHandler(void) {
if (dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INT_FLAG_FTF)) {
dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INT_FLAG_FTF);
spi_dma_rx_complete = true;
}
}
/**
* @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初始化
spi_dma_init(); // DMA初始化
return 0;
}
/**
* @ 角度传感器类 设置当前角度
* @param angle 输出级角度值
* @return 0成功/1失败
*/
u8 angle_sensor::angle_set(float angle) {
m_cumulativeAngle = angle * REDUCTION_RATIO; // 从Flash读取上次保存的角度
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_dma(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) {
// 使用更高效的串口输出替代printf(如果可用)
printf("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;
}