From d147a057ac75e52421c8d277655e2e48ca0376a3 Mon Sep 17 00:00:00 2001
From: bkubicek <bkubicek@x201.(none)>
Date: Sun, 6 Oct 2013 21:14:51 +0200
Subject: [PATCH] Add the socalled "Babystepping" feature. It is a realtime
 control over the head position via the LCD menu system that works _while_
 printing. Using it, one can e.g. tune the z-position in realtime, while
 printing the first layer. Also, lost steps can be manually added/removed, but
 thats not the prime feature. Stuff is placed into the Tune->Babystep *

It is not possible to have realtime control via gcode sending due to the buffering, so I did not include a gcode yet. However, it could be added, but it movements will not be realtime then.

Historically, a very similar thing was implemented for the "Kaamermaker" project, while Joris was babysitting his offspring, hence the name.

say goodby to fuddling around with the z-axis.
---
 Marlin/Configuration_adv.h |  11 ++++
 Marlin/stepper.cpp         | 110 +++++++++++++++++++++++++++++++++++++
 Marlin/stepper.h           |   6 ++
 Marlin/temperature.cpp     |  25 ++++++++-
 Marlin/temperature.h       |   5 ++
 Marlin/ultralcd.cpp        |  70 +++++++++++++++++++++++
 6 files changed, 226 insertions(+), 1 deletion(-)

diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 3cbe131c95..b47233a027 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -270,6 +270,17 @@
 // Enable the option to stop SD printing when hitting and endstops, needs to be enabled from the LCD menu when this option is enabled.
 //#define ABORT_ON_ENDSTOP_HIT_FEATURE_ENABLED
 
+// Babystepping enables the user to control the axis in tiny amounts, independently from the normal printing process
+// it can e.g. be used to change z-positions in the print startup phase in realtime
+// does not respect endstops!
+
+//#define BABYSTEPPING
+//#define BABYSTEP_XY  //not only z, but also XY
+
+#ifdef COREXY
+    #error BABYSTEPPING not implemented for COREXY yet.
+#endif
+
 // extruder advance constant (s2/mm3)
 //
 // advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2
diff --git a/Marlin/stepper.cpp b/Marlin/stepper.cpp
index 8b39a41d64..1dc3902b3e 100644
--- a/Marlin/stepper.cpp
+++ b/Marlin/stepper.cpp
@@ -997,6 +997,116 @@ void quickStop()
   ENABLE_STEPPER_DRIVER_INTERRUPT();
 }
 
+#ifdef BABYSTEPPING
+
+
+void babystep(const uint8_t axis,const bool direction)
+{
+  //MUST ONLY BE CALLED BY A ISR, it depends on that no other ISR interrupts this
+    //store initial pin states
+  switch(axis)
+  {
+  case X_AXIS:
+  {
+    enable_x();   
+    uint8_t old_x_dir_pin= READ(X_DIR_PIN);  //if dualzstepper, both point to same direction.
+   
+    //setup new step
+    WRITE(X_DIR_PIN,(INVERT_X_DIR)^direction);
+    #ifdef DUAL_X_CARRIAGE
+      WRITE(X2_DIR_PIN,(INVERT_X_DIR)^direction);
+    #endif
+    
+    //perform step 
+    WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN); 
+    #ifdef DUAL_X_CARRIAGE
+      WRITE(X2_STEP_PIN, !INVERT_X_STEP_PIN);
+    #endif
+    {
+    float x=1./float(axis+1)/float(axis+2); //wait a tiny bit
+    }
+    WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
+    #ifdef DUAL_X_CARRIAGE
+      WRITE(X2_STEP_PIN, INVERT_X_STEP_PIN);
+    #endif
+
+    //get old pin state back.
+    WRITE(X_DIR_PIN,old_x_dir_pin);
+    #ifdef DUAL_X_CARRIAGE
+      WRITE(X2_DIR_PIN,old_x_dir_pin);
+    #endif
+
+  }
+  break;
+  case Y_AXIS:
+  {
+    enable_y();   
+    uint8_t old_y_dir_pin= READ(Y_DIR_PIN);  //if dualzstepper, both point to same direction.
+   
+    //setup new step
+    WRITE(Y_DIR_PIN,(INVERT_Y_DIR)^direction);
+    #ifdef DUAL_Y_CARRIAGE
+      WRITE(Y2_DIR_PIN,(INVERT_Y_DIR)^direction);
+    #endif
+    
+    //perform step 
+    WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN); 
+    #ifdef DUAL_Y_CARRIAGE
+      WRITE(Y2_STEP_PIN, !INVERT_Y_STEP_PIN);
+    #endif
+    {
+    float x=1./float(axis+1)/float(axis+2); //wait a tiny bit
+    }
+    WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
+    #ifdef DUAL_Y_CARRIAGE
+      WRITE(Y2_STEP_PIN, INVERT_Y_STEP_PIN);
+    #endif
+
+    //get old pin state back.
+    WRITE(Y_DIR_PIN,old_y_dir_pin);
+    #ifdef DUAL_Y_CARRIAGE
+      WRITE(Y2_DIR_PIN,old_y_dir_pin);
+    #endif
+
+  }
+  break; 
+  case Z_AXIS:
+  {
+    enable_z();
+    uint8_t old_z_dir_pin= READ(Z_DIR_PIN);  //if dualzstepper, both point to same direction.
+    //setup new step
+    WRITE(Z_DIR_PIN,(INVERT_Z_DIR)^direction);
+    #ifdef Z_DUAL_STEPPER_DRIVERS
+      WRITE(Z2_DIR_PIN,(INVERT_Z_DIR)^direction);
+    #endif
+    //perform step 
+    WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN); 
+    #ifdef Z_DUAL_STEPPER_DRIVERS
+      WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
+    #endif
+    //wait a tiny bit
+    {
+    float x=1./float(axis+1); //absolutely useless
+    }
+    WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
+    #ifdef Z_DUAL_STEPPER_DRIVERS
+      WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
+    #endif
+
+    //get old pin state back.
+    WRITE(Z_DIR_PIN,old_z_dir_pin);
+    #ifdef Z_DUAL_STEPPER_DRIVERS
+      WRITE(Z2_DIR_PIN,old_z_dir_pin);
+    #endif
+
+  }
+  break;
+ 
+  default:    break;
+  }
+}
+#endif //BABYSTEPPING
+
 void digitalPotWrite(int address, int value) // From Arduino DigitalPotControl example
 {
   #if defined(DIGIPOTSS_PIN) && DIGIPOTSS_PIN > -1
diff --git a/Marlin/stepper.h b/Marlin/stepper.h
index 82b41c90de..3a1cb0b5d9 100644
--- a/Marlin/stepper.h
+++ b/Marlin/stepper.h
@@ -92,4 +92,10 @@ void digipot_current(uint8_t driver, int current);
 void microstep_init();
 void microstep_readings();
 
+#ifdef BABYSTEPPING
+  void babystep(const uint8_t axis,const bool direction); // perform a short step with a single stepper motor, outside of any convention
+#endif
+     
+
+
 #endif
diff --git a/Marlin/temperature.cpp b/Marlin/temperature.cpp
index 9d87c54bbd..decab104d5 100644
--- a/Marlin/temperature.cpp
+++ b/Marlin/temperature.cpp
@@ -66,6 +66,10 @@ float current_temperature_bed = 0.0;
   unsigned char fanSpeedSoftPwm;
 #endif
   
+#ifdef BABYSTEPPING
+  volatile int babystepsTodo[3]={0,0,0};
+#endif
+  
 //===========================================================================
 //=============================private variables============================
 //===========================================================================
@@ -1252,7 +1256,26 @@ ISR(TIMER0_COMPB_vect)
        bed_max_temp_error();
     }
 #endif
-  }  
+  }
+  
+#ifdef BABYSTEPPING
+  for(uint8_t axis=0;axis<3;axis++)
+  {
+    int curTodo=babystepsTodo[axis]; //get rid of volatile for performance
+   
+    if(curTodo>0)
+    {
+      babystep(axis,/*fwd*/true);
+      babystepsTodo[axis]--; //less to do next time
+    }
+    else
+    if(curTodo<0)
+    {
+      babystep(axis,/*fwd*/false);
+      babystepsTodo[axis]++; //less to do next time
+    }
+  }
+#endif //BABYSTEPPING
 }
 
 #ifdef PIDTEMP
diff --git a/Marlin/temperature.h b/Marlin/temperature.h
index 75ffcd06bf..a5974241c4 100644
--- a/Marlin/temperature.h
+++ b/Marlin/temperature.h
@@ -53,6 +53,11 @@ extern float current_temperature_bed;
   extern float bedKp,bedKi,bedKd;
 #endif
   
+  
+#ifdef BABYSTEPPING
+  extern volatile int babystepsTodo[3];
+#endif
+  
 //high level conversion routines, for use outside of temperature.cpp
 //inline so that there is no performance decrease.
 //deg=degreeCelsius
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index 05ace2d491..0a0df8f9e0 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -322,6 +322,68 @@ static void lcd_cooldown()
     lcd_return_to_status();
 }
 
+#ifdef BABYSTEPPING
+static void lcd_babystep_x()
+{
+    if (encoderPosition != 0)
+    {
+        babystepsTodo[X_AXIS]+=(int)encoderPosition;
+        encoderPosition=0;
+        lcdDrawUpdate = 1;
+    }
+    if (lcdDrawUpdate)
+    {
+        lcd_implementation_drawedit(PSTR("Babystepping X"),"");
+    }
+    if (LCD_CLICKED)
+    {
+        lcd_quick_feedback();
+        currentMenu = lcd_tune_menu;
+        encoderPosition = 0;
+    }
+}
+
+static void lcd_babystep_y()
+{
+    if (encoderPosition != 0)
+    {
+        babystepsTodo[Y_AXIS]+=(int)encoderPosition;
+        encoderPosition=0;
+        lcdDrawUpdate = 1;
+    }
+    if (lcdDrawUpdate)
+    {
+        lcd_implementation_drawedit(PSTR("Babystepping Y"),"");
+    }
+    if (LCD_CLICKED)
+    {
+        lcd_quick_feedback();
+        currentMenu = lcd_tune_menu;
+        encoderPosition = 0;
+    }
+}
+
+static void lcd_babystep_z()
+{
+    if (encoderPosition != 0)
+    {
+        babystepsTodo[Z_AXIS]+=(int)encoderPosition;
+        encoderPosition=0;
+        lcdDrawUpdate = 1;
+    }
+    if (lcdDrawUpdate)
+    {
+        lcd_implementation_drawedit(PSTR("Babystepping Z"),"");
+    }
+    if (LCD_CLICKED)
+    {
+        lcd_quick_feedback();
+        currentMenu = lcd_tune_menu;
+        encoderPosition = 0;
+    }
+}
+#endif //BABYSTEPPING
+
 static void lcd_tune_menu()
 {
     START_MENU();
@@ -339,6 +401,14 @@ static void lcd_tune_menu()
 #endif
     MENU_ITEM_EDIT(int3, MSG_FAN_SPEED, &fanSpeed, 0, 255);
     MENU_ITEM_EDIT(int3, MSG_FLOW, &extrudemultiply, 10, 999);
+    
+#ifdef BABYSTEPPING
+    #ifdef BABYSTEP_XY
+      MENU_ITEM(submenu, "Babystep X", lcd_babystep_x);
+      MENU_ITEM(submenu, "Babystep Y", lcd_babystep_y);
+    #endif //BABYSTEP_XY
+    MENU_ITEM(submenu, "Babystep Z", lcd_babystep_z);
+#endif
 #ifdef FILAMENTCHANGEENABLE
      MENU_ITEM(gcode, MSG_FILAMENTCHANGE, PSTR("M600"));
 #endif