最近在准备全国大学生电子设计大赛,发现“车载平衡滚球运动控制系统”这类题目对学生的综合能力要求很高,它融合了机械结构、传感器、控制算法和嵌入式开发等多个领域。很多同学在拿到题目后,面对从零开始的系统设计、硬件选型、软件编程和算法调试,常常感到无从下手,网上资料也多是零散的模块介绍,缺乏一个从需求分析到最终实现的完整闭环指导。
本文旨在为备战此类赛事的同学提供一个系统性的实战教程。我们将围绕“车载平衡滚球运动控制系统”的核心需求,拆解其技术要点,从系统方案设计、硬件选型与搭建、核心控制算法(PID)的实现,到嵌入式软件编程与调试,提供一个完整的、可复现的开发流程。无论你是初次参赛的新手,还是希望深化理解控制系统的同学,都能从中获得清晰的思路和可直接借鉴的代码。
1. 系统需求分析与整体方案设计
在动手之前,我们必须清晰地理解题目要求。全国大学生电子设计大赛的题目通常具有明确的指标和开放性。对于“车载平衡滚球运动控制系统”,我们可以提炼出以下核心需求:
1.1 核心功能需求:
- 基本平衡控制:小车平台(载体)需要能够自主保持水平或特定角度的平衡,使得放置在平台上的小球不会滚落。
- 小球位置控制:系统需要能够检测小球在平台上的实时位置(二维坐标X, Y),并控制平台倾斜,驱动小球运动到指定的目标位置。
- 路径跟踪与运动控制:可能需要控制小球沿着预设的轨迹(如直线、圆形、“8”字形)运动。
- 人机交互:通常需要具备按键、显示屏等输入输出设备,用于设定目标、切换模式、显示状态(如小球坐标、平台倾角、控制参数等)。
1.2 性能指标(示例,需根据当年赛题细则调整):
- 平衡响应时间:平台从扰动中恢复平衡的时间。
- 定位精度:小球静止时,其实际位置与目标位置的误差。
- 轨迹跟踪误差:小球运动轨迹与预设轨迹的最大偏差。
- 系统稳定性:在一定的干扰下,系统能否保持稳定工作。
1.3 整体系统架构设计:基于以上需求,我们设计一个典型的四层架构:
- 感知层:负责采集系统状态信息。
- 平台姿态感知:采用MPU6050(集成三轴加速度计和三轴陀螺仪)模块,实时测量平台的俯仰角(Pitch)和横滚角(Roll)。这是实现平衡控制的基础。
- 小球位置感知:方案有多种:
- 摄像头方案:在平台上方架设摄像头(如OpenMV、OV7670),通过图像处理算法(颜色识别、轮廓提取)识别小球中心坐标。优点是直观,信息丰富;缺点是对处理能力要求较高,可能受光照影响。
- 电阻触摸屏方案:使用一个透明的电阻式触摸屏覆盖在平台表面,小球滚动时压迫屏幕产生电压信号,通过AD转换可计算出坐标。优点是检测直接、快速;缺点是屏幕表面需要平整,且小球需有一定重量。
- 激光/红外对管阵列:在平台四周布置多组对射式红外传感器,通过判断哪些光束被小球遮挡来粗略定位。成本低,但精度和分辨率也较低。
- 本文示例将采用“MPU6050 + 电阻触摸屏”方案,因其数据稳定、处理简单,更适合嵌入式单片机实时控制。
- 控制层:系统的“大脑”,负责数据处理和算法执行。
- 主控芯片:推荐使用STM32F4系列或STM32H7系列单片机。它们具有较高的主频、丰富的定时器和外设(多路ADC、DMA、硬件浮点运算单元FPU),能流畅运行浮点运算密集的PID控制算法。对于更复杂的图像处理,可能需要树莓派或Jetson Nano等Linux平台。
- 本文以STM32F407为例进行讲解。
- 执行层:接收控制指令,驱动平台运动。
- 执行机构:通常采用两个舵机(Servo)或步进电机(Stepper Motor),分别控制平台在X轴和Y轴方向的倾斜。
- 舵机:控制简单(PWM信号),扭矩大,但行程角度有限(通常±90°),且需要额外的机械结构(如连杆)将旋转运动转换为平台的倾斜。
- 步进电机:可以精确控制旋转角度,通过丝杆或连杆机构也能实现平台倾斜,但需要驱动器(如A4988、TMC2208)和更复杂的脉冲控制。
- 本文示例采用两个大扭矩舵机,因其控制简单,响应快,适合快速原型开发。
- 交互层:提供用户操作界面。
- OLED显示屏(如0.96寸 SSD1306):用于显示小球坐标、平台角度、PID参数、系统状态等。
- 按键/旋转编码器:用于切换模式、设定目标坐标、调整PID参数。
系统工作流程:触摸屏/摄像头获取小球坐标(x, y),MPU6050获取平台角度(θ_x, θ_y)。控制核心根据目标坐标(x_target, y_target)和当前坐标(x, y)的偏差,计算出期望的平台目标角度(θ_x_target, θ_y_target)。再根据当前角度(θ_x, θ_y)与目标角度的偏差,通过PID控制器计算出需要输出给X轴和Y轴舵机的PWM占空比,从而驱动平台倾斜,使小球向目标位置运动。同时,平衡控制环(内环)始终运行,确保平台自身稳定。
2. 硬件选型、电路设计与平台搭建
2.1 核心元器件清单
| 模块 | 型号示例 | 主要参数 | 用途 |
|---|---|---|---|
| 主控MCU | STM32F407ZGT6 | 168MHz, FPU, 1MB Flash, 192KB RAM | 系统控制核心 |
| 姿态传感器 | MPU6050 | 3轴加速度计+3轴陀螺仪,I2C接口 | 测量平台倾角 |
| 位置传感器 | 4线电阻触摸屏 | 如 XPT2046 控制器,SPI接口 | 检测小球坐标 |
| 执行器 | 舵机 MG996R | 扭矩 9.4kg·cm,工作电压 4.8-7.2V | 驱动平台倾斜 |
| 显示模块 | OLED SSD1306 | 0.96寸,128x64, I2C接口 | 显示系统信息 |
| 输入设备 | 按键、旋转编码器 | - | 模式切换、参数设置 |
| 电源模块 | LM2596降压模块 | 输入7-40V,输出5V/3A | 为MCU、传感器供电 |
| 电机驱动 | 需注意舵机直接由PWM控制,若用步进电机则需A4988等驱动器 | - | - |
| 平台结构 | 亚克力板、碳杆、轴承、3D打印件 | - | 机械本体 |
2.2 关键电路设计与连接
- STM32F4 最小系统:包括核心芯片、晶振、复位电路、Boot模式选择、电源滤波(3.3V)。确保电源稳定。
- MPU6050连接:使用I2C1接口。
VCC -> 3.3VGND -> GNDSCL -> PB8 (I2C1_SCL)SDA -> PB9 (I2C1_SDA)INT -> 可选,接外部中断引脚
- 电阻触摸屏(XPT2046)连接:使用SPI1接口。
VCC -> 3.3VGND -> GNDCLK -> PA5 (SPI1_SCK)DIN -> PA7 (SPI1_MOSI)DOUT -> PA6 (SPI1_MISO)CS -> PA4 (SPI1_CS)IRQ -> 可选,接外部中断引脚
- 舵机连接:使用定时器产生PWM信号。
舵机1 (X轴) 信号线 -> PA8 (TIM1_CH1)舵机2 (Y轴) 信号线 -> PA9 (TIM1_CH2)舵机电源+ -> 外部5V/6V电源(需与MCU共地)舵机电源- -> GND- 重要:舵机功率较大,务必使用独立电源供电,避免从MCU的3.3V取电,否则可能导致MCU复位或损坏。
- OLED (SSD1306) 连接:使用I2C2接口。
VCC -> 3.3VGND -> GNDSCL -> PB10 (I2C2_SCL)SDA -> PB11 (I2C2_SDA)
2.3 机械平台搭建要点
- 平台板:使用轻质且有一定强度的材料,如亚克力板。尺寸根据小球和舵机行程决定,例如15cm x 15cm。
- 十字轴结构:平台板通过两个互相垂直的轴(可以用碳纤维杆或金属轴)连接。X轴舵机控制平台绕X轴旋转(影响小球Y方向运动),Y轴舵机控制平台绕Y轴旋转(影响小球X方向运动)。两个旋转轴的交点应位于平台中心。
- 轴承支撑:在轴的两端使用轴承固定,减少摩擦,使平台转动平滑。
- 连杆机构:将舵机摆臂的旋转运动,通过连杆转化为平台的倾斜运动。需要仔细设计连杆长度和舵机安装位置,以匹配平台所需的倾斜角度范围。
- 整体底座:所有部件(MCU、电源、舵机)应固定在一个稳固的底座上。
3. 核心控制算法:PID原理与双环控制设计
本系统的核心是控制算法,我们采用经典的PID控制,并设计为双环(串级)控制结构。
3.1 PID控制算法基础PID是比例(Proportional)、积分(Integral)、微分(Derivative)控制的缩写。
- 比例P:输出与当前误差成正比。增大P可加快响应,但过大会引起振荡。
- 积分I:输出与误差的累积(积分)成正比。用于消除静态误差(稳态误差),但过大会导致系统响应变慢,超调增大。
- 微分D:输出与误差的变化率(微分)成正比。具有预见性,能抑制振荡,提高稳定性,但对噪声敏感。
离散化的位置式PID公式:u(k) = Kp * e(k) + Ki * ∑e(j) + Kd * [e(k) - e(k-1)]其中,u(k)是第k次输出,e(k)是第k次误差,Kp, Ki, Kd是待调参数。
在实际嵌入式系统中,更常用增量式PID,它只计算输出的变化量,抗积分饱和效果好,且更安全。Δu(k) = Kp*[e(k)-e(k-1)] + Ki*e(k) + Kd*[e(k)-2e(k-1)+e(k-2)]u(k) = u(k-1) + Δu(k)
3.2 双环控制结构设计对于“平衡滚球”系统,单一PID环很难同时处理好平台平衡和小球位置跟踪。因此我们采用外环(位置环)+内环(平衡环)的串级控制。
- 内环(平衡环):
- 被控量:平台倾角
θ_x, θ_y(来自MPU6050)。 - 设定值:由外环计算出的目标角度
θ_x_target, θ_y_target。 - 控制器:PID控制器(两个独立的PID,分别对应X轴和Y轴)。
- 输出:直接控制舵机的PWM占空比。
- 作用:快速响应,抵抗干扰,确保平台能快速、稳定地达到外环给出的目标角度。这个环要求响应频率高(如100Hz以上)。
- 被控量:平台倾角
- 外环(位置环):
- 被控量:小球坐标
x, y(来自触摸屏)。 - 设定值:用户指定的目标坐标
x_target, y_target。 - 控制器:PID控制器(两个独立的PID)。
- 输出:内环的角度设定值
θ_x_target, θ_y_target。 - 作用:根据小球位置偏差,计算出需要平台倾斜多少才能让小球滚向目标。这个环的频率可以稍低(如50Hz),因为它依赖于内环的快速执行。
- 被控量:小球坐标
控制流程简述:
- 外环PID根据
(x_target - x)和(y_target - y)计算出θ_x_target和θ_y_target。注意映射关系:想让小球向X正方向运动,需要平台绕Y轴向负方向倾斜(θ_y_target为负)。 - 内环PID根据
(θ_x_target - θ_x)和(θ_y_target - θ_y)计算出PWM增量。 - 将PWM值输出给对应的舵机。
- 平台倾斜,小球受力开始滚动,坐标
(x, y)改变。 - 循环执行。
4. 嵌入式软件实现与代码详解
我们使用STM32CubeMX进行基础配置,Keil MDK进行开发。工程主要包含以下模块。
4.1 工程配置与驱动初始化使用STM32CubeMX生成代码:
- 配置时钟树,达到最大频率(168MHz)。
- 配置I2C1(MPU6050)、I2C2(OLED)、SPI1(触摸屏)。
- 配置两个定时器(如TIM1)的通道1和通道2为PWM输出模式,频率50Hz(舵机标准)。
- 配置一个基本定时器(如TIM6)用于产生系统控制周期中断(例如5ms)。
- 配置USART用于调试信息打印。
- 生成代码。
4.2 传感器数据读取与处理
- MPU6050数据读取与姿态解算: 我们需要从MPU6050读取原始加速度计和陀螺仪数据,并通过互补滤波或卡尔曼滤波算法融合,得到稳定的平台倾角。这里给出一个简化的互补滤波示例。
// 文件:mpu6050.c #include "mpu6050.h" #include "math.h" float angle_roll, angle_pitch; // 最终解算出的横滚角、俯仰角 float Gyro_x, Gyro_y, Gyro_z; // 陀螺仪角速度 float Accel_x, Accel_y, Accel_z; // 加速度计值 // 互补滤波系数,需要根据实际调试 #define Kp 0.8f #define Ki 0.0f #define dt 0.005f // 5ms采样周期 void MPU6050_Get_Angle(void) { // 1. 读取MPU6050原始数据(通过I2C) MPU6050_Read_Accel(&Accel_x, &Accel_y, &Accel_z); MPU6050_Read_Gyro(&Gyro_x, &Gyro_y, &Gyro_z); // 2. 加速度计计算倾角(有噪声,但长期稳定) float accel_angle_pitch = atan2(Accel_y, Accel_z) * 180 / PI; float accel_angle_roll = atan2(-Accel_x, sqrt(Accel_y*Accel_y + Accel_z*Accel_z)) * 180 / PI; // 3. 互补滤波融合 // 角度 = Kp * (上一时刻角度 + 陀螺仪积分) + (1-Kp) * 加速度计角度 angle_pitch = Kp * (angle_pitch + Gyro_x * dt) + (1 - Kp) * accel_angle_pitch; angle_roll = Kp * (angle_roll + Gyro_y * dt) + (1 - Kp) * accel_angle_roll; // 注意:这里简化了坐标系转换,实际需根据MPU6050安装方向调整 }- 触摸屏坐标读取: XPT2046通过SPI接口读取,需要校准。通常采用两点校准法,将AD值转换为实际屏幕坐标(像素或毫米)。
// 文件:touch.c #define TOUCH_X_MIN 200 #define TOUCH_X_MAX 3800 #define TOUCH_Y_MIN 200 #define TOUCH_Y_MAX 3800 #define SCREEN_WIDTH 240 // 假设屏幕物理宽度对应240单位 #define SCREEN_HEIGHT 320 uint16_t TOUCH_GetX(void) { // SPI读取X通道AD值 uint16_t adc_x = XPT2046_Read_AD(0x90); // 命令字,具体查芯片手册 // 线性映射到屏幕坐标 if(adc_x < TOUCH_X_MIN) adc_x = TOUCH_X_MIN; if(adc_x > TOUCH_X_MAX) adc_x = TOUCH_X_MAX; return (uint16_t)((adc_x - TOUCH_X_MIN) * SCREEN_WIDTH / (TOUCH_X_MAX - TOUCH_X_MIN)); } uint16_t TOUCH_GetY(void) { // 类似地读取Y通道 uint16_t adc_y = XPT2046_Read_AD(0xD0); if(adc_y < TOUCH_Y_MIN) adc_y = TOUCH_Y_MIN; if(adc_y > TOUCH_Y_MAX) adc_y = TOUCH_Y_MAX; return (uint16_t)((adc_y - TOUCH_Y_MIN) * SCREEN_HEIGHT / (TOUCH_Y_MAX - TOUCH_Y_MIN)); }4.3 PID控制器实现实现一个通用的增量式PID控制器结构体。
// 文件:pid.c / pid.h typedef struct { float Target; // 目标值 float Current; // 当前值 float Err; // 当前误差 float Err_Last; // 上次误差 float Err_Prev; // 上上次误差 float Kp, Ki, Kd; // PID参数 float Output; // 控制器输出 float Output_Last; // 上次输出 float Integral; // 积分项(位置式PID用) float OutputMax; // 输出限幅 float OutputMin; } PID_TypeDef; void PID_Init(PID_TypeDef *pid, float kp, float ki, float kd, float max, float min) { pid->Kp = kp; pid->Ki = ki; pid->Kd = kd; pid->OutputMax = max; pid->OutputMin = min; pid->Target = 0; pid->Current = 0; pid->Err = 0; pid->Err_Last = 0; pid->Err_Prev = 0; pid->Output = 0; pid->Output_Last = 0; pid->Integral = 0; } // 增量式PID计算 float PID_Incremental_Calc(PID_TypeDef *pid, float current) { pid->Current = current; pid->Err = pid->Target - pid->Current; float delta_output = pid->Kp * (pid->Err - pid->Err_Last) + pid->Ki * pid->Err + pid->Kd * (pid->Err - 2*pid->Err_Last + pid->Err_Prev); pid->Output = pid->Output_Last + delta_output; // 输出限幅 if(pid->Output > pid->OutputMax) pid->Output = pid->OutputMax; if(pid->Output < pid->OutputMin) pid->Output = pid->OutputMin; // 更新历史误差 pid->Err_Prev = pid->Err_Last; pid->Err_Last = pid->Err; pid->Output_Last = pid->Output; return pid->Output; }4.4 主控制逻辑与定时中断服务函数在5ms定时器中断中执行核心控制循环。
// 文件:main.c 或 独立的控制任务文件 #include "pid.h" #include "mpu6050.h" #include "touch.h" #include "servo.h" // 定义四个PID控制器:外环X,Y,内环Roll, Pitch PID_TypeDef PID_Position_X, PID_Position_Y; PID_TypeDef PID_Angle_Roll, PID_Angle_Pitch; // 目标坐标和角度 float target_x = 120.0f, target_y = 160.0f; // 屏幕中心 float target_roll = 0.0f, target_pitch = 0.0f; // 当前坐标和角度 float current_x = 0.0f, current_y = 0.0f; float current_roll = 0.0f, current_pitch = 0.0f; // 舵机PWM占空比对应角度范围,需根据实际校准 #define SERVO_MID 1500 // 1.5ms, 中间位置 #define SERVO_SCALE 10.0f // 每度对应的PWM增量,需实测 void Control_Loop(void) { // 此函数在5ms定时中断中调用 // 1. 读取传感器数据 MPU6050_Get_Angle(); // 更新 current_roll, current_pitch current_x = TOUCH_GetX(); current_y = TOUCH_GetY(); // 2. 外环(位置环)计算:根据小球位置偏差,计算目标平台角度 PID_Position_X.Target = target_x; PID_Position_Y.Target = target_y; // 注意:坐标到角度的映射关系。例如,想让小球向右(X+)运动,需要平台向左倾斜(Roll-) target_roll = -PID_Incremental_Calc(&PID_Position_X, current_x); // 符号根据实际安装调整 target_pitch = PID_Incremental_Calc(&PID_Position_Y, current_y); // 3. 内环(平衡环)计算:根据角度偏差,计算舵机PWM PID_Angle_Roll.Target = target_roll; PID_Angle_Pitch.Target = target_pitch; float pwm_roll = SERVO_MID + PID_Incremental_Calc(&PID_Angle_Roll, current_roll) * SERVO_SCALE; float pwm_pitch = SERVO_MID + PID_Incremental_Calc(&PID_Angle_Pitch, current_pitch) * SERVO_SCALE; // 4. 输出PWM到舵机 SERVO_SetPulse(TIM1, TIM_CHANNEL_1, (uint16_t)pwm_roll); // X轴舵机 SERVO_SetPulse(TIM1, TIM_CHANNEL_2, (uint16_t)pwm_pitch); // Y轴舵机 // 5. (可选)在OLED上显示状态 OLED_Show_Status(current_x, current_y, current_roll, current_pitch); }4.5 OLED显示与按键处理在主循环中处理按键,更新目标坐标或PID参数,并刷新OLED显示。
// 文件:main.c int main(void) { // HAL初始化、外设初始化... PID_Init(&PID_Position_X, 0.5, 0.01, 0.2, 20.0, -20.0); // 外环参数,需调试 PID_Init(&PID_Position_Y, 0.5, 0.01, 0.2, 20.0, -20.0); PID_Init(&PID_Angle_Roll, 3.0, 0.1, 0.5, 500.0, -500.0); // 内环参数,需调试 PID_Init(&PID_Angle_Pitch, 3.0, 0.1, 0.5, 500.0, -500.0); OLED_Init(); OLED_Clear(); OLED_Show_String(0, 0, "Ball Balance System", 16); while (1) { // 按键扫描,例如切换模式、微调目标坐标 if(KEY_Scan() == KEY1_PRESSED) { target_x += 10; // 向右移动目标 } if(KEY_Scan() == KEY2_PRESSED) { target_y += 10; // 向下移动目标 } // 延时,避免按键扫描过快 HAL_Delay(100); } }5. 系统调试、参数整定与常见问题
5.1 PID参数整定步骤(“先内后外”)
- 内环(角度环)调试:
- 将外环断开,直接给内环一个固定的目标角度(如0度)。
- 先调P:将Ki和Kd设为0。逐渐增大Kp,直到平台开始以较小的幅度持续振荡。
- 再调D:加入Kd,逐渐增大,用于抑制振荡,使平台能快速稳定在目标角度。D太大可能引入高频抖动。
- 最后调I:如果平台稳定后仍有静态误差(无法精确归零),则加入一个很小的Ki。注意积分饱和问题。
- 目标是平台能快速、无超调(或很小超调)地响应角度阶跃变化。
- 外环(位置环)调试:
- 接上外环,给定一个目标坐标。
- 同样按照P -> D -> I的顺序调试。外环的响应速度应慢于内环,否则会相互干扰导致系统失稳。
- 观察小球从边缘回到中心的过程,应平滑、快速,且无大幅振荡或过冲。
5.2 常见问题与排查思路
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 平台剧烈振荡甚至翻转 | 1. PID参数,尤其是P和D值过大。 2. 传感器数据噪声大或延时大。 3. 机械结构松动,存在间隙。 | 1. 大幅减小P和D参数,从很小值开始慢慢增加。 2. 检查MPU6050数据是否稳定,尝试增加滤波强度(如卡尔曼滤波)。 3. 紧固所有机械连接,确保传动无空程。 |
| 小球无法稳定在目标点,始终在周围徘徊 | 1. 外环P值太小,响应慢。 2. 存在静态摩擦(静摩擦力)导致“死区”。 3. 平台水平零点未校准。 | 1. 适当增大外环P值。 2. 在PID输出中加入一个很小的死区补偿(但需谨慎)。 3. 系统上电静止时,记录此时MPU6050的角度作为软件零点。 |
| 小球向一个方向持续加速滚出平台 | 1. 外环I值过大导致积分饱和。 2. 坐标与角度的映射关系符号错误。 3. 舵机运动方向与预期相反。 | 1. 限制积分项上限(抗积分饱和),或减小Ki。 2. 检查代码中 target_roll = -PID_Calc(...)的符号,根据实际安装调整。3. 调换舵机信号线或修改PWM输出极性。 |
| 触摸屏坐标跳动或不准 | 1. 触摸屏未校准或校准参数错误。 2. SPI通信受到干扰。 3. 小球压力不足或接触不良。 | 1. 重新进行两点校准,获取准确的X_MIN, X_MAX, Y_MIN, Y_MAX。2. 检查SPI线缆,远离电机等干扰源,在读取函数中加入软件滤波(如多次采样取平均)。 3. 确保小球有一定重量,能可靠触发触摸屏。 |
| 系统响应迟钝 | 1. 控制周期太长。 2. PID参数过小。 3. 舵机扭矩不足或机械阻力大。 | 1. 缩短定时器中断周期(如从10ms改为5ms)。 2. 适当增大P值。 3. 更换更大扭矩舵机,给转动关节加润滑油。 |
5.3 调试工具与技巧
- 串口绘图:将关键变量(如
current_x,target_roll,pwm_output)通过串口发送到电脑,使用Serial Plotter(Arduino IDE)或vofa+等工具绘制实时曲线,直观观察系统响应和超调。 - OLED显示:实时显示PID参数、误差、坐标等信息,方便现场调试。
- 参数在线调整:通过旋转编码器或按键,实现不重新烧录程序就能微调PID参数,极大提高调试效率。
6. 进阶优化与扩展方向
完成基本功能后,可以考虑以下优化以提升性能或增加功能,这在比赛中是重要的加分项。
6.1 算法优化
- 变参数PID:根据误差大小切换不同的PID参数集。大误差时用大P快速接近,小误差时用小P和D精细调节。
- 模糊PID:使用模糊规则动态调整PID参数,适应更复杂的非线性系统。
- 状态观测器:如果小球速度信息难以直接测量(如仅用触摸屏),可以设计状态观测器(如龙伯格观测器)来估计小球速度,用于微分项,提高控制品质。
- 轨迹规划:对于“8”字形等复杂轨迹,不是简单给定目标点,而是需要实时计算轨迹上的下一个目标点
(x_target(t), y_target(t)),使小球平滑跟踪。
6.2 性能提升
- 传感器融合:对MPU6050使用更先进的卡尔曼滤波或Mahony互补滤波,获得更精确、更稳定的姿态角。
- 前馈控制:当目标坐标变化时,除了反馈控制,还可以加入基于模型的前馈控制,提前给出舵机动作,减少跟踪延迟。
- 机械优化:使用更轻、更坚固的平台;采用低回差、高精度的舵机或步进电机;优化连杆机构,减少摩擦和空程。
6.3 功能扩展
- 多种控制模式:通过按键切换“平衡模式”、“定点模式”、“循迹模式”、“遥控模式”。
- 自动校准:上电时系统自动进行平台水平校准和触摸屏校准。
- 无线通信:加入蓝牙或Wi-Fi模块,实现手机APP遥控或上位机监控。
- 视觉识别:使用OpenMV或树莓派+摄像头,实现颜色识别、形状识别,让系统能够追踪特定颜色的小球或完成更复杂的任务。
6.4 工程化建议
- 模块化编程:将PID、MPU6050、触摸屏、OLED等驱动和控制逻辑封装成独立的
.c/.h文件,提高代码可读性和可移植性。 - 使用RTOS:如果功能复杂(如同时处理控制、显示、通信),可以考虑引入FreeRTOS等实时操作系统,将不同任务分配到不同优先级中。
- 参数存储:将调试好的PID参数保存到STM32的Flash中,避免每次上电重新设置。
- 安全保护:在代码中加入软件限幅,防止计算出的PWM值超出舵机安全范围;加入倾角过大保护,当平台倾斜接近机械极限时,强制回中。
从系统分析、硬件搭建、软件编程到调试优化,完成一个“车载平衡滚球运动控制系统”是对嵌入式开发能力的一次全面锻炼。关键在于理解双环PID的控制逻辑,耐心地进行参数整定,并细致地处理机械和传感器带来的实际问题。希望这篇教程能为你提供一个清晰的开发框架和实用的代码参考,祝你在全国大学生电子设计大赛中取得优异成绩。在实际动手过程中,多思考、多调试、多记录,每一次遇到的问题和解决的方案,都是最宝贵的经验。