cleanup all libs/ headers and dependent files
[clinton/Smoothieware.git] / src / modules / robot / arm_solutions / JohannKosselSolution.cpp
CommitLineData
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
11JohannKosselSolution::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
21void 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
40void 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
56void 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 95bool 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 111bool 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};