modified: src/modules/robot/arm_solutions/RotatableDeltaSolution.cpp
[clinton/Smoothieware.git] / src / modules / robot / arm_solutions / MorganSCARASolution.cpp
CommitLineData
1217e470
QH
1#include "MorganSCARASolution.h"
2#include <fastmath.h>
3#include "checksumm.h"
4#include "ConfigValue.h"
5#include "libs/Kernel.h"
6//#include "StreamOutputPool.h"
7//#include "Gcode.h"
8//#include "SerialMessage.h"
9//#include "Conveyor.h"
10//#include "Robot.h"
11//#include "StepperMotor.h"
12
13#include "libs/nuts_bolts.h"
14
15#include "libs/Config.h"
16
2490d558
QH
17#define arm1_length_checksum CHECKSUM("arm1_length")
18#define arm2_length_checksum CHECKSUM("arm2_length")
19#define morgan_offset_x_checksum CHECKSUM("morgan_offset_x")
20#define morgan_offset_y_checksum CHECKSUM("morgan_offset_y")
21#define axis_scaling_x_checksum CHECKSUM("axis_scaling_x")
22#define axis_scaling_y_checksum CHECKSUM("axis_scaling_y")
23#define morgan_homing_checksum CHECKSUM("morgan_homing")
24#define morgan_undefined_min_checksum CHECKSUM("morgan_undefined_min")
25#define morgan_undefined_max_checksum CHECKSUM("morgan_undefined_max")
1217e470
QH
26
27#define SQ(x) powf(x, 2)
28#define ROUND(x, y) (roundf(x * 1e ## y) / 1e ## y)
29
30MorganSCARASolution::MorganSCARASolution(Config* config)
31{
32 // arm1_length is the length of the inner main arm from hinge to hinge
33 arm1_length = config->value(arm1_length_checksum)->by_default(150.0f)->as_number();
34 // arm2_length is the length of the inner main arm from hinge to hinge
35 arm2_length = config->value(arm2_length_checksum)->by_default(150.0f)->as_number();
36 // morgan_offset_x is the x offset of bed zero position towards the SCARA tower center
37 morgan_offset_x = config->value(morgan_offset_x_checksum)->by_default(100.0f)->as_number();
38 // morgan_offset_y is the y offset of bed zero position towards the SCARA tower center
2490d558
QH
39 morgan_offset_y = config->value(morgan_offset_y_checksum)->by_default(-60.0f)->as_number();
40 // morgan_undefined is the ratio at which the SCARA position is undefined.
41 // required to prevent the arm moving through singularity points
42 // min: head close to tower
43 morgan_undefined_min = config->value(morgan_undefined_min_checksum)->by_default(0.95f)->as_number();
44 // max: head on maximum reach
45 morgan_undefined_max = config->value(morgan_undefined_max_checksum)->by_default(0.95f)->as_number();
1217e470
QH
46
47 init();
48}
49
50void MorganSCARASolution::init() {
51
52}
53
54float MorganSCARASolution::to_degrees(float radians) {
55 return radians*(180.0F/3.14159265359f);
56}
57
58void MorganSCARASolution::cartesian_to_actuator( float cartesian_mm[], float actuator_mm[] )
59{
60
61 float SCARA_pos[2],
62 SCARA_C2,
63 SCARA_S2,
64 SCARA_K1,
65 SCARA_K2,
66 SCARA_theta,
67 SCARA_psi;
2490d558 68
1217e470
QH
69 SCARA_pos[X_AXIS] = cartesian_mm[X_AXIS] - this->morgan_offset_x; //Translate cartesian to tower centric SCARA X Y
70 SCARA_pos[Y_AXIS] = cartesian_mm[Y_AXIS] - this->morgan_offset_y; // morgan_offset not to be confused with home offset. Makes the SCARA math work.
2490d558 71
1217e470
QH
72 if (this->arm1_length == this->arm2_length)
73 SCARA_C2 = (SQ(SCARA_pos[X_AXIS])+SQ(SCARA_pos[Y_AXIS])-2.0f*SQ(this->arm1_length)) / (2.0f * SQ(this->arm1_length));
74 else
900601b5
QH
75 SCARA_C2 = (SQ(SCARA_pos[X_AXIS])+SQ(SCARA_pos[Y_AXIS])-SQ(this->arm1_length)-SQ(this->arm2_length)) / (2.0f * SQ(this->arm1_length));
76
77 // SCARA position is undefined if abs(SCARA_C2) >=1
78 // In reality abs(SCARA_C2) >0.95 is problematic.
79
2490d558
QH
80 if (SCARA_C2 > this->morgan_undefined_max)
81 SCARA_C2 = this->morgan_undefined_max;
82 else if (SCARA_C2 < -this->morgan_undefined_min)
83 SCARA_C2 = -this->morgan_undefined_min;
84
900601b5 85
1217e470
QH
86 SCARA_S2 = sqrtf(1.0f-SQ(SCARA_C2));
87
88 SCARA_K1 = this->arm1_length+this->arm2_length*SCARA_C2;
89 SCARA_K2 = this->arm2_length*SCARA_S2;
2490d558 90
1217e470
QH
91 SCARA_theta = (atan2f(SCARA_pos[X_AXIS],SCARA_pos[Y_AXIS])-atan2f(SCARA_K1, SCARA_K2))*-1.0f; // Morgan Thomas turns Theta in oposite direction
92 SCARA_psi = atan2f(SCARA_S2,SCARA_C2);
2490d558
QH
93
94
1217e470
QH
95 actuator_mm[ALPHA_STEPPER] = to_degrees(SCARA_theta); // Multiply by 180/Pi - theta is support arm angle
96 actuator_mm[BETA_STEPPER ] = to_degrees(SCARA_theta + SCARA_psi); // Morgan kinematics (dual arm)
97 //actuator_mm[BETA_STEPPER ] = to_degrees(SCARA_psi); // real scara
98 actuator_mm[GAMMA_STEPPER] = cartesian_mm[Z_AXIS]; // No inverse kinematics on Z - Position to add bed offset?
99
100}
101
102void MorganSCARASolution::actuator_to_cartesian( float actuator_mm[], float cartesian_mm[] ) {
103 // Perform forward kinematics, and place results in cartesian_mm[]
2490d558 104
1217e470
QH
105 float y1, y2,
106 actuator_rad[2];
107
108 actuator_rad[X_AXIS] = actuator_mm[X_AXIS]/(180.0F/3.14159265359f);
109 actuator_rad[Y_AXIS] = actuator_mm[Y_AXIS]/(180.0F/3.14159265359f);
110
111 y1 = sinf(actuator_rad[X_AXIS])*this->arm1_length;
112 y2 = sinf(actuator_rad[Y_AXIS])*this->arm2_length + y1;
2490d558 113
1217e470
QH
114 cartesian_mm[X_AXIS] = cosf(actuator_rad[X_AXIS])*this->arm1_length + cosf(actuator_rad[Y_AXIS])*this->arm2_length + this->morgan_offset_x;
115 cartesian_mm[Y_AXIS] = y2 + this->morgan_offset_y;
116 cartesian_mm[Z_AXIS] = actuator_mm[Z_AXIS];
117
118 cartesian_mm[0] = ROUND(cartesian_mm[0], 4);
119 cartesian_mm[1] = ROUND(cartesian_mm[1], 4);
120 cartesian_mm[2] = ROUND(cartesian_mm[2], 4);
121}
122
123bool MorganSCARASolution::set_optional(const arm_options_t& options) {
124
125 arm_options_t::const_iterator i;
126
127 i= options.find('T'); // Theta arm1 length
128 if(i != options.end()) {
129 arm1_length= i->second;
130
131 }
132 i= options.find('P'); // Psi arm2 length
133 if(i != options.end()) {
134 arm2_length= i->second;
135 }
136 i= options.find('X'); // Home initial position X
137 if(i != options.end()) {
138 morgan_offset_x= i->second;
139 }
140 i= options.find('Y'); // Home initial position Y
141 if(i != options.end()) {
142 morgan_offset_y= i->second;
143 }
2490d558 144
1217e470
QH
145 init();
146 return true;
147}
148
149bool MorganSCARASolution::get_optional(arm_options_t& options) {
150 options['T']= this->arm1_length;
151 options['P']= this->arm2_length;
152 options['X']= this->morgan_offset_x;
153 options['Y']= this->morgan_offset_y;
154 return true;
155};