Advertisement
yclee126

NoLash gcode backlash compensator (standalone version)

Feb 27th, 2023
703
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 3.81 KB | None | 0 0
  1. # NoLash ported from java (https://github.com/Lenbok/NoLash) by yclee126
  2. # Standalone version
  3.  
  4.  
  5. class NoLash:
  6.     class Axis:
  7.         def __init__(self, name, lash):
  8.             self.name = name
  9.             self.lash = lash
  10.             self.dir = 1
  11.             self.pos = 0
  12.        
  13.         def reset(self):
  14.             self.dir = 1
  15.             self.pos = 0
  16.    
  17.     def __init__(self, x, y):
  18.         # forward and backward, thus divided by 2
  19.         self.x_lash = x/2
  20.         self.y_lash = y/2
  21.    
  22.     def compensate(self, in_file, out_file):
  23.         x = NoLash.Axis('X', self.x_lash)
  24.         y = NoLash.Axis('Y', self.y_lash)
  25.  
  26.         for line in in_file:
  27.             line = line.strip()
  28.  
  29.             # get gcode command
  30.             command = line.split(' ', 1)[0]
  31.  
  32.             # update commands if needed
  33.             if command == 'G0' or command == 'G1':
  34.                 line = self.repair_command(x, y, line, out_file)
  35.             elif command == 'G28':
  36.                 x.reset()
  37.                 y.reset()
  38.  
  39.             # write (modified) gcode
  40.             out_file.write(line + '\n')
  41.    
  42.     def repair_command(self, x, y, line, out_file):
  43.         self.countermeasure = ''
  44.  
  45.         # recalc each axis
  46.         line = self.repair_axis(x, line)
  47.         line = self.repair_axis(y, line)
  48.  
  49.         # write counterpeasure to file before writing modded line
  50.         if self.countermeasure != '':
  51.             out_file.write(self.countermeasure + '\n')
  52.        
  53.         return line
  54.    
  55.     def repair_axis(self, axis, line):
  56.         # check if backlash is present
  57.         if axis.lash <= 0:
  58.             return line
  59.        
  60.         # remove comments (possibly containing X or Y characters inside)
  61.         line_comments = ''
  62.         parts = line.split(';', 1)
  63.         if len(parts) > 1:
  64.             line, line_comments = parts
  65.             line_comments = ';' + line_comments
  66.  
  67.         # check if this axis move
  68.         parts = line.split(axis.name, 1)
  69.         if len(parts) == 1:
  70.             return line + line_comments
  71.        
  72.         # parse value
  73.         line_front, axis_value = parts
  74.         parts = axis_value.split(' ', 1)
  75.         line_back = ''
  76.         if len(parts) > 1:
  77.             axis_value, line_back = parts
  78.             line_back = ' ' + line_back
  79.  
  80.         new_pos = float(axis_value)
  81.  
  82.         # compare to curr pos, generate necessary countermeasure
  83.         if not self.is_same_direction(axis, new_pos):
  84.             axis.dir = -axis.dir
  85.             calc = axis.pos + axis.lash * axis.dir # countermeasure pos
  86.            
  87.             # init countermeasure string
  88.             if self.countermeasure == '':
  89.                 self.countermeasure = 'G0'
  90.             self.countermeasure += ' ' + axis.name + str(calc)
  91.         axis.pos = new_pos
  92.  
  93.         # compensated value
  94.         recalc = new_pos + axis.lash * axis.dir
  95.  
  96.         # return updated command
  97.         return line_front + axis.name + str(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:
  106.             return True
  107.         return new_dir == axis.dir
  108.  
  109.  
  110. if __name__ == '__main__':
  111.     # basic CUI interface
  112.     import sys
  113.  
  114.     # check arg count
  115.     if len(sys.argv) != 5:
  116.         print('Usage: NoLash.py X_LASH Y_LASH IN_FILE.gcode OUT_FILE.gcode')
  117.         exit()
  118.    
  119.     # parse args
  120.     __name = sys.argv[0]
  121.     x_lash = float(sys.argv[1])
  122.     y_lash = float(sys.argv[2])
  123.     in_file = open(sys.argv[3], 'r', encoding='utf-8')
  124.     out_file = open(sys.argv[4], 'w', encoding='utf-8')
  125.  
  126.     # process gcode
  127.     no_lash = NoLash(x_lash, y_lash)
  128.     no_lash.compensate(in_file, out_file)
  129.  
  130.     # close files
  131.     in_file.close()
  132.     out_file.close()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement