3. 底层电机调试:电机驱动原理、PID参数整定、编码器数据读取与校准、电机堵转与过流保护

电机调试,是AMR控制系统里最「接地气」的一环。说白了,你算法写得再漂亮,电机转不起来,车就是一块废铁。我刚开始做机器人那会儿,就吃过这个亏——PID参数调了一整天,结果发现编码器线接反了。嗯,这种低级错误,谁还没犯过几次呢?

核心要点:电机调试的本质,是让控制指令与物理运动之间建立精确的映射关系。你给电机发一个速度指令,它就得老老实实按这个速度转,不能抖、不能偏、不能过热。

3.1 电机驱动原理

先说说驱动原理。AMR常用的直流有刷电机或无刷电机,驱动方式其实不复杂——靠PWM波控制MOS管的开关,调节平均电压来调速。我习惯把驱动电路分成三块:功率级、逻辑级、保护级。

  • 功率级:H桥电路,控制电机正反转。四个MOS管,对角导通。
  • 逻辑级:PWM信号输入,一般用定时器产生,频率我常用10kHz~20kHz。
  • 保护级:电流采样电阻+比较器,一旦过流立刻关断。

这里有个坑——PWM频率不能太低。我见过有人用1kHz,电机嗡嗡响,发热严重。为什么?频率太低,电流纹波大,铁损飙升。建议至少10kHz起步,听不到啸叫为止。

// 简单的PWM初始化(STM32 HAL库)
void Motor_PWM_Init(void)
{
    TIM_HandleTypeDef htim;
    htim.Instance = TIM2;
    htim.Init.Prescaler = 84-1;      // 84MHz / 84 = 1MHz
    htim.Init.Period = 100-1;        // 1MHz / 100 = 10kHz
    htim.Init.CounterMode = TIM_COUNTERMODE_UP;
    HAL_TIM_PWM_Init(&htim);
    
    TIM_OC_InitTypeDef sConfigOC;
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 0;             // 初始占空比0
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_1);
}

我的经验:调试驱动电路时,先别接电机。用示波器看PWM波形,确认频率、占空比、死区时间都对,再上电机。我曾经跳过这一步,结果MOS管直通短路,板子冒烟了……

3.2 PID参数整定

PID整定,是电机调试的重头戏。很多人一上来就调三个参数,结果越调越乱。我个人的习惯是:先调P,再调I,最后调D。别急着上积分,先让系统稳定下来。

参数 作用 调大后的效果 调小后的效果
Kp(比例) 快速响应误差 响应快,可能超调 响应慢,稳态误差大
Ki(积分) 消除稳态误差 消除静差,可能振荡 稳态误差消除慢
Kd(微分) 抑制超调 阻尼增加,响应变慢 超调明显,系统易抖

具体怎么调?我一般用「临界比例法」:

  1. 先把Ki和Kd设为0,只留Kp。
  2. 慢慢增大Kp,直到系统出现等幅振荡。
  3. 记录此时的Kp(记为Ku)和振荡周期Tu。
  4. 按经验公式计算:Kp=0.6Ku,Ki=1.2Ku/Tu,Kd=0.075Ku*Tu。
  5. 微调,直到响应曲线满意。

注意:积分项千万别设太大。我遇到过一台AGV,Ki设高了,电机低速时来回抖,像得了帕金森。后来把Ki砍掉一半,立马稳了。积分饱和也是个常见问题,记得加限幅。

// 位置式PID实现(C语言)
typedef struct {
    float Kp, Ki, Kd;
    float integral;
    float prev_error;
    float limit;  // 输出限幅
} PID_Controller;

float PID_Update(PID_Controller *pid, float target, float current)
{
    float error = target - current;
    pid->integral += error;
    // 积分限幅
    if(pid->integral > pid->limit) pid->integral = pid->limit;
    if(pid->integral < -pid->limit) pid->integral = -pid->limit;
    
    float output = pid->Kp * error 
                 + pid->Ki * pid->integral 
                 + pid->Kd * (error - pid->prev_error);
    pid->prev_error = error;
    
    // 输出限幅
    if(output > pid->limit) output = pid->limit;
    if(output < -pid->limit) output = -pid->limit;
    return output;
}

3.3 编码器数据读取与校准

编码器是电机的「眼睛」。没有准确的编码器数据,PID就是瞎调。我常用的编码器有两种:增量式和绝对式。增量式便宜,但上电不知道位置;绝对式贵,但一开机就知道角度。

读取编码器,核心是处理脉冲信号。我习惯用定时器的编码器模式,硬件自动计数,省CPU资源。

// 定时器编码器模式配置
void Encoder_Init(void)
{
    TIM_Encoder_InitTypeDef sEncoder;
    TIM_MasterConfigTypeDef sMasterConfig;
    
    htim3.Instance = TIM3;
    htim3.Init.Prescaler = 0;
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim3.Init.Period = 65535;
    
    sEncoder.EncoderMode = TIM_ENCODERMODE_TI12;  // 双沿计数
    sEncoder.IC1Polarity = TIM_ICPOLARITY_RISING;
    sEncoder.IC2Polarity = TIM_ICPOLARITY_RISING;
    HAL_TIM_Encoder_Init(&htim3, &sEncoder);
}

校准这一步,很多人会忽略。我建议做两件事:

  • 零点校准:让电机转到机械零点,把编码器计数值清零。
  • 方向校准:正转时计数值增加,反转时减少。如果反了,交换A、B相或者软件取反。

避坑指南:我曾经遇到过编码器读数跳变的问题。查了半天,发现是信号线太长,干扰严重。后来加了RC滤波(100Ω+100nF),问题解决。编码器线一定要用双绞屏蔽线,别省这个钱。

3.4 电机堵转与过流保护

电机堵转,是AMR的常见故障。轮子卡住了、撞到障碍物了,电机还在使劲转,电流飙升,轻则烧MOS管,重则起火。所以过流保护必须做,而且要做两层:硬件保护和软件保护。

硬件保护:用电流采样电阻+比较器,电流超过阈值直接关断PWM。这个响应时间在微秒级,能保命。

软件保护:在控制循环里检测电流,如果连续N个周期电流都超过阈值,就主动停止电机并报错。

// 软件过流检测
#define CURRENT_THRESHOLD  3.0f  // 3A
#define OVERCURRENT_COUNT  10    // 连续10次触发

uint8_t overcurrent_cnt = 0;

void Motor_Overcurrent_Check(float current)
{
    if(current > CURRENT_THRESHOLD)
    {
        overcurrent_cnt++;
        if(overcurrent_cnt >= OVERCURRENT_COUNT)
        {
            Motor_Stop();  // 立即停止
            Error_Report(MOTOR_OVER_CURRENT);
            overcurrent_cnt = 0;
        }
    }
    else
    {
        overcurrent_cnt = 0;  // 正常就清零
    }
}

重要提醒:堵转保护不能只靠软件。我见过一个案例,软件跑飞了,保护逻辑失效,电机一直堵转,最后把减速器齿轮打碎了。硬件保护是最后一道防线,必须独立于MCU运行。

另外,堵转检测还有个技巧——别只看电流。有时候电流不大,但电机就是不转(比如机械卡死但阻力不大)。我习惯同时检测编码器速度:如果PWM输出很大,但编码器反馈速度接近0,那基本就是堵转了。

// 堵转检测:结合电流和速度
bool Motor_Stall_Check(float current, float speed, float pwm_output)
{
    // 如果PWM大于50%,但速度小于1rpm,且电流偏大
    if(pwm_output > 0.5f && fabs(speed) < 1.0f && current > 1.0f)
    {
        return true;  // 堵转
    }
    return false;
}

嗯,电机调试这块,说到底就是细心加耐心。驱动原理搞明白,PID参数慢慢试,编码器数据校准好,保护逻辑做周全——这四步走下来,你的AMR底盘基本就稳了。我调试过几十台机器人,每次都是按这个流程走,没出过大问题。

底层电机调试知识体系 电机调试核心 电机驱动原理 H桥电路 PWM频率选择 死区时间设置 PID参数整定 临界比例法 积分限幅 响应曲线分析 编码器数据读取 增量式/绝对式 零点校准 方向校准 堵转与过流保护 硬件保护(比较器) 软件保护(循环检测) 速度+电流联合判断 调试顺序:驱动原理 → PID整定 → 编码器校准 → 保护验证 每步验证通过后再进入下一步,避免问题叠加

专注资料整理