00001
00011 #include "robodyn_mechanisms/WristMechanism.h"
00012 #include "nasa_common_logging/Logger.h"
00013 #include <Eigen/LU>
00014
00015 using namespace Eigen;
00016 using namespace std;
00017 using namespace log4cpp;
00018
00019 WristMechanism::WristMechanism()
00020 : logCategory("gov.nasa.robodyn.WristMechanism")
00021 {
00022 maxIt = 20;
00023 eps = 0.001;
00024 isCalibrated = false;
00025 }
00026
00027 WristMechanism::~WristMechanism()
00028 {
00029 }
00030
00036 void WristMechanism::setSliderOffsetGain(Vector2d sliderOffset, Vector2d sliderGain)
00037 {
00038 this->sliderOffset = sliderOffset;
00039 this->sliderGain = sliderGain;
00040 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG << "Slider Offset: " << sliderOffset;
00041 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG << "Slider Gain: " << sliderGain;
00042 }
00043
00049 void WristMechanism::setAngleOffsetGain(Vector2d angleOffset, Vector2d angleGain)
00050 {
00051 this->angleOffset = angleOffset;
00052 this->angleGain = angleGain;
00053 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG
00054 << "Angle Offset: " << angleOffset << "\r\n"
00055 << "Angle Gain: " << angleGain;
00056 }
00057
00077 void WristMechanism::loadDesignParams(Vector3d A, Vector3d A0, Vector3d B, Vector3d C, Vector3d D, Vector3d D0, Vector3d Pitch, Vector3d Yaw, Vector3d M, Vector3d N, double linkLength)
00078 {
00079 this->linkLength = linkLength;
00080
00081
00082 alpha = A0 - Pitch;
00083 beta = B - Yaw;
00084 gamma = C - Yaw;
00085 delta = D0 - Pitch;
00086 p = Yaw - Pitch;
00087
00088
00089 Vector3d uMag = A - A0;
00090 double uNorm = uMag.norm();
00091
00092 if (uNorm != 0)
00093 {
00094 u = uMag / uNorm;
00095 }
00096 else
00097 {
00098 std::stringstream err;
00099 err << "in loadDesignParams A and A0 cannot be the same or produce a normal of 0";
00100 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00101 throw std::runtime_error(err.str());
00102 }
00103
00104
00105 Vector3d vMag = D - D0;
00106 double vNorm = vMag.norm();
00107
00108 if (vNorm != 0)
00109 {
00110 v = vMag / vNorm;
00111 }
00112 else
00113 {
00114 std::stringstream err;
00115 err << "in loadDesignParams D and D0 cannot be the same or produce a normal of 0";
00116 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00117 throw std::runtime_error(err.str());
00118 }
00119
00120
00121 lengthSq = linkLength * linkLength;
00122
00123 m = M;
00124 n = N;
00125
00126 R1m = AA2Rot(m, ONE);
00127 R1n = AA2Rot(n, ONE);
00128 Rsm = AA2Rot(m, SIN);
00129 Rsn = AA2Rot(n, SIN);
00130 Rcm = AA2Rot(m, COS);
00131 Rcn = AA2Rot(n, COS);
00132
00133 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG
00134 << "a: (" << alpha(0) << "," << alpha(1) << "," << alpha(2) << ")\r\n"
00135 << "b: (" << beta(0) << "," << beta(1) << "," << beta(2) << ")\r\n"
00136 << "c: (" << gamma(0) << "," << gamma(1) << "," << gamma(2) << ")\r\n"
00137 << "d: (" << delta(0) << "," << delta(1) << "," << delta(2) << ")\r\n"
00138 << "m: (" << m(0) << "," << m(1) << "," << m(2) << ")\r\n"
00139 << "n: (" << n(0) << "," << n(1) << "," << n(2) << ")\r\n"
00140 << "u: (" << u(0) << "," << u(1) << "," << u(2) << ")\r\n"
00141 << "v: (" << v(0) << "," << v(1) << "," << v(2) << ")\r\n"
00142 << "p: (" << p(0) << "," << p(1) << "," << p(2) << ")\r\n"
00143 << "link length: " << linkLength;
00144
00145 }
00146
00158 void WristMechanism::setLimits(const double& upperPitchMin,
00159 const double& upperPitchMax,
00160 const double& lowerPitchMin,
00161 const double& lowerPitchMax,
00162 const double& upperYawMin,
00163 const double& upperYawMax,
00164 const double& lowerYawMin,
00165 const double& lowerYawMax)
00166 {
00167 this->upperPitchMin = upperPitchMin;
00168 this->upperPitchMax = upperPitchMax;
00169 this->lowerPitchMin = lowerPitchMin;
00170 this->lowerPitchMax = lowerPitchMax;
00171 this->upperYawMin = upperYawMin;
00172 this->upperYawMax = upperYawMax;
00173 this->lowerYawMin = lowerYawMin;
00174 this->lowerYawMax = lowerYawMax;
00175
00176 getLineFromPoints(upperYawMax, upperYawMin, upperPitchMin, upperPitchMax, mUpperPitchUpperYaw, bUpperPitchUpperYaw);
00177 getLineFromPoints(upperYawMax, upperYawMin, lowerPitchMax, lowerPitchMin, mLowerPitchUpperYaw, bLowerPitchUpperYaw);
00178 getLineFromPoints(lowerYawMax, lowerYawMin, lowerPitchMin, lowerPitchMax, mLowerPitchLowerYaw, bLowerPitchLowerYaw);
00179 getLineFromPoints(lowerYawMin, lowerYawMax, upperPitchMin, upperPitchMax, mUpperPitchLowerYaw, bUpperPitchLowerYaw);
00180
00181 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG
00182 << "Upper Pitch Max: " << upperPitchMax << "\r\n"
00183 << "Upper Pitch Min: " << upperPitchMin << "\r\n"
00184 << "Lower Pitch Max: " << lowerPitchMax << "\r\n"
00185 << "Lower Pitch Min: " << lowerPitchMin << "\r\n"
00186 << " Upper Yaw Max: " << upperYawMax << "\r\n"
00187 << " Upper Yaw Min: " << upperYawMin << "\r\n"
00188 << " Lower Yaw Max: " << lowerYawMax << "\r\n"
00189 << " Lower Yaw Min: " << lowerYawMin << "\r\n"
00190 << "UpperPitchUpperYaw equation: y=" << mUpperPitchUpperYaw << "x + " << bUpperPitchUpperYaw << "\r\n"
00191 << "UpperPitchLowerYaw equation: y=" << mUpperPitchLowerYaw << "x + " << bUpperPitchLowerYaw << "\r\n"
00192 << "LowerPitchUpperYaw equation: y=" << mLowerPitchUpperYaw << "x + " << bLowerPitchUpperYaw << "\r\n"
00193 << "LowerPitchLowerYaw equation: y=" << mLowerPitchLowerYaw << "x + " << bLowerPitchLowerYaw;
00194 }
00195
00205 void WristMechanism::getLimits(double pitch, double yaw, double& upperPitch, double& lowerPitch, double& upperYaw, double& lowerYaw)
00206 {
00207 upperPitch = upperPitchMax;
00208 lowerPitch = lowerPitchMin;
00209 upperYaw = upperYawMax;
00210 lowerYaw = lowerYawMin;
00211
00213 if (yaw > upperYawMax)
00214 {
00215 yaw = upperYawMax;
00216 }
00217 else if (yaw < lowerYawMin)
00218 {
00219 yaw = lowerYawMin;
00220 }
00221
00222 if (pitch > upperPitchMax)
00223 {
00224 pitch = upperPitchMax;
00225 }
00226 else if (pitch < lowerPitchMin)
00227 {
00228 pitch = lowerPitchMin;
00229 }
00230
00231 if (pitch > upperPitchMin && yaw > upperYawMin)
00232 {
00233 getNearest(mUpperPitchUpperYaw, bUpperPitchUpperYaw, yaw, pitch, upperYaw, upperPitch);
00234 upperYaw = std::max(upperYawMin, upperYaw);
00235 upperPitch = std::max(upperPitchMin, upperPitch);
00236 }
00237 else if (pitch > upperPitchMin && yaw < lowerYawMax)
00238 {
00239 getNearest(mUpperPitchLowerYaw, bUpperPitchLowerYaw, yaw, pitch, lowerYaw, upperPitch);
00240 lowerYaw = std::min(lowerYawMax, lowerYaw);
00241 upperPitch = std::max(upperPitchMin, upperPitch);
00242 }
00243 else if (pitch < lowerPitchMax && yaw > upperYawMin)
00244 {
00245 getNearest(mLowerPitchUpperYaw, bLowerPitchUpperYaw, yaw, pitch, upperYaw, lowerPitch);
00246 upperYaw = std::max(upperYawMin, upperYaw);
00247 lowerPitch = std::min(lowerPitchMax, lowerPitch);
00248 }
00249 else if (pitch < lowerPitchMax && yaw < lowerYawMax)
00250 {
00251 getNearest(mLowerPitchLowerYaw, bLowerPitchLowerYaw, yaw, pitch, lowerYaw, lowerPitch);
00252 lowerYaw = std::min(lowerYawMax, lowerYaw);
00253 lowerPitch = std::min(lowerPitchMax, lowerPitch);
00254 }
00255 }
00256
00262 void WristMechanism::applyLimits(double& pitch, double& yaw)
00263 {
00264 double upperPitch, lowerPitch, upperYaw, lowerYaw;
00265 getLimits(pitch, yaw, upperPitch, lowerPitch, upperYaw, lowerYaw);
00266
00267 if (pitch > upperPitch)
00268 {
00269 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG << "limiting pitch from: " << pitch << " to: " << upperPitch;
00270 pitch = upperPitch;
00271 }
00272 else if (pitch < lowerPitch)
00273 {
00274 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG << "limiting pitch from: " << pitch << " to: " << lowerPitch;
00275 pitch = lowerPitch;
00276 }
00277
00278 if (yaw > upperYaw)
00279 {
00280 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG << "limiting yaw from: " << yaw << " to: " << upperYaw;
00281 yaw = upperYaw;
00282 }
00283 else if (yaw < lowerYaw)
00284 {
00285 NasaCommonLogging::Logger::getCategory(logCategory) << log4cpp::Priority::DEBUG << "limiting yaw from: " << yaw << " to: " << lowerYaw;
00286 yaw = lowerYaw;
00287 }
00288 }
00289
00299 void WristMechanism::getNearest(double m, double b, double x_in, double y_in, double& x_out, double& y_out)
00300 {
00301 x_out = (m * y_in + x_in - m * b) / (m * m + 1);
00302 y_out = (m * m * y_in + m * x_in + b) / (m * m + 1);
00303 }
00304
00308 void WristMechanism::getLineFromPoints(double x1, double x2, double y1, double y2, double& m, double& b)
00309 {
00310 if (fabs(x2 - x1) < eps)
00311 {
00312 throw std::runtime_error("in WristMechanism::getLineFromPoints denominator is zero!");
00313 }
00314
00315 m = (y2 - y1) / (x2 - x1);
00316 b = y1 - m * x1;
00317 }
00318
00326 int WristMechanism::doFwdKin(Vector2d& ang, Vector2d pos, Vector2d lastang)
00327 {
00328 if (angleGain(0) == 0.0)
00329 {
00330 stringstream err;
00331 err << "angleGain(0) must be non-zero. Provided value of [" << angleGain(0) << "] is invalid.";
00332 NasaCommonLogging::Logger::log("gov.nasa.robodyn.WristMechanism", Priority::ERROR, err.str());
00333 throw runtime_error(err.str());
00334 }
00335
00336 if (angleGain(1) == 0.0)
00337 {
00338 stringstream err;
00339 err << "angleGain(0) must be non-zero. Provided value of [" << angleGain(1) << "] is invalid.";
00340 NasaCommonLogging::Logger::log("gov.nasa.robodyn.WristMechanism", Priority::ERROR, err.str());
00341 throw runtime_error(err.str());
00342 }
00343
00344 lastang(0) = (lastang(0) - angleOffset(0)) / angleGain(0);
00345 lastang(1) = (lastang(1) - angleOffset(1)) / angleGain(1);
00346
00347 ang = Vector2d::Zero();
00348
00349 Matrix3d AB = findFwdKinMatrix(alpha, beta, this->u, pos(0));
00350 Matrix3d DC = findFwdKinMatrix(delta, gamma, this->v, pos(1));
00351
00352 MatrixXd Cfk = MatrixXd::Zero(8, 8);
00353 MatrixXd Dfk = MatrixXd::Zero(8, 8);
00354 MatrixXd Efk = MatrixXd::Zero(8, 8);
00355 MatrixXd Ffk = MatrixXd::Zero(8, 8);
00356
00357
00358 Cfk << AB(0, 0), AB(0, 1), AB(0, 2), 0, AB(1, 0), AB(1, 1), AB(2, 0), AB(2, 1),
00359 0, 0, 0, 0, AB(0, 0), AB(0, 1), AB(1, 0), AB(1, 1),
00360 0, AB(0, 0), AB(0, 1), AB(0, 2), 0, AB(1, 0), 0, AB(2, 0),
00361 0, 0, 0, 0, 0, AB(0, 0), 0, AB(1, 0),
00362 DC(0, 0), DC(0, 1), DC(0, 2), 0, DC(1, 0), DC(1, 1), DC(2, 0), DC(2, 1),
00363 0, 0, 0, 0, DC(0, 0), DC(0, 1), DC(1, 0), DC(1, 1),
00364 0, DC(0, 0), DC(0, 1), DC(0, 2), 0, DC(1, 0), 0, DC(2, 0),
00365 0, 0, 0, 0, 0, DC(0, 0), 0, DC(1, 0);
00366
00367
00368
00369 Dfk << AB(1, 2), 0, AB(2, 2), 0, 0, 0, 0, 0,
00370 AB(0, 2), 0, AB(1, 2), 0, AB(2, 0), AB(2, 1), AB(2, 2), 0,
00371 AB(1, 1), AB(1, 2), AB(2, 1), AB(2, 2), 0, 0, 0, 0,
00372 AB(0, 1), AB(0, 2), AB(1, 1), AB(1, 2), 0, AB(2, 0), AB(2, 1), AB(2, 2),
00373 DC(1, 2), 0, DC(2, 2), 0, 0, 0, 0, 0,
00374 DC(0, 2), 0, DC(1, 2), 0, DC(2, 0), DC(2, 1), DC(2, 2), 0,
00375 DC(1, 1), DC(1, 2), DC(2, 1), DC(2, 2), 0, 0, 0, 0,
00376 DC(0, 1), DC(0, 2), DC(1, 1), DC(1, 2), 0, DC(2, 0), DC(2, 1), DC(2, 2);
00377
00378
00379 Efk << 0, 0, 0, 0, 1, 0, 0, 0,
00380 0, 0, 0, 0, 0, 1, 0, 0,
00381 0, 0, 0, 0, 0, 0, 0, 0,
00382 0, 0, 0, 0, 0, 0, 0, 0,
00383 0, 0, 0, 0, 0, 0, 1, 0,
00384 0, 0, 0, 0, 0, 0, 0, 1,
00385 0, 0, 0, 0, 0, 0, 0, 0,
00386 0, 0, 0, 0, 0, 0, 0, 0;
00387
00388 Ffk << 0, 0, 0, 0, 0, 0, 0, 0,
00389 0, 0, 0, 0, 0, 0, 0, 0,
00390 1, 0, 0, 0, 0, 0, 0, 0,
00391 0, 1, 0, 0, 0, 0, 0, 0,
00392 0, 0, 0, 0, 0, 0, 0, 0,
00393 0, 0, 0, 0, 0, 0, 0, 0,
00394 0, 0, 0, 0, 1, 0, 0, 0,
00395 0, 0, 0, 0, 0, 1, 0, 0;
00396
00397
00398 MatrixXd Dfki = Dfk.lu().inverse();
00399
00400 MatrixXd Mfk = (Efk - (Ffk * Dfki * Cfk));
00401
00402 EigenSolver<MatrixXd> es(Mfk);
00403
00404
00405 VectorXcd xtheta = es.eigenvalues();
00406
00407
00408 MatrixXcd ephi = es.eigenvectors();
00409
00410 VectorXcd yphi = VectorXcd::Zero(8);
00411
00412 if (ephi.rows() != 8)
00413 {
00414 std::stringstream err;
00415 err << "in doFwdKin there should be 8 rows in ephi";
00416 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00417 throw std::runtime_error(err.str());
00418 }
00419
00420 if (ephi.cols() != 8)
00421 {
00422 std::stringstream err;
00423 err << "in doFwdKin there should be 8 cols in ephi";
00424 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00425 throw std::runtime_error(err.str());
00426 }
00427
00428 if (yphi.rows() != 8)
00429 {
00430 std::stringstream err;
00431 err << "in doFwdKin there should be 8 rows in yphi";
00432 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00433 throw std::runtime_error(err.str());
00434 }
00435
00436 std::complex<double> zero(0, 0);
00437
00438 for (unsigned int i = 0; i < ephi.rows(); i++)
00439 {
00440 if (ephi(0, i) != zero)
00441 {
00442 yphi(i) = ephi(1, i) / ephi(0, i);
00443 }
00444 else
00445 {
00446 std::stringstream err;
00447 err << "in doFwdKin -- divide by zero error in calculating yphi for " << ephi(i, 1) << ", M1'' is zero " << ephi(i, 0);
00448 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00449 throw std::runtime_error(err.str());
00450 }
00451
00452 }
00453
00454 std::vector<double> ptheta;
00455 std::vector<double> pphi;
00456 double tantheta, tanphi, sintheta, costheta, theta, sinphi, cosphi, phi, dist;
00457
00458 ptheta.clear();
00459 pphi.clear();
00460
00461
00462 for (unsigned int i = 0; i < xtheta.rows(); i++)
00463 {
00464 if (xtheta(i).imag() == 0 && yphi(i).imag() == 0)
00465 {
00466
00467 tantheta = xtheta(i).real();
00468 tanphi = yphi(i).real();
00469
00470 sintheta = (2 * tantheta) / (1 + tantheta * tantheta);
00471 costheta = (1 - tantheta * tantheta) / (1 + tantheta * tantheta);
00472 theta = atan2(sintheta, costheta);
00473
00474 sinphi = 2 * tanphi / (1 + tanphi * tanphi);
00475 cosphi = (1 - tanphi * tanphi) / (1 + tanphi * tanphi);
00476 phi = atan2(sinphi, cosphi);
00477
00478
00479 if (theta > lowerPitchMin - .1 && theta < upperPitchMax + .1 &&
00480 phi > lowerYawMin - .1 && phi < upperYawMax + .1)
00481 {
00482
00483 ptheta.push_back(theta);
00484 pphi.push_back(phi);
00485 }
00486
00487
00488 }
00489 }
00490
00491 if (ptheta.size() != pphi.size())
00492 {
00493 std::stringstream err;
00494 err << "in doFwdKin vectors ptheta and pphi should be the same size";
00495 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00496 return -1;
00497 }
00498
00499
00500
00501 if (ptheta.size() > 1 && pphi.size() > 1)
00502 {
00503 unsigned int i = 0;
00504
00505 theta = ptheta.at(i);
00506 phi = pphi.at(i);
00507
00508 dist = sqrt(pow(theta - lastang(0), 2.0) + pow(phi - lastang(1), 2.0));
00509
00510 ang(0) = theta;
00511 ang(1) = phi;
00512
00513 i++;
00514
00515 for (; i < ptheta.size(); i++)
00516 {
00517 theta = ptheta.at(i);
00518 phi = pphi.at(i);
00519
00520 if (dist > sqrt(pow((theta - lastang(0)), 2.0) + pow((phi - lastang(1)), 2.0)))
00521 {
00522 dist = sqrt(pow((theta - lastang(0)), 2.0) + pow((phi - lastang(1)), 2.0));
00523
00524 ang(0) = theta;
00525 ang(1) = phi;
00526 }
00527 }
00528 }
00529 else if (ptheta.size() == 1 && pphi.size() == 1)
00530 {
00531
00532 ang(0) = ptheta.at(0);
00533 ang(1) = pphi.at(0);
00534 }
00535 else
00536 {
00537 return -1;
00538 }
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 return 0;
00565
00566 }
00567
00568 Matrix3d WristMechanism::findFwdKinMatrix(Vector3d a, Vector3d b, Vector3d u, double q)
00569 {
00570 Matrix3d aOut;
00571
00572 Vector3d ahat = a + q * u;
00573 RowVector3d pT = p.transpose();
00574 RowVector3d ahatT = ahat.transpose();
00575
00576 double a1, b1, c1, d1, e1, f1, g1, h1, k1;
00577
00578 a1 = p.dot(p) + b.dot(b) + ahat.dot(ahat) - lengthSq + 2 * pT * R1n * b - 2 * ahatT * R1m * (p + R1n * b);
00579 double b11 = -2 * ahatT * R1m * Rsn * b;
00580 b1 = b11 + 2 * pT * Rsn * b ;
00581 double c11 = -2 * ahatT * R1m * Rcn * b;
00582 c1 = c11 + 2 * pT * Rcn * b ;
00583 d1 = -2 * ahatT * Rsm * (p + R1n * b);
00584 e1 = -2 * ahatT * Rsm * Rsn * b;
00585 f1 = -2 * ahatT * Rsm * Rcn * b;
00586 g1 = -2 * ahatT * Rcm * (p + R1n * b);
00587 h1 = -2 * ahatT * Rcm * Rsn * b;
00588 k1 = -2 * ahatT * Rcm * Rcn * b;
00589
00590
00591 aOut(0, 0) = a1 + c1 + g1 + k1;
00592 aOut(1, 0) = 2 * d1 + 2 * f1;
00593 aOut(2, 0) = a1 + c1 - g1 - k1;
00594
00595 aOut(0, 1) = 2 * b1 + 2 * h1;
00596 aOut(1, 1) = 4 * e1;
00597 aOut(2, 1) = 2 * b1 - 2 * h1;
00598
00599 aOut(0, 2) = a1 - c1 + g1 - k1;
00600 aOut(1, 2) = 2 * d1 - 2 * f1;
00601 aOut(2, 2) = a1 - c1 - g1 + k1;
00602
00603 return aOut;
00604 }
00605
00612 int WristMechanism::doInvKin(Vector2d& pos, Vector2d ang)
00613 {
00614 int success = 0;
00615 double pitch = ang(0);
00616 double yaw = ang(1);
00617
00618
00619
00620 double bravo, charlie, david;
00621 Vector3d r1, r2;
00622
00623
00624 Matrix3d Rpitch = AA2Rot(m, pitch);
00625
00626 Matrix3d Ryaw = AA2Rot(n, yaw);
00627
00628
00629 r1 = Ryaw * beta;
00630 r2 = Rpitch * (p + r1);
00631
00632 bravo = -2 * u.dot(r2) + 2 * alpha.dot(u);
00633 charlie = p.dot(p) + 2 * p.dot(r1) + beta.dot(beta) - 2 * alpha.dot(r2) + alpha.dot(alpha) - lengthSq;
00634 david = bravo * bravo - 4 * charlie;
00635
00636 if (david >= 0)
00637 {
00638 pos(0) = -0.5 * bravo - 0.5 * sqrt(david);
00639 }
00640 else
00641 {
00642 success = -1;
00643 }
00644
00645 r1 = Ryaw * gamma;
00646 r2 = Rpitch * (p + r1);
00647
00648 bravo = -2 * v.dot(r2) + 2 * delta.dot(v);
00649 charlie = p.dot(p) + 2 * p.dot(r1) + gamma.dot(gamma) - 2 * delta.dot(r2) + delta.dot(delta) - lengthSq;
00650 david = bravo * bravo - 4 * charlie;
00651
00652 if (david >= 0)
00653 {
00654 pos(1) = -0.5 * bravo - 0.5 * sqrt(david);
00655 }
00656 else
00657 {
00658 success = -1;
00659 }
00660
00661 return success;
00662 }
00663
00664
00671 Vector2d WristMechanism::getAngleFromSlider(Vector2d slider)
00672 {
00673 Vector2d ang;
00674
00675 if (doFwdKin(ang, slider, lastAng) != 0)
00676 {
00677 std::stringstream err;
00678 err << "Could not find fwd kinematic solution";
00679 throw std::runtime_error(err.str());
00680 }
00681
00682
00683 ang(0) = ang(0) * angleGain(0) + angleOffset(0);
00684 ang(1) = ang(1) * angleGain(1) + angleOffset(1);
00685 lastAng = ang;
00686
00687 return ang;
00688 }
00689
00695 Vector2d WristMechanism::getSliderFromWristEncoder(Vector2d encoder)
00696 {
00697 if (!isCalibrated)
00698 {
00699 throw std::runtime_error("wrist has not been calibrated");
00700 }
00701
00702 Vector2d encoderTared = encoder - encoderTarePos;
00703
00704 Vector2d taredSliderEncoderPos = encoderTared + calSliderPos;
00705
00706 Vector2d sliderPos;
00707
00708 sliderPos(0) = taredSliderEncoderPos(0) * sliderGain(0) + sliderOffset(0);
00709 sliderPos(1) = taredSliderEncoderPos(1) * sliderGain(1) + sliderOffset(1);
00710
00711 return sliderPos;
00712 }
00713
00719 Vector2d WristMechanism::getWristEncoderFromSlider(Vector2d sliderPos)
00720 {
00721 if (!isCalibrated)
00722 {
00723 throw std::runtime_error("wrist has not been calibrated");
00724 }
00725
00726 Vector2d encoder, sliderEncoderPos, encoderTared;
00727
00728 if (sliderGain(0) == 0.0)
00729 {
00730 stringstream err;
00731 err << "sliderGain(0) must be non-zero. Provided value of [" << sliderGain(0) << "] is invalid.";
00732 NasaCommonLogging::Logger::log("gov.nasa.robodyn.WristMechanism", Priority::ERROR, err.str());
00733 throw runtime_error(err.str());
00734 }
00735
00736 if (sliderGain(1) == 0.0)
00737 {
00738 stringstream err;
00739 err << "sliderGain(1) must be non-zero. Provided value of [" << sliderGain(1) << "] is invalid.";
00740 NasaCommonLogging::Logger::log("gov.nasa.robodyn.WristMechanism", Priority::ERROR, err.str());
00741 throw runtime_error(err.str());
00742 }
00743
00744 sliderEncoderPos(0) = (sliderPos(0) - sliderOffset(0)) / sliderGain(0);
00745 sliderEncoderPos(1) = (sliderPos(1) - sliderOffset(1)) / sliderGain(1);
00746
00747 encoderTared = sliderEncoderPos - calSliderPos;
00748 encoder = encoderTared + encoderTarePos;
00749
00750 return encoder;
00751 }
00752
00759 Vector2d WristMechanism::getSliderFromAngle(Vector2d ang)
00760 {
00761 Vector2d angle;
00762
00763 if (angleGain(0) == 0.0)
00764 {
00765 stringstream err;
00766 err << "angleGain(0) must be non-zero. Provided value of [" << angleGain(0) << "] is invalid.";
00767 NasaCommonLogging::Logger::log("gov.nasa.robodyn.WristMechanism", Priority::ERROR, err.str());
00768 throw runtime_error(err.str());
00769 }
00770
00771 if (angleGain(1) == 0.0)
00772 {
00773 stringstream err;
00774 err << "angleGain(1) must be non-zero. Provided value of [" << angleGain(1) << "] is invalid.";
00775 NasaCommonLogging::Logger::log("gov.nasa.robodyn.WristMechanism", Priority::ERROR, err.str());
00776 throw runtime_error(err.str());
00777 }
00778
00779 angle(0) = (ang(0) - angleOffset(0)) / angleGain(0);
00780 angle(1) = (ang(1) - angleOffset(1)) / angleGain(1);
00781
00782 Vector2d sliderPos;
00783
00784 if (doInvKin(sliderPos, angle) != 0)
00785 {
00786 std::stringstream err;
00787 err << "Could not find inv kinematic solution: " << angle(0) << ", " << angle(1);
00788 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::DEBUG, err.str());
00789 throw std::runtime_error(err.str());
00790 }
00791
00792 return sliderPos;
00793 }
00794
00795
00801 void WristMechanism::tareWristEncoders(Vector2d encoder)
00802 {
00803 this->encoderTarePos = encoder;
00804 return;
00805 }
00806
00817 void WristMechanism::calWrist(Vector2d encoder, Vector2d sliderPos, Vector2d angle)
00818 {
00819 tareWristEncoders(encoder);
00820
00821 if (sliderGain(0) == 0.0)
00822 {
00823 stringstream err;
00824 err << "sliderGain(0) must be non-zero. Provided value of [" << sliderGain(0) << "] is invalid.";
00825 NasaCommonLogging::Logger::log("gov.nasa.robodyn.WristMechanism", Priority::ERROR, err.str());
00826 throw runtime_error(err.str());
00827 }
00828
00829 if (sliderGain(1) == 0.0)
00830 {
00831 stringstream err;
00832 err << "sliderGain(1) must be non-zero. Provided value of [" << sliderGain(1) << "] is invalid.";
00833 NasaCommonLogging::Logger::log("gov.nasa.robodyn.WristMechanism", Priority::ERROR, err.str());
00834 throw runtime_error(err.str());
00835 }
00836
00837 this->calSliderPos(0) = (sliderPos(0) - sliderOffset(0)) / sliderGain(0);
00838 this->calSliderPos(1) = (sliderPos(1) - sliderOffset(1)) / sliderGain(1);
00839
00840 isCalibrated = true;
00841 lastAng = angle;
00842
00843 return;
00844 }
00845
00853 Matrix3d WristMechanism::AA2Rot(Vector3d axis, double theta)
00854 {
00855 Matrix3d rot = Matrix3d::Zero();
00856
00857 double norm = axis.norm();
00858
00859 if (norm == 0)
00860 {
00861 std::stringstream err;
00862 err << "in AA2Rot(axis, theta) could not find find unit vector for axis (axis.norm() = 0)";
00863 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00864 throw std::runtime_error(err.str());
00865 }
00866
00867 Vector3d unitAxis = 1 / norm * axis;
00868
00869 double c = cos(theta);
00870 double s = sin(theta);
00871 double v = 1 - c;
00872 double kx = unitAxis(0);
00873 double ky = unitAxis(1);
00874 double kz = unitAxis(2);
00875
00876 rot(0, 0) = (kx * kx * v) + c;
00877 rot(1, 0) = (kx * ky * v) + (kz * s);
00878 rot(2, 0) = (kx * kz * v) - (ky * s);
00879
00880 rot(0, 1) = (kx * ky * v) - (kz * s);
00881 rot(1, 1) = (ky * ky * v) + c;
00882 rot(2, 1) = (ky * kz * v) + (kx * s);
00883
00884 rot(0, 2) = (kx * kz * v) + (ky * s);
00885 rot(1, 2) = (ky * kz * v) - (kx * s);
00886 rot(2, 2) = (kz * kz * v) + c;
00887
00888
00889 return rot;
00890 }
00891
00892
00901 Matrix3d WristMechanism::AA2Rot(Vector3d axis, RotationType index)
00902 {
00903 Matrix3d rot = Matrix3d::Zero();
00904
00905 double norm = axis.norm();
00906
00907 if (norm == 0)
00908 {
00909 std::stringstream err;
00910 err << "in AA2Rot(axis, index) could not find find unit vector for axis (axis.norm() = 0)";
00911 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00912 throw std::runtime_error(err.str());
00913 }
00914
00915 Vector3d unitAxis = 1 / norm * axis;
00916
00917 double c, s, v;
00918
00919 switch (index)
00920 {
00921 case ONE:
00922 c = 0;
00923 s = 0;
00924 v = 1;
00925 break;
00926
00927 case SIN:
00928 c = 0;
00929 s = 1;
00930 v = 0;
00931 break;
00932
00933 case COS:
00934 c = 1;
00935 s = 0;
00936 v = -1;
00937 break;
00938
00939 default:
00940 std::stringstream err;
00941 err << "AA2Rot Rotation type not defined ";
00942 NasaCommonLogging::Logger::log("gov.nasa.robonet.WristMechanism", log4cpp::Priority::ERROR, err.str());
00943 throw std::invalid_argument(err.str());
00944 }
00945
00946 double kx = unitAxis(0);
00947 double ky = unitAxis(1);
00948 double kz = unitAxis(2);
00949
00950 rot(0, 0) = (kx * kx * v) + c;
00951 rot(1, 0) = (kx * ky * v) + (kz * s);
00952 rot(2, 0) = (kx * kz * v) - (ky * s);
00953
00954 rot(0, 1) = (kx * ky * v) - (kz * s);
00955 rot(1, 1) = (ky * ky * v) + c;
00956 rot(2, 1) = (ky * kz * v) + (kx * s);
00957
00958 rot(0, 2) = (kx * kz * v) + (ky * s);
00959 rot(1, 2) = (ky * kz * v) - (kx * s);
00960 rot(2, 2) = (kz * kz * v) + c;
00961
00962 return rot;
00963 }
00964
00971 Vector2d WristMechanism::NewtonsMethod(Vector2d ang, Vector2d pos)
00972 {
00973 WristMechanism::Partials Pabpo = findPartialDerivatives(alpha, beta, u, pos(0), ang);
00974 WristMechanism::Partials Pdcpo = findPartialDerivatives(delta, gamma, v, pos(1), ang);
00975
00976 Matrix2d Fy;
00977 Fy << Pabpo.ftheta, Pabpo.fphi,
00978 Pdcpo.ftheta, Pdcpo.fphi;
00979
00980 Vector2d Fxy;
00981 Fxy << Pabpo.f - lengthSq,
00982 Pdcpo.f - lengthSq;
00983
00984 Vector2d dy = Fy.inverse() * Fxy;
00985
00986 return dy;
00987 }
00988
00989 WristMechanism::Partials WristMechanism::findPartialDerivatives(Vector3d a, Vector3d b, Vector3d w, double q, Vector2d ang)
00990 {
00991 WristMechanism::Partials wrist;
00992
00993 Matrix3d Rmtheta = AA2Rot(m, ang(0));
00994 Matrix3d Rnphi = AA2Rot(n, ang(1));
00995
00996 Vector3d r1 = Rnphi * b;
00997 Vector3d r2 = Rmtheta * (p + r1);
00998 Vector3d r = r2 - a - q * w;
00999 Vector3d r0 = r2 - a;
01000 wrist.f0 = r0.dot(r0);
01001 wrist.f = r.dot(r);
01002 wrist.fq = -2 * r.dot(w);
01003 wrist.ftheta = 2 * r.dot(m.cross(r2));
01004 wrist.fphi = 2 * r.dot(Rmtheta * (n.cross(r1)));
01005
01006 return wrist;
01007 }
01008