资源描述
机电综合实验
步行机器人
机械与运载工程学院机自1103班
实验者:陈正敏
学 号:20110401310
二零一四年12月16日
一、认识龙人步行者
尽管它看起来很简单,但确实这种使用两个伺服电机实现两足移动的步行机器人比两轮机器人复杂的得多。它通过机械机构和 C 语言指令控制来实现行走。实际上,步行机器人可使用许多传感器作为反馈元件,其中包括能检测到一定距离内是否有物体的红外线发射器及红外线检测器,缓冲传感器(闪光脚趾)和用以测量倾斜参数的加速度计。(注意,闪光脚趾和加速度计不是步行机器人的标准配件,用户需另外采购。)如果你耐心调节步行机器人的硬件和软件,步行机器人可以完成轮式机器人所能完成的所有动作。步行机器人不仅比轮式机器人有趣很多,而且通过学习步行机器人行走控制,也能更加熟练的掌握控制程序的编写。
步行机器人的编程将会引导你学会如何设计C语言程序,包括如何使用常量和变量、数组、程序的指针,函数以及存储数据的EEPROM(电可擦除只读存储器)。程序设计是否良好的其中一个标准是,在对一些机械装置调整后,不需重新编写整个程序,只需对程序作简单修改就能实现所要求的功能,即我们通常所说的可维护性。步行机器人的运动由两个伺服电机控制(这有点类似于操纵飞机的螺旋桨)。两个伺服电机有各自的作用, 顶部的伺服电机控制机器人的重心位置在1.5CM的范围内摆动,而底部的伺服电机控制机器人的前后行走。步行机器人的腿和脚踝之间采用了一个简单的平行连接件,确保双脚能够平行的站在地面上。两条腿都连接在同一个电机上,所以一只脚向前移动时,另一只脚就会向后移动。单独控制一个电动机,步行机器人能够完成前进、后退、左转、右转等动作。综合控制步行机器人两个伺服电机的运动,能实现更加协调、更加平稳的行走。
步行机器人的伺服电机和传感器由一个 AVR 单片机来控制。 AVR 单片机是工程中运用很广泛的一种芯片,它提供了较大的程序空间、存储空间供机器人使用,并且处理速度快比 51 单片机快 1 倍以上。
二、实验要求
1、了解和掌握自动化系统集成的一般过程和方法,同学们在课程中逐步掌握使用、调试、维护自动化系统方面的能力。
2、了解AT89S52芯片的主要性能,学会分析和使用常用电子芯片、电子元件和仪器设备的能力。
3、掌握机器人机械工作方式,红外避障工作原理,掌握机器人尾随行走所需的闭环控制算法,学会将机械运动和自动化(利用软、硬件)紧密结合。
4、学会查阅科技参考资料,根据自己的设计任务和设计方法编制程序、调试程序软、硬件联机调试,达到设计要求收集实验数据,并对结论进行分析,写好实验报告。
三、实验原理
1)时间测量和电压
在这本学习指南中,我们将多次提到几个重要的时间单位秒(s),毫秒(ms),
微秒(us)。通常,我们将秒用小写字母“s ”表示,所以,可以将1秒写成1s。
毫秒则用“ms”表示,1毫秒等于1/1000秒;微秒用“us”表示,1微秒等于
1/1000000秒,从毫秒、微秒与秒的关系你是否已经推出:1毫秒=1000微秒。在
2)运动原理
从AVR CPU中发送出来的一组控制伺服电机的控制信号被称为“脉冲序列”,
如图2-1所示。AVR CPU能够通过编程产生这样的信号波形,而且还能用它任意的
一个I/O口进行信号的输出。在下面的例子中,AVR CPU向 PC2(跨步伺服电机)
和PC3(倾斜伺服电机)各发送一个1500微秒的脉冲信号。在1500微秒的高电平
送出后,AVR CPU继续发送一个25毫秒的低电平给该引脚,产生一组脉冲序列
如图所示,这个脉冲序列由1500微秒的高电平和25毫秒的低电平组成。伺服
电机的控制主要由1500微秒的高电平来控制,我们通常称这一段时间为脉宽。脉
冲信号由低电平到高电平这一变化过程我们称为上升沿。同理,由高电平到低电
平的变化我们称为下降沿。
步行机器人的行走的分4个步骤:
a. 向一边倾斜
b. 移动被提起的那只腿
c. 向另一边倾斜
d. 移动被提起的那只腿
3)滑动式转弯
步行机器人有点不大灵活。它只能向前或向后移动它的步子,不能相对它
的身体旋转步子。但这并没有阻碍他的转弯能力,当走直线时,步行机器人和
人走直线是相似的,而转弯就明显不同。步行机器人转弯和人最接近的是就象
人穿着平底鞋站在冰面上转弯的情形。
人站在冰上右转弯的过程是相当简单的,把你的左脚向前迈一步放在地面
上,然后把左脚向后滑行回收,这样你就可以以右脚为轴向右转了。如果冰是
湿滑的话可能要多次转动才能转过 90 度。同样要左转就滑行右脚。
标准的步行机器人在冰上转弯的效果并不理想,但利用这种原理,在其它
表面上可以转得很好。步行机器人的平滑金属脚提供了一个光滑的表面。当它
站在能提供摩擦力的表面上来做转弯,效果会更加好。如果走的平面太光滑,
那么对步行机器人的脚掌进行一些处理以便提供更大的摩擦力。最典型的做法
四、相关资料及问题
(一)、PWM 直流电机调速原理:通过AVR 单片机ATmega8直接产生PWM 波形经过电机驱动芯片L298 分别驱动两个直流电机,PWM 将占空比不同的脉冲变成不同的电压驱动直流电机转动从而得到不同的转速,且实现电机启动、停止、正反转等功能。
(二)、直流电机控制模块
1、控制板的使用说明
#define POSITIVE_DIR 1 //正向旋转
#define NEGATIVE_DIR 0 //反向旋转
#define LEFT_MOTOR 0 //左电机
#define RIGHT_MOTOR 1 //右电机
#define NOT_STOP 0 //不停止
#define STOP 1 //停止
#define BY_10MS 0 //时间控制系数 10毫秒倍率
#define BY_100MS 1 //100毫秒倍率
#define BY_1000MS 2 //1000毫秒倍率
#define NOT_CONTROL_TIME 3 //不控制时间
2、通过TTL串口驱动PWM直流电机驱动模块
void write_pwm(unsigned char bDirection, unsigned char bSide, unsigned char bStop, unsigned char TimeFactor, unsigned char Speed, unsigned char Time)
{
unsigned char Command;
bSide = bSide << 1;
bStop = bStop << 2;
TimeFactor = TimeFactor << 3;
Command = bDirection | bSide | bStop | TimeFactor; //组合命令字节
soft_send_enable (); //允许软串口发送
EA=1;
rs_send_byte(0xaa); //发送控制命令的头部,恒为0xaa
rs_send_byte(Command); //发送命令字节,想要了解命令格式
rs_send_byte(Speed); //发送速度描述字节,0~255
rs_send_byte(Time); //发送时间倍率,0~255
rs_send_byte(0xbb); //发送控制命令的尾部,恒为0xbb
while(rs_f_TI==0); //等待所有的命令发出完毕
EA=0;
}
3、几个基本函数
驱动电机后退函数
原理:左电机正转,右电机反转,以同样的速度旋转,完成后退动作
参数:Speed:速度系数(0~255);TimeFactor:时间系数(X10ms,X100ms,X1000ms);Seconds:时间倍率(0~255);时间倍率*时间系数=实际时间
void Backward(unsigned char Speed, unsigned char TimeFactor, unsigned char Seconds)
{
write_pwm(POSITIVE_DIR,LEFT_MOTOR,NOT_STOP,TimeFactor,Speed,Seconds);
write_pwm(NEGATIVE_DIR,RIGHT_MOTOR,NOT_STOP,TimeFactor,Speed,Seconds);
}
驱动电机右转函数
原理:左右电机正转,以不一样的速度旋转,完成右转动作
参数:Speed:速度系数(0~255);TimeFactor:时间系数(X10ms,X100ms,X1000ms);Seconds:时间倍率(0~255);时间倍率*时间系数=实际时间
void Right(unsigned char Speed, unsigned char TimeFactor, unsigned char Seconds)
{
write_pwm(POSITIVE_DIR,LEFT_MOTOR,NOT_STOP,TimeFactor,Speed,Seconds);
write_pwm(POSITIVE_DIR,RIGHT_MOTOR,NOT_STOP,TimeFactor,Speed,Seconds);
}
驱动电机左转函数
原理:左右电机反转,以不一样的速度旋转,完成左转动作
参数:Speed:速度系数(0~255);TimeFactor:时间系数(X10ms,X100ms,X1000ms);Seconds:时间倍率(0~255);时间倍率*时间系数=实际时间
void Left(unsigned char Speed, unsigned char TimeFactor, unsigned char Seconds)
{
write_pwm(NEGATIVE_DIR,LEFT_MOTOR,NOT_STOP,TimeFactor,Speed,Seconds);
write_pwm(NEGATIVE_DIR,RIGHT_MOTOR,NOT_STOP,TimeFactor,Speed,Seconds);
}
驱动电机前进函数
原理:左电机反转,右电机正转,以同样的速度旋转,完成后退动作
参数:Speed:速度系数(0~255);TimeFactor:时间系数(X10ms,X100ms,X1000ms);Seconds:时间倍率(0~255);时间倍率*时间系数=实际时间
void Forward(unsigned char Speed, unsigned char TimeFactor, unsigned char Seconds)
{
write_pwm(NEGATIVE_DIR,LEFT_MOTOR,NOT_STOP,TimeFactor,Speed,Seconds);
write_pwm(POSITIVE_DIR,RIGHT_MOTOR,NOT_STOP,TimeFactor,Speed,Seconds);
}
(三)、头文件及PWM_Init()函数说明
uart.h:硬串口的相关程序。包含该文件后,在程序中调用uart_Init()函数,即可完硬串口的初始化。
soft_rs232.h:TTL-RS232的实现程序。在该文件中,可修改TTL-RS232的通信波特率以及输出端口。如果在设置的TTL-RS232数据输出端口外接一个RS232电平转换芯片并搭载DB9串口接口,这样相当于构建了C51平台上的第二个串口。该程序构建的串口为单工串口。
Movement.h:该文件提供了龙人贝塔的运动控制函数的范例。在包含该文件之前,请包含BetaRobot.h文件。否则,在编译程序的时候会出现错误。
PWM_Init()函数的作用是为初始化第一层与第二层之间的TTL串口连接。其中TTL串口的数据输出口定义为P1.0口,在程序设计的过程中,请回避该端口,避免引起机器人运动控制的错误。在KEIL工程中,如果要使用到机器人的运动控制部分,那么在主程序的开头部分,就必须首先执行该函数,进行TTL串口初始化。
五、步行机器人走“日”字
#include<WalkingRobot.h>
#include<uart.h>
#define uint16_t unsigned int
#define StrideServo P1_0 //stride servo
#define TiltServo P1_1 //Tilt servo
#define MoveDelay 15 //in ms time
#define TiltStep 25 //step size
#define StrideStep 25 //step size
#define RightTilt 1200 //tilt limits
#define CenterTilt 1500
#define LeftTilt 1800
#define RightStride 1800 //stride limits
#define CenterStride 1500
#define LeftStride 1200
//movement state numbers:
#define TL 0 //representation of tiltleft
#define TC 1 //representation of tiltcenter
#define TR 2 //representation of tiltright
#define SL 3 //representation of strideleft
#define SC 4 //representation of stridecenter
#define SR 5 //representation of strideright
#define xx 255 //end representation
int code WalkForward[5]={TR,SL,TL,SR,xx}; //state table
int code WalkBackward[5]={TR,SR,TL,SL,xx};
int code TurnLeft[5]={TL,SR,TC,SL,xx};
int code WideTurnLeft[9]={TL,SR,TC,SL,TR,SL,TL,SR,xx};
int code TurnRight[5]={TR,SL,TC,SR,xx};
int code PivotRight[9]={TR,SL,TC,SR,TL,SL,TC,SR,xx};
//--------------------[variables]---------------------------------------------
int MoveLoop; //loop times of repeat movement
uint16_t Pulses; //pulses variable
uint16_t CurrentTilt; //
uint16_t CurrentStride;
uint16_t NewValue;
int *Mx; //state table index
//--------------------[movement routines]---------------------------------------------
void MovementTilt(void) //tilt
{
int step;
Pulses= CurrentTilt;
if(Pulses>NewValue)
step=-TiltStep;
else
step=TiltStep;
while(Pulses!=NewValue)
{
TiltServo=1;
delay_nus(Pulses);
TiltServo=0;
StrideServo=1;
delay_nus(CurrentStride);
StrideServo=0;
delay_nms(MoveDelay);
Pulses=Pulses+step;
}
CurrentTilt=NewValue;
}
void MovementStride(void) //stide
{
int step;
Pulses= CurrentStride;
if(Pulses>NewValue)
step=-StrideStep;
else
step=StrideStep;
while(Pulses!=NewValue)
{
TiltServo=1;
delay_nus(CurrentTilt);
TiltServo=0;
StrideServo=1;
delay_nus(Pulses);
StrideServo=0;
delay_nms(MoveDelay);
Pulses=Pulses+step;
}
CurrentStride=NewValue;
}
//--------------------[subroutines]---------------------------------------------
void ResetCC(void) //move initial
{
CurrentTilt=CenterTilt;
CurrentStride=CenterStride;
for( Pulses=0;Pulses<=10;Pulses=Pulses+StrideStep)
{
TiltServo=1;
delay_nus(CenterTilt);
TiltServo=0;
StrideServo=1;
delay_nus(CenterStride);
StrideServo=0;
delay_nms(MoveDelay);
}
}
void Movement(void) //move by data table referenced by Mx
{
while(*Mx != xx)
{
switch(*Mx) //比3小,执行MovementTilt()
{
case 0:
{NewValue=LeftTilt;
MovementTilt();
break;}
case 1:
{NewValue=CenterTilt;
MovementTilt();
break;}
case 2:
{NewValue=RightTilt;
MovementTilt();
break;}
case 3:
{NewValue=LeftStride;
MovementStride();
break;}
case 4:{NewValue=CenterStride;
MovementStride();
break;}
case 5:
{NewValue=RightStride;
MovementStride();
break;}
}
Mx++; //INPUT;Mx=table index ; END:Mx=xx
}
}
//--------------------------------------[Main]--------------------------------------
int main(void)
{
uart_Init();
printf("Program started!\r\n");
ResetCC() ;
for(MoveLoop=1;MoveLoop<=10;MoveLoop++) // WalkForward
{
Mx=WalkForward;
Movement();
}
for(MoveLoop=1;MoveLoop<=7;MoveLoop++) //turn right
{
Mx=TurnRight;
Movement();
}
for(MoveLoop=1;MoveLoop<=5;MoveLoop++) // WalkForward
{
Mx=WalkForward;
Movement();
}
for(MoveLoop=1;MoveLoop<=7;MoveLoop++) //turn right
{
Mx=TurnRight;
Movement();
}
for(MoveLoop=1;MoveLoop<=10;MoveLoop++) // WalkForward
{
Mx=WalkForward;
Movement();
}
for(MoveLoop=1;MoveLoop<=7;MoveLoop++) //turn right
{
Mx=TurnRight;
Movement();
}
for(MoveLoop=1;MoveLoop<=5;MoveLoop++) // WalkForward
{
Mx=WalkForward;
Movement();
}
for(MoveLoop=1;MoveLoop<=7;MoveLoop++) //turn right
{
Mx=TurnRight;
Movement();
}
for(MoveLoop=1;MoveLoop<=5;MoveLoop++) // WalkForward
{
Mx=WalkForward;
Movement();
}
for(MoveLoop=1;MoveLoop<=7;MoveLoop++) //turn right
{
Mx=TurnRight;
Movement();
}
for(MoveLoop=1;MoveLoop<=5;MoveLoop++) // WalkForward
{
Mx=WalkForward;
Movement();
}
Mx=FinishForward; //end
Movement();
}五、心得体会
通过这次对于机电综合实验的学习,从中获益良多。首先让我对机电这门课程有了更加深入的了解,机械的自动化才是机械的最终走向,随着几点这门学科越来越发展,他的研究领域将会变得更加广泛,成果也将越来越多的应用于人们的生产生活实践中。同时通过这次实践我也更加体会到了团队协作的重要性,在未来的工作学习中我们也将会碰到越来越多需要团队协作才能更好完成的事情,所以团队的重要性是不言而喻的,我们要不断的从团队中学习,更加的要把自己融入团队之中,只有这样我们才能不断进步。
参考文献
《步行机器人与高级 C 程序设计》秦志强
《C51单片机应用与C语言程序设计》秦志强,电子工业出版社;
展开阅读全文