示例#1
0
    def test_g28(self):
        # no parameters
        gcode = "G28"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertDictEqual({}, parsed.parameters)

        # all parameters, funky spaces
        gcode = "g  2  8 xy zw; some kind of comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertIsNone(parsed.parameters["X"])
        self.assertIsNone(parsed.parameters["Y"])
        self.assertIsNone(parsed.parameters["Z"])
        self.assertIsNone(parsed.parameters["W"])

        # all parameters, no spaces
        gcode = "g28wzxy; some kind of comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertIsNone(parsed.parameters["X"])
        self.assertIsNone(parsed.parameters["Y"])
        self.assertIsNone(parsed.parameters["Z"])
        self.assertIsNone(parsed.parameters["W"])

        # some parameters
        gcode = "g28 xy; some kind of comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertIsNone(parsed.parameters["X"])
        self.assertIsNone(parsed.parameters["Y"])
        self.assertNotIn("Z", parsed.parameters)
        self.assertNotIn("W", parsed.parameters)
示例#2
0
 def test_parse_int_negative(self):
     # test negative F error
     gcode = "G00 F- 1 09 "
     with self.assertRaises(Exception) as context:
         Commands.parse(gcode)
     self.assertTrue(
         "The parameter value is negative, which is not allowed." in
         context.exception)
示例#3
0
 def test_multiple_decimals_command(self):
     # test multiple decimal points in parameter 2
     gcode = "G28.0."
     with self.assertRaises(Exception) as context:
         Commands.parse(gcode)
     self.assertTrue(
         "Cannot parse the gcode address, multiple periods seen." in
         context.exception)
示例#4
0
    def test_unknown_command(self):
        gcode = "G9999fdafdsafdafsd"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G9999")
        self.assertIsNone(parsed.parameters)

        gcode = "G9999"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G9999")
        self.assertIsNone(parsed.parameters)
示例#5
0
    def test_ExtruderMovement(self):
        """Test the M82 and M83 command."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        previous_pos = Pos(self.Settings.current_printer(), self.OctoprintPrinterProfile)
        # test initial position
        self.assertIsNone(position.e())
        self.assertIsNone(position.is_extruder_relative())
        self.assertIsNone(position.e_relative_pos(previous_pos))

        # set extruder to relative coordinates
        position.update(Commands.parse("M83"))

        # test movement
        previous_pos = Pos(self.Settings.current_printer(), self.OctoprintPrinterProfile, position.get_position())
        position.update(Commands.parse("G0 E100"))
        self.assertEqual(position.e(), 100)
        # this is somewhat reversed from what we do in the position.py module
        # there we update the pos() object and compare to the current state, so
        # comparing the current state to the
        # previous will result in the opposite sign
        self.assertEqual(position.e_relative_pos(previous_pos), -100)

        # switch to absolute movement
        previous_pos = Pos(self.Settings.current_printer(), self.OctoprintPrinterProfile, position.get_position())
        position.update(Commands.parse("M82"))
        self.assertFalse(position.is_extruder_relative())
        self.assertEqual(position.e(), 100)
        self.assertEqual(position.e_relative_pos(previous_pos), 0)

        # move to -25
        previous_pos = Pos(self.Settings.current_printer(), self.OctoprintPrinterProfile, position.get_position())
        position.update(Commands.parse("G0 E-25"))
        self.assertEqual(position.e(), -25)
        self.assertEqual(position.e_relative_pos(previous_pos), 125)

        # test movement to origin
        previous_pos = Pos(self.Settings.current_printer(), self.OctoprintPrinterProfile, position.get_position())
        position.update(Commands.parse("G0 E0"))
        self.assertEqual(position.e(), 0)
        self.assertEqual(position.e_relative_pos(previous_pos), -25)

        # switch to relative position
        previous_pos = Pos(self.Settings.current_printer(), self.OctoprintPrinterProfile, position.get_position())
        position.update(Commands.parse("M83"))
        position.update(Commands.parse("G0 e1.1"))
        self.assertEqual(position.e(), 1.1)
        self.assertEqual(position.e_relative_pos(previous_pos), -1.1)

        # move and test
        previous_pos = Pos(self.Settings.current_printer(), self.OctoprintPrinterProfile, position.get_position())
        position.update(Commands.parse("G0 e1.1"))
        self.assertEqual(position.e(), 2.2)
        self.assertEqual(position.e_relative_pos(previous_pos), -1.1)

        # move and test
        previous_pos = Pos(self.Settings.current_printer(), self.OctoprintPrinterProfile, position.get_position())
        position.update(Commands.parse("G0 e-2.2"))
        self.assertEqual(position.e(), 0)
        self.assertEqual(position.e_relative_pos(previous_pos), 2.2)
示例#6
0
    def test_g21(self):
        # no parameters
        gcode = "G21"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G21")
        self.assertDictEqual({}, parsed.parameters)

        # with parameters (bogus)
        gcode = "G21X100fdafdsa; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G21")
        self.assertDictEqual({}, parsed.parameters)
示例#7
0
    def test_g20(self):
        # no parameters
        gcode = "G20"
        cmd, parameters = Commands.parse(gcode)
        self.assertEqual(cmd, "G20")
        self.assertDictEqual({}, parameters)

        # with parameters (bogus)
        gcode = "G20X100fdafdsa; Here is a comment"
        cmd, parameters = Commands.parse(gcode)
        self.assertEqual(cmd, "G20")
        self.assertDictEqual({}, parameters)
示例#8
0
 def test_IsAtCurrentPosition(self):
     # Received: x:119.91,y:113.34,z:2.1,e:0.0, Expected:
     # x:119.9145519,y:113.33847,z:2.1
     # G1 X119.915 Y113.338 F7200
     position = Position(self.Settings, self.OctoprintPrinterProfile, False)
     position.Printer.printer_position_confirmation_tolerance = .0051
     position.update(Commands.parse("M83"))
     position.update(Commands.parse("G90"))
     position.update(Commands.parse("G28"))
     position.update(Commands.parse("G1 X119.915 Y113.338 Z2.1 F7200"))
     self.assertTrue(position.is_at_current_position(119.91, 113.34, 2.1))
     position.update(Commands.parse("g0 x120 y121 z2.1"))
     self.assertTrue(position.is_at_previous_position(119.91, 113.34, 2.1))
示例#9
0
    def test_reset(self):
        """Test init state."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        # reset all initialized vars to something else
        position.update(Commands.parse("G28"))
        position.update(Commands.parse("G0 X1 Y1 Z1"))

        # reset
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        # test initial state
        self.assertEqual(len(position.Positions), 0)
        self.assertIsNone(position.SavedPosition)
示例#10
0
    def test_parameter_repetition(self):
        # test parameter repetition
        gcode = "g28 xxz"
        with self.assertRaises(Exception) as context:
            Commands.parse(gcode)
        self.assertTrue('A parameter value was repeated, cannot parse gcode.'
                        in context.exception)

        # test parameter repetition wrapped in comments
        gcode = "(comment in the front)g(comment in middle)2()8x(another comment in middle)x(comment between" \
                " address and value)100()1 . 1(another); Here is a comment"
        with self.assertRaises(Exception) as context:
            Commands.parse(gcode)
        self.assertTrue('A parameter value was repeated, cannot parse gcode.'
                        in context.exception)
示例#11
0
    def test_parameter_repetition(self):
        # test parameter repetition
        gcode = "g28 xxz"
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNotNone(parsed.error)
        self.assertNotEqual(len(parsed.error), 0)

        # test parameter repetition wrapped in comments
        gcode = "(comment in the front)g(comment in middle)2()8x(another comment in middle)x(comment between" \
                " address and value)100()1 . 1(another); Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNotNone(parsed.error)
        self.assertNotEqual(len(parsed.error), 0)
示例#12
0
 def test_multiple_signs_parameter(self):
     # test multiple signs in parameter 1
     gcode = "(comment in the front)g(comment in middle)2()8(another comment in middle)x(comment between" \
             " address and value)+100()1 . 1+(another); Here is a comment"
     parsed = Commands.parse(gcode)
     self.assertIsNone(parsed.cmd)
     self.assertIsNotNone(parsed.error)
     self.assertNotEqual(len(parsed.error), 0)
     # test multiple signs in parameter 2
     gcode = "(comment in the front)g(comment in middle)2()8x(another comment in middle)x(comment between" \
             " address and value)++100()1 . 1(another); Here is a comment"
     parsed = Commands.parse(gcode)
     self.assertIsNone(parsed.cmd)
     self.assertIsNotNone(parsed.error)
     self.assertNotEqual(len(parsed.error), 0)
示例#13
0
    def test_m105(self):
        gcode = "m105;"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "M105")
        self.assertDictEqual(parsed.parameters, {})

        gcode = "m105X1;"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "M105")
        self.assertDictEqual(parsed.parameters, {})

        gcode = "m105fdsafdsafdsfsdfsd;"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "M105")
        self.assertDictEqual(parsed.parameters, {})
示例#14
0
 def test_parse_int_negative(self):
     # test negative F error
     gcode = "G00 F- 1 09 "
     parsed = Commands.parse(gcode)
     self.assertIsNone(parsed.cmd)
     self.assertIsNotNone(parsed.error)
     self.assertNotEqual(len(parsed.error), 0)
示例#15
0
 def test_multiple_decimals_command(self):
     # test multiple decimal points in parameter 2
     gcode = "G28.0."
     parsed = Commands.parse(gcode)
     self.assertIsNone(parsed.cmd)
     self.assertIsNotNone(parsed.error)
     self.assertNotEqual(len(parsed.error), 0)
示例#16
0
    def test_multiple_decimals_parameter(self):
        # test multiple decimal points in parameter 1
        gcode = "(comment in the front)g(comment in middle)2()8x(another comment in middle)x(comment between" \
                "address and value)+100()1 . 1(another).; Here is a comment"
        with self.assertRaises(Exception) as context:
            Commands.parse(gcode)
        self.assertTrue(
            "Could not parse float from parameter string, saw multiple decimal points."
            in context.exception)

        # test multiple decimal points in parameter 2
        gcode = "(comment in the front)g(comment in middle)2()8x(another comment in middle)x(comment between" \
                " address and value)1.00()1 . 1(another); Here is a comment"
        with self.assertRaises(Exception) as context:
            Commands.parse(gcode)
        self.assertTrue(
            "Could not parse float from parameter string, saw multiple decimal points."
            in context.exception)
示例#17
0
    def test_g0(self):

        # no parameters
        gcode = "g0"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertDictEqual({}, parsed.parameters)

        # no parameters, double 0
        gcode = "g00"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertDictEqual({}, parsed.parameters)

        # all parameters with comment
        gcode = "g0 x100 y200.0 z3.0001 e1.1 f7200.000; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)

        # all parameters, no spaces
        gcode = "g0x100y200.0z3.0001e1.1f7200.000"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)

        # all parameters, funky spaces
        gcode = "g  0 x  10 0  y2 00 .0z  3.0 001 e1. 1 f72 00 .000 "
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)
示例#18
0
    def test_G90InfluencesExtruder_UpdatePosition(self):
        """Test G90 for machines where it influences the coordinate system of the extruder."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, True)
        # Make sure the axis is homed
        position.update(Commands.parse("G28"))
        # set absolute mode with G90
        position.update(Commands.parse("g90"))
        # update the position to 10 (absolute)
        position.update_position(e=10)
        self.assertEqual(position.e(), 10)
        # update the position to 10 again (absolute) to make sure we are in absolute
        # coordinates.
        position.update_position(e=10)
        self.assertEqual(position.e(), 10)

        # set relative mode with G90
        position.update(Commands.parse("g91"))
        # update the position to 20 (relative)
        position.update_position(e=20)
        self.assertEqual(position.e(), 30)
示例#19
0
    def test_G92AbsoluteMovement(self):
        """Test the G92 command, move in absolute mode and test results."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        # set homed axis, absolute coordinates, and set position
        position.update(Commands.parse("G28"))
        position.update(Commands.parse("G90"))
        position.update(Commands.parse("G1 x100 y200 z150"))
        position.update(Commands.parse("G92 x10 y20 z30"))
        self.assertEqual(position.x(), 100)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 200)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 150)
        self.assertEqual(position.z_offset(), 120)

        # move to origin
        position.update(Commands.parse("G1 x-90 y-180 z-120"))
        self.assertEqual(position.x(), 0)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 0)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 0)
        self.assertEqual(position.z_offset(), 120)

        # move back
        position.update(Commands.parse("G1 x0 y0 z0"))
        self.assertEqual(position.x(), 90)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 180)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 120)
        self.assertEqual(position.z_offset(), 120)
示例#20
0
    def test_G92SetPosition(self):
        """Test the G92 command, settings the position."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        # no homed axis
        position.update(Commands.parse("G92 x10 y20 z30"))
        self.assertEqual(position.x(), 10)
        self.assertEqual(position.y(), 20)
        self.assertEqual(position.z(), 30)
        self.assertFalse(position.has_homed_axes())

        # set homed axis, absolute coordinates, and set position
        position.update(Commands.parse("G28"))
        position.update(Commands.parse("G90"))
        position.update(Commands.parse("G1 x100 y200 z150"))
        position.update(Commands.parse("G92 x10 y20 z30"))
        self.assertEqual(position.x(), 100)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 200)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 150)
        self.assertEqual(position.z_offset(), 120)

        # Move to same position and retest
        position.update(Commands.parse("G1 x0 y0 z0"))
        self.assertEqual(position.x(), 90)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 180)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 120)
        self.assertEqual(position.z_offset(), 120)

        # Move and retest
        position.update(Commands.parse("G1 x-10 y10 z20"))
        self.assertEqual(position.x(), 80)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 190)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 140)
        self.assertEqual(position.z_offset(), 120)

        # G92 with no parameters
        position.update(Commands.parse("G92"))
        self.assertEqual(position.x(), 80)
        self.assertEqual(position.x_offset(), 80)
        self.assertEqual(position.y(), 190)
        self.assertEqual(position.y_offset(), 190)
        self.assertEqual(position.z(), 140)
        self.assertEqual(position.z_offset(), 140)
示例#21
0
    def test_GetSnapshotGcode_Fixed_AbsoluteCoordintes_ExtruderRelative(self):
        """Test snapshot gcode in absolute coordinate system with relative extruder and fixed coordinate
        stabilization """
        # adjust the settings for absolute position and create the snapshot gcode generator
        self.Settings.current_stabilization().x_type = "fixed_coordinate"
        self.Settings.current_stabilization().x_fixed_coordinate = 10
        self.Settings.current_stabilization().y_type = "fixed_coordinate"
        self.Settings.current_stabilization().y_fixed_coordinate = 20
        snapshot_gcode_generator = SnapshotGcodeGenerator(
            self.Settings, self.create_octoprint_printer_profile())
        self.Extruder.is_retracted = lambda: True

        self.Position.update(Commands.parse("G90"))
        self.Position.update(Commands.parse("M83"))
        self.Position.update(Commands.parse("G28"))
        self.Position.update(Commands.parse("G0 X95 Y95 Z0.2 F3600"))
        parsed_command = Commands.parse("G0 X100 Y100")
        self.Position.update(parsed_command)
        snapshot_gcode = snapshot_gcode_generator.create_snapshot_gcode(
            self.Position, None, parsed_command)
        gcode_commands = snapshot_gcode.snapshot_gcode()

        # verify the created gcodegcode_commands
        self.assertEqual(gcode_commands[0], "G1 E-4.00000 F4800")
        self.assertEqual(gcode_commands[1], "G1 X10.000 Y20.000 F10800")
        self.assertEqual(gcode_commands[2], "G1 X100.000 Y100.000")
        self.assertEqual(gcode_commands[3], "G1 E4.00000 F3000")
        self.assertEqual(gcode_commands[4], "G1 F3600")
        self.assertEqual(gcode_commands[5], parsed_command.gcode)

        # verify the return coordinates
        self.assertEqual(snapshot_gcode.ReturnX, 100)
        self.assertEqual(snapshot_gcode.ReturnY, 100)
        self.assertEqual(snapshot_gcode.ReturnZ, 0.2)

        self.assertEqual(snapshot_gcode.X, 10)
        self.assertEqual(snapshot_gcode.Y, 20)
        self.assertEqual(snapshot_gcode.Z, None)
示例#22
0
    def test_g1(self):
        # no parameters
        gcode = "g1"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G1")
        self.assertDictEqual({}, parsed.parameters)

        # no parameters, double 0
        gcode = "g01"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G1")
        self.assertDictEqual({}, parsed.parameters)

        # all parameters with comment
        gcode = "g1 x100 y200.0 z3.0001 e1.1 f7200.000; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G1")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)

        # all parameters, no spaces
        gcode = "g1x100y200.0z3.0001e1.1f7200.000"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G1")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)

        # all parameters, funky spaces
        gcode = "g  01 x  10 0  y2 00 .0z  3.0 001 e1. 1 f72 00 .000 "
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G1")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)

        # from issue 86
        gcode = "G1 X -18 Y95 F1000"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G1")
        self.assertEqual(parsed.parameters["X"], -18)
        self.assertEqual(parsed.parameters["Y"], 95)
        self.assertNotIn("Z", parsed.parameters)
        self.assertNotIn("E", parsed.parameters)
        self.assertEqual(parsed.parameters["F"], 1000)
示例#23
0
    def test_G92RelativeMovement(self):
        """Test the G92 command, move in relative mode and test results."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        # set homed axis, relative coordinates, and set position
        position.update(Commands.parse("G28"))
        position.update(Commands.parse("G91"))
        position.update(Commands.parse("G1 x100 y200 z150"))
        position.update(Commands.parse("G92 x10 y20 z30"))
        self.assertEqual(position.x(), 100)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 200)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 150)
        self.assertEqual(position.z_offset(), 120)

        # move to origin
        position.update(Commands.parse("G1 x-100 y-200 z-150"))
        self.assertEqual(position.x(), 0)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 0)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 0)
        self.assertEqual(position.z_offset(), 120)

        # advance each axis
        position.update(Commands.parse("G1 x1 y2 z3"))
        self.assertEqual(position.x(), 1)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 2)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 3)
        self.assertEqual(position.z_offset(), 120)

        # advance again
        position.update(Commands.parse("G1 x1 y2 z3"))
        self.assertEqual(position.x(), 2)
        self.assertEqual(position.x_offset(), 90)
        self.assertEqual(position.y(), 4)
        self.assertEqual(position.y_offset(), 180)
        self.assertEqual(position.z(), 6)
        self.assertEqual(position.z_offset(), 120)
示例#24
0
    def test_UpdatePosition_force(self):
        """Test the UpdatePosition function with the force option set to true."""
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)
        position.update(Commands.parse("G28"))
        position.update_position(x=0, y=0, z=0, e=0, force=True)

        self.assertEqual(position.x(), 0)
        self.assertEqual(position.y(), 0)
        self.assertEqual(position.z(), 0)
        self.assertEqual(position.e(), 0)

        position.update_position(x=1, y=2, z=3, e=4, force=True)
        self.assertEqual(position.x(), 1)
        self.assertEqual(position.y(), 2)
        self.assertEqual(position.z(), 3)
        self.assertEqual(position.e(), 4)

        position.update_position(x=None, y=None, z=None, e=None, force=True)
        self.assertEqual(position.x(), 1)
        self.assertEqual(position.y(), 2)
        self.assertEqual(position.z(), 3)
        self.assertEqual(position.e(), 4)
示例#25
0
    def test_inline_comments(self):
        gcode = "g28(this is an inline commentx)yz; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertFalse("X" in parsed.parameters)
        self.assertIsNone(parsed.parameters["Y"])
        self.assertIsNone(parsed.parameters["Z"])

        gcode = "g28(this is an inline commentx); Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertFalse("X" in parsed.parameters)
        self.assertFalse("Y" in parsed.parameters)
        self.assertFalse("Z" in parsed.parameters)

        gcode = "(comment in the front)g28; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertFalse("X" in parsed.parameters)
        self.assertFalse("Y" in parsed.parameters)
        self.assertFalse("Z" in parsed.parameters)

        gcode = "(comment in the front)g28(comment in back); Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertFalse("X" in parsed.parameters)
        self.assertFalse("Y" in parsed.parameters)
        self.assertFalse("Z" in parsed.parameters)

        gcode = "(comment in the front)g(comment in middle)28(comment in back); Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertFalse("X" in parsed.parameters)
        self.assertFalse("Y" in parsed.parameters)
        self.assertFalse("Z" in parsed.parameters)

        gcode = "(comment in the front)g(comment in middle)2()8(another comment in middle)x(comment between" \
                "address and value)100()1 . 1(another); Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertEqual(parsed.parameters["X"], 1001.1)
        self.assertFalse("Y" in parsed.parameters)
        self.assertFalse("Z" in parsed.parameters)
示例#26
0
    def test_zHop(self):
        """Test zHop detection."""
        # set zhop distance
        self.Settings.current_printer().z_hop = .5
        position = Position(self.Settings, self.OctoprintPrinterProfile, False)

        # test initial state
        self.assertFalse(position.is_zhop())

        # check without homed axis
        position.update(Commands.parse("G1 x0 y0 z0"))
        self.assertFalse(position.is_zhop())
        position.update(Commands.parse("G1 x0 y0 z0.5"))
        self.assertFalse(position.is_zhop())

        # set relative extruder, absolute xyz, home axis, check again
        position.update(Commands.parse("M83"))
        position.update(Commands.parse("G90"))
        position.update(Commands.parse("G28"))
        self.assertFalse(position.is_zhop())
        # Position reports as NotHomed (misnomer, need to replace), needs to get
        # coordinates
        position.update(Commands.parse("G1 x0 y0 z0"))

        # Move up without extrude, this is not a zhop since we haven't extruded
        # anything!
        position.update(Commands.parse("g0 z0.5"))
        self.assertFalse(position.is_zhop())
        # move back down to 0 and extrude
        position.update(Commands.parse("g0 z0 e1"))
        self.assertFalse(position.is_zhop())
        # Move up without extrude, this should trigger zhop start
        position.update(Commands.parse("g0 z0.5"))
        self.assertTrue(position.is_zhop())
        # move below zhop threshold
        position.update(Commands.parse("g0 z0.3"))
        self.assertFalse(position.is_zhop())

        # move right up to zhop without going over, we are within the rounding error
        position.update(Commands.parse("g0 z0.4999"))
        self.assertTrue(position.is_zhop())

        # Extrude on z5
        position.update(Commands.parse("g0 z0.5 e1"))
        self.assertFalse(position.is_zhop())

        # partial z lift, , we are within the rounding error
        position.update(Commands.parse("g0 z0.9999"))
        self.assertTrue(position.is_zhop())
        # Still hopped!
        position.update(Commands.parse("g0 z1"))
        self.assertTrue(position.is_zhop())
        # test with extrusion start at 1.5
        position.update(Commands.parse("g0 z1.5 e1"))
        self.assertFalse(position.is_zhop())
        # test with extrusion at 2
        position.update(Commands.parse("g0 z2 e1"))
        self.assertFalse(position.is_zhop())

        # zhop
        position.update(Commands.parse("g0 z2.5 e0"))
        self.assertTrue(position.is_zhop())

        position.update(Commands.parse("no-command"))
        self.assertTrue(position.is_zhop())
示例#27
0
    def test_comments(self):
        """Try to parse the G0 Command, parsed.parameters and comment"""

        gcode = ";"
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNone(parsed.parameters)

        gcode = " ;"
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNone(parsed.parameters)

        gcode = "; "
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNone(parsed.parameters)

        gcode = ";  "
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNone(parsed.parameters)

        gcode = "%"
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNone(parsed.parameters)

        gcode = "% "
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNone(parsed.parameters)

        gcode = "%   "
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNone(parsed.parameters)

        gcode = " % this is a comment"
        parsed = Commands.parse(gcode)
        self.assertIsNone(parsed.cmd)
        self.assertIsNone(parsed.parameters)

        gcode = "g0 x100 y200.0 z3.0001 e1.1 f7200.000; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)

        gcode = "g0x100y200.0z3.0001e1.1f7200.000; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)

        # test signs 1
        gcode = "g0x+100y-200.0z - 3.0001e +1.1f 7200.000; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertEqual(parsed.parameters["X"], 100)
        self.assertEqual(parsed.parameters["Y"], -200.0)
        self.assertEqual(parsed.parameters["Z"], -3.0001)
        self.assertEqual(parsed.parameters["E"], 1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)
        # test signs 2
        gcode = "g0x-100y + 200.0z+  3.0001e -1.1f  +  7200.000; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G0")
        self.assertEqual(parsed.parameters["X"], -100)
        self.assertEqual(parsed.parameters["Y"], 200.0)
        self.assertEqual(parsed.parameters["Z"], 3.0001)
        self.assertEqual(parsed.parameters["E"], -1.1)
        self.assertEqual(parsed.parameters["F"], 7200.000)

        gcode = "g28xyz; Here is a comment"
        parsed = Commands.parse(gcode)
        self.assertEqual(parsed.cmd, "G28")
        self.assertIsNone(parsed.parameters["X"])
        self.assertIsNone(parsed.parameters["Y"])
        self.assertIsNone(parsed.parameters["Z"])
示例#28
0
 def test_unknown_word(self):
     gcode = "K100"
     parsed = Commands.parse(gcode)
     self.assertIsNone(parsed.cmd)
     self.assertIsNone(parsed.parameters)
示例#29
0
    def on_gcode_queuing(self, command_string, cmd_type, gcode, tags):

        self.detect_timelapse_start(command_string, tags)

        # if the timelapse is not active, exit without changing any gcode
        if not self.is_timelapse_active():
            return

        self.check_current_line_number(tags)

        # update the position tracker so that we know where all of the axis are.
        # We will need this later when generating snapshot gcode so that we can return to the previous
        # position
        is_snapshot_gcode_command = self._is_snapshot_command(command_string)

        try:
            self.Settings.current_debug_profile().log_gcode_queuing(
                "Queuing Command: Command Type:{0}, gcode:{1}, cmd: {2}, tags: {3}".format(
                    cmd_type, gcode, command_string, tags
                )
            )

            try:
                cmd, parameters = Commands.parse(command_string)
            except ValueError as e:
                message = "An error was thrown by the gcode parser, stopping timelapse.  Details: {0}".format(e.message)
                self.Settings.current_debug_profile().log_warning(
                    message
                )
                self.stop_snapshots(message, True)
                return None

            # get the position state in case it has changed
            # if there has been a position or extruder state change, inform any listener

            if cmd is not None and not is_snapshot_gcode_command:
                # create our state change dictionaries
                self.Position.update(command_string, cmd, parameters)

            # if this code is snapshot gcode, simply return it to the printer.
            if {'plugin:octolapse', 'snapshot_gcode'}.issubset(tags):
                return None

            if not self.check_for_non_metric_errors():
                if self.Position.has_position_error(0):
                    # There are position errors, report them!
                    self._on_position_error()
                elif (self.State == TimelapseState.WaitingForTrigger
                        and (self.Position.requires_location_detection(1)) and self.OctoprintPrinter.is_printing()):

                    self.State = TimelapseState.AcquiringLocation

                    if self.OctoprintPrinter.set_job_on_hold(True):
                        thread = threading.Thread(target=self.acquire_position, args=[command_string, cmd, parameters])
                        thread.daemon = True
                        thread.start()
                        return None,
                elif (self.State == TimelapseState.WaitingForTrigger
                      and self.OctoprintPrinter.is_printing()
                      and not self.Position.has_position_error(0)):
                    # update the triggers with the current position
                    self.Triggers.update(self.Position, command_string)
                    # see if at least one trigger is triggering
                    _first_triggering = self.get_first_triggering()

                    if _first_triggering:
                        # We are triggering, take a snapshot
                        self.State = TimelapseState.TakingSnapshot
                        # pause any timer triggers that are enabled
                        self.Triggers.pause()

                        # get the job lock
                        if self.OctoprintPrinter.set_job_on_hold(True):
                            # take the snapshot on a new thread
                            thread = threading.Thread(
                                target=self.acquire_snapshot, args=[command_string, cmd, parameters, _first_triggering]
                            )
                            thread.daemon = True
                            thread.start()
                            # suppress the current command, we'll send it later
                            return None,

                elif self.State == TimelapseState.TakingSnapshot:
                    # Don't do anything further to any commands unless we are
                    # taking a timelapse , or if octolapse paused the print.
                    # suppress any commands we don't, under any cirumstances,
                    # to execute while we're taking a snapshot

                    if cmd in self.Commands.SuppressedSnapshotGcodeCommands:
                        command_string = None,  # suppress the command

            if is_snapshot_gcode_command:
                # in all cases do not return the snapshot command to the printer.
                # It is NOT a real gcode and could cause errors.
                command_string = None,

        except Exception as e:
            self.Settings.current_debug_profile().log_exception(e)
            raise

        # notify any callbacks
        self._send_state_changed_message()

        # do any post processing for test mode
        if command_string != (None,):
            command_string = self._get_command_for_octoprint(command_string, cmd,parameters)
        return command_string
示例#30
0
文件: gcode.py 项目: xj3-me/Octolapse
    def create_snapshot_gcode(self, position, trigger, gcode, cmd, parameters,
                              triggering_command_position,
                              triggering_extruder_position):

        assert (isinstance(triggering_command_position, Pos))

        x_return = position.x()
        y_return = position.y()
        z_return = position.z()
        f_return = position.f()
        # e_return = position.e()

        is_relative = position.is_relative()
        is_extruder_relative = position.is_extruder_relative()
        is_metric = position.is_metric()
        z_lift = position.distance_to_zlift()
        if z_lift is None:
            pos = position.get_position(0)
            if pos is not None:
                self.Settings.current_debug_profile().log_warning(
                    "gcode.py - ZLift is none: Z:{0}, LastExtrusionHeight:{1}".
                    format(pos.Z, pos.LastExtrusionHeight))
        length_to_retract = position.Extruder.length_to_retract()
        final_command = gcode

        self.reset()
        if x_return is None or y_return is None or z_return is None:
            self.HasSnapshotPositionErrors = True
            message = "Cannot create GCode when x,y,or z is None.  Values: x:{0} y:{1} z:{2}".format(
                x_return, y_return, z_return)
            self.SnapshotPositionErrors = message
            self.Settings.current_debug_profile().log_error(
                "gcode.py - CreateSnapshotGcode - {0}".format(message))
            return None

        # Todo:  Clean this mess up (used to take separate params in the fn, now we take a position object)
        self.ReturnWhenComplete = True
        self.FOriginal = f_return
        self.FCurrent = f_return
        self.RetractedBySnapshotStartGcode = False
        self.RetractedLength = 0
        self.ZhopBySnapshotStartGcode = False
        self.ZLift = z_lift
        self.IsRelativeOriginal = is_relative
        self.IsRelativeCurrent = is_relative
        self.IsExtruderRelativeOriginal = is_extruder_relative
        self.IsExtruderRelativeCurrent = is_extruder_relative

        # check the units
        if is_metric is None or not is_metric:
            self.Settings.current_debug_profile().log_error(
                "No unit of measurement has been set and the current"
                " printer profile is set to require explicit G20/G21, or the unit of measurement is inches. "
            )
            return None

        # create our gcode object
        new_snapshot_gcode = SnapshotGcode(self.IsTestMode)

        # create the start and end gcode, which would include any split gcode (position restriction intersection)
        # or any saved command that needs to be appended

        # Flag to indicate that we should make sure the final feedrate = self.FOriginal
        # by default we want to change the feedrate if FCurrent != FOriginal
        reset_feedrate_before_end_gcode = True
        triggered_type = trigger.triggered_type(0)
        if triggered_type is None:
            triggered_type = trigger.triggered_type(1)

        # handle the trigger types
        if triggered_type == Triggers.TRIGGER_TYPE_DEFAULT:
            if triggering_command_position.IsTravelOnly:
                self.Settings.current_debug_profile().log_snapshot_gcode(
                    "The triggering command is travel only, skipping return command generation"
                )
                # No need to perform the return step!  We'll go right the the next travel location after
                # taking the snapshot!
                self.ReturnWhenComplete = False
        elif triggered_type == Triggers.TRIGGER_TYPE_IN_PATH:
            # see if the snapshot command is a g1 or g0
            if cmd:
                if cmd not in ["G0", "G1"]:
                    # if this isn't a g0 or g1, I don't know what's up!
                    return None
                # get the data necessary to split the command up
                in_path_position = trigger.in_path_position(0)
                intersection = in_path_position["intersection"]
                path_ratio_1 = in_path_position["path_ratio_1"]
                path_ratio_2 = in_path_position["path_ratio_2"]

                _x1 = intersection[0]  # will be in absolute coordinates
                _y1 = intersection[1]  # will be in absolute coordinates
                _x2 = parameters[
                    "X"] if "X" in parameters else None  # should remain in the original coordinate system
                _y2 = parameters[
                    "Y"] if "Y" in parameters else None  # should remain in the original coordinate system
                _z = parameters[
                    "Z"] if "Z" in parameters else None  # should remain in the original coordinate system
                _e = parameters["E"] if "E" in parameters else None
                _f = parameters["F"] if "F" in parameters else None
                # if the command has an F parameter, update FCurrent

                if _f:
                    _f = float(_f)
                    if self.FCurrent != _f:
                        # if we have a new speed here, set it as the original
                        self.FCurrent = _f
                        self.FOriginal = _f

                _e1 = None
                _e2 = None
                # calculate e
                if _e:
                    _e = float(_e)
                    if not self.IsExtruderRelativeCurrent:
                        _extrusion_amount = position.e_relative(e=_e)
                        # set e1 absolute
                        _e1 = _e - _extrusion_amount * path_ratio_2
                        _e2 = _e
                    else:
                        _e1 = _e * path_ratio_1
                        _e2 = _e * path_ratio_2

                # Convert X1 and y1 to relative
                if self.IsRelativeCurrent:
                    if _x1:
                        _x1 = position.x_relative(_x1)
                    if _y1:
                        _y1 = position.y_relative(_y1)

                if _x2:
                    _x2 = float(_x2)
                if _y2:
                    _y2 = float(_y2)

                if _z:
                    _z = float(_z)
                if _f:
                    _f = float(_f)

                if (self.IsTestMode):
                    _e1 = None
                    _e2 = None

                gcode1 = self.get_g_command(cmd, _x1, _y1, _z, _e1, _f)
                # create the second command
                gcode2 = self.get_g_command(cmd, _x2, _y2, _z, _e2, _f)

                # append both commands
                new_snapshot_gcode.append(SnapshotGcode.START_GCODE, gcode1)

                final_command = gcode2
                # set the return x and return y to the intersection point
                # must be in absolute coordinates
                x_return = intersection[0]  # will be in absolute coordinates
                y_return = intersection[1]  # will be in absolute coordinates

                # recalculate z_lift and retract distance since we have moved a bit
                cmd1, cmd1_parameters = Commands.parse(gcode1)
                position.update(gcode, cmd1, cmd1_parameters)
                # set z_return to the new z position
                # must be absolute
                z_return = position.z()
                self.ZLift = position.distance_to_zlift()
                length_to_retract = position.Extruder.length_to_retract()

                # undo the update since the position has not changed, only the zlift value and potentially the
                # retraction length
                position.undo_update()
        else:
            return None

        if (self.Snapshot.retract_before_move and length_to_retract > 0):
            if not self.IsExtruderRelativeCurrent:
                new_snapshot_gcode.append(SnapshotGcode.START_GCODE,
                                          self.get_gcode_extruder_relative())
                self.IsExtruderRelativeCurrent = True

            if self.RetractSpeed != self.FCurrent:
                new_f = self.RetractSpeed
                self.FCurrent = new_f
            else:
                new_f = None
            if length_to_retract > 0:
                new_snapshot_gcode.append(
                    SnapshotGcode.START_GCODE,
                    self.get_gcode_retract(length_to_retract, new_f))
                self.RetractedLength = length_to_retract
                self.RetractedBySnapshotStartGcode = True

        # Can we hop or are we too close to the top?
        can_zhop = self.ZLift is not None and self.Printer.z_hop > 0 and utility.is_in_bounds(
            self.BoundingBox, z=z_return + self.ZLift)
        # if we can ZHop, do
        if can_zhop and self.ZLift > 0 and self.Snapshot.lift_before_move:
            if not self.IsRelativeCurrent:  # must be in relative mode
                new_snapshot_gcode.append(SnapshotGcode.START_GCODE,
                                          self.get_gcode_axes_relative())
                self.IsRelativeCurrent = True

            if self.ZHopSpeed != self.FCurrent:
                new_f = self.ZHopSpeed
                self.FCurrent = new_f
            else:
                new_f = None
            # append to snapshot gcode
            new_snapshot_gcode.append(
                SnapshotGcode.START_GCODE,
                self.get_gcode_z_lift_relative(self.ZLift, new_f))
            self.ZhopBySnapshotStartGcode = True

        # Create code to move from the current extruder position to the snapshot position
        # get the X and Y coordinates of the snapshot
        snapshot_position = self.get_snapshot_position(x_return, y_return)
        new_snapshot_gcode.X = snapshot_position["X"]
        new_snapshot_gcode.Y = snapshot_position["Y"]

        if new_snapshot_gcode.X is None or new_snapshot_gcode.Y is None:
            # either x or y is out of bounds.
            return None

        # Move back to the snapshot position - make sure we're in absolute mode for this
        if self.IsRelativeCurrent:  # must be in absolute mode
            new_snapshot_gcode.append(SnapshotGcode.SNAPSHOT_COMMANDS,
                                      self.get_gcode_axes_absolute())
            self.IsRelativeCurrent = False

        # detect speed change
        if self.FCurrent != self.TravelSpeed:
            new_f = self.TravelSpeed
            self.FCurrent = new_f
        else:
            new_f = None

        # Move to Snapshot Position
        new_snapshot_gcode.append(
            SnapshotGcode.SNAPSHOT_COMMANDS,
            self.get_gcode_travel(new_snapshot_gcode.X, new_snapshot_gcode.Y,
                                  new_f))
        # End Snapshot Gcode

        # Start Return Gcode
        if self.ReturnWhenComplete:
            # Only return to the previous coordinates if we need to (which will be most cases,
            # except when the triggering command is a travel only (moves both X and Y)
            # record our previous position for posterity
            new_snapshot_gcode.ReturnX = x_return
            new_snapshot_gcode.ReturnY = y_return
            new_snapshot_gcode.ReturnZ = z_return

            # Move back to previous position - make sure we're in absolute mode for this (hint: we already are right now)
            # also, our current speed will be correct, no need to append F
            if x_return is not None and y_return is not None:
                new_snapshot_gcode.append(
                    SnapshotGcode.RETURN_COMMANDS,
                    self.get_gcode_travel(x_return, y_return))
        else:
            # record the final position
            new_snapshot_gcode.ReturnX = triggering_command_position.X
            new_snapshot_gcode.ReturnY = triggering_command_position.Y
            # see about Z, we may need to suppress our
            new_snapshot_gcode.ReturnZ = triggering_command_position.Z
            self.Settings.current_debug_profile().log_snapshot_gcode(
                "Skipping return position, traveling to the triggering command position: X={0}, y={0}"
                .format(triggering_command_position.X,
                        triggering_command_position.Y))
            new_snapshot_gcode.append(
                SnapshotGcode.RETURN_COMMANDS,
                self.get_gcode_travel(triggering_command_position.X,
                                      triggering_command_position.Y))

            # Return to the previous feedrate if it's changed

        # If we zhopped in the beginning, lower z
        if self.ZhopBySnapshotStartGcode:
            if not self.IsRelativeCurrent:
                new_snapshot_gcode.append(SnapshotGcode.END_GCODE,
                                          self.get_gcode_axes_relative())
                self.IsRelativeCurrent = True

            if self.ZHopSpeed != self.FCurrent:
                new_f = self.ZHopSpeed
                self.FCurrent = new_f
            else:
                new_f = None

            new_snapshot_gcode.append(
                SnapshotGcode.END_GCODE,
                self.get_gocde_z_lower_relative(self.ZLift, new_f))

        # detract
        if self.RetractedBySnapshotStartGcode:
            if not self.IsExtruderRelativeCurrent:
                new_snapshot_gcode.append(SnapshotGcode.END_GCODE,
                                          self.get_gcode_extruder_relative())
                self.IsExtruderRelativeCurrent = True

            if self.DetractSpeed != self.FCurrent:
                new_f = self.DetractSpeed
                self.FCurrent = new_f
            else:
                new_f = None

            if self.RetractedLength > 0:
                new_snapshot_gcode.append(
                    SnapshotGcode.END_GCODE,
                    self.get_gcode_detract(self.RetractedLength, new_f))

        # reset the coordinate systems for the extruder and axis
        if self.IsRelativeOriginal != self.IsRelativeCurrent:
            if self.IsRelativeCurrent:
                new_snapshot_gcode.append(SnapshotGcode.END_GCODE,
                                          self.get_gcode_axes_absolute())
            else:
                new_snapshot_gcode.append(SnapshotGcode.END_GCODE,
                                          self.get_gcode_axes_relative())
            self.IsRelativeCurrent = self.IsRelativeOriginal

        if self.IsExtruderRelativeOriginal != self.IsExtruderRelativeCurrent:
            if self.IsExtruderRelativeOriginal:
                new_snapshot_gcode.append(SnapshotGcode.END_GCODE,
                                          self.get_gcode_extruder_relative())
            else:
                new_snapshot_gcode.append(SnapshotGcode.END_GCODE,
                                          self.get_gcode_extruder_absolute())

        # Make sure we return to the original feedrate
        if reset_feedrate_before_end_gcode and self.FOriginal != self.FCurrent:
            # we can't count on the end gcode to set f, set it here
            new_snapshot_gcode.append(SnapshotGcode.END_GCODE,
                                      self.get_gcode_feedrate(self.FOriginal))

        new_snapshot_gcode.append(SnapshotGcode.END_GCODE, final_command)

        if self.IsTestMode:
            self.Settings.current_debug_profile().log_snapshot_gcode(
                "The print is in test mode, so all extrusion has been stripped from the following gcode."
            )
        self.Settings.current_debug_profile().log_snapshot_gcode(
            "Snapshot Gcode - SnapshotCommandIndex:{0}, EndIndex:{1}, Triggering Command:{2}"
            .format(new_snapshot_gcode.snapshot_index(),
                    new_snapshot_gcode.end_index(), gcode))
        for gcode in new_snapshot_gcode.snapshot_gcode():
            self.Settings.current_debug_profile().log_snapshot_gcode(
                "    {0}".format(gcode))

        return new_snapshot_gcode