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 }