 # Motor timing problems with CNC setup - help needed

Hi,

This is my first post - I’m not sure this is the right part of forum, but here goes.

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)

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

First - is there a particular reason you are writing your own g-code interpreter? I believe there are few that already exist…

Thank you cr0sh for your reply. I have not written my own G-Code interpreter, just modified a few existing ones to use with my hardware - the adafruit motor shield and the libraries that can be used with it. You lost me there a little bit with Bresenham's line algorithm - a bit beyond me I'm afraid.

If x needs to travel 100, and y needs to travel 50, and they both need to arrive at the same time - then the speed of Y will be Y/X * (the speed of X).

Does that sound right?

When I set it up with the motors, the motor with the slowest speed always stops a fraction early.

I don't think you can use these routines because you don't know what they are and they are not synchronised to each other.

You lost me there a little bit with Bresenham's line algorithm

It's just a fancy name for what you are trying to do:- http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm

You want to work out how many of the more numerous pulses you need to before you pulse the lessor motor. This number will be a floating point value and less that zero, you pulse the slower motor every time the integer part of the accumulation changes. For an example see the code in my project:- http://www.thebox.myzen.co.uk/Hardware/CNC_Conversion.html

Thank you Grumpy Mike. Excuse me while I pick my jaw off the floor after looking at your milling machine. That is very nice indeed. I think I'm getting the picture - I have let the library I'm using do all the pulses for me, so I haven't really looked at exactly how it happens. And seeing that it seems to be doing it incorrectly, I think I'd better start finding out for myself. Ho hum.

A bit late here in the UK - going to bed now, I will look again in the morning.

Bed yes that's good. In the UK myself. Anywhere near Newcastle, I will be at the Maker Fair next month, I might bring my CNC conversion to show, but I haven't decided yet.

Thanks Grumpy_Mike and Cr0sh,

I abandoned AccelStepper in the end because I couldn't get it to interleave properly. After your pointers to B's line algorithm I managed to rewrite the code so the steppers interleave exactly. It seemed a little bit like reinventing the wheel with so much 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.

The general approach is called DDA - This article might be useful if it covered all the other DDA techniques for doing curves: http://en.wikipedia.org/wiki/Digital_Differential_Analyzer_%28graphics_algorithm%29 but the circle-drawing version is here: http://en.wikipedia.org/wiki/Midpoint_circle_algorithm

My code is not as neat and tidy as the Bresenham's example code - I just wanted to write it in a way that I understand. It's interesting how the code is used for Bezier curves here http://free.pages.at/easyfilter/bresenham.html It seems that normal Gcode plots arcs rather than curves, Why is this? Surely more accurate results could be made using a curves method. Is this machine limitations perhaps? I am wondering how to include G02 Gcode interpretation with my limited programming.

It seems that normal Gcode plots arcs rather than curves, Why is this?

First of all Gcode is rather old and curves in software were not developed until much later. Then it is rather computational expensive plotting the curve in real time, circles are much easer. The simplest method is to draw a polygon, with enough sides it is indistinguishable from a circle. Look in my CNC software for an example of how to do G2 commands.

Grumpy

I was wondering why you chose to use a 328 instead of the 644p? wouldn't it give you better performance? I'm currently building my second cnc. This one will be for pcb's only, Desktop size. i'm building this one around Texas Instruments DRV8818. Do I even need to worry about proccessor power? or does the 328 work fine? My first machine uses a PC and LinuxCNC, but I want to go with a duino this time.

Submicro