1. STM32读取编码器数据
使用霍尔传感器进行电机的闭环反馈。霍尔传感器通过磁电转换将输出轴上的机械几何位移量转换为脉冲或数字量。霍尔传感器由霍尔码盘和霍尔元件组成。霍尔码盘是在一定直径的圆板上等分的布置有不同的磁极。霍尔码盘与电机同轴,电机旋转时,霍尔元件检测输出若干脉冲信号。为判断转向,一般输出两组存在一定相位差的方波信号。
——所使用的电机(图片来源:平衡小车之家)
编码器有AB相输出,可以测速和辨别转向。编码器自带了上拉电阻,可以直接连接到单片机读取。
编码器输出的波形图如下(图片来源:平衡小车之家):
通过软件的方法实现四倍频。分别测量A相和B相的上升沿和下降沿。可使用STM32的硬件计数。
/**************************************************************************
函数功能:把TIM2初始化为编码器接口模式
**************************************************************************/
void Encoder_Init_TIM2(void)
{
RCC->APB1ENR|=1<<0; //TIM2时钟使能
RCC->APB2ENR|=1<<2; //PA时钟使能
GPIOA->CRL&=0XFFFFFF00;//PA0 PA1
GPIOA->CRL|=0X00000044;//浮空输入
TIM2->DIER|=1<<0; //允许更新中断
TIM2->DIER|=1<<6; //允许触发中断
MY_NVIC_Init(1,3,TIM2_IRQn,1);
TIM2->PSC = 0x0;//预分频器
TIM2->ARR = ENCODER_TIM_PERIOD;//设定计数器自动重装值
TIM2->CR1 &=~(3<<8);// 时钟不分频
TIM2->CR1 &=~(3<<5);// 边沿对齐模式
TIM2->CCMR1 |= 1<<0; //CC1S='01' IC1FP1映射到TI1
TIM2->CCMR1 |= 1<<8; //CC2S='01' IC2FP2映射到TI2
TIM2->CCER &= ~(1<<1); //CC1P='0' IC1FP1映射到IC1FP1=TI1
TIM2->CCER &= ~(1<<5); //CC2P='0' IC2FP2映射到IC2FP2=TI2
TIM2->CCMR1 |= 3<<4; // IC1F='1000' 输入捕获1滤波器
TIM2->SMCR |= 3<<0; //SMS='011' 所有的输入均在上升沿和下降沿有效
TIM2->CR1 |= 0x01; //CEN=1 使能定时器
}
初始化完成后,通过读取寄存器 CNT 的值获得编码器的位置信息
2. 速度闭环控制
将测量值和目标值比较,得到控制偏差,再对偏差通过PID环节得出控制量,使偏差趋向于零。
离散PID公式:
Δ
u
(
k
)
=
k
p
∗
(
e
r
r
o
r
(
k
)
−
e
r
r
o
r
(
k
−
1
)
)
+
k
i
∗
e
r
r
o
r
(
k
)
+
k
d
∗
(
e
r
r
o
r
(
k
)
−
2
∗
e
r
r
o
r
(
k
−
1
)
+
e
r
r
o
r
(
k
−
2
)
)
\Delta u(k) = k_{p} * (error(k) - error(k - 1)) +k_{i} * error(k) + k_{d} * (error(k) - 2* error(k - 1) + error(k - 2))
Δu(k)=kp∗(error(k)−error(k−1))+ki∗error(k)+kd∗(error(k)−2∗error(k−1)+error(k−2))
只使用PI控制,
k
d
=
0
k_{d} = 0
kd=0
C语言实现:
int Right_PI(int Encoder,int Target)
{
float Kp1 = 20,Ki1 = 30;
static int Bias1,Pwm1,Last_bias1;
Bias1 = Encoder-Target; //计算偏差
Pwm1 += Kp1*(Bias1-Last_bias1)+Ki1*Bias1; //增量式PI控制器
Last_bias1 = Bias1; //保存上一次偏差
return Pwm1; //增量输出
}
3.发送控制数据
使用串口3接收中断接收控制信息,串口3的配置有很多资料,接收协议模仿正点原子的协议,定义数据格式为包头为“ { ” ,包尾为“ } ”
void USART3_IRQHandler(void)
{
u8 res;
if(USART3->SR&(1<<5))//接收到数据
{
res=USART3->DR;
if((USART3_RX_STA&0x8000)==0)//接收完成了
{
if(u3_flag==1)
{
if(res=='}') //接收到“}”
{
USART3_RX_STA|=0x8000; //接收完成
}
else
{
USART3_RX_BUF[USART3_RX_STA&0X3FFF]=res;
USART3_RX_STA++;
if(USART3_RX_STA>(USART3_MAX_RECV_LEN-1))
USART3_RX_STA=0;//接收错误,重新开始接收
}
}
if(res=='{') //接收到 “{”,则开始写入
{
u3_flag=1;
}
}
}
}
3.硬件设计
用覆铜板做的接口板:
参考:平衡小车之家