int main( int argc, char** argv ) { // initialize ROS ros::init(argc, argv, "lwr_hw_interface", ros::init_options::NoSigintHandler); // ros spinner ros::AsyncSpinner spinner(1); spinner.start(); // custom signal handlers signal(SIGTERM, quitRequested); signal(SIGINT, quitRequested); signal(SIGHUP, quitRequested); // create a node ros::NodeHandle lwr_nh; std::string robot_namespace = lwr_nh.getNamespace(); ROS_INFO("kuka_lwr_hw_rt_node -> **** node handle namespace = '%s'",robot_namespace.c_str()); // Remove the first two characters. std::string robot_namespace_param; int nb_char_to_remove = 2; robot_namespace_param = robot_namespace.substr(nb_char_to_remove,robot_namespace.size()-nb_char_to_remove); ROS_INFO("kuka_lwr_hw_rt_node -> **** node handle robot_namespace_param = '%s'",robot_namespace_param.c_str()); // If robot_namespace is "kuka_lwr_left" the Robot Hardware need to open the fri driver file contains in ros param : fri_driver_file_left // If robot_namespace is "kuka_lwr_right" the Robot Hardware need to open the fri driver file contains in ros param : fri_driver_file_right std::string file; if (robot_namespace.compare("//kuka_lwr_left") == 0) lwr_nh.param("/fri_driver_file_left", file, std::string("")); else lwr_nh.param("/fri_driver_file_right", file, std::string("")); ROS_INFO("fril node -> driver file = %s, namespace = %s",file.c_str(),robot_namespace_param.c_str()); // Get the the general robot description URDF XML from the parameter server // Be careful ! the 'robot_description' parameter is set inside a 'group' (a namespace) in the launch file. // so don't forget to concatenate the namespace ! std::string urdf_string = getURDF(lwr_nh, robot_namespace + "/robot_description"); // construct and start the real lwr lwr_hw::LWRHWFRIL lwr_robot; lwr_robot.create(robot_namespace_param, urdf_string); lwr_robot.setInitFile(file); if(!lwr_robot.init()) { ROS_FATAL_NAMED("lwr_hw","Could not initialize robot real interface"); return -1; } // timer variables struct timespec ts = {0, 0}; ros::Time last(ts.tv_sec, ts.tv_nsec), now(ts.tv_sec, ts.tv_nsec); ros::Duration period(1.0); ROS_INFO("Before controller_manager::ControllerManager !"); //the controller manager controller_manager::ControllerManager manager(&lwr_robot, lwr_nh); // run as fast as possible while( !g_quit ) { // get the time / period if (!clock_gettime(CLOCK_REALTIME, &ts)) { now.sec = ts.tv_sec; now.nsec = ts.tv_nsec; period = now - last; last = now; } else { ROS_FATAL("Failed to poll realtime clock!"); break; } // read the state from the lwr lwr_robot.read(now, period); // update the controllers manager.update(now, period); // write the command to the lwr lwr_robot.write(now, period); } std::cerr<<"Stopping spinner..."<<std::endl; spinner.stop(); std::cerr<<"Stopping LWR..."<<std::endl; lwr_robot.stop(); std::cerr<<"This node was killed!"<<std::endl; return 0; }
// Overloaded Gazebo entry point void GazeboRosControlPlugin::Load(gazebo::physics::ModelPtr parent, sdf::ElementPtr sdf) { ROS_INFO_STREAM_NAMED("gazebo_ros_control","Loading gazebo_ros_control plugin"); // Save pointers to the model parent_model_ = parent; sdf_ = sdf; // Error message if the model couldn't be found if (!parent_model_) { ROS_ERROR_STREAM_NAMED("loadThread","parent model is NULL"); return; } // Check that ROS has been initialized if(!ros::isInitialized()) { ROS_FATAL_STREAM_NAMED("gazebo_ros_control","A ROS node for Gazebo has not been initialized, unable to load plugin. " << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)"); return; } // Get namespace for nodehandle if(sdf_->HasElement("robotNamespace")) { robot_namespace_ = sdf_->GetElement("robotNamespace")->Get<std::string>(); } else { robot_namespace_ = parent_model_->GetName(); // default } // Get robot_description ROS param name if (sdf_->HasElement("robotParam")) { robot_description_ = sdf_->GetElement("robotParam")->Get<std::string>(); } else { robot_description_ = "robot_description"; // default } // Get the robot simulation interface type if(sdf_->HasElement("robotSimType")) { robot_hw_sim_type_str_ = sdf_->Get<std::string>("robotSimType"); } else { robot_hw_sim_type_str_ = "gazebo_ros_control/DefaultRobotHWSim"; ROS_DEBUG_STREAM_NAMED("loadThread","Using default plugin for RobotHWSim (none specified in URDF/SDF)\""<<robot_hw_sim_type_str_<<"\""); } // Get the Gazebo simulation period ros::Duration gazebo_period(parent_model_->GetWorld()->GetPhysicsEngine()->GetMaxStepSize()); // Decide the plugin control period if(sdf_->HasElement("controlPeriod")) { control_period_ = ros::Duration(sdf_->Get<double>("controlPeriod")); // Check the period against the simulation period if( control_period_ < gazebo_period ) { ROS_ERROR_STREAM_NAMED("gazebo_ros_control","Desired controller update period ("<<control_period_ <<" s) is faster than the gazebo simulation period ("<<gazebo_period<<" s)."); } else if( control_period_ > gazebo_period ) { ROS_WARN_STREAM_NAMED("gazebo_ros_control","Desired controller update period ("<<control_period_ <<" s) is slower than the gazebo simulation period ("<<gazebo_period<<" s)."); } } else { control_period_ = gazebo_period; ROS_DEBUG_STREAM_NAMED("gazebo_ros_control","Control period not found in URDF/SDF, defaulting to Gazebo period of " << control_period_); } // Get parameters/settings for controllers from ROS param server model_nh_ = ros::NodeHandle(robot_namespace_); // Initialize the emergency stop code. e_stop_active_ = false; last_e_stop_active_ = false; if (sdf_->HasElement("eStopTopic")) { const std::string e_stop_topic = sdf_->GetElement("eStopTopic")->Get<std::string>(); e_stop_sub_ = model_nh_.subscribe(e_stop_topic, 1, &GazeboRosControlPlugin::eStopCB, this); } ROS_INFO_NAMED("gazebo_ros_control", "Starting gazebo_ros_control plugin in namespace: %s", robot_namespace_.c_str()); // Read urdf from ros parameter server then // setup actuators and mechanism control node. // This call will block if ROS is not properly initialized. const std::string urdf_string = getURDF(robot_description_); if (!parseTransmissionsFromURDF(urdf_string)) { ROS_ERROR_NAMED("gazebo_ros_control", "Error parsing URDF in gazebo_ros_control plugin, plugin not active.\n"); return; } // Load the RobotHWSim abstraction to interface the controllers with the gazebo model try { robot_hw_sim_loader_.reset (new pluginlib::ClassLoader<gazebo_ros_control::RobotHWSim> ("gazebo_ros_control", "gazebo_ros_control::RobotHWSim")); robot_hw_sim_ = robot_hw_sim_loader_->createInstance(robot_hw_sim_type_str_); urdf::Model urdf_model; const urdf::Model *const urdf_model_ptr = urdf_model.initString(urdf_string) ? &urdf_model : NULL; if(!robot_hw_sim_->initSim(robot_namespace_, model_nh_, parent_model_, urdf_model_ptr, transmissions_)) { ROS_FATAL_NAMED("gazebo_ros_control","Could not initialize robot simulation interface"); return; } // Create the controller manager ROS_DEBUG_STREAM_NAMED("ros_control_plugin","Loading controller_manager"); controller_manager_.reset (new controller_manager::ControllerManager(robot_hw_sim_.get(), model_nh_)); // Listen to the update event. This event is broadcast every simulation iteration. update_connection_ = gazebo::event::Events::ConnectWorldUpdateBegin (boost::bind(&GazeboRosControlPlugin::Update, this)); } catch(pluginlib::LibraryLoadException &ex) { ROS_FATAL_STREAM_NAMED("gazebo_ros_control","Failed to create robot simulation interface loader: "<<ex.what()); } ROS_INFO_NAMED("gazebo_ros_control", "Loaded gazebo_ros_control."); }
bool loadControllerManagerFromURDF() { std::string urdf_string = getURDF(robot_description_); // initialize TiXmlDocument doc with a string TiXmlDocument doc; if (!doc.Parse(urdf_string.c_str()) && doc.Error()) { ROS_ERROR("Could not load the gazebo_ros_control plugin's" " configuration file: %s\n", urdf_string.c_str()); return false; } // debug //doc.Print(); //std::cout << *(doc.RootElement()) << std::endl; /* THIS IS USEFUL BUT NOT FOR NOW // Pulls out the list of actuators used in the robot configuration. struct GetActuators : public TiXmlVisitor { std::set<std::string> actuators; virtual bool VisitEnter(const TiXmlElement &elt, const TiXmlAttribute *) { if (elt.ValueStr() == std::string("actuator") && elt.Attribute("name")) actuators.insert(elt.Attribute("name")); else if (elt.ValueStr() == std::string("rightActuator") && elt.Attribute("name")) actuators.insert(elt.Attribute("name")); else if (elt.ValueStr() == std::string("leftActuator") && elt.Attribute("name")) actuators.insert(elt.Attribute("name")); return true; } } get_actuators; doc.RootElement()->Accept(&get_actuators); // Places the found actuators into the hardware interface. std::set<std::string>::iterator it; for (it = get_actuators.actuators.begin(); it != get_actuators.actuators.end(); ++it) { std::cout << " adding actuator " << (*it) << std::endl; //pr2_hardware_interface::Actuator* pr2_actuator = // new pr2_hardware_interface::Actuator(*it); //pr2_actuator->state_.is_enabled_ = true; //hardware_interface_.addActuator(pr2_actuator); } // Find joints in transmission tags TiXmlElement *root = doc.RootElement(); // Constructs the transmissions by parsing custom xml. TiXmlElement *xit = NULL; for (xit = root->FirstChildElement("transmission"); xit; xit = xit->NextSiblingElement("transmission")) { // Get <transmission type=""> property std::string type(xit->Attribute("type")); // \todo error check this? Transmission *t = NULL; try { // Backwards compatibility for using non-namespaced controller types if (!transmission_loader_->isClassAvailable(type)) { std::vector<std::string> classes = transmission_loader_->getDeclaredClasses(); for(unsigned int i = 0; i < classes.size(); ++i) { if(type == transmission_loader_->getName(classes[i])) { ROS_WARN("The deprecated transmission type %s was not found. Using the namespaced version %s instead. " "Please update your urdf file to use the namespaced version.", type.c_str(), classes[i].c_str()); type = classes[i]; break; } } } t = transmission_loader_->createClassInstance(type); } catch (const std::runtime_error &ex) { ROS_ERROR("Could not load class %s: %s", type.c_str(), ex.what()); } if (!t) ROS_ERROR("Unknown transmission type: %s", type.c_str()); else if (!t->initXml(xit, this)){ ROS_ERROR("Failed to initialize transmission"); delete t; } else // Success! transmissions_.push_back(t); } */ return true; }