HLManager.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: 06.05.2013.
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         //Fill controller names
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         //Initialize publishers
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         //Initialze subscribers
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         //Configure service
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         //If in latitude/longitude convert to meters
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         //Check if the mode is already active
00166         if (this->mode == req.mode) return true;
00167         //Else handle the mode change
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         //srv.request.desired_mode[srv.request.u] = srv.request.DirectAxis;
00179         //srv.request.desired_mode[srv.request.v] = srv.request.DirectAxis;
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                 //\todo Generalize this 0.1 with Ts.
00292                 s +=twist->twist.linear.x*0.1;
00293 
00294                 //Circle
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         //In case we didn't have a fix on launch, but now we get one.
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                 //Init the gyroYaw
00361                 gyroYaw = 0;
00362 
00363                 //Check if fix is valid
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         //Get current heading and calculate the desired point
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                 //Some action
00394                 //Turn off all control, switch to manual ?
00395                 this->fullStop();
00396         }
00397 }
00398 
00399 void HLManager::bArtStep()
00400 {
00401                 //Check that enough time has passed
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                         //Switch to combined heading
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                         //Switch to combined heading
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                         //Switch to station keeping
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                 //Publish the launch information
00444                 this->bArtStep();
00445         };
00446 
00447         //Check distance to point
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                 //If distance to point is OK or the vehicle missed the point
00457                 if (dist < safetyRadius || ((dist < 2*safetyRadius) && (angleDiff > M_PI/2)))
00458                 {
00459                         //Switch to station keeping
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 }


labust_control
Author(s): Gyula Nagy
autogenerated on Fri Feb 7 2014 11:36:43