学习目标

  1. 了解编码器的构成
  2. 理解编码器采样原理
  3. 掌握编码器获取转速信息

    学习内容

    编码器组成

    V5.png

  4. 左侧的减速齿轮

  5. 中间的电机部分
  6. 右侧的电路板

    减速齿轮

    将电机转速通过齿轮按照一定比例进行降速。

    电路板

    V4.png
    电路板中,包含了一个圆形磁体,还有两个霍尔传感器。
    电机转动时,圆形的磁体会同步进行转动,

    传动过程

    074.png

  7. 电机转动时,中轴会转动

  8. 中轴和圆形磁铁是连在一起的,圆形磁铁也会同步转动
  9. 中轴的一端和减速齿轮连接在一起,中轴转动会带动齿轮按照一定的比例进行转动(减速比)。

    霍尔传感器

    078.png
    开发板中包括了两个霍尔传感器,一个磁铁。
    磁铁是由7对N极和S极组成的。
    076.png
  • 当电机转动时,磁铁也转动。
  • 当磁铁的N极正对霍尔传感器时,霍尔传感器会将这个信号转化为高电平。
  • 当磁铁的S极正对霍尔传感器时,霍尔传感器会将这个信号转化为低电平。
  • 通过记录高低电平变换次数,可以得到电机中轴转动的速度。

    重要的概念名称

    减速比和额定转速

    以下是以N20电机为例,N20的规格参数,其中我们关注额定转速和减速比。
    075.png
    额定转速:rpm,全称Revolutions Per Minute,每分钟转动的圈数,说的时末端连接轴的转速。
    减速比:电机中轴连接了齿轮,当中轴转动时,齿轮随着中轴转动而转动,最终传导到末端连接轴。末端连接轴的速度,被减速齿轮降低了,末端连接轴和中轴的速度比就是减速比。例如rpm为300,减速比为50,那么电机中轴的转速为300*50 = 15000转/分

    轮子行进速度

    079.png
    我们知道,速度=距离/时间
    轮子是和末端连接轴连接在一起的,RPM为300时,轮子1分钟可以转300圈,那轮子可以走过的距离我们是可以求出来的。
    转一圈,就是轮子的一个周长,周长=2ΠR
    因此,在RPM为300时,轮子的速度为 300(rpm) x 43(直径) x Π / 60
    得出结果为 675.442409 mm/s,换算下来差不多为 0.6到0.7米/秒

霍尔传感器采样

127.png
两个霍尔传感器加上磁铁,可以测出电机的转速和方向。

  • 当A传感器是上升沿时,如果B此时为低电平,那么就是反转。
  • 当A传感器是上升沿时,如果B此时为高电平,那么就是正转。
  • 产生一次上升沿或者下降沿,就记一次数,通过时间就可以测出当前的转速了。

对于霍尔采样,我们可以通过外部中断方式进行实现,代码如下:

  1. #include "gd32f4xx.h"
  2. #include "systick.h"
  3. #include <stdio.h>
  4. #include "main.h"
  5. #include "Usart.h"
  6. #include "I2C.h"
  7. #include "bsp_mpu6050.h"
  8. #include "inv_mpu.h"
  9. #include "inv_mpu_dmp_motion_driver.h"
  10. FlagStatus pre = RESET;
  11. int8_t dir = 1;
  12. int32_t cnt = 0;
  13. void Usart0_recv(uint8_t* data, uint32_t len) {
  14. printf("recv: %s\r\n", data);
  15. }
  16. static void EXTI8_config() {
  17. uint32_t extix = EXTI_8;
  18. uint32_t extix_irq = EXTI5_9_IRQn;
  19. uint32_t extix_irq_pre = 1;
  20. uint32_t extix_irq_sub = 1;
  21. uint32_t extix_trig = EXTI_TRIG_RISING;
  22. uint32_t extix_rcu = RCU_GPIOB;
  23. uint32_t extix_port = GPIOB;
  24. uint32_t extix_pin = GPIO_PIN_8;
  25. uint32_t extix_pupd = GPIO_PUPD_NONE;
  26. uint32_t extix_src_port = EXTI_SOURCE_GPIOB;
  27. uint32_t extix_src_pin = EXTI_SOURCE_PIN8;
  28. /*************** gpio ****************/
  29. // PA0,
  30. // 时钟初始化
  31. rcu_periph_clock_enable(extix_rcu);
  32. // 配置GPIO模式
  33. gpio_mode_set(extix_port, GPIO_MODE_INPUT, extix_pupd, extix_pin);
  34. /*************** exti ****************/
  35. // 时钟配置
  36. rcu_periph_clock_enable(RCU_SYSCFG);
  37. // 配置中断源
  38. syscfg_exti_line_config(extix_src_port, extix_src_pin);
  39. // 中断初始化
  40. exti_init(extix, EXTI_INTERRUPT, extix_trig);
  41. // 配置中断优先级
  42. nvic_irq_enable(extix_irq, extix_irq_pre, extix_irq_sub);
  43. // 使能中断
  44. exti_interrupt_enable(extix);
  45. // 清除中断标志位
  46. exti_interrupt_flag_clear(extix);
  47. }
  48. void EXTI5_9_IRQHandler() {
  49. // 判断寄存器状态
  50. if(SET == exti_interrupt_flag_get(EXTI_8)) {
  51. FlagStatus current = gpio_input_bit_get(GPIOB, GPIO_PIN_9);
  52. if(RESET == current && SET == pre) {
  53. pre = current;
  54. dir = 1;
  55. //cnt = 0;
  56. } else if(SET == current && RESET == pre) {
  57. pre = current;
  58. dir = -1;
  59. //cnt = 0;
  60. }
  61. cnt += dir;
  62. printf("cnt: %d\r\n", cnt);
  63. // 清除中断标志位
  64. exti_interrupt_flag_clear(EXTI_8);
  65. }
  66. }
  67. static void GPIO_config() {
  68. rcu_periph_clock_enable(RCU_GPIOB);
  69. gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_PIN_9);
  70. }
  71. int main(void)
  72. {
  73. nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
  74. systick_config();
  75. GPIO_config();
  76. Usart_init();
  77. EXTI8_config();
  78. while(1) {
  79. }
  80. }

正交编码

正交编码是一种用于测量旋转位置或速度的技术。它通常涉及到两个相位差90度的信号(A相和B相)。这两个信号通过光电传感器、磁性传感器或其他位置传感器生成。正交编码的主要原理是通过检测A相和B相信号的相对相位变化来确定旋转的方向和步数。
A相和B相信号: A相和B相信号是两个相位差90度的正弦波形或方波形。这两个信号的变化在旋转方向上具有差异。
相位关系: 如果A相先于B相发生变化,系统会认为是顺时针旋转;如果B相先于A相发生变化,系统会认为是逆时针旋转。通过检测这两个信号的相对相位变化,可以确定旋转的方向。
脉冲计数: 在正交编码器中,每个脉冲表示一个步进。通过计数脉冲的数量,可以确定旋转的总步数。
增量式测量: 正交编码器提供的是增量式的测量,而不是绝对位置。为了得到绝对位置,通常需要在系统启动时将编码器归零,然后开始测量。

当前的电机测速传感器满足这种结构和表现。

在GD32中,配置正交编码如下:

  1. // 输入配置
  2. timer_ic_parameter_struct tips;
  3. timer_channel_input_struct_para_init(&tips);
  4. tips.icfilter = 10;
  5. timer_input_capture_config(timerx, TIMER_CH_0, &tips);
  6. timer_quadrature_decoder_mode_config(timerx,
  7. TIMER1_QUADRATURE_DECODER_MODE,
  8. TIMER1_QUADRATURE_DECODER_IC0,
  9. TIMER1_QUADRATURE_DECODER_IC1);

对于正交编码采样逻辑如下:

  1. short Timer1_input_read() {
  2. uint32_t timerx = TIMER1;
  3. short value = 0;
  4. value = (short)timer_counter_read(timerx);
  5. timer_counter_value_config(timerx, 0);
  6. return value;
  7. }

练习

  • 能够读取轮子转速