英飞凌TC264无刷驱动方案simplefoc移植(1)-霍尔编码器移植
从今天开始,我将会写一个系列博客,分享我在有感无刷电机移植simplefoc的全过程,并提出自己的理解和改进方案,希望各位大佬讨论。
十七届直立单车组在十六届的基础之后允许动量轮的存在,维持车模平衡,所以就需要使用英飞凌的无刷驱动方案。
本文基于链接:
一、 基于英飞凌MCU GTM模块的无刷电机驱动方
二、 基于英飞凌AURIX的平衡单车组BLDC项目开源
三、 逐飞科技TC264开源库
四、 Arduino SimpleFOClibrary
五、SimpleFOC移植STM32(一)—简介
一、硬件电路配置
无刷电机驱动板 :使用TC264单片机 详细链接如下
17届平衡单车组英飞凌无刷电机驱动英飞凌TC264方案驱动 逐飞科技
无刷电机为选择有感、三槽两极、2860Kv(Kv表示每增加一伏电压电机增加的转速,最高12V)、尺寸36(mm)*50(mm)、额定功率190W、支持1-3S锂电池供电。
二 、 问题的提出
在逐飞的方案中:
扫描霍尔主要是统计每次换相的时间,如果换相时间过长则认为出现故障此时应该及时关闭输出。
当电机正常运行的时候将每次换相的时间都保存在数组内,当得到最近6次的换相时间之后,我们就能知道电机转动一圈所花费的时间,从而就能够计算出电机的转速了。
然后根据读取到的霍尔值计算出下次期望的霍尔值。 霍尔扫描结束之后,开始检查延时换相时间是否到,时间没有到则延时时间减一,延时时间为0的时候开始进行换相动作,这里延时换相的原因是因为在电机高速运转的时候霍尔有滞后导致的,可能有人问为什么霍尔滞后了,你还要延时换相呢,
因为我们采用的方法是,当霍尔出现滞后之后,我们换相的时候并不是换到下一相,而是换到了下下相,这样就相当于超前换相了,所以我们需要加一定的延时去匹配,从而得到一个最佳的换相点。
但是,这就这些操作使用的是CCU6模块,这就需要CPU频繁的处理无刷驱动的换相控制而且方波的控制缺点是噪声特别大,低速的时候会导致车身震荡。
三 、霍尔编码器原理
霍尔编码器检测转子位置,一共安装三个霍尔分别间隔120度安装,霍尔输出的波形如下图所,每当波形改变的时候就需要进行换相。
但是霍尔采集的角度数据是离散的,比如30, 60, 90等,比较适合方波控制。
四 、霍尔编码角度速度读取
4-1底层配置
宏定义霍尔编码器的io口以及极对数,同时设置方向枚举变量
//定义电机极对数
#define POLEPAIRss 1
#define HALL_A_PIN P15_6
#define HALL_B_PIN P15_7
#define HALL_C_PIN P15_8
/**
* Direction structure
*/
enum Direction{
CW = 1, //clockwise
CCW = -1, // counter clockwise
UNKNOWN = 0 //not yet known or invalid state
};
初始化io口,这里必须设置输入上拉模式
初始化的时候使用gpio_get先读一次io口,并更新此时的状态。
// HallSensor initialisation of the hardware pins
// and calculation variables
void HallSensor_init(){
// initialise the electrical rotations to 0
electric_rotations = 0;
gpio_init(HALL_A_PIN, GPI, 0, PULLDOWN);
gpio_init(HALL_B_PIN, GPI, 0, PULLDOWN);
gpio_init(HALL_C_PIN, GPI, 0, PULLDOWN);
//读取一下当前的霍尔值
A_active = gpio_get(HALL_A_PIN);
B_active = gpio_get(HALL_B_PIN);
C_active = gpio_get(HALL_C_PIN);
HallSensor_updateState();
pulse_timestamp = systick_getval_us(STM0)
}
4-2 状态更新
更新霍尔状态,调用的是simple的库,有兴趣的可以直接看一。研究一下原理,主要就是判断当前状态和上次状态的变化。
如果变化,利用霍尔编码表查阅状态,判断方向,累计计数。
// seq 1 > 5 > 4 > 6 > 2 > 3 > 1 000 001 010 011 100 101 110 111
const int8_t ELECTRIC_SECTORS[8] = {
-1, 0, 4, 5, 2, 1, 3 , -1 };
/**
* Updates the state and sector following an interrupt
*/
void HallSensor_updateState() {
long new_pulse_timestamp = systick_getval_us(STM0);
int8_t new_hall_state = C_active + (B_active << 1) + (A_active << 2);
// glitch avoidance #1 - sometimes we get an interrupt but pins haven't changed
if (new_hall_state == hall_state) {
return;
}
hall_state = new_hall_state;
int8_t new_electric_sector = ELECTRIC_SECTORS[hall_state];
static int old_direction;
if (new_electric_sector - electric_sector > 3) {
//underflow
direction = CCW