Add homing order to config
[clinton/Smoothieware.git] / src / modules / tools / zprobe / ThreePointStrategy.cpp
CommitLineData
97832d6d
JM
1#include "ThreePointStrategy.h"
2#include "Kernel.h"
3#include "Config.h"
4#include "Robot.h"
5#include "StreamOutputPool.h"
6#include "Gcode.h"
7#include "checksumm.h"
8#include "ConfigValue.h"
9#include "PublicDataRequest.h"
10#include "PublicData.h"
11#include "Conveyor.h"
12#include "ZProbe.h"
a5542cae 13#include "Plane3D.h"
97832d6d
JM
14
15#include <string>
16#include <algorithm>
0e44e7d7 17#include <cstdlib>
a5542cae 18#include <cmath>
97832d6d
JM
19
20#define probe_point_1_checksum CHECKSUM("point1")
21#define probe_point_2_checksum CHECKSUM("point2")
22#define probe_point_3_checksum CHECKSUM("point3")
23
a5542cae
JM
24ThreePointStrategy::ThreePointStrategy(ZProbe *zprobe) : LevelingStrategy(zprobe)
25{
26 for (int i = 0; i < 3; ++i) {
27 probe_points[i] = std::make_tuple(NAN, NAN);
28 }
29 plane = nullptr;
30}
31
32ThreePointStrategy::~ThreePointStrategy()
33{
34 delete plane;
35}
97832d6d
JM
36
37bool ThreePointStrategy::handleConfig()
38{
0e44e7d7 39 // format is xxx,yyy for the probe points
a5542cae
JM
40 std::string p1 = THEKERNEL->config->value(leveling_strategy_checksum, three_point_leveling_strategy_checksum, probe_point_1_checksum)->by_default("")->as_string();
41 std::string p2 = THEKERNEL->config->value(leveling_strategy_checksum, three_point_leveling_strategy_checksum, probe_point_2_checksum)->by_default("")->as_string();
42 std::string p3 = THEKERNEL->config->value(leveling_strategy_checksum, three_point_leveling_strategy_checksum, probe_point_3_checksum)->by_default("")->as_string();
43 if(!p1.empty()) probe_points[0] = parseXY(p1.c_str());
44 if(!p2.empty()) probe_points[1] = parseXY(p2.c_str());
45 if(!p3.empty()) probe_points[2] = parseXY(p3.c_str());
97832d6d
JM
46 return true;
47}
48
49bool ThreePointStrategy::handleGcode(Gcode *gcode)
50{
51 if( gcode->has_g) {
52 // G code processing
53 if( gcode->g == 32 ) { // three point probe
54 // first wait for an empty queue i.e. no moves left
55 THEKERNEL->conveyor->wait_for_empty_queue();
0e44e7d7
JM
56 if(!doProbing(gcode->stream)) {
57 gcode->stream->printf("Probe failed to complete, probe not triggered\n");
a5542cae 58 } else {
0e44e7d7
JM
59 gcode->stream->printf("Probe completed, bed plane defined\n");
60 }
97832d6d
JM
61 return true;
62 }
63
64 } else if(gcode->has_m) {
0e44e7d7 65 if(gcode->m == 557) { // M557 - set probe points eg M557 P0 X30 Y40.5 where P is 0,1,2
a5542cae
JM
66 int idx = 0;
67 float x = NAN, y = NAN;
68 if(gcode->has_letter('P')) idx = gcode->get_value('P');
69 if(gcode->has_letter('X')) x = gcode->get_value('X');
70 if(gcode->has_letter('Y')) y = gcode->get_value('Y');
0e44e7d7 71 if(idx >= 0 && idx <= 2) {
a5542cae 72 probe_points[idx] = std::make_tuple(x, y);
0e44e7d7
JM
73 }
74 return true;
75
a5542cae 76 } else if(gcode->m == 503) {
0e44e7d7
JM
77 gcode->stream->printf(";Probe points:\n");
78 for (int i = 0; i < 3; ++i) {
79 float x, y;
80 std::tie(x, y) = probe_points[i];
81 gcode->stream->printf("M557 P%d X%1.5f Y%1.5f\n", i, x, y);
82 }
ff7e9858 83 // TODO encode plane if set and M500
0e44e7d7
JM
84 return true;
85 }
97832d6d
JM
86 }
87
88 return false;
89}
90
ff7e9858
JM
91void ThreePointStrategy::homeXY()
92{
93 Gcode gc("G28 X0 Y0", &(StreamOutput::NullStream));
94 THEKERNEL->call_event(ON_GCODE_RECEIVED, &gc);
95}
96
0e44e7d7
JM
97bool ThreePointStrategy::doProbing(StreamOutput *stream)
98{
99 float x, y;
100 // check the probe points have been defined
101 for (int i = 0; i < 3; ++i) {
102 std::tie(x, y) = probe_points[i];
103 if(isnan(x) || isnan(y)) {
a5542cae
JM
104 stream->printf("Probe point P%d has not been defined, use M557 P%d Xnnn Ynnn to define it\n", i, i);
105 return false;
0e44e7d7
JM
106 }
107 }
108
80605954 109 // TODO allow for manual homing
ff7e9858
JM
110 // home X & Y
111 homeXY();
112
113 // move to the first probe point
114 std::tie(x, y) = probe_points[0];
115 zprobe->coordinated_move(x, y, NAN, zprobe->getFastFeedrate());
0e44e7d7 116
ff7e9858
JM
117 // for now we use probe to find bed and not the Z min endstop
118 // TODO this needs to be configurable to use min z or probe
119
120 // find bed via probe
121 int s;
122 if(!zprobe->run_probe(s, true)) return false;
123 // do we need to set set to Z == 0 here? as the rest is relative anyway
124
125 // move up to specified probe start position
0e44e7d7
JM
126 zprobe->coordinated_move(NAN, NAN, zprobe->getProbeHeight(), zprobe->getFastFeedrate(), true); // do a relative move from home to the point above the bed
127
128 // probe the three points
129 Vector3 v[3];
130 for (int i = 0; i < 3; ++i) {
131 std::tie(x, y) = probe_points[i];
ff7e9858 132 float z = zprobe->probeDistance(x, y);
0e44e7d7 133 if(isnan(z)) return false; // probe failed
ff7e9858 134 z -= zprobe->getProbeHeight(); // relative distance between the probe points
0e44e7d7
JM
135 stream->printf("DEBUG: P%d:%1.4f\n", i, z);
136 v[i].set(x, y, z);
137 }
138
80605954
JM
139 // TODO if first point is not within toloerance of of probe height report it.
140
0e44e7d7
JM
141 // define the plane
142 delete this->plane;
80605954 143 // TODO set a tolerance level here default 0.03mm
ff7e9858
JM
144 if(v[0][2] == v[1][2] && v[1][2] == v[2][2]) {
145 this->plane= nullptr; // plane is flat no need to do anything
146 stream->printf("DEBUG: flat plane\n");
147 // THEKERNEL->robot->adjustZfnc= nullptr;
148 }else{
149 this->plane = new Plane3D(v[0], v[1], v[2]);
150 stream->printf("DEBUG: plane normal= %f, %f, %f\n", plane->getNormal()[0], plane->getNormal()[1], plane->getNormal()[2]);
151 // TODO set the adjustZfnc in robot
152 // THEKERNEL->robot->adjustZfnc= [this](float x, float y) { return this->getZOffset(x, y); }
153 }
0e44e7d7
JM
154
155 return true;
156}
157
158// find the Z offset for the point on the plane at x, y
159float ThreePointStrategy::getZOffset(float x, float y)
160{
ff7e9858
JM
161 if(this->plane == nullptr) return NAN;
162 return this->plane->getz(x, y);
0e44e7d7 163}
97832d6d 164
0e44e7d7 165// parse a "X,Y" string return x,y
a5542cae
JM
166std::tuple<float, float> ThreePointStrategy::parseXY(const char *str)
167{
168 float x = NAN, y = NAN;
0e44e7d7 169 char *p;
a5542cae
JM
170 x = strtof(str, &p);
171 if(p + 1 < str + strlen(str)) {
172 y = strtof(p + 1, nullptr);
0e44e7d7
JM
173 }
174 return std::make_tuple(x, y);
175}