两轮平衡车PID闭环控制系统

两轮平衡车PID闭环控制系统

两轮平衡车控制系统,包含直立环(PD)、速度环(PI)、位置环(PID) 的三环闭环控制,支持参数整定、实时监测和仿真测试。

一、系统架构

两轮平衡车控制系统架构:
├── 传感器模块
│   ├── MPU6050陀螺仪加速度计
│   ├── 编码器速度检测
│   └── 超声波/红外位置检测
├── 控制算法模块
│   ├── 直立环PD控制(内环)
│   ├── 速度环PI控制(中环)
│   ├── 位置环PID控制(外环)
│   └── 串级控制融合
├── 电机驱动模块
│   ├── TB6612/TB67H450电机驱动
│   ├── PWM输出控制
│   └── 死区补偿
├── 系统保护模块
│   ├── 倾角超限保护
│   ├── 过流保护
│   └── 欠压保护
└── 调试接口
    ├── 串口参数配置
    ├── 实时数据监测
    └── 波形显示

二、核心代码实现

2.1 PID控制器结构 (pid_controller.h)

#ifndef PID_CONTROLLER_H
#define PID_CONTROLLER_H

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>

// PID参数结构
typedef struct {
    float kp;           // 比例系数
    float ki;           // 积分系数
    float kd;           // 微分系数
    float integral;     // 积分项
    float prev_error;   // 上次误差
    float max_output;   // 最大输出限制
    float min_output;   // 最小输出限制
    float integral_limit; // 积分限幅
    float dead_zone;    // 死区
    float output;       // 当前输出
    uint8_t enabled;    // 使能标志
} PID_Controller;

// 平衡车系统状态
typedef struct {
    // 传感器数据
    float pitch;        // 俯仰角(度)
    float roll;         // 横滚角(度)
    float gyro_y;       // Y轴角速度(度/秒)
    float left_speed;   // 左轮速度(脉冲/秒)
    float right_speed;  // 右轮速度(脉冲/秒)
    float position;     // 位置(米)
    
    // 目标值
    float target_pitch; // 目标俯仰角
    float target_speed; // 目标速度
    float target_position; // 目标位置
    
    // 控制输出
    float upright_output; // 直立环输出
    float speed_output;  // 速度环输出
    float position_output; // 位置环输出
    float left_motor;    // 左电机输出
    float right_motor;   // 右电机输出
    
    // 系统状态
    uint8_t balanced;    // 平衡状态
    uint8_t moving;      // 运动状态
    uint8_t error_code;  // 错误代码
} BalanceCar_State;

// 系统参数
typedef struct {
    // 物理参数
    float wheel_radius;  // 轮子半径(米)
    float car_length;    // 车体长度(米)
    float mass;          // 质量(kg)
    float gravity;       // 重力加速度
    
    // 编码器参数
    int encoder_ppr;     // 每转脉冲数
    float gear_ratio;    // 减速比
    
    // 控制周期
    float dt;            // 控制周期(秒)
} BalanceCar_Params;

// 函数声明
void PID_Init(PID_Controller *pid, float kp, float ki, float kd);
void PID_SetLimits(PID_Controller *pid, float min, float max);
void PID_SetIntegralLimit(PID_Controller *pid, float limit);
void PID_Enable(PID_Controller *pid, uint8_t enable);
float PID_Calculate(PID_Controller *pid, float target, float feedback);
void PID_Reset(PID_Controller *pid);

// 平衡车控制函数
void BalanceCar_Init(BalanceCar_State *state, BalanceCar_Params *params);
void BalanceCar_UpdateSensors(BalanceCar_State *state, 
                           float pitch, float gyro_y, 
                           int left_encoder, int right_encoder,
                           float position);
void BalanceCar_ControlLoop(BalanceCar_State *state, 
                          PID_Controller *upright_pid,
                          PID_Controller *speed_pid,
                          PID_Controller *position_pid);
void BalanceCar_MotorOutput(BalanceCar_State *state);
void BalanceCar_SafetyCheck(BalanceCar_State *state);

#endif // PID_CONTROLLER_H

2.2 PID控制器实现 (pid_controller.c)

#include "pid_controller.h"

// 初始化PID控制器
void PID_Init(PID_Controller *pid, float kp, float ki, float kd) {
    pid->kp = kp;
    pid->ki = ki;
    pid->kd = kd;
    pid->integral = 0.0f;
    pid->prev_error = 0.0f;
    pid->output = 0.0f;
    pid->enabled = 1;
    pid->dead_zone = 0.0f;
}

// 设置输出限制
void PID_SetLimits(PID_Controller *pid, float min, float max) {
    pid->min_output = min;
    pid->max_output = max;
}

// 设置积分限制
void PID_SetIntegralLimit(PID_Controller *pid, float limit) {
    pid->integral_limit = limit;
}

// 使能/失能PID
void PID_Enable(PID_Controller *pid, uint8_t enable) {
    pid->enabled = enable;
    if (!enable) {
        pid->integral = 0.0f;
        pid->prev_error = 0.0f;
    }
}

// 计算PID输出
float PID_Calculate(PID_Controller *pid, float target, float feedback) {
    if (!pid->enabled) {
        return 0.0f;
    }
    
    float error = target - feedback;
    
    // 死区处理
    if (fabs(error) < pid->dead_zone) {
        error = 0.0f;
    }
    
    // 比例项
    float proportional = pid->kp * error;
    
    // 积分项(抗积分饱和)
    pid->integral += pid->ki * error;
    if (pid->integral > pid->integral_limit) {
        pid->integral = pid->integral_limit;
    } else if (pid->integral < -pid->integral_limit) {
        pid->integral = -pid->integral_limit;
    }
    
    // 微分项(使用微分先行,避免设定值突变)
    float derivative = pid->kd * (error - pid->prev_error);
    pid->prev_error = error;
    
    // 计算输出
    pid->output = proportional + pid->integral + derivative;
    
    // 输出限幅
    if (pid->output > pid->max_output) {
        pid->output = pid->max_output;
    } else if (pid->output < pid->min_output) {
        pid->output = pid->min_output;
    }
    
    return pid->output;
}

// 重置PID控制器
void PID_Reset(PID_Controller *pid) {
    pid->integral = 0.0f;
    pid->prev_error = 0.0f;
    pid->output = 0.0f;
}

// 更新传感器数据
void BalanceCar_UpdateSensors(BalanceCar_State *state, 
                           float pitch, float gyro_y, 
                           int left_encoder, int right_encoder,
                           float position) {
    state->pitch = pitch;
    state->gyro_y = gyro_y;
    
    // 计算速度(脉冲转换为实际速度)
    static int prev_left_encoder = 0;
    static int prev_right_encoder = 0;
    
    int left_delta = left_encoder - prev_left_encoder;
    int right_delta = right_encoder - prev_right_encoder;
    
    // 转换为速度(米/秒)
    float dt = 0.005f; // 5ms控制周期
    state->left_speed = (float)left_delta / 780.0f * 2.0f * 3.14159f * 0.0325f / dt;
    state->right_speed = (float)right_delta / 780.0f * 2.0f * 3.14159f * 0.0325f / dt;
    
    prev_left_encoder = left_encoder;
    prev_right_encoder = right_encoder;
    
    state->position = position;
}

// 直立环PD控制(内环)
float Upright_Control(BalanceCar_State *state, PID_Controller *pid) {
    // 直立环:角度和角速度反馈
    float angle_error = state->target_pitch - state->pitch;
    float gyro_feedback = state->gyro_y;
    
    // PD控制
    float output = pid->kp * angle_error + pid->kd * gyro_feedback;
    
    // 输出限制
    if (output > pid->max_output) output = pid->max_output;
    if (output < pid->min_output) output = pid->min_output;
    
    return output;
}

// 速度环PI控制(中环)
float Speed_Control(BalanceCar_State *state, PID_Controller *pid) {
    // 计算平均速度
    float avg_speed = (state->left_speed + state->right_speed) / 2.0f;
    
    // 速度环输出作为直立环的目标角度
    float speed_error = state->target_speed - avg_speed;
    
    // PI控制
    pid->integral += pid->ki * speed_error;
    if (pid->integral > pid->integral_limit) pid->integral = pid->integral_limit;
    if (pid->integral < -pid->integral_limit) pid->integral = -pid->integral_limit;
    
    float output = pid->kp * speed_error + pid->integral;
    
    // 输出限制
    if (output > pid->max_output) output = pid->max_output;
    if (output < pid->min_output) output = pid->min_output;
    
    return output;
}

// 位置环PID控制(外环)
float Position_Control(BalanceCar_State *state, PID_Controller *pid) {
    float position_error = state->target_position - state->position;
    
    // PID控制
    pid->integral += pid->ki * position_error;
    if (pid->integral > pid->integral_limit) pid->integral = pid->integral_limit;
    if (pid->integral < -pid->integral_limit) pid->integral = -pid->integral_limit;
    
    float derivative = pid->kd * (position_error - pid->prev_error);
    pid->prev_error = position_error;
    
    float output = pid->kp * position_error + pid->integral + derivative;
    
    // 输出限制
    if (output > pid->max_output) output = pid->max_output;
    if (output < pid->min_output) output = pid->min_output;
    
    return output;
}

// 主控制循环
void BalanceCar_ControlLoop(BalanceCar_State *state, 
                          PID_Controller *upright_pid,
                          PID_Controller *speed_pid,
                          PID_Controller *position_pid) {
    
    // 1. 位置环(外环)
    if (position_pid->enabled) {
        state->position_output = Position_Control(state, position_pid);
        state->target_speed = state->position_output;
    }
    
    // 2. 速度环(中环)
    if (speed_pid->enabled) {
        state->speed_output = Speed_Control(state, speed_pid);
        state->target_pitch = state->speed_output;
    }
    
    // 3. 直立环(内环)
    if (upright_pid->enabled) {
        state->upright_output = Upright_Control(state, upright_pid);
    }
    
    // 4. 电机输出合成
    BalanceCar_MotorOutput(state);
}

// 电机输出计算
void BalanceCar_MotorOutput(BalanceCar_State *state) {
    // 直立环输出作为基础
    float base_output = state->upright_output;
    
    // 左右轮差速(转向控制)
    float turn_diff = 0.0f; // 转向差速,可通过遥控器或陀螺仪获得
    
    // 计算左右电机输出
    state->left_motor = base_output - turn_diff;
    state->right_motor = base_output + turn_diff;
    
    // 输出限幅
    if (state->left_motor > 100.0f) state->left_motor = 100.0f;
    if (state->left_motor < -100.0f) state->left_motor = -100.0f;
    if (state->right_motor > 100.0f) state->right_motor = 100.0f;
    if (state->right_motor < -100.0f) state->right_motor = -100.0f;
}

// 安全检查
void BalanceCar_SafetyCheck(BalanceCar_State *state) {
    // 倾角过大保护
    if (fabs(state->pitch) > 45.0f) {
        state->error_code = 1; // 倾角超限
        state->balanced = 0;
        state->left_motor = 0;
        state->right_motor = 0;
        return;
    }
    
    // 速度过大保护
    float avg_speed = (fabs(state->left_speed) + fabs(state->right_speed)) / 2.0f;
    if (avg_speed > 5.0f) { // 5m/s速度限制
        state->error_code = 2; // 速度超限
        state->balanced = 0;
        return;
    }
    
    // 正常状态
    state->error_code = 0;
    state->balanced = 1;
}

2.3 主程序与参数整定 (main.c)

#include "pid_controller.h"
#include <time.h>
#include <unistd.h>

// 系统参数
BalanceCar_Params car_params = {
    .wheel_radius = 0.0325f,    // 3.25cm轮子半径
    .car_length = 0.15f,        // 15cm车体长度
    .mass = 1.5f,               // 1.5kg质量
    .gravity = 9.81f,           // 重力加速度
    .encoder_ppr = 780,         // 编码器每转780脉冲
    .gear_ratio = 30.0f,        // 30:1减速比
    .dt = 0.005f                // 5ms控制周期
};

// PID控制器
PID_Controller upright_pid;     // 直立环
PID_Controller speed_pid;       // 速度环
PID_Controller position_pid;    // 位置环

// 系统状态
BalanceCar_State car_state;

// 模拟传感器数据
typedef struct {
    float pitch;
    float gyro_y;
    int left_encoder;
    int right_encoder;
    float position;
} SimulatedData;

SimulatedData sim_data = {0};

// 生成模拟数据
void GenerateSimulatedData(SimulatedData *sim, float target_pitch, float target_speed) {
    static float time = 0.0f;
    
    // 模拟倾角变化(受控制输出影响)
    sim->pitch += (target_pitch - sim->pitch) * 0.1f + (rand() % 100 - 50) * 0.001f;
    
    // 模拟角速度
    sim->gyro_y = (sim->pitch - target_pitch) * 10.0f;
    
    // 模拟编码器
    float motor_output = (car_state.left_motor + car_state.right_motor) / 2.0f;
    sim->left_encoder += (int)(motor_output * 10.0f);
    sim->right_encoder += (int)(motor_output * 10.0f);
    
    // 模拟位置
    float avg_speed = motor_output * 0.1f;
    sim->position += avg_speed * 0.005f;
    
    time += 0.005f;
}

// 参数整定函数
void AutoTune_Parameters() {
    printf("开始参数整定...\n");
    
    // 1. 直立环整定(先关闭速度环和位置环)
    printf("1. 直立环整定\n");
    PID_Enable(&speed_pid, 0);
    PID_Enable(&position_pid, 0);
    
    // 从小到大调整Kp,直到小车能站立但轻微震荡
    for (float kp = 10.0f; kp < 100.0f; kp += 5.0f) {
        upright_pid.kp = kp;
        printf("测试 Kp = %.1f\n", kp);
        // 这里应该在实际硬件上测试
        usleep(100000); // 模拟延时
    }
    
    // 2. 速度环整定
    printf("2. 速度环整定\n");
    PID_Enable(&speed_pid, 1);
    PID_Enable(&position_pid, 0);
    
    // 调整Ki,消除稳态误差
    speed_pid.ki = 0.1f;
    speed_pid.kp = 5.0f;
    
    // 3. 位置环整定
    printf("3. 位置环整定\n");
    PID_Enable(&position_pid, 1);
    
    // 标准PID整定
    position_pid.kp = 1.0f;
    position_pid.ki = 0.05f;
    position_pid.kd = 0.1f;
}

// 打印系统状态
void PrintSystemStatus(BalanceCar_State *state) {
    static int counter = 0;
    if (counter++ % 100 == 0) { // 每500ms打印一次
        printf("========================================\n");
        printf("俯仰角: %6.2f°  目标: %6.2f°\n", state->pitch, state->target_pitch);
        printf("角速度: %6.2f°/s\n", state->gyro_y);
        printf("速度: L=%6.2f R=%6.2f m/s\n", state->left_speed, state->right_speed);
        printf("位置: %6.2f m  目标: %6.2f m\n", state->position, state->target_position);
        printf("输出: L=%6.2f%% R=%6.2f%%\n", state->left_motor, state->right_motor);
        printf("直立环: %6.2f  速度环: %6.2f  位置环: %6.2f\n", 
               state->upright_output, state->speed_output, state->position_output);
        printf("状态: %s  错误: %d\n", state->balanced ? "平衡" : "失衡", state->error_code);
        printf("========================================\n");
    }
}

int main() {
    printf("两轮平衡车PID控制系统启动\n");
    printf("=============================\n");
    
    // 初始化系统
    BalanceCar_Init(&car_state, &car_params);
    
    // 初始化PID参数(经验值)
    // 直立环PD参数(最重要)
    PID_Init(&upright_pid, 45.0f, 0.0f, 1.2f);  // Kp=45, Ki=0, Kd=1.2
    PID_SetLimits(&upright_pid, -100.0f, 100.0f);
    PID_SetIntegralLimit(&upright_pid, 50.0f);
    
    // 速度环PI参数
    PID_Init(&speed_pid, 5.0f, 0.1f, 0.0f);    // Kp=5, Ki=0.1, Kd=0
    PID_SetLimits(&speed_pid, -10.0f, 10.0f);
    PID_SetIntegralLimit(&speed_pid, 5.0f);
    
    // 位置环PID参数
    PID_Init(&position_pid, 1.0f, 0.05f, 0.1f); // Kp=1, Ki=0.05, Kd=0.1
    PID_SetLimits(&position_pid, -2.0f, 2.0f);
    PID_SetIntegralLimit(&position_pid, 1.0f);
    
    // 设置目标值
    car_state.target_pitch = 0.0f;      // 直立时目标角度为0
    car_state.target_speed = 0.0f;      // 静止
    car_state.target_position = 0.0f;   // 原点位置
    
    printf("初始参数设置完成\n");
    printf("直立环: Kp=%.1f, Kd=%.1f\n", upright_pid.kp, upright_pid.kd);
    printf("速度环: Kp=%.1f, Ki=%.1f\n", speed_pid.kp, speed_pid.ki);
    printf("位置环: Kp=%.1f, Ki=%.1f, Kd=%.1f\n", position_pid.kp, position_pid.ki, position_pid.kd);
    
    // 参数整定选项
    printf("\n是否进行参数整定?(y/n): ");
    char choice;
    scanf(" %c", &choice);
    if (choice == 'y' || choice == 'Y') {
        AutoTune_Parameters();
    }
    
    printf("\n开始控制循环...\n");
    
    // 控制循环
    int step = 0;
    while (1) {
        // 生成模拟传感器数据
        GenerateSimulatedData(&sim_data, car_state.target_pitch, car_state.target_speed);
        
        // 更新传感器数据
        BalanceCar_UpdateSensors(&car_state, 
                               sim_data.pitch, 
                               sim_data.gyro_y,
                               sim_data.left_encoder,
                               sim_data.right_encoder,
                               sim_data.position);
        
        // 安全检查
        BalanceCar_SafetyCheck(&car_state);
        
        if (car_state.balanced) {
            // 执行控制循环
            BalanceCar_ControlLoop(&car_state, &upright_pid, &speed_pid, &position_pid);
        }
        
        // 打印系统状态
        PrintSystemStatus(&car_state);
        
        // 模拟控制周期
        usleep(5000); // 5ms
        
        // 测试不同工况
        step++;
        if (step == 1000) {  // 5秒后前进
            printf("\n>>> 开始前进测试 <<<\n");
            car_state.target_speed = 0.5f;  // 0.5m/s
        } else if (step == 2000) {  // 10秒后后退
            printf("\n>>> 开始后退测试 <<<\n");
            car_state.target_speed = -0.5f; // -0.5m/s
        } else if (step == 3000) {  // 15秒后位置控制
            printf("\n>>> 开始位置控制测试 <<<\n");
            car_state.target_position = 2.0f; // 前进2米
        } else if (step == 4000) {  // 20秒后停止
            printf("\n>>> 停止测试 <<<\n");
            car_state.target_speed = 0.0f;
            car_state.target_position = 0.0f;
        }
    }
    
    return 0;
}

2.4 硬件接口层 (hardware_interface.h)

#ifndef HARDWARE_INTERFACE_H
#define HARDWARE_INTERFACE_H

#include "pid_controller.h"

// 硬件接口函数声明
void HW_Init(void);
void HW_Encoder_Init(void);
void HW_MPU6050_Init(void);
void HW_Motor_Init(void);
void HW_Ultrasonic_Init(void);

// 读取传感器数据
float HW_ReadPitch(void);
float HW_ReadGyroY(void);
int HW_ReadLeftEncoder(void);
int HW_ReadRightEncoder(void);
float HW_ReadPosition(void);

// 设置电机输出
void HW_SetMotorOutput(float left, float right);

// 系统保护
void HW_OverCurrentProtection(void);
void HW_TiltProtection(void);
void HW_UnderVoltageProtection(void);

// 调试接口
void HW_DebugPrint(const char *format, ...);
void HW_SendDataToPC(BalanceCar_State *state);

#endif // HARDWARE_INTERFACE_H

2.5 参数配置文件 (config.h)

#ifndef CONFIG_H
#define CONFIG_H

// 系统配置参数
#define CONTROL_PERIOD_MS   5       // 控制周期5ms
#define ENCODER_PPR        780      // 编码器每转脉冲数
#define WHEEL_RADIUS_MM    32.5     // 轮子半径32.5mm
#define CAR_LENGTH_MM     150.0     // 车体长度150mm
#define MAX_TILT_ANGLE     45.0     // 最大倾角45度
#define MAX_SPEED_MS       5.0      // 最大速度5m/s

// PID参数默认值
#define UPRIGHT_KP_DEFAULT  45.0f
#define UPRIGHT_KI_DEFAULT   0.0f
#define UPRIGHT_KD_DEFAULT   1.2f

#define SPEED_KP_DEFAULT     5.0f
#define SPEED_KI_DEFAULT     0.1f
#define SPEED_KD_DEFAULT     0.0f

#define POSITION_KP_DEFAULT  1.0f
#define POSITION_KI_DEFAULT   0.05f
#define POSITION_KD_DEFAULT  0.1f

// 电机参数
#define MOTOR_PWM_MAX       1000
#define MOTOR_DEAD_ZONE     50
#define MOTOR_ACCEL_LIMIT   100

// 调试选项
#define DEBUG_ENABLED       1
#define DATA_RECORD_ENABLED 1
#define PLOT_ENABLED        1

#endif // CONFIG_H

三、编译与部署

3.1 Makefile

# 两轮平衡车PID控制系统 Makefile
CC = arm-none-eabi-gcc
CFLAGS = -Wall -Wextra -O2 -std=c99 -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
LDFLAGS = -Tstm32f407.ld -Wl,-Map=output.map

# 源文件
SRCS = main.c pid_controller.c hardware_interface.c
OBJS = $(SRCS:.c=.o)

# 目标文件
TARGET = balance_car

all: $(TARGET).elf $(TARGET).bin

$(TARGET).elf: $(OBJS)
	$(CC) $(LDFLAGS) -o $@ $^

$(TARGET).bin: $(TARGET).elf
	arm-none-eabi-objcopy -O binary $< $@

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

clean:
	rm -f *.o *.elf *.bin *.map

flash: $(TARGET).bin
	st-flash write $< 0x08000000

.PHONY: all clean flash

3.2 实时数据监测脚本 (monitor.py)

#!/usr/bin/env python3
import serial
import matplotlib.pyplot as plt
import numpy as np
from collections import deque
import threading

class BalanceCarMonitor:
    def __init__(self, port='/dev/ttyUSB0', baudrate=115200):
        self.ser = serial.Serial(port, baudrate, timeout=1)
        self.data_queue = deque(maxlen=1000)
        self.running = False
        
    def start(self):
        self.running = True
        thread = threading.Thread(target=self.read_serial)
        thread.daemon = True
        thread.start()
        self.plot_data()
        
    def read_serial(self):
        while self.running:
            try:
                line = self.ser.readline().decode('utf-8').strip()
                if line.startswith('='):
                    # 解析数据
                    parts = line.split()
                    if len(parts) >= 10:
                        data = {
                            'pitch': float(parts[1]),
                            'target_pitch': float(parts[3]),
                            'gyro': float(parts[5]),
                            'left_speed': float(parts[7]),
                            'right_speed': float(parts[9]),
                            'position': float(parts[11])
                        }
                        self.data_queue.append(data)
            except:
                pass
                
    def plot_data(self):
        plt.ion()
        fig, axes = plt.subplots(3, 2, figsize=(12, 8))
        
        while self.running:
            if len(self.data_queue) > 10:
                # 提取数据
                pitches = [d['pitch'] for d in list(self.data_queue)[-100:]]
                targets = [d['target_pitch'] for d in list(self.data_queue)[-100:]]
                positions = [d['position'] for d in list(self.data_queue)[-100:]]
                speeds = [(d['left_speed'] + d['right_speed'])/2 for d in list(self.data_queue)[-100:]]
                
                # 清除并重新绘制
                for ax in axes.flat:
                    ax.clear()
                
                # 倾角图
                axes[0,0].plot(pitches, 'b-', label='实际倾角')
                axes[0,0].plot(targets, 'r--', label='目标倾角')
                axes[0,0].set_title('倾角控制')
                axes[0,0].set_ylabel('角度(°)')
                axes[0,0].legend()
                axes[0,0].grid(True)
                
                # 位置图
                axes[0,1].plot(positions, 'g-', label='实际位置')
                axes[0,1].set_title('位置控制')
                axes[0,1].set_ylabel('位置(m)')
                axes[0,1].legend()
                axes[0,1].grid(True)
                
                # 速度图
                axes[1,0].plot(speeds, 'm-', label='实际速度')
                axes[1,0].set_title('速度控制')
                axes[1,0].set_ylabel('速度(m/s)')
                axes[1,0].legend()
                axes[1,0].grid(True)
                
                # PID输出
                axes[1,1].plot([d['pitch'] for d in list(self.data_queue)[-100:]], 'c-', label='直立环输出')
                axes[1,1].set_title('PID输出')
                axes[1,1].set_ylabel('输出(%)')
                axes[1,1].legend()
                axes[1,1].grid(True)
                
                # 误差图
                errors = [t - p for t, p in zip(targets, pitches)]
                axes[2,0].plot(errors, 'r-', label='倾角误差')
                axes[2,0].set_title('控制误差')
                axes[2,0].set_ylabel('误差(°)')
                axes[2,0].legend()
                axes[2,0].grid(True)
                
                # 状态图
                axes[2,1].plot([1]*len(pitches), 'k-', alpha=0.3)
                axes[2,1].fill_between(range(len(pitches)), pitches, targets, alpha=0.3, color='red')
                axes[2,1].set_title('控制状态')
                axes[2,1].set_ylabel('状态')
                axes[2,1].grid(True)
                
                plt.tight_layout()
                plt.pause(0.1)
                
            plt.pause(0.1)
            
    def stop(self):
        self.running = False
        self.ser.close()

if __name__ == '__main__':
    monitor = BalanceCarMonitor()
    try:
        monitor.start()
    except KeyboardInterrupt:
        monitor.stop()

参考代码 包括速度环和位置环的pid闭环控制对两轮车的平衡进行调节 www.youwenfan.com/contentcnv/72184.html

四、参数整定指南

4.1 整定步骤

  1. 直立环整定(最关键)

    • 关闭速度环和位置环
    • 只保留直立环PD控制
    • 从小到大调整Kp,直到小车能站立但不稳
    • 增加Kd,减小震荡
  2. 速度环整定

    • 开启直立环和速度环
    • 设置小目标速度(0.2m/s)
    • 调整Kp消除稳态误差
    • 调整Ki消除静差
  3. 位置环整定

    • 开启所有环路
    • 设置小目标位置(0.5m)
    • 标准PID整定

4.2 典型参数范围

参数 范围 说明
直立环Kp 30-80 越大响应越快,但易震荡
直立环Kd 0.5-3.0 抑制震荡,过大产生高频噪声
速度环Kp 3-10 影响速度响应
速度环Ki 0.05-0.5 消除稳态误差
位置环Kp 0.5-3.0 影响位置精度
位置环Ki 0.01-0.1 消除位置静差
位置环Kd 0.05-0.5 抑制位置超调

五、故障排除

5.1 常见问题

  1. 无法站立

    • 检查倾角传感器安装方向
    • 检查电机极性
    • 调整直立环Kp
  2. 前后晃动

    • 增加直立环Kd
    • 减小直立环Kp
    • 检查机械结构松动
  3. 漂移严重

    • 调整速度环Ki
    • 检查编码器安装
    • 校准传感器零点
  4. 响应迟钝

    • 增大直立环Kp
    • 减小速度环Ki
    • 检查控制周期

专注于matlab/simulink,电子电路,编程