Commit | Line | Data |
---|---|---|
2c7ab192 JM |
1 | #include "JohannKosselSolution.h" |
2 | #include <fastmath.h> | |
7af0714f | 3 | #include "checksumm.h" |
8d54c34c | 4 | #include "ConfigValue.h" |
2c7ab192 | 5 | |
b00bb4b5 MM |
6 | #include "Vector3.h" |
7 | ||
ec4773e5 | 8 | #define SQ(x) powf(x, 2) |
b00bb4b5 | 9 | #define ROUND(x, y) (roundf(x * 1e ## y) / 1e ## y) |
2c7ab192 | 10 | |
78d0e16a MM |
11 | JohannKosselSolution::JohannKosselSolution(Config* config) |
12 | { | |
2c7ab192 | 13 | // arm_length is the length of the arm from hinge to hinge |
78d0e16a | 14 | arm_length = config->value(arm_length_checksum)->by_default(250.0f)->as_number(); |
2c7ab192 | 15 | // arm_radius is the horizontal distance from hinge to hinge when the effector is centered |
78d0e16a | 16 | arm_radius = config->value(arm_radius_checksum)->by_default(124.0f)->as_number(); |
2c7ab192 | 17 | |
ec4773e5 JM |
18 | init(); |
19 | } | |
20 | ||
21 | void JohannKosselSolution::init() { | |
78d0e16a | 22 | arm_length_squared = SQ(arm_length); |
ec4773e5 | 23 | |
2c7ab192 | 24 | // Effective X/Y positions of the three vertical towers. |
78d0e16a | 25 | float DELTA_RADIUS = arm_radius; |
2c7ab192 | 26 | |
78d0e16a MM |
27 | float SIN_60 = 0.8660254037844386F; |
28 | float COS_60 = 0.5F; | |
2c7ab192 | 29 | |
78d0e16a MM |
30 | DELTA_TOWER1_X = -SIN_60 * DELTA_RADIUS; // front left tower |
31 | DELTA_TOWER1_Y = -COS_60 * DELTA_RADIUS; | |
2c7ab192 | 32 | |
78d0e16a MM |
33 | DELTA_TOWER2_X = SIN_60 * DELTA_RADIUS; // front right tower |
34 | DELTA_TOWER2_Y = -COS_60 * DELTA_RADIUS; | |
35 | ||
36 | DELTA_TOWER3_X = 0.0F; // back middle tower | |
37 | DELTA_TOWER3_Y = DELTA_RADIUS; | |
2c7ab192 JM |
38 | } |
39 | ||
b00bb4b5 MM |
40 | void JohannKosselSolution::cartesian_to_actuator( float cartesian_mm[], float actuator_mm[] ) |
41 | { | |
01cf96fb | 42 | actuator_mm[ALPHA_STEPPER] = sqrtf(this->arm_length_squared |
4c9ccd0b MM |
43 | - SQ(DELTA_TOWER1_X - cartesian_mm[X_AXIS]) |
44 | - SQ(DELTA_TOWER1_Y - cartesian_mm[Y_AXIS]) | |
45 | ) + cartesian_mm[Z_AXIS]; | |
01cf96fb | 46 | actuator_mm[BETA_STEPPER ] = sqrtf(this->arm_length_squared |
4c9ccd0b MM |
47 | - SQ(DELTA_TOWER2_X - cartesian_mm[X_AXIS]) |
48 | - SQ(DELTA_TOWER2_Y - cartesian_mm[Y_AXIS]) | |
49 | ) + cartesian_mm[Z_AXIS]; | |
01cf96fb | 50 | actuator_mm[GAMMA_STEPPER] = sqrtf(this->arm_length_squared |
4c9ccd0b MM |
51 | - SQ(DELTA_TOWER3_X - cartesian_mm[X_AXIS]) |
52 | - SQ(DELTA_TOWER3_Y - cartesian_mm[Y_AXIS]) | |
53 | ) + cartesian_mm[Z_AXIS]; | |
78d0e16a MM |
54 | } |
55 | ||
b00bb4b5 MM |
56 | void JohannKosselSolution::actuator_to_cartesian( float actuator_mm[], float cartesian_mm[] ) |
57 | { | |
58 | // from http://en.wikipedia.org/wiki/Circumscribed_circle#Barycentric_coordinates_from_cross-_and_dot-products | |
59 | // based on https://github.com/ambrop72/aprinter/blob/2de69a/aprinter/printer/DeltaTransform.h#L81 | |
60 | Vector3 tower1( DELTA_TOWER1_X, DELTA_TOWER1_Y, actuator_mm[0] ); | |
61 | Vector3 tower2( DELTA_TOWER2_X, DELTA_TOWER2_Y, actuator_mm[1] ); | |
62 | Vector3 tower3( DELTA_TOWER3_X, DELTA_TOWER3_Y, actuator_mm[2] ); | |
63 | ||
614b5947 MM |
64 | Vector3 s12 = tower1.sub(tower2); |
65 | Vector3 s23 = tower2.sub(tower3); | |
66 | Vector3 s13 = tower1.sub(tower3); | |
b00bb4b5 | 67 | |
614b5947 | 68 | Vector3 normal = s12.cross(s23); |
b00bb4b5 MM |
69 | |
70 | float magsq_s12 = s12.magsq(); | |
71 | float magsq_s23 = s23.magsq(); | |
72 | float magsq_s13 = s13.magsq(); | |
73 | ||
74 | float inv_nmag_sq = 1.0F / normal.magsq(); | |
75 | float q = 0.5F * inv_nmag_sq; | |
76 | ||
77 | float a = q * magsq_s23 * s12.dot(s13); | |
78 | float b = q * magsq_s13 * s12.dot(s23) * -1.0F; // negate because we use s12 instead of s21 | |
79 | float c = q * magsq_s12 * s13.dot(s23); | |
80 | ||
614b5947 MM |
81 | Vector3 circumcenter( DELTA_TOWER1_X * a + DELTA_TOWER2_X * b + DELTA_TOWER3_X * c, |
82 | DELTA_TOWER1_Y * a + DELTA_TOWER2_Y * b + DELTA_TOWER3_Y * c, | |
83 | actuator_mm[0] * a + actuator_mm[1] * b + actuator_mm[2] * c ); | |
b00bb4b5 MM |
84 | |
85 | float r_sq = 0.5F * q * magsq_s12 * magsq_s23 * magsq_s13; | |
86 | float dist = sqrtf(inv_nmag_sq * (arm_length_squared - r_sq)); | |
87 | ||
614b5947 | 88 | Vector3 cartesian = circumcenter.sub(normal.mul(dist)); |
b00bb4b5 MM |
89 | |
90 | cartesian_mm[0] = ROUND(cartesian[0], 4); | |
91 | cartesian_mm[1] = ROUND(cartesian[1], 4); | |
92 | cartesian_mm[2] = ROUND(cartesian[2], 4); | |
2c7ab192 JM |
93 | } |
94 | ||
1ad23cd3 | 95 | bool JohannKosselSolution::set_optional(char parameter, float value) { |
ec4773e5 JM |
96 | |
97 | switch(parameter) { | |
98 | case 'L': // sets arm_length | |
78d0e16a | 99 | arm_length= value; |
ec4773e5 JM |
100 | break; |
101 | case 'R': // sets arm_radius | |
78d0e16a | 102 | arm_radius= value; |
ec4773e5 JM |
103 | break; |
104 | default: | |
105 | return false; | |
106 | } | |
78d0e16a | 107 | init(); |
ec4773e5 JM |
108 | return true; |
109 | } | |
110 | ||
1ad23cd3 | 111 | bool JohannKosselSolution::get_optional(char parameter, float *value) { |
ec4773e5 JM |
112 | if(value == NULL) return false; |
113 | ||
114 | switch(parameter) { | |
115 | case 'L': // get arm_length | |
116 | *value= this->arm_length; | |
117 | break; | |
118 | case 'R': // get arm_radius | |
119 | *value= this->arm_radius; | |
120 | break; | |
121 | default: | |
122 | return false; | |
123 | } | |
124 | ||
125 | return true; | |
126 | }; |