在实际嵌入式系统开发中,控制一个在二维平面内自由滚动的球体,使其能够快速、准确地追踪预设轨迹或到达指定位置,是一个经典的、综合性极强的工程实践问题。它不仅考验开发者对PID控制算法、传感器融合、电机驱动等核心技术的理解,更要求具备将理论模型转化为稳定可靠物理系统的能力。2017年全国大学生电子设计大赛的B题“滚球控制系统”正是这样一个项目,它要求参赛者设计并制作一套能够控制平板倾斜角度,从而引导滚球完成指定任务的装置。
本文将以一个资深嵌入式开发者的视角,从头构建一套“滚球控制系统”。我们将从系统的工作原理和数学模型入手,逐步完成硬件选型、电路搭建、软件框架设计、核心控制算法实现,最终让系统能够稳定运行。文章的重点不在于复现某个特定比赛方案,而在于揭示这类系统通用的设计思路、开发流程和调试方法。无论你是正在备赛的学生,还是希望深入理解运动控制与嵌入式系统结合的工程师,都能通过本文获得一套可复现、可排查、可优化的完整技术方案。
1. 系统原理与数学模型:理解“球”与“板”的动力学关系
在开始动手焊接电路或编写代码之前,必须透彻理解被控对象的物理本质。滚球控制系统的核心是一个“球-板”系统(Ball and Plate System),它是“球-杆”系统(Ball and Beam)的二维扩展。
1.1 核心工作原理
系统的基本构成是一块可以绕X轴和Y轴旋转的平板,以及一个在平板上自由滚动的球(通常是钢球)。通过两个正交安装的舵机或步进电机,控制平板的俯仰(Pitch)和横滚(Roll)角度。当平板倾斜时,重力在平板平面上的分力会驱动球向低处滚动。我们的目标就是通过实时调整这两个角度,抵消球的惯性运动,使其停留在目标位置或沿着目标轨迹运动。
关键点:控制输入是平板的两个倾角,被控输出是球在平板平面上的二维坐标(x, y)。这是一个典型的、具有强耦合性的多输入多输出(MIMO)系统。
1.2 建立简化数学模型
为了设计控制器,我们需要一个描述球位置(x, y)与平板倾角(θ_x, θ_y)之间关系的模型。这里给出一个常用的线性化简化模型,它基于以下假设:
- 球在平板上纯滚动,无滑动。
- 平板倾角
θ较小(sinθ ≈ θ, cosθ ≈ 1)。 - 忽略空气阻力和轴承摩擦等次要因素。
根据牛顿第二定律和刚体转动定律,可以推导出球在X方向运动的传递函数(Y方向同理,相互独立):
X(s) / Θ_x(s) = g / (s^2)其中:
X(s)是球在X方向位置的拉普拉斯变换。Θ_x(s)是平板绕Y轴旋转角度(即影响X方向运动)的拉普拉斯变换。g是重力加速度(约9.8 m/s²)。s是拉普拉斯算子。
这个模型的工程意义:它告诉我们,球的位置对平板倾角的二阶导数是常数。从控制角度看,“球-板”系统本质上是两个双重积分器。这意味着:
- 开环系统是不稳定的。
- 需要引入反馈(测量球的位置)来稳定系统。
- 至少需要PD(比例-微分)控制器才能稳定系统;为了消除稳态误差,通常需要PID控制器。
1.3 系统框图与设计挑战
基于以上分析,我们可以画出系统的核心控制框图:
目标位置 (X_ref, Y_ref) +—[PID控制器]—> [电机驱动] —> [平板倾角(θ_x, θ_y)] ^ | | v 实际位置 (X, Y) <——[位置传感器]—— [球] <——[重力/动力学]——设计挑战:
- 传感器精度与延迟:如何快速、精确地测量球的实时位置
(x, y)? - 执行器性能:电机/舵机的响应速度、扭矩和精度是否足以实现快速调整?
- 耦合与非线性:X和Y方向的运动并非完全独立,大角度下模型非线性显著。
- 抗干扰:如何应对球本身的滚动惯性、平板振动、外界扰动?
2. 硬件系统设计与选型:搭建可靠的物理基础
硬件是算法的载体,一个设计不当的硬件平台会让再优秀的算法也无用武之地。我们将系统硬件分解为以下几个模块进行选型和设计。
2.1 核心控制器选型
控制器负责运行控制算法、处理传感器数据、产生电机控制信号。常见选择有:
- STM32系列(如F103、F407、H743):资源丰富,生态完善,是电赛主流选择。F4及以上系列带FPU,适合浮点运算密集的控制算法。
- ESP32系列:集成Wi-Fi/蓝牙,适合需要无线调试或上下位机通信的场景,但其实时性稍弱于纯MCU。
- 树莓派 Pico:双核ARM Cortex-M0+,性价比高,但外设和生态相对较新。
推荐方案:对于学习和大多数比赛场景,STM32F407ZGT6是平衡性能与易用性的首选。它拥有168MHz主频、带FPU、足够的定时器和通信接口。
2.2 位置检测模块选型与电路
这是系统的“眼睛”,至关重要。主流方案有:
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 摄像头+OpenMV/OpenCV | 摄像头拍摄平板图像,图像处理识别球心坐标。 | 非接触,精度高,可获取全局信息。 | 处理延迟大,受光照影响,算法复杂,占用CPU资源高。 | 对实时性要求不高、需要复杂轨迹识别的场景。 |
| 电阻触摸屏 | 使用四线/五线电阻屏,球压在上面形成触点。 | 电路简单,价格低廉,直接输出坐标。 | 有摩擦,影响球滚动;长期使用易磨损;精度一般。 | 低成本、低速度、演示性项目。 |
| 激光对管阵列 | 平板边缘布置多对红外发射/接收管,通过遮挡检测球位置。 | 响应极快,实时性好。 | 分辨率低(取决于对管数量),只能检测边界,无法连续定位。 | 要求极高实时性的简单定位(如平衡)。 |
| 线性CCD/摄像头一维扫描 | 使用两个正交放置的线性CCD,分别扫描X和Y方向。 | 精度和速度介于摄像头和触摸屏之间。 | 需要自己设计光学路径和扫描电路,难度较大。 | 电赛中追求高性能的经典方案。 |
推荐入门方案:电阻触摸屏。我们先使用它快速搭建系统,验证控制算法。后续可以升级为摄像头方案。
- 型号:4线电阻式触摸屏(如XPT2046控制器)。
- 连接:通常通过SPI接口与MCU通信。
- 电路注意:触摸屏需要稳定的模拟参考电压,布线时注意避免数字噪声干扰。
2.3 执行机构选型与驱动
这是系统的“手脚”,负责改变平板姿态。
| 方案 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 舵机 | 内置控制电路,给定PWM信号即可转到指定角度。 | 使用简单,无需额外驱动电路,扭矩大。 | 响应有延迟,精度有限(通常0.5°~1°),存在死区。 | 快速原型验证,对精度和速度要求不高的场景。 |
| 步进电机+丝杆 | 通过脉冲控制旋转步数,经丝杆转换为直线位移,顶起平板一角。 | 精度高,位置控制准确,保持力矩大。 | 需要复杂的驱动电路(如A4988/TMC2208),可能失步,低速可能振动。 | 高精度、高保持力要求的场景。 |
| 空心杯电机+编码器 | 直流电机配合编码器实现精确位置闭环。 | 响应速度快,控制性能最好。 | 系统最复杂,需要电机驱动、编码器计数、位置闭环PID。 | 高性能、高动态响应的终极方案。 |
推荐入门方案:数字舵机。如MG996R(扭矩约15kg·cm)。使用两个舵机,通过十字轴或万向节连接,分别控制平板X和Y方向的倾斜。
驱动电路:舵机直接由MCU的定时器产生PWM信号驱动。需注意:
- 舵机工作电流较大(峰值可达1-2A),必须单独供电,不能从MCU的3.3V或5V引脚取电。
- MCU的PWM信号线(控制线)与舵机电源地线需共地。
- 在电源入口处并联一个大电容(如470uF~1000uF)以缓冲电机启停造成的电压波动。
2.4 系统供电设计
混乱的供电是系统不稳定的主要元凶。必须分开供电:
- MCU及传感器供电:使用稳定的5V或3.3V LDO线性稳压芯片(如AMS1117-3.3),从总电源降压得到。为模拟部分(触摸屏)提供干净的电源。
- 舵机供电:直接使用大容量锂电池或稳压电源(如6V~7.4V),通过大电流开关(如MOS管)控制通断。务必与MCU电源共地。
- 总开关与保险:电源入口处设置总开关和可恢复保险丝。
2.5 机械结构设计要点
- 平板:需要轻质且平整。亚克力板是常用材料。
- 支撑与转动中心:平板中心需要有一个“万向节”结构(如十字轴),使其能绕中心点灵活倾斜,避免平移。
- 舵机安装:舵机臂通过连杆与平板边缘连接。连杆长度和安装点决定了倾角范围和控制分辨率。需要进行运动学正反解计算。
- 减震与润滑:在转动关节处使用轴承,并适当润滑,减少摩擦和回差。
3. 软件架构与核心模块实现
硬件连接好后,软件是让系统“活”起来的关键。我们采用模块化设计,便于调试和维护。
3.1 开发环境与工程初始化
- IDE:使用 STM32CubeIDE 或 Keil MDK。
- 初始化:利用STM32CubeMX生成初始化代码,配置以下关键外设:
- 时钟树:配置到最高频率(如168MHz)。
- GPIO:用于LED、按键等。
- 定时器:
- TIMx 用于产生两路PWM信号驱动舵机(周期20ms,脉宽0.5ms~2.5ms)。
- 另一个TIMx 用于配置系统定时中断,作为控制周期(如10ms)。
- ADC:如果使用模拟量输出的传感器。
- SPI:用于连接触摸屏控制器XPT2046。
- UART:用于调试信息输出(连接USB转TTL模块到电脑)。
3.2 模块一:触摸屏数据采集与滤波
触摸屏读取的原始数据通常带有噪声,必须经过滤波。
// touch.h typedef struct { float x; // 归一化后的X坐标 (0.0 ~ 1.0) float y; // 归一化后的Y坐标 (0.0 ~ 1.0) uint8_t pressed; // 是否被按下(有球) } BallPosition_t; void TOUCH_Init(void); BallPosition_t TOUCH_GetFilteredPosition(void);// touch.c #include "touch.h" #include "xpt2046.h" // 假设有底层驱动 #include <math.h> #define SAMPLE_NUM 5 #define FILTER_ALPHA 0.3f // 一阶低通滤波系数 static BallPosition_t last_position = {0.5f, 0.5f, 0}; BallPosition_t TOUCH_GetFilteredPosition(void) { uint32_t raw_x_sum = 0, raw_y_sum = 0; uint8_t valid_count = 0; BallPosition_t current; // 1. 多次采样取平均,消除突发噪声 for(int i=0; i<SAMPLE_NUM; i++) { if(XPT2046_Read(&raw_x, &raw_y)) { // 底层读取函数 raw_x_sum += raw_x; raw_y_sum += raw_y; valid_count++; } HAL_Delay(1); } if(valid_count == 0) { current.pressed = 0; return last_position; // 返回上一次有效值 } uint16_t avg_raw_x = raw_x_sum / valid_count; uint16_t avg_raw_y = raw_y_sum / valid_count; // 2. 将原始AD值转换为归一化坐标 (需根据实际校准) // 假设校准后,X方向 AD值范围是 [x_min, x_max] -> [0.0, 1.0] const uint16_t x_min = 200, x_max = 3800; const uint16_t y_min = 300, y_max = 3900; current.x = (float)(avg_raw_x - x_min) / (x_max - x_min); current.y = (float)(avg_raw_y - y_min) / (y_max - y_min); current.x = fmaxf(0.0f, fminf(1.0f, current.x)); // 限幅 current.y = fmaxf(0.0f, fminf(1.0f, current.y)); // 3. 一阶低通滤波,平滑数据 current.x = FILTER_ALPHA * current.x + (1 - FILTER_ALPHA) * last_position.x; current.y = FILTER_ALPHA * current.y + (1 - FILTER_ALPHA) * last_position.y; current.pressed = 1; last_position = current; return current; }3.3 模块二:PID控制器实现
PID是系统的“大脑”。我们实现一个位置式PID,并加入抗积分饱和和输出限幅。
// pid.h typedef struct { float kp, ki, kd; // PID参数 float integral; // 积分项 float prev_error; // 上一次误差 float integral_limit; // 积分限幅 float output_limit; // 输出限幅 float output; // 控制器输出 } PID_Controller_t; void PID_Init(PID_Controller_t *pid, float kp, float ki, float kd, float i_limit, float out_limit); float PID_Update(PID_Controller_t *pid, float setpoint, float measurement, float dt);// pid.c #include "pid.h" void PID_Init(PID_Controller_t *pid, float kp, float ki, float kd, float i_limit, float out_limit) { pid->kp = kp; pid->ki = ki; pid->kd = kd; pid->integral = 0.0f; pid->prev_error = 0.0f; pid->integral_limit = i_limit; pid->output_limit = out_limit; pid->output = 0.0f; } float PID_Update(PID_Controller_t *pid, float setpoint, float measurement, float dt) { float error = setpoint - measurement; // 比例项 float p_out = pid->kp * error; // 积分项(带限幅和抗饱和) pid->integral += error * dt; // 积分限幅 if(pid->integral > pid->integral_limit) pid->integral = pid->integral_limit; else if(pid->integral < -pid->integral_limit) pid->integral = -pid->integral_limit; float i_out = pid->ki * pid->integral; // 微分项(使用测量值微分,对设定值变化不敏感) float derivative = (measurement - pid->prev_measurement) / dt; // 假设传入上一次测量值 float d_out = pid->kd * derivative; pid->prev_measurement = measurement; // 计算总输出 pid->output = p_out + i_out - d_out; // 注意:微分项通常取负,抑制变化 // 输出限幅 if(pid->output > pid->output_limit) pid->output = pid->output_limit; else if(pid->output < -pid->output_limit) pid->output = -pid->output_limit; return pid->output; }关键解释:
dt是控制周期,必须准确。我们在定时器中断中调用PID,dt就是中断周期。- 微分项作用于
measurement而非error,可以避免设定值突变引起的微分冲击。 - 积分限幅是防止“积分饱和”的关键,当输出长期处于限幅状态时,积分器会停止累积,避免系统恢复时产生超调。
3.4 模块三:舵机控制与平板运动学
将PID输出的控制量(角度或位置修正量)转换为舵机的PWM脉宽。
// servo.h void SERVO_SetPulseWidth(uint8_t servo_id, float pulse_ms); // pulse_ms: 0.5 ~ 2.5 // plate_kinematics.h typedef struct { float angle_x; // 平板目标X倾角(弧度) float angle_y; // 平板目标Y倾角(弧度) } PlateAngle_t; PlateAngle_t CalculatePlateAngle(float control_x, float control_y);// plate_kinematics.c #include "plate_kinematics.h" #include "servo.h" #include "math.h" // 假设机械结构:舵机中立位时平板水平,舵机臂长L1,连杆长L2,连接点距平板中心距离D // 这是一个简化的几何模型,实际需要根据你的机械结构推导 PlateAngle_t CalculatePlateAngle(float control_x, float control_y) { PlateAngle_t angle; const float scale_factor = 0.05f; // 控制量到角度的缩放系数,需实际调试 const float max_angle = 0.17f; // 最大倾角约10度,防止球滚落 // 计算目标倾角 angle.angle_x = control_y * scale_factor; // 注意:控制X方向位置,需要倾斜Y轴 angle.angle_y = -control_x * scale_factor; // 控制Y方向位置,需要倾斜X轴 // 限幅 angle.angle_x = fmaxf(-max_angle, fminf(max_angle, angle.angle_x)); angle.angle_y = fmaxf(-max_angle, fminf(max_angle, angle.angle_y)); return angle; } // 将倾角转换为舵机PWM(需要根据舵机安装方式校准) void ApplyPlateAngle(PlateAngle_t angle) { // 假设舵机中立位对应1.5ms,角度变化率是0.5ms/rad float pulse_x = 1.5f + angle.angle_y * 0.5f; // angle_y 控制X方向舵机 float pulse_y = 1.5f + angle.angle_x * 0.5f; // angle_x 控制Y方向舵机 SERVO_SetPulseWidth(SERVO_X_ID, pulse_x); SERVO_SetPulseWidth(SERVO_Y_ID, pulse_y); }3.5 模块四:主控制循环与任务调度
在定时器中断(如10ms一次)中执行核心控制逻辑,避免在main函数的while(1)中无节制循环。
// main.c 或 control_task.c #include "touch.h" #include "pid.h" #include "plate_kinematics.h" PID_Controller_t pid_x, pid_y; float target_x = 0.5f, target_y = 0.5f; // 目标位置:平板中心 void ControlLoop_Init(void) { // 初始化PID参数,需要大量调试! // Kp: 基本响应速度, Ki: 消除静差, Kd: 抑制振荡 PID_Init(&pid_x, 1.2f, 0.05f, 0.8f, 10.0f, 1.0f); // 输出限幅±1.0 PID_Init(&pid_y, 1.2f, 0.05f, 0.8f, 10.0f, 1.0f); } // 此函数在10ms定时器中断中调用 void ControlLoop_Update(void) { BallPosition_t ball = TOUCH_GetFilteredPosition(); if(!ball.pressed) { // 球未检测到,可能已滚落,停止电机或回到安全位置 ApplyPlateAngle((PlateAngle_t){0, 0}); // 回水平位置 return; } // 1. PID计算控制量 float control_x = PID_Update(&pid_x, target_x, ball.x, 0.01f); // dt=0.01s (10ms) float control_y = PID_Update(&pid_y, target_y, ball.y, 0.01f); // 2. 通过运动学计算平板所需倾角 PlateAngle_t angle = CalculatePlateAngle(control_x, control_y); // 3. 驱动舵机 ApplyPlateAngle(angle); // 4. (可选)通过串口发送数据到上位机调试 // printf("[%.3f,%.3f] -> [%.3f,%.3f]\r\n", ball.x, ball.y, angle.angle_x, angle.angle_y); }4. 系统调试、参数整定与性能优化
代码写完只是开始,调试才是真正的挑战。遵循“先静后动,先单后双,先P后I再D”的原则。
4.1 调试准备与安全检查
- 硬件检查:确保所有连接牢固,电源电压正确,电机固定稳妥,平板运动顺畅无卡滞。
- 开环测试:将PID输出置零,手动给平板倾角,观察球是否随重力自然滚动,验证传感器读数变化方向是否正确。
- 通信调试:确保串口调试助手能正常接收数据,用于绘制曲线。
4.2 PID参数整定流程
这是最核心的调试环节。使用试凑法或临界比例度法。
步骤1:整定X轴(固定Y轴)
- 将Y轴PID输出设为0,或物理固定Y轴舵机。
- 设置目标位置在X轴中心(0.5)。
- 先调Kp:将Ki, Kd设为0。逐渐增大Kp,直到球在目标位置附近开始持续等幅振荡。记录此时的Kp为
Ku,振荡周期为Tu。 - 应用齐格勒-尼科尔斯经验公式:
- P控制器:
Kp = 0.5 * Ku - PI控制器:
Kp = 0.45 * Ku,Ki = 0.54 * Ku / Tu(需转换为每秒积分) - PID控制器:
Kp = 0.6 * Ku,Ki = 1.2 * Ku / Tu,Kd = 0.075 * Ku * Tu
- P控制器:
- 将计算值作为起点,微调。先加Kp提高响应速度,再加Kd抑制超调和振荡,最后加Ki消除静差。Ki要非常小心,加多了极易导致系统不稳定。
步骤2:整定Y轴(固定X轴)
- 用同样的方法整定Y轴参数。由于机械对称,参数可能接近,但未必完全相同。
步骤3:双轴联调
- 同时启用两个轴的PID。此时可能会出现耦合振荡。
- 适当降低两个轴的Kp和Ki,增加Kd。
- 可以尝试非对称参数,因为X/Y轴机械性能可能有细微差别。
4.3 利用串口绘图调试
在ControlLoop_Update函数中打印球的位置和目标位置,使用串口绘图工具(如SerialPlot、Vofa+)观察曲线。
// 打印格式:目标X,实际X,目标Y,实际Y printf("%.3f,%.3f,%.3f,%.3f\r\n", target_x, ball.x, target_y, ball.y);观察曲线,判断问题:
- 响应慢:增大Kp。
- 静差大:适度增大Ki。
- 超调大、振荡:增大Kd,或减小Kp。
- 低频振荡:可能是积分饱和,检查积分限幅是否合理,或减小Ki。
- 高频抖动:可能是传感器噪声或机械振动,检查滤波参数,或减小Kp/Kd。
4.4 常见问题与排查清单
| 问题现象 | 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|---|
| 球完全不受控,乱飞 | 1. X/Y方向控制耦合错误。 2. 传感器坐标轴与舵机控制轴映射反了。 3. PID输出正负号错误。 | 1. 单轴测试,看球运动方向与平板倾斜方向是否对应重力方向。 2. 打印传感器原始值,确认坐标原点。 | 检查CalculatePlateAngle函数中的control_x与angle.angle_y的对应关系。确保“球往+X跑,平板应绕Y轴向-X方向倾斜”。 |
| 球在目标点附近剧烈振荡 | 1. PID参数过于激进(Kp/Ki太大)。 2. 微分项D引入噪声。 3. 控制周期太快,执行器跟不上。 | 1. 观察振荡频率。高频可能是Kp/D太大或噪声;低频可能是积分饱和。 2. 将D设为0,看是否改善。 | 1. 大幅降低Kp,暂时去掉I和D。 2. 对测量值进行更重的低通滤波。 3. 适当加长控制周期(如20ms)。 |
| 球有静差,无法到达中心点 | 1. 积分项Ki太小或为0。 2. 机械回差或摩擦力太大。 3. 平板未调水平。 | 1. 观察误差是否恒定。 2. 手动将球放到目标点,观察平板是否水平。 | 1. 缓慢增加Ki。 2. 在机械上消除间隙,润滑关节。 3. 系统上电时执行“调平”归零操作。 |
| 响应非常迟钝,球慢慢飘向目标 | 比例项Kp太小。 | 增大Kp,直到开始出现微小振荡,然后回调一点。 | 按4.2节流程重新整定Kp。 |
| 移动目标点时,球会“冲过头”再回来 | 微分项设置不当(对误差微分),导致设定值变化瞬间微分项巨大。 | 改用“对测量值微分”的形式(如我们代码所示)。 | 修改PID微分项的计算源。 |
| 舵机发出异响,不转动 | 1. 电源功率不足,电压被拉低。 2. PWM信号频率不对(不是50Hz)。 3. 机械负载卡死。 | 1. 用万用表测量舵机供电电压在动作时是否跌落到额定电压以下。 2. 用示波器查看PWM波形。 | 1. 更换更大功率电源,电源线加粗。 2. 确认定时器配置为50Hz(20ms周期)。 |
4.5 进阶优化策略
当基本PID能稳定后,可以考虑以下优化:
- 变参数PID:根据误差大小切换参数。大误差时用大Kp快速接近,小误差时用小Kp和加入D项精细稳定。
- 前馈控制:如果让球跟踪一个已知轨迹,可以根据轨迹的导数(速度)提前给出平板倾角。
- 状态空间控制:建立更精确的“球-板”状态空间模型,使用LQR(线性二次型调节器)等现代控制方法,性能优于PID,但数学复杂。
- 模糊PID:用模糊规则动态调整PID参数,适应非线性系统。
- 摄像头反馈替代:升级为摄像头,实现更复杂的轨迹跟踪(如圆形、八字形)。
5. 从原型到可靠系统:工程化与扩展思考
让一个系统在实验室跑起来是一回事,让它稳定可靠是另一回事。
5.1 增加系统鲁棒性
- 启动自检与校准:系统上电后,自动驱动舵机回到机械零点,并读取此时触摸屏的AD值作为基准。
- 异常状态处理:
- 球丢失检测:连续多次读取不到触摸信号,则缓慢回平并报警。
- 输出限幅保护:防止计算出的倾角超过机械极限。
- 软件看门狗:防止程序跑飞。
- 手动-自动切换:增加按键或遥控,可以在手动控制(调试模式)和自动控制间切换。
5.2 实现比赛典型任务
参考2017年赛题要求,可以扩展以下功能:
- 基本定位:已实现。
- 轨迹跟踪:将目标点
(target_x, target_y)按照时间序列变化。例如画圆:target_x = 0.5 + 0.3*sin(2πt/T),target_y = 0.5 + 0.3*cos(2πt/T)。 - 路径规划与避障:在软件中设置虚拟障碍区,当球靠近时,修改目标点绕行。
- 上下坡:通过控制平板做周期性起伏运动模拟坡道,考验系统的动态调节能力。
5.3 扩展硬件与算法
- 无线通信:增加蓝牙或Wi-Fi模块,用手机APP或电脑上位机设置目标点、轨迹和PID参数,实时显示球位置和系统状态。
- 多球控制:使用更高分辨率的摄像头,同时识别并控制多个球(挑战极大)。
- 机器学习调参:记录调试数据,使用简单的强化学习算法自动寻找更优的PID参数。
构建滚球控制系统的过程,是一次完整的嵌入式控制系统开发实践。它清晰地串联了建模、选型、电路、编程、调试、优化各个环节。最大的收获往往不是最终让球稳定在了一点,而是在无数次振荡、发散、跑飞中,逐步理解每个参数、每行代码、每个硬件细节是如何影响整个物理系统的动态行为的。当你亲手调出一个响应迅速、稳定可靠的系统时,你对反馈、延迟、非线性、耦合这些控制理论概念的理解,将远比书本上深刻得多。下一步,可以尝试更换为摄像头传感器,挑战更复杂的轨迹跟踪;或者尝试用状态空间控制替代PID,比较两者的性能差异。这个平台就像一个微型的实验床,足以验证许多有趣的控制思想。