|
|
View previous topic :: View next topic |
Author |
Message |
jemly
Joined: 13 May 2007 Posts: 34
|
2 motor control - accuracy problem |
Posted: Wed Jul 25, 2007 6:00 am |
|
|
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
|
|
Posted: Wed Jul 25, 2007 7:05 am |
|
|
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
|
|
Posted: Fri Jul 27, 2007 11:12 am |
|
|
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
|
|
Posted: Fri Jul 27, 2007 11:32 am |
|
|
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
|
|
Posted: Mon Jul 30, 2007 7:50 am |
|
|
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
|
|
Posted: Tue Jul 31, 2007 3:15 am |
|
|
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
|
|
Posted: Wed Nov 28, 2012 12:36 am |
|
|
What code for this function?
Code: | step_motor(CLockwise,1); |
|
|
|
fkl
Joined: 20 Nov 2010 Posts: 44
|
|
Posted: Wed Jan 23, 2013 11:50 am |
|
|
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
|
|
Posted: Wed Jan 23, 2013 2:37 pm |
|
|
How do you set/control speed?
Mike |
|
|
fkl
Joined: 20 Nov 2010 Posts: 44
|
|
Posted: Thu Jan 24, 2013 12:11 am |
|
|
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
|
|
Posted: Thu Jan 24, 2013 3:30 pm |
|
|
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 |
|
|
|
|
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
|