毕业设计| STM32坡道行驶巡线小车制作教程

发布时间:2023-04-26  

1)主控芯片STM32F103C8T6

2)编码电机

型号MG513 p30 12v;转动一圈390个脉冲;减速比1比30。通过获取每100毫秒的脉冲个数,就可以计算出速度的大小

3)7针0.96寸oled显示屏

4)舵机:看着挺高级的,马力大,不过控制代码与那种两块钱的一样,模拟控制,PWM控制,用来控制方向


5)红外传感器模块:4个红外对管,一块模拟转数字模块

6)电源18650+电池座:经济实惠

7)锂电池充电器:一个模块加一个电池座,加起来不到2块钱

8)旋转编码器,用来调节时间的,按下小车就可以跑了



8)小车底盘

购买链接:m.tb.cn/h.4MEu0RC?

其实编码电机与舵机小车上面都有,直接买一个小车车身。买来是散装的,装了好久装好:


02

原理图设计

首先就是要进行硬件设计,连接好了硬件,软件就好办了。

然后开始连接硬件。

连接好了硬件,写程序就可以调试了…

硬件与程序调试用了两天时间总算搞定了接下来开始测量数据。


03

数据测量

1)功耗测量:

设置全程1.5m走的时间:


2)OLED速度监测

显示屏数据说明:

V1、V2左右轮实时速度

PIDOUT:输出PWM值

time:定时间

speed:通过设定时间计算得到的速度,因为路程固定

running/stop运行状态


可以看到PID算法起到了良好的效果,很好的把速度恒定在指定范围之内

平地测量场景:

记录数据:



04

程序设计

1)主程序设计

主函数是执行了整个程序的入口点。

首先初始设置定时器参数,设置TIM1 16位定时器递增计数,设置定时器时间10MS,主要用来在定时器中断测量小车速度与PID算法调用。


配置TIM4为PWM模式,设置周期为30ms,298能够反应过来,周期太大小车会有抖动,通过脉宽来调节小车速度,脉宽越大,小车运动越快,设置计数器为1000向上计数,也就是重装载值设置1000小车最快,设置重装载值0小车不运动。


配置TIM3为PWM模式,根据舵机的特性,配置周期为30MS,向上计数模式,计数器设置为3000,当脉宽长度为28MS时,舵机刚好再0度位置,所以初始化重装载寄存器为2800,上电默认向前方向。


配置红外传感器4个输入引脚为输入模式,来检测输入的电平情况


配置旋钮编码器为3个引脚输入模式,用来检测是否旋转与按下


配置LED引脚为推挽输出模式,来驱动LED闪烁


配置串口与滴答定时器延时,串口主要用来调试,延时用来消耗某些时刻需要消耗的时间


循环:循环检测旋钮状态,如果旋转了就根据旋转的方向与角度设定时间的大小,如果旋钮按键按下,那么前进状态变成1

//主函数

int main(void)

{

  u8 state;

  int ang,i;

  

  uart_init(9600);//蓝牙串口初始化

  delay_init(); //延时初始化

  SteerinMotor_Init(); //舵机初始化

  EncodeMotor_Init();//编码电机初始化

  OLED_Init();//oled初始化

  LED_Init();//led初始化

  TIM1_Int_Init(100,7200);//定时器初始化10ms

  Encodeing_Init();//旋钮编码器初始化

  //测试

  printf(" this is Ramp patorl trolley  by HUAZUOCHEN! ^_^ rn");

  while (1) {

  OLED_update();//更新OLED显示

  encodeing_scan();//编码器扫描

  //获取红外线传感器传回的数据

  state = Get_Infrared_Sensor();

  ang = 0;

  switch (state)//循迹转弯设置

  {

      case 0x00:ang = 0;

        break;

      case 0x01:ang = -55;

        break;

      case 0x03:ang = -45;

        break;

      case 0x02:ang = -10;

        break;

      case 0x06:set_steerMotor_ang(0);//设置舵机角度 0

        break;

      case 0x04:ang = 10;

        break;

      case 0x0c:ang = 45;

        break;

      case 0x08:ang = 55;

        break;

      case 0x0f:  //识别到杂乱信号角度设置为0

      case 0x09:

      case 0x05:

      case 0x0a:

      case 0x0e:

      case 0x0b:

        run_flag = 0;//停止  

        break;

      default:ang = 0;

        break;

    }

    if(ang != 0)

    {

      set_steerMotor_ang(ang);//设置舵机角度

      delay_ms(100);

    }

    state = 0;

    }

}


定时器1中断,10ms调用一次,调用时计数10次调用,也就是100ms进行一次速度测量,V = X/t ,速度等于位移处以时间,位移等一编码个数乘以编码单位长度,小车轮的直径为6.4厘米,周长为20.12cm,得到一个脉冲计数,大约是0.258毫米,得出左轮速度V_left = pause_cnt_left2.58;右轮速度V_right = pause_cnt_right2.58;当按下旋转编码器的按键run_flag = 1;使得PID算法开始运行,小车开始按照计算好的速度与当前测量到的速度做比较,进行闭环PID调节。


u16 time_cnt,run_cnt;

//100ms计算一次速度

void TIM1_UP_IRQHandler(void)

{

  if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 

  {

    TIM_ClearITPendingBit(TIM1, TIM_IT_Update);  //清除TIMx的中断待处理位:TIM 中断源 

    time_cnt ++;

    if(time_cnt >= 10)

    {

      V_left = pause_cnt_left*2.58;

      V_right = pause_cnt_right*2.58;

      pause_cnt_left=0;

      pause_cnt_right=0;

      time_cnt =0;

      LED = !LED;

    }

    

    if(run_flag)

    {

      speed = 1200/time;  //总路程/时间

      Set_Temp1 = Set_Temp = speed;

      set_pid_speed();

      run_cnt++;

      if(run_cnt == time*200)

      {

        run_flag = 0;

        run_cnt = 0;

      }

    }

    else 

    {

      PID_OUT = 0;

      PID_OUT1= 0;

      //run_cnt = 0;

      car_go_forward(0,0);//停止

    }

  }

}


霍尔编码器脉冲获取采用中断方式,中断设置上升沿下降沿都触发,电机传动轴与编码器相连,编码器感应论上有13个感应线条,从而使得编码器齿轮转动一圈,或编码器能识别到13个脉冲。


减速箱使得小车轮子转动一圈,电机轴转动30圈,使得编码器齿轮也转动30圈,得到,小车轮子转动一圈,编码器输出13×30,等于390个脉冲,又因为一个脉冲有一个上升,沿有一个下降沿,单片机通过检测上升沿和下降沿,可以得到有780个计数。


double V_left,V_right;//定时器计算

u16 pause_cnt_left,pause_cnt_right;//脉冲计数


//外部中断2服务程序

void EXTI2_IRQHandler(void)

{

  pause_cnt_left++;

  EXTI_ClearITPendingBit(EXTI_Line2);  //清除LINE2上的中断标志位  

}

//外部中断3服务程序

void EXTI3_IRQHandler(void)

{

  

  pause_cnt_right++;

  EXTI_ClearITPendingBit(EXTI_Line3);  //清除LINE3上的中断标志位  

}

速度平衡算法,给定一个速度,听过与编码电机反馈的速度进行比对,然后输出一个算出来的PWM值返回给电机调速,达成闭环速度调节。


void PID_calc(float V_1, float V_2) //PID算法

{

    /***********************左轮**************************/

    float Rate;//误差变化率

    float Rate1;//误差变化率

    Current_Error = Set_Temp - V_1;//当前误差

    Sum_Error += Current_Error; //误差积分

    Prev_Error = Last_Error;//存储误差积分

    Last_Error = Current_Error;//存储误差分析

    Rate = Current_Error - Last_Error; //变化速率计算



    if (Rate > 10) //不让ta大于5也不让ta小于5

        Rate = 10;

    if (Rate < -10)

        Rate = -10;


    P_OUT = P * Gain * Current_Error; //比列项

    I_OUT = I * Gain * Sum_Error; //积分项


    //积分限幅处理

    if (I_OUT > PID_I_MAX)  I_OUT = PID_I_MAX; //不能超过最大值不能低于最小值

    if (I_OUT < PID_I_MIN)  I_OUT = PID_I_MIN;


    //微分输出处理

    D_OUT = D * Gain * Rate;

    PID_OUT =  P_OUT  +  I_OUT  +  D_OUT ;

    if (PID_OUT >= V_DATA_MAX)  PID_OUT = V_DATA_MAX;

    if (PID_OUT <= V_DATA_MIN)  PID_OUT = V_DATA_MIN;


    /***********************右轮********************************/


    Current_Error1 = Set_Temp1 - V_2;//当前误差

    Sum_Error1 += Current_Error1; //误差积分

    Prev_Error1 = Last_Error1;//存储误差积分

    Last_Error1 = Current_Error1;//存储误差分析

    Rate1 = Current_Error1 - Last_Error1; //变化速率计算



    if (Rate1 > 10) //不让ta大于5也不让ta小于5

        Rate1 = 10;

    if (Rate1 < -10)

        Rate1 = -10;


    P_OUT1 = P * Gain1 * Current_Error1; //比列项

    I_OUT1 = I * Gain1 * Sum_Error1; //积分项


    //积分限幅处理

    if (I_OUT1 > PID_I_MAX1)  I_OUT1 = PID_I_MAX1; //不能超过最大值不能低于最小值

    if (I_OUT1 < PID_I_MIN1)  I_OUT1 = PID_I_MIN1;


    //微分输出处理

    D_OUT1 = D * Gain * Rate1;

    PID_OUT1 =  P_OUT1  +  I_OUT1  +  D_OUT1 ;

    if (PID_OUT1 >= V_DATA_MAX1)  PID_OUT1 = V_DATA_MAX1;

    if (PID_OUT1 <= V_DATA_MIN1)  PID_OUT1 = V_DATA_MIN1;

    /*******************************************************/

}


获取红外传感器值,红外对管用一个发射管与一个接收管组成,红外发射管发射出去的红外线遇到白色物体会反射回红外接收管,使之导通,反之遇到黑色物体不反射,使之截止。接收到的红外线越强,导通电流越大,输出电压越大,输出的电压经过逻辑电路转换为数字信号传回到单片机进行识别处理。单片机引出4个引脚对应接收电平状态,4个引脚配置为输入模式,循环检测电平的变化,电平为1则对应红外对管识别到黑色,电平0对应红外对管识别到白色。


//获取传感器状态

u8 Get_Infrared_Sensor(void)

{

  u8 state=0;

  if(PBin(4) == 1)     

    state |= 0x08;  //IN4

  if(PBin(5) == 1)

    state |= 0x04;   //IN3

  if(PBin(6) == 1)

    state |= 0x02;   //IN2

  if(PBin(7) == 1)

    state |= 0x01;   //IN1

  

  return state;

}


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>