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/IdentificationNode.hpp>
00038 #include <labust/math/NumberManipulation.hpp>
00039 #include <labust/tools/conversions.hpp>
00040
00041 #include <auv_msgs/BodyForceReq.h>
00042
00043 #include <boost/bind.hpp>
00044
00045 using namespace labust::control;
00046
00047 const char dofNames[]={'X','Y','Z','K','M','N','A'};
00048
00049 IdentificationNode::IdentificationNode():
00050 measurements(MeasVec::Zero()),
00051 integrateUV(true),
00052 useUV(false),
00053 useW(false)
00054 {
00055 this->onInit();
00056 }
00057
00058 void IdentificationNode::onInit()
00059 {
00060 ros::NodeHandle nh,ph("~");
00061 aserver.reset(new ActionServer(nh,
00062 "Identification",
00063 boost::bind(&IdentificationNode::doIdentification, this, _1),
00064 false));
00065 aserver->start();
00066
00067 tauOut = nh.advertise<auv_msgs::BodyForceReq>("tauOut", 1);
00068 stateOut = nh.advertise<auv_msgs::NavSts>("identState", 1);
00069 meas = nh.subscribe<auv_msgs::NavSts>("meas", 1,
00070 &IdentificationNode::onMeasurement,this);
00071
00072 ph.param("integrateUV",integrateUV, true);
00073 ph.param("useUV",useUV, false);
00074 ph.param("useW",useW, false);
00075 }
00076
00077 void IdentificationNode::onMeasurement(const auv_msgs::NavSts::ConstPtr& meas)
00078 {
00079 static ros::Time lastSampleTime=ros::Time::now();
00080
00081 if (integrateUV)
00082 {
00083 boost::mutex::scoped_lock l(measmux);
00084 double dT = (ros::Time::now() - lastSampleTime).toSec();
00085 lastSampleTime = ros::Time::now();
00086
00087 measurements(x) += meas->body_velocity.x*dT;
00088 measurements(y) += meas->body_velocity.y*dT;
00089 ROS_DEBUG("Estimated pos: Ts=%f, x=%f, y=%f",dT, measurements(x), measurements(y));
00090 }
00091 else
00092 {
00093 boost::mutex::scoped_lock l(measmux);
00094 measurements(x) = meas->position.north;
00095 measurements(y) = meas->position.east;
00096 }
00097 measurements(z) = meas->position.depth;
00098 measurements(roll) = meas->orientation.roll;
00099 measurements(pitch) = meas->orientation.pitch;
00100 measurements(yaw) = meas->orientation.yaw;
00101
00102 measurements(altitude) = meas->altitude;
00103 measurements(u) = meas->body_velocity.x;
00104 measurements(v) = meas->body_velocity.y;
00105 measurements(w) = meas->body_velocity.z;
00106 }
00107
00108 void IdentificationNode::doIdentification(const Goal::ConstPtr& goal)
00109 {
00110 ROS_INFO("Recevied goal.");
00111
00112
00113 if ((goal->sampling_rate <= 0) ||
00114 (goal->command == 0) ||
00115 (goal->hysteresis == 0) ||
00116 (goal->dof < Goal::Surge) || (goal->dof > Goal::Altitude))
00117 {
00118 ROS_ERROR("Some identification criteria are faulty: "
00119 "command: (%f != 0), "
00120 "hysteresis: (%f != 0), "
00121 "dof: (abs(%d) < 6), "
00122 "(sampling_rate: (%f >=0)", goal->command,
00123 goal->hysteresis, goal->dof, goal->sampling_rate);
00124 return;
00125 }
00126
00127 ros::Rate rate(goal->sampling_rate);
00128 int oscnum(0);
00129
00130 SOIdentification ident;
00131 ident.setRelay(goal->command,goal->hysteresis);
00132 ident.Ref(goal->reference);
00133
00134 ROS_INFO("Started identification of %c DOF.",dofNames[goal->dof]);
00135
00136
00137 if (integrateUV)
00138 {
00139 boost::mutex::scoped_lock l(measmux);
00140 measurements(x)=0;
00141 measurements(y)=0;
00142 }
00143
00144
00145 if (useUV)
00146 {
00147 cumulative_error = 0;
00148 }
00149
00150 while (!ident.isFinished())
00151 {
00152 double error = goal->reference - measurements(goal->dof);
00153
00154 if (((goal->dof <= Goal::Sway) && useUV) || ((goal->dof == Goal::Heave) && useW))
00155 {
00156 enum {stateDiff = 7};
00157
00158 error = goal->reference - measurements(goal->dof + stateDiff);
00159 cumulative_error += error/goal->sampling_rate;
00160 error = cumulative_error;
00161 }
00162
00163
00164 if ((goal->dof >= Goal::Roll) && (goal->dof <=Goal::Yaw))
00165 {
00166 error = labust::math::wrapRad(
00167 labust::math::wrapRad(goal->reference) -
00168 labust::math::wrapRad(measurements(goal->dof)));
00169 }
00170
00171 if ((goal->dof >= Goal::Surge) && (goal->dof <= Goal::Yaw))
00172 {
00173 this->setTau(goal->dof, ident.step(error, 1/goal->sampling_rate));
00174 }
00175 else if (goal->dof == Goal::Altitude)
00176 {
00177 ROS_INFO("Doing identification: %f %f %f.",goal->reference, measurements[goal->dof], error);
00178 this->setTau(Goal::Heave, -ident.step(error, 1/goal->sampling_rate));
00179 }
00180
00181
00182 if (aserver->isPreemptRequested() || !ros::ok())
00183 {
00184 ROS_INFO("DOFIdentification for %d: Preempted", goal->dof);
00185
00186 this->setTau(0, 0.0);
00187
00188 aserver->setPreempted();
00189 return;
00190 }
00191
00192
00193 if (ident.hasSwitched())
00194 {
00195 navcon_msgs::DOFIdentificationFeedback feedback;
00196 feedback.dof = goal->dof;
00197 feedback.error = ident.avgError();
00198 feedback.oscillation_num = ++oscnum/2;
00199 aserver->publishFeedback(feedback);
00200 }
00201
00202 auv_msgs::NavSts::Ptr outsts(new auv_msgs::NavSts);
00203 outsts->position.north = measurements(x);
00204 outsts->position.east = measurements(y);
00205 outsts->position.depth = measurements(z);
00206 outsts->orientation.roll = measurements(roll);
00207 outsts->orientation.pitch = measurements(pitch);
00208 outsts->orientation.yaw = measurements(yaw);
00209 stateOut.publish(outsts);
00210
00211
00212 rate.sleep();
00213 }
00214
00215
00216 this->setTau(0, 0.0);
00217
00218 if (ident.isFinished())
00219 {
00220 const std::vector<double>& params = ident.parameters();
00221 Result result;
00222 result.dof = goal->dof;
00223 result.alpha = params[SOIdentification::alpha];
00224 result.beta = params[SOIdentification::kx];
00225 result.betaa = params[SOIdentification::kxx];
00226 result.delta = params[SOIdentification::delta];
00227 result.wn = params[SOIdentification::wn];
00228
00229 ROS_INFO("Identified parameters: %f %f %f %f",
00230 params[SOIdentification::alpha],
00231 params[SOIdentification::kx],
00232 params[SOIdentification::kxx],
00233 params[SOIdentification::delta],
00234 params[SOIdentification::wn]);
00235
00236
00237 aserver->setSucceeded(result);
00238 }
00239 }
00240
00241 void IdentificationNode::setTau(int elem, double value)
00242 {
00243 labust::simulation::vector tauvec = labust::simulation::vector::Zero();
00244 tauvec(elem) = value;
00245 std::ostringstream out;
00246 out<<"ident_"<<dofNames[elem];
00247 auv_msgs::BodyForceReqPtr tau(new auv_msgs::BodyForceReq());
00248 tau->header.stamp = ros::Time::now();
00249 tau->goal.requester = out.str();
00250 labust::tools::vectorToPoint(tauvec,tau->wrench.force);
00251 labust::tools::vectorToPoint(tauvec,tau->wrench.torque,3);
00252 tauOut.publish(tau);
00253 }
00254
00255 int main(int argc, char* argv[])
00256 {
00257 ros::init(argc,argv,"ident_node");
00258 labust::control::IdentificationNode ident;
00259 ros::spin();
00260 return 0;
00261 }