2014-06-05 11:45:40 -07:00
/ *
Copyright ( c ) 2014 , Lars Brubaker
All rights reserved .
Redistribution and use in source and binary forms , with or without
2015-04-08 15:20:10 -07:00
modification , are permitted provided that the following conditions are met :
2014-06-05 11:45:40 -07:00
1. Redistributions of source code must retain the above copyright notice , this
2015-04-08 15:20:10 -07:00
list of conditions and the following disclaimer .
2014-06-05 11:45:40 -07:00
2. Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
2015-04-08 15:20:10 -07:00
and / or other materials provided with the distribution .
2014-06-05 11:45:40 -07:00
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
2015-04-08 15:20:10 -07:00
of the authors and should not be interpreted as representing official policies ,
2014-06-05 11:45:40 -07:00
either expressed or implied , of the FreeBSD Project .
* /
2018-03-29 12:31:36 -07:00
using MatterHackers.Agg ;
2014-06-05 11:45:40 -07:00
using MatterHackers.Agg.UI ;
using MatterHackers.Localizations ;
2018-04-03 18:17:27 -07:00
using MatterHackers.MatterControl.PrinterCommunication.Io ;
2014-06-05 11:45:40 -07:00
using MatterHackers.MatterControl.SlicerConfiguration ;
2015-04-08 15:20:10 -07:00
using MatterHackers.VectorMath ;
using System ;
2017-05-19 14:39:57 -07:00
using System.Collections.Generic ;
2014-06-05 11:45:40 -07:00
2014-06-06 16:05:18 -07:00
namespace MatterHackers.MatterControl.ConfigurationPage.PrintLeveling
2014-06-05 11:45:40 -07:00
{
2018-03-29 12:31:36 -07:00
public abstract class LevelWizardBase : SystemWindow
2015-04-08 15:20:10 -07:00
{
2018-03-29 18:12:02 -07:00
protected PrinterConfig printer ;
protected WizardControl printLevelWizard ;
private static SystemWindow printLevelWizardWindow ;
2017-09-05 10:33:14 -07:00
private LevelingStrings levelingStrings ;
2015-04-08 15:20:10 -07:00
2018-04-09 12:22:18 -07:00
public LevelWizardBase ( PrinterConfig printer , ThemeConfig theme )
2018-03-29 12:31:36 -07:00
: base ( 500 , 370 )
2015-04-08 15:20:10 -07:00
{
2017-09-15 12:08:00 -07:00
levelingStrings = new LevelingStrings ( printer . Settings ) ;
this . printer = printer ;
2015-04-08 15:20:10 -07:00
AlwaysOnTopOfMain = true ;
2018-03-29 12:31:36 -07:00
levelingStrings = new LevelingStrings ( printer . Settings ) ;
string printLevelWizardTitle = ApplicationController . Instance . ProductName ;
string printLevelWizardTitleFull = "Print Leveling Wizard" . Localize ( ) ;
Title = string . Format ( "{0} - {1}" , printLevelWizardTitle , printLevelWizardTitleFull ) ;
List < ProbePosition > probePositions = new List < ProbePosition > ( ProbeCount ) ;
2018-03-29 16:48:54 -07:00
for ( int j = 0 ; j < ProbeCount ; j + + )
2018-03-29 12:31:36 -07:00
{
probePositions . Add ( new ProbePosition ( ) ) ;
}
printLevelWizard = new WizardControl ( ) ;
AddChild ( printLevelWizard ) ;
2018-04-06 14:58:25 -07:00
// If no leveling data has been calculated
bool showWelcomeScreen = printer . Settings . Helpers . GetPrintLevelingData ( ) . SampledPositions . Count = = 0
& & ! ProbeCalibrationWizard . UsingZProbe ( printer ) ;
if ( showWelcomeScreen )
2017-05-19 14:39:57 -07:00
{
2018-04-06 14:58:25 -07:00
string part1 = "Congratulations on connecting to your printer. Before starting your first print we need to run a simple calibration procedure." . Localize ( ) ;
string part2 = "The next few screens will walk your through calibrating your printer." . Localize ( ) ;
2018-04-03 12:10:33 -07:00
string requiredPageInstructions = $"{part1}\n\n{part2}" ;
2018-04-09 12:22:18 -07:00
printLevelWizard . AddPage ( new FirstPageInstructions ( printer , levelingStrings . initialPrinterSetupStepText , requiredPageInstructions , theme ) ) ;
2018-03-29 12:31:36 -07:00
}
2018-04-03 12:10:33 -07:00
// To make sure the bed is at the correct temp, put in a filament selection page.
bool hasHeatedBed = printer . Settings . GetValue < bool > ( SettingsKey . has_heated_bed ) ;
2018-03-29 12:31:36 -07:00
bool useZProbe = printer . Settings . Helpers . UseZProbe ( ) ;
2018-04-03 12:10:33 -07:00
int zProbeSamples = printer . Settings . GetValue < int > ( SettingsKey . z_probe_samples ) ;
var secondsPerManualSpot = 10 * 3 ;
var secondsPerAutomaticSpot = 3 * zProbeSamples ;
var secondsToCompleteWizard = ProbeCount * ( useZProbe ? secondsPerAutomaticSpot : secondsPerManualSpot ) ;
secondsToCompleteWizard + = ( hasHeatedBed ? 60 * 3 : 0 ) ;
2018-04-04 15:58:57 -07:00
printLevelWizard . AddPage ( new FirstPageInstructions ( printer ,
"Print Leveling Overview" . Localize ( ) ,
2018-04-09 12:22:18 -07:00
levelingStrings . WelcomeText ( ProbeCount , ( int ) Math . Round ( secondsToCompleteWizard / 60.0 ) ) , theme ) ) ;
2018-04-03 12:10:33 -07:00
2018-04-10 14:40:19 -07:00
double targetBedTemp = 0 ;
double targetHotendTemp = 0 ;
if ( hasHeatedBed )
{
targetBedTemp = printer . Settings . GetValue < double > ( SettingsKey . bed_temperature ) ;
}
2018-03-29 12:31:36 -07:00
if ( ! useZProbe )
{
2018-04-10 14:40:19 -07:00
targetHotendTemp = printer . Settings . Helpers . ExtruderTemperature ( 0 ) ;
2018-03-29 12:31:36 -07:00
}
2018-04-10 14:40:19 -07:00
// If we need to heat the bed or the extruder, select the current material
if ( targetBedTemp > 0 | | targetHotendTemp > 0 )
2018-03-29 12:31:36 -07:00
{
2018-04-10 14:40:19 -07:00
var instruction1 = "" ;
if ( targetBedTemp > 0 & & targetHotendTemp > 0 )
{
// heating both the bed and the hotend
instruction1 = "To ensure accurate calibration both the bed and the hotend need to be heated." . Localize ( ) ;
}
else if ( targetBedTemp > 0 )
{
// only heating the bed
instruction1 = "The temperature of the bed can have a significant effect on the quality of leveling." . Localize ( ) ;
}
else // targetHotendTemp > 0
{
// only heating the hotend
instruction1 + = "The hot end needs to be heated to ensure it is clean." . Localize ( ) ;
}
var instruction2 = "Please select the material you will be printing, so we can heat the printer before calibrating." . Localize ( ) ;
printLevelWizard . AddPage ( new SelectMaterialPage ( printer , "Select Material" . Localize ( ) , $"{instruction1}\n\n{instruction2}" , theme ) ) ;
2018-03-29 12:31:36 -07:00
}
2018-04-03 12:10:33 -07:00
2018-03-29 12:31:36 -07:00
printLevelWizard . AddPage ( new HomePrinterPage ( printer , printLevelWizard ,
levelingStrings . HomingPageStepText ,
2018-04-04 15:58:57 -07:00
levelingStrings . HomingPageInstructions ( useZProbe , hasHeatedBed ) ,
2018-04-09 12:22:18 -07:00
useZProbe , theme ) ) ;
2018-04-04 13:45:10 -07:00
2018-04-10 14:40:19 -07:00
if ( targetBedTemp > 0 | | targetHotendTemp > 0 )
2018-03-29 12:31:36 -07:00
{
2018-04-10 14:40:19 -07:00
string heatingInstructions = "" ;
if ( targetBedTemp > 0 & & targetHotendTemp > 0 )
{
// heating both the bed and the hotend
heatingInstructions = $"Waiting for the bed to heat to {targetBedTemp}" . Localize ( ) + "\n"
+ $"and the hotend to heat to {targetHotendTemp}." . Localize ( ) + "\n"
+ "\n"
+ "This will improve the accuracy of print leveling" . Localize ( )
+ "and ensure no filament is stuck to the tip of the extruder." . Localize ( ) + "\n"
+ "\n"
+ "Warning! The tip of the extrude will be HOT!" . Localize ( ) + "\n"
+ "Avoid contact with your skin." . Localize ( ) ;
}
else if ( targetBedTemp > 0 )
{
// only heating the bed
heatingInstructions = $"Waiting for the bed to heat to {targetBedTemp}." . Localize ( ) + "\n"
+ "This will improve the accuracy of print leveling." . Localize ( ) ;
}
else // targetHotendTemp > 0
{
// only heating the hotend
heatingInstructions + = $"Waiting for the hotend to heat to {targetHotendTemp}." . Localize ( ) + "\n"
+ "This will ensure no filament is stuck to the tip." . Localize ( ) + "\n"
+ "\n"
+ "Warning! The tip of the extrude will be HOT!" . Localize ( ) + "\n"
+ "Avoid contact with your skin." . Localize ( ) ;
}
printLevelWizard . AddPage ( new WaitForTempPage ( printer , printLevelWizard ,
"Waiting For Printer To Heat" . Localize ( ) , heatingInstructions ,
targetBedTemp , targetHotendTemp ,
theme ) ) ;
2018-03-29 12:31:36 -07:00
}
string positionLabel = "Position" . Localize ( ) ;
string autoCalibrateLabel = "Auto Calibrate" . Localize ( ) ;
string lowPrecisionLabel = "Low Precision" . Localize ( ) ;
string medPrecisionLabel = "Medium Precision" . Localize ( ) ;
string highPrecisionLabel = "High Precision" . Localize ( ) ;
2018-04-03 12:10:33 -07:00
double bedRadius = Math . Min ( printer . Settings . GetValue < Vector2 > ( SettingsKey . bed_size ) . X , printer . Settings . GetValue < Vector2 > ( SettingsKey . bed_size ) . Y ) / 2 ;
2018-03-29 12:31:36 -07:00
2018-04-03 12:10:33 -07:00
double startProbeHeight = printer . Settings . GetValue < double > ( SettingsKey . print_leveling_probe_start ) ;
2018-03-29 18:12:02 -07:00
int i = 0 ;
2018-03-29 16:48:54 -07:00
foreach ( var goalProbePosition in GetPrintLevelPositionToSample ( ) )
2018-03-29 12:31:36 -07:00
{
2018-04-03 12:10:33 -07:00
var validProbePosition = EnsureInPrintBounds ( printer . Settings , goalProbePosition ) ;
2018-03-29 12:31:36 -07:00
2018-04-03 12:10:33 -07:00
if ( printer . Settings . Helpers . UseZProbe ( ) )
2018-03-29 12:31:36 -07:00
{
2018-04-03 18:17:27 -07:00
var stepString = $"{" Step ".Localize()} {i + 1} {" of ".Localize()} {ProbeCount}:" ;
2018-04-09 12:22:18 -07:00
printLevelWizard . AddPage ( new AutoProbeFeedback ( printer , printLevelWizard , new Vector3 ( validProbePosition , startProbeHeight ) , string . Format ( "{0} {1} {2} - {3}" , stepString , positionLabel , i + 1 , autoCalibrateLabel ) , probePositions , i , theme ) ) ;
2018-03-29 12:31:36 -07:00
}
else
2017-05-19 14:39:57 -07:00
{
2018-04-09 12:22:18 -07:00
printLevelWizard . AddPage ( new GetCoarseBedHeight ( printer , printLevelWizard , new Vector3 ( validProbePosition , startProbeHeight ) , string . Format ( "{0} {1} {2} - {3}" , levelingStrings . GetStepString ( TotalSteps ) , positionLabel , i + 1 , lowPrecisionLabel ) , probePositions , i , levelingStrings , theme ) ) ;
printLevelWizard . AddPage ( new GetFineBedHeight ( printer , printLevelWizard , string . Format ( "{0} {1} {2} - {3}" , levelingStrings . GetStepString ( TotalSteps ) , positionLabel , i + 1 , medPrecisionLabel ) , probePositions , i , levelingStrings , theme ) ) ;
printLevelWizard . AddPage ( new GetUltraFineBedHeight ( printer , printLevelWizard , string . Format ( "{0} {1} {2} - {3}" , levelingStrings . GetStepString ( TotalSteps ) , positionLabel , i + 1 , highPrecisionLabel ) , probePositions , i , levelingStrings , theme ) ) ;
2017-05-19 14:39:57 -07:00
}
2018-03-29 16:48:54 -07:00
i + + ;
2017-05-19 14:39:57 -07:00
}
2018-03-29 12:31:36 -07:00
2018-04-09 12:22:18 -07:00
printLevelWizard . AddPage ( new LastPagelInstructions ( printer , printLevelWizard , "Done" . Localize ( ) , levelingStrings . DoneInstructions , probePositions , theme ) ) ;
2018-03-29 12:31:36 -07:00
}
2018-03-29 18:12:02 -07:00
public abstract int ProbeCount { get ; }
public int TotalSteps = > ProbeCount * 3 ;
2018-03-29 12:31:36 -07:00
2018-04-09 12:22:18 -07:00
public static void ShowPrintLevelWizard ( PrinterConfig printer , ThemeConfig theme )
2015-04-08 15:20:10 -07:00
{
if ( printLevelWizardWindow = = null )
{
2018-04-03 18:17:27 -07:00
// turn off print leveling
2018-04-04 15:58:57 -07:00
PrintLevelingStream . AllowLeveling = false ;
2018-04-03 18:17:27 -07:00
2018-04-09 12:22:18 -07:00
printLevelWizardWindow = LevelWizardBase . CreateAndShowWizard ( printer , theme ) ;
2018-04-03 18:17:27 -07:00
2015-04-08 15:20:10 -07:00
printLevelWizardWindow . Closed + = ( sender , e ) = >
{
2018-04-03 18:17:27 -07:00
// If leveling was on when we started, make sure it is on when we are done.
2018-04-04 15:58:57 -07:00
PrintLevelingStream . AllowLeveling = true ;
2018-04-03 18:17:27 -07:00
2015-04-08 15:20:10 -07:00
printLevelWizardWindow = null ;
2017-06-07 15:56:02 -07:00
2018-03-29 18:12:02 -07:00
// make sure we raise the probe on close
2017-09-15 12:08:00 -07:00
if ( printer . Settings . GetValue < bool > ( SettingsKey . has_z_probe )
& & printer . Settings . GetValue < bool > ( SettingsKey . use_z_probe )
& & printer . Settings . GetValue < bool > ( SettingsKey . has_z_servo ) )
2017-06-07 15:56:02 -07:00
{
// make sure the servo is retracted
2017-09-15 12:08:00 -07:00
var servoRetract = printer . Settings . GetValue < double > ( SettingsKey . z_servo_retracted_angle ) ;
2018-01-04 17:30:48 -08:00
printer . Connection . QueueLine ( $"M280 P0 S{servoRetract}" ) ;
2017-06-07 15:56:02 -07:00
}
2015-04-08 15:20:10 -07:00
} ;
}
else
{
printLevelWizardWindow . BringToFront ( ) ;
}
}
2018-03-29 18:12:02 -07:00
public abstract IEnumerable < Vector2 > GetPrintLevelPositionToSample ( ) ;
2018-04-09 12:22:18 -07:00
private static LevelWizardBase CreateAndShowWizard ( PrinterConfig printer , ThemeConfig theme )
2015-04-08 15:20:10 -07:00
{
2016-10-11 14:56:36 -07:00
// clear any data that we are going to be acquiring (sampled positions, after z home offset)
2018-04-03 18:17:27 -07:00
PrintLevelingData levelingData = new PrintLevelingData ( )
{
LevelingSystem = printer . Settings . GetValue < LevelingSystem > ( SettingsKey . print_leveling_solution )
} ;
2017-09-15 12:08:00 -07:00
printer . Settings . SetValue ( SettingsKey . baby_step_z_offset , "0" ) ;
2017-02-22 16:16:40 -08:00
2015-04-08 15:20:10 -07:00
LevelWizardBase printLevelWizardWindow ;
2018-03-30 14:48:55 -07:00
switch ( levelingData . LevelingSystem )
2015-04-08 15:20:10 -07:00
{
2018-03-30 14:48:55 -07:00
case LevelingSystem . Probe3Points :
2018-04-09 12:22:18 -07:00
printLevelWizardWindow = new LevelWizard3Point ( printer , theme ) ;
2015-04-08 15:20:10 -07:00
break ;
2018-03-30 14:48:55 -07:00
case LevelingSystem . Probe7PointRadial :
2018-04-09 12:22:18 -07:00
printLevelWizardWindow = new LevelWizard7PointRadial ( printer , theme ) ;
2015-08-01 14:44:53 -07:00
break ;
2018-03-30 14:48:55 -07:00
case LevelingSystem . Probe13PointRadial :
2018-04-09 12:22:18 -07:00
printLevelWizardWindow = new LevelWizard13PointRadial ( printer , theme ) ;
2015-08-05 11:12:01 -07:00
break ;
2018-03-30 14:48:55 -07:00
case LevelingSystem . Probe3x3Mesh :
2018-04-09 12:22:18 -07:00
printLevelWizardWindow = new LevelWizard3x3Mesh ( printer , theme ) ;
2017-05-19 14:39:57 -07:00
break ;
2018-04-04 13:45:10 -07:00
case LevelingSystem . Probe5x5Mesh :
2018-04-09 12:22:18 -07:00
printLevelWizardWindow = new LevelWizard5x5Mesh ( printer , theme ) ;
2018-04-04 13:45:10 -07:00
break ;
2015-04-08 15:20:10 -07:00
default :
throw new NotImplementedException ( ) ;
}
printLevelWizardWindow . ShowAsSystemWindow ( ) ;
return printLevelWizardWindow ;
}
2018-03-29 18:12:02 -07:00
private Vector2 EnsureInPrintBounds ( PrinterSettings printerSettings , Vector2 probePosition )
{
// check that the position is within the printing arrea and if not move it back in
if ( printerSettings . Helpers . UseZProbe ( ) )
{
var probeOffset = printer . Settings . GetValue < Vector2 > ( SettingsKey . z_probe_xy_offset ) ;
2018-04-04 14:57:59 -07:00
var actualNozzlePosition = probePosition - probeOffset ;
2018-04-04 15:58:57 -07:00
2018-03-29 18:12:02 -07:00
// clamp this to the bed bounds
2018-04-04 14:57:59 -07:00
Vector2 bedSize = printer . Settings . GetValue < Vector2 > ( SettingsKey . bed_size ) ;
Vector2 printCenter = printer . Settings . GetValue < Vector2 > ( SettingsKey . print_center ) ;
RectangleDouble bedBounds = new RectangleDouble ( printCenter - bedSize / 2 , printCenter + bedSize / 2 ) ;
2018-04-04 15:58:57 -07:00
Vector2 adjustedPosition = bedBounds . Clamp ( actualNozzlePosition ) ;
2018-03-29 18:12:02 -07:00
// and push it back into the probePosition
2018-04-04 15:58:57 -07:00
probePosition = adjustedPosition + probeOffset ;
2018-03-29 18:12:02 -07:00
}
return probePosition ;
}
2015-04-08 15:20:10 -07:00
}
2018-03-29 18:12:02 -07:00
// this class is so that it is not passed by value
public class ProbePosition
2015-04-08 15:20:10 -07:00
{
2018-03-29 18:12:02 -07:00
public Vector3 position ;
2015-04-08 15:20:10 -07:00
}
}