本文详细介绍了基于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); // 编码器值重新设为0
distance += 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源码)