Seeking advice on using ISR flags for 2nd purpose, Opto-encoders on Steppers

Hello.

Maybe youse guys with more Arduino experience and brain power can point me to solutions for an issue, I'll try to be brief in my descriptions... ...famous last words.

I'm running an Arduino routine on a Mega to drive stepper motors for an industrial machine. 2 of the motors have quadrature optical encoders that provide positional feedback, and the code for this feedback, processed by 4 interrupts, modifies the next motor rotation step counts. This is all fine.

But now I need to use the encoder pulses, I think, the 4 ISR flags to count motor rotations, forward and backward, provide this info to the serial monitor, and also when the steppers are not in use (though the encoders are powered, the motors are not enabled). The machine transports can be advanced by hand during mechanical set-up.

Can anyone suggest a method to use the ISR flags or some other approach to count all motor rotations from init, in a way that can print-out for the operator in real-time without slowing the machine down?

I made a quick attempt at the bottom of the code in the 'encoder correction and debug' section at the bottom. It sort of works but it slows down the routine and doesn't really work properly.

I have extracted the relevant ISR code and definitions, to keep the long stepper drive code from bogging you down here. I can include more if it can't be understood without it.

Thanks in advance for your time!

-girgs

/*  ************* 2 Stepper motors with optical quaderature encoder feedback via ISR,
***************** used to maintain lock to 'home' positions and further to use
***************** ISR flags to count motor rotations, forward and backwards, and real-time println
* 
*                 This needs not to slow down the machine movement and needs to be active when
*                 the steppers are not enabled, as the motors can be turned by hand, non-energized.
* 
*                 This code extracts the relevant ISR and encoder sections only, leaving out
*                 a lot of code that drives the steppers, just to keep it simpler for viewing.
*                 
*                 This is used with a Mega. The two steppers are called "Camera" and "Projector"



*/

#define CAMERAA 18
#define CAMERAB 19
#define PROJECTORA 20
#define PROJECTORB 21

#define CAMFIRST 1285 // stepper home position points, in 2K steps
#define PROJFIRST 976
#define FADERFIRST 1285
#define CAMBACK 516
#define PROJBACK 831
#define FADERBACK 516

int trx18, trx20; // captures rotation position of camera A projector A. Forward
int trx19, trx21; // captures rotation position of camera B and projector B, Reverse
volatile boolean flag18, flag19, flag20, flag21;
int camcount, projcount;
int correctcam = 0, correctproj = 0;
int CameraOptoA = 0;
int ProjectorOptoA = 0;
int lastCamFrameCount = -1;
int lastProjFrameCount = 0;

int CamHomePin = 18;    // Pin for input Aø camera encoder
int CamHomePinB = 19;    // Pin for input Bø camera encoder
int ProjHomePin = 20;    // Pin for input Aø Projector encoder
int ProjHomePinB = 21;   // Pin for input Bø Projector encoder

}

void setup() {  
  int i; // general index
  volatile boolean flag18=false, flag19=false, flag20=false, flag21=false;

}

  pinMode(CamHomePin, INPUT); // Pin set at point in Cam motor rotation
  pinMode(CamHomePinB, INPUT); // B home pin
  pinMode(ProjHomePin, INPUT); // Pin set at point in Proj motor rotation
  pinMode(ProjHomePinB, INPUT); // Pin home B
  attachInterrupt(5, set18, RISING); // Camera first transition, Interrupt#, ISRname, mode
  attachInterrupt(4, set19, RISING); // Camera B transition
  attachInterrupt(3, set20, RISING); // Projector first transition
  attachInterrupt(2, set21, RISING); // Projector B transition

  Serial.begin(38400); // set speed for reading from serial line

  } // end of one time module setup

//       ********* ISRs ***********

void set18() {  // Interrupt module 5 
  trx18 = camcount; // count seen at location (loc)
    flag18 = true; // create cameraA encoder event Tick
}
void set19() {  // Interrupt module 4
  trx19 = camcount;   // capture location at interrupt
    flag19 = true; // create ProjectorA encoder event Tick
}
void set20() {  // Interrupt module 3 for histogram
  trx20 = projcount; // count seen at location (loc)
    flag20 = true; // create CameraB encoder event Tick
}
void set21() {  // Interrupt module 2
  trx21 = projcount;   // Capture location when signal changes
    flag21 = true; // create ProjectorB encoder event Tick
}

void loop() { //to get the full TOTALSTEPS = 2000, takes about .25 seconds.
  int i; // general index

// a bunch of code for stepper drive

  boolean waiting=true; // To accumulate number and command
  boolean camsel=false, projsel=false, fadersel=false; // true for transport enables
  boolean adjust=true; // Correction but protected to take place only after transition sample has been seen
  boolean DoLoop=true; // cycle through action command
  boolean prnt = false; // HIDE print transitions, debug homing precision
  boolean forward = true;
  boolean projforward=true, camforward=true, faderforward=true;
  steps = 0;
  while(waiting) { // - 2 waiting for command entry

// a bunch of code for CASE stepper drive commands, serial monitor print




// ***********   MAIN EVENTS   ************
      
    } // if serial available - 2
  } // while waiting - 1
  correctcam = 0;
  correctproj = 0;
  DoLoop = true;
  while(DoLoop) { // - 2

// a ton of code for stepper drive


  // *********   Encoder Correction and Debug **********
      
      
      if(prnt) {
        gona=2000+correctcam;    
        Serial.print("Camera steps to Home / steps taken ");
        Serial.print(gona, DEC);
        Serial.print(" / ");
        Serial.println(camcount, DEC);
        gona=2000-correctproj;
        Serial.print("Projector steps to Home / steps taken ");
        Serial.print(gona, DEC);
        Serial.print(" / ");
        Serial.println(projcount, DEC);
      }

      if(adjust) { // - 4
        if(forward) { // - 5
          if(trx18 != 0) correctcam = trx18-CAMFIRST-correctcam;
          if(trx20 != 0) correctproj = trx20-PROJFIRST-correctproj;
        } // - 4
        else { // - 5
          if(trx18 != 0) correctcam = trx18-CAMBACK-correctcam;
          if(trx20 != 0) correctproj = trx20-PROJBACK-correctproj;
        }  // - 4        
      } // -  3 end adjust 
      
      
      
        if (flag18) { // -4
          if(forward) { // - 5
          CameraOptoA++;
          delay(250);
          } // - 4
          else { // - 5
            if(flag19) 
              CameraOptoA--;
              delay(250);
            }
       // }
         // if (lastFrameCount != CamApulses)  {  // - 4 only do output if the count has changed

           Serial.print ("CF = ");          // out to serial
           Serial.println(CameraOptoA, DEC);
          } // - 3
                  
          lastCamFrameCount = CameraOptoA;    // end track count
          
          if (flag20) { // -4
             if(forward) { // - 5
          ProjectorOptoA++;
          delay(250);
          } // - 4
          else { // - 5
            if(flag21) 
              ProjectorOptoA--;
              delay(250);
            }
       // }
         // if (lastFrameCount != CamApulses)  {  // - 4 only do output if the count has changed

           Serial.print ("PF = ");          // out to serial
           Serial.println(ProjectorOptoA, DEC);
          } // - 3
                  
          lastProjFrameCount = ProjectorOptoA;    // end track count
   
 
      
      
      /*

      USE FLAGS to Tick FRAME COUNTS  here?

      
      Serial.print(" Encoder Pulses ");
      Serial.print(flag18, BIN);
      Serial.print(" / ");
      Serial.print(flag19, BIN);
      Serial.print(" / ");
      Serial.print(flag20, BIN);
      Serial.print(" / ");
      Serial.println(flag21, BIN);
      
      */
      
      if(prnt) { // - 4 show transitions
        Serial.print(" Pin 18/Pin 19/Pin 20/Pin 21/ ");
        Serial.print(trx18, DEC);
        Serial.print(" / ");
        Serial.print(trx19, DEC);
        Serial.print(" / ");
        Serial.print(trx20, DEC);
        Serial.print(" / ");
        Serial.print(trx21, DEC);
        Serial.print(" / ");
        Serial.print(" Correction for Camera and Projector /");
        Serial.print(correctcam, DEC);
        Serial.print(" / ");
        Serial.println(correctproj, DEC);
      } // - 3
      trx18 = 0;
      trx20 = 0;

    } // - 2 cycles end
    DoLoop = false;
  } // - 1 while loop
  digitalWrite(CamEnablePin, HIGH); // Stepper idles
  digitalWrite(ProjEnablePin, HIGH); //
  digitalWrite(FaderEnablePin, HIGH); //
} // routine void - 0

How do You intend to use the info received in Serial monitor?
A high speed of data bursting in can be analized later by copying the Serial monitor into some analize Environment or, do You want to read the Serial monitor data in real time using Your eyes and make descicions?

Right, thanks for your response.

The data is in fact for the operator to verify that machine movement jives with 'his' initial movement commands. The 'status' of the machine needs to be verified in real-time, or risk wasting a lot of expensive process material.

Another hope is to send this data and other information, via serial3, to a legacy, embedded system local control panel, for machine status update, but that's a future improvement for now.

Can You let the code compare info and send alerts to the operator in case there is a difference, an abnormality? No operator will manage to analyze a high speed stream of data for more than a very short time. I know, I have been checking the output of a high speed machine in order to sort out defective items. It is just not posible in a production environment.

Yeah, that might be useful. The rotations are relatively slow, like 2/second, and the two motor movements alternate, so the op can keep up, for a time, come back later and look again, that type of thing. The workflow is such that when the op takes a look, it's appropriate to check a mechanical legacy counter and the spit-out from the Arduino version of counting better match. Best to check that a 'wet' run of the machine move matches or one can make an expensive mistake. But point taken.

I guess the larger question is about whether (and how) the ISR flags are used for the 2nd purpose, that of the rotation counting, and what code I can add to do it properly. It needs to be out of the operative loop so that it counts during set-up, but then within the the loop as the machine moves. The current attempt I mentioned in the intro needs to be modified to get it to work during movement and idle. I'll take another look later to see exactly how it fails. I should've done that before posting... ...of course.

I haven't analyzed Your code. My intention was to make You find out how often You want the data. Then You can choose where in the code You output the Serial data.
Very often people head for faar more info than any human can observe and then loop() is delayed because of a filled up Serial output buffer. If You can use a high baud rate the risc for waiting in Serial.print is lowered. But, no need for outputting more data then the operator can observe.
Night time for me.....

OK, thanks, I'll do some more pondering on that!