mirror of
https://git.mirrors.martin98.com/https://github.com/petaflot/pygcode
synced 2025-04-22 05:40:07 +08:00
232 lines
7.8 KiB
Python
232 lines
7.8 KiB
Python
import unittest
|
|
|
|
# Add relative pygcode to path
|
|
from testutils import add_pygcode_to_path, str_lines
|
|
add_pygcode_to_path()
|
|
|
|
# Units under test
|
|
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):
|
|
def test_basics(self):
|
|
p = Position()
|
|
#
|
|
|
|
def test_default_axes(self):
|
|
p = Position() # no instantiation parameters
|
|
# all initialized to zero
|
|
for axis in 'XYZABCUVW':
|
|
self.assertEqual(getattr(p, axis), 0)
|
|
|
|
for axis in 'XYZABCUVW':
|
|
# set to 100
|
|
setattr(p, axis, 100)
|
|
self.assertEqual(getattr(p, axis), 100)
|
|
for inner_axis in set('XYZABCUVW') - {axis}: # no other axis has changed
|
|
self.assertEqual(getattr(p, inner_axis), 0), "axis '%s'" % inner_axis
|
|
# revert back to zero
|
|
setattr(p, axis, 0)
|
|
self.assertEqual(getattr(p, axis), 0)
|
|
|
|
# Equality
|
|
def test_equality(self):
|
|
p1 = Position(axes='XYZ', X=1, Y=2)
|
|
p2 = Position(axes='XYZ', X=1, Y=2, Z=0)
|
|
p3 = Position(axes='XYZ', X=1, Y=2, Z=1000)
|
|
p4 = Position(axes='XYZA', X=1, Y=2, Z=0)
|
|
|
|
# p1 <--> p2
|
|
self.assertTrue(p1 == p2)
|
|
self.assertFalse(p1 != p2) # negative case
|
|
|
|
# p2 <--> p3
|
|
self.assertTrue(p2 != p3)
|
|
self.assertFalse(p2 == p3) # negative case
|
|
|
|
# p2 <--> p4
|
|
self.assertTrue(p2 != p4)
|
|
self.assertFalse(p2 == p4) # negative case
|
|
|
|
# Arithmetic
|
|
def test_arithmetic_add(self):
|
|
p1 = Position(axes='XYZ', X=1, Y=2)
|
|
p2 = Position(axes='XYZ', Y=10, Z=-20)
|
|
self.assertEqual(p1 + p2, Position(axes='XYZ', X=1, Y=12, Z=-20))
|
|
|
|
p3 = Position(axes='XYZA')
|
|
with self.assertRaises(MachineInvalidAxis):
|
|
p1 + p3 # mismatched axes
|
|
with self.assertRaises(MachineInvalidAxis):
|
|
p3 + p1 # mismatched axes
|
|
|
|
def test_arithmetic_sub(self):
|
|
p1 = Position(axes='XYZ', X=1, Y=2)
|
|
p2 = Position(axes='XYZ', Y=10, Z=-20)
|
|
self.assertEqual(p1 - p2, Position(axes='XYZ', X=1, Y=-8, Z=20))
|
|
|
|
p3 = Position(axes='XYZA')
|
|
p3 - p1 # fine
|
|
with self.assertRaises(MachineInvalidAxis):
|
|
p1 - p3 # mismatched axes
|
|
|
|
def test_arithmetic_multiply(self):
|
|
p = Position(axes='XYZ', X=2, Y=10)
|
|
self.assertEqual(p * 2, Position(axes='XYZ', X=4, Y=20))
|
|
|
|
def test_arithmetic_divide(self):
|
|
p = Position(axes='XYZ', X=2, Y=10)
|
|
self.assertEqual(p / 2, Position(axes='XYZ', X=1, Y=5))
|
|
|
|
|
|
class MachineGCodeProcessingTests(unittest.TestCase):
|
|
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:
|
|
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)
|
|
|
|
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)
|