def _update_state(self, state, state_previous): retraction_length = utility.round_to(state.RetractionLength, self.PrinterTolerance) detraction_length = utility.round_to(state.DetractionLength, self.PrinterTolerance) extrusion_length = utility.round_to(state.ExtrusionLength, self.PrinterTolerance) previous_retraction_length = utility.round_to(state_previous.RetractionLength, self.PrinterTolerance) previous_detraction_length = utility.round_to(state_previous.DetractionLength, self.PrinterTolerance) state.IsExtrudingStart = True if extrusion_length > 0 and state_previous.ExtrusionLength == 0 else False state.IsExtruding = True if extrusion_length > 0 else False state.IsPrimed = True if extrusion_length == 0 and retraction_length == 0 else False state.IsRetractingStart = True if previous_retraction_length == 0 and retraction_length > 0 else False state.IsRetracting = True if retraction_length > previous_retraction_length else False state.IsPartiallyRetracted = True if (0 < retraction_length < self.PrinterRetractionLength) else False state.IsRetracted = True if retraction_length >= self.PrinterRetractionLength else False state.IsDetractingStart = True if detraction_length > 0 and previous_detraction_length == 0 else False state.IsDetracting = True if detraction_length > previous_detraction_length else False state.IsDetracted = True if previous_retraction_length > 0 and retraction_length == 0 else False if not state.is_state_equal(state_previous): state.HasChanged = True else: state.HasChanged = False if state.HasChanged: message = ( "Extruder Changed: E:{0}, Retraction:{1} IsExtruding:{2}-{3}, " "IsExtrudingStart:{4}-{5}, IsPrimed:{6}-{7}, IsRetractingStart:{8}-{9}, " "IsRetracting:{10}-{11}, IsPartiallyRetracted:{12}-{13}, " "IsRetracted:{14}-{15}, IsDetractingStart:{16}-{17}, " "IsDetracting:{18}-{19}, IsDetracted:{20}-{21}" ).format( state.E, state.RetractionLength, state_previous.IsExtruding, state.IsExtruding, state_previous.IsExtrudingStart, state.IsExtrudingStart, state_previous.IsPrimed, state.IsPrimed, state_previous.IsRetractingStart, state.IsRetractingStart, state_previous.IsRetracting, state.IsRetracting, state_previous.IsPartiallyRetracted, state.IsPartiallyRetracted, state_previous.IsRetracted, state.IsRetracted, state_previous.IsDetractingStart, state.IsDetractingStart, state_previous.IsDetracting, state.IsDetracting, state_previous.IsDetracted, state.IsDetracted ) self.Settings.current_debug_profile().log_extruder_change(message)
def _calculate_fps(self): self._fps = self._rendering.fps if self._rendering.fps_calculation_type == 'duration': self._fps = utility.round_to( float(self._imageCount) / float(self._rendering.run_length_seconds), 1) if self._fps > self._rendering.max_fps: self._fps = self._rendering.max_fps elif self._fps < self._rendering.min_fps: self._fps = self._rendering.min_fps message = ("FPS Calculation Type:{0}, Fps:{1}, NumFrames:{2}, " "DurationSeconds:{3}, Max FPS:{4}, Min FPS:{5}").format( self._rendering.fps_calculation_type, self._fps, self._imageCount, self._rendering.run_length_seconds, self._rendering.max_fps, self._rendering.min_fps) self._debug.log_render_start(message) else: message = "FPS Calculation Type:{0}, Fps:{0}" message = message.format(self._rendering.fps_calculation_type, self._fps) self._debug.log_render_start(message) # Add the FPS to the output tokens self._output_tokens["FPS"] = "{0}".format(int(math.ceil(self._fps)))
def Update(self, eRelative): if (eRelative is None): return e = float(eRelative) if (e is None or abs(e) < utility.FLOAT_MATH_EQUALITY_RANGE): e = 0.0 state = None previousState = None numStates = len(self.StateHistory) if (numStates > 0): state = ExtruderState(state=self.StateHistory[0]) previousState = ExtruderState(state=self.StateHistory[0]) else: state = ExtruderState() previousState = ExtruderState() state.E = e # Update RetractionLength and ExtrusionLength state.RetractionLength -= e state.RetractionLength = utility.round_to(state.RetractionLength, self.PrinterTolerance) if (state.RetractionLength <= utility.FLOAT_MATH_EQUALITY_RANGE): # we can use the negative retraction length to calculate our extrusion length! state.ExtrusionLength = abs(state.RetractionLength) # set the retraction length to 0 since we are etruding state.RetractionLength = 0 else: state.ExtrusionLength = 0 # Update extrusion length state.ExtrusionLengthTotal += state.ExtrusionLength # calculate detraction length if (previousState.RetractionLength > state.RetractionLength): state.DetractionLength = utility.round_to( previousState.RetractionLength - state.RetractionLength, self.PrinterTolerance) else: state.DetractionLength = 0 # round our lengths to the nearest .05mm to avoid some floating point math errors self._UpdateState(state, previousState) # Add the current position, remove positions if we have more than 5 from the end self.AddState(state)
def DistanceToZLift(self, index=0): if (len(self.Positions) > index): pos = self.Positions[index] currentLift = utility.round_to(pos.Z - pos.Height, self.PrinterTolerance) if (currentLift < self.Printer.z_hop): return self.Printer.z_hop - currentLift return 0 return None
def LengthToRetract(self): if (len(self.StateHistory) > 0): retractLength = utility.round_to( self.PrinterRetractionLength - self.StateHistory[0].RetractionLength, self.PrinterTolerance) if (retractLength <= 0): retractLength = 0 return retractLength return self.PrinterRetractionLength
def distance_to_zlift(self, z_hop, restrict_lift_height=True): amount_to_lift = (None if self.z is None or self.last_extrusion_height is None else z_hop - (self.z - self.last_extrusion_height)) if restrict_lift_height: if amount_to_lift < utility.FLOAT_MATH_EQUALITY_RANGE: return 0 elif amount_to_lift > z_hop: return z_hop return utility.round_to(amount_to_lift, utility.FLOAT_MATH_EQUALITY_RANGE)
def _calculateFps(self): self._fps = self._rendering.fps if(self._rendering.fps_calculation_type == 'duration'): self._fps = utility.round_to(float(self._imageCount)/float(self._rendering.run_length_seconds),1) if(self._fps > self._rendering.max_fps): self._fps = self._rendering.max_fps elif(self._fps < self._rendering.min_fps): self._fps = self._rendering.min_fps self._debug.LogRenderStart("FPS Calculation Type:{0}, Fps:{1}, NumFrames:{2}, DurationSeconds:{3}, Max FPS:{4}, Min FPS:{5}".format(self._rendering.fps_calculation_type,self._fps, self._imageCount,self._rendering.run_length_seconds,self._rendering.max_fps,self._rendering.min_fps)) else: self._debug.LogRenderStart("FPS Calculation Type:{0}, Fps:{0}".format(self._rendering.fps_calculation_type,self._fps))
def IsPositionEqual(self, pos, tolerance): if (pos.X is not None and utility.round_to(pos.X, tolerance) == utility.round_to( self.X, tolerance) and pos.Y is not None and utility.round_to(pos.Y, tolerance) == utility.round_to( self.Y, tolerance) and pos.Z is not None and utility.round_to(pos.Z, tolerance) == utility.round_to( self.Z, tolerance)): return True return False
def is_position_equal(self, pos, tolerance): if tolerance == 0: return (pos.X is not None and self.X is not None and pos.X == self.X and pos.Y is not None and self.Y is not None and pos.Y == self.Y and pos.Z is not None and self.Z is not None and pos.Z == self.Z) elif (pos.X is not None and self.X is not None and utility.round_to( pos.X, tolerance) == utility.round_to(self.X, tolerance) and pos.Y is not None and self.Y is not None and utility.round_to(pos.Y, tolerance) == utility.round_to( self.Y, tolerance) and pos.Z is not None and self.Z is not None and utility.round_to( pos.Z, tolerance) == utility.round_to(self.Z, tolerance)): return True return False
def IsStateEqual(self, pos, tolerance): if (self.XHomed == pos.XHomed and self.YHomed == pos.YHomed and self.ZHomed == pos.ZHomed and self.IsLayerChange == pos.IsLayerChange and self.IsHeightChange == pos.IsHeightChange and self.IsZHop == pos.IsZHop and self.IsRelative == pos.IsRelative and self.IsExtruderRelative == pos.IsExtruderRelative and utility.round_to(pos.Layer, tolerance) != utility.round_to( self.Layer, tolerance) and utility.round_to(pos.Height, tolerance) != utility.round_to(self.Height, tolerance) and utility.round_to(pos.LastExtrusionHeight, tolerance) != utility.round_to(self.LastExtrusionHeight, tolerance) and self.HasPositionError == pos.HasPositionError and self.PositionError == pos.PositionError and self.HasReceivedHomeCommand == pos.HasReceivedHomeCommand): return True return False
def is_state_equal(self, pos, tolerance): if (self.XHomed == pos.XHomed and self.YHomed == pos.YHomed and self.ZHomed == pos.ZHomed and self.IsLayerChange == pos.IsLayerChange and self.IsHeightChange == pos.IsHeightChange and self.IsZHop == pos.IsZHop and self.IsRelative == pos.IsRelative and self.IsExtruderRelative == pos.IsExtruderRelative and utility.round_to(pos.Layer, tolerance) != utility.round_to( self.Layer, tolerance) and utility.round_to(pos.Height, tolerance) != utility.round_to(self.Height, tolerance) and utility.round_to(pos.LastExtrusionHeight, tolerance) != utility.round_to(self.LastExtrusionHeight, tolerance) and self.IsPrimed == pos.IsPrimed and self.IsInPosition == pos.IsInPosition and self.InPathPosition == Pos.InPathPosition and self.HasPositionError == pos.HasPositionError and self.PositionError == pos.PositionError and self.HasReceivedHomeCommand == pos.HasReceivedHomeCommand and self.IsTravelOnly == pos.IsTravelOnly): return True return False
def update(self, gcode): cmd = self.Commands.get_command(gcode) # a new position pos = None previous_pos = None num_positions = len(self.Positions) if num_positions > 0: pos = Pos(self.Printer, self.OctoprintPrinterProfile, self.Positions[0]) previous_pos = Pos(self.Printer, self.OctoprintPrinterProfile, self.Positions[0]) if pos is None: pos = Pos(self.Printer, self.OctoprintPrinterProfile) if previous_pos is None: previous_pos = Pos(self.Printer, self.OctoprintPrinterProfile) # reset the current position state (copied from the previous position, # or a # new position) pos.reset_state() # set the pos gcode cmd pos.GCode = gcode # apply the cmd to the position tracker # TODO: this should NOT be an else/if structure anymore.. Simplify if cmd is not None: if cmd.Command in self.Commands.CommandsRequireMetric and not pos.IsMetric: pos.HasPositionError = True pos.PositionError = "Units are not metric. Unable to continue print." elif cmd.Command in ["G0", "G1"]: # Movement if cmd.parse(): self.Settings.current_debug_profile( ).log_position_command_received("Received {0}".format( cmd.Name)) x = cmd.Parameters["X"].Value y = cmd.Parameters["Y"].Value z = cmd.Parameters["Z"].Value e = cmd.Parameters["E"].Value f = cmd.Parameters["F"].Value if x is not None or y is not None or z is not None or f is not None: if pos.IsRelative is not None: if pos.HasPositionError and not pos.IsRelative: pos.HasPositionError = False pos.PositionError = "" pos.update_position(self.BoundingBox, x, y, z, e=None, f=f) else: self.Settings.current_debug_profile( ).log_position_command_received( "Position - Unable to update the X/Y/Z axis position, the axis mode (" "relative/absolute) has not been explicitly set via G90/G91. " ) if e is not None: if pos.IsExtruderRelative is not None: if pos.HasPositionError and not pos.IsExtruderRelative: pos.HasPositionError = False pos.PositionError = "" pos.update_position(self.BoundingBox, x=None, y=None, z=None, e=e, f=None) else: self.Settings.current_debug_profile().log_error( "Position - Unable to update the extruder position, the extruder mode (" "relative/absolute) has been selected (absolute/relative). " ) message = "Position Change - {0} - {1} Move From(X:{2},Y:{3},Z:{4},E:{5}) - To(X:{6},Y:{7},Z:{8}," \ "E:{9}) " if previous_pos is None: message = message.format( gcode, "Relative" if pos.IsRelative else "Absolute", "None", "None", "None", "None", pos.X, pos.Y, pos.Z, pos.E) else: message = message.format( gcode, "Relative" if pos.IsRelative else "Absolute", previous_pos.X, previous_pos.Y, previous_pos.Z, previous_pos.E, pos.X, pos.Y, pos.Z, pos.E) self.Settings.current_debug_profile().log_position_change( message) else: error_message = "Unable to parse the gcode command: {0}".format( gcode) pos.HasPositionError = True # Todo: We need to end the timelapse if we get here #pos.X = None #pos.Y = None #pos.Z = None #pos.E = None# #pos.F = None pos.PositionError = "Unable to parse the gcode command" self.Settings.current_debug_profile().log_error( "Position - {0}".format(error_message)) elif cmd.Command == "G20": # change units to inches if pos.IsMetric is None or pos.IsMetric: self.Settings.current_debug_profile( ).log_position_command_received( "Received G20 - Switching units to inches.") pos.IsMetric = False else: self.Settings.current_debug_profile( ).log_position_command_received( "Received G20 - Already in inches.") elif cmd.Command == "G21": # change units to millimeters if pos.IsMetric is None or not pos.IsMetric: self.Settings.current_debug_profile( ).log_position_command_received( "Received G21 - Switching units to millimeters.") pos.IsMetric = True else: self.Settings.current_debug_profile( ).log_position_command_received( "Received G21 - Already in millimeters.") elif cmd.Command == "G28": # Home if cmd.parse(): pos.HasReceivedHomeCommand = True x = cmd.Parameters["X"].Value y = cmd.Parameters["Y"].Value z = cmd.Parameters["Z"].Value # ignore the W parameter, it's used in Prusa firmware to indicate a home without mesh bed leveling # w = cmd.Parameters["W"].Value x_homed = False y_homed = False z_homed = False if x is not None: x_homed = True if y is not None: y_homed = True if z is not None: z_homed = True # if there are no x,y or z parameters, we're homing all axes if x is None and y is None and z is None: x_homed = True y_homed = True z_homed = True home_strings = [] if x_homed: pos.XHomed = True pos.X = self.Origin[ "X"] if not self.Printer.auto_detect_position else None if pos.X is None: home_strings.append("Homing X to Unknown Origin.") else: home_strings.append("Homing X to {0}.".format( get_formatted_coordinate(pos.X))) if y_homed: pos.YHomed = True pos.Y = self.Origin[ "Y"] if not self.Printer.auto_detect_position else None if pos.Y is None: home_strings.append("Homing Y to Unknown Origin.") else: home_strings.append("Homing Y to {0}.".format( get_formatted_coordinate(pos.Y))) if z_homed: pos.ZHomed = True pos.Z = self.Origin[ "Z"] if not self.Printer.auto_detect_position else None if pos.Z is None: home_strings.append("Homing Z to Unknown Origin.") else: home_strings.append("Homing Z to {0}.".format( get_formatted_coordinate(pos.Z))) self.Settings.current_debug_profile( ).log_position_command_received("Received G28 - ".format( " ".join(home_strings))) pos.HasPositionError = False pos.PositionError = None # we must do this in case we have more than one home command previous_pos = Pos(self.Printer, self.OctoprintPrinterProfile, pos) else: self.Settings.current_debug_profile().log_error( "Position - Unable to parse the Gcode:{0}".format( gcode)) elif cmd.Command == "G90": # change x,y,z to absolute if pos.IsRelative is None or pos.IsRelative: self.Settings.current_debug_profile( ).log_position_command_received( "Received G90 - Switching to absolute x,y,z coordinates." ) pos.IsRelative = False else: self.Settings.current_debug_profile( ).log_position_command_received( "Received G90 - Already using absolute x,y,z coordinates." ) # for some firmwares we need to switch the extruder to # absolute # coordinates # as well if self.G90InfluencesExtruder: if pos.IsExtruderRelative is None or pos.IsExtruderRelative: self.Settings.current_debug_profile( ).log_position_command_received( "Received G90 - Switching to absolute extruder coordinates" ) pos.IsExtruderRelative = False else: self.Settings.current_debug_profile( ).log_position_command_received( "Received G90 - Already using absolute extruder coordinates" ) elif cmd.Command == "G91": # change x,y,z to relative if pos.IsRelative is None or not pos.IsRelative: self.Settings.current_debug_profile( ).log_position_command_received( "Received G91 - Switching to relative x,y,z coordinates" ) pos.IsRelative = True else: self.Settings.current_debug_profile( ).log_position_command_received( "Received G91 - Already using relative x,y,z coordinates" ) # for some firmwares we need to switch the extruder to # absolute # coordinates # as well if self.G90InfluencesExtruder: if pos.IsExtruderRelative is None or not pos.IsExtruderRelative: self.Settings.current_debug_profile( ).log_position_command_received( "Received G91 - Switching to relative extruder coordinates" ) pos.IsExtruderRelative = True else: self.Settings.current_debug_profile( ).log_position_command_received( "Received G91 - Already using relative extruder coordinates" ) elif cmd.Command == "M83": # Extruder - Set Relative if pos.IsExtruderRelative is None or not pos.IsExtruderRelative: self.Settings.current_debug_profile( ).log_position_command_received( "Received M83 - Switching Extruder to Relative Coordinates" ) pos.IsExtruderRelative = True elif cmd.Command == "M82": # Extruder - Set Absolute if pos.IsExtruderRelative is None or pos.IsExtruderRelative: self.Settings.current_debug_profile( ).log_position_command_received( "Received M82 - Switching Extruder to Absolute Coordinates" ) pos.IsExtruderRelative = False elif cmd.Command == "G92": # Set Position (offset) if cmd.parse(): x = cmd.Parameters["X"].Value y = cmd.Parameters["Y"].Value z = cmd.Parameters["Z"].Value e = cmd.Parameters["E"].Value if x is None and y is None and z is None and e is None: pos.XOffset = pos.X pos.YOffset = pos.Y pos.ZOffset = pos.Z pos.EOffset = pos.E # set the offsets if they are provided if x is not None and pos.X is not None and pos.XHomed: pos.XOffset = pos.X - utility.get_float(x, 0) if y is not None and pos.Y is not None and pos.YHomed: pos.YOffset = pos.Y - utility.get_float(y, 0) if z is not None and pos.Z is not None and pos.ZHomed: pos.ZOffset = pos.Z - utility.get_float(z, 0) if e is not None and pos.E is not None: pos.EOffset = pos.E - utility.get_float(e, 0) self.Settings.current_debug_profile( ).log_position_command_received( "Received G92 - Set Position. Command:{0}, XOffset:{1}, " + "YOffset:{2}, ZOffset:{3}, EOffset:{4}".format( gcode, pos.XOffset, pos.YOffset, pos.ZOffset, pos.EOffset)) else: self.Settings.current_debug_profile().log_error( "Position - Unable to parse the Gcode:{0}".format( gcode)) ######################################## # Update the extruder monitor. self.Extruder.update(self.e_relative_pos(pos)) ######################################## # If we have a homed axis, detect changes. ######################################## # for now we're going to ignore extruder changes and just run calculations every time. # has_extruder_changed = self.Extruder.HasChanged() pos.HasPositionChanged = not pos.is_position_equal(previous_pos, 0) pos.HasStateChanged = not pos.is_state_equal(previous_pos, self.PrinterTolerance) if pos.has_homed_position() and previous_pos.has_homed_position(): # if (hasExtruderChanged or pos.HasPositionChanged): if pos.HasPositionChanged: if self.HasRestrictedPosition: _is_in_position, _intersections = self.calculate_path_intersections( self.Snapshot.position_restrictions, pos.X, pos.Y, previous_pos.X, previous_pos.Y) if _is_in_position: pos.IsInPosition = _is_in_position else: pos.IsInPosition = False pos.InPathPosition = _intersections else: pos.IsInPosition = True # calculate LastExtrusionHeight and Height if self.Extruder.is_extruding(): pos.LastExtrusionHeight = pos.Z # see if we have primed yet if self.Printer.priming_height > 0: if not pos.IsPrimed and pos.LastExtrusionHeight < self.Printer.priming_height: pos.IsPrimed = True else: # if we have no priming height set, just set IsPrimed = true. pos.IsPrimed = True # make sure we are primed before calculating height/layers if pos.IsPrimed: if pos.Height is None or utility.round_to( pos.Z, self.PrinterTolerance) > previous_pos.Height: pos.Height = utility.round_to(pos.Z, self.PrinterTolerance) self.Settings.current_debug_profile( ).log_position_height_change( "Position - Reached New Height:{0}.".format( pos.Height)) # calculate layer change if (utility.round_to(self.z_delta(pos), self.PrinterTolerance) > 0 or pos.Layer == 0): pos.IsLayerChange = True pos.Layer += 1 self.Settings.current_debug_profile( ).log_position_layer_change( "Position - Layer:{0}.".format(pos.Layer)) else: pos.IsLayerChange = False # Calculate ZHop based on last extrusion height if pos.LastExtrusionHeight is not None: # calculate lift, taking into account floating point # rounding lift = pos.distance_to_zlift(self.Printer.z_hop) # todo: replace rounding with a call to is close or greater than utility function lift = utility.round_to(lift, self.PrinterTolerance) is_lifted = lift >= self.Printer.z_hop and ( not self.Extruder.is_extruding() or self.Extruder.is_extruding_start()) if is_lifted or self.Printer.z_hop == 0: pos.IsZHop = True if pos.IsZHop and self.Printer.z_hop > 0: self.Settings.current_debug_profile().log_position_zhop( "Position - Zhop:{0}".format(self.Printer.z_hop)) self.Positions.appendleft(pos)
def Update(self, gcode): command = self.Commands.GetCommand(gcode) # a new position pos = None previousPos = None numPositions = len(self.Positions) if (numPositions > 0): pos = Pos(self.OctoprintPrinterProfile, self.Positions[0]) if (numPositions > 1): previousPos = Pos(self.OctoprintPrinterProfile, self.Positions[1]) if (pos is None): pos = Pos(self.OctoprintPrinterProfile) if (previousPos is None): previousPos = Pos(self.OctoprintPrinterProfile) # reset the current position state (copied from the previous position, or a new position) pos.ResetState() # set the pos gcode command pos.GCode = gcode # apply the command to the position tracker if (command is not None): # I'm currently too lazy to keep this DRY # TODO: Make DRY if (command.Command in ["G0", "G1"]): #Movement if (command.Parse()): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived("Received {0}".format( command.Name)) x = command.Parameters["X"].Value y = command.Parameters["Y"].Value z = command.Parameters["Z"].Value e = command.Parameters["E"].Value f = command.Parameters["F"].Value if (x is not None or y is not None or z is not None or f is not None): if (pos.HasPositionError and not pos.IsRelative): pos.HasPositionError = False pos.PositionError = "" pos.UpdatePosition(self.BoundingBox, x, y, z, e=None, f=f) if (e is not None): if (pos.IsExtruderRelative is not None): if (pos.HasPositionError and not pos.IsExtruderRelative): pos.HasPositionError = False pos.PositionError = "" pos.UpdatePosition(self.BoundingBox, x=None, y=None, z=None, e=e, f=None) else: self.Settings.CurrentDebugProfile().LogError( "Position - Unable to update the extruder position, no extruder coordinate system has been selected (absolute/relative)." ) message = "Position Change - {0} - {1} Move From(X:{2},Y:{3},Z:{4},E:{5}) - To(X:{6},Y:{7},Z:{8},E:{9})" if (previousPos is None): message = message.format( gcode, "Relative" if pos.IsRelative else "Absolute", "None", "None", "None", "None", pos.X, pos.Y, pos.Z, pos.E) else: message = message.format( gcode, "Relative" if pos.IsRelative else "Absolute", previousPos.X, previousPos.Y, previousPos.Z, previousPos.E, pos.X, pos.Y, pos.Z, pos.E) self.Settings.CurrentDebugProfile().LogPositionChange( message) else: self.Settings.CurrentDebugProfile().LogError( "Position - Unable to parse the gcode command: {0}". format(gcode)) elif (command.Command == "G28"): # Home if (command.Parse()): pos.HasReceivedHomeCommand = True x = command.Parameters["X"].Value y = command.Parameters["Y"].Value z = command.Parameters["Z"].Value xHomed = False yHomed = False zHomed = False if (x is not None): xHomed = True if (y is not None): yHomed = True if (z is not None): zHomed = True if (x is None and y is None and z is None): xHomed = True yHomed = True zHomed = True homeStrings = [] if (xHomed): pos.XHomed = True pos.X = self.Origin[ "X"] if not self.Printer.auto_detect_origin else None if (pos.X is None): homeStrings.append("Homing X to Unknown Origin.") else: homeStrings.append("Homing X to {0}.".format( GetFormattedCoordinate(pos.X))) zHomedString = "" if (yHomed): pos.YHomed = True pos.Y = self.Origin[ "Y"] if not self.Printer.auto_detect_origin else None if (pos.Y is None): homeStrings.append("Homing Y to Unknown Origin.") else: homeStrings.append("Homing Y to {0}.".format( GetFormattedCoordinate(pos.Y))) xHomedString = "" if (zHomed): pos.ZHomed = True pos.Z = self.Origin[ "Z"] if not self.Printer.auto_detect_origin else None if (pos.Z is None): homeStrings.append("Homing Z to Unknown Origin.") else: homeStrings.append("Homing Z to {0}.".format( GetFormattedCoordinate(pos.Z))) self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived("Received G28 - ".format( " ".join(homeStrings))) pos.HasPositionError = False pos.PositionError = None else: self.Settings.CurrentDebugProfile().LogError( "Position - Unable to parse the Gcode:{0}".format( gcode)) elif (command.Command == "G90"): # change x,y,z to absolute if (pos.IsRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G90 - Switching to absolute x,y,z coordinates." ) pos.IsRelative = False else: self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G90 - Already using absolute x,y,z coordinates." ) # for some firmwares we need to switch the extruder to absolute coordinates as well if (self.G90InfluencesExtruder): if (pos.IsExtruderRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G90 - Switching to absolute extruder coordinates" ) pos.IsExtruderRelative = False else: self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G90 - Already using absolute extruder coordinates" ) elif (command.Command == "G91"): # change x,y,z to relative if (not pos.IsRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G91 - Switching to relative x,y,z coordinates" ) pos.IsRelative = True else: self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G91 - Already using relative x,y,z coordinates" ) # for some firmwares we need to switch the extruder to absolute coordinates as well if (self.G90InfluencesExtruder): if (not pos.IsExtruderRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G91 - Switching to relative extruder coordinates" ) pos.IsExtruderRelative = True else: self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G91 - Already using relative extruder coordinates" ) elif (command.Command == "M83"): # Extruder - Set Relative if (pos.IsExtruderRelative is None or not pos.IsExtruderRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received M83 - Switching Extruder to Relative Coordinates" ) pos.IsExtruderRelative = True elif (command.Command == "M82"): # Extruder - Set Absolute if (pos.IsExtruderRelative is None or pos.IsExtruderRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received M82 - Switching Extruder to Absolute Coordinates" ) pos.IsExtruderRelative = False elif (command.Command == "G92"): # Set Position (offset) if (command.Parse()): previousRelativeValue = pos.IsRelative previousExtruderRelativeValue = pos.IsExtruderRelative x = command.Parameters["X"].Value y = command.Parameters["Y"].Value z = command.Parameters["Z"].Value e = command.Parameters["E"].Value resetAll = False if (x is None and y is None and z is None and e is None): pos.XOffset = pos.X pos.YOffset = pos.Y pos.ZOffset = pos.Z pos.EOffset = pos.E # set the offsets if they are provided if (x is not None and pos.X is not None and pos.XHomed): pos.XOffset = pos.X - utility.getfloat(x, 0) if (y is not None and pos.Y is not None and pos.YHomed): pos.YOffset = pos.Y - utility.getfloat(y, 0) if (z is not None and pos.Z is not None and pos.ZHomed): pos.ZOffset = pos.Z - utility.getfloat(z, 0) if (e is not None and pos.E is not None): pos.EOffset = pos.E - utility.getfloat(e, 0) self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G92 - Set Position. Command:{0}, XOffset:{1}, YOffset:{2}, ZOffset:{3}, EOffset:{4}" .format(gcode, pos.XOffset, pos.YOffset, pos.ZOffset, pos.EOffset)) else: self.Settings.CurrentDebugProfile().LogError( "Position - Unable to parse the Gcode:{0}".format( gcode)) ######################################## # Update the extruder monitor. self.Extruder.Update(self.ERelative(pos)) ######################################## # If we have a homed axis, detect changes. ######################################## hasExtruderChanged = self.Extruder.HasChanged() pos.HasPositionChanged = not pos.IsPositionEqual( previousPos, self.PrinterTolerance) pos.HasStateChanged = not pos.IsStateEqual(previousPos, self.PrinterTolerance) if (self.HasHomedPosition()): if (hasExtruderChanged or pos.HasPositionChanged): # calculate LastExtrusionHeight and Height if (self.Extruder.IsExtruding()): pos.LastExtrusionHeight = pos.Z if (pos.Height is None or utility.round_to(pos.Z, self.PrinterTolerance) > previousPos.Height): pos.Height = utility.round_to( pos.Z, self.PrinterTolerance) self.Settings.CurrentDebugProfile( ).LogPositionHeightChange( "Position - Reached New Height:{0}.".format( pos.Height)) # calculate layer change if (utility.round_to(self.ZDelta(pos), self.PrinterTolerance) > 0 or pos.Layer == 0): pos.IsLayerChange = True pos.Layer += 1 self.Settings.CurrentDebugProfile( ).LogPositionLayerChange( "Position - Layer:{0}.".format(pos.Layer)) else: pos.IsLayerChange = False # Calculate ZHop based on last extrusion height if (pos.LastExtrusionHeight is not None): # calculate lift, taking into account floating point rounding lift = utility.round_to( pos.Z - pos.LastExtrusionHeight, self.PrinterTolerance) if (lift >= self.Printer.z_hop): lift = self.Printer.z_hop isLifted = self.Printer.z_hop > 0.0 and lift >= self.Printer.z_hop and ( not self.Extruder.IsExtruding() or self.Extruder.IsExtrudingStart()) if (isLifted): pos.IsZHop = True if (pos.IsZHop): self.Settings.CurrentDebugProfile().LogPositionZHop( "Position - Zhop:{0}".format(self.Printer.z_hop)) # Add the current position, remove positions if we have more than 5 from the end self.Positions.insert(0, pos) while (len(self.Positions) > 5): del self.Positions[5]
def Update(self, gcode): # reset state variables self.IsLayerChange = False self.HasPositionChanged = False command = self.Commands.GetCommand(gcode) # a new position pos = None previousPos = None numPositions = len(self.Positions) if (numPositions > 0): pos = Pos(self.OctoprintPrinterProfile, self.Positions[0]) if (numPositions > 1): previousPos = Pos(self.OctoprintPrinterProfile, self.Positions[1]) if (pos is None): pos = Pos(self.OctoprintPrinterProfile) if (previousPos is None): previousPos = Pos(self.OctoprintPrinterProfile) # Movement detected, set the previous values # disect the gcode and use it to update our position if (pos.IsZHopStart): pos.IsZHop = True elif (pos.IsZHopCompleting): pos.IsZHop = False pos.IsZHopCompleting = False pos.IsZHopStart = False # apply the command to the position tracker if (command is not None): if (command.Command in ["G0", "G1"]): #Movement if (command.Parse()): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived("Received {0}".format( command.Name)) x = command.Parameters["X"].Value y = command.Parameters["Y"].Value z = command.Parameters["Z"].Value e = command.Parameters["E"].Value f = command.Parameters["F"].Value if (x is not None or y is not None or z is not None or f is not None): if (self.HasPositionError and not pos.IsRelative): self.HasPositionError = False self.PositionError = "" pos.UpdatePosition(x, y, z, e=None, f=f) if (e is not None): if (pos.IsExtruderRelative is not None): if (self.HasPositionError and not pos.IsExtruderRelative): self.HasPositionError = False self.PositionError = "" pos.UpdatePosition(x=None, y=None, z=None, e=e, f=None) else: self.Settings.CurrentDebugProfile().LogError( "Position - Unable to update the extruder position, no extruder coordinate system has been selected (absolute/relative)." ) message = "Position Change - {0} - {1} Move From(X:{2},Y:{3},Z:{4},E:{5}) - To(X:{6},Y:{7},Z:{8},E:{9})" if (previousPos is None): message = message.format( gcode, "Relative" if pos.IsRelative else "Absolute", "None", "None", "None", "None", pos.X, pos.Y, pos.Z, pos.E) else: message = message.format( gcode, "Relative" if pos.IsRelative else "Absolute", previousPos.X, previousPos.Y, previousPos.Z, previousPos.E, pos.X, pos.Y, pos.Z, pos.E) self.Settings.CurrentDebugProfile().LogPositionChange( message) else: self.Settings.CurrentDebugProfile().LogError( "Position - Unable to parse the gcode command: {0}". format(gcode)) # If we've not yet homed the axis ######################################################### elif (command.Command == "G28"): # test homing of only X,Y or Z if (command.Parse()): x = command.Parameters["X"].Value y = command.Parameters["Y"].Value z = command.Parameters["Z"].Value if (x is not None): pos.XHomed = True if (y is not None): pos.YHomed = True if (z is not None): pos.ZHomed = True if (x is None and y is None and z is None): pos.XHomed = True pos.YHomed = True pos.ZHomed = True self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G28 - Homing to {0}".format( GetFormattedCoordinates(x, y, z, pos.E))) self.HasPositionError = False self.PositionError = None else: self.Settings.CurrentDebugProfile().LogError( "Position - Unable to parse the Gcode:{0}".format( gcode)) elif (command.Command == "G90"): # change x,y,z to absolute if (pos.IsRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G90 - Switching to absolute x,y,z coordinates." ) pos.IsRelative = False else: self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G90 - Already using absolute x,y,z coordinates." ) # for some firmwares we need to switch the extruder to absolute coordinates as well if (self.G90InfluencesExtruder): if (pos.IsExtruderRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G90 - Switching to absolute extruder coordinates" ) pos.IsExtruderRelative = False else: self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G90 - Already using absolute extruder coordinates" ) elif (command.Command == "G91"): # change x,y,z to relative if (not pos.IsRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G91 - Switching to relative x,y,z coordinates" ) pos.IsRelative = True else: self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G91 - Already using relative x,y,z coordinates" ) # for some firmwares we need to switch the extruder to absolute coordinates as well if (self.G90InfluencesExtruder): if (not pos.IsExtruderRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G91 - Switching to relative extruder coordinates" ) pos.IsExtruderRelative = True else: self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G91 - Already using relative extruder coordinates" ) elif (command.Command == "M83"): if (pos.IsExtruderRelative is None or not pos.IsExtruderRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received M83 - Switching Extruder to Relative Coordinates" ) pos.IsExtruderRelative = True elif (command.Command == "M82"): if (pos.IsExtruderRelative is None or pos.IsExtruderRelative): self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received M82 - Switching Extruder to Absolute Coordinates" ) pos.IsExtruderRelative = False elif (command.Command == "G92"): if (command.Parse()): previousRelativeValue = self.IsRelative previousExtruderRelativeValue = self.IsExtruderRelative x = command.Parameters["X"].Value y = command.Parameters["Y"].Value z = command.Parameters["Z"].Value e = command.Parameters["E"].Value resetAll = False if (x is None and y is None and z is None and e is None): pos.XOffset = pos.X pos.YOffset = pos.Y pos.ZOffset = pos.Z pos.EOffset = pos.E # set the offsets if they are provided if (x is not None and pos.X is not None and pos.XHomed): pos.XOffset = pos.X - utility.getfloat(x, 0) if (y is not None and pos.Y is not None and pos.YHomed): pos.YOffset = pos.Y - utility.getfloat(y, 0) if (z is not None and pos.Z is not None and pos.ZHomed): pos.ZOffset = pos.Z - utility.getfloat(z, 0) if (e is not None and pos.E is not None): pos.EOffset = pos.E - utility.getfloat(e, 0) self.Settings.CurrentDebugProfile( ).LogPositionCommandReceived( "Received G92 - Set Position. Command:{0}, XOffset:{1}, YOffset:{2}, ZOffset:{3}, EOffset:{4}" .format(gcode, pos.XOffset, pos.YOffset, pos.ZOffset, pos.EOffset)) else: self.Settings.CurrentDebugProfile().LogError( "Position - Unable to parse the Gcode:{0}".format( gcode)) ######################################################### # Update the extruder monitor if there was movement self.Extruder.Update(self.ERelative(pos)) if (self.HasHomedAxis()): hasExtruderChanged = (utility.round_to( self.ERelative(pos), self.PrinterTolerance) != 0) hasXYZChanged = ( utility.round_to(pos.X, self.PrinterTolerance) != utility.round_to(previousPos.X, self.PrinterTolerance) or utility.round_to(pos.Y, self.PrinterTolerance) != utility.round_to(previousPos.Y, self.PrinterTolerance) or utility.round_to(pos.Z, self.PrinterTolerance) != utility.round_to(previousPos.Z, self.PrinterTolerance)) if (hasExtruderChanged or hasXYZChanged): self.HasPositionChanged = True # calculate LastExtrusionHeight and Height if (self.Extruder.IsExtruding() or self.Extruder.IsExtrudingStart()): pos.LastExtrusionHeight = pos.Z if (pos.Height is None or utility.round_to( pos.Z, self.PrinterTolerance) > self.Height): self.Height = utility.round_to( pos.Z, self.PrinterTolerance) pos.Height = self.Height self.Settings.CurrentDebugProfile( ).LogPositionHeightChange( "Position - Reached New Height:{0}.".format( pos.Height)) # calculate layer change if (utility.round_to(self.ZDelta(pos), self.PrinterTolerance) > 0 or self.Layer == 0): self.IsLayerChange = True self.Layer += 1 self.Settings.CurrentDebugProfile( ).LogPositionLayerChange( "Position - Layer:{0}.".format(self.Layer)) else: self.IsLayerChange = False # Calculate ZHop based on last extrusion height if (pos.LastExtrusionHeight is not None): # calculate lift, taking into account floating point rounding lift = utility.round_to( pos.Z - pos.LastExtrusionHeight, self.PrinterTolerance) if (lift >= self.Printer.z_hop): lift = self.Printer.z_hop isLifted = self.Printer.z_hop > 0.0 and lift >= self.Printer.z_hop and ( not self.Extruder.IsExtruding() or self.Extruder.IsExtrudingStart()) if (isLifted): if (not pos.IsZHop): pos.IsZHopStart = True else: if (pos.IsZHop): pos.IsZHopCompleting = True if (pos.IsZHopStart): self.Settings.CurrentDebugProfile().LogPositionZHop( "Position - ZhopStart:{0}".format( self.Printer.z_hop)) if (pos.IsZHop): self.Settings.CurrentDebugProfile().LogPositionZHop( "Position - Zhop:{0}".format(self.Printer.z_hop)) if (pos.IsZHopCompleting): self.Settings.CurrentDebugProfile().LogPositionZHop( "Position - IsZHopCompleting:{0}".format( self.Printer.z_hop)) # Add the current position, remove positions if we have more than 5 from the end self.Positions.insert(0, pos) while (len(self.Positions) > 5): del self.Positions[5]
def Update(self, position): try: # get the last state to use as a starting point for the update # if there is no state, this will return the default state state = self.GetState(0) if (state is None): # create a new object, it's our first state! state = TimerTriggerState() else: # create a copy so we aren't working on the original state = TimerTriggerState(state) # reset any variables that must be reset each update state.ResetState() state.IsTriggered = False # Don't update the trigger if we don't have a homed axis # Make sure to use the previous value so the homing operation can complete if (not position.HasHomedPosition(1)): state.IsTriggered = False state.IsHomed = False else: state.IsHomed = True # record the current time to keep things consistant currentTime = time.time() # if the trigger start time is null, set it now. if (state.TriggerStartTime is None): state.TriggerStartTime = currentTime self.Settings.CurrentDebugProfile().LogTriggerTimeRemaining( 'TimerTrigger - {0} second interval, {1} seconds elapsed, {2} seconds to trigger' .format( self.IntervalSeconds, int(currentTime - state.TriggerStartTime), int(self.IntervalSeconds - (currentTime - state.TriggerStartTime)))) # how many seconds to trigger secondsToTrigger = self.IntervalSeconds - ( currentTime - state.TriggerStartTime) state.SecondsToTrigger = utility.round_to(secondsToTrigger, 1) # see if enough time has elapsed since the last trigger if (state.SecondsToTrigger <= 0): state.IsWaiting = True # see if the exturder is in the right position if (position.Extruder.IsTriggered(1, self.ExtruderTriggers)): if (self.RequireZHop and not position.IsZHop(1)): self.Settings.CurrentDebugProfile( ).LogTriggerWaitState( "TimerTrigger - Waiting on ZHop.") state.IsWaitingOnZHop = True else: # Is Triggering self.TriggeredCount += 1 state.IsTriggered = True state.TriggerStartTime = None state.IsWaitingOnZHop = False state.IsWaitingOnExtruder = False # Log trigger self.Settings.CurrentDebugProfile().LogTriggering( 'TimerTrigger - Triggering.') else: self.Settings.CurrentDebugProfile( ).LogTriggerWaitState( 'TimerTrigger - Triggering, waiting for extruder') state.IsWaitingOnExtruder = True # calculate changes and set the current state state.HasChanged = not state.IsEqual(self.GetState(0)) # add the state to the history self.AddState(state) except Exception as e: self.Settings.CurrentDebugProfile().LogException(e)
def UpdateState(self, pos, previousPos): # Todo: Properly deal with floating compare self.HasChanged = False # If we were not previously extruding, but are now #utility.round_to(pos.ExtrusionLength,0.0001) pos.IsExtrudingStart = True if utility.round_to( pos.ExtrusionLength, 0.0001) > 0 and utility.round_to( previousPos.ExtrusionLength, 0.0001) == 0 else False pos.IsExtruding = True if ( utility.round_to(previousPos.ExtrusionLength, 0.0001) > 0 ) and utility.round_to(pos.ExtrusionLength, 0.0001) > 0 else False pos.IsPrimed = True if utility.round_to( previousPos.RetractionLength, 0.0001) == 0 and utility.round_to( pos.ExtrusionLength, 0.0001) == 0 and utility.round_to( pos.RetractionLength, 0.0001) == 0 else False pos.IsRetractingStart = True if utility.round_to( previousPos.RetractionLength, 0.0001) == 0 and utility.round_to( pos.RetractionLength, 0.0001) > 0 else False pos.IsRetracting = True if ( utility.round_to(previousPos.RetractionLength, 0.0001) > 0 and utility.round_to(pos.RetractionLength, 0.0001) > utility.round_to(previousPos.RetractionLength, 0.0001)) else False pos.IsPartiallyRetracted = True if utility.round_to( previousPos.RetractionLength, 0.0001) > 0 and utility.round_to( previousPos.RetractionLength, 0.0001) < utility.round_to( pos.PrinterRetractionLength, 0.0001) else False pos.IsRetracted = True if utility.round_to( previousPos.RetractionLength, 0.0001) > 0 and utility.round_to( previousPos.RetractionLength, 0.0001) >= utility.round_to( pos.PrinterRetractionLength, 0.0001) else False pos.IsDetractingStart = True if utility.round_to( pos.DetractionLength, 0.0001) > 0 and utility.round_to( previousPos.DetractionLength, 0.0001) == 0 else False pos.IsDetracting = True if utility.round_to( previousPos.DetractionLength, 0.0001) > 0 and utility.round_to( pos.DetractionLength, 0.0001) > 0 else False pos.IsDetracted = True if utility.round_to( previousPos.RetractionLength, 0.0001) == 0 and utility.round_to( previousPos.DetractionLength, 0.0001) > 0 and utility.round_to( previousPos.ExtrusionLength, 0.0001) == 0 else False if (previousPos.RetractionLength != pos.RetractionLength or previousPos.IsExtrudingStart != pos.IsExtrudingStart or previousPos.IsExtruding != pos.IsExtruding or previousPos.IsPrimed != pos.IsPrimed or previousPos.IsRetractingStart != pos.IsRetractingStart or previousPos.IsRetracting != pos.IsRetracting or previousPos.IsPartiallyRetracted != pos.IsPartiallyRetracted or previousPos.IsRetracted != pos.IsRetracted or previousPos.IsDetractingStart != pos.IsDetractingStart or previousPos.IsDetracting != pos.IsDetracting or previousPos.IsDetracted != pos.IsDetracted): self.HasChanged = True if (self.HasChanged): self.Settings.CurrentDebugProfile().LogExtruderChange( "Extruder Changed: E:{0}, Retraction:{1} IsExtruding:{2}-{3}, IsExtrudingStart:{4}-{5}, IsPrimed:{6}-{7}, IsRetractingStart:{8}-{9}, IsRetracting:{10}-{11}, IsPartiallyRetracted:{12}-{13}, IsRetracted:{14}-{15}, IsDetractingStart:{16}-{17}, IsDetracting:{18}-{19}, IsDetracted:{20}-{21}" .format(pos.E, pos.RetractionLength, previousPos.IsExtruding, pos.IsExtruding, previousPos.IsExtrudingStart, pos.IsExtrudingStart, previousPos.IsPrimed, pos.IsPrimed, previousPos.IsRetractingStart, pos.IsRetractingStart, previousPos.IsRetracting, pos.IsRetracting, previousPos.IsPartiallyRetracted, pos.IsPartiallyRetracted, previousPos.IsRetracted, pos.IsRetracted, previousPos.IsDetractingStart, pos.IsDetractingStart, previousPos.IsDetracting, pos.IsDetracting, previousPos.IsDetracted, pos.IsDetracted))