电角度与机械角度
float zero_mechanical_angle = 0.36;float zero_electrical_angle = 0.891460538;float last_mechanical_angle = 0;uint32_t pre_tick;
机械角:机械角就是空间几何角度,用圆规能够测量到的。因为电机是圆形的,所以它的范围是0-360度。
电角度:从定子来看,定子电流变化一个完整的周期定义为电角度的0-360度,称为一个电周期。一个电周期可以在空间360度完成也可以在空间180度或者90度或者60度完成,这和电动机(发电机也是这样)绕组布置成几对磁级有关。
从转子来看, 转子上分布有N对磁钢,电角度以一对磁钢为基准,形成电磁场的绕组经过一对磁钢的N极、S极、再回到另一对磁钢的N极时,完成从N、S、再到 N极一对磁钢的跨越,这就是电角度的一周。从N极只到 S极,则转子只运行了180°。一台电动机的转子转动一圈有多少电角度,视磁钢对数而定,只有一对磁钢的,电角度和自然角度一致,有两对磁钢的,为2X360°,5对磁钢的,为5X360°,依此类推。
电角度=机械角度×极对数
FOC的电角度校准
void FOC_electrical_angle_calibration() {// FOC calibrationFOC_SVPWM(0, 8, 0);//为什么8?HAL_Delay(400);zero_electrical_angle = FOC_electrical_angle();HAL_Delay(100);FOC_SVPWM(0, 0, 0);}
FOC_SVPWM

去掉了电流采样,所以简单了很多,有位置传感器,所以不用观测器估算位置。对空间矢量作用时间可以直接利用下面的公式

Udc表示电源电压(在代码中是voltage_limit),Uref表示设置的力矩大小(在代码中是target_voltage),Ts表示PWM周期(代码中没有把Ts体现出来,代码中的T1、T2是周期的百分比)。
void FOC_SVPWM(float Uq, float Ud, float angle) {int sector;// Nice video explaining the SpaceVectorModulation (FOC_SVPWM) algorithm// https://www.youtube.com/watch?v=QMSWUMEAejg// the algorithm goes// 1) Ualpha, Ubeta// 2) Uout = sqrt(Ualpha^2 + Ubeta^2)// 3) angle_el = atan2(Ubeta, Ualpha)//// equivalent to 2) because the magnitude does not change is:// Uout = sqrt(Ud^2 + Uq^2)// equivalent to 3) is// angle_el = angle_el + atan2(Uq,Ud)float Uout = _sqrt(Ud * Ud + Uq * Uq) / VOLTAGE_LIMIT; // Actually, Uout is a ratioangle = _normalizeAngle(angle + atan2(Uq, Ud));// find the sector we are in currentlysector = floor(angle / _PI_3) + 1;// calculate the duty cyclesfloat T1 = _SQRT3 * _sin(sector * _PI_3 - angle) * Uout;float T2 = _SQRT3 * _sin(angle - (sector - 1.0f) * _PI_3) * Uout;// two versions possible// float T0 = 0; // pulled to 0 - better for low power supply voltagefloat T0 = 1 - T1 - T2; // modulation_centered around driver->voltage_limit/2// calculate the duty cycles(times)float Ta, Tb, Tc;switch (sector) {case 1:Ta = T1 + T2 + T0 / 2;Tb = T2 + T0 / 2;Tc = T0 / 2;break;case 2:Ta = T1 + T0 / 2;Tb = T1 + T2 + T0 / 2;Tc = T0 / 2;break;case 3:Ta = T0 / 2;Tb = T1 + T2 + T0 / 2;Tc = T2 + T0 / 2;break;case 4:Ta = T0 / 2;Tb = T1 + T0 / 2;Tc = T1 + T2 + T0 / 2;break;case 5:Ta = T2 + T0 / 2;Tb = T0 / 2;Tc = T1 + T2 + T0 / 2;break;case 6:Ta = T1 + T2 + T0 / 2;Tb = T0 / 2;Tc = T1 + T0 / 2;break;default:// possible error stateTa = 0;Tb = 0;Tc = 0;}// Ta, Tb, Tc range [0,1]_writeDutyCycle3PWM(Ta, Tb, Tc);//设置三个通道的占空比}
void _writeDutyCycle3PWM(float dc_a, float dc_b, float dc_c) {// transform duty cycle from [0,1] to [0,_PWM_RANGE]__HAL_TIM_SET_COMPARE(_STM32_TIMER_HANDLE, TIM_CHANNEL_1, _PWM_RANGE*dc_a);__HAL_TIM_SET_COMPARE(_STM32_TIMER_HANDLE, TIM_CHANNEL_2, _PWM_RANGE*dc_b);__HAL_TIM_SET_COMPARE(_STM32_TIMER_HANDLE, TIM_CHANNEL_3, _PWM_RANGE*dc_c);}
Clarke&Park
void FOC_Clarke_Park(float Ia, float Ib, float Ic, float angle, float *Id, float *Iq) {// Clarke transformfloat mid = (1.f / 3) * (Ia + Ib + Ic);float a = Ia - mid;float b = Ib - mid;float i_alpha = a;float i_beta = _1_SQRT3 * a + _2_SQRT3 * b;// Park transformfloat ct = _cos(angle);float st = _sin(angle);*Id = i_alpha * ct + i_beta * st;*Iq = i_beta * ct - i_alpha * st;return;}
电角度与机械角度获取
float FOC_get_mechanical_angle() {return AS5600_ReadSensorRawData() / SENSOR_VALUE_RANGE * _2PI;}float FOC_electrical_angle() {return _normalizeAngle(SENSOR_DIRECTION * POLE_PAIR * FOC_get_mechanical_angle() - zero_electrical_angle);}// rad/s
速度转化
float FOC_get_velocity() {float ts = (float) (HAL_GetTick() - pre_tick) * 1e-3;if (ts < 1e-3) ts = 1e-3;pre_tick = HAL_GetTick();float now_mechanical_angle = FOC_get_mechanical_angle();float delta_angle = now_mechanical_angle - last_mechanical_angle;last_mechanical_angle = now_mechanical_angle;if (fabs(delta_angle) > _PI) {if (delta_angle > 0) {delta_angle -= _2PI;} else {delta_angle += _2PI;}}// return delta_angle;return delta_angle / ts;}
开环-电压控制环
void FOC_open_loop_voltage_control_loop(float Uq) {float electrical_angle = FOC_electrical_angle();// Current sensefloat Id, Iq;cs_get_value();FOC_Clarke_Park(cs_value[0], cs_value[1], cs_value[2], electrical_angle, &Id, &Iq);Id = FOC_low_pass_filter(&lpf_current_d, Id);//低通滤波Iq = FOC_low_pass_filter(&lpf_current_q, Iq);FOC_SVPWM(Uq, 0, electrical_angle);// debugprintf("%.1f,%.1f,%.1f,%.1f,%.1f\n", cs_value[0], cs_value[1], cs_value[2], Id, Iq);}
电流采样
uint8_t cs_get_value() {for (int i = 0; i < 3; ++i) {// Enables ADC, starts conversion of regular group.HAL_ADC_Start(&hadc1);// Wait for regular group conversion to be completed.HAL_ADC_PollForConversion(&hadc1, 100);// 判断ADC是否转换成功// if (HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC)) {// Get ADC regular group conversion result.// Reading register DR automatically clears ADC flag EOC (ADC group regular end of unitary conversion).// 该函数读取寄存器DR同时自动清除了EOC(End Of unitary Conversation)标志位// cs_value[i] = HAL_ADC_GetValue(&hadc1) - cs_zero_value;cs_value[i] = FOC_low_pass_filter(lpf_cs + i, HAL_ADC_GetValue(&hadc1) - cs_zero_value);// } else {// HAL_ADC_Stop(&hadc1);// 如果转换失败就返回-1// return -1;// }}// Stop ADC conversion of regular group, disable ADC peripheral.HAL_ADC_Stop(&hadc1);// cs_value[0] = -cs_value[1] - cs_value[2] + 3 * cs_zero_value;return 0;}
电流环控制
void FOC_current_control_loop(float target_Iq){static float electrical_angle;electrical_angle = FOC_electrical_angle();// Current sensestatic float Id, Iq;cs_get_value();FOC_Clarke_Park(cs_value[0], cs_value[1], cs_value[2], electrical_angle, &Id, &Iq);Id = FOC_low_pass_filter(&lpf_current_d, Id);Iq = FOC_low_pass_filter(&lpf_current_q, Iq);// back feedstatic float Uq, Ud;Uq = pid_get_u(&pid_current_q, target_Iq, Iq);Ud = pid_get_u(&pid_current_d, 0, Id);// front feedUq += 0.008 * Iq;FOC_SVPWM(Uq, Ud, electrical_angle);// debug// printf("%.1f,%.1f,%.1f,%.1f,%.1f\n", cs_value[0], cs_value[1], cs_value[2], Id, Iq);}
速度环控制
void FOC_velocity_control_loop(float target_velocity) {static float now_velocity;now_velocity = FOC_low_pass_filter(&lpf_velocity, FOC_get_velocity());float Uq = pid_get_u(&pid_velocity, target_velocity, now_velocity);float electrical_angle = FOC_electrical_angle();FOC_SVPWM(Uq, 0, electrical_angle);// cs_get_value();// printf("%d,%d,%d\n", cs_value[0], cs_value[1], cs_value[2]);}
位置环控制
void FOC_position_control_loop(float target_angle) {target_angle = _normalizeAngle(target_angle);float now_angle = _normalizeAngle(FOC_get_mechanical_angle() - zero_mechanical_angle);// float now_angle = FOC_get_mechanical_angle();float angle_error = target_angle - now_angle;if (angle_error < -_PI) target_angle += _2PI;else if (angle_error > _PI) target_angle -= _2PI;float target_velocity = pid_get_u(&pid_position, target_angle, now_angle);float now_velocity = FOC_low_pass_filter(&lpf_velocity, FOC_get_velocity());float Uq = pid_get_u(&pid_velocity, target_velocity, now_velocity);float electrical_angle = FOC_electrical_angle();FOC_SVPWM(Uq, 0, electrical_angle);//printf("%.2f,%.2f,%.2f,%.2f\n", target_angle, now_angle, target_velocity, now_velocity);}
模拟弹簧
void FOC_spring_loop(float target_angle, PID_Datatype *pid) {target_angle = _normalizeAngle(target_angle);float now_angle = _normalizeAngle(FOC_get_mechanical_angle() - zero_mechanical_angle);float angle_error = target_angle - now_angle;if (angle_error < -_PI) target_angle += _2PI;else if (angle_error > _PI) target_angle -= _2PI;float Uq = FOC_low_pass_filter(&lpf_spring, pid_get_u(pid, target_angle, now_angle));float electrical_angle = FOC_electrical_angle();FOC_SVPWM(Uq, 0, electrical_angle);}
模拟旋钮
void FOC_knob_loop(uint8_t sector_num) {float now_angle = _normalizeAngle(FOC_get_mechanical_angle() - zero_mechanical_angle);uint8_t now_sector = (uint8_t) floor(now_angle * sector_num / _2PI);float target_angle = now_sector * _2PI / sector_num + _PI / sector_num;float angle_error = target_angle - now_angle;if (angle_error < -_PI) target_angle += _2PI;else if (angle_error > _PI) target_angle -= _2PI;float Uq = pid_get_u(&pid_knob, target_angle, now_angle);float electrical_angle = FOC_electrical_angle();FOC_SVPWM(Uq, 0, electrical_angle);char data = now_sector + '0';HAL_UART_Transmit(&huart1, &data, 1, 0xff);}


