1. 为什么需要闭环控制在机器人或智能小车开发中电机控制是最基础也最关键的环节。很多初学者刚开始接触电机时会觉得只要接上电源能让电机转起来就万事大吉了。但实际应用中特别是需要精确控制移动距离或速度的场景简单的开环控制往往会出现各种问题。我刚开始做智能小车时就遇到过这种情况同样的PWM值在不同负载下电机转速差异很大电池电压下降时小车速度明显变慢更不用说精确控制移动距离了完全靠猜。这些问题都源于开环控制的固有缺陷——它无法感知电机的实际运行状态也就无法做出相应调整。闭环控制的核心思想就是引入反馈机制。通过编码器实时监测电机的实际转速和位置与目标值进行比较动态调整PWM输出。这就好比开车时不仅要踩油门还要时刻关注车速表根据实际车速调整油门开度。这种控制方式能显著提高系统的抗干扰能力和控制精度。2. TB6612电机驱动详解2.1 TB6612的优势与特性TB6612FNG是目前机器人开发中最常用的电机驱动芯片之一。相比老牌的L298N它有几个明显的优势首先是效率更高实测在相同负载下发热量只有L298N的1/3左右其次是体积小巧整个驱动模块可以做到比火柴盒还小最重要的是支持高达100kHz的PWM频率这让速度控制更加精细。我在多个项目中使用过TB6612最直观的感受就是稳定可靠。即使在长时间连续工作的情况下芯片也只是微微发热完全不用担心过热保护的问题。它的工作电压范围是2.5V-13.5V可以适配大多数小型直流电机。2.2 硬件连接与基础控制TB6612的接线其实很简单主要分为三部分电源部分VM接电机电源2.5-13.5VVCC接逻辑电源3.3V或5V控制信号PWMA/PWMB接PWM信号AIN1/AIN2和BIN1/BIN2接方向控制电机输出AO1/AO2和BO1/BO2分别接两个电机这里有个实用技巧STBY引脚可以直接接到VCC这样就不需要额外控制。但如果要实现紧急停止功能可以通过单片机控制STBY引脚。控制逻辑也很直观AIN11, AIN20电机正转AIN10, AIN21电机反转AIN1AIN2电机刹车停止PWMA的占空比决定电机转速// 示例代码使用Arduino控制TB6612 #define AIN1 2 #define AIN2 3 #define PWMA 9 void setup() { pinMode(AIN1, OUTPUT); pinMode(AIN2, OUTPUT); pinMode(PWMA, OUTPUT); } void loop() { // 电机正转50%速度 digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW); analogWrite(PWMA, 128); delay(2000); // 电机停止 digitalWrite(AIN1, LOW); digitalWrite(AIN2, LOW); delay(1000); }3. 电机编码器的原理与应用3.1 编码器类型与工作原理电机编码器主要分为光电式和霍尔式两种。光电编码器精度高但价格较贵霍尔编码器成本低且更耐用。在实际项目中我通常会根据精度要求来选择需要精确位置控制时用光电编码器普通速度控制用霍尔编码器就足够了。编码器输出的AB相信号包含了电机的全部运动信息。这两个信号是正交的方波相位差90度。通过分析这两个信号的相位关系和脉冲数量我们可以获取电机转向A相超前还是滞后B相电机位置累计脉冲数电机速度单位时间内的脉冲数3.2 编码器信号处理处理编码器信号有几种常见方法简单计数法使用外部中断捕获脉冲边沿四倍频计数在上升沿和下降沿都计数提高分辨率专用编码器接口如STM32的定时器编码器模式这里特别推荐STM32的编码器模式配置简单且性能稳定。以下是一个典型配置// STM32编码器模式配置示例 void Encoder_Init(void) { TIM_Encoder_InitTypeDef encoderConfig {0}; TIM_MasterConfigTypeDef masterConfig {0}; htimer3.Instance TIM3; htimer3.Init.Prescaler 0; htimer3.Init.CounterMode TIM_COUNTERMODE_UP; htimer3.Init.Period 65535; htimer3.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; encoderConfig.EncoderMode TIM_ENCODERMODE_TI12; encoderConfig.IC1Polarity TIM_ICPOLARITY_RISING; encoderConfig.IC1Selection TIM_ICSELECTION_DIRECTTI; encoderConfig.IC1Prescaler TIM_ICPSC_DIV1; encoderConfig.IC1Filter 0xF; encoderConfig.IC2Polarity TIM_ICPOLARITY_RISING; encoderConfig.IC2Selection TIM_ICSELECTION_DIRECTTI; encoderConfig.IC2Prescaler TIM_ICPSC_DIV1; encoderConfig.IC2Filter 0xF; HAL_TIM_Encoder_Init(htimer3, encoderConfig); masterConfig.MasterOutputTrigger TIM_TRGO_RESET; masterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronize(htimer3, masterConfig); HAL_TIM_Encoder_Start(htimer3, TIM_CHANNEL_ALL); }读取编码器值只需要调用__HAL_TIM_GET_COUNTER(htimer3)硬件会自动处理计数方向非常方便。4. 构建完整的闭环控制系统4.1 PID控制基础要实现精准的闭环控制PID算法是必不可少的。PID代表比例Proportional、积分Integral、微分Derivative三种控制作用。简单来说P项解决当前误差误差越大调整力度越大I项解决历史误差消除稳态误差D项预测未来误差抑制超调和振荡在实际调试中我发现几个经验法则先调P直到系统出现轻微振荡然后加D抑制振荡最后加I消除稳态误差三个参数要反复微调找到最佳组合4.2 速度环控制实现下面是一个简单的速度环PID实现示例typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PIDController; float PID_Update(PIDController* pid, float setpoint, float measurement, float dt) { float error setpoint - measurement; // 比例项 float P pid-Kp * error; // 积分项带抗饱和 pid-integral error * dt; float I pid-Ki * pid-integral; // 微分项 float derivative (error - pid-prev_error) / dt; float D pid-Kd * derivative; pid-prev_error error; return P I D; } // 使用示例 PIDController speedPID {0.5, 0.1, 0.01, 0, 0}; float targetSpeed 100.0; // 目标速度100脉冲/秒 float currentSpeed getEncoderSpeed(); // 获取当前速度 float pwmOutput PID_Update(speedPID, targetSpeed, currentSpeed, 0.01); // 10ms控制周期 setMotorPWM(pwmOutput); // 设置电机PWM4.3 位置环控制实现位置环与速度环类似只是控制目标从速度变成了位置。在实际项目中我通常会采用串级控制外环是位置环内环是速度环。这样既能保证最终位置准确又能使运动过程平稳。// 串级PID控制示例 float positionControl(float targetPos, float currentPos, float dt) { static PIDController posPID {1.0, 0.05, 0.2, 0, 0}; static PIDController speedPID {0.8, 0.1, 0.02, 0, 0}; // 位置环计算目标速度 float targetSpeed PID_Update(posPID, targetPos, currentPos, dt); // 获取当前速度 float currentSpeed getEncoderSpeed(); // 速度环计算PWM输出 float pwmOutput PID_Update(speedPID, targetSpeed, currentSpeed, dt); return pwmOutput; }5. 实战经验与常见问题5.1 编码器安装注意事项在实际安装编码器时有几个容易踩坑的地方机械安装要牢固编码盘与电机轴之间不能有松动否则会导致计数不准传感器距离要合适光电编码器的传感器与编码盘距离通常在1-3mm信号线要加滤波长距离传输时容易引入干扰建议加RC滤波电源要稳定编码器供电不稳会导致信号抖动我曾经在一个项目中发现编码器计数偶尔会跳变后来发现是电源问题。在编码器VCC和GND之间加了一个100μF的电容后问题立即解决。5.2 PID参数调试技巧调试PID参数时建议先用手动方式测试电机响应给一个固定PWM值观察速度变化曲线突然改变PWM观察系统的响应速度记录这些数据有助于理解系统特性另一个实用技巧是使用阶跃响应法给电机一个突变的PWM信号记录速度变化曲线。理想的响应应该是快速上升且超调小。根据曲线形状调整PID参数上升太慢增大P超调太大增大D稳态误差增大I5.3 抗干扰措施在实际环境中电机运行时会产生大量电气噪声。以下措施可以有效提高系统稳定性电机电源与逻辑电源分开编码器信号线使用双绞线在信号线上加磁珠或小电容滤波PCB布局时电机驱动部分与信号处理部分保持距离所有信号地单点连接我曾经遇到过一个奇怪的故障电机转速高时编码器计数会乱跳。后来发现是电机电源回流路径设计不当在信号地上产生了压降。重新设计地线布局后问题解决。