【丁丁历险记】使用4988控制多个步进电机异步工作


  • 本节教大家解决在控制步进电机时如何让多个步进电机以不同的速度不同的脉冲数同时工作。有些类似于3D打印机中Marlin固件的实现原理。可以做到变速精准控制。

一、4988控制电机原理

  • 4988是在控制步进电机最常用的驱动。在RAMPS系列的控制板中支持的也非常好。其控制方法非常的简单,在连接好电源的情况下在STEP引脚输出一个脉冲即可,步进电机会朝着指定方向走一步。

  •  一个驱动对应着一个电机,DIR引脚用于控制方向,ENA用于控制芯片的工作使能,默认为低电平(启动)。步进电机的4个引脚两两相通,如图所示,可以使用电压表的通断档进行测量。

二、控制问题分析

  •  在控制一个电机时旋转三个脉冲,只需要产生三次脉冲即可,以下均用伪代码实现。
pin_Dir = HIGH; //给定一个方向
for(int i=0;i<3;i++){
    pin_Step = HIGH;  //高电平
    delayUS(1500);
    pin_Step = LOW;   //低电平
    delayUS(1500);
}
  • 这样会产生三个脉冲信号如下图所示。

     

  • 当使用两个电机的时候,如果还用这个方法,实现同时运转就不能控制每个电机运转的步数,举一个反例:

  •  

    反例1:可以控制步数,不能同时运动

     

    //电机一先运动
    pin_Dir = HIGH; //给定一个方向
    for(int i=0;i<3;i++){
        pin_Step = HIGH;  //高电平
        delayUS(1500);
        pin_Step = LOW;   //低电平
        delayUS(1500);
    }
    
    //电机二再运动
    pin2_Dir = HIGH; //给定一个方向
    for(int i=0;i<3;i++){
        pin2_Step = HIGH;  //高电平
        delayUS(1500);
        pin2_Step = LOW;   //低电平
        delayUS(1500);
    }

    波形如下

    可以看到输出波形中,电机是先输出第一个的控制信号再输出第二个的。

  • 反例2:同时控制,但是不能单独进行电机脉冲的控制

pin_Dir = HIGH; //电机1运动方向
pin2_Dir = HIGH; //电机2运动方向
for(int i=0;i<3;i++){
    pin_Step = HIGH;  //电机1高电平
    pin2_Step = HIGH;  //电机2高电平
    delayUS(1500);
    pin_Step = LOW;   //电机1低电平
    pin2_Step = LOW;   //电机2低电平
    delayUS(1500);
}

      很容易就可以理解上面是如何工作了的,就不补充波形了

  • 反例3:最容易犯的错误,速度控制问题
  • 可能有的同学看到反例1的时候就想使用微分的思想将 电机只运行一步,然后通过改变循环数量来控制电机,具体实现的方法多种多样,但是如果你的代码中出现以下部分,在大量的循环后就会出现问题
pin_Step = HIGH;  //电机1高电平
delayUS(1500);
pin_Step = LOW;   //电机1低电平
delayUS(1500);
pin2_Step = HIGH;  //电机2高电平
delayUS(1500);
pin2_Step = LOW;   //电机2低电平
delayUS(1500);

      只要你的函数中产生了这样的循环体,那么电机的运行速度上一定会出现问题。看起来延迟都是一样的,但是电机1的脉冲在低电平的部分其实已经整合了电机2的延迟时间。也就是虽然延迟相同但是,电机1的高电平时间是1500ms,低电平的时间为1500ms * 3 即4500ms;因此循环时则会产生速度不同的问题,切次方法的电机速度难以控制。

从占空比的对比可以看出低电平一直都在整合前一个电机的高电平所使用的时间。虽然做到了同时控制,但是单个电机的运行速度始终受到其他电机的影响。

三、解决方案,利用时间轴控制

  • 无论脉冲在何时产生,在何时结束,都会在时间上有所体现。在若将上述图标中的横座标看做成时间轴,那么通过对IO在不同时间上的变换,就可以实现对多个电机的准确定时控制。
  • 使用定时器来产生脉冲,通过对占空比的计算将多个电机的输出整合在时间轴上进行实现。
    Motor.ioState //当前时间IO的输出状态,bool
    Motor.turnSpeed  //电机旋转的速度uint8
    Motor.speedCopy  //电机旋转的速度uint8
    Motor.step    //需要旋转的脉冲数量int
    
    void timeInterruption(){
      countIndex += 1;
      /*xy轴输出状态*/
      digitalWrite(X_STEP,MotorX.ioState);
      digitalWrite(Y_STEP,motorY.ioState);
    
      /*下面则是判断在时间轴上电机的应该处于的状态*/
      if(MotorX.step> 0){
        MotorX.turnSpeed -= 1 ;
        if(MotorX.turnSpeed <= 0){
          MotorX.ioState= !MotorX.ioState;
          MotorX.turnSpeed = MotorX.speedCopy;
          MotorX.step-= 1;
        }
      }
      if(motorY.step> 0){
        motorY.turnSpeed -= 1 ;
        if(motorY.turnSpeed <= 0){
          motorY.ioState= !motorY.ioState;
          motorY.turnSpeed = motorY.speedCopy;
          motorY.step-= 1;
        }
      }
      if(MotorX.step<= 0 and motorY.step<= 0  ){
        countIndex = 0;
      }
    }
  • 以上则是通过判断脉冲的时间状态,来改变IO的ioState。

    产生波形如上图所示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章