Why does it all happen at once?

I am relatively new to the Arduino scene and have gone through most of the tutorials that i have the kit to do but i require a bit of help on a small project for the wife.

We are looking at re-purposing an obsolete printer to cutour rolls of vinyl to more manageable sizes, the printer is stripped down to the parts I need, Motors, Encoders, Feed and Cut systems.

I have a Arduino Mega 2650 to control my project via a L298 Dual H-Bridge and can successfully control the motors and positioning via the encoders using a sketch on the Homofacians website. I have adapted this to run 2 motors and encoders including moving the pins about to allow the use of the interupt pins 2-5. However i am struggling to work the code to run a sequence to allow the system to run autonomously.

The sequence would look like this:

  • Feed Roller (x axis) feeds out 36600 steps (297mm in real measurements)
  • Once (x axis) reaches position the cutter (y axis) runs full width of 6600 steps (1500mm)
  • This will run for a set amount of times

I can run the feed out to the correct distance and also throw the cutter in both directions(including adapting the code to run the cutter from a single button in both directions, however if I try to sequence them they either feed and cut together or only do 1 of the 2 actions, I have tried "IF, IF..ELSE, WHILE, DO..WHILE, DELAY and MILLIS"

This is a snippet of the code that i used to run the motors:

void loop() {                       // main program

  unsigned long currentTime = millis();
  xdutyCycle = (double)(abs(xsetPoint - xactualPoint)) * (double)P_FRACTION;
  ydutyCycle = (double)(abs(ysetPoint - yactualPoint)) * (double)P_FRACTION;
  // possibly look at map and constrain next 4 if loops.
  if (xdutyCycle < MIN_XDUTYCYCLE) { // x min constrain
    xdutyCycle = MIN_XDUTYCYCLE;
  }
  if (xdutyCycle > MAX_XDUTYCYCLE) { // x max constrain
    xdutyCycle = MAX_XDUTYCYCLE;
  }
  if (ydutyCycle < MIN_YDUTYCYCLE) { // y min constrain
    ydutyCycle = MIN_YDUTYCYCLE;
  }
  if (ydutyCycle > MAX_YDUTYCYCLE) { // y min constrain
    ydutyCycle = MAX_YDUTYCYCLE;
  }
  // end of poss map & constrain

  if (abs(xsetPoint - xactualPoint) < XSTEP_MARGIN) { // x axis no movement
    analogWrite(XMOTOR_PWM, 0);
    digitalWrite(XMOTOR_DIRECTION, 0);
  }
  else {
    if (xactualPoint < xsetPoint) {                   // x axis Fwd movement Feed Out
      digitalWrite(XMOTOR_DIRECTION, 1);
      analogWrite(XMOTOR_PWM, 255 - xdutyCycle);
    }
    if (xactualPoint > xsetPoint) {                   // x axis Rev movement Feed In
      digitalWrite(XMOTOR_DIRECTION, 0);
      analogWrite(XMOTOR_PWM, xdutyCycle);
    }
  }
  if (abs(ysetPoint - yactualPoint) < YSTEP_MARGIN) { // y axis no movement
    analogWrite(YMOTOR_PWM, 0);
    digitalWrite(YMOTOR_DIRECTION, 0);
  }
  else {
    if (yactualPoint < ysetPoint) {                   // y axis Fwd movement Cut to Left
      digitalWrite(YMOTOR_DIRECTION, 1);
      analogWrite(YMOTOR_PWM, 255 - ydutyCycle);
    }
    if (yactualPoint > ysetPoint) {                   // x axis Fwd movement Cut to Right
      digitalWrite(YMOTOR_DIRECTION, 0);
      analogWrite(YMOTOR_PWM, ydutyCycle);
    }
  }
  xDiff = (xsetPoint - xactualPoint - XSTEP_MARGIN);
  readByte = 0;                                       // serial input set to nul
  if (Serial.available() > 0) {                       //if we get a valid byte, read from serial: used for serial controll
    //get incoming byte:
    readByte = Serial.read();
    //Serial.println('r');                              // send a 'r' to initiate next data from computer
 
    

    if (readByte > 0) {                               // read serial input
      if (readByte == '0') {
        //for ( int i=0; i<5; i++ ) {                  
        FeedL();
        if (xDiff <= XSTEP_MARGIN){
          CutL();
        }
        //xactualPoint = 0;
        //previousTime = currentTime;
        //Serial.println (previousTime);
        //Serial.println (currentTime);
        
        /*do
        {
          xsetPoint += 36600;
        }while (xactualPoint != (xsetPoint - XSTEP_MARGIN));
          //xsetPoint++;
        CutL();*/

        /*xsetPoint += 36600;
          delay(3000);
          CutL();*/

        /*if (xactualPoint >= (xsetPoint - XSTEP_MARGIN)) {  
          CutL();
          } else if (xsetPoint < 36600) {
          xsetPoint++;
          } else {
          CutL();
          }*/
      }
      if (readByte == '9') { // cut any way
        if (yactualPoint < 3300) {
          CutL();
        } else {
          CutR();
        }
      }
      if (readByte == 'h') { // y  10
        yactualPoint = 0;
        ysetPoint = 0;
        Serial.println("Cut Home Set!!");
      }
      if (readByte == '4') { //A4 Portrait feedout (36600)
        xsetPoint += 36600;
      }
      if (readByte == '3') { // feed in
        xsetPoint -= 36600;
      }
      if (readByte == '2') { //A4 Landscape feed out (25700)
        FeedL();
      }
      if (readByte == '1') { // feed in
        xsetPoint -= 25700;
      }
    }

  }
}
void FeedL() {
  xactualPoint = 0;
  xsetPoint = 25700;
}
void FeedP() {
  xactualPoint = 0;
  xsetPoint = 36600;
}
void FeedL_delay() {
  delay(3000);
}
void CutL() {
  ysetPoint = 6600;
}
void CutR() {
  ysetPoint = 5;
}

Due to the forum limitations and size of the code i have attached the full .ino file that i am currently working from, I know it is bloated with bits that are not needed or could be simplified with library's such as encoder.h.

Currently this all runs from the serial monitor but when I can nail the problem swapping to buttons on the front panel wont be such a drama.

As you can see i have lined out the codes i have tried but I am quickly loosing hair and sanity as i know its something simple that I am overlooking. Maybe just a fresh set of eyes will be able to point out he errors.

Any help or guidance on this sketch will be gratefully appreciated.

Regards

Smiler

cut_func_working.ino (8.97 KB)

"0" reads as askii code 48

Normally, you use a state machine for this.

Will your cutter cut in both directions? If so, then what you want to do is feed, cut one way, feed, cut the other way, and so on.

So your state has three different factors:
1 - how many more sheets remain to be cut? If zero, then we are stopped.
2 - are we feeding or cutting?
3 - which direction are we running the cutter?

the loop is:

int numCutsToDo = 0;
boolean cutterDirectionForward = true;

enum State {
  IDLE, FEEDING, CUTTING
} state = IDLE;


void loop() {
  switch(state) {
  case IDLE: do_idle(); break;
  case FEEDING: do_feeding(); break;
  case IDLE: do_cutting(); break;
  }
}

void do_idle() {
  if buttons have been pressed and it's time to cut 5 sheets, then
    put '5' into numCutsToDo, 
    start the feeding process, 
    state = FEEDING
}

void do_feeding() {
  if the motor has reached the feed end stop (or we have done the requisite number of steps, then
    stop the feed process
    start cutting in the appropriate direction
    state = CUTTING
}

void do_cutting() {
  if the current cut is complete, then
    stop cutting
    reverse cutterDirectionForward (cutterDirectionForward = !cutterDirectionForward)
    decrement the number of remaining cuts to do
    if there are no more cuts to do, then
      turn everything off
      state = IDLE
    else
      start the feed process
      state = FEEDING
}

Purely based on the below, I suspect that a statemachine based on a switch/case is what you need

The sequence would look like this:
Feed Roller (x axis) feeds out 36600 steps (297mm in real measurements)
Once (x axis) reaches position the cutter (y axis) runs full width of 6600 steps (1500mm)
This will run for a set amount of times

  1. Wait for a start command.
  2. Start moving X
  3. Wait for X move completed
  4. Cutter down
  5. Start moving Y
  6. Wait for Y move completed
  7. Cutter up
  8. Back to (1)

The below can act as a framework.

Define the states (steps) that your program has to go through; based on above

// possible states
#define WAIT_START 0
#define START_X 1
#define WAIT_X_COMPLETED 2
#define CUTTER_DOWN 3
#define START_Y 4
#define WAIT_Y_COMPLETED 5
#define CUTTER_UP 6
#define FINISHED 7

// current state
byte currentState = WAIT_START;

void setup()
{
  ...
  ...
}

You can expand as you like; numbers need to be unique but sequence does not matter.

In loop()

void loop() {

  switch (currentState)
  {
    case WAIT_START;
      if (digitalRead(startButton) == LOW)
      {
        currentState = START_X;
      }
      break;
    case START_X;
      digitalWrite(motorX, HIGH);
      currentState = WAIT_X_COMPLETED;
      break;
    case WAIT_X_COMPLETED:
      countStepsX();
      if (stepsX == 36600)
      {
        digitalWrite(motorX, LOW);
        currentState = CUTTER_DOWN;
      }
      break;
    case CUTTER_DOWN:
      digitalWrite(cutter, HIGH);
      currentStep = START_Y;
      break;
    case START_Y:
      digitalWrite(motorY, HIGH);
      currentState = WAIT_X_COMPLETED;
      break;
    case WAIT_Y_COMPLETED:
      countStepsY();
      if (stepsY == 6600)
      {
        digitalWrite(motorY, LOW);
        currentState = CUTTER_UP;
      }
      break;
    case CUTTER_UP:
      digitalWrite(cutter, LOW);
      currentState = FINISHED;
      break;
    case FINISHED:
      currentState = WAIT_START;
      break;
    default:
      Serial.println("unknown state");
      break;
  }
}

Every time a state is completed, currentState will be updated and the next time loop() is called, the corresponding case will be executed.

As said, a framework; it was not immediately clear to me what exactly needed to happen once a cycle is completed. In the FINISHED state, you can have a counter; once the counter reaches a defined number of cycles, you can go to WAIT_START, else you can go to START_X and repeat the cycle.

I hope this gets you on the way.

Thanks for the swift responses and guidance guys, I thought there would be a simpler way to achieve my goal just couldn't see the woods for the trees.

Paul, yes the cutter would feed then cut in one direction feed again then cut in the opposite direction running the cycle.

Looks like i'm off code bashing a new sketch for the next week or so turning this into a state machine, I'll be back when the next code wall jumps up in front of me.

Again thanks for the pointers

Smiler

I'll be back when the next code wall jumps up in front of me.

So, that's what those are the I keep running into. 8)

Smiler2000:
Looks like i'm off code bashing a new sketch for the next week or so turning this into a state machine, I'll be back when the next code wall jumps up in front of me.

Have a look at Planning and Implementing a Program

...R