作者:Edison钟

日期:2012.9

产品&技术开发背景

  1. 在人形机器人领域代表世界最先进水平的应当是日本的ASIMO机器人,其采用电驱方式拥有灵活的步态及环境感知,在此领域可为是巅峰之作。
  2. 而在国内人形机器人发展相对迟缓落后,基于本人儿时的憧憬及个人爱好此项目在酝酿许久后正式启动。

设计目标及要求

  1. 基于成本及控制难易程度的考虑,此项目拟定使用航模舵机作位动力执行器
  2. DOFs:10自由度
  3. 重量:<=2.5kg
  4. 运动控制: 前进,后退,左转,右转,壁障,目标追踪
  5. 控制方式:UART无线串口控制

      

3D建模渲染效果图

设计思路及原理:

  1. MCU通过定时器生成8路PWM信号控制舵机转角,舵机控制周期20ms,有效脉冲宽度为2.5ms所以一个控制周期刚好可以控制8路舵机。
  2. 考虑到腿关节灵活性的要求,该设计特别考虑了减少腿部惯量的设计要求而采用了连杆机构驱动。
  3. 各动作的数学模型主要通过三角函数的计算对各关节角度的拆解。

关节角度反三角函数计算

3D建模软件运动仿真

运动仿真视频:SlimRobot运动模拟-CSDN直播

  1. 电源:DC7.4V
  2. 核心控制器:STC12C5A60S2 1T单片机,硬件资源:两个16位定时器,两路8位PWM输出,两个自带独立波特率发生器串口,两路外部中断
  3. 传感器:
  • MPU-6050三轴加速度及三轴陀螺仪并附带温度传感器
  • OV7670 CMOS图像传感器
  1. 动力执行元件:
  • 舵机类型:辉盛MG946R模拟舵机,PWM控制方式
  • 额定扭矩:10.5KG*CM@4.8V, 13KG*CM@6V
  • 反应速度:空载运行速度: 0.20sec/60° at 4.8V, 0.17sec/60°at 6.0V空载运行速度: 0.20sec/60° at 4.8V, 0.17sec/60°at 6.0V空载运行速度: 0.20sec/60° at 4.8V, 0.17sec/60°at 6.0V0.2s/60@4.8V, 0.17s/60@6V
  • 标称最大转动角度:±90°,实测最大转动角度约为±60°(脉冲控制角度范围约为30°- 150°)
  • 控制方式:PWM控制,周期2.5ms, 1.5ms为0°
  • 输出轴连接方式:20齿花键加M3螺钉
  1. 舵机驱动板:
  • 驱动类型:自制10路驱动板,采用S8550 PNP三极管一级驱动
  • 电压:7.4V
  • 持续工作电流:10A以上
  • 控制方式:MCU产生10路PWM经驱动板放大驱动舵机
  1. 总高度:450mm
  2. 腿长:400mm
  3. 两腿跨距:120mm

  

舵机拆解图

模型组装效果图

设计注意事项:

  1. 上电时如何解决各舵机初始化时由于快速复位引起的加速度冲击
  2. 如何控制步态—通过算法还是经验值
  3. 舵机扭矩及精度的要求

项目回顾及展望:

  1. 该项目完成了3D模型的创建及运动的仿真,对运动仿真及关节角度控制有了进一步了解。
  2. 完成了原型机的制作并实现了基本的下蹲及站立基本动作。
  3. 选用的航模舵机不管是扭矩还是位置控制精度都达不到预期,并且也没有位置反馈无法实现闭环控制,整体控制效果不佳,无法稳定完成行走动作。
  4. 同时结构刚性不足导致脚掌定位不准,且舵机扭矩不够导致关节角度不能达到目标值,此项目暂停。
  5. 后续如有更好的运动驱动单元再考虑重启项目。

控制软件版本更改记录:

V0.1:

  1. 原始版本
  2. 6自由度
  3. 运动控制采用经验值函数模块化控制,如向前走,下蹲,站立功能函数等
  4. 定时器0产生8路PWM信号
  5. 定时器1用于串口波特率发生器
  6. 串口波特率为57600
  7. MCU: STC89C52RC@11.0592MHz

V0.2:

  1. 脚板增加2自由度,总自由度增至8个
  2. 运动控制采用经验值查表方式(运动组)以达到对运动过程中的速度控制(二维数组)
  3. 增加注释

V0.3:

  1. 胯部增加2自由度,总自由度增至10个
  2. 运动控制采用经验值查表方式(运动组)以达到对运动过程中的速度控制(二维数组)
  3. MCU: STC12C5A60S2,FOSC:11.0592MHz,T0产生8路PWM,T1产生2路PWM,总共控制10路舵机
  4. 串口波特率为57600

V0.4:

1. 运动控制采用建立数学模型, 通过算法控制脚掌的坐标:X, Y, Z, Rx, Ry, Rz

V0.5:

  1. 脚掌左右转动电机改为春天SR-403P舵机,旋转角度范围180度。
  2. L7长度从158mm改为198.5mm; L9长度从43mm改为42mm
  3. 结构刚性不足导致脚掌定位不准,且舵机扭矩不够导致关节角度不能达到目标值,此项目暂停。

最新软件代码:

/**********************************************V0.5**********************************************/

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

两足机器人控制主函数,利用定时器0产生8路PWM信号及定时器1产生2路PWM信号实现对总共10路舵机的控制
伺服电机的控制
MCU: STC12C5A60S2
FOSC: 11.0592MHZ

***********************************************************************************************/
#include <STC12C5A.h>
#include <math.h>
#include <stdio.h>   //Keil library	
#include <stdlib.h>
#include <string.h>

#include "Servo_Driver.h"
#include "MCU_Setting.h"
#include "delayms.h"
#include "Auxiliary_Functions.h"
#include "motion_control.h"

#define uchar unsigned char
#define uint  unsigned int

uchar T0_order_flag,T1_order_flag;
uchar UART_count=0;
uchar ReData[7];
float data speed_index;
uint  T1_L,T2_L,T3_L,T4_L,T5_L,T1_R,T2_R,T3_R,T4_R,T5_R;
float data X_axis_L,Y_axis_L,Z_axis_L,R_x_L,R_y_L,R_z_L,R_z_C_L;
float data X_axis_R,Y_axis_R,Z_axis_R,R_x_R,R_y_R,R_z_R,R_z_C_R;
uchar motion_cmd=0;

void main(void)
{

	
	MCU_init();				         //单片机初始化
	parameter_init();	             //系统参数初始化

	T0_order_flag =1;
	T1_order_flag =1;

	//delayms(1000);

    while(1)
    {	
																		  
       stepping(motion_cmd);		 //"0"表示停止,“1”表示原地踏步

       angle_calculation();

	   if(motion_cmd==2)servo_neutral();

	   else set_servo();

	   data_upload();
    }
}

/*********************************************************
//timer0中断函数产生8路PWM控制8个舵机
*********************************************************/
void timer0(void) interrupt 1 using 1
{
   switch(T0_order_flag)          //8路舵机PWM控制,每路舵机实际控制周期2.5ms,8路舵机总时长为2.5ms x 8=20ms为各路舵机推荐总控制周期
   {
      case 1: 		              //1号舵机PWM高电平时间
	     
		  servo_L1=1;
          TH0=T1_L>>8;            
          TL0=T1_L;              
          break;

      case 2: 		              //1号舵机PWM低电平时间
	     
		  servo_L1=0;        
		  TH0=(0xf700-T1_L)>>8;   //0xf700延时2.5ms
          TL0=(0xf700-T1_L);    	
          break;

      case 3: 
	   
	      servo_L2=1;
          TH0=T2_L>>8;
          TL0=T2_L;
          break;

      case 4: 
	  
	      servo_L2=0;
          TH0=(0xf700-T2_L)>>8;
          TL0=(0xf700-T2_L);
          break;

      case 5: 
	  
	      servo_L3=1;
          TH0=T3_L>>8;
          TL0=T3_L;
          break;

      case 6: 
	   
	      servo_L3=0 ;
          TH0=(0xf700-T3_L)>>8;
          TL0=(0xf700-T3_L);
          break;

      case 7: 
	  
	      servo_L4=1;
          TH0=T4_L>>8;
          TL0=T4_L;
          break;
		   
      case 8: 
	  
	      servo_L4=0;
          TH0=(0xf700-T4_L)>>8;
          TL0=(0xf700-T4_L);
          break;

      case 9: 
	  
	      servo_L5=1;
          TH0=T5_L>>8;
          TL0=T5_L;		 
          break;

      case 10: 
	  
	      servo_L5=0;
          TH0=(0xf700-T5_L)>>8;
          TL0=(0xf700-T5_L);
          break;

      case 11: 
	  
	      servo_R1=1;
          TH0=T1_R>>8;
          TL0=T1_R;
          break;

      case 12:
	  
	      servo_R1=0;
          TH0=(0xf700-T1_R)>>8;
          TL0=(0xf700-T1_R);
          break;

      case 13: 
	  
	      servo_R2=1;
          TH0=T2_R>>8;
          TL0=T2_R;
          break;

      case 14:
	  
	      servo_R2=0;
          TH0=(0xf700-T2_R)>>8;
          TL0=(0xf700-T2_R);
          break;

      case 15: 
	  
	      servo_R3=1;
          TH0=T3_R>>8;
          TL0=T3_R;
          break;

      case 16:
	  
	      servo_R3=0;
          T0_order_flag=0;
          TH0=(0xf700-T3_R)>>8;
          TL0=(0xf700-T3_R);
          break;
    }
    T0_order_flag++;
}

/*********************************************************
////timer1中断函数产生2路PWM控制2个舵机
*********************************************************/
void timer1(void) interrupt 3 using 2
{
   switch(T1_order_flag)        //2路舵机PWM控制,每路舵机实际控制周期2.5ms
   {
      case 1: 		            //9号舵机PWM高电平时间
	     
		  servo_R4=1;
          TH1=T4_R>>8;          
          TL1=T4_R;             
          break;

      case 2: 		            //9号舵机PWM低电平时间
	     
		  servo_R4=0;        
		  TH1=(0xf700-T4_R)>>8; //0xf700延时2.5ms
          TL1=(0xf700-T4_R);    	
          break;

      case 3: 
	   
	      servo_R5=1;
          TH1=T5_R>>8;
          TL1=T5_R;
          break;

      case 4: 
	  
	      servo_R5=0;
		  T1_order_flag=0;
          TH1=(0xf700-T5_R)>>8;
          TL1=(0xf700-T5_R);
          break;

      case 5: 
	  
		  T1_order_flag=0;
          TH1 = 0xCA;			  //定时15ms补齐总共的20ms控制周期
          TL1 = 0x00;
          break;
	}
	T1_order_flag++;
}

/*********************************************************
串口通信中断函数
*********************************************************/
void series_int (void) interrupt 4
{ 
    if(RI == 1)                    //RI接受中断标志
    { 
	    RI = 0;		               //清除RI接受中断标志				
	    ReData[UART_count] = SBUF; //SUBF接受/发送缓冲器
			
//	    SBUF=ReData[UART_count]; //回传控制参数以供上位机确认控制命令
//		while(!TI);
//	    TI = 0;		             //清除TI发送中断标志

		UART_count++;
	    if(UART_count==7)
		{	
//		     X_axis_L = (float)ReData[0]-128;	     //X坐标值
//			 Y_axis_L = (float)ReData[1];	         //Y坐标值
//			 Z_axis_L = (float)ReData[2]+150;	     //Z坐标值
//			 R_x_L = (float)ReData[3];
//			 R_y_L = (float)ReData[4];
//			 R_z_L = (float)ReData[5];
//			 speed_index = (float)ReData[6];
			 
//		     X_axis_R = (float)ReData[0]-128;	     //X坐标值
//			 Y_axis_R = (float)ReData[1];	         //Y坐标值
//			 Z_axis_R = (float)ReData[2]+50;	     //Z坐标值
//			 R_x_R = (float)ReData[3];
//			 R_y_R = (float)ReData[4];
//			 R_z_R = (float)ReData[5];
//			 speed_index = ReData[6];

		     motion_cmd = ReData[0];	             //运动控制指令
//
		     UART_count=0;
		}
	}	
}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐