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/>.
11 #include "BaseSolution.h"
14 #include "StepperMotor.h"
15 #include "StreamOutputPool.h"
19 #include "checksumm.h"
20 #include "ConfigValue.h"
21 #include "SerialMessage.h"
22 #include "EndstopsPublicAccess.h"
23 #include "PublicData.h"
27 #define scaracal_checksum CHECKSUM("scaracal")
28 #define enable_checksum CHECKSUM("enable")
29 #define slow_feedrate_checksum CHECKSUM("slow_feedrate")
30 #define z_move_checksum CHECKSUM("z_move")
36 #define STEPPER THEROBOT->actuators
37 #define STEPS_PER_MM(a) (STEPPER[a]->get_steps_per_mm())
39 void SCARAcal::on_module_loaded()
41 // if the module is disabled -> do nothing
42 if(!THEKERNEL
->config
->value( scaracal_checksum
, enable_checksum
)->by_default(false)->as_bool()) {
43 // as this module is not needed free up the resource
49 this->on_config_reload(this);
50 // register event-handlers
51 register_for_event(ON_GCODE_RECEIVED
);
54 void SCARAcal::on_config_reload(void *argument
)
56 this->slow_rate
= THEKERNEL
->config
->value( scaracal_checksum
, slow_feedrate_checksum
)->by_default(5)->as_number(); // feedrate in mm/sec
57 this->z_move
= THEKERNEL
->config
->value( scaracal_checksum
, z_move_checksum
)->by_default(0)->as_number(); // Optional movement of Z relative to the home position.
58 // positive values increase distance between nozzle and bed.
59 // negative will decrease. Useful when level code active to prevent collision
67 Gcode
gc("G28", &(StreamOutput::NullStream
));
68 THEKERNEL
->call_event(ON_GCODE_RECEIVED
, &gc
);
71 bool SCARAcal::get_trim(float& x
, float& y
, float& z
)
74 bool ok
= PublicData::get_value( endstops_checksum
, trim_checksum
, &returned_data
);
77 float *trim
= static_cast<float *>(returned_data
);
86 bool SCARAcal::set_trim(float x
, float y
, float z
, StreamOutput
*stream
)
89 bool ok
= PublicData::set_value( endstops_checksum
, trim_checksum
, t
);
92 stream
->printf("set trim to X:%f Y:%f Z:%f\n", x
, y
, z
);
94 stream
->printf("unable to set trim, is endstops enabled?\n");
100 bool SCARAcal::get_home_offset(float& x
, float& y
, float& z
)
103 bool ok
= PublicData::get_value( endstops_checksum
, home_offset_checksum
, &returned_data
);
106 float *home_offset
= static_cast<float *>(returned_data
);
115 bool SCARAcal::set_home_offset(float x
, float y
, float z
, StreamOutput
*stream
)
119 // Assemble Gcode to add onto the queue
120 snprintf(cmd
, sizeof(cmd
), "M206 X%1.3f Y%1.3f Z%1.3f", x
, y
, z
); // Send saved Z homing offset
122 Gcode
gc(cmd
, &(StreamOutput::NullStream
));
123 THEKERNEL
->call_event(ON_GCODE_RECEIVED
, &gc
);
125 stream
->printf("Set home_offset to X:%f Y:%f Z:%f\n", x
, y
, z
);
130 bool SCARAcal::translate_trim(StreamOutput
*stream
)
134 ActuatorCoordinates actuator
;
136 this->get_home_offset(home_off
[0], home_off
[1], home_off
[2]); // get home offsets
137 this->get_trim(S_trim
[0], S_trim
[1], S_trim
[2]); // get current trim
139 THEROBOT
->arm_solution
->cartesian_to_actuator( home_off
, actuator
); // convert current home offset to actuator angles
141 // Subtract trim values from actuators to determine the real home offset actuator position for X and Y.
143 actuator
[0] -= S_trim
[0];
144 actuator
[1] -= S_trim
[1];
146 // Clear X and Y trims internally
150 // convert back to get the real cartesian home offsets
152 THEROBOT
->arm_solution
->actuator_to_cartesian( actuator
, home_off
);
154 this->set_home_offset(home_off
[0], home_off
[1], home_off
[2],stream
); // get home offsets
155 // Set the correct home offsets;
157 this->set_trim(S_trim
[0], S_trim
[1], S_trim
[2], stream
); // Now Clear relevant trims
162 void SCARAcal::SCARA_ang_move(float theta
, float psi
, float z
, float feedrate
)
166 ActuatorCoordinates actuator
;
168 // Assign the actuator angles from input
173 // Calculate the physical position relating to the arm angles
174 THEROBOT
->arm_solution
->actuator_to_cartesian( actuator
, cartesian
);
176 // Assemble Gcode to add onto the queue
177 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)
179 //THEKERNEL->streams->printf("DEBUG: move: %s\n", cmd);
181 Gcode
gc(cmd
, &(StreamOutput::NullStream
));
182 THEROBOT
->on_gcode_received(&gc
); // send to robot directly
185 //A GCode has been received
186 //See if the current Gcode line has some orders for us
187 void SCARAcal::on_gcode_received(void *argument
)
189 Gcode
*gcode
= static_cast<Gcode
*>(argument
);
194 case 114: { // Extra stuff for Morgan calibration
197 ActuatorCoordinates actuators
;
199 THEROBOT
->get_axis_position(cartesian
); // get actual position from robot
200 THEROBOT
->arm_solution
->cartesian_to_actuator( cartesian
, actuators
); // translate to get actuator position
202 int n
= snprintf(buf
, sizeof(buf
), " A: Th:%1.3f Ps:%1.3f",
204 actuators
[1]); // display actuator angles Theta and Psi.
205 gcode
->txt_after_ok
.append(buf
, n
);
210 float target
[2] = {0.0F
, 120.0F
},
214 this->get_trim(S_trim
[0], S_trim
[1], S_trim
[2]); // get current trim to conserve other calbration values
216 if(gcode
->has_letter('P')) {
217 // Program the current position as target
218 ActuatorCoordinates actuators
;
222 THEROBOT
->get_axis_position(cartesian
); // get actual position from robot
223 THEROBOT
->arm_solution
->cartesian_to_actuator( cartesian
, actuators
); // translate to get actuator position
225 S_delta
[0] = actuators
[0] - target
[0];
227 set_trim(S_delta
[0], S_trim
[1], S_trim
[2], gcode
->stream
);
229 set_trim(0, S_trim
[1], S_trim
[2], gcode
->stream
); // reset trim for calibration move
230 this->home(); // home
231 THEROBOT
->get_axis_position(cartesian
); // get actual position from robot
232 SCARA_ang_move(target
[0], target
[1], cartesian
[2] + this->z_move
, slow_rate
* 3.0F
); // move to target
238 float target
[2] = {90.0F
, 130.0F
},
241 if(gcode
->has_letter('P')) {
242 // Program the current position as target
243 ActuatorCoordinates actuators
;
245 THEROBOT
->get_axis_position(cartesian
); // get actual position from robot
246 THEROBOT
->arm_solution
->cartesian_to_actuator( cartesian
, actuators
); // translate to get actuator position
248 STEPPER
[0]->change_steps_per_mm(actuators
[0] / target
[0] * STEPPER
[0]->get_steps_per_mm()); // Find angle difference
249 STEPPER
[1]->change_steps_per_mm(STEPPER
[0]->get_steps_per_mm()); // and change steps_per_mm to ensure correct steps per *angle*
251 this->home(); // home - This time leave trims as adjusted.
252 THEROBOT
->get_axis_position(cartesian
); // get actual position from robot
253 SCARA_ang_move(target
[0], target
[1], cartesian
[2] + this->z_move
, slow_rate
* 3.0F
); // move to target
260 float target
[2] = {45.0F
, 135.0F
},
264 this->get_trim(S_trim
[0], S_trim
[1], S_trim
[2]); // get current trim to conserve other calbration values
266 if(gcode
->has_letter('P')) {
267 // Program the current position as target
268 ActuatorCoordinates actuators
;
271 THEROBOT
->get_axis_position(cartesian
); // get actual position from robot
272 THEROBOT
->arm_solution
->cartesian_to_actuator( cartesian
, actuators
); // translate it to get actual actuator angles
274 S_delta
[1] = ( actuators
[1] - actuators
[0]) - ( target
[1] - target
[0] ); // Find difference in angle - not actuator difference, and
275 set_trim(S_trim
[0], S_delta
[1], S_trim
[2], gcode
->stream
); // set trim to reflect the difference
277 set_trim(S_trim
[0], 0, S_trim
[2], gcode
->stream
); // reset trim for calibration move
278 this->home(); // home
279 THEROBOT
->get_axis_position(cartesian
); // get actual position from robot
280 SCARA_ang_move(target
[0], target
[1], cartesian
[2] + this->z_move
, slow_rate
* 3.0F
); // move to target
285 case 366: // Translate trims to the actual endstop offsets for SCARA
286 this->translate_trim(gcode
->stream
);