calibration_offset_parser.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013-2014 Unbounded Robotics Inc.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 // Author: Michael Ferguson
00018 
00019 #include <string>
00020 #include <map>
00021 #include <tinyxml.h>
00022 #include <boost/algorithm/string.hpp>
00023 #include <boost/lexical_cast.hpp>
00024 #include <robot_calibration/calibration_offset_parser.h>
00025 #include <robot_calibration/models/chain.h>  // for rotation functions
00026 
00027 namespace robot_calibration
00028 {
00029 
00030 CalibrationOffsetParser::CalibrationOffsetParser()
00031 {
00032   // TODO?
00033 }
00034 
00035 bool CalibrationOffsetParser::add(const std::string name)
00036 {
00037   parameter_names_.push_back(name);
00038   parameter_offsets_.push_back(0.0);
00039   return true;
00040 }
00041 
00042 bool CalibrationOffsetParser::addFrame(
00043     const std::string name,
00044     bool calibrate_x, bool calibrate_y, bool calibrate_z,
00045     bool calibrate_roll, bool calibrate_pitch, bool calibrate_yaw)
00046 {
00047   frame_names_.push_back(name);
00048   if (calibrate_x)
00049     add(std::string(name).append("_x"));
00050   if (calibrate_y)
00051     add(std::string(name).append("_y"));
00052   if (calibrate_z)
00053     add(std::string(name).append("_z"));
00054 
00055   // These don't really correspond to rpy unless only one is set 
00056   // TODO: check that we do either roll, pitch or yaw, or all 3 (never just 2)   
00057   if (calibrate_roll)
00058     add(std::string(name).append("_a"));
00059   if (calibrate_pitch)
00060     add(std::string(name).append("_b"));
00061   if (calibrate_yaw)
00062     add(std::string(name).append("_c"));
00063 
00064   return true;
00065 }
00066 
00067 bool CalibrationOffsetParser::update(const double* const free_params)
00068 {
00069   for (size_t i = 0; i < parameter_offsets_.size(); ++i)
00070     parameter_offsets_[i] = free_params[i];
00071   return true;
00072 }
00073 
00074 double CalibrationOffsetParser::get(const std::string name) const
00075 {
00076   for (size_t i = 0; i < parameter_names_.size(); ++i)
00077   {
00078     if (parameter_names_[i] == name)
00079       return parameter_offsets_[i];
00080   }
00081   // Not calibrating this
00082   return 0.0;
00083 }
00084 
00085 bool CalibrationOffsetParser::getFrame(const std::string name, KDL::Frame& offset) const
00086 {
00087   // Don't bother with following computation if this isn't a calibrated frame.
00088   bool has_offset = false;
00089   for (size_t i = 0; i < frame_names_.size(); ++i)
00090   {
00091     if (frame_names_[i] == name)
00092     {
00093       has_offset = true;
00094       break;
00095     }
00096   }
00097  
00098   if (!has_offset)
00099     return false;
00100 
00101   offset.p.x(get(std::string(name).append("_x")));
00102   offset.p.y(get(std::string(name).append("_y")));
00103   offset.p.z(get(std::string(name).append("_z")));
00104 
00105   offset.M = rotation_from_axis_magnitude(
00106                  get(std::string(name).append("_a")),
00107                  get(std::string(name).append("_b")),
00108                  get(std::string(name).append("_c")));
00109 
00110   return true;
00111 }
00112 
00113 int CalibrationOffsetParser::size()
00114 {
00115   return parameter_names_.size();
00116 }
00117 
00118 std::string CalibrationOffsetParser::getOffsetYAML()
00119 {
00120   std::stringstream ss;
00121   for (size_t i = 0; i < parameter_names_.size(); ++i)
00122   {
00123     ss << parameter_names_[i] << ": " << parameter_offsets_[i] << std::endl;
00124   }
00125   return ss.str();
00126 }
00127 
00128 std::string CalibrationOffsetParser::updateURDF(const std::string &urdf)
00129 {
00130   const double precision = 8;
00131 
00132   TiXmlDocument xml_doc;
00133   xml_doc.Parse(urdf.c_str());
00134 
00135   TiXmlElement *robot_xml = xml_doc.FirstChildElement("robot");
00136   if (!robot_xml)
00137   {
00138     // TODO: error notification? We should never get here since URDF parse
00139     //       at beginning of calibration will fail
00140     return urdf;
00141   }
00142 
00143   // Update each joint
00144   for (TiXmlElement* joint_xml = robot_xml->FirstChildElement("joint"); joint_xml; joint_xml = joint_xml->NextSiblingElement("joint"))
00145   {
00146     const char * name = joint_xml->Attribute("name");
00147 
00148     // Is there a joint calibration needed?
00149     double offset = get(std::string(name));
00150     if (offset != 0.0)
00151     {
00152       TiXmlElement *calibration_xml = joint_xml->FirstChildElement("calibration");
00153       if (calibration_xml)
00154       {
00155         // Existing calibration, update rising attribute
00156         const char * rising_position_str = calibration_xml->Attribute("rising");
00157         if (rising_position_str != NULL)
00158         {
00159           try
00160           {
00161             offset += double(boost::lexical_cast<double>(rising_position_str));
00162             calibration_xml->SetDoubleAttribute("rising", offset);
00163           }
00164           catch (boost::bad_lexical_cast &e)
00165           {
00166             // TODO: error
00167           }
00168         }
00169         else
00170         {
00171           // TODO: error
00172         }
00173       }
00174       else
00175       {
00176         // No calibration previously, add an element + attribute
00177         calibration_xml = new TiXmlElement("calibration");
00178         calibration_xml->SetDoubleAttribute("rising", offset);
00179         TiXmlNode * calibration = calibration_xml->Clone();
00180         joint_xml->InsertEndChild(*calibration);
00181       }
00182     }
00183 
00184     KDL::Frame frame_offset;
00185     bool has_update = getFrame(name, frame_offset);
00186     if (has_update)
00187     {
00188       std::vector<double> xyz(3, 0.0);
00189       std::vector<double> rpy(3, 0.0);
00190 
00191       xyz[0] = frame_offset.p.x();
00192       xyz[1] = frame_offset.p.y();
00193       xyz[2] = frame_offset.p.z();
00194 
00195       // Get roll, pitch, yaw about fixed axis
00196       frame_offset.M.GetRPY(rpy[0], rpy[1], rpy[2]);
00197 
00198       // String streams for output
00199       std::stringstream xyz_ss, rpy_ss;
00200 
00201       TiXmlElement *origin_xml = joint_xml->FirstChildElement("origin");
00202       if (origin_xml)
00203       {
00204         // Update existing origin
00205         const char * xyz_str = origin_xml->Attribute("xyz");
00206         const char * rpy_str = origin_xml->Attribute("rpy");
00207 
00208         // Split out xyz of origin, break into 3 strings
00209         std::vector<std::string> xyz_pieces;
00210         boost::split(xyz_pieces, xyz_str, boost::is_any_of(" "));
00211 
00212         if (xyz_pieces.size() == 3)
00213         {
00214           // Update xyz
00215           for (int i = 0; i < 3; ++i)
00216           {
00217             double x = double(boost::lexical_cast<double>(xyz_pieces[i]) + xyz[i]);
00218             if (i > 0)
00219               xyz_ss << " ";
00220             xyz_ss << std::fixed << std::setprecision(precision) << x;
00221           }
00222         }
00223         else
00224         {
00225           // Create xyz
00226           for (int i = 0; i < 3; ++i)
00227           {
00228             if (i > 0)
00229               xyz_ss << " ";
00230             xyz_ss << std::fixed << std::setprecision(precision) << xyz[i];
00231           }
00232         }
00233 
00234         // Split out rpy of origin, break into 3 strings
00235         std::vector<std::string> rpy_pieces;
00236         boost::split(rpy_pieces, rpy_str, boost::is_any_of(" "));
00237 
00238         if (rpy_pieces.size() == 3)
00239         {
00240           // Update rpy
00241           for (int i = 0; i < 3; ++i)
00242           {
00243             double x = double(boost::lexical_cast<double>(rpy_pieces[i]) + rpy[i]);
00244             if (i > 0)
00245               rpy_ss << " ";
00246             rpy_ss << std::fixed << std::setprecision(precision) << x;
00247           }
00248         }
00249         else
00250         {
00251           // Create rpy
00252           for (int i = 0; i < 3; ++i)
00253           {
00254             if (i > 0)
00255               rpy_ss << " ";
00256             rpy_ss << std::fixed << std::setprecision(precision) << rpy[i];
00257           }
00258         }
00259 
00260         // Update xml
00261         origin_xml->SetAttribute("xyz", xyz_ss.str());
00262         origin_xml->SetAttribute("rpy", rpy_ss.str());
00263       }
00264       else
00265       {
00266         // No existing origin, create an element with attributes
00267         origin_xml = new TiXmlElement("origin");
00268 
00269         // Create xyz
00270         for (int i = 0; i < 3; ++i)
00271         {
00272           if (i > 0)
00273             xyz_ss << " ";
00274           xyz_ss << std::fixed << std::setprecision(precision) << xyz[i];
00275         }
00276         origin_xml->SetAttribute("xyz", xyz_ss.str());
00277 
00278         // Create rpy
00279         for (int i = 0; i < 3; ++i)
00280         {
00281           if (i > 0)
00282             rpy_ss << " ";
00283           rpy_ss << std::fixed << std::setprecision(precision) << rpy[i];
00284         }
00285         origin_xml->SetAttribute("rpy", rpy_ss.str());
00286 
00287         TiXmlNode * origin = origin_xml->Clone();
00288         joint_xml->InsertEndChild(*origin);
00289       }
00290     }
00291   }
00292 
00293   // Print to a string
00294   TiXmlPrinter printer;
00295   printer.SetIndent("  ");
00296   xml_doc.Accept(&printer);
00297   std::string new_urdf = printer.CStr();
00298 
00299   return new_urdf;
00300 }
00301 
00302 }  // namespace robot_calibration


robot_calibration
Author(s): Michael Ferguson
autogenerated on Thu Jun 6 2019 21:54:10