updated readme

fixed canned drilling cycle machine processing bugs
improved tests for linear movement
This commit is contained in:
Peter Boin 2017-07-25 01:52:55 +10:00
parent b4b71daae8
commit aef2728b0d
3 changed files with 176 additions and 48 deletions

View File

@ -111,15 +111,13 @@ To elaborate, here are some line examples
G01 X1 Y2 F100 S1000 ; blah
>>> print(line.block)
G01 X1 Y2 F100 S1000
>>> sorted(line.block.gcodes)
[<GCodeFeedRate: F100>,
<GCodeSpindleSpeed: S1000>,
<GCodeLinearMove: G01{X1, Y2}>]
>>> print(line.comment)
; blah
>>> line = Line('G0 x1 y2 (foo) f100 (bar) s1000')
>>> print(line)
G00 X1 Y2 F100 S1000 (foo. bar)
>>> print(line.comment)
(foo. bar)
Interpreting what a line of gcode does depends on the machine it's running on,
and also that machine's state (or 'mode')

View File

@ -218,15 +218,29 @@ class GCode(object):
return copy(self.word_key)
raise AssertionError("class %r has no default word" % self.__class__)
# Comparisons
# Equality
def __eq__(self, other):
return (
(self.word == other.word) and
(self.params == other.params)
)
def __ne__(self, other):
return not self.__eq__(other)
# Sort by execution order
def __lt__(self, other):
"""Sort by execution order"""
return self.exec_order < other.exec_order
def __le__(self, other):
return self.exec_order <= other.exec_order
def __gt__(self, other):
"""Sort by execution order"""
return self.exec_order > other.exec_order
def __ge__(self, other):
return self.exec_order >= other.exec_order
# Parameters
def add_parameter(self, word):
"""
@ -483,10 +497,18 @@ class GCodeCannedCycle(GCode):
if isinstance(machine.mode.canned_cycles_return, GCodeCannedCycleReturnToR):
# canned return is to this.R, not this.Z (plane dependent)
moveto_coords.update({
machine.mode.plane_selection.normal_axis: this.R,
machine.mode.plane_selection.normal_axis: self.R,
})
else: # default: GCodeCannedCycleReturnPrevLevel
# Remove this.Z (plane dependent) value (ie: no machine movement on this axis)
moveto_coords.pop(machine.mode.plane_selection.normal_axis, None)
machine.move_to(**moveto_coords)
# Process action 'L' times
loop_count = self.L
if (loop_count is None) or (loop_count <= 0):
loop_count = 1
for i in range(loop_count):
machine.move_to(**moveto_coords)
class GCodeDrillingCycle(GCodeCannedCycle):
@ -929,7 +951,7 @@ class GCodeCannedReturnMode(GCode):
exec_order = 220
class GCodeCannedCycleReturnLevel(GCodeCannedReturnMode):
class GCodeCannedCycleReturnPrevLevel(GCodeCannedReturnMode):
"""G98: Canned Cycle Return to the level set prior to cycle start"""
# "retract to the position that axis was in just before this series of one or more contiguous canned cycles was started"
word_key = Word('G', 98)

View File

@ -8,6 +8,11 @@ add_pygcode_to_path()
from pygcode.machine import Position, Machine
from pygcode.line import Line
from pygcode.exceptions import MachineInvalidAxis
from pygcode.gcodes import (
GCodeAbsoluteDistanceMode, GCodeIncrementalDistanceMode,
GCodeAbsoluteArcDistanceMode, GCodeIncrementalArcDistanceMode,
GCodeCannedCycleReturnPrevLevel, GCodeCannedCycleReturnToR,
)
class PositionTests(unittest.TestCase):
@ -81,43 +86,146 @@ class PositionTests(unittest.TestCase):
self.assertEqual(p / 2, Position(axes='XYZ', X=1, Y=5))
class MachineGCodeProcessingTests(unittest.TestCase):
def test_linear_movement(self):
m = Machine()
test_str = '''; move in a 10mm square
F100 M3 S1000 ; 0
g1 x0 y10 ; 1
g1 x10 y10 ; 2
g1 x10 y0 ; 3
g1 x0 y0 ; 4
'''
expected_pos = {
'0': m.Position(),
'1': m.Position(X=0, Y=10),
'2': m.Position(X=10, Y=10),
'3': m.Position(X=10, Y=0),
'4': m.Position(X=0, Y=0),
}
#print("\n%r\n%r" % (m.mode, m.state))
for line_text in str_lines(test_str):
line = Line(line_text)
def assert_processed_lines(self, line_data, machine):
"""
Process lines & assert machine's position
:param line_data: list of tuples [('g1 x2', {'X':2}), ... ]
"""
for (i, (line_str, expected_pos)) in enumerate(line_data):
line = Line(line_str)
if line.block:
#print("\n%s" % line.block)
m.process_block(line.block)
# Assert possition change correct
comment = line.comment.text
if comment in expected_pos:
self.assertEqual(m.pos, expected_pos[comment])
#print("%r\n%r\npos=%r" % (m.mode, m.state, m.pos))
machine.process_block(line.block)
# Assert possition change correct
if expected_pos is not None:
p1 = machine.pos
p2 = machine.Position(**expected_pos)
self.assertEqual(p1, p2, "index:%i '%s': %r != %r" % (i, line_str, p1, p2))
# Rapid Movement
def test_rapid_abs(self):
m = Machine()
m.process_gcodes(GCodeAbsoluteDistanceMode())
line_data = [
('', {}), # start @ 0,0,0
('g0 x0 y10', {'X':0, 'Y':10}),
(' x10 y10', {'X':10, 'Y':10}),
(' x10 y0', {'X':10, 'Y':0}),
(' x0 y0', {'X':0, 'Y':0}),
]
self.assert_processed_lines(line_data, m)
#m = Machine()
#
#file = GCodeParser('part1.gcode')
#for line in file.iterlines():
# for (i, gcode) in enumerate(line.block.gcode):
# if isinstance(gcode, GCodeArcMove):
# arc = gcode
# line_params = arc.line_segments(precision=0.0005)
# for
def test_rapid_inc(self):
m = Machine()
m.process_gcodes(GCodeIncrementalDistanceMode())
line_data = [
('', {}), # start @ 0,0,0
('g0 y10', {'X':0, 'Y':10}),
(' x10', {'X':10, 'Y':10}),
(' y-10', {'X':10, 'Y':0}),
(' x-10', {'X':0, 'Y':0}),
]
self.assert_processed_lines(line_data, m)
# Linearly Interpolated Movement
def test_linear_abs(self):
m = Machine()
m.process_gcodes(GCodeAbsoluteDistanceMode())
line_data = [
('g1 x0 y10', {'X':0, 'Y':10}),
(' x10 y10', {'X':10, 'Y':10}),
(' x10 y0', {'X':10, 'Y':0}),
(' x0 y0', {'X':0, 'Y':0}),
]
self.assert_processed_lines(line_data, m)
def test_linear_inc(self):
m = Machine()
m.process_gcodes(GCodeIncrementalDistanceMode())
line_data = [
('g1 y10', {'X':0, 'Y':10}),
(' x10', {'X':10, 'Y':10}),
(' y-10', {'X':10, 'Y':0}),
(' x-10', {'X':0, 'Y':0}),
]
self.assert_processed_lines(line_data, m)
# Arc Movement
def test_arc_abs(self):
m = Machine()
m.process_gcodes(
GCodeAbsoluteDistanceMode(),
GCodeIncrementalArcDistanceMode(),
)
line_data = [
# Clockwise circle in 4 segments
('g2 x0 y10 i5 j5', {'X':0, 'Y':10}),
(' x10 y10 i5 j-5', {'X':10, 'Y':10}),
(' x10 y0 i-5 j-5', {'X':10, 'Y':0}),
(' x0 y0 i-5 j5', {'X':0, 'Y':0}),
# Counter-clockwise circle in 4 segments
('g3 x10 y0 i5 j5', {'X':10, 'Y':0}),
(' x10 y10 i-5 j5', {'X':10, 'Y':10}),
(' x0 y10 i-5 j-5', {'X':0, 'Y':10}),
(' x0 y0 i5 j-5', {'X':0, 'Y':0}),
]
self.assert_processed_lines(line_data, m)
def test_arc_inc(self):
m = Machine()
m.process_gcodes(
GCodeIncrementalDistanceMode(),
GCodeIncrementalArcDistanceMode(),
)
line_data = [
# Clockwise circle in 4 segments
('g2 y10 i5 j5', {'X':0, 'Y':10}),
(' x10 i5 j-5', {'X':10, 'Y':10}),
(' y-10 i-5 j-5', {'X':10, 'Y':0}),
(' x-10 i-5 j5', {'X':0, 'Y':0}),
# Counter-clockwise circle in 4 segments
('g3 x10 i5 j5', {'X':10, 'Y':0}),
(' y10 i-5 j5', {'X':10, 'Y':10}),
(' x-10 i-5 j-5', {'X':0, 'Y':10}),
(' y-10 i5 j-5', {'X':0, 'Y':0}),
]
self.assert_processed_lines(line_data, m)
# Canned Drilling Cycles
def test_canned_return2oldz(self):
m = Machine()
m.process_gcodes(
GCodeAbsoluteDistanceMode(),
GCodeCannedCycleReturnPrevLevel(),
)
line_data = [
('g0 z5', {'Z':5}),
('g81 x10 y20 z-2 r1', {'X':10, 'Y':20, 'Z':5}),
]
self.assert_processed_lines(line_data, m)
def test_canned_return2r(self):
m = Machine()
m.process_gcodes(
GCodeAbsoluteDistanceMode(),
GCodeCannedCycleReturnToR(),
)
line_data = [
('g0 z5', {'Z':5}),
('g81 x10 y20 z-2 r1', {'X':10, 'Y':20, 'Z':1}),
]
self.assert_processed_lines(line_data, m)
def test_canned_loops(self):
m = Machine()
m.process_gcodes(
GCodeAbsoluteDistanceMode(),
GCodeCannedCycleReturnPrevLevel(),
)
line_data = [
('g0 z5', None),
('g81 x10 y20 z-2 r1 l2', {'X':10, 'Y':20, 'Z':5}),
('g91', None), # switch to incremental mode
('g81 x10 y20 z-2 r1 l2', {'X':30, 'Y':60, 'Z':5}),
]
self.assert_processed_lines(line_data, m)