mirror of
https://git.mirrors.martin98.com/https://github.com/petaflot/pygcode
synced 2025-07-28 05:41:57 +08:00
updated readme
fixed canned drilling cycle machine processing bugs improved tests for linear movement
This commit is contained in:
parent
b4b71daae8
commit
aef2728b0d
10
README.rst
10
README.rst
@ -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')
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user