def GetSnapshotPosition(self, xPos, yPos): xPath = self.StabilizationPaths["X"] xPath.CurrentPosition = xPos yPath = self.StabilizationPaths["Y"] yPath.CurrentPosition = yPos coords = dict(X=self.GetSnapshotCoordinate(xPath), Y=self.GetSnapshotCoordinate(yPath)) if (not utility.IsInBounds(self.BoundingBox, x=coords["X"])): message = "The snapshot X position ({0}) is out of bounds!".format( coords["X"]) self.HasSnapshotPositionErrors = True self.Settings.CurrentDebugProfile().LogError( "gcode.py - GetSnapshotPosition - {0}".format(message)) if (self.Printer.abort_out_of_bounds): coords["X"] = None else: coords["X"] = utility.GetClosestInBoundsPosition( self.BoundingBox, x=coords["X"])["X"] message += " Using nearest in-bound position ({0}).".format( coords["X"]) self.SnapshotPositionErrors += message if (not utility.IsInBounds(self.BoundingBox, y=coords["Y"])): message = "The snapshot Y position ({0}) is out of bounds!".format( coords["Y"]) self.HasSnapshotPositionErrors = True self.Settings.CurrentDebugProfile().LogError( "gcode.py - GetSnapshotPosition - {0}".format(message)) if (self.Printer.abort_out_of_bounds): coords["Y"] = None else: coords["Y"] = utility.GetClosestInBoundsPosition( self.BoundingBox, y=coords["Y"])["Y"] message += " Using nearest in-bound position ({0}).".format( coords["Y"]) if (len(self.SnapshotPositionErrors) > 0): self.SnapshotPositionErrors += " " self.SnapshotPositionErrors += message return coords
def test_IsInBounds_CustomBox(self): """Test the IsInBounds function to make sure the program will not attempt to operate after being told to move out of bounds.""" # test custom box with values above zero customBox = { "volume": { "custom_box": { "x_min": 1, "x_max": 200, "y_min": 1, "y_max": 200, "z_min": 1, "z_max": 200 } } } # Initial test, should return false without any coordinates self.assertTrue(not utility.IsInBounds(None, None, None, customBox)) # test the origin (min), should return false self.assertTrue(not utility.IsInBounds(0, 0, 0, customBox)) # test 1,1,1 - True self.assertTrue(utility.IsInBounds(1, 1, 1, customBox)) # move X out of bounds - Min self.assertTrue(not utility.IsInBounds(.9999, 1, 1, customBox)) # move X out of bounds - Max self.assertTrue(not utility.IsInBounds(200.0001, 1, 1, customBox)) # move X in bounds - Max self.assertTrue(utility.IsInBounds(200.0000, 1, 1, customBox)) # move X in bounds - Middle self.assertTrue(utility.IsInBounds(100.5000, 1, 1, customBox)) # move Y out of bounds - Min self.assertTrue(not utility.IsInBounds(1,.9999, 1, customBox)) # move Y out of bounds - Max self.assertTrue(not utility.IsInBounds(1,200.0001, 1, customBox)) # move Y in bounds - Max self.assertTrue(utility.IsInBounds(1,200.0000, 1, customBox)) # move Y in bounds - Middle self.assertTrue(utility.IsInBounds(1,100.5000, 1, customBox)) # move Z out of bounds - Min self.assertTrue(not utility.IsInBounds(1, 1, .9999, customBox)) # move Z out of bounds - Max self.assertTrue(not utility.IsInBounds(1, 1, 200.0001, customBox)) # move Z in bounds - Max self.assertTrue(utility.IsInBounds(1, 1, 200.0000, customBox)) # move Z in bounds - Middle self.assertTrue(utility.IsInBounds(1, 1, 100.5000, customBox)) # test custom box with negative min values customBox = { "volume": { "custom_box": { "x_min": -1, "x_max": 250, "y_min": -2, "y_max": 200, "z_min": -3, "z_max": 200 } } } # move X out of bounds - Min self.assertTrue(not utility.IsInBounds(-1.0001, 1, 1, customBox)) # move X out of bounds - Max self.assertTrue(not utility.IsInBounds(250.0001, 1, 1, customBox)) # move X in bounds - Max self.assertTrue(utility.IsInBounds(250.0000, 1, 1, customBox)) # move X in bounds - Middle self.assertTrue(utility.IsInBounds(123.5000, 1, 1, customBox)) # move Y out of bounds - Min self.assertTrue(not utility.IsInBounds(1,-2.0001, 1, customBox)) # move Y out of bounds - Max self.assertTrue(not utility.IsInBounds(1,200.0001, 1, customBox)) # move Y in bounds - Max self.assertTrue(utility.IsInBounds(1,200.0000, 1, customBox)) # move Y in bounds - Middle self.assertTrue(utility.IsInBounds(1,99.0000, 1, customBox)) # move Z out of bounds - Min self.assertTrue(not utility.IsInBounds(1, 1, -3.0001, customBox)) # move Z out of bounds - Max self.assertTrue(not utility.IsInBounds(1, 1, 200.0001, customBox)) # move Z in bounds - Max self.assertTrue(utility.IsInBounds(1, 1, 200.0000, customBox)) # move Z in bounds - Middle self.assertTrue(utility.IsInBounds(1, 1, 98.5000, customBox)) # test custom box with all negative min values customBox = { "volume": { "custom_box": { "x_min": -100, "x_max": -50, "y_min": -100, "y_max": -50, "z_min": -100, "z_max": -50 } } } # test X axis # move out of bounds - Min self.assertTrue(not utility.IsInBounds(-100.0001, -100, -100, customBox)) # move out of bounds - Max self.assertTrue(not utility.IsInBounds(-49.9999, -100, -100, customBox)) # move in bounds - Max self.assertTrue(utility.IsInBounds(-50.0000, -100, -100, customBox)) # move in bounds - Middle self.assertTrue(utility.IsInBounds(-75.0000, -100, -100, customBox)) # test Y axis # move out of bounds - Min self.assertTrue(not utility.IsInBounds(-100,-100.0001, -100, customBox)) # move out of bounds - Max self.assertTrue(not utility.IsInBounds(-100,-49.9999, -100, customBox)) # move in bounds - Max self.assertTrue(utility.IsInBounds(-100,-50.0000, -100, customBox)) # move in bounds - Middle self.assertTrue(utility.IsInBounds(-100,-75.0000, -100, customBox)) # test Z axis # move out of bounds - Min self.assertTrue(not utility.IsInBounds(-100, -100, -100.0001, customBox)) # move out of bounds - Max self.assertTrue(not utility.IsInBounds(-100, -100,-49.9999, customBox)) # move in bounds - Max self.assertTrue(utility.IsInBounds(-100, -100,-50.0000, customBox)) # move in bounds - Middle self.assertTrue(utility.IsInBounds(-100, -100,-75.0000, customBox))
def test_IsInBounds(self): """Test the IsInBounds function to make sure the program will not attempt to operate after being told to move out of bounds.""" # Initial test, should return false without any coordinates self.assertTrue(not utility.IsInBounds(None, None, None, self.OctoprintPrinterProfile)) # test the origin (min), should return true self.assertTrue(utility.IsInBounds(0, 0, 0, self.OctoprintPrinterProfile)) # move X out of bounds of the min self.assertTrue(not utility.IsInBounds(-0.0001, 0, 0, self.OctoprintPrinterProfile)) # move X out of bounds of the max self.assertTrue(not utility.IsInBounds(250.0001, 0, 0, self.OctoprintPrinterProfile)) # move X to the max of bounds of the max self.assertTrue(utility.IsInBounds(250.0000, 0, 0, self.OctoprintPrinterProfile)) # move Y out of bounds of the min self.assertTrue(not utility.IsInBounds(0, -0.0001, 0, self.OctoprintPrinterProfile)) # move Y out of bounds of the max self.assertTrue(not utility.IsInBounds(0, 200.0001, 0, self.OctoprintPrinterProfile)) # move Y to the max of bounds of the max self.assertTrue(utility.IsInBounds(0, 200.0000, 0, self.OctoprintPrinterProfile)) # move Z out of bounds of the min self.assertTrue(not utility.IsInBounds(0, 0, -0.0001, self.OctoprintPrinterProfile)) # move Z out of bounds of the max self.assertTrue(not utility.IsInBounds(0, 0, 200.0001, self.OctoprintPrinterProfile)) # move Z to the max of bounds of the max self.assertTrue(utility.IsInBounds(0, 0, 200.0000, self.OctoprintPrinterProfile))
def UpdatePosition(self, boundingBox, x=None, y=None, z=None, e=None, f=None, force=False): if (f is not None): self.F = float(f) if (force): # Force the coordinates in as long as they are provided. # if (x is not None): x = float(x) x = x + self.XOffset self.X = x if (y is not None): y = float(y) y = y + self.YOffset self.Y = y if (z is not None): z = float(z) z = z + self.ZOffset self.Z = z if (e is not None): e = float(e) e = e + self.EOffset self.E = e else: # Update the previous positions if values were supplied if (x is not None and self.XHomed): x = float(x) if (self.IsRelative): if (self.X is not None): self.X += x else: self.X = x + self.XOffset if (y is not None and self.YHomed): y = float(y) if (self.IsRelative): if (self.Y is not None): self.Y += y else: self.Y = y + self.YOffset if (z is not None and self.ZHomed): z = float(z) if (self.IsRelative): if (self.Z is not None): self.Z += z else: self.Z = z + self.ZOffset if (e is not None): e = float(e) if (self.IsExtruderRelative): if (self.E is not None): self.EPrevious = self.E self.E += e else: self.EPrevious = self.E self.E = e + self.EOffset if (not utility.IsInBounds( boundingBox, x=self.X, y=self.Y, z=self.Z)): self.HasPositionError = True self.PositionError = "Position - Coordinates {0} are out of the printer area! Cannot resume position tracking until the axis is homed, or until absolute coordinates are received.".format( GetFormattedCoordinates(self.X, self.Y, self.Z, self.E)) else: self.HasPositionError = False self.PositionError = None
def CreateSnapshotGcode(self, x, y, z, f, isRelative, isExtruderRelative, extruder, zLift, savedCommand=None): self.Reset() if (x is None or y is None or z 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, y, z) self.SnapshotPositionErrors = message self.Settings.CurrentDebugProfile().LogError( "gcode.py - CreateSnapshotGcode - {0}".format(message)) return None self.FOriginal = f self.FCurrent = f self.RetractedBySnapshotStartGcode = False self.RetractedLength = 0 self.ZhopBySnapshotStartGcode = False self.ZLift = zLift self.IsRelativeOriginal = isRelative self.IsRelativeCurrent = isRelative self.IsExtruderRelativeOriginal = isExtruderRelative self.IsExtruderRelativeCurrent = isExtruderRelative newSnapshotGcode = SnapshotGcode(self.IsTestMode) # retract if necessary # Note that if IsRetractedStart is true, that means the printer is now retracted. IsRetracted will be false because we've undone the previous position update. if (self.Snapshot.retract_before_move and not (extruder.IsRetracted() or extruder.IsRetractingStart())): if (not self.IsExtruderRelativeCurrent): newSnapshotGcode.Append( self.GetSetExtruderRelativePositionGcode()) self.IsExtruderRelativeCurrent = True self.AppendFeedrateGcode(newSnapshotGcode, self.Printer.retract_speed) retractedLength = extruder.LengthToRetract() if (retractedLength > 0): newSnapshotGcode.Append(self.GetRetractGcode(retractedLength)) self.RetractedLength = retractedLength self.RetractedBySnapshotStartGcode = True # Can we hop or is the print too tall? # todo: detect zhop and only zhop if we are not currently hopping. canZHop = self.Printer.z_hop > 0 and utility.IsInBounds( self.BoundingBox, z=z + self.Printer.z_hop) # if we can ZHop, do if (canZHop and self.ZLift > 0): if (not self.IsRelativeCurrent): # must be in relative mode newSnapshotGcode.Append(self.GetSetRelativePositionGcode()) self.IsRelativeCurrent = True self.AppendFeedrateGcode(newSnapshotGcode, self.Printer.z_hop_speed) newSnapshotGcode.Append(self.GetRelativeZLiftGcode(self.ZLift)) self.ZhopBySnapshotStartGcode = True # Wait for current moves to finish before requesting the startgcodeposition #newSnapshotGcode.Append(self.GetWaitForCurrentMovesToFinishGcode()) # Get the final position after the saved command. When we get this position we'll know it's time to resume the print. #newSnapshotGcode.Append(self.GetPositionGcode()) # Log the commands #self.Settings.CurrentDebugProfile().LogSnapshotGcode("Snapshot Start Gcode") #for str in newSnapshotGcode.GcodeCommands: # self.Settings.CurrentDebugProfile().LogSnapshotGcode(" {0}".format(str)) ### End start gcode # Create code to move from the current extruder position to the snapshot position # get the X and Y coordinates of the snapshot snapshotPosition = self.GetSnapshotPosition(x, y) newSnapshotGcode.X = snapshotPosition["X"] newSnapshotGcode.Y = snapshotPosition["Y"] if (newSnapshotGcode.X is None or newSnapshotGcode.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 newSnapshotGcode.Append(self.GetSetAbsolutePositionGcode()) self.IsRelativeCurrent = False ## speed change - Set to movement speed IF we have specified one self.AppendFeedrateGcode(newSnapshotGcode, self.Printer.movement_speed) # Move to Snapshot Position newSnapshotGcode.Append( self.GetMoveGcode(newSnapshotGcode.X, newSnapshotGcode.Y)) # Wait for current moves to finish before requesting the position newSnapshotGcode.Append(self.GetWaitForCurrentMovesToFinishGcode()) # Get the final position after moving. When we get a response from the, we'll know that the snapshot is ready to be taken newSnapshotGcode.Append(self.GetPositionGcode()) # mark the snapshot command index newSnapshotGcode.SetSnapshotIndex() # create return gcode #record our previous position for posterity newSnapshotGcode.ReturnX = x newSnapshotGcode.ReturnY = y newSnapshotGcode.ReturnZ = z #Move back to previous position - make sure we're in absolute mode for this (hint: we already are right now) #if(self.IsRelativeCurrent): # newSnapshotGcode.Append(self.GetSetAbsolutePositionGcode()) # self.IsRelativeCurrent = False if (x is not None and y is not None): newSnapshotGcode.Append(self.GetMoveGcode(x, y)) # If we zhopped in the beginning, lower z if (self.ZhopBySnapshotStartGcode): if (not self.IsRelativeCurrent): newSnapshotGcode.Append(self.GetSetRelativePositionGcode()) self.IsRelativeCurrent = True self.AppendFeedrateGcode(newSnapshotGcode, self.Printer.z_hop_speed) newSnapshotGcode.Append(self.GetRelativeZLowerGcode(self.ZLift)) # detract if (self.RetractedBySnapshotStartGcode): if (not self.IsExtruderRelativeCurrent): newSnapshotGcode.Append.GetSetExtruderRelativePositionGcode() self.IsExtruderRelativeCurrent = True self.AppendFeedrateGcode(newSnapshotGcode, self.Printer.detract_speed) if (self.RetractedLength > 0): newSnapshotGcode.Append( self.GetDetractGcode(self.RetractedLength)) # reset the coordinate systems for the extruder and axis if (self.IsRelativeOriginal != self.IsRelativeCurrent): if (self.IsRelativeCurrent): newSnapshotGcode.Append(self.GetSetAbsolutePositionGcode()) else: newSnapshotGcode.Append(self.GetSetRelativePositionGcode()) self.IsRelativeCurrent = self.IsRelativeOriginal if (self.IsExtruderRelativeOriginal != self.IsExtruderRelativeCurrent): if (self.IsExtruderRelativeOriginal): newSnapshotGcode.Append( self.GetSetExtruderRelativePositionGcode()) else: newSnapshotGcode.Append( self.GetSetExtruderAbslutePositionGcode()) # Make sure we return to the original feedrate self.AppendFeedrateGcode(newSnapshotGcode, self.FOriginal) # What the hell was this for?! #newSnapshotGcode.GcodeCommands[-1] = "{0}".format(newSnapshotGcode.GcodeCommands[-1]) # add the saved command, if there is one if (savedCommand is not None): newSnapshotGcode.Append(savedCommand) # Wait for current moves to finish before requesting the save command position newSnapshotGcode.Append(self.GetWaitForCurrentMovesToFinishGcode()) # Get the final position after the saved command. When we get this position we'll know it's time to resume the print. newSnapshotGcode.Append(self.GetPositionGcode()) self.Settings.CurrentDebugProfile().LogSnapshotGcode( "Snapshot Gcode - SnapshotCommandIndex:{0}, EndIndex{1}, Gcode:". format(newSnapshotGcode.SnapshotIndex, newSnapshotGcode.EndIndex())) for str in newSnapshotGcode.GcodeCommands: self.Settings.CurrentDebugProfile().LogSnapshotGcode( " {0}".format(str)) self.Settings.CurrentDebugProfile().LogSnapshotPosition( "Snapshot Position: (x:{0:f},y:{1:f})".format( newSnapshotGcode.X, newSnapshotGcode.Y)) self.Settings.CurrentDebugProfile().LogSnapshotPositionReturn( "Return Position: (x:{0:f},y:{1:f})".format( newSnapshotGcode.ReturnX, newSnapshotGcode.ReturnY)) return newSnapshotGcode