Currently finished coupling 6 legs to a simulation body, with the leg inverse kinematics functional for all of the legs. The remaining elements to implement would be select-able individual joint controls for each leg and the body kinematics itself.
Then I completed the inverse kinematics that allows for the coupling between the body of the robot and its 6 corresponding legs (arranged with 60 degrees between each leg). I wonโt bother explaining the mathematics going into these calculations in detail as they have been outlined in Oscar Liangโs blog post and the equations from TogleFritzโs Lair.
The resultant equations needed a bit of tweaking, especially with the orientation of the coordinate plane and the direction of certain rotations. Additionally, the equations from TogleFritzโs Lair are unnecessarily redundant when implemented in code. I added some optimizations and loop logic to help make the equations less cumbersome to use.
void Droid::ikCalculate() {
const float increment = M_PI/3;
for(int i = 0; i < 6; i++) {
vec3 bodyOffset = vec3(cos(increment * i) * legRadius, 0, sin(increment * i) * legRadius);
vec3 legPos = vec3(
cos(increment * i) * (DEFAULT_COXA_LEN + DEFAULT_FEMUR_LEN),
-DEFAULT_TIBIA_LEN,
sin(increment * i) * (DEFAULT_COXA_LEN + DEFAULT_FEMUR_LEN));
vec3 totalPos = bodyOffset + legPos + bodyPos;
float distToLeg = sqrt(pow(totalPos[0], 2) + pow(totalPos[2], 2));
float angleToLeg = atan2(totalPos[2], totalPos[0]);
float roll = tan(bodyRot[2]) * totalPos[0]; // About the Z Axis
float pitch = tan(bodyRot[0]) * totalPos[2]; // About the X Axis
float bodyIkX = cos(angleToLeg + bodyRot[1]) * distToLeg - totalPos[0];
float bodyIkY = roll + pitch;
float bodyIkZ = sin(angleToLeg + bodyRot[1]) * distToLeg - totalPos[2];
vec3 finalLegPos = legPos + vec3(bodyIkX, bodyIkY, bodyIkZ) + bodyPos;
// Coordinate frame transform from body to leg (rotated)
vec3 legCordFrame = vec3(
cos(i * increment) * finalLegPos[0] + sin(i * increment) * finalLegPos[2],
finalLegPos[1],
-sin(i * increment) * finalLegPos[0] + cos(i * increment) * finalLegPos[2]);
gl::drawVector(vec3(0,0,0), legCordFrame);
mLeg[i].moveToCoord(&legCordFrame);
}
}
With those changes and a couple of new ImGui control panels, everything is looking nice and functional!