Welcome! Log In Create A New Profile

Advanced

Marlin Babystepping

Posted by lvx0 
Marlin Babystepping
March 25, 2014 04:44PM
Hi All,

I'm new to this forum as a contributor, but a frequent reader and reprap enthusiast.
I have a Delta 3D printer (home build on megatronics v2.0) running Erik Zalms Marlin firmware.

One thing that is keeping me busy lately is this new feature called 'Babysteps'.
It gives the user the opportunity the move one of the axis while printing, this comes in handy if your z-level (or x and y) isn't correct. You can now adjust the x,y or z level realtime. And put the hotend really close to the printbed for the first layer adhesion. See this video.

The implementation of babystepping by the marlin team is done at the lcd menu. This gives the user a real time adjustment by the rotary encoder of the lcd.

I don't have a lcd or keypad, so my bad luck is to implement it myself.
My setup uses to push buttons, one for z-up, one for z-down. They are wired to 2 digital pins on the board as pulldown's.

My question is if someone is trying to achieve the same, and is willing to discuss/share on this subject, or help to improve the marlin firmware.

Best regards,
lvx0
Re: Marlin Babystepping
March 26, 2014 12:27AM
I think this is a brilliant idea!

Have you got source code working for Marlin? I'm using Rich Cattel's Marlin fork... I haven't much C++ programming experience but I'd be willing to help!
Re: Marlin Babystepping
March 26, 2014 05:35AM
Of course I have some, but the Marlin guys did some including on their own.

You have to activate babystepping in the configuration_adv.h, search for babystep and uncomment the '#define BABYSTEPPING'.
If you have a lcd hooked up, then the above code will enabled it for you.

If not,..then you have to find some available logic pins on your board, mine is a megatronics v2.0. I'm using the Aux3 pins 46, 48 and GND.
After that you have to add some code to make the pins available and some code to check the state of the pins.

In pins.h you have to add the pins at the corresponding board:
 // Babystep pins for buttons up and down
 #define BABYSTEP_UP_PIN 48
 #define BABYSTEP_DOWN_PIN 46


In marlin_main.cpp I added the below code just before the void setup():
//=============================
// BabyStepping !!!!!!!!
//=============================
bool babystep_switch_up = false;           // on/off boolean switch for baby up step commando's
bool babystep_switch_down = false;         // on/off boolean switch for baby down step commando's
 
void setup_babystep_pins() {
    #if defined (BABYSTEP_UP_PIN) && (BABYSTEP_UP_PIN > -1)
	SET_INPUT(BABYSTEP_UP_PIN);
	WRITE(BABYSTEP_UP_PIN, HIGH);
    #endif
    #if defined (BABYSTEP_DOWN_PIN) && (BABYSTEP_DOWN_PIN > -1)
         SET_INPUT(BABYSTEP_DOWN_PIN);
	 WRITE(BABYSTEP_DOWN_PIN, HIGH);
    #endif
}

void babystep_update() {
	if ((READ(BABYSTEP_UP_PIN) == 0) && (babystep_switch_up == false)) {
		babystepsTodo[Z_AXIS]+=BABYSTEP_Z_MULTIPLICATOR;
		babystep_switch_up = true;
                SERIAL_ECHOLN("BabyUp Pushed");
	}
	if ((READ(BABYSTEP_UP_PIN) == 1) && (babystep_switch_up == true)) {
		babystep_switch_up = false;
                SERIAL_ECHOLN("BabyUp Off");
                SERIAL_ECHO("BabyStepTodo: ");
                SERIAL_ECHOLN(babystepsTodo[Z_AXIS]);
	}
	if ((READ(BABYSTEP_DOWN_PIN) == 0) && (babystep_switch_down == false)) {
		babystepsTodo[Z_AXIS]-=BABYSTEP_Z_MULTIPLICATOR;
		babystep_switch_down = true;
                SERIAL_ECHOLN("BabyDown Pushed");
	}
	if ((READ(BABYSTEP_DOWN_PIN) == 1) && (babystep_switch_down == true)) {
		babystep_switch_down = false;
                SERIAL_ECHOLN("BabyDown Off");
                SERIAL_ECHO("BabyStepTodo: ");
               SERIAL_ECHOLN(babystepsTodo[Z_AXIS]);
	}
}

Then you have to add a line in 'void setup()' calling for the function 'setup_babystep_pins()'.
And a line in 'void main()' for the function 'babystep_update()' .

View the code snippets in marlin_main.cpp:
void setup()
{
  setup_killpin();
  setup_powerhold();
  MYSERIAL.begin(BAUDRATE);
  SERIAL_PROTOCOLLNPGM("start");
  SERIAL_ECHO_START;
  setup_babystep_pins();
  ....
void loop()
{
...
  //check heater every n milliseconds
  manage_heater();
  manage_inactivity();
  checkHitEndstops();
  lcd_update();
  babystep_update();
}


That's it.....the rest is up to the marlin guys. The function will increase or decrease the variable 'babystepsTodo[AXIS]'. And in temperature.cpp there is an interrupt handler ("ISR(TIMER0_COMPB_vect)") which will work to babysteps.

That last part is the tricky bit, I just can't get to work. It should and it does, but no movement for me.

Keep me updated on your progress......

Edited 1 time(s). Last edit at 03/26/2014 05:38AM by lvx0.
Re: Marlin Babystepping
March 27, 2014 01:18PM
Thank you for the explicit code!

After having a bit of thought I reckon the next step would be to determine how large a babystep is (steps / babystep) and send the appropriate pulses to each stepper. I reckon there would be a timing arrangement of some sort as well.

Unfortunately, the fork of Marlin I'm currently using doesn't have the baby-stepping functionality but I imagine it'd be simple thing to merge.

I'll let you know if I have any breakthroughs - presently I've discovered major rocking in my effector and I have a feeling it's the new springs I setup on the arms... too tight.
Re: Marlin Babystepping
March 27, 2014 03:44PM
Just to follow up on your comment,.

The variable "BABYSTEP_Z_MULTIPLICATOR" is a predefined variable by the marlin team. It is a multiplicator for the encoder steps.
I reused this variable, so that by default the above code is easy to use for everyone.

And as far as I know 1 babystep is 1 stepper step.
So I put the BABYSTEP_Z_MULTIPLICATOR to 1/10 of my stepper resolution. This gives me 0.1mm of movement per button push.

With that I would suggest it;s working, but at the moment I'm having a blank moment on why it isn't.

Maybe I have to put up an issue request on Erik Zalms Marlin github.
Re: Marlin Babystepping
March 27, 2014 10:33PM
Please forgive my naive optimism, however, is it possible to append the BabySteps within the prepare_move() function within Marlin_main.cpp, similar to this:

void prepare_move()
{
  clamp_to_software_endstops(destination);

  previous_millis_cmd = millis();
#ifdef DELTA
  float difference[NUM_AXIS];
  for (int8_t i=0; i < NUM_AXIS; i++) {
    difference = destination - current_position;
  }
  float cartesian_mm = sqrt(sq(difference[X_AXIS]) +
                            sq(difference[Y_AXIS]) +
                            sq(difference[Z_AXIS]));
  if (cartesian_mm < 0.000001) { cartesian_mm = abs(difference[E_AXIS]); }
  if (cartesian_mm < 0.000001) { return; }
  float seconds = 6000 * cartesian_mm / feedrate / feedmultiply;

  // Append Baby Steps
  int steps = max(1, int(DELTA_SEGMENTS_PER_SECOND * seconds) + babystepsTodo[Z_AXIS]);
  
  // Clear babystepsTodo
  babystepsTodo[Z_AXIS] = 0;
  
  // SERIAL_ECHOPGM("mm="); SERIAL_ECHO(cartesian_mm);
  // SERIAL_ECHOPGM(" seconds="); SERIAL_ECHO(seconds);
  // SERIAL_ECHOPGM(" steps="); SERIAL_ECHOLN(steps);
  for (int s = 1; s <= steps; s++) {
    float fraction = float(s) / float(steps);
    for(int8_t i=0; i < NUM_AXIS; i++) {
      destination = current_position + difference * fraction;
    }
    calculate_delta(destination);
    adjust_delta(destination);
    plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS],
                     destination[E_AXIS], feedrate*feedmultiply/60/100.0,
                     active_extruder);
  }
#else

...


I'm going to start experimenting soon. Right now I'm in the middle of a 5 hour print to torture test a new extruder design.
Re: Marlin Babystepping
March 28, 2014 03:26PM
Hi Vitaminrad,

What I think you want is an update of the babystepsTodo at every prepare_move(). That would be nice.
That said I think the best place for that would in the interrupt handler of the steppers in stepper.cpp.

I'm not sure if this will work. I'm (at htis point) not even sure if this is the correct location. Because the prepare move is called at several locations.

One small error is the line:
// Clear babystepsTodo
  babystepsTodo[Z_AXIS] = 0;
This is a global variable passing around the requested number of steps per axis.
In the temperature.cpp you can find the loop (also an interrupt loop) that will handle that request. It checks of the variable is 0(zero), means do nothing. >0 means do forward stepping or <0 means do backward stepping.
That means if you change the variable to 0 (zero) there is no request. But if the code in the prepare_move() is being interrupted (and that it will) the variable will be zero by the time it reaches that line.

But for sure we are trying to find a solution to this....keep up......I like your idea of an integral update loop.
Re: Marlin Babystepping
April 17, 2014 11:55AM
Take a look here:

Marlin Github issue 861
Re: Marlin Babystepping
April 18, 2014 10:48AM
From the git issue and it being closed, it think the guys did not understood what you wanted to do. If i understand correctly, you want to access the babysteping utility without a lcd, and using 2 GPIO pins instead- no lcd, no menu.
So in ultralcd.cpp when lcd is babystepping all it does its chaging a var babystepsTodo per each axis. Idd we could have some other function doing the same thing without lcd, and that would put life in the rest of the existing babystepping utility. Nice idea and since i have a setup made for playing around, i just tried this and i find it to be both quite useful but also potentially dangerous if used with latched hardware or if other bad things happen.

Atm i got the following working, if you want to test my approach.

The following goes in config advanced but since we need to also define babystepping then its good to have it nested into that:
#define BABYSTEPPING
#ifdef BABYSTEPPING
  #define BABYSTEP_XY  //not only z, but also XY in the menu. more clutter, more functions
  #define BABYSTEP_INVERT_Z false  //true for inverse movements in Z
  #define BABYSTEP_Z_MULTIPLICATOR 2 //faster z movements
  
(+)  #define BABYSTP_GPIO_Z /*nbm alternate babystepping Z with 2 GPIO buttons (no lcd, no menu) */
(+)  	#ifdef BABYSTP_GPIO_Z
(+)  	#define BABYSTP_GPIO_ZUP 46 // Babystep pin for up
(+)  	#define BABYSTP_GPIO_ZDN 48 // Babystep pin for down
(+)  	#define BABYSTP_GPIO_NUM 1  // Impact variable, sort of number of steps, default 1
(+)  #endif //BABYSTP_GPIO_Z

(+)  #define BABYSTP_DLYU_FCT 1000  // only applies if babystep() in stepper.cpp is using delayMicroseconds()

  #ifdef COREXY
    #error BABYSTEPPING not implemented for COREXY yet.
  #endif
  #ifdef DELTA
    #ifdef BABYSTEP_XY
      #error BABYSTEPPING only implemented for Z axis on deltabots.
    #endif
  #endif
#endif

/* declarations going in temperature.h : */
#ifdef BABYSTP_GPIO_Z
  void babystp_gpio_z_setup();
  void babystp_gpio_z_read();
#endif /*BABYSTP_GPIO_Z*/

/*nbm functions content going in temperature.cpp under "fuctions" chapter*/
#ifdef BABYSTP_GPIO_Z
  void babystp_gpio_z_setup() /*nbm actual pin setup*/
	{
	SET_INPUT(BABYSTP_GPIO_ZUP); /*maybe simpler with pinmode etc, instead fastio*/
	WRITE(BABYSTP_GPIO_ZUP,1);
	SET_INPUT(BABYSTP_GPIO_ZDN); 
	WRITE(BABYSTP_GPIO_ZDN,1);
	}

void babystp_gpio_z_read() /*nbm pin reading changing the babystepsTodo*/
	{
	if      ((READ(BABYSTP_GPIO_ZUP))==LOW) /*prioritize up and ignore case with both*/
		{    babystepsTodo[Z_AXIS]+=BABYSTP_GPIO_NUM; }
	else if ((READ(BABYSTP_GPIO_ZDN))==LOW)
		{    babystepsTodo[Z_AXIS]+=BABYSTP_GPIO_NUM*(-1); } /*double check whats up and down*/
	}
#endif /*BABYSTP_GPIO_Z*/

/* calling for pin setup in marlin_main from the void setup(){....at the end} */
#ifdef BABYSTP_GPIO_Z 
  babystp_gpio_z_setup(); /*nbm call for _setup() from marlin_main void setup(){...at the end} */
#endif /*BABYSTP_GPIO_Z*/

At this point the pin setup function is ok if both the pins are measured with multimeter and they have ~5v (are "high").

/* calling for _read() update from ... some unknown place e.g. void updateTemperaturesFromRawValues() or test other places*/
#ifdef BABYSTP_GPIO_Z  
  babystp_gpio_z_read(); /*nbm call for read() update from ... some other function, guess a good place*/
#endif /*BABYSTP_GPIO_Z*/

At this point i put a 1k resistor in either of the two defined pins, and touch it to a place where is ground, basically driving the pin low. The Z axis does move immediately, even during printing, so i can adjust the size of the first layer like this.

Now, i dont know Marlin and dont know of the best place to call the babystp_gpio_z_read(). I tested it and works if its called from several places in the temperature.cpp, last time i called it from the end of the function updateTemperaturesFromRawValues(). I tried to hack it, not to do it properly. But i am sure somebody with a better understanding would find a better place for this update. I tried to call from ISR just before babystepTodo is evaluated, it also does work like this eventually, but each time the printer starts after reset the Z is enabled and makes some weird stuttering noise (maybe something to do with pins setup).

So for me it basically works for the intended purpose. Now should mention that Z moves as long as the pins are driven low from their own pullup, so perhaps its a good idea to use push buttons and not switches, because if you flip the switch open by mistake, or again if the switch is forgot in the wrong position, it would ruin prints and even it would make the z move infinitely which is quite bad. The implementation could be changed with some debounce, something like a added variable or checks that it only makes some moves for a push and then clears the variable, etc, and that would perhaps make it less dangerous, even if not completely proof.

Further on, i think its not the best implementation - on more than one count. Again, this currently uses 2 pins for 2 "keys", which is sort of bad. By all means it should better use one analog pin to read a ladder, perhaps with more than just 2 keys, could easily be extended for 8keys like z+x+y+e, or even could use a regular 16 keys keypad for an input. And all that can be with 1 analog pin and resistor ladder, where there are predefined adc values for each key pressed, and that is basically a read method almost identically to the thermistor reading. Could have sort of a "adc table for keys". Something like this would be better pin-wise.

I also had issues with the speed of Z (bit too fast), so i changed that short calculation delay to delayMicroseconds() with a variable from config file so i can play with it, and i think i will settle for 1000 us, i dont want the z moves to be too fast so i dont get collisions with the bed while using this. I also added for a delay when the step is low and again a delay for when the step line is high.

Back to the matter at hand, can anybody else check this and see if it works for them also? Cheers.

Edited 2 time(s). Last edit at 04/18/2014 11:32AM by NoobMan.
Re: Marlin Babystepping
May 01, 2014 10:51AM
Hello babystep users :-)

I think....my babysteps don't work.
As you can see in the image below, the menu is active during the print but there is no number on the right side of the menu.
I've turned the knob left and right...no action.

I've activated babysteps in "Configuration_adv.h"
Is there anything else I have to configure?
Where?


Re: Marlin Babystepping
May 01, 2014 11:47AM
two hours later... problem solved.
The steppers were not babystepping because the step-pulses were to short for my DRV8852 drivers.

But, Paulusbrand's solution worked for me.
https://github.com/ErikZalm/Marlin/issues/861



(hey, this is just another post, don't start summing up the beers :-) )
Re: Marlin Babystepping
May 18, 2014 04:37PM
Very nice. I think that the two button solution is perfect, even when you have a lcd.
The problem with babystepping is that it is mostly needed during the first layer, depending on model size and print speed, and so when you have to go through the menus to activate babystepping, the print is already halfway through the first layer.
Would the two button solution also work when the lcd is active?

Besides, does babystepping work together with autobed leveling? It should...
Re: Marlin Babystepping
May 21, 2014 06:57AM
I tried babystepping together with autobed leveling.. it seems not to work, since the lcd shows no value except babystepping Z, no number or anything. Could this have to do with ABL?
Re: Marlin Babystepping
May 23, 2014 11:52AM
The changes above were for a babystepping mod to make it work with 2 buttons (no lcd).

If you do have a lcd, within its menu choose babystepping and rotate the encoder, the number of steps it takes is proportional to how much you moved the encoder.
Re: Marlin Babystepping
July 21, 2015 12:12PM
Quote
yellobello
The problem with babystepping is that it is mostly needed during the first layer, depending on model size and print speed, and so when you have to go through the menus to activate babystepping, the print is already halfway through the first layer.

Try moving the z-axis baby stepping to the top of the Tune menu. This way its very quick to get to it. Works great for us.

Edited 1 time(s). Last edit at 07/21/2015 12:14PM by gordo3di.
Re: Marlin Babystepping
July 23, 2015 01:32AM
OK, the thread was a bit cold already, but new to me.

Q: would it be possible to use unused endstop-switches and the endstop-connectors of a Ramps to implement the 2 button variant?
Which pin number would I chose then? ( eg. y-max and x-min are unused)

The endstops already have a debounce circuit onboard which is a plus for safety.
-Olaf
Re: Marlin Babystepping
September 22, 2015 04:29AM
I don't use ABL because I have a solid steel frame which just does not need leveling after swapping glass on the bed. So would babystepping be of any use?
Re: Marlin Babystepping
September 22, 2015 11:54AM
Sure... If your first layer looks like to not stick properbly you can lower/higher the bed slightly. I also don't use ABL anymore. But this feature is pretty nice. Sometimes you need just 1/100mm to get it stick on your bed. Do you want to restart your print for that?


Triffid Hunter's Calibration Guide --> X <-- Drill for new Monitor Most important Gcode.
Re: Marlin Babystepping
February 18, 2016 04:25AM
Quote
gordo3di
Quote
yellobello
The problem with babystepping is that it is mostly needed during the first layer, depending on model size and print speed, and so when you have to go through the menus to activate babystepping, the print is already halfway through the first layer.

Try moving the z-axis baby stepping to the top of the Tune menu. This way its very quick to get to it. Works great for us.

How do you do this? I'd like to have the babystep option at the top of the tune menu (or even on the main menu).

Does anyone here know if babystepping creates a persistent z-offset? Does it do this if you do m500 after babystepping?
Sorry, only registered users may post in this forum.

Click here to login