MG_996R舵机

舵机(Servo Motor)是一种集电机、控制电路和反馈系统于一体的伺服电机系统,用于精确控制位置(角度)、速度或力矩。它最常见的用途是 角度伺服控制,即驱动一个机械装置旋转到特定角度并保持稳定。

组成

一个典型的舵机包括以下部分:

  1. 电机
    • 通常是一个直流电机(DC Motor)或无刷电机,负责提供驱动力。
  2. 齿轮组
    • 电机驱动输出轴通过齿轮组减速并放大扭矩,从而增加精度和力量。
  3. 控制电路
    • 内部的电子控制模块接收控制信号(如 PWM 信号),将其转换为电机的转速和方向。
  4. 位置反馈系统(通常是电位计)
    • 用于检测输出轴的当前位置,反馈给控制电路以形成闭环控制。
  5. 输出轴
    • 连接外部机械装置,执行精确的角度控制。

F407duojiyli

特点

  • 精准角度控制
    舵机可以控制输出轴在特定范围内(通常为 0° 到 180° 或 360°)的位置。

  • 闭环控制
    舵机通过位置反馈系统(如电位计或编码器)不断调整输出轴的位置,确保达到目标角度。

  • 易于使用
    使用简单的 PWM 信号即可控制,无需复杂的驱动器。

  • 扭矩输出
    舵机通常以 kg.cm(千克力·厘米)为单位来表示其扭矩能力。

工作原理

舵机的工作原理基于闭环控制系统,它通过比较控制信号与实际位置之间的差异,调整电机的转动,最终使舵机的输出轴达到并保持在目标位置。具体过程如下:

接收 PWM 信号

  • MCU 输出一个 PWM 信号,通常是周期为 20ms,脉冲宽度在 1ms 到 2ms 之间。

  • 例如,1ms 的脉冲宽度对应 0°,1.5ms 对应 90°,2ms 对应 180°。

  • 这个 PWM 信号决定了舵机的 目标位置

舵机判断是否需要转动

  • 舵机内部有一个电位器,它持续监控舵机的实际角度

  • 控制电路将接收到的目标角度与电位器提供的当前角度进行比较,计算出 误差(即目标角度与当前角度之间的差值)。

  • 如果目标角度实际角度不一致,舵机会继续转动,通过电机和齿轮组调整到目标位置。

  • 如果目标角度实际角度相同,电机停止转动,舵机就会维持当前的角度。

电机转动

  • 是否需要转动:舵机是否继续转动取决于 当前角度目标角度 之间的误差。如果两者一致,舵机不需要转动;如果存在误差,舵机会转动直到达到目标角度。

  • PWM信号 只负责设置目标角度,舵机根据当前角度和目标角度的差值决定是否需要转动。

分类

模拟舵机(Analog Servo)

  • 使用模拟电路控制,接收连续的 PWM 信号。
  • 优点:成本低,适合低精度应用。
  • 缺点:响应速度较慢,抗干扰能力弱。

数字舵机(Digital Servo)

  • 使用数字信号处理器(DSP)控制。
  • 优点:控制更精确,响应速度快。
  • 缺点:价格较高,功耗略高。

连续旋转舵机(Continuous Servo)

  • 特点:能够连续旋转,不局限于角度范围。
  • 应用:作为轮子或传动装置,用于机器人。

工业伺服电机(Industrial Servo Motor)

  • 用于精确控制速度和位置。
  • 应用:工业自动化设备、机械臂等高精度场景。

与普通电机的区别

特性 舵机 普通电机
控制精度 高,可控制到具体角度或位置 低,通常只控制速度或方向
结构 集成反馈和控制电路 仅包含电机本体
控制方式 通过 PWM 信号或命令控制 电压、电流或占空比控制
应用 精确控制机械位置 旋转运动或动力输出

MG 996R

MG 996R 型号对于舵机的控制如下:

1.5ms 对应中间位置,2ms 对应最右边位置(+90°),1ms 对应最左边位置(-90°)。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "gd32f4xx.h"
#include "systick.h"
#include <stdio.h>
#include "main.h"
#include "BSP_USART.h"

// 预分频值
#define PRESCALER (168 - 1) //
// 周期为 20ms
// 也就是 1s = 20000ms 1000000/10000 = 100
#define PERIOD (((SystemCoreClock / (PRESCALER + 1)) / 50) - 1)

// Timer8 GPIO Config
void Timer8_GPIO_Config(void) {
// PE5
rcu_periph_clock_enable(RCU_GPIOE);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
gpio_af_set(GPIOE, GPIO_AF_3, GPIO_PIN_5);
}

// TImer8 Config
void TImer8_Config(void) {
timer_deinit(TIMER8);
rcu_periph_clock_enable(RCU_TIMER8);
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL2);
timer_parameter_struct initpara;
timer_struct_para_init(&initpara);
initpara.prescaler = PRESCALER;
initpara.period = PERIOD;
timer_init(TIMER8, &initpara);

// PWM 配置
timer_oc_parameter_struct ocpara;
timer_channel_output_struct_para_init(&ocpara);
ocpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
ocpara.outputstate = TIMER_CCX_ENABLE;
// 第一个参数是我们使用的是哪一个定时器
// 第二个参数是我们使用的哪一个通道,也是就在服用编号表中看到的编号 TIMER3_CH3
timer_channel_output_config(TIMER8, TIMER_CH_0, &ocpara);
// 输出模式配置
// 模式0:在向上计数时,一旦计数器值小于 TIMERx_CH0CV 时,O0CPRE 为高电平,否则为低电平。
// 在向下计数时,一旦计数器的值大于 TIMERx_CH0CV 时 O0CPRE 为低电平,否则为高电平。
// 在 TIMERx_CH0CV 下面就是高电平
timer_channel_output_mode_config(TIMER8, TIMER_CH_0, TIMER_OC_MODE_PWM0);
// 配置占空比
// 为了达到流水灯的效果,我们要让他一开始是 熄灭的,然后逐渐亮灭
// 周期和分频会自动 + 1 ,占空比不会所以需要加回来
timer_channel_output_pulse_value_config(TIMER8, TIMER_CH_0, (uint16_t)(PERIOD + 1) * 2.5 / 100);
timer_enable(TIMER8);
}

int main(void) {
systick_config();
usart0_init();
Timer8_GPIO_Config();
TImer8_Config();
printf("App_start...");
while(1){

}
}

问题

一、周期计算

如何计算周期为 20ms 的 PWM 参数

已知:当前频率为 1000000Hz,周期为 20ms

频率为 1000000Hz,表示一秒钟有 1000000 个周期,每个周期的时间 = 1 / 1000000 = 0.001ms

我想要数 20 ms,也就是说我要数 x 个数,0.001x = 20ms,x = 20000

所以我们此时 pwm 的周期应该设置为 20000