00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 #include <labust/allocation/x2d_adaptive.h>
00035 #include <labust/math/NumberManipulation.hpp>
00036 
00037 #include <pluginlib/class_list_macros.h>
00038 #include <std_msgs/Float32.h>
00039 #include <ros/ros.h>
00040 
00041 #include <boost/array.hpp>
00042 #include <Eigen/Dense>
00043 
00044 #include <cmath>
00045 #include <vector>
00046 
00047 using namespace labust::allocation;
00048 
00049 X2dAdaptive::X2dAdaptive():
00050                 _windup(6,false),
00051                 minN(1),
00052                 daisy_chain(true),
00053                 multi_chain(true),
00054                 tau_ach(Eigen::VectorXd::Zero(6)){}
00055 
00056 bool X2dAdaptive::configure(ros::NodeHandle& nh, ros::NodeHandle& ph)
00057 {
00058         
00059         bool valid = thrusters.configure(nh, ph);
00060         if (!valid) return false;
00061         
00062         ph.param("min_torque", minN, minN);
00063         ph.param("daisy_chain", daisy_chain, daisy_chain);
00064         ph.param("multi_chain", multi_chain, multi_chain);
00065         Eigen::Vector3d tn(0,0,minN);
00066         tnmax = (thrusters.Binv()*tn).cwiseAbs();
00067         tnmin = -tnmax;
00068 
00069         return valid;
00070 }
00071 
00072 const std::vector<double>& X2dAdaptive::allocate(const Eigen::VectorXd& tau)
00073 {
00074         
00075         const Eigen::VectorXd& tmax(thrusters.maxF());
00076         const Eigen::VectorXd& tmin(thrusters.minF());
00077         
00078         Eigen::Vector4d txymax(tmax - tnmax);
00079         Eigen::Vector4d txymin(tmin - tnmin);
00080         Eigen::Vector4d tnmax(this->tnmax);
00081         Eigen::Vector4d tnmin(this->tnmin);
00082 
00083         
00084         Eigen::Vector3d tauN, tauXY;
00085         tauN<<0.0,0.0,tau(N);
00086         tauXY<<tau(X),tau(Y),0.0;
00087         
00088         Eigen::Vector4d tN, tXY;
00089         tN = thrusters.Binv()*tauN;
00090         tXY = thrusters.Binv()*tauXY;
00091 
00092         
00093         bool satN(false),satXY(false);
00094 
00095         for (int i=0; i<tN.size(); ++i)
00096         {
00097                 satN = satN || ((tN(i) > tnmax(i)) || (tN(i) < tnmin(i)));
00098           satXY = satXY || ((tXY(i) > txymax(i)) || (tXY(i) < txymin(i)));
00099         }
00100 
00101         if (!satN && !satXY)
00102         {
00103             
00104             ROS_DEBUG("Everything allocated without saturation.");
00105         }
00106         else if (satN && !satXY)
00107         {
00108             ROS_DEBUG("Yaw DoF is saturated.");
00109             this->recalcOpLimits(tXY,txymax,txymin,&tnmax,&tnmin);
00110             satN = saturate(tN, tnmin, tnmax);
00111         }
00112         else if (satXY && !satN)
00113         {
00114             ROS_DEBUG("XY DoF are saturated.");
00115             this->recalcOpLimits(tN,tnmax,tnmin,&txymax,&txymin);
00116             satXY = saturate(tXY, txymin, txymax);
00117         }
00118         else if (satXY && satN)
00119         {
00120             ROS_DEBUG("All DoFs are saturated.");
00121             satN = saturate(tN, tnmin, tnmax);
00122             satXY = saturate(tXY, txymin, txymax);
00123         }
00124         Eigen::VectorXd tT = tXY+tN;
00125         Eigen::VectorXd tauA = thrusters.B()*tT;
00126 
00127         
00128         if (daisy_chain && (satXY || satN))
00129         {
00130                 Eigen::VectorXd tauS(3);
00131                 tauS<<tau(X),tau(Y),tau(N);
00132                 bool ssat = this->secondRun(tauS, tmax, tmin, &tauA, &tT);
00133                 Eigen::VectorXd arem = (tauS - tauA).cwiseAbs();
00134                 const double sm_th(0.001);
00135                 satXY = (arem(X) > sm_th) || (arem(Y) > sm_th);
00136                 satN = (arem(Z) > sm_th);
00137         }
00138 
00139         _windup[X] = _windup[Y] = satXY;
00140         _windup[N] = satN;
00141 
00142         
00143         enum {Xi=0,Yi=1,Ni=2};
00144         tau_ach(X) = tauA(Xi);
00145         tau_ach(Y) = tauA(Yi);
00146         tau_ach(N) = tauA(Ni);
00147 
00148         return thrusters.pwm(tT);
00149 }
00150 
00151 void X2dAdaptive::recalcOpLimits(Eigen::Vector4d& used, Eigen::Vector4d& pmax,
00152                 Eigen::Vector4d& pmin, Eigen::Vector4d* cmax, Eigen::Vector4d* cmin)
00153 {
00154   for (int i=0; i<used.size(); ++i)
00155   {
00156       if (used(i) >= 0)
00157       {
00158           double delta = pmax(i) - used(i);
00159           (*cmax)(i) += delta;
00160           (*cmin)(i) += pmin(i);
00161       }
00162       else
00163       {
00164           double delta = pmin(i) - used(i);
00165           (*cmin)(i) += delta;
00166           (*cmax)(i) += pmax(i);
00167       }
00168   }
00169 }
00170 
00171 bool X2dAdaptive::saturateN(Eigen::Vector4d& t,
00172                 const Eigen::Vector4d& pmin, const Eigen::Vector4d& pmax)
00173 {
00174         bool retVal(false);
00175   for (int i=0; i<t.size(); ++i)
00176   {
00177         double tn = labust::math::coerce(t(i), pmin(i), pmax(i));
00178         if (tn != t(i)) retVal |= true;
00179         t(i) = tn;
00180   }
00181   return retVal;
00182 }
00183 
00184 bool X2dAdaptive::saturate(Eigen::Vector4d& t,
00185                 const Eigen::Vector4d& pmin, const Eigen::Vector4d& pmax)
00186 {
00187         double scalef(1.0), scale(0.0);
00188   for (int i=0;i<t.size(); ++i)
00189   {
00190      if (t(i) >= 0)
00191         scale = t(i)/pmax(i);
00192      else
00193         scale = t(i)/pmin(i);
00194 
00195      if (scale > scalef) scalef=scale;
00196   }
00197   t = t/scalef;
00198 
00199   return (scalef > 1.0);
00200 }
00201 
00202 bool X2dAdaptive::secondRun(const Eigen::VectorXd& tau,
00203                 const Eigen::VectorXd& tmax, const Eigen::VectorXd& tmin,
00204                 Eigen::VectorXd* tauA, Eigen::VectorXd* tT)
00205 {
00206         bool retVal;
00207         bool do_loop(true);
00208 
00209         
00210         const double sm_th(0.001);
00211 
00212         while (do_loop)
00213         {
00214                 Eigen::VectorXd tauR(tau - (*tauA));
00215                 
00216                 if (tauR.norm() < sm_th)
00217                 {
00218                         ROS_DEBUG("Norm is smaller that threshold: %f", tauR.norm());
00219                         retVal = false;
00220                         break;
00221                 }
00222 
00223                 std::vector<double> tdmax,tdmin;
00224                 std::vector<int> notsat;
00225 
00226                 for(int i=0; i<tT->size(); ++i)
00227                 {
00228                         if ((*tT)(i) >= 0)
00229                         {
00230                                 double cmax = tmax(i) - (*tT)(i);
00231                                 
00232                                 if (cmax > sm_th)
00233                                 {
00234                                         notsat.push_back(i);
00235                                         tdmax.push_back(cmax);
00236                                         tdmin.push_back(tmin(i));
00237                                 }
00238                         }
00239                         else
00240                         {
00241                                 double cmin = tmin(i) - (*tT)(i);
00242                                 if (cmin < -sm_th)
00243                                 {
00244                                         notsat.push_back(i);
00245                                         tdmin.push_back(cmin);
00246                                         tdmax.push_back(tmax(i));
00247                                 }
00248                         }
00249                 }
00250 
00251                 if (!multi_chain && (notsat.size() < (tT->size()-1)))
00252                 {
00253                         ROS_DEBUG("Less than %d are saturated. Daisy chain allocation complete.", int(tT->size()-1));
00254                         retVal = true;
00255                         break;
00256                 }
00257                 
00258                 Eigen::MatrixXd Bd(tau.size(), notsat.size());
00259                 for (int i=0; i<notsat.size(); ++i)
00260                 {
00261                         Bd.col(i) = thrusters.B().col(notsat[i]);
00262                 }
00263 
00264                 Eigen::MatrixXd Bdinv;
00265                 if (notsat.size() <= (tT->size()-2))
00266                 {
00267                         Bdinv = (Bd.transpose()*Bd).inverse()*Bd.transpose();
00268                 }
00269                 else
00270                 {
00271                         Bdinv = Bd.transpose()*(Bd*Bd.transpose()).inverse();
00272                 }
00273 
00274                 
00275                 if (isnan(Bdinv.norm()))
00276                 {
00277                         ROS_ERROR("Singular inverse allocation matrix. Aborting daisy chain.");
00278                         retVal = true;
00279                         break;
00280                 }
00281 
00282                 Eigen::VectorXd tTd = Bdinv*tauR;
00283 
00284                 
00285                 
00286                 
00287 
00288                 double scalef(1.0),scale(0.0);
00289     for (int i=0; i< tTd.size(); ++i)
00290     {
00291         if (tTd(i) >= 0)
00292             scale = tTd(i)/tdmax[i];
00293         else
00294             scale = tTd(i)/tdmin[i];
00295 
00296         if (scale > scalef) scalef=scale;
00297     }
00298     tTd = tTd/scalef;
00299 
00300     Eigen::VectorXd tTn(*tT);
00301     for (int i=0; i< notsat.size(); ++i)
00302     {
00303         tTn(notsat[i]) += tTd(i);
00304     }
00305     Eigen::VectorXd tauf = thrusters.B()*(tTn);
00306     Eigen::VectorXd tauRf= tau - tauf;
00307 
00308     enum {Xi=0,Yi=1,Ni=2};
00309     
00310     bool limit = fabs(tauR(Xi)) - fabs(tauRf(Xi)) < -sm_th;
00311     limit = limit || (fabs(tauR(Yi)) - fabs(tauRf(Yi)) < -sm_th);
00312                 limit = limit || (fabs(tauR(Ni)) - fabs(tauRf(Ni)) < -sm_th);
00313 
00314     if (limit)
00315     {
00316         ROS_DEBUG("Scaling or yaw contract broken. Skipping this contribution.");
00317         retVal = true;
00318         break;
00319     }
00320 
00321     if ((tTd.norm() < sm_th))
00322     {
00323         ROS_DEBUG("The daisy chain allocation is not contributing any change.");
00324         retVal = true;
00325         break;
00326     }
00327 
00328     (*tT) = tTn;
00329     (*tauA) = tauf;
00330         }
00331 
00332         return retVal;
00333 }
00334 
00335 PLUGINLIB_EXPORT_CLASS(labust::allocation::X2dAdaptive, labust::allocation::AllocationInterface)