ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

编码器读到的到底是什么:从脉冲到速度

编码器读到的到底是什么:从脉冲到速度 经典三问Q: 增量式编码器是什么A: 它会把轴的转动变成一串脉冲程序数一数这些脉冲就能知道轴转过多少A、B 两相信号还能分辨转动方向。Q: 为什么需要编码器A: PWM 只表示给电机多少驱动力不等于轮子真的转了多少、转得多快。编码器把轮子的实际运动交回给程序。Q: 编码器常见使用场景A: 测量轮速、记录转过的距离、判断正反转以及让左右轮尽量保持一致。我在前面的实验里就碰到过这个困惑两边电机明明给了同样的 PWM实际转起来的速度却不一样。左轮像有点着急右轮却慢半拍两边都写 30%小车还是会慢慢往一侧偏。把数值改成 40、50两个轮子当然都会更有劲可它们依然不同速。回想整个链路我本质上就是提供了一个 PWM。PWM 决定驱动器在一个周期里给电机通电多久它给的是驱动力的比例关键就在这PWM 没有说一定是“请以每分钟多少转运行”的命令。电机本身的差异、减速箱摩擦、轮胎压紧程度、电池电压和地面阻力都会让同一个 PWM 变成不同的速度。这时候就需要编码器出场啦如果没有编码器程序只知道“我给左右轮都写了 30%”至于它们到底转没转、谁快谁慢只能靠眼睛猜。有了编码器轴每转过一点就留下一次脉冲。程序把这些脉冲数起来就知道轮子实际留下的痕迹。六根线里哪四根不是给电机的这次使用六线霍尔编码器电机。两根较粗的线属于电机本体接到电机驱动板另外四根线属于编码器线的用途常见标记本例连接位置电机两线M、M-或两根无标记粗线驱动板的电机输出端编码器电源VCC按编码器资料供电本例为 5V编码器地GNDSTM32、驱动板和电源的公共地A 相A、CHAPB6 / TIM4_CH1B 相B、CHBPB7 / TIM4_CH2颜色没有统一标准。某个商品图里的红线是VCC不代表另一台电机的红线也一定是VCC。先看卖家的引脚说明、插头丝印或产品资料线序没有确认以前不要急着上电。本例把 PB6、PB7 配成内部上拉输入gpio.GPIO_PinGPIO_Pin_6|GPIO_Pin_7;gpio.GPIO_ModeGPIO_Mode_IPU;GPIO_Init(GPIOB,gpio);内部上拉适合开漏输出的编码器编码器没有主动拉低时引脚保持高电平它拉低时STM32 就读到低电平。A、B 不是两根重复的脉冲线先不让电机自己转断开电机驱动的功率输出只给编码器供电。手慢慢转动输出轴A、B 两根线上都会出现高低变化它们的区别在于变化时间故意错开了一点。一个方向 A __|----|____|----|__ B ____|----|____|----|__ 反方向 A ____|----|____|----|__ B __|----|____|----|__哪一相先变化方向就不同。A、B 交换后程序看见的方向通常也会反过来。至于“先到的是 A 就叫正转”还是“先到的是 B 就叫正转”没有脱离安装方向的标准答案左、右电机的安装朝向不同轮子装反了或者插头的 A/B 标记相反都会让正负号翻过来。先转一圈看计数朝哪个方向变化再约定“小车向前时应当是正数”还是负数。方向的名字可以在软件里统一A、B 的先后关系不能靠猜。只接 A 相也能看到脉冲却少了另一相提供的先后关系。这样还能做单向计数却无法可靠判断正反转对于需要知道轮子往哪边转的小车A、B 两根都要接。让 TIM4 自己数脉冲最直观的做法是 A 相每跳一次就进入一次中断再去读 B 相判断方向。手转时很容易看见效果电机转快以后CPU 会频繁停下手里的事去数脉冲。STM32 的通用定时器已经准备好另一种做法。TIM4 的 CH1、CH2 正好在 PB6、PB7 上。把 TIM4 设成编码器模式后硬件会持续观察 A/B 的先后关系自行给计数器加一或减一CPU 不必为每一个边沿进入中断。voidEncoder_Init(void){GPIO_InitTypeDef gpio;TIM_TimeBaseInitTypeDef timer;TIM_ICInitTypeDef input;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);gpio.GPIO_PinGPIO_Pin_6|GPIO_Pin_7;gpio.GPIO_ModeGPIO_Mode_IPU;GPIO_Init(GPIOB,gpio);timer.TIM_Prescaler0;timer.TIM_CounterModeTIM_CounterMode_Up;timer.TIM_Period0xFFFF;timer.TIM_ClockDivisionTIM_CKD_DIV1;timer.TIM_RepetitionCounter0;TIM_TimeBaseInit(TIM4,timer);TIM_EncoderInterfaceConfig(TIM4,TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICPolarity_Rising);TIM_ICStructInit(input);input.TIM_ChannelTIM_Channel_1;input.TIM_ICFilter6;TIM_ICInit(TIM4,input);input.TIM_ChannelTIM_Channel_2;TIM_ICInit(TIM4,input);TIM_SetCounter(TIM4,0);TIM_Cmd(TIM4,ENABLE);}TIM_EncoderMode_TI12表示 TIM4 同时使用 CH1 和 CH2也就是同时使用 A、B 两相。TIM_Period 0xFFFF让这只 16 位计数器使用完整范围从 0 到 65535。TIM_ICFilter 6是输入数字滤波。导线较长、附近有电机电源线时A/B 信号上可能出现很短的毛刺滤波会忽略一部分短到不合理的跳变。数值不是越大越好滤波越重真实边沿也会更晚被看见。出现跳数时先检查供电、接线和共地再决定是否调整滤波。取走一段时间里的脉冲TIM4 一直在数程序不必每次脉冲都去碰它。等 100ms读一次当前值再把计数器清零拿到的便是这 100ms 内的增量int16_tEncoder_ReadDelta(void){int16_tdelta(int16_t)TIM_GetCounter(TIM4);TIM_SetCounter(TIM4,0);returndelta;}反转时TIM4 会向下数。寄存器里的 16 位数字从 0 再减一会回到 65535把它看成int16_t时65535 正好表示 -1。因此delta是有正负号的正数和负数分别代表两个相反方向0 代表这段时间没有数到脉冲。这不是计数器永远不会绕回的魔法。一次取数的时间太长、轮子又转得很快时计数器可能绕回不止一次正负号和数量都会失去意义。最高转速、每圈计数和取数周期要放在一起考虑。第一次观察时直接用已经写好的Delay_ms(100)等 100ms再取一次计数并刷新 OLEDintmain(void){int16_tdelta;int32_ttotal_count0;Encoder_Init();OLED_Init();OLED_Clear();Delay_Init();while(1){Delay_ms(100);deltaEncoder_ReadDelta();total_countdelta;OLED_ShowSignedNum(0,0,delta,5,OLED_6X8);OLED_ShowSignedNum(0,8,total_count,8,OLED_6X8);OLED_Update();}}第一行delta是最近 100ms 内数到的脉冲数第二行total_count是从上电到现在的累计数。手转时delta忽大忽小很正常手的速度本来就不稳定只要正转时累计数持续往一个方向走反转时能够掉头A/B 两相和 TIM4 的方向判断就已经正常工作了。三个亲手能确认的现象正转和反转先不接电机功率端手转输出轴一圈。观察 OLED 的累计数一个方向会持续增加换方向后会持续减少。符号和心里定义的“前进”相反不算故障只需要在左右电机真正装好后统一方向约定。交换 A、B断电后交换 A、B 两根编码器线再用同一个方向手转。累计数的正负通常会翻转。重新断电把线换回原位。这个小实验能直接看见方向不是某一根线上的高或低而是两根线变化的先后。静止时不该自己记数轮子静止时连续观察累计数一段时间它应当保持不变。若数字自己跳动先确认编码器电源、公共地和 A/B 接线再检查编码器线是否和电机供电线长距离缠在一起。一圈到底是多少个脉冲原始计数已经足够回答“轮子有没有转”和“哪个方向转”。要把它换成每分钟转速还需要知道输出轴转一整圈会产生多少计数。每分钟转速 本次增量 × 60000 / 输出轴每圈实际计数 / 取数周期毫秒例如 100ms 内读到 220 个计数确认输出轴每圈是 1320 个计数每分钟转速 220 × 60000 / 1320 / 100 100 rpmrpm是每分钟转数revolutions per minute。这里一定要写“输出轴每圈实际计数”。商品页上常常同时出现 PPR、减速比、电机轴转速和输出轴转速其中一个11 PPR不一定就是 TIM4 在输出轴转一圈时读到的计数。先看编码器手册里的数字对应电机轴还是减速后的输出轴再手动让输出轴完整转一圈记录累计数实际变化了多少。两者对得上再把这个值用于换算。不要在没有确认前随便填一个数字算出来的小数点后面再漂亮也不会变成真实速度。取数周期从 100ms 改成 200ms 时同样速度下的delta大约会变成两倍因为收集脉冲的时间翻倍了。公式中的取数周期也必须一起从 100 改成 200否则轮子没变快算出来的转速却会刚好偏一倍。最后橘猫说同一个 PWM 不能保证两个轮子同速因为 PWM 交出去的是驱动力比例不是速度测量。编码器把转动翻译成 A、B 两相脉冲TIM4 再把脉冲变成有方向的计数。从“我给了多少 PWM”走到“轮子实际留下了多少脉冲”小车才第一次有了可以相信的运动记录。
返回列表