Hi,
im currently building an hexapod and right now some of the functions dosent output the right data... i have tracked most of the bug to overflow and solved it by adding (long) but there is more to find and in an attempt to solve it added more cast to (long) than needed but now i cant seams to figure this out...
Thx Madrang
Because the source cant all fit in one post i'm gonna post the more important function and data table.
Struct.h
struct CosSin {
int Sin4;
int Cos4;
};
struct Axes {
int X;
int Y;
int Z;
};
//Tables
/*ArcCosinus Table
*Table build in to 3 part to get higher accuracy near cos = 1.
*The biggest error is near cos = 1 and has a biggest value of 3*0.012098rad = 0.521 deg.
*- Cos 0 to 0.9 is done by steps of 0.0079 rad. (1/127)
*- Cos 0.9 to 0.99 is done by steps of 0.0008 rad (0.1/127)
*- Cos 0.99 to 1 is done by step of 0.0002 rad (0.01/64)
//Since the tables are overlapping the full range of 127+127+64 is not necessary. Total bytes: 277*/
const byte GetACos[] = {
255,254,252,251,250,249,247,246,245,243,242,241,240,238,237,236,234,233,232,231,229,228,227,225,
224,223,221,220,219,217,216,215,214,212,211,210,208,207,206,204,203,201,200,199,197,196,195,193,
192,190,189,188,186,185,183,182,181,179,178,176,175,173,172,170,169,167,166,164,163,161,160,158,
157,155,154,152,150,149,147,146,144,142,141,139,137,135,134,132,130,128,127,125,123,121,119,117,
115,113,111,109,107,105,103,101,98,96,94,92,89,87,84,81,79,76,73,73,73,72,72,72,71,71,71,70,70,
70,70,69,69,69,68,68,68,67,67,67,66,66,66,65,65,65,64,64,64,63,63,63,62,62,62,61,61,61,60,60,59,
59,59,58,58,58,57,57,57,56,56,55,55,55,54,54,53,53,53,52,52,51,51,51,50,50,49,49,48,48,47,47,47,
46,46,45,45,44,44,43,43,42,42,41,41,40,40,39,39,38,37,37,36,36,35,34,34,33,33,32,31,31,30,29,28,
28,27,26,25,24,23,23,23,23,22,22,22,22,21,21,21,21,20,20,20,19,19,19,19,18,18,18,17,17,17,17,16,
16,16,15,15,15,14,14,13,13,13,12,12,11,11,10,10,9,9,8,7,6,6,5,3,0};
//Sin table 90 deg, persision 0.5 deg (180 values)
const int GetSin[] = {
0, 87, 174, 261, 348, 436, 523, 610, 697, 784, 871, 958, 1045, 1132, 1218, 1305, 1391, 1478, 1564,
1650, 1736, 1822, 1908, 1993, 2079, 2164, 2249, 2334, 2419, 2503, 2588, 2672, 2756, 2840, 2923, 3007,
3090, 3173, 3255, 3338, 3420, 3502, 3583, 3665, 3746, 3826, 3907, 3987, 4067, 4146, 4226, 4305, 4383,
4461, 4539, 4617, 4694, 4771, 4848, 4924, 4999, 5075, 5150, 5224, 5299, 5372, 5446, 5519, 5591, 5664,
5735, 5807, 5877, 5948, 6018, 6087, 6156, 6225, 6293, 6360, 6427, 6494, 6560, 6626, 6691, 6755, 6819,
6883, 6946, 7009, 7071, 7132, 7193, 7253, 7313, 7372, 7431, 7489, 7547, 7604, 7660, 7716, 7771, 7826,
7880, 7933, 7986, 8038, 8090, 8141, 8191, 8241, 8290, 8338, 8386, 8433, 8480, 8526, 8571, 8616, 8660,
8703, 8746, 8788, 8829, 8870, 8910, 8949, 8987, 9025, 9063, 9099, 9135, 9170, 9205, 9238, 9271, 9304,
9335, 9366, 9396, 9426, 9455, 9483, 9510, 9537, 9563, 9588, 9612, 9636, 9659, 9681, 9702, 9723, 9743,
9762, 9781, 9799, 9816, 9832, 9848, 9862, 9876, 9890, 9902, 9914, 9925, 9935, 9945, 9953, 9961, 9969,
9975, 9981, 9986, 9990, 9993, 9996, 9998, 9999, 10000};
//Get the sinus and cosinus from the angle +/- multiple circles
CosSin GetSinCos(int AngleDeg1){
CosSin Result;
word ABSAngleDeg1 = abs(AngleDeg1); //Absolute value of the Angle in Degrees, decimals = 1
//Shift rotation to a full circle of 360 deg -> AngleDeg : 360
/*if(AngleDeg1 < 0)//Negative values
AngleDeg1 = 3600 - (ABSAngleDeg1 - (3600 * (ABSAngleDeg1 / 3600)));
else AngleDeg1 = ABSAngleDeg1 - (3600 * (ABSAngleDeg1 / 3600)); //Positive values*/ // COMMENTED OUT MADRANG
if(AngleDeg1 < 0) //ADDED MADRANG
AngleDeg1 = 3600 - ABSAngleDeg1; //ADDED MADRANG
else AngleDeg1 = ABSAngleDeg1; //ADDED MADRANG
if(AngleDeg1 >= 0 && AngleDeg1 <= 900){// 0 to 90 deg
Result.Sin4 = GetSin[AngleDeg1 / 5]; //5 is the presision (0.5) of the table
Result.Cos4 = GetSin[(900 - AngleDeg1) / 5];
}
else if (AngleDeg1>900 && AngleDeg1<=1800){// 90 to 180 deg
Result.Sin4 = GetSin[(900 - (AngleDeg1 - 900)) / 5]; //5 is the presision (0.5) of the table
Result.Cos4 = -GetSin[(AngleDeg1 - 900) / 5];
}
else if (AngleDeg1 > 1800 && AngleDeg1 <= 2700){// 180 to 270 deg
Result.Sin4 = -GetSin[(AngleDeg1 - 1800) / 5]; //5 is the presision (0.5) of the table
Result.Cos4 = -GetSin[(2700 - AngleDeg1) / 5];
}
else if (AngleDeg1 > 2700 && AngleDeg1 <= 3600){// 270 to 360 deg
Result.Sin4 = -GetSin[(3600 - AngleDeg1) / 5]; //5 is the presision (0.5) of the table
Result.Cos4 = GetSin[(AngleDeg1 - 2700) / 5];
}
return Result;
}
//Get the sinus and cosinus from the angle +/- multiple circles
int GetArcCos(int Cos4){
//Check for negative value
boolean NegativeValue = false;
if(Cos4 < 0){
Cos4 = abs(Cos4);
NegativeValue = true;
}
//Limit Cos to his maximal value
Cos4 = max(Cos4, c4DEC);
int AngleRad4;
if(Cos4 >= 0 && Cos4 < 9000){
AngleRad4 = GetACos[Cos4 / 79]; //79=table resolution (1/127)
AngleRad4 = ((long)AngleRad4 * 616 / c1DEC); //616=acos resolution (pi/2/255)
}
else if (Cos4 >= 9000 && Cos4 < 9900){
AngleRad4 = GetACos[(Cos4 - 9000) / 8 + 114]; //8=table resolution (0.1/127), 114 start address 2nd bytetable range
AngleRad4 = ((long)AngleRad4 * 616 / c1DEC); //616=acos resolution (pi/2/255)
}
else if(Cos4 >= 9900 && Cos4 <= 10000){
AngleRad4 = GetACos[(Cos4 - 9900) / 2 + 227]; //2=table resolution (0.01/64), 227 start address 3rd bytetable range
AngleRad4 = ((long)AngleRad4 * 616 / c1DEC); //616=acos resolution (pi/2/255)
}
//Add negative sign
if(NegativeValue)
AngleRad4 = 31416 - AngleRad4;
return AngleRad4;
}
//Output presenting Hypotenuse of X and Y
unsigned long XYhyp2(int AtanX, int AtanY){
return sqrt((sq((long)AtanX)*c4DEC) + (sq((long)AtanY)*c4DEC));
}
//Simplyfied ArcTan2 function based on fixed point ArcCos
int GetATan2(int AtanX, int AtanY){
int AngleRad = GetArcCos(((long)AtanX * (long)c6DEC) / (long)XYhyp2(AtanX, AtanY));
return (AngleRad * (AtanY / abs(AtanY)));//Add sign
}
//Calculates the angles of the coxa, femur and tibia for the given position of the feet
void LegIK(Axes IKFeetPos, byte LegIKLegNr){
if(_DEBUG){
Serial.print("Leg No : ");
Serial.print(LegIKLegNr,DEC);
Serial.print(", X : ");
Serial.print(IKFeetPos.X,DEC);
Serial.print(", Y : ");
Serial.print(IKFeetPos.Y,DEC);
Serial.print(", Z : ");
Serial.println(IKFeetPos.Z,DEC);
}
//Calculate IKCoxaAngle and IKFeetPosXZ
int ATan4 = GetATan2(IKFeetPos.X, IKFeetPos.Z);
CoxaAngle1[LegIKLegNr] = (((long)ATan4 * 180) / 3141) + cCoxaAngle1[LegIKLegNr];
//Length between the Coxa and tars (foot)
int IKFeetPosXZ = (XYhyp2(IKFeetPos.X, IKFeetPos.Z) / c2DEC); //Diagonal direction from Input X and Z
//Using GetAtan2 for solving IKA1 and IKSW
//IKA14 - Angle between SW line and the ground in radians
unsigned long IKA14 = GetATan2(IKFeetPos.Y, IKFeetPosXZ - cCoxaLength); //Angle of the line S>W with respect to the ground in radians, decimals = 4
//IKSW2 - Length between femur axis and tars
unsigned long IKSW2 = XYhyp2(IKFeetPos.Y, IKFeetPosXZ - cCoxaLength); //Length between Shoulder and Wrist, decimals = 2
//IKA2 - Angle of the line S>W with respect to the femur in radians
unsigned long Temp1 = ((sq((long)cFemurLength) - sq((long)cTibiaLength)) * c4DEC + sq((long)IKSW2));
unsigned long Temp2 = ((2 * cFemurLength) * c2DEC * IKSW2);
unsigned long IKA24 = GetArcCos(Temp1 / (Temp2 / c4DEC)); //Angle of the line S>W with respect to the femur in radians, decimals = 4
if(_DEBUG){
Serial.print("XZ : ");
Serial.print(XYhyp2(IKFeetPos.X, IKFeetPos.Z),DEC);
Serial.print(", Temp1 : ");
Serial.print(Temp1,DEC);
Serial.print(", Temp2 : ");
Serial.print(Temp2,DEC);
Serial.print(", IKA14 : ");
Serial.print(IKA14,DEC);
Serial.print(", IKA24 : ");
Serial.print(IKA24,DEC);
Serial.print(", IKSW2 : ");
Serial.println(IKSW2,DEC);
}
//IKFemurAngle
FemurAngle1[LegIKLegNr] = (-(((long)IKA14 + IKA24) * 180 / 3141) + 900);
//IKTibiaAngle
Temp1 = ((sq((long)cFemurLength) + sq((long)cTibiaLength)) * c4DEC - sq((long)IKSW2));
Temp2 = (2 * cFemurLength * cTibiaLength);
int AngleRad4 = GetArcCos(Temp1 / Temp2);
TibiaAngle1[LegIKLegNr] = -(900 - (long)AngleRad4 * 180 / 3141);
//Set the Solution quality
if(_DEBUG){
if(IKSW2 < (cFemurLength + cTibiaLength - 30) * c2DEC){
Serial.println("IK Ok");
}
else if(IKSW2 < (cFemurLength + cTibiaLength) * c2DEC){
Serial.println("IK Warning");
}
else{
Serial.println("IK Error : ");
}
}
}