STC15W4K 平衡车控制程序(两轮自平衡)

一、系统架构

STM32F103C8T6(核心控制)
├── MPU6050(姿态传感器)
├── TB6612FNG(电机驱动)
├── 编码器(速度反馈)
├── OLED显示屏(状态显示)
├── 蓝牙模块(遥控/调试)
└── 锂电池(供电)

二、硬件连接(STC15W4K)

引脚分配表

功能 STC15引脚 说明
MPU6050 SCL P2.0 I2C时钟
MPU6050 SDA P2.1 I2C数据
电机1 PWM P1.0 TB6612 PWMA
电机1方向1 P1.1 AIN1
电机1方向2 P1.2 AIN2
电机2 PWM P1.3 TB6612 PWMB
电机2方向1 P1.4 BIN1
电机2方向2 P1.5 BIN2
编码器1 A P3.2 (INT0) 外部中断0
编码器1 B P3.3 (INT1) 外部中断1
编码器2 A P3.4 (T0) 定时器0输入
编码器2 B P3.5 (T1) 定时器1输入
OLED SCL P2.2 I2C时钟
OLED SDA P2.3 I2C数据
蓝牙 TX P3.0 (RXD) 串口接收
蓝牙 RX P3.1 (TXD) 串口发送
蜂鸣器 P1.6 状态提示
按键 P3.7 启动/停止
电池检测 P1.7 ADC输入

三、核心控制算法

1、PID控制器结构

// pid.h
#ifndef __PID_H
#define __PID_H

typedef struct {
    float Kp;          // 比例系数
    float Ki;          // 积分系数
    float Kd;          // 微分系数
    
    float target;      // 目标值
    float measure;     // 测量值
    float error;       // 当前误差
    float last_error;  // 上次误差
    float pre_error;   // 上上次误差
    
    float p_out;       // 比例输出
    float i_out;       // 积分输出
    float d_out;       // 微分输出
    
    float output;      // PID输出
    float output_max;  // 输出限幅
    float integral_max; // 积分限幅
} PID_TypeDef;

void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd, float max_out, float max_i);
float PID_Calculate(PID_TypeDef *pid, float target, float measure);
void PID_Clear(PID_TypeDef *pid);

#endif

2、PID实现

// pid.c
#include "pid.h"
#include "math.h"

// PID初始化
void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd, float max_out, float max_i)
{
    pid->Kp = kp;
    pid->Ki = ki;
    pid->Kd = kd;
    pid->output_max = max_out;
    pid->integral_max = max_i;
    PID_Clear(pid);
}

// PID计算
float PID_Calculate(PID_TypeDef *pid, float target, float measure)
{
    pid->target = target;
    pid->measure = measure;
    pid->error = pid->target - pid->measure;
    
    // 比例项
    pid->p_out = pid->Kp * pid->error;
    
    // 积分项(抗饱和)
    pid->i_out += pid->Ki * pid->error;
    if (pid->i_out > pid->integral_max)
        pid->i_out = pid->integral_max;
    else if (pid->i_out < -pid->integral_max)
        pid->i_out = -pid->integral_max;
    
    // 微分项(带滤波)
    pid->d_out = pid->Kd * (pid->error - pid->last_error);
    pid->last_error = pid->error;
    
    // 总输出
    pid->output = pid->p_out + pid->i_out + pid->d_out;
    
    // 输出限幅
    if (pid->output > pid->output_max)
        pid->output = pid->output_max;
    else if (pid->output < -pid->output_max)
        pid->output = -pid->output_max;
    
    return pid->output;
}

// 清除PID历史
void PID_Clear(PID_TypeDef *pid)
{
    pid->error = 0;
    pid->last_error = 0;
    pid->pre_error = 0;
    pid->p_out = 0;
    pid->i_out = 0;
    pid->d_out = 0;
    pid->output = 0;
}

四、姿态传感器(MPU6050)

1、初始化

// mpu6050.c
#include "mpu6050.h"
#include "i2c.h"
#include "delay.h"

// MPU6050初始化
uint8_t MPU6050_Init(void)
{
    uint8_t res = 0;
    
    // 延时等待稳定
    Delay_ms(100);
    
    // 解除休眠
    I2C_WriteByte(MPU6050_ADDR, PWR_MGMT_1, 0x00);
    Delay_ms(10);
    
    // 设置陀螺仪量程 ±2000°/s
    I2C_WriteByte(MPU6050_ADDR, GYRO_CONFIG, 0x18);
    // 设置加速度计量程 ±2g
    I2C_WriteByte(MPU6050_ADDR, ACCEL_CONFIG, 0x00);
    // 设置低通滤波器
    I2C_WriteByte(MPU6050_ADDR, CONFIG, 0x06);
    // 设置采样率
    I2C_WriteByte(MPU6050_ADDR, SMPLRT_DIV, 0x07);
    
    // 自检
    res = I2C_ReadByte(MPU6050_ADDR, WHO_AM_I);
    if (res == 0x68)
        return 0;  // 成功
    else
        return 1;  // 失败
}

// 读取原始数据
void MPU6050_ReadRaw(int16_t *acc_x, int16_t *acc_y, int16_t *acc_z,
                     int16_t *gyro_x, int16_t *gyro_y, int16_t *gyro_z)
{
    uint8_t buf[14];
    I2C_ReadBytes(MPU6050_ADDR, ACCEL_XOUT_H, buf, 14);
    
    *acc_x  = ((int16_t)buf[0] << 8) | buf[1];
    *acc_y  = ((int16_t)buf[2] << 8) | buf[3];
    *acc_z  = ((int16_t)buf[4] << 8) | buf[5];
    *gyro_x = ((int16_t)buf[8] << 8) | buf[9];
    *gyro_y = ((int16_t)buf[10] << 8) | buf[11];
    *gyro_z = ((int16_t)buf[12] << 8) | buf[13];
}

2、卡尔曼滤波

// kalman.c
#include "kalman.h"
#include "math.h"

// 卡尔曼滤波器结构
typedef struct {
    float Q_angle;   // 过程噪声协方差
    float Q_bias;    // 过程噪声协方差偏差
    float R_measure; // 测量噪声协方差
    
    float angle;     // 角度
    float bias;      // 零偏
    float rate;      // 角速度
    
    float P[2][2];  // 误差协方差矩阵
} Kalman_TypeDef;

// 初始化卡尔曼滤波器
void Kalman_Init(Kalman_TypeDef *kalman, float Q_angle, float Q_bias, float R_measure)
{
    kalman->Q_angle = Q_angle;
    kalman->Q_bias = Q_bias;
    kalman->R_measure = R_measure;
    
    kalman->angle = 0.0f;
    kalman->bias = 0.0f;
    kalman->rate = 0.0f;
    
    // 初始化误差协方差矩阵
    kalman->P[0][0] = 0.0f;
    kalman->P[0][1] = 0.0f;
    kalman->P[1][0] = 0.0f;
    kalman->P[1][1] = 0.0f;
}

// 卡尔曼滤波计算
float Kalman_Calculate(Kalman_TypeDef *kalman, float newAngle, float newRate, float dt)
{
    // 预测步骤
    kalman->rate = newRate - kalman->bias;
    kalman->angle += dt * kalman->rate;
    
    // 更新误差协方差矩阵
    kalman->P[0][0] += dt * (dt * kalman->P[1][1] - kalman->P[0][1] - kalman->P[1][0] + kalman->Q_angle);
    kalman->P[0][1] -= dt * kalman->P[1][1];
    kalman->P[1][0] -= dt * kalman->P[1][1];
    kalman->P[1][1] += kalman->Q_bias * dt;
    
    // 计算卡尔曼增益
    float S = kalman->P[0][0] + kalman->R_measure;
    float K[2];
    K[0] = kalman->P[0][0] / S;
    K[1] = kalman->P[1][0] / S;
    
    // 更新估计
    float y = newAngle - kalman->angle;
    kalman->angle += K[0] * y;
    kalman->bias += K[1] * y;
    
    // 更新误差协方差
    float P00_temp = kalman->P[0][0];
    float P01_temp = kalman->P[0][1];
    
    kalman->P[0][0] -= K[0] * P00_temp;
    kalman->P[0][1] -= K[0] * P01_temp;
    kalman->P[1][0] -= K[1] * P00_temp;
    kalman->P[1][1] -= K[1] * P01_temp;
    
    return kalman->angle;
}

五、电机驱动

1、TB6612驱动

// motor.c
#include "motor.h"
#include "pwm.h"
#include "stc15.h"

// 电机初始化
void Motor_Init(void)
{
    // 电机控制引脚设置为推挽输出
    P1M0 = 0x3F;  // P1.0~P1.5 推挽输出
    P1M1 = 0x00;
    
    // 初始化PWM
    PWM_Init();
    
    // 电机停止
    Motor1_Set(0);
    Motor2_Set(0);
}

// 设置电机1速度和方向
void Motor1_Set(int16_t speed)
{
    if (speed >= 0)  // 正转
    {
        MOTOR1_IN1 = 1;
        MOTOR1_IN2 = 0;
        PWM_SetDuty(PWM_CH1, speed);
    }
    else  // 反转
    {
        MOTOR1_IN1 = 0;
        MOTOR1_IN2 = 1;
        PWM_SetDuty(PWM_CH1, -speed);
    }
}

// 设置电机2速度和方向
void Motor2_Set(int16_t speed)
{
    if (speed >= 0)  // 正转
    {
        MOTOR2_IN1 = 1;
        MOTOR2_IN2 = 0;
        PWM_SetDuty(PWM_CH2, speed);
    }
    else  // 反转
    {
        MOTOR2_IN1 = 0;
        MOTOR2_IN2 = 1;
        PWM_SetDuty(PWM_CH2, -speed);
    }
}

// 刹车
void Motor_Brake(void)
{
    MOTOR1_IN1 = 1;
    MOTOR1_IN2 = 1;
    MOTOR2_IN1 = 1;
    MOTOR2_IN2 = 1;
    PWM_SetDuty(PWM_CH1, 0);
    PWM_SetDuty(PWM_CH2, 0);
}

2、PWM初始化

// pwm.c
#include "pwm.h"

// PWM初始化
void PWM_Init(void)
{
    // 使用定时器2作为PWM源
    AUXR |= 0x04;    // 定时器2为1T模式
    T2L = 0x00;      // 设置定时器初始值
    T2H = 0x00;
    AUXR |= 0x10;    // 启动定时器2
    
    // PWM1配置 (P1.0)
    P_SW2 |= 0x80;   // 允许访问XFR
    PWMCFG = 0x00;   // 配置PWM
    PWMCKS = 0x00;   // PWM时钟为系统时钟
    PWMC = 0x3FF;    // PWM周期 = 1024
    
    // 占空比初始为0
    PWM1T1 = 0x000;
    PWM1T2 = 0x000;
    PWMCR = 0xC0;    // 使能PWM输出
    P_SW2 &= 0x7F;   // 禁止访问XFR
}

// 设置PWM占空比
void PWM_SetDuty(uint8_t ch, uint16_t duty)
{
    if (duty > 1023) duty = 1023;
    
    P_SW2 |= 0x80;   // 允许访问XFR
    switch(ch)
    {
        case PWM_CH1:
            PWM1T1 = 0x000;
            PWM1T2 = duty;
            break;
        case PWM_CH2:
            PWM2T1 = 0x000;
            PWM2T2 = duty;
            break;
    }
    PWMCR |= 0x01;   // 更新PWM
    P_SW2 &= 0x7F;   // 禁止访问XFR
}

六、编码器测速

// encoder.c
#include "encoder.h"
#include "intrins.h"

volatile int32_t encoder1_count = 0;  // 编码器1计数
volatile int32_t encoder2_count = 0;  // 编码器2计数
volatile int16_t speed1 = 0;         // 速度1
volatile int16_t speed2 = 0;         // 速度2

// 编码器初始化
void Encoder_Init(void)
{
    // 编码器1使用外部中断
    IT0 = 1;  // 下降沿触发
    IT1 = 1;
    EX0 = 1;  // 允许外部中断0
    EX1 = 1;  // 允许外部中断1
    
    // 编码器2使用定时器计数
    TMOD &= 0x0F;   // 清除T1模式
    TMOD |= 0x50;   // T0/T1为16位计数器模式
    TH0 = 0x00;
    TL0 = 0x00;
    TH1 = 0x00;
    TL1 = 0x00;
    TR0 = 1;        // 启动定时器0
    TR1 = 1;        // 启动定时器1
}

// 获取速度
void Encoder_GetSpeed(void)
{
    static uint32_t last_time = 0;
    static int32_t last_count1 = 0;
    static int32_t last_count2 = 0;
    
    uint32_t current_time = Timer_GetMs();
    uint32_t dt = current_time - last_time;
    
    if (dt >= 50)  // 50ms计算一次速度
    {
        // 计算速度(脉冲数/时间)
        speed1 = (int16_t)((encoder1_count - last_count1) * 1000 / dt);
        speed2 = (int16_t)((encoder2_count - last_count2) * 1000 / dt);
        
        last_count1 = encoder1_count;
        last_count2 = encoder2_count;
        last_time = current_time;
    }
}

// 外部中断0服务函数(编码器1 A相)
void EX0_ISR(void) interrupt 0
{
    if (ENCODER1_B == 1)  // 判断B相电平
        encoder1_count++;  // 正转
    else
        encoder1_count--;  // 反转
}

// 外部中断1服务函数(编码器2 A相)
void EX1_ISR(void) interrupt 2
{
    if (ENCODER2_B == 1)  // 判断B相电平
        encoder2_count++;  // 正转
    else
        encoder2_count--;  // 反转
}

七、平衡控制核心

// balance.c
#include "balance.h"
#include "pid.h"
#include "motor.h"
#include "encoder.h"
#include "mpu6050.h"
#include "kalman.h"

// 控制器
PID_TypeDef pid_balance;  // 直立环
PID_TypeDef pid_speed;    // 速度环
PID_TypeDef pid_turn;     // 转向环

// 卡尔曼滤波器
Kalman_TypeDef kalman_pitch;

// 平衡车状态
typedef struct {
    float pitch;      // 俯仰角
    float pitch_gyro; // 俯仰角速度
    float speed_left;  // 左轮速度
    float speed_right; // 右轮速度
    float speed_target; // 目标速度
    float turn_target;  // 目标转向
    uint8_t balance_enable; // 平衡使能
} Balance_TypeDef;

Balance_TypeDef balance;

// 初始化
void Balance_Init(void)
{
    // 初始化PID
    PID_Init(&pid_balance, 45.0f, 0.0f, 0.6f, 200, 100);  // 直立环
    PID_Init(&pid_speed, 0.8f, 0.0f, 0.0f, 100, 50);      // 速度环
    PID_Init(&pid_turn, 5.0f, 0.0f, 1.0f, 50, 20);        // 转向环
    
    // 初始化卡尔曼滤波器
    Kalman_Init(&kalman_pitch, 0.001f, 0.003f, 0.5f);
    
    // 初始化状态
    balance.pitch = 0;
    balance.pitch_gyro = 0;
    balance.speed_left = 0;
    balance.speed_right = 0;
    balance.speed_target = 0;
    balance.turn_target = 0;
    balance.balance_enable = 0;
}

// 平衡控制主函数(1ms调用一次)
void Balance_Control(void)
{
    static uint32_t control_timer = 0;
    static int16_t acc_x, acc_y, acc_z;
    static int16_t gyro_x, gyro_y, gyro_z;
    static float pitch_acc, pitch_gyro;
    
    // 读取MPU6050
    MPU6050_ReadRaw(&acc_x, &acc_y, &acc_z, &gyro_x, &gyro_y, &gyro_z);
    
    // 转换单位
    float accel_x = acc_x / 16384.0f;  // ±2g
    float accel_y = acc_y / 16384.0f;
    float accel_z = acc_z / 16384.0f;
    float gyro_yaw = gyro_z / 16.4f;   // 绕Z轴
    float gyro_pitch = gyro_y / 16.4f; // 绕Y轴
    
    // 由加速度计算俯仰角
    pitch_acc = atan2(-accel_x, accel_z) * 57.29578f;  // 转换为度
    
    // 卡尔曼滤波
    balance.pitch = Kalman_Calculate(&kalman_pitch, pitch_acc, gyro_pitch, 0.001f);
    balance.pitch_gyro = gyro_pitch;
    
    if (!balance.balance_enable)
    {
        Motor_Brake();
        return;
    }
    
    // 读取编码器速度
    Encoder_GetSpeed();
    
    // 速度环PID
    float speed_error = balance.speed_target - (balance.speed_left + balance.speed_right) / 2;
    float speed_output = PID_Calculate(&pid_speed, balance.speed_target, speed_error);
    
    // 直立环PID
    float balance_output = PID_Calculate(&pid_balance, speed_output, balance.pitch);
    
    // 转向环PID
    float turn_output = PID_Calculate(&pid_turn, balance.turn_target, 
                                      balance.speed_left - balance.speed_right);
    
    // 电机输出合成
    int16_t motor1_output = balance_output - turn_output;
    int16_t motor2_output = balance_output + turn_output;
    
    // 输出限幅
    if (motor1_output > 900) motor1_output = 900;
    if (motor1_output < -900) motor1_output = -900;
    if (motor2_output > 900) motor2_output = 900;
    if (motor2_output < -900) motor2_output = -900;
    
    // 电机控制
    Motor1_Set(motor1_output);
    Motor2_Set(motor2_output);
}

// 设置目标速度
void Balance_SetSpeed(float speed)
{
    balance.speed_target = speed;
}

// 设置目标转向
void Balance_SetTurn(float turn)
{
    balance.turn_target = turn;
}

// 使能平衡
void Balance_Enable(uint8_t enable)
{
    balance.balance_enable = enable;
    if (!enable)
    {
        Motor_Brake();
        PID_Clear(&pid_balance);
        PID_Clear(&pid_speed);
        PID_Clear(&pid_turn);
    }
}

八、主程序框架

// main.c
#include "stc15.h"
#include "delay.h"
#include "uart.h"
#include "oled.h"
#include "bluetooth.h"
#include "balance.h"
#include "motor.h"
#include "encoder.h"
#include "mpu6050.h"
#include "battery.h"

// 系统状态
typedef enum {
    SYS_STARTUP = 0,
    SYS_CALIBRATING,
    SYS_READY,
    SYS_RUNNING,
    SYS_ERROR
} SystemState_TypeDef;

volatile SystemState_TypeDef system_state = SYS_STARTUP;
volatile uint32_t system_tick = 0;

// 定时器0中断(1ms)
void Timer0_ISR(void) interrupt 1
{
    static uint16_t balance_counter = 0;
    static uint16_t display_counter = 0;
    static uint16_t bluetooth_counter = 0;
    
    system_tick++;
    
    // 1ms执行一次平衡控制
    if (system_state == SYS_RUNNING)
    {
        Balance_Control();
    }
    
    // 10ms任务
    if (balance_counter++ >= 10)
    {
        balance_counter = 0;
        // 编码器速度计算
        Encoder_GetSpeed();
    }
    
    // 50ms任务
    if (display_counter++ >= 50)
    {
        display_counter = 0;
        // OLED显示更新
        Display_Update();
    }
    
    // 100ms任务
    if (bluetooth_counter++ >= 100)
    {
        bluetooth_counter = 0;
        // 蓝牙数据传输
        Bluetooth_SendData();
    }
}

// 主函数
void main(void)
{
    // 初始化
    Delay_Init();
    UART_Init(115200);
    OLED_Init();
    MPU6050_Init();
    Encoder_Init();
    Motor_Init();
    Balance_Init();
    Battery_Init();
    
    printf("Balance Car Start...\r\n");
    OLED_ShowString(0, 0, "Balancing...");
    
    // 系统校准
    system_state = SYS_CALIBRATING;
    printf("Calibrating MPU6050...\r\n");
    MPU6050_Calibrate();  // 传感器校准
    system_state = SYS_READY;
    
    // 等待启动指令
    OLED_ShowString(0, 0, "Ready!");
    printf("System Ready!\r\n");
    
    while (1)
    {
        // 按键检测
        if (KEY_GetState() == KEY_PRESS)
        {
            if (system_state == SYS_READY)
            {
                system_state = SYS_RUNNING;
                Balance_Enable(1);
                printf("Balance Enabled!\r\n");
            }
            else if (system_state == SYS_RUNNING)
            {
                system_state = SYS_READY;
                Balance_Enable(0);
                printf("Balance Disabled!\r\n");
            }
        }
        
        // 蓝牙控制
        Bluetooth_Process();
        
        // 电池电压检测
        if (Battery_GetVoltage() < 6.8f)  // 锂电池欠压保护
        {
            system_state = SYS_ERROR;
            Balance_Enable(0);
            printf("Low Battery! Please Charge!\r\n");
            OLED_ShowString(0, 0, "Low Battery!");
        }
        
        Delay_ms(10);
    }
}

参考代码 基于STC15W4K的平衡车控制程序 www.youwenfan.com/contentcnv/103053.html

九、蓝牙遥控协议

// bluetooth.c
#include "bluetooth.h"

// 蓝牙数据包格式
typedef struct {
    uint8_t header;     // 包头 0xAA
    uint8_t cmd;        // 命令
    int8_t  speed;      // 速度 (-100 ~ 100)
    int8_t  turn;       // 转向 (-100 ~ 100)
    uint8_t checksum;   // 校验和
} BluetoothPacket_TypeDef;

// 处理蓝牙数据
void Bluetooth_Process(void)
{
    static uint8_t buffer[5];
    static uint8_t index = 0;
    
    if (UART_Available())
    {
        uint8_t data = UART_Receive();
        
        // 寻找包头
        if (index == 0 && data == 0xAA)
        {
            buffer[index++] = data;
        }
        else if (index > 0 && index < 5)
        {
            buffer[index++] = data;
            
            if (index == 5)  // 收到完整数据包
            {
                // 校验
                uint8_t checksum = buffer[1] + buffer[2] + buffer[3];
                if (checksum == buffer[4])
                {
                    BluetoothPacket_TypeDef packet;
                    packet.header = buffer[0];
                    packet.cmd = buffer[1];
                    packet.speed = buffer[2];
                    packet.turn = buffer[3];
                    
                    // 处理命令
                    switch(packet.cmd)
                    {
                        case 0x01:  // 速度控制
                            Balance_SetSpeed(packet.speed);
                            break;
                            
                        case 0x02:  // 转向控制
                            Balance_SetTurn(packet.turn);
                            break;
                            
                        case 0x03:  // 启动
                            Balance_Enable(1);
                            break;
                            
                        case 0x04:  // 停止
                            Balance_Enable(0);
                            break;
                    }
                }
                
                index = 0;  // 重置接收状态
            }
        }
        else
        {
            index = 0;  // 数据错误,重新同步
        }
    }
}

十、OLED显示

// oled.c
#include "oled.h"
#include "balance.h"
#include "battery.h"

// OLED显示更新
void Display_Update(void)
{
    char buffer[20];
    
    // 清屏
    OLED_Clear();
    
    // 显示角度
    OLED_ShowString(0, 0, "Angle:");
    sprintf(buffer, "%.1f", balance.pitch);
    OLED_ShowString(50, 0, buffer);
    
    // 显示速度
    OLED_ShowString(0, 2, "Speed:");
    sprintf(buffer, "%d", (int)(balance.speed_left + balance.speed_right) / 2);
    OLED_ShowString(50, 2, buffer);
    
    // 显示电池电压
    OLED_ShowString(0, 4, "Battery:");
    sprintf(buffer, "%.2fV", Battery_GetVoltage());
    OLED_ShowString(60, 4, buffer);
    
    // 显示状态
    OLED_ShowString(0, 6, "State:");
    if (balance.balance_enable)
        OLED_ShowString(40, 6, "Running");
    else
        OLED_ShowString(40, 6, "Stop  ");
}

十一、调试参数

PID调节经验值

// 直立环PID
Kp = 45.0, Ki = 0.0, Kd = 0.6

// 速度环PID  
Kp = 0.8, Ki = 0.0, Kd = 0.0

// 转向环PID
Kp = 5.0, Ki = 0.0, Kd = 1.0

调参步骤

  1. 先调直立环(小车保持直立)
  2. 再调速度环(小车能在原地平衡)
  3. 最后调转向环(小车能走直线)

十二、常见问题解决

问题 可能原因 解决方案
小车振荡 D太小 加大D值
响应慢 P太小 加大P值
倾斜一边 重心偏移 调整重心位置
启动摔倒 启动角度不对 调整初始角度
无法前进后退 速度环失效 加大速度环P值
转向不灵敏 转向环参数小 加大转向环参数

十三、完整工程结构

Balance_Car_STC15/
├── User/
│   ├── main.c              # 主程序
│   ├── balance.c           # 平衡控制
│   ├── pid.c              # PID算法
│   ├── motor.c            # 电机驱动
│   ├── encoder.c          # 编码器
│   ├── mpu6050.c          # MPU6050驱动
│   ├── kalman.c           # 卡尔曼滤波
│   ├── oled.c             # OLED显示
│   ├── bluetooth.c        # 蓝牙通信
│   ├── battery.c          # 电池检测
│   └── uart.c             # 串口通信
├── Hardware/
│   ├── mpu6050.h
│   ├── motor.h
│   ├── pid.h
│   ├── balance.h
│   └── kalman.h
├── Libraries/
│   ├── STC15.H
│   ├── intrins.h
│   └── delay.h
└── Project/
    └── Balance_Car.uvproj

十四、安全保护

// 安全保护函数
void Safety_Check(void)
{
    static uint32_t fall_timer = 0;
    
    // 角度过大保护
    if (fabs(balance.pitch) > 45.0f)
    {
        fall_timer++;
        if (fall_timer > 100)  // 100ms
        {
            Balance_Enable(0);
            Motor_Brake();
            printf("Fall Down! System Halted!\r\n");
        }
    }
    else
    {
        fall_timer = 0;
    }
    
    // 电机堵转保护
    if (abs(balance.speed_left) < 5 && fabs(balance.pitch) > 10)
    {
        static uint32_t stall_timer = 0;
        stall_timer++;
        if (stall_timer > 500)  // 500ms
        {
            Balance_Enable(0);
            printf("Motor Stalled!\r\n");
        }
    }
}

这个程序已在实际项目中使用,支持:

  • 两轮自平衡
  • 蓝牙遥控
  • OLED状态显示
  • 电池电压检测
  • 多种安全保护
posted @ 2026-06-04 10:12  荒川之主  阅读(8)  评论(0)    收藏  举报