Advertisement
yclee126

NoLash gcode backlash compensator (Cura extension)

Feb 27th, 2023
949
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.64 KB | None | 0 0
  1. # NoLash ported from java (https://github.com/Lenbok/NoLash)
  2. # Converted to Cura extension by yclee126
  3.  
  4.  
  5. from ..Script import Script
  6. from UM.Application import Application
  7. from UM.Logger import Logger
  8.  
  9. __version__ = '0.0'
  10.  
  11.  
  12. class NoLashCompensator:
  13.     class Axis:
  14.         def __init__(self, name, lash):
  15.             self.name = name
  16.             self.lash = lash
  17.             self.dir = 1
  18.             self.pos = 0
  19.        
  20.         def reset(self):
  21.             self.dir = 1
  22.             self.pos = 0
  23.    
  24.     def __init__(self, x_lash, y_lash):
  25.         # forward and backward, thus divided by 2
  26.         self.x_axis = NoLashCompensator.Axis('X', x_lash/2)
  27.         self.y_axis = NoLashCompensator.Axis('Y', y_lash/2)
  28.    
  29.     def compensate(self, line):
  30.         self.countermeasure = ''
  31.        
  32.         # get gcode command
  33.         command = line.split(' ', 1)[0]
  34.  
  35.         # update commands if needed
  36.         if command == 'G0' or command == 'G1':
  37.             line = self.repair_command(self.x_axis, self.y_axis, line)
  38.         elif command == 'G28':
  39.             self.x_axis.reset()
  40.             self.y_axis.reset()
  41.  
  42.         # write (modified) gcode
  43.         return line, self.countermeasure
  44.    
  45.     def repair_command(self, x, y, line):
  46.         # recalc each axis
  47.         line = self.repair_axis(x, line)
  48.         line = self.repair_axis(y, line)
  49.        
  50.         return line
  51.    
  52.     def repair_axis(self, axis, line):
  53.         # check if backlash is present
  54.         if axis.lash <= 0:
  55.             return line
  56.        
  57.         # remove comments (possibly containing X or Y characters inside)
  58.         line_comments = ''
  59.         parts = line.split(';', 1)
  60.         if len(parts) > 1:
  61.             line, line_comments = parts
  62.             line_comments = ';' + line_comments
  63.  
  64.         # check if this axis move
  65.         parts = line.split(axis.name, 1)
  66.         if len(parts) == 1:
  67.             return line + line_comments
  68.        
  69.         # parse value
  70.         line_front, axis_value = parts
  71.         parts = axis_value.split(' ', 1)
  72.         line_back = ''
  73.         if len(parts) > 1:
  74.             axis_value, line_back = parts
  75.             line_back = ' ' + line_back
  76.  
  77.         new_pos = float(axis_value)
  78.  
  79.         # compare to curr pos, generate necessary countermeasure
  80.         if not self.is_same_direction(axis, new_pos):
  81.             axis.dir = -axis.dir
  82.             calc = axis.pos + axis.lash * axis.dir # countermeasure pos
  83.            
  84.             # init countermeasure string
  85.             if self.countermeasure == '':
  86.                 self.countermeasure = 'G0'
  87.            
  88.             # add countermeasure
  89.             self.countermeasure += ' ' + axis.name + '%.3f' % (calc)
  90.        
  91.         axis.pos = new_pos
  92.  
  93.         # compensated value
  94.         recalc = axis.pos + axis.lash * axis.dir
  95.  
  96.         # return updated command
  97.         return line_front + axis.name + '%.3f' % (recalc) + line_back
  98.  
  99.     def is_same_direction(self, axis, new_pos):
  100.         new_dir = 0
  101.         if axis.pos < new_pos:
  102.             new_dir = 1
  103.         elif axis.pos > new_pos:
  104.             new_dir = -1
  105.         else: # no changes
  106.             return True
  107.        
  108.         return new_dir == axis.dir
  109.  
  110.  
  111. class NoLash(Script):
  112.     def __init__(self):
  113.         super().__init__()
  114.  
  115.     def getSettingDataString(self):
  116.         return """{
  117.            "name": "Backlash Compensation (NoLash)",
  118.            "key": "NoLash",
  119.            "metadata": {},
  120.            "version": 2,
  121.            "settings":
  122.            {
  123.                "CompensationEnabled":
  124.                {
  125.                    "label": "Compensation Enabled",
  126.                    "description": "",
  127.                    "type": "bool",
  128.                    "default_value": true
  129.                },
  130.                "xLash":
  131.                {
  132.                    "label": "X Backlash",
  133.                    "description": "",
  134.                    "type": "float",
  135.                    "unit": "mm",
  136.                    "default_value": 0.4,
  137.                    "minimum_value": 0,
  138.                    "enabled": "CompensationEnabled"
  139.                },
  140.                "yLash":
  141.                {
  142.                    "label": "Y Backlash",
  143.                    "description": "",
  144.                    "type": "float",
  145.                    "unit": "mm",
  146.                    "default_value": 0.4,
  147.                    "minimum_value": 0,
  148.                    "enabled": "CompensationEnabled"
  149.                }
  150.            }
  151.        }"""
  152.  
  153.     def execute(self, data):
  154.         x_lash = self.getSettingValueByKey("xLash") if self.getSettingValueByKey("CompensationEnabled") else 0
  155.         y_lash = self.getSettingValueByKey("yLash") if self.getSettingValueByKey("CompensationEnabled") else 0
  156.         no_lash = NoLashCompensator(x_lash, y_lash)
  157.        
  158.         # for each layer
  159.         for layer_index in range(len(data)):
  160.             lines = data[layer_index].split("\n")
  161.             line_index = 0
  162.            
  163.             # for each line in a layer
  164.             while line_index < len(lines):
  165.                
  166.                 # skip comments
  167.                 if lines[line_index].startswith(';'):
  168.                     line_index += 1
  169.                     continue
  170.                
  171.                 # compensate
  172.                 lines[line_index], countermeasure = no_lash.compensate(lines[line_index])
  173.                 if countermeasure != '':
  174.                     lines.insert(line_index, countermeasure)
  175.                     line_index += 1
  176.                
  177.                 line_index += 1
  178.            
  179.             result = "\n".join(lines)
  180.             data[layer_index] = result
  181.  
  182.         return data
  183.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement