38 #include "PlanarManipulator.h"
39 #include <boost/math/constants/constants.hpp>
42 #define PI boost::math::constants::pi<double>()
43 #define TWOPI boost::math::constants::two_pi<double>()
45 PlanarManipulator::PlanarManipulator(
unsigned int numLinks,
double linkLength,
const std::pair<double, double> &origin)
46 : numLinks_(numLinks), linkLengths_(numLinks_, linkLength)
48 baseFrame_ = Eigen::Affine2d::Identity();
49 baseFrame_.translation()[0] = origin.first;
50 baseFrame_.translation()[1] = origin.second;
52 hasBounds_.assign(numLinks_,
false);
53 lowerBounds_.assign(numLinks_, std::numeric_limits<double>::min());
54 upperBounds_.assign(numLinks_, std::numeric_limits<double>::max());
57 PlanarManipulator::PlanarManipulator(
unsigned int numLinks,
const std::vector<double> &linkLengths,
58 const std::pair<double, double> &origin)
59 : numLinks_(numLinks), linkLengths_(linkLengths)
61 if (linkLengths_.size() != numLinks)
63 std::cerr <<
"Length of linkLengths (" << linkLengths.size() <<
") is not equal to the number of links ("
64 << numLinks <<
")" << std::endl;
68 baseFrame_ = Eigen::Affine2d::Identity();
69 baseFrame_.translation()[0] = origin.first;
70 baseFrame_.translation()[1] = origin.second;
72 hasBounds_.assign(numLinks_,
false);
73 lowerBounds_.assign(numLinks_, std::numeric_limits<double>::min());
74 upperBounds_.assign(numLinks_, std::numeric_limits<double>::max());
77 PlanarManipulator::~PlanarManipulator()
82 unsigned int PlanarManipulator::getNumLinks()
const
87 const Eigen::Affine2d &PlanarManipulator::getBaseFrame()
const
92 void PlanarManipulator::setBaseFrame(
const Eigen::Affine2d &frame)
98 const std::vector<double> &PlanarManipulator::getLinkLengths()
const
104 void PlanarManipulator::setBounds(
unsigned int link,
double low,
double high)
106 assert(link < hasBounds_.size());
108 hasBounds_[link] =
true;
109 lowerBounds_[link] = low;
110 upperBounds_[link] = high;
114 void PlanarManipulator::setBounds(
const std::vector<double> &low,
const std::vector<double> &high)
116 assert(low.size() == high.size());
117 assert(low.size() == numLinks_);
119 hasBounds_.assign(numLinks_,
true);
124 bool PlanarManipulator::hasBounds(
unsigned int link)
const
126 return hasBounds_[link];
129 void PlanarManipulator::getBounds(
unsigned int link,
double &low,
double &high)
const
131 low = lowerBounds_[link];
132 high = upperBounds_[link];
134 const std::vector<double> &PlanarManipulator::lowerBounds()
const
139 const std::vector<double> &PlanarManipulator::upperBounds()
const
146 void PlanarManipulator::FK(
const std::vector<double> &joints, std::vector<Eigen::Affine2d> &frames)
const
148 FK(&joints[0], frames);
151 void PlanarManipulator::FK(
const Eigen::VectorXd &joints, std::vector<Eigen::Affine2d> &frames)
const
153 FK(&joints(0), frames);
156 void PlanarManipulator::FK(
const double *joints, std::vector<Eigen::Affine2d> &frames)
const
159 Eigen::Affine2d frame(baseFrame_);
161 for (
unsigned int i = 0; i < numLinks_; ++i)
164 Eigen::Affine2d offset(Eigen::Rotation2Dd(joints[i]) * Eigen::Translation2d(linkLengths_[i], 0));
165 frame = frame * offset;
166 frames.push_back(frame);
170 void PlanarManipulator::FK(
const std::vector<double> &joints, Eigen::Affine2d &eeFrame)
const
172 FK(&joints[0], eeFrame);
175 void PlanarManipulator::FK(
const Eigen::VectorXd &joints, Eigen::Affine2d &eeFrame)
const
177 FK(&joints(0), eeFrame);
180 void PlanarManipulator::FK(
const double *joints, Eigen::Affine2d &eeFrame)
const
182 eeFrame = baseFrame_;
184 for (
unsigned int i = 0; i < numLinks_; ++i)
187 Eigen::Affine2d offset(Eigen::Rotation2Dd(joints[i]) * Eigen::Translation2d(linkLengths_[i], 0));
188 eeFrame = eeFrame * offset;
194 bool PlanarManipulator::IK(std::vector<double> &solution,
const Eigen::Affine2d &eeFrame)
const
196 std::vector<double> seed(numLinks_, M_PI / 2.0);
197 return IK(solution, seed, eeFrame);
200 bool PlanarManipulator::IK(std::vector<double> &solution,
const std::vector<double> &seed,
201 const Eigen::Affine2d &desiredFrame)
const
204 if (infeasible(desiredFrame))
208 double angle = acos(desiredFrame.rotation()(0, 0));
213 angle = asin(desiredFrame.rotation()(0, 1));
220 Eigen::Affine2d frame;
222 Eigen::VectorXd current;
223 frameToPose(frame, current);
226 Eigen::VectorXd desired;
227 frameToPose(desiredFrame, desired);
230 Eigen::VectorXd e(desired - current);
232 Eigen::VectorXd joints(seed.size());
233 for (
size_t i = 0; i < seed.size(); ++i)
238 unsigned int iter = 1;
241 Eigen::MatrixXd jac = Eigen::MatrixXd::Zero(3, numLinks_);
242 Eigen::JacobiSVD<Eigen::MatrixXd> svd(3, numLinks_, Eigen::ComputeFullU | Eigen::ComputeFullV);
243 Eigen::MatrixXd D = Eigen::MatrixXd::Zero(numLinks_, 3);
246 while (e.norm() > eps)
249 Jacobian(joints, jac);
257 const Eigen::JacobiSVD<Eigen::MatrixXd>::SingularValuesType &d = svd.singularValues();
260 for (
int i = 0; i < d.size(); ++i)
262 D(i, i) = 1.0 / d(i);
267 Eigen::MatrixXd jac_inv = svd.matrixV() * D * svd.matrixU().transpose();
270 Eigen::VectorXd delta_theta = jac_inv * e;
273 if (delta_theta(0) != delta_theta(0))
280 joints = joints + (alpha * delta_theta);
284 frameToPose(frame, current);
286 e = desired - current;
294 solution.resize(numLinks_);
295 for (
size_t i = 0; i < solution.size(); ++i)
297 double angle = joints(i);
300 while (angle < -M_PI)
308 bool PlanarManipulator::FABRIK(std::vector<double> &solution,
const Eigen::Affine2d &eeFrame,
double xyTol,
309 double thetaTol)
const
311 std::vector<double> seed(numLinks_, M_PI / 2.0);
312 return FABRIK(solution, seed, eeFrame, xyTol, thetaTol);
315 bool PlanarManipulator::FABRIK(std::vector<double> &solution,
const std::vector<double> &seed,
316 const Eigen::Affine2d &desiredFrame,
double xyTol,
double thetaTol)
const
318 unsigned int numLinks = getNumLinks();
321 if (seed.size() != numLinks)
323 std::cerr <<
"Seed has length " << seed.size() <<
" but there are " << numLinks <<
" links" << std::endl;
328 if (infeasible(desiredFrame))
332 solution.assign(seed.begin(), seed.end());
336 Eigen::Vector2d loc(-linkLengths_.back(), 0);
337 loc = desiredFrame * loc;
340 double v = desiredFrame.matrix()(0, 0);
346 double eeTheta = acos(v);
347 if (desiredFrame.matrix()(1, 0) < 0)
352 std::vector<Eigen::Vector2d> jointPositions;
353 jointPositions.push_back(baseFrame_.translation());
356 Eigen::Affine2d frame(baseFrame_);
357 for (
unsigned int i = 0; i < seed.size(); ++i)
359 Eigen::Affine2d offset(Eigen::Rotation2Dd(seed[i]) * Eigen::Translation2d(linkLengths_[i], 0));
360 frame = frame * offset;
361 jointPositions.push_back(frame.translation());
365 double xyError = std::numeric_limits<double>::max();
366 double thetaError = std::numeric_limits<double>::max();
368 int numIterations = 0;
371 while ((xyError > xyTol || thetaError > thetaTol) && numIterations++ < maxIter)
373 xyError = thetaError = 0.0;
376 jointPositions[numLinks] = desiredFrame.translation();
377 jointPositions[numLinks - 1] = loc;
382 Eigen::Affine2d backwardFrame(Eigen::Translation2d(jointPositions[numLinks - 1]) *
383 Eigen::Rotation2Dd(PI + eeTheta));
386 for (
int i = jointPositions.size() - 3; i >= 0;
390 double t = linkLengths_[i] / (jointPositions[i + 1] - jointPositions[i]).norm();
391 jointPositions[i] = (1 - t) * jointPositions[i + 1] + t * jointPositions[i];
394 Eigen::Vector2d vec = backwardFrame.inverse() * jointPositions[i];
395 double angle = -atan2(vec(1), vec(0));
399 if (hasBounds_[i] && (angle < lowerBounds_[i] || angle > upperBounds_[i]))
401 double dlow = fabs(angle - lowerBounds_[i]);
402 double dhigh = fabs(angle - upperBounds_[i]);
403 angle = (dlow < dhigh ? lowerBounds_[i] : upperBounds_[i]);
406 Eigen::Affine2d offset(Eigen::Rotation2Dd(-angle) * Eigen::Translation2d(linkLengths_[i], 0));
407 backwardFrame = backwardFrame * offset;
408 jointPositions[i] = backwardFrame.translation();
411 jointPositions[0] = baseFrame_.translation();
412 Eigen::Affine2d forwardFrame(baseFrame_);
415 for (
size_t i = 0; i < jointPositions.size() - 1;
420 double t = linkLengths_[i] / (jointPositions[i + 1] - jointPositions[i]).norm();
421 jointPositions[i + 1] = (1 - t) * jointPositions[i] + t * jointPositions[i + 1];
424 Eigen::Vector2d vec = forwardFrame.inverse() * jointPositions[i + 1];
425 double angle = atan2(vec(1), vec(0));
428 if (hasBounds_[i] && (angle < lowerBounds_[i] || angle > upperBounds_[i]))
430 double dlow = fabs(angle - lowerBounds_[i]);
431 double dhigh = fabs(angle - upperBounds_[i]);
432 angle = (dlow < dhigh ? lowerBounds_[i] : upperBounds_[i]);
437 Eigen::Affine2d offset(Eigen::Rotation2Dd(angle) * Eigen::Translation2d(linkLengths_[i], 0));
438 forwardFrame = forwardFrame * offset;
439 jointPositions[i + 1] = forwardFrame.translation();
444 xyError = (jointPositions.back() - desiredFrame.translation()).norm();
446 v = forwardFrame.matrix()(0, 0);
454 double thetaActual = acos(v);
455 if (forwardFrame.matrix()(1, 0) < 0)
456 thetaActual = -thetaActual;
457 thetaError = fabs(eeTheta - thetaActual);
461 if (xyError < xyTol && thetaError < thetaTol)
467 void PlanarManipulator::Jacobian(
const double *joints, Eigen::MatrixXd &jac)
const
469 if (jac.rows() != 3 || jac.cols() != numLinks_)
470 jac = Eigen::MatrixXd::Zero(3, numLinks_);
472 std::vector<double> sins(numLinks_);
473 std::vector<double> coss(numLinks_);
475 for (
size_t i = 0; i < numLinks_; ++i)
478 sins[i] = sin(theta);
479 coss[i] = cos(theta);
482 for (
size_t i = 0; i < numLinks_; ++i)
486 for (
size_t j = numLinks_; j > i; --j)
488 entry1 += -(linkLengths_[j - 1] * sins[j - 1]);
489 entry2 += linkLengths_[j - 1] * coss[j - 1];
498 void PlanarManipulator::Jacobian(
const std::vector<double> &joints, Eigen::MatrixXd &jac)
const
500 Jacobian(&joints[0], jac);
503 void PlanarManipulator::Jacobian(
const Eigen::VectorXd &joints, Eigen::MatrixXd &jac)
const
505 Jacobian(&joints(0), jac);
508 void PlanarManipulator::frameToPose(
const Eigen::Affine2d &frame, Eigen::VectorXd &pose)
510 pose = Eigen::VectorXd(3);
511 pose(0) = frame.translation()(0);
512 pose(1) = frame.translation()(1);
513 pose(2) = acos(frame.matrix()(0, 0));
516 bool PlanarManipulator::infeasible(
const Eigen::Affine2d &frame)
const
520 Eigen::Vector2d loc(-linkLengths_[numLinks_ - 1], 0);
525 for (
size_t i = 0; i < numLinks_ - 1; ++i)
526 len += linkLengths_[i];
530 Eigen::Vector2d org(baseFrame_.translation());
531 if ((org - loc).norm() > len)