舵机(Servo)实际上可以看作一个伺服电机,其拥有驱动电路、控制电路,只不过一般舵机工作在一定的角度范围内,最常见的就是 180 度的舵机,它适用于那些需要角度不断变化并可以保持的控制系统中。在一定范围内连续改变输出轴角度并且可以保持住。这种电机

舵机最早被用在航模和船模等遥控模型中,控制各种舵面的转动,这就是舵机。现在舵机除了运用在遥控模型中,也大量的运用在各种机器人、机械臂的关节以及智能小车的转向机构中。

舵机按制电路分,可以分数字舵机和模拟舵机,它们的机械结构是完全一模一样的,其最大的区别体现在控制电路上,数字舵机的伺服控制器采用了数字电路(拥有MCU 和晶振),而模拟舵机的控制器采用的是模拟电路。模拟舵机需要给它不停的发送 PWM 信号,才能让它保持在规定的位置或者让它按照某个速度转动,数字舵机则只需要发送一次 PWM 信号就能保持在规定的某个位置。

按照旋转角度:可分为 180°与 360°的舵机,180 度舵机只能在 0 度到 180 度(±90 度)之间运动; 360°舵机转动的方式和普通的电机类似,可以连续的转动,不过我们只可以控制它转动的方向和速度,不能调节转动角度。

按照使用对象:的不同,可以分为:航模舵机、车模舵机、船模舵机和机器人舵机。航模舵机一般要求速度快、精度高,而车模和船模用的舵机一般要求具有大扭矩和防水性好。

按照内部机械材质,又可分成:塑料齿舵机和金属齿舵机。塑料齿舵机内部的传动齿轮是塑料的,重量轻价格便宜,但是扭矩一般较小无法做大;金属齿舵机的扭矩更大,舵机更结实耐用,但是相比塑料齿更重也更贵。

认识舵机的结构

舵机的结构主要由以下几个部分组成:外壳舵盘直流电机减速齿轮组角度传感器控制驱动电路接口线缆等。

  • 角度传感器:用来实现位置反馈的,它会将其旋转后产生的电阻变化信号发送回控制电路,从而监控当前轴旋转的角度;

  • 控制电路用来驱动电机和接收 PWM 控制信号以及电位器反馈信号;

  • 减速齿轮组用来增大直流电机的扭矩。齿轮的材质一般有塑料齿轮、混合材料齿轮和金属齿轮。

舵机工作原理

①首先由控制电路板接收到信号线的控制信号(一般为 PWM 信号),进而控制直流电机转动

②电机的输出轴和减速齿轮组的轴是相连的,所以只要电机一转动就会带动减速齿轮组转动

③减速齿轮组又和角度传感器连接在一起,所以同时也会带动角度传感器转动

④接着角度传感器会将当前的电压信号反馈到控制电路板,控制电路板会根据反馈的比例电压调节舵机的转动位置,当达到目标位置后停止,形成一个闭环控制系统。

舵机的控制

舵机的输入线共有三条:如下图 14.3.2 所示,一般棕色表示 GND,红色表示 VCC,橙色表示信号脚,工作电压一般在 4.8 ~ 6V,不同的工作电压对应不同的转矩标准,即输出力矩不同,6V 的工作电压对应的力矩要大一些;根据不同的扭矩负载,工作电流可达 2A 以上。

  • 棕色表示 GND
  • 红色表示 VCC
  • 橙色表示信号脚,

舵机的控制通常采用 PWM 信号,例如需要一个周期为 20ms 的脉冲宽度调制(PWM),脉冲宽度部分一般为 0.5ms-2.5ms 范围内的角度控制脉冲部分,总间隔为 2ms。当脉冲宽度为 1.5ms 时,舵机旋转至中间角度,大于 1.5ms 时舵机旋转角度增大,小于 1.5ms 时舵机旋转角度减小。舵机分90°180°270°360° 舵机,以 180° 的舵机为例来看看脉冲宽度与角度的关系。

其中信号线就是控制电路用于接受外部控制信号的,该信号一般周期为 20ms(频率:50HZ)的脉宽调制(PWM)信号。并且该脉冲的高电平持续时间为 0.5 ~ 2.5ms,对应舵盘旋转角度的 0 ~ 180°

  • 0.5ms———————0度
  • 1.0ms———————45度
  • 1.5ms———————90度
  • 2.0ms———————135度
  • 2.5ms———————180度

可以看出脉冲宽度与舵机旋转角度呈线性变化关系。也就是说我们只需要不断的提供一个脉冲周期为 20ms 的 PWM 信号给舵机,并且控制该脉冲信号的高电平持续时间占比,就可以控制输出轴保持在对应的角度上,注意角度范围不可超过 180°。0.5ms 对应 0 度,2.5ms对应最大旋转角度,脉冲宽度与旋转角度也是线性关系

舵机的参数

响应速度:即在接收到目标位置之后多久才可以转到目标角度,一般舵机为 60 度每 0.17秒,另外根据负载扭矩相应速度也不等。

工作死区,死区数值越小,控制精度越高;数值越大,精度越小。

材质:舵机材质一般有塑料齿轮和金属齿轮,金属材质相对的质量更好,价格也更高些。

舵机的扭矩:根据应用场合可从飞行器模型舵机的 1.2KG/cm 到大扭矩舵机的500~2000KG/cm 不等,不过一般扭矩越大舵机消耗电流也越大。由此可见这类舵机具有以下这些特点:输出力矩大,稳定性好;体积小,易安装;控制简单等。所以现在不仅仅应用于航模运动中,在机器人的关节,飞机的舵面,以及机械手等应用也越来越广泛。

驱动MG996R

MG996R 参数

  • 尺寸:40.5_20_41mm
  • 重量:55g
  • 速度:4.8V@ 0.12±0.01sec/60°——6.0V@ 0.11±0.01sec/60°
  • 扭力:4.8V@ 11kg-cm——6.0V@ 13kg-cm
  • 电压:4.8V-6V
  • 空载工作电流:220±20mA
  • 堵转工作电流:2000±30mA
  • 响应脉宽时间 ≤5usec
  • 角度偏差:回中差 ≤1°,左右各 45° 误差 ≤3°。
  • 齿轮:5 级金属齿轮组
  • 连接线长度:300mm

设计流程

在单片机系统实现对舵机输出转角的控制

  • 1 产生基本的PWM周期信号,我们前面讲过产生20ms的周期信号
  • 2 是脉宽的调整,即单片机模拟PWM信号的输出,并且调整占空比   

具体的设计过程:例如让舵机转向左极限的角度,它的正脉冲为2ms,则负脉冲为20ms-2ms=18ms,所以开始时在控制口发送高电平,然后设置定时器在2ms后发生中断,中断发生后,在中断程序里将控制口改为低电平,并将中断时间改为18ms,再过18ms进入下一次定时中断,再将控制口改为高电平,并将定时器初值改为2ms,等待下次中断到来,如此往复实现PWM信号输出到舵机。用修改定时器中断初值的方法巧妙形成了脉冲信号,调整时间段的宽度便可使伺服机灵活运动。为保证软件在定时中断里采集其他信号,并且使发生PWM信号的程序不影响中断程序的运行(如果这些程序所占用时间过长,有可能会发生中断程序还未结束,下次中断又到来的后果),所以需要将采集信号的函数放在长定时中断过程中执行,也就是说每经过两次中断执行一次这些程序,执行的周期还是20ms。

Code

初始化STM32F103ZET6定时器4的GPIOB6~9 与定时器3的 PA6 PA7 PB0 PB1

mg996r.c

#include "sg90.h"
#include "usart.h"

//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void PWM_Init(u16 arr,u16 psc)
{
    GPIO_InitTypeDef GPIO_InitStructure;              //定义GPIO结构体 需要用结构体类型参数时候一定要先在前面定义
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;    //定义TIMx定时器结构体
    TIM_OCInitTypeDef TIM_OCInitStructure;            //定义定时器脉宽调制结构体

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3|RCC_APB1Periph_TIM4,ENABLE);          //使能TIM3、4时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOA时钟和GPIOB时钟

    //设置该引脚为复用输出功能,输出TIM3、4 的PWM脉冲波形    GPIOB.0、1、6、7、8、9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9;                               
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         //复用输出 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                       //配置输出速率
    GPIO_Init(GPIOB,&GPIO_InitStructure);                                   //初始化GPIOB

     //设置该引脚为复用输出功能,输出TIM3 的PWM脉冲波形    GPIOA 6、7
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;                               
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                         //复用输出 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                       //配置输出速率
    GPIO_Init(GPIOA,&GPIO_InitStructure);                                   //初始化GPIOA

    //初始化TIM3
    TIM_TimeBaseStructure.TIM_Period = arr;                                 //设置自动重装载寄存器周期的值 arr=value-1
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                              //设置预分频值 psc=value-1
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                            //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //TIM向上计数模式
    TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);                          //初始化TIMx时间基数

    //初始化TIM4
    TIM_TimeBaseStructure.TIM_Period = arr;                                 //设置自动重装载寄存器周期的值 arr=value-1
    TIM_TimeBaseStructure.TIM_Prescaler = psc;                              //设置预分频值 psc=value-1
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;                            //设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //TIM向上计数模式
    TIM_TimeBaseInit(TIM4,&TIM_TimeBaseStructure);                          //初始化TIMx时间基数

    //初始化TIM3 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                       //选择定时器模式:TIM脉冲宽度调制模式1(改变占空比)
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //使能比较输出
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;               //输出极性:TIM输出比较极性高
    TIM_OC1Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC1
    TIM_OC2Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2
    TIM_OC3Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2
    TIM_OC4Init(TIM3,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM3 OC2


    //初始化TIM4 Channel2 PWM模式     
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                       //选择定时器模式:TIM脉冲宽度调制模式1
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;           //使能比较输出
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;               //输出极性:TIM输出比较极性高
    TIM_OC1Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC1
    TIM_OC2Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2
    TIM_OC3Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2
    TIM_OC4Init(TIM4,&TIM_OCInitStructure);                                 //根据T指定的参数初始化外设TIM4 OC2

    TIM_Cmd(TIM3, ENABLE);                                                  //使能TIM3
    TIM_Cmd(TIM4, ENABLE);                                                  //使能TIM4
}

mg996r.h

#ifndef _PWM_H  //头文件中使用#ifndef #define #endif条件编译,避免重复定义
#define _PWM_H
#include "sys.h"
void PWM_Init(u16 arr,u16 psc); //定义PWM初始化函数

#endif

main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "mg996r.h"


 int main(void)
 {
     vu8 key=0;    
    delay_init();             //延时函数初始化      
    LED_Init();                  //初始化与LED连接的硬件接口
    PWM_Init(199,7199); //舵机初始化   不分频。PWM频率=72000000/900=80Khz
    LED0=0;                    //先点亮红灯

//计算,假设PWM周期设置为20ms
//公式为:溢出时间Tout=(arr+1)*(psc+1)/Tclk,Tclk为通用定时器的时钟,如果APB1没有分频,则就为系统时钟,72MHZ
    while(1)
    {
        TIM_SetCompare1(TIM4,5);//定时器4通道1---0度
        delay_ms(1000);
        TIM_SetCompare1(TIM4,15);//定时器4通道1---90度
        delay_ms(1000); 
    }     
}

舵机作用

在各种各样的传感器获取需要的参数,然后使用PID系统输出,通过PWM控制系统就可以得到一个很好的控制系统。例子控制小车走直线,就可以通过mpu6050的数据输入PID系统,根据PID系统输出的数据控制舵机控制小车运动的方向。