CHAPTER 16 / FIELD GUIDE

编码器与闭环入门

先把速度测准,再调控制器。

建议用时 60–90 分钟先预测,再实验,再解释

脉冲数的单位必须说清

编码器可能标注电机轴每转脉冲数,也可能给减速后输出轴的计数;还可能按单边沿或四倍频计算。把这些混在一起,速度会差几倍甚至几十倍。

本章只对 A 相上升沿计数,B 相不接,测量速度大小,不测方向。先确认编码器供电和输出可兼容 3.3 V:A 接 GPIO6、GND 共地。若输出是开集电极,按模块要求上拉到 3V3;5 V 推挽输出需要合适电平转换。

实验工程 · 11_encoder

先用手慢慢转动轮子,观察累计脉冲和每秒脉冲数。PCNT 硬件负责计数,软件每 200 ms 读取一次。

打开 main.c · 查看公共驱动 lab.c · 下载全部工程

#include "lab.h"
#include "driver/pulse_cnt.h"
#include "esp_log.h"
// Count rising edges on A only. B is not used: this example measures magnitude, not direction.
void app_main(void) {
    pcnt_unit_config_t u= {
        .low_limit=-30000,
        .high_limit=30000,
        .flags.accum_count=true
    };
    pcnt_unit_handle_t unit;
    ESP_ERROR_CHECK(pcnt_new_unit(&u,&unit));
    pcnt_chan_config_t c= {
        .edge_gpio_num=6,
        .level_gpio_num=-1
    };
    pcnt_channel_handle_t channel;
    ESP_ERROR_CHECK(pcnt_new_channel(unit,&c,&channel));
    ESP_ERROR_CHECK(pcnt_channel_set_edge_action(channel,PCNT_CHANNEL_EDGE_ACTION_INCREASE,PCNT_CHANNEL_EDGE_ACTION_HOLD));
    ESP_ERROR_CHECK(pcnt_unit_add_watch_point(unit,30000));
    ESP_ERROR_CHECK(pcnt_unit_add_watch_point(unit,-30000));
    pcnt_glitch_filter_config_t f= {
        .max_glitch_ns=1000
    };
    ESP_ERROR_CHECK(pcnt_unit_set_glitch_filter(unit,&f));
    ESP_ERROR_CHECK(pcnt_unit_enable(unit));
    ESP_ERROR_CHECK(pcnt_unit_clear_count(unit));
    ESP_ERROR_CHECK(pcnt_unit_start(unit));
    int last=0;
    int64_t last_us=esp_timer_get_time();
    for(;; ) {
        vTaskDelay(pdMS_TO_TICKS(200));
        int count=0;
        ESP_ERROR_CHECK(pcnt_unit_get_count(unit,&count));
        int64_t t=esp_timer_get_time();
        float pps=(count-last)*1000000.0f/(t-last_us);
        ESP_LOGI("encoder","count=%d pulses_per_second=%.2f",count,(double)pps);
        last=count;
        last_us=t;
    }
}

从计数变成速度

手动把输出轮转 10 圈,用累计计数变化除以 10,得到本接法下的每圈脉冲 P。采样周期为 Δt 秒、计数变化为 ΔN:

轮速 RPM = 60 × ΔN / (P × Δt)
线速度 m/s = (ΔN / P) × π × 轮径米 / Δt
例:P=600,Δt=0.2 s,ΔN=120 → 60 RPM

从开环到闭环

开环只输出 PWM,不知道轮子是否达到目标。闭环把测得速度与目标比较,依据误差调整输出。先用 P 控制,再学习 I 消除稳态偏差;低速脉冲稀疏时,D 容易放大噪声,不急着加入。

# 算法伪代码;不是固件工程,增益必须实测整定
error = target_rpm - measured_rpm
candidate_integral = integral + error * dt
candidate = feedforward + Kp * error + Ki * candidate_integral
output = clamp(candidate, 0, max_output)
# 仅在未饱和,或误差使输出离开饱和时,接受积分更新
# 停止、故障、方向切换时清空积分;反向先停稳

控制周期固定,测量使用真实时间差。先把 Ki 设为 0,用较小 Kp 观察。出现来回振荡就停止并减小增益、检查测量延迟。电机停住而控制器仍持续积分会产生积分饱和;解除阻碍后可能突然加速。

闭环扩展实验的交付要求

给左右轮分别建立采样与控制通道,先在单轮架空环境记录时间、目标 RPM、实际 RPM、输出;加入第二轮前先验证故障停车。教程提供测量工程和算法解释,整车闭环需要按所购电机实测参数实现,不能把一组通用 PID 系数直接用于所有车。

停下来想一想

手转一圈记录 600,但代码按 P=150 计算,显示速度会怎样?

查看推导与答案

显示速度会变成实际的 4 倍,因为分母少了 4 倍。这往往来自不同计数模式的定义混淆。

本章验收

本章一手资料

卡住时可以直接向我提问:附上章节号、工程名、接线和第一条错误日志。