工作原理
无刷电机和有刷电机不同,无刷电机采用三相控制,大概是这样,原理就是安培定则,也叫右手螺旋定则,电生磁来控制转子,也就是说我们需要输出的pwm波有三条通道。
无刷电机用到的传感器是霍尔传感器。霍尔传感器是根据霍尔效应制作的一种磁场传感器。霍尔效应:当电流垂直于外磁场通过半导体时, 载流子发生偏转,垂直于电流和磁场的方向会产生一附加电场,从而在半导体的两端产生电势差, 这一现象就是霍尔效应,这个电势差也被称为霍尔电势差。
在BLDC中一般采用3个开关型霍尔传感器测量转子的位置,由其输出的3位二进制编码去控制三相六臂全桥中的6 个MOS管的导通实现换相。如果将一只霍尔传感器安装在靠近转子的位置,当N极逐渐靠近霍尔传感器即磁感器达到一定值时, 其输出是导通状态;当N极逐渐离开霍尔传感器、磁感应逐渐小时,其输出仍然保持导通状态; 只有磁场转变为S极便达到一定值时,其输出才翻转为截止状态。在S和N交替变化下传感器输出波形占高、 低电平各占50%。如果转子是一对极,则电机旋转一周霍尔传感器输出一个周期的电压波形,如果转子是两对极, 则输出两个周期的波形。
在直流无刷电机中一般把3个霍尔传感器按间隔120度或60度的圆周分布来安装,如果按间隔120度来安装, 则3个霍尔传感器输出波形相差120度电度角,输出信号中高、低电平各占180度电度角。 如果规定输出信号高电平用“1”表示,低电平用“0”表示,则输出的三个信号可以用三位二进制码表示, 如下图所示。
转子每旋转一周可以输出6个不同的信号,这样正好可以满足我们条件。只要我们根据霍尔传感器输出的值来导通MOS管即可。 通常厂家也会给出真值表。一般有两个,一个是对应顺时针旋转,另一个对应的是逆时针旋转。配套电机的真值表如下。
上表的意思是:当检测到的3个霍尔传感器的值,则导通对应值的MOS管。例如,检测到霍尔a、 霍尔b和霍尔c分别为0、0和1,则导通B-和C+对应的MOS管,其他MOS管都要处于截止状态。 当导通对应的MOS管后电机就会旋转一个角度,旋转到下一个霍尔值改变为101,这时在关闭B-和C+, 导通A+和B-,这样电机有将会旋转一个角度直到下一个霍尔值改变, 只要我们按表中的霍尔值导通对应的MOS管电机就可按一定的方向旋转。
软件设计
-
基础定时器产生定时更新执行回调函数
-
回调函数判断是否堵转保护电路
-
回调函数执行pid控制函数bldcm_pid_control()
-
pid控制函数获得电机转动速度,判断执行pid计算,判断运行方向,根据pid计算返回值设置电机速度函数set_bldcm_speed()
-
电机控制函数输出pwm波控制函数set_pwm_pulse
-
pwm控制函数对通道进行占空比调整,再对三相进行换相HAL_TIM_TriggerCallback。
-
换相函数中调取函数get_hall_state获取霍尔传感器的状态作为换相的依据,判断正反转之后进行换相来,换相函数中进行pwm波输出。
mian.c中的控制速度是调控pwm波占空比的多少。
霍尔传感器采用输入捕获模式,三个通道捕获。
无刷电机的多环控制是,类比于有刷电机的多环控制。采用双环,原因是野火无刷电机驱动板上没有电流检测。
void bldcm_pid_control(void)
{
int32_t location_actual = get_motor_location(); // 电机旋转的当前位置
if (bldcm_data.is_enable)
{
float cont_val = 0; // 当前控制值
cont_val = location_pid_realize(&pid_location, location_actual); // 进行 PID 计算
/* 目标速度上限处理 */
if (cont_val > TARGET_SPEED_MAX)
{
cont_val = TARGET_SPEED_MAX;
}
else if (cont_val < -TARGET_SPEED_MAX)
{
cont_val = -TARGET_SPEED_MAX;
}
set_pid_target(&pid_speed, cont_val); // 设定位置的目标值
#if defined(PID_ASSISTANT_EN)
int32_t temp = cont_val;
set_computer_value(SEND_TARGET_CMD, CURVES_CH2, &temp, 1); // 给通道 2 发送目标值
#endif
int32_t actual_speed = get_motor_speed();
cont_val = speed_pid_realize(&pid_speed, actual_speed); // 进行 PID 计算
if (cont_val < 0)
{
cont_val = -cont_val;
bldcm_data.direction = MOTOR_REV;
}
else
{
bldcm_data.direction = MOTOR_FWD;
}
cont_val = (cont_val > PWM_PERIOD_COUNT) ? PWM_PERIOD_COUNT : cont_val; // 上限处理
set_bldcm_speed(cont_val);
#if defined(PID_ASSISTANT_EN)
set_computer_value(SEND_FACT_CMD, CURVES_CH2, &actual_speed, 1); // 给通道 2 发送实际值
set_computer_value(SEND_FACT_CMD, CURVES_CH1, &location_actual, 1); // 给通道 1 发送实际值
#else
printf("实际值:%d, 目标值: %.0f,控制值: %.0f\n", location_actual, get_pid_target(), cont_val);
#endif
}
}