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 #include <labust/vehicles/PlaDyPosNode.hpp>
00035 #include <labust/vehicles/Allocation.hpp>
00036 #include <labust/math/NumberManipulation.hpp>
00037
00038 #include <diagnostic_msgs/DiagnosticStatus.h>
00039
00040 #include <std_msgs/Float32MultiArray.h>
00041
00042 #include <boost/regex.hpp>
00043
00044 #include <string>
00045 #include <sstream>
00046
00047 using namespace labust::vehicles;
00048
00049 const float PlaDyPosNode::sscale[6]={0.00926,
00050 0.00926,
00051 0.00926,
00052 0.00926,
00053 0.0152738,
00054 0.02795
00055 };
00056
00057 PlaDyPosNode::PlaDyPosNode():
00058 io(),
00059 port(io),
00060 lastTau(ros::Time::now()),
00061 timeout(0.5),
00062 revControl(false){}
00063
00064 PlaDyPosNode::~PlaDyPosNode()
00065 {
00066 io.stop();
00067 safety.join();
00068 iorunner.join();
00069 }
00070
00071 void PlaDyPosNode::configure(ros::NodeHandle& nh, ros::NodeHandle& ph)
00072 {
00073
00074 tau = nh.subscribe("tauIn", 1, &PlaDyPosNode::onTau,this);
00075 tauAch = nh.advertise<auv_msgs::BodyForceReq>("tauAch",1);
00076 diag = nh.advertise<diagnostic_msgs::DiagnosticStatus>("diagnostics",1);
00077 info = nh.advertise<std_msgs::Float32MultiArray>("pladypos_info",1);
00078
00079
00080 double maxThrust(1),minThrust(-1);
00081 ph.param("maxThrust",maxThrust,maxThrust);
00082 ph.param("minThrust",minThrust,minThrust);
00083
00084
00085 Eigen::Matrix<float, 3,4> B;
00086 float cp(cos(M_PI/4)),sp(sin(M_PI/4));
00087 B<<-cp,cp,cp,-cp,
00088 -sp,-sp,sp,sp,
00089 1,-1,1,-1;
00090
00091
00092 allocator.configure(B,maxThrust,minThrust);
00093
00094
00095 std::string portName("/dev/ttyUSB0");
00096 int baud(9600);
00097 ph.param("PortName",portName,portName);
00098 ph.param("Baud",baud,baud);
00099 port.open(portName);
00100
00101 if (port.is_open())
00102 {
00103 ROS_INFO("Port %s on is open.", portName.c_str());
00104 port.set_option(boost::asio::serial_port::baud_rate(baud));
00105
00106
00107
00108
00109 }
00110 else
00111 {
00112 ROS_WARN("Port %s on is not open.", portName.c_str());
00113 }
00114
00115
00116 server.setCallback(boost::bind(&PlaDyPosNode::dynrec, this, _1, _2));
00117
00118 this->start_receive();
00119 safety = boost::thread(boost::bind(&PlaDyPosNode::safetyTest, this));
00120 iorunner = boost::thread(boost::bind(&boost::asio::io_service::run, &this->io));
00121 }
00122
00123 void PlaDyPosNode::start_receive()
00124 {
00125 boost::asio::async_read_until(port, sbuffer, boost::regex("\\)|!|\\?"),
00126 boost::bind(&PlaDyPosNode::onReply,this,_1,_2));
00127 }
00128
00129 void PlaDyPosNode::onReply(const boost::system::error_code& error, const size_t& transferred)
00130 {
00131 static int trackC=0;
00132 if (!error)
00133 {
00134 std::istream is(&sbuffer);
00135 char c;
00136 is>>c;
00137
00138 char ret, junk, delimit;
00139 int idx, value;
00140 switch (c)
00141 {
00142 case '!':
00143
00144 break;
00145 case '?':
00146
00147 break;
00148 case '(':
00149 is>>ret>>idx>>junk>>value>>delimit;
00150 if (ret == 'c')
00151 {
00152 ++trackC;
00153 sensors[idx] = value*sscale[idx];
00154
00155
00156 if (trackC == sensors.size()-1)
00157 {
00158 trackC = 0;
00159 pubDiagnostics();
00160 }
00161 }
00162 break;
00163 default:
00164 ROS_ERROR("Unknown start character.");
00165 }
00166 }
00167 start_receive();
00168 }
00169
00170 void PlaDyPosNode::pubDiagnostics()
00171 {
00172 diagnostic_msgs::DiagnosticStatusPtr status(new diagnostic_msgs::DiagnosticStatus());
00173
00174 status->level = status->OK;
00175 status->name = "PlaDyPos Driver";
00176 status->message = "Voltage and current report";
00177 status->hardware_id = "None";
00178
00179 std::string names[6]={"C0","C1","C2","C3","CP","Voltage"};
00180 std::ostringstream out;
00181 std_msgs::Float32MultiArrayPtr data(new std_msgs::Float32MultiArray());
00182 data->data.resize(sensors.size());
00183 for (size_t i=0; i<sensors.size(); ++i)
00184 {
00185 out.str("");
00186 out<<sensors[i];
00187 diagnostic_msgs::KeyValue ddata;
00188 ddata.key = names[i];
00189 ddata.value = out.str();
00190 status->values.push_back(ddata);
00191 data->data[i]=sensors[i];
00192 }
00193
00194 for (size_t i=0; i<4; ++i) data->data.push_back(lastRevs[i]);
00195
00196 diag.publish(status);
00197 info.publish(data);
00198 }
00199
00200 void PlaDyPosNode::dynrec(pladypos::ThrusterMappingConfig& config, uint32_t level)
00201 {
00202 revControl = config.enableRevs;
00203
00204 if (revControl)
00205 {
00206 int n[4]={config.rev0, config.rev1, config.rev2, config.rev3};
00207 driverMsg(n);
00208
00209 }
00210 }
00211
00212 void PlaDyPosNode::safetyTest()
00213 {
00214 ros::Rate rate(5);
00215
00216 while (ros::ok())
00217 {
00218 if (((ros::Time::now() - lastTau).toSec() > timeout) && !revControl)
00219 {
00220 ROS_WARN("Timeout triggered.");
00221 int n[4]={0,0,0,0};
00222 driverMsg(n);
00223 }
00224 rate.sleep();
00225 }
00226 }
00227
00228 void PlaDyPosNode::driverMsg(const int n[4])
00229 {
00230 std::ostringstream out;
00231
00232
00233 for (int i=0; i<4;++i)
00234 {
00235 lastRevs[i]=n[i];
00236 out<<"(P"<<i<<","<<abs(n[i])<<","<<((n[i]>0)?1:0)<<")";
00237 }
00238
00239 for (int i=0; i<6;++i) out<<"(C"<<i<<")";
00240
00241 boost::mutex::scoped_lock lock(serialMux);
00242 boost::asio::write(port,boost::asio::buffer(out.str()));
00243 }
00244
00245 void PlaDyPosNode::onTau(const auv_msgs::BodyForceReq::ConstPtr tau)
00246 {
00247 lastTau = ros::Time::now();
00248 if (revControl) return;
00249
00250 Eigen::Vector3f tauXYN,tauXYNsc;
00251 Eigen::Vector4f tauI;
00252 tauXYN<<tau->wrench.force.x,tau->wrench.force.y,tau->wrench.torque.z;
00253 double scale = allocator.scaleII(tauXYN,&tauXYNsc,&tauI);
00254
00255
00256 auv_msgs::BodyForceReq t;
00257 t.wrench.force.x = tauXYNsc(0);
00258 t.wrench.force.y = tauXYNsc(1);
00259 t.wrench.force.z = 0;
00260 t.wrench.torque.x = 0;
00261 t.wrench.torque.y = 0;
00262 t.wrench.torque.z = tauXYNsc(2);
00263 t.header.stamp = ros::Time::now();
00264
00265 if (scale>1)
00266 {
00267 t.disable_axis.x = 1;
00268 t.disable_axis.y = 1;
00269 t.disable_axis.yaw = 1;
00270 }
00271
00272 tauAch.publish(t);
00273
00274
00275 int n[4];
00276
00277 for (int i=0; i<4;++i)
00278 {
00279
00280
00281
00282
00283
00284 if (fabs(tauI(i)) < 0.23184)
00285 {
00286 n[i] = 255*labust::vehicles::AffineThruster::getRevsD(tauI(i),1.894,1.894);
00287 }
00288 else
00289 {
00290 double a(1.21), b(-0.1915);
00291 n[i]=255*labust::math::coerce((tauI(i)-fabs(tauI(i))/tauI(i)*b)/a, -1,1);
00292 }
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 driverMsg(n);
00305
00306
00307 }