找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7188|回复: 6
收起左侧

关于51单片机控制舵机(减速电机类似)的详解

[复制链接]
ID:105323 发表于 2016-2-23 22:25 | 显示全部楼层 |阅读模式
关于舵机,目前网络上和书本上,很难找到详细可行的资料(如果有,那估计是我眼瞎,不要理我就好啦- -!),我在制作ROBOTCUP搬运机器人的过程中,由于听取学长的“建议”,采用舵机作为机器人的驱动,加之当时太年轻,使用90系列51单片机,所以一个舵机耗了3个月,并没有按照预期,参加比赛(这个也真的不怪谁,不走个弯路,也不会对舵机和51单片机有如今的大彻大悟- -!)。所以啊,如果有学弟学妹,想要在以后做之类的比赛甚至于从事相关的工作,那么好好研究下舵机的控制,对你是十分有帮助的(无论是对于舵机控制的原理还是对主控芯片的理解都很有帮助)。关于舵机的控制,我查询过相关的资料,也请教过我的导师,但是结果都很不满意,舵机乱转,转速控制不精确,出现过各种问题。最终,我也硬是通过砸钱和砸时间(20块一个的PWM调制器不知道烧了多少- -!这个反正烧的不是我的,不心疼,但是90块一个舵机,加上60块一个的航模PWM舵机调制器还是砸了几百块进去的),和小伙伴通过实验,反复测试得到的结果,在这里分享出来,希望能帮助到学弟学妹。
首先,舵机是做什么的?舵机按照旋转的角度,可以分为180°和360°连续旋转舵机。180°舵机,顾名思义,就是只能旋转180°的舵机,我们可以通过一定的方法,精确的控制舵机旋转的角度,因此,就我目前接触到的比赛来看,180°舵机在双足机器人以及飞思卡尔竞速车的转向上使用的很多,双足机器人就是模仿人走路的机器人,通过控制180°舵机转动的角度,完成指定的动作。飞思卡尔转向类似于汽车使用方向盘转向,舵机就起到方向盘的作用。360°连续旋转舵机,可以通过一定手段,控制舵机的旋转方向和速度,因此,也常常用于小车型机器人的驱动上。这里需要说明的是,180°舵机是无法调速的,就是说,他始终会以最快速度,朝着你设定的角度旋转,直到旋转到目标角度停止。而360°舵机是无法控制旋转的角度的,只可以控制转和停,正转和反转以及转速。
下面是舵机: 
 


安装有180°舵机的双足机器人: 

安装有360°舵机的搬运机器人:

 
上一段中,我提到可以通过一定的方法,控制舵机,到底是什么方法?PWM!我也不是什么老教授,我不喜欢说太多抽象的理论,这里,只需要知道,要控制舵机,我们要让单片机输出一个周期为20ms-30ms,高电平为0.5ms-2.5ms的信号即可。 

关于硬件上的设计,无非是保证供电的稳定和预留出PWM的接口,由于我本身也不是做硬件的,这里就不详细说明了,这里附上一张图,感兴趣的小伙伴可以研究一下,如果对硬件上有其他的问题,也可以私下联系我,我们组做硬件的小伙伴,还是很厉害的。 

我这里对360°舵机如果通过51单片机的程序进行控制做详细的说明。对于360°舵机而言,PWM高电平为0.5-1.5ms为正转区间,1.5-2.5ms为反转区间,1.5ms为舵机刹车点,实际测试过程中,我使用的舵机,高电平0.5ms-1.37ms为以最大速度正转,正转的调速高电平区间为1.37ms-1.47ms(高电平越靠近1.5ms,舵机转速越慢),高电平1.53ms-2.5ms为以最大速度反转,反转调速高电平区间为:1.53-1.63ms(高电平越靠近1.5ms,舵机转速越慢),刹车高电平区间为:1.47-1.53ms。是不是感觉很简单呢?听起来好像是挺简单的,但是有没有想过如何使用51单片机产生我们需要的PWM呢?有小伙伴会说,用定时器啊!当然,我一开始也是这么想的,看看下面这段程序:
unsigned int i=1;
int n;
void ste360(n){
TMOD=0X01;
TL0=0XF6; // 0.01ms
TH0=0XFF;
TR0=1;
EA=1;
ET0=1;
P1=0X00; 
while(1);
}

void _pwm () interrupt 1 {
TH0=0xff; // 0.01ms
TL0=0xF6;
i++;

if(i<=n){
P1=0XFF; // 1.37<<1.47-1.54<<1.63
} else P1=0x00;

if(i>=2000){
i=1;

}
}
看起来程序好像没有什么问题,ste360(n)这个函数,n就可以控制pwm高电平的时间,我设定定时器为每0.01ms进入一次中断,所以,要想得到1.5ms高电平,是不是n填写150就行了?答案是否定的,至于具体结果怎么样,我这里就不截图了,没有在学校没法用示波器,之后完善吧。我这里告诉你,虽然程序逻辑是没有问题的,计算出来确实是1.5ms,但是结果可能是高电平为3ms+,为什么?这个问题困惑了我挺久,我和学长也讨论过,他说,编译过程中,会将我们写的c文件,编译成汇编文件,然后转成机器语言,这个过程中可能会有误差。而我觉得,晶振本身是有误差的,其次,这样反复的进入中断,细小的误差会被无限的放大。同样是使用c,stm32上pwm的精度高的离谱。所以,使用51单片机的8位定时器来控制舵机,在我看来,是完全不可行的(可以质疑我的能力,但是上面的程序是在我写的众多定时器控制pwm输出程序中早期的一个,放出来理解简单,但我在很长一段时间里,极力优化代码,尝试过各种思路,但是结果只能说有提升,但是远远达不到控制舵机的要求),有不怕死的小伙伴,也可以自己写点小程序,打在示波器上看看。不能用定时器,那怎么办?又有小伙伴说了,stc12系列的51单片机是自带8位pwm模块,是不是可以用12系列的单片机实现?看程序:
#include
              //-----------------------------
              // 7  6 5 4 | 3 2  1    0
sfr CCON=0xD8;//CF CR - - | - - CCF1 CCF0
              //-----------------------------
              //CF:PCA计数阵列溢出标志.计数值翻转时由硬件置位。
              //CR:PCA计数阵列运行控制位。
              //CCF1:PCA模块1中断标志。当出现匹配或者捕获时由硬件置位。
              //CCF0:PCA模块0中断标志。当出现匹配或者捕获时由硬件置位。
              /
sfr CCAP0L=0xEA;//PCA模块0的捕捉/比较寄存器低8位
sfr CCAP0H=0xFA;//PCA模块0的捕捉/比较寄存器高8位

sfr CCAPM0=0xDA;//PCA模块0的工作模式寄存器
                //---------------------------------------
                //7   6    5     4     3    2    1    0
                //- ECMn CAPPn CAPNn MATn T0Gn PWMn ECCFn
                //----------------------------------------
                //ECOMn:使能比较器,1时使能比较器功能
                //CAPPn:正捕获,1时使能上升沿捕获
                //CAPNn:负捕获,1时使能下降沿捕获
                //MATn:匹配:1时,PCA计数器的值与模块的比较/捕获寄存器的值匹配将置位CCON寄存器中断标志位CCFn
                //T0Gn:翻转,1时,工作在PCA告诉输出模式,PCA计数器的值与模块的比较/捕获寄存器的值匹配将是CEXn脚翻转
                //PWMn:脉宽调节输出模式,1时,使能CEXn脚用做PWM输出
                //EECFn:使能CCFn中断,使能寄存器CCON中的捕获/比较标志CCFn,用来产生中断
sfr PCA_PWM0=0xF2;//PCA模块0,PWM寄存器
                  //-----------------------------------
                  //         7 6 5 4   3 2   1     0    
                  //PCA_PWMn:- - - - | - - EPCnH EPCnL
                  //-----------------------------------
sfr CCAP1L=0xEB;
sfr CCAP1H=0xFB;
sfr CCAPM1=0xDB;
sfr PCA_PWM1=0xF3;//
sbit CR=0xDE;//因为只有能和8整除的才能位寻址,所以能些0xDE,看起来有冲突,实际上不会。
sfr AUXR1=0xA2;//PWM引脚位置 串口2位置 双DPTR选择 AD转换结果存放方式调整 SPI位置调整

void ini_T0(void)
{
    TMOD=0x02;//T0方式2
TH0=0xb2; //12MH时
TL0=0xb2;
    TR0=1;
}
//
//频率为50HZ 周期的1/50=0.02s,将0.02S分成256分:0.02/256=0.000078125S=0.078125ms
//0.078125为一份的时间 一共256份
//CCAP0L=223;CCAP0H=223;为2.5ms //243时约为1ms (0.9375)
//CCAP0L=249;CCAP0H=248;为0.5ms //236时为1.5ms (1.484375)
                                 //230为2ms (2.03125)

void main(void)
{
    ini_T0();  //方式2,0.078125ms溢出,每溢出一次CL加1
CMOD=0x04;//定时器0溢出率作为时钟输入
             //CIDL - - -  CPS2 CPS1 CPS0 ECF
              //--------------------------------
              //CIDL:计数阵列空闲控制,0时,空闲模式下PCA计数器继续工作;1时空闲模式PCA停止工作。
              //----------------------------------------------
              //CPS2 CPS1 CPS0: PCA计数脉冲选择
              //000:系统时钟,FOSC/12
              //001:系统时钟,FOSC/2
              //010:定时器0的溢出,可实现可调频率PWM输出
              //011:ECI/P3.4脚的外部时钟输入(最大速率FOSC/2)
              //100:系统时钟,FOSC
              //101:系统时钟/4,FOSC/4
              //110:系统时钟/6,FOSC/6
              //111:系统时钟/8,FOSC/8
              //-----------------------------------------------
              //ECF:PCA计数溢出中断使能:1时,使能寄存器CCON CF位的中断。0时禁止该功能。
CL=0x00;//清零自由递增计数的16位定时器的值
CH=0x00;//CH0为00  看结构图,CL前面是永远是0
   
//CCAP0L=223;//装入比较初值
//CCAP0H=223;
PCA_PWM0=0x00; //EPC0H=0,EPC0L=0
CCAPM0=0x42;//设置ECOM1=1,PWM1=1.
   
    //CCAP1L=223;
    //CCAP1H=223;
    PCA_PWM1=0x00;//EPC1H=0,EPC1L=0
CCAPM1=0x42;//设置ECOM1=1,PWM1=1.
CR=1;//CR=1,启动PCA阵列计数。  看151页,其中和CMOD的CIDL位有关,又和IDLE有关,看183页。
   
   
//AUXR1=0xc0;//PWM0从P1.3切换到P4.2
    //PWM1从P1.4切换到P4.3
while(1)
{
//========================两舵机停止,中位调节用
   CCAP0L=236;//装入比较初值
   CCAP0H=236;
        CCAP1L=230;//装入比较初值
   CCAP1H=230;
while(1);
}
}
至于怎么调整pwm的高电平,修改上面CCAPXL和CCAPXH就可以了,这段代码不是我写的,但明显是个高手写的- -!至于这段代码是怎么实现的,程序里的注释很详细,小伙伴们在学了郭天祥的教程以后,尝试着查看官方的手册吧,学习单片机,重要的不是你学会了多少多少东西,更重要的还是一种自学能力,翻手册,学这款芯片怎么用的能力。是不是大功告成了呢?并没有!!测试中我发现,CCAPXH和CCAPXL的值每改变1,PWM高电平改变0.07ms左右。那么问题来了,在前面我提到过,360°舵机调速的区间,只有0.1ms(1.47-1.37=0.1),这个0.07,是可以让舵机实现正转反转,以及停止,但是没办法调速,循迹小车是需要控制车子两侧的轮子产生转速差来控制方向的,没法调速,就没法实现循迹。造成这个问题的原因是什么?8位的pwm模块,8位的pwm,上面程序中的注释中有这样一段:
//频率为50HZ 周期的1/50=0.02s,将0.02S分成256分: 0.02/256=0.000078125S=0.078125ms
//0.078125为一份的时间 一共256份
很清楚了吧!那么是不是51单片机控制不了360°舵机呢?在我制作搬运机器人的过程中,有一段时间我是想过放弃的,但是最终,我发现了stc15系列单片机,很有意思的是,我在查询芯片的时候,15这款单片机是没有pwm模块的,后来才知道,这款芯片带有16位的定时器,这样,问题就迎刃而解了,官方提供的手册中,有用16位定时器(自动重装模式)实现8~16位PWM的示例,具体的程序在这里我就不列出来了,在15的手册100页,感兴趣的小伙伴,自己去看看吧。
好了,360°舵机基本上说完了,其实180°舵机也是相似的,只是高电平的不同代表着不同的角度,0.5ms为0°,2.5为180°。程序都是一样的。我在这里说下比较容易出现的问题吧。首先,电路上的设计,舵机要求的电压为6v-7.2v,你也许会发现5v其实舵机也能转,但是,低电压会带来很多未知的问题,比如舵机乱转,曾经有一段时间,我陷入舵机乱转的怪圈,我以为是我程序的问题,但是示波器显示没问题,以至于我以为是舵机坏了。实际上,是电池的问题,电池用的时间长了,电压不足,让舵机乱转。所以,电池我建议使用航模sss电池,这个电池是11.2V的,使用降压模块,降成7.2v,给舵机供电,将成5v给单片机和传感器供电就行了。另外,舵机的自己的电路有时候会对单片机有影响,最好加上光耦隔离,防止舵机电路对单片机的干扰。
最后,简单说下使用舵机驱动小车和电机相比,有什么优劣。首先,就电路而言,由于舵机内置有电路,因此我们做机器人设计电路的时候,仅需要设计好阴阳极和PWM信号输入的接口,非常简单。而普通的减速电机在设计电路的时候,则需要考虑到驱动芯片,就比较复杂了。淘宝上有现成的驱动模块,买回来也就直接用了。而在控制上,舵机对于PWM的精度要求也更高,上文中已经论述过了。价格方面,舵机的价格是普通减速电机的很多倍,但是昂贵的价格带来的是拖刹的快速响应,给定高电平1.5ms的pwm,舵机会立刻刹住以及其充沛的动力这一点是减速电机做不到的。所以到底是采用舵机还是电机,学弟学妹自己斟酌吧。
一不留神竟然写了4000字- -!可以可以,如果觉得这篇文章不错,对你有帮助,也欢迎转载啦(请注明本文出处及作者)。我在大一加入了很多组织,最终在机器人协会找到了落脚点,从最初没有目的学习51单片机,做机器人,到现在有了目标,学习linux,学习开发智能路由器,在这个协会我还是学到了很多的东西的。现在呢,其实是以一种感恩的心态,在重复着往届学长学姐做的事情,很多优秀都是一种传承嘛!也欢迎各位小伙伴加入到重邮基协,加入到我们这个基情四射,整天撕逼的阵营中来吧- -!我相信在这个良心协会(真的良心),你会学习到你想学的东西哒!若是对舵机的控制仍有疑问,可以在下方评论留言,我看到会尽快回复。


重庆邮电大学机器人协会
魏佩儒              
回复

使用道具 举报

ID:130713 发表于 2016-10-15 12:32 | 显示全部楼层
可以,很详细
回复

使用道具 举报

ID:231115 发表于 2017-9-9 22:37 | 显示全部楼层
谢谢,学习的好资料
回复

使用道具 举报

ID:248544 发表于 2018-6-14 19:06 | 显示全部楼层
很有帮助
回复

使用道具 举报

ID:223274 发表于 2019-4-30 11:27 | 显示全部楼层
资料还不错哦
回复

使用道具 举报

ID:893947 发表于 2021-3-19 19:38 | 显示全部楼层
感谢楼主,我最近在琢磨怎么用80c52控制舵机,程序没问题,试了好几天都不行,看到这个解答真的是茅塞顿开
回复

使用道具 举报

ID:584041 发表于 2021-5-8 21:39 | 显示全部楼层
我纠正一下,舵机都是可以调速的,我以前用ARDUINO控制舵机,让它一度一度地转动,每度之间的延时达到了控制速度的目的。只是说这样的编程方式转换到51单片机可能有难度,但是一定行的,所以舵机是可以调速的。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表