use crate::chains::Chain;
use crate::geometry::{Frame, Introspection, Twist};
use crate::joint::JointType;
pub fn reference_frame(
total_twist: Twist,
segment_twist: Twist,
total_pose: Frame,
segment_pose: Frame,
) -> Twist {
let rotation = total_pose.get_rotation();
let rot = rotation * segment_twist.fixed_rows::<3>(3);
let tmp = rotation * segment_pose.get_translation();
let trans =
rotation * segment_twist.fixed_rows::<3>(0) + total_twist.fixed_rows::<3>(3).cross(&tmp);
Twist::new(trans[0], trans[1], trans[2], rot[0], rot[1], rot[2])
}
#[derive(Clone, Debug)]
pub struct ForwardDiffKinematicsSolver {
chain: Chain,
}
impl ForwardDiffKinematicsSolver {
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>,
qdots: &Vec<f64>,
segment_index: usize,
) -> Twist {
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 num_joints != qdots.len() {
panic!(
"Got {} angle differentials, but the chain has {} joints",
qdots.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 result_pose = Frame::identity();
let mut result_twist = Twist::zeros();
for i in 0..segment_index + 1 {
let segment = self.chain.get_segment(i);
let pose = segment.pose(angles[counter]);
let twist = segment.twist(angles[counter], qdots[counter]);
result_twist += reference_frame(result_twist, twist, result_pose, pose);
result_pose *= pose;
if segment.get_joint_type() != JointType::NoJoint {
counter += 1;
}
}
result_twist
}
pub fn solve(&self, angles: &Vec<f64>, qdots: &Vec<f64>) -> Twist {
self.solve_at_segment(angles, qdots, self.chain.get_num_segments() - 1)
}
}
#[cfg(test)]
mod test {
use crate::chains::tests::create_testing_chain;
use crate::forward_diff_kinematics::ForwardDiffKinematicsSolver;
use crate::geometry::{get_twist_error, Twist};
#[test]
fn base_twist_correct() {
let chain = create_testing_chain();
let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
let qdots = vec![1.0, -0.65, 0.87, 0.01, -0.41, -0.98, 0.24];
let solver = ForwardDiffKinematicsSolver::new(chain);
let base_twist = solver.solve_at_segment(&angles, &qdots, 0);
assert_eq!(base_twist, Twist::zeros())
}
#[test]
fn end_twist_correct() {
let chain = create_testing_chain();
let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
let qdots = vec![1.0, -0.65, 0.87, 0.01, -0.41, -0.98, 0.24];
let solver = ForwardDiffKinematicsSolver::new(chain);
let end_twist = solver.solve(&angles, &qdots);
let error = get_twist_error(
end_twist,
Twist::new(-0.423878, -1.01074, 0.123592, -2.28297, 0.209941, 1.80897),
);
assert!(error < 0.00001)
}
#[test]
fn middle_twist_correct() {
let chain = create_testing_chain();
let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
let qdots = vec![1.0, -0.65, 0.87, 0.01, -0.41, -0.98, 0.24];
let solver = ForwardDiffKinematicsSolver::new(chain);
let middle_twist = solver.solve_at_segment(&angles, &qdots, 4);
let error = get_twist_error(
middle_twist,
Twist::new(-0.344006, 0.591387, 0.0751308, -1.1035, -0.0710371, 1.45781),
);
assert!(error < 0.00001)
}
}