本文章主要介绍如何用PID算法和电感使你的小车完成最简单的循迹。
需要准备的硬件:芯片ch32v103R8T6,电机驱动板,核心板,两个电机,一个舵机,四个轮子,电磁传感器,干簧管(本文罗列的硬件对型号不做要求)。
我们使用的编译软件是MounRiver Studio,使用的库是由逐飞提供的库。
我们使用干黄管来使其可以完美的停车。
下图为我们对硬件结构的一个整体思路
下图为我们智能车
下图为我们程序设计的基本思路
程序源代码如下
#include "headfile.h"
int16 Left_Adc1=0,Right_Adc1=0; //转换后的左右电感值
int16 Left_Adc2=0,Mid_Adc=0,Right_Adc2=0;
int stop=0;
uint16 duty3=8000;//停车电机反转
int16 duty1=0; //舵机占空比
float kp,kd; //舵机pid的p d参数
//误差值
float error;
float error_last;
float error_angle; //舵机转角pd算法偏值
int16 ad_value1;
int16 ad_value2;
//获取电感值
float get_adc(void){
int i,j;
float ad_value[10],sum_value=0;
float temp;
for(i=0;i<10;i++)
{
ad_value1=adc_convert(ADC_IN6_A6, ADC_12BIT);
ad_value2=adc_convert(ADC_IN8_B0, ADC_12BIT);
//差比和算法
ad_value[i]=100*(ad_value2-ad_value1)/(ad_value2+ad_value1);
}
//冒泡算法
for(j=0;j<9;j++)
{
for(i=0;i<9-j;i++)
{
if(ad_value[i]>ad_value[i+1])
{
temp=ad_value[i];
ad_value[i]=ad_value[i+1];
ad_value[i+1]=temp;
}
}
}
for(i=1;i<9;i++){
sum_value+=ad_value[i];
}
temp=sum_value/8;
return temp;
}
int main(void)
{
//关闭总中断
DisableGlobalIRQ();
//务必保留,本函数用于初始化MPU 时钟 调试串口
board_init();
//此处编写用户代码(例如:外设初始化代码等)
//lcd初始化
lcd_init();
//lcd_clear(WHITE);
//adc初始化
adc_init(ADC_IN6_A6);//中
adc_init(ADC_IN8_B0);//右二
//电机初始化
timer_pwm_init(PWM4_CH4_B9, 12500, 0);
timer_pwm_init(PWM4_CH3_B8, 12500, 0);
timer_pwm_init(PWM4_CH2_B7, 12500, 0);
timer_pwm_init(PWM4_CH1_B6, 12500, 0);
//舵机初始化
timer_pwm_init(PWM3_CH1_C6,50,740);//舵机的pwm
//D2口初始化
gpio_init(D2,GPI,0,IN_PULLUP);
//变量初始化
error=0;
error_last=0;
//舵机pd算法的pd值
kp=1.39;//5.2 4.57
kd=0.02551; //1 1.15 1.55
//总中断最后开启
EnableGlobalIRQ(0);
while(1)
{
error_last=error;
error=get_adc();
error_angle=kp*error+kd*(error-error_last);//舵机pd算法确定转角偏值
duty1=740-(int16)error_angle;
//舵机限幅
if(duty1>=796)
duty1=796;
else if(duty1<=662)
duty1=662;
timer_pwm_duty(PWM3_CH1_C6,duty1);
if(stop<=2)
{
//电机
timer_pwm_duty(PWM4_CH3_B8,1500);//开关这边电机正转
//timer_pwm_duty(PWM4_CH4_B9, 1800);//开关这边电机反转
timer_pwm_duty(PWM4_CH2_B7,1850);//非正转
//timer_pwm_duty(PWM4_CH1_B6,1800);//非反转
}
//干簧管停车
if(gpio_get(D2)==0)
{
stop++;
systick_delay_ms(100);
}
if(stop>2)
{
timer_pwm_duty(PWM3_CH1_C6,740);//992
timer_pwm_duty(PWM4_CH4_B9,duty3);//开关这边电机
timer_pwm_duty(PWM4_CH2_B7,0);
timer_pwm_duty(PWM4_CH3_B8,0);//非开关这边电机
timer_pwm_duty(PWM4_CH1_B6,duty3);
systick_delay_ms(100);
while(1){
//电机反转实现停车
timer_pwm_duty(PWM4_CH4_B9,0);//开关这边电机
timer_pwm_duty(PWM4_CH2_B7,0);
timer_pwm_duty(PWM4_CH3_B8,0);//非开关这边电机
timer_pwm_duty(PWM4_CH1_B6,0);
}
}
//lcd显示
lcd_showstr(1, 0, "Left_Adc1");
lcd_showint16(80,0, Left_Adc1);
lcd_showstr(2, 1, "Left_Adc2");
lcd_showint16(80, 1, Left_Adc2);
lcd_showstr(3, 2, "L1");//左电感 A6
lcd_showint16(80,2, ad_value1);
lcd_showstr(4, 3, "Right_Adc1");
lcd_showint16(90,3, Right_Adc1);
lcd_showstr(5, 4, "R2");//右电感 B0
lcd_showint16(90, 4, ad_value2);
lcd_showint32(1, 5, duty1,4);
}
}
由于电感的接口不同,可能电感的初始化不同。
本人建议自己画电路板和驱动板,避免出现一些小问题。