use crate::chains::Chain;
use crate::geometry::{
new_ref_base, new_ref_frame, new_ref_point, Frame, Introspection, Twist, Vector,
};
use crate::joint::JointType;
use nalgebra::{Dyn, Matrix3, OMatrix, U6};
pub type Jacobian = OMatrix<f64, U6, Dyn>;
pub fn vec_to_jacobian(ncols: usize, vector: Vec<f64>) -> Jacobian {
Jacobian::from_fn(ncols, |i, j| vector[(i * ncols + j) % (ncols * 6)])
}
pub trait JointOperations {
fn get_joint_twist(&self, joint_index: usize) -> Twist;
fn new_ref_point(&mut self, new_ref: Vector);
fn new_ref_base(&mut self, new_ref: Matrix3<f64>);
fn new_ref_frame(&mut self, new_ref: Frame);
}
impl JointOperations for Jacobian {
fn get_joint_twist(&self, joint_index: usize) -> Twist {
let num_cols = self.ncols();
if num_cols <= joint_index {
panic!(
"Requested Joint {}, but Jacobian only has {}",
joint_index, num_cols
);
}
let col = self.column(joint_index);
Twist::from_columns(&[col])
}
fn new_ref_point(&mut self, new_ref: Vector) {
let num_cols = self.ncols();
for col in 0..num_cols {
self.set_column(col, &new_ref_point(self.get_joint_twist(col), new_ref));
}
}
fn new_ref_base(&mut self, new_ref: Matrix3<f64>) {
let num_cols = self.ncols();
for col in 0..num_cols {
self.set_column(col, &new_ref_base(self.get_joint_twist(col), new_ref));
}
}
fn new_ref_frame(&mut self, new_ref: Frame) {
let num_cols = self.ncols();
for col in 0..num_cols {
self.set_column(col, &new_ref_frame(self.get_joint_twist(col), new_ref));
}
}
}
pub trait JacobianSolver {
fn solve_from_chain(&mut self, chain: &Chain, angles: &Vec<f64>);
}
impl JacobianSolver for Jacobian {
fn solve_from_chain(&mut self, chain: &Chain, angles: &Vec<f64>) {
let num_joints = chain.get_num_ind_joints();
if angles.len() != num_joints {
panic!(
"Unable to compute Jacobian of a chain with {} \
joints from {} angles",
num_joints,
angles.len()
);
}
if num_joints != self.ncols() {
panic!(
"Unable to store jacobian of a chain with {} \
joints in a matrix with {} columns",
num_joints,
self.ncols()
);
}
let mut pose_tmp = Frame::identity();
let mut pose_total;
let mut jac_index = 0;
let mut joint_index = 0;
for segment_index in 0..chain.get_num_segments() {
let segment = chain.get_segment(segment_index);
pose_total = pose_tmp * segment.pose(angles[joint_index]);
self.new_ref_point(pose_total.get_translation() - pose_tmp.get_translation());
if segment.get_joint_type() != JointType::NoJoint {
if !chain.get_locked_joints()[joint_index] {
let twist = new_ref_base(
segment.twist(angles[joint_index], 1.0),
pose_tmp.get_rotation(),
);
self.set_column(jac_index, &twist);
jac_index += 1;
}
joint_index += 1;
}
pose_tmp = pose_total;
}
self.clone().mul_to(&chain.get_coupling_matrix(), self);
}
}
pub fn get_jacobian_error(left: Jacobian, right: Jacobian) -> f64 {
let num_joints = left.ncols();
if num_joints != right.ncols() {
panic!(
"Unable to comapre Jacobians of different sizes. Got {} and {}",
num_joints,
right.ncols()
);
}
let error = (left - right).abs();
let total = num_joints as f64;
error.fold(0.0, |a: f64, b: f64| a + b) / total
}
#[cfg(test)]
mod tests {
use crate::chains::tests::create_testing_chain;
use crate::geometry::{Frame, Twist, Vector};
use crate::jacobian::{
get_jacobian_error, vec_to_jacobian, Jacobian, JacobianSolver, JointOperations,
};
use nalgebra::Matrix3;
#[test]
fn get_twist_from_jacobian() {
let jacobian = vec_to_jacobian(
3,
vec![
0.419164, 0.818984, 0.707018, 0.41915, 0.421392, 0.753147, 0.865399, 0.119757,
0.30401, 0.65547, 0.674511, 0.386427, 0.647384, 0.251815, 0.908477, 0.50629,
0.060354, 0.482741,
],
);
let first_twist = Twist::new(0.419164, 0.41915, 0.865399, 0.65547, 0.647384, 0.50629);
let second_twist = Twist::new(0.818984, 0.421392, 0.119757, 0.674511, 0.251815, 0.060354);
let third_twist = Twist::new(0.707018, 0.753147, 0.30401, 0.386427, 0.908477, 0.482741);
assert_eq!(first_twist, jacobian.get_joint_twist(0));
assert_eq!(second_twist, jacobian.get_joint_twist(1));
assert_eq!(third_twist, jacobian.get_joint_twist(2));
}
#[test]
fn change_ref_point() {
let point = Vector::new(0.1, 0.5, 6.0);
let mut jacobian = vec_to_jacobian(
4,
vec![
0.419164, 0.818984, 0.707018, 0.01, 0.41915, 0.421392, 0.753147, 0.01, 0.865399,
0.119757, 0.30401, 0.01, 0.65547, 0.674511, 0.386427, 0.01, 0.647384, 0.251815,
0.908477, 0.01, 0.50629, 0.060354, 0.482741, 0.01,
],
);
let expected = vec_to_jacobian(
4,
vec![
4.05032, 2.2997, 5.91651, 0.065, -3.46304, -3.61964, -1.51714, -0.049, 1.1284,
0.431831, 0.406376, 0.014, 0.65547, 0.674511, 0.386427, 0.01, 0.647384, 0.251815,
0.908477, 0.01, 0.50629, 0.060354, 0.482741, 0.01,
],
);
jacobian.new_ref_point(point);
let error = get_jacobian_error(jacobian, expected);
assert!(error < 0.0001)
}
#[test]
fn change_ref_base() {
let rotation = Matrix3::new(
0.842629, 0.323976, 0.430135, -0.24521, 0.942, -0.229147, -0.479426, 0.0876121,
0.873198,
);
let mut jacobian = vec_to_jacobian(
4,
vec![
0.419164, 0.818984, 0.707018, 0.01, 0.41915, 0.421392, 0.753147, 0.01, 0.865399,
0.119757, 0.30401, 0.01, 0.65547, 0.674511, 0.386427, 0.01, 0.647384, 0.251815,
0.908477, 0.01, 0.50629, 0.060354, 0.482741, 0.01,
],
);
let expected = vec_to_jacobian(
4,
vec![
0.861233, 0.878132, 0.970521, 0.0159674, 0.0937526, 0.168686, 0.466433, 0.00467643,
0.59143, -0.251151, -0.0075167, 0.00481385, 0.979828, 0.675905, 0.827583,
0.0159674, 0.333093, 0.0579828, 0.650411, 0.00467643, 0.184561, -0.248615,
0.315859, 0.00481385,
],
);
jacobian.new_ref_base(rotation);
let error = get_jacobian_error(jacobian, expected);
assert!(error < 0.0001);
}
#[test]
fn change_ref_frame() {
let frame = Frame::new(
0.842629, 0.323976, 0.430135, 0.1, -0.24521, 0.942, -0.229147, 0.5, -0.479426,
0.0876121, 0.873198, 6.0, 0.0, 0.0, 0.0, 1.0,
);
let mut jacobian = vec_to_jacobian(
4,
vec![
0.419164, 0.818984, 0.707018, 0.01, 0.41915, 0.421392, 0.753147, 0.01, 0.865399,
0.119757, 0.30401, 0.01, 0.65547, 0.674511, 0.386427, 0.01, 0.647384, 0.251815,
0.908477, 0.01, 0.50629, 0.060354, 0.482741, 0.01,
],
);
let expected = vec_to_jacobian(
4,
vec![
-1.04504,
0.405928,
-2.77401,
-0.00968425,
5.95426,
4.24898,
5.40035,
0.0999994,
0.134825,
-0.583305,
-0.356267,
-0.00270221,
0.979828,
0.675905,
0.827583,
0.0159674,
0.333093,
0.0579828,
0.650411,
0.00467643,
0.184561,
-0.248615,
0.315859,
0.00481385,
],
);
jacobian.new_ref_frame(frame);
let error = get_jacobian_error(jacobian, expected);
assert!(error < 0.0001);
}
#[test]
fn jacobian_from_chain_correct() {
let chain = create_testing_chain();
let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
let mut result = Jacobian::zeros(angles.len());
result.solve_from_chain(&chain, &angles);
let expected = vec_to_jacobian(
7,
vec![
-0.330827,
0.261285,
-0.0634603,
-0.640334,
-0.44059,
-0.00594982,
-0.20031,
-1.48783,
-1.80195,
-0.39123,
-0.911489,
-0.717405,
0.675781,
0.0976329,
-0.0176899,
0.160687,
-0.0226411,
-0.952894,
-0.85285,
0.0807787,
0.0185394,
-0.218351,
0.852363,
-0.387827,
0.629791,
0.632632,
0.971581,
0.133574,
0.036957,
0.167762,
0.00956914,
-0.727376,
-0.721899,
0.0365101,
0.0865809,
0.97517,
0.495311,
0.921682,
0.272557,
0.280427,
-0.233875,
0.98725,
],
);
let error = get_jacobian_error(result, expected);
assert!(error < 0.0001);
}
}