步进电机多轴联动算法

       声明:本博客文档均由我本人编写,如需转载请先联系我。

         本人可是要做机械臂的人啊!在控制步进电机多轴联动的时候遇到过以下问题,刚开始实现步进电机联动的时候,采用简单的斜率法。。。。,实现原理就是找出最大和最小值的斜率,然后步数最多的轴先动,每走斜率的那么多的步数,次轴才走,这只是两轴的,要是更多的轴岂不是恶心死?每个轴都求斜率。。。。嗯,代码太丑了,舍弃吧,而且精度还存在一定的问题,主要是求斜率存在除法。。。。这简直不允许啊,舍弃了舍弃了。。。

        什么是多轴联动控制呢?我们知道在机械臂或者3D打印机中,几个轴总要“同时启动”,“同时停止”,因为不可能说,A轴你先动,然后B轴再动,这在很多场合是不允许的,比如六轴。。你一步我一步的走,得多丑啊。。。而且还可能会产生奇葩的姿态。总之联动控制就是,几个电机同时启动同时停止,并且步数均匀分配。

        国内资料较少,实际上可能是大家也不愿意分享吧,导致在学习与共同进步的道路上困难重重。一般直接百度是找不到的,都是一些乱七八糟的资料,很难有一篇从理论到实践的完整文档,我希望这篇文章能够给一些想搞这方面技术的人一些帮助,并且我也想得到别人的帮助,毕竟还是有很多问题想向大佬们学习一下。

        一开始的学习是百度开始,CSDN搜索资料,嗯。。。结果你懂的。。。。乱七八糟一堆资料,知道我去研究了以下开源3D打印固件Marlin的代码,嗯,这个确实是我想要的!,大家感兴趣可以去github搜一下这个固件,这个就牛逼了,这个算法,我都想不到。。。当然我能想到这个算法那还得了。。。看了一下这个实现原理,并且去研究了一下这个理论知识,这竟然是:计算机绘图学里的Bresenham法。。而我之前哪个斜率的就是DDA法。。。在marlin固件中借鉴了Bresenham法,转化为了步进电机多轴联动算法,这个太厉害了。。。

        回归正题,现在我知道了多轴联动可以使用bresham法转化过来,并且由Marlin固件源码作为参考,那么我们先来学习理论吧。。。基础知识。。。这个,会加减乘除,直线的一些定理都能算了。

        Bresenham算法

        关于此算法的实际,请大家自行百度啦,这里我以步进电机为例进行推导,先从简单的二轴联动开始,首先我们把其中一个轴称x轴、第二轴称y轴,(联动的结果相当于在坐标系上绘制了一条直线,但是都是以步数最多的轴作为参考)在坐标系上就代表一个点,刚开始时是在原点,那么我们把运行步数最多的轴定为x轴,步数少的定为y轴,那么还是联动的老问题,我x轴走几步你y轴才能走一步呢?按之前我的想法就是x每走一步,y就走y+k步,k是斜率,而在此算法中的想法是,我走了这一步,真实的y和计算出来的y距离短还是我不走这一步真实的y和计算出来的y距离短呢?显然它想用计算出来的离y最短的距离来代替真实的y,或者他们的距离相等时,Y就输出一步,而在我们的步进电机里显然不想再计算斜率K了,因此,考虑最后一种方式,就是判断他们离Y的距离相等,就输出Y+1步,否则就不输出。

        说得太乱了,直接贴理论吧,原理不难理解,大家可以自己演算一下。








        以上就是Bresenham算法的推导过程,大家可以自己演算,我觉得自己再算过一遍会更踏实一些,好,理论推导完毕,怎么应用到联动控制里边呢?

        那我们先要确定出X的值,所有轴的步数都是相当于Y就可以了,比如一个3轴,我x轴输出30,y轴输出20,z轴输出10,则选取最大的步数值作为X,则所有的轴都是Y,即转化到bresenham当中为3条直线,其中初始位置都是(0,0),x轴对应的坐标为(30,30),y轴对应的坐标为(30,20),z轴对应的坐标为(30,10),则各自的ΔY就是本身输入的步数,ΔX都是最大步数30。

        我们变换一下想法,为了减少计算量,我们将所有的公式左右两边都除以2(程序中只需要右移>>1).则只要Pi还是小于零, Pi+1 = Pi + ΔY

        若Pi > 0   Pi+1 = Pi + ΔY - ΔX,

        相信聪明的小伙伴一经发现了 Pi +ΔY 只用算一遍就够了,只有在Pi > 0 的情况下 再减去ΔX就可以了。

        需要注意的是P1 =  ΔY - ΔX/2,

        从marlin固件中提取出了多轴breshenham算法如下:采用Arduino Uno(ATMega328)实现例程控制3轴联动如下:

int step_even_count; // 步数计数
int step_x,step_y,step_z; //各轴输出的步数 ΔY
int count_x,count_y,count_z;//各轴的Pi
int step_completed;//步数计数器

void setup() {
step_x=1600;
step_y=800;
step_z=400;
step_even_count = max(step_x,step_y);
step_even_count = max(step_z,step_even_count);//取各轴最大值作为X(ΔX)
count_x = -(step_even_count>>1);//-ΔX/2  ΔX➗2,后边所有数据都是除2处理 
count_y = count_x;
count_z = count_x;


pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
digitalWrite(2,1);
digitalWrite(8,1);
Serial.begin(9600);
}



void loop() {
  // put your main code here, to run repeatedly:
  // ΔX都是一致的
  // < 0 Pi + ΔY
  // > 0 Pi + ΔY - ΔX
  //并且应该注意到 P1 = ΔY - ΔX/2
  while(step_completed<step_even_count)
  {
      count_x+=step_x;  //计算小于0 的情况 = Pi + ΔY
      if(count_x>0)		//Pi >0
      {
        digitalWrite(3,1);		  //输出一个脉冲
        count_x-=step_even_count; //由于Pi + ΔY已经计算,此处直接减去ΔX即可
        digitalWrite(3,0);
        }

         count_y+=step_y;
      if(count_y>0)
      {
        digitalWrite(9,1);
        count_y-=step_even_count;
        digitalWrite(9,0);
        }

       count_z+=step_z;
      if(count_z>0)
      {
        digitalWrite(10,1);
        count_z-=step_even_count;
        digitalWrite(10,0);
        }
   step_completed+=1;
   delayMicroseconds(300);//脉冲间隔
    }
   while(1);
}

好吧,这就是Marlin固件中的多轴联动控制了,能想到这样控制的人真厉害可怜,我也只是重新推导了而已。

大家多留言评论一下给我点创作的动力,后面还有好多详细的算法还会分享,都是经过本人从理论论证到实践使用的算法。或者直接和我交流共同进步。

        

猜你喜欢

转载自blog.csdn.net/Renjiankun/article/details/80555251
今日推荐