四足机器人设计 Microsoft Word 文档
四足机器人设计
摘要:本文介绍了四足机器人(walking dog)的设计过程,其中包括控制系统软硬件的设计、传感器的应用以及机器人步态的规划。
四足机器人设计
摘要:本文介绍了四足机器人(walking dog)的设计过程,其中包括控制系统软硬件的设计、传感器的应用以及机器人步态的规划。
一、本体设计:
walking dog的单腿设置髋关节和踝关节两自由度,能在一个平面内自由运动(见图1.1)。采用舵机作为机器人的关节驱动器,其单腿结构图见(图1.2)。为了便于步态规划,设计上下肢L1、L2长均为 65mm 。四肢间用铝合金框架连接,完成后照片见(图1.3)。walking dog 的每只脚底均有一个光电传感器,能有效检测脚底环境的变化。walking dog的头部为一个舵机,携带光电反射式传感器,能探测前方180度75cm 内的障碍物。
图1.3:完成后照片
二、控制系统设计
为了使机器人能灵活地搭载各种传感器以及实现不同的步态,将底层驱动单元与上层步态算法平台分开。因为walking dog的各关节均为舵机,特设计了16路舵机驱动器作为底层驱动单元,用来驱动机器人全身各关节。并设计了上层算法平台,将各关节参数通过UART 实时地发送到底层驱动单元。图2.1为系统框图。
1、底层驱动单元设计
图2.2给出了舵机的工作原理框图,电动机驱动减速齿轮组, 并带动一个线性的电位器作位置检测, 控制电路将反馈电压与输入的控制脉冲信号作比较, 产生偏差并驱动直流电动机正向或反向转动, 使齿轮组的输出位置与期望值相符。
针对舵机这一特性,设计底层驱动器的系统结构图见图2.3。Mage8的16位定时器分时产生16次定时中断,中断子程序产生移位脉冲,通过4N25光偶隔离输入到移位寄存器,实现各路PWM 信号高电平部分的分时产生。 图2.4为定时产生脉冲的中断处理流程,图
2.5例举了产生4路PWM 信号的波形图。实际电路原理图见附录1。
图2.5:产生4路PWM 的波形信号 图2.4:定时中断服务流程
2、算法平台的设计
步态机器人要求对各个关节实施快速准确的位置控制,因此对控制系统提出了比较高的要求:
1、具有大量数据存储能力用来存储大量的步态数据。
2、实时地采集、处理传感器的数据,以便在控制系统的信号综合中使用。
3、具有良好的控制结构和接口,便于高层控制软件的开发。
4、有一定的预留接口、良好的兼容性和扩展性,以便进行功能扩展和二次开发
根据以上要求,采用ATmega16作为控制核心,将规划好的步态参数存入单片机,单片机根据定时器产生的时钟将相应关节数据发送到底层驱动单元。同时单片机通过传感器返回的信号感知周围环境,并及时对运动状态进行调整。
三、步态参数化设计
1、离线轨迹规划
为了使机器人行走平缓,要求足底轨迹有二阶光滑度,即有二阶连续导数。数学上的三次样条插值曲线即可满足上述条件。
设步长 =40,摆动腿离地最高H=20,可求得:踝关节的轨迹函数
由踝关节的轨迹函数可得踝关节关于时间的函数:
其中: 为步长
髋关节关于时间的函数:
Hk 为髋关节离地高度,取122.6
用MATLAB 仿真得到:
由以上仿真结果可知,在行走过程中机器人的踝关节轨迹、踝关节轨迹的一阶导数
和踝关节轨迹的二阶导数都是连续的。而且摆动腿着地时的速度为零,大大减小了冲击,保证了机器人行走的稳定性。
根据上述髋关节和踝关节关于时间的轨迹函数,可求得各关节角度关于时间的函数:
2、步序规划
目前主要有两类步态机器人的稳定性:静态稳定性和动态稳定性。静态稳定性忽略机器人的动态性能,采用重心(COG)作为稳定性标准,适用于移动较慢的机器人。而动态稳定性一般采用零力矩点(ZMP)作为稳定性判定标准,即考虑重力、惯性力及地面反力三者合力矢的延长线与地面的交点。在对角小跑(Trot )、溜蹄(Pace )、跳跃(bounding )等有较多应用。由于舵机性能及机械加工精度等方面的限制,WALKING DOG 采用静态稳定性作为约束步态的条件。
静态稳定性约束的步态任一时刻至少应有3条腿与地面接触支撑机体,且机体的中心必须落在3足支撑点构成的三角形区域内,据此设计步态图如下:
实验结果表明这种步序能使机器人连续稳定地行走。
四、结论
采用模块化设计的方法设计了四足机器人,使其控制简便灵活,可升级性强。并用步态规划的方法使机器人能稳定连续地行走,并对环境作出简单的感知与反应。通过实验发现机器人实际行走轨迹与规划的轨迹有较大差别,这对行走的稳定性和速度都造成了较大影响。
WALKING DOG 参数计算
#include "ad.h"
static unsigned int g_aAdValue[8];
void ad_init(void)
{
// ADMUX=(1// ADCSRA=(1}
unsigned int ad(unsigned char ad_x)
{
unsigned char i;
unsigned int ret;
unsigned char max_id,min_id,max_value,min_value;
switch(ad_x)
{
case 0: ADMUX=0x40;break;
case 1: ADMUX=0x41;break;
case 2: ADMUX=0x42;break;
case 3: ADMUX=0x43;break;
}
// ADMUX=0xc1; //内部2.56V 参考电压,0 通道
ADCSRA=_BV(ADEN); //使能ADC ,单次转换模式
for(i=0;i
{
ADCSRA|=_BV(ADSC);
_delay_loop_1(60);
while(ADCSRA&_BV(ADSC))
_delay_loop_1(60);
ret=ADCL;
ret|=(unsigned int)(ADCH
g_aAdValue[i]=ret;
}
ret=0;
for(i=1;i
ret+=g_aAdValue[i];
//找到最大和最小值索引
ret/=7;
max_id=min_id=1;
max_value=min_value=0;
for(i=1;i
{
if(g_aAdValue[i]>ret)
{
if(g_aAdValue[i]-ret>max_value)
{
max_value=g_aAdValue[i]-ret;
max_id=i;
}
}
else
{
if(ret-g_aAdValue[i]>min_value)
{
min_value=ret-g_aAdValue[i];
min_id=i;
}
}
}
//去掉第一个和最大最小值后的平均值
ret=0;
for(i=1;i
{
if((i!=min_id)&&(i!=max_id))
{
ret+=g_aAdValue[i];
}
}
if(min_id!=max_id)
{
ret/=5;
}
else ret/=6;
ADCSRA=0;//关闭ADC
return ret;
}
void delay_1us(void) //1us延时函数
{
asm("nop");
}
void delay_nus(unsigned int n) //N us延时函数
{
unsigned int i=0;
for (i=0;i
delay_1us();
}
void delay_1ms(void) //1ms延时函数
{
unsigned int i;
for (i=0;i
}
void delay_nms(unsigned int n) //N ms延时函数
{
unsigned int i=0;
for (i=0;i
delay_1ms();
}
#include "gait.h"
const prog_uchar t_a1[]={ // 1#膝关节
53,51,46,41,35,29,24,20,16,14,13,13,14,16,20,24,29,35,41,46,51,53, 53,52,52,52,51,51,51,51,50,50,50,50,50,50,50,50,50,50,50,50,50,50, 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,51,51,51,51,51, 51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,53,53,53,53 };
const prog_uchar t_a2[]={ // 1#髋关节
18,18,16,14,12,10,8,7,6,6,6,6,8,10,12,15,19,22,26,30,32,34,
34,34,33,32,32,31,31,30,29,29,28,28,28,28,28,28,28,28,27,27,27, 27,27,27,27,26,26,26,26,26,26,26,26,26,25,25,25,25,25,25,25,25, 25,24,24,24,24,24,24,24,24,23,23,23,23,22,22,22,21,21,21,20,20,19, 19,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,18,18,18,18,18 };
const prog_uchar t_a3[]={ // 3#膝关节
34,34,34,34,34,34,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36, 36,37,37,37,38,38,38,38,39,39,39,
39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, 39,39,39,39,39,39,39,39,39,39,40,39,39,39,39,39,39,39,39,39,39, 39,39,39,39,39,39,39,39,38,38,38,
38,40,44,49,55,60,65,70,73,75,76,76,75,72,69,64,59,53,47,41,36,34 };
const prog_uchar t_a4[]={ // 3#髋关节
72,72,72,72,72,72,72,72,72,72,72,72,71,71,71,71,71,71,71,71,71, 71,71,70,70,70,70,69,69,68,68,68,
68,68,68,67,67,67,67,67,67,67,67,67,67,66,66,66,66,66,66,66,66, 66,66,65,65,65,65,65,65,65,65,65,64,64,64,64,64,64,64,64,63,63, 63,63,62,62,61,61,60,60,59,58,58,
58,60,62,66,69,73,76,77,78,79,80,80,81,81,80,79,78,77,76,74,73,72 };
const prog_uchar t_a5[]={ //2#膝关节
39,39,39,39,39,39,39,39,39,39,40,39,39,39,39,39,39,39,39,39,39, 39,39,39,39,39,39,39,39,38,38,38,
38,38,38,38,38,37,37,37,37,37,37,37,37,37,37,37,37,36,36,36,36, 36,38,43,48,54,60,65,69,73,75,76,76,75,73,69,65,60,54,48,43,38,36, 36,37,37,37,38,38,38,38,39,39,39,
39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39
};
const prog_uchar t_a6[]={ //2#髋关节
63,63,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,66,66, 66,66,67,67,67,68,68,68,69,69,70,
70,70,70,70,70,70,70,70,70,70,70,70,70,71,71,71,71,71,71,71,71, 71,71,73,75,76,77,78,78,79,79,79,79,78,78,76,74,70,67,63,59,57,55, 55,55,56,57,57,58,58,59,60,60,61,
61,61,61,61,61,61,61,62,62,62,62,62,62,62,63,63,63,63,63,63,63 };
const prog_uchar t_a7[]={ //4#膝关节
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, 50,50,50,50,50,50,50,50,51,51,51,
51,49,45,40,34,29,24,19,16,14,13,13,14,17,20,25,30,36,42,48,53,55, 55,55,55,55,55,55,54,54,54,54,54,54,54,54,53,53,53,53,53,53,53, 53,52,52,52,51,51,51,51,50,50,50,
50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50 };
const prog_uchar t_a8[]={ //4#髋关节
23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,26,26, 26,26,27,27,28,28,29,29,30,31,31,
31,29,27,23,20,16,13,10,7,5,4,4,3,3,4,6,8,10,13,15,16,17,
17,17,17,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18, 18,18,19,19,19,19,20,20,21,21,21,
21,21,21,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23 };
void up_data(unsigned char time)
{
send_pwm[0]=pgm_read_byte(t_a1+time); send_pwm[1]=pgm_read_byte(t_a2+time); send_pwm[2]=pgm_read_byte(t_a3+time); send_pwm[3]=pgm_read_byte(t_a4+time)-5;
send_pwm[4]=pgm_read_byte(t_a5+time); send_pwm[5]=pgm_read_byte(t_a6+time); send_pwm[6]=pgm_read_byte(t_a7+time); send_pwm[7]=pgm_read_byte(t_a8+time); }
void right_data(unsigned char time) {
}
/
#include
#include
#include
#include
//#include
#include "gait.h"
#include "usart.h"
#include "think.h"
#include "ad.h"
unsigned char send_pwm[9]={53,18,34,67,39,63,50,23,45}; //PWM参数数组
unsigned char up_t=0; //时钟更新标志
unsigned char t; //步态时钟节拍
unsigned char error=0; //错误标志
unsigned char t_backup; //t的备份
unsigned char one_T=0;
void time_init(void)
{
TCCR0=(0
OCR0=38; //设置时钟节拍
TIMSK=(1
TCCR2=(0
TCCR1A=(1
TCCR1B=(0
}
void io_init()
{
DDRB|=(0
DDRD=(1
}
SIGNAL(SIG_OUTPUT_COMPARE0) {
if(t>105)
{
t=0;
one_T=1;
}
else t++;
up_t=1;
}
SIGNAL(SIG_UART_RECV) {
if('N'==UDR)
{
error=1;
}
}
int main(void)
{
cli();
wdt_disable();
io_init();
usart_init();
time_init();
sei();
usart_send_pwm(); //位置初始化 find_do();
}
#include "think.h"
const prog_uchar scan_n[]={ 44,46,48,50,52,54,56,58,60,62, 64,66,68,70,72,74,76,78,80,82, 84,86,86,84,82,80,78,76,74,72, 70,68,66,64,62,60,58,56,54,52, 50,48,46,44,42,40,38,36,34,32, 30,28,26,24,22,20,18,16,14,12, 10,8,6,4,2,0,0,2,4,6,
8,10,12,14,16,18,20,22,24,26, 28,30,32,34,36,38,40,42,44 };