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 #include <algorithm>
00030 #include <assert.h>
00031
00032 #include <tinyxml/tinyxml.h>
00033
00034 #include <gazebo_plugins/gazebo_ros_factory.h>
00035 #include <gazebo_tools/urdf2gazebo.h>
00036
00037 #include <gazebo/Global.hh>
00038 #include <gazebo/XMLConfig.hh>
00039 #include <gazebo/gazebo.h>
00040 #include <gazebo/GazeboError.hh>
00041 #include <gazebo/ControllerFactory.hh>
00042 #include <gazebo/Simulator.hh>
00043
00044 #include <boost/thread/recursive_mutex.hpp>
00045
00046 using namespace gazebo;
00047
00048 GZ_REGISTER_DYNAMIC_CONTROLLER("gazebo_ros_factory", GazeboRosFactory);
00049
00051
00052 GazeboRosFactory::GazeboRosFactory(Entity *parent)
00053 : Controller(parent)
00054 {
00055
00056 this->myParent = dynamic_cast<Model*>(this->parent);
00057
00058 if (!this->myParent)
00059 gzthrow("GazeboRosFactory controller requires a Model as its parent");
00060
00061 Param::Begin(&this->parameters);
00062 this->robotNamespaceP = new ParamT<std::string>("robotNamespace", "/", 0);
00063 this->spawnModelServiceNameP = new ParamT<std::string>("spawnModelServiceName","spawn_model", 0);
00064 this->deleteModelServiceNameP = new ParamT<std::string>("deleteModelServiceName","delete_model", 0);
00065 Param::End();
00066 }
00067
00069
00070 GazeboRosFactory::~GazeboRosFactory()
00071 {
00072 delete this->robotNamespaceP;
00073 delete this->spawnModelServiceNameP;
00074 delete this->deleteModelServiceNameP;
00075 }
00076
00078
00079 void GazeboRosFactory::LoadChild(XMLConfigNode *node)
00080 {
00081 this->robotNamespaceP->Load(node);
00082 this->robotNamespace = this->robotNamespaceP->GetValue();
00083 if (!ros::isInitialized())
00084 {
00085 int argc = 0;
00086 char** argv = NULL;
00087 ros::init(argc,argv,"gazebo",ros::init_options::NoSigintHandler|ros::init_options::AnonymousName);
00088 }
00089
00090 this->rosnode_ = new ros::NodeHandle(this->robotNamespace);
00091
00092 this->spawnModelServiceNameP->Load(node);
00093 this->spawnModelServiceName = this->spawnModelServiceNameP->GetValue();
00094
00095 ros::AdvertiseServiceOptions spawn_aso = ros::AdvertiseServiceOptions::create<gazebo_plugins::SpawnModel>(
00096 this->spawnModelServiceName,boost::bind( &GazeboRosFactory::spawnModel, this, _1, _2 ), ros::VoidPtr(), &this->factory_queue_);
00097 this->spawnModelService = this->rosnode_->advertiseService(spawn_aso);
00098
00099 this->deleteModelServiceNameP->Load(node);
00100 this->deleteModelServiceName = this->deleteModelServiceNameP->GetValue();
00101
00102 ros::AdvertiseServiceOptions delete_aso = ros::AdvertiseServiceOptions::create<gazebo_plugins::DeleteModel>(
00103 this->deleteModelServiceName,boost::bind( &GazeboRosFactory::deleteModel, this, _1, _2 ), ros::VoidPtr(), &this->factory_queue_);
00104 this->deleteModelService = this->rosnode_->advertiseService(delete_aso);
00105 }
00106
00108
00109 bool GazeboRosFactory::IsURDF(std::string robot_model)
00110 {
00111 TiXmlDocument doc_in;
00112 doc_in.Parse(robot_model.c_str());
00113 if (doc_in.FirstChild("robot"))
00114 return true;
00115 else
00116 return false;
00117 }
00118
00120
00121 bool GazeboRosFactory::IsGazeboModelXML(std::string robot_model)
00122 {
00123 TiXmlDocument doc_in;
00124 doc_in.Parse(robot_model.c_str());
00125 if (doc_in.FirstChild("model:physical"))
00126 return true;
00127 else
00128 return false;
00129 }
00131
00132 bool GazeboRosFactory::deleteModel(gazebo_plugins::DeleteModel::Request &req,
00133 gazebo_plugins::DeleteModel::Response &res)
00134 {
00135 if (!this->pushToDeleteQueue(req.model_name))
00136 {
00137 ROS_ERROR("Failed to push robot model to deletion queue iface");
00138 return 0;
00139 }
00140
00141
00142 while (gazebo::World::Instance()->GetEntityByName(req.model_name))
00143 {
00144 ROS_DEBUG("Waiting for model deletion (%s)",req.model_name.c_str());
00145 usleep(1000);
00146 }
00147
00148
00149 res.success = true;
00150 res.status_message = std::string("successfully deleted robot");
00151
00152 return 1;
00153 }
00154
00156
00157 bool GazeboRosFactory::spawnModel(gazebo_plugins::SpawnModel::Request &req,
00158 gazebo_plugins::SpawnModel::Response &res)
00159 {
00160
00161 std::string model_name = req.model.model_name;
00162 if (gazebo::World::Instance()->GetEntityByName(model_name))
00163 {
00164 ROS_ERROR("model name %s already exist.",model_name.c_str());
00165 return 0;
00166 }
00167
00168
00169 std::string robot_namespace = req.model.robot_namespace;
00170
00171
00172
00173
00174
00175
00176
00177 std::string robot_model = req.model.robot_model;
00178 bool convert_urdf2gazebo = false;
00179 if (req.model.xml_type == req.model.URDF)
00180 {
00181
00182
00183 if (this->IsURDF(robot_model))
00184 {
00185 convert_urdf2gazebo = true;
00186 }
00187 else
00188 {
00189 ROS_ERROR("input xml type does not match xml_type in request: input URDF XML must begin with <robot>");
00190 return 0;
00191 }
00192 }
00193 else if (req.model.xml_type == req.model.GAZEBO_XML)
00194 {
00195
00196
00197 if (this->IsGazeboModelXML(robot_model))
00198 {
00199 convert_urdf2gazebo = false;
00200 }
00201 else
00202 {
00203 ROS_ERROR(" input Gazebo Model XML must begin with <model:physical>\n");
00204 return 0;
00205 }
00206
00207 }
00208 else if (req.model.xml_type == req.model.URDF_PARAM_NAME)
00209 {
00210
00211
00212 std::string full_param_name;
00213 if (rosnode_->searchParam(robot_model,full_param_name))
00214 rosnode_->getParam(full_param_name.c_str(),robot_model);
00215 else
00216 rosnode_->getParam(robot_model,robot_model);
00217
00218 convert_urdf2gazebo = true;
00219
00220 if (robot_model.c_str()==NULL)
00221 {
00222 ROS_ERROR("Unable to load robot model from param server robot_description\n");
00223 return 0;
00224 }
00225 else if (!this->IsURDF(robot_model))
00226 {
00227 ROS_ERROR("input xml type does not match xml_type in request: input URDF PARAM XML must begin with <robot>");
00228 return 0;
00229 }
00230 }
00231 else if (req.model.xml_type == req.model.GAZEBO_XML_PARAM_NAME)
00232 {
00233
00234
00235 std::string full_param_name;
00236 rosnode_->searchParam(robot_model,full_param_name);
00237 rosnode_->getParam(full_param_name.c_str(),robot_model);
00238
00239 convert_urdf2gazebo = false;
00240
00241 if (robot_model.c_str()==NULL)
00242 {
00243 ROS_ERROR("Unable to load robot model from param server robot_description\n");
00244 return 0;
00245 }
00246 else if (!this->IsGazeboModelXML(robot_model))
00247 {
00248 ROS_ERROR("input Gazebo Model PARAM XML must begin with <model:physical>\n");
00249 return 0;
00250 }
00251 }
00252 else if (req.model.xml_type == req.model.URDF_FILE_NAME)
00253 {
00254
00255
00256 ROS_WARN("spawning from resource_retriever using a URDF filename is not supported right now");
00257
00258 TiXmlDocument robot_model_xml(robot_model);
00259 robot_model_xml.LoadFile();
00260
00261 std::ostringstream stream;
00262 stream << robot_model_xml;
00263 robot_model = stream.str();
00264 convert_urdf2gazebo = true;
00265
00266 if (robot_model.c_str()==NULL)
00267 {
00268 ROS_ERROR("Unable to load robot model from param server robot_description\n");
00269 return 0;
00270 }
00271 else if (!this->IsURDF(robot_model))
00272 {
00273 ROS_ERROR("input xml type does not match xml_type in request: input URDF XML FILE must begin with <robot>");
00274 return 0;
00275 }
00276 }
00277 else if (req.model.xml_type == req.model.GAZEBO_XML_FILE_NAME)
00278 {
00279
00280
00281 ROS_WARN("spawning from resource_retriever using a Gazebo Model XML filename is not supported right now");
00282
00283 TiXmlDocument robot_model_xml(robot_model);
00284 robot_model_xml.LoadFile();
00285
00286 std::ostringstream stream;
00287 stream << robot_model_xml;
00288 robot_model = stream.str();
00289 convert_urdf2gazebo = false;
00290
00291 if (robot_model.c_str()==NULL)
00292 {
00293 ROS_ERROR("Unable to load robot model from param server robot_description\n");
00294 return 0;
00295 }
00296 else if (!this->IsGazeboModelXML(robot_model))
00297 {
00298 ROS_ERROR("input Gazebo Model XML FILE must begin with <model:physical>\n");
00299 return 0;
00300 }
00301 }
00302 else
00303 {
00304 ROS_ERROR("type of robot model to be spawned is incorrect, options are:(URDF,GAZEBO_XML,URDF_PARAM_NAME,GAZEBO_XML_PARAM_NAME)");
00305 return 0;
00306 }
00307
00308
00309
00310 double initial_x = req.model.initial_pose.position.x;
00311 double initial_y = req.model.initial_pose.position.y;
00312 double initial_z = req.model.initial_pose.position.z;
00313 urdf::Vector3 initial_xyz(initial_x,initial_y,initial_z);
00314
00315 urdf::Rotation initial_q(req.model.initial_pose.orientation.x,req.model.initial_pose.orientation.y,req.model.initial_pose.orientation.z,req.model.initial_pose.orientation.w);
00316 double initial_rx,initial_ry,initial_rz;
00317 initial_q.getRPY(initial_rx,initial_ry,initial_rz);
00318 urdf::Vector3 initial_rpy(initial_rx*180/M_PI,initial_ry*180/M_PI,initial_rz*180/M_PI);
00319
00320 bool disable_urdf_joint_limits = req.model.disable_urdf_joint_limits;
00321
00322
00323 urdf2gazebo::URDF2Gazebo u2g;
00324 TiXmlDocument gazebo_model_xml;
00325 if (convert_urdf2gazebo)
00326 {
00327
00328
00329
00330 TiXmlDocument robot_model_xml;
00331 robot_model_xml.Parse(robot_model.c_str());
00332 u2g.convert(robot_model_xml, gazebo_model_xml, disable_urdf_joint_limits, initial_xyz, initial_rpy, model_name, robot_namespace);
00333 }
00334 else
00335 {
00336
00337
00338
00339
00343 std::string open_bracket("<?");
00344 std::string close_bracket("?>");
00345 int pos1 = robot_model.find(open_bracket,0);
00346 int pos2 = robot_model.find(close_bracket,0);
00347 robot_model.replace(pos1,pos2-pos1+2,std::string(""));
00348
00349
00350 gazebo_model_xml.Parse(robot_model.c_str());
00351
00352
00353
00354
00355 TiXmlElement* model;
00356 model = gazebo_model_xml.FirstChildElement("model:physical");
00357 if (model)
00358 {
00359
00360
00361 TiXmlElement* xyz_key = model->FirstChildElement("xyz");
00362 if (xyz_key)
00363 model->RemoveChild(xyz_key);
00364 TiXmlElement* rpy_key = model->FirstChildElement("rpy");
00365 if (rpy_key)
00366 model->RemoveChild(rpy_key);
00367
00368 xyz_key = new TiXmlElement("xyz");
00369 rpy_key = new TiXmlElement("rpy");
00370
00371 std::ostringstream xyz_stream, rpy_stream;
00372 xyz_stream << initial_x << " " << initial_y << " " << initial_z;
00373 rpy_stream << initial_rx << " " << initial_ry << " " << initial_rz;
00374
00375 TiXmlText* xyz_txt = new TiXmlText(xyz_stream.str());
00376 TiXmlText* rpy_txt = new TiXmlText(rpy_stream.str());
00377
00378 xyz_key->LinkEndChild(xyz_txt);
00379 rpy_key->LinkEndChild(rpy_txt);
00380
00381 model->LinkEndChild(xyz_key);
00382 model->LinkEndChild(rpy_key);
00383
00384
00385
00386 if (!model_name.empty())
00387 {
00388 model->RemoveAttribute("name");
00389 model->SetAttribute("name",model_name);
00390 }
00391
00392 }
00393 }
00394
00395
00396 std::ostringstream stream;
00397 stream << gazebo_model_xml;
00398 std::string gazebo_model_xml_string = stream.str();
00399 ROS_DEBUG("Gazebo Model XML\n\n%s\n\n ",gazebo_model_xml_string.c_str());
00400
00401 if (!this->pushToFactory(gazebo_model_xml_string))
00402 {
00403 ROS_ERROR("Failed to push robot model to factory iface");
00404 return 0;
00405 }
00406
00407
00408 while (true)
00409 {
00410 boost::recursive_mutex::scoped_lock lock(*gazebo::Simulator::Instance()->GetMRMutex());
00411 if (gazebo::World::Instance()->GetEntityByName(model_name)) break;
00412 ROS_DEBUG("Waiting for spawning model (%s)",model_name.c_str());
00413 usleep(1000);
00414 }
00415
00416
00417 res.success = true;
00418 res.status_message = std::string("successfully spawned robot");
00419
00420 return 1;
00421 }
00422
00424
00425 bool GazeboRosFactory::pushToFactory(std::string gazebo_model_xml)
00426 {
00427
00428
00429
00430 libgazebo::Client *client = new libgazebo::Client();
00431 libgazebo::FactoryIface *factoryIface = new libgazebo::FactoryIface();
00432
00433 int serverId = 0;
00434
00435 bool connected_to_server = false;
00437 while (!connected_to_server)
00438 {
00439 try
00440 {
00441 ROS_DEBUG("spawn_gazebo_model waiting for gazebo factory, usually launched by 'roslaunch `rospack find gazebo_worlds`/launch/empty_world.launch'");
00442 client->ConnectWait(serverId, GZ_CLIENT_ID_USER_FIRST);
00443 connected_to_server = true;
00444 }
00445 catch (gazebo::GazeboError e)
00446 {
00447 ROS_ERROR("Gazebo error: Unable to connect\n %s\n",e.GetErrorStr().c_str());
00448 usleep(1000);
00449 connected_to_server = false;
00450 }
00451 }
00452
00453
00454
00455
00456 try
00457 {
00458 factoryIface->Open(client, "default");
00459 }
00460 catch (gazebo::GazeboError e)
00461 {
00462 ROS_ERROR("Gazebo error: Unable to connect to the factory interface\n%s\n",e.GetErrorStr().c_str());
00463 return false;
00464 }
00465
00466
00467
00468
00469 std::ostringstream stream;
00470 stream << gazebo_model_xml;
00471 std::string gazebo_model_xml_string = stream.str();
00472 ROS_DEBUG("Gazebo Model XML\n\n%s\n\n ",gazebo_model_xml_string.c_str());
00473
00474 bool writing_iface = true;
00475 while (writing_iface)
00476 {
00477 factoryIface->Lock(1);
00478 if (strcmp((char*)factoryIface->data->newModel,"")==0)
00479 {
00480
00481 strcpy((char*)factoryIface->data->newModel, gazebo_model_xml_string.c_str());
00482 writing_iface = false;
00483 }
00484 factoryIface->Unlock();
00485 }
00486 return true;
00487 }
00489
00490 bool GazeboRosFactory::pushToDeleteQueue(std::string model_name)
00491 {
00492
00493 libgazebo::Client *client = new libgazebo::Client();
00494 libgazebo::FactoryIface *factoryIface = new libgazebo::FactoryIface();
00495
00496 int serverId = 0;
00497
00498 bool connected_to_server = false;
00500 while (!connected_to_server)
00501 {
00502 try
00503 {
00504 client->ConnectWait(serverId, GZ_CLIENT_ID_USER_FIRST);
00505 connected_to_server = true;
00506 }
00507 catch (gazebo::GazeboError e)
00508 {
00509 ROS_ERROR("Gazebo error: Unable to connect\n %s\n",e.GetErrorStr().c_str());
00510 usleep(1000);
00511 connected_to_server = false;
00512 }
00513 }
00514
00516 try
00517 {
00518 factoryIface->Open(client, "default");
00519 }
00520 catch (gazebo::GazeboError e)
00521 {
00522 ROS_ERROR("Gazebo error: Unable to connect to the factory interface\n%s\n",e.GetErrorStr().c_str());
00523 return -1;
00524 }
00525
00526 bool writing_iface = true;
00527 while (writing_iface)
00528 {
00529 factoryIface->Lock(1);
00530 if (strcmp((char*)factoryIface->data->deleteEntity,"")==0)
00531 {
00532 ROS_INFO("Deleting Robot Model Name:%s in Gazebo\n",model_name.c_str());
00533
00534 strcpy((char*)factoryIface->data->deleteEntity, model_name.c_str());
00535 writing_iface = false;
00536 }
00537 factoryIface->Unlock();
00538 }
00539
00540 return true;
00541
00542 }
00544
00545 void GazeboRosFactory::InitChild()
00546 {
00547
00548 this->callback_queue_thread_ = boost::thread( boost::bind( &GazeboRosFactory::FactoryQueueThread,this ) );
00549 }
00550
00552
00553 void GazeboRosFactory::UpdateChild()
00554 {
00555
00556
00557
00558
00559
00560 }
00561
00563
00564 void GazeboRosFactory::FiniChild()
00565 {
00566 this->factory_queue_.disable();
00567 this->factory_queue_.clear();
00568 this->rosnode_->shutdown();
00569 this->callback_queue_thread_.join();
00570 }
00571
00573
00574 void GazeboRosFactory::FactoryQueueThread()
00575 {
00576 ROS_DEBUG_STREAM("Callback thread id=" << boost::this_thread::get_id());
00577
00578 static const double timeout = 0.01;
00579
00580 while (this->rosnode_->ok())
00581 {
00582 this->factory_queue_.callAvailable(ros::WallDuration(timeout));
00583 }
00584 }
00585