导言
上一章节《无刷电机控制 - SimpleFOC05 - 基于STM32F103+CubeMX,实现速度开环控制》完成三相无刷电机的开环速度控制。接下来,开始调试编码器(位置传感器)。为接下来的位置闭环控制,速度闭环控制做准备。
github:
项目源码:https://github.com/q164129345/MCU_Develop/tree/main/simplefoc06_stm32f103_encoder_align
gitee(国内):
项目源码:https://gitee.com/wallace89/MCU_Develop/tree/main/simplefoc06_stm32f103_encoder_align
RTT_Viewer
编码器校准的动作
飞书20250108-121114
一、校准编码器的目的
a.校准编码器的目的是确定编码器的方向direction与计算出零电角度zero_electric_angle。 编码器输出的方向可能与电机的旋转方向不一致,它们之间的方向关系是1或者-1。校准方向一次只需要进行一次,同一个电机与编码器只需要校准一次,后续就可以写死在程序里。编码器安装在电机轴上时,可能由于安装的角度误差,导致编码器与电机转子之间产生固定的角度偏移,它就是偏移角offset。理论上来说,这个偏移角等于0。每一个电机与编码器的组合都要校准一遍,因为每一个的安装公差都不一样。校准之后,可以将偏移角保存在Flash里,程序初始化时,从flash里读取出来。
b.为什么需要计算零电角度(zero_electric_angle)? 零电角度指在电机控制算法(如 FOC)中,把传感器读到的某个转子位置定义为“电角度=0”的参考点。电机控制(尤其是 FOC)需要知道转子和定子磁场之间的相对角度。如果没有统一的“零基准”,控制器无法准确判断转子到底处在哪个“电角度”,从而无法正确生成相电压来驱动电机。编码器或霍尔传感器的机械装配位置往往并不在物理“0°”上。总之,0电角度的目的是让电角度与机械角度联系起来。
c.不计算零电角度,会怎样?
1、转矩输出会不稳定。传感器的读数和电机实际的电角度对不上。可能会出现反转、抖动、或转不动等问题。最不幸的应该是d轴与q轴调换了,导致转子卡死。
2、效率和性能受损。如果电机在错位的电角度下工作,电流无法对准磁极的最佳方向,浪费能量、温升增加,且输出力矩下降。
二、代码
2.1、user_main.cpp
如上图所示,增加三句代码后,运行代码motor_initFOC()
的时候会执行编码器的校准,最终的到编码器方向CCW与编码器偏移角2.0924。
如上所示,编译代码成功,下载到开发板即可。
三、细节补充
3.1、motor.initFOC()执行编码器校准的流程
如上所示,simpleFOC校准编码器的代码真的很简单。
3.2、为什么计算偏移角时,需要将磁场方向固定在电角度_3PI_2(270°)?
a. 便于实现一个稳定的转子位置。在 FOC 控制中,转子的稳定位置依赖于定子产生的磁场方向。如果施加的电角度为_3PI_2,实际上是将电机定子的磁场指向一个固定方向。
- 电角度270°是一个常用的选择,因为这个角度会使得转子受到定子磁场的吸引(而不是排斥),最终停留在唯一确定的位置。在数学上,“电角度 0°、电角度 90°、电角度 180°,其实都可以拿来当做你的“零参考”。因为正余弦函数有 360° 的周期性,最后只要记住“我目前用哪个角度来做零点”,算法都能正常工作。所以,采用270°作为校准的电角度不是取决于软件,而是硬件。
- 为什么选择固定方向:校准的关键是将转子停在一个已知的位置,以便读取编码器的机械角度。因此,任何固定且有效的电角度都可以实现这一目标。
b.为什么说励磁到 270°,读取到的电角度就是 0°?
因为我们人为规定:当电机受控锁定在“定子电角度 270°”时,读到的传感器输出(本次实验读到的是2.0924),被赋予“0° (电角度)”的含义,也叫“零参考点”。这就好比在时钟表盘上,指针实际指到 “9 点钟” 位置,但我们决定从现在开始把“9点钟”当作我们的“0°”。
simpleFOC源码:
3.3、转子的机械角度与电角度的关系
a.电角度 = 极对数p x 机械角度。 极对数7的无刷电机的电角度范围是(0° ~ 360° x 7) = 0° ~ 2520°。如果只有 1 对极:扫过一次 N-S,电角度就转了 360°;机械上也转了 360°。如果有 7 对极:转子转一圈机械角度(360°),定子却感受到 7 次 N-S 的完整通过 → 电角度=7×360°=2520°。
b.电角度的用途:
- Park/Clarke 变换:把三相电流转换到旋转坐标系(d-q轴),需要知道电角度来确定坐标轴的旋转位置。
- 无刷换相:无刷直流电机(BLDC)在进行六步换相或正弦驱动时,需要实时知道当前转子的电角度,以切换或调制合适的绕组励磁。
c.机械角度的用途:
- 位置或速度控制:如果要让电机旋转到某个机械位置(比如 90°),我们用机械角度来参考。
- 外部运动系统的坐标:如机械臂、轮子等,都关注物理位置。
3.4、为什么FOCMotor::electricalAngle()的输出被限制在 0 ~ 2π?
float FOCMotor::electricalAngle(){
// if no sensor linked return previous value ( for open loop )
if(!sensor) return electrical_angle;
return _normalizeAngle( (float)(sensor_direction * pole_pairs) * sensor->getMechanicalAngle() - zero_electric_angle );
}
FOCMotor::electricalAngle()
输出的是当前的电角度,那么电角度 = 极对数p x 机械角度。为什么函数里使用函数_normalizeAngle()将电角度归一化到0 ~ 2π?
a.FOC控制算法只需要“相位”,0 ~ 2π区间内足矣。 在电机控制算法(尤其是 FOC)中,我们关心的“电角度”其实是一个在正弦/余弦空间里“周期为 360°(或 2π)”的相位角。只要知道当前电角度在 0 ~ 2π 范围内(或 0 ~ 360°),就能计算正、余弦进行坐标变换(Park / Clarke 变换)或换相等。换言之,电角度多绕几圈(例如 2520° 对应 7 圈)和只取余数 (0~360° 这一圈) 对正余弦计算结果是一样的。例如,正弦波Sin(θ)在0或0+2kπ(k是整数)时,计算的结果是一样的。如果应用场景需要跟踪转过多少圈,可以在机械角度或传感器圈计数的层面上去做,而不是在“电角度”输出里进行。
b.避免数值溢出或精度问题。 如果让电角度不断累加,很可能越转越大,数值最终会溢出 float/int 的范围或变得难以管理。用作实时控制时,各种算法、观察器、滤波器、状态机都通常假定角度在0 ~ 2π或者-π ~ π之间。
例如,若让电角度保持累加到 2520°(极对数7)、5040°(极对数14)……乃至更大,会给各种运算、比较、滤波带来麻烦。
综上所述,由于正弦和余弦函数的 2π 周期性,我们在做 FOC(场向量控制)或换相等运算时,
- 只要知道角度在0 ~ 2π(或者0 ~ 360)范围内足够了。
- 多出来的部分(比如极对数7的三相无刷电机的 7 倍机械角度,也就是0 ~ 2520°),在数学上跟取模到0 ~ 360°是等价的,对控制算法不会造成差别。
这就是为什么FOCMotor::electricalAngle()
在函数的最后,用_normalizeAngle()
将电角度维持在0 ~ 2π的区间里,方便直接调用三角函数进行坐标变换或矢量运算。