diff --git a/MatterControl.Printing/Settings/PrinterSettings.cs b/MatterControl.Printing/Settings/PrinterSettings.cs index b2ca5e6c6..79d70a4bc 100644 --- a/MatterControl.Printing/Settings/PrinterSettings.cs +++ b/MatterControl.Printing/Settings/PrinterSettings.cs @@ -137,6 +137,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.has_sd_card_reader, SettingsKey.has_z_probe, SettingsKey.has_z_servo, + SettingsKey.has_conductive_nozzle, + SettingsKey.measure_probe_offset_conductively, + SettingsKey.conductive_pad_position, SettingsKey.heat_extruder_before_homing, SettingsKey.inactive_cool_down, SettingsKey.include_firmware_updater, @@ -166,7 +169,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.printer_name, SettingsKey.probe_has_been_calibrated, SettingsKey.probe_offset, - SettingsKey.probe_offset_sample_point, SettingsKey.progress_reporting, SettingsKey.read_regex, SettingsKey.recover_first_layer_speed, diff --git a/MatterControl.Printing/Settings/SettingsKey.cs b/MatterControl.Printing/Settings/SettingsKey.cs index c0b65f57e..7a56514e0 100644 --- a/MatterControl.Printing/Settings/SettingsKey.cs +++ b/MatterControl.Printing/Settings/SettingsKey.cs @@ -123,6 +123,9 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string has_sd_card_reader = nameof(has_sd_card_reader); public const string has_z_probe = nameof(has_z_probe); public const string has_z_servo = nameof(has_z_servo); + public const string has_conductive_nozzle = nameof(has_conductive_nozzle); + public const string measure_probe_offset_conductively = nameof(measure_probe_offset_conductively); + public const string conductive_pad_position = nameof(conductive_pad_position); public const string heat_extruder_before_homing = nameof(heat_extruder_before_homing); public const string inactive_cool_down = nameof(inactive_cool_down); public const string include_firmware_updater = nameof(include_firmware_updater); @@ -182,7 +185,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration public const string printer_name = nameof(printer_name); public const string probe_has_been_calibrated = nameof(probe_has_been_calibrated); public const string probe_offset = nameof(probe_offset); - public const string probe_offset_sample_point = nameof(probe_offset_sample_point); public const string progress_reporting = nameof(progress_reporting); public const string publish_bed_image = nameof(publish_bed_image); public const string raft_air_gap = nameof(raft_air_gap); diff --git a/MatterControl.Printing/Settings/SliceSettingsFields.cs b/MatterControl.Printing/Settings/SliceSettingsFields.cs index 23a29aa4a..7ab1390d3 100644 --- a/MatterControl.Printing/Settings/SliceSettingsFields.cs +++ b/MatterControl.Printing/Settings/SliceSettingsFields.cs @@ -897,6 +897,41 @@ namespace MatterHackers.MatterControl.SlicerConfiguration RebuildGCodeOnChange = false }, new SliceSettingData() + { + SlicerConfigName = SettingsKey.has_conductive_nozzle, + PresentationName = "Has Conductive Nozzle".Localize(), + HelpText = "The printer has the ability to check for continuity on the nozzle.".Localize(), + DataEditType = DataEditTypes.CHECK_BOX, + ShowAsOverride = true, + DefaultValue = "0", + UiUpdate = UiUpdateRequired.SliceSettings, + RebuildGCodeOnChange = false + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.measure_probe_offset_conductively, + PresentationName = "Measure Probe Offset Conductively".Localize(), + HelpText = "If the printer has both a conductive nozzle and a z probe this will enable automatic validation of the distance between their readings. Expected output is 'conductive: TRIGGERED' on M119.".Localize(), + DataEditType = DataEditTypes.CHECK_BOX, + ShowAsOverride = true, + DefaultValue = "0", + ShowIfSet = "!has_hardware_leveling&has_z_probe&has_conductive_nozzle", + UiUpdate = UiUpdateRequired.SliceSettings, + RebuildGCodeOnChange = false + }, + new SliceSettingData() + { + SlicerConfigName = SettingsKey.conductive_pad_position, + PresentationName = "Conductive Pad Position".Localize(), + HelpText = "The position of the conductive pad used for nozzle probing.".Localize(), + DataEditType = DataEditTypes.VECTOR2, + ShowAsOverride = true, + DefaultValue = "0,0", + ShowIfSet = "!has_hardware_leveling&has_z_probe&has_conductive_nozzle&measure_probe_offset_conductively", + UiUpdate = UiUpdateRequired.SliceSettings, + RebuildGCodeOnChange = false + }, + new SliceSettingData() { SlicerConfigName = SettingsKey.has_hardware_leveling, PresentationName = "Has Hardware Leveling".Localize(), @@ -1035,17 +1070,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration RebuildGCodeOnChange = false }, new SliceSettingData() - { - SlicerConfigName = SettingsKey.probe_offset_sample_point, - PresentationName = "Probe Offset Sample Point".Localize(), - HelpText = "The position to measure the probe offset.".Localize(), - Units = "mm".Localize(), - DataEditType = DataEditTypes.VECTOR2, - DefaultValue = "100,100", - ShowIfSet = "!has_hardware_leveling&print_leveling_solution=Custom Points&use_z_probe", - RebuildGCodeOnChange = false - }, - new SliceSettingData() { SlicerConfigName = SettingsKey.print_leveling_required_to_print, PresentationName = "Require Leveling To Print".Localize(), diff --git a/MatterControl.Printing/Settings/SliceSettingsLayouts.cs b/MatterControl.Printing/Settings/SliceSettingsLayouts.cs index 28a572287..2a6c5e25d 100644 --- a/MatterControl.Printing/Settings/SliceSettingsLayouts.cs +++ b/MatterControl.Printing/Settings/SliceSettingsLayouts.cs @@ -291,7 +291,6 @@ namespace MatterHackers.MatterControl.SlicerConfiguration { SettingsKey.print_leveling_solution, SettingsKey.leveling_sample_points, - SettingsKey.probe_offset_sample_point, SettingsKey.print_leveling_required_to_print, }), ("Print Recovery", new[] @@ -310,6 +309,8 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.probe_offset, SettingsKey.z_servo_depolyed_angle, SettingsKey.z_servo_retracted_angle, + SettingsKey.measure_probe_offset_conductively, + SettingsKey.conductive_pad_position, }), ("Behavior", new[] { @@ -346,6 +347,7 @@ namespace MatterHackers.MatterControl.SlicerConfiguration SettingsKey.runout_sensor_trigger_ratio, SettingsKey.has_z_probe, SettingsKey.has_z_servo, + SettingsKey.has_conductive_nozzle, SettingsKey.has_c_axis, SettingsKey.enable_network_printing, SettingsKey.enable_sailfish_communication, diff --git a/MatterControlLib/ConfigurationPage/PrintLeveling/LevelingPlan.cs b/MatterControlLib/ConfigurationPage/PrintLeveling/LevelingPlan.cs index d2cfa451f..5048d58b7 100644 --- a/MatterControlLib/ConfigurationPage/PrintLeveling/LevelingPlan.cs +++ b/MatterControlLib/ConfigurationPage/PrintLeveling/LevelingPlan.cs @@ -52,9 +52,10 @@ namespace MatterHackers.MatterControl.ConfigurationPage.PrintLeveling public static Vector2 ProbeOffsetSamplePosition(PrinterConfig printer) { - if (printer.Settings.GetValue(SettingsKey.print_leveling_solution) == LevelingSystem.ProbeCustom) + if (printer.Settings.GetValue(SettingsKey.has_conductive_nozzle) + && printer.Settings.GetValue(SettingsKey.measure_probe_offset_conductively)) { - return printer.Settings.GetValue(SettingsKey.probe_offset_sample_point); + return printer.Settings.GetValue(SettingsKey.conductive_pad_position); } return printer.Settings.GetValue(SettingsKey.print_center); diff --git a/MatterControlLib/ConfigurationPage/PrintLeveling/SetupWizards/ZCalibrationWizard.cs b/MatterControlLib/ConfigurationPage/PrintLeveling/SetupWizards/ZCalibrationWizard.cs index b5276db4e..c87eaaf19 100644 --- a/MatterControlLib/ConfigurationPage/PrintLeveling/SetupWizards/ZCalibrationWizard.cs +++ b/MatterControlLib/ConfigurationPage/PrintLeveling/SetupWizards/ZCalibrationWizard.cs @@ -207,89 +207,79 @@ namespace MatterHackers.MatterControl.ConfigurationPage.PrintLeveling 0); } - // show what steps will be taken - yield return new WizardPage( - this, - "Measure the nozzle offset".Localize(), - "{0}:\n\n\t• {1}\n\n{2}\n\n{3}".FormatWith( - "To complete the next few steps you will need".Localize(), - "A sheet of paper".Localize(), - "We will use this paper to measure the distance between the nozzle and the bed.".Localize(), - "Click 'Next' to continue.".Localize())); - - for (int extruderIndex = 0; extruderIndex < hotendCount; extruderIndex++) + if (hotendCount == 1 + && probeBeingUsed + && printer.Settings.GetValue(SettingsKey.has_conductive_nozzle) + && printer.Settings.GetValue(SettingsKey.measure_probe_offset_conductively)) { - if (extruderCount > 1) - { - // reset the extruder that was active - printer.Connection.QueueLine($"T{extruderIndex}"); - } - - // do the manual prob of the same position - yield return new GetCoarseBedHeight( + yield return new ConductiveProbeFeedback( this, - new Vector3(probePosition, startProbeHeight), - string.Format( - "{0} {1} {2} - {3}", - levelingStrings.GetStepString(totalSteps), - "Position".Localize(), - 1, - "Low Precision".Localize()), - manualProbePositions[extruderIndex], - 0, - levelingStrings); + probeStartPosition, + "Conductive Probing".Localize(), + "Measure the nozzle to probe offset using the conductive pad.".Localize(), + manualProbePositions[0]); - yield return new GetFineBedHeight( + SetExtruderOffset(autoProbePositions, manualProbePositions, false, 0); + } + else // collect the probe information manually + { + // show what steps will be taken + yield return new WizardPage( this, - string.Format( - "{0} {1} {2} - {3}", - levelingStrings.GetStepString(totalSteps), - "Position".Localize(), - 1, - "Medium Precision".Localize()), - manualProbePositions[extruderIndex], - 0, - levelingStrings); + "Measure the nozzle offset".Localize(), + "{0}:\n\n\t• {1}\n\n{2}\n\n{3}".FormatWith( + "To complete the next few steps you will need".Localize(), + "A sheet of paper".Localize(), + "We will use this paper to measure the distance between the nozzle and the bed.".Localize(), + "Click 'Next' to continue.".Localize())); - yield return new GetUltraFineBedHeight( - this, - string.Format( - "{0} {1} {2} - {3}", - levelingStrings.GetStepString(totalSteps), - "Position".Localize(), - 1, - "High Precision".Localize()), - manualProbePositions[extruderIndex], - 0, - levelingStrings); - - if (probeBeingUsed && extruderIndex == 0) + for (int extruderIndex = 0; extruderIndex < hotendCount; extruderIndex++) { - // set the probe z offset - double newProbeOffset = autoProbePositions[0].Position.Z - manualProbePositions[0][0].Position.Z; - var probe_offset = printer.Settings.GetValue(SettingsKey.probe_offset); - probe_offset.Z = -newProbeOffset; - printer.Settings.SetValue(SettingsKey.probe_offset, $"{probe_offset.X},{probe_offset.Y},{probe_offset.Z}"); - - printer.Settings.SetValue(SettingsKey.probe_has_been_calibrated, "1"); - } - else if (extruderIndex > 0) - { - // store the offset into the extruder offset z position - double newZOffset; - - if (probeBeingUsed) + if (extruderCount > 1) { - var extruderOffset = autoProbePositions[0].Position.Z - manualProbePositions[extruderIndex][0].Position.Z; - var hotend0Offset = printer.Settings.GetValue(SettingsKey.probe_offset); - newZOffset = extruderOffset + hotend0Offset.Z; - } - else - { - newZOffset = manualProbePositions[0][0].Position.Z - manualProbePositions[extruderIndex][0].Position.Z; + // reset the extruder that was active + printer.Connection.QueueLine($"T{extruderIndex}"); } - printer.Settings.Helpers.SetExtruderZOffset(1, newZOffset); + // do the manual probe of the same position + yield return new GetCoarseBedHeight( + this, + new Vector3(probePosition, startProbeHeight), + string.Format( + "{0} {1} {2} - {3}", + levelingStrings.GetStepString(totalSteps), + "Position".Localize(), + 1, + "Low Precision".Localize()), + manualProbePositions[extruderIndex], + 0, + levelingStrings); + + yield return new GetFineBedHeight( + this, + string.Format( + "{0} {1} {2} - {3}", + levelingStrings.GetStepString(totalSteps), + "Position".Localize(), + 1, + "Medium Precision".Localize()), + manualProbePositions[extruderIndex], + 0, + levelingStrings); + + yield return new GetUltraFineBedHeight( + this, + string.Format( + "{0} {1} {2} - {3}", + levelingStrings.GetStepString(totalSteps), + "Position".Localize(), + 1, + "High Precision".Localize()), + manualProbePositions[extruderIndex], + 0, + levelingStrings); + + SetExtruderOffset(autoProbePositions, manualProbePositions, probeBeingUsed, extruderIndex); } } @@ -307,5 +297,37 @@ namespace MatterHackers.MatterControl.ConfigurationPage.PrintLeveling yield return new CalibrateProbeLastPageInstructions(this, this.Title + " " + "Wizard".Localize()); } + + private void SetExtruderOffset(List autoProbePositions, List> manualProbePositions, bool probeBeingUsed, int extruderIndex) + { + if (extruderIndex == 0) + { + // set the probe z offset + double newProbeOffset = autoProbePositions[0].Position.Z - manualProbePositions[0][0].Position.Z; + var probe_offset = printer.Settings.GetValue(SettingsKey.probe_offset); + probe_offset.Z = -newProbeOffset; + printer.Settings.SetValue(SettingsKey.probe_offset, $"{probe_offset.X},{probe_offset.Y},{probe_offset.Z}"); + + printer.Settings.SetValue(SettingsKey.probe_has_been_calibrated, "1"); + } + else if (extruderIndex > 0) + { + // store the offset into the extruder offset z position + double newZOffset; + + if (probeBeingUsed) + { + var extruderOffset = autoProbePositions[0].Position.Z - manualProbePositions[extruderIndex][0].Position.Z; + var hotend0Offset = printer.Settings.GetValue(SettingsKey.probe_offset); + newZOffset = extruderOffset + hotend0Offset.Z; + } + else + { + newZOffset = manualProbePositions[0][0].Position.Z - manualProbePositions[extruderIndex][0].Position.Z; + } + + printer.Settings.Helpers.SetExtruderZOffset(1, newZOffset); + } + } } } \ No newline at end of file diff --git a/MatterControlLib/ConfigurationPage/PrintLeveling/WizardPages/ConductiveProbeFeedback.cs b/MatterControlLib/ConfigurationPage/PrintLeveling/WizardPages/ConductiveProbeFeedback.cs new file mode 100644 index 000000000..acba2c1f4 --- /dev/null +++ b/MatterControlLib/ConfigurationPage/PrintLeveling/WizardPages/ConductiveProbeFeedback.cs @@ -0,0 +1,150 @@ +/* +Copyright (c) 2019, Lars Brubaker, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using MatterControl.Printing; +using MatterHackers.Agg.UI; +using MatterHackers.MatterControl.PrinterCommunication; +using MatterHackers.MatterControl.SlicerConfiguration; +using MatterHackers.VectorMath; + +namespace MatterHackers.MatterControl.ConfigurationPage.PrintLeveling +{ + public class ConductiveProbeFeedback : WizardPage + { + private readonly List probePositions; + + private Vector3 nozzleCurrentPosition; + + public ConductiveProbeFeedback(ISetupWizard setupWizard, Vector3 nozzleStartPosition, string headerText, string details, List probePositions) + : base(setupWizard, headerText, details) + { + this.nozzleCurrentPosition = nozzleStartPosition; + this.probePositions = probePositions; + + var spacer = new GuiWidget(15, 15); + contentRow.AddChild(spacer); + + feedRates = printer.Settings.Helpers.ManualMovementSpeeds(); + } + + double moveDelta = .5; + + enum State + { + WaitingForEndstopStatusStart, + WaitingForEndstopStatusOk, + } + + State state = State.WaitingForEndstopStatusStart; + private Vector3 feedRates; + + private void PrinterLineRecieved(object sender, string line) + { + // looking for 'conductive: TRIGGERED' in an M119 command + if (line != null) + { + switch (state) + { + case State.WaitingForEndstopStatusStart: + if (line.StartsWith("conductive:")) + { + if (line.Contains("TRIGGERED")) + { + if (moveDelta > .02) + { + nozzleCurrentPosition.Z += moveDelta * 3; + moveDelta *= .5; + state = State.WaitingForEndstopStatusOk; + } + else + { + probePositions[0].Position = nozzleCurrentPosition; + + // move on to the next page of the wizard + UiThread.RunOnIdle(() => NextButton.InvokeClick()); + } + } + else // did not find endstop yet + { + nozzleCurrentPosition.Z -= moveDelta; + state = State.WaitingForEndstopStatusOk; + } + } + break; + + case State.WaitingForEndstopStatusOk: + // found the ok of the M119 command + // move down more + if (nozzleCurrentPosition.Z < -2) + { + // we have gone down too far + // abort with error + } + else if (line.StartsWith("ok")) + { + state = State.WaitingForEndstopStatusStart; + // send the next set of commands + printer.Connection.MoveAbsolute(nozzleCurrentPosition, feedRates.X); + printer.Connection.QueueLine("M119"); + } + break; + } + } + } + + public override void OnLoad(EventArgs args) + { + // always make sure we don't have print leveling turned on + printer.Connection.AllowLeveling = false; + + NextButton.Enabled = false; + + // do a last minute check that the printer is read to do this action + if (printer.Connection.IsConnected + && !(printer.Connection.Printing + || printer.Connection.Paused)) + { + printer.Connection.LineReceived += PrinterLineRecieved; + printer.Connection.MoveAbsolute(nozzleCurrentPosition, feedRates.X); + printer.Connection.QueueLine("M119"); + } + + base.OnLoad(args); + } + + public override void OnClosed(EventArgs e) + { + printer.Connection.LineReceived -= PrinterLineRecieved; + base.OnClosed(e); + } + } +} \ No newline at end of file diff --git a/MatterControlLib/PrinterCommunication/Drivers/Emulator/Emulator.cs b/MatterControlLib/PrinterCommunication/Drivers/Emulator/Emulator.cs index 741275eda..f21d8ab3e 100644 --- a/MatterControlLib/PrinterCommunication/Drivers/Emulator/Emulator.cs +++ b/MatterControlLib/PrinterCommunication/Drivers/Emulator/Emulator.cs @@ -76,6 +76,7 @@ namespace MatterHackers.PrinterEmulator responses = new Dictionary>() { { "A", Echo }, + { "FAST", ChangeToFast }, { "G0", ParseMovmentCommand }, { "G1", ParseMovmentCommand }, { "G28", HomeAxis }, @@ -89,6 +90,7 @@ namespace MatterHackers.PrinterEmulator { "M110", SetLineCount }, { "M114", GetPosition }, { "M115", ReportMarlinFirmware }, + { "M119", ReportEndStops }, { "M140", SetBedTemperature }, { "M190", SetBedTemperature }, { "M20", ListSdCard }, @@ -96,13 +98,31 @@ namespace MatterHackers.PrinterEmulator { "M306", SetHomeOffset }, { "M851", SetXYZProbeOffset }, { "N", ParseChecksumLine }, + { "SLOW", ChangeToSlow }, { "T0", SetExtruderIndex }, { "T1", SetExtruderIndex }, - { "SLOW", ChangeToSlow }, - { "FAST", ChangeToFast }, }; } + private AxisAlignedBoundingBox xMaxTriggerRegion = new AxisAlignedBoundingBox(95, 210, -10, 105, 220, 0); + + private string ReportEndStops(string arg) + { + var xMaxOpen = "open"; + if (xMaxTriggerRegion.Contains(CurrentPosition)) + { + xMaxOpen = "TRIGGERED"; + } + + var status = "Reporting endstop status\n"; + status += $"x_min: open\n"; + status += $"x_max: {xMaxOpen}\n"; + status += $"y_min: open\n"; + status += $"z_min: open\n"; + status += "ok\n"; + return status; + } + public event EventHandler ExtruderIndexChanged; public event EventHandler ExtruderTemperatureChanged; @@ -440,7 +460,7 @@ ok Thread.Sleep(500); } - return $"Bed Position X: {CurrentPosition.X} Y: {CurrentPosition.Y} Z: {rand.NextDouble():0.###}\n" + return $"Bed Position X: {CurrentPosition.X} Y: {CurrentPosition.Y} Z: {-XYZProbeOffset.Z + rand.NextDouble():0.###}\n" + "ok\n"; } @@ -722,7 +742,7 @@ ok public Vector3 HomePosition { get; set; } = default(Vector3); - public Vector3 XYZProbeOffset { get; set; } = default(Vector3); + public Vector3 XYZProbeOffset { get; set; } = new Vector3(0, 0, -5); public void Close() {