
最近在准备全国大学生电子设计大赛发现“车载平衡滚球运动控制系统”这类题目对学生的综合能力要求很高它融合了机械结构、传感器、控制算法和嵌入式开发等多个领域。很多同学在拿到题目后面对从零开始的系统设计、硬件选型、软件编程和算法调试常常感到无从下手网上资料也多是零散的模块介绍缺乏一个从需求分析到最终实现的完整闭环指导。本文旨在为备战此类赛事的同学提供一个系统性的实战教程。我们将围绕“车载平衡滚球运动控制系统”的核心需求拆解其技术要点从系统方案设计、硬件选型与搭建、核心控制算法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 核心元器件清单模块型号示例主要参数用途主控MCUSTM32F407ZGT6168MHz, FPU, 1MB Flash, 192KB RAM系统控制核心姿态传感器MPU60503轴加速度计3轴陀螺仪I2C接口测量平台倾角位置传感器4线电阻触摸屏如 XPT2046 控制器SPI接口检测小球坐标执行器舵机 MG996R扭矩 9.4kg·cm工作电压 4.8-7.2V驱动平台倾斜显示模块OLED SSD13060.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。配置I2C1MPU6050、I2C2OLED、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 PlotterArduino 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的控制逻辑耐心地进行参数整定并细致地处理机械和传感器带来的实际问题。希望这篇教程能为你提供一个清晰的开发框架和实用的代码参考祝你在全国大学生电子设计大赛中取得优异成绩。在实际动手过程中多思考、多调试、多记录每一次遇到的问题和解决的方案都是最宝贵的经验。