首页 > 其他 > 详细

机器人底盘运动控制

时间:2019-11-13 23:00:13      阅读:104      评论:0      收藏:0      [点我收藏+]

机器人底盘运动控制

运动控制使用增量式PID进行控制,控制周期20ms,当上位机发送速度控制命令时,下位机读取发送的速度值,获取的速度值需要转化成编码器脉冲,根据轮径、减速比确定速度与脉冲间的换算关系系数(单位m/s):

SpeedParm=CntPerCicle/(D*Pi*(50/100))

式中CntPerCicle为轮子每转一周所产生的脉冲数,D为轮子直径,根据测算,CntPerCircle取4100,D取10.5,故实际需要的脉冲为Speed*SpeedParm,据此找到速度与控制脉冲之间的换算关系。将计算的脉冲值传递给速度控制函数,在速度控制函数中首先对计算获取的脉冲值进行限幅处理,将目标控制的脉冲值与实际获取的脉冲值做差,根据计算的偏差进行分段,速度控制过程分为启动阶段、分段PID控制阶段、减速停止阶段。当偏差大于设定的启动脉冲值,并且实际运动的脉冲值小于设定脉冲判断为处于启动状态,当实际的脉冲大于等于设定启动脉冲时即可判断机器人已经启动,此时切换到PID控制阶段,PID控制阶段,使用增量式PID,根据脉冲偏差将整个PID控制过程分为三段,当偏差较大时给相对较大的PID系数,当实际的脉冲较为接近设定值时,切换到稍小的PID系数,当实际脉冲在设定值附近时,切换到较小的PID系数,当偏差较大时,系统能够较快的作出响应,当调到设定值附件时,较大的PID系数会导致系统不稳定,采用较小的PID系数,保证系统有很好的稳态控制效果。

速度、脉冲换算:

/****************************************************
Input  : LeftSpeed RightSpeed
OutPut : None
Berif  : SpeedControl
Note   : 
Add    :
Version: V 1.0
****************************************************/
float SpeedParm=248.58;// (4100/(10.5*pi)) *2
short RightCntSet=0,LeftCntSet=0;
void SpeedControl(int LeftSpeed,int RightSpeed)
{
       if(LeftSpeed>SpeedMax)LeftSpeed=SpeedMax;//限幅
       if(LeftSpeed<-SpeedMax)LeftSpeed=-SpeedMax;
       if(RightSpeed>SpeedMax)RightSpeed=SpeedMax;
       if(RightSpeed<-SpeedMax)RightSpeed=-SpeedMax;
       LeftCntSet=(short)(LeftSpeed*SpeedParm/100000);//上位机发送扩大10万倍、还原
       RightCntSet=(short)(RightSpeed*SpeedParm/100000);
       RIGHT_ENCODE_CONTROL(RightCntSet);
       LEFT_ENCODE_CONTROL(LeftCntSet);
}

 

电机脉冲闭环控制:

/*****************************************************
Input  : short EncodeCnt
OutPut : None
Berif  : LEFT_ENCODE_CONTROL
Add    :
Version: V 2.0
******************************************************/
float ti=0.1,tp=0.19,td=0.015;
float left_err=0,p_left_err=0,pp_left_err=0;
float left_delta_duty=0;//0.044  0.079 0.05 
float lki=0.6,lkp=0.79,lkd=0.25;//lki=0.045,lkp=0.079,lkd=0.05;
char LeftMoveState=E;//S:start  E:stop M:move 
float CorrectionParam=0.95;
void LEFT_ENCODE_CONTROL(short EncodeCnt)
{
      if(EncodeCnt==0) LEFT_PWM=0;
      if(EncodeCnt>EncodeCntMax)EncodeCnt=EncodeCntMax;
        if(EncodeCnt<EncodeCntMin)EncodeCnt=EncodeCntMin;
      if(EncodeCnt*EncodeLeftCnt<0)EncodeCnt=0;
      left_err=EncodeCnt-EncodeLeftCnt;//EncodeCnt 目标脉冲数;EncodeLeftCnt 实时编码器脉冲数
       if((left_err<=10)&&(left_err>=-10))
             lki=0.1,lkp=0.019,lkd=0.015;    
      else if((left_err<=12)&&(left_err>=-12))
            lki=0.2,lkp=0.19,lkd=0.025;
        else if((left_err<=18)&&(left_err>=-18))
            lki=0.4,lkp=0.39,lkd=0.25;
        else
            lki=0.6,lkp=0.59,lkd=0.25;
        if((left_err>DeadZoneErrCnt)||(left_err<-DeadZoneErrCnt))
         {
            if((EncodeLeftCnt<2)&&(EncodeLeftCnt>-2))//start up zone            
                    LeftMoveState=S;            
            else 
            {  
                if((EncodeCnt<DeadZoneCnt)&&(EncodeCnt>-DeadZoneCnt))
                     LeftMoveState=E;//stop
              else
                   LeftMoveState=M;
            }
        }
        if((left_err<=DeadZoneErrCnt)&&(left_err>=-DeadZoneErrCnt))
        {
             if((EncodeCnt<DeadZoneCnt)&&(EncodeCnt>-DeadZoneCnt))
                LeftMoveState=E;//End
             else
                  LeftMoveState=M;//move normal
        }
        switch(LeftMoveState)
        {
            case S:
                     if(EncodeCnt>0)
                         {
                       if(LEFT_PWM<DeadZonePwm*CorrectionParam)
                                 LEFT_PWM=DeadZonePwm*CorrectionParam;
                               left_delta_duty=2;
                         }
                         if(EncodeCnt<0)
                         {
                              if(LEFT_PWM>-DeadZonePwm*CorrectionParam)
                                 LEFT_PWM=-DeadZonePwm*CorrectionParam;
                               left_delta_duty=-2;
                         }
                break;
            case M:
                     left_err=(EncodeCnt-EncodeLeftCnt)/2.0;
                break;
            case E:
                     left_err=(EncodeCnt-EncodeLeftCnt)/1.0;
                break;
            default:
                break;
        }
      if(LeftMoveState!=S)
        {
         left_delta_duty=lkp*(left_err-p_left_err)+lki*left_err+lkd*(left_err-2*p_left_err+pp_left_err);
         pp_left_err=p_left_err;
         p_left_err=left_err;
        }
      if((left_delta_duty<=DeadZone)&&(left_delta_duty>0))//死区控制
         {
             left_delta_duty=0;
         }
         if((left_delta_duty>=-DeadZone)&&(left_delta_duty<0))
         {
             left_delta_duty=0;
         }
      LEFT_PWM+=left_delta_duty;
      if(EncodeCnt==0)LEFT_DIR_CONTROL(S);//方向控制
      if(EncodeCnt>0)LEFT_DIR_CONTROL(D);
      if(EncodeCnt<0)LEFT_DIR_CONTROL(R);
      
        if(LEFT_PWM>PWM_Period) LEFT_PWM=PWM_Period;//限幅
        if(LEFT_PWM<-PWM_Period)LEFT_PWM=-PWM_Period;
        if(LEFT_PWM<=0)
        {
             LEFT_MOTOR_PWM_OUT(-(short)LEFT_PWM);
        }
        else
        {
             LEFT_MOTOR_PWM_OUT((short)LEFT_PWM);
        }      
}

 

机器人底盘运动控制

原文:https://www.cnblogs.com/xgth/p/11853728.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!