SURFACE Mapping – using MARLIN – try it out

New Home Forum Mostly Printed CNC – MPCNC Troubleshooting – MPCNC SURFACE Mapping – using MARLIN – try it out

This topic contains 11 replies, has 5 voices, and was last updated by  Jeffeb3 1 week, 4 days ago.

Viewing 12 posts - 1 through 12 (of 12 total)
  • Author
  • #49154


    I modified Marlin so it can use the built-in Auto Bed Leveling feature for use with my MPCNC.   I have posted my modified Configuration.h and Marlin_main.cpp files,   so you can try it out…   CAUTION:  Personally i have only dry run tested this myself, but, it seems to work fine (dry run, meaning i create the map  with a board that was on a tilt,  and after mapping it, i can move  the spindle all around the work surface and it automatically keeps the Z to just touching the surface.)

    Mapping the work surface is needed for several uses-    1) is PCB etching (carving)   2) V-Carving not so flat boards, especially v-carving smaller text,    3) etching (carving) onto acrylic, or glass.   There may be other times it’s needed also, so, if you need it, this should work.

    BUT, you would need to have your machine set up for it.  I use Z-Max for homing my spindle up     when issuing a Home command,   and use Z-Min for the Touch Probe / Mapping Probe.

    For mapping,  I have a Vacuum shoe sweep that I attach with magnets to my spindle, so I printed a bracket to hold a micro sw   and i take off the Vacuum shoe sweep and attach my Mapping Probe using those same magnet points.  My sw sits right at or below (X Y aligned) the bit –     so i don’t need an X or Y offset,   but, if your probe sits off to a side, in the configuration.h you can set a Probe X or Y offset.  You can also specify a Probe Z offset, but  I programmed this so that the Z offset will be calculated Automatically when i do a G30 command to get the top of the surface work piece.

    My GCODE Header work flow is as follows – in Gcode — without leveling:
    ; Beginning of Header
    M80; Turn On Power Supply (PC ATX PS = Power for Steppers)

    G28 Z0 ; home to limit sw
    G28 Y0 ; home to limit sw
    G28 X0 ; home to limit sw

    M3 S8500; turn Spindle On to Snnn RPM

    ; Move spindle to desired Start Pos – XY corner of the Work piece
    G0 X20 Y40 F12000 ; xy corner of material
    G0 Z132 F1200 ; top of material NOTE: in my set up, ZMAX == 210, so I am moving it down from 210 to 132 (This Value is obtained by running a G30 command and is different with each bit change and material height )

    G92 X0 Y0 Z0 ; set current LOGICAL location to 0,0,0

    G0 Z5.080 F1200; Spindle is now 5mm above the XY starting corner of the material.
    ;—– End Of Header
    ; — run the actual Gcode for Cutting —-

    So, to use the Surface mapping, here is my new work flow, before I run the above GCode header and cutting file

    G28; Home
    G0 Xnn Ynn Fnn; send the spindle to the XY corner of the work material, such as X20 Y40
    G92 X0 Y0;  set logic Zero/       this is same as i do in my normal header

    ; Issue the Surface Map command and create a map of the work piece surface

    G29 L0 F0 Rrr Bbb Xxx Yyy T; Where   L and F set the starting corner of the work piece,   I am using 0,0 for the start because i moved my spindle to that location and issued a G92 command to set that location as 0,0,0   for the cutting file.   Rrr = Right (X) size of work area to map, Bbb= back or Y size of material to map, such as R200 B300 for a work material that is 200mm in the X direction by 300mm in the Y direction.    And, i supply X and Y  – which in the G29 command sets how many grid points our map will have.  X4 Y5 will set a map with 4 points in the X direction and 5 in the Y,  20 points total.  If T is given it will print the results out to the serial port so the host software will display the Map data once it is created.  (I am currently using Repetier Host for sending the GCode files)

    ; I put in code so that this data,   the LFRB and XY data, MUST be sent with the G29 command, or it will give an error and not create the map.   I’ve included a CNC_LEVELING_VALUES define in the configuration.h file, you can comment that out if you don’t want that feature.        The only exception is you can issue a “G29 T” and it will not do a map, but, will print out the current map to the serial port

    ; The G29 command will create the MAP –     but, uses the Z Height at whatever Height the Probe is– which will NOT be the same as the cutting Bit…
    ; so, after running G29 i move the spindle back to the material XY starting corner, which will be 0, 0  (since I used the G92 command to set 0,0 to the work piece corner)
    G0 X0 Y0 F12000

    ; remove the Probe and if not already installed, install the router bit,

    ; then place the metal touch-plate at that location and attach the wire to the bit ,   and issue the G30 command.

    This will do a single probe at the starting corner of the work piece.

    I Modified the G30.   As long as CNC_LEVELING is defined in the configuration.h file,   the G30 command will get the height of the work surface, for the bit that is installed.  In the Configuration.h file I have also added a define called  ZERO_PLATE_THICKNESS     which you set to the thickness of the metal touch plate that you are using.

    ; this way when we do a G30 cmnd    it will calculate the Z height (-) (minus) the thickenss of the touchplate, so it will get the exact Z height of the work stock at the starting corner.
    ; the other I have the G30 command do, is it will calculate the difference between the Bit Z height and the Probed Z height, meaning it will automatically calculate the Probe Z offset value.   And, it then goes through the Map data and applys that offset to the remaining Map data points.    So, the map get re-aligned to the bit height    all just by issuing the G30 command.

    ; after issuing this G30 we can then go ahead and run the Gcode script to cut the work piece,
    ; the Gcode can re-Home the spindle, etc, and run as normal,    and the mapping data will still be there and mapping will still be enabled  (as long as the CNC_LEVELING flag is defined in the configuration.h file).

    ; After the first bit is done cutting, if another bit is needed, like a rough cut, then final cut or additional cuts,
    ; go ahead and change the bit and move spindle to Starting corner of work piece (Logical 0,0) and issue another G30 with the touch plate in place and it will get the Z height with the new bit – (minus) the thickness of the touch plate, get the difference in height and apply that new  difference to the map – again, and it is ready to cut with the second bit,. Again you can Home, etc, and cut away. An d, you can do this as many times as you need, the map data will not be disabled.

    you can issue a G29 T to view the existing map data.

    So far i have only DRY run it, i haven’t had time to put on a piece of wood and cut it, but, after mapping, I issue HOME and G30, i can use G0, G1 and move the spindle around (I had purposefully put a board on the work area on a tilt) and as you move around the spindle in the X Y directions, the Z tracks up and down as needed to keep the spindle level to the tilted surface.

    I am uploading the Configuration.h and Marlin_main.cpp     These are the files from the DualDual_1_1_5  iteration of marlin,  that was made for the separate control of the X and Y stepper pairs.

    I have noted where i did the changes for the CNC Leveling, so if you want to apply this to another version of Marlin, search for “CNC_Added” and copy the code in those areas to the .cpp file that you use. Same with the Configuration.h file. Let me know if this works for you.




    3 users thanked author for this post.


    Awesome! This is great and well thought out. I am not at my computer but I will look at this and get it on a branch in Ryan’s GitHub. I really want to try this myself on my low rider.



    I just realized  –   when i run the G30 command, after getting the bit to surface height,  i then read out the first Map data,  z_values[0][0]  and subtract our bit Z height to get the difference.  What I have the code do next is take the difference value and run through the map data (z_values) and apply the difference to all the map points.   Although this works, it may not be the right or best way to do it.   There is a Z Probe Offset variable,  so, really I think all that would be needed is to set the Z Probe Offset with the difference value,   rather then changing all the data points in the map.  Either way should work, but, it will probably be cleaner to use the Z Probe Offset variable, and let Marlin’s planner do it’s thing.

    Another thing, if the code is going to be submitted to github,   a more clean configuration.h file should be used,  as i made a few value changes specific to my machine in the Config i attached.   Be better to use a clean config file and just add the <CNC_Added> defines to it.   Such as the CNC_LEVLEING,  CNC_LEVELING_VALUES and ZERO_PLATE_THICKNESS – i think are the only changes,  other than enabling Bilinear Bed Leveling



    Holy cow. I read that, first email of the day, coffee in hand, 15 minutes after waking up.  I have to read that in a bit again, some of that went over my head. I am sure a bunch of people will want to try that.

    I like the header idea, just change your piecework values and that modifies the probing and includes work offsets. That has been a major issue as Marlin expects a never changing “bed” size. Nice idea, I appreciate all the work that must to have gone into this already!



    In my personal workflow, I would probably want to move the head manually (or with a jog commands) to the lower left corner, and then start the gcode. I would try it with a separate gcode script first, probably.

    But at some point, I would probably add some kind of script to my workflow, so that out of EstlCAM or whatever I’m using to do the CAM (might be something else for PCB ((on a Low Rider!?))). Anyway, after tha CAM, I would run it through a script that would calculate the mesh parameters and put them in the top of the gcode. I never have ran the same gcode twice, because everything I do is a one off piece, so I would rather have the location, width, height, etc. determined for me, instead of fiddling with the text editor. The script would just read the gcode, and come up with the parameters for the G29 command.



    Been working on this for the last couple of days – My programming ability is really letting me down.

    I’ve had a couple of thoughts on it though and what I am currently working on this this;


    I’ve got a microswitch on the bottom of a burnt out router bit, means I don’t need an offset, that plugs into the lowrider and can be swapped for a touchplate for setting the offset.

    I don’t really want to have end stops, but from what I can see it is a must. My cheap and dirty solution is to have a switch that I can turn on while homing, keeping the X and Y axis where I’ve set them, and convincing Marlin that I’ve installed end stops.

    That seems to work okay for the moment.

    However the probe when it homes, only seems to want to home on the Z Max pin, not the Z Min. Again, workable. But less than ideal.

    The big problem I’m facing is that it seems once the Z Axis homes, the steppers disengage and the Z axis comes tumbling down.

    Anyways, I hope to come up with something fruitful by the end of the weekend. I’d like to hide all the Gcode settings in the LCD Menu as I don’t like having a PC attached to the Lowrider.


    I don’t really want to have end stops, but from what I can see it is a must.

    There is a “safe homing z” setting which might be what you need to turn off. Otherwise, disabling the endstops in firmware would be good.

    only seems to want to home on the Z Max pin, not the Z Min.

    That’s a setting in the configuration. Something like, “z probe uses z min”

    The big problem I’m facing is that it seems once the Z Axis homes, the steppers disengage and the Z axis comes tumbling down.

    What? Homes or probes? Which gcode are you using? It should definitely not be doing that.

    I’d like to hide all the Gcode settings in the LCD Menu as I don’t like having a PC attached to the Lowrider.

    The easy way too do that is to put them on files in the SD card, but that sometimes gets treated a little differently. Alternatively, there was a thread here where someone edited the lcd menus.



    I’ve put the setup codes UnLtdSoul provided in the menu along with a return to home – It all seems to be working.

    I’ve noticed I’ve been homing from my Max X point and Min Y, I’ve had to change this to have the machine auto home correctly.

    So I can map the surface, and all goes well, however when I try to create a CAM file in fusion, I can invert the X axis, to match up to my table, but then it inverts the Z axis, when I invert the Z axis in fusion it then inverts the Y axis, which doesn’t have an option to flip it.

    Once I’ve got this sorted I’ll upload the firmware file I have.

    I’ve put a switch in for the endstops, basically you turn the switch on, autohome, then turn the switch off, line up the router to the workpiece, then set that as the home position through the option I added in the menu. From there you can map the worksurface (my programming ability is not very good, so I just have a map half size (1200×1200) or full size sheet (1200×2400), Ideally I would like to have a menu option to set the workpiece size and the number of mapping points. I’ve noticed if you leave the endstops engaged, once it maps the first 3 lines, it assumes the router bit is at 0,0 so tried to run it out of the X Axis.


    EDIT: Sorry I should mention, I kind of have to home to the bottom right hand corner of the table as firstly, thats where the LCD is, and secondly, the workspace it is in leaves me space on the bottom of the table and the right hand side – the top and left hand side is more or less inaccessible.


    EDIT2: Flipped the Y stepper connector and it’s working as I want it to. Keep running into probing failure at the moment, I’m wondering if it’s because the difference in height of the workpiece is too severe


    EDIT3: Nope. That still doesn’t solve the problem in Fusion 360. It’s probing after I increased the max bed size.



    I’ve got it working now – didn’t manage to cut much, cause I broke a bit. But it is cutting much easier, only mapping a 3×3 grid across 1200×1200

    I’ve attached the firmware file if anyone wants to give it a go. It’s running off the DualDual1.15 version of Marlin – It seems they got rid of ‘parsing’ somewhere along the line.


    As a heads up, this isn’t anywhere near finished or complete, but it does work.


    Thanks a lot for this very clear tuto and for the files!

    I’ll give it a try soon on my machine, it’s been a while since I didn’t use the autoleveling function and I haven’t been super motivated to actually go through the process of editing Marlin again. This will come in handy 🙂




    I’ve got the file, it’s not uploading though!



    You can upload zip files.

Viewing 12 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic.