InverseKinematicsVrepPlugin.hpp
Go to the documentation of this file.
1 /// @author Andrew Hundt <athundt@gmail.com>
2 #ifndef _INVERSE_KINEMATICS_VREP_PLUGIN_
3 #define _INVERSE_KINEMATICS_VREP_PLUGIN_
4 
5 /// @todo remove IGNORE_ROTATION or make it a runtime configurable parameter
6 // #define IGNORE_ROTATION
7 
8 
9 
10 #include <string>
11 #include <tuple>
12 #include <boost/format.hpp>
13 #include <Eigen/Core>
14 #include <Eigen/Geometry>
15 
16 // SpaceVecAlg
17 // https://github.com/jrl-umi3218/SpaceVecAlg
18 #include <SpaceVecAlg/SpaceVecAlg>
19 
20 // RBDyn
21 // https://github.com/jrl-umi3218/RBDyn
22 #include <RBDyn/Body.h>
23 #include <RBDyn/Joint.h>
24 #include <RBDyn/MultiBody.h>
25 #include <RBDyn/MultiBodyConfig.h>
26 #include <RBDyn/MultiBodyGraph.h>
27 #include <RBDyn/EulerIntegration.h>
28 #include <RBDyn/FK.h>
29 #include <RBDyn/IK.h>
30 #include <RBDyn/FV.h>
31 #include <RBDyn/ID.h>
32 
33 // Tasks
34 // https://github.com/jrl-umi3218/Tasks
35 #include <Tasks/Tasks.h>
36 #include <Tasks/Bounds.h>
37 #include <Tasks/QPConstr.h>
38 #include <Tasks/QPContactConstr.h>
39 #include <Tasks/QPMotionConstr.h>
40 #include <Tasks/QPSolver.h>
41 #include <Tasks/QPTasks.h>
42 
43 // grl
44 #include "grl/vrep/Vrep.hpp"
47 #include "grl/vrep/Eigen.hpp"
48 #include "grl/vrep/SpaceVecAlg.hpp"
49 
50 #include <boost/lexical_cast.hpp>
51 #include <boost/range/algorithm/copy.hpp>
52 
53 namespace grl {
54 namespace vrep {
55 
56 /// Sets the VREP simulation joint positions from the RBDyn configuration
57 ///
58 /// @param vrepJointNames the name of each joint, order must match vrepJointHandles
59 /// @param vrepJointHandles the V-REP simulation object handle for each joint
60 /// @param rbdJointNames the names of all the simArmMultiBody joints, which typically has more joints than the VREP list.
61 /// @param simArmMultiBody defines the structure of the robot arm for the RBDyn library, see RBDyn documentation
62 /// @param simArmConfig defines the current position of the robot arm for the RBDyn library, see RBDyn documentation
63 /// @param debug if empty string, no effect, if any other string a trace of the joint angles will be printed to std::cout
65  const std::vector<std::string>& vrepJointNames,
66  const std::vector<int>& vrepJointHandles,
67  const rbd::MultiBody& simArmMultiBody,
68  const rbd::MultiBodyConfig& simArmConfig,
69  std::string debug = "")
70 {
71  std::string str;
72  for (std::size_t i = 0; i < vrepJointHandles.size(); ++ i)
73  {
74  // modify parameters as follows https://github.com/jrl-umi3218/Tasks/issues/10#issuecomment-257466822
75  std::string jointName = vrepJointNames[i];
76  std::size_t jointIdx = simArmMultiBody.jointIndexByName(jointName);
77  float futureAngle = simArmConfig.q[jointIdx][0];
78  simSetJointPosition(vrepJointHandles[i],futureAngle);
79  /// @todo TODO(ahundt) add torque information
80  // simSetJointTargetVelocity(jointHandles_[i],jointAngles_dt[i]/simulationTimeStep);
81  // simSetJointTargetPosition(jointHandles_[i],jointAngles_dt[i]);
82  // simSetJointTargetPosition(jointHandles_[i],futureAngle);
83 
84  if(!debug.empty())
85  {
86  str+=boost::lexical_cast<std::string>(futureAngle);
87  if (i<vrepJointHandles.size()-1) str+=", ";
88  }
89  }
90 
91  if(!debug.empty())
92  {
93  BOOST_LOG_TRIVIAL(trace) << debug << " jointAngles: " << str;
94  }
95 }
96 
97 
98 /// Sets the VREP simulation joint positions from the RBDyn configuration
99 ///
100 /// @param vrepJointNames the name of each joint, order must match vrepJointHandles
101 /// @param vrepJointHandles the V-REP simulation object handle for each joint
102 /// @param rbdJointNames the names of all the simArmMultiBody joints, which typically has more joints than the VREP list.
103 /// @param simArmMultiBody defines the structure of the robot arm for the RBDyn library, see RBDyn documentation
104 /// @param simArmConfig defines the current position of the robot arm for the RBDyn library, see RBDyn documentation
105 /// @param debug if empty string, no effect, if any other string a trace of the joint angles will be printed to std::cout
107  const std::vector<std::string>& vrepJointNames,
108  const std::vector<int>& vrepJointHandles,
109  const rbd::MultiBody& simArmMultiBody,
110  rbd::MultiBodyConfig& simArmConfig,
111  std::string debug = "")
112 {
113  std::string str;
114  float futureAngle;
115  for (std::size_t i = 0; i < vrepJointHandles.size(); ++ i)
116  {
117  // modify parameters as follows https://github.com/jrl-umi3218/Tasks/issues/10#issuecomment-257466822
118  std::string jointName = vrepJointNames[i];
119  std::size_t jointIdx = simArmMultiBody.jointIndexByName(jointName);
120  simGetJointPosition(vrepJointHandles[i],&futureAngle);
121  if(simArmConfig.q[jointIdx].size()>0) simArmConfig.q[jointIdx][0] = futureAngle;
122 
123  /// @todo TODO(ahundt) add torque information
124  // simSetJointTargetVelocity(jointHandles_[i],jointAngles_dt[i]/simulationTimeStep);
125  // simSetJointTargetPosition(jointHandles_[i],jointAngles_dt[i]);
126  // simSetJointTargetPosition(jointHandles_[i],futureAngle);
127 
128  if(!debug.empty())
129  {
130  str+=boost::lexical_cast<std::string>(futureAngle);
131  if (i<vrepJointHandles.size()-1) str+=", ";
132  }
133  }
134 
135  if(!debug.empty())
136  {
137  BOOST_LOG_TRIVIAL(trace) << debug << " jointAngles: " << str;
138  }
139 }
140 
141 
142 /// This object handles taking data from a V-REP based arm simulation
143 /// using it to configure an arm constrained optimization algorithm,
144 /// runs the algorithm, then updates the simulation accordingly.
145 ///
146 /// The types of problems this can solve include reaching a goal position,
147 /// applying the desired levels of force to a system, and avoiding obstacles
148 /// at each time step.
149 ///
150 /// @see the Tasks libraryhttps://github.com/jrl-umi3218/Tasks for a full set of possible capabilities.
151 ///
152 /// @todo verify Robotiiwa is the correct base, and RobotMillTipTarget is the right target, because if the transform doesn't match the one in the jacobian the algorithm will break
153 //template<typename DesiredKinematics = DesiredKinematicsObject>
155 {
156 public:
157 
158  //typedef grl::InverseKinematicsController parent_type;
159 
160  //using parent_type::currentKinematicsStateP_;
161  //using parent_type::parent_type::InitializeKinematicsState;
162 
166  };
167 
168  typedef std::tuple<
169  std::string // DesiredKinematicsObjectName
170  ,std::string // IKGroupName
172 
174  {
175  return std::make_tuple("RobotMillTipTarget","IK_Group1_iiwa");
176  }
177 
178  /// @todo need to call parent constructor:
179  /*! Constructor
180  */
182  {
183  }
184 
185  /// @todo TODO(ahundt) accept params for both simulated and measured arms
186  void construct(Params params = defaultParams()){
187  // get kinematics group name
188  // get number of joints
189 
190  // Get the arm that will be used to generate simulated results to command robot
191  // the "base" of this ik is Robotiiwa
192  VrepRobotArmDriverSimulatedP_ = std::make_shared<vrep::VrepRobotArmDriver>();
193  VrepRobotArmDriverSimulatedP_->construct();
194  // Get the "Measured" arm that will be set based off of real arm sensor data, from sources like KukaVrepPlugin or ROS
195  // in example simulation this ends in #0
196  VrepRobotArmDriverMeasuredP_ = std::make_shared<vrep::VrepRobotArmDriver>(vrep::VrepRobotArmDriver::measuredArmParams());
197  VrepRobotArmDriverMeasuredP_->construct();
198 
199  ikGroupHandle_ = simGetIkGroupHandle(std::get<IKGroupName>(params).c_str());
200  simSetExplicitHandling(ikGroupHandle_,1); // enable explicit handling for the ik
201 
202  auto armDriverSimulatedParams = VrepRobotArmDriverSimulatedP_->getParams();
203  // the base frame of the arm
204  ikGroupBaseName_ = (std::get<VrepRobotArmDriver::RobotTargetBaseName>(armDriverSimulatedParams));
205  // the tip of the arm
206  ikGroupTipName_ = (std::get<VrepRobotArmDriver::RobotTipName>(armDriverSimulatedParams));
207  // the target, or where the tip of the arm should go
208  ikGroupTargetName_ = (std::get<VrepRobotArmDriver::RobotTargetName>(armDriverSimulatedParams));
209  robotFlangeTipName_ = (std::get<VrepRobotArmDriver::RobotFlangeTipName>(armDriverSimulatedParams));
210 
214  /// for why this is named as it is see: https://github.com/jrl-umi3218/Tasks/blob/master/tests/arms.h#L34
215  sva::PTransform<double> X_base = getObjectPTransform(ikGroupBaseHandle_);
216  //X_base = sva::PTransformd(X_base.rotation().inverse(), X_base.translation());
217  // start by assuming the base is fixed
218  bool isFixed = true;
219  bool isForwardJoint = true;
220 
221  { // Initalize the RBDyn arm representation
222 
223  jointHandles_ = VrepRobotArmDriverSimulatedP_->getJointHandles();
224  jointNames_ = VrepRobotArmDriverSimulatedP_->getJointNames();
225 
226  linkNames_ =VrepRobotArmDriverSimulatedP_->getLinkNames();
227  linkHandles_ =VrepRobotArmDriverSimulatedP_->getLinkHandles();
228  linkRespondableNames_ = VrepRobotArmDriverSimulatedP_->getLinkRespondableNames();
229  linkRespondableHandles_ = VrepRobotArmDriverSimulatedP_->getLinkRespondableHandles();
230 
231  // save the initial joint angles for later
232  // and set the arm to the 0 position for initialization of the
233  // optimizer
234  std::vector<float> initialJointAngles;
235  for (int handle : jointHandles_) {
236  float angle;
237  simGetJointPosition(handle,&angle);
238  simSetJointPosition(handle,0);
239  initialJointAngles.push_back(angle);
240  }
241 
242  rbd_bodyNames_.push_back(ikGroupBaseName_);
243  // note: bodyNames are 1 longer than link names, and start with the base!
244  boost::copy(linkNames_, std::back_inserter(rbd_bodyNames_));
245  boost::copy(jointNames_, std::back_inserter(rbd_jointNames_));
246  /// @todo TODO(ahundt) replace hardcoded joint strings with a vrep tree traversal object that generates an RBDyn MultiBodyGraph
247  jointNames_.push_back("LBR_iiwa_14_R820_link8");
248  jointNames_.push_back("cutter_joint");
249  rbd_jointNames_.push_back("LBR_iiwa_14_R820_link8");
251  rbd_jointNames_.push_back("cutter_joint");
252  rbd_jointNames_.push_back(ikGroupTipName_);
253 
254  rbd_bodyNames_.push_back("cutter_joint");
255  rbd_bodyNames_.push_back(ikGroupTipName_);
256  getHandles(rbd_bodyNames_,std::back_inserter(bodyHandles_));
257  getHandles(rbd_jointNames_,std::back_inserter(rbd_jointHandles_));
258 
259  // Note that V-REP specifies full transforms to place objects that rotate joints around the Z axis
260 
261  // based on: https://github.com/jrl-umi3218/Tasks/blob/master/tests/arms.h#L34
262  // and https://github.com/jrl-umi3218/RBDyn/issues/18#issuecomment-257214536
263  for(std::size_t i = 0; i < rbd_jointNames_.size(); i++)
264  {
265 
266  // Note that V-REP specifies full transforms to place objects that rotate joints around the Z axis
267  std::string thisJointName = rbd_jointNames_[i];
268  rbd::Joint::Type jointType = rbd::Joint::Fixed;
269  /// @todo TODO(ahundt) fix hard coded Revolute vs fixed joint https://github.com/ahundt/grl/issues/114
271  {
272  jointType = rbd::Joint::Rev;
273  }
274  rbd::Joint j_i(jointType, Eigen::Vector3d::UnitZ(), isForwardJoint, thisJointName);
275  rbd_mbg_.addJoint(j_i);
276  }
277 
278  // Note that V-REP specifies full transforms to place objects that rotate joints around the Z axis
279  /// @todo TODO(ahundt) last "joint" RobotMillTip is really fixed...
280  //rbd::Joint j_i(rbd::Joint::Fixed, Eigen::Vector3d::UnitZ(), isForwardJoint, ikGroupTipName_);
281  //rbd::Joint j_i(rbd::Joint::Fixed, Eigen::Vector3d::UnitZ(), isForwardJoint, ikGroupTipName_);
282  //rbd_mbg_.addJoint(j_i);
283 
284 
285  for(std::size_t i = 0; i < rbd_bodyNames_.size(); i++)
286  {
287  /// @todo TODO(ahundt) extract real inertia and center of mass from V-REP with http://www.coppeliarobotics.com/helpFiles/en/regularApi/simGetShapeMassAndInertia.htm
288 
289  double mass = 1.;
290  auto I = Eigen::Matrix3d::Identity();
291  auto h = Eigen::Vector3d::Zero();
292  /// @todo TODO(ahundt) consider the origin of the inertia! https://github.com/jrl-umi3218/Tasks/issues/10#issuecomment-257198604
293  sva::RBInertiad rbi_i(mass, h, I);
294  /// @todo TODO(ahundt) add real support for links, particularly the respondable aspects, see LBR_iiwa_14_R820_joint1_resp in RoboneSimulation.ttt
295  // @todo TODO(ahundt) REMEMBER: The first joint is NOT respondable!
296 
297  // remember, bodyNames[0] is the ikGroupBaseName, so entity order is
298  // bodyNames[i], joint[i], bodyNames[i+1]
299  std::string bodyName(rbd_bodyNames_[i]);
300  rbd::Body b_i(rbi_i,bodyName);
301 
302  rbd_mbg_.addBody(b_i);
303  }
304 
305  std::string dummyName0(("Dummy"+ boost::lexical_cast<std::string>(0+10)));
306  int currentDummy0 = simGetObjectHandle(dummyName0.c_str());
307  Eigen::Affine3d eto0 = getObjectTransform(rbd_jointHandles_[0],-1);
308  BOOST_LOG_TRIVIAL(trace) << dummyName0 << " \n" << eto0.matrix();
309  setObjectTransform(currentDummy0,-1,eto0);
310 
311  std::vector<int> frameHandles;
312  frameHandles.push_back(simGetObjectHandle(ikGroupBaseName_.c_str()));
313  boost::copy(rbd_jointHandles_,std::back_inserter(frameHandles));
314  for(std::size_t i = 0; i < rbd_jointHandles_.size()-1; i++)
315  {
316  // note: Tasks takes transforms in the successor (child link) frame, so it is the inverse of v-rep
317  // thus we are getting the current joint in the frame of the next joint
318  sva::PTransformd to(getObjectPTransform(frameHandles[i+1],frameHandles[i]));
319  // this should be the identity matrix because we set the joints to 0!
320  //sva::PTransformd from(getJointPTransform(rbd_jointHandles_[i+1]));
321  sva::PTransformd from(sva::PTransformd::Identity());
322 
323  // Link the PREVIOUSLY created body to the currently created body with the PREVIOUSLY created joint
324  // remember, bodyNames[0] is the ikGroupBaseName, so entity order is
325  // bodyNames[i], joint[i], bodyNames[i+1]
326  std::string prevBody = rbd_bodyNames_[i];
327  std::string curJoint = rbd_jointNames_[i];
328  std::string nextBody = rbd_bodyNames_[i+1];
329 
330  rbd_mbg_.linkBodies(prevBody, to, nextBody, from, curJoint);
331 
332  }
333 
334 
335  // note: Tasks takes transforms in the successor (child link) frame, so it is the inverse of v-rep
336  rbd_mbs_.push_back(rbd_mbg_.makeMultiBody(ikGroupBaseName_,isFixed,X_base));
337  rbd_mbcs_.push_back(rbd::MultiBodyConfig(rbd_mbs_[0]));
338  rbd_mbcs_[0].zero(rbd_mbs_[0]);
339 
340  // we only have one robot for the moment so the index of it is 0
341  const std::size_t simulatedRobotIndex = 0;
342  auto& simArmMultiBody = rbd_mbs_[simulatedRobotIndex];
343  auto& simArmConfig = rbd_mbcs_[simulatedRobotIndex];
344 
345  // update the simulated arm position
346  for (std::size_t i = 0; i < jointHandles_.size(); ++i) {
347  simSetJointPosition(jointHandles_[i],initialJointAngles[i]);
348  }
349  SetRBDynArmFromVrep(jointNames_,jointHandles_,simArmMultiBody,simArmConfig);
350 
351  rbd::forwardKinematics(simArmMultiBody, simArmConfig);
352  rbd::forwardVelocity(simArmMultiBody, simArmConfig);
353 
354  // set the preferred position to the initial position
355  // https://github.com/jrl-umi3218/Tasks/blob/15aff94e3e03f6a161a87799ca2cf262b756bd0c/src/QPTasks.h#L426
356  rbd_preferred_mbcs_.push_back(simArmConfig);
357 
358  debugFrames();
359 
360  }
361 
362  /// @todo verify object lifetimes
363 
364  // add virtual fixtures? need names and number of rows
365 
366 
367  /// @todo read objective rows from vrep
368 
369  /// @todo set vrep explicit handling of IK here, plus unset in destructor of this object
370 
371  }
372 
373 
374 
375  /// Set dummy frames named Dummy0 to Dummy19 to the current state of the
376  /// RBDyn and V-REP representations of joints for debugging.
377  void debugFrames(bool print = false)
378  {
379  int prevDummy = -1;
380  // we only have one robot for the moment so the index of it is 0
381  const std::size_t simulatedRobotIndex = 0;
382  auto& simArmMultiBody = rbd_mbs_[simulatedRobotIndex];
383  auto& simArmConfig = rbd_mbcs_[simulatedRobotIndex];
384 
385  // Debug output
386  for (std::size_t i=0 ; i < jointHandles_.size() ; i++)
387  {
388  Eigen::Affine3d eto;
389  std::string dummyName2(("Dummy"+ boost::lexical_cast<std::string>(i+11)));
390  int currentDummy2 = simGetObjectHandle(dummyName2.c_str());
391  eto = getObjectTransform(jointHandles_[i],-1);
392  setObjectTransform(currentDummy2,-1,eto);
393  if(print) BOOST_LOG_TRIVIAL(trace) << dummyName2 << " V-REP World\n" << eto.matrix();
394 
395  if(i>0)
396  {
397  Eigen::Affine3d NextJointinPrevFrame(getObjectTransform(jointHandles_[i],jointHandles_[i-1]));
398  if(print) BOOST_LOG_TRIVIAL(trace) << dummyName2 << " V-REP JointInPrevFrame\n" << NextJointinPrevFrame.matrix();
399  }
400 
401  bool dummy_world_frame = true;
402  if( dummy_world_frame )
403  {
404  // visualize each joint position
405  sva::PTransform<double> plinkWorld = simArmConfig.bodyPosW[simArmMultiBody.bodyIndexByName(linkNames_[i])];
406  Eigen::Affine3d linkWorld = PTranformToEigenAffine(plinkWorld);
407  std::string dummyName(("Dummy0"+ boost::lexical_cast<std::string>(i+1)));
408  int currentDummy = simGetObjectHandle(dummyName.c_str());
409  if(print) BOOST_LOG_TRIVIAL(trace) << dummyName << " RBDyn World\n" << linkWorld.matrix();
410  setObjectTransform(currentDummy,-1,linkWorld);
411  prevDummy=currentDummy;
412  sva::PTransform<double> plinkToSon = simArmConfig.parentToSon[simArmMultiBody.bodyIndexByName(linkNames_[i])];
413  Eigen::Affine3d linkToSon = PTranformToEigenAffine(plinkToSon);
414  if(print) BOOST_LOG_TRIVIAL(trace) << dummyName << " RBDyn ParentLinkToSon\n" << linkToSon.matrix();
415 
416  }
417  else
418  {
419  // visualize each joint position
420  sva::PTransform<double> plinkWorld = simArmConfig.parentToSon[simArmMultiBody.bodyIndexByName(linkNames_[i])];
421  Eigen::Affine3d linkWorld = PTranformToEigenAffine(plinkWorld);
422  std::string dummyName(("Dummy0"+ boost::lexical_cast<std::string>(i+1)));
423  int currentDummy = simGetObjectHandle(dummyName.c_str());
424  if(print) BOOST_LOG_TRIVIAL(trace) << dummyName << " RBDyn\n" << linkWorld.matrix();
425  setObjectTransform(currentDummy,prevDummy,linkWorld);
426  prevDummy=currentDummy;
427 
428  }
429  }
430 
431  // Frame "Dummy" with no numbers goes at the tip!
432  Eigen::Affine3d tipTf = PTranformToEigenAffine(simArmConfig.bodyPosW[simArmMultiBody.bodyIndexByName(ikGroupTipName_)]);
433  setObjectTransform(simGetObjectHandle("Dummy"),-1,tipTf);
434  }
435 
436 
437 
438  void testPose(){
439 
440  /// simulation tick time step in float seconds from vrep API call
441  float simulationTimeStep = simGetSimulationTimeStep();
442 
443  // we only have one robot for the moment so the index of it is 0
444  const std::size_t simulatedRobotIndex = 0;
445  auto& simArmMultiBody = rbd_mbs_[simulatedRobotIndex];
446  auto& simArmConfig = rbd_mbcs_[simulatedRobotIndex];
447 
448  std::vector<float> vrepJointAngles;
449  double angle = 0.7;
450  for(auto i : jointHandles_)
451  {
452  angle *= -1;
453  simSetJointPosition(i,angle);
454  vrepJointAngles.push_back(angle);
455  }
456 
457  /// @todo TODO(ahundt) rethink where/when/how to send command for the joint angles. Return to LUA? Set Directly? Distribute via vrep send message command?
458 
459  ////////////////////////////////////////////////////
460  // Set joints to current arm position in simulation
461  SetRBDynArmFromVrep(jointNames_,jointHandles_,simArmMultiBody,simArmConfig);
462  rbd::forwardKinematics(simArmMultiBody, simArmConfig);
463  rbd::forwardVelocity(simArmMultiBody, simArmConfig);
464 
465  debugFrames();
466  }
467 
468 
469  /// Configures updateKinematics with the goal the kinematics should aim for
471  /// Configures updateKinematics the algorithm the kinematics should use for solving
472  enum class AlgToUseE { ik, multiIterQP, singleIterQP };
473  /// Configures if the target pose objective should stick to the constant initalized
474  /// version, or if it should update every iteration in tasks::qp::PostureTask
475  /// https://github.com/jrl-umi3218/Tasks/blob/15aff94e3e03f6a161a87799ca2cf262b756bd0c/src/QPTasks.h#L426
476  enum class PostureTaskStrategyE { constant, updateToCurrent };
477 
478 
479  /// Runs inverse kinematics or constrained optimization at every simulation time step
480  /// @param runOnce Set runOnce = true to only update kinematics once for debugging purposes. runOnce = false runs this function at every time step.
482  const bool runOnce = false,
483  const GoalPosE solveForPosition = GoalPosE::realGoalPosition,
484  const AlgToUseE alg = AlgToUseE::multiIterQP,
486  ){
487  if(runOnce && ranOnce_) return;
488  ranOnce_ = true;
489 
490  jointHandles_ = VrepRobotArmDriverSimulatedP_->getJointHandles();
491 
492 
493  ///////////////////////////////////////////////////////////
494  // Copy Joint Interval, the range of motion for each joint
495 
496  /// @todo TODO(ahundt) change source of current state based on if physical arm is running
498 
499  // lower limits
500  auto & llim = std::get<vrep::VrepRobotArmDriver::JointLowerPositionLimit>(currentArmState_);
501  std::vector<double> llimits(llim.begin(),llim.end());
502 
503  // upper limits
504  auto & ulim = std::get<vrep::VrepRobotArmDriver::JointUpperPositionLimit>(currentArmState_);
505  std::vector<double> ulimits(ulim.begin(),ulim.end());
506 
507  // current position
508  auto & currentJointPos = std::get<vrep::VrepRobotArmDriver::JointPosition>(currentArmState_);
509  std::vector<double> currentJointPosVec(currentJointPos.begin(),currentJointPos.end());
510 
511 
512  const auto& handleParams = VrepRobotArmDriverSimulatedP_->getVrepHandleParams();
513  Eigen::Affine3d currentEndEffectorPose =
515  std::get<vrep::VrepRobotArmDriver::RobotTipName>(handleParams)
516  ,std::get<vrep::VrepRobotArmDriver::RobotTargetBaseName>(handleParams)
517  );
518  auto currentEigenT = currentEndEffectorPose.translation();
519 
520 
521  Eigen::Affine3d desiredEndEffectorPose =
523  std::get<vrep::VrepRobotArmDriver::RobotTargetName>(handleParams)
524  ,std::get<vrep::VrepRobotArmDriver::RobotTargetBaseName>(handleParams)
525  );
526  auto desiredEigenT = desiredEndEffectorPose.translation();
527 
528  //////////////////////
529  /// @todo TODO(ahundt) move code below here back into separate independent setup and solve functions, move some steps like limits to construct()
530 
531  /// simulation tick time step in float seconds from vrep API call
532  float simulationTimeStep = simGetSimulationTimeStep();
533 
534  // we only have one robot for the moment so the index of it is 0
535  const std::size_t simulatedRobotIndex = 0;
536  auto& simArmMultiBody = rbd_mbs_[simulatedRobotIndex];
537  auto& simArmConfig = rbd_mbcs_[simulatedRobotIndex];
538 
539 
540 
541  /// @todo TODO(ahundt) rethink where/when/how to send command for the joint angles. Return to LUA? Set Directly? Distribute via vrep send message command?
542 
543  ////////////////////////////////////////////////////
544  // Set joints to current arm position in simulation
545  SetRBDynArmFromVrep(jointNames_,jointHandles_,simArmMultiBody,simArmConfig);
546  rbd::forwardKinematics(simArmMultiBody, simArmConfig);
547  rbd::forwardVelocity(simArmMultiBody, simArmConfig);
548 
549  // save the current MultiBodyConfig for comparison after running algorithms
551  // set the preferred position to the current position
552  // https://github.com/jrl-umi3218/Tasks/blob/15aff94e3e03f6a161a87799ca2cf262b756bd0c/src/QPTasks.h#L426
554 
555  /// @todo TODO(ahundt) make solver object a member variable if possible, initialize in constructor
556  tasks::qp::QPSolver solver;
557 
558  ////////////////////////////////////////////////////
559  // Set position goal of the arm
560  sva::PTransformd targetWorldTransform;
561 
562  if( solveForPosition == GoalPosE::realGoalPosition )
563  {
564  // go to the real target position
565  targetWorldTransform = getObjectPTransform(ikGroupTargetHandle_);
566  BOOST_LOG_TRIVIAL(trace) << "target translation (vrep format):\n"<< targetWorldTransform.translation();
567  }
568  else
569  {
570  // go to a debugging target position
571  targetWorldTransform = simArmConfig.bodyPosW[simArmMultiBody.bodyIndexByName(ikGroupTipName_)];
572  targetWorldTransform.translation().z() -= 0.0001;
573  BOOST_LOG_TRIVIAL(trace) << "target translation (rbdyn format):\n"<< targetWorldTransform.translation();
574  }
575  tasks::qp::PositionTask posTask(rbd_mbs_, simulatedRobotIndex, ikGroupTipName_,targetWorldTransform.translation());
576  tasks::qp::SetPointTask posTaskSp(rbd_mbs_, simulatedRobotIndex, &posTask, 50., 1.);
577  tasks::qp::OrientationTask oriTask(rbd_mbs_,simulatedRobotIndex, ikGroupTipName_,targetWorldTransform.rotation());
578  tasks::qp::SetPointTask oriTaskSp(rbd_mbs_, simulatedRobotIndex, &oriTask, 50., 1.);
579  tasks::qp::PostureTask postureTask(rbd_mbs_,simulatedRobotIndex,rbd_preferred_mbcs_[simulatedRobotIndex].q,1,0.01);
580 
581  double inf = std::numeric_limits<double>::infinity();
582 
583 
584  ////////////////////////////////////
585  // Set joint limits
586 
587  // joint limit objects, initialize to current q so entries
588  // will be reasonable, such as empty entries for fixed joints
589  std::vector<std::vector<double> > lBound = simArmConfig.q;
590  std::vector<std::vector<double> > uBound = simArmConfig.q;
591  std::vector<std::vector<double> > lVelBound = simArmConfig.alpha;
592  std::vector<std::vector<double> > uVelBound = simArmConfig.alpha;
593 
594 
595  // for all joints
596  for (std::size_t i=0 ; i < rbd_jointHandles_.size()-1; i++)
597  {
598  /// limits must be organized as described in https://github.com/jrl-umi3218/Tasks/issues/10#issuecomment-257793242
599  std::string jointName = rbd_jointNames_[i];
600  std::size_t jointIdx = simArmMultiBody.jointIndexByName(jointName);
601 
602  /// @todo TODO(ahundt) ulimits aren't the same size as jointHandles_, need velocity limits too
603  // set joint position limits
604  if(boost::iequals(jointName,"cutter_joint"))
605  { /// @todo TODO(ahundt) hardcoded mill tip joint limits, remove these
606  lBound[jointIdx][0] = -inf;
607  uBound[jointIdx][0] = inf;
608  }
609  else if(i<llimits.size() && lBound[jointIdx].size()==1)
610  {
611  lBound[jointIdx][0] = llimits[i];
612  uBound[jointIdx][0] = ulimits[i];
613  }
614 
615  // set joint velocity limits
616  if(lVelBound[jointIdx].size()==1)
617  {
618  /// @todo TODO(ahundt) replace hardcoded velocity limits with real and useful limits specific to each joint loaded from V-REP or another file.
619  // 0.99 radians per second is the limit of the slowest joint (joint 1) on the KUKA iiwa R820
620  lVelBound[jointIdx][0] = -0.99;
621  uVelBound[jointIdx][0] = 0.99;
622  }
623  }
624 
625  tasks::qp::DamperJointLimitsConstr dampJointConstr(rbd_mbs_, simulatedRobotIndex, {lBound, uBound},{lVelBound, uVelBound}, 0.125, 0.025, 1., simulationTimeStep);
626 
627  // Test add*Constraint
628  dampJointConstr.addToSolver(solver);
629  BOOST_VERIFY(solver.nrBoundConstraints() == 1);
630  BOOST_VERIFY(solver.nrConstraints() == 1);
631 
632  solver.nrVars(rbd_mbs_, {}, {});
633  solver.updateConstrSize();
634 
635  solver.addTask(&posTaskSp);
636  BOOST_VERIFY(solver.nrTasks() == 1);
637  solver.addTask(&oriTaskSp);
638  solver.addTask(&postureTask);
639 
640  ////////////////////////////////////
641  // Run constrained optimization
642  if(alg == AlgToUseE::ik)
643  {
644  // use basic inverse kinematics to solve for the position
645  //rbd::InverseKinematics ik(simArmMultiBody,simArmMultiBody.jointIndexByName(jointNames_[6]));
646  rbd::InverseKinematics ik(simArmMultiBody,simArmMultiBody.bodyIndexByName(ikGroupTipName_));
647  ik.sInverseKinematics(simArmMultiBody,simArmConfig,targetWorldTransform);
648  // update the simulated arm position
649  }
650  else if( alg == AlgToUseE::multiIterQP)
651  {
652  // multiple iteration version of solving
653  // Test JointLimitsConstr
654  /// @todo TODO(ahundt) was this commented correctly?
655  //simArmConfig = mbcInit;
656  int numSolverIterations = 10;
657  double timeStepDividedIntoIterations = simulationTimeStep/numSolverIterations;
658  // This actually runs every time step, so only one iteration here, unless we want to subdivide
659  // a v-rep time step into smaller rbdyn time steps.
660  for(int i = 0; i < numSolverIterations; ++i)
661  {
662  //BOOST_REQUIRE(solver.solve(rbd_mbs_, rbd_mbcs_));
663  /// @todo TODO(ahundt) remove BOOST_VERIFY(), try/catch solver failure, print an error, send a v-rep message, and shut down solver or enter a hand guiding mode
664  BOOST_VERIFY(solver.solve(rbd_mbs_, rbd_mbcs_));
665  // This should be handled by the simulator or physical robot, "forward simulation of dynamics"
666  //rbd::sEulerIntegration(simArmMultiBody, simArmConfig, timeStepDividedIntoIterations);
667  rbd::sEulerIntegration(simArmMultiBody, simArmConfig, simulationTimeStep);
668 
669  rbd::sForwardKinematics(simArmMultiBody, simArmConfig);
670  rbd::sForwardVelocity(simArmMultiBody, simArmConfig);
671  //BOOST_REQUIRE_GT(simArmConfig.q[1][simulatedRobotIndex], -cst::pi<double>()/4. - 0.01);
672  }
673  }
674  else
675  {
676  // single iteration version of solving
677  BOOST_VERIFY(solver.solve(rbd_mbs_, rbd_mbcs_));
678  rbd::sEulerIntegration(simArmMultiBody, simArmConfig, simulationTimeStep);
679  rbd::sForwardKinematics(simArmMultiBody, simArmConfig);
680  rbd::sForwardVelocity(simArmMultiBody, simArmConfig);
681  // update the simulated arm position
682  }
683 
684  SetVRepArmFromRBDyn(jointNames_,jointHandles_,simArmMultiBody,simArmConfig);
685 
686  debugFrames();
687  } // end updateKinematics()
688 
689  /// may not need this it is in the base class
690  /// blocking call, call in separate thread, just allocates memory
691  void run_one(){
692  const bool ik = true;
693  if(ik) updateKinematics();
694  else testPose();
695  }
696 
697 
698  /// may not need this it is in the base class
699  /// this will have output
700  /// blocking call, call in separate thread, just allocates memory
701  /// this runs the actual optimization algorithm
702  void solve(){
703 
704  }
705 
706  rbd::MultiBodyGraph rbd_mbg_;
707  std::vector<rbd::MultiBody> rbd_mbs_;
708  std::vector<rbd::MultiBodyConfig> rbd_mbcs_;
709  /// rbd_prev_mbcs_ is for debugging
710  std::vector<rbd::MultiBodyConfig> rbd_prev_mbcs_;
711  /// preferred posture to resolve ambiguities
712  std::vector<rbd::MultiBodyConfig> rbd_preferred_mbcs_;
713  std::vector<rbd::Body> rbd_bodies_;
714  std::vector<sva::RBInertia<double>> rbd_inertias_;
715  std::vector<rbd::Joint> rbd_joints_;
716  std::vector<std::string> rbd_bodyNames_;
717  std::vector<int> bodyHandles_;
718  /// rbd "joints" include fixed joints that bridge
719  /// various v-rep objects like the world origin and the ik group base.
720  /// This is organized a bit differently from the v-rep joint names
721  /// because we need additional fixed "joints" so we have transforms
722  /// that match the V-REP scene
723  std::vector<std::string> rbd_jointNames_;
724  /// rbd "joints" include fixed joints that bridge
725  /// various v-rep objects like the world origin and the ik group base.
726  /// This is organized a bit differently from the v-rep joint names
727  /// because we need additional fixed "joints" so we have transforms
728  /// that match the V-REP scene
729  std::vector<int> rbd_jointHandles_;
730 
731 
732  //tasks::qp::QPSolver qp_solver_;
733 
734  std::vector<int> jointHandles_; ///< @todo move this item back into VrepRobotArmDriver
735  std::vector<int> linkHandles_;
736  std::vector<int> linkRespondableHandles_;
737  std::vector<std::string> jointNames_;
738  std::vector<std::string> linkNames_;
739  std::vector<std::string> linkRespondableNames_;
740 
745 
746  std::string ikGroupBaseName_;
747  std::string ikGroupTipName_;
748  std::string ikGroupTargetName_;
749  std::string robotFlangeTipName_; // not part of the V-REP ik group
750 
751  std::shared_ptr<vrep::VrepRobotArmDriver> VrepRobotArmDriverSimulatedP_;
752  std::shared_ptr<vrep::VrepRobotArmDriver> VrepRobotArmDriverMeasuredP_;
754 
755  bool ranOnce_ = false;
756 };
757 
758 } // namespace vrep
759 } // namespace grl
760 
761 #endif
Eigen::Affine3d PTranformToEigenAffine(sva::PTransform< double > &ptransform)
Definition: SpaceVecAlg.hpp:27
std::tuple< std::string,std::string > Params
AlgToUseE
Configures updateKinematics the algorithm the kinematics should use for solving.
ptrSimGetJointPosition simGetJointPosition
Definition: v_repLib.cpp:79
GoalPosE
Configures updateKinematics with the goal the kinematics should aim for.
int getHandle(const std::string &param)
Definition: Vrep.hpp:10
ptrSimGetObjectType simGetObjectType
Definition: v_repLib.cpp:94
ptrSimGetObjectHandle simGetObjectHandle
Definition: v_repLib.cpp:62
Eigen::Affine3d getObjectTransform(int objectHandle, int relativeToObjectHandle=-1)
Definition: Eigen.hpp:135
ptrSimGetIkGroupHandle simGetIkGroupHandle
Definition: v_repLib.cpp:157
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
void SetRBDynArmFromVrep(const std::vector< std::string > &vrepJointNames, const std::vector< int > &vrepJointHandles, const rbd::MultiBody &simArmMultiBody, rbd::MultiBodyConfig &simArmConfig, std::string debug="")
ptrSimSetJointPosition simSetJointPosition
Definition: v_repLib.cpp:80
std::vector< sva::RBInertia< double > > rbd_inertias_
OutputIterator getHandles(const SinglePassRange inputRange, OutputIterator out)
Definition: Vrep.hpp:20
std::shared_ptr< vrep::VrepRobotArmDriver > VrepRobotArmDriverSimulatedP_
void updateKinematics(const bool runOnce=false, const GoalPosE solveForPosition=GoalPosE::realGoalPosition, const AlgToUseE alg=AlgToUseE::multiIterQP, const PostureTaskStrategyE postureStrategy=PostureTaskStrategyE::constant)
void construct(Params params=defaultParams())
void setObjectTransform(int objectHandle, int relativeToObjectHandle, T &transform)
Definition: Eigen.hpp:117
std::shared_ptr< vrep::VrepRobotArmDriver > VrepRobotArmDriverMeasuredP_
void SetVRepArmFromRBDyn(const std::vector< std::string > &vrepJointNames, const std::vector< int > &vrepJointHandles, const rbd::MultiBody &simArmMultiBody, const rbd::MultiBodyConfig &simArmConfig, std::string debug="")
sva::PTransform< double > getObjectPTransform(int objectHandle, int relativeToObjectHandle=-1)
Definition: SpaceVecAlg.hpp:15
std::vector< rbd::MultiBodyConfig > rbd_mbcs_
std::vector< rbd::MultiBodyConfig > rbd_prev_mbcs_
rbd_prev_mbcs_ is for debugging
std::tuple< JointScalar, JointScalar, JointScalar, JointScalar, JointScalar, TransformationMatrices, JointStateTag, JointScalar > State
static const Params measuredArmParams()
ptrSimSetExplicitHandling simSetExplicitHandling
Definition: v_repLib.cpp:267
std::vector< rbd::MultiBodyConfig > rbd_preferred_mbcs_
preferred posture to resolve ambiguities
ptrSimGetSimulationTimeStep simGetSimulationTimeStep
Definition: v_repLib.cpp:181