基于STM32+PID控制两轮智能自平衡小车设计

目录

  1. 绪论 1
    1.1 研究意义及背景 1
    1.2 本文主要研究内容及任务 1
  2. 系统概述 2
    2.1 控制系统要求分析 2
    2.2 平衡小车控制原理分析 2
    2.3 自平衡小车PID控制器分析 4
    2.3.1 PID控制原理 4
    2.3.2 PID控制器设计 4
  3. 系统硬件电路设计 5
    3.1 硬件电路整体框架 5
    3.2 电源供电部分 5
    3.3 STM32F103C8T6最小系统 7
    3.3.1 复位电路 8
    3.3.2 Boot选择部分 8
    3.3.3晶振部分 9
    3.3.4 指示灯部分 9
    3.3.5 st-link下载部分 9
    3.4 九轴姿态角度传感器部分 10
    3.4.1 九轴姿态角度传感器基本介绍 10
    3.4.2 九轴姿态角度传感器性能 10
    3.4.3 实物图 10
    3.4.4 引脚说明 11
    3.4.5 通信方式 11
    3.5 电机驱动编码器部分 12
    3.5.1电机编码器基本介绍 12
    3.5.2 电机实物图 12
    3.5.3 电机编码器引脚说明 12
    3.5.4 电机驱动A4950 13
    3.6 巡线避障部分 14
    3.6.1 传感器介绍 14
    3.7 蓝牙通信部份 15
  4. 软件设计部分 16
    4.1 操作系统RTOS(RtThread) 16
    4.1.1简介RtThread 16
    4.1.2 系统任务的划分 17
    4.2 电机驱动 18
    4.2.1 流程图 18
    4.2.2 主要API函数 18
    4.3 九轴姿态角度传感器数据读取 19
    4.3.1 数据格式 19
    4.3.2 程序流程 20
    4.4 编码器数据读取 22
    4.4.1 数据格式 22
    4.4.2 程序流程 22
    4.5 直立PID功能实现 23
    4.5.1 控制策略 23
    4.5.2 流程图 23
    4.5.3 直立环 24
    4.5.4 速度环 25
    4.5.5 转向环 26
    4.6 蓝牙遥控部分 26
    4.6.1 数据协议 26
    4.7 循迹避障部分 27
    4.7.1 主要API解析 27
  5. 系统PID调试部分 28
    5.1 直立环 29
    5.2 速度环 30
    5.3 转向环 30
    5.4 角度锁死 31
  6. 总结 31
    参考文献 32
    致谢 32
    附录 33
    附录一 主要代码 33
    附录二 原理图 40
    附录三 实物图 41
    设计一款两轮自平衡小车,通过对陀螺仪的数据的读取处理,从而识别出车身姿态,根据车身姿态计算PID,通过对小车进行实时的PID控制,使得小车可以按照要求实现自主平衡,根据遥控可以实现平稳前进后退;根据灰度传感器数据,可以实现循迹和避障。具体内容分为以下几个部分:
    1.平衡小车机械设计部分:主要是机械,重心调整,电气设计部分。
    2.信号处理部分:九轴陀螺仪数据的读取和处理,灰度传感器的读取和处理,电机编码器的数据读取和处理。
    3.控制算法PID:根据输入的信息,完成直立环,速度环,转向环的计算控制。
    4.遥控传输部分:采用蓝牙无线模块,接收手机的遥控数据。
    2.系统概述
    2.1 控制系统要求分析
    要使小车在干扰的情况下实现自平衡,自恢复干扰,并且能够在遥控下实现前进后退,左转右转功能。结合系统分析可知,自平衡小车需要维持原地不倒和运动,运动的动力来自自平衡车的两轮,两轮由两个直流电机驱动。因此,自平衡小车可以作为被控制对象,自平衡小车的两轮可以作为控制系统的控制量。整个系统划分为三个部分:
    1.自平衡小车的站立控制(直立环):以小车的倾斜角度和角速度作为输入参数,通过计算直立环的PD控制器,得到电机的输出大小,控制电机的速度来保持小车的自平衡。
    2.自平衡小车的速度控制(速度环):在站立环的基础上,通过改变自平衡小车电机的编码器数值来调整车体的实际运动速度。通过计算PI,通过调整电机的运行速度,改变小车的实际运行速度。当速度环的速度设置为0的时候,小车可以实现在原地保持不动,当人为干扰,推动小车,小车可以自动回到原地。设置为某一数值的时候,可以实现前进后退。
    3.自平衡小车转向调整(转向环):通过调整自平衡小车两轮的速度,利用差速转弯,采用P控制器。可以实现左右转弯。
#include "main.h"

u16 imuCorrectCount=0,imuErrorCount=0,readEncodeCount=0,sendDataCount=0,controlMotorCount=0;		//记录hz数

s32 leftEncoder=0,rightEncoder=0;

/*
线	程:readEncode
作	用:读取左右电机编码器脉冲数
频	率:100Hz
*/
void readEncode(void* parameter){
	while(1){
		readEncodeCount++;
		leftEncoder += Read_Encoder(2);
		rightEncoder -= Read_Encoder(4);
		
		rt_thread_delay(1);
		rt_timer_check();
	}
	
}

/*
线	程:sendData
作	用:使用printf,通过串口3打印数据,也可使用rt_kprintf,通过串口1打印数据
频	率:10Hz
*/
void sendData(void* parameter){

//	printf("d = %.2f\r\n\r\n",m[2]);
//		rt_thread_delay(1000);		//do something
//		rt_timer_check();
	
}


/*
线	程:controlMotor
作	用:控制电机
频	率:1000Hz
日	期:2019年1月26日
作	者:meetwit
*/
void controlMotor(void* parameter){
	float temp1,temp2,temp3;
	float get_angle,get_gyro;
	temp1 = 32768/180.0;			//角度
	temp2 = 32768/2000.0;			//角速度
	temp3 = 32768/16.0;				//角加速度
	int finalPwm = 0,finalPwm2 = 0;
	u8 time=0;
	while(1){
		time++;
		controlMotorCount++;
			finalPwm = 0;
		get_angle = stcAngle.Angle[0]/temp1;
		get_gyro = stcGyro.w[0]/temp2;
		if(get_angle>40||get_angle<-40){									//角度过大,锁住
			motor_run(0,0);
			stop_flag = 1;
		}
		if(stop_flag){
			if(get_angle>-5&&get_angle<5){									//角度适合,解锁
				rt_thread_delay(RT_TICK_PER_SECOND*2);				//扶正后等待x秒
				stop_flag = 0;																//解锁
			}
				velocity_mw();																//执行一次清除积分
				motor_run(0,0);																
		}else{
			//10和300 进行PID控制
			finalPwm += balance_mw(get_angle,get_gyro);
			finalPwm += velocity_mw();
			finalPwm2 = finalPwm+Flag_turn;
			if(finalPwm2>=0){
					motor_run(3,finalPwm2); 
			}else{
					motor_run(4,-finalPwm2); 
			}
			if(finalPwm>=0){
					motor_run(2,finalPwm);
			}else{
					motor_run(1,-finalPwm);
			}
			if(time%20==0){
				Flag_v = 0;
				Flag_turn = 0;
			}
		}
		rt_thread_delay(5);
		rt_timer_check();
	}
	
}

void timer1_f(void* parameter){
	Rx_Tm3--;
	if(Rx_Tm3==1)
	Task_Pc3();
}

/*
线	程:time_thread
作	用:通过串口1打印系统时间
频	率:1Hz
日	期:2019年1月26日
作	者:meetwit
*/
void time_thread(void* parameter){
	rt_tick_t tick_temp;
  rt_uint8_t h=0,m=0,s=0;
	
	while(1){
		tick_temp = rt_tick_get();
		s=tick_temp/RT_TICK_PER_SECOND%60;
		m=tick_temp/RT_TICK_PER_SECOND/60%60;
		h=tick_temp/RT_TICK_PER_SECOND/60/60%24;
		rt_kprintf("\r\nThe system runtime is %d:%d:%d.%d\r\n",h,m,s,tick_temp%RT_TICK_PER_SECOND);
		rt_kprintf("imuCorrectCount=%d,imuErrorCount=%d,readEncodeCount=%d,sendDataCount=%d,controlMotorCount=%d\r\n",imuCorrectCount/3,imuErrorCount,readEncodeCount,sendDataCount,controlMotorCount);

		imuCorrectCount=0;
		imuErrorCount=0;
		readEncodeCount=0;
		sendDataCount=0;
		controlMotorCount=0;
		rt_thread_delay(RT_TICK_PER_SECOND);
	}
	
}


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述