Arduino开发板实验四:步进电机控制

上周总算做成了点事,其实很简单,就是用Arduino实现了步进电机的正转和反转。因为总是很忙,所以拖到现在才有时间补上攻略。感慨一下,IT民工真辛苦啊,有位同事的昵称已经改成 “还是古代好,切掉小JJ就可以当公务员了”。 好吧,祝这位朋友心想事成,我还是坚持当民工好了 :)

在步进电机实验前,从网上找到了一个关于步进电机驱动的文档,使用的是L298N的驱动芯片。这个文档里面有些错误,导致我浪费了大量时间。也许不同的电机和芯片版本也许有区别吧,请大家慎重使用。先借用一下原理图:

L298N步进电机驱动芯片原理图

错误的L298N步进电机驱动芯片原理图

其中IN1~IN4以及ENA,ENB在之前的一篇关于直流电机驱动中有介绍过,分别对应输入的六个管脚。这个图里有两处错误,首先可以看到有两个ENA,其中一个应该是ENB;另外这两个EN都是接地的,但是经我实验看来,应该接+5V的电压才对。

所以正确的原理图应该是这样的:

正确的L298N原理图

正确的L298N原理图

下面是对应的接线图:

乱七八糟的接线图

乱七八糟的接线图

接线之后按照说明书里的时序图写了一段程序,呼呼,一次就通过了电机的正转实验。可是在企图实现反转的时候,总是不成功。在焦头烂额之后,终于开始怀疑文档是否正确。事实证明,大家做任何事情都要相信伟大的党而不是万恶的“文档”,下面是错误的反转时序图和经我验证可行的时序图:

步进电机驱动的时序图

步进电机驱动的时序图

基于以上时序图,我写了一段代码,让步进电机实现下面的动作:
正转一圈 -> 暂停1秒钟 -> 反转一圈 -> 暂停一秒钟 ->循环

代码如下:

int LeftI1 = 28;     //连接电机驱动板的I1接口
int LeftI2 = 22;     //连接电机驱动板的I2接口
int LeftEA = 8;      //连接电机驱动板的EA接口
int RightI1 = 36;    //连接电机驱动板的I1接口
int RightI2 = 42;    //连接电机驱动板的I2接口
int RightEB = 6;     //连接电机驱动板的EB接口
int StepCount = 0;
int StepDelayTime=1500;

void setup()
{
  pinMode(LeftI1, OUTPUT);     //I1和I2都是数字信号
  pinMode(LeftI2, OUTPUT);     //通过设置I1和I2来控制电机旋转方向
  pinMode(LeftEA, OUTPUT);     //按占空比方式输出的模拟信号
  pinMode(RightI1, OUTPUT);    //I1和I2都是数字信号
  pinMode(RightI2, OUTPUT);    //通过设置I1和I2来控制电机旋转方向
  pinMode(RightEB, OUTPUT);    //按占空比方式输出的模拟信号
  Serial.begin(9600);          //设置波特率
}
void ForwardInit()
{
  digitalWrite(LeftEA, HIGH);
  digitalWrite(RightEB,HIGH );
  digitalWrite(LeftI1, LOW);
  digitalWrite(LeftI2,HIGH );
  digitalWrite(RightI1,HIGH);
  digitalWrite(RightI2, HIGH);
  StepCount=0;
}
void BackwardInit()
{
  digitalWrite(LeftEA, HIGH);
  digitalWrite(RightEB,HIGH );
  digitalWrite(LeftI1, LOW);
  digitalWrite(LeftI2,LOW );
  digitalWrite(RightI1,LOW);
  digitalWrite(RightI2, HIGH);
  StepCount=0;
}
void ForwardOneStep()
{
  delayMicroseconds(StepDelayTime);
  switch(StepCount)
  {
    case 0:
      digitalWrite(RightI2,LOW);
      digitalWrite(LeftI1,HIGH);
      break;
    case 1:
      digitalWrite(RightI1,LOW);
      digitalWrite(RightI2,HIGH);
      break;
    case 2:
      digitalWrite(LeftI2,LOW);
      digitalWrite(RightI1,HIGH);
      break;
    case 3:
      digitalWrite(LeftI1,LOW);
      digitalWrite(LeftI2,HIGH);
      break;
  }
  StepCount=(StepCount + 1) % 4;
}

void BackwardOneStep()
{
  delayMicroseconds(StepDelayTime);
  switch(StepCount)
  {
    case 0:
      digitalWrite(RightI2,LOW);
      digitalWrite(LeftI1,HIGH);
      break;
    case 1:
      digitalWrite(LeftI1,LOW);
      digitalWrite(LeftI2,HIGH);
      break;
    case 2:
      digitalWrite(LeftI2,LOW);
      digitalWrite(RightI1,HIGH);
      break;
    case 3:
      digitalWrite(RightI1,LOW);
      digitalWrite(RightI2,HIGH);
      break;
  }
  StepCount=(StepCount + 1) % 4;
}

void loop()
{
  while(1)
  {
    ForwardInit();
    for(int i=0;i<200;i++)
    {
      ForwardOneStep();
    }
    delay(1000);
    BackwardInit();
    for(int i=0;i<200;i++)
    {
      BackwardOneStep();
    }
    delay(1000);
  }
}

除了实现了动作之外,我还搭车实验了下面几件事情:

1,步进电机的转角相当精确,我捆了根电线当指针,反复转了几百圈之后,指针的位置几乎没有变化

2,扭矩还挺大,我选用的是标称扭矩是3.4Kg.cm的步进电机,用铅酸蓄电池供电,旋转时我用爪子完全不能把它捏住(NXT的电机貌似没有这么强劲)。

3,经我测试,每个脉冲之间的间距最好大于1500μs(1.5ms),如果间距太小的话,就会出现失步的情况。

思考问题:基本上来说,每个步进电机都需要一个驱动板(L298N)和一个控制板(Arduino或其它单片机)。如果需要控制多个电机的话(小爱也许会有20多个关节),买这么多板子成本就太高了。实际上,每个脉冲间距之间有1500微秒的空闲时间,对CPU来说简直是漫漫长夜。所以我觉得可以用类似于操作系统多任务的思想来生成时序,充分利用脉冲间距之间的剩余价值,这样就可以只用一块Arduino实验板来控制多个电机了。

呵呵,又想多了,等下周有空再试试吧!



对 “Arduino开发板实验四:步进电机控制” 的 34 条 评论

  1. 又是一技术牛人。膜拜

  2. lemon 说:

    hi,博客又更新了呢,呵呵,顺便想请教下建bolg的话购买虚拟主机能给个建议吗,比如这个博客,谢谢啦~

  3. SEVEN 说:

    真实牛人,能折腾。 佩服

  4. 沉冰浮水 说:

    话说。。你博客的名字一直就这么XE吗?
    ———-
    笑话不需要分类,只需要全文订阅。。

  5. 牌技 说:

    偶头一次来,
    偶就支持一下,
    偶其实应该说我。

  6. 这么专业的东西
    基本上很难看明白

  7. 北屯 说:

    有些东西很难超越的哈!

  8. Arduino 说:

    Arduino多个步进电机的控制可以实现阿,我都做出来拉,可以控制它的速度,还有脉冲个数阿。

  9. 动力老男孩 说:

    你是怎么做的呢,如果Arduino支持多线程的话就方便了
    但是没有查到相关的资料
    我的想法是做一个Timer对象来模拟多线程
    这样可以控制多个电机,并分别控制它们的转速

  10. 锋儿 说:

    我有办法让它控制多个电机,在循环语句中加N++,用条件语句判断N等于多少了发个脉冲,几个电机几个IF,速度要求快的电机N值可小,N值大就会变慢。

    • 没错,这样可以控制多个电机
      其实这个相当于是模拟了多个线程
      但是我觉得这个方法还需要再优化
      因为这种方式下,一块Arduino板只能用来控制(多个)电机
      没法做别的事情
      不知道能不能用控制电机的闲余时间做点其他的逻辑

  11. 机械工程 说:

    你好!请问下,我想闭环控制直线电机的运动,就是用位移传感器测直线电机的位移,然后将传感器采到的信号给开发板,开发板根据自己写的算法计算出输出信号,然后在将输出的信号(电压信号)传给电机,驱动电机运动。
    您觉得我用开发板可以实现吗?有合适的开发板可以推荐下吗?

    • 就arduino就可以,传感器输入0~5V的电压给开发板,对应到0~1024的读数

    • darkorigin 说:

      对于简单的算法来说和硬件关联不大,毕竟是在ARDUINO的处理能力以内(毕竟ARDUINO等单片机擅长的就是控制和采集)
      建议好好的看语言和算法,吃透了就很简单

  12. yangqq 说:

    你好,拜读了您的大作。我想用一个arduino控制4个不同的步进电机(4个独立的,不需要相互配合工作),用什么办法比较好呢?

  13. roger_gao 说:

    请问下,我是新手,我正在用arduino UNO和L298N控制一个步进电机。因为是新手,查了很多的网上资料,对于实现步进电机的预想功能感到很迷茫,希望能够指教一下。

    我的步进电机需要 1、通过改变频率控制步进电机的速度(pwm指令输出吧,但是具体不知道怎么操作) 2、改变脉冲的个数控制步进电机的行程 3、要实现步进电机某项功能的循环输出(猜想是不是用while指令啊,不是很会用)

  14. DIY learner 说:

    你好,看了你的文章我受益匪浅。我准备在做一个遥控智能小车(比市面上的遥控车大点)。控制板子是用arduino uno,电机驱动板子是l298n,不知道选多大转矩的电机和相应的蓄电池供电,希望你能帮我出出注意!谢谢啦!

    • 市面上的普通遥控小车,就是用的直径20mm到30mm左右的有刷直流电机
      这种电机转速比较快,所以一般要通过齿轮组来减速
      电池就用那种一节一节的充电锂电池组合起来就可以

  15. haiyi 说:

    楼主按照上面的接线,用uno+298,通电后像堵转现象,不知道啥问题,out1,2是不是应该接motor1??

  16. DLJ 说:

    EN称为使能端,其特点是高电平有效,低电平是相当于将逻辑器件置于高阻态,可以视为将这个逻辑器件从图中移走,不影响其他部分器件的工作。由于驱动板的图中,EN并没有取反,所以还是高电平有效。这就是,这个驱动板中EN要接高电平的原因。

    freshman才看到,首发。就全当是为了积极参与讨论吧。

  17. 令狐冲 说:

    你好,拜读了您的作品。我想用一个arduino控制3个不同的步进电机(4个步进电机需要相互配合工作),用什么办法比较好呢?

  18. 令狐冲 说:

    你好,拜读了您的作品。我想用一个arduino控制3个不同的步进电机(3个步进电机需要相互配合工作),用什么办法比较好呢?

  19. 沙罗 说:

    你好,我是一个新手,目前是做一个小项目,可是完全不懂。就是通过光电感应器感应到没有物料的存在则步进电机正转,有物料则停止运动。
    1、需要的设备:两个按钮(启动与急停)、光电感应器、Arduino UNO(微控制器)、Arduino L298N
    2、问题:我选的设备是否正确?
    按钮就是数字输入,光电感应属于模拟量输入,而步进电机属于数字输出?
    就这两方面的问题,麻烦回复下,谢谢。

  20. 星陨 说:

    请问loop循环中200怎么算出来的呢

发表评论

可以使用下列 XHTML 标签:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>