2016-10-12 00:01:55 so_cracy 阅读数 5985
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3419 人正在学习 去看看 朱有鹏

大三上学期的期末设计,全程全手工DIY,历时一个月,时间主要花在机器人步态的调整,为了让机器人走得好一点,花了不少功夫,给出设计方案,仅供参考

先来看看视频效果:链接:http://pan.baidu.com/s/1eR2d1Fc 密码:8o8h

机器有点简陋,当时是想要把电池做在机器人里面的,无奈当初经费有限(100块,买舵机就花了90多),买的舵机不给力,加上电池后太重,机器站不起来,所以就有了视频中连着两条电线。

一、整体框架:

(1)设计功能:

①能完成多方向行走以及其他的自定义的动作。(前进,后撤,左右转,避障);

②可自动避障;

③通过手机蓝牙下令他的下一步动作。

(2)功能框架:

 

(3)使用器材:

①STC89C52单片机、74LS04(反相器);

②蓝牙串口通信模块;

③超声波测距模块;

④9G舵机18个;

⑤PVC线槽若干(模具);

⑥PCB转印板;

⑦螺丝螺母若干。

⑦keil3软件

二、工作原理:

(1)蓝牙串口通讯模块:

蓝牙串口通讯模块接收手机蓝牙软件发送字符串信号,单片机通过串口通讯协议处理蓝牙模块接收到的信息,再根据信息的内容来判断机器人将进行的下一步行动。


(2)超声波测距模块:

超声波模块向某一方向发射超声波,在发射时刻的同时开始计时(传出低电平),超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时(回到高电平),根据低电平的长短来计算测量距离。(超声波在空气中的传播速度为340m/s,根据计时器记录的时间t,就可以计算出发射点距障碍物的距离(s),即:s=340t/2)

 

(3)舵机控制:

控制电路板接受来自信号线的控制信号,控制电机转动,电机带动一系列齿轮组,减速后传动至输出舵盘。舵机的输出轴和位置反馈电位计是相连的,舵盘转动的同时,带动位置反馈电位计,电位计将输出一个电压信号到控制电路板,进行反馈,然后控制电路板根据所在位置决定电机转动的方向和速度,从而达到目标停止。舵机的控制信号周期为20MS的脉宽调制(PWM)信号,其中脉冲宽度从0.5-2.5MS,相对应的舵盘位置为0-180度,呈线性变化。也就是说,给他提供一定的脉宽,它的输出轴就会保持一定对应角度上,无论外界转矩怎么改变,直到给它提供一个另外宽度的脉冲信号,它才会改变输出角度到新的对应位置上。

在我们的作品中,18路舵机分成2组,分别用一个内部定时器来控制,产生对应舵机的PWM信号(首先定时器1生成第一个舵机的脉宽,再生成第二个舵机的,到第9个舵机为止,然后定时器2以同样方式生成剩余的9个舵机的PWM信号,以此往复)。

三、制作过程:

(1)仿真原理图:

 

(2)PCB制作:

 

(3)硬件搭建:

<a>肢体制作:

材料:PVC线槽,PVC板

①模型制作:(纯手工割出来的)

 

②舵机改造:

 

③整体:

 

四、调试以及问题解决:

①结构问题:

我们认为,整体的外形结构是决定作品成败的关键。经过多种材料的试验,最终我们选择了容易裁剪、硬度基本满足的PVC线槽来改装拼接肢体,躯体使用更厚的塑料板。经历一周的纯手工加工改造后,完成了整个模型的制作。

②供电问题:

由于我们使用的是9G舵机,性能较差,扭力不够,无法支撑起我们设计的电源与稳压模块,最后放弃了内嵌的电源,使用实验室的可调电源箱通过电线来供电,无法独立开来也是我们的唯一遗憾。

③机器抖动问题

由于89C52只有6个内部中断,远远无法满足18个舵机的控制,并且其他功能模块也要使用到内部中断。所以我们将18路舵机分成了2组,初始时一个接一个舵机(每个舵机20ms周期)来发送PWM,但这也产生了发送一次18路PWM的总周期长度太大(18*20=360ms),足以产生被人眼所察觉的抖动。经过反复研究,让当前舵机的PWM信号在上一个PWM信号的低电平处开始产生高电平(在上一个PWM的高电平结束后)如下图,大大缩短了18路舵机一次动作的总周期长度(经过18路后,总周期长度为一个PWM的周期长度约20ms),使抖动无法被人眼所观察。

代码挺多,给出主要的舵机控制代码,代码看不懂没关系,后面有解释:

#include<reg52.h>

#include<intrins.h>

#include<dongzuo.h>

#define ucharunsigned char

#define uintunsigned int

 

//PWM

sbit PWM0 = P1^0;

sbit PWM1 = P1^1;

sbit PWM2 = P1^2;

sbit PWM3 = P1^3;

sbit PWM4 = P1^4;

sbit PWM5 = P1^5;

 

sbit PWM6 = P3^4;

sbit PWM7 = P3^5;

sbit PWM8 = P3^6;

sbit PWM9 = P3^7;

 

sbit PWM10 = P2^0;

sbit PWM11 = P2^1;

sbit PWM12 = P2^2;

sbit PWM13 = P2^3;

sbit PWM14 = P2^4;

sbit PWM15 = P2^5;

sbit PWM16 = P2^6;

sbit PWM17 = P2^7;

 

//超声波测距

sfr T2MOD = 0XC9;           //定时器2模式控制寄存器地址

sbit Trig    =P3^2;

sbit Echo   =P3^3;

 

unsigned intdistance;

uchar DZCS                =0x11;       //控制动作

uchar buf;

uchar sd=3;

bit flag=0;                             //是否发送字符

bit CSB     =0;                                //超声波启动控制位

bit HZ=0;                              //后退后左转控制位

 

uchar PWMscan =0;

uchar PWMscan1        =0;

 

uchar PWMval[]={//初始姿态

        0xf8,0x8f,0xf7,0x05,0xf9,0x8c,/*5*/                0xfa,0x0d,0xf8,0x0b,0xf9,0x67,/*b*/               0xfa,0xd4,0xf7,0x94,0xf9,0xcb,/*11*/

        0xfa,0xad,0xfc,0xdd,0xfb,0x58,/*17*/    0xfa,0xe9,0xfc,0xfc,0xfb,0x39,/*1d*/     0xfc,0x18,0xfc,0xca,0xfb,0x00/*23*/     

};

void delay(uint a)

{

        uchar j;

        for(a;a>0;a--)

                  for(j=0;j<112;j++)

                           ;

}

void task00()

{

        if(PWMscan==1)             //第1路PWM。

        {

                  PWM0=1;

                  TH0=PWMval[0];

                  TL0=PWMval[1];

        }

        else if(PWMscan==2)     //第2路PWM。

        {

                  PWM0=0;

                  PWM1=1;

                  TH0=PWMval[2];       

                  TL0=PWMval[3];

        }

        else if(PWMscan==3)     //第3路PWM。

        {

                  PWM1=0;

                  PWM2=1;

                  TH0=PWMval[4];

                  TL0=PWMval[5];

                  }

        else if(PWMscan==4)     //第4路PWM。

        {

                  PWM2=0;

                  PWM3=1;

                  TH0=PWMval[6];       

                  TL0=PWMval[7];

        }

        else if(PWMscan==5)     //第5路PWM。

        {

                  PWM3=0;

                  PWM4=1;

                  TH0=PWMval[8];       

                  TL0=PWMval[9];

        }

        else if(PWMscan==6)     //第6路PWM。

        {

                  PWM4=0;

                  PWM5=1;

                  TH0=PWMval[10];     

                  TL0=PWMval[11];

        }

        else if(PWMscan==7)     //第7路PWM。

        {

                  PWM5=0;

                  PWM6=1;

                  TH0=PWMval[12];

                  TL0=PWMval[13];

        }

        else if(PWMscan==8)     //第8路PWM。

        {

                  PWM6=0;

                  PWM7=1;

                  TH0=PWMval[14];     

                  TL0=PWMval[15];

        }

        else if(PWMscan==9)     //第9路PWM。

        {

                  PWM7=0;

                  PWM8=1;

                  TH0=PWMval[16];     

                  TL0=PWMval[17];

        }

        else if(PWMscan==10)                   //给一定低电平,将周期拉长

        {

                  PWM8=0;

                  TH0=0xFF;

                  TL0=0xd2;

                  PWMscan=0;

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

                  TR1  = 1;

        }

        PWMscan++;

}

void task01()

{

        if(PWMscan1==1)             //第10路PWM。

        {

                  PWM9=1;

                  TH1=PWMval[18];

                  TL1=PWMval[19];

        }

        else if(PWMscan1==2)     //第11路PWM。

        {

                  PWM9=0;

                  PWM10=1;

                  TH1=PWMval[20];

                  TL1=PWMval[21];

        }

        else if(PWMscan1==3)     //第12路PWM。

        {

                  PWM10=0;

                  PWM11=1;

                 TH1=PWMval[22];

                  TL1=PWMval[23];

        }

        else if(PWMscan1==4)     //第13路PWM。

        {

                  PWM11=0;

                  PWM12=1;

                  TH1=PWMval[24];

                  TL1=PWMval[25];

        }

        else if(PWMscan1==5)     //第14路PWM。

        {

                  PWM12=0;

                  PWM13=1;

                  TH1=PWMval[26];

                  TL1=PWMval[27];

        }

        else if(PWMscan1==6)     //第15路PWM。

        {

                  PWM13=0;

                  PWM14=1;

                  TH1=PWMval[28];

                  TL1=PWMval[29];

        }

        else if(PWMscan1==7)     //第16路PWM。

        {

                  PWM14=0;

                  PWM15=1;

                  TH1=PWMval[30];

                  TL1=PWMval[31];

        }

        else if(PWMscan1==8)     //第17路PWM。

        {

                  PWM15=0;

                  PWM16=1;

                  TH1=PWMval[32];

                  TL1=PWMval[33];

        }

        else if(PWMscan1==9)     //第18路PWM。

        {

                  PWM16=0;

                  PWM17=1;

                  TH1=PWMval[34];

                  TL1=PWMval[35];

        }

        else if(PWMscan1==10)     //给一定低电平,将周期拉长

        {

                  PWM17=0;

                  TH1=0xFf;//b1 //这是一个大概的值,由于每一组的PWMval的总和(PWMval中定时器的间隔的总和就是一个周期)不一致,

//所以会导致周期不一定是20ms,但大概可以控制在20ms左右,也是因为周期的不固定,所以才需要

                  TL1=0xd2;//e0 //调整每一个舵机的实际的占空比。

                  PWMscan1=0;

       

                  TR0  = 1;//开定时器0

                 TR1  = 0;//关定时器1

        }

        PWMscan1++;

}

void timer0()interrupt 1

{

         task00();//控制前9路PWM

}

void timer1()interrupt 3

{

        task01();//控制后9路PWM        

}


在实际过程中,或许是由于舵机的质量问题,又或者是其他问题,舵机的角度控制总是难以运用原理上的公式来控制角度,都是实际操作,手动调整高电平的宽度,当达到合适的值的时候,然后再把相应的代码记录下来。

单片机的高电平宽度是通过定时器的两个寄存器控制的,所以操作舵机的转动就变成操作定时器的寄存器,再具体一点就是要得到TH、TL两个值。(定时器高低位的差值对应高电平的宽度)

在代码上,在控制第几路舵机的时候,TH、TL的值已经定死了为哪一个PWMval[?],比如第18路:

TH1=PWMval[34];

  TL1=PWMval[35];

这将决定此时第18路舵机的转动角度是多少,那么怎么控制下一次该舵机的转动角度呢?答案很简单,就是把PWMval[34];PWMval[35];的值修改一下就可以了,其他的舵机同样是这个道理。所以,机器人的一个姿态就可以变为这样:机器人姿态→18路舵机的角度→18个TH、TL的值→一个36个元素的数组PWMval的值。

所以,一个动作姿态就可以用这样一个函数来确定:

void DZ(ucharPWM[])//动作

{

        uchar i;

        for(i=0;i<36;i++)

                  PWMval[i]=PWM[i];

}

明白了这个之后,就是对每一个姿态收集数据了,在制作过程,我是把TH和TL的两个值显示在数码管上,然后记录下来的。

后面又加入了蓝牙控制模块,超声波测距,发现51单片机的定时器不太够用,改成了52系列的单片机,还一个定时器即用蓝牙模块,又用超声波测距,现在想来真佩服自己。给出控制代码,大家自行研究:

//***************************中断初始化************************** 

void Init()

{

        TMOD |= 0x11;//定时器0、1      

        ET0 = 1;//使能定时器0中断

        TR0 = 1;//开启定时器0,定时器1中断在定时器0开始后才打开

        ET1   = 1;//使能定时器1中断

        IT1      = 0;//外部中断1,低电平触发 (边沿高变低)

        EX1  =   1;//开外部中断1

//定时器2用于波特率的产生

        SCON=0x50;

        PCON=0x00;

        RCAP2H=0xFF;

        RCAP2L=0xDC;//设置波特率为9600

        T2CON=0x34;//将定时器2设置为波特率发生器(接收和发送都用Timer2) //此处包括启动T2

        ES=1;         //串口中断

        EA      = 1;//开总中断

}

void timer0()interrupt 1

{

         task00();//控制前9路PWM

}

void timer1()interrupt 3

{

        task01();//控制后9路PWM        

}

void  serial() interrupt 4

{

        EA=0;                //其余中断全停

        if(RI)

        {      

                  RI=0;                   //清除串行接受标志位                 

                  flag=1;            

                  buf=SBUF;   //从串口缓冲区取得数据 (i-0x30)将ASCLL码转换成数字

                  switch(buf)

                  {

                           case 0x00:  DZCS=0x00;break;  //向前走

                           case 0x01:  DZCS=0x01;break;  //向后走

                           case 0x02:  DZCS=0x02;break;  //左转

                           case 0x03:  DZCS=0x03;break;  //右转

                           case 0x04:  DZCS=0x04;break;  //横着左

                           case 0x05:  DZCS=0x05;break;  //横着右

                           case 0x06:  DZCS=0x06;break;  //挥爪子

                           case 0x07:  sd++;break;         //减速,其实就是每个姿态中的延时不一样

                           case 0x08:  sd--;break;           //加速

                           case 0xff:   CSB=!CSB;break;  //启动关闭超声波壁障

                           default:   

                                    DZCS=0x11;break;  // 

                  }      

        }

        EA = 1;    //打开总中断

}

void start()// 超声波测距启动函数

{

        uchar i;

        Trig=1;

        for(i=0;i<20;i++)

        {

                  _nop_();

        }

        Trig=0;

}

void count()// 超声波测距函数

{

        unsigned int time,timeH,timeL;

        timeH=TH1;

        timeL=TL1;

        time=timeH*256+timeL;

        distance=time*1.7/100;

}

void Inter()interrupt 2//外部中断1在次完成测距以及相应的后续操作

{     

        EA =0;               

        ET0=0;                                   //关定时器中断0

        TH1=0;

        TL1=0;

        TR1  =1;                                //检测到距离开启定时器1

        while(!Echo);                //当echo为零时等待,中断flag跳出等待           

        TR1  =0;                  //关闭定时器1

        count();                        //计算距离

        if(((10<distance)&&(distance<30))||HZ)  //当距离小于5cm时,变换动作哦(在中断中变换平面感应

        {

                  DZCS=0x02;                         //向左

                  HZ=0;

        }

        if(distance<10)             //当距离小于10cm时,变换动作哦(在中断中变换曲面感应

        {

                  DZCS=0x01;                //后退

                  HZ=1;                           //后退后左转标志

        }

        if(distance>30)             //当距离小于40cm时,变换动作哦(在中断中变换

        {

                  DZCS=0x00;                         //向前

                  HZ=0;

        }

        TR1=1;

        ET0=1;

        EA = 1;

}

void main()

{

        Init();

        while(1)

        {

                  uchar DZCST;//,i;

                  if(CSB)

                           start();

                  if(DZCST!=DZCS)//动作发生改变,则回到平衡

                           DZ(PH1);

                  if(sd==0)

                           sd=1;

                  switch(DZCS)

                  {                         

                           case0x00:DZXQ(sd);break;

                           case0x01:DZXH(sd);break;

                           case0x02:DZXZ(sd);break;

                           case0x03:DZXY(sd);break;

                           case0x04:DZHZZ(sd);break;

                           case0x05:DZHZY(sd);break;

                           case0x06:DZZZ(sd);break;

                           default:

                                    DZ(PH1);           

                  }

                  DZCST=DZCS;

        }      

}

2019-01-13 19:15:51 qq_38844099 阅读数 291
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3419 人正在学习 去看看 朱有鹏

51单片机电机控制机器人,超声波HCSR04测距,LCD显示电机速度,距离仿真。

步进电机模块,电机驱动模块,HCSR04测距模块,LCD显示模块,按键控制模块等。
在这里插入图片描述
lcd1602与51单片机连接显示HCSR04测到的距离和电机转速。
在这里插入图片描述
uln2803作为电机驱动模块,电机为四相六线步进电机 。采用lm7805三端集成电路为电机提供稳定电源。
在这里插入图片描述
由于proteus7.8无hcsr04超声波仿真芯片,可自作器件,内部电路仅为几个与或门,简单实现仿真,
若要完整仿真HCSR04,内部电路可采用555时序电路实现,此处不作介绍。给Echo引脚加脉冲激励源简单实现,
改变脉冲的频率从而改变测量距离。

改变脉冲频率
在这里插入图片描述
独立按键实现电机正反转,加减速功能。
在这里插入图片描述
详细电路图及程序和相应源文件可下载,仅供学习。
https://download.csdn.net/download/qq_38844099/10914421

2008-12-03 15:36:00 yuedingy 阅读数 3856
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3419 人正在学习 去看看 朱有鹏

本课题研究的机器人工作在大约40 m深的浆液下,为了防止水煤浆由于长时间的存贮而沉淀,他能在按照预先规划的轨迹行走时完成搅拌功能。       

  在这种条件下,一个很重要的问题就是机器人定位功能的实现,用来实时了解其具体位置。本机器人定位系统采用多路超声波传感器测距,然后采用三点定位法,把测距信息转化为机器人的位置信息。超声波作为一种无接触检测方式,与激光、红外以及无线电测距相比,在水煤浆中可以比较容易地穿透水煤浆达到测距的目的,且精度较高。      

 l 超声波测距系统      

 1.1 超声波测距原理      

  超声波测距原理一般采用时间度量法,计算公式为:

  式中D(m)为超声波传播的距离,v(m/s)为超声波在介质中传播的速度,t(s)为超声波在介质中传播的时间。而超声波在介质中传播的速度由介质的性质和温度T(℃)决定,由此可得到水中超声波的波速为:

  1.2 超声波测距的硬件系统

  系统硬件框图如图1所示,其设计为分布式控制系统。在本系统中USR1为超声波发射传感器,USR2,USR3,USR4为接收传感器,他是型号为JSS-03的液下专用超声波传感器,该传感器既可做接收用同时也可做发射用,其灵敏度高,额定脉冲工作电压高,瞬时输出功率大。温度传感器选用DS18B20,该传感器具有单总线、抗干扰、测温范围宽(-55~+125℃)、适合远距离恶劣环境测温的特点。在本系统中使用的单片机(MCU0,MCU1,…MCU4)均选用51系列单片机AT89C52。

  当系统处于工作状态,由MCU0每隔3 s产生一个脉冲,信号经过放大激发信号发生器ST-3A,然后触发超声波发生器USR1;同时给MCU2,MCU3,MCU4的中断INT0一个低电平,使他们开始计时。当接收超声波传感器接收到发射超声波传感器发出的信号后,立即把产生的接收信号传给单片机,中间的信号调理过程为一级放大(放大100倍)、带通滤波、二级放大(放大50倍)、电压比较、光电隔离,其中电压比较的基准电压可调,当信号电压高于基准电压时使MCU的INT1中断。INT0中断和INT1中断的时间间隔即为发射与接收传感器间的时间,他存储在单片机固定的RAM中。而温度传感器DS18B20是分时完成对环境温度的测量的,采用严格的时序单片机进行双向通讯。单片机把温度信息存在他的固定RAM中。

  1.3 超声波测距的软件系统

  要完成对机器人的位置信息的测量就要求把存储在单片机RAM内的时间信息和温度信息采集到上位机中,然后把这些信息融合起来得到机器人的确切坐标。工控机与下位机采用串口通讯方式,通讯协议为MODBUS协议。同时上位机采用VC 6.0作为开发工具,工控机的软件程序采用模块化编程,程序主要由串口通讯模块、三点定位模块、数据库模块及界面模块组成,其循环通讯的流程如图2所示。

       2 实 验

       2.1 实验准备

       为了验证程序的可靠性和对比两种超声波发射传感器在定位过程中的效果,做了水下定位实验,该实验是在9 m×7 m的长方形水池中进行的,水深25 cm左右。在实验之前在水平面内建立直角坐标系,同时在r=3 300 mm的圆周上均匀放置三个超声波接收传感器,其坐标(单位:mm)分别为(3 300,0)、(-1 650,2 858)、(-1 650,2 858),在实验过程中超声波发射传感器在此圆周内移动。

       根据以前一系列的实验结果,在本次实验的软件系统中对测距程序按下式进行了修正:(单位:mm)

       2.2 实验结果

       (1)JSS-03型超声波发射传感器

       该传感器的最佳发射频率为10 kHz,发射面为一个平面,波束角为60°,其指向性很强,在此定位系统中,3个接收传感器都能够收到该发射传感器的信号,但在其波束角内的接收传感器接收的信号比其他两个强,这就影响了接收传感器触发时的灵敏性。

       如图3所示,中间的实线圆为经过非线性优化过的发射传感器的移动轨迹,半径为3 204 mm,这些定位点分散在轨迹圆的周围,外侧的虚线圆为偏离原点最远点所在的圆,内侧的虚线圆为距离原点最近的点所在的圆,最大误差为8.08%,这些误差主要来自于发射中心产生的误差和测距产生的误差。

  (2)LYF-20型圆周发射传感器    

  复制的最佳发射频率为22 kHz,发射面为圆柱面,他的优点就是对于三个接收传感器而言发射中心是固定的,并且他们接收的信号强弱一致,但他的指向性不强,由于信号分散,故其发射的信号弱于JSS-03型传感器。如图4所示。由于从发射源头就避免了发射中心产生的误差,所以他的定位精度较高,主要误差来自于测距误差,其优化后的轨迹圆半径为3 154 mm,最大误差为3.78%。在此可以看出,频率对超声波的测距是有很大影响的,频率越大,精度越高。

   3 结 语

  从实验结果看出,定位系统是可行的,有较高的可靠性,并且本系统的实时性可达1 s,其精度也可以达到我们预期的效果,但是硬件系统还有提升的空间。研究内容对水下机器人的定位,信号的采集,数据的远距离传输等都有参考价值。

2012-08-11 09:12:55 wgluser 阅读数 1405
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3419 人正在学习 去看看 朱有鹏

MCS-51单片机机器码


2019-12-30 10:48:05 qq_40911269 阅读数 41
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3419 人正在学习 去看看 朱有鹏

想直接下载代码或者查看详细文字/图片描述的请划到最底直接下载哦!

一、摘要
本设计通过arduino单片机和网上购买的机械臂零件设计一个手柄操控自学习机械臂模型,通过记录机械臂移动的位置进行重复的指定位置抓取放置操作,以简化更新机械臂数据或调试机械臂的过程。
报告通过对机械臂运动分析,和程序设计思路的叙述来对设计过程进行描述,比较详细展现构思过程和思考逻辑。
二、前言
本次设计实验使用arduino单片机进行设计,Arduino是一款便捷灵活、方便上手的开源电子原型平台。包含硬件(各种型号的Arduino板)和软件(Arduino IDE)。由一个欧洲开发团队于2005年冬季开发。本次设计使用的具体型号为uno r3 国产版本,Arduino Uno是一款基于ATmega328P的微控制器板。它有14个数字输入/输出引脚(其中6个可用作PWM输出),6个模拟输入,16MHz晶振时钟,USB连接,电源插孔,ICSP接头和复位按钮。只需要通过USB数据线连接电脑就能供电、程序下载和数据通讯。
通过机器人基础的课程学习,我了解到关于机械臂一些跨学科的基础,因此想通过机械臂与单片机的结合进行一次实验设计,以加深对机械臂的理解,并且运用机械臂。因此,自学习机械臂的想法油然而生,自学习主要是针对机器的记录与学习提出的说法。成熟的自学习系统(self-learningsystem)能模仿生物学习功能,它能在系统运行过程中通过评估已有行为的正确性或优良度,自动修改系统结构或参数以改进自身品质的系统。
本次设计打算利用代码的记录功能简单的模拟机械臂的自学习功能,因此设计比较简单,用途不具备广泛性。但由于arduino的优势和开源,这也会是一个比较容易发展的系统。最主要的是,这次设计能够让我初步理解机械臂的运动,走出课堂学习,进行实践。
三、硬件系统搭建与组装
机械臂的套件购买于淘宝网站,材料是亚克力塑料,使用了四个舵机,所以是一个四自由度的机械臂。以下展示组装过程:

(1)舵机复位
购买回来的舵机轮轴角度不一样,需要手动进行调节。首先向左旋转到尽头,然后横向安装如图扇翼,旋转到90°既垂直位置,调节完毕。
(2)底盘舵机的安装
底盘负责带动机械臂上半部分的转向,舵机跟地面方向平行,如图所示。
底盘的拼接零件 大,复杂度小,因此过程很快。
(3)后臂的安装
后臂驱动舵机和前臂驱动舵机如图所示在机械臂的两侧,方向垂直于水平面,用于带动机械臂垂直方向的运动。
(4)连接前臂舵机
前臂左边的杆跟左边的舵机进行连接,旋转点落在后臂顶端,舵机通过后臂与结点连杆对前臂进行带动控制。
(5)安装机械爪
机械爪由一个舵机控制,舵机通过齿轮结构带动爪子张开闭合,安装过程需要注意螺丝长度与规格,并且不能上太紧,同时检测舵机角度是否已经调到合适位置。预计爪子闭合舵机角度90°,爪子张开,舵机角度0°。
(6)拼接前臂、后臂和机械爪
连接舵机上半身的三个结构,形成平面上的3自由度机械臂,旋转舵机,查看是否出现阻塞问题或部位太紧的问题。
(7)拼接机械臂与底盘
把舵机上半部分连接底盘,形成3维4自由度的机械臂,同时装上负责驱动的arduino板,扩展版和电池。
至此,机械臂硬件组装完成。
五、简单自学习系统开发设计
(1)系统设计目标
简单自学习系统要求机械臂能够记录夹取物体的位置和放置物体的位置,并且根据记录的两个位置完成夹取和放置工作。假设接近地面的位置会有其他物体阻挡,应当尽量避免与这些物体发生碰撞。本系统假设地面所处平面上方基本没有障碍,机械臂抬高后可以无障碍运动。
完成自学习功能,首先要让机械臂完成两点位置的记录。然后根据位置开启自动移动功能。完成抓取与放置流程。这个过程需要规划路线,尽量避免贴着低水平面移动机械臂,因为这样会发生触碰目标物体或者别的障碍物的风险。设计机械臂按照底盘、前臂、后臂、爪子的顺序进行移动,这样可以避免与路径上的物体发生碰撞。同时在移动之前再次抬高机械臂(后臂、前臂的顺序),避免与低水平面物体发生碰撞。如图ABC路径为机械臂移动的大致路径。

设计过程考虑位置记录方法,考虑以机械臂底盘为O点建立坐标系,但是空间坐标计算过于复杂,时间有限无法实现,因此直接采用舵机角度的位置记录方法,例如旋转到左边30°,后臂垂直位置向前倾45°,前臂左向下60°抓取一个物体,则如图所示(2D平面,地盘旋转角度没有画出,只分析了机械臂上半身的运动),记录(底盘舵机120°,后臂舵机135°前臂舵机)。
(3)简易自学习系统存储数据结构
记录机械臂4个舵机的各种状态,需要一个大小为4的数组,每个舵机需要记录旋转范围(最小,最大),记录当前角度,记录初始状态角度,记录舵机当前运行方向至少5个数据量,因此需要一个4X5大小的数组对舵机的数据进行存储。
简易自学习需要记录机械臂的抓取位置和放置位置,既记录两次4个舵机的角度,需要一个2X4的数组。
考虑到爪子只是一开一合(0-90),因此可以适当去掉关于爪子角度的存储。
(4)机械臂控制移动实现设计
前期系统采用手柄移动控制机械臂运作,手柄由左摇杆和右摇杆组成,左遥感左右控制底盘左右移动,上下控制后臂上下移动,右摇杆左右控制爪子张开闭合,上下控制前臂上下移动。前臂的上下移动对应舵机角度的增加减少,前臂舵机移动角度范围为(0-120),后臂上下移动对应舵机角度的增加减少,前臂舵机移动角度范围为(0-100),底盘左右移动对应舵机角度的增加减少,前臂舵机移动角度范围为(0-180),爪子舵机移动范围(0-90),张开对应角度减少,闭合对应角度增加。
进行手柄控制移动时,首先检测当前时刻下手柄按键,并且以此更改各个舵机所记录的方向(可以是静止)。然后根据舵机记录的移动方向逐个移动舵机,每次移动2°,大概没几十毫秒检测并移动一次,在手柄控制模式达到所有自由度同时控制移动的效果。
(5)简易学习后自移动实现设计
在手柄控制模式下,第一次按下左遥感记录第一个位置,并认定为抓取位置,第二次按下记录为第二个位置,认定为放置位置。
按下第二次左摇杆后进入自动模式,会按照上述设计的机械臂移动顺序自动重复进行抓取和放置,代码设计只需要for循环按照顺序进行并移动到记录位置即可。移动过程的程序设计非常的简介且死板,具体可查看附件处代码文件。
自动过程中手柄动作无效,除了右摇杆的按下设计为外部中断,该中断处理函数设置标志位让遥感执行完本次自动抓取放置后停止操作变回手柄控制模式。
八、附录
(1)CAD绘图文件
CAD文件夹中的绘图,需要用CAD软件打开

(2)arduino代码文件
Arm文件夹中的是VS2017项目,可以用VS2017打开,其中Arm.ino是arduino专用的代码文件,可以用写代码的软件打开。

(3)机械臂演示视频
演示机械臂操作流程的录制视频。

附件下载:

百度网盘下载 提取码:c2q3

服务机器人架构

阅读数 165

移动机器人入门篇

阅读数 24896

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