Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说
stm32平衡小车课程设计报告_用车辆识别代码怎么查车型号,希望能够帮助你!!!。
从零开始写STM32平衡小车代码,从0到1
教你从零开始写STM32平衡小车代码
前言:
本人也是学生,只是分享一下自己的设计思路与代码教学。
这次STM32平衡小车是基于STM32CubeMX软件生成HAL库代码编写。
第一部分:前期准备
这部分主要是关于组装基本平衡小车需要的零件
1.小车车架以及电机固定架轮子和联轴器(我是通过淘宝上购买的)
2.带有编码器的直流电机
3.直流电机驱动电路(也可以通过网上购买推荐大鱼电子的电机驱动价格:30+)
4.一个STM32最小系统板(本人芯片型号为STM32F103ZET6)
5.一个陀螺仪随意型号可以买贵一点的这样数据不会很多毛刺,如果要节约成本就需要自己进行滤波优化了。(本人使用的是维特智能jy61p)
6.3S航模电池,想要小车跑起来电池是必不可少的
第二部分:新建STM32CubeMX工程
主页面
进入页面后先选择一款MUC:点击 ACCESS TO MCU
在此搜索你们使用的芯片型号即可
进去后先点击SYS修改Debug模式,我这里选择SWD
在RCC下选择外部晶振如图
点击上方的时钟树,正确配置后只要在最后
这个位置,输入最大的速率,软件就会自动配置好时钟树
最后在上方的项目管理界面选择你要的IDE
勾选需要的配置,这样工程就基本建立完成。
第三部分:配置需要的外设
在第二部分的基础上配置
1.定时器
首先是定时器,想要驱动电机,我们需要配置定时器生成PWM波
这里使用TIM1的CH1和CH2生成PWM控制两路电机
自动重装载值设置为7200-1
这样生成的是10khz的方波足够我们使用了
这里顺便说一下电机的驱动原理:电机的转速是和PWM的占空比成正比的。
2.编码器
编码器是读取电机真实速度,作为后序PID控制的反馈值。
TIM2和TIM3都如图配置编码器模式
3.主要控制定时器
配置一个10ms的定时器,作为我们的控制周期
网上很多平衡小车都是通过陀螺仪的引脚外部中进行控制周期
其实不是很需要这样,这样写代码也不好理解
只需要确保陀螺仪的回传速率能够大于等于控制周期即可
4.串口
作为陀螺仪数据的接收和处理
波特率为
如果和我是同款陀螺仪的话初始波特率是9600回传速率是10hz需要使用官方的上位机进行设置。
其实也可以使用指令进行配置,但是我一直没有成功,最后还是使用TTL连接上位机配置。
这样所有需要的配置都配置完啦,接下来只要点击右上角的生成代码就可以啦。
会生成这样一个文件夹
打开里面的MDK-ARM就是熟悉的Keil了因为我选择的是MDK IDE
第四部分:代码编写
1.基础HAL库运行编写
因为上面的步骤软件已经帮我们把基础的外设驱动代码编写完了
接下来我们要做一些必要的代码
在HAL库中定时器中断需要我们手动开启
找到main.c
开启定时器中断开启编码器和PWM以及串口接收中断
以及编码器启动,和PWM生成都需要手动先开启
2.编码器代码
因为编码器是基于定时器的,所以我们找到tim.c底下进行代码编写
找到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教程到此结
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
上一篇
已是最后文章
下一篇
已是最新文章