仅用于备份本人所写笔记,如有错误还请包含。转载请注明出处!
程序使用逐飞科技K60库 V2.0.3
首先需要获取编码器的值,每 2ms 取一次值,为了减小误差,再每 4ms 计算一次平均值,所以需要用到定时器,这里不多赘述。取到的值再经过计算,即可算出电机当前速度。
代码示例:
#define unitPulse 1783 // 编码器测得的车轮转一圈的单位脉冲
#define motorRadius 0.063 // 车轮轮胎半径(米)
// 编码器初始化
void EncoderInit(void) {
ftm_quad_init(ftm2); // 初始化 ftm2 为正交解码
port_init_NoAlt(B18, PULLUP); // 上拉
port_init_NoAlt(B19, PULLUP);
}
// 获取编码器脉冲值
float EncoderRead(void) {
float _data = 0;
_data = ftm_quad_get(ftm2); // 获取编码器的脉冲值
ftm_quad_clean(ftm2); // 清除正交解码的脉冲值
return ABS(_data);
}
// 计算电机速度
void GetMotorSpeed(void) {
encoder.finalValue += 0.25f * (encoder.averValue - encoder.finalValue); // 一阶低通滤波
encoder.motorRounds = (encoder.finalValue * 250) / unitPulse; // 电机每 1s 转的圈数
encoder.motorDistance = encoder.motorRounds * (2*PI*motorRadius); // 电机运行长度 m
encoder.motorSpeed = encoder.motorDistance / 1; // 电机速度 m/s
}
需要放到定时器里的程序:
// 放到 2ms 里
encoder.value += EncoderRead(); // 每 2ms 读取编码器的值
// 放到 4ms 里
encoder.averValue = encoder.value / 2; // 将编码器的值求平均,减少误差
encoder.value = 0; // 将编码器值归零,重新记值
最后得出的变量 encoder.motorSpeed
就是电机当前速度。
计算出速度后,把该变量赋值给 PID 计算,算出电机需要的占空比,这样就能对电机速度闭环了。
代码示例:
uint16 motorPid_10Kp = 1, motorPid_10Ki = 2; // 10 倍的 KP、KI 值(之所以用10倍,是因为需要在 OLED 上调参,而 OLED 上改一次值变化范围为 1,而我们需要的参数变化范围为 0.1)
// 电机 pid 计算
static void MotorPid(void) {
static float _err, _expectPwm, _lastErr;
motorPid.kp = (float)(motorPid_10Kp) / 10; // 动态调整 PID 参数,因为在不同路段需要不同的效果
motorPid.ki = (float)(motorPid_10Ki) / 10; // Ki 越大,速度变化越快 0.1-1.0
_err = motor.expectSpeed - encoder.motorSpeed; // 期望速度可以自己设定,或者通过计算得到
_expectPwm += motorPid.kp * (_err - _lastErr) + motorPid.ki * _err;
_lastErr = _err;
// 电机占空比限幅
if(_expectPwm > 260) _expectPwm = 260; // 限制最高占空比
if(_expectPwm <= 0) _expectPwm = 0; // 限制最低占空比
motor.expectDutyRatio = (int16)(_expectPwm);
}
把期望占空比赋值给电机控制函数即可:
// 电机初始化
void MotorInit(void) {
ftm_pwm_init(ftm1, ftm_ch0, 10*1000, 0); // A12 端口,初始化 ftm_pwm,频率为 10k,占空比为 0
ftm_pwm_init(ftm1, ftm_ch1, 10*1000, 0); // A13 端口,初始化 ftm_pwm,频率为 10k,占空比为 0
}
// 电机占空比赋值
void Motor(uint16 _speed1, uint16 _speed2) {
ftm_pwm_duty(ftm1, ftm_ch0, _speed1); // A12 端口
ftm_pwm_duty(ftm1, ftm_ch1, _speed2); // A13 端口
}
// 电机控制
void MotorControl(void) {
MotorPid(); // PID 计算
Motor(0, motor.expectDutyRatio); // 赋值占空比
}