从零开始写STM32平衡小车代码,从0到1

从零开始写STM32平衡小车代码,从0到1

273cfdc033aaeb3e62f26bd6dea9b7a5.png

教你从零开始写STM32平衡小车代码

前言:

本人也是学生,只是分享一下自己的设计思路与代码教学。

这次STM32平衡小车是基于STM32CubeMX软件生成HAL库代码编写。

第一部分:前期准备

这部分主要是关于组装基本平衡小车需要的零件

1.小车车架以及电机固定架轮子和联轴器(我是通过淘宝上购买的)

2.带有编码器的直流电机

3.直流电机驱动电路(也可以通过网上购买推荐大鱼电子的电机驱动价格:30+)

4.一个STM32最小系统板(本人芯片型号为STM32F103ZET6)

5.一个陀螺仪随意型号可以买贵一点的这样数据不会很多毛刺,如果要节约成本就需要自己进行滤波优化了。(本人使用的是维特智能jy61p)

6.3S航模电池,想要小车跑起来电池是必不可少的

第二部分:新建STM32CubeMX工程

d94b135873ab528c63c23daad612552f.png主页面

进入页面后先选择一款MUC:点击 ACCESS TO MCU

0b56fe38d3b5149401c48bac31a0f766.png

在此搜索你们使用的芯片型号即可

c05d1ee08349e19442e9a46a2ec2c738.png

进去后先点击SYS修改Debug模式,我这里选择SWD

994dbe8a6cdf682948579885f0d1bfe4.png

在RCC下选择外部晶振如图

a7bf3d7404fde319919f23efe83a76d8.png

点击上方的时钟树,正确配置后只要在最后

413f6c52c404bb1919904b6516075409.png

这个位置,输入最大的速率,软件就会自动配置好时钟树

d44d168d09f42a48b47d6fb9d2a8469e.png

最后在上方的项目管理界面选择你要的IDE

2ccb6101f612b6ef3a91b78a759d0852.png

勾选需要的配置,这样工程就基本建立完成。

第三部分:配置需要的外设

在第二部分的基础上配置

1.定时器

a9fbfd815787250d355652be67c6c014.png

首先是定时器,想要驱动电机,我们需要配置定时器生成PWM波

这里使用TIM1的CH1和CH2生成PWM控制两路电机

自动重装载值设置为7200-1

这样生成的是10khz的方波足够我们使用了

这里顺便说一下电机的驱动原理:电机的转速是和PWM的占空比成正比的。

2.编码器

e3f0e69e406949bdf7ee25a44e90580c.png

编码器是读取电机真实速度,作为后序PID控制的反馈值。

TIM2和TIM3都如图配置编码器模式

3.主要控制定时器

85607ff64734db35f0cd262e17cf587e.png

配置一个10ms的定时器,作为我们的控制周期

网上很多平衡小车都是通过陀螺仪的引脚外部中进行控制周期

其实不是很需要这样,这样写代码也不好理解

只需要确保陀螺仪的回传速率能够大于等于控制周期即可

4.串口

作为陀螺仪数据的接收和处理

fc1c9376abe92819d19d741aa55dd2b8.png

波特率为115200

如果和我是同款陀螺仪的话初始波特率是9600回传速率是10hz需要使用官方的上位机进行设置。

其实也可以使用指令进行配置,但是我一直没有成功,最后还是使用TTL连接上位机配置。

这样所有需要的配置都配置完啦,接下来只要点击右上角的生成代码就可以啦。

3b9276831857d6c3273de795e77ed953.png

会生成这样一个文件夹

打开里面的MDK-ARM就是熟悉的Keil了因为我选择的是MDK IDE

第四部分:代码编写

1.基础HAL库运行编写

因为上面的步骤软件已经帮我们把基础的外设驱动代码编写完了

接下来我们要做一些必要的代码

在HAL库中定时器中断需要我们手动开启

找到main.c

2e8a4ec933bf1e676f2996634917f06b.pngf496720cb60e7aa5379398f33635ac06.png开启定时器中断ba272a4160aa4465d58db1fad89cc431.png开启编码器和PWM以及串口接收中断

以及编码器启动,和PWM生成都需要手动先开启

2.编码器代码

因为编码器是基于定时器的,所以我们找到tim.c底下进行代码编写

8170d17971aa4eb9f19a1eebff7a4f92.png213ecfb6b8c8d54ba7b08db7770f202f.png

找到user code begin1

因为HAL库代码是软件生成的我们需要按照提示进行编写代码,否则下次生成代码,会消失

intRead_Encoder(uint8_tTIMX){

intEncoder_TIM;

switch(TIMX)

{

case2:Encoder_TIM=(short)TIM2->CNT;TIM2->CNT=0;break;

case3:Encoder_TIM=(short)TIM3->CNT;TIM3->CNT=0;break;

case4:Encoder_TIM=(short)TIM4->CNT;TIM4->CNT=0;break;

default:Encoder_TIM=0;

}

returnEncoder_TIM;}

编码器代码如上,控制周期为10ms

3.电机控制代码

先前讲过电机主要是通过PWM的占空比进行速度控制

所以我们需要编写一个控制占空比的函数

voidsetspeed(intleft_1,intright_1){

if(right_1>0)

{

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_RESET);//电机方向控制HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);

}

else

{

HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_SET);//电机方向控制HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET);

}

if(left_1>0)

{

HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_RESET);

HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);

}

else

{

HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9,GPIO_PIN_SET);

HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_RESET);

}

if(left_16900)//满速是7200限制速度避免坏电机left_1=-6900;

if(left_1>6900)

left_1=6900;

if(right_16900)

right_1=-6900;

if(right_1>6900)

right_1=6900;

left_1=abs(left_1);//输出占空比一定不能是负值right_1=abs(right_1);

__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,left_1);

__HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,right_1);}

稍微讲解一下代码,首先需要对输入的占空比进行判断,是负的还是正的

对电机进行方向控制

后序进行一个限制速率的操作,避免电机太快损坏

由于输出给驱动的占空比一定不是能负数,所以我们还需要一个abs函数取绝对值

__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2,left_1);

就是HAL库设置TIM1通道2的占空比函数

4.陀螺仪

陀螺仪是整个小车的灵魂,但是代码太长不好展示,大家可以去卖家找对应的例程

这里说一下思路就是通过串口不断读取数据

/***************串口中断回调函数数据处理***************/voidHAL_UART_RxCpltCallback(UART_HandleTypeDef*huart){

if(huart->Instance==USART2)

{

USART2_IT_OK=USART2_IT_OK+1;

CopeSerial2Data(jydata);

//陀螺仪数据处理

//加速度a[0]=(float)stcAcc.a[0]/32768*16;

a[1]=(float)stcAcc.a[1]/32768*16;

a[2]=(float)stcAcc.a[2]/32768*16;

//角速度w[0]=(float)stcGyro.w[0]/32768*2000;

w[1]=(float)stcGyro.w[1]/32768*2000;

w[2]=(float)stcGyro.w[2]/32768*2000;

//角度Angle[0]=(float)stcAngle.Angle[0]/32768*180;

Angle[1]=(float)stcAngle.Angle[1]/32768*180;

Angle[2]=(float)stcAngle.Angle[2]/32768*180;

//四元素q[0]=(float)stcQ.q[0]/32768;

q[1]=(float)stcQ.q[1]/32768;

q[2]=(float)stcQ.q[2]/32768;

q[3]=(float)stcQ.q[3]/32768;

HAL_UART_Receive_IT(&huart2,&jydata,1);

}}

5.PID算法代码

PID算法在小车中有很多种

这里使用的是经过推导后的直立环和速度环

要让小车直立这两个环是必不可少的

转向环可以暂时不需要

直立环是让小车具有一个直立的趋势

速度环是让小车在直立的情况下还能在原地不动

转向环是让小车具有走直线的能力

这里的代码借鉴了平衡小车之家的代码

直立环代码

floatBias,kp=100,kd=12;intbalance(floatAngle,floatGyro){

intbalance;

Bias=Angle-3;//===求出平衡的角度中值和机械相关balance=kp*Bias+Gyro*kd;//===计算平衡控制的电机PWM PD控制   kp是P系数 kd是D系数returnbalance;}

单单有直立环是很难直立起来的还需要加入速度环

速度环代码

floatVelocity_Kp=60,Velocity_Ki=0.3;//PID参数intvelocity(intencoder_left,intencoder_right){

staticfloatVelocity,Encoder_Least,Encoder,Movement;

staticfloatEncoder_Integral;

//=============速度PI控制器=======================//Encoder_Least=(encoder_left+encoder_right)-0;//===获取最新速度偏差==测量速度(左右编码器之和)-目标速度(此处为零)Encoder*=0.8;//===一阶低通滤波器Encoder+=Encoder_Least*0.2;//===一阶低通滤波器Encoder_Integral+=Encoder;//===积分出位移积分时间:10msEncoder_Integral=Encoder_Integral-Movement;//===接收遥控器数据,控制前进后退if(Encoder_Integral>10000)Encoder_Integral=10000;//===积分限幅if(Encoder_Integral10000)Encoder_Integral=-10000;//===积分限幅Velocity=Encoder*Velocity_Kp+Encoder_Integral*Velocity_Ki;//===速度控制returnVelocity;}

至于PID的调参,那就是另一门学问了,这里就先不讲解

PID代码里面的一些低通滤波也不做讲解,想要做出来只要会用就行了

至此基本的代码都已经写完,是不是感觉其实平衡小车并不难造

接下来就是控制部分的代码了,要将上面的代码有序的组合起来

合成小车的灵魂

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

{

  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */

  if (htim->Instance == TIM8) {

    HAL_IncTick();

  }

  /* USER CODE BEGIN Callback 1 */

if (htim->Instance == TIM1) //10khz

{

TIM1_IT_OK = 1;

}

if (htim->Instance == TIM2) //encoder

{

TIM2_IT_OK = 1;

}

if (htim->Instance == TIM3) //encoder

{

TIM3_IT_OK = 1;

}

if (htim->Instance == TIM4) //5ms

{

TIM4_IT_OK = 1;

}

if (htim->Instance == TIM6) //10ms

{

TIM6_IT_OK = 1;

Left_Speed = -Read_Encoder(3);

Right_Speed = -Read_Encoder(2);

Balance_Pwm = balance(-Angle[0],-w[0]);

Velocity_Pwm = velocity(Left_Speed,Right_Speed);

setspeed(Balance_Pwm+Velocity_Pwm,Balance_Pwm+Velocity_Pwm);

}

  /* USER CODE END Callback 1 */

}

这里是HAL库的定时器中断回调函数

因为我设置的是TIM6就在TIM6的中断回调函数中进行编写

注意控制周期是10ms对应陀螺仪的速率一定不能低于100hz不然小车就会一直摇摆。

先读取编码器的数据,自己在操作的时候要调好正负,因为每个人安装都不太一样

平衡小车pid调参后

ok教程到此结

猜你喜欢

转载自blog.csdn.net/danpianji777/article/details/125064394
今日推荐