Dual endstops for X and Y

I've seen reference to using dual endstops to drive each Z motor (on separate drivers of course) to their own endstop, to level out a long axis.

On an MPCNC (popular CNC project using RAMPS), I'm running X and Y with second motors on E0 and E1 using FEATURE_TWO_XSTEPPER and FEATURE_TWO_YSTEPPER, works great and happy to see this in the FW, looked for it in vain on Marlin (or at least not done as simply).

Is there a way to use 2 X and Y endstops like the Z to square off the unit? On longer runs it's not uncommon to see the carriages at each end find their way to being up to a couple centimeters out of alignment after some usage.


  • No, there is no option for dual xy endstops. Z was only added since same stuff can happen if you have separate rods for z axis, which is quite common for 3d printers (prusa style).

  • edited April 2017
    Would I be able to easily adapt the Z code for X and Y, and if so, what would you quickly suggest I look at to get that done?  I took a dev fork to look at but haven't gotten dirty yet, thought maybe there was already a built in option that wasn't documented.
  • I'm going through and doing the XY versions to see if it's as trivial as it looks given the existing MULTI_ZENDSTOP_HOMING code I see there already.  

    I'll post back if I have any questions.
  • Mainly you add more dnstops in configuration and endstop class in printer.h/cpp and copy everything as you plan where MULTI_ZENDSTOP_HOMING  is used. The trick is simply in homing to stop only motor that is triggered and stop complete move if all endstops are triggered. Normal print does not use dual endstops.
  • Well, I had that code copypasta worked up in a couple hours and then rigged my extra endstops yesterday morning.  But I'm not getting what looks like independent sled motion and I'm really not sure why.  

    I've added a Pull Request if you get some time to look at it and see what mistake I've made here.  I've stared at it and obviously I'm not understanding something about the Z2 method.  

    I also don't quite see what the EXTENDED_ENDSTOPS and accumulator2 do in there, maybe that's where I'm going wrong.
  • EXTENDED_ENDSTOPS is just because endstops is a 8 bit field with 1bit per endstop. First covers 8 so has the most widely used. If you need new bits e.g. for X2/Y2 you have to store them in second endstop flag byte.

    If you look into printer.h you see the IDs how second x and y endstops are already defined for the extended endstop byte:

    #define ENDSTOP_X2_MIN_ID 1
    #define ENDSTOP_X2_MAX_ID 2
    #define ENDSTOP_Y2_MIN_ID 4
    #define ENDSTOP_Y2_MAX_ID 8
    #define ENDSTOP_Z2_MAX_ID 16
    #define ENDSTOP_Z3_MIN_ID 32
    #define ENDSTOP_Z3_MAX_ID 64

    so please use these in lastRead2, they are only missing in update function for endstops. Please also use both directions separately as planned.

    And one last wish so I can merge pull requests - please do not try to push your personal configuration.h version. After pulling it will be new default and that makes no sense. Just copy original before committing, also it might be already to late for this if git does not see it, but we will see.

    Except this I think it looks good.
  • edited April 2017
    I wondered about those defined stops, I couldn't find any places they were used but I didn't want to step on your toes if you had plans for them other than this particular purpose.  Seems like this is the purpose you had in mind.  Like an idiot, I didn't track down the size of the variable, I just figured most compilers will choke and throw an error if they don't like the attempt to stuff something too big into it, but since it didn't, I figured I was good to go.  I guess it just ignores it quietly since it doesn't know how much you're going to try to put into it at compile time.

    As for the config, I pushed it just so you had a reference, I did see your request to the last pull request about that, but since I knew this wasn't being merged, I thought I'd include it just in case I'd messed something else up endstop related.  Not quite sure how to remove it at this point from the request, I'm a complete noob at github, but I'll see what I can do, other than starting a new request.

    I'll see where EXTENDED_ENDSTOPS and swapping those IDs takes me then.  Thanks for the guidance.
  • edited April 2017
    OK, I've done another pull request with my somewhat working changes to the dual endstop code.

    As noted in the PR, Y is working properly, but for the life of me I can't see why X does not.  If I swap pins so the axis are swapped in firmware, the problem just follows the X axis, so it does not seem to be a hardware issue as I don't change anything on the board.  I must be missing something in X that I have in Y, but I've looked at all of the inserts several times and can't see any differences.

    Also, I've done all the dev in the first byte laststate, not laststate2, because I see the ENDSTOP_Z2_MINMAX_ID done there as well and I figured to reduce the potential troubleshooting, I'd stick with a known working byte.  Consequently I moved the X and Y MAX to EXTENDED_ENDSTOPS since they wouldn't be used anyway.

    I was also mystified what in my coding was causing it to act as if there were software min endstops acting on all axis, as Z will not go negative at all (since there's no endstop to home) and X and Y won't go back past where they were initialized as well, though it allowed me to home.  I pulled a clean copy of Dev and loaded up a config from a working Master, and it still acts like there are software endstops in force.  I have no clue why this is and couldn't trace the issue.

    I feel really close, but can't figure out these issues, so if you have a chance to check that PR again and make some suggestions about why X won't work but Y does, and why there is this software min going on even on a clean copy, it would be great to get some guidance on that so I can wrap this up and maybe try a couple of other additions.
  • I pushed the commits to that PR, if you get a chance let me know what you think, but at this point I'm pretty perplexed why it isn't working on X but works on Y.

    I might try coding it on the Master branch as a test because there's some behaviour in the Dev branch that seems related enough to potentially be an issue.
  • Please read github comment on this.
  • I've try the latest dev version 26/10 where it's now implemented, thanks to @Repetier, it work perfectly on Z and Y; on X the firmware doesn't send step to the mirror axle driver (the system work if I move manually X slave); anyone the same problem any suggestion?
  • Make sure you have not selected dual x axis as well. That would mean extruder 0 active->move stepper 1, extruder 1 active-> move stepper 2.
  • edited October 2017
    sure I didn't check dual axis.
    I'm comparing now dual motor configuration.h for X and for Y, I let U know in few minutes
  • Also just checked it and saw no error in enable/direction/steps. What drive system are you using here?
    Also do you have 2 endstops or one for x?
  • configuration.h with two motors on Y axis, everything work.
    loaded in online configuration the working configuration.h, make changes to configure two motor on X axis, homing driving only X and not mirror to X2, same with movement over X from repetier host X move X2 not.

    relevant diff changes after axis swapping working/not working
    #define MIN_HARDWARE_ENDSTOP_X2 false/true
    #define X2_MIN_PIN -1/ORIG_X_MAX_PIN
    #define FEATURE_TWO_XSTEPPER 0/1
    #define FEATURE_TWO_YSTEPPER 1/0

    the changes seems are OK

    I don't know if can affect the function but, there is this leftover in configuration.h
    #define MIN_HARDWARE_ENDSTOP_Y2 true (not swapped to false)
    #define Y2_MIN_PIN ORIG_X_MAX_PIN (not swapped to -1)
    something was wrong with the online configurator, checked two times the parameters aren't present in the screen, but not resetted when saved.

    Now I will try to edit by hand and test 
  • edited October 2017
    nope also with the corrections doesn't work.
    The endstops working, also the home cycle is active; when I homing X I see x axis homing to endstop and start to wait forever for x2 endstop, when I manually move the x2 axes to endstop the x move to x_back_on_home and finish the homing.
    So just the driver doesn't receive the pulses, like mirror function is ignored (all the test made without touching wires, just properly assigned axes/endstop to different physical axis, in both cases 2nd motor is connected to E1 out so no any change in configuration.h for this section)
    I can't understand where I'm wrong
  • edited October 2017
    Repetier said:
    Also do you have 2 endstops or one for x?
    I'm using arduino 2 & radds 1.5
    Yes off course two indipendent endstop; and everything working perfectly if I set in the configuration that this physical axis is the Y
  • Have rechecked everything and still do not see the problem. So please help me with some more detailed informations.
    1. DUAL_X_AXIS 0 right?
    2. M119 returns signal for X2 correctly?
    3. What happens if you try to move? Does the motor turn on so it is blocked or nothing?
    4. What DRIVE_SYSTEM have you set. Each type has parts differently, so different parts to check here.
    5. If ALWAYS_CHECK_EDSTOPS 0 does x2 move?
    For all tests also try with MOVE_X_WHEN_HOMED 0 so it should also move if you did not home before to test that as well.

    Hopefully that will show me the section where the error happens.
  • 1. yes dual_x_axis 0
    2. m119 return the correct status for x and x2
    3. the x motor move the x2 motor not and it's locked so EN is ok, with m84 unlock
    4. drive system 0
    5. already set ALWAYS_CHECK_EDSTOPS 0
    also MOVE_X_WHEN_HOMED 0

    same configuration file with X2 endstop disabled work obviously no multi home
  • edited October 2017
    I guess is something with endstop check...
    with this configuration work X2 motor move togheter with X but X2 endstop is disabled so multihoming is disabled
    same file just enabled X2 endstop the x2 motor doesn't move

    here the configuration with dual motor axis declared as X (not working)
    and the working one with the same physical axis declared as Y
  • forgot to say, with all config m119 work as aspected
  • Ok, I think I have found it. In printer.h for me line 960

    #else // DUAL_X_AXIS


            if(Printer::multiXHomeFlags & 1) {




    above is correct version, the error was that the last line was


    So change that line and it should work as expected. Have to add invert direction config before I can publish the update, which I will do soon. So do not forget to look for the extra options when I did.

  • Now it work perfectly, thanks
  • Can I assume this all works good now? Have the changes been pushed to the master and does all this configuration need to be done manually or will the online configuration work? I have a RADDS board and the MPCNC and have been fighting that stupid Marlin 2.0 trying to get it working (doesn't work with LCD?). I would love to use Repetier instead of Marlin.
  • Yes, should all be in master version 1.0.2 and configurable in config tool.
  • Ok. Thanks, just need to figure out why 0.92 (<1) the RADDS display worked but the newer stuff doesn't work with the RADDS display.
  • Good question. Haven't touched the ui code. 20x4 display on my delta is still working with radds.
Sign In or Register to comment.