资讯详情

无刷有感电机测速、速度闭环控制

无刷感电机测速,速度闭环控制

1.介绍直流无刷感电机

无刷直流 (Brushless Direct Current, BLDC)电机是一种快速流行的电机类型,在移动机器人领域也有很多应用。在这里,我们将描述无刷直流电机的常见问题。

首先,让我们来看看无刷电机的工作原理。下图显示了三电极、二磁极和内转子无刷电机。

20160920130958307

。从上图可以看出,无刷电机没有碳刷,

内转子无刷电机,顾名思义,磁铁在里面。而外转子无刷电机则相反,它的磁铁“包”在外面。而A、B、C电极在里面。这种设计可以增加电机的扭矩,但速度不能上升。因此,四旋翼无人机上常见的外转子无刷电机(需要大扭矩),而内转子无刷电机通常用于模型车辆和模型船(需要高速)。

要解释这个问题,首先要明白什么是感觉。感觉无刷的感觉是指霍尔传感器,那么什么是霍尔呢?霍尔是指美国物理学家霍尔在1879年研究金属导电机构时发现的霍尔效应。当电流垂直于外磁场通过导体时,导体垂直于磁场和电流方向的两端之间会出现电位差,这就是霍尔效应。这种电势差也叫霍尔电势差。

那么,我们为什么要感知这个东西呢?要解释这个问题,我们必须从一个无刷的缺点开始。无刷电机的速度取决于交流电频率,因此电调应尽量了解当前电机的速度和当前电机的状态。事实上,这对于已经正常运行的电机来说很容易,

但是人们发现无论什么运行状态的无刷电机,它的霍尔效应都是明显的,所以通过霍尔效应电调可以很容易的知道无论高速还是低速电机的运行状态,从而解决了无感无刷电机的毛病!

直流无刷电机的驱动电路一般由6个驱动MOS桥式电路由管道组成。

编程控制无刷直流电机的运行,其底层工作是控制6台MOS管道的两种状态**:导通和关断**。

根据相关的控制理论,我们可以清楚地知道:

(1)一次只能打开两个MOS管道。在任何两个电极上保持电源。

(2)驱动电路上下一排MOS两个不会同时打开。只打开一行,只发送一个电极。

(3)同一列MOS管道不会同时打开,电源会短路。

所以6个MOS管道开关状态只有六种,常见的无刷电机驱动电路原型就是这样,即六步换向法的由来。

假如我们对下一排MOS根据驱动原理一次性完全打开和关闭管道,,这样,我们就实现了调速。

无刷电机的正反转过程通过三个霍尔传感器的六种状态来表示。一般来说,无刷传感器安装了三个霍尔传感器,其特点如下:

(1)霍尔信号不会出现全零(000)和全一(111)两种状态。因此,三个霍尔只有6个状态。

(2)霍尔的六种状态是顺序变化和往复循环。电机的正反转可以通过顺序来判断。

所以我们能理解吗?

常用的霍耳传感器安装方法有120种 ° 安装和60° 安装2 种,2 可输出6种方法 不同的霍耳信号对应6 在不同的区域,当无刷直流电机转子转移到某一区域时,电机可以正常工作。如果霍耳信号与绕组关系错误,则无法正常工作,甚至损坏电机或功率设备。因此,无刷直流电机确定霍耳信号与定子绕组的关系非常重要。

霍耳传感器常用于检测无刷直流电机的换相点。三相无刷直流电机需要3 霍耳传感器检测6 霍耳传感器安装在不同的位置120° 安装和60° 安装2 种方式,120° 安装指3 霍耳传感器相差120° (电角),而60°安装指3 霍耳传感器相差60° (电角度)。2 安装方法最大的区别在于使用60 ° 120° 安装不会输出这2 霍耳传感器的安装方法可以通过这一点来判断。

霍尔的安装角度对驱动器的选择有很大的影响,卖家通常会询问霍尔无刷电机的安装角度。

2.STM32无刷电机轮速测量

单片机转速测量的算法有很多,主要有频率测速法(M法)、周期测速法(T法)等。

:传感器输出的脉冲数量在同一时间T间隔内计算;

将R设为每转脉冲信号,T间隔时间,M是T时间内测量的脉冲数。由此可见,该测速方法的分辨率取决于输出R和测速周期T,极对数越多或测量周期越长,分辨率越小,但一般电机R不大,测量周期不宜过大,因为测量周期过大会影响测量速度的反应速度,降低系统的实时性。因此,这种方法是不可取的。

:转速是通过测量传感器发出的相邻两个脉冲之间的T来计算的;

用计数器收集三个霍尔的脉冲信号;从脉冲触发到下一个脉冲触发的新时间,测量每两个脉冲之间的时间T;

所以,T电机速度法测速speed=N/T;

,获取N有两种方法。首先,它可以根据电机参数获得。除以车轮周长的脉冲数。第二,可以测量10圈车轮的累积脉冲,寻求平均值。

(1)尽量细化速度分辨率。

(2)计算轮子的实际线速m/s,而不是电机的速度。因此,应明确两个脉冲对应轮子旋转的物理距离。

(3)用速度的正负值清晰区分轮子的正反转。因此,有必要根据霍尔组合状态来判断电机所谓的正反。

首先,通过,获得同一触发时刻的三个霍尔信号状态,并通过二进制组合成状态数字;根据下一个状态数字区分速度正反。

其次,通过,计算每两个脉冲之间的时间。也就是说,从上升到下降,或者从下降到上升,或者从下降到下降等等。

最后,计算速度,改变符号。

,这里提到的每两个脉冲不是霍尔的每两个脉冲,而是三个霍尔的每两个脉冲,包括上升和下降。

STM32F103单片机 120度霍尔的无刷有感电机 keil5。

以电机为例。文件,可以

外部中断配置代码:

///电机霍尔外部中断配置函数 void Hall_EXIT_Config(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{ 
        
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	u8 EXTI_IRQn;
	uint8_t GPIO_PortSource,GPIO_PinSource;
	uint32_t EXTI_Line;
	
	//外部中断,需要使能AFIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);   
	
	//使能GPIO时钟
	if(GPIOx == GPIOA) 	    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE),GPIO_PortSource = GPIO_PortSourceGPIOA;
	else if(GPIOx == GPIOB) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE),GPIO_PortSource = GPIO_PortSourceGPIOB;
	else if(GPIOx == GPIOC) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE),GPIO_PortSource = GPIO_PortSourceGPIOC;
	else if(GPIOx == GPIOD) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE),GPIO_PortSource = GPIO_PortSourceGPIOD;
	else if(GPIOx == GPIOE) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE),GPIO_PortSource = GPIO_PortSourceGPIOE;
	else if(GPIOx == GPIOF) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE),GPIO_PortSource = GPIO_PortSourceGPIOF;
	else if(GPIOx == GPIOG) RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE),GPIO_PortSource = GPIO_PortSourceGPIOG;	

	//选择中断线,中断服务函数
	if(GPIO_Pin == GPIO_Pin_0)       GPIO_PinSource = GPIO_PinSource0, EXTI_Line = EXTI_Line0, EXTI_IRQn = EXTI0_IRQn;
	else if(GPIO_Pin == GPIO_Pin_1)  GPIO_PinSource = GPIO_PinSource1, EXTI_Line = EXTI_Line1, EXTI_IRQn = EXTI1_IRQn;
	else if(GPIO_Pin == GPIO_Pin_2)  GPIO_PinSource = GPIO_PinSource2, EXTI_Line = EXTI_Line2, EXTI_IRQn = EXTI2_IRQn;
	else if(GPIO_Pin == GPIO_Pin_3)  GPIO_PinSource = GPIO_PinSource3, EXTI_Line = EXTI_Line3, EXTI_IRQn = EXTI3_IRQn;
	else if(GPIO_Pin == GPIO_Pin_4)  GPIO_PinSource = GPIO_PinSource4, EXTI_Line = EXTI_Line4, EXTI_IRQn = EXTI4_IRQn;
	else if(GPIO_Pin == GPIO_Pin_5)  GPIO_PinSource = GPIO_PinSource5, EXTI_Line = EXTI_Line5, EXTI_IRQn = EXTI9_5_IRQn;
	else if(GPIO_Pin == GPIO_Pin_6)  GPIO_PinSource = GPIO_PinSource6, EXTI_Line = EXTI_Line6, EXTI_IRQn = EXTI9_5_IRQn;
	else if(GPIO_Pin == GPIO_Pin_7)  GPIO_PinSource = GPIO_PinSource7, EXTI_Line = EXTI_Line7, EXTI_IRQn = EXTI9_5_IRQn;
	else if(GPIO_Pin == GPIO_Pin_8)  GPIO_PinSource = GPIO_PinSource8, EXTI_Line = EXTI_Line8, EXTI_IRQn = EXTI9_5_IRQn;
	else if(GPIO_Pin == GPIO_Pin_9)  GPIO_PinSource = GPIO_PinSource9, EXTI_Line = EXTI_Line9, EXTI_IRQn = EXTI9_5_IRQn;
	else if(GPIO_Pin == GPIO_Pin_10) GPIO_PinSource = GPIO_PinSource10,EXTI_Line = EXTI_Line10,EXTI_IRQn = EXTI15_10_IRQn;
	else if(GPIO_Pin == GPIO_Pin_11) GPIO_PinSource = GPIO_PinSource11,EXTI_Line = EXTI_Line11,EXTI_IRQn = EXTI15_10_IRQn;
	else if(GPIO_Pin == GPIO_Pin_12) GPIO_PinSource = GPIO_PinSource12,EXTI_Line = EXTI_Line12,EXTI_IRQn = EXTI15_10_IRQn;
	else if(GPIO_Pin == GPIO_Pin_13) GPIO_PinSource = GPIO_PinSource13,EXTI_Line = EXTI_Line13,EXTI_IRQn = EXTI15_10_IRQn;
	else if(GPIO_Pin == GPIO_Pin_14) GPIO_PinSource = GPIO_PinSource14,EXTI_Line = EXTI_Line14,EXTI_IRQn = EXTI15_10_IRQn;
	else if(GPIO_Pin == GPIO_Pin_15) GPIO_PinSource = GPIO_PinSource15,EXTI_Line = EXTI_Line15,EXTI_IRQn = EXTI15_10_IRQn;

	//引脚初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin;	              //端口配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         //上拉输入
	GPIO_Init(GPIOx, &GPIO_InitStructure);			      //根据设定参数初始化GPIO
	
	GPIO_EXTILineConfig(GPIO_PortSource,GPIO_PinSource);
	
	EXTI_InitStructure.EXTI_Line    = EXTI_Line;
	EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;	
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;  //上升下降都触发
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);	 	                            //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI_IRQn;			        //使能按键所在的外部中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;		    //子优先级1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;				    //使能外部中断通道
	NVIC_Init(&NVIC_InitStructure); 
}

定时器配置代码:

void TIM4Init(u16 Timing,u16 Divis)
{ 
        
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; 
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
  
	TIM_TimeBaseStructure.TIM_Period = Timing;//计数值
	TIM_TimeBaseStructure.TIM_Prescaler = Divis; //预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //不分频72Mhz时钟频率
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式 
	
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
	
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //允许定时器3更新中断

	TIM_Cmd(TIM4, ENABLE);//开启TIM4
	
	NVIC_InitStructure.NVIC_IRQChannel=TIM4_IRQn; //定时器4中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x03; //抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x01; //子优先级1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}

左轮三相霍尔处理函数:

//左轮三相霍尔处理函数
void left_hall_deal(TIM_TypeDef* TIMx,char *motor_state,char *hall_state_last,char *hall_state_now,unsigned short int *count,double *speed)
{ 
        
	if(*motor_state==2){ 
                    //如果是静止状态,之前的计数,不论是什么样子都为零
		*count=0;                   //计数为零
		TIM_SetCounter(TIMx,0);	    //定时器清零
	}
	else                            //如果不是静止状态
	{ 
        
		*count=TIM_GetCounter(TIMx);//记录两个脉冲之间的定时器的计数值
		TIM_SetCounter(TIMx,0);		//清零定时计数器,开始新的计数
	}
	
	if(*count==0){ 
                          //如果定时计数器计数为零,则速度为零
		*speed=0;
	}
	else if(*count>10)              //防止重复进入中断,因为电机的速度不会达到,16077.1mm/s = 16.0071m/s
	{ 
        
		//0.5/311.0=0.00160771704 每两个脉冲之间轮子走的真实距离,这里根据大家自己的情况轮子情况而定
		//0.001607717/(1/100000.0)=160.771704 两个脉冲之间只计量到一个数的速度是160.771704m/s,这里的100000是因为定时器的计数频率是100k,也就是每记一个数用时1/100000s。
		//计数器个数越多,速度越小,个数超过10000认为静止,10000可以修改,也就是计数器的溢出值
		*speed=1000*160.771704/(double)*count;
		
		*count=0;		            //速度计算完毕,计数缓存清零,等待下次计数
	}
	//获取三路霍尔的组合状态的一种容易理解的方法
	*hall_state_now=(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_10)<<2)|(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_11)<<1)|(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_12));
	
	if(*count>10||*count==0)
	{ 
        
		switch(*hall_state_last)
		{ 
        // 反转 正转 不变
			case 1:if(*hall_state_now!=3){ 
        *motor_state=1;}else if(*hall_state_now==1){ 
        }else{ 
        *motor_state=0;};break;
			case 3:if(*hall_state_now!=2){ 
        *motor_state=1;}else if(*hall_state_now==3){ 
        }else{ 
        *motor_state=0;};break;
			case 2:if(*hall_state_now!=6){ 
        *motor_state=1;}else if(*hall_state_now==2){ 
        }else{ 
        *motor_state=0;};break;
			case 6:if(*hall_state_now!=4){ 
        *motor_state=1;}else if(*hall_state_now==6){ 
        }else{ 
        *motor_state=0;};break;
			case 4:if(*hall_state_now!=5){ 
        *motor_state=1;}else if(*hall_state_now==4){ 
        }else{ 
        *motor_state=0;};break;
			case 5:if(*hall_state_now!=1){ 
        *motor_state=1;}else if(*hall_state_now==5){ 
        }else{ 
        *motor_state=0;};break;
			default:break;
		}	
	}	
	
	if(*motor_state==1)              //根据电机正反,给速度符号
		*speed=-*speed;	
	*hall_state_last=*hall_state_now;//记录上一次霍尔组合状态,用于下一次判断电机正反 
}

左轮三相霍尔中断服务函数:


//L
void EXTI15_10_IRQHandler(void)
{ 
        
	if(EXTI_GetITStatus(EXTI_Line10)==SET){ 
        
		EXTI_ClearITPendingBit(EXTI_Line10);  //清除LINE10线路挂起位 
	}
	if(EXTI_GetITStatus(EXTI_Line11)==SET){ 
        
		EXTI_ClearITPendingBit(EXTI_Line11);  //清除LINE11线路挂起位 
	}
	if(EXTI_GetITStatus(EXTI_Line12)==SET){ 
        
		EXTI_ClearITPendingBit(EXTI_Line12);  //清除LINE12线路挂起位 
	}
	left_hall_deal(TIM4,&left_motor_state,&left_hall_state_last,&left_hall_state_now,&left_count,&left_speed);
}

定时器中断服务函数:

void TIM4_IRQHandler(void)
{ 
        
	if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET) //溢出中断
	{ 
        
		TIM_ClearITPendingBit(TIM4,TIM_IT_Update);  //清除中断标志位
		left_motor_state=2;//电机静止,还需要根据具体情况,测量电机最低速是多少
		left_count=0;
		left_speed=0;
	}
}

主函数:

//=================================头文件===================================
#include "sys.h"
#include "delay.h"
#include "exti.h"
#include "tim4.h"

/*=================================================================== 程序功能:直流无刷有感电机的速度测量测试 程序编写:公众号:小白学移动机器人 其他 :如果对代码有任何疑问,可以私信小编,一定会回复的。 ===================================================================== ------------------关注公众号,获得更多有趣的分享--------------------- ===================================================================*/
int main(void)
{ 
        	
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁用JTAG 启用 SWD
	
	NVIC_PriorityGroupConfig(2);	     //=====设置中断分组
	
	delay_init();	                     //=====延时函数初始化 

	Hall_EXIT_Config(GPIOE,GPIO_Pin_10); //LA 霍尔外部中断检测用
	Hall_EXIT_Config(GPIOE,GPIO_Pin_11); //LB
	Hall_EXIT_Config(GPIOE,GPIO_Pin_12); //LC 
    
	TIM4Init(10000-1,720-1);             //=====测速用
    
	while(1)
	{ 
        
	}
}
//===================================END======================================

3.STM32无刷电机速度PID闭环控制

关于无刷电机的速度闭环控制和有刷直流除了速度测量之外没有区别,可以参照我之前的文章,

https://blog.csdn.net/zhao_ke_xue/article/details/108112694

4.参考:

https://blog.csdn.net/dddxxxx/article/details/52564571

https://wenku.baidu.com/view/938a55d3162ded630b1c59eef8c75fbfc77d94d7.html

https://blog.csdn.net/do_just/article/details/52443442

5.公众号:

标签: 18lb接近传感器开关用法

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台