Imprecision while controlling 28BYJ-48 with AccelStepper

As everyone else, I have built a plotter based on an old scanner, a printer and two 28BYJ-48 motors controlled with two ULN2003 drivers. As a raster device it works surprisingly well - it is very precise in its dot placement, in fact, in printouts the resolution is dictated more by the pen tip size than by the mechanical limits.

However, as far as vector drawing is concerned, it is quite disappointing. I am outputting gcode from Inkscape via Processing and into TinyCNC-code based interpreter, with the line drawing instructions substituted for AccelStepper:Multistepper movement instructions. The drawings are rather imprecise: curves that are to be aligned are not, circles' ends do not meet etc. Curiously, the inaccuracy seems to be more pronounced in smaller shapes.

What could be the reason for this? The gcode provided is good enough, as I have checked it in an online simulator and got the original shapes back. The coordinates are necessarily rounded - they are outputted with four-digit precision while my shorter axis has around 1000 steps - but the inacurracy seems to be larger than the rounding. Could it be that the Multistepper in the AccelStepper procedures are not precise enough? I do not think it is mechanical imprecision, considering that raster steps are quite accurate...

Jabberwock:
with the line drawing instructions substituted for AccelStepper:Multistepper movement instructions.

Explain and post your code.

...R

The sketches from TinyCNC have a gcode interpreter which I basically use to intepret G1 Xa Yb codes. The interpreter calls then the drawing line code which is this:

void drawLine(float x1, float y1) {
  
  long positions[2]; // Array of desired stepper positions

  float x0 = Xpos;
  float y0 = Ypos;

  float tempx = x1*100;
  float tempy = y1*100;
  
  positions[0] = (long) tempx;
  positions[1] = (long) tempy;
  
  steppers.moveTo(positions);
  steppers.runSpeedToPosition(); // Blocks until all are in position
  
  Xpos = x1;
  Ypos = y1;
}

I have managed to manipulate the Inkscape parameters so that the coordinates do not exceed 99.99, I multiply them by 100 to get the steps (in the OP I have incorrectly given the number of steps per axis - it is 10000, not 1000).

I reckon you have missteps due to overloading the motors - smaller shapes mean
higher accelerations (and thus torques on the motors).

Try running everything at half the speed and reducing the max acceleration considerably
and see if this fixes it - if so start trying faster and faster rates till it mis-steps again, then
back-off 20% or so. Do the same for max acceleration.

I have tried running the plotter at 20% of speed and 10% of acceleration - the results are exactly the same. The curious thing is - they are exactly the same - no matter what speed and accel the distortions are almost perfectly repeatable - I have even drawn the same picture on the same piece of paper twice and the outlines matched almost ideally, with the slight irregularities attributable to pen/paper shifting. For example, the ends of a circle are apart in exactly the same way on three different drawings.

Would you say this rules out missteps?

You do know about the odd ratio of the gear in these steppers ?
Such things can be easily explained with that knowledge.

No, I do not know what you mean?

There's this 11 page thread about this stepper and libraries.
I think it was user sbright33, who mentioned about this ratio, but i'm not sure it was in this thread.

There's a lot of info to be found on this stepper using the (google) forum search, on top right of every page in the forum.

OK, I will have a look at that...

I have browsed through the topic, but I did find anything that seemed to be related... AccelStepper's procedures are step-based, so actual RPMs are not even specified.

I cannot seem to find any implementation of the Bresenham's algorithm for the standard stepper library so I could test my code without AccelStepper... the algorithm is mentioned often enough, but any code I have found seems to implement a different movement mechanism and I am not sure how to adapt it to my steppers.

MAS3:
You do know about the odd ratio of the gear in these steppers ?
Such things can be easily explained with that knowledge.

The fact its not exactly 2048:1 is immaterial, that could only cause minor scaling issues,
not corrupt movement.

If the speed of operation doesn't change things, then the steps being generated are
likely wrong.

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?
Also a picture of your project, how are you power you project?

Tom.... :slight_smile:

Jabberwock:
The interpreter calls then the drawing line code which is this:

If you create a very short program that includes the code you posted and simply ask it to draw a diagonal line does it work properly ? For example, with a call like

drawLine(10.5, 87.3);

If that simple code DOES work correctly my guess would be that the problem lies in how the Gcode is being interpreted and fed to the function.

...R

I have drawn various diagonal lines (2:1, 4:1 etc.) and they seem to be OK, but the distortion might be too small to be noticed... The effect is most visible with curves.

Another thing I have noticed is that if I scale the shape (e.g. a letter "o") to very small sizes, it get distorted more, so this could be caused by small mechanical issues. However, if I scale it up - for example, I draw the letter half the page size and then the whole page size - the distortion is exactly the same and it is repeatable.

I have fed the lines of gcode manually through the serial window to the function and got it to feed them back to me. In other words, I know exactly that the coordinates in gcodes are directly fed to the AccelStepper function (there was a tiny issue with casting some numbers to long, but when corrected it did not affect the result).

I will draw the diagram later. Basically these are two ULN2003 drivers connected to relevant pins on Leonardo and powered with a separate 5V 2400mA supply.

Jabberwock:
I have drawn various diagonal lines (2:1, 4:1 etc.) and they seem to be OK, but the distortion might be too small to be noticed… The effect is most visible with curves.

How is a curve created ?
I know there are GCode commands that define curves. But they must be converted into sequences of straight-line stepper moves (even if each move is only a single step).

I remain with my guess that the problem lies in the Gcode to Stepper Movement conversion rather than in the way AccelStepper is working.

It may be possible to write some Arduino code (as an alternative to AccelStepper) that would match the stepper movements more closely to GCode curves, but that could be complicated (I have only done it for straight lines). I wonder if that exists in programs like GRBL or the various 3D printer programs for Arduinos.

…R

Hi,

When you command a diagonal line at 45Deg to your main axes, can you see the x and y steps in the diagonal line?

Tom.... :slight_smile:

There is no need to convert curves to straight lines, you can synthesis steps from an equation of
motion without linearizing things.

The issue seems to be that the software is generating pulses incorectly - this is the "TinyCNC code based
interpreter" I presume. The obvious way to confirm this would be to connect it to a known good
motion control system, or use another microcontroller to count the steps generated against whats
expected.

You could also use another stepper library to exercise the motors for repeatability checking.

Tom: On a diagonal line the steps are not seen, as the pen spot is bigger than a step being taken...

The gcodes consist of straight lines only. The example code is here:

(Polyline consisting of 1 segments.)
G1 X-2726 Y1246 F3500.00
M300 S30.00 (pen down)
G1 X-2575 Y1217 F3500.00
G1 X-2454 Y1130 F3500.00
G1 X-2374 Y991 F3500.00
G1 X-2347 Y805 F3500.00
G1 X-2359 Y652 F3500.00
G1 X-2395 Y538 F3500.00
G1 X-2452 Y453 F3500.00
G1 X-2531 Y390 F3500.00
G1 X-2726 Y337 F3500.00
G1 X-2880 Y366 F3500.00
G1 X-3001 Y454 F3500.00
G1 X-3079 Y595 F3500.00
G1 X-3106 Y791 F3500.00
G1 X-3074 Y1003 F3500.00
G1 X-2980 Y1150 F3500.00
G1 X-2865 Y1222 F3500.00
G1 X-2726 Y1246 F3500.00
M300 S50.00 (pen up)
G4 P150 (wait 150ms)



(Polyline consisting of 1 segments.)
G1 X-2726 Y1149 F3500.00
M300 S30.00 (pen down)
G4 P150 (wait 150ms)
G1 X-2830 Y1126 F3500.00
G1 X-2914 Y1059 F3500.00
G1 X-2970 Y946 F3500.00
G1 X-2988 Y791 F3500.00
G1 X-2970 Y637 F3500.00
G1 X-2914 Y525 F3500.00
G1 X-2830 Y457 F3500.00
G1 X-2726 Y434 F3500.00
G1 X-2623 Y457 F3500.00
G1 X-2539 Y525 F3500.00
G1 X-2484 Y639 F3500.00
G1 X-2465 Y797 F3500.00
G1 X-2484 Y947 F3500.00
G1 X-2539 Y1058 F3500.00
G1 X-2624 Y1126 F3500.00
G1 X-2726 Y1149 F3500.00
M300 S50.00 (pen up)
G4 P150 (wait 150ms)

I have checked the codes with two online gcode viewers e.g. here and the result is exactly as was drawn - a letter 'o'. As I wrote, the coordinates input into AccelStepper procedures are exactly as given here. On my plotter it is consistently drawn distorted: the bigger circle is more rectangular, the smaller circle touches the bigger one at the top and is also skewed. The result is always the same.

For a moment I thought that the misalignment accumulates with movement, but it does not: I have made a file with the above 'o' repeated four times in the exact same coordinates and the shape was drawn almost exactly in the same place: the lines were a bit thicker, but this might be attributed to pen/paper movement and ink accumulation. But the shape was, of course, consistently incorrect.

I will look for another stepper library that does movement in coordinates, if I will not find anything, I guess I will write my own, although I hoped the library would save me exactly that.

Perhaps a picture would be worth a 1000 words - or here two pictures, the gcode viewer
v. your plotter's output.

If the error doesn't accumulate and circles come out squared that strongly suggests backlash.

MarkT:
There is no need to convert curves to straight lines, you can synthesis steps from an equation of
motion without linearizing things.

I understand but I don't think that the OP's code does that and it is probably not so simple to write.

...R