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
00035 #include <cstdio>
00036 #include <cstdlib>
00037
00038 #include <vector>
00039 #include <string>
00040 #include <sstream>
00041
00042
00043 #include <gazebo_plugins/DeleteModel.h>
00044 #include <gazebo_plugins/SpawnModel.h>
00045 #include <gazebo_plugins/SetPose.h>
00046
00047 #include <ros/ros.h>
00048 #include <boost/program_options.hpp>
00049
00050 #include <gazebo_tools/urdf2gazebo.h>
00051
00052 void usage(const char *progname)
00053 {
00054 printf("\nUsage: %s [options] <spawn|kill> <model_name>\n", progname);
00055 printf(" Example: %s --help\n",progname);
00056 printf(" Example: %s -p robot_description -x 10 spawn pr2\n",progname);
00057 printf(" Example: %s -f my_urdf_file.urdf -o gazebo_model.xml -x 10\n",progname);
00058 printf(" Example: %s kill pr2_model\n",progname);
00059 }
00060
00063 bool getXMLType(TiXmlDocument &xml_doc,uint32_t &xml_type)
00064 {
00065
00066 if (xml_doc.FirstChild("robot"))
00067 xml_type = gazebo_plugins::GazeboModel::URDF;
00068 else if (xml_doc.FirstChild("model:physical"))
00069 xml_type = gazebo_plugins::GazeboModel::GAZEBO_XML;
00070 else
00071 return 0;
00072
00073 return 1;
00074 }
00075 bool getXMLType(std::string xml_string,uint32_t &xml_type)
00076 {
00077 TiXmlDocument xml_doc;
00078 xml_doc.Parse(xml_string.c_str());
00079 return getXMLType(xml_doc,xml_type);
00080 }
00081
00082 void convertToGazeboXML(std::string xml_string,TiXmlDocument &gazebo_model_xml,bool enforce_limits,urdf::Vector3 initial_xyz,urdf::Vector3 initial_rpy,std::string model_name,std::string robot_namespace)
00083 {
00084
00085 TiXmlDocument xml_doc;
00086 xml_doc.Parse(xml_string.c_str());
00087
00088
00089 if (xml_doc.FirstChild("robot"))
00090 {
00091
00092 urdf2gazebo::URDF2Gazebo u2g;
00093 u2g.convert(xml_doc, gazebo_model_xml, enforce_limits, initial_xyz, initial_rpy, model_name, robot_namespace);
00094 }
00095 else if (xml_doc.FirstChild("model:physical"))
00096 {
00100 std::string open_bracket("<?");
00101 std::string close_bracket("?>");
00102 int pos1 = xml_string.find(open_bracket,0);
00103 int pos2 = xml_string.find(close_bracket,0);
00104 xml_string.replace(pos1,pos2-pos1+2,std::string(""));
00105
00106
00107 gazebo_model_xml.Parse(xml_string.c_str());
00108
00109
00110
00111
00112 TiXmlElement* model;
00113 model = gazebo_model_xml.FirstChildElement("model:physical");
00114 if (model)
00115 {
00116
00117
00118 TiXmlElement* xyz_key = model->FirstChildElement("xyz");
00119 if (xyz_key)
00120 model->RemoveChild(xyz_key);
00121 TiXmlElement* rpy_key = model->FirstChildElement("rpy");
00122 if (rpy_key)
00123 model->RemoveChild(rpy_key);
00124
00125 xyz_key = new TiXmlElement("xyz");
00126 rpy_key = new TiXmlElement("rpy");
00127
00128 std::ostringstream xyz_stream, rpy_stream;
00129 xyz_stream << initial_xyz.x << " " << initial_xyz.y << " " << initial_xyz.z;
00130 rpy_stream << initial_rpy.x << " " << initial_rpy.y << " " << initial_rpy.z;
00131
00132 TiXmlText* xyz_txt = new TiXmlText(xyz_stream.str());
00133 TiXmlText* rpy_txt = new TiXmlText(rpy_stream.str());
00134
00135 xyz_key->LinkEndChild(xyz_txt);
00136 rpy_key->LinkEndChild(rpy_txt);
00137
00138 model->LinkEndChild(xyz_key);
00139 model->LinkEndChild(rpy_key);
00140
00141
00142
00143 if (!model_name.empty())
00144 {
00145
00146 model->RemoveAttribute("name");
00147 model->SetAttribute("name",model_name);
00148 }
00149 else
00150 {
00151
00152 model_name = model->Attribute("name");
00153 }
00154
00155 }
00156
00157 }
00158 else
00159 {
00160 printf("Unable to determine XML type for writing to file\n");
00161 exit(3);
00162 }
00163 }
00164 namespace po = boost::program_options;
00165
00166 int main(int argc, char **argv)
00167 {
00168 ros::init(argc,argv,"gazebo_model",ros::init_options::AnonymousName);
00169
00170
00171 if (argc < 2)
00172 {
00173 usage(argv[0]);
00174 exit(1);
00175 }
00176
00177
00178 ros::NodeHandle nh_("~");
00179
00180 ros::ServiceClient spawn_model_srv_ = nh_.serviceClient<gazebo_plugins::SpawnModel>("/spawn_model");
00181 ros::ServiceClient delete_model_srv_ = nh_.serviceClient<gazebo_plugins::DeleteModel>("/delete_model");
00182
00183
00184
00185 double initial_x = 0;
00186 double initial_y = 0;
00187 double initial_z = 0;
00188 double initial_rx = 0;
00189 double initial_ry = 0;
00190 double initial_rz = 0;
00191
00192
00193 po::options_description v_desc("Allowed options");
00194 v_desc.add_options()
00195 ("help,h" , "produce this help message")
00196 ("param-name,p" , po::value<std::string>() , "Name of parameter on parameter server containing the model XML.")
00197 ("namespace,n" , po::value<std::string>() , "ROS namespace of the model spawned in simulation. If not specified, the namespace of this node is used.")
00198 ("input-filename,f" , po::value<std::string>() , "read input model from file, not from the parameter server, exclusive with -p option.")
00199 ("output-filename,o" , po::value<std::string>() , "write converted gazebo model xml to a file instead, model is not spawned in simulation.")
00200 ("skip-joint-limits,s" , "do not enforce joint limits during urdf-->gazebo conversion.")
00201 ("init-x,x" , po::value<double>() , "set initial x position of model, defaults to 0.")
00202 ("init-y,y" , po::value<double>() , "set initial y position of model, defaults to 0.")
00203 ("init-z,z" , po::value<double>() , "set initial z position of model, defaults to 0.")
00204 ("init-roll,R" , po::value<double>() , "set initial roll (rx) of model, defaults to 0. application orders are r-p-y.")
00205 ("init-pitch,P" , po::value<double>() , "set initial pitch (ry) of model, defaults to 0. application orders are r-p-y.")
00206 ("init-yaw,Y" , po::value<double>() , "set initial yaw (rz) of model, defaults to 0. application orders are r-p-y.");
00207
00208 po::options_description h_desc("Hidden options");
00209 h_desc.add_options()
00210 ("command" , po::value< std::vector<std::string> >(), "<spawn|kill>")
00211 ("model-name" , po::value< std::vector<std::string> >(), "overwrite name of the gazebo model in simulation. If not specified, the model name defaults to the name in urdf.");
00212
00213 po::options_description desc("Allowed options");
00214 desc.add(v_desc).add(h_desc);
00215
00216 po::positional_options_description p_desc;
00217 p_desc.add("command", 1);
00218 p_desc.add("model-name", 2);
00219
00220 po::variables_map vm;
00221
00222 po::store(po::command_line_parser(argc, argv).options(desc).positional(p_desc).run(), vm);
00223 po::notify(vm);
00224
00225 if (vm.count("help"))
00226 {
00227 usage(argv[0]);
00228 std::cout << v_desc << std::endl;
00229 exit(1);
00230 }
00231
00232
00233
00234 bool enforce_limits = true;
00235 if (vm.count("skip-joint-limits"))
00236 enforce_limits = false;
00237
00238
00239
00240 std::string file_in;
00241 if (vm.count("input-filename"))
00242 file_in = vm["input-filename"].as<std::string>();
00243 else
00244 file_in.clear();
00245
00246 std::string file_out;
00247 if (vm.count("output-filename"))
00248 {
00249 file_out = vm["output-filename"].as<std::string>();
00250 }
00251
00252 std::string robot_namespace;
00253 if (vm.count("namespace"))
00254 {
00255 robot_namespace = vm["namespace"].as<std::string>();
00256 }
00257 else
00258 {
00259 robot_namespace = ros::this_node::getNamespace();
00260 ROS_DEBUG("NOTE: %s is called under namespace %s, this namespace is passed to gazebo so all Gazebo plugins (e.g.ros_time, gazebo_mechanism_control,etc.) will start up under this namespace. User can overwrite by passing in argument -namespace, for example: %s /prf/robot_description -n /prf",argv[0],argv[0],robot_namespace.c_str());
00261 }
00262 ROS_DEBUG("namespace: %s",robot_namespace.c_str());
00263
00264
00265 if (vm.count("init-x"))
00266 {
00267 initial_x = vm["init-x"].as<double>();
00268 ROS_DEBUG("x: %f",initial_x);
00269 }
00270 if (vm.count("init-y"))
00271 {
00272 initial_y = vm["init-y"].as<double>();
00273 ROS_DEBUG("y: %f",initial_y);
00274 }
00275 if (vm.count("init-z"))
00276 {
00277 initial_z = vm["init-z"].as<double>();
00278 ROS_DEBUG("z: %f",initial_z);
00279 }
00280 if (vm.count("init-roll"))
00281 {
00282 initial_rx = vm["init-roll"].as<double>();
00283 ROS_DEBUG("init-roll: %f",initial_rx);
00284 }
00285 if (vm.count("init-pitch"))
00286 {
00287 initial_ry = vm["init-pitch"].as<double>();
00288 ROS_DEBUG("init-pitch: %f",initial_ry);
00289 }
00290 if (vm.count("init-yaw"))
00291 {
00292 initial_rz = vm["init-yaw"].as<double>();
00293 ROS_DEBUG("init-yaw: %f",initial_rz);
00294 }
00295
00296 std::string command;
00297 if (vm.count("command"))
00298 {
00299 std::vector<std::string> str_vec = vm["command"].as<std::vector<std::string> >();
00300 if (str_vec.size() == 1)
00301 command = str_vec[0];
00302 else
00303 command.clear();
00304 }
00305
00306 std::string param_name;
00307 if (vm.count("param-name"))
00308 {
00309 param_name = vm["param-name"].as<std::string>();
00310 if (!file_in.empty())
00311 {
00312 ROS_ERROR("Both param-name and input-filename are specified. Only one input source is allowed.\n");
00313 exit(2);
00314 }
00315 }
00316 else if (command == "spawn" && file_in.empty())
00317 {
00318 ROS_ERROR("Either param-name or input-filename must be specified for spawn to work. Need one input source.\n");
00319 exit(2);
00320 }
00321
00322
00323
00324 std::string model_name;
00325 if (vm.count("model-name"))
00326 {
00327 std::vector<std::string> str_vec = vm["model-name"].as<std::vector<std::string> >();
00328 if (str_vec.size() == 1)
00329 {
00330 model_name = str_vec[0];
00331
00332 std::replace(model_name.begin(),model_name.end(),'/','_');
00333 ROS_DEBUG("model name will be: %s",model_name.c_str());
00334 }
00335 else
00336 model_name.clear();
00337 }
00338
00339
00340
00341 urdf::Vector3 initial_xyz(initial_x,initial_y,initial_z);
00342 urdf::Vector3 initial_rpy(initial_rx,initial_ry,initial_rz);
00343
00344 if (command == "kill" && !model_name.empty())
00345 {
00346
00347
00348 delete_model_srv_.waitForExistence();
00349
00350 gazebo_plugins::DeleteModel model_msg;
00351 model_msg.request.model_name = model_name;
00352 if (delete_model_srv_.call(model_msg))
00353 ROS_INFO("successfully deleted model %s",model_name.c_str());
00354 else
00355 ROS_INFO("could not delete model %s",model_name.c_str());
00356 }
00357 else
00358 {
00359
00360 spawn_model_srv_.waitForExistence();
00361
00362
00363 gazebo_plugins::SpawnModel model_msg;
00364
00366 model_msg.request.model.model_name = model_name;
00367
00368
00369
00370
00371
00372 if (file_in.empty())
00373 {
00374
00375 std::string xml_string;
00376 std::string full_param_name;
00377 nh_.searchParam(param_name,full_param_name);
00378 nh_.getParam(full_param_name.c_str(),xml_string);
00379 ROS_DEBUG("%s content\n%s\n", full_param_name.c_str(), xml_string.c_str());
00380 if (xml_string.c_str()==NULL)
00381 {
00382 ROS_ERROR("Unable to load robot model from param server robot_description\n");
00383 exit(2);
00384 }
00385 else
00386 {
00387 model_msg.request.model.robot_model = xml_string;
00388 }
00389 }
00390 else
00391 {
00392
00393 TiXmlDocument xml_in(file_in);
00394 xml_in.LoadFile();
00395
00396 std::ostringstream stream;
00397 stream << xml_in;
00398 model_msg.request.model.robot_model = stream.str();
00399 }
00400
00401 getXMLType(model_msg.request.model.robot_model,model_msg.request.model.xml_type);
00402
00403
00404 if (command == "spawn" && file_out.empty())
00405 {
00406
00407 if (spawn_model_srv_.call(model_msg))
00408 ROS_INFO("successfull spawned model %s",model_name.c_str());
00409 else
00410 ROS_INFO("could not spawn model %s",model_name.c_str());
00411 }
00412 else if (!file_out.empty())
00413 {
00414
00415 TiXmlDocument gazebo_model_xml;
00416 convertToGazeboXML(model_msg.request.model.robot_model,gazebo_model_xml,enforce_limits,initial_xyz,initial_rpy,model_name,robot_namespace);
00417
00418 if (!gazebo_model_xml.SaveFile(file_out))
00419 {
00420 printf("Unable to save gazebo model in %s\n", file_out.c_str());
00421 exit(3);
00422 }
00423 }
00424 else
00425 {
00426 ROS_ERROR("command must be either spawn, kill or use -o option to do file conversion.");
00427 }
00428 }
00429
00430 return 0;
00431 }
00432