Optical Table CNC Lathe - MPG

I really dislike jogging axes on a computer, so a manual pulse generator was always planned for this build. In order to implement this, I have dedicated headers on the KFlop breakout board. I added 2 3-position switches. The first to select between disable and the x and z axes. The second to select the step size 1x, 10x and 100x.

Naturally, I forgot to connect the Gnd net to the appropriate pins in the header:

But it's easy to fix. Electrically, then, this is how the MPG is implemented:

Next comes the software implementation. There are some examples to work off of, but I am starting with this one:

https://github.com/mhaberler/KMotion432/blob/master/C%20Programs/MPGSmoothHardwareEnc.c

It starts out with this:

// Example Init program that includes "smooth" MPG motion example
// which makes use of the exponential motion command.
#define MPG_INPUT_AXIS 6
#define TAU 0.08 // smoothness factor (Low Pass Time constant seconds)
#define FINAL_TIME 1.0 // Set final dest after this amount of time with no change
#define ENABLE_MPG 14
#define SELECTX 16
#define SELECTY 17
#define SELECTZ 18
#define FACTOR1 19
#define FACTOR10 20
#define FACTOR100 21

The MPG_INPUT_AXIS is the hardware encoder input which the MPG wheel is on. I have it on H2 of the expansion board, which goes to Enc3 (on U2), which goes to the 26 pin header on KFlop on pins 13 and 14. To KFlop, this is AXIS number 3. (https://dynomotion.com/Help/SchematicsKFLOP/ConnectorsKFLOP.htm)

The ENABLE_MPG signal is going to H6 pin 5 on the expansion board, which goes to pin 12 on the SnapAMP 50 pin expansion header. To SnapAMP, this is IO pin number 12. (https://dynomotion.com/Help/SchematicsSnap/Header50Pin.PNG). This translates to bit 92 inside of the KFlop. (http://dynomotion.com/Help/KFlopManual.pdf page 78)

The SELECTX signal is going to H6 pin 6 on the expansion board, which goes to pin 14 on the SnapAMP 50 pin expansion header. To SnapAMP, this is IO pin number 13. (https://dynomotion.com/Help/SchematicsSnap/Header50Pin.PNG). This translates to bit 93 inside of the KFlop. (http://dynomotion.com/Help/KFlopManual.pdf page 78)

The SELECTY signal is not necessary, so I remove it.

The SELECTZ signal is going to H6 pin 4 on the expansion board, which goes to pin 13 on the SnapAMP 50 pin expansion header. To SnapAMP, this is IO pin number 6. (https://dynomotion.com/Help/SchematicsSnap/Header50Pin.PNG). This translates to bit 86 inside of the KFlop. (http://dynomotion.com/Help/KFlopManual.pdf page 78)

The FACTOR1 signal is going to H5 pin 5 on the expansion board, which goes to pin 4 on the SnapAMP 50 pin expansion header. To SnapAMP, this is IO pin number 8. (https://dynomotion.com/Help/SchematicsSnap/Header50Pin.PNG). This translates to bit 88 inside of the KFlop. (http://dynomotion.com/Help/KFlopManual.pdf page 78)

The FACTOR10 signal is going to H5 pin 6 on the expansion board, which goes to pin 6 on the SnapAMP 50 pin expansion header. To SnapAMP, this is IO pin number 9. (https://dynomotion.com/Help/SchematicsSnap/Header50Pin.PNG). This translates to bit 89 inside of the KFlop. (http://dynomotion.com/Help/KFlopManual.pdf page 78)

The FACTOR100 signal is going to H5 pin 4 on the expansion board, which goes to pin 8 on the SnapAMP 50 pin expansion header. To SnapAMP, this is IO pin number 10. (https://dynomotion.com/Help/SchematicsSnap/Header50Pin.PNG). This translates to bit 90 inside of the KFlop. (http://dynomotion.com/Help/KFlopManual.pdf page 78)

So the code changes to

#define MPG_INPUT_AXIS 3
#define TAU 0.08 // smoothness factor (Low Pass Time constant seconds)
#define FINAL_TIME 1.0 // Set final dest after this amount of time with no change
#define ENABLE_MPG 92
#define SELECTX 93
#define SELECTZ 86
#define FACTOR1 88
#define FACTOR10 89
#define FACTOR100 90

Wow! Pretty easy to make mistakes....

The rest of the code is relatively straightforward:

int Change1, NewPos, Pos;

  int InMotion=FALSE,Axis,LastAxis=-1;
  double LastChangeTime=0,Target,Factor=0;
  Pos = chan[MPG_INPUT_AXIS].Position;
  for (;;)
  {
    NewPos = chan[MPG_INPUT_AXIS].Position;
    Change1 = NewPos - Pos;
    Pos = NewPos;
    if (ReadBit(ENABLE_MPG)) // if button pressed ignore the encoder.
      Change1 = 0;
    else if (ReadBit(FACTOR1))  // is X1 selected?
      Factor = 2;
    else if (ReadBit(FACTOR10))  // is X10 selected?
      Factor = 20;
    else if (ReadBit(FACTOR100))  // is X100 selected?
      Factor = 200;
    else                  
      Factor = 0.0;
    if (ReadBit(SELECTX))  // is x selected?
      Axis=0;
    else if (ReadBit(SELECTY))  // is y selected?
      Axis=1;
    else if (ReadBit(SELECTZ))  // is z selected?
      Axis=2;
    // check if the Axis just changed or we have been
    // converging to the target for a long time
    if (Axis != LastAxis ||
      (InMotion && Time_sec() > LastChangeTime+FINAL_TIME))
    {
      if (InMotion)
        Move(LastAxis,Target);  //finalize any motion
 
      LastAxis = Axis;
      InMotion = FALSE;
    }
   
    if (Change1) // did we move?
    {
      if (!InMotion) Target = chan[Axis].Dest;
      Target += Change1 * Factor;
      MoveExp(Axis,Target,TAU);  // note: contains a WaitNextTimeSlice
      LastChangeTime = Time_sec();
      InMotion=TRUE;
    }
    else
    {
      WaitNextTimeSlice();
    }   
  } 

But it still requires some changes.

This section :

if (ReadBit(ENABLE_MPG)) // if button pressed ignore the encoder.

      Change1 = 0;
    else if (ReadBit(FACTOR1))  // is X1 selected?
      Factor = 2;
    else if (ReadBit(FACTOR10))  // is X10 selected?
      Factor = 20;
    else if (ReadBit(FACTOR100))  // is X100 selected?
      Factor = 200;
    else                  
      Factor = 0.0;

assumes that there is an enable bit that is active high, however, my enable is active low, so I have to invert the logic.

if (0 == ReadBit(ENABLE_MPG)) // if rotary knob is on 'off' this bit is high

      Change1 = 0;
    else if (ReadBit(FACTOR1))  // is X1 selected?
      Factor = 2;
    else if (ReadBit(FACTOR10))  // is X10 selected?
      Factor = 20;
    else if (ReadBit(FACTOR100))  // is X100 selected?
      Factor = 200;
    else                  
      Factor = 0.0;

Next, this section:

if (ReadBit(SELECTX)) // is x selected?

      Axis=0;
    else if (ReadBit(SELECTY))  // is y selected?
      Axis=1;
    else if (ReadBit(SELECTZ))  // is z selected?
      Axis=2;

needs to be adjusted because I don't have a y axis. Also, my x and z axes are not on channel 0 and 1, but 4 and 5

if (ReadBit(SELECTX)) // is x selected?

      Axis=4;
    else if (ReadBit(SELECTZ))  // is z selected?
      Axis=5;