1#ifndef TR_INVERSEKINEMATICS_HPP
2#define TR_INVERSEKINEMATICS_HPP
5#include <Eigen/Geometry>
7#include <unsupported/Eigen/AutoDiff>
16namespace tinyrobotics {
25 template <
typename Scalar,
int n>
26 inline void eigen_to_nlopt(
const Eigen::Matrix<Scalar, n, 1>& eigen_vec, std::vector<Scalar>& nlopt_vec) {
28 Eigen::Map<Eigen::Matrix<Scalar, n, 1>> nlopt_eigen_vec(nlopt_vec.data(), n);
31 nlopt_eigen_vec = eigen_vec;
41 template <
typename Scalar,
int n>
42 inline void nlopt_to_eigen(
const std::vector<Scalar>& nlopt_vec, Eigen::Matrix<Scalar, n, 1>& eigen_vec) {
44 const Eigen::Map<const Eigen::Matrix<Scalar, n, 1>> nlopt_eigen_vec(nlopt_vec.data(), n);
47 eigen_vec = nlopt_eigen_vec;
55 template <
typename Scalar,
int nv>
57 std::function<Scalar(
const Eigen::Matrix<Scalar, nv, 1>&, Eigen::Matrix<Scalar, nv, 1>&,
void*)>;
69 template <
typename Scalar,
int nv>
74 Eigen::Map<const Eigen::Matrix<Scalar, nv, 1>> eigen_x(x, n);
75 Eigen::Matrix<Scalar, nv, 1> eigen_grad = Eigen::Matrix<Scalar, nv, 1>::Zero();
79 Eigen::Map<Eigen::Matrix<Scalar, nv, 1>>(grad, n) = eigen_grad;
83 Scalar result = obj_fun(eigen_x, eigen_grad, data);
87 Eigen::Map<Eigen::Matrix<Scalar, nv, 1>>(grad, n) = eigen_grad;
112 template <
typename Scalar,
int nq>
135 Eigen::Matrix<Scalar, 6, 6>
K = Eigen::Matrix<Scalar, 6, 6>::Identity();
138 Eigen::Matrix<Scalar, nq, nq>
W = 1e-3 * Eigen::Matrix<Scalar, nq, nq>::Identity();
178 template <
typename Scalar,
int nq>
179 Scalar
cost(
const Eigen::Matrix<Scalar, nq, 1>& q,
181 const std::string& target_link_name,
182 const std::string& source_link_name,
183 const Eigen::Transform<Scalar, 3, Eigen::Isometry>& desired_pose,
184 const Eigen::Matrix<Scalar, nq, 1>& q0,
185 Eigen::Matrix<Scalar, nq, 1>& gradient,
189 Eigen::Transform<Scalar, 3, Eigen::Isometry> current_pose =
193 Eigen::Matrix<Scalar, 6, 1> pose_error =
homogeneous_error(current_pose, desired_pose);
197 Eigen::Matrix<Scalar, 1, 1>
cost =
198 0.5 * pose_error.transpose() * options.
K * pose_error + 0.5 * (q - q0).transpose() * options.
W * (q - q0);
201 Eigen::Matrix<Scalar, 6, nq> J =
jacobian(model, q, target_link_name);
202 gradient = J.transpose() * options.
K * pose_error + options.
W * (q - q0);
218 template <
typename Scalar,
int nq>
221 const std::string& target_link_name,
222 const std::string& source_link_name,
223 const Eigen::Transform<Scalar, 3, Eigen::Isometry>& desired_pose,
224 const Eigen::Matrix<Scalar, nq, 1> q0,
231 [&](
const Eigen::Matrix<Scalar, nq, 1>& q, Eigen::Matrix<Scalar, nq, 1>& grad,
void* data) -> Scalar {
235 Eigen::Matrix<Scalar, nq, 1> gradient;
236 Scalar cost_value = 0.0;
237 cost_value =
cost(q, model, target_link_name, source_link_name, desired_pose, q0, gradient, options);
240 for (
int i = 0; i < nq; ++i) {
241 grad[i] = gradient(i);
247 opt.set_min_objective(eigen_objective_wrapper<Scalar, nq>, &obj_fun);
257 std::vector<Scalar> x_initial(nq);
258 eigen_to_nlopt<Scalar, nq>(q0, x_initial);
262 opt.optimize(x_initial, minf);
265 Eigen::Matrix<Scalar, nq, 1> optimized_solution(nq);
266 nlopt_to_eigen<Scalar, nq>(x_initial, optimized_solution);
267 return optimized_solution;
281 template <
typename Scalar,
int nq>
284 const std::string& target_link_name,
285 const std::string& source_link_name,
286 const Eigen::Transform<Scalar, 3, Eigen::Isometry>& desired_pose,
287 const Eigen::Matrix<Scalar, nq, 1> q0,
291 Eigen::Matrix<Scalar, nq, 1> q_current = q0;
294 for (
int iteration = 0; iteration < options.
max_iterations; ++iteration) {
297 Eigen::Transform<Scalar, 3, Eigen::Isometry> current_pose =
301 Eigen::Matrix<Scalar, 6, 1> pose_error =
homogeneous_error(current_pose, desired_pose);
304 if (pose_error.norm() < options.
tolerance) {
309 Eigen::Matrix<Scalar, 6, nq> J =
jacobian(model, q_current, target_link_name);
312 Eigen::Matrix<Scalar, nq, 1> delta_q =
313 J.completeOrthogonalDecomposition().pseudoInverse() * (-options.
step_size * pose_error);
316 q_current += delta_q;
334 template <
typename Scalar,
int nq>
337 const std::string& target_link_name,
338 const std::string& source_link_name,
339 const Eigen::Transform<Scalar, 3, Eigen::Isometry>& desired_pose,
340 const Eigen::Matrix<Scalar, nq, 1> q0,
344 Eigen::Matrix<Scalar, nq, 1> q_current = q0;
350 for (
int iteration = 0; iteration < options.
max_iterations; ++iteration) {
353 Eigen::Transform<Scalar, 3, Eigen::Isometry> current_pose =
357 Eigen::Matrix<Scalar, 6, 1> pose_error =
homogeneous_error(current_pose, desired_pose);
360 if (pose_error.norm() < options.
tolerance) {
365 Eigen::Matrix<Scalar, 6, nq> J =
jacobian(model, q_current, target_link_name);
368 Eigen::Matrix<Scalar, nq, nq> H = J.transpose() * J;
369 Eigen::Matrix<Scalar, nq, 1> g = J.transpose() * pose_error;
372 Eigen::Matrix<Scalar, nq, 1> delta_q =
373 (H + lambda * Eigen::Matrix<Scalar, nq, nq>(H.diagonal().asDiagonal())).ldlt().solve(-g);
376 Eigen::Matrix<Scalar, nq, 1> q_new = q_current + delta_q;
377 Eigen::Transform<Scalar, 3, Eigen::Isometry> new_pose =
381 Eigen::Matrix<Scalar, 6, 1> new_pose_error;
382 new_pose_error.head(3) = new_pose.translation() - desired_pose.translation();
383 Eigen::AngleAxis<Scalar> new_rot_error(new_pose.rotation().transpose() * desired_pose.rotation());
384 new_pose_error.tail(3) = new_rot_error.angle() * new_rot_error.axis();
387 if (new_pose_error.norm() < pose_error.norm()) {
413 template <
typename Scalar,
int nq>
416 const std::string& target_link_name,
417 const std::string& source_link_name,
418 const Eigen::Transform<Scalar, 3, Eigen::Isometry>& desired_pose,
419 const Eigen::Matrix<Scalar, nq, 1> q0,
423 Scalar omega = options.
omega;
424 Scalar c1 = options.
c1;
425 Scalar c2 = options.
c2;
428 std::vector<Eigen::Matrix<Scalar, nq, 1>> particles(num_particles, q0);
429 std::vector<Eigen::Matrix<Scalar, nq, 1>> velocities(num_particles, Eigen::Matrix<Scalar, nq, 1>::Zero());
430 std::vector<Scalar> fitness_values(num_particles, std::numeric_limits<Scalar>::max());
431 Eigen::Matrix<Scalar, nq, 1> best_global_position = q0;
432 Scalar best_global_fitness = std::numeric_limits<Scalar>::max();
435 for (
int i = 0; i < num_particles; ++i) {
440 for (
int iteration = 0; iteration < options.
max_iterations; ++iteration) {
441 for (
int i = 0; i < num_particles; ++i) {
443 Eigen::Transform<Scalar, 3, Eigen::Isometry> current_pose =
445 Scalar fitness_value =
homogeneous_error(current_pose, desired_pose).squaredNorm();
448 if (fitness_value < fitness_values[i]) {
449 fitness_values[i] = fitness_value;
453 if (fitness_value < best_global_fitness) {
454 best_global_fitness = fitness_value;
455 best_global_position = particles[i];
460 for (
int i = 0; i < num_particles; ++i) {
463 omega * velocities[i]
464 + c1 * Eigen::Matrix<Scalar, nq, 1>::Random().cwiseProduct(particles[i] - best_global_position)
465 + c2 * Eigen::Matrix<Scalar, nq, 1>::Random().cwiseProduct(best_global_position - particles[i]);
468 particles[i] += velocities[i];
472 if (best_global_fitness < options.
tolerance) {
478 return best_global_position;
492 template <
typename Scalar,
int nq>
495 const std::string& target_link_name,
496 const std::string& source_link_name,
497 const Eigen::Transform<Scalar, 3, Eigen::Isometry>& desired_pose,
498 const Eigen::Matrix<Scalar, nq, 1> q0,
501 Eigen::Matrix<Scalar, nq, 1> q = q0;
502 Eigen::Matrix<Scalar, nq, 1> grad;
503 Eigen::Matrix<Scalar, nq, nq> inverse_hessian = Eigen::Matrix<Scalar, nq, nq>::Identity();
505 for (
int iteration = 0; iteration < options.
max_iterations; ++iteration) {
507 Scalar cost_value =
cost(q, model, target_link_name, source_link_name, desired_pose, q0, grad, options);
513 Eigen::Matrix<Scalar, nq, 1> direction = -inverse_hessian * grad;
515 Eigen::Matrix<Scalar, nq, 1> grad_new;
520 Eigen::Matrix<Scalar, nq, 1> q_new = q + alpha * direction;
521 cost_new =
cost(q_new, model, target_link_name, source_link_name, desired_pose, q0, grad_new, options);
522 }
while (cost_new > cost_value + options.
step_size * alpha * grad.dot(direction));
524 Eigen::Matrix<Scalar, nq, 1> q_new = q + alpha * direction;
526 Eigen::Matrix<Scalar, nq, 1> s = q_new - q;
527 Eigen::Matrix<Scalar, nq, 1> y = grad_new - grad;
528 Scalar rho = 1.0 / y.dot(s);
530 Eigen::Matrix<Scalar, nq, nq> I = Eigen::Matrix<Scalar, nq, nq>::Identity();
531 inverse_hessian = (I - rho * s * y.transpose()) * inverse_hessian * (I - rho * y * s.transpose())
532 + rho * s * s.transpose();
552 template <
typename Scalar,
int nq>
554 const std::string& target_link_name,
555 const std::string& source_link_name,
556 const Eigen::Transform<Scalar, 3, Eigen::Isometry>& desired_pose,
557 const Eigen::Matrix<Scalar, nq, 1> q0,
560 case InverseKinematicsMethod::NLOPT:
562 case InverseKinematicsMethod::JACOBIAN:
569 case InverseKinematicsMethod::LEVENBERG_MARQUARDT:
576 case InverseKinematicsMethod::PARTICLE_SWARM:
578 case InverseKinematicsMethod::BFGS:
580 default:
throw std::runtime_error(
"Unknown inverse kinematics method");
Eigen::Matrix< Scalar, nq, 1 > inverse_kinematics_jacobian(Model< Scalar, nq > &model, const std::string &target_link_name, const std::string &source_link_name, const Eigen::Transform< Scalar, 3, Eigen::Isometry > &desired_pose, const Eigen::Matrix< Scalar, nq, 1 > q0, const InverseKinematicsOptions< Scalar, nq > &options)
Solves the inverse kinematics problem between two links using the Jacobian method.
Definition: inversekinematics.hpp:282
Eigen::Matrix< Scalar, nq, 1 > inverse_kinematics(Model< Scalar, nq > &model, const std::string &target_link_name, const std::string &source_link_name, const Eigen::Transform< Scalar, 3, Eigen::Isometry > &desired_pose, const Eigen::Matrix< Scalar, nq, 1 > q0, const InverseKinematicsOptions< Scalar, nq > &options)
Solves the inverse kinematics problem between two links using user specified method.
Definition: inversekinematics.hpp:553
Eigen::Matrix< Scalar, nq, 1 > inverse_kinematics_bfgs(Model< Scalar, nq > &model, const std::string &target_link_name, const std::string &source_link_name, const Eigen::Transform< Scalar, 3, Eigen::Isometry > &desired_pose, const Eigen::Matrix< Scalar, nq, 1 > q0, const InverseKinematicsOptions< Scalar, nq > &options)
Solves the inverse kinematics problem between two links using Broyden-Fletcher-Goldfarb-Shanno (BFGS)...
Definition: inversekinematics.hpp:493
Eigen::Matrix< Scalar, nq, 1 > inverse_kinematics_levenberg_marquardt(Model< Scalar, nq > &model, const std::string &target_link_name, const std::string &source_link_name, const Eigen::Transform< Scalar, 3, Eigen::Isometry > &desired_pose, const Eigen::Matrix< Scalar, nq, 1 > q0, const InverseKinematicsOptions< Scalar, nq > &options)
Solves the inverse kinematics problem between two links using the Levenberg-Marquardt method.
Definition: inversekinematics.hpp:335
void nlopt_to_eigen(const std::vector< Scalar > &nlopt_vec, Eigen::Matrix< Scalar, n, 1 > &eigen_vec)
Converts an std::vector to an Eigen vector.
Definition: inversekinematics.hpp:42
std::function< Scalar(const Eigen::Matrix< Scalar, nv, 1 > &, Eigen::Matrix< Scalar, nv, 1 > &, void *)> ObjectiveFunction
Type definition for an objective function that takes an Eigen vector as input and returns a scalar va...
Definition: inversekinematics.hpp:57
Eigen::Matrix< Scalar, nq, 1 > inverse_kinematics_pso(Model< Scalar, nq > &model, const std::string &target_link_name, const std::string &source_link_name, const Eigen::Transform< Scalar, 3, Eigen::Isometry > &desired_pose, const Eigen::Matrix< Scalar, nq, 1 > q0, const InverseKinematicsOptions< Scalar, nq > &options)
Solves the inverse kinematics problem between two links using Particle Swarm Optimization.
Definition: inversekinematics.hpp:414
void eigen_to_nlopt(const Eigen::Matrix< Scalar, n, 1 > &eigen_vec, std::vector< Scalar > &nlopt_vec)
Converts an Eigen vector to an std::vector.
Definition: inversekinematics.hpp:26
Scalar cost(const Eigen::Matrix< Scalar, nq, 1 > &q, Model< Scalar, nq > &model, const std::string &target_link_name, const std::string &source_link_name, const Eigen::Transform< Scalar, 3, Eigen::Isometry > &desired_pose, const Eigen::Matrix< Scalar, nq, 1 > &q0, Eigen::Matrix< Scalar, nq, 1 > &gradient, const InverseKinematicsOptions< Scalar, nq > &options)
Cost function for general inverse kinematics with analytical jacobian.
Definition: inversekinematics.hpp:179
InverseKinematicsMethod
Solver methods for inverse kinematics.
Definition: inversekinematics.hpp:94
@ LEVENBERG_MARQUARDT
Levenberg-Marquardt method.
@ PARTICLE_SWARM
Particle swarm optimization method.
@ JACOBIAN
Jacobian method.
Scalar eigen_objective_wrapper(unsigned n, const Scalar *x, Scalar *grad, void *data)
Wrapper function that converts input and output between NLopt and Eigen formats for an objective func...
Definition: inversekinematics.hpp:70
Eigen::Matrix< Scalar, nq, 1 > inverse_kinematics_nlopt(Model< Scalar, nq > &model, const std::string &target_link_name, const std::string &source_link_name, const Eigen::Transform< Scalar, 3, Eigen::Isometry > &desired_pose, const Eigen::Matrix< Scalar, nq, 1 > q0, const InverseKinematicsOptions< Scalar, nq > &options)
Solves the inverse kinematics problem between two links using NLopt.
Definition: inversekinematics.hpp:219
Contains functions for computing various kinematic quantities of a tinyrobotics model.
Eigen::Matrix< Scalar, 6, nq > jacobian(Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q, const TargetLink &target_link)
Computes the geometric jacobian of the target link from the base link, in the base link frame.
Definition: kinematics.hpp:175
std::vector< Eigen::Transform< Scalar, 3, Eigen::Isometry > > forward_kinematics(Model< Scalar, nq > &model, const Eigen::Matrix< Scalar, nq, 1 > &q)
Computes the transform to all the links in the tinyrobotics model.
Definition: kinematics.hpp:47
Contains various math related functions.
Eigen::Matrix< Scalar, 6, 1 > homogeneous_error(const Eigen::Transform< Scalar, 3, Eigen::Isometry > &H1, const Eigen::Transform< Scalar, 3, Eigen::Isometry > &H2)
Computes the error between two homogeneous transformation matrices.
Definition: math.hpp:132
Contains struct for representing a tinyrobotics model.
Options for inverse kinematics solver.
Definition: inversekinematics.hpp:113
Scalar init_position_scale
Scale for initializing particle positions around the initial guess.
Definition: inversekinematics.hpp:164
InverseKinematicsMethod method
Inverse kinematics solver method.
Definition: inversekinematics.hpp:124
Eigen::Matrix< Scalar, nq, nq > W
Weighting matrix for joint displacement from initial configuration.
Definition: inversekinematics.hpp:138
nlopt::algorithm algorithm
NLopt optimization algorithm to use.
Definition: inversekinematics.hpp:132
int max_iterations
Maximum number of iterations for optimization.
Definition: inversekinematics.hpp:121
Scalar xtol_rel
Relative tolerance for NLopt optimization variables.
Definition: inversekinematics.hpp:118
Scalar damping_decrease_factor
Damping decrease factor for Levenberg-Marquardt.
Definition: inversekinematics.hpp:145
Scalar damping_increase_factor
Damping increase factor for Levenberg-Marquardt.
Definition: inversekinematics.hpp:148
Scalar c1
Cognitive weight (c1) for updating particle velocities.
Definition: inversekinematics.hpp:158
Scalar initial_damping
Inital damping factor for Levenberg-Marquardt.
Definition: inversekinematics.hpp:142
int num_particles
Number of particles in the swarm.
Definition: inversekinematics.hpp:152
Scalar omega
Inertia weight (omega) for updating particle velocities.
Definition: inversekinematics.hpp:155
Scalar tolerance
Relative tolerance for cost function value.
Definition: inversekinematics.hpp:115
Scalar step_size
Step size.
Definition: inversekinematics.hpp:128
Eigen::Matrix< Scalar, 6, 6 > K
Weighting matrix for pose error.
Definition: inversekinematics.hpp:135
Scalar c2
Social weight (c2) for updating particle velocities.
Definition: inversekinematics.hpp:161
A tinyrobotics model.
Definition: model.hpp:25