mirror of
https://github.com/sinseman44/PyCNC.git
synced 2026-01-11 02:30:05 +00:00
281 lines
12 KiB
Python
281 lines
12 KiB
Python
import unittest
|
|
|
|
from cnc.pulses import *
|
|
from cnc.config import *
|
|
from cnc.coordinates import *
|
|
from cnc import hal_virtual
|
|
|
|
|
|
class TestPulses(unittest.TestCase):
|
|
def setUp(self):
|
|
self.v = STEPPER_MAX_VELOCITY_MM_PER_MIN
|
|
|
|
def tearDown(self):
|
|
pass
|
|
|
|
def test_zero(self):
|
|
# PulseGenerator should never receive empty movement.
|
|
self.assertRaises(ZeroDivisionError,
|
|
PulseGeneratorLinear,
|
|
Coordinates(0, 0, 0, 0), self.v)
|
|
self.assertRaises(ZeroDivisionError, PulseGeneratorCircular,
|
|
Coordinates(0, 0, 0, 0), Coordinates(0, 0, 9, 9),
|
|
PLANE_XY, CW, self.v)
|
|
self.assertRaises(ZeroDivisionError, PulseGeneratorCircular,
|
|
Coordinates(0, 0, 0, 0), Coordinates(9, 0, 0, 9),
|
|
PLANE_YZ, CW, self.v)
|
|
self.assertRaises(ZeroDivisionError, PulseGeneratorCircular,
|
|
Coordinates(0, 0, 0, 0), Coordinates(0, 9, 0, 9),
|
|
PLANE_ZX, CW, self.v)
|
|
|
|
def test_step_linear(self):
|
|
# Check if PulseGenerator returns correctly single step movement.
|
|
g = PulseGeneratorLinear(Coordinates(1.0 / STEPPER_PULSES_PER_MM_X,
|
|
0, 0, 0),
|
|
self.v)
|
|
i = 0
|
|
for direction, px, py, pz, pe in g:
|
|
if direction:
|
|
continue
|
|
i += 1
|
|
self.assertEqual(px, 0)
|
|
self.assertEqual(py, None)
|
|
self.assertEqual(pz, None)
|
|
self.assertEqual(pe, None)
|
|
self.assertEqual(i, 1)
|
|
g = PulseGeneratorLinear(Coordinates(
|
|
1.0 / STEPPER_PULSES_PER_MM_X,
|
|
1.0 / STEPPER_PULSES_PER_MM_Y,
|
|
1.0 / STEPPER_PULSES_PER_MM_Z,
|
|
1.0 / STEPPER_PULSES_PER_MM_E),
|
|
self.v)
|
|
i = 0
|
|
for direction, px, py, pz, pe in g:
|
|
if direction:
|
|
continue
|
|
i += 1
|
|
self.assertEqual(px, 0)
|
|
self.assertEqual(py, 0)
|
|
self.assertEqual(pz, 0)
|
|
self.assertEqual(pe, 0)
|
|
self.assertEqual(i, 1)
|
|
|
|
def __check_circular(self, delta, radius, plane, direction=CW):
|
|
g = PulseGeneratorCircular(delta, radius, plane, direction, self.v)
|
|
x, y, z, e = 0, 0, 0, 0
|
|
dx, dy, dz, de = None, None, None, None
|
|
dir_changed = 0
|
|
dir_requested = False
|
|
t = -1
|
|
for direction_i, px, py, pz, pe in g:
|
|
if direction_i:
|
|
dx, dy, dz, de = px, py, pz, pe
|
|
dir_requested = True
|
|
continue
|
|
if dir_requested: # ignore last change
|
|
dir_requested = False
|
|
dir_changed += 1
|
|
if px is not None:
|
|
x += dx
|
|
if py is not None:
|
|
y += dy
|
|
if pz is not None:
|
|
z += dz
|
|
if pe is not None:
|
|
e += de
|
|
v = list(i for i in (px, py, pz, pe) if i is not None)
|
|
self.assertEqual(min(v), max(v))
|
|
self.assertLessEqual(t, min(v))
|
|
t = max(v)
|
|
return dir_changed, Coordinates(x / STEPPER_PULSES_PER_MM_X,
|
|
y / STEPPER_PULSES_PER_MM_Y,
|
|
z / STEPPER_PULSES_PER_MM_Z,
|
|
e / STEPPER_PULSES_PER_MM_E)
|
|
|
|
def test_single_radius_circles(self):
|
|
# Check if PulseGenerator returns correctly single radius movement in
|
|
# both direction.
|
|
zero_delta = Coordinates(0, 0, 0, 0)
|
|
radius = Coordinates(1.0 / STEPPER_PULSES_PER_MM_X, 0, 0, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_XY, CW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(-1.0 / STEPPER_PULSES_PER_MM_X, 0, 0, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius,
|
|
PLANE_XY, CW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(0, 1.0 / STEPPER_PULSES_PER_MM_Y, 0, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_YZ, CW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(0, -1.0 / STEPPER_PULSES_PER_MM_Y, 0, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_YZ, CW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(0, 0, 1.0 / STEPPER_PULSES_PER_MM_Z, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_ZX, CW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(0, 0, -1.0 / STEPPER_PULSES_PER_MM_Z, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_ZX, CW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(1.0 / STEPPER_PULSES_PER_MM_X, 0, 0, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_XY, CCW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(-1.0 / STEPPER_PULSES_PER_MM_X, 0, 0, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_XY, CCW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(0, 1.0 / STEPPER_PULSES_PER_MM_Y, 0, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_YZ, CCW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(0, -1.0 / STEPPER_PULSES_PER_MM_Y, 0, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_YZ, CCW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(0, 0, 1.0 / STEPPER_PULSES_PER_MM_Z, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_ZX, CCW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
radius = Coordinates(0, 0, -1.0 / STEPPER_PULSES_PER_MM_Z, 0)
|
|
_, pos = self.__check_circular(zero_delta, radius, PLANE_ZX, CCW)
|
|
self.assertEqual(pos, Coordinates(0, 0, 0, 0))
|
|
|
|
def test_with_hal_virtual(self):
|
|
# Using hal_virtual module for this test, it already contains plenty
|
|
# of asserts for wrong number of pulses, pulse timing issues etc
|
|
hal_virtual.move(PulseGeneratorLinear(Coordinates(1, 0, 0, 0),
|
|
self.v))
|
|
hal_virtual.move(PulseGeneratorLinear(Coordinates(25.4, 0, 0, 0),
|
|
self.v))
|
|
hal_virtual.move(PulseGeneratorLinear(Coordinates(25.4, 0, 0, 0),
|
|
self.v))
|
|
hal_virtual.move(PulseGeneratorLinear(Coordinates(25.4, 0, 0, 0),
|
|
self.v))
|
|
hal_virtual.move(PulseGeneratorLinear(Coordinates(TABLE_SIZE_X_MM,
|
|
TABLE_SIZE_Y_MM,
|
|
TABLE_SIZE_Z_MM,
|
|
100.0), self.v))
|
|
hal_virtual.move(PulseGeneratorCircular(Coordinates(0, 20, 0, 0),
|
|
Coordinates(-10, 10, 0, 0),
|
|
PLANE_XY, CW, self.v))
|
|
hal_virtual.move(PulseGeneratorCircular(Coordinates(-4, -4, 0, 0),
|
|
Coordinates(-2, -2, 0, 0),
|
|
PLANE_XY, CW, self.v))
|
|
delta = Coordinates(- 2.0 / STEPPER_PULSES_PER_MM_X,
|
|
- 2.0 / STEPPER_PULSES_PER_MM_Y, 0, 0)
|
|
radius = Coordinates(- 1.0 / STEPPER_PULSES_PER_MM_X,
|
|
- 1.0 / STEPPER_PULSES_PER_MM_Y, 0, 0)
|
|
hal_virtual.move(PulseGeneratorCircular(delta, radius, PLANE_XY, CW,
|
|
self.v))
|
|
|
|
def test_twice_faster_linear(self):
|
|
# Checks if one axis moves exactly twice faster, pulses are correct.
|
|
m = Coordinates(2, 4, 0, 0)
|
|
g = PulseGeneratorLinear(m, self.v)
|
|
i = 0
|
|
for direction, px, py, pz, pe in g:
|
|
if direction:
|
|
continue
|
|
if i % 2 == 0:
|
|
self.assertNotEqual(px, None)
|
|
else:
|
|
self.assertEqual(px, None)
|
|
self.assertNotEqual(py, None)
|
|
self.assertEqual(pz, None)
|
|
self.assertEqual(pe, None)
|
|
i += 1
|
|
self.assertEqual(m.find_max() * STEPPER_PULSES_PER_MM_Y, i)
|
|
|
|
def test_pulses_count_and_timings(self):
|
|
# Check if number of pulses is equal to specified distance.
|
|
m = Coordinates(TABLE_SIZE_X_MM, TABLE_SIZE_Y_MM, TABLE_SIZE_Z_MM,
|
|
100.0)
|
|
g = PulseGeneratorLinear(m, self.v)
|
|
ix = 0
|
|
iy = 0
|
|
iz = 0
|
|
ie = 0
|
|
t = -1
|
|
for direction, px, py, pz, pe in g:
|
|
if direction:
|
|
continue
|
|
if px is not None:
|
|
ix += 1
|
|
if py is not None:
|
|
iy += 1
|
|
if pz is not None:
|
|
iz += 1
|
|
if pe is not None:
|
|
ie += 1
|
|
v = list(x for x in (px, py, pz, pe) if x is not None)
|
|
self.assertEqual(min(v), max(v))
|
|
self.assertLess(t, min(v))
|
|
t = max(v)
|
|
self.assertEqual(m.x * STEPPER_PULSES_PER_MM_X, ix)
|
|
self.assertEqual(m.y * STEPPER_PULSES_PER_MM_Y, iy)
|
|
self.assertEqual(m.z * STEPPER_PULSES_PER_MM_Z, iz)
|
|
self.assertEqual(m.e * STEPPER_PULSES_PER_MM_E, ie)
|
|
self.assertLessEqual(t, g.total_time_s())
|
|
_, pos = self.__check_circular(Coordinates(0, 8, 0, 7),
|
|
Coordinates(1, 0, 1, 0),
|
|
PLANE_ZX, CCW)
|
|
self.assertEqual(pos, Coordinates(0, 8, 0, 7))
|
|
_, pos = self.__check_circular(Coordinates(5, 0, 0, 6),
|
|
Coordinates(0, 1, -1, 0),
|
|
PLANE_YZ, CW)
|
|
self.assertEqual(pos, Coordinates(5, 0, 0, 6))
|
|
_, pos = self.__check_circular(Coordinates(-2, -2, 3, 2),
|
|
Coordinates(-1, -1, 0, 0),
|
|
PLANE_XY, CCW)
|
|
self.assertEqual(pos, Coordinates(-2, -2, 3, 2))
|
|
|
|
def test_acceleration_velocity(self):
|
|
# Check if acceleration present in pulses sequence and if velocity
|
|
# is correct, since PulseGenerator is responsible for this, check only
|
|
# one child class.
|
|
m = Coordinates(TABLE_SIZE_X_MM, 0, 0, 0)
|
|
g = PulseGeneratorLinear(m, self.v)
|
|
i = 0
|
|
lx = 0
|
|
lt, at, bt = None, None, None
|
|
for direction, px, py, pz, pe in g:
|
|
if direction:
|
|
continue
|
|
if i == 2:
|
|
at = px - lx
|
|
if i == TABLE_SIZE_X_MM * STEPPER_PULSES_PER_MM_X / 2:
|
|
lt = px - lx
|
|
bt = px - lx
|
|
lx = px
|
|
i += 1
|
|
self.assertEqual(round(60.0 / lt / STEPPER_PULSES_PER_MM_X),
|
|
round(self.v))
|
|
self.assertGreater(at, lt)
|
|
self.assertGreater(bt, lt)
|
|
|
|
def test_directions(self):
|
|
# Check if directions are set up correctly.
|
|
m = Coordinates(1, -2, 3, -4)
|
|
g = PulseGeneratorLinear(m, self.v)
|
|
dir_found = False
|
|
for direction, px, py, pz, pe in g:
|
|
if direction:
|
|
# should be once
|
|
self.assertFalse(dir_found)
|
|
dir_found = True
|
|
# check dirs
|
|
self.assertTrue(px > 0 and py < 0 and pz > 0 and pe < 0)
|
|
m = Coordinates(-1, 2, -3, 4)
|
|
g = PulseGeneratorLinear(m, self.v)
|
|
dir_found = False
|
|
for direction, px, py, pz, pe in g:
|
|
if direction:
|
|
# should be once
|
|
self.assertFalse(dir_found)
|
|
dir_found = True
|
|
# check dirs
|
|
self.assertTrue(px < 0 and py > 0 and pz < 0 and pe > 0)
|
|
# check for circle, full circle
|
|
dir_changed, _ = self.__check_circular(Coordinates(0, 0, 0, 0),
|
|
Coordinates(1.0, 1.0, 0, 0),
|
|
PLANE_ZX, CCW)
|
|
self.assertEqual(dir_changed, 4)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|