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
00035
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
00078 tauOut = nh.advertise<auv_msgs::BodyForceReq>("tauOut", 1);
00079 tauAchW = nh.advertise<auv_msgs::BodyForceReq>("tauAchVelCon", 1);
00080
00081
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
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
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
00118 server.setCallback(boost::bind(&VelocityControl::dynrec_cb, this, _1, _2));
00119
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
00181
00182
00183
00184
00185
00186
00187
00188 lastRef = ros::Time::now();
00189
00190
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
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
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
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
00271 if (axis_control[i] != controlAxis)
00272 {
00273 controller[i].output = controller[i].internalState = tauAch[i];
00274 }
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
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
00316 if (axis_control[i] != controlAxis) controller[i].desired = nu[i];
00317 }
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 lastEst = ros::Time::now();
00328
00329
00330
00331
00332 };
00333
00334 void VelocityControl::handleMeasurement(const auv_msgs::NavSts::ConstPtr& meas)
00335 {
00336
00337 double dT = (ros::Time::now() - lastMeas).toSec();
00338
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
00348
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
00372
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
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
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 case disableAxis:
00418 default:
00419 controller[i].output = 0;
00420 break;
00421 }
00422 }
00423
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
00470
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
00547 labust::control::VelocityControl controller;
00548
00549 controller.start();
00550 return 0;
00551 }