diff options
Diffstat (limited to 'intern/iksolver/intern/IK_QJacobian.cpp')
-rw-r--r-- | intern/iksolver/intern/IK_QJacobian.cpp | 208 |
1 files changed, 98 insertions, 110 deletions
diff --git a/intern/iksolver/intern/IK_QJacobian.cpp b/intern/iksolver/intern/IK_QJacobian.cpp index bb7b7c5c0b8..2925cadf435 100644 --- a/intern/iksolver/intern/IK_QJacobian.cpp +++ b/intern/iksolver/intern/IK_QJacobian.cpp @@ -32,7 +32,6 @@ #include "IK_QJacobian.h" -#include "TNT/svd.h" IK_QJacobian::IK_QJacobian() : m_sdls(true), m_min_damp(1.0) @@ -48,74 +47,66 @@ void IK_QJacobian::ArmMatrices(int dof, int task_size) m_dof = dof; m_task_size = task_size; - m_jacobian.newsize(task_size, dof); - m_jacobian = 0; + m_jacobian.resize(task_size, dof); + m_jacobian.setZero(); - m_alpha.newsize(dof); - m_alpha = 0; + m_alpha.resize(dof); + m_alpha.setZero(); - m_null.newsize(dof, dof); + m_nullspace.resize(dof, dof); - m_d_theta.newsize(dof); - m_d_theta_tmp.newsize(dof); - m_d_norm_weight.newsize(dof); + m_d_theta.resize(dof); + m_d_theta_tmp.resize(dof); + m_d_norm_weight.resize(dof); - m_norm.newsize(dof); - m_norm = 0.0; + m_norm.resize(dof); + m_norm.setZero(); - m_beta.newsize(task_size); + m_beta.resize(task_size); - m_weight.newsize(dof); - m_weight_sqrt.newsize(dof); - m_weight = 1.0; - m_weight_sqrt = 1.0; + m_weight.resize(dof); + m_weight_sqrt.resize(dof); + m_weight.setOnes(); + m_weight_sqrt.setOnes(); if (task_size >= dof) { m_transpose = false; - m_jacobian_tmp.newsize(task_size, dof); + m_jacobian_tmp.resize(task_size, dof); - m_svd_u.newsize(task_size, dof); - m_svd_v.newsize(dof, dof); - m_svd_w.newsize(dof); + m_svd_u.resize(task_size, dof); + m_svd_v.resize(dof, dof); + m_svd_w.resize(dof); - m_work1.newsize(task_size); - m_work2.newsize(dof); - - m_svd_u_t.newsize(dof, task_size); - m_svd_u_beta.newsize(dof); + m_svd_u_beta.resize(dof); } else { // use the SVD of the transpose jacobian, it works just as well // as the original, and often allows using smaller matrices. m_transpose = true; - m_jacobian_tmp.newsize(dof, task_size); - - m_svd_u.newsize(task_size, task_size); - m_svd_v.newsize(dof, task_size); - m_svd_w.newsize(task_size); + m_jacobian_tmp.resize(dof, task_size); - m_work1.newsize(dof); - m_work2.newsize(task_size); + m_svd_u.resize(task_size, task_size); + m_svd_v.resize(dof, task_size); + m_svd_w.resize(task_size); - m_svd_u_t.newsize(task_size, task_size); - m_svd_u_beta.newsize(task_size); + m_svd_u_beta.resize(task_size); } } -void IK_QJacobian::SetBetas(int id, int, const MT_Vector3& v) +void IK_QJacobian::SetBetas(int id, int, const Vector3d& v) { m_beta[id + 0] = v.x(); m_beta[id + 1] = v.y(); m_beta[id + 2] = v.z(); } -void IK_QJacobian::SetDerivatives(int id, int dof_id, const MT_Vector3& v, MT_Scalar norm_weight) +void IK_QJacobian::SetDerivatives(int id, int dof_id, const Vector3d& v, double norm_weight) { - m_jacobian[id + 0][dof_id] = v.x() * m_weight_sqrt[dof_id]; - m_jacobian[id + 1][dof_id] = v.y() * m_weight_sqrt[dof_id]; - m_jacobian[id + 2][dof_id] = v.z() * m_weight_sqrt[dof_id]; + m_jacobian(id + 0, dof_id) = v.x() * m_weight_sqrt[dof_id]; + m_jacobian(id + 1, dof_id) = v.y() * m_weight_sqrt[dof_id]; + m_jacobian(id + 2, dof_id) = v.z() * m_weight_sqrt[dof_id]; m_d_norm_weight[dof_id] = norm_weight; } @@ -125,14 +116,18 @@ void IK_QJacobian::Invert() if (m_transpose) { // SVD will decompose Jt into V*W*Ut with U,V orthogonal and W diagonal, // so J = U*W*Vt and Jinv = V*Winv*Ut - TNT::transpose(m_jacobian, m_jacobian_tmp); - TNT::SVD(m_jacobian_tmp, m_svd_v, m_svd_w, m_svd_u, m_work1, m_work2); + Eigen::JacobiSVD<MatrixXd> svd(m_jacobian.transpose(), Eigen::ComputeThinU | Eigen::ComputeThinV); + m_svd_u = svd.matrixV(); + m_svd_w = svd.singularValues(); + m_svd_v = svd.matrixU(); } else { // SVD will decompose J into U*W*Vt with U,V orthogonal and W diagonal, // so Jinv = V*Winv*Ut - m_jacobian_tmp = m_jacobian; - TNT::SVD(m_jacobian_tmp, m_svd_u, m_svd_w, m_svd_v, m_work1, m_work2); + Eigen::JacobiSVD<MatrixXd> svd(m_jacobian, Eigen::ComputeThinU | Eigen::ComputeThinV); + m_svd_u = svd.matrixU(); + m_svd_w = svd.singularValues(); + m_svd_v = svd.matrixV(); } if (m_sdls) @@ -143,7 +138,7 @@ void IK_QJacobian::Invert() bool IK_QJacobian::ComputeNullProjection() { - MT_Scalar epsilon = 1e-10; + double epsilon = 1e-10; // compute null space projection based on V int i, j, rank = 0; @@ -154,26 +149,24 @@ bool IK_QJacobian::ComputeNullProjection() if (rank < m_task_size) return false; - TMatrix basis(m_svd_v.num_rows(), rank); - TMatrix basis_t(rank, m_svd_v.num_rows()); + MatrixXd basis(m_svd_v.rows(), rank); int b = 0; for (i = 0; i < m_svd_w.size(); i++) if (m_svd_w[i] > epsilon) { - for (j = 0; j < m_svd_v.num_rows(); j++) - basis[j][b] = m_svd_v[j][i]; + for (j = 0; j < m_svd_v.rows(); j++) + basis(j, b) = m_svd_v(j, i); b++; } - TNT::transpose(basis, basis_t); - TNT::matmult(m_null, basis, basis_t); + m_nullspace = basis * basis.transpose(); - for (i = 0; i < m_null.num_rows(); i++) - for (j = 0; j < m_null.num_cols(); j++) + for (i = 0; i < m_nullspace.rows(); i++) + for (j = 0; j < m_nullspace.cols(); j++) if (i == j) - m_null[i][j] = 1.0 - m_null[i][j]; + m_nullspace(i, j) = 1.0 - m_nullspace(i, j); else - m_null[i][j] = -m_null[i][j]; + m_nullspace(i, j) = -m_nullspace(i, j); return true; } @@ -184,7 +177,7 @@ void IK_QJacobian::SubTask(IK_QJacobian& jacobian) return; // restrict lower priority jacobian - jacobian.Restrict(m_d_theta, m_null); + jacobian.Restrict(m_d_theta, m_nullspace); // add angle update from lower priority jacobian.Invert(); @@ -197,19 +190,15 @@ void IK_QJacobian::SubTask(IK_QJacobian& jacobian) m_d_theta[i] = m_d_theta[i] + /*m_min_damp * */ jacobian.AngleUpdate(i); } -void IK_QJacobian::Restrict(TVector& d_theta, TMatrix& null) +void IK_QJacobian::Restrict(VectorXd& d_theta, MatrixXd& nullspace) { // subtract part already moved by higher task from beta - TVector beta_sub(m_beta.size()); - - TNT::matmult(beta_sub, m_jacobian, d_theta); - m_beta = m_beta - beta_sub; + m_beta = m_beta - m_jacobian * d_theta; // note: should we be using the norm of the unrestricted jacobian for SDLS? // project jacobian on to null space of higher priority task - TMatrix jacobian_copy(m_jacobian); - TNT::matmult(m_jacobian, jacobian_copy, null); + m_jacobian = m_jacobian * nullspace; } void IK_QJacobian::InvertSDLS() @@ -230,20 +219,20 @@ void IK_QJacobian::InvertSDLS() // DLS. The SDLS damps individual singular values, instead of using a single // damping term. - MT_Scalar max_angle_change = MT_PI / 4.0; - MT_Scalar epsilon = 1e-10; + double max_angle_change = M_PI / 4.0; + double epsilon = 1e-10; int i, j; - m_d_theta = 0; + m_d_theta.setZero(); m_min_damp = 1.0; for (i = 0; i < m_dof; i++) { m_norm[i] = 0.0; for (j = 0; j < m_task_size; j += 3) { - MT_Scalar n = 0.0; - n += m_jacobian[j][i] * m_jacobian[j][i]; - n += m_jacobian[j + 1][i] * m_jacobian[j + 1][i]; - n += m_jacobian[j + 2][i] * m_jacobian[j + 2][i]; + double n = 0.0; + n += m_jacobian(j, i) * m_jacobian(j, i); + n += m_jacobian(j + 1, i) * m_jacobian(j + 1, i); + n += m_jacobian(j + 2, i) * m_jacobian(j + 2, i); m_norm[i] += sqrt(n); } } @@ -252,40 +241,40 @@ void IK_QJacobian::InvertSDLS() if (m_svd_w[i] <= epsilon) continue; - MT_Scalar wInv = 1.0 / m_svd_w[i]; - MT_Scalar alpha = 0.0; - MT_Scalar N = 0.0; + double wInv = 1.0 / m_svd_w[i]; + double alpha = 0.0; + double N = 0.0; // compute alpha and N - for (j = 0; j < m_svd_u.num_rows(); j += 3) { - alpha += m_svd_u[j][i] * m_beta[j]; - alpha += m_svd_u[j + 1][i] * m_beta[j + 1]; - alpha += m_svd_u[j + 2][i] * m_beta[j + 2]; + for (j = 0; j < m_svd_u.rows(); j += 3) { + alpha += m_svd_u(j, i) * m_beta[j]; + alpha += m_svd_u(j + 1, i) * m_beta[j + 1]; + alpha += m_svd_u(j + 2, i) * m_beta[j + 2]; // note: for 1 end effector, N will always be 1, since U is // orthogonal, .. so could be optimized - MT_Scalar tmp; - tmp = m_svd_u[j][i] * m_svd_u[j][i]; - tmp += m_svd_u[j + 1][i] * m_svd_u[j + 1][i]; - tmp += m_svd_u[j + 2][i] * m_svd_u[j + 2][i]; + double tmp; + tmp = m_svd_u(j, i) * m_svd_u(j, i); + tmp += m_svd_u(j + 1, i) * m_svd_u(j + 1, i); + tmp += m_svd_u(j + 2, i) * m_svd_u(j + 2, i); N += sqrt(tmp); } alpha *= wInv; // compute M, dTheta and max_dtheta - MT_Scalar M = 0.0; - MT_Scalar max_dtheta = 0.0, abs_dtheta; + double M = 0.0; + double max_dtheta = 0.0, abs_dtheta; for (j = 0; j < m_d_theta.size(); j++) { - MT_Scalar v = m_svd_v[j][i]; - M += MT_abs(v) * m_norm[j]; + double v = m_svd_v(j, i); + M += fabs(v) * m_norm[j]; // compute tmporary dTheta's m_d_theta_tmp[j] = v * alpha; // find largest absolute dTheta // multiply with weight to prevent unnecessary damping - abs_dtheta = MT_abs(m_d_theta_tmp[j]) * m_weight_sqrt[j]; + abs_dtheta = fabs(m_d_theta_tmp[j]) * m_weight_sqrt[j]; if (abs_dtheta > max_dtheta) max_dtheta = abs_dtheta; } @@ -293,18 +282,18 @@ void IK_QJacobian::InvertSDLS() M *= wInv; // compute damping term and damp the dTheta's - MT_Scalar gamma = max_angle_change; + double gamma = max_angle_change; if (N < M) gamma *= N / M; - MT_Scalar damp = (gamma < max_dtheta) ? gamma / max_dtheta : 1.0; + double damp = (gamma < max_dtheta) ? gamma / max_dtheta : 1.0; for (j = 0; j < m_d_theta.size(); j++) { // slight hack: we do 0.80*, so that if there is some oscillation, // the system can still converge (for joint limits). also, it's // better to go a little to slow than to far - MT_Scalar dofdamp = damp / m_weight[j]; + double dofdamp = damp / m_weight[j]; if (dofdamp > 1.0) dofdamp = 1.0; m_d_theta[j] += 0.80 * dofdamp * m_d_theta_tmp[j]; @@ -315,19 +304,19 @@ void IK_QJacobian::InvertSDLS() } // weight + prevent from doing angle updates with angles > max_angle_change - MT_Scalar max_angle = 0.0, abs_angle; + double max_angle = 0.0, abs_angle; for (j = 0; j < m_dof; j++) { m_d_theta[j] *= m_weight[j]; - abs_angle = MT_abs(m_d_theta[j]); + abs_angle = fabs(m_d_theta[j]); if (abs_angle > max_angle) max_angle = abs_angle; } if (max_angle > max_angle_change) { - MT_Scalar damp = (max_angle_change) / (max_angle_change + max_angle); + double damp = (max_angle_change) / (max_angle_change + max_angle); for (j = 0; j < m_dof; j++) m_d_theta[j] *= damp; @@ -353,12 +342,12 @@ void IK_QJacobian::InvertDLS() // find the smallest non-zero W value, anything below epsilon is // treated as zero - MT_Scalar epsilon = 1e-10; - MT_Scalar max_angle_change = 0.1; - MT_Scalar x_length = sqrt(TNT::dot_prod(m_beta, m_beta)); + double epsilon = 1e-10; + double max_angle_change = 0.1; + double x_length = sqrt(m_beta.dot(m_beta)); int i, j; - MT_Scalar w_min = MT_INFINITY; + double w_min = std::numeric_limits<double>::max(); for (i = 0; i < m_svd_w.size(); i++) { if (m_svd_w[i] > epsilon && m_svd_w[i] < w_min) @@ -367,8 +356,8 @@ void IK_QJacobian::InvertDLS() // compute lambda damping term - MT_Scalar d = x_length / max_angle_change; - MT_Scalar lambda; + double d = x_length / max_angle_change; + double lambda; if (w_min <= d / 2) lambda = d / 2; @@ -386,20 +375,19 @@ void IK_QJacobian::InvertDLS() // rather than matrix*matrix products // compute Ut*Beta - TNT::transpose(m_svd_u, m_svd_u_t); - TNT::matmult(m_svd_u_beta, m_svd_u_t, m_beta); + m_svd_u_beta = m_svd_u.transpose() * m_beta; - m_d_theta = 0.0; + m_d_theta.setZero(); for (i = 0; i < m_svd_w.size(); i++) { if (m_svd_w[i] > epsilon) { - MT_Scalar wInv = m_svd_w[i] / (m_svd_w[i] * m_svd_w[i] + lambda); + double wInv = m_svd_w[i] / (m_svd_w[i] * m_svd_w[i] + lambda); // compute V*Winv*Ut*Beta m_svd_u_beta[i] *= wInv; for (j = 0; j < m_d_theta.size(); j++) - m_d_theta[j] += m_svd_v[j][i] * m_svd_u_beta[i]; + m_d_theta[j] += m_svd_v(j, i) * m_svd_u_beta[i]; } } @@ -407,31 +395,31 @@ void IK_QJacobian::InvertDLS() m_d_theta[j] *= m_weight[j]; } -void IK_QJacobian::Lock(int dof_id, MT_Scalar delta) +void IK_QJacobian::Lock(int dof_id, double delta) { int i; for (i = 0; i < m_task_size; i++) { - m_beta[i] -= m_jacobian[i][dof_id] * delta; - m_jacobian[i][dof_id] = 0.0; + m_beta[i] -= m_jacobian(i, dof_id) * delta; + m_jacobian(i, dof_id) = 0.0; } m_norm[dof_id] = 0.0; // unneeded m_d_theta[dof_id] = 0.0; } -MT_Scalar IK_QJacobian::AngleUpdate(int dof_id) const +double IK_QJacobian::AngleUpdate(int dof_id) const { return m_d_theta[dof_id]; } -MT_Scalar IK_QJacobian::AngleUpdateNorm() const +double IK_QJacobian::AngleUpdateNorm() const { int i; - MT_Scalar mx = 0.0, dtheta_abs; + double mx = 0.0, dtheta_abs; for (i = 0; i < m_d_theta.size(); i++) { - dtheta_abs = MT_abs(m_d_theta[i] * m_d_norm_weight[i]); + dtheta_abs = fabs(m_d_theta[i] * m_d_norm_weight[i]); if (dtheta_abs > mx) mx = dtheta_abs; } @@ -439,7 +427,7 @@ MT_Scalar IK_QJacobian::AngleUpdateNorm() const return mx; } -void IK_QJacobian::SetDoFWeight(int dof, MT_Scalar weight) +void IK_QJacobian::SetDoFWeight(int dof, double weight) { m_weight[dof] = weight; m_weight_sqrt[dof] = sqrt(weight); |