31 #include <Eigen/Geometry>    33 #include <boost/program_options.hpp>    34 namespace po=boost::program_options;
    36 static void usage (
const char* prog_name, 
const po::options_description &opts, 
bool desc=
false) {
    38     std::cout << 
"A command line utility for manually defining a (static) transform" << std::endl;
    39     std::cout << 
"from parent_frame_id to child_frame_id." << std::endl;
    41   std::cout << std::endl;
    42   std::cout << 
"Usage: static_transform_publisher [options] x y z  <rotation> parent_frame_id child_frame_id" << std::endl;
    43   std::cout << opts << std::endl;
    47                             geometry_msgs::TransformStamped &msg) {
    49   po::options_description options_description(
"allowed options");
    50   options_description.add_options()
    51       (
"help,h", 
"show this help message")
    52       (
"mode,m", po::value<std::string>(&mode))
    55   po::variables_map variables_map;
    56   std::vector<std::string> 
args;
    57   std::vector<std::string>::const_iterator arg;
    59     po::parsed_options parsed =
    60         po::command_line_parser(argc, argv)
    61         .options(options_description)
    65     po::store(parsed, variables_map);
    66     po::notify(variables_map);
    67     args = po::collect_unrecognized(parsed.options, po::include_positional);
    70     if (variables_map.count(
"help")) {
    71       usage(argv[0], options_description, 
true);
    74     const size_t numArgs = 3 + 2;
    76     bool bQuatMode = (mode == 
"wxyz" || mode == 
"xyzw");
    79       if (args.size() == numArgs+4) {
    82       } 
else if (args.size() == numArgs+3) {
    85         throw po::error(
"invalid number of positional arguments");
    90     msg.transform.translation.x = boost::lexical_cast<
double>(*arg); ++arg;
    91     msg.transform.translation.y = boost::lexical_cast<
double>(*arg); ++arg;
    92     msg.transform.translation.z = boost::lexical_cast<
double>(*arg); ++arg;
    97       if (args.size() != numArgs+4)
    98         throw po::error(
"quaternion mode requires " +
    99                         boost::lexical_cast<std::string>(numArgs+4) +
   100                         " positional arguments");
   102       const std::string eigen_order(
"xyzw");
   104       for (
size_t i=0; i<4; ++i) {
   105         size_t idx = eigen_order.find(mode[i]);
   106         data[idx] = boost::lexical_cast<
double>(*arg); ++arg;
   108       q = Eigen::Quaterniond(data);
   111       if (args.size() != numArgs+3)
   112         throw po::error(
"Euler angles require " +
   113                         boost::lexical_cast<std::string>(numArgs+3) +
   114                         " positional arguments");
   115       if (mode.size() != 3)
   116         throw po::error(
"mode specification for Euler angles requires a string from 3 chars (xyz)");
   118       const std::string axes_order(
"xyz");
   122       for (
size_t i=0; i<3; ++i) {
   123         size_t idx = axes_order.find(mode[i]);
   124         if (idx == std::string::npos)
   125           throw po::error(
"invalid axis specification for Euler angles: " +
   126                           boost::lexical_cast<std::string>(mode[i]));
   128         angles[i] = boost::lexical_cast<
double>(*arg); ++arg;
   130       q = Eigen::AngleAxisd(angles[0], Eigen::Vector3d::Unit(axes_idxs[0])) *
   131           Eigen::AngleAxisd(angles[1], Eigen::Vector3d::Unit(axes_idxs[1])) *
   132           Eigen::AngleAxisd(angles[2], Eigen::Vector3d::Unit(axes_idxs[2]));
   136     msg.transform.rotation.x = q.x();
   137     msg.transform.rotation.y = q.y();
   138     msg.transform.rotation.z = q.z();
   139     msg.transform.rotation.w = q.w();
   142     msg.header.frame_id = *arg++;
   143     msg.child_frame_id = *arg++;
   144   } 
catch (
const po::error  &e) {
   146     usage(argv[0], options_description);
   148   } 
catch (
const boost::bad_lexical_cast &e) {
   150     usage(argv[0], options_description);
   155 int main(
int argc, 
char ** argv)
   160   geometry_msgs::TransformStamped msg;
   163   if (msg.header.frame_id.empty() || msg.child_frame_id.empty())
   165     ROS_FATAL(
"target or source frame is empty");
   168   if (msg.header.frame_id == msg.child_frame_id)
   170     ROS_FATAL(
"target and source frame are the same (%s, %s) this cannot work",
   171               msg.child_frame_id.c_str(), msg.header.frame_id.c_str());
   178   ROS_INFO(
"Spinning until killed, publishing %s to %s",
   179            msg.header.frame_id.c_str(), msg.child_frame_id.c_str());
 
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
ROSCPP_DECL void spin(Spinner &spinner)
#define ROS_FATAL_STREAM(args)