CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

2 motor control - accuracy problem

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

2 motor control - accuracy problem
PostPosted: Wed Jul 25, 2007 6:00 am     Reply with quote

I am trying to write some software which enables control of 2 stepper motors for fairly complex shapes. I have a version working which I am pretty happy with but there is an accuracy problem. The sw works by iterating through a list coordinates then does the following for each point:

- works out the difference between this point and the last point
- works out which direction (x or y) will need the greatest move for this stage (maxMove)
- Let's say maxMove is in the x direction, then the software will pulse the x motor for 'maxMove' times.
- Works out how many times to pulse the other motor during this time. (pulseCount);

Everything is done with integers at the moment so there is obviously a lacking degree of detail. So I would like to use decimals or floats or some technique to increase the accuracy. For instance if maxMove was 6 in the case above, and xMove was 4, then pulsecount would end up being 1, but it should be 2 in order to be more accurate. (i.e. decimal rounding up to nearest integer). Can anyone help steer me in the right direction to make this more accurate?!
jma_1



Joined: 08 Feb 2005
Posts: 147
Location: Wisconsin

View user's profile Send private message

PostPosted: Wed Jul 25, 2007 7:05 am     Reply with quote

Greetings,
What does the stepper motor control? How often are you determining the 'maxCount'? How are you determining what the longest move is (look up table from programmed sequence; physical measurement from sensor)?

Would it be possible to use an analog voltage or pulse counter, and combine it with PID? I think part of your accuracy problem might be the motion of what you are controlling with the stepper (inertia - start / stop; wheel slippage; etc).

Integer math is the way to go. Sometimes merely scaling the data to increase resolution is all it takes to improve performance.

Floats or decimals will cause large processing delays -> only 8 bit micro. I would avoid this direction if at all possible.

Cheers,
JMA
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

PostPosted: Fri Jul 27, 2007 11:12 am     Reply with quote

Hi jma_1 - thanks for your reply and sorry for my slow response. The program consists of 2 key loops. The first one loops through an array of coordinates such as 1000,400 or 1550,630. Each coordinate is the next position needed for the motors to draw the 'pattern' defined by the coordinates.

In the coordinates given above, if the motors have just moved to 1000,400 and the next move needed is to 1550,630 then:

lastPt = 1000,400;
thisPt = 1550,630; - where each of these is a coordinate defined in my code with two int16 properties x and y. i.e lastPt.x = 1000 and lastPt.y = 400.

Firstly I need to work out which axis the greatest distance to be moved is on, and I call this variable maxMove. In this case maxMove = 550 and is on the x axis.

Now I have another for loop (for j=1; j<maxMove+1;j++)

Obviously every time this loops I want to pulse the x axis motor but I only want to pulse the y axis motor 230 times.

Therefore every 550/230 cycles I need to unmask the pins to pulse the y axis. I call this variable pulseCount and in this case pulseCount = 2.39. However because I am only using integers, not floats this is where the innacuracy creeps in. In this case pulseCount would actually equal 2.

So for every 550 pulses of the x axis, the y axis would actually be pulsed 275 times.

I can work the innacuracy out in my code by comparing the required value with the 'actual' but how can I integrate this compensation into the loop that drives the motors? Or am I looking at this the wrong way....?!

Any thoughts/ideas/examples would be really appreciated.
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Fri Jul 27, 2007 11:32 am     Reply with quote

Maybe you are using stepper motors if so there is a relationship between the step ( or half step) and the physical movement. If this is true then your application space can be considered as if it were pixels ( a grid) with the pixel dimensions of the smallest physical change in position on an axis.
Take a look at the mathematics of finite differences especially Bresenham algorithms for lines and for circles.
Here is an example of some code for a CNC lathe I wrote several years ago. The LCD displays the current x y and z positions of the cutting head.
suppose the application space is 6"x6" and you can step 1/10000 the 16 bit integers are sufficient. The routine line moved the cutter from x1.y1 to x2,y2 in as straight a line as the ten thou accuracy of stepping would allow.

Code:

void line(int16 x1,int16 y1,int16 x2,int16 y2)
{
int16 i,line_length,x,y;
signed int16 deltax,deltay,accm_error;
signed int16 xchange,ychange;
// bresenham algorithm for lines

 X = x1 ;
 Y = y1;

DeltaX = x2 - x1;
DeltaY = y2 - y1 ;
Ychange=1;
Xchange=1;
current_pos[0]=x;
current_pos[1]=y;
 lcd_update(0,8,current_pos[0]);

   lcd_update(1,8,current_pos[1]);
If (DeltaX < 0 )
   {
    XChange = -1 ;
    DeltaX  = -DeltaX ;
   }




If (DeltaY < 0 )
    {
    YChange = -1;
    DeltaY  = -DeltaY ;
    }




accm_error = 0;
i = 0 ;

If (DeltaX < DeltaY)
    {
    Line_Length = DeltaY ;

    while (i < Line_Length && (busy) )
       {
        while(pause); /// del pressed while processing 2nd press resumes
        Y =Y + YChange ;
        if (YChange<0 ) step_motor(CClockwise,1);
        else step_motor(CLockwise,1);
        if(!busy) return; /// key other than <- -> or del was pressed causing an abort
        accm_error = accm_error + DeltaX ;

        IF (accm_error > DeltaY)
           {
            X = X + XChange  ;
           if (XChange<0 ) step_motor(CClockwise,0);
           else step_motor(CLockwise,0);
           if(!busy) return; /// key other than <- -> or del was pressed causing an abort
           accm_error = accm_error - DeltaY ;

           }

        i = i + 1 ;

       }
    }
else
    {
    Line_Length = DeltaX ;

     While (i < Line_Length && (busy))
      {
       while(pause);
        X =X + XChange ;

        if (XChange<0 ) step_motor(CClockwise,0);
           else step_motor(CLockwise,0);
         if(!busy) return; /// key other than <- -> or del was pressed causing an abort
        accm_error = accm_error + DeltaY;

        If (accm_error > DeltaX)
            {
            Y = Y + YChange;
            if (YChange<0 ) step_motor(CClockwise,1);
            else step_motor(CLockwise,1);
            if(!busy) return; /// key other than <- -> or del was pressed causing an abort
            accm_error= accm_error - DeltaX ;
            }

        i = i + 1;

      }
    }
//// make the last step

if (Y<y2) step_motor(CLockwise,1);
if (Y>y2) step_motor(CCLockwise,1);

if (X<x2) step_motor(CLockwise,0);
if (X>x2) step_motor(CCLockwise,0);
}

I found this code I wrote for ellipsoidal stuff
Code:

/// involute curve for gears x = a(cos(t) + t sin(t)), y = a(sin(t) - t cos(t))

void ellipse(int8 a,int8 b)

{
 int x,y,a2,b2, S, T;
////   x^2/b^2 + y^2/a^2 = 1

///// ellipse (bx)^2 +(ay)^2 =(a*b)^2
////  area of the ellipse is pi*a*b
 a2 = a*a;
 b2 = b*b;
 x = 0;
 y = b;
 S = a2*(1-2*b) + 2*b2;
 T = b2 - 2*a2*(2*b-1);
 symmetry(x,y);
 do
   {
    if (S<0)
       {
        S += 2*b2*(2*x+3);
        T += 4*b2*(x+1);
        x++;
       }
      else if (T<0)
          {
           S += 2*b2*(2*x+3) - 4*a2*(y-1);
           T += 4*b2*(x+1) - 2*a2*(2*y-3);
           x++;
           y--;
          }
         else
          {
           S -= 4*a2*(y-1);
           T -= 2*a2*(2*y-3);
           y--;
          }
    symmetry(x,y);
   }
 while (y>0);
}
jemly



Joined: 13 May 2007
Posts: 34

View user's profile Send private message

PostPosted: Mon Jul 30, 2007 7:50 am     Reply with quote

Hi Douglas - thank you so much!!!!I used the first bit of code you posted to guide me. What I'd originally written was very similar but I was using division which caused the innaccuracy whereas you were incrementing and resetting accm_error which did what I was trying to do but in a much better way!! All innacuracy has now gone. I've got one question - I don't entirely understand why the last section as follows is needed:

if (Y<y2) step_motor(CLockwise,1);
if (Y>y2) step_motor(CCLockwise,1);

if (X<x2) step_motor(CLockwise,0);
if (X>x2) step_motor(CCLockwise,0);

One other thing - I have made a small change so that the motors can be pulsed at the same time if necessary - I've found this gets a much smoother result so I thought I'd post the code for comments and for other peopke's info!

Code:

BYTE const POSITIONS[8] = {0b0000,      //0   OFF
                           0b0100,      //1   BWD
                           0b1100,      //2   FWD
                           0b0001,      //3   RIGHT
                           0b0011};     //4   LEFT


      if(deltaX < deltaY)
      {
         maxMove = deltaY;
     
         //motor pulse loop
         while(j < maxMove)
         {
            y = y + yChange;

            if(yChange < 0) NextDir = POSITIONS[1]; //pulseMotors(POSITIONS[1],i); //y axis bkwd
            else NextDir = POSITIONS[2];//pulseMotors(POSITIONS[2],i); // y axis fwd

            adjerror = adjerror + deltaX;

            if(adjerror > deltaY)
            {
               x = x + xChange;
               if(xChange<0)
               {
                  NextDir = NextDir | POSITIONS[4];//pulseMotors(POSITIONS[4],i); //x axis left
               }
               else
               {
                  NextDir = NextDir | POSITIONS[3]; //pulseMotors(POSITIONS[3],i); //x axis right
               }
               adjerror = adjerror - deltaY;
            }
           
            j = j +1;

            //actually pulse the motor
            pulseMotors(NextDir, i);
         }

      }
      else
      {
         maxMove = deltaX;
     
         //motor pulse loop
         while(j < maxMove)
         {
            x = x + xChange;

            if(xChange < 0) NextDir = POSITIONS[4];//pulseMotors(POSITIONS[4],i); //x axis left
            else NextDir = POSITIONS[3];//pulseMotors(POSITIONS[3],i); // x axis right

            adjerror = adjerror + deltaY;

            if(adjerror > deltaX)
            {
               y = y + yChange;
               if(yChange<0)
               {
                  NextDir = NextDir | POSITIONS[1];  //pulseMotors(POSITIONS[1],i); //y axis bkwd
               }
               else
               {
                  NextDir = NextDir | POSITIONS[2];//pulseMotors(POSITIONS[2],i); //y axis fwd
               }
               adjerror = adjerror - deltaX;
            }
           
            j = j + 1;

            //actually pulse the motor
            pulseMotors(NextDir, i);

         }
[/code]
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Tue Jul 31, 2007 3:15 am     Reply with quote

First much thanks needs to go to PCM programmer Mark and others.
By standing on their shoulders I was able to see much further into the PIC world than I ever would have done alone.
Quote:

I don't entirely understand why the last section as follows is needed:

if (Y<y2) step_motor(CLockwise,1);
if (Y>y2) step_motor(CCLockwise,1);

if (X<x2) step_motor(CLockwise,0);
if (X>x2) step_motor(CCLockwise,0);

It isn't needed the math does it all assuming it compiles correctly that is . This code was an unnecessary redundant guarantee that the end point ( x2,y2) is always reached.
Pulsing the motors at the same time is a good feature ....I was driving a 150 in oz stepper using a used PC switching power supply into an H bridge with 50 amp FET's so total power draw was a factor.
The line circle etc algorithms usually used for pixelated LCD screens are very useful for steppers when you treat a step as a pixel. The finite difference logic the algorithms use can be applied to other curves.
fkl



Joined: 20 Nov 2010
Posts: 44

View user's profile Send private message

PostPosted: Wed Nov 28, 2012 12:36 am     Reply with quote

What code for this function?
Code:
step_motor(CLockwise,1);
fkl



Joined: 20 Nov 2010
Posts: 44

View user's profile Send private message

PostPosted: Wed Jan 23, 2013 11:50 am     Reply with quote

Hello
I do CNC controller, already with all figured out, but I can not understand how do the right increase speed with constant acceleration for stepper motors. Please tell me how to do it right.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Jan 23, 2013 2:37 pm     Reply with quote

How do you set/control speed?

Mike
fkl



Joined: 20 Nov 2010
Posts: 44

View user's profile Send private message

PostPosted: Thu Jan 24, 2013 12:11 am     Reply with quote

Mike Walne wrote:
How do you set/control speed?

Mike

Apply a timer, the delay timer is a variable speed 16-bit.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Thu Jan 24, 2013 3:30 pm     Reply with quote

I was anticipating that you might be a little more specific about how you set the speed.

I'll rephrase the question.

What calculation do you perform to set the speed at say 2 revs per second?

Mike
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group