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/manual_control.h>
00038 #include <labust/tools/conversions.hpp>
00039 #include <labust/math/NumberManipulation.hpp>
00040
00041 #include <auv_msgs/BodyForceReq.h>
00042 #include <auv_msgs/BodyVelocityReq.h>
00043 #include <auv_msgs/NavSts.h>
00044
00045 #include <boost/bind.hpp>
00046
00047 using namespace labust::control;
00048
00049 ManualControl::ManualControl():
00050 nav_valid(false),
00051 navstate(DOF+1,0),
00052 mapped(DOF,0)
00053 {
00054 generators.assign(SRequest::DISABLED);
00055 this->onInit();
00056 }
00057
00058 void ManualControl::onInit()
00059 {
00060 ros::NodeHandle nh, ph("~");
00061
00062 this->setDefaultConfig();
00063 if (!this->setupConfig())
00064 {
00065 ROS_ERROR("ManualControl: Wrong configuration. Check all "
00066 "vector sizes are %d and sampling size is >0.", DOF);
00067 this->setDefaultConfig();
00068 }
00069
00070
00071 tauref = nh.advertise<auv_msgs::BodyForceReq>("manual_tau",1);
00072 nuref = nh.advertise<auv_msgs::BodyVelocityReq>("manual_nu",1);
00073 etaref = nh.advertise<auv_msgs::NavSts>("manual_eta",1);
00074
00075 joyin = nh.subscribe(config.topic, 1, &ManualControl::onJoystick, this);
00076 navsts = nh.subscribe("navsts", 1, &ManualControl::onNavSts, this);
00077
00078 config_server = nh.advertiseService("manual_configure", &ManualControl::onConfiguration, this);
00079 select_server = nh.advertiseService("manual_select", &ManualControl::onSelect, this);
00080 }
00081
00082 bool ManualControl::setupConfig()
00083 {
00084 ros::NodeHandle nh, ph("~");
00085
00086 ph.param("axes_map", config.axes_map, config.axes_map);
00087 ph.param("scale_map", config.scale_map, config.scale_map);
00088 ph.param("integrated", config.integrated, config.integrated);
00089
00090 ph.param("maximum_effort", config.maximum_effort, config.maximum_effort);
00091 ph.param("maximum_nu", config.maximum_nu, config.maximum_nu);
00092 ph.param("maximum_speed", config.maximum_speed, config.maximum_speed);
00093 std::vector<int> ug(SRequest::DISABLED,0);
00094 ph.param("use_generators", ug, ug);
00095 for (int i=0; i<ug.size(); ++i)
00096 {
00097 if (i >= generators.size()) break;
00098 generators[i] = ug[i];
00099 }
00100
00101 nh.param("simulation/sampling_time", config.sampling_time, config.sampling_time);
00102 nh.param("runtime/sampling_time", config.sampling_time, config.sampling_time);
00103 ph.param("sampling_time", config.sampling_time, config.sampling_time);
00104 bool use_ff(false);
00105 ph.param("use_feedforward", use_ff, use_ff);
00106 config.use_ff = use_ff;
00107
00108
00109 bool flag(config.sampling_time > 0);
00110 flag = flag && (config.axes_map.size() == DOF);
00111 flag = flag && (config.scale_map.size() == DOF);
00112 flag = flag && (config.maximum_effort.size() == DOF);
00113 flag = flag && (config.maximum_nu.size() == DOF);
00114 flag = flag && (config.maximum_speed.size() == DOF);
00115
00116 return flag;
00117 }
00118
00119 void ManualControl::setDefaultConfig()
00120 {
00121
00122 for(int i=0; i<DOF; ++i) config.axes_map.push_back(i);
00123 config.scale_map.resize(6,1);
00124
00125 config.integrated.resize(6,0);
00126
00127 config.maximum_effort.resize(6,1);
00128
00129 config.maximum_nu.resize(6,1);
00130
00131 config.maximum_speed.resize(6,1);
00132 config.sampling_time = 0.1;
00133 config.use_ff = false;
00134
00135 config.topic = "joy";
00136 }
00137
00138 bool ManualControl::onConfiguration(CRequest& req, CResponse& resp)
00139 {
00140 boost::mutex::scoped_lock l(cfg_mutex);
00141 navcon_msgs::ManualConfiguration& cfg(req.configuration);
00142 if (cfg.axes_map.size() == DOF)
00143 {
00144 this->config.axes_map = cfg.axes_map;
00145 }
00146 if (cfg.scale_map.size() == DOF) this->config.scale_map = cfg.scale_map;
00147 if (cfg.integrated.size() == DOF) this->config.integrated = cfg.integrated;
00148 if (cfg.maximum_effort.size() == DOF) this->config.maximum_effort = cfg.maximum_effort;
00149 if (cfg.maximum_nu.size() == DOF) this->config.maximum_nu = cfg.maximum_nu;
00150 if (cfg.maximum_speed.size() == DOF)
00151 {
00152 this->config.maximum_speed = cfg.maximum_speed;
00153 this->config.use_ff = cfg.use_ff;
00154 this->config.sampling_time = cfg.sampling_time;
00155 }
00156
00157 if (!req.configuration.topic.empty())
00158 {
00159 this->config.topic = req.configuration.topic;
00160 ros::NodeHandle nh;
00161 joyin = nh.subscribe(config.topic, 1, &ManualControl::onJoystick, this);
00162 }
00163
00164 resp.current_configuration = this->config;
00165 return true;
00166 }
00167
00168 bool ManualControl::onSelect(SRequest& req, SResponse& resp)
00169 {
00170 boost::mutex::scoped_lock l(cfg_mutex);
00171 for (int i=0; i<req.use_generator.size(); ++i)
00172 {
00173 if ((req.use_generator[i]>=SRequest::DISABLED) &&
00174 (req.use_generator[i]<=SRequest::POSITION))
00175 {
00176 this->generators[i] = req.use_generator[i];
00177 }
00178 }
00179
00180 return true;
00181 }
00182
00183 void ManualControl::onJoystick(const sensor_msgs::Joy::ConstPtr& joy)
00184 {
00185 this->remap(joy);
00186
00187 bool pubEffort(false), pubSpeed(false), pubPos(false);
00188
00189 std::vector<double> tauv(DOF,0),nuv(DOF,0),etaff(DOF,0);
00190
00191 boost::mutex::scoped_lock l(cfg_mutex);
00192 for(int i=0; i<DOF; ++i)
00193 {
00194 if (config.axes_map[i] == CRequest::DISABLED) continue;
00195
00196 switch (generators[i])
00197 {
00198 case SRequest::EFFORT:
00199 pubEffort = true;
00200 tauv[i] = mapped[i] * config.maximum_effort[i];
00201 break;
00202 case SRequest::SPEED:
00203 pubSpeed = true;
00204 nuv[i] = mapped[i] * config.maximum_speed[i];
00205 break;
00206 case SRequest::POSITION:
00207 if (!nav_valid) continue;
00208 pubPos = true;
00209 etaff[i] = mapped[i] * config.maximum_speed[i];
00210 break;
00211 }
00212 }
00213 l.unlock();
00214
00215 if (pubEffort) pubTau(tauv);
00216 if (pubSpeed) pubNu(nuv);
00217 if (pubPos) pubEta(etaff);
00218 };
00219
00220 void ManualControl::onNavSts(const auv_msgs::NavSts::ConstPtr& state)
00221 {
00222 boost::mutex::scoped_lock l(nav_mutex);
00223
00224 DataType pos(DOF+1,0);
00225 labust::tools::nedToVector(state->position,pos);
00226 labust::tools::rpyToVector(state->orientation,pos,3);
00227 pos[A] = state->altitude;
00228
00229 if (nav_valid)
00230 {
00231
00232 for(int i=0; i<DOF; ++i)
00233 {
00234 if (generators[i] != SRequest::POSITION) navstate[i] = pos[i];
00235 }
00236 }
00237 else
00238 {
00239
00240 navstate = pos;
00241 nav_valid = true;
00242 }
00243 }
00244
00245 void ManualControl::pubEta(const DataType& etaff)
00246 {
00247 boost::mutex::scoped_lock l(nav_mutex);
00248 if (!nav_valid) return;
00249
00250
00251 Eigen::Vector3d compff, ff;
00252 Eigen::Quaternion<double> quat;
00253 ff<<etaff[X],etaff[Y],etaff[Z];
00254 labust::tools::quaternionFromEulerZYX(navstate[K], navstate[M], navstate[N],quat);
00255 compff = quat.toRotationMatrix()*ff;
00256
00257 DataType etadot(DOF,0);
00258 for (int i=X; i<compff.size(); ++i) etadot[i] = compff(i);
00259 for (int i=K; i<DOF; ++i) etadot[i] = etaff[i];
00260
00261 boost::mutex::scoped_lock lcfg(cfg_mutex);
00262 for (int i=X; i<DOF; ++i)
00263 {
00264 navstate[i] += etadot[i]*config.sampling_time;
00265
00266 if (i>(DOF/2-1)) navstate[i] = labust::math::wrapRad(navstate[i]);
00267 }
00268
00269 navstate[A] += etadot[Z]*config.sampling_time;
00270
00271 auv_msgs::NavSts eta;
00272 labust::tools::vectorToNED(navstate, eta.position);
00273 labust::tools::vectorToRPY(navstate, eta.orientation, 3);
00274 if (config.use_ff)
00275 {
00276 labust::tools::vectorToPoint(etaff, eta.body_velocity);
00277 labust::tools::vectorToRPY(etaff, eta.orientation_rate, 3);
00278 }
00279 lcfg.unlock();
00280 l.unlock();
00281
00282 eta.header.stamp = ros::Time::now();
00283 eta.header.frame_id = "local";
00284 etaref.publish(eta);
00285 };
00286
00287 void ManualControl::pubTau(const DataType& tauv)
00288 {
00289 auv_msgs::BodyForceReq tau;
00290 labust::tools::vectorToPoint(tauv, tau.wrench.force);
00291 labust::tools::vectorToPoint(tauv, tau.wrench.torque, 3);
00292 tau.header.stamp = ros::Time::now();
00293 tau.header.frame_id = "base_link";
00294 tauref.publish(tau);
00295 }
00296
00297 void ManualControl::pubNu(const DataType& nuv)
00298 {
00299 auv_msgs::BodyVelocityReq nu;
00300 labust::tools::vectorToPoint(nuv, nu.twist.linear);
00301 labust::tools::vectorToPoint(nuv, nu.twist.angular, 3);
00302 nu.header.stamp = ros::Time::now();
00303 nu.header.frame_id = "base_link";
00304 nuref.publish(nu);
00305 }
00306
00307 void ManualControl::remap(const sensor_msgs::Joy::ConstPtr& joy)
00308 {
00309 boost::mutex::scoped_lock l(cfg_mutex);
00310 for (int i=0;i<DOF;++i)
00311 {
00312
00313 if (config.axes_map[i] == CRequest::DISABLED)
00314 {
00315 mapped[i] = 0;
00316 continue;
00317 }
00318
00319 if (joy->axes.size() <= i) continue;
00320
00321 if (config.integrated[i] > 0)
00322 {
00323 mapped[i] += joy->axes[config.axes_map[i]]*config.scale_map[i]*config.integrated[i];
00324 mapped[i] = labust::math::coerce(mapped[i], -1, 1);
00325 }
00326 else
00327 {
00328 mapped[i] = joy->axes[config.axes_map[i]]*config.scale_map[i];
00329 }
00330 }
00331 };
00332
00333 int main(int argc, char* argv[])
00334 {
00335 ros::init(argc,argv,"manual");
00336
00337 labust::control::ManualControl controller;
00338 ros::spin();
00339
00340 return 0;
00341 }
00342
00343
00344