JointTrajectoryController.cpp
Go to the documentation of this file.
00001 /****************************************************************
00002  *
00003  * Copyright (c) 2011
00004  * All rights reserved.
00005  *
00006  * Hochschule Bonn-Rhein-Sieg
00007  * University of Applied Sciences
00008  * Computer Science Department
00009  *
00010  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00011  *
00012  * Author:
00013  * Jan Paulus, Nico Hochgeschwender, Michael Reckhaus, Azamat Shakhimardanov
00014  * Supervised by:
00015  * Gerhard K. Kraetzschmar
00016  *
00017  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00018  *
00019  * This sofware is published under a dual-license: GNU Lesser General Public 
00020  * License LGPL 2.1 and BSD license. The dual-license implies that users of this
00021  * code may choose which terms they prefer.
00022  *
00023  * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00024  *
00025  * Redistribution and use in source and binary forms, with or without
00026  * modification, are permitted provided that the following conditions are met:
00027  *
00028  *     * Redistributions of source code must retain the above copyright
00029  *       notice, this list of conditions and the following disclaimer.
00030  *     * Redistributions in binary form must reproduce the above copyright
00031  *       notice, this list of conditions and the following disclaimer in the
00032  *       documentation and/or other materials provided with the distribution.
00033  *     * Neither the name of the Hochschule Bonn-Rhein-Sieg nor the names of its
00034  *       contributors may be used to endorse or promote products derived from
00035  *       this software without specific prior written permission.
00036  *
00037  * This program is free software: you can redistribute it and/or modify
00038  * it under the terms of the GNU Lesser General Public License LGPL as
00039  * published by the Free Software Foundation, either version 2.1 of the
00040  * License, or (at your option) any later version or the BSD license.
00041  *
00042  * This program is distributed in the hope that it will be useful,
00043  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00044  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00045  * GNU Lesser General Public License LGPL and the BSD license for more details.
00046  *
00047  * You should have received a copy of the GNU Lesser General Public
00048  * License LGPL and BSD license along with this program.
00049  *
00050  ****************************************************************/
00051 #include <youbot_driver/youbot/JointTrajectoryController.hpp>
00052 namespace youbot
00053 {
00054 
00055 JointTrajectoryController::JointTrajectoryController()
00056 {
00057 
00058   this->pid.initPid(80.0, 1, 0, 1000, -1000);
00059   time = boost::posix_time::microsec_clock::local_time();
00060   last_time = boost::posix_time::microsec_clock::local_time();
00061 
00062   this->isControllerActive = false;
00063   this->targetPosition = 0;
00064   this->targetVelocity = 0;
00065   this->targetAcceleration = 0;
00066   this->encoderTicksPerRound = 1;
00067   this->gearRatio = 1;
00068   this->inverseDirection = false;
00069   actualpose = 0;
00070   actualvel = 0;
00071 
00072   // Creates a dummy trajectory
00073   boost::shared_ptr<SpecifiedTrajectory> traj_ptr(new SpecifiedTrajectory(1));
00074   SpecifiedTrajectory &traj = *traj_ptr;
00075   traj[0].start_time = boost::posix_time::microsec_clock::local_time();
00076   traj[0].duration = boost::posix_time::microseconds(0);
00077   //traj[0].splines.coef[0] = 0.0;
00078   current_trajectory_box_.Set(traj_ptr);
00079 
00080 }
00081 
00082 JointTrajectoryController::~JointTrajectoryController()
00083 {
00084 
00085 }
00086 
00087 void JointTrajectoryController::getConfigurationParameter(double& PParameter, double& IParameter, double& DParameter,
00088                                                           double& IClippingMax, double& IClippingMin)
00089 {
00090 
00091   if (this->isControllerActive)
00092     throw JointParameterException("The trajectory controller is running");
00093   this->pid.getGains(PParameter, IParameter, DParameter, IClippingMax, IClippingMin);
00094 
00095 }
00096 
00097 void JointTrajectoryController::setConfigurationParameter(const double PParameter, const double IParameter,
00098                                                           const double DParameter, const double IClippingMax,
00099                                                           const double IClippingMin)
00100 {
00101 
00102   if (this->isControllerActive)
00103     throw JointParameterException("The trajectory controller is running");
00104   this->pid.setGains(PParameter, IParameter, DParameter, IClippingMax, IClippingMin);
00105 
00106 }
00107 
00108 void JointTrajectoryController::setTrajectory(const JointTrajectory& input_traj)
00109 {
00110 
00111   if (input_traj.segments.size() == 0)
00112     throw std::runtime_error("Invalid trajectory");
00113 
00114   boost::posix_time::ptime time_now = boost::posix_time::microsec_clock::local_time();
00115 
00116   boost::shared_ptr<SpecifiedTrajectory> new_traj_ptr(new SpecifiedTrajectory);
00117   SpecifiedTrajectory &new_traj = *new_traj_ptr;
00118 
00119   // ------ Grabs the trajectory that we're currently following.
00120 
00121   boost::shared_ptr<const SpecifiedTrajectory> prev_traj_ptr;
00122   current_trajectory_box_.Get(prev_traj_ptr);
00123   if (!prev_traj_ptr)
00124   {
00125     throw std::runtime_error("The current trajectory can never be null");
00126     return;
00127   }
00128   const SpecifiedTrajectory &prev_traj = *prev_traj_ptr;
00129 
00130   // ------ Copies over the segments from the previous trajectory that are still useful.
00131 
00132   // Useful segments are still relevant after the current time.
00133   int first_useful = -1;
00134   while (first_useful + 1 < (int)prev_traj.size() && prev_traj[first_useful + 1].start_time <= time_now)
00135   {
00136     ++first_useful;
00137   }
00138 
00139   // Useful segments are not going to be completely overwritten by the message's splines.
00140   int last_useful = -1;
00141   while (last_useful + 1 < (int)prev_traj.size() && prev_traj[last_useful + 1].start_time < time_now)
00142   {
00143     ++last_useful;
00144   }
00145 
00146   if (last_useful < first_useful)
00147     first_useful = last_useful;
00148 
00149   // Copies over the old segments that were determined to be useful.
00150   for (int i = std::max(first_useful, 0); i <= last_useful; ++i)
00151   {
00152     new_traj.push_back(prev_traj[i]);
00153   }
00154 
00155   // We always save the last segment so that we know where to stop if
00156   // there are no new segments.
00157   if (new_traj.size() == 0)
00158     new_traj.push_back(prev_traj[prev_traj.size() - 1]);
00159 
00160   // ------ Determines when and where the new segments start
00161 
00162   // Finds the end conditions of the final segment
00163   Segment &last = new_traj[new_traj.size() - 1];
00164   double prev_positions;
00165   double prev_velocities;
00166   double prev_accelerations;
00167 
00168   LOG(debug) << "Initial conditions for new set of splines:";
00169 
00170   sampleSplineWithTimeBounds(last.spline.coef, (double)last.duration.total_microseconds() / 1000.0 / 1000.0,
00171                              (double)last.start_time.time_of_day().total_microseconds() / 1000.0 / 1000.0,
00172                              prev_positions, prev_velocities, prev_accelerations);
00173   //  ROS_DEBUG("    %.2lf, %.2lf, %.2lf  (%s)", prev_positions[i], prev_velocities[i],
00174   //            prev_accelerations[i], joints_[i]->joint_->name.c_str());
00175 
00176   // ------ Tacks on the new segments
00177 
00178   double positions;
00179   double velocities;
00180   double accelerations;
00181 
00182   std::vector<boost::posix_time::time_duration> durations;
00183   durations.push_back(input_traj.segments[0].time_from_start);
00184 
00185   for (size_t i = 1; i < input_traj.segments.size(); ++i)
00186     durations.push_back(input_traj.segments[i].time_from_start - input_traj.segments[i - 1].time_from_start);
00187 
00188   for (unsigned int i = 0; i < input_traj.segments.size(); ++i)
00189   {
00190     Segment seg;
00191 
00192     seg.start_time = input_traj.start_time + input_traj.segments[i].time_from_start;
00193     seg.duration = durations[i];
00194 
00195     positions = input_traj.segments[i].positions.value();
00196     velocities = input_traj.segments[i].velocities.value();
00197     accelerations = input_traj.segments[i].accelerations.value();
00198 
00199     // Converts the boundary conditions to splines.
00200 
00201     //   if (prev_accelerations.size() > 0 && accelerations.size() > 0)
00202     //   {
00203     getQuinticSplineCoefficients(prev_positions, prev_velocities, prev_accelerations, positions, velocities,
00204                                  accelerations, (double)durations[i].total_microseconds() / 1000.0 / 1000.0,
00205                                  seg.spline.coef);
00206     /*
00207      }
00208      else if (prev_velocities.size() > 0 && velocities.size() > 0)
00209      {
00210      getCubicSplineCoefficients(
00211      prev_positions[j], prev_velocities[j],
00212      positions[j], velocities[j],
00213      durations[i],
00214      seg.splines[j].coef);
00215      seg.splines[j].coef.resize(6, 0.0);
00216      }
00217      else
00218      {
00219      seg.splines[j].coef[0] = prev_positions[j];
00220      if (durations[i] == 0.0)
00221      seg.splines[j].coef[1] = 0.0;
00222      else
00223      seg.splines[j].coef[1] = (positions[j] - prev_positions[j]) / durations[i];
00224      seg.splines[j].coef[2] = 0.0;
00225      seg.splines[j].coef[3] = 0.0;
00226      seg.splines[j].coef[4] = 0.0;
00227      seg.splines[j].coef[5] = 0.0;
00228      }
00229      */
00230 
00231     // Pushes the splines onto the end of the new trajectory.
00232     new_traj.push_back(seg);
00233 
00234     // Computes the starting conditions for the next segment
00235 
00236     prev_positions = positions;
00237     prev_velocities = velocities;
00238     prev_accelerations = accelerations;
00239   }
00240 
00241   // ------ Commits the new trajectory
00242 
00243   if (!new_traj_ptr)
00244   {
00245     throw std::runtime_error("The new trajectory was null!");
00246     return;
00247   }
00248 
00249   current_trajectory_box_.Set(new_traj_ptr);
00250   LOG(debug) << "The new trajectory has " << new_traj.size() << " segments";
00251   this->isControllerActive = true;
00252 
00253 }
00254 
00255 void JointTrajectoryController::cancelCurrentTrajectory()
00256 {
00257   // Creates a dummy trajectory
00258   boost::shared_ptr<SpecifiedTrajectory> traj_ptr(new SpecifiedTrajectory(1));
00259   SpecifiedTrajectory &traj = *traj_ptr;
00260   traj[0].start_time = boost::posix_time::microsec_clock::local_time();
00261   traj[0].duration = boost::posix_time::microseconds(0);
00262   //traj[0].splines.coef[0] = 0.0;
00263   current_trajectory_box_.Set(traj_ptr);
00264   LOG(trace) << "Trajectory has been canceled";
00265 }
00266 
00267 bool JointTrajectoryController::isTrajectoryControllerActive()
00268 {
00269   return this->isControllerActive;
00270 }
00271 
00272 bool JointTrajectoryController::updateTrajectoryController(const SlaveMessageInput& actual,
00273                                                            SlaveMessageOutput& velocity)
00274 {
00275 
00276   time = boost::posix_time::microsec_clock::local_time();
00277   boost::posix_time::time_duration dt = time - last_time;
00278   last_time = time;
00279 
00280   boost::shared_ptr<const SpecifiedTrajectory> traj_ptr;
00281   current_trajectory_box_.Get(traj_ptr);
00282   if (!traj_ptr || !this->isControllerActive)
00283   {
00284     this->isControllerActive = false;
00285     //   LOG(error) << "The current trajectory can never be null";
00286     return false;
00287   }
00288 
00289   // Only because this is what the code originally looked like.
00290   const SpecifiedTrajectory &traj = *traj_ptr;
00291 
00292   // Determines which segment of the trajectory to use.  (Not particularly realtime friendly).
00293   int seg = -1;
00294   while (seg + 1 < (int)traj.size() && traj[seg + 1].start_time < time)
00295   {
00296     ++seg;
00297   }
00298 
00299   if (seg == -1)
00300   {
00301     if (traj.size() == 0)
00302       LOG(error) << "No segments in the trajectory";
00303     else
00304       LOG(error) << "No earlier segments.";
00305     return false;
00306   }
00307   if (seg == (int)traj.size() - 1 && (traj[seg].start_time + traj[seg].duration) < time)
00308   {
00309     LOG(trace) << "trajectory finished.";
00310     this->isControllerActive = false;
00311     velocity.value = 0;
00312     velocity.controllerMode = VELOCITY_CONTROL;
00313     return true;
00314   }
00315 
00316   // ------ Trajectory Sampling
00317   duration = (double)traj[seg].duration.total_microseconds() / 1000.0 / 1000.0; //convert to seconds
00318   time_till_seg_start = (double)(time - traj[seg].start_time).total_microseconds() / 1000.0 / 1000.0;
00319 
00320   sampleSplineWithTimeBounds(traj[seg].spline.coef, duration, time_till_seg_start, targetPosition, targetVelocity,
00321                              targetAcceleration);
00322 
00323   if (inverseDirection)
00324   {
00325     actualpose = -actual.actualPosition;
00326     actualvel = -actual.actualVelocity;
00327   }
00328   else
00329   {
00330     actualpose = actual.actualPosition;
00331     actualvel = actual.actualVelocity;
00332   }
00333   // ------ Trajectory Following
00334   pose_error = ((actualpose / encoderTicksPerRound) * gearRatio * (2.0 * M_PI)) - targetPosition;
00335   velocity_error = ((actualvel / 60.0) * gearRatio * 2.0 * M_PI) - targetVelocity;
00336 
00337   velsetpoint = pid.updatePid(pose_error, velocity_error, dt);
00338 
00339   velocity.value = (int32)round((velsetpoint / (gearRatio * 2.0 * M_PI)) * 60.0);
00340 
00341   velocity.controllerMode = VELOCITY_CONTROL;
00342 
00343   if (inverseDirection)
00344   {
00345     velocity.value = -velocity.value;
00346   }
00347 
00348   return true;
00349 
00350 }
00351 
00352 void JointTrajectoryController::getLastTargetPosition(JointAngleSetpoint& position)
00353 {
00354 
00355   position.angle = targetPosition * radian;
00356 
00357 }
00358 
00359 void JointTrajectoryController::getLastTargetVelocity(JointVelocitySetpoint& velocity)
00360 {
00361   velocity.angularVelocity = targetVelocity * radian_per_second;
00362 }
00363 
00364 void JointTrajectoryController::getQuinticSplineCoefficients(const double start_pos, const double start_vel,
00365                                                              const double start_acc, const double end_pos,
00366                                                              const double end_vel, const double end_acc,
00367                                                              const double time, std::vector<double>& coefficients)
00368 {
00369 
00370   coefficients.resize(6);
00371 
00372   if (time == 0.0)
00373   {
00374     coefficients[0] = end_pos;
00375     coefficients[1] = end_vel;
00376     coefficients[2] = 0.5 * end_acc;
00377     coefficients[3] = 0.0;
00378     coefficients[4] = 0.0;
00379     coefficients[5] = 0.0;
00380   }
00381   else
00382   {
00383     double T[6];
00384     generatePowers(5, time, T);
00385 
00386     coefficients[0] = start_pos;
00387     coefficients[1] = start_vel;
00388     coefficients[2] = 0.5 * start_acc;
00389     coefficients[3] = (-20.0 * start_pos + 20.0 * end_pos - 3.0 * start_acc * T[2] + end_acc * T[2]
00390         - 12.0 * start_vel * T[1] - 8.0 * end_vel * T[1]) / (2.0 * T[3]);
00391     coefficients[4] = (30.0 * start_pos - 30.0 * end_pos + 3.0 * start_acc * T[2] - 2.0 * end_acc * T[2]
00392         + 16.0 * start_vel * T[1] + 14.0 * end_vel * T[1]) / (2.0 * T[4]);
00393     coefficients[5] = (-12.0 * start_pos + 12.0 * end_pos - start_acc * T[2] + end_acc * T[2] - 6.0 * start_vel * T[1]
00394         - 6.0 * end_vel * T[1]) / (2.0 * T[5]);
00395   }
00396 
00397 }
00398 
00399 void JointTrajectoryController::sampleQuinticSpline(const std::vector<double>& coefficients, const double time,
00400                                                     double& position, double& velocity, double& acceleration)
00401 {
00402 
00403   // create powers of time:
00404   double t[6];
00405   generatePowers(5, time, t);
00406 
00407   position = t[0] * coefficients[0] + t[1] * coefficients[1] + t[2] * coefficients[2] + t[3] * coefficients[3]
00408       + t[4] * coefficients[4] + t[5] * coefficients[5];
00409 
00410   velocity = t[0] * coefficients[1] + 2.0 * t[1] * coefficients[2] + 3.0 * t[2] * coefficients[3]
00411       + 4.0 * t[3] * coefficients[4] + 5.0 * t[4] * coefficients[5];
00412 
00413   acceleration = 2.0 * t[0] * coefficients[2] + 6.0 * t[1] * coefficients[3] + 12.0 * t[2] * coefficients[4]
00414       + 20.0 * t[3] * coefficients[5];
00415 
00416 }
00417 
00418 void JointTrajectoryController::getCubicSplineCoefficients(const double start_pos, const double start_vel,
00419                                                            const double end_pos, const double end_vel,
00420                                                            const double time, std::vector<double>& coefficients)
00421 {
00422 
00423   coefficients.resize(4);
00424 
00425   if (time == 0.0)
00426   {
00427     coefficients[0] = end_pos;
00428     coefficients[1] = end_vel;
00429     coefficients[2] = 0.0;
00430     coefficients[3] = 0.0;
00431   }
00432   else
00433   {
00434     double T[4];
00435     generatePowers(3, time, T);
00436 
00437     coefficients[0] = start_pos;
00438     coefficients[1] = start_vel;
00439     coefficients[2] = (-3.0 * start_pos + 3.0 * end_pos - 2.0 * start_vel * T[1] - end_vel * T[1]) / T[2];
00440     coefficients[3] = (2.0 * start_pos - 2.0 * end_pos + start_vel * T[1] + end_vel * T[1]) / T[3];
00441   }
00442 
00443 }
00444 
00445 void JointTrajectoryController::generatePowers(const int n, const double x, double* powers)
00446 {
00447 
00448   powers[0] = 1.0;
00449   for (int i = 1; i <= n; i++)
00450   {
00451     powers[i] = powers[i - 1] * x;
00452   }
00453 
00454 }
00455 
00456 void JointTrajectoryController::sampleSplineWithTimeBounds(const std::vector<double>& coefficients,
00457                                                            const double duration, const double time, double& position,
00458                                                            double& velocity, double& acceleration)
00459 {
00460 
00461   if (time < 0)
00462   {
00463     double _;
00464     sampleQuinticSpline(coefficients, 0.0, position, _, _);
00465     velocity = 0;
00466     acceleration = 0;
00467   }
00468   else if (time > duration)
00469   {
00470     double _;
00471     sampleQuinticSpline(coefficients, duration, position, _, _);
00472     velocity = 0;
00473     acceleration = 0;
00474   }
00475   else
00476   {
00477     sampleQuinticSpline(coefficients, time, position, velocity, acceleration);
00478   }
00479 
00480 }
00481 
00482 } // namespace youbot


youbot_driver
Author(s): Jan Paulus
autogenerated on Mon Oct 6 2014 09:08:01