static_transform_broadcaster_program.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include <tf2_ros/static_transform_broadcaster.h>
00031 #include <Eigen/Geometry>
00032 
00033 #include <boost/program_options.hpp>
00034 namespace po=boost::program_options;
00035 
00036 static void usage (const char* prog_name, const po::options_description &opts, bool desc=false) {
00037   if (desc) {
00038     std::cout << "A command line utility for manually defining a (static) transform" << std::endl;
00039     std::cout << "from parent_frame_id to child_frame_id." << std::endl;
00040   }
00041   std::cout << std::endl;
00042   std::cout << "Usage: static_transform_publisher [options] x y z  <rotation> parent_frame_id child_frame_id" << std::endl;
00043   std::cout << opts << std::endl;
00044 }
00045 
00046 static void parse_arguments(int argc, char **argv,
00047                             geometry_msgs::TransformStamped &msg) {
00048   std::string mode;
00049   po::options_description options_description("allowed options");
00050   options_description.add_options()
00051       ("help,h", "show this help message")
00052       ("mode,m", po::value<std::string>(&mode))
00053       ;
00054 
00055   po::variables_map variables_map;
00056   std::vector<std::string> args;
00057   std::vector<std::string>::const_iterator arg;
00058   try {
00059     po::parsed_options parsed =
00060         po::command_line_parser(argc, argv)
00061         .options(options_description)
00062         .allow_unregistered()
00063         .run();
00064 
00065     po::store(parsed, variables_map);
00066     po::notify(variables_map);
00067     args = po::collect_unrecognized(parsed.options, po::include_positional);
00068     arg = args.begin();
00069 
00070     if (variables_map.count("help")) {
00071       usage(argv[0], options_description, true);
00072       exit (EXIT_SUCCESS);
00073     }
00074     const size_t numArgs = 3 + 2;
00075 
00076     bool bQuatMode = (mode == "wxyz" || mode == "xyzw");
00077     if (mode == "")
00078     {
00079       if (args.size() == numArgs+4) {
00080         bQuatMode = true; // 4 rotational args trigger quaternion mode too
00081         mode = "xyzw";
00082       } else if (args.size() == numArgs+3) {
00083         mode = "zyx";
00084       } else {
00085         throw po::error("invalid number of positional arguments");
00086       }
00087     }
00088 
00089     // consume position arguments
00090     msg.transform.translation.x = boost::lexical_cast<double>(*arg); ++arg;
00091     msg.transform.translation.y = boost::lexical_cast<double>(*arg); ++arg;
00092     msg.transform.translation.z = boost::lexical_cast<double>(*arg); ++arg;
00093 
00094     // consume orientation arguments
00095     Eigen::Quaterniond q;
00096     if (bQuatMode) { // parse Quaternion
00097       if (args.size() != numArgs+4)
00098         throw po::error("quaternion mode requires " +
00099                         boost::lexical_cast<std::string>(numArgs+4) +
00100                         " positional arguments");
00101 
00102       const std::string eigen_order("xyzw");
00103       double data[4];
00104       for (size_t i=0; i<4; ++i) {
00105         size_t idx = eigen_order.find(mode[i]);
00106         data[idx] = boost::lexical_cast<double>(*arg); ++arg;
00107       }
00108       q = Eigen::Quaterniond(data);
00109 
00110     } else { // parse Euler angles
00111       if (args.size() != numArgs+3)
00112         throw po::error("Euler angles require " +
00113                         boost::lexical_cast<std::string>(numArgs+3) +
00114                         " positional arguments");
00115       if (mode.size() != 3)
00116         throw po::error("mode specification for Euler angles requires a string from 3 chars (xyz)");
00117 
00118       const std::string axes_order("xyz");
00119       size_t axes_idxs[3];
00120       double angles[3];
00121 
00122       for (size_t i=0; i<3; ++i) {
00123         size_t idx = axes_order.find(mode[i]);
00124         if (idx == std::string::npos)
00125           throw po::error("invalid axis specification for Euler angles: " +
00126                           boost::lexical_cast<std::string>(mode[i]));
00127         axes_idxs[i] = idx;
00128         angles[i] = boost::lexical_cast<double>(*arg); ++arg;
00129       }
00130       q = Eigen::AngleAxisd(angles[0], Eigen::Vector3d::Unit(axes_idxs[0])) *
00131           Eigen::AngleAxisd(angles[1], Eigen::Vector3d::Unit(axes_idxs[1])) *
00132           Eigen::AngleAxisd(angles[2], Eigen::Vector3d::Unit(axes_idxs[2]));
00133     }
00134     // assign quaternion
00135     q.normalize();
00136     msg.transform.rotation.x = q.x();
00137     msg.transform.rotation.y = q.y();
00138     msg.transform.rotation.z = q.z();
00139     msg.transform.rotation.w = q.w();
00140 
00141     // consume link arguments
00142     msg.header.frame_id = *arg++;
00143     msg.child_frame_id = *arg++;
00144   } catch (const po::error  &e) {
00145     ROS_FATAL_STREAM(e.what());
00146     usage(argv[0], options_description);
00147     exit (EXIT_FAILURE);
00148   } catch (const boost::bad_lexical_cast &e) {
00149     ROS_FATAL_STREAM("failed to parse numerical value: " << *arg);
00150     usage(argv[0], options_description);
00151     exit (EXIT_FAILURE);
00152   }
00153 }
00154 
00155 int main(int argc, char ** argv)
00156 {
00157   // Initialize ROS
00158   ros::init(argc, argv, "static_transform_publisher", ros::init_options::AnonymousName);
00159 
00160   geometry_msgs::TransformStamped msg;
00161   parse_arguments(argc, argv, msg);
00162 
00163   if (msg.header.frame_id.empty() || msg.child_frame_id.empty())
00164   {
00165     ROS_FATAL("target or source frame is empty");
00166     exit(1);
00167   }
00168   if (msg.header.frame_id == msg.child_frame_id)
00169   {
00170     ROS_FATAL("target and source frame are the same (%s, %s) this cannot work",
00171               msg.child_frame_id.c_str(), msg.header.frame_id.c_str());
00172     exit(1);
00173   }
00174 
00175   tf2_ros::StaticTransformBroadcaster broadcaster;
00176   broadcaster.sendTransform(msg);
00177 
00178   ROS_INFO("Spinning until killed, publishing %s to %s",
00179            msg.header.frame_id.c_str(), msg.child_frame_id.c_str());
00180   ros::spin();
00181 
00182   return 0;
00183 }


agni_tf_tools
Author(s): Robert Haschke
autogenerated on Sat Jun 8 2019 21:01:20