打印
[STM32]

第一次发视频,发一个PID方式控制步进电机的运行测试视频

[复制链接]
2086|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ColeYao|  楼主 | 2022-1-18 09:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ColeYao 于 2022-1-19 12:39 编辑

https://v.douyin.com/8wNREjf/    视频显示的是采用stm32H750作为主芯片的最高速100转每分与1000转每分时步进电机运行控制效果对比,加减速采用PID方式,贴上部分代码,供大家参考! 理论上可以15个步进电机同时运行,互不干涉,实际上同时运行的电机应该不可能有15个,而且运行速度也应该受结构限制远达不到几千转每分的速度,所以应该是可以正常工作的。   https://v.douyin.com/8E2JGvA/   视频显示的是采用stm32H750作为主芯片的最高速300转每分与3000转每分的测试状况。之前发的那个视频是1000转每分钟的,程序有bug,更正后重发一个3000转每分钟的测试视频。  以上视频中步进电机驱动器采用4细分驱动(每4个脉冲,步进电机旋转1.8度),当采用16细分驱动时不失步空载最大转速只能到2200转每分,修改定时器设置才能达到3000转每分,视频就不发了。   达到1000rpm时步进电机速度几乎已经可以和伺服电机相比了!



使用特权

评论回复

相关帖子

沙发
ColeYao|  楼主 | 2022-1-19 10:23 | 只看该作者
2F贴上步进电机控制的部分代码供参考!

#include "MotorController.h"
#include "MotorDriver.h"

extern TIM_HandleTypeDef htim2,htim1,htim5,htim8;
extern MotorInterFace MtDrvA;    // 1
extern MotorInterFace MtDrvB;    // 2
extern MotorInterFace MtDrvC;    // 3
extern MotorInterFace MtDrvD;    // 4
extern MotorInterFace MtDrvE;    // 5
extern MotorInterFace MtDrvF;    // 6
extern MotorInterFace MtDrvG;    // 7
extern MotorInterFace MtDrvH;    // 8
extern MotorInterFace MtDrvI;    // 9
extern MotorInterFace MtDrvJ;    // 10
extern MotorInterFace MtDrvK;    // 11
extern MotorInterFace MtDrvL;    // 12
extern MotorInterFace MtDrvM;    // 13
extern MotorInterFace MtDrvN;    // 14
extern MotorInterFace MtDrvO;    // 15

extern MotorInterFace* MtDriver[15];   

extern StepMotor*   Motor[15];

//extern MotorDriver DrvA;
//extern MotorDriver DrvB;
//extern MotorDriver DrvC;
//extern MotorDriver DrvD;
//extern MotorDriver DrvE;

float KSin[257]=                 //20190116
{0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};

float StepMotor::PidAdjust(float ErrIn)
{
  float temi;
  if(CntTime<1024) CntTime++;
  if((ErrIn<0.00001)&&(ErrIn>-0.00001))  {   temi=0;  CntTime=0;  }
   else temi=-FdK*(ErrIn+PreK*(ErrIn-ErrInL));
  ErrInLL=ErrInL;
  ErrInL=ErrIn;
  CalResult=temi;
  return(temi);
}


float StepMotor::PidSinAdjust(float ErrIn)   
{
  float temi;
  if(CntTime<1024) CntTime++;
  if((ErrIn<0.00001)&&(ErrIn>-0.00001))    CntTime=0;
  else temi=-FdK*KSin[CntTime/4]*(ErrIn+PreK*(ErrIn-ErrInL));
  ErrInLL=ErrInL;
  ErrInL=ErrIn;
  CalResult=temi;
  return(temi);
}

float StepMotor::PidSinFAdjust(float ErrIn)   
{
  float temi;
  if(CntTime<512) CntTime++;
  if((ErrIn<0.00001)&&(ErrIn>-0.00001))    CntTime=0;
  else temi=-FdK*KSin[CntTime/2]*(ErrIn+PreK*(ErrIn-ErrInL));
  ErrInLL=ErrInL;
  ErrInL=ErrIn;
  CalResult=temi;
  return(temi);
}

void  StepMotor::SetPar(float pFdK,float pPreK,float pPreKv)
{
  FdK=pFdK;
  PreK=pPreK;
  PreKv=pPreKv;
  ErrInL=0;
  ErrInLL=0;
}
/*
void EnClk(GPIO_TypeDef* GPIOA2H)
{
  if(GPIOA2H==GPIOA)        __HAL_RCC_GPIOA_CLK_ENABLE();
   else if(GPIOA2H==GPIOB)  __HAL_RCC_GPIOB_CLK_ENABLE();  
   else if(GPIOA2H==GPIOC)  __HAL_RCC_GPIOC_CLK_ENABLE();
   else if(GPIOA2H==GPIOD)  __HAL_RCC_GPIOD_CLK_ENABLE();
   else if(GPIOA2H==GPIOE)  __HAL_RCC_GPIOE_CLK_ENABLE();
   else if(GPIOA2H==GPIOF)  __HAL_RCC_GPIOF_CLK_ENABLE();
   else if(GPIOA2H==GPIOG)  __HAL_RCC_GPIOG_CLK_ENABLE();
   else if(GPIOA2H==GPIOH)  __HAL_RCC_GPIOH_CLK_ENABLE();        
}

uint16_t StepMotor::SetPortOut(GPIO_TypeDef* GPIOA2H,uchar PosPin)
{
        uint16_t  GPIOxPin;
        GPIOxPin=(1<<PosPin);
    GPIO_InitStruct.Pin = GPIOxPin;               
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;;   //输出
        GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA2H, &GPIO_InitStruct);
        return(GPIOxPin);
}
*/
StepMotor::StepMotor(uchar MtNo)
{
  uint16_t i;
  Iam=MtNo;

    RevDir=1;
    Runing=0;
    dir=0;
    Pos_Pul=0;
    Pos_Des=0;
    Half_Pos=0;
    Half_Step=0;
    ZeroOutCnt=0;
    ZeroTriged=0;

//X电机MPos=9022;  Y电机MPos=3463;  Z电机MPos=2165;
//X电机VRadio=2*8=16; Y 电机VRadio=8; Z电机VRadio=10;
    if(Iam==1)  { MaxPos=MaxAPos; RadioV=16;  MaxSpeed=(10/RadioV);   }            //最大速度约50转每秒
    if(Iam==2)  { MaxPos=MaxBPos; RadioV=1;  MaxSpeed=10/RadioV;     }  //最大速度约50转每秒
    if(Iam==3)  { MaxPos=MaxCPos; RadioV=4;  MaxSpeed=(10/RadioV)*(MotorMaxV_rps/10);  }             //最大速度约10转每秒
    if(Iam==4)  { MaxPos=MaxDPos; RadioV=4;  MaxSpeed=(10/RadioV)*(MotorMaxV_rps/10);  }             //最大速度约10转每秒
    if(Iam==5)  { MaxPos=MaxEPos; RadioV=4;  MaxSpeed=(10/RadioV)*(MotorMaxV_rps/10);  }             //最大速度约10转每秒
    if(Iam>5)   { MaxPos=MaxAPos; RadioV=1;  MaxSpeed=10/RadioV;  }  //最大速度约50转每秒

    if(Iam==1)  { SetPar(0.01,3,0);  }
    if(Iam==2)  { SetPar(0.01,3,0);  }  
    if(Iam==3)  { SetPar(0.01,3,0);  }  
    if(Iam==4)  { SetPar(0.01,3,0);  }  
    if(Iam==5)  { SetPar(0.01,3,0);  }
    if(Iam>5)   { SetPar(0.01,3,0);  }

    for(i=0;i<257;i++)
    {
      KSin[i]=(1-cos(3.1415926*i/256))/2;   //20190116
      if(KSin[i]<0.03)  KSin[i]=0.03;       //20201018
    }

    MovePhase=0xff;
    PhaseZero=0xff;
    Go0Finished=0;
}

void StepMotor::SetTimCCR(void)
{
uint32_t uhCapture,count;

        //        count=LL_TIM_GetCounter(TIM1);
        //        /*设置比较数值*/
        //        LL_TIM_OC_SetCompareCH1(TIM1, count + 1000);

  switch(Iam)
  {
    case 1:  count=LL_TIM_GetCounter(TIM2);
             if((count + CurSpeed)>TIM2->ARR)  LL_TIM_OC_SetCompareCH1(TIM2, count + CurSpeed-TIM2->ARR);  
              else  LL_TIM_OC_SetCompareCH1(TIM2, count + CurSpeed);   break;
    case 2:  count=LL_TIM_GetCounter(TIM2);
             if((count + CurSpeed)>TIM2->ARR)  LL_TIM_OC_SetCompareCH2(TIM2, count + CurSpeed-TIM2->ARR);  
              else  LL_TIM_OC_SetCompareCH2(TIM2, count + CurSpeed);   break;
    case 3:  count=LL_TIM_GetCounter(TIM2);
             if((count + CurSpeed)>TIM2->ARR)  LL_TIM_OC_SetCompareCH3(TIM2, count + CurSpeed-TIM2->ARR);  
              else  LL_TIM_OC_SetCompareCH3(TIM2, count + CurSpeed);   break;
    case 4:  count=LL_TIM_GetCounter(TIM1);
             if((count + CurSpeed)>TIM2->ARR)  LL_TIM_OC_SetCompareCH4(TIM2, count + CurSpeed-TIM2->ARR);  
              else  LL_TIM_OC_SetCompareCH4(TIM2, count + CurSpeed);   break;
    case 5:  count=LL_TIM_GetCounter(TIM1);
             if((count + CurSpeed)>TIM1->ARR)  LL_TIM_OC_SetCompareCH1(TIM1, count + CurSpeed-TIM1->ARR);  
              else  LL_TIM_OC_SetCompareCH1(TIM1, count + CurSpeed);   break;
    case 6:  count=LL_TIM_GetCounter(TIM1);
             if((count + CurSpeed)>TIM1->ARR)  LL_TIM_OC_SetCompareCH2(TIM1, count + CurSpeed-TIM1->ARR);  
              else  LL_TIM_OC_SetCompareCH2(TIM1, count + CurSpeed);   break;
    case 7:  count=LL_TIM_GetCounter(TIM1);
             if((count + CurSpeed)>TIM1->ARR)  LL_TIM_OC_SetCompareCH3(TIM1, count + CurSpeed-TIM1->ARR);  
              else  LL_TIM_OC_SetCompareCH3(TIM1, count + CurSpeed);   break;
    case 8:  count=LL_TIM_GetCounter(TIM1);
             if((count + CurSpeed)>TIM1->ARR)  LL_TIM_OC_SetCompareCH4(TIM1, count + CurSpeed-TIM1->ARR);  
              else  LL_TIM_OC_SetCompareCH4(TIM1, count + CurSpeed);   break;
    case 9:  count=LL_TIM_GetCounter(TIM5);
             if((count + CurSpeed)>TIM5->ARR)  LL_TIM_OC_SetCompareCH1(TIM5, count + CurSpeed-TIM5->ARR);  
              else  LL_TIM_OC_SetCompareCH1(TIM5, count + CurSpeed);   break;
    case 10:  count=LL_TIM_GetCounter(TIM5);
             if((count + CurSpeed)>TIM5->ARR)  LL_TIM_OC_SetCompareCH2(TIM5, count + CurSpeed-TIM5->ARR);  
              else  LL_TIM_OC_SetCompareCH2(TIM5, count + CurSpeed);   break;
    case 11:  count=LL_TIM_GetCounter(TIM8);
             if((count + CurSpeed)>TIM8->ARR)  LL_TIM_OC_SetCompareCH1(TIM8, count + CurSpeed-TIM8->ARR);  
              else  LL_TIM_OC_SetCompareCH1(TIM8, count + CurSpeed);   break;
    case 12:  count=LL_TIM_GetCounter(TIM8);
             if((count + CurSpeed)>TIM8->ARR)  LL_TIM_OC_SetCompareCH2(TIM8, count + CurSpeed-TIM8->ARR);  
              else  LL_TIM_OC_SetCompareCH2(TIM8, count + CurSpeed);   break;
    case 13:  count=LL_TIM_GetCounter(TIM8);
             if((count + CurSpeed)>TIM8->ARR)  LL_TIM_OC_SetCompareCH3(TIM8, count + CurSpeed-TIM8->ARR);  
              else  LL_TIM_OC_SetCompareCH3(TIM8, count + CurSpeed);   break;
    case 14:  count=LL_TIM_GetCounter(TIM8);
             if((count + CurSpeed)>TIM8->ARR)  LL_TIM_OC_SetCompareCH4(TIM8, count + CurSpeed-TIM8->ARR);  
              else  LL_TIM_OC_SetCompareCH4(TIM8, count + CurSpeed);   break;
    case 15:  count=LL_TIM_GetCounter(TIM5);
             if((count + CurSpeed)>TIM5->ARR)  LL_TIM_OC_SetCompareCH3(TIM5, count + CurSpeed-TIM5->ARR);  
              else  LL_TIM_OC_SetCompareCH3(TIM5, count + CurSpeed);   break;
  }
}

void StepMotor::DisTimCCR(void)
{
  switch(Iam)
  {
    case 1:  DisTim2CC1; break;
    case 2:  DisTim2CC2; break;
    case 3:  DisTim2CC3; break;
    case 4:  DisTim2CC4; break;
    case 5:  DisTim1CC1; break;
    case 6:  DisTim1CC2; break;
    case 7:  DisTim1CC3; break;
    case 8:  DisTim1CC4; break;
    case 9:  DisTim5CC1; break;
    case 10:  DisTim5CC2; break;
    case 11:  DisTim8CC1; break;
    case 12:  DisTim8CC2; break;
    case 13:  DisTim8CC3; break;
    case 14:  DisTim8CC4; break;
    case 15:  DisTim5CC3; break;
  }       
}

void StepMotor::EnTimCCR(void)
{
  switch(Iam)
  {
    case 1:  EnTim2CC1; break;
    case 2:  EnTim2CC2; break;
    case 3:  EnTim2CC3; break;
    case 4:  EnTim2CC4; break;
    case 5:  EnTim1CC1; break;
    case 6:  EnTim1CC2; break;
    case 7:  EnTim1CC3; break;
    case 8:  EnTim1CC4; break;
    case 9:  EnTim5CC1; break;
    case 10:  EnTim5CC2; break;
    case 11:  EnTim8CC1; break;
    case 12:  EnTim8CC2; break;
    case 13:  EnTim8CC3; break;
    case 14:  EnTim8CC4; break;
    case 15:  EnTim5CC3; break;
  }       
}

void StepMotor::MoveT0(int32_t DestPos,int16_t DestV)   //位置为脉冲数,速度为多少圈每分钟
{

   if(DestPos>MaxPos)  {   return; }
   Pos_Des=DestPos;
   if(Pos_Des>Pos_Pul)
   {
     Half_Pos=((Pos_Des-Pos_Pul)>>1)+Pos_Pul;
     Half_Step=((Pos_Des-Pos_Pul)>>1);
     dir=1;
     //if(RevDir==0)  HAL_GPIO_WritePin(MyGPIOAn_Dir,MyAn_DirPin,GPIO_PIN_SET); else  HAL_GPIO_WritePin(MyGPIOAn_Dir,MyAn_DirPin,GPIO_PIN_RESET);  
   }
   else if(Pos_Des<Pos_Pul)
   {
     Half_Pos=((Pos_Pul-Pos_Des)>>1)+Pos_Des;
     Half_Step=((Pos_Pul-Pos_Des)>>1);
     dir=0;  
     //if(RevDir==0)  HAL_GPIO_WritePin(MyGPIOAn_Dir,MyAn_DirPin,GPIO_PIN_RESET);  else  HAL_GPIO_WritePin(MyGPIOAn_Dir,MyAn_DirPin,GPIO_PIN_SET);
   }
   else
   {
     Half_Pos=Pos_Des;
     Half_Step=0;
     dir=0;   
   }
  if(Motor[Iam-1]->dir==Motor[Iam-1]->RevDir)     MtDriver[Iam-1]->MtCCW;  else   MtDriver[Iam-1]->MtCW;  
  if(RadioV==0) RadioV=1;  //默认细分数为1,
  //HignSpeed=MotorMaxV_rps*60*2*10/(DestV*RadioV);
  HignSpeed=600000*60/((Presca_TIM+1)*DestV*RadioV);
  LowSpeed=(HignSpeed<<10);
  if(LowSpeed>0xffff)  LowSpeed=0xffff;
  CurSpeed=LowSpeed;
  SetTimCCR();
  if(dir==1)  vCirpMinDes=DestV;  else   vCirpMinDes=-DestV;
  Runing=1;
  SmodePhase=0;
}   


uchar StepMotor::IsZero(void)         //返回是否零位处于触发状态,当前低电平为零位状态
{
   if(ZeroTriged) return(1);  else return(0);   
}

//原先是先走脉冲再计数,控制方式兼容直接驱动后改为先计数,然后根据计数再发脉冲
uchar StepMotor::GoZeroInit(void)      //以固定的速度(圈每分)归零,速度由执行周期决定
{
  switch(PhaseZero)
  {
     case 0xff:  
                if(IsZero()==1)  PhaseZero=0;   else   PhaseZero=5;  
                ZeroOutCnt=0;
               break;
     case    0:        //在零位时向外运动
                dir=1;   PhaseZero=1;   
               break;   
     case    1:  
                Pos_Pul++;  vTaskDelay(1); PhaseZero=2;  
               break;
     case    2:  
                ZeroOutCnt++;
                if(IsZero()==0) PhaseZero=3; else PhaseZero=1;  
                if(ZeroOutCnt>300) PhaseZero=3;    //出零位以200个脉冲作为超时退出
               break;
     case    3:         //出零位后再运行100脉冲
                Pos_Pul++;   PhaseZero=4;  
               break;   
     case    4:  
                 ZeroOutCnt++;
                if(ZeroOutCnt<300) PhaseZero=3; else PhaseZero=5;  
               break;
     case    5:        //不在零位时向内运动
                dir=0;   PhaseZero=6;  
               break;   
     case    6:  
                Pos_Pul++;   PhaseZero=7;  
               break;
     case    7:  
                if(IsZero()==1) PhaseZero=8; else PhaseZero=6;  
               break;
     case    8:            //到达零位后返回1
                Pos_Pul=0;  PhaseZero=0xff;  return(1);   
               break;   
  }
  return(0);             //未到达零位后返回0
}

void StepMotor::ReFreshCnt(void)   //根据调整过的马达速度更新计数器变量  HignSpeed=600000*60/((Presca_TIM+1)*DestV*RadioV);
{
   if(vCirpMinDes>0)  HignSpeed=600000*60/(uint32_t)((Presca_TIM+1)*vCirpMinDes*RadioV);// =(240000000/(Presca_TIM+1))/((vCirpMinDes/60)*200*2*RadioV)  定时器时钟/每秒脉冲数
   else HignSpeed=600000*60/(uint32_t)((Presca_TIM+1)*(-vCirpMinDes)*RadioV);           //1200=60*2*10   //HignSpeed=24000/((uint32_t)(-vCirpMinDes)*RadioV*200/60);
   if(HignSpeed<MaxSpeed) HignSpeed=MaxSpeed;
//  if((vCirpMinDes>60)||(vCirpMinDes<-60)) LowSpeed=(HignSpeed<<5);  else   LowSpeed=(HignSpeed<<2);
   LowSpeed=(HignSpeed<<10);
   if(LowSpeed>0xffff)  LowSpeed=0xffff;
   if(v_CirpMin>0)
   {
     if(v_CirpMin<1)  v_CirpMin=1;  //限制马达转速不低于1转每分,否则可能会导致数据溢出出错
     CurSpeed=600000*60/(uint32_t)((Presca_TIM+1)*v_CirpMin*RadioV);   //4000=10*200*2
   }
   else if(v_CirpMin<=0)  
   {
     if(v_CirpMin>-1) v_CirpMin=-1;
     CurSpeed=600000*60/(uint32_t)((Presca_TIM+1)*(-v_CirpMin)*RadioV);   //4000=10*200*2
   }
   if(CurSpeed<HignSpeed)  CurSpeed=HignSpeed;
   if(CurSpeed>LowSpeed)   CurSpeed=LowSpeed;
   if(v_CirpMin>0)
   {
     v_CirpMin=(float)(600000*60)/(float)(RadioV*CurSpeed*(Presca_TIM+1));   //1200=60*2*10  
     if(v_CirpMin<1)  v_CirpMin=1;  //限制马达转速不低于1转每分,否则可能会导致数据溢出出错
   }
   else if(v_CirpMin<=0)  
   {
     v_CirpMin=-float(600000*60)/(float)(RadioV*CurSpeed*(Presca_TIM+1));    //1200=60*2*10  
     if(v_CirpMin>-1) v_CirpMin=-1;
   }
  //取消16位到32位扩展,直接使用32位计数器 if(Iam==1) Tim3CC1SetShdARR(CurSpeed,0);
  //取消16位到32位扩展,直接使用32位计数器 if(Iam==2) Tim3CC2SetShdARR(CurSpeed,0);
  //取消16位到32位扩展,直接使用32位计数器 if(Iam==3) Tim3CC3SetShdARR(CurSpeed,0);
  //取消16位到32位扩展,直接使用32位计数器 if(Iam==4) Tim3CC4SetShdARR(CurSpeed,0);
}

void StepMotor::Move(void)   //,uint16_t MinV,uint16_t MaxV)
{  
      switch(MovePhase)
      {
       case 0xff:   
                     if(Go0Finished==1) MovePhase=10; DisTimCCR();  //不需要等待回零的电机,Go0Finished初始化时直接置一
                     break;
//使用X电机脉冲控制电机走到指定的位置      
        case 10:   
                    CurSpeed=LowSpeed;
                    SetTimCCR();
                    MtDriver[Iam-1]->On=1;  //MtDrvA.On=1;        //??????????是否必须。。。。。。。。。。。。。。
                    if(Pos_Des==Pos_Pul) { Runing=0; StopCode=22; }     //20210316 Pos_Pul //20190227 避免已到指定位置后再次下指令Runing=1无法自动关闭
                    else  { MovePhase=11; vTaskDelay(80); CalTimes=0;    EnTimCCR();   v_CirpMin=0; }      //等待方向切换完成 //20210319  加入速度初始值为0的条件
                    break;
        case 11:   
                     if((dir>0)&&(Runing>0))  
                      {
                       if(Half_Pos>Pos_Pul)
                       {
                         v_CirpMin+=PidAdjust(v_CirpMin-vCirpMinDes);   
                         if((v_CirpMin+0.0015*vCirpMinDes)<vCirpMinDes)
                         {
                           if(SmodePhase<1) SmodePhase=1;
                         }
                         else { v_CirpMin=vCirpMinDes; SmodePhase=2;}    // ConvIndex++;
                       }
                      }

                     if((dir==0)&&(Runing>0))
                      {
                       if(Half_Pos<Pos_Pul)
                       {
                         v_CirpMin+=PidAdjust(v_CirpMin-vCirpMinDes);   
                         if((v_CirpMin+0.0015*vCirpMinDes)>vCirpMinDes)     //1  - 改为 +
                         {
                          if(SmodePhase<1) SmodePhase=1;
                         }
                         else { v_CirpMin=vCirpMinDes;  SmodePhase=2; }
                       }
                      }

                    ReFreshCnt();
                    CalTimes++;     //20211209  PID调整次数

                    if(Runing==0) { DisTimCCR();   MovePhase=12;  MtDriver[Iam-1]->On=0;   }  //MtDrvA.On=0;
                    break;
        case 12:  
                   v_CirpMin=PidAdjust(0);   
                   Half_Pos=Pos_Des;   
                   SmodePhase=0;  
                   MovePhase=0xff;  
                   break;
      }
}

使用特权

评论回复
板凳
90houyidai| | 2022-1-19 11:41 | 只看该作者
正转和翻转后归零情况咋样?

使用特权

评论回复
地板
ColeYao|  楼主 | 2022-1-19 12:20 | 只看该作者
本帖最后由 ColeYao 于 2022-1-19 12:33 编辑
90houyidai 发表于 2022-1-19 11:41
正转和翻转后归零情况咋样?

视频就是正转到某个位置8000(脉冲数/200*4=10圈),然后反转回0脉冲的位置(归零),从视频看应该是没有失步的(起始和结束位置是同一个位置,转了10圈)。

使用特权

评论回复
5
GlenX| | 2022-1-20 22:52 | 只看该作者
常规的步进电机转速都在3000rpm以下,功率大点的在1500以下,能更高的都是采用了特殊工艺和材料。
所以最好不要做太高转速的尝试,否则即使短时间不发热,也有发生失步的嫌疑。

使用特权

评论回复
6
ColeYao|  楼主 | 2022-1-21 10:50 | 只看该作者
GlenX 发表于 2022-1-20 22:52
常规的步进电机转速都在3000rpm以下,功率大点的在1500以下,能更高的都是采用了特殊工艺和材料。
所以最好 ...

  这个是知道的,只是空载不失步,实际带负载时能1000rmp不失步就不错了,一般步进电机不细分时推荐的最高速度为1000pps,转换后为5圈每秒即300rpm.

使用特权

评论回复
7
gdszzyq| | 2022-1-23 14:12 | 只看该作者
本帖最后由 gdszzyq 于 2022-1-23 15:42 编辑

看起来好复杂,不知道用PID方式加减速有什么好处,我都是用S曲线加减速的。我最高也只敢用到750RPM,不敢再高了,力矩下降实在太历害了,当然有闭环控制器除外,但用了闭环我觉得还不如直接上伺服。

使用特权

评论回复
8
ColeYao|  楼主 | 2022-1-23 17:38 | 只看该作者
本帖最后由 ColeYao 于 2022-1-23 19:14 编辑
gdszzyq 发表于 2022-1-23 14:12
看起来好复杂,不知道用PID方式加减速有什么好处,我都是用S曲线加减速的。我最高也只敢用到750RPM,不敢再 ...

PID方式加减速的好处是在很大的范围内比如1rpm~1000rpm,都可以做到S曲线平滑加速,并且是实时运算,不需要提前计算一组数组出来,一个数组对应一个速度。(即有采用固定数组控制S曲线运行类似的平滑曲线效果,又克服了采用固定数组时数组需要提前算好,无法实时运算的弊端,并且克服了采用固定数组时一个数组一般只能用于一个最大速度,无法做到适应各种最大速度运行的不便)

使用特权

评论回复
9
gdszzyq| | 2022-1-28 11:10 | 只看该作者
ColeYao 发表于 2022-1-23 17:38
PID方式加减速的好处是在很大的范围内比如1rpm~1000rpm,都可以做到S曲线平滑加速,并且是实时运算,不需 ...

用固定数组实现S算法的确有你说的那些弊端,那请问用PID加减速可以实现不同的加速模式吗?比如有时需要0.2秒加速到高速度,有时需要1秒加速到最高速度.谢谢指教!

使用特权

评论回复
10
ColeYao|  楼主 | 2022-1-29 14:30 | 只看该作者
gdszzyq 发表于 2022-1-28 11:10
用固定数组实现S算法的确有你说的那些弊端,那请问用PID加减速可以实现不同的加速模式吗?比如有时需要0. ...


一般PID加速起步阶段的加速度较大,接近设定速度时加速度较小,尽管曲线也是S曲线,但起点和终点并不对称,PID参数可以控制曲线大致的斜率,但是没法控制形状,要是想要形状尽量接近是标准曲线的话,可以对PID公式乘以一个正弦函数,要想控制从零到最大速度的加速时间,可以调整PID参数中的反馈强度参数,不过PID三个参数一般是需要同步调整的,以避免产生过冲或曲线上升过缓的现象。






使用特权

评论回复
11
wsnsyy| | 2022-2-8 15:27 | 只看该作者
实时转速怎么测

使用特权

评论回复
12
ColeYao|  楼主 | 2022-2-8 16:46 | 只看该作者
本帖最后由 ColeYao 于 2022-2-8 16:48 编辑
wsnsyy 发表于 2022-2-8 15:27
实时转速怎么测

不是很快的话就肉眼数一下一秒钟几圈,乘以60就是每分钟圈数,快的话就拿手机录个几秒的视频,然后慢放数圈数。

使用特权

评论回复
13
xumengyuanlinda| | 2022-3-18 14:36 | 只看该作者
有需要用到 板队板连接器(浮动连接器)的工程师吗?浮动连接器就是:可以弥补安装的定位误差,也可以适应 因振动产生位置偏移、或间隙存在的连接器即为浮动连接器。我们主要是日系KEL浮动连接器代理,在工控运动控制器行业已经有典型客户在用,需要了解的可以联系本人 18682337202 徐**

使用特权

评论回复
14
秋雨| | 2022-4-9 12:24 | 只看该作者
PID的话反馈是什么?加的测试电路?

使用特权

评论回复
15
GlenX| | 2022-10-12 20:02 | 只看该作者
实际感觉PID不如直接S控制!

使用特权

评论回复
16
ColeYao|  楼主 | 2022-10-14 13:37 | 只看该作者
GlenX 发表于 2022-10-12 20:02
实际感觉PID不如直接S控制!

    使用仿真工具软件评估的效果是差不多的!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

34

主题

353

帖子

5

粉丝