2018-01-05 20:29:22 xuw_xy 阅读数 18382
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    413 人正在学习 去看看 陈贤能

舵机,又称伺服马达,是一种具有闭环控制系统的机电结构。舵机主要是由外 壳、电路板、无核心马达、齿轮与位置检测器所构成。其工作原理是由控制器发出PWM(脉冲宽度调制)信号给舵机,经电路板上的IC处理后计算出转动方向, 再驱动无核心马达转动,透过减速齿轮将动力传至摆臂,同时由位置检测器(电位器)返回位置信号,判断是否已经到达设定位置,一般舵机只能旋转180度。舵机有3根线,棕色为地,红色为电源正,橙色为信号线,但不同牌子的舵机,线的颜色可能不同,需要注意。

舵机的转动位置是靠控制PWM(脉冲宽度调制)信号的占空比来实现的,标准PWM(脉冲宽度调制)信号的周期固定为20ms,占空比0.5~2.5ms 的正脉冲宽度和舵机的转角-90°~90°(即0~180度)相对应。注意,由于舵机牌子不同,其控制器解析出的脉冲宽度也不同,所以对于同一信号,不同牌子的舵机旋转的角度也不同。其原理是:它内部有一个基准电路,产生周期为20ms,宽度为1.5ms的基准信号, 控制信号由接收机的通道进入信号调制芯片,获得直流偏置电压。将获得的直流偏置电压与电位器的电压比较,获得电压差输出。最后,电压差的正负输出到电机驱动芯片决定电机的正反转。当电机转速一定时,通过级联减速齿轮带动电位器旋转,使得电压差为0,电机停止转动。

   0.5ms------------0度;

   1.0ms------------45度;

   1.5ms------------90度;

   2.0ms-----------135度;

   2.5ms-----------180度;

 

采用11.0592MHZ51单片机驱动舵机转动程序如下:

//上电自动转动

#include <reg52.h>

unsigned char count;      //0.5ms次数标识

sbit pwm =P1^0 ;          //PWM信号输出

sbit jia =P2^4;           //角度增加按键检测IO口

sbit jian =P2^5;           //角度减少按键检测IO口

unsigned char jd;         //角度标识

 

sbit pwm1 =P0^0 ;          //PWM信号输出给示波器,检测PWM波用

void delay(unsigned char i)//延时

{

  unsigned char j,k;

  for(j=i;j>0;j--)

    for(k=125;k>0;k--);

}

void Time0_Init()          //定时器0初始化

{

//定时器0装初值 用示波器检测后,11.0592MHZ晶振 定时0.5ms进入中断 装初值如下

TH0  = (65536-445)/256;

TL0  = (65536-445)%256;

 
TMOD = 0x01;    //定时器0工作在方式1   

IE = 0x82;	//IE=0x82=1000 0010 等价于 EA=1 开总中断  ET0=1 开定时器0中断

  TR0=1;          //开定时器0

}

void Time0_Int() interrupt 1 //中断程序

{

//重装初值

TH0  = (65536-445)/256;

TL0  = (65536-445)%256;

 

    if(count< jd)

{

 pwm=1;                  //确实小于,PWM输出高电平

 pwm1=pwm;              //接示波器用的io口,观测PWM波形用	    }	//判断0.5ms次数是否小于角度标识

 //pwm=1;                  //确实小于,PWM输出高电平

    else

{

 pwm=0;                  //确实小于,PWM输出高电平

 pwm1=pwm;             //接示波器用的io口,观测PWM波形用	}

    //  pwm=0;                  //大于则输出低电平

    count=(count+1);          //0.5ms次数加1

    count=count%40;     //次数始终保持为40 即保持周期为20ms

}

 

//此注销掉部分为通过按键控制舵机转动的程序,功能为通过jia按键控制正转,

//通过jian按键控制反转

/*void keyscan()              //按键扫描

{

   if(jia==0)               //角度增加按键是否按下

  {

    delay(10);              //按下延时,消抖

    if(jia==0)              //确实按下

     {

      jd++;                 //角度标识加1

      count=0;              //按键按下 则20ms周期从新开始

      if(jd==6)

        jd=5;               //已经是180度,则保持

      while(jia==0);        //等待按键放开

     }

  }

  if(jian==0)                //角度减小按键是否按下

  {

    delay(10);

    if(jian==0)

     {

      jd--;                 //角度标识减1

      count=0;

      if(jd==0)

        jd=1;               //已经是0度,则保持

      while(jan==0);

     }

  }

}*/

 
void main()

{

//上电,舵机自动正反转    

//应注意每次步进是延时函数delay参数的设置,此处延时函数参数设置的并不理想    

while(1)

{

  for(jd=1;jd<6;jd++)

{

count=0;

Time0_Init();

delay(50000000);

}

delay(50000000);

for(jd=6;jd>0;jd--)

{

count=0;

Time0_Init();

delay(50000000);

}

}

}


 

2019-10-29 19:31:23 qq_45497666 阅读数 545
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    413 人正在学习 去看看 陈贤能

概述

在这篇博客中,将介绍一个基于51单片机的舵机控制系统,其可以通过矩阵按键输入角度,舵机打到预定角度,并在数码管上显示。

硬件设计

这次的小系统电路都由洞洞板搭建,主要包括51单片机最小系统,矩阵按键,数码管驱动和舵机四个部分。Protues仿真电路图如下
在这里插入图片描述

  • 数码管驱动
    仿真测试程序数码管时可以直接用IO口驱动,但是实物搭建电路需要再接驱动电路,这次选择了74HC245芯片来驱动。这款芯片使用非常简单,在驱动显示屏,做隔离芯片时应用都非常多。它有A0-A7,B0-B7两组输入输出口,可以DIR管脚选择数据传输方向,在使用时如果不需要转换传输方向可以直接将此管脚接到芯片VCC或者GND。
    在这里插入图片描述

  • 矩阵按键
    4*4的矩阵按键每一行每一列接在一个口上,通过行列扫描确定哪一个按键被按下,也就是导通。

  • 舵机
    舵机一般分为数字舵机和模拟电机。它们都由马达,减速齿轮组和控制电路组成。主要区别是数字电机有微处理器和晶振,能产生一周期为20ms,占空比为7.5%(即1.5ms高电平)的基准信号,通过输入与信号比较确定打角。而模拟电机则通过电位器产生的差分电压驱动电机正反转从而改变角度。这次选用的是SG90 180度的模拟舵机,价格低,带动一个激光头绰绰有余。通过单片机输出的周期为20ms的PWM波控制,在宽度从0.5ms到2.5ms,每一个占空比对应一个角度,示意图如下
    在这里插入图片描述

程序设计

PWM波的产生

在51单片机中,没有可以直接调用产生PWM波的底层库,需要自己用定时器写。一般产生PWM波能用两个定时器写,每一个定时器只固定拉高或者拉低,靠时间差确定周期。也可以只用一个定时器写,通过改变装载值来反复改变电平。以下详细说明用一个定时器写的方式,另外一个定时器空余出来可以实现更多功能。
一个定时器产生PWM波需要两组装载值,分别控制高低电平时间。设置一个全局变量作为中断标志位确定用哪一组装载值,拉高还是拉低电平,每一次进入中断后改变标志位的值。舵机180度对应每周期高电平时间0.5到2.5ms,可调范围2ms,用12M晶振时也就是2000个机器周期长,得到装载值与角度关系系数为11.11,取11,再加0.5ms对应的500个机器周期,就能得到角度与高电平对应值的关系。
机器周期数=角度*11+500
*周期20ms减去高电平时间就能换算出低电平对应装载值。*如果想要更精确,系数和对应值可以用浮点型,在最后计算装载值时再强制转换成整型。
把这段程序单独贴出来

 /*******************************************************
 装载值计算函数
*******************************************************/
 void zhuang(u8 jiaodu)
 {
   u16 zhuangza; //高电平对应机械周期数
   zhuangza=jiaodu*11+500;  //2000/180=11.11  
   H1=  (65536-zhuangza)/256; 
   L1 = (65536-zhuangza)%256;
   H2 = (45536+zhuangza)/256;//65535-(2000-高电平值)
   L2 = (45536+zhuangza)%256;
 }
 
/*******************************************************
定时器1中断服务函数
*******************************************************/
void Time1(void) interrupt 3    
{
 if(servoflag==0) //中断标志位
 {
 TH1 = H1; 
 TL1 = L1;   
 PWM=1;
 servoflag=1;
 }
 else if(servoflag==1)
 {
 TH1 = H2; 
 TL1 = L2;   
 PWM=0;
 servoflag=0;
 } 
}    

矩阵按键功能与数码管显示参数传递

矩阵按键前10个值分别对应0到9。10为确定键,按下后在主函数中将按键读到的几个一位数转换成角度,传给装载值计算函数,改变PWM波占空比,舵机打到对应角度。另外设计了11,12,13三个键,按下后能使舵机直接打到程序预定好的角度。相应按键功能分配在主函数中。具体程序不再赘述。
为了使输入多位数时能正确显示,让数码管的每一位固定显示个、十、百位,对应数组的四个元素,初值不显示,输入低位后,接受按键值的元素移向高位。

完整程序

#include "reg52.h"

typedef unsigned int u16;   
typedef unsigned char u8;

sbit LA=P2^4;     //数码管位选
sbit LB=P2^1;
sbit LC=P2^2;
sbit LD=P2^3;
sbit PWM=P2^5;   //PWM输出口
u8 code smgduan[17]={0x3f,0x06,0x9b,0x8f,0xA6,0xAd,0xBd,0x07,0xBf,
0xAf,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//0到9,大于9不显示
u8 f=0; 
static u8 jiaodu=0; //角度
u8 keyflag,servoflag;  //按键标志位,中断标志位
u8 H1=0xFA,L1=0x24,H2=0xB7,L2=0xBC;  //两组装载值
u16 zhuangzai;    
u8 w[4]={16,16,16,16};   //按键输入值保存数组,初值16不显示
u8 KeyValue;  //按键值
/*******************************************************
延时函数
*******************************************************/
void delay(u16 i)
{
 while(i--); 
}
/*******************************************************
定时器1初始化
*******************************************************/

void Timer1Init()
{
 TMOD|=0X10;
 
 TH1 = 0xFC; 
 TL1 = 0x18;
 ET1=1;   
 EA=1;
 TR1=1; 
}
/******************************************************
装载值计算函数
*******************************************************/
void zhuang(u8 jiaodu)
 { 
  u16 zhuangza;
 zhuangza=jiaodu*11+500;  //高电平对应值与角度换算
  H1=  (65536-zhuangza)/256; //H,L分别是装载值高、低8位
 L1 = (65536-zhuangza)%256;  //1是高电平装载值,2是低电平装载值
 H2 = (45536+zhuangza)/256;
 L2 = (45536+zhuangza)%256;
}
/*******************************************************
数码管动态扫描
*******************************************************/
void DigDisplay()    
{
 u8 i;
 for(i=0;i<4;i++)
 {
  switch(i)  
  {
   case(0):
    LA=0;LB=1;LC=1;LD=1; P0=smgduan[w[0]];break;
   case(1):
    LA=1;LB=0;LC=1;LD=1; P0=smgduan[w[1]];break;
   case(2):
    LA=1;LB=1;LC=0;LD=1; P0=smgduan[w[2]];break;
   case(3):
    LA=1;LB=1;LC=1;LD=0; P0=smgduan[w[3]];break;
  } 
  delay(10);  
  P0=0x00;
//  delay(100);   //不加亮度更高
 }
}
/*******************************************************
矩阵按键扫描
*******************************************************/
void KeyDown(void)
{
 char a=0;
 P1=0x0f;
 if(P1!=0x0f)
 {
  delay(1000);//消抖
  if(P1!=0x0f)
  { 
   keyflag=1;
   //测试列
   P1=0X0F;
   switch(P1)
   {
    case(0X0e): KeyValue=0;break;
    case(0X0d): KeyValue=1;break;
    case(0X0b): KeyValue=2;break;
    case(0X07): KeyValue=3;break;
   }
   //测试行
   P1=0XF0;
   switch(P1)
   {
    case(0Xe0): KeyValue=KeyValue;break;
    case(0Xd0): KeyValue=KeyValue+4;break;
    case(0Xb0): KeyValue=KeyValue+8;break;
    case(0X70): KeyValue=KeyValue+12;break;
   }
   while((a<50)&&(P1!=0xf0))  //松手检测
   {
    delay(1000);
    a++;
   }
  }
 }
}
/*******************************************************
主函数
*******************************************************/
void main()  
{
 u8 i=0;
 Timer1Init();  //定时器1初始化
 while(1)
 {
  DigDisplay();
  KeyDown();
  if(keyflag==1)
  {
   w[i]=KeyValue;
      i++;
   keyflag=0;
  }
  if(KeyValue==10)    //确定键
  {
   for(i=0;w[i]<10;i++)
    jiaodu=jiaodu*10+w[i];
   zhuang(jiaodu);
   jiaodu=0;
  }
  if(KeyValue==12)
  {
   zhuang(87);      //特定角度
  }
  if(KeyValue==13)
  {
   zhuang(97);
  }
   if(KeyValue==14)
  {
   zhuang(109);
  }
 }  
}
/*******************************************************
定时器中断服务函数
*******************************************************/
void Time1(void) interrupt 3    
{
 if(servoflag==0) 
 {
 TH1 = H1; 
 TL1 = L1;   
 PWM=1;
 servoflag=1;   //改变值,下次进入中断用另一组装载值
 }
 else if(servoflag==1)
 {
 TH1 = H2; 
 TL1 = L2;   
 PWM=0;
 servoflag=0;
 } 
}

外加模块

为了增加系统的趣味性,可以在舵机上安装激光头,距离一定距离放置三个目标靶,将其角度写入程序,则可以通过特定按键打靶。还可以在目标靶上增加指示电路,是激光打到靶后指示灯亮,可以通过光敏电阻的简单电路实现。

2016-08-08 09:43:54 channel_Z 阅读数 3753
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    413 人正在学习 去看看 陈贤能

2012-01-09


之前写了一个51单片机的6路舵机程序,其原理很简单,舵机需要一个约20ms的脉冲,其中高电平0.5-2.5ms,其余为低电平。这样我们可以用一个定时器,每0.1ms中断,各用一个变量来记录每个舵机的计数,这样就用软件方式实现了6个定时器。

这样的程序一般也够用了,不过,如果要用来驱动改造的连续旋转舵机的话就困难了。如果像刚才那样的程序,精度是0.1ms(100μs),将舵机的角度平分成20个角度,每次调节舵机就转了9度。一般的舵机死区都在10μs以下,应该可以0.9度地调节。

一开始我理所当然的将原来的程序,由0.1ms中断改为0.01ms中断,经过多次调整测试都不行,后来将STC C52的CPU换成STC12的CPU,发现可以控制1个舵机了,但后来换成2个舵机又不行了。正当百思不得其解的时候,忽然醒悟,0.01ms就是10μs,10μs才几个CPU时钟周期,根本不可能做那么多的运算,这样写的效率很低。

正当我打算放弃51单片机的时候,忽然想到一个算法。将20ms的脉冲分成2部分,10ms和10ms(后来改成17ms和3ms),第一段时间负责计算,将接下来6个舵机分别要在什么时候中断计算好,存放在变量里,第二段时间开始的时候,将全部舵机输出高电平,然后依次中断,将舵机置低电平,然后循环。(后来又改成主程序定时排序,定时器中断只负责根据数组置高低电平),这样精度就可以达到计时器级别(12M的晶振是1μs),但这里我们只需要10μs即可。

这个算法的关键是要对数组进行排序。一开始程序写好了,但总是会在某些点抖动,总是找不到原因。后来尝试将排序算法由“快速排序法”换成其他的排序法(插入排序法,选择排序法,冒泡排序法),发现各有不同的表现,最后发现冒泡排序法最稳定,比较适合。

附上上下位程序代码,供网友参考。单片机程序加了一个路由是否启动的检测,这样就不用先启动路由,然后再打开单片机了。由于单片机需要一个1-200的数来控制舵机,很多都是不可见字符,所以上位机就干脆省略了控制字符设置,直接写在代码里。其实下位机程序效率还是稍微有点不够,STC C52还是偶尔会卡顿,STC12系列就比较流畅,但我也不知道怎样再提高效率了。

编译好的程序:http://bbs.igee.cn/read.php?tid=5649

 http://download.csdn.net/detail/channel_z/4074607

 

2012-1-14更新:

经一位网友指点,找到一个更好的算法,将20ms分成8个2.5ms,轮流对8个舵机输出PWM,这样效率很高,STC89和12都能用,而且还学到了一招,强推挽输出,不用上拉电阻也可以推动舵机了,不过STC12才有强推挽输出。

2012-2-11更新:

STC12的强推挽输出还真的是鸡肋啊,驱动能力还是太弱,连续改变脉冲就反应不过来,一开始还没找到原因,后来换另外那个焊了电阻的就没问题了,建议大家还是老老实实焊个电阻吧。

更新后的下位机代码如下:

/*预处理命令*/

#include <reg52.h>  //包含单片机寄存器的头文件

#define uchar unsigned char

#define uint unsigned int

P0M1=0X00; 

P0M0=0XFF;//设置P0 为强推挽输出

 

sbit servo0=P0^0;

sbit servo1=P0^1;

sbit servo2=P0^2;

sbit servo3=P0^3;

sbit servo4=P0^4;

sbit servo5=P0^5;

sbit servo6=P0^6;

sbit servo7=P0^7;

 

uchar serVal[2];

uint pwm[]={1382,1382,1382,1382,1382,1382,1382,1382}; //初始90度,(实际是1382.4,取整得1382)

uchar pwm_flag=0;

uint code ms0_5Con=461; //0.5ms计数 (实际是460.8,取整得461)

uint code ms2_5Con=2304; //2.5ms计数

 

/********************************************************************

* 功能 : 串口初始化,晶振11.0592,波特率9600,使能了串口中断

***********************************************************************/

void Com_Init()

{

TMOD |= 0x20;   //用定时器设置串口波特率

TH1=0xFD;   //256-11059200/(32*12*9600)=253 (FD)

TL1=0xFD;//同上

TR1=1;//定时器1开关打开  

REN=1;          //开启允许串行接收位

SM0=0;//串口方式,8位数据

SM1=1;//同上

EA=1;           //开启总中断

ES=1;  //串行口中断允许位

}

/********************************************************************

* 功能 : 舵机PWM中断初始化

***********************************************************************/

void Timer0Init()

{

//0度=0.5ms, 45度=1ms, 90度=1.5ms, 135度=2ms, 180度=2.5ms

//2.5 ms初始值 F700, (12n/11059200=2.5/1000, n=2304, X=65536-2304=63232 > F700)  

TMOD |= 0x01;  //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响

TH0=-ms2_5Con>>8;      //给定初值,17ms中断

TL0=-ms2_5Con;

EA=1;            //总中断打开

ET0=1;           //定时器0中断打开

TR0=1;           //定时器0开关打开                                   

}

 

/********************************************************************

* 功能 : 舵机PWM中断, //舵机控制函数 周期为20ms 一个循环20MS  = 8*2.5ms 

***********************************************************************/

void SteeringGear() interrupt 1

{

    switch(pwm_flag)

    {

        case 1:  servo0=1; TH0=-pwm[0]>>8; TL0=-pwm[0]; break;

        case 2:  servo0=0; TH0=-(ms2_5Con-pwm[0])>>8; TL0=-(ms2_5Con-pwm[0]); break;

case 3:  servo1=1; TH0=-pwm[1]>>8; TL0=-pwm[1]; break;

        case 4:  servo1=0; TH0=-(ms2_5Con-pwm[1])>>8; TL0=-(ms2_5Con-pwm[1]); break;   

case 5:  servo2=1; TH0=-pwm[2]>>8; TL0=-pwm[2]; break;

        case 6:  servo2=0; TH0=-(ms2_5Con-pwm[2])>>8; TL0=-(ms2_5Con-pwm[2]); break;

case 7:  servo3=1; TH0=-pwm[3]>>8; TL0=-pwm[3]; break;

        case 8:  servo3=0; TH0=-(ms2_5Con-pwm[3])>>8; TL0=-(ms2_5Con-pwm[3]); break;

case 9:  servo4=1; TH0=-pwm[4]>>8; TL0=-pwm[4]; break;

        case 10: servo4=0; TH0=-(ms2_5Con-pwm[4])>>8; TL0=-(ms2_5Con-pwm[4]); break;

        case 11: servo5=1; TH0=-pwm[5]>>8; TL0=-pwm[5]; break;

        case 12: servo5=0; TH0=-(ms2_5Con-pwm[5])>>8; TL0=-(ms2_5Con-pwm[5]); break;

case 13: servo6=1;TH0=-pwm[6]>>8; TL0=-pwm[6]; break;                      

        case 14: servo6=0;TH0=-(ms2_5Con-pwm[6])>>8; TL0=-(ms2_5Con-pwm[6]); break;  

        case 15: servo7=1;TH0=-pwm[7]>>8;  TL0=-pwm[7]; break;      

        case 16: servo7=0;TH0=-(ms2_5Con-pwm[7])>>8; TL0=-(ms2_5Con-pwm[7]); break; 

default: TH0=0xff; TL0=0x80; pwm_flag=0;          

  }

    pwm_flag++;

}

 

  void SetSteeringGear(uchar i, uchar val)

{

uint a = (val+46)*10;

    if(a<ms0_5Con)

a=ms0_5Con;

if(a>ms2_5Con)

a=ms2_5Con;

pwm[i]=a;

serVal[0]=255; //清除缓存

}

 

  void SteeringGearUp(uchar i)

{

    if(pwm[i]>ms0_5Con)

pwm[i]=pwm[i]-10;

}

 

  void SteeringGearDown(uchar i)

{

    if(pwm[i]<ms2_5Con)

pwm[i]=pwm[i]+10;

}

 

/********************************************************************

* 功能 : 串口中断接收数据

***********************************************************************/

void ser() interrupt 4

{

serVal[0]=serVal[1];

serVal[1]=SBUF;

RI=0;//串口中断清0

}

 

/*********************************************************************************

** 函数功能 : 主函数

*********************************************************************************/

void main()

{

bit started=0; //路由是否已经启动完毕

    Com_Init();//串口初始化

    Timer0Init();//舵机初始化

 

while(1)

{

if(serVal[0]=='w' && serVal[1]=='d'){

started=1; //路由启动最后会出现:ar71xx-wdt,由此判断路由已经启动

}

 

if(started)

{

if(serVal[0]==0){

switch(serVal[1])

{

case 'A': SteeringGearUp(0); break;

case 'B': SteeringGearDown(0); break;

case 'C': SteeringGearUp(1); break;

case 'D': SteeringGearDown(1); break;

case 'E': SteeringGearUp(2); break;

case 'F': SteeringGearDown(2); break;

case 'G': SteeringGearUp(3); break;

case 'H': SteeringGearDown(3); break;

case 'I': SteeringGearUp(4); break;

case 'J': SteeringGearDown(4); break;

case 'K': SteeringGearUp(5); break;

case 'L': SteeringGearDown(5); break;

default:break; 

}

serVal[0]=255; //清除缓存

}else if(serVal[0]==1){

SetSteeringGear(0,serVal[1]);

}else if(serVal[0]==2){

SetSteeringGear(1,serVal[1]);

}else if(serVal[0]==3){

SetSteeringGear(2,serVal[1]);

}else if(serVal[0]==4){

SetSteeringGear(3,serVal[1]);

}else if(serVal[0]==5){

SetSteeringGear(4,serVal[1]);

}else if(serVal[0]==6){

SetSteeringGear(5,serVal[1]);

}

}

}

}


2019-11-22 15:50:48 pang9998 阅读数 509
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    413 人正在学习 去看看 陈贤能

工作环境(蓝色粗体字为特别注意内容)
1、系统环境:SG90模拟舵机、MG90S数字舵机、12C5A60S2单片机
2、参考文献:

很多不是航模或者机器人爱好者的同学可能舵机了解比较少,笔者也一样,只是单纯的单片机爱好者,只是有时候需要用舵机来控制一些机械机构,因此对舵机不是很了解。对新手来说可能会有以下疑问
1、舵机是什么?有什么作用?
2、数字舵机和模拟舵机的区别是什么?模拟舵机和数字舵机接口是否通用?
3、舵机的工作原理是怎么样的?
4、舵机控制方式是怎么样的?
5、舵机工作的时候电流是多大?
6、舵机是否需要驱动电路?

那么今天咱就来彻底的了解一下舵机的来龙去脉。有图有真相,咱们先来看看舵机长什么样。

 笔者为了弄清楚以上两个问题,特地从某宝买了以上两种舵机,都比较便宜,也非常好找,分别是SG90模拟舵机(蓝色塑料齿轮)<10元,MG90S(灰色金属齿轮)<20元。可以发现,金属齿轮比塑料齿轮要贵,数字舵机比模拟舵机要贵。那么下面咱们来一一解答上面的问题。

1、舵机是什么?有什么用?
舵机是一种位置(角度)伺服的驱动器,适用于那些需要角度不断变化并可以保持的控制系统。目前,在高档遥控玩具,如飞机、潜艇模型,遥控机器人中已经得到了普遍应用。
主要用于需要输出某一控制角度的场合,舵机可以根据控制信号来输出指定的角度,常见的有0-90°、0-180°、0-360°,这几种舵机除了能够输出最大角度不同之外,价格和性能参数没有任何区别(同一型号而言)。

2、数字舵机和模拟舵机的区别是什么?模拟舵机和数字舵机接口是否通用?
数字舵机(Digital Servo)和模拟舵机(Analog Servo)在基本的机械结构方面是完全一样的,主要由马达、减速齿轮、控制电路等组成,而数字舵机和模拟舵机的最大区别则体现在控制电路上,数字舵机的控制电路比模拟舵机的多了微处理器和晶振。不要小看这一点改变,它对提高舵机的性能有着决定性的影响。
①处理接收机的输入信号的方式;
②控制舵机马达初始电流的方式,减少无反应区(对小量信号无反应的控制区域),增加分辨率以及产生更大的固定力量。
③实际应用不同,数字舵机在位置准确度方面要高于模拟舵机。在同样标称1.6公斤的舵机面前数字舵机在实际表现中会感觉更加“力气大”而模拟舵机就会“肉”点。模拟舵机由于控制芯片是模拟电路,所以即便是相同型号的舵机会存在小小的性能差异,而数字舵机在一致性方面就非常好。

3、舵机的工作原理是怎么样的?
舵机主要是由外壳、电路板、驱动马达、减速器与位置检测元件所构成。其工作原理是由接收机发出讯号给舵机,经由电路板上的 IC驱动无核心马达开始转动,透过减速齿轮将动力传至摆臂,同时由位置检测器送回讯号,判断是否已经到达定位。位置检测器其实就是可变电阻,当舵机转动时电阻值也会随之改变,藉由检测电阻值便可知转动的角度。一般的伺服马达是将细铜线缠绕在三极转子上,当电流流经线圈时便会产生磁场,与转子外围的磁铁产生排斥作用,进而产生转动的作用力。依据物理学原理,物体的转动惯量与质量成正比,因此要转动质量愈大的物体,所需的作用力也愈大。舵机为求转速快、耗电小,于是将细铜线缠绕成极薄的中空圆柱体,形成一个重量极轻的无极中空转子,并将磁铁置於圆柱体内,这就是空心杯马达。

下面咱们针对具体型号,比如SG90模拟舵机和MG90S数字舵机,来看看这两者之间的区别。
首先,引脚都是兼容的三根线排列一致,分别是GND(棕色)、VCC(红色)、PWM(黄色),控制方式也是一样的PWM时序,具体对应角度如下:

这里要注意,PWM波的频率不能太高,大约50HZ,即周期0.02s,20ms左右,(为了方便大家使用,笔者已经将驱动程序整理好,供大家点击下载舵机驱动程序所以如果要用12C5A60S2的PCA产生PWM波的话输出频率最低只能达到10khz左右,还是太高,无法驱动舵机,因此需要使用定时器来实现。实际波形像下面这样:


为了更加形象地了解pwm波形和输出角度的对应关系,我们来看一张动图,非常形象:

因为要考虑能耗问题,所以关于SG90模拟舵机和MG90S数字舵机工作电流可以分为几种状态。

① 舵机上电,无pwm控制信号
此时舵机不工作,静态电流均为4mA左右,舵机不会自动复位,完全不动作。
② 舵机上电,有pwm控制信号,舵机工作在输出到指定角度的过程中
此时舵机工作,需要消耗大约300mA的工作电流。
③舵机上电,有pwm控制信号,舵机已工作至指定角度
此时,舵机主要工作是维持指定角度,如果无外力抗拒,则消耗电流较小,SG90大约需要5mA,MG90S大约需要8mA左右。当然如果有外力抗拒的话则输出电流增大以抗拒外力。

4、舵机是否需要驱动电路?
一般来讲,舵机不需要特别的驱动电路,因为舵机内部已经有驱动电路了,一般单片机IO口输出的PWM波都可以驱动舵机。下图是12C5A60S2驱动舵机的电路图(p1.2没用到)
 

点击下载舵机驱动程序

 

 

 

2019-10-19 09:47:19 qq_41926119 阅读数 275
  • arduino实战

    学习如何在arduino中使用各种传感器,包括人体红外传感器,超声波传感器,舵机控制,温湿度传感器,激光接收传感器等,空气质量传感器,wifi模块等....课程内容会不断的更新增加,只要发现比较有趣的传感器就会做对应的实战视频

    413 人正在学习 去看看 陈贤能

文中介绍了一种模拟电磁曲射炮。该装置由驱动装置、控制系统和定位系统组成。驱动装置由6-12v电源、100v 1000μf电容、升压线圈构成;控制系统是使用Arduino Mega2560单片机、继电器等;定位系统主要使用单片机控制舵机实现。测试结果显示:当几v电源供电时,单片机利用程序控制舵机水平、垂直角度。根据发射炮管角度的变化控制弹丸的落点,使得弹丸可以在指定输入的条件下,击中目标环形靶。本装置满足设计的基本要求,达到理想效果。

 

1 系统方案

模拟电磁曲射炮

系统采用Arduino Mega2560单片机作为主控制器,通过键盘输入距离、角度参数,由两台舵机和云台控制炮管执行转向输出。实际测量时,主办方将环形靶放于指定位置,键盘输入距离和角度参数,通过单片机的算法控制,使得舵机调整角度,命中目标环形靶。系统整体结构如图所示。

 

                                 图1 系统整体结构图

1.1 角度控制模块的方案论证

方案一:使用舵机进行角度调整。电机传动系统在机械学中有重要应用。本方案中单片机控制舵机的转动参数,使得炮管角度发生改变,从而使得弹丸射中目标环形靶。利用惯性、pwm占空比以及舵机型号,使修改角度参数可以使弹丸射中环形靶及达到题目要求的发射周期。此方法最大的优点是适用于那些需要角度不断变化并可以保持的控制系统,故本设计选择该方案进行研究。

方案二:使用步进电机完成角度调节。它是一种通过由电脉冲转化的角位移的执行机构,即通过控制脉冲个数来控制角位移量,从而达到精确定位,通常电机内部都是有铁芯和绕阻线圈的,损耗会以热的形式表现出来,从而影响电机的效率。步进电机效率较低,电流一般较大致使电机普遍存在发热情况,甚至比一般交流电机更为严重,因此,我们选择方案一。

1.2 标靶距离检测模块的检测及论证

     方案一:激光测距,即由激光头发射可见激光和光敏电阻接收来测量距离。通过激光测量发射炮管和标识靶之间的距离,通过算法命中地面环形靶。该方法测量精度较高。

方案二:超声波测距,即通过超声波在空气中的传播速度为已知,超声波遇到障碍物反射回来的特性进行测量的。测距仪的精度是厘米级的,容易报错,易受环境及障碍物的干扰。

方案三:通过改变炮管倾斜角度改变落点位置。发射角度越大,电磁力转化为弹丸重力势能就越多,所以是90度角发射,落地时间最长;0度发射,落地时间最短。本题目中没有限制炮管垂直方向上的角度,为了得到最优方案,应该采用45度为发射初始角度。由于本设计中使用舵机,索性采用方案三。

1.3单片机选择方案及论证

方案一:用普通51直插单片机做控制核心。单片机只有P0、P1、P2、P3四个及16个引脚、两个定时器等,本次设计代码相对复杂,高电平时无输出能力,因此51单片机不合适。

方案二:用Arduino开发板做控制核心。它是一款开源硬件产品,同时支持SPI、IIC、UART串口通信,能通过多种传感器感知环境。其中Arduino Mega2560是采用USB接口的核心电路板,具有54路数字输入输出,适合需要大量I0接口的设计。处理器核心是ATmega2560,同时具有54路数字输入/输出口(其中1~5路可作为PWM输出)、15路模拟输入、4路UART接口、一个16MHz晶体振荡器、一个USB口等,通过USB数据线连接电脑便能实现供电、程序下载和数据通讯。综合我们对于单片机的了解程度以及实验要求,最终选用方案二。

2系统理论分析与计算

2.1 电磁炮总体设计分析

电磁炮是电磁发射技术演化而来的一种先进动能的发射系统,利用电磁系统中电磁场产生的安培力对金属炮弹进行加速,将电能转化为弹丸动能,大大提高弹丸的速度和射程,使其具备打击目标所需的动能。

电磁炮发射是由线圈、电感、电容、磁性弹丸以及附属部件组成。它是利用驱动线圈中的电流与被磁化的磁性弹丸的磁化电流之间的安培力将弹丸发射出去,由于磁化电流与驱动线圈中的电流具有相同的方向,致使弹丸受到吸力而加速,电磁炮炮管部分原理图如图所示。

 

图2 电磁炮炮管部分原理图

2.2电磁炮参数的分析

电磁炮是由电池组、电解电容、发射线圈、升压线圈等组成。

电容器是储存电量和电势能的元件,通常是一个导体被另一个导体所包围,或者由一个导体发出的电场线全部终止在另一个导体的导体系。电容的具体参数对于本次设计至关重要。

标称电容量,标识电容器的电容量,但电容器实际电容量与标称电容量是有偏差的。电解电容器的容值越大,在同等条件下,电容越大,放电时的电流越大;额定电压,为最低环境温度和额定环境温度下可连续加在电容器两端的最高直流电压,此电压的作用在于保护电容器。若工作电压超过电容器的耐压,电容器将被击穿,造成不可逆损害。

线圈是电磁炮动力的决定因素之一。线圈的制作,匝数的多少决定着威力和精度的大小,但这并不意味着单位长度内匝数越多场强越强。匝数越多电阻越大,电流也随之减小,需要找到一个合适的平衡点,致使磁场最强。值得注意的是,线圈本质上是一种电感,作为一种储能元件,需要考虑电感。空心线圈电感量的公式是L=(2R*μ*n^2*S)/h^2,其中h为线圈的长度,可得若线圈长度过长,电感将迅速减小,影响线圈的储能,但h过短将影响弹丸的初速,则线圈匝数及长度的选择需要慎之又慎。

2.3炮管情况分析

  电磁炮是用电磁力加速弹丸从而使其发射的系统。它凭借新能源动力和赋予弹丸较高的初速度吸引着人们,本设计同样也存在着一系列问题。

第一,弹道磨损问题。电磁炮炮管的磨损,主要是前期对于电解电容充放电掌握不够,导致弹丸在弹道内与内壁碰撞,电磁力转换的能量部分变成热能消耗,最终造成能量的流失;

第二,电、动能转化之间的损电问题。常规火炮的转换效率仅有20%,而电磁炮的能源转换效率最高可达50%,更加重了它的使用比例。但是因为电容技术、配件材料等因素的限制,远达不到理论的能量转化率,导致电磁炮的耗电较大。

3电路与程序设计

3.1电路设计

3.1.1总体电路设计

本次设计的系统总体电路设计,包括了电源模块、发射模块、操作模块。该系统主要由5—12V电源输入、舵机、继电器、电解电容、升压线圈、弹丸等构成。

 

3.1.2舵机角度控制部分

本次设计采用数字舵机,只需要发送一次PWM信号就能保持在规定的某个位置,具有控制精度高、线性度好、响应速度快等特点。

PWM脉宽型调节角度,周期20ms,占空比0.5ms~ 2.5ms的脉宽电平对应舵机0度~ 180度角度范围,且成线性关系。此次设计所用LD-1501MG舵机控制器采用500~2500数值对应舵机控制输出角度的占空比0.5ms~2.5ms的范围,这样舵机的控制精度是3us,在2000个脉宽范围内控制精度能达到0.3度。

3.1.3独立按键系统

通过独立按键系统,完成基础实验键盘输入环形靶靶心距离和中心轴线偏离角度,从而击中环形靶。独立按键电路图如图所示。

 

3.2 程序设计

本次设计系统程序主要包括:主程序模块、按键处理程序模块、电磁炮发射模块、继电器子程序等几个部分。系统总体流程如图所示:

 

 

 

 

 

 

 

4 测试方案与测试结果

4.1测试方案

将电磁炮放置于定标点,做到精确命中环形靶。按照题目要求输入距离和夹角参数,并通过LCD显示,单片机经过计算得出舵机的水平、垂直旋转角度,最后一键启动电磁炮,命中环形靶。具体的实物如附件1所示。

4.2测试结果

经测试和不断分析数据后,原理图没有出现问题,硬件电路根据测试不断调整可以实现题目所要求的功能。测试数据:

环形靶放置位置

电磁炮命中位置

实验差

200cm

200cm

0cm

225cm

220cm

5cm

250cm

230cm

20cm

300cm

270cm

30cm

 

没有更多推荐了,返回首页