use crate::chains::Chain;
use crate::geometry::Frame;
use crate::joint::JointType;
#[derive(Clone, Debug)]
pub struct ForwardKinematicsSolver {
chain: Chain,
}
impl ForwardKinematicsSolver {
pub fn default() -> Self {
Self {
chain: Chain::default(),
}
}
pub fn new(in_chain: Chain) -> Self {
Self { chain: in_chain }
}
pub fn solve_at_segment(&self, angles: &Vec<f64>, segment_index: usize) -> Frame {
let num_joints = self.chain.get_num_joints();
let num_segments = self.chain.get_num_segments();
if num_joints != angles.len() {
panic!(
"Got {} angles, but the chain has {} joints",
angles.len(),
num_joints
);
}
if segment_index >= num_segments {
panic!(
"Asked for pose at segment {}, but the chain has {} segments",
segment_index, num_segments
);
}
let mut counter = 0;
let mut pose = Frame::identity();
for i in 0..segment_index + 1 {
let segment = self.chain.get_segment(i);
pose *= segment.pose(angles[counter]);
if segment.get_joint_type() != JointType::NoJoint {
counter += 1;
}
}
let result = pose;
result
}
pub fn solve(&self, angles: &Vec<f64>) -> Frame {
self.solve_at_segment(angles, self.chain.get_num_segments() - 1)
}
}
#[cfg(test)]
mod tests {
use crate::chains::tests::create_testing_chain;
use crate::forward_kinematics::ForwardKinematicsSolver;
use crate::geometry::{get_frame_error, Frame};
use nalgebra::geometry::{Isometry3, Translation3, UnitQuaternion};
#[test]
fn base_pose_correct() {
let chain = create_testing_chain();
let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
let solver = ForwardKinematicsSolver::new(chain);
let base_pose = solver.solve_at_segment(&angles, 0);
assert_eq!(
base_pose,
Isometry3::from_parts(
Translation3::new(0.1, -0.2, 0.3),
UnitQuaternion::from_euler_angles(-0.1, -0.2, 0.3)
)
.to_homogeneous()
);
}
#[test]
fn end_pose_correct() {
let chain = create_testing_chain();
let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
let solver = ForwardKinematicsSolver::new(chain);
let end_pose = solver.solve(&angles);
let error = get_frame_error(
end_pose,
Frame::new(
0.464207, -0.287552, -0.83775, -1.6869, 0.531446, 0.847084, 0.0037244, 0.183458,
0.708574, -0.446948, 0.546041, 1.46649, 0.0, 0.0, 0.0, 1.0,
),
);
assert!(error < 0.0001);
}
#[test]
fn middle_pose_correct() {
let chain = create_testing_chain();
let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
let solver = ForwardKinematicsSolver::new(chain);
let middle_pose = solver.solve_at_segment(&angles, 4);
let error = get_frame_error(
middle_pose,
Frame::new(
-0.721694, -0.280953, 0.632632, -0.398326, -0.418169, -0.551359, -0.721899,
0.0611589, 0.551627, -0.785537, 0.280427, 0.90368, 0.0, 0.0, 0.0, 1.0,
),
);
assert!(error < 0.00001);
}
}