热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ETR获取转速及PID调节原则

一、前言由于单片机硬件资源稀缺,有些时候无法使用正交编码的方式获取速度,可使用单脉冲ETR功能获取转速,通过软件设定的转速判定方向。其他方

一、前言

        由于单片机硬件资源稀缺,有些时候无法使用正交编码的方式获取速度,可使用单脉冲ETR功能获取转速,通过软件设定的转速判定方向。其他方案缺点:比如使用外部中断方式,来一个信号触发一次中断,在中断程序里实现计数累加,但由于被统计的信号频率较高,而中断本身也是需要时间的,往往导致有些脉冲没被统计而发生丢数的问题。况且,CPU这样频繁地去响应中断还会衍生出其它系统性问题。

         对于这种情况,我们可以将被统计信号连接到定时器的ETR脚,并作为定时器的计数时钟,择时读取计数器的值和溢出次数即可。这样既避免了CPU频繁进中断而无法应对别的事情的困境,也避免了因CPU优先忙于别的事情而来不及响应外部中断导致计数出错的麻烦。对于STM32(GD32)来讲,从ETR脚引入时钟信号,可以有两种模式。

第一种模式,即外部时钟1模式,此时来自ETR脚的信号经过滤波、边沿检测和极性选择后,以触发信号的角色连接到从模式控制器,并作为定时器的时钟源,即下图中的1路。
第二种模式,即外部时钟2模式,来自ETR脚的时钟信号经过极性选择、分频、滤波后不经过从模式控制器,而是像内部时钟源一样直接为计数器提供计数时钟,即下图中的2路。


二、编码器配置


1、GPIO配置

static void GPIOConfiguration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // 关闭JTAG功能

//  GPIO config
GPIO_InitStructure.GPIO_Pin = ENCODER_LEFT_A_PIN;// | ENCODER_LEFT_B_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2, ENABLE);//重映射TIM2的CH1、CH2到PA15和PB3
// GPIO config
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = ENCODER_RIGHT_A_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

}


2、Timer配置

static void encoderConfiguration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB1Periph_TIM2, ENABLE);

TIM_DeInit(ENCODER_LEFT_TIMER);
TIM_DeInit(ENCODER_RIGHT_TIMER);

TIM_TimeBaseStructure.TIM_Prescaler = 0x0;
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(ENCODER_LEFT_TIMER, &TIM_TimeBaseStructure);
TIM_TimeBaseInit(ENCODER_RIGHT_TIMER, &TIM_TimeBaseStructure);

//选择ETR通过外部时钟2输入时钟
TIM_ETRClockMode2Config(ENCODER_LEFT_TIMER, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);
TIM_ETRClockMode2Config(ENCODER_RIGHT_TIMER, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);

TIM_ClearITPendingBit(ENCODER_LEFT_TIMER,TIM_IT_Update);
TIM_ClearITPendingBit(ENCODER_RIGHT_TIMER,TIM_IT_Update);
TIM_ITConfig(ENCODER_LEFT_TIMER,TIM_IT_Update,ENABLE);
TIM_ITConfig(ENCODER_RIGHT_TIMER,TIM_IT_Update,ENABLE);
TIM_SetCounter(ENCODER_LEFT_TIMER, 0);
TIM_SetCounter(ENCODER_RIGHT_TIMER, 0);
TIM_Cmd(ENCODER_LEFT_TIMER, ENABLE);
TIM_Cmd(ENCODER_RIGHT_TIMER, ENABLE);
}


3、部分函数接口可供参考


函数名称

功能

TIM_DeInit恢复缺省配置
TIM_TimeBaseInit时基单元初始化
TIM_TimeBaseStructInit赋给结构体变量一个默认值
TIM_Cmd使能计数器
TIM_ITConfig使能中断输出信号
TIM_InternalClockConfig选择内部时钟
TIM_ITRxExternalClockConfig选择ITRx其他定时器的时钟
TIM_TIxExternalClockConfig选择TIx捕获通道的时钟
TIM_ETRClockMode1Config选择ETR通过外部时钟1输入的时钟
TIM_ETRClockMode2Config选择ETR通过外部时钟2输入的时钟
TIM_ETRConfig单独配置ETR引脚的预分频器,极性,滤波器
TIM_PrescalerConfig单独配置预分频值
TIM_CounterModeConfig改变计数器的计数模式
TIM_ARRPreloadConfig自动重装器预装功能配置
TIM_SetCounter给计数器写入一个值
TIM_SetAutoreload给自动重装器写入一个值
TIM_GetCounter获取当前计数器的值
TIM_GetPrescaler获取当前预分频器的值


三、转速获取

由于采用的ETR单脉冲获取转速故无法感知反向,在故编码器反馈的速度会一直为正的。在此项目中获取转速的频率为250HZ,g_encoder.right_encoder_delta为两次读取的脉冲数的差,g_encoder.right_encoder_delta * ENCODER_UPDATE_FREQUENCY及得到脉冲的频率。在宏定义中有以下参数,脉冲的频率除以理论一圈的脉冲数就能得到抹布的转速。

#define WHEEL_PPR 1 // ETR不倍频
#define WHEEL_POLAR_NUM 4 // 极对数(4对8极)
#define GERA_RATIO 30.82 //减速比
#define PULSE_PER_CIRCLE (s32)(WHEEL_POLAR_NUM * WHEEL_PPR * GERA_RATIO) //493.12 一圈理论的脉冲数


转速1获取


static void updateLeftEncoder(void)
{
TMopMotor left_mop;
getMopMotorInfor(&left_mop);
if(g_encoder.left_first_measure_flag == FALSE)
{
g_encoder.left_encoder = (int16_t) ENCODER_LEFT_TIMER->CNT;
g_encoder.left_encoder_delta = g_encoder.left_encoder - g_encoder.last_left_encoder ;

// Counter down, the pulse decrease

g_encoder.last_left_encoder = g_encoder.left_encoder;
g_encoder.left_speed = (s32)g_encoder.left_encoder_delta * ENCODER_UPDATE_FREQUENCY;
g_encoder.left_rpm = g_encoder.left_speed * 60 / PULSE_PER_CIRCLE ;
g_encoder.left_encoder_sum += g_encoder.left_encoder_delta;
}
else
{
g_encoder.left_first_measure_flag = FALSE;
g_encoder.left_encoder = 0;
g_encoder.last_left_encoder = g_encoder.left_encoder;
g_encoder.left_encoder_delta = g_encoder.left_encoder - g_encoder.last_left_encoder;
g_encoder.left_encoder_sum = g_encoder.left_encoder;
g_encoder.left_encoder_overflow = 0;
g_encoder.left_speed = 0;

ENCODER_LEFT_TIMER->CNT = g_encoder.left_encoder;
}
}


转速2获取


static void updateRightEncoder(void)
{
TMopMotor right_mop;
getMopMotorInfor(&right_mop);
if(g_encoder.right_first_measure_flag == FALSE)
{
g_encoder.right_encoder = ENCODER_RIGHT_TIMER->CNT;

g_encoder.right_encoder_delta = (g_encoder.right_encoder - g_encoder.last_right_encoder);

// Counter down, the pulse decrease
g_encoder.last_right_encoder = g_encoder.right_encoder;
g_encoder.right_speed = (s32)g_encoder.right_encoder_delta * ENCODER_UPDATE_FREQUENCY;
g_encoder.right_rpm = g_encoder.right_speed * 60 / PULSE_PER_CIRCLE ;
g_encoder.right_encoder_sum += g_encoder.right_encoder_delta;

}
else
{
g_encoder.right_first_measure_flag = FALSE;
g_encoder.right_encoder = 0;
g_encoder.last_right_encoder = g_encoder.right_encoder;
g_encoder.right_encoder_delta = g_encoder.right_encoder - g_encoder.last_right_encoder;
g_encoder.right_encoder_sum = g_encoder.right_encoder;
g_encoder.right_encoder_overflow = 0;
g_encoder.right_speed = 0;

ENCODER_RIGHT_TIMER->CNT = g_encoder.right_encoder;
}


四、PID调节

实际最终的PID参数需根据实际项目进行调整,已确保响应快、抗干扰能力强。


1.PID调试一般原则


a.在输出不振荡时,增大比例增益P。
b.在输出不振荡时,减小积分时间常数Ti。
c.在输出不振荡时,增大微分时间常数Td。



2.一般步骤


a.确定比例增益P
  确定比例增益P 时,首先去掉PID的积分项和微分项,一般是令Ti=0、Td=0(具体见PID的参数设定说明),使PID为纯比例调节。输入设定为系统允许的最大值的60%~70%,由0逐渐加大比例增益P,直至系统出现振荡;再反过来,从此时的比例增益P逐渐减小,直至系统振荡消失,记录此时的比例增益P,设定PID的比例增益P为当前值的60%~70%。比例增益P调试完成。


b.确定积分时间常数Ti
  比例增益P确定后,设定一个较大的积分时间常数Ti的初值,然后逐渐减小Ti,直至系统出现振荡,之后在反过来,逐渐加大Ti,直至系统振荡消失。记录此时的Ti,设定PID的积分时间常数Ti为当前值的150%~180%。积分时间常数Ti调试完成。


c.确定积分时间常数Td
  积分时间常数Td一般不用设定,为0即可。若要设定,与确定 P和Ti的方法相同,取不振荡时的30%。


d.系统空载、带载联调,再对PID参数进行微调,直至满足要求


推荐阅读
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有