From 3dbea6c396e226759a359f9daf2df5abd5992b42 Mon Sep 17 00:00:00 2001 From: Nikolay Khabarov <2xl@mail.ru> Date: Sun, 21 May 2017 15:13:23 +0300 Subject: [PATCH] add ijk to gcode parser --- cnc/enums.py | 18 ++++++++++++++++++ cnc/gcode.py | 24 ++++++++++++++++++++++++ tests/test_gcode.py | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 cnc/enums.py diff --git a/cnc/enums.py b/cnc/enums.py new file mode 100644 index 0000000..040ccee --- /dev/null +++ b/cnc/enums.py @@ -0,0 +1,18 @@ +from enum import Enum + +""" This module describes system wide enums. +""" + +class Plane(Enum): + """ Enum for choosing plane for circular interpolation. + """ + PLANE_XY = 1 + PLANE_ZX = 2 + PLANE_YZ = 3 + + +class RotationDirection(Enum): + """ Enum for choosing rotation direction. + """ + CW = 1 + CCW = 2 diff --git a/cnc/gcode.py b/cnc/gcode.py index 08e0591..81d7616 100644 --- a/cnc/gcode.py +++ b/cnc/gcode.py @@ -1,6 +1,8 @@ import re +import math from cnc.coordinates import Coordinates +from cnc.enums import Plane gpattern = re.compile('([A-Z])([-+]?[0-9.]+)') cleanpattern = re.compile('\s+|\(.*?\)|;.*') # white spaces and comments start with ';' and in '()' @@ -50,6 +52,26 @@ class GCode(object): """ return 'X' in self.params or 'Y' in self.params or 'Z' in self.params + def radius(self, plane, default, multiply): + """ Get radius for circular interpolation(I, J, K or R). + :param plane: If R is present, specify which axises should be used. + :param default: Default values, if any of coords is not specified. + :param multiply: If value exist, multiply it by this value. + :return: Coord object. + """ + i = self.get('I', default.x, multiply) + j = self.get('J', default.y, multiply) + k = self.get('K', default.z, multiply) + if 'R' in self.params: + r1 = self.get('R', None, multiply) / math.sqrt(2.0) + if plane == Plane.PLANE_XY: + i = j = r1 + elif plane == Plane.PLANE_ZX: + k = i = r1 + elif plane == Plane.PLANE_YZ: + j = k = r1 + return Coordinates(i, j, k) + def command(self): """ Get value from gcode line. :return: String with command or None if no command specified. @@ -82,4 +104,6 @@ class GCode(object): raise GCodeException('duplicated gcode entries') if 'G' in params and 'M' in params: raise GCodeException('g and m command found') + if 'R' in params and ('I' in params or 'J' in params or 'K' in params): + raise GCodeException('r and component radius found') return GCode(params) diff --git a/tests/test_gcode.py b/tests/test_gcode.py index 538b818..cf44aca 100644 --- a/tests/test_gcode.py +++ b/tests/test_gcode.py @@ -1,6 +1,8 @@ import unittest +import math from cnc.coordinates import * +from cnc.enums import * from cnc.gcode import * @@ -65,6 +67,40 @@ class TestGCode(unittest.TestCase): gc = GCode.parse_line("Z1") self.assertTrue(gc.has_coordinates()) + def test_radius(self): + gc = GCode.parse_line("G2I1J2K3") + self.assertEqual(gc.radius(None, self.default, 1).x, 1) + self.assertEqual(gc.radius(None, self.default, 1).y, 2) + self.assertEqual(gc.radius(None, self.default, 1).z, 3) + gc = GCode.parse_line("G3") + self.assertEqual(gc.radius(None, self.default, 1).x, self.default.x) + self.assertEqual(gc.radius(None, self.default, 1).y, self.default.y) + self.assertEqual(gc.radius(None, self.default, 1).z, self.default.z) + self.assertRaises(GCodeException, GCode.parse_line, "R1I2") + self.assertRaises(GCodeException, GCode.parse_line, "R1J2") + self.assertRaises(GCodeException, GCode.parse_line, "R1K2") + gc = GCode.parse_line("G3R9") + self.assertAlmostEqual(gc.radius(Plane.PLANE_XY, self.default, 1).x, + math.sqrt(40.5), 9) + self.assertAlmostEqual(gc.radius(Plane.PLANE_XY, self.default, 1).y, + math.sqrt(40.5), 9) + self.assertEqual(gc.radius(Plane.PLANE_XY, self.default, 1).z, + self.default.z) + gc = GCode.parse_line("G3R10") + self.assertAlmostEqual(gc.radius(Plane.PLANE_ZX, self.default, 1).x, + math.sqrt(50), 9) + self.assertEqual(gc.radius(Plane.PLANE_ZX, self.default, 1).y, + self.default.y) + self.assertAlmostEqual(gc.radius(Plane.PLANE_ZX, self.default, 1).z, + math.sqrt(50), 9) + gc = GCode.parse_line("G3R11") + self.assertEqual(gc.radius(Plane.PLANE_YZ, self.default, 1).x, + self.default.x) + self.assertAlmostEqual(gc.radius(Plane.PLANE_YZ, self.default, 1).y, + math.sqrt(60.5), 9) + self.assertAlmostEqual(gc.radius(Plane.PLANE_YZ, self.default, 1).z, + math.sqrt(60.5), 9) + def test_multiply(self): # getting coordinates could modify value be specified multiplier. gc = GCode.parse_line("X2 Y-3 Z4")