PlaDyPosNode.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 #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 //#include <cart2/ImuInfo.h>
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         //Initialize subscribers and publishers
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         //Initialize max/min tau
00080         double maxThrust(1),minThrust(-1);
00081         ph.param("maxThrust",maxThrust,maxThrust);
00082         ph.param("minThrust",minThrust,minThrust);
00083 
00084         //Initialize the allocation matrix
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         //Scaling allocation only for XYN
00092         allocator.configure(B,maxThrust,minThrust);
00093 
00094         //Setup serial port
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     //port.set_option(serial_port::flow_control(config->flowControl));
00106     //port.set_option(serial_port::parity(config->parity));
00107     //port.set_option(serial_port::stop_bits(config->stopBits));
00108     //port.set_option(serial_port::character_size(config->dataBits));
00109   }
00110   else
00111   {
00112         ROS_WARN("Port %s on is not open.", portName.c_str());
00113   }
00114 
00115         //Configure the dynamic reconfigure server
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                         //ROS_INFO("Message acknowledged.");
00144                         break;
00145                 case '?':
00146                         //ROS_INFO("Communication error - received '?'");
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                                 //ROS_INFO("Received data: type=%c, idx=%d, value=%d", ret,idx,value);
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                 //ROS_INFO("Revoultion control enabled.");
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         //Here we set the thrust
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         //Here we request the currents and voltages.
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         //Perform allocation
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         //Publish the scaled values if scaling occured
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         //Tau to Revs
00275         int n[4];
00276         //Here we map the thrusts
00277         for (int i=0; i<4;++i)
00278         {
00279                 //This is the quadratic allocation.
00280                 //n[i] = labust::vehicles::AffineThruster::getRevs(tauI(i),1.0/(255*255),1.0/(255*255));
00281                 //This is the linear allocation.
00282                 //n[i]=tauI(i)*255; 
00283                 //This is the compensated quadratic+linear allocation.
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         //Manual corection
00296         //if (n[3] < 0)
00297         //{ 
00298         //      n[3]*= 1.15;
00299         //      n[3] = labust::math::coerce(n[3],-255,255);
00300         //}
00301         //n[1] *= 0.95;
00302 
00303         
00304         driverMsg(n);
00305 
00306         //ROS_INFO("Revs: %d %d %d %d\n",n[0],n[1],n[2],n[3]);
00307 }


pladypos
Author(s): Gyula Nagy
autogenerated on Fri Feb 7 2014 11:37:13