00001 #include <robodyn_controllers/MinJerkTrajectory.h>
00002
00003 #include "nasa_common_logging/Logger.h"
00004 #include <tf/tf.h>
00005 #include <tf_conversions/tf_kdl.h>
00006 #include <limits>
00007
00008 void MinJerkUtility::TimeUtility::setTime(double timeIn)
00009 {
00010 if (timeIn < 0. || timeIn > 1.)
00011 {
00012 std::stringstream err;
00013 err << "MinJerkUtility::TimeUtility::setTime() - invalid time value (" << timeIn << ")";
00014 NasaCommonLogging::Logger::log("gov.nasa.controllers.MinJerkUtility", log4cpp::Priority::ERROR, err.str());
00015 throw std::runtime_error(err.str());
00016 return;
00017 }
00018
00019 t = timeIn;
00020 t2 = t * t;
00021 t3 = t2 * t;
00022 t4 = t3 * t;
00023 t5 = t4 * t;
00024 }
00025
00026 void MinJerkUtility::setConstraints(double pinit, double pfinal, double vinit, double vfinal, double ainit, double afinal)
00027 {
00028 vinit = 0.;
00029 vfinal = 0.;
00030 ainit = 0.;
00031 afinal = 0.;
00032
00033
00034 dist = pfinal - pinit;
00035
00036 a0 = pinit;
00037
00038 a1 = vinit;
00039
00040 a2 = ainit / 2.;
00041
00042 a3 = 10. * dist - 6. * a1 - 3. * a2 - 4. * vfinal + afinal / 2.;
00043
00044 a4 = 7. * vfinal - afinal - 15.*dist + 8. * a1 + 3. * a2;
00045
00046 a5 = afinal / 2. - 3. * vfinal - a2 - 3. * a1 + 6. * dist;
00047
00048 dist = fabs(dist);
00049 }
00050
00051 double MinJerkUtility::duration(double vmax) const
00052 {
00053 static const double eps = std::numeric_limits<float>::epsilon();
00054
00055 if (vmax <= eps)
00056 {
00057 if (dist > eps)
00058 {
00059
00060 std::stringstream err;
00061 err << "MinJerkUtility::duration() - move requested but velocity limited to zero";
00062 NasaCommonLogging::Logger::log("gov.nasa.controllers.MinJerkUtility", log4cpp::Priority::ERROR, err.str());
00063 throw std::runtime_error(err.str());
00064 return 0.;
00065 }
00066 else
00067 {
00068 return 0.;
00069 }
00070 }
00071 else
00072 {
00073 return dist * 1.875 / vmax;
00074 }
00075 }
00076
00077 double MinJerkUtility::p(const TimeUtility& t) const
00078 {
00079 return a0 + a1 * t.t + a2 * t.t2 + a3 * t.t3 + a4 * t.t4 + a5 * t.t5;
00080 }
00081
00082 double MinJerkUtility::v(const TimeUtility& t) const
00083 {
00084 return a1 + 2.*a2 * t.t + 3.*a3 * t.t2 + 4.*a4 * t.t3 + 5.*a5 * t.t4;
00085 }
00086
00087 double MinJerkUtility::a(const TimeUtility& t) const
00088 {
00089 return 2.*a2 + 6.*a3 * t.t + 12.*a4 * t.t2 + 20.*a5 * t.t3;
00090 }
00091
00092 MinJerkJointTrajectory::MinJerkJointTrajectory(const JointVelocityLimiter& jvl, const KDL::JntArrayAcc& startPose,
00093 const KDL::JntArrayAcc& goalPose, double durationIn)
00094 : JointTrajectory(), JointVelocityLimiter(jvl)
00095 {
00096 if (startPose.q.rows() != goalPose.q.rows())
00097 {
00098 std::stringstream err;
00099 err << "MinJerkJointTrajectory::MinJerkJointTrajectory() - startPose and goalPose lengths don't match";
00100 NasaCommonLogging::Logger::log("gov.nasa.controllers.MinJerkJointTrajectory", log4cpp::Priority::ERROR, err.str());
00101 throw std::runtime_error(err.str());
00102 return;
00103 }
00104
00105 utils.resize(startPose.q.rows());
00106
00107 for (unsigned int i = 0; i < startPose.q.rows(); ++i)
00108 {
00109 utils[i].setConstraints(startPose.q(i), goalPose.q(i), startPose.qdot(i), goalPose.qdot(i), startPose.qdotdot(i), goalPose.qdotdot(i));
00110
00111 double jointDur = utils[i].duration(getVelocityLimit(i));
00112
00113 if (jointDur > durationIn)
00114 {
00115 durationIn = jointDur;
00116 }
00117 }
00118
00119 setDuration(durationIn);
00120 }
00121
00122 MinJerkJointTrajectory::~MinJerkJointTrajectory()
00123 {
00124
00125 }
00126
00127 void MinJerkJointTrajectory::getPose(double time, KDL::JntArrayAcc& pose)
00128 {
00129 MinJerkUtility::TimeUtility timeU;
00130 double dur = getDuration();
00131
00132 if (dur == 0)
00133 {
00134 if (time > 0)
00135 {
00136 throw std::runtime_error("MinJerkJointTrajectory::getPose cannot get a pose for a zero duration trajectory with nonzero time");
00137 return;
00138 }
00139 else
00140 {
00141 timeU.setTime(0.);
00142 }
00143 }
00144 else
00145 {
00146 timeU.setTime(time / getDuration());
00147 }
00148
00149 pose.resize(utils.size());
00150
00151 for (unsigned int i = 0; i < utils.size(); ++i)
00152 {
00153 pose.q(i) = utils[i].p(timeU);
00154 pose.qdot(i) = utils[i].v(timeU) / dur;
00155 pose.qdotdot(i) = utils[i].a(timeU) / (dur * dur);
00156 }
00157 }
00158
00159 MinJerkCartesianTrajectory::MinJerkCartesianTrajectory(const CartesianVelocityLimiter& cvl,
00160 const KDL::FrameAcc& startPose, const KDL::FrameAcc& goalPose, double durationIn)
00161 : CartesianTrajectory(), CartesianVelocityLimiter(cvl)
00162 {
00163 utils.resize(2);
00164
00165
00166 startVec = startPose.p.p;
00167 moveVec = goalPose.p.p - startVec;
00168
00170 utils[0].setConstraints(0., 1., startPose.p.v.Norm(), goalPose.p.v.Norm(), startPose.p.dv.Norm(), startPose.p.dv.Norm());
00171 double linDuration = moveVec.Norm() * utils[0].duration(getLinearVelocityLimit());
00172
00173
00174 double x, y, z, w;
00175
00176 startPose.M.R.GetQuaternion(x, y, z, w);
00177 startQ.setValue(x, y, z, w);
00178 goalPose.M.R.GetQuaternion(x, y, z, w);
00179 goalQ.setValue(x, y, z, w);
00180
00181 double angle = startQ.angleShortestPath(goalQ);
00182
00184 utils[1].setConstraints(0., 1., startPose.M.w.Norm(), goalPose.M.w.Norm(), startPose.M.dw.Norm(), startPose.M.dw.Norm());
00185 double rotDuration = angle * utils[1].duration(getRotationalVelocityLimit());
00186
00187 setDuration(std::max(std::max(linDuration, rotDuration), durationIn));
00188 }
00189
00190 MinJerkCartesianTrajectory::~MinJerkCartesianTrajectory()
00191 {
00192
00193 }
00194
00195 void MinJerkCartesianTrajectory::getPose(double time, KDL::FrameAcc& pose)
00196 {
00197 MinJerkUtility::TimeUtility timeU;
00198 timeU.setTime(time / getDuration());
00199
00200 double p = utils[0].p(timeU);
00201 pose.p = startVec + moveVec * p;
00202 p = utils[1].p(timeU);
00203 tf::Quaternion stepQ = startQ.slerp(goalQ, p).normalize();
00204 pose.M = KDL::Rotation::Quaternion(stepQ.x(), stepQ.y(), stepQ.z(), stepQ.w());
00205 }