Sequence of AccelStepper commands for printing

Hi guys,

I’m struggling with what seems like a really simple issue, but despite having trawled the forums and Google I can’t get my head round it!

I’m building a (sort of) printer and have a moving stage actuated by stepper motors, and inkjet printhead controlled by the Tone() function. The code below causes the moving stage to move back and forth in the x direction, with a small y movement at the end of each x stroke. This means the stage moves in a pattern of tightly packed parallel lines. This movement stops once a certain displacement has been reached in the Y direction. Whilst this movement is happening, the Tone() sends a waveform down a BNC cable, causing the printhead to fire at the specified frequency.

When positioned below a stationary printhead, this will mean that a series of parallel lines are printed onto the moving stage.

#include <AccelStepper.h>

#define X_STEP_PIN 54
#define X_DIR_PIN 55
#define X_ENABLE_PIN 38
#define Y_STEP_PIN 60
#define Y_DIR_PIN 61
#define Y_ENABLE_PIN 56
#define Z_STEP_PIN 36
#define Z_DIR_PIN 34
#define Z_ENABLE_PIN 30
#define Trigger_PIN 12

AccelStepper Xaxis(1, X_STEP_PIN, X_DIR_PIN);
AccelStepper Yaxis(1, Y_STEP_PIN, Y_DIR_PIN);
AccelStepper Zaxis(1, Z_STEP_PIN, Z_DIR_PIN);

void setup() {
  Xaxis.setMaxSpeed(10000);
  Xaxis.setAcceleration(10000);
  Xaxis.moveTo(330);
  Xaxis.setEnablePin(X_ENABLE_PIN);
  Xaxis.setPinsInverted(false,false,true);
  Xaxis.enableOutputs();
  Yaxis.setMaxSpeed(500);
  Yaxis.setAcceleration(10000);
  Yaxis.setEnablePin(Y_ENABLE_PIN);
  Yaxis.setPinsInverted(false,false,true);
  Yaxis.enableOutputs();
  Zaxis.setMaxSpeed(10000);
  Zaxis.setAcceleration(1000);
  Zaxis.moveTo(10000);
  Zaxis.setEnablePin(Z_ENABLE_PIN);
  Zaxis.setPinsInverted(false,false,true);
  Zaxis.enableOutputs();
}

void loop() 
{  while (Yaxis.currentPosition() == 660){
  Yaxis.stop();
  Xaxis.stop();
  noTone(Trigger_PIN);}
  
  if (Xaxis.distanceToGo() == 0){
  Yaxis.move(33);
  Xaxis.moveTo(-Xaxis.currentPosition());}
  
  Xaxis.run();
  Yaxis.run();
  tone(Trigger_PIN, 1000);
}

The bit I’m having trouble with seems like it should be much simpler than all this but I can’t get it to work. I need to be able to add simple x, y or z movements either before or after this printing sequence so that I can hold the printhead away from the printing area initially, then move it across, do the printing, then move it back.

For example, I’d like my code to be able to do:

move 10000 in x direction

do printing sequence

move -10000 in x direction.

Whenever I try and add anything at the start or end of the loop though everything just goes absolutely crazy! I suspect this is due to a fundamental lack of understanding of what is going on but I’m running out of time and my research so far hasn’t helped.

Any pointers would be greatly anticipated!

Cheers,

Michael

I suspect this is due to a fundamental lack of understanding of what is going on

I suspect that is a large part of it. I suspect that your crappy code layout is a contributing factor.

NOTHING follows the {, on the same line, in any recognized coding style.

The } goes on a line by itself in every recognized coding style.

Whether the { goes on a line by itself, as I prefer, or on the same line as the statement it does with (ugh!), is a matter of debate. If it must go on the line with the statement, it must be visually separate.

The first block of code will be an endless loop, if the y axis ever steps 660 times. The only way to do anything else is to reset the Arduino. Doesn't really seem useful. Telling the motors to stop IF the y axis is at 660 seems reasonable. Telling them to stop, over and over, WHILE the y axis is at 660 seems pointless.

If that code does what you want, though, and some other code, that you didn't post, doesn't, we can hardly help you fix the code you didn't post that does something we can't see.

Hi Paul,

To be honest I'm a bit surprised by the tone of your reply. I have just come here politely asking if anyone is willing to help?

I've never done any coding of any sort and have been chucked in at the deep end on a project with a very tight deadline. I've done my best to read and understand how it works but clearly haven't had much success. I wasn't aware that the spacing of the { and } was so critical or that anyone would be so offended by it. Sorry about that.

The reason I have used while() instead of if() is that if() causes the stage to keep moving in the x direction once all of the lines have been drawn. If you could suggest a reason for this I'd be really grateful.

Simplifying things for a moment, suppose I just wanted to move in the x direction 1000 steps then once that is finished move in the z direction 1000 steps. From my other reading I thought that the code below would work, but instead the two motors just move at the same time?

void loop() 
{
  left();
  up();
}

void left()
{
  Xaxis.moveTo(-1000);
  Xaxis.run();
}

void up()
{
  Zaxis.moveTo(-1000);
  Zaxis.run();
}

Michael

I wasn’t aware that the spacing of the { and } was so critical or that anyone would be so offended by it. Sorry about that.

I’m not offended by the arrangement of the code, but, it is difficult to follow. If you line the { and } up, I think YOU will find it easier to understand your own code.

The reason I have used while() instead of if() is that if() causes the stage to keep moving in the x direction once all of the lines have been drawn. If you could suggest a reason for this I’d be really grateful.

Locking the whole processor up in a do nothing (useful) loop isn’t the best idea.

Perhaps the key is to do something only when possible, rather than not doing something when not possible.

if(xPos >= 0 && xPos <= 330)
{
   // We are good in the X direction
   if(yPos >= 0 && yPos <= 660)
   {
      // We are good in the Y direction
      doWhatNeedsDoing();
   }
}

From my other reading I thought that the code below would work, but instead the two motors just move at the same time?

That is because run() just causes the stepper motor to step once if it is not at the last commanded position. There are other methods with run in the name that cause the stepper motor to keep moving until the motor IS at the last commanded position.

But, really, if you only want to move one axis at a time, AccelStepper is not the best choice.

If you want to move two motors at (nearly) the same time, such as when moving along a diagonal, then AccelStepper is the only choice.

PaulS:
If you want to move two motors at (nearly) the same time, such as when moving along a diagonal, then AccelStepper is the only choice.

I disagree based on what its author says
"AccvelStepper does not guarantee any synchronisation between individual
steppers."

However that may be irrrelevant :slight_smile:

From the Original Post

I need to be able to add simple x, y or z movements either before or after this printing sequence so that I can hold the printhead away from the printing area initially, then move it across, do the printing, then move it back.

You have not told us how you want to convey those instructions to the Arduino. For example, will they come from a PC over the USB cable?

I use an Uno to control 3 stepper motors on a small lathe. I use my PC to turn GCode instructions into movements for the motors which are sent to the Arduino (and which can include synchronized movements). I also have a PC program that can turn a simple black and white image into a set of GCode instructions that represent the path for a milling cutter to carve out the black shape. That sounds a little like what you are trying to do with ink.

The code you have in loop() is not very long and I doubt if it can be significantly simpler.

However I can't place that piece of code in the wider context of what you want to achieve. Is it just to move the stepper to another position and repeat the code that is in loop()? In that case move the present code into a function (perhaps call it makePattern() ) and then, very crudely, the code in loop() could be something like

void loop() {
    // code to move motor to XY
    makePattern();
    // mov motor to X1Y1
    makePattern();
}

But I may well be misinterpreting your requirement.

...R

Paul:

Okay I see what you are getting at regarding the { } usage, I think I have tidied things up now. I also see what you mean about my while loop, but given that it does perform as required - however crudely - I was hoping I wouldn't have to change that part and would be able to just add the other bits at the start and end.

Robin2:

You have not told us how you want to convey those instructions to the Arduino. For example, will they come from a PC over the USB cable?

I haven't been clear here - these movements aren't going to be something I'm changing, they're just going to be part of the code that runs the same every time. I'll do a bit of testing with my system to figure out how far these movements need to be and then write that into the code.

To give some context and perhaps clarify why I need to do this: the project involves printing ink onto a heated powder bed through an inkjet printhead. The powder with ink printed on is then moved under an infrared heat source which will cause sintering of the powder in the regions with ink present, creating a solid layer. This is all part of the development of an additive manufacture process called High Speed Sintering - quick explanatory video here if you're interested 3D Printing: High Speed Sintering - YouTube

So I need the heated powder stage to be in 4 different positions:

  1. Away from the printhead and IR source whilst the powder is laid.
  2. Then it must move to underneath the printhead, so that the printing operation (parallel lines) can occur.
  3. After this it must move again to underneath the IR source for sintering to occur.
  4. Finally it should move back out from underneath the IR source for the sintered powder to be removed.

That would be one full cycle, after which the powder would be removed and replaced, and the whole process repeated.

So I simply need a way of adding these movements in the x and y plane so that the powder bed is in the required position for each step of the process. I hope that makes more sense?

Do you think the code structure that you have suggested would allow me to achieve what I have described above?

I suppose I should have explained all that properly to start with, sorry about that!

Thanks for all your help.

Michael

mcaley:
Do you think the code structure that you have suggested would allow me to achieve what I have described above?

It’s a bit hard to answer that without knowing how you are interpreting my comments. I say that because I’m not clear why it has not already occurred to you, given that you seem able to do some of the stuff you want.

If it was my project I would have code in loop() that reflects your description - perhaps like this

void loop() {
  moveToPowderPosition();
  moveToPrintHead();
  operatePrinter();
  moveToHeater();
}

and the code you already have would be in the function operatePrinter()

However I am seriously concerned that we may be misunderstanding each other.

…R

I think you understand me completely actually. My problem is I think that is what I tried initially, but with no success, and the motors just wouldn't move at all or moved in an unexpected manner.

I don't have access to the code this evening but tomorrow I will go and have another look and post it up so we can figure out where I've gone wrong.

Thanks again,

Michael

tomorrow I will go and have another look and post it up so we can figure out where I've gone wrong.

I think that is a great idea.

Are you using appropriately named functions, as Robin2 suggests? If not, that would really be the first change I'd make.

Test each function, to make sure it does exactly what you want. Then, comment out the call to the function, and add another function, and call it. Repeat until all the functions work individually. Then, uncomment the commented out calls, and you are done.

Okay, I've simplified things to just consider getting two steps to run in sequence. I've made some progress and actually it was something that Paul said previously about using run(). Initially I had the movement commands set up as follows:

void loop() 
{
  left();
  up();
}

void left()
{
  Xaxis.moveTo(-1000);
  Xaxis.run();
}

void up()
{
  Zaxis.moveTo(-1000);
  Zaxis.run();
}

This was just causing the two steppers to move at the same time.

Changing moveTo() and run() to runToNewPosition() has fixed this, so with the following code the two commands now run in sequence as desired. Such a simple alteration!

void loop() 
{
  left();
  up();
}

void left()
{
  Xaxis.runToNewPosition(1000);
}

void up()
{
  Zaxis.runToNewPosition(-1000);
}

Now I've tried adding in the operatePrinter() function as follows (the movements in the other functions are just arbitrary at this point)

void setup() {
  Xaxis.setMaxSpeed(10000);
  Xaxis.setAcceleration(10000);
  Xaxis.moveTo(330);
  Xaxis.setEnablePin(X_ENABLE_PIN);
  Xaxis.setPinsInverted(false,false,true);
  Xaxis.enableOutputs();
  Yaxis.setMaxSpeed(500);
  Yaxis.setAcceleration(10000);
  Yaxis.setEnablePin(Y_ENABLE_PIN);
  Yaxis.setPinsInverted(false,false,true);
  Yaxis.enableOutputs();
  Zaxis.setMaxSpeed(10000);
  Zaxis.setAcceleration(1000);
  Zaxis.moveTo(10000);
  Zaxis.setEnablePin(Z_ENABLE_PIN);
  Zaxis.setPinsInverted(false,false,true);
  Zaxis.enableOutputs();
}

void loop() 
{
  moveToPowderPosition();
  moveToPrinthead();
  operatePrinter();
  moveToHeater();
}

void moveToPowderPosition()
{
  Xaxis.runToNewPosition(1000);
}

void moveToPrinthead()
{
  Zaxis.runToNewPosition(-500);
}

void operatePrinter()
{  
  while (Yaxis.currentPosition() == 660){
  Yaxis.stop();
  Xaxis.stop();
  noTone(Trigger_PIN);}
  
  if (Xaxis.distanceToGo() == 0){
  Yaxis.move(33);
  Xaxis.moveTo(-Xaxis.currentPosition());}
  
  Xaxis.run();
  Yaxis.run();
  tone(Trigger_PIN, 1000);
}

void moveToHeater()
{
    Xaxis.runToNewPosition(-1000);
}

The first two movements run fine, but then during operatePrinter() it just moves back and forth in the x direction indefinitely without the y step at the end of each line.

I think this must be something to do with the while() loop I have used or the fact that I've used the moveTo() function in the setup part? I'm not sure how I'd restructure this to get it to work.

Thanks again for your time,

Michael

Actually, thinking about it I might be able to have a crack at that later today - I've just had to jet off to a lecture now.

I'd still be interested to hear any opinions though.

I'm not sure how I'd restructure this to get it to work.

Start with the curly braces. It is easy to read code that has consistent placement of curly braces. It's a bitch to read code that has inconsistent styles.

void operatePrinter()
{
while (Yaxis.currentPosition() == 660){

ALWAYS with the function/statement (which I hate):

void operatePrinter() { 
  while (Yaxis.currentPosition() == 660) {

ALWAYS on a new line (which I prefer):

void operatePrinter()
{ 
  while (Yaxis.currentPosition() == 660)
  {

If you are going to use the first style, PUT A SPACE BEFORE THE {, as I did.

 noTone(Trigger_PIN);}

NOTHING on the same line as the }.

 noTone(Trigger_PIN);
}

I think this must be something to do with the while() loop

Why do you have a while loop at all?

At the time the function is called, you KNOW that the machine is ready to do some printing. It CAN'T be out of range, or your code is wrong prior to the function being called.

 if (Xaxis.distanceToGo() == 0){

Can it be anything other than 0? You waited, prior to this function being called, for the Xaxis stepper to get to position.

The function name, operatePrinter(), implies (to me, at least, and I suspect to Robin2, too) that ALL the code to do the printing would be done in this function, and that this function would not return until it was done operating the printer.

That is certainly not the way the code in the function is organized.

Since you've learned to defeat the synchronous nature of AccelStepper, why are you still using the synchronous nature of AccelStepper here?

Yeah sorry about the curly brace mess, I was rushing when posting it up before. I've fixed it now.

I think I see what you're saying about the use of the while loop. When I wrote it previously I had seen a similar method used to achieve this 'bouncing' elsewhere and just copied it. However all I really need now is a repeated series of:

left by stroke length - up a tiny bit - right by stroke length - up a tiny bit.

I think I can achieve this using a 'for' loop?

I think I can achieve this using a 'for' loop?

Well, I could...

Annoyingly the uni’s WiFi has gone down so I can’t post my code - I’m having to use my phone network to write this.

I’m confused about how the commands you want to repeat using the for() loop know that’s what you want.

For example if I do

void operatePrinter()
{
for (int i=1; i<10; i++)
{
Commands that I want to repeat eg Xaxis.runToNewPosition() etc
}
}

I know that can’t be right as the commands aren’t referencing the i at all? These commands just loop indefinitely without being limited to 10 repeats as intended. I’ve seen another example which seems to just use this method but it isn’t working for me.

Thanks for your patience.

I've seen another example which seems to just use this method but it isn't working for me.

The difference must be the code in the body of the for loop.

If you want to move the carriage left to right, wouldn't you set the position to step to, and then use the blocking stepTillYouGetThere method that you found?

Then, step, in a blocking fashion, until the carriage moves forward.

Then, step, in a blocking fashion, until the carriage is back on the left.

Then, step, in a blocking fashion, until the carriage moves forward.

Repeat however many times are need to move all the way up the paper. Nothing in the step right, step up, step left, step up series of commands cares about the loop index, that I can see.

I’ve actually come up with a different method of doing this now, which is probably not the neatest way but it works. I was trying to figure out how to get the printing loop to step according to the index, and managed it with the quality (!) bit of coding you can see below.

void loop() 
{
  moveToPrinthead();
  lowerPrinthead();
  operatePrinter();
  raisePrinthead();
  moveToHeater();
  returnHome();
  exit(0);
}

void moveToPrinthead()
{
  Xaxis.runToNewPosition(-10000);
  Xaxis.setCurrentPosition(0);
  Yaxis.runToNewPosition(5000);
  Yaxis.setCurrentPosition(0);
  delay(2000);
}

void lowerPrinthead()
{
  Zaxis.runToNewPosition(10000);
}

void operatePrinter()
{  
  for (int i=1; i<10; i++)
  {
  tone(Trigger_PIN, 1000);
  Xaxis.runToNewPosition(660);
  Xaxis.setCurrentPosition(0);
  Yaxis.runToNewPosition(33*(i*2-1));
  Xaxis.runToNewPosition(-660);
  Xaxis.setCurrentPosition(0);
  Yaxis.runToNewPosition(66*i);
  noTone(Trigger_PIN);
  }
  Xaxis.runToNewPosition(0);
  Yaxis.runToNewPosition(0);
}

void raisePrinthead()
{
  Zaxis.runToNewPosition(0);
}

void moveToHeater()
{
   Xaxis.runToNewPosition(8000);
   Xaxis.setCurrentPosition(0);
   Yaxis.runToNewPosition(2000);
   Yaxis.setCurrentPosition(0);
   delay(5000);
}

void returnHome()
{
  Yaxis.runToNewPosition(-7000);
  Xaxis.runToNewPosition(2000);
  Yaxis.setCurrentPosition(0);
  Xaxis.setCurrentPosition(0);
}

I couldn’t find a neat way of getting the steppers to move by a relative amount each time, hence I have to keep resetting the position to zero. If there was a command that can make it move a certain amount relative to the current position that would be better, however I couldn’t find one and in this form it functions exactly as I need it to, so I think I’m going to stop messing about with it! Thanks very much for all your help and extreme patience.

Michael

so I think I'm going to stop messing about with it!

Aw, come on. F**k with it until it doesn't work at all.

Good job on making something that does something useful.

One thing about the code. There doesn't HAVE to be anything in loop(). Put all the code (except the exit() call, which should be removed) in setup().

I like my opening brace at the end of the line like

void myFunction () {

}

I suspect stepper.run() (or stepper.runSpeed() if you don't want acceleration) is more appropriate for your situation but it MUST be called from within loop() and not from within a function. And loop() must repeat hundreds or thousands of times per second to ensure that the steps happen at the right instant.

You control the position of the stepper by changing the destination value - not by calling, or not calling the .run() function. IIRC the AccelStepper library has absolute and relative movements.

Do you have a single set of coordinates for the gross movements of the table (say from the printer to the heater) and for the finer movements under the print head? For example, for every movement is the bottom left of the possible motion always 0,0 and the top right maxY, maxX ?

...R

Paul - that makes sense, thanks.

Robin2 - I could probably work out an absolute set of coordinates for each movement, however the benefit of doing it the way I have meant that I could do a bit of trial and error in the process of figuring out each of the movement distances. I guess I could now convert this to a series of movements between absolute coordinates, but as I have it working exactly as I need it I think I'm just gonna leave it.

Thanks again for all your help and patience!

Michael