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/HLManager.hpp>
00038 #include <labust_uvapp/ConfigureVelocityController.h>
00039 #include <labust_uvapp/EnableControl.h>
00040 #include <labust/math/NumberManipulation.hpp>
00041 #include <labust/tools/GeoUtilities.hpp>
00042 #include <labust/tools/MatrixLoader.hpp>
00043 #include <labust/tools/conversions.hpp>
00044 #include <navcon_msgs/HLMessage.h>
00045 #include <std_msgs/Float32.h>
00046 #include <std_msgs/Int32.h>
00047
00048 using labust::control::HLManager;
00049
00050 HLManager::HLManager():
00051 nh(ros::NodeHandle()),
00052 ph(ros::NodeHandle("~")),
00053 lastEst(ros::Time::now()),
00054 launchTime(ros::Time::now()),
00055 launchDetected(false),
00056 timeout(5),
00057 mode(HLManager::stop),
00058 type(HLManager::bArt),
00059 safetyRadius(2),
00060 safetyDistance(20),
00061 safetyTime(15),
00062 safetyTime2(2*safetyTime),
00063 gyroYaw(0),
00064 circleRadius(10),
00065 s(0),
00066 fixValidated(false)
00067 {this->onInit();}
00068
00069 void HLManager::onInit()
00070 {
00071
00072 controllers.insert(std::make_pair("LF",false));
00073 controllers.insert(std::make_pair("DP",false));
00074 controllers.insert(std::make_pair("VT",false));
00075 controllers.insert(std::make_pair("HDG",false));
00076
00077
00078 refPoint = nh.advertise<geometry_msgs::PointStamped>("ref_point", 1);
00079 refTrack = nh.advertise<auv_msgs::NavSts>("ref_track", 1);
00080 openLoopSurge = nh.advertise<std_msgs::Float32>("open_loop_surge", 1);
00081 curMode = nh.advertise<std_msgs::Int32>("current_mode", 1);
00082 refHeading = nh.advertise<std_msgs::Float32>("heading_ref", 1);
00083 hlMessagePub = nh.advertise<navcon_msgs::HLMessage>("hl_diagnostics", 1);
00084 sfPub = nh.advertise<auv_msgs::NavSts>("sf_diagnostics", 1);
00085
00086
00087 state = nh.subscribe<auv_msgs::NavSts>("stateHat", 1,
00088 &HLManager::onVehicleEstimates,this);
00089 launch = nh.subscribe<std_msgs::Bool>("launched", 1,
00090 &HLManager::onLaunch,this);
00091 gpsData = nh.subscribe<sensor_msgs::NavSatFix>("gps", 1,
00092 &HLManager::onGPSData,this);
00093 virtualTargetTwist = nh.subscribe<geometry_msgs::TwistStamped>("virtual_target_twist", 1,
00094 &HLManager::onVTTwist,this);
00095 imuMeas = nh.subscribe<sensor_msgs::Imu>("imu", 1,
00096 &HLManager::onImuMeas,this);
00097
00098
00099 modeServer = nh.advertiseService("SetHLMode",
00100 &HLManager::setHLMode, this);
00101 bool isBart(false);
00102 nh.param("hl_manager/timeout",timeout,timeout);
00103 nh.param("hl_manager/radius",safetyRadius,safetyRadius);
00104 nh.param("hl_manager/safetyDistance",safetyDistance,safetyDistance);
00105 nh.param("hl_manager/safetyTime",safetyTime,safetyTime);
00106 nh.param("hl_manager/safetyTime2",safetyTime2,safetyTime2);
00107 nh.param("hl_manager/circleRadius", circleRadius, circleRadius);
00108 nh.param("hl_manager/isBart",isBart,isBart);
00109 nh.param("LocalOriginLat",originLat,originLat);
00110 nh.param("LocalOriginLon",originLon,originLon);
00111 ph.param("LocalFixSim",fixValidated, fixValidated);
00112 }
00113
00114 bool HLManager::setHLMode(navcon_msgs::SetHLMode::Request& req,
00115 navcon_msgs::SetHLMode::Response& resp)
00116 {
00117 if (req.mode >= lastMode)
00118 {
00119 ROS_ERROR("Faulty mode reuqest.");
00120 this->fullStop();
00121 return false;
00122 }
00123
00124 if (req.ref_point.header.frame_id == "worldLatLon")
00125 {
00126 std::pair<double, double> location = labust::tools::deg2meter(req.ref_point.point.x-originLat,
00127 req.ref_point.point.y-originLon,
00128 originLat);
00129 this->point.point.x = location.first;
00130 this->point.point.y = location.second;
00131 }
00132 else if (req.ref_point.header.frame_id == "base_link")
00133 {
00134 this->point.point.x = stateHat.position.north + req.ref_point.point.x;
00135 this->point.point.y = stateHat.position.east + req.ref_point.point.y;
00136 }
00137 else
00138 {
00139 this->point = req.ref_point;
00140 }
00141
00142 this->point.header.frame_id = "local";
00143 point.header.stamp = ros::Time::now();
00144 refPoint.publish(point);
00145 hlDiagnostics.ref_point = point;
00146
00147 if (req.radius) circleRadius = req.radius;
00148 hlDiagnostics.radius = circleRadius;
00149
00150 std_msgs::Float32 surge;
00151 surge.data = req.surge;
00152 hlDiagnostics.surge = req.surge;
00153 openLoopSurge.publish(surge);
00154
00155 std_msgs::Int32 cmode;
00156 cmode.data = req.mode;
00157 hlDiagnostics.mode = req.mode;
00158 curMode.publish(cmode);
00159
00160 std_msgs::Float32 deshdg;
00161 deshdg.data = req.yaw;
00162 hlDiagnostics.yaw = req.yaw;
00163 refHeading.publish(deshdg);
00164
00165
00166 if (this->mode == req.mode) return true;
00167
00168 mode = req.mode;
00169
00170 ros::ServiceClient client =
00171 nh.serviceClient<labust_uvapp::ConfigureVelocityController>("ConfigureVelocityController");
00172 labust_uvapp::ConfigureVelocityController srv;
00173 for (int32_t i=srv.request.u; i<= srv.request.r;++i)
00174 {
00175 srv.request.desired_mode[i] = srv.request.DisableAxis;
00176 }
00177
00178
00179
00180 srv.request.desired_mode[srv.request.u] = srv.request.ControlAxis;
00181 srv.request.desired_mode[srv.request.v] = srv.request.ControlAxis;
00182 srv.request.desired_mode[srv.request.r] = srv.request.ControlAxis;
00183
00184 geometry_msgs::TwistStampedPtr fakeTwist(new geometry_msgs::TwistStamped());
00185 disableControllerMap();
00186
00187 switch (mode)
00188 {
00189 case manual:
00190 ROS_INFO("Set to manual mode.");
00191 srv.request.desired_mode[srv.request.u] = srv.request.ManualAxis;
00192 srv.request.desired_mode[srv.request.v] = srv.request.ManualAxis;
00193 srv.request.desired_mode[srv.request.r] = srv.request.ManualAxis;
00194 break;
00195 case gotoPoint:
00196 ROS_INFO("Set to GoTo mode.");
00197 controllers["LF"] = true;
00198 break;
00199 case stationKeeping:
00200 ROS_INFO("Set to Station keeping mode.");
00201 controllers["DP"] = true;
00202 break;
00203 case circle:
00204 ROS_INFO("Set to Circle mode.");
00205 controllers["VT"] = true;
00206 s = 0;
00207 this->onVTTwist(fakeTwist);
00208 break;
00209 case heading:
00210 ROS_INFO("Set to Heading mode.");
00211 srv.request.desired_mode[srv.request.u] = srv.request.ManualAxis;
00212 srv.request.desired_mode[srv.request.v] = srv.request.ManualAxis;
00213 controllers["HDG"] = true;
00214 break;
00215 case headingSurge:
00216 ROS_INFO("Set to Heading + constant surge mode.");
00217 controllers["HDG"] = true;
00218 break;
00219 case vtManual:
00220 ROS_INFO("Set to vt manual mode.");
00221 srv.request.desired_mode[srv.request.u] = srv.request.ManualAxis;
00222 srv.request.desired_mode[srv.request.r] = srv.request.ManualAxis;
00223 controllers["VT"] = true;
00224 s = 0;
00225 this->onVTTwist(fakeTwist);
00226 break;
00227 case stop:
00228 ROS_INFO("Stopping.");
00229 return this->fullStop();
00230 break;
00231 default:
00232 ROS_ERROR("Wrong mode selected:%d",mode);
00233 break;
00234 }
00235
00236 return client.call(srv) && configureControllers();
00237 }
00238
00239 void HLManager::disableControllerMap()
00240 {
00241 for (ControllerMap::iterator it=controllers.begin();
00242 it != controllers.end(); ++it)
00243 {
00244 it->second = false;
00245 }
00246 }
00247
00248 bool HLManager::fullStop()
00249 {
00250 labust_uvapp::EnableControl srv;
00251 srv.request.enable = false;
00252 ros::ServiceClient client = nh.serviceClient<labust_uvapp::EnableControl>("VelCon_enable");
00253 bool serviceFlag;
00254 if (!((serviceFlag=client.call(srv))))
00255 {
00256 ROS_ERROR("Failed to call velocity control configuration service.");
00257 return false;
00258 }
00259
00260 disableControllerMap();
00261
00262 if (!configureControllers()) return false;
00263
00264 ROS_INFO("Stopping all axes.\n");
00265 return true;
00266 }
00267
00268 bool HLManager::configureControllers()
00269 {
00270 bool success = true;
00271 for (ControllerMap::const_iterator it=controllers.begin();
00272 it != controllers.end(); ++it)
00273 {
00274 ros::ServiceClient client = nh.serviceClient<labust_uvapp::EnableControl>(it->first + "_enable");
00275 labust_uvapp::EnableControl srv;
00276 srv.request.enable = it->second;
00277 if (!client.call(srv))
00278 {
00279 ROS_ERROR("Failed to call the %s configuration service.",it->first.c_str());
00280 success = false;
00281 }
00282 }
00283
00284 return success;
00285 }
00286
00287 void HLManager::onVTTwist(const geometry_msgs::TwistStamped::ConstPtr& twist)
00288 {
00289 if (mode == circle || mode == vtManual)
00290 {
00291
00292 s +=twist->twist.linear.x*0.1;
00293
00294
00295 if (s>=2*circleRadius*M_PI) s=s-2*circleRadius*M_PI;
00296 else if (s<0) s=2*circleRadius*M_PI-s;
00297
00298 double xRabbit = point.point.x + circleRadius*cos(s/circleRadius);
00299 double yRabbit = point.point.y + circleRadius*sin(s/circleRadius);
00300 double gammaRabbit=labust::math::wrapRad(s/circleRadius)+M_PI/2;
00301
00302 tf::Transform transform;
00303 transform.setOrigin(tf::Vector3(xRabbit, yRabbit, 0));
00304 Eigen::Quaternion<float> q;
00305 labust::tools::quaternionFromEulerZYX(0,0,gammaRabbit, q);
00306 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00307 broadcaster.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "local", "serret_frenet_frame"));
00308
00309 auv_msgs::NavStsPtr msg(new auv_msgs::NavSts());
00310 msg->position.north = xRabbit;
00311 msg->position.east = yRabbit;
00312 msg->body_velocity.x = twist->twist.linear.x;
00313 msg->orientation.yaw = gammaRabbit;
00314 sfPub.publish(msg);
00315 }
00316 }
00317
00318 void HLManager::onImuMeas(const sensor_msgs::Imu::ConstPtr& imu)
00319 {
00320 if (this->launchDetected)
00321 {
00322 double Ts(0.1);
00323 gyroYaw+=imu->angular_velocity.z*Ts;
00324 ROS_INFO("Desired gyro yaw: %f",gyroYaw);
00325 }
00326 else
00327 {
00328 gyroYaw = 0;
00329 }
00330 }
00331
00332 void HLManager::onVehicleEstimates(const auv_msgs::NavSts::ConstPtr& estimate)
00333 {
00334 this->stateHat = *estimate;
00335 lastEst = ros::Time::now();
00336 };
00337
00338 void HLManager::onGPSData(const sensor_msgs::NavSatFix::ConstPtr& fix)
00339 {
00340 this->fix = *fix;
00341 this->fix.header.stamp = ros::Time::now();
00342
00343
00344 if (!fixValidated)
00345 {
00346 originLat = fix->latitude;
00347 originLon = fix->longitude;
00348 fixValidated = true;
00349 }
00350 };
00351
00352 void HLManager::onLaunch(const std_msgs::Bool::ConstPtr& isLaunched)
00353 {
00354 if ((type== bArt) && (mode==stop) && (!launchDetected && isLaunched->data))
00355 {
00356 ROS_INFO("Launch detected");
00357 launchDetected = isLaunched->data;
00358 launchTime = ros::Time::now();
00359
00360
00361 gyroYaw = 0;
00362
00363
00364 if ((fixValidated = (fix.header.stamp - ros::Time::now()).sec < safetyTime))
00365 {
00366 originLat = fix.latitude;
00367 originLon = fix.longitude;
00368 }
00369 }
00370 else
00371 {
00372 ROS_INFO("Ignoring launch while in %d mode.", mode);
00373 }
00374 }
00375
00376 void HLManager::calculateBArtPoint(double heading)
00377 {
00378
00379 point.point.x = stateHat.position.north + safetyDistance*cos(heading);
00380 point.point.y = stateHat.position.east + safetyDistance*sin(heading);
00381 point.point.z = 0;
00382 point.header.frame_id = "local";
00383 }
00384
00385 void HLManager::safetyTest()
00386 {
00387 bool estTimeout = (ros::Time::now() - lastEst).toSec() > timeout;
00388
00389 if (estTimeout)
00390 {
00391 ROS_WARN("Timeout on the control channel. Controlled axes will be disabled.");
00392
00393
00394
00395 this->fullStop();
00396 }
00397 }
00398
00399 void HLManager::bArtStep()
00400 {
00401
00402 double dT = (ros::Time::now() - launchTime).toSec();
00403 double sft2 = 5;
00404 if ((dT > safetyTime) && (dT < (safetyTime + sft2)))
00405 {
00406 ROS_INFO("Heading only mode.");
00407
00408 navcon_msgs::SetHLMode srv;
00409 srv.request.mode = srv.request.HeadingSurge;
00410 srv.request.yaw = stateHat.orientation.yaw-gyroYaw;
00411 srv.request.surge = 0;
00412 this->setHLMode(srv.request, srv.response);
00413 }
00414
00415 if ((dT > (safetyTime+sft2)) && (dT < safetyTime2))
00416 {
00417 ROS_INFO("Heading + surge mode.");
00418
00419 navcon_msgs::SetHLMode srv;
00420 srv.request.mode = srv.request.HeadingSurge;
00421 srv.request.yaw = stateHat.orientation.yaw-gyroYaw;
00422 srv.request.surge = 0.5;
00423 this->setHLMode(srv.request, srv.response);
00424 }
00425
00426 if (dT >= safetyTime2)
00427 {
00428 launchDetected = false;
00429
00430 navcon_msgs::SetHLMode srv;
00431 srv.request.mode = srv.request.GoToPoint;
00432 this->calculateBArtPoint(stateHat.orientation.yaw-gyroYaw);
00433 srv.request.ref_point = point;
00434 srv.request.surge = 0.5;
00435 this->setHLMode(srv.request, srv.response);
00436 }
00437 }
00438
00439 void HLManager::step()
00440 {
00441 if ((type == bArt) && (launchDetected))
00442 {
00443
00444 this->bArtStep();
00445 };
00446
00447
00448 double dx(point.point.x - stateHat.position.north);
00449 double dy(point.point.y - stateHat.position.east);
00450 double dist(sqrt(dx*dx+dy*dy));
00451 double relAngle(atan2(dy,dx));
00452 double angleDiff(fabs(labust::math::wrapRad(relAngle - stateHat.orientation.yaw)));
00453
00454 if (mode == gotoPoint)
00455 {
00456
00457 if (dist < safetyRadius || ((dist < 2*safetyRadius) && (angleDiff > M_PI/2)))
00458 {
00459
00460 navcon_msgs::SetHLMode srv;
00461 srv.request.mode = srv.request.StationKeeping;
00462 srv.request.ref_point = point;
00463 this->setHLMode(srv.request, srv.response);
00464 }
00465 }
00466 }
00467
00468 void HLManager::start()
00469 {
00470 ros::Rate rate(10);
00471
00472 while (nh.ok())
00473 {
00474 if (fixValidated)
00475 {
00476 tf::Transform transform;
00477 transform.setOrigin(tf::Vector3(originLon, originLat, 0));
00478 transform.setRotation(tf::createQuaternionFromRPY(0,0,0));
00479 broadcaster.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/worldLatLon", "/world"));
00480 transform.setOrigin(tf::Vector3(0, 0, 0));
00481 Eigen::Quaternion<float> q;
00482 labust::tools::quaternionFromEulerZYX(M_PI,0,M_PI/2,q);
00483 transform.setRotation(tf::Quaternion(q.x(),q.y(),q.z(),q.w()));
00484 broadcaster.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "/world", "local"));
00485 }
00486 this->safetyTest();
00487 this->step();
00488 hlMessagePub.publish(hlDiagnostics);
00489 rate.sleep();
00490 ros::spinOnce();
00491 }
00492 }