Commit | Line | Data |
---|---|---|
ed866a4b QH |
1 | /* |
2 | This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl). | |
3 | Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | |
4 | Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |
5 | You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>. | |
6 | */ | |
7 | ||
8 | #include "SCARAcal.h" | |
9 | ||
10 | #include "Kernel.h" | |
11 | #include "BaseSolution.h" | |
12 | #include "Config.h" | |
13 | #include "Robot.h" | |
14 | #include "StepperMotor.h" | |
15 | #include "StreamOutputPool.h" | |
16 | #include "Gcode.h" | |
17 | #include "Conveyor.h" | |
18 | #include "Stepper.h" | |
19 | #include "checksumm.h" | |
20 | #include "ConfigValue.h" | |
21 | #include "SerialMessage.h" | |
22 | #include "EndstopsPublicAccess.h" | |
23 | #include "PublicData.h" | |
983e6549 QH |
24 | #include <algorithm> |
25 | #include <map> | |
ed866a4b | 26 | |
33bacc39 QH |
27 | #define scaracal_checksum CHECKSUM("scaracal") |
28 | #define enable_checksum CHECKSUM("enable") | |
29 | #define slow_feedrate_checksum CHECKSUM("slow_feedrate") | |
ed866a4b QH |
30 | |
31 | #define X_AXIS 0 | |
32 | #define Y_AXIS 1 | |
33 | #define Z_AXIS 2 | |
34 | ||
35 | #define STEPPER THEKERNEL->robot->actuators | |
36 | #define STEPS_PER_MM(a) (STEPPER[a]->get_steps_per_mm()) | |
ed866a4b QH |
37 | |
38 | void SCARAcal::on_module_loaded() | |
39 | { | |
40 | // if the module is disabled -> do nothing | |
33bacc39 | 41 | if(!THEKERNEL->config->value( scaracal_checksum, enable_checksum )->by_default(false)->as_bool()) { |
ed866a4b QH |
42 | // as this module is not needed free up the resource |
43 | delete this; | |
44 | return; | |
45 | } | |
46 | ||
47 | // load settings | |
48 | this->on_config_reload(this); | |
49 | // register event-handlers | |
50 | register_for_event(ON_GCODE_RECEIVED); | |
ed866a4b QH |
51 | } |
52 | ||
53 | void SCARAcal::on_config_reload(void *argument) | |
54 | { | |
33bacc39 | 55 | this->slow_rate = THEKERNEL->config->value( scaracal_checksum, slow_feedrate_checksum )->by_default(5)->as_number(); // feedrate in mm/sec |
ed866a4b QH |
56 | |
57 | } | |
58 | ||
ed866a4b QH |
59 | |
60 | // issue home command | |
61 | void SCARAcal::home() | |
62 | { | |
63 | Gcode gc("G28", &(StreamOutput::NullStream)); | |
64 | THEKERNEL->call_event(ON_GCODE_RECEIVED, &gc); | |
65 | } | |
66 | ||
157d2308 QH |
67 | bool SCARAcal::get_trim(float& x, float& y, float& z) |
68 | { | |
69 | void *returned_data; | |
70 | bool ok = PublicData::get_value( endstops_checksum, trim_checksum, &returned_data ); | |
71 | ||
72 | if (ok) { | |
73 | float *trim = static_cast<float *>(returned_data); | |
74 | x= trim[0]; | |
75 | y= trim[1]; | |
76 | z= trim[2]; | |
77 | return true; | |
78 | } | |
79 | return false; | |
80 | } | |
81 | ||
ed866a4b QH |
82 | bool SCARAcal::set_trim(float x, float y, float z, StreamOutput *stream) |
83 | { | |
84 | float t[3]{x, y, z}; | |
85 | bool ok= PublicData::set_value( endstops_checksum, trim_checksum, t); | |
86 | ||
87 | if (ok) { | |
88 | stream->printf("set trim to X:%f Y:%f Z:%f\n", x, y, z); | |
89 | } else { | |
90 | stream->printf("unable to set trim, is endstops enabled?\n"); | |
91 | } | |
92 | ||
93 | return ok; | |
94 | } | |
95 | ||
157d2308 | 96 | bool SCARAcal::get_home_offset(float& x, float& y, float& z) |
ed866a4b QH |
97 | { |
98 | void *returned_data; | |
157d2308 | 99 | bool ok = PublicData::get_value( endstops_checksum, home_offset_checksum, &returned_data ); |
ed866a4b QH |
100 | |
101 | if (ok) { | |
157d2308 QH |
102 | float *home_offset = static_cast<float *>(returned_data); |
103 | x= home_offset[0]; | |
104 | y= home_offset[1]; | |
105 | z= home_offset[2]; | |
ed866a4b QH |
106 | return true; |
107 | } | |
108 | return false; | |
109 | } | |
110 | ||
157d2308 QH |
111 | bool SCARAcal::set_home_offset(float x, float y, float z, StreamOutput *stream) |
112 | { | |
113 | char cmd[64]; | |
114 | ||
115 | // Assemble Gcode to add onto the queue | |
116 | snprintf(cmd, sizeof(cmd), "M206 X%1.3f Y%1.3f Z%1.3f", x, y, z); // Send saved Z homing offset | |
117 | ||
118 | Gcode gc(cmd, &(StreamOutput::NullStream)); | |
119 | THEKERNEL->call_event(ON_GCODE_RECEIVED, &gc); | |
120 | ||
983e6549 | 121 | stream->printf("Set home_offset to X:%f Y:%f Z:%f\n", x, y, z); |
157d2308 QH |
122 | |
123 | return true;//ok; | |
124 | } | |
125 | ||
126 | bool SCARAcal::translate_trim(StreamOutput *stream) | |
127 | { | |
128 | float S_trim[3], | |
129 | home_off[3], | |
130 | actuator[3];; | |
131 | ||
132 | this->get_home_offset(home_off[0], home_off[1], home_off[2]); // get home offsets | |
133 | this->get_trim(S_trim[0], S_trim[1], S_trim[2]); // get current trim | |
134 | ||
135 | THEKERNEL->robot->arm_solution->cartesian_to_actuator( home_off, actuator ); // convert current home offset to actuator angles | |
136 | ||
137 | // Subtract trim values from actuators to determine the real home offset actuator position for X and Y. | |
138 | ||
139 | actuator[0] -= S_trim[0]; | |
140 | actuator[1] -= S_trim[1]; | |
141 | ||
142 | // Clear X and Y trims internally | |
143 | S_trim[0] = 0.0F; | |
144 | S_trim[1] = 0.0F; | |
145 | ||
146 | // convert back to get the real cartesian home offsets | |
147 | ||
148 | THEKERNEL->robot->arm_solution->actuator_to_cartesian( actuator, home_off ); | |
149 | ||
150 | this->set_home_offset(home_off[0], home_off[1], home_off[2],stream); // get home offsets | |
151 | // Set the correct home offsets; | |
152 | ||
153 | this->set_trim(S_trim[0], S_trim[1], S_trim[2], stream); // Now Clear relevant trims | |
154 | ||
155 | return true; | |
156 | } | |
157 | ||
ed866a4b QH |
158 | void SCARAcal::SCARA_ang_move(float theta, float psi, float z, float feedrate) |
159 | { | |
ed866a4b | 160 | char cmd[64]; |
ed866a4b QH |
161 | float actuator[3], |
162 | cartesian[3]; | |
163 | ||
164 | // Assign the actuator angles from input | |
165 | actuator[0] = theta; | |
166 | actuator[1] = psi; | |
167 | actuator[2] = z; | |
168 | ||
169 | // Calculate the physical position relating to the arm angles | |
170 | THEKERNEL->robot->arm_solution->actuator_to_cartesian( actuator, cartesian ); | |
171 | ||
172 | // Assemble Gcode to add onto the queue | |
c2663be2 | 173 | snprintf(cmd, sizeof(cmd), "G0 X%1.3f Y%1.3f Z%1.3f F%1.1f", cartesian[0], cartesian[1], cartesian[2], feedrate * 60); // use specified feedrate (mm/sec) |
ed866a4b | 174 | |
33bacc39 | 175 | //THEKERNEL->streams->printf("DEBUG: move: %s\n", cmd); |
ed866a4b | 176 | |
e0c008fe QH |
177 | Gcode gc(cmd, &(StreamOutput::NullStream)); |
178 | THEKERNEL->robot->on_gcode_received(&gc); // send to robot directly | |
ed866a4b QH |
179 | } |
180 | ||
181 | //A GCode has been received | |
182 | //See if the current Gcode line has some orders for us | |
183 | void SCARAcal::on_gcode_received(void *argument) | |
184 | { | |
185 | Gcode *gcode = static_cast<Gcode *>(argument); | |
186 | ||
187 | if( gcode->has_m) { | |
188 | switch( gcode->m ) { | |
189 | ||
190 | case 114: { // Extra stuff for Morgan calibration | |
191 | char buf[32]; | |
192 | float cartesian[3], | |
193 | actuators[3]; | |
194 | ||
195 | THEKERNEL->robot->get_axis_position(cartesian); // get actual position from robot | |
196 | THEKERNEL->robot->arm_solution->cartesian_to_actuator( cartesian, actuators ); // translate to get actuator position | |
197 | ||
e0c008fe | 198 | int n = snprintf(buf, sizeof(buf), " A: Th:%1.3f Ps:%1.3f", |
ed866a4b | 199 | actuators[0], |
33bacc39 | 200 | actuators[1]); // display actuator angles Theta and Psi. |
ed866a4b | 201 | gcode->txt_after_ok.append(buf, n); |
ed866a4b | 202 | } |
6e92ab91 | 203 | break; |
157d2308 | 204 | |
ed866a4b QH |
205 | case 360: { |
206 | float target[2] = {0.0F, 120.0F}, | |
207 | S_trim[3]; | |
208 | ||
209 | this->get_trim(S_trim[0], S_trim[1], S_trim[2]); // get current trim to conserve other calbration values | |
210 | ||
211 | if(gcode->has_letter('P')) { | |
212 | // Program the current position as target | |
213 | float cartesian[3], | |
214 | actuators[3], | |
215 | S_delta[2], | |
216 | S_trim[3]; | |
217 | ||
218 | THEKERNEL->robot->get_axis_position(cartesian); // get actual position from robot | |
219 | THEKERNEL->robot->arm_solution->cartesian_to_actuator( cartesian, actuators ); // translate to get actuator position | |
220 | ||
221 | S_delta[0] = actuators[0] - target[0]; | |
222 | ||
223 | set_trim(S_delta[0], S_trim[1], 0, gcode->stream); | |
224 | } else { | |
225 | set_trim(0, S_trim[1], 0, gcode->stream); // reset trim for calibration move | |
226 | this->home(); // home | |
227 | SCARA_ang_move(target[0], target[1], 100.0F, slow_rate * 3.0F); // move to target | |
228 | } | |
ed866a4b | 229 | } |
6e92ab91 JM |
230 | break; |
231 | ||
ed866a4b QH |
232 | case 361: { |
233 | float target[2] = {90.0F, 130.0F}; | |
234 | if(gcode->has_letter('P')) { | |
235 | // Program the current position as target | |
236 | float cartesian[3], | |
237 | actuators[3]; | |
238 | ||
239 | THEKERNEL->robot->get_axis_position(cartesian); // get actual position from robot | |
240 | THEKERNEL->robot->arm_solution->cartesian_to_actuator( cartesian, actuators ); // translate to get actuator position | |
241 | ||
33bacc39 | 242 | STEPPER[0]->change_steps_per_mm(actuators[0] / target[0] * STEPPER[0]->get_steps_per_mm()); // Find angle difference |
157d2308 | 243 | STEPPER[1]->change_steps_per_mm(STEPPER[0]->get_steps_per_mm()); // and change steps_per_mm to ensure correct steps per *angle* |
ed866a4b QH |
244 | } else { |
245 | this->home(); // home - This time leave trims as adjusted. | |
246 | SCARA_ang_move(target[0], target[1], 100.0F, slow_rate * 3.0F); // move to target | |
247 | } | |
6e92ab91 | 248 | |
ed866a4b | 249 | } |
6e92ab91 JM |
250 | break; |
251 | ||
252 | case 364: { | |
ed866a4b QH |
253 | float target[2] = {45.0F, 135.0F}, |
254 | S_trim[3]; | |
255 | ||
256 | this->get_trim(S_trim[0], S_trim[1], S_trim[2]); // get current trim to conserve other calbration values | |
257 | ||
258 | if(gcode->has_letter('P')) { | |
259 | // Program the current position as target | |
260 | float cartesian[3], | |
261 | actuators[3], | |
262 | S_delta[2]; | |
263 | ||
33bacc39 QH |
264 | THEKERNEL->robot->get_axis_position(cartesian); // get actual position from robot |
265 | THEKERNEL->robot->arm_solution->cartesian_to_actuator( cartesian, actuators ); // translate it to get actual actuator angles | |
ed866a4b | 266 | |
1a15649d QH |
267 | S_delta[1] = ( actuators[1] - actuators[0]) - ( target[1] - target[0] ); // Find difference in angle - not actuator difference, and |
268 | set_trim(S_trim[0], S_delta[1], 0, gcode->stream); // set trim to reflect the difference | |
ed866a4b | 269 | } else { |
1a15649d QH |
270 | set_trim(S_trim[0], 0, 0, gcode->stream); // reset trim for calibration move |
271 | this->home(); // home | |
272 | SCARA_ang_move(target[0], target[1], 100.0F, slow_rate * 3.0F); // move to target | |
ed866a4b | 273 | } |
ed866a4b | 274 | } |
6e92ab91 | 275 | break; |
157d2308 | 276 | |
983e6549 QH |
277 | /* TODO case 365: { // set scara scaling |
278 | std::map<char, float> buf = gcode->get_args(); | |
279 | //algorithm::replace(buf.begin, buf.end , 'X', 'A'); | |
280 | //algorithm::algorithm::replace(buf.begin, buf.end , 'Y', 'B'); | |
281 | //algorithm::replace(buf.begin, buf.end , 'Z', 'C'); | |
282 | ||
283 | buf = string("M665 ") + buf; | |
284 | ||
285 | Gcode gc(buf, &(StreamOutput::NullStream)); | |
286 | THEKERNEL->call_event(ON_GCODE_RECEIVED, &gc); | |
287 | ||
288 | //stream->printf("Set scaling to X:%f Y:%f Z:%f\n", x, y, z); | |
289 | ||
6e92ab91 | 290 | */ |
983e6549 | 291 | |
6e92ab91 | 292 | case 366: // Translate trims to the actual endstop offsets for SCARA |
157d2308 | 293 | this->translate_trim(gcode->stream); |
6e92ab91 | 294 | break; |
983e6549 | 295 | |
ed866a4b | 296 | } |
157d2308 | 297 | } |
ed866a4b QH |
298 | } |
299 |