Kinematics - xelfe/weefee_project GitHub Wiki
Quadruped Kinematics
This page explains the kinematics implementation used in the Weefee quadruped robot.
Introduction to Robot Kinematics
Kinematics is the mathematical description of motion without considering the forces that cause it. For a quadruped robot, kinematics is essential for:
- Forward Kinematics: Calculating where the foot will be based on joint angles
- Inverse Kinematics: Calculating joint angles needed to place the foot at a specific position
Leg Configuration
The Weefee robot uses a standard 3-joint leg configuration per leg:
- Coxa: The hip joint that rotates horizontally (connecting to the body)
- Femur: The middle joint between the coxa and tibia
- Tibia: The final segment connecting to the foot
Each leg has three degrees of freedom (DoF), giving the robot a total of 12 DoF for its four legs.
Coordinate System
The robot uses a right-handed coordinate system:
- X-axis: Forward/backward direction
- Y-axis: Left/right direction
- Z-axis: Up/down direction
The origin is at the center of the robot's body.
Forward Kinematics
Forward kinematics calculates the foot position given the joint angles.
Mathematical Approach
For a leg with joint angles θ₁ (coxa), θ₂ (femur), and θ₃ (tibia):
-
Calculate the position after coxa rotation:
x_coxa = L_coxa * cos(θ₁) y_coxa = L_coxa * sin(θ₁) z_coxa = 0
-
Calculate the femur contribution:
x_femur = L_femur * cos(θ₂) * cos(θ₁) y_femur = L_femur * cos(θ₂) * sin(θ₁) z_femur = -L_femur * sin(θ₂)
-
Calculate the tibia contribution:
x_tibia = L_tibia * cos(θ₃ + θ₂) * cos(θ₁) y_tibia = L_tibia * cos(θ₃ + θ₂) * sin(θ₁) z_tibia = -L_tibia * sin(θ₃ + θ₂)
-
Sum all contributions to get the final foot position:
x = mounting_x + x_coxa + x_femur + x_tibia y = mounting_y + y_coxa + y_femur + y_tibia z = mounting_z + z_coxa + z_femur + z_tibia
Where:
L_coxa
,L_femur
,L_tibia
are the lengths of each segmentmounting_x/y/z
is the position where the leg connects to the body
Implementation
The forward kinematics is implemented in both the ESP32 firmware (quadruped_kinematics.c
) and the ROS2 code (quadruped_inverse_kinematics.h
).
Inverse Kinematics
Inverse kinematics calculates the joint angles required to position the foot at a specific location.
Mathematical Approach
For a target foot position (x, y, z) relative to the leg's mounting point:
-
Calculate the horizontal distance from leg base to foot:
L = sqrt(x² + y²)
-
Calculate the coxa angle:
θ₁ = atan2(y, x)
-
Remove the coxa length from the horizontal distance:
L2 = L - L_coxa
-
Calculate the straight-line distance from femur joint to foot:
L_femur_tibia = sqrt(L2² + z²)
-
Check if the position is reachable (L_femur_tibia ≤ L_femur + L_tibia)
-
Using the law of cosines, calculate:
gamma = atan2(z, L2) alpha = acos((L_femur² + L_femur_tibia² - L_tibia²) / (2 * L_femur * L_femur_tibia)) beta = acos((L_femur² + L_tibia² - L_femur_tibia²) / (2 * L_femur * L_tibia))
-
Calculate the final joint angles:
θ₂ (femur) = 90° - (gamma + alpha) θ₃ (tibia) = 180° - beta
Implementation
The inverse kinematics is implemented in both the ESP32 firmware and ROS2 control code.
Key functions:
inverse_kinematics()
inquadruped_kinematics.c
(ESP32)inverse_kinematics()
inquadruped_inverse_kinematics.h
(ROS2)
Body Movements
The kinematics system also handles whole-body movements:
- Translation: Moving the body position while adjusting all legs to maintain the same foot positions relative to the ground
- Rotation: Rotating the body while adjusting leg positions to maintain foot positions
This is achieved by:
- Converting the desired global foot positions to body-relative positions
- Applying the inverse transformation of the body movement
- Calculating inverse kinematics for each leg
Gait Generation
Gaits are created by generating foot position trajectories over time:
- Stance Phase: When the foot is on the ground, moving backward
- Swing Phase: When the foot is lifted and moving forward
Different gait patterns (walk, trot) vary in how these phases are coordinated across legs.
The implementation supports:
- Walking Gait: One leg at a time (sequence: FR → RR → FL → RL)
- Trotting Gait: Diagonal legs move together (FR+RL, then FL+RR)
Code Example: Inverse Kinematics
Here's a simplified version of the inverse kinematics calculation:
bool inverse_kinematics(int leg_index, const Vec3 &target_pos, float angles_out[3]) {
Leg &leg = legs_[leg_index];
// Calculate leg-relative position
float leg_x = target_pos.x - leg.mounting_position.x;
float leg_y = target_pos.y - leg.mounting_position.y;
float leg_z = target_pos.z - leg.mounting_position.z;
// Horizontal distance from leg base to foot
float L = sqrtf(leg_x * leg_x + leg_y * leg_y);
// Distance for coxa (first segment)
float L_coxa = leg.coxa_length;
// Calculate coxa angle (horizontal rotation)
float coxa_angle = atan2f(leg_y, leg_x) * 180.0f / M_PI;
// Adjust positions for femur and tibia calculations
float L2 = L - L_coxa;
// Distance for femur/tibia joints
float L_femur_tibia = sqrtf(L2 * L2 + leg_z * leg_z);
// Check if position is reachable
if (L_femur_tibia > (leg.femur_length + leg.tibia_length)) {
return false; // Target position out of reach
}
// Calculate angles using law of cosines
float a = leg.femur_length;
float b = leg.tibia_length;
float c = L_femur_tibia;
float gamma = atan2f(leg_z, L2) * 180.0f / M_PI;
float alpha = acosf((a*a + c*c - b*b) / (2.0f * a * c)) * 180.0f / M_PI;
float beta = acosf((a*a + b*b - c*c) / (2.0f * a * b)) * 180.0f / M_PI;
// Final angle calculations
float femur_angle = 90.0f - (gamma + alpha);
float tibia_angle = 180.0f - beta;
// Assign results
angles_out[JOINT_COXA] = coxa_angle;
angles_out[JOINT_FEMUR] = femur_angle;
angles_out[JOINT_TIBIA] = tibia_angle;
return true;
}
Resources
For those wanting to learn more about quadruped kinematics: