ColeYao 发表于 2022-1-18 09:45

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

本帖最后由 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;   

extern StepMotor*   Motor;

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

float KSin=               //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*(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*(ErrIn+PreK*(ErrIn-ErrInL));
ErrInLL=ErrInL;
ErrInL=ErrIn;
CalResult=temi;
return(temi);
}

voidStepMotor::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_tGPIOxPin;
        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=(1-cos(3.1415926*i/256))/2;   //20190116
      if(KSin<0.03)KSin=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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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);
            elseLL_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); elseHAL_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);elseHAL_GPIO_WritePin(MyGPIOAn_Dir,MyAn_DirPin,GPIO_PIN_SET);
   }
   else
   {
   Half_Pos=Pos_Des;
   Half_Step=0;
   dir=0;   
   }
if(Motor->dir==Motor->RevDir)   MtDriver->MtCCW;else   MtDriver->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->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++;   //20211209PID调整次数

                  if(Runing==0) { DisTimCCR();   MovePhase=12;MtDriver->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圈)。

GlenX 发表于 2022-1-20 22:52

常规的步进电机转速都在3000rpm以下,功率大点的在1500以下,能更高的都是采用了特殊工艺和材料。
所以最好不要做太高转速的尝试,否则即使短时间不发热,也有发生失步的嫌疑。

ColeYao 发表于 2022-1-21 10:50

GlenX 发表于 2022-1-20 22:52
常规的步进电机转速都在3000rpm以下,功率大点的在1500以下,能更高的都是采用了特殊工艺和材料。
所以最好 ...

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

gdszzyq 发表于 2022-1-23 14:12

本帖最后由 gdszzyq 于 2022-1-23 15:42 编辑

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

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曲线运行类似的平滑曲线效果,又克服了采用固定数组时数组需要提前算好,无法实时运算的弊端,并且克服了采用固定数组时一个数组一般只能用于一个最大速度,无法做到适应各种最大速度运行的不便)

gdszzyq 发表于 2022-1-28 11:10

ColeYao 发表于 2022-1-23 17:38
PID方式加减速的好处是在很大的范围内比如1rpm~1000rpm,都可以做到S曲线平滑加速,并且是实时运算,不需 ...

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

ColeYao 发表于 2022-1-29 14:30

gdszzyq 发表于 2022-1-28 11:10
用固定数组实现S算法的确有你说的那些弊端,那请问用PID加减速可以实现不同的加速模式吗?比如有时需要0. ...


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





wsnsyy 发表于 2022-2-8 15:27

实时转速怎么测

ColeYao 发表于 2022-2-8 16:46

本帖最后由 ColeYao 于 2022-2-8 16:48 编辑

wsnsyy 发表于 2022-2-8 15:27
实时转速怎么测
不是很快的话就肉眼数一下一秒钟几圈,乘以60就是每分钟圈数,快的话就拿手机录个几秒的视频,然后慢放数圈数。{:lol:}

xumengyuanlinda 发表于 2022-3-18 14:36

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

秋雨 发表于 2022-4-9 12:24

PID的话反馈是什么?加的测试电路?

GlenX 发表于 2022-10-12 20:02

实际感觉PID不如直接S控制!

ColeYao 发表于 2022-10-14 13:37

GlenX 发表于 2022-10-12 20:02
实际感觉PID不如直接S控制!

    使用仿真工具软件评估的效果是差不多的!
页: [1]
查看完整版本: 第一次发视频,发一个PID方式控制步进电机的运行测试视频