Commit | Line | Data |
---|---|---|
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 |
24 | ThreePointStrategy::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 | ||
32 | ThreePointStrategy::~ThreePointStrategy() | |
33 | { | |
34 | delete plane; | |
35 | } | |
97832d6d JM |
36 | |
37 | bool 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 | ||
49 | bool 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 |
91 | void ThreePointStrategy::homeXY() |
92 | { | |
93 | Gcode gc("G28 X0 Y0", &(StreamOutput::NullStream)); | |
94 | THEKERNEL->call_event(ON_GCODE_RECEIVED, &gc); | |
95 | } | |
96 | ||
0e44e7d7 JM |
97 | bool 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 | |
159 | float 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 |
166 | std::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 | } |