KukaLBRiiwaVrepPlugin.hpp
Go to the documentation of this file.
1 #ifndef KUKA_VREP_PLUGIN_HPP_
2 #define KUKA_VREP_PLUGIN_HPP_
3 
4 #include <iostream>
5 #include <memory>
6 #include <array>
7 
8 #include <boost/log/trivial.hpp>
9 #include <boost/exception/all.hpp>
10 #include <boost/algorithm/string.hpp>
11 
12 #include "grl/kuka/KukaDriver.hpp"
13 #include "grl/vrep/Vrep.hpp"
15 #include <iterator>
16 #include "v_repLib.h"
17 
18 /// @todo move elsewhere, because it will conflict with others' implementations of outputting vectors
19 template<typename T>
20 inline boost::log::formatting_ostream& operator<<(boost::log::formatting_ostream& out, std::vector<T>& v)
21 {
22  out << "[";
23  size_t last = v.size() - 1;
24  for(size_t i = 0; i < v.size(); ++i) {
25  out << v[i];
26  if (i != last)
27  out << ", ";
28  }
29  out << "]";
30  return out;
31 }
32 
33 namespace grl { namespace vrep {
34 
35 
36 
37 
38 /// Creates a complete vrep plugin object
39 /// usage:
40 /// @code
41 /// auto kukaPluginPG = std::make_shared<grl::KukaVrepPlugin>();
42 /// kukaPluginPG->construct();
43 /// while(true) kukaPluginPG->run_one();
44 /// @endcode
45 ///
46 /// @todo this implementation is a bit hacky, redesign it
47 /// @todo separate out grl specific code from general kuka control code
48 /// @todo Template on robot driver and create a driver that just reads/writes to/from the simulation, then pass the two templates so the simulation and the real driver can be selected.
49 ///
50 class KukaVrepPlugin : public std::enable_shared_from_this<KukaVrepPlugin> {
51 public:
52 
53  enum ParamIndex {
70  };
71 
72  typedef std::tuple<
73  std::vector<std::string>,
74  std::string,
75  std::string,
76  std::string,
77  std::string,
78  std::string,
79  std::string,
80  std::string,
81  std::string,
82  std::string,
83  std::string,
84  std::string,
85  std::string,
86  std::string,
87  std::string,
88  std::string
89  > Params;
90 
91 
92  static const Params defaultParams(){
93  std::vector<std::string> jointHandles;
94 
95  jointHandles.push_back("LBR_iiwa_14_R820_joint1"); // Joint1Handle,
96  jointHandles.push_back("LBR_iiwa_14_R820_joint2"); // Joint2Handle,
97  jointHandles.push_back("LBR_iiwa_14_R820_joint3"); // Joint3Handle,
98  jointHandles.push_back("LBR_iiwa_14_R820_joint4"); // Joint4Handle,
99  jointHandles.push_back("LBR_iiwa_14_R820_joint5"); // Joint5Handle,
100  jointHandles.push_back("LBR_iiwa_14_R820_joint6"); // Joint6Handle,
101  jointHandles.push_back("LBR_iiwa_14_R820_joint7"); // Joint7Handle,
102  return std::make_tuple(
103  jointHandles , // JointHandles,
104  "RobotFlangeTip" , // RobotFlangeTipHandle,
105  "RobotMillTip" , // RobotTipHandle,
106  "RobotMillTipTarget" , // RobotTargetHandle,
107  "Robotiiwa" , // RobotTargetBaseHandle,
108  "KUKA_LBR_IIWA_14_R820" , // RobotModel (options are KUKA_LBR_IIWA_14_R820, KUKA_LBR_IIWA_7_R800)
109  "tcp://0.0.0.0" , // LocalUDPAddress
110  "30010" , // LocalUDPPort
111  "172.31.1.147" , // RemoteUDPAddress
112  "192.170.10.100" , // LocalHostKukaKoniUDPAddress,
113  "30200" , // LocalHostKukaKoniUDPPort,
114  "192.170.10.2" , // RemoteHostKukaKoniUDPAddress,
115  "30200" , // RemoteHostKukaKoniUDPPort
116  "JAVA" , // KukaCommandMode (options are FRI, JAVA)
117  "FRI" , // KukaMonitorMode (options are FRI, JAVA)
118  "IK_Group1_iiwa" // IKGroupName
119  );
120  }
121 
122  /// @todo measuredArmParams are hardcoded, parameterize them
123  // parameters for measured arm
124  static const Params measuredArmParams(){
125  std::vector<std::string> jointHandles;
126 
127  jointHandles.push_back("LBR_iiwa_14_R820_joint1#0"); // Joint1Handle,
128  jointHandles.push_back("LBR_iiwa_14_R820_joint2#0"); // Joint2Handle,
129  jointHandles.push_back("LBR_iiwa_14_R820_joint3#0"); // Joint3Handle,
130  jointHandles.push_back("LBR_iiwa_14_R820_joint4#0"); // Joint4Handle,
131  jointHandles.push_back("LBR_iiwa_14_R820_joint5#0"); // Joint5Handle,
132  jointHandles.push_back("LBR_iiwa_14_R820_joint6#0"); // Joint6Handle,
133  jointHandles.push_back("LBR_iiwa_14_R820_joint7#0"); // Joint7Handle,
134  return std::make_tuple(
135  jointHandles , // JointHandles,
136  "RobotFlangeTip#0" , // RobotFlangeTipHandle,
137  "RobotMillTip#0" , // RobotTipHandle,
138  "RobotMillTipTarget#0" , // RobotTargetHandle,
139  "Robotiiwa#0" , // RobotTargetBaseHandle,
140  "KUKA_LBR_IIWA_14_R820" , // RobotModel (options are KUKA_LBR_IIWA_14_R820, KUKA_LBR_IIWA_7_R800)
141  "tcp://0.0.0.0" , // LocalUDPAddress
142  "30010" , // LocalUDPPort
143  "172.31.1.147" , // RemoteUDPAddress
144  "192.170.10.100" , // LocalHostKukaKoniUDPAddress,
145  "30200" , // LocalHostKukaKoniUDPPort,
146  "192.170.10.2" , // RemoteHostKukaKoniUDPAddress,
147  "30200" , // RemoteHostKukaKoniUDPPort
148  "JAVA" , // KukaCommandMode (options are FRI, JAVA)
149  "FRI" , // KukaMonitorMode (options are FRI, JAVA)
150  "IK_Group1_iiwa#0" // IKGroupName
151  );
152  }
153 
154 
155 
156 
157 
158 
159 /// @todo allow KukaFRIThreadSeparator parameters to be updated
160 /// @param params a tuple containing all of the parameter strings needed to configure the device.
161 ///
162 /// The KukaCommandMode parameters supports the options "FRI" and "JAVA". This configures how commands will
163 /// be sent to the arm itself. "FRI" mode is via a direct "Fast Robot Interface" "KUKA KONI"
164 /// ethernet connection which provides substantially higher performance and response time,
165 /// but is extremely sensitive to delays, and any delay will halt the robot and require a manual reset.
166 /// "JAVA" mode sends the command to the Java application installed on the KUKA robot, which then submits
167 /// it to the arm itself to execute. This is a much more forgiving mode of communication, but it is subject to delays.
168 ///
169 /// @todo read ms_per_tick from the java interface
171  :
172  params_(params)
173 {
174 }
175 
176 void construct(){construct(params_);}
177 
178 /// construct() function completes initialization of the plugin
179 /// @todo move this into the actual constructor, but need to correctly handle or attach vrep shared libraries for unit tests.
180 void construct(Params params){
181  params_ = params;
182  // keep driver threads from exiting immediately after creation, because they have work to do!
183  device_driver_workP_.reset(new boost::asio::io_service::work(device_driver_io_service));
184  kukaDriverP_=std::make_shared<robot::arm::KukaDriver>(std::make_tuple(
185 
186  std::get<RobotTargetBaseName>(params),
187  std::get<RobotModel>(params),
188  std::get<LocalUDPAddress>(params),
189  std::get<LocalUDPPort>(params),
190  std::get<RemoteUDPAddress>(params),
191  std::get<LocalHostKukaKoniUDPAddress>(params),
192  std::get<LocalHostKukaKoniUDPPort>(params),
193  std::get<RemoteHostKukaKoniUDPAddress>(params),
194  std::get<RemoteHostKukaKoniUDPPort>(params),
195  std::get<KukaCommandMode>(params),
196  std::get<KukaMonitorMode>(params)
197 
198 
199  ));
200  kukaDriverP_->construct();
202  std::cout << "KUKA COMMAND MODE: " << std::get<KukaCommandMode>(params) << "\n";
203  initHandles();
204 }
205 
206 
207 void run_one(){
208 
209  if(!allHandlesSet) BOOST_THROW_EXCEPTION(std::runtime_error("KukaVrepPlugin: Handles have not been initialized, cannot run updates."));
210  getRealKukaAngles();
211  bool isError = getStateFromVrep(); // true if there is an error
212  allHandlesSet = !isError;
213  /// @todo re-enable simulation feedback based on actual kuka state
214  syncVrepAndKuka();
215 }
216 
217 
219  device_driver_workP_.reset();
220 
221  if(driver_threadP){
222  device_driver_io_service.stop();
223  driver_threadP->join();
224  }
225 }
226 
227 private:
228 
229 
230 
231 void initHandles() {
232 
233  vrepRobotArmDriverP_ = std::make_shared<VrepRobotArmDriver>
234  (
235  std::make_tuple(
236  std::get<JointNames> (params_),
237  std::get<RobotFlangeTipName> (params_),
238  std::get<RobotTipName> (params_),
239  std::get<RobotTargetName> (params_),
240  std::get<RobotTargetBaseName> (params_),
241  std::get<IKGroupName> (params_)
242  )
243  );
244 
245 
246  vrepRobotArmDriverP_->construct();
247 
248  measuredParams_ = measuredArmParams();
249  vrepMeasuredRobotArmDriverP_ = std::make_shared<VrepRobotArmDriver>
250  (
251  std::make_tuple(
252  std::get<JointNames> (measuredParams_),
253  std::get<RobotFlangeTipName> (measuredParams_),
254  std::get<RobotTipName> (measuredParams_),
255  std::get<RobotTargetName> (measuredParams_),
256  std::get<RobotTargetBaseName> (measuredParams_),
257  std::get<IKGroupName> (measuredParams_)
258  )
259  );
260  vrepMeasuredRobotArmDriverP_->construct();
261 
262 
263  /// @todo remove this assumption
264  allHandlesSet = true;
265 }
266 
267 void getRealKukaAngles() {
268  /// @todo m_haveReceivedRealData = true is a DANGEROUS HACK!!!! REMOVE ME AFTER DEBUGGING
269  m_haveReceivedRealData = true;
270 
271 
272 
273 }
274 
275 void syncVrepAndKuka(){
276 
277  if(!allHandlesSet || !m_haveReceivedRealData) return;
278 
279  /// @todo make this handled by template driver implementations/extensions
280  kukaDriverP_->set(simulationTimeStep_,time_duration_command_tag());
281  kukaDriverP_->set( simJointPosition, grl::revolute_joint_angle_open_chain_command_tag());
282  if(0) kukaDriverP_->set( simJointForce , grl::revolute_joint_torque_open_chain_command_tag());
283 
284 
285  kukaDriverP_->run_one();
286  // We have the real kuka state read from the device now
287  // update real joint angle data
288  realJointPosition.clear();
289  kukaDriverP_->get(std::back_inserter(realJointPosition), grl::revolute_joint_angle_open_chain_state_tag());
290 
291  realJointForce.clear();
292  kukaDriverP_->get(std::back_inserter(realJointForce), grl::revolute_joint_torque_open_chain_state_tag());
293 
294  realExternalJointTorque.clear();
295  kukaDriverP_->get(std::back_inserter(realExternalJointTorque), grl::revolute_joint_torque_external_open_chain_state_tag());
296 
297  realExternalForce.clear();
298  kukaDriverP_->get(std::back_inserter(realExternalForce), grl::cartesian_external_force_tag());
299 
300  if(0){
301  // debug output
302  std::cout << "Measured Torque: ";
303  std::cout << std::setw(6);
304  for (float t:realJointForce) {
305  std::cout << t << " ";
306  }
307  std::cout << '\n';
308 
309  std::cout << "External Torque: ";
310  std::cout << std::setw(6);
311  for (float t:realExternalJointTorque) {
312  std::cout << t << " ";
313  }
314  std::cout << '\n';
315 
316  std::cout << "Measured Position: ";
317  for (float t:realJointPosition) {
318  std::cout << t << " ";
319  }
320  std::cout << '\n';
321  }
322 
323  if(!allHandlesSet || !vrepMeasuredRobotArmDriverP_) return;
324 
325  if (realJointPosition.size() > 0) { // if there are valid measured states
326  VrepRobotArmDriver::State measuredArmState;
327  std::get<VrepRobotArmDriver::JointPosition>(measuredArmState) = realJointPosition;
328  std::get<VrepRobotArmDriver::JointForce>(measuredArmState) = realJointForce;
329  std::get<VrepRobotArmDriver::ExternalTorque>(measuredArmState) = realExternalJointTorque;
330 
331  vrepMeasuredRobotArmDriverP_->setState(measuredArmState);
332  }
333 
334 }
335 
336 /// @todo if there aren't real limits set via the kuka model already then implement me
337 void setArmLimits(){
338  //simSetJointInterval(simInt objectHandle,simBool cyclic,const simFloat* interval); //Sets the interval parameters of a joint (i.e. range values)
339  //simSetJointMode(simInt jointHandle,simInt jointMode,simInt options); //Sets the operation mode of a joint. Might have as side-effect the change of additional properties of the joint
340 
341 }
342 
343 /// @return isError - true if there is an error, false if there is no Error
344 bool getStateFromVrep(){
345  if(!allHandlesSet || !vrepRobotArmDriverP_) return false;
346 
347  VrepRobotArmDriver::State armState;
348 
349  bool isError = vrepRobotArmDriverP_->getState(armState);
350 
351  if(isError) return isError;
352 
353  simJointPosition = std::get<VrepRobotArmDriver::JointPosition> (armState);
354  simJointForce = std::get<VrepRobotArmDriver::JointForce> (armState);
355  simJointTargetPosition = std::get<VrepRobotArmDriver::JointTargetPosition>(armState);
356  simJointTransformationMatrix = std::get<VrepRobotArmDriver::JointMatrix> (armState);
357 
358 
359  /// need to provide tick time in double seconds and get from vrep API call
360  simulationTimeStep_ = simGetSimulationTimeStep()*1000;
361 
362 // for (int i=0 ; i < KUKA::LBRState::NUM_DOF ; i++)
363 // {
364 // simGetJointPosition(jointHandle[i],&simJointPosition[i]); //retrieves the intrinsic position of a joint (Angle for revolute joint)
365 // simGetJointForce(jointHandle[i],&simJointForce[i]); //retrieves the force or torque applied to a joint along/about its active axis. This function retrieves meaningful information only if the joint is prismatic or revolute, and is dynamically enabled.
366 // simGetJointTargetPosition(jointHandle[i],&simJointTargetPosition[i]); //retrieves the target position of a joint
367 // simGetJointMatrix(jointHandle[i],&simJointTransformationMatrix[i]); //retrieves the intrinsic transformation matrix of a joint (the transformation caused by the joint movement)
368 //
369 // }
370 //
371 // BOOST_LOG_TRIVIAL(info) << "simJointPostition = " << simJointPosition << std::endl;
372 // BOOST_LOG_TRIVIAL(info) << "simJointForce = " << simJointForce << std::endl;
373 // BOOST_LOG_TRIVIAL(info) << "simJointTargetPostition = " << simJointTargetPosition << std::endl;
374 // BOOST_LOG_TRIVIAL(info) << "simJointTransformationMatrix = " << simJointTransformationMatrix << std::endl;
375 //
376 // float simTipPosition[3];
377 // float simTipOrientation[3];
378 //
379 // simGetObjectPosition(target, targetBase, simTipPosition);
380 // simGetObjectOrientation(target, targetBase, simTipOrientation);
381 //
382 // for (int i = 0 ; i < 3 ; i++)
383 // {
384 // BOOST_LOG_TRIVIAL(info) << "simTipPosition[" << i << "] = " << simTipPosition[i] << std::endl;
385 // BOOST_LOG_TRIVIAL(info) << "simTipOrientation[" << i << "] = " << simTipOrientation[i] << std::endl;
386 //
387 // }
388  // Send updated position to the real arm based on simulation
389  return false;
390 }
391 
392 /// @todo reenable this component
393 bool updateVrepFromKuka() {
394  // Step 1
395  ////////////////////////////////////////////////////
396  // call the functions here and just print joint angles out
397  // or display something on the screens
398 
399  ///////////////////
400  // call our object to get the latest real kuka state
401  // then use the functions below to set the simulation state
402  // to match
403 
404  /////////////////// assuming given real joint position (angles), forces, target position and target velocity
405 
406 
407  // setting the simulation variables to data from real robot (here they have been assumed given)
408 
409  for (int i=0 ; i < 7 ; i++)
410  {
411  //simSetJointPosition(jointHandle[i],realJointPosition[i]); //Sets the intrinsic position of a joint. May have no effect depending on the joint mode
412 
413 
414  //simSetJointTargetPosition(jointHandle[i],realJointTargetPosition[i]); //Sets the target position of a joint if the joint is in torque/force mode (also make sure that the joint's motor and position control are enabled
415 
416  //simSetJointForce(jointHandle[i],realJointForce[i]); //Sets the maximum force or torque that a joint can exert. This function has no effect when the joint is not dynamically enabled
417 
418 
419  //simSetJointTargetVelocity(jointHandle[i],realJointTargetVelocity[i]); //Sets the intrinsic target velocity of a non-spherical joint. This command makes only sense when the joint mode is: (a) motion mode: the joint's motion handling feature must be enabled (simHandleJoint must be called (is called by default in the main script), and the joint motion properties must be set in the joint settings dialog), (b) torque/force mode: the dynamics functionality and the joint motor have to be enabled (position control should however be disabled)
420  }
421  return false;
422 }
423 
424 volatile bool allHandlesSet = false;
425 volatile bool m_haveReceivedRealData = false;
426 
427 double simulationTimeStep_; // ms
428 
429 boost::asio::io_service device_driver_io_service;
430 std::unique_ptr<boost::asio::io_service::work> device_driver_workP_;
431 std::unique_ptr<std::thread> driver_threadP;
432 std::shared_ptr<grl::robot::arm::KukaDriver> kukaDriverP_;
433 std::shared_ptr<VrepRobotArmDriver> vrepRobotArmDriverP_;
434 std::shared_ptr<VrepRobotArmDriver> vrepMeasuredRobotArmDriverP_;
435 //boost::asio::deadline_timer sendToJavaDelay;
436 
437 /// @todo replace all these simJoint elements with simple VrepRobotArmDriver::State
438 std::vector<float> simJointPosition = {0.0,0.0,0.0,0.0,0.0,0.0,0.0};
439 // std::vector<float> simJointVelocity = {0.0,0.0,0.0,0.0,0.0,0.0,0.0}; no velocity yet
440 std::vector<float> simJointForce = {0.0,0.0,0.0,0.0,0.0,0.0,0.0};
441 std::vector<float> simJointTargetPosition = {0.0,0.0,0.0,0.0,0.0,0.0,0.0};
442 VrepRobotArmDriver::TransformationMatrices simJointTransformationMatrix;
443 
444 /// @note loss of precision! kuka sends double values, if you write custom code don't use these float values. Vrep uses floats internally which is why they are used here.
445 std::vector<float> realJointPosition = { 0, 0, 0, 0, 0, 0, 0 };
446 // does not exist
447 // std::vector<float> realJointTargetPosition = { 0, 0, 0, 0, 0, 0, 0 };
448 std::vector<float> realJointForce = { 0, 0, 0, 0, 0, 0, 0 };
449 // does not exist yet
450 //std::vector<float> realJointTargetVelocity = { 0, 0, 0, 0, 0, 0, 0 };
451 std::vector<float> realExternalJointTorque = { 0, 0, 0, 0, 0, 0, 0};
452 std::vector<float> realExternalForce = { 0, 0, 0, 0, 0, 0};
453 private:
454 Params params_;
455 Params measuredParams_;
456 /// for use in FRI clientdata mode
457 std::shared_ptr<KUKA::FRI::ClientData> friData_;
458 };
459 
460 }} // grl::vrep
461 
462 #endif
external joint torque, i.e. torques applied to an arm excluding those caused by the mass of the arm i...
Definition: tags.hpp:64
static const Params measuredArmParams()
std::tuple< std::vector< std::string >, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string, std::string > Params
the time duration over which a command should be completed
Definition: tags.hpp:73
static const Params defaultParams()
std::vector< TransformationMatrix > TransformationMatrices
external forces, i.e. forces applied to an arm excluding those caused by the mass of the arm itself a...
Definition: tags.hpp:67
KukaVrepPlugin(Params params=defaultParams())
std::tuple< JointScalar, JointScalar, JointScalar, JointScalar, JointScalar, TransformationMatrices, JointStateTag, JointScalar > State
ptrSimGetSimulationTimeStep simGetSimulationTimeStep
Definition: v_repLib.cpp:181