KukaDriver.hpp
Go to the documentation of this file.
1 #ifndef GRL_KUKA_DRIVER
2 #define GRL_KUKA_DRIVER
3 
4 
5 #include <tuple>
6 #include <memory>
7 #include <thread>
8 #include <boost/asio.hpp>
9 #include <boost/circular_buffer.hpp>
10 #include <boost/exception/all.hpp>
11 #include <boost/config.hpp>
12 
13 #include <boost/make_shared.hpp>
14 #include <boost/range/algorithm/copy.hpp>
15 #include <boost/range/algorithm/transform.hpp>
16 
17 #include <boost/make_shared.hpp>
18 
19 #ifdef BOOST_NO_CXX11_ATOMIC_SMART_PTR
20 #include <boost/thread.hpp>
21 #endif
22 
23 #include "Kuka.hpp"
26 #include "grl/tags.hpp"
27 
28 
29 namespace grl { namespace robot { namespace arm {
30 
31 
32  ///
33  ///
34  /// @brief Kuka LBR iiwa Primary Multi Mode Driver, supports communication over FRI and JAVA interfaces
35  ///
36  /// The most effective configuration of this driver is to command the KUKA in JAVA mode
37  /// and receive robot status updates via FRI mode.
38  ///
39  /// @todo enable commanding and monitoring to be independently configured for both FRI and JAVA interface.
40  ///
41  class KukaDriver : public std::enable_shared_from_this<KukaDriver> {
42  public:
43 
44  enum ParamIndex {
56  };
57 
58  typedef std::tuple<
59  std::string,
60  std::string,
61  std::string,
62  std::string,
63  std::string,
64  std::string,
65  std::string,
66  std::string,
67  std::string,
68  std::string,
69  std::string
70  > Params;
71 
72 
73  static const Params defaultParams(){
74  return std::make_tuple(
75  "Robotiiwa" , // RobotName,
76  "KUKA_LBR_IIWA_14_R820" , // RobotModel (options are KUKA_LBR_IIWA_14_R820, KUKA_LBR_IIWA_7_R800)
77  "0.0.0.0" , // LocalUDPAddress
78  "30010" , // LocalUDPPort
79  "172.31.1.147" , // RemoteUDPAddress
80  "192.170.10.100" , // LocalHostKukaKoniUDPAddress,
81  "30200" , // LocalHostKukaKoniUDPPort,
82  "192.170.10.2" , // RemoteHostKukaKoniUDPAddress,
83  "30200" , // RemoteHostKukaKoniUDPPort
84  "JAVA" , // KukaCommandMode (options are FRI, JAVA)
85  "FRI" // KukaMonitorMode (options are FRI, JAVA)
86  );
87  }
88 
89 
91  : params_(params), debug(false)
92  {}
93 
94  void construct(){ construct(params_);}
95 
96  bool destruct(){ return JAVAdriverP_->destruct(); }
97 
98 
99  /// @todo create a function that calls simGetObjectHandle and throws an exception when it fails
100  /// @warning getting the ik group is optional, so it does not throw an exception
101  void construct(Params params ) {
102 
103  params_ = params;
104  // keep driver threads from exiting immediately after creation, because they have work to do!
105  //device_driver_workP_.reset(new boost::asio::io_service::work(device_driver_io_service));
106 
107  /// @todo figure out how to re-enable when .so isn't loaded
108  if( boost::iequals(std::get<KukaCommandMode>(params_),std::string("FRI"))
109  || boost::iequals(std::get<KukaMonitorMode>(params_),std::string("FRI")))
110  {
111  FRIdriverP_.reset(
113  //device_driver_io_service,
114  std::make_tuple(
115  std::string(std::get<RobotModel > (params)),
116  std::string(std::get<LocalHostKukaKoniUDPAddress > (params)),
117  std::string(std::get<LocalHostKukaKoniUDPPort > (params)),
118  std::string(std::get<RemoteHostKukaKoniUDPAddress> (params)),
119  std::string(std::get<RemoteHostKukaKoniUDPPort > (params)),
121  )
122  )
123 
124  );
125  FRIdriverP_->construct();
126  }
127 
128  /// @todo implement reading configuration in both FRI and JAVA mode from JAVA interface
129  if( boost::iequals(std::get<KukaCommandMode>(params_),std::string("JAVA"))
130  || boost::iequals(std::get<KukaCommandMode>(params_),std::string("FRI")))
131  {
132  try {
133  JAVAdriverP_ = boost::make_shared<KukaJAVAdriver>(params_);
134  JAVAdriverP_->construct();
135 
136  // start up the driver thread
137  /// @todo perhaps allow user to control this?
138  //driver_threadP.reset(new std::thread([&]{ device_driver_io_service.run(); }));
139  } catch( boost::exception &e) {
140  e << errmsg_info("KukaDriver: Unable to connect to ZeroMQ Socket from " +
141  std::get<LocalUDPAddress> (params_) + " to " +
142  std::get<RemoteUDPAddress> (params_));
143  throw;
144  }
145 
146  }
147  }
148 
149 
150 
151 
152 
153 
154  const Params & getParams(){
155  return params_;
156  }
157 
159  device_driver_workP_.reset();
160 
161  if(driver_threadP){
163  driver_threadP->join();
164  }
165  }
166 
167  /**
168  * spin once
169  *
170  */
171  bool run_one(){
172 
173  // @todo CHECK FOR REAL DATA BEFORE SENDING COMMANDS
174  //if(!m_haveReceivedRealDataCount) return;
175  bool haveNewData = false;
176 
177  /// @todo make this handled by template driver implementations/extensions
178 
179  if(JAVAdriverP_.get() != nullptr)
180  {
181  if (debug) {
182  std::cout << "commandedpos:" << armState_.commandedPosition << "\n";
183  }
184 
185 
186  /////////////////////////////////////////
187  // Do some configuration
188  if(boost::iequals(std::get<KukaCommandMode>(params_),std::string("FRI")))
189  {
190  // configure to send commands over FRI interface
191  JAVAdriverP_->set(flatbuffer::KUKAiiwaInterface_FRI,command_tag());
192  }
193 
194  if(boost::iequals(std::get<KukaMonitorMode>(params_),std::string("FRI")))
195  {
196  // configure to send commands over FRI interface
197  JAVAdriverP_->set(flatbuffer::KUKAiiwaInterface_FRI,state_tag());
198  }
199 
200 
201  /////////////////////////////////////////
202  // set new destination
203 
204  if( boost::iequals(std::get<KukaCommandMode>(params_),std::string("JAVA")))
205  {
206  JAVAdriverP_->set(armState_.commandedPosition,revolute_joint_angle_open_chain_command_tag());
207 
208  // configure to send commands over JAVA interface
210 
211  }
212 
213  // sync JAVA driver with the robot, note client sends to server asynchronously!
214  haveNewData = JAVAdriverP_->run_one();
215 
216  if( boost::iequals(std::get<KukaMonitorMode>(params_),std::string("JAVA")))
217  {
218  JAVAdriverP_->get(armState_);
220 
221  }
222  }
223 
224  if(FRIdriverP_.get() != nullptr)
225  {
226  if( boost::iequals(std::get<KukaCommandMode>(params_),std::string("FRI")))
227  {
229  }
230 
231  haveNewData = FRIdriverP_->run_one();
232 
233  if( boost::iequals(std::get<KukaMonitorMode>(params_),std::string("FRI")))
234  {
235  FRIdriverP_->get(armState_);
236  JAVAdriverP_->getWrench(armState_);
237  }
238  }
239 
240  return haveNewData;
241  }
242 
243 
244  /// set the mode of the arm. Examples: Teach or MoveArmJointServo
245  /// @see grl::flatbuffer::ArmState in ArmControlState_generated.h
246  void set(const flatbuffer::ArmState & armControlMode)
247  {
248  if(JAVAdriverP_)
249  {
250  JAVAdriverP_->set(armControlMode);
251  }
252  }
253 
254  /**
255  * \brief Set the joint positions for the current interpolation step.
256  *
257  * This method is only effective when the client is in a commanding state.
258  * @param state Object which stores the current state of the robot, including the command to send next
259  * @param range Array with the new joint positions (in radians)
260  * @param tag identifier object indicating that revolute joint angle commands should be modified
261  */
262  template<typename Range>
264  boost::unique_lock<boost::mutex> lock(jt_mutex);
265  armState_.clearCommands();
266  boost::copy(range, std::back_inserter(armState_.commandedPosition));
267  boost::copy(range, std::back_inserter(armState_.commandedPosition_goal));
268 
269  std::cout << "set commandedpos:" << armState_.commandedPosition;
270  }
271 
272  /**
273  * \brief Set the applied joint torques for the current interpolation step.
274  *
275  * This method is only effective when the client is in a commanding state.
276  * The ControlMode of the robot has to be joint impedance control mode. The
277  * Client Command Mode has to be torque.
278  *
279  * @param state Object which stores the current state of the robot, including the command to send next
280  * @param torques Array with the applied torque values (in Nm)
281  * @param tag identifier object indicating that the torqe value command should be modified
282  */
283  template<typename Range>
285  boost::unique_lock<boost::mutex> lock(jt_mutex);
286  armState_.clearCommands();
287  boost::copy(range, std::back_inserter(armState_.commandedTorque));
288  }
289 
290 
291  /**
292  * @brief Set the time duration expected between new position commands in ms
293  *
294  * The driver will likely be updated every so often, such as every 25ms, and the lowest level of the
295  * driver may update even more frequently, such as every 1ms. By providing as accurate an
296  * estimate between high level updates the low level driver can smooth out the motion through
297  * interpolation (the default), or another algorithm. See LowLevelStepAlgorithmType template parameter
298  * in the KukaFRIdriver class if you want to change out the low level algorithm.
299  *
300  * @see KukaFRIdriver::get(time_duration_command_tag)
301  *
302  * @param duration_to_goal_command std::chrono time format representing the time duration between updates
303  *
304  */
305  void set(double duration_to_goal_command, time_duration_command_tag tag) {
306  boost::lock_guard<boost::mutex> lock(jt_mutex);
307  armState_.goal_position_command_time_duration = duration_to_goal_command;
308  if(FRIdriverP_)
309  {
310  FRIdriverP_->set(duration_to_goal_command,tag);
311  }
312  if(JAVAdriverP_)
313  {
314  JAVAdriverP_->set(duration_to_goal_command,tag);
315  }
316  }
317 
318 
319  /**
320  * @brief Get the timestamp of the most recent armState
321  *
322  *
323  *
324  * @see KukaFRIdriver::set(Range&& range, grl::revolute_joint_angle_open_chain_command_tag)
325  *
326  */
328  boost::lock_guard<boost::mutex> lock(jt_mutex);
329  return armState_.timestamp;
330  }
331 
332  /**
333  * \brief Set the applied wrench vector of the current interpolation step.
334  *
335  * The wrench vector consists of:
336  * [F_x, F_y, F_z, tau_A, tau_B, tau_C]
337  *
338  * F ... forces (in N) applied along the Cartesian axes of the
339  * currently used motion center.
340  * tau ... torques (in Nm) applied along the orientation angles
341  * (Euler angles A, B, C) of the currently used motion center.
342  *
343  * This method is only effective when the client is in a commanding state.
344  * The ControlMode of the robot has to be Cartesian impedance control mode. The
345  * Client Command Mode has to be wrench.
346  *
347  * @param state object storing the command data that will be sent to the physical device
348  * @param range wrench Applied Cartesian wrench vector, in x, y, z, roll, pitch, yaw force measurments.
349  * @param tag identifier object indicating that the wrench value command should be modified
350  *
351  * @todo perhaps support some specific more useful data layouts
352  */
353  template<typename Range>
354  void set(Range&& range, grl::cartesian_wrench_command_tag) {
355  boost::unique_lock<boost::mutex> lock(jt_mutex);
356  armState_.clearCommands();
358  }
359 
360  /// @todo implement get function
361  template<typename OutputIterator>
362  void get(OutputIterator output, grl::revolute_joint_angle_open_chain_state_tag)
363  {
364  boost::unique_lock<boost::mutex> lock(jt_mutex);
365  boost::copy(armState_.position,output);
366  }
367 
368  /// @todo implement get function
369  template<typename OutputIterator>
370  void get(OutputIterator output, grl::revolute_joint_torque_open_chain_state_tag)
371  {
372  boost::unique_lock<boost::mutex> lock(jt_mutex);
373  boost::copy(armState_.torque,output);
374 
375  }
376 
377  template<typename OutputIterator>
379  {
380  boost::unique_lock<boost::mutex> lock(jt_mutex);
381  boost::copy(armState_.externalTorque,output);
382 
383  }
384 
385  template<typename OutputIterator>
386  void get(OutputIterator output, grl::cartesian_external_force_tag)
387  {
388  boost::unique_lock<boost::mutex> lock(jt_mutex);
389  boost::copy(armState_.externalForce,output);
390 
391  }
392 
393  template<typename OutputIterator>
394  void getWrench(OutputIterator output)
395  {
396  boost::unique_lock<boost::mutex> lock(jt_mutex);
397  boost::copy(armState_.wrenchJava,output);
398 
399  }
400 
401  volatile std::size_t m_haveReceivedRealDataCount = 0;
402  volatile std::size_t m_attemptedCommunicationCount = 0;
405 
406  boost::asio::io_service device_driver_io_service;
407  std::unique_ptr<boost::asio::io_service::work> device_driver_workP_;
408  std::unique_ptr<std::thread> driver_threadP;
409 
410 
411 
412  private:
413 
414  KukaState armState_;
415 
416  boost::mutex jt_mutex;
417  boost::shared_ptr<KukaFRIdriver<LinearInterpolation>> FRIdriverP_;
418  boost::shared_ptr<KukaJAVAdriver> JAVAdriverP_;
419 
420  Params params_;
421 
422  bool debug;
423 
424  };
425 
426 }}}// namespace grl::robot::arm
427 
428 #endif
cartesian_state externalForce
Definition: Kuka.hpp:50
std::unique_ptr< std::thread > driver_threadP
Definition: KukaDriver.hpp:408
cartesian_state wrenchJava
Definition: Kuka.hpp:53
void getWrench(OutputIterator output)
Definition: KukaDriver.hpp:394
joint_state commandedPosition
Definition: Kuka.hpp:51
time_point_type timestamp
Definition: Kuka.hpp:74
Internal implementation class for driver use only, stores all the kuka state data in a simple object...
Definition: Kuka.hpp:40
static const Params defaultParams()
Definition: KukaDriver.hpp:73
std::unique_ptr< boost::asio::io_service::work > device_driver_workP_
Definition: KukaDriver.hpp:407
std::chrono::time_point< std::chrono::high_resolution_clock > time_point_type
Definition: Kuka.hpp:45
volatile std::size_t m_attemptedCommunicationConsecutiveFailureCount
Definition: KukaDriver.hpp:403
KukaDriver(Params params=defaultParams())
Definition: KukaDriver.hpp:90
Simple low level driver to communicate over the Kuka iiwa FRI interface using KUKA::FRI::ClientData s...
external joint torque, i.e. torques applied to an arm excluding those caused by the mass of the arm i...
Definition: tags.hpp:64
cartesian_state commandedCartesianWrenchFeedForward
Definition: Kuka.hpp:52
Primary Kuka FRI driver, only talks over realtime network FRI KONI ethernet port. ...
OutputIterator copy(std::string model, OutputIterator it, grl::revolute_joint_velocity_open_chain_state_constraint_tag)
copy vector of joint velocity limits in radians/s
Definition: Kuka.hpp:131
std::tuple< std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string > Params
Definition: KukaDriver.hpp:70
double goal_position_command_time_duration
Definition: Kuka.hpp:91
Kuka LBR iiwa Primary Multi Mode Driver, supports communication over FRI and JAVA interfaces...
Definition: KukaDriver.hpp:41
defines tag dispatching types used throughout grl
const Params & getParams()
Definition: KukaDriver.hpp:154
data for changing a system&#39;s physical state, such as joint angles to be sent to a robot arm...
Definition: tags.hpp:35
boost::error_info< struct tag_errmsg, std::string > errmsg_info
Definition: exception.hpp:7
volatile std::size_t m_attemptedCommunicationConsecutiveSuccessCount
Definition: KukaDriver.hpp:404
the time duration over which a command should be completed
Definition: tags.hpp:73
joint_state position
Definition: Kuka.hpp:47
boost::asio::io_service device_driver_io_service
Definition: KukaDriver.hpp:406
joint_state commandedPosition_goal
we need to mind arm constraints, so we set a goal then work towards it
Definition: Kuka.hpp:82
volatile std::size_t m_haveReceivedRealDataCount
Definition: KukaDriver.hpp:401
joint_state torque
Definition: Kuka.hpp:48
void construct(Params params)
Definition: KukaDriver.hpp:101
external forces, i.e. forces applied to an arm excluding those caused by the mass of the arm itself a...
Definition: tags.hpp:67
volatile std::size_t m_attemptedCommunicationCount
Definition: KukaDriver.hpp:402
joint_state externalTorque
Definition: Kuka.hpp:49
identifies data representing the state of a sytem
Definition: tags.hpp:34
joint_state commandedTorque
Definition: Kuka.hpp:54
single point in time relative to some start point
Definition: tags.hpp:21