VelocityControl.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2010, LABUST, UNIZG-FER
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the LABUST nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  *  Author: Dula Nad
00035  *  Created: 01.02.2013.
00036  *********************************************************************/
00037 #include <labust/control/VelocityControl.hpp>
00038 #include <labust/tools/MatrixLoader.hpp>
00039 #include <labust/simulation/matrixfwd.hpp>
00040 #include <labust/simulation/DynamicsParams.hpp>
00041 #include <labust/tools/DynamicsLoader.hpp>
00042 #include <labust/math/NumberManipulation.hpp>
00043 #include <labust/tools/conversions.hpp>
00044 #include <labust/control/PIFFController.h>
00045 
00046 #include <auv_msgs/BodyForceReq.h>
00047 #include <boost/bind.hpp>
00048 
00049 #include <cmath>
00050 #include <vector>
00051 #include <string>
00052 
00053 using labust::control::VelocityControl;
00054 
00055 const std::string VelocityControl::dofName[]=
00056 {"Surge","Sway","Heave","Roll","Pitch","Yaw"};
00057 
00058 VelocityControl::VelocityControl():
00059                         nh(ros::NodeHandle()),
00060                         ph(ros::NodeHandle("~")),
00061                         lastEst(ros::Time::now()),
00062                         lastRef(ros::Time::now()),
00063                         lastMan(ros::Time::now()),
00064                         lastMeas(ros::Time::now()),
00065                         timeout(0.5),
00066                         joy_scale(1),
00067                         Ts(0.1),
00068                         externalIdent(false),
00069                         use_gvel(false),
00070                         server(serverMux),
00071                         doSafetyTest(true)
00072 {this->onInit();}
00073 
00074 void VelocityControl::onInit()
00075 {
00076         std::string name;
00077         //Initialize publishers
00078         tauOut = nh.advertise<auv_msgs::BodyForceReq>("tauOut", 1);
00079         tauAchW = nh.advertise<auv_msgs::BodyForceReq>("tauAchVelCon", 1);
00080 
00081         //Initialze subscribers
00082         velocityRef = nh.subscribe<auv_msgs::BodyVelocityReq>("nuRef", 1,
00083                         &VelocityControl::handleReference,this);
00084         stateHat = nh.subscribe<auv_msgs::NavSts>("stateHat", 1,
00085                         &VelocityControl::handleEstimates,this);
00086         measSub = nh.subscribe<auv_msgs::NavSts>("meas", 1,
00087                         &VelocityControl::handleMeasurement,this);
00088         tauAch = nh.subscribe<auv_msgs::BodyForceReq>("tauAch", 1,
00089                         &VelocityControl::handleWindup,this);
00090         manualIn = nh.subscribe<sensor_msgs::Joy>("joy",1,
00091                         &VelocityControl::handleManual,this);
00092         modelUpdate = nh.subscribe<navcon_msgs::ModelParamsUpdate>("model_update", 1,
00093                         &VelocityControl::handleModelUpdate,this);
00094         //Configure service
00095         highLevelSelect = nh.advertiseService("ConfigureVelocityController",
00096                         &VelocityControl::handleServerConfig, this);
00097         enableControl = nh.advertiseService("VelCon_enable",
00098                         &VelocityControl::handleEnableControl, this);
00099 
00100         nh.param("velocity_controller/joy_scale",joy_scale,joy_scale);
00101         nh.param("velocity_controller/timeout",timeout,timeout);
00102         nh.param("velocity_controller/external_ident",externalIdent, externalIdent);
00103         nh.param("velocity_controller/use_ground_vel",use_gvel, use_gvel);
00104 
00105         //Added to avoid safety tests in simulation time.
00106         bool sim(false);
00107         nh.param("use_sim_time",sim,sim);
00108         doSafetyTest = !sim;
00109 
00110         if (externalIdent)
00111         {
00112                 identExt = nh.subscribe<auv_msgs::BodyForceReq>("tauIdent",1,
00113                                         &VelocityControl::handleExt,this);
00114                 for (int i=0; i<5; ++i) tauExt[i] = 0;
00115         }
00116 
00117         //Configure the dynamic reconfigure server
00118         server.setCallback(boost::bind(&VelocityControl::dynrec_cb, this, _1, _2));
00119         //Init tauManual
00120         for (int i=0; i<N+1;++i) tauManual[i] = 0;
00121 
00122         initialize_controller();
00123         config.__fromServer__(ph);
00124         server.setConfigDefault(config);
00125         this->updateDynRecConfig();
00126 }
00127 
00128 bool VelocityControl::handleEnableControl(navcon_msgs::EnableControl::Request& req,
00129                 navcon_msgs::EnableControl::Response& resp)
00130 {
00131         if (!req.enable)
00132         {
00133                 for (int i=u; i<=r;++i) axis_control[i] = disableAxis;
00134                 this->updateDynRecConfig();
00135         }
00136 
00137         return true;
00138 }
00139 
00140 void VelocityControl::updateDynRecConfig()
00141 {
00142         ROS_INFO("Updating the dynamic reconfigure parameters.");
00143 
00144         config.Surge_mode = axis_control[u];
00145         config.Sway_mode = axis_control[v];
00146         config.Heave_mode = axis_control[w];
00147         config.Roll_mode = axis_control[p];
00148         config.Pitch_mode = axis_control[q];
00149         config.Yaw_mode = axis_control[r];
00150 
00151         config.High_level_controller="0 - None\n 1 - DP";
00152 
00153         server.updateConfig(config);
00154 }
00155 
00156 bool VelocityControl::handleServerConfig(navcon_msgs::ConfigureVelocityController::Request& req,
00157                 navcon_msgs::ConfigureVelocityController::Response& resp)
00158 {
00159         for (int i=0; i<req.desired_mode.size();++i)
00160         {
00161                 if (req.desired_mode[i] == -1) continue;
00162                 if (axis_control[i] != req.desired_mode[i])
00163                 {
00164                         axis_control[i] = req.desired_mode[i];
00165                         controller[i].internalState = 0;
00166                 }
00167         }
00168         this->updateDynRecConfig();
00169         return true;
00170 }
00171 
00172 void VelocityControl::handleReference(const auv_msgs::BodyVelocityReq::ConstPtr& ref)
00173 {
00174         double nuRef[numcnt];
00175         labust::tools::pointToVector(ref->twist.linear, nuRef);
00176         labust::tools::pointToVector(ref->twist.angular, nuRef, 3);
00177 
00178         for(int i=0; i<numcnt; ++i)     controller[i].desired = nuRef[i];
00179 
00180 //      //Copy into controller
00181 //      controller[u].desired = ref->twist.linear.x;
00182 //      controller[v].desired = ref->twist.linear.y;
00183 //      controller[w].desired = ref->twist.linear.z;
00184 //      controller[p].desired = ref->twist.angular.x;
00185 //      controller[q].desired = ref->twist.angular.y;
00186 //      controller[r].desired = ref->twist.angular.z;
00187 
00188         lastRef = ros::Time::now();
00189         //newReference = true;
00190         //if (newEstimate) step();
00191 }
00192 
00193 void VelocityControl::handleManual(const sensor_msgs::Joy::ConstPtr& joy)
00194 {
00195         tauManual[X] = config.Surge_joy_scale * joy->axes[1];
00196         tauManual[Y] = -config.Sway_joy_scale * joy->axes[0];
00197         tauManual[Z] = -config.Heave_joy_scale * joy->axes[3];
00198 /*
00199         if (joy->buttons.size() >= 4)
00200         {
00201                 double increment = 0.05;
00202                 if (joy->buttons[1]) tauManual[M] = 0;
00203                 else if (joy->buttons[2]) tauManual[M] += increment;
00204                 else if (joy->buttons[3]) tauManual[M] -= increment;
00205 
00206                 tauManual[M] = labust::math::coerce(tauManual[M],-config.Pitch_joy_scale, config.Pitch_joy_scale);
00207         }
00208         else
00209         {
00210                 tauManual[K] = 0;
00211                 tauManual[M] = 0;
00212         }
00213 */
00214         //PGA ROVSEE
00215         tauManual[M] = config.Pitch_joy_scale * joy->axes[4];
00216         tauManual[N] = -config.Yaw_joy_scale * joy->axes[2];
00217         lastMan = ros::Time::now();
00218 }
00219 
00220 void VelocityControl::handleModelUpdate(const navcon_msgs::ModelParamsUpdate::ConstPtr& update)
00221 {
00222         ROS_INFO("Updating controller parameters for %d DoF",update->dof);
00223         controller[update->dof].model.alpha = update->alpha;
00224         if (update->use_linear)
00225         {
00226                 controller[update->dof].model.beta = update->beta;
00227                 controller[update->dof].model.betaa = 0;
00228         }
00229         else
00230         {
00231                 controller[update->dof].model.beta = 0;
00232                 controller[update->dof].model.betaa = update->betaa;
00233         }
00234 
00235         //Tune controller
00236         PIFF_modelTune(&controller[update->dof], &controller[update->dof].model, controller[update->dof].w);
00237 }
00238 
00239 void VelocityControl::dynrec_cb(navcon_msgs::VelConConfig& config, uint32_t level)
00240 {
00241         this->config = config;
00242 
00243         config.__toServer__(ph);
00244         for(size_t i=u; i<=r; ++i)
00245         {
00246                 int newMode(0);
00247                 ph.getParam(dofName[i]+"_mode", newMode);
00248                 axis_control[i] = newMode;
00249         }
00250 }
00251 
00252 void VelocityControl::handleWindup(const auv_msgs::BodyForceReq::ConstPtr& tau)
00253 {
00254         int tauWindup[numcnt];
00255         double tauAch[numcnt];
00256         labust::tools::pointToVector(tau->windup, tauWindup);
00257         labust::tools::rpyToVector(tau->windup, tauWindup, 3);
00258 
00259         labust::tools::pointToVector(tau->wrench.force, tauAch);
00260         labust::tools::pointToVector(tau->wrench.torque, tauAch, 3);
00261 
00262         for (int i=0; i<numcnt; ++i)
00263         {
00264                 if (!controller[i].autoWindup)
00265                 {
00266                         controller[i].extWindup = tauWindup[i];
00267                         controller[i].track = tauAch[i];
00268                 }
00269 
00270                 //For tracking external tau commands (bumpless transfer)
00271                 if (axis_control[i] != controlAxis)
00272                 {
00273                         controller[i].output = controller[i].internalState = tauAch[i];
00274                 }
00275         }
00276 
00277 //      if (!controller[u].autoWindup) controller[u].extWindup = tau->windup.x;
00278 //      if (!controller[v].autoWindup) controller[v].extWindup = tau->windup.y;
00279 //      if (!controller[w].autoWindup) controller[w].extWindup = tau->windup.z;
00280 //      if (!controller[p].autoWindup) controller[p].extWindup = tau->windup.roll;
00281 //      if (!controller[q].autoWindup) controller[q].extWindup = tau->windup.pitch;
00282 //      if (!controller[r].autoWindup) controller[r].extWindup = tau->windup.yaw;
00283 
00284 //      if (!controller[u].autoWindup) controller[u].track = tau->wrench.force.x;
00285 //      if (!controller[v].autoWindup) controller[v].track = tau->wrench.force.y;
00286 //      if (!controller[w].autoWindup) controller[w].track = tau->wrench.force.z;
00287 //      if (!controller[p].autoWindup) controller[p].track = tau->wrench.torque.x;
00288 //      if (!controller[q].autoWindup) controller[q].track = tau->wrench.torque.y;
00289 //      if (!controller[r].autoWindup) controller[r].track = tau->wrench.torque.z;
00290 };
00291 
00292 void VelocityControl::handleExt(const auv_msgs::BodyForceReq::ConstPtr& tau)
00293 {
00294         labust::tools::pointToVector(tau->wrench.force, tauExt);
00295         labust::tools::pointToVector(tau->wrench.torque, tauExt, 3);
00296 };
00297 
00298 void VelocityControl::handleEstimates(const auv_msgs::NavSts::ConstPtr& estimate)
00299 {
00300         double nu[numcnt];
00301         if (use_gvel)
00302         {
00303                 labust::tools::pointToVector(estimate->gbody_velocity, nu);
00304         }
00305         else
00306         {
00307                 labust::tools::pointToVector(estimate->body_velocity, nu);
00308         }
00309         labust::tools::rpyToVector(estimate->orientation_rate, nu, 3);
00310 
00311         for(int i=0; i<numcnt; ++i)
00312         {
00313                 controller[i].state = nu[i];
00314                 //For tracking external commands (bumpless transfer)
00316                 if (axis_control[i] != controlAxis) controller[i].desired = nu[i];
00317         }
00318 
00319 //      //Copy into controller
00320 //      controller[u].state = estimate->body_velocity.x;
00321 //      controller[v].state = estimate->body_velocity.y;
00322 //      controller[w].state = estimate->body_velocity.z;
00323 //      controller[p].state = estimate->orientation_rate.roll;
00324 //      controller[q].state = estimate->orientation_rate.pitch;
00325 //      controller[r].state = estimate->orientation_rate.yaw;
00326 
00327         lastEst = ros::Time::now();
00328         //ROS_INFO("Semi-travel time:%f",(lastEst - estimate->header.stamp).toSec());
00329         //lastEst = estimate->header.stamp;
00330         //newEstimate = true;
00331         //if (newReference) step();
00332 };
00333 
00334 void VelocityControl::handleMeasurement(const auv_msgs::NavSts::ConstPtr& meas)
00335 {
00336         //Copy into controller
00337         double dT = (ros::Time::now() - lastMeas).toSec();
00338         //ROS_INFO("Estimated rate for integration: %f",dT);
00339         measurement[u] += meas->body_velocity.x*dT;
00340         measurement[v] += meas->body_velocity.y*dT;
00341         measurement[w] = meas->position.depth;
00342         measurement[p] = meas->orientation.roll;
00343         measurement[q] = meas->orientation.pitch;
00344         measurement[r] = meas->orientation.yaw;
00345 
00346         lastMeas = ros::Time::now();
00347         //newEstimate = true;
00348         //if (newReference) step();
00349 };
00350 
00351 void VelocityControl::safetyTest()
00352 {
00353         bool refTimeout = (ros::Time::now() - lastRef).toSec() > timeout;
00354         bool estTimeout = (ros::Time::now() - lastEst).toSec() > timeout;
00355         bool manTimeout = (ros::Time::now() - lastMan).toSec() > timeout;
00356         bool measTimeout = (ros::Time::now() - lastMeas).toSec() > timeout;
00357         bool changed = false;
00358 
00359         for (int i=u; i<=r;++i)
00360         {
00361                 bool cntChannel = (refTimeout || estTimeout) && (axis_control[i] == controlAxis);
00362                 if (cntChannel) ROS_WARN("Timeout on the control channel: %d. Controlled axes will be disabled.",i);
00363                 bool measChannel = measTimeout && (axis_control[i] == identAxis);
00364                 if (measChannel) ROS_WARN("Timeout on the measurement channel: %d. Stopping identifications in progress.",i);
00365                 bool manChannel = manTimeout && (axis_control[i] == manualAxis);
00366                 if (manChannel) ROS_WARN("Timeout on the manual channel: %d. Manual axes will be disabled.",i);
00367 
00368                 suspend_axis[i] = (cntChannel || measChannel || manChannel);
00369         }
00370 
00371         //Update only on change.
00372         //if (changed) this->updateDynRecConfig();
00373 }
00374 
00375 void VelocityControl::step()
00376 {
00377         auv_msgs::BodyForceReq tau, tauach;
00378         if (doSafetyTest) this->safetyTest();
00379 
00380         for (int i=u; i<=r;++i)
00381         {
00382                 if ((axis_control[i] != controlAxis) || (suspend_axis[i])) PIFF_idle(&controller[i], Ts);
00383 
00384                 //If some of the axis are timed-out just ignore
00385                 if (suspend_axis[i])
00386                 {
00387                         controller[i].output = 0;
00388                         continue;
00389                 }
00390 
00391                 switch (axis_control[i])
00392                 {
00393                 case manualAxis:
00394                         controller[i].output = tauManual[i];
00395                         break;
00396                 case controlAxis:
00397                         ROS_DEBUG("Controller %d : %f %f %f",
00398                                         i,
00399                                         controller[i].desired,
00400                                         controller[i].state,
00401                                         controller[i].output);
00402                         PIFF_step(&controller[i], Ts);
00403                         break;
00404                 case identAxis:
00405                         controller[i].output = externalIdent?tauExt[i]:0;
00406                         break;
00407 //        //Deprecated
00408 //              case directAxis:
00409 //                      controller[i].output = controller[i].desired;
00410 //                      if (controller[i].autoWindup)
00411 //                      {
00412 //                              if (fabs(controller[i].desired) > controller[i].outputLimit)
00413 //                                      controller[i].desired = controller[i].desired/fabs(controller[i].desired)*controller[i].outputLimit;
00414 //                              tau.wrench.force.x = controller[i].desired;
00415 //                      }
00416 //                      break;
00417                 case disableAxis:
00418                 default:
00419                         controller[i].output = 0;
00420                         break;
00421                 }
00422         }
00423         //Copy to tau
00424         tau.wrench.force.x = controller[u].output;
00425         tau.wrench.force.y = controller[v].output;
00426         tau.wrench.force.z = controller[w].output;
00427         tau.wrench.torque.x = controller[p].output;
00428         tau.wrench.torque.y = controller[q].output;
00429         tau.wrench.torque.z = controller[r].output;
00430 
00431         tauach.wrench.force.x  = tau.wrench.force.x;
00432         tauach.wrench.force.y  = tau.wrench.force.y;
00433         tauach.wrench.force.z  = tau.wrench.force.z;
00434         tauach.wrench.torque.x = tau.wrench.torque.x;
00435         tauach.wrench.torque.y = tau.wrench.torque.y;
00436         tauach.wrench.torque.z = tau.wrench.torque.z;
00437 
00438         if (controller[u].autoWindup)
00439         {
00440                 tauach.disable_axis.x = controller[u].windup;
00441                 tauach.windup.x = controller[u].windup;
00442         }
00443         if (controller[v].autoWindup)
00444         {
00445                 tauach.disable_axis.y = controller[v].windup;
00446                 tauach.windup.y = controller[v].windup;
00447         }
00448         if (controller[w].autoWindup)
00449         {
00450                 tauach.disable_axis.z = controller[w].windup;
00451                 tauach.windup.z = controller[w].windup;
00452         }
00453         if (controller[p].autoWindup)
00454         {
00455                 tauach.disable_axis.roll = controller[p].windup;
00456                 tauach.windup.roll = controller[p].windup;
00457         }
00458         if (controller[q].autoWindup)
00459         {
00460                 tauach.disable_axis.pitch = controller[q].windup;
00461                 tauach.windup.pitch = controller[q].windup;
00462         }
00463         if (controller[r].autoWindup)
00464         {
00465                 tauach.disable_axis.yaw = controller[r].windup;
00466                 tauach.windup.yaw = controller[r].windup;
00467         }
00468 
00469         //Restart values
00470         //newReference = newEstimate = false;
00471         tauach.header.stamp = tau.header.stamp = lastEst;
00472         tauAchW.publish(tauach);
00473         tauOut.publish(tau);
00474 }
00475 
00476 void VelocityControl::start()
00477 {
00478         ros::Rate rate(1/Ts);
00479 
00480         while (nh.ok())
00481         {
00482                 ros::spinOnce();
00483                 step();
00484                 rate.sleep();
00485         }
00486 }
00487 
00488 void VelocityControl::initialize_controller()
00489 {
00490         ROS_INFO("Initializing velocity controller...");
00491 
00492         typedef Eigen::Matrix<double,6,1> Vector6d;
00493         using labust::simulation::vector;
00494         vector closedLoopFreq(vector::Ones());
00495         labust::tools::getMatrixParam(nh,"velocity_controller/closed_loop_freq", closedLoopFreq);
00496         vector outputLimit(vector::Zero());
00497         labust::tools::getMatrixParam(nh,"velocity_controller/output_limits", outputLimit);
00498         vector disAxis(vector::Ones());
00499         labust::tools::getMatrixParam(nh,"velocity_controller/disable_axis", disAxis);
00500         vector manAxis(vector::Ones());
00501         labust::tools::getMatrixParam(nh,"velocity_controller/manual_axis", manAxis);
00502         vector autoWindup(vector::Zero());
00503         labust::tools::getMatrixParam(nh,"velocity_controller/auto_tracking", autoWindup);
00504 
00505         labust::simulation::DynamicsParams model;
00506         labust::tools::loadDynamicsParams(nh,model);
00507         vector alphas(model.Ma.diagonal());
00508         vector alpha_mass;
00509         alpha_mass<<model.m,model.m,model.m,model.Io.diagonal();
00510         alphas += alpha_mass;
00511 
00512         nh.param("velocity_controller/Ts",Ts,Ts);
00513 
00514         for (int32_t i = u; i <=r; ++i)
00515         {
00516                 PIDBase_init(&controller[i]);
00517                 controller[i].w = closedLoopFreq(i);
00518                 controller[i].outputLimit = outputLimit(i);
00519                 controller[i].model.alpha = alphas(i);
00520                 controller[i].model.beta = model.Dlin(i,i);
00521                 controller[i].model.betaa = model.Dquad(i,i);
00522                 PIFF_modelTune(&controller[i], &controller[i].model, controller[i].w);
00523                 controller[i].autoWindup = autoWindup(i);               
00524 
00525                 if (!manAxis(i)) axis_control[i] = controlAxis;
00526                 if (manAxis(i)) axis_control[i] = manualAxis;
00527                 if (disAxis(i)) axis_control[i] = disableAxis;
00528                 suspend_axis[i]=false;
00529 
00530                 ph.setParam(dofName[i]+"_Kp",controller[i].Kp);
00531                 ph.setParam(dofName[i]+"_Ki",controller[i].Ki);
00532 
00533                 ROS_INFO("Controller %d:",i);
00534                 ROS_INFO("ModelParams: %f %f %f",controller[i].model.alpha, controller[i].model.beta,
00535                                 controller[i].model.betaa);
00536                 ROS_INFO("Gains: %f %f %f",controller[i].Kp, controller[i].Ki,
00537                                 controller[i].Kt);
00538         }
00539 
00540         ROS_INFO("Velocity controller initialized.");
00541 }
00542 
00543 int main(int argc, char* argv[])
00544 {
00545         ros::init(argc,argv,"velocity_control");
00546         //Initialize
00547         labust::control::VelocityControl controller;
00548         //Start execution.
00549         controller.start();
00550         return 0;
00551 }


labust_control
Author(s): Gyula Nagy
autogenerated on Fri Aug 28 2015 11:22:42