前言
之前使用有硬件浮点单元的单片机,就一直在用浮点PID,最近在STM32F1上面跑FOC,再使用浮点肯定是不太合适的了,就研究了下STM32官方的定点PID。由于FOC算法一般使用PI就够了,所以下面算法只有PI(比例,积分)部分,没有加入D(微分)部分。
结构体
typedef struct {
int16_t h_kp;
int16_t h_ki;
int32_t w_integral_term;
// limit
int32_t w_upper_integral_limit;
int32_t w_lower_integral_limit;
int16_t h_upper_output_limit;
int16_t h_lower_output_limit;
uint16_t h_kp_divisor_pow2;
uint16_t h_ki_divisor_pow2;
} mc_pid_t;
ST的代码喜欢用h开头表示16位数据,w开头表示32位数据,对于需要做定点乘法的代码来说,这种表示方法能避免出错,所以我们这里沿用这种表示方法。
变量名 | 含义 |
---|---|
h_kp | 当前使用的kp值 |
h_ki | 当前使用的ki值 |
w_integral_term | 积分项的值,由于积分项需要累加,所以将其值保存在结构体中 |
w_upper_integral_limit | 积分项的最大值 |
w_lower_integral_limit | 积分项的最小值 |
h_upper_output_limit | 输出的最大值 |
h_lower_output_limit | 输出的最小值 |
h_kp_divisor_pow2 | 比例项右移的位数 |
h_ki_divisor_pow2 | 比例项右移的位数 |
在我们使用浮点pid算法时,kp,ki的值我们都能够设置成小数,而定点不行。那怎么处理呢?最简单的办法就是,将比例项和积分项都除以一个数,如果kp为1,除以10就相当于kp是0.1了。
在STM32这样的单片机中,进行除法运算效率也是比较低的,所以采用右移运算,右移1位表示除以2,右移2位表示除以2^2,一次类推。。。我们变量名中的pow2就是这个意思了,