赞
踩
最近接触到的问题用到编码器,所以还是学了一段时间这方面的知识,如果有问题欢迎各位朋友指教:
所用的的器件为:
STM32F407系列,电机型号为JGB37-520(带有霍尔编码器),电池为飞行电池,尤其要吐槽飞行电池的大电流烧了我几个LM298N电机驱动器,后面改成大功率驱动器。
首先基本东西介绍:
JBGB37-520是AB项的减速电机,每个编码器至少要用两个定时器。(关于ABZ的自行找资料)
给出编码器原理:编码器原理
编码器的分类:
按工作原理:光电式、磁电式和触点电刷式
按码盘的刻孔方式:增量式和绝对式两类
由于博主接触面还不是很广,一共就用过两个种类的编码器,都是属于光电编码器和霍尔编码器:一般由6线差分A+ A- B+ B- VCC 和GND;正交编码器:一般是5根线连接,信号线分别为A B Z VCC和GND
编码器线数: 就是旋转一圈你的A(B)会输出多少个脉冲 ,这里的A B就是上面的输出脉冲信号线,它们转一圈发出的脉冲数一样的,不过存在90°相位差 通常都是360线的 线数越高代表编码器能够反应的位置精度越高
给出我在课题中用的电机参数
线速:线速度??? 基础脉冲11*减速比 我的理解是算出线速度然后除以减速比10,
磁环触发极数: 我的理解是上边有个圆盘,里面有11个磁极,AB有两极所以22对极,参考图中给出的霍尔传感器原理。
电机旋转一圈产生11个脉冲: what ’s the fuck ???是单极产生11个脉冲,还是两极一共产生11个脉冲,单片机的双边极性采集得到22或者44个脉冲!这就让我很迷,问过淘宝客服,他们也说不清白,简直了。刚开始计数计数清零,然后手动采集10多组旋转一圈的脉冲数值,发现脉冲数在214呈现正态分布,所以我最终取旋转一圈产生214个脉冲。
后语:写到这214与22成10倍(减速比为10),这难道是巧合???希望有人解答。
关于F407定时器重装载值的的选取问题,这里我就比较迷,到目前为止看到了三种:
(1)基于光电编码器:这里给出参考(光电编码器历程),之前看过一篇对原理介绍的更详细的博客,没有收藏。 拿360个栅格的光栅(线数)来举例子,一度一个光栅。因此AB两极,且程序通常又是双边采集,因此一个栅格会产生四个脉冲,360个栅格会产生360x4个脉冲,因此通常会写成:360x4-1,这样做的好处对求旋转的角度很方便:即编码器的旋转角度直接等于采集到的脉冲数除以4得到角度,然后微分得到角速度,然后由减速比得到车轮线速度(正比关系)。
(2)基于霍尔编码器:参考这篇(霍尔编码器教程),也谢谢这位博客主给出了思路,我也是按照他的方法进行的测试,首先明确定时器计数器的最大计数值0XFFFF,这样才不会溢出,然后直接给到最大,我也是采用这种方式。(后面,发现其实也用不到那么多计数值)这位博客主给出的“齿数比”我也不知道怎么求,百度感觉就是减速比,但是与他的文章不符合,也问过淘宝客服,结果了无音讯———知道的朋友希望留言告知,哈哈!
给出详细细节,也可以参考给出的博客主:
(3)基于STM32CUEMX:目前用这个软件用来统计端口和查询端口,之前也研究过一段时间,会一点点,不过还是习惯于自己调库。给出这位博客主的博文:STM32CUBEMX的使用介绍,并没有介绍的很详细,只是串口输出的数据对我有启发。
代码部分:
代码属于原来工程的下面的一部分,需要同时对车速度进行控制,所以对四个车轮的属性进行了采集,进行反馈,也利于后面换装麦克纳姆轮。代码有点乱,仅供参考:
#include "encoder.h" #include "sys.h" //使用的定时器 //TIM1 3 4 8 void encoder_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//开启TIM4时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);//开启GPIOB时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//开启TIM3时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//开启GPIOB时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);//开启TIM3时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);//开启GPIOB时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE);//开启TIM3时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);//开启GPIOB时钟 GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_TIM4);//PB0引脚复用 GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_TIM4);//PB1引脚服用 GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_TIM3);//PB0引脚复用 GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM3);//PB1引脚服用 GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_TIM1);//PB0引脚复用 GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_TIM1);//PB1引脚服用 GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8);//PB0引脚复用 GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_TIM8);//PB1引脚服用 /*--------------------------------------------------------------*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13; //GPIOD12,GPIOD13 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOD,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //GPIOB0,GPIOB1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_11; //GPIOB0,GPIOB1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOE,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //GPIOB0,GPIOB1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOC,&GPIO_InitStructure); /*--------------------------------------------------------------*/ TIM_TimeBaseStructure.TIM_Period = 65535; //设置下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置用来作为TIMx时钟频率除数的预分频值 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period =65535; //设置下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置用来作为TIMx时钟频率除数的预分频值 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period =65535; //设置下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置用来作为TIMx时钟频率除数的预分频值 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = 65535; //设置下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置用来作为TIMx时钟频率除数的预分频值 不分频 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure); /*--------------------------------------------------------------*/ TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12,TIM_ICPolarity_BothEdge,TIM_ICPolarity_BothEdge); TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 10; //输入滤波器 TIM_ICInit(TIM4, &TIM_ICInitStructure); TIM_ClearFlag(TIM4, TIM_FLAG_Update); //清楚所有标志位 TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); //允许中断更新 TIM4->CNT = 0; TIM_Cmd(TIM4, ENABLE); //使能TIM3 TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_BothEdge,TIM_ICPolarity_BothEdge); TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 10; //输入滤波器 TIM_ICInit(TIM3, &TIM_ICInitStructure); TIM_ClearFlag(TIM3, TIM_FLAG_Update); //清楚所有标志位 TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); //允许中断更新 TIM3->CNT = 0; TIM_Cmd(TIM3, ENABLE); //使能TIM3 TIM_EncoderInterfaceConfig(TIM1, TIM_EncoderMode_TI12,TIM_ICPolarity_BothEdge,TIM_ICPolarity_BothEdge); TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 10; //输入滤波器 TIM_ICInit(TIM1, &TIM_ICInitStructure); TIM_ClearFlag(TIM1, TIM_FLAG_Update); //清楚所有标志位 TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); //允许中断更新 TIM1->CNT = 0; TIM_Cmd(TIM1, ENABLE); //使能TIM3 TIM_EncoderInterfaceConfig(TIM8, TIM_EncoderMode_TI12,TIM_ICPolarity_BothEdge,TIM_ICPolarity_BothEdge); TIM_ICStructInit(&TIM_ICInitStructure); TIM_ICInitStructure.TIM_ICFilter = 10; //输入滤波器 TIM_ICInit(TIM8, &TIM_ICInitStructure); TIM_ClearFlag(TIM8, TIM_FLAG_Update); //清楚所有标志位 TIM_ITConfig(TIM8, TIM_IT_Update, ENABLE); //允许中断更新 TIM8->CNT = 0; TIM_Cmd(TIM8, ENABLE); //使能TIM3 } _EncoderStructure EncoderStructure; void Read_Encoder(void) { int i; EncoderStructure.Encoder_Value[0]=TIM1 -> CNT; //正数 EncoderStructure.Encoder_Value[1]=TIM3 -> CNT; EncoderStructure.Encoder_Value[2]=TIM4 -> CNT; EncoderStructure.Encoder_Value[3]=TIM8 -> CNT; //清零 TIM1 -> CNT=0;TIM3 -> CNT=0; TIM4 -> CNT=0;TIM8 -> CNT=0; for(i=0;i<=3;i++) { if(EncoderStructure.Encoder_Value[i]>6000) { EncoderStructure.Encoder_Value[i]=EncoderStructure.Encoder_Value[i]-65535; //负数 } } // 屏蔽小波动 for(i=0;i<=3;i++) { if(EncoderStructure.Encoder_Value[i]<=2&&EncoderStructure.Encoder_Value[i]>=-2) {EncoderStructure.Encoder_Value[i]=0; } } } _WheelStructure WheelStructure; //10ms中断一次然后测速 //计数CNT 单项极对数为11对,产生11个脉冲 ,两个对极,双边检测,因此单旋转一圈产生44个脉冲 //实际测量旋转一圈旋转的脉冲数为 //217 214 216 214 214 215 214 212 212 218 取众数214 #define Dt_10ms 1e-3 void EnANWh_Velocity(void) { u8 i; //读取编码器的值 EncoderStructure.Encoder_Value[0]=TIM1 -> CNT; EncoderStructure.Encoder_Value[1]=TIM3 -> CNT; EncoderStructure.Encoder_Value[2]=TIM4 -> CNT; EncoderStructure.Encoder_Value[3]=TIM8 -> CNT; //大端取反得负数 for(i=0;i<=3;i++) { if(EncoderStructure.Encoder_Value[i]>6000) { EncoderStructure.Encoder_Value[i]=EncoderStructure.Encoder_Value[i]-65535; } } //清零 TIM1 -> CNT=0;TIM3 -> CNT=0; TIM4 -> CNT=0;TIM8 -> CNT=0; // 屏蔽小波动 for(i=0;i<=3;i++) { if(EncoderStructure.Encoder_Value[i]<=2&&EncoderStructure.Encoder_Value[i]>=-2) { EncoderStructure.Encoder_Value[i]=0; } } //得到旋转的圈数 for(i=0;i<=3;i++) { EncoderStructure.Motor_CylNum[i]=EncoderStructure.Encoder_Value[i]/214; //得到电机的角速度,车轮的角速度,减速比为10 EncoderStructure.Motor_angVel[i]=EncoderStructure.Motor_CylNum[i]*200*pai; //单位(rad/s) WheelStructure.Wheel_angVel[i]=EncoderStructure.Motor_angVel[i]/10 ; //得到车轮的线速度 WheelStructure.Wheel_linVel[i]=WheelStructure.Wheel_angVel[i]*WheelStructure.wheel_R; //得到车轮的行驶距离 WheelStructure.Wheel_distance[i]=WheelStructure.wheel_perimeter*EncoderStructure.Motor_CylNum[i]/10; } } 低通滤波器 //float L_filter(float value,float a) //{ // static float Last_value; // value=Last_value*(256-a)/256+a*value/256; // Last_value=value; // return value; //} #define TIM9_arr 839 #define TIM9_psc 999 //得到快关频率 100hz //车轮速度专用解算定时器 //10ms中断一次 void TIM9_EnAnWh_Vel(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9,ENABLE); ///使能TIM2时钟 TIM_TimeBaseInitStructure.TIM_Period = TIM9_arr; //自动重装载值 TIM_TimeBaseInitStructure.TIM_Prescaler=TIM9_psc; //定时器分频 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; TIM_TimeBaseInit(TIM9,&TIM_TimeBaseInitStructure);//初始化TIM7 TIM_ITConfig(TIM9,TIM_IT_Update,ENABLE); //允许定时器2更新中断 TIM_Cmd(TIM9,ENABLE); //使能定时器9 NVIC_InitStructure.NVIC_IRQChannel=TIM1_BRK_TIM9_IRQn; //定时器2中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3; //抢占优先级3 NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; //子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); } s16 TIM9_flag; void TIM1_BRK_TIM9_IRQHandler(void) { if(TIM_GetITStatus(TIM9,TIM_IT_Update)!=RESET) { EnANWh_Velocity(); TIM_ClearITPendingBit(TIM9,TIM_IT_Update); } }
测得的数据如下:
差不多就这吧!
V12/12
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。