Motor Shield for CNC plotter problem

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
lazygeorge
 
Posts: 8
Joined: Wed Feb 09, 2011 8:11 pm

Motor Shield for CNC plotter problem

Post by lazygeorge »

Hi,

I'm hoping someone with stepper CNC control experience can help me with this one.

I have Duemilanove with Adafruit motor shield controlling two stepper motors and and a small servo for a simple CNC type setup. Like a plotter, the motors run the x and y axis and the servo lifts a pen/cutter up or down for the z axis. G code is sent to arduino via serial a line at a time and arduino calculates the speed or stepper motors and servo etc. The G-code is only sending straight line commands, so the steppers do not change speed, they run at the same speed between co-ordinates.

The way I have calculated the speeds for the steppers for each move is like this -

I know the distance needed to travel for both the X motor and the Y motor to reach the co-ordinate, lets say X needs to travel 100 steps and Y needs to travel 50 steps simultaneously.

So I set the X motor (running the longest distance) to a set speed, say 100 steps a second. Then I calculate the speed of Y motor (running the shorter distance) to Y.distance(50) / X.distance(100) * X.speed(100). So Y should be running at 50 steps a second, stopping at the same time as X.

So I figure both motors should arrive at their co-ordinates at the same time using this method. But they don't! There seems to be a difference, so that although they are changing their speeds accordingly, they don't arrive at their destination at the correct time. One of the motors seems to carry on running a bit longer than the other. I can't seem to find out why this is.

All the values I'm using are floats so I don't think anything is lost by converting integers to floats.

Here's the code described above:

(delta_steps is just the number of steps that the each motor needs to make)

Code: Select all

    if (delta_steps.x !=0 && delta_steps.y !=0){            //if both motors are moving
            if (abs(delta_steps.x) > abs(delta_steps.y))     //if x distance is longer than y distance
            {
             stepperx.setMaxSpeed(max_speed);
             stepperx.setAcceleration(max_speed);             
             steppery.setMaxSpeed((abs(delta_steps.y)/abs(delta_steps.x))*max_speed);
             steppery.setAcceleration((abs(delta_steps.y)/abs(delta_steps.x))*max_speed);          }
          else
          {
             steppery.setMaxSpeed(max_speed);
             steppery.setAcceleration(max_speed);             
             stepperx.setMaxSpeed((abs(delta_steps.x)/abs(delta_steps.y))*max_speed);
             stepperx.setAcceleration((abs(delta_steps.x)/abs(delta_steps.y))*max_speed);   
          }
    }
    else {
        stepperx.setMaxSpeed(max_speed);
        steppery.setMaxSpeed(max_speed);
        stepperx.setAcceleration(max_speed);
        steppery.setAcceleration(max_speed);
    }
You will notice the acceleration variable is there too. This doesn't seem to have any effect on the problem if I change this,for example if I set maximum acceleration to the steppers so they both move full speed immediately, one of the motors is still delayed.

Any help greatly appreciated. I am using both the Adafruit library and Accelstepper library to run the motors. All the code etc can be found here

http://www.maxlivesey.co.uk/maxtest/arduino/gcoder.zip

adafruit
 
Posts: 12151
Joined: Thu Apr 06, 2006 4:21 pm

Re: Motor Shield for CNC plotter problem

Post by adafruit »

you can try using without the accel library, to determine if that is not the problem

lazygeorge
 
Posts: 8
Joined: Wed Feb 09, 2011 8:11 pm

Re: Motor Shield for CNC plotter problem

Post by lazygeorge »

Thanks for your reply,

Yes, I could take out Accel library, but I want to run two steppers simultaneously - which seems to be a bit tricky for me using AFmotor. That's why I'm using Accel library. Can I run two motors simultaneously with AFmotor?

adafruit
 
Posts: 12151
Joined: Thu Apr 06, 2006 4:21 pm

Re: Motor Shield for CNC plotter problem

Post by adafruit »

http://www.ladyada.net/make/mshield/faq.html
I have two stepper motors and I want to run them simulaneously but the example code can only control one and then the other?

The stepper motor library step() routine does not have the ability to run both motors at a time. Instead, you will have to 'interleave' the calls. For example, to have both motors step forward 100 times you must write code like this:

for (i=0; i<100; i++) {
motor1.step(1, FORWARD, SINGLE);
motor2.step(1, FORWARD, SINGLE);
}

No existing stepper motor driver has the ability to 'intelligently' interleave the steps. You will have to write a loop or use interrupts to control the motors the way you'd like.

lazygeorge
 
Posts: 8
Joined: Wed Feb 09, 2011 8:11 pm

Re: Motor Shield for CNC plotter problem

Post by lazygeorge »

Yes, this is exactly why I have used AccelStepper library as it does allow you to run two motors at the same time. Although not perfectly it seems!

adafruit
 
Posts: 12151
Joined: Thu Apr 06, 2006 4:21 pm

Re: Motor Shield for CNC plotter problem

Post by adafruit »

yes, so you need to try using without the accel library, to determine if that is not the problem

lazygeorge
 
Posts: 8
Joined: Wed Feb 09, 2011 8:11 pm

Re: Motor Shield for CNC plotter problem

Post by lazygeorge »

Yes thanks,

I abandoned AccelStepper in the end because I couldn't get it to interleave properly. I got a few pointers from some guys at the Arduino forum and managed to rewrite the code so the steppers interleave exactly. It seemed a little bit like reinventing the wheel with so many other CNC type code out there, but I can definitely say it works for me now.

GUI - Hydra gcode software
Uses Arduino Duemilanove and AF Stepper Shield
Uses AFMotor library only (not AcellStepper)
2 steppers and 1 servo
2 Axis with third axis penup/down

If anyone wants to use the code its here: http://www.maxlivesey.co.uk/maxtest/arduino/gcoder.zip

P.S. The GCODE needs to be straight line only (G01) not curved lines (G02). I used Inkscape (convert vectors to straight lines) and the Inkscape Gcode plugin to create the Gcode.

User avatar
johngineer
 
Posts: 105
Joined: Fri Aug 14, 2009 6:05 pm

Re: Motor Shield for CNC plotter problem

Post by johngineer »

Hi George:

The best and most accurate way to do what you need to do is step-by-step, not by varying motor speeds. Industrial CNC controllers first calculate a line from their present position to the destination given in the g-code. Then they move the motors along this line exactly. There's no need to have the motors both moving at the same time either, assuming the plotter has decent resolution. Even at a resolution of 1/250th of an inch, you'd be hard pressed to notice any "staircase" artifacts on the paper.

The easiest way to do this on an Arduino would be to create two arrays, one for X and one for Y, and populate them with the "steps" you need to take. Let's say you need to move from position 0,0 to position 8,2, your arrays would look like this:

X = [0, 1, 2, 3, 4, 5, 6, 7, 8]
Y = [0, 0, 0, 1, 1, 1, 2, 2, 2]

You'd have to set up a subroutine to create the arrays first, based on the difference between the current position and the destination. The size of the arrays would depend on the largest distance between the two points. In the above example, the size is 9 because that's the number of steps (inclusive) between 0 and 8. This algorithm has the added benefit of working for both "diagonal" lines, and lines which only require travel on one axis, so you don't need to check for "only x travel" or "only y travel".

Further, by going step-by-step, you can introduce delays between step-pairs to allow for adjustable feedrates. I realize you might not need variable feedrate on a plotter, but this will help generalize the code should you decide to use it for something else later on which does require such control.

The above method would be for the G01 command only. For G00 (the rapid positioning command), most CNC controllers do the axes separately -- first X, then Y -- as fast as possible.

One more thing -- looking at your code, it seems you are using FLOATs to keep track of your position and thus doing floating point math to solve for your position. I would suggest maybe switching to INTs, which both compute faster and take up less memory (important if you're going to be creating large arrays). Assuming your machine has a resolution of 0.001" of an inch, an int will still give you a 65x65 inch "canvas" to work on.

Hope this didn't sound like a lecture, it wasn't meant to. Just thought I'd share what I know with you.

Good luck on your project! Please post up some details when you're finished and don't forget to add the photos to the Adafruits flickr pool! :)

User avatar
adafruit_support_bill
 
Posts: 88086
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield for CNC plotter problem

Post by adafruit_support_bill »

You'd have to set up a subroutine to create the arrays first, based on the difference between the current position and the destination.
The classic algorithm for calculating straight-line movements in 2 dimensions is a Dynamic Difference Analyzer (DDA). A slight variant of that known as Bresenham's Algorithm is commonly used and there are many efficient integer-only implementations in C/C++. You should be able to find one on-line with a litle searching.

lazygeorge
 
Posts: 8
Joined: Wed Feb 09, 2011 8:11 pm

Re: Motor Shield for CNC plotter problem

Post by lazygeorge »

Hi Johngineer,

Thanks for your advice and information, I hadn't thought of using an array process for this task, that sounds very interesting. I guess that would mean the calculating is happening between lines allowing CNC hardware to be dedicated to motor control. As Aduwino mentions, I ended up using Bresenham's Line algorithm as the basis for the moves. It seems to step perfectly now but does have to calculate between steps. Would the stepping be slightly less jerky between steps if I used an array method? Now you mention it, I wonder if the steppers pause briefly for the processor to calculate the next step.

I know there are much simpler ways of coding this, but I'm really only just getting familiar with Arduino coding and it seems to work for me.
I have also seen algorithm examples that just use integers instead of floats, I never got round to adapting my code to this, but the speed that I am running the motors does seem to cope comfortably with the floats.

One reason I am disappointed that I can't use the Accelstepper library is the acceleration and deceleration options. Would there be a simple method to accelerate and decelerate? Would it just be a matter of varying the motor speeds between steps?

User avatar
johngineer
 
Posts: 105
Joined: Fri Aug 14, 2009 6:05 pm

Re: Motor Shield for CNC plotter problem

Post by johngineer »

lazygeorge wrote:I ended up using Bresenham's Line algorithm as the basis for the moves. It seems to step perfectly now but does have to calculate between steps. Would the stepping be slightly less jerky between steps if I used an array method? Now you mention it, I wonder if the steppers pause briefly for the processor to calculate the next step.
...
One reason I am disappointed that I can't use the Accelstepper library is the acceleration and deceleration options. Would there be a simple method to accelerate and decelerate? Would it just be a matter of varying the motor speeds between steps?
To your first question, about the motors being jerky, it's hard to say. When using steppers motors "straight" -- without any microstepping -- they are always a bit jerky, particularly at low RPMs. This is a result of the high torque they exhibit when stepping. You can "smooth" things out a bit by using microstepping and ramping the motors up and down. I suspect this is exactly what the accelstepper library does.

While the array method would probably result in faster movement, it would mean a longer pause between executing subsequent lines of g-code. Regardless, I don't think computing on the fly or computing before each line is going to affect the jerkiness all that much. That's just the natural behavior of a stepper motor.

One thing to remember is that motor speed is an abstraction. Stepper motors don't have a continuous speed the way DC motors do. It's better to think of it as a step rate. Steppers have a fundamental unit of movement -- the step -- and you can take multiple steps in quick succession, or you can step, then pause, then step, then pause, etc. The actual steps take the same amount of time regardless of the pause in between. When you set the "speed" using setSpeed, all it does is insert a delay between steps to achieve a certain rate.

Microstepping makes the step process "softer" by gradually increasing the amount of energy you put into the motor for each step, instead of just feeding it an on/off square wave. You still need to account for whole steps, however, because the fixed steps are what give you the precision you need.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”