00001 /* 00002 lukaskins.c 00003 00004 Modification history: 00005 00006 15-May-2001 FMP changed kinematicsType to KINEMATICS_BOTH 00007 4-May-2001 FMP fixed undef's, which were defs 00008 16-Apr-2001 FMP created from Lukas du Plessis' figure 00009 */ 00010 00011 /* 00012 These kinematics are for Lukas du Plessis' planar parallel mechanism: 00013 00014 A--------B 00015 / \ \ ^ 00016 / \ \ | 00017 / \ \ y 00018 / \ \ | 00019 C---------D--------E +-- x --> 00020 00021 where C is the origin; 00022 the x and y directions are to the left and up, respectively, and z is 00023 out of the page; 00024 AC, AD, and BE are struts whose length can be controlled; 00025 C, D, and E are fixed points; and 00026 AB is a fixed-length strut. 00027 00028 The kinematics use variables named from the figure, where single capital 00029 letters indicate vertex points (e.g., A, B); single capital letters 00030 followed by lowercase x or y indicate the x or y coordinate of the vertex 00031 point, respectively, with respect to the origin C; double capital letters 00032 indicate the length of sides (e.g., AB, BE); and triple lowercase letters 00033 indicate angles (e.g., bae, the angle between BA and AC). 00034 00035 Changing the lengths of AC, AD, and BE result in points A and B moving 00036 about. Point B is the controlled point, and the three Cartesian variables 00037 are Bx, By, and the angle of AB relative to the horizontal (x) axis, 00038 called theta. This is the angle of rotation of B about the z axis, 00039 In the above figure theta (not labeled) is 0. 00040 00041 The arguments to the kinematics functions are named "pos" for the 00042 Cartesian EmcPose type, and "joints" for the joint (strut length) array. 00043 The association between these names and names from the figure are: 00044 00045 pos->tran.x = Bx 00046 pos->tran.y = By 00047 pos->c = theta 00048 00049 The inverse kinematics have no singularities. Any values for Bx, By, and 00050 theta will yield numerical results. Of course, these may be beyond the 00051 strut length limits, but there are no singular effects like infinite speed. 00052 00053 The forward kinematics have two singularities. The first occurs when 00054 struts AC and AD are not long enough to span base length CD and the 00055 triangle inquality is violated. The second occurs when struts AB and BE 00056 are not long enough to span the distance between points A and E. 00057 00058 The forward kinematics flags, referred to in kinematicsForward and 00059 set in kinematicsInverse, let the forward kinematics select between 00060 multiple valid solutions of B and theta for a given set of strut 00061 values. The two types of solutions correspond to 00062 00063 a) "head" point A is above (as in figure) or below x axis; 00064 b) "elbow" point B is up (as in figure) or down. 00065 00066 Bit 0 of fflags selects between (a), with 0 = above, 1 = below; 00067 bit 1 of fflags selects between (b), with 0 = up, 1 = down. 00068 00069 The inverse kinematics flags let the inverse kinematics select between 00070 multiple valid solutions of strut lengths for given Cartesian values 00071 for B and theta. There are no multiple solutions: B and theta constrain 00072 the strut lengths completely. So, the inverse flags are ignored. 00073 */ 00074 00075 #include "emcmot.h" /* these decls */ 00076 #include <math.h> 00077 00078 /* ident tag */ 00079 #ifndef __GNUC__ 00080 #ifndef __attribute__ 00081 #define __attribute__(x) 00082 #endif 00083 #endif 00084 00085 /* define the constant strut lengths here */ 00086 #define CD 10.0 00087 #define DE 4.0 00088 #define AB 8.7 00089 00090 #define sq(x) ((x)*(x)) 00091 00092 /* 00093 forward kinematics takes three strut lengths and computes Bx, By, 00094 and theta, as pos->tran.x,y, and pos->c, respectively. The forward 00095 flags are used to resolve head above/below and elbow up/down. The 00096 inverse flags are not set since there are no ambiguities going from 00097 world to joint coordinates. 00098 */ 00099 int kinematicsForward(const double * joints, 00100 EmcPose * pos, 00101 const KINEMATICS_FORWARD_FLAGS * fflags, 00102 KINEMATICS_INVERSE_FLAGS * iflags) 00103 { 00104 #define AC (joints[0]) 00105 #define AD (joints[1]) 00106 #define BE (joints[2]) 00107 #define Bx (pos->tran.x) 00108 #define By (pos->tran.y) 00109 #define theta (pos->c) 00110 double temp; 00111 double CE; 00112 double AE; 00113 double Ax, Ay; 00114 double bae; 00115 double aec; 00116 00117 Ax = (sq(AC) + sq(CD) - sq(AD)) / (2.0 * CD); 00118 temp = sq(AC) - sq(Ax); 00119 if (temp < 0.0) { 00120 return -1; 00121 } 00122 Ay = sqrt(temp); 00123 if (*fflags % 2) { 00124 Ay = -Ay; /* head below */ 00125 } 00126 00127 CE = CD + DE; 00128 AE = sqrt(sq(Ay) + sq(CE - Ax)); 00129 temp = (sq(AB) + sq(AE) - sq(BE)) / (2.0 * AB * AE); 00130 if (temp < -1.0 || 00131 temp > +1.0) { 00132 return -1; 00133 } 00134 bae = acos(temp); 00135 if ((*fflags >> 1) % 2) { 00136 bae = -bae; /* elbow down */ 00137 } 00138 /* else elbow up */ 00139 aec = atan2(Ay, CE - Ax); 00140 theta = bae - aec; 00141 Bx = Ax + AB * cos(theta); 00142 By = Ay + AB * sin(theta); 00143 00144 /* pos->tran.x,y are Bx, By resp.; pos->c is theta; they're 00145 already done via #define, so no assignment necessary. We'll 00146 set the others to 0. */ 00147 pos->tran.z = 0.0; 00148 pos->a = 0.0; 00149 pos->b = 0.0; 00150 00151 return 0; 00152 00153 #undef AC 00154 #undef AD 00155 #undef BE 00156 #undef Bx 00157 #undef By 00158 #undef theta 00159 } 00160 00161 int kinematicsInverse(const EmcPose * pos, 00162 double * joints, 00163 const KINEMATICS_INVERSE_FLAGS * iflags, 00164 KINEMATICS_FORWARD_FLAGS * fflags) 00165 { 00166 #define AC (joints[0]) 00167 #define AD (joints[1]) 00168 #define BE (joints[2]) 00169 #define Bx (pos->tran.x) 00170 #define By (pos->tran.y) 00171 #define theta (pos->c) 00172 double CE; 00173 double Ax; 00174 double Ay; 00175 00176 CE = CD + DE; 00177 BE = sqrt(sq(Bx - CE) + sq(By)); 00178 Ax = Bx - AB * cos(theta); 00179 Ay = By - AB * sin(theta); 00180 AC = sqrt(sq(Ax) + sq(Ay)); 00181 AD = sqrt(sq(CD - Ax) + sq(Ay)); 00182 00183 /* AC, AD, and BE are joints[0,1,2], resp.; they're already 00184 done via #define, so no assignment necessary */ 00185 00186 /* set fflags to appropriately for given B and theta */ 00187 *fflags = 0; 00188 if (Ay < 0.0) { 00189 *fflags = 1; /* head below */ 00190 } 00191 /* use sign of cross product EB X BA for elbow; positive is 00192 elbow up */ 00193 if ((Bx - CE) * (Ay - By) - By * (Ax - Bx) < 0.0) { 00194 *fflags += 2; 00195 } 00196 00197 return 0; 00198 00199 #undef AC 00200 #undef AD 00201 #undef BE 00202 #undef Bx 00203 #undef By 00204 #undef theta 00205 } 00206 00207 /* the inverse kinematics have no singularities, so kinematicsHome gives 00208 the world position preferences, and fills in the joint values */ 00209 int kinematicsHome(EmcPose * world, 00210 double * joint, 00211 KINEMATICS_FORWARD_FLAGS * fflags, 00212 KINEMATICS_INVERSE_FLAGS * iflags) 00213 { 00214 *fflags = 0; 00215 *iflags = 0; 00216 00217 return kinematicsInverse(world, joint, iflags, fflags); 00218 } 00219 00220 KINEMATICS_TYPE kinematicsType() 00221 { 00222 return KINEMATICS_BOTH; 00223 }