本文详细介绍了基于STM32微控制器的两轮自平衡小车的设计与实现过程。内容包括小车的硬件选型、电路设计、软件编程以及PID控制算法的应用。通过陀螺仪和加速度计获取小车的姿态信息,利用PID控制算法调整电机输出,实现小车的自主平衡。此外,还探讨了如何通过遥控实现小车的平稳前进和后退,以及利用灰度传感器实现循迹和避障功能。
驱动步进电机如下:
硬件接线图
系统原理图如下:
IN1-IN4 :
逻辑输入端,其中 IN1 、 IN2 控制电机 M1 ; IN3 、 IN4 控制电机 M2 。例如
IN1 输入
高电平 1,IN2 输入低电平 0 ,对应电机 M1 正转; IN1 输入低电平 0,IN2
输入高电平 1 , 对应电机 M1 反转,调速就是改变高电平的占空比。(如何改变
占空比请学会百度)
PWMA 、
PWMB :
L298N 使能端(高电平有效,常态下用跳线帽接于 VCC ),可通过这两个端
口实现 PWM 调速(使用 PWM 调速时取下跳线帽),具体参考 L298N 芯片手册。
如何控制直流电机正反转 ?
如逻辑输入部分接单片机 P0 口的 P0.0-P0.3. 那么想让电机正转只要给 1010, 反转给 0101 即
可:
Void main()
{
While(1)
{
P0=0xaa;
Delay(1000);
P0=0x55;
Delay(1000);
}
}
主程序:
#define PI (3.14159265)
// 度数表示的角速度*1000
#define MDPS (70)
// 弧度表示的角速度
#define RADPS ((float)MDPS*PI/180000)
// 每个查询周期改变的角度
#define RADPT (RADPS/(-100))// 平衡的角度范围;+-60度(由于角度计算采用一阶展开,实际值约为46度)
#define ANGLE_RANGE_MAX (60*PI/180)
#define ANGLE_RANGE_MIN (-60*PI/180)// 全局变量
pid_s sPID; // PID控制参数结构体
float radian_filted=0; // 滤波后的弧度
accelerometer_s acc; // 加速度结构体,包含3维变量
gyroscope_s gyr; // 角速度结构体,包含3维变量
int speed=0, distance=0; // 小车移动的速度,距离
int tick_flag = 0; // 定时中断标志
int pwm_speed = 0; // 电机pwm控制的偏置值,两个电机的大小、正负相同,使小车以一定的速度前进
int pwm_turn = 0; // 电机pwm控制的差异值,两个电机的大小相同,正负相反,使小车左、右转向
float angle_balance = 0; // 小车的平衡角度。由于小车重心的偏移,小车的平衡角度不一定是radian_filted为零的时候// 定时器周期中断,10ms
void sys_tick_proc(void)
{static unsigned int i = 0;tick_flag++;i++;if(i>=100) i=0;if(i==0) // 绿灯的闪烁周期为1秒{LED1_OFF();}else if(i==50){LED1_ON();}
}void control_proc(void)
{int i = ir_key_proc(); // 将红外接收到的按键值,转换为小车控制的相应按键值。switch(i){case KEY_TURN_LEFT:if(pwm_turn<500) pwm_turn += 50;break;case KEY_TURN_RIGHT:if(pwm_turn>-500) pwm_turn -= 50;break;case KEY_TURN_STOP:pwm_turn = 0;distance = 0;pwm_speed = 0;break;case KEY_SPEED_UP:if(pwm_speed<500) pwm_speed+=100;break;case KEY_SPEED_DOWN:if(pwm_speed>-500) pwm_speed-=100;break;case KEY_SPEED_0:pwm_speed = 0;break;case KEY_SPEED_F1:pwm_speed = 150;break;case KEY_SPEED_F2:pwm_speed = 300;break;case KEY_SPEED_F3:pwm_speed = 450;break;case KEY_SPEED_F4:pwm_speed = 600;break;case KEY_SPEED_F5:pwm_speed = 750;break;case KEY_SPEED_F6:pwm_speed = 900;break;case KEY_SPEED_B1:pwm_speed = -150;case KEY_SPEED_B2:pwm_speed = -300;case KEY_SPEED_B3:pwm_speed = -450;break;default:break;}pwm_turn *= 0.9; // pwm_turn的值以0.9的比例衰减,使小车在接收到一个转向信号后只转动一定的时间后停止转动。speed = speed*0.7 +0.3*(encoder_read()); // 定周期(10ms)读取编码器数值得到实时速度,再对速度进行平滑滤波if(speed!=0){printf("speed: %d, dst: %d, pwm: %d \r\n", speed,distance,(int)(speed*6+distance*0.1));}encoder_write(0); // 编码器值重新设为0distance += speed; // 对速度进行积分,得到移动距离if(distance>6000) distance = 6000; // 减少小车悬空、空转对控制的影响else if(distance<-6000) distance = -6000;}void balance_proc(void)
{static unsigned int err_cnt=0;// float tFloat;int pwm_balance;
// static float angle;
// float angle_t;float radian, radian_pt; // 当前弧度及弧度的微分(角速度,角度值用弧度表示)adxl345_read(&acc); // 读取当前加速度。由于传感器按照的位置原因,传感器的值在函数内部经过处理,变为小车的虚拟坐标系。l3g4200d_read(&gyr); // 读取当前角速度。同样经过坐标系变换。// 此段程序用于传感器出错时停止小车err_cnt = err_cnt*115>>7; // err_cnt以0.9的比例系数衰减(115>>7的值约为0.9,避免浮点数,提高速度)if(acc.flag != 0x0F || gyr.flag != 0x0F) // 读取的角度、角速度值有误。可能是电磁干扰、iic线太长等导致出错。{
资源下载:
两轮自平衡小车资料(L298N 模块原理图及使用说明+c源码)