基于51单片机的六足仿生机器人

发布者:MysticalGarden最新更新时间:2017-04-04 来源: 21ic关键字:51单片机  六足仿生机器人 手机看文章 扫描二维码
随时随地手机看文章

一、整体框架:

(1)设计功能:

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

②可自动避障;

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

(2)功能框架:

 

1.png

 

(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)仿真原理图:

 

六足机器人.png

 

(2)PCB制作:

 

3.png

 

(3)硬件搭建:

《a》肢体制作:

材料:PVC线槽,PVC板

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

 

4.png

 

②舵机改造:

 

5.png

 

③整体:

 

6.png

 

四、调试以及问题解决:

①结构问题:

我们认为,整体的外形结构是决定作品成败的关键。经过多种材料的试验,最终我们选择了容易裁剪、硬度基本满足的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;

}

}


关键字:51单片机  六足仿生机器人 引用地址:基于51单片机的六足仿生机器人

上一篇:如何用C51实现单片机和PLC之间通讯的实例
下一篇:基于单片机的温度传感器设计

推荐阅读最新更新时间:2024-03-16 15:34

汇编的51单片机的跑马灯
话不多说,先上程序 ORG 0000H MAIN:MOV P1,#0O LCALL DELAY MOV A,#0FEH SETB C TO: MOV P1,A LCALL DELAY LCALL DELAY RLC A JC TO MOV P1,A LCALL DELAY LCALL DELAY TO1: RRC A MOV P1,A LCALL DELAY LCALL DELAY JC TO1 AJMP TO DELAY:MOV R2,#0FEH TC1:MOV R3,#0FEH TC2:DJNZ R3,TC2 DJNZ R2,TC1 RET END 这个程序的目的是使8个LED循环点亮,还有一个状态是都不亮,我的LED是搭在P
[单片机]
基于51单片机的智能水表
一.硬件方案 本设计主要以51单片机作为主控处理器的智能水表,该水表能够记录总的用水量和单次用水量,当用水量超出设定值时系统发出声光报警提醒,水量报警值能够通过按键进行自行设置,并且存储于AT24C02中,并且可以测量水流速度。测量的结果采用LCD1602液晶显示平显示出来。 主要由51单片机+最小系统+LCD1602液晶显示模块+蜂鸣器模块+LED指示灯模块+继电器驱动模块+按键电路+AT24C02芯片模块+水泵驱动电路;如图: 二.设计功能 (1)采用LCD1602液晶显示屏实时显示瞬时水流速、总用水量、本次用水量、水流量限值; (2)可通过按键设置水流量限值,当本次用水量超过水流量限值时系统发出声光报警提醒; (3)
[单片机]
基于<font color='red'>51单片机</font>的智能水表
51单片机定时/计数器T0、T1的组成与功能简介
1、 主体结构 1)16位加法 计数器 ,由高8位(THi)和低8位(TLi)SFR组成。 2)在用作计数器时,引脚P3。4(T0)和P3。5(T1)分别是两个计数器的外部脉冲输入端。 3)引脚P3。2(/INT0)和P3。3(/INT1)在位GATE=1时可用作T0、T1的门控信号。 4)SFR-TCON和TMOD控制T0和T1的运行状态和工作方式。 2、 控制寄存器TCON(地址88H) D7~D0:TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0 高4位与定时/计数器有关,低4位用于控制外部中断。 TFi-定时/计数器溢出标志位;计数溢出时,硬件自动置1,在中断允许条件下,是向CPU请求中断的
[单片机]
C51单片机与PC串口通信的单片机部分程序
注意波特率是9600 功能:电脑通过串口给单片机发一个字节,单片机收到后又给电脑发回去 、#include #define uchar unsigned char #define uint unsigned int uint temp; bit flag; void init_ser1(); main() { init_ser1(); while(1) { if(RI==1) { P1=SBUF; RI=0; } if(flag==1) { ES=0;//暂时关闭接收 flag=0; SBUF=temp; while(!TI);//等待发送完毕 TI=0; ES=1; } } } void sel() interrup
[单片机]
利用51单片机制作廉价盒仔机器人
一、盒仔机器人 BOXZ,昵称盒仔,是一款开源的互动娱乐平台!百度一下,有很多盒仔的制作教程,基本都是用arduino制作完成的。假期没事,带着宝宝们用51制作了一个廉价的BOXZ。先上张图: 从图上不难看出,为了宝宝们易于接受,我把盒仔的手机摇控改成了用线控的方法,做了一个简易的摇控器。 二、材料准备 以上原器件,某宝网上都有。另外,制作中需要用到壁纸刀、电钻、钢尺、胶水等工具。 三、外壳及皮肤制作 1、外壳的制作 (1)下载模板 下载地址:https://yunpan.cn/crIvLu9R8xVyI 访问密码 9fe1 从上面的下载地址下载模板,打印出来,然后将硬纸板切割成图
[单片机]
利用<font color='red'>51单片机</font>制作廉价盒仔机器人
嵌入式学习笔记3——51单片机之闪烁灯设计
1. 电路图 一个二极管点亮一般需流经的电流值为3mA~10mA,二极管两边的压降为1.6V~1.7V。 2. 点亮二极管: (1)位操作: sbit led0=P0^0; led0=0;//单个位的赋值 (2)总线操作: P0=0xfe;//11111110 整个8位引脚一起赋值 3. 软件仿真: 点工具栏上d图标,双击某行即设置断点;若要用软件仿真查看一条语句的执行时间,一定要在Options for target - target- Xtal(MHz)中将晶振频率设成与单片机的频率相同。(机器周期=12*晶振周期=12*系统时钟周期, 晶振频率越高,单片 机执行速度
[单片机]
嵌入式学习笔记3——<font color='red'>51单片机</font>之闪烁灯设计
51单片机 I2C AT24C02
I2C协议在项目开发中使用很常见,很多存储芯片使用I2C接口。由于51单片机没有I2C接口,这里使用IO口模拟I2C通讯协议,来完成I2C芯片驱动。使用的I2C芯片为AT24C02。 原理图如下: 代码如下: //程序功能:计时器每一秒向AT24C02保持数据,同时数码管显示,重启之后读取出数据接着计时,100S循环 //程序问题:无法写入 #include #define uint unsigned int #define uchar unsigned char //变量定义 uint timer_flag; //用于判断定时器T0方式一是否计满1s u
[单片机]
TMS320VC5402与51单片机的接口设计
  TMS320VC5402(VC5402)是德州仪器公司推出的具有较高性价比的定点数字信号处理器。VC5402增强外设由软件等待状态发生器、锁相环时钟发生器、6通道直接存储器访问(DMA)控制器、增强型8位并行主机接口(HPI)等组成。两个可编程的多通道缓冲串口(McBSP)能够全双工、快速地与其他同步串口进行数据交换,硬件连接简单,串口的工作模式和传送数据的格式可通过编程实现。DSP和单片机之间的通信一般利用双口RAM,通过串口或DSP的HPI接口实现。   利用双口RAM实现   CY7C026是CYPRESS公司生产的16k×16B高速双口静态RAM,存取速度小于25ns。他具有真正的双端口,可以同时进行数据存取,两个端
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved