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 <boost/array.hpp>
00036 #include <boost/bind.hpp>
00037 #include <boost/date_time/posix_time/posix_time_types.hpp>
00038 
00039 #include <angles/angles.h>
00040 
00041 #include <tinyxml.h>
00042 
00043 #include <kuka_eki_hw_interface/kuka_eki_hw_interface.h>
00044 
00045 
00046 namespace kuka_eki_hw_interface
00047 {
00048 
00049 KukaEkiHardwareInterface::KukaEkiHardwareInterface() : joint_position_(n_dof_, 0.0), joint_velocity_(n_dof_, 0.0),
00050     joint_effort_(n_dof_, 0.0), joint_position_command_(n_dof_, 0.0), joint_names_(n_dof_), deadline_(ios_),
00051     eki_server_socket_(ios_, boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(), 0))
00052 {
00053 
00054 }
00055 
00056 
00057 KukaEkiHardwareInterface::~KukaEkiHardwareInterface() {}
00058 
00059 
00060 void KukaEkiHardwareInterface::eki_check_read_state_deadline()
00061 {
00062   
00063   if (deadline_.expires_at() <= boost::asio::deadline_timer::traits_type::now())
00064   {
00065     eki_server_socket_.cancel();
00066     deadline_.expires_at(boost::posix_time::pos_infin);
00067   }
00068 
00069   
00070   deadline_.async_wait(boost::bind(&KukaEkiHardwareInterface::eki_check_read_state_deadline, this));
00071 }
00072 
00073 
00074 void KukaEkiHardwareInterface::eki_handle_receive(const boost::system::error_code &ec, size_t length,
00075                                                   boost::system::error_code* out_ec, size_t* out_length)
00076 {
00077   *out_ec = ec;
00078   *out_length = length;
00079 }
00080 
00081 
00082 bool KukaEkiHardwareInterface::eki_read_state(std::vector<double> &joint_position,
00083                                               std::vector<double> &joint_velocity,
00084                                               std::vector<double> &joint_effort,
00085                                               int &cmd_buff_len)
00086 {
00087   static boost::array<char, 2048> in_buffer;
00088 
00089   
00090   
00091   deadline_.expires_from_now(boost::posix_time::seconds(eki_read_state_timeout_));  
00092   boost::system::error_code ec = boost::asio::error::would_block;
00093   size_t len = 0;
00094   eki_server_socket_.async_receive(boost::asio::buffer(in_buffer),
00095                                    boost::bind(&KukaEkiHardwareInterface::eki_handle_receive, _1, _2, &ec, &len));
00096   do
00097     ios_.run_one();
00098   while (ec == boost::asio::error::would_block);
00099   if (ec)
00100     return false;
00101 
00102   
00103   if (len == 0)
00104     return false;
00105 
00106   
00107   TiXmlDocument xml_in;
00108   in_buffer[len] = '\0';  
00109   xml_in.Parse(in_buffer.data());
00110   TiXmlElement* robot_state = xml_in.FirstChildElement("RobotState");
00111   if (!robot_state)
00112     return false;
00113   TiXmlElement* pos = robot_state->FirstChildElement("Pos");
00114   TiXmlElement* vel = robot_state->FirstChildElement("Vel");
00115   TiXmlElement* eff = robot_state->FirstChildElement("Eff");
00116   TiXmlElement* robot_command = robot_state->FirstChildElement("RobotCommand");
00117   if (!pos || !vel || !eff || !robot_command)
00118     return false;
00119 
00120   
00121   double joint_pos;  
00122   double joint_vel;  
00123   double joint_eff;  
00124   char axis_name[] = "A1";
00125   for (int i = 0; i < n_dof_; ++i)
00126   {
00127     pos->Attribute(axis_name, &joint_pos);
00128     joint_position[i] = angles::from_degrees(joint_pos);  
00129     vel->Attribute(axis_name, &joint_vel);
00130     joint_velocity[i] = joint_vel;
00131     eff->Attribute(axis_name, &joint_eff);
00132     joint_effort[i] = joint_eff;
00133     axis_name[1]++;
00134   }
00135 
00136   
00137   robot_command->Attribute("Size", &cmd_buff_len);
00138 
00139   return true;
00140 }
00141 
00142 
00143 bool KukaEkiHardwareInterface::eki_write_command(const std::vector<double> &joint_position_command)
00144 {
00145   TiXmlDocument xml_out;
00146   TiXmlElement* robot_command = new TiXmlElement("RobotCommand");
00147   TiXmlElement* pos = new TiXmlElement("Pos");
00148   TiXmlText* empty_text = new TiXmlText("");
00149   robot_command->LinkEndChild(pos);
00150   pos->LinkEndChild(empty_text);   
00151   char axis_name[] = "A1";
00152   for (int i = 0; i < n_dof_; ++i)
00153   {
00154     pos->SetAttribute(axis_name, std::to_string(angles::to_degrees(joint_position_command[i])).c_str());
00155     axis_name[1]++;
00156   }
00157   xml_out.LinkEndChild(robot_command);
00158 
00159   TiXmlPrinter xml_printer;
00160   xml_printer.SetStreamPrinting();  
00161   xml_out.Accept(&xml_printer);
00162 
00163   size_t len = eki_server_socket_.send_to(boost::asio::buffer(xml_printer.CStr(), xml_printer.Size()),
00164                                           eki_server_endpoint_);
00165 
00166   return true;
00167 }
00168 
00169 
00170 void KukaEkiHardwareInterface::init()
00171 {
00172   
00173   if (!nh_.getParam("controller_joint_names", joint_names_))
00174   {
00175     ROS_ERROR("Cannot find required parameter 'controller_joint_names' on the parameter server.");
00176     throw std::runtime_error("Cannot find required parameter 'controller_joint_names' on the parameter server.");
00177   }
00178 
00179   
00180   const std::string param_addr = "eki/robot_address";
00181   const std::string param_port = "eki/robot_port";
00182   const std::string param_socket_timeout = "eki/socket_timeout";
00183   const std::string param_max_cmd_buf_len = "eki/max_cmd_buf_len";
00184 
00185   if (nh_.getParam(param_addr, eki_server_address_) &&
00186       nh_.getParam(param_port, eki_server_port_))
00187   {
00188     ROS_INFO_STREAM_NAMED("kuka_eki_hw_interface", "Configuring Kuka EKI hardware interface on: "
00189                           << eki_server_address_ << ", " << eki_server_port_);
00190   }
00191   else
00192   {
00193     std::string msg = "Failed to get EKI address/port from parameter server (looking for '" + param_addr +
00194                       "', '" + param_port + "')";
00195     ROS_ERROR_STREAM(msg);
00196     throw std::runtime_error(msg);
00197   }
00198 
00199   if (nh_.getParam(param_socket_timeout, eki_read_state_timeout_))
00200   {
00201     ROS_INFO_STREAM_NAMED("kuka_eki_hw_interface", "Configuring Kuka EKI hardware interface socket timeout to "
00202                           << eki_read_state_timeout_ << " seconds");
00203   }
00204   else
00205   {
00206     ROS_INFO_STREAM_NAMED("kuka_eki_hw_interface", "Failed to get EKI socket timeout from parameter server (looking "
00207                           "for '" + param_socket_timeout + "'), defaulting to " +
00208                           std::to_string(eki_read_state_timeout_)  + " seconds");
00209   }
00210 
00211   if (nh_.getParam(param_max_cmd_buf_len, eki_max_cmd_buff_len_))
00212   {
00213     ROS_INFO_STREAM_NAMED("kuka_eki_hw_interface", "Configuring Kuka EKI hardware interface maximum command buffer "
00214                           "length to " << eki_max_cmd_buff_len_);
00215   }
00216   else
00217   {
00218     ROS_INFO_STREAM_NAMED("kuka_eki_hw_interface", "Failed to get EKI hardware interface maximum command buffer length "
00219                           "from parameter server (looking for '" + param_max_cmd_buf_len + "'), defaulting to " +
00220                           std::to_string(eki_max_cmd_buff_len_));
00221   }
00222 
00223   
00224   for (std::size_t i = 0; i < n_dof_; ++i)
00225   {
00226     
00227     joint_state_interface_.registerHandle(
00228         hardware_interface::JointStateHandle(joint_names_[i], &joint_position_[i], &joint_velocity_[i],
00229                                              &joint_effort_[i]));
00230 
00231     
00232     position_joint_interface_.registerHandle(
00233         hardware_interface::JointHandle(joint_state_interface_.getHandle(joint_names_[i]),
00234                                         &joint_position_command_[i]));
00235   }
00236 
00237   
00238   registerInterface(&joint_state_interface_);
00239   registerInterface(&position_joint_interface_);
00240 
00241   ROS_INFO_STREAM_NAMED("kukw_eki_hw_interface", "Loaded Kuka EKI hardware interface");
00242 }
00243 
00244 
00245 void KukaEkiHardwareInterface::start()
00246 {
00247   ROS_INFO_NAMED("kuka_eki_hw_interface", "Starting Kuka EKI hardware interface...");
00248 
00249   
00250   ROS_INFO_NAMED("kuka_eki_hw_interface", "... connecting to robot's EKI server...");
00251   boost::asio::ip::udp::resolver resolver(ios_);
00252   eki_server_endpoint_ = *resolver.resolve({boost::asio::ip::udp::v4(), eki_server_address_, eki_server_port_});
00253   boost::array<char, 1> ini_buf = { 0 };
00254   eki_server_socket_.send_to(boost::asio::buffer(ini_buf), eki_server_endpoint_);  
00255 
00256   
00257   deadline_.expires_at(boost::posix_time::pos_infin);  
00258   eki_check_read_state_deadline();
00259 
00260   
00261   if (!eki_read_state(joint_position_, joint_velocity_, joint_effort_, eki_cmd_buff_len_))
00262   {
00263     std::string msg = "Failed to read from robot EKI server within alloted time of "
00264                       + std::to_string(eki_read_state_timeout_) + " seconds.  Make sure eki_hw_interface is running "
00265                       "on the robot controller and all configurations are correct.";
00266     ROS_ERROR_STREAM(msg);
00267     throw std::runtime_error(msg);
00268   }
00269   joint_position_command_ = joint_position_;
00270 
00271   ROS_INFO_NAMED("kuka_eki_hw_interface", "... done. EKI hardware interface started!");
00272 }
00273 
00274 
00275 void KukaEkiHardwareInterface::read(const ros::Time &time, const ros::Duration &period)
00276 {
00277   if (!eki_read_state(joint_position_, joint_velocity_, joint_effort_, eki_cmd_buff_len_))
00278   {
00279     std::string msg = "Failed to read from robot EKI server within alloted time of "
00280                       + std::to_string(eki_read_state_timeout_) + " seconds.  Make sure eki_hw_interface is running "
00281                       "on the robot controller and all configurations are correct.";
00282     ROS_ERROR_STREAM(msg);
00283     throw std::runtime_error(msg);
00284   }
00285 }
00286 
00287 
00288 void KukaEkiHardwareInterface::write(const ros::Time &time, const ros::Duration &period)
00289 {
00290   
00291   if (eki_cmd_buff_len_ < eki_max_cmd_buff_len_)
00292     eki_write_command(joint_position_command_);
00293 
00294   
00295   
00296   
00297   
00298   
00299   
00300   
00301   
00302   
00303 }
00304 
00305 }