|
@@ -894,7 +894,7 @@ static void set_bed_level_equation_lsq(double *plane_equation_coefficients)
|
894
|
894
|
current_position[Y_AXIS] = corrected_position.y;
|
895
|
895
|
current_position[Z_AXIS] = corrected_position.z;
|
896
|
896
|
|
897
|
|
- // but the bed at 0 so we don't go below it.
|
|
897
|
+ // put the bed at 0 so we don't go below it.
|
898
|
898
|
current_position[Z_AXIS] = zprobe_zoffset; // in the lsq we reach here after raising the extruder due to the loop structure
|
899
|
899
|
|
900
|
900
|
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
|
|
@@ -1862,6 +1862,280 @@ void process_commands()
|
1862
|
1862
|
}
|
1863
|
1863
|
}
|
1864
|
1864
|
break;
|
|
1865
|
+
|
|
1866
|
+// M48 Z-Probe repeatability measurement function.
|
|
1867
|
+//
|
|
1868
|
+// Usage: M48 <n #_samples> <X X_position_for_samples> <Y Y_position_for_samples> <V Verbose_Level> <Engage_probe_for_each_reading> <L legs_of_movement_prior_to_doing_probe>
|
|
1869
|
+//
|
|
1870
|
+// This function assumes the bed has been homed. Specificaly, that a G28 command
|
|
1871
|
+// as been issued prior to invoking the M48 Z-Probe repeatability measurement function.
|
|
1872
|
+// Any information generated by a prior G29 Bed leveling command will be lost and need to be
|
|
1873
|
+// regenerated.
|
|
1874
|
+//
|
|
1875
|
+// The number of samples will default to 10 if not specified. You can use upper or lower case
|
|
1876
|
+// letters for any of the options EXCEPT n. n must be in lower case because Marlin uses a capital
|
|
1877
|
+// N for its communication protocol and will get horribly confused if you send it a capital N.
|
|
1878
|
+//
|
|
1879
|
+
|
|
1880
|
+#ifdef ENABLE_AUTO_BED_LEVELING
|
|
1881
|
+#ifdef Z_PROBE_REPEATABILITY_TEST
|
|
1882
|
+
|
|
1883
|
+ case 48: // M48 Z-Probe repeatability
|
|
1884
|
+ {
|
|
1885
|
+ #if Z_MIN_PIN == -1
|
|
1886
|
+ #error "You must have a Z_MIN endstop in order to enable calculation of Z-Probe repeatability."
|
|
1887
|
+ #endif
|
|
1888
|
+
|
|
1889
|
+ double sum=0.0;
|
|
1890
|
+ double mean=0.0;
|
|
1891
|
+ double sigma=0.0;
|
|
1892
|
+ double sample_set[50];
|
|
1893
|
+ int verbose_level=1, n=0, j, n_samples = 10, n_legs=0, engage_probe_for_each_reading=0 ;
|
|
1894
|
+ double X_current, Y_current, Z_current;
|
|
1895
|
+ double X_probe_location, Y_probe_location, Z_start_location, ext_position;
|
|
1896
|
+
|
|
1897
|
+ if (code_seen('V') || code_seen('v')) {
|
|
1898
|
+ verbose_level = code_value();
|
|
1899
|
+ if (verbose_level<0 || verbose_level>4 ) {
|
|
1900
|
+ SERIAL_PROTOCOLPGM("?Verbose Level not plausable.\n");
|
|
1901
|
+ goto Sigma_Exit;
|
|
1902
|
+ }
|
|
1903
|
+ }
|
|
1904
|
+
|
|
1905
|
+ if (verbose_level > 0) {
|
|
1906
|
+ SERIAL_PROTOCOLPGM("M48 Z-Probe Repeatability test. Version 2.00\n");
|
|
1907
|
+ SERIAL_PROTOCOLPGM("Full support at: http://3dprintboard.com/forum.php\n");
|
|
1908
|
+ }
|
|
1909
|
+
|
|
1910
|
+ if (code_seen('n')) {
|
|
1911
|
+ n_samples = code_value();
|
|
1912
|
+ if (n_samples<4 || n_samples>50 ) {
|
|
1913
|
+ SERIAL_PROTOCOLPGM("?Specified sample size not plausable.\n");
|
|
1914
|
+ goto Sigma_Exit;
|
|
1915
|
+ }
|
|
1916
|
+ }
|
|
1917
|
+
|
|
1918
|
+ X_current = X_probe_location = st_get_position_mm(X_AXIS);
|
|
1919
|
+ Y_current = Y_probe_location = st_get_position_mm(Y_AXIS);
|
|
1920
|
+ Z_current = st_get_position_mm(Z_AXIS);
|
|
1921
|
+ Z_start_location = st_get_position_mm(Z_AXIS) + Z_RAISE_BEFORE_PROBING;
|
|
1922
|
+ ext_position = st_get_position_mm(E_AXIS);
|
|
1923
|
+
|
|
1924
|
+ if (code_seen('E') || code_seen('e') )
|
|
1925
|
+ engage_probe_for_each_reading++;
|
|
1926
|
+
|
|
1927
|
+ if (code_seen('X') || code_seen('x') ) {
|
|
1928
|
+ X_probe_location = code_value() - X_PROBE_OFFSET_FROM_EXTRUDER;
|
|
1929
|
+ if (X_probe_location<X_MIN_POS || X_probe_location>X_MAX_POS ) {
|
|
1930
|
+ SERIAL_PROTOCOLPGM("?Specified X position out of range.\n");
|
|
1931
|
+ goto Sigma_Exit;
|
|
1932
|
+ }
|
|
1933
|
+ }
|
|
1934
|
+
|
|
1935
|
+ if (code_seen('Y') || code_seen('y') ) {
|
|
1936
|
+ Y_probe_location = code_value() - Y_PROBE_OFFSET_FROM_EXTRUDER;
|
|
1937
|
+ if (Y_probe_location<Y_MIN_POS || Y_probe_location>Y_MAX_POS ) {
|
|
1938
|
+ SERIAL_PROTOCOLPGM("?Specified Y position out of range.\n");
|
|
1939
|
+ goto Sigma_Exit;
|
|
1940
|
+ }
|
|
1941
|
+ }
|
|
1942
|
+
|
|
1943
|
+ if (code_seen('L') || code_seen('l') ) {
|
|
1944
|
+ n_legs = code_value();
|
|
1945
|
+ if ( n_legs==1 )
|
|
1946
|
+ n_legs = 2;
|
|
1947
|
+ if ( n_legs<0 || n_legs>15 ) {
|
|
1948
|
+ SERIAL_PROTOCOLPGM("?Specified number of legs in movement not plausable.\n");
|
|
1949
|
+ goto Sigma_Exit;
|
|
1950
|
+ }
|
|
1951
|
+ }
|
|
1952
|
+
|
|
1953
|
+//
|
|
1954
|
+// Do all the preliminary setup work. First raise the probe.
|
|
1955
|
+//
|
|
1956
|
+
|
|
1957
|
+ st_synchronize();
|
|
1958
|
+ plan_bed_level_matrix.set_to_identity();
|
|
1959
|
+ plan_buffer_line( X_current, Y_current, Z_start_location,
|
|
1960
|
+ ext_position,
|
|
1961
|
+ homing_feedrate[Z_AXIS]/60,
|
|
1962
|
+ active_extruder);
|
|
1963
|
+ st_synchronize();
|
|
1964
|
+
|
|
1965
|
+//
|
|
1966
|
+// Now get everything to the specified probe point So we can safely do a probe to
|
|
1967
|
+// get us close to the bed. If the Z-Axis is far from the bed, we don't want to
|
|
1968
|
+// use that as a starting point for each probe.
|
|
1969
|
+//
|
|
1970
|
+ if (verbose_level > 2)
|
|
1971
|
+ SERIAL_PROTOCOL("Positioning probe for the test.\n");
|
|
1972
|
+
|
|
1973
|
+ plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location,
|
|
1974
|
+ ext_position,
|
|
1975
|
+ homing_feedrate[X_AXIS]/60,
|
|
1976
|
+ active_extruder);
|
|
1977
|
+ st_synchronize();
|
|
1978
|
+
|
|
1979
|
+ current_position[X_AXIS] = X_current = st_get_position_mm(X_AXIS);
|
|
1980
|
+ current_position[Y_AXIS] = Y_current = st_get_position_mm(Y_AXIS);
|
|
1981
|
+ current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS);
|
|
1982
|
+ current_position[E_AXIS] = ext_position = st_get_position_mm(E_AXIS);
|
|
1983
|
+
|
|
1984
|
+//
|
|
1985
|
+// OK, do the inital probe to get us close to the bed.
|
|
1986
|
+// Then retrace the right amount and use that in subsequent probes
|
|
1987
|
+//
|
|
1988
|
+
|
|
1989
|
+ engage_z_probe();
|
|
1990
|
+
|
|
1991
|
+ setup_for_endstop_move();
|
|
1992
|
+ run_z_probe();
|
|
1993
|
+
|
|
1994
|
+ current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS);
|
|
1995
|
+ Z_start_location = st_get_position_mm(Z_AXIS) + Z_RAISE_BEFORE_PROBING;
|
|
1996
|
+
|
|
1997
|
+ plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location,
|
|
1998
|
+ ext_position,
|
|
1999
|
+ homing_feedrate[X_AXIS]/60,
|
|
2000
|
+ active_extruder);
|
|
2001
|
+ st_synchronize();
|
|
2002
|
+ current_position[Z_AXIS] = Z_current = st_get_position_mm(Z_AXIS);
|
|
2003
|
+
|
|
2004
|
+ if (engage_probe_for_each_reading)
|
|
2005
|
+ retract_z_probe();
|
|
2006
|
+
|
|
2007
|
+ for( n=0; n<n_samples; n++) {
|
|
2008
|
+
|
|
2009
|
+ do_blocking_move_to( X_probe_location, Y_probe_location, Z_start_location); // Make sure we are at the probe location
|
|
2010
|
+
|
|
2011
|
+ if ( n_legs) {
|
|
2012
|
+ double radius=0.0, theta=0.0, x_sweep, y_sweep;
|
|
2013
|
+ int rotational_direction, l;
|
|
2014
|
+
|
|
2015
|
+ rotational_direction = (unsigned long) millis() & 0x0001; // clockwise or counter clockwise
|
|
2016
|
+ radius = (unsigned long) millis() % (long) (X_MAX_LENGTH/4); // limit how far out to go
|
|
2017
|
+ theta = (float) ((unsigned long) millis() % (long) 360) / (360./(2*3.1415926)); // turn into radians
|
|
2018
|
+
|
|
2019
|
+//SERIAL_ECHOPAIR("starting radius: ",radius);
|
|
2020
|
+//SERIAL_ECHOPAIR(" theta: ",theta);
|
|
2021
|
+//SERIAL_ECHOPAIR(" direction: ",rotational_direction);
|
|
2022
|
+//SERIAL_PROTOCOLLNPGM("");
|
|
2023
|
+
|
|
2024
|
+ for( l=0; l<n_legs-1; l++) {
|
|
2025
|
+ if (rotational_direction==1)
|
|
2026
|
+ theta += (float) ((unsigned long) millis() % (long) 20) / (360.0/(2*3.1415926)); // turn into radians
|
|
2027
|
+ else
|
|
2028
|
+ theta -= (float) ((unsigned long) millis() % (long) 20) / (360.0/(2*3.1415926)); // turn into radians
|
|
2029
|
+
|
|
2030
|
+ radius += (float) ( ((long) ((unsigned long) millis() % (long) 10)) - 5);
|
|
2031
|
+ if ( radius<0.0 )
|
|
2032
|
+ radius = -radius;
|
|
2033
|
+
|
|
2034
|
+ X_current = X_probe_location + cos(theta) * radius;
|
|
2035
|
+ Y_current = Y_probe_location + sin(theta) * radius;
|
|
2036
|
+
|
|
2037
|
+ if ( X_current<X_MIN_POS) // Make sure our X & Y are sane
|
|
2038
|
+ X_current = X_MIN_POS;
|
|
2039
|
+ if ( X_current>X_MAX_POS)
|
|
2040
|
+ X_current = X_MAX_POS;
|
|
2041
|
+
|
|
2042
|
+ if ( Y_current<Y_MIN_POS) // Make sure our X & Y are sane
|
|
2043
|
+ Y_current = Y_MIN_POS;
|
|
2044
|
+ if ( Y_current>Y_MAX_POS)
|
|
2045
|
+ Y_current = Y_MAX_POS;
|
|
2046
|
+
|
|
2047
|
+ if (verbose_level>3 ) {
|
|
2048
|
+ SERIAL_ECHOPAIR("x: ", X_current);
|
|
2049
|
+ SERIAL_ECHOPAIR("y: ", Y_current);
|
|
2050
|
+ SERIAL_PROTOCOLLNPGM("");
|
|
2051
|
+ }
|
|
2052
|
+
|
|
2053
|
+ do_blocking_move_to( X_current, Y_current, Z_current );
|
|
2054
|
+ }
|
|
2055
|
+ do_blocking_move_to( X_probe_location, Y_probe_location, Z_start_location); // Go back to the probe location
|
|
2056
|
+ }
|
|
2057
|
+
|
|
2058
|
+ if (engage_probe_for_each_reading) {
|
|
2059
|
+ engage_z_probe();
|
|
2060
|
+ delay(1000);
|
|
2061
|
+ }
|
|
2062
|
+
|
|
2063
|
+ setup_for_endstop_move();
|
|
2064
|
+ run_z_probe();
|
|
2065
|
+
|
|
2066
|
+ sample_set[n] = current_position[Z_AXIS];
|
|
2067
|
+
|
|
2068
|
+//
|
|
2069
|
+// Get the current mean for the data points we have so far
|
|
2070
|
+//
|
|
2071
|
+ sum=0.0;
|
|
2072
|
+ for( j=0; j<=n; j++) {
|
|
2073
|
+ sum = sum + sample_set[j];
|
|
2074
|
+ }
|
|
2075
|
+ mean = sum / (double (n+1));
|
|
2076
|
+//
|
|
2077
|
+// Now, use that mean to calculate the standard deviation for the
|
|
2078
|
+// data points we have so far
|
|
2079
|
+//
|
|
2080
|
+
|
|
2081
|
+ sum=0.0;
|
|
2082
|
+ for( j=0; j<=n; j++) {
|
|
2083
|
+ sum = sum + (sample_set[j]-mean) * (sample_set[j]-mean);
|
|
2084
|
+ }
|
|
2085
|
+ sigma = sqrt( sum / (double (n+1)) );
|
|
2086
|
+
|
|
2087
|
+ if (verbose_level > 1) {
|
|
2088
|
+ SERIAL_PROTOCOL(n+1);
|
|
2089
|
+ SERIAL_PROTOCOL(" of ");
|
|
2090
|
+ SERIAL_PROTOCOL(n_samples);
|
|
2091
|
+ SERIAL_PROTOCOLPGM(" z: ");
|
|
2092
|
+ SERIAL_PROTOCOL_F(current_position[Z_AXIS], 6);
|
|
2093
|
+ }
|
|
2094
|
+
|
|
2095
|
+ if (verbose_level > 2) {
|
|
2096
|
+ SERIAL_PROTOCOL(" mean: ");
|
|
2097
|
+ SERIAL_PROTOCOL_F(mean,6);
|
|
2098
|
+
|
|
2099
|
+ SERIAL_PROTOCOL(" sigma: ");
|
|
2100
|
+ SERIAL_PROTOCOL_F(sigma,6);
|
|
2101
|
+ }
|
|
2102
|
+
|
|
2103
|
+ if (verbose_level > 0)
|
|
2104
|
+ SERIAL_PROTOCOLPGM("\n");
|
|
2105
|
+
|
|
2106
|
+ plan_buffer_line( X_probe_location, Y_probe_location, Z_start_location,
|
|
2107
|
+ current_position[E_AXIS], homing_feedrate[Z_AXIS]/60, active_extruder);
|
|
2108
|
+ st_synchronize();
|
|
2109
|
+
|
|
2110
|
+ if (engage_probe_for_each_reading) {
|
|
2111
|
+ retract_z_probe();
|
|
2112
|
+ delay(1000);
|
|
2113
|
+ }
|
|
2114
|
+ }
|
|
2115
|
+
|
|
2116
|
+ retract_z_probe();
|
|
2117
|
+ delay(1000);
|
|
2118
|
+
|
|
2119
|
+ clean_up_after_endstop_move();
|
|
2120
|
+
|
|
2121
|
+// enable_endstops(true);
|
|
2122
|
+
|
|
2123
|
+ if (verbose_level > 0) {
|
|
2124
|
+ SERIAL_PROTOCOLPGM("Mean: ");
|
|
2125
|
+ SERIAL_PROTOCOL_F(mean, 6);
|
|
2126
|
+ SERIAL_PROTOCOLPGM("\n");
|
|
2127
|
+ }
|
|
2128
|
+
|
|
2129
|
+SERIAL_PROTOCOLPGM("Standard Deviation: ");
|
|
2130
|
+SERIAL_PROTOCOL_F(sigma, 6);
|
|
2131
|
+SERIAL_PROTOCOLPGM("\n\n");
|
|
2132
|
+
|
|
2133
|
+Sigma_Exit:
|
|
2134
|
+ break;
|
|
2135
|
+ }
|
|
2136
|
+#endif // Z_PROBE_REPEATABILITY_TEST
|
|
2137
|
+#endif // ENABLE_AUTO_BED_LEVELING
|
|
2138
|
+
|
1865
|
2139
|
case 104: // M104
|
1866
|
2140
|
if(setTargetedHotend(104)){
|
1867
|
2141
|
break;
|