CHAPTER 16 / FIELD GUIDE
编码器与闭环入门
先把速度测准,再调控制器。
脉冲数的单位必须说清
编码器可能标注电机轴每转脉冲数,也可能给减速后输出轴的计数;还可能按单边沿或四倍频计算。把这些混在一起,速度会差几倍甚至几十倍。
本章只对 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 倍。这往往来自不同计数模式的定义混淆。
本章验收
本章一手资料
卡住时可以直接向我提问:附上章节号、工程名、接线和第一条错误日志。