se2ez
ik.cpp
Go to the documentation of this file.
1 /* Author: Zachary Kingston */
2 
3 #include <iostream>
4 
5 #include <se2ez/core/log.h>
6 #include <se2ez/core/math.h>
7 #include <se2ez/core/state.h>
8 #include <se2ez/core/robot.h>
10 #include <se2ez/core/ik.h>
11 
12 using namespace se2ez;
13 
14 ///
15 /// IKSolver
16 ///
17 
18 IKSolver::IKSolver(const RobotPtr &robot, unsigned int frames)
19  : n_(robot->getNumJoints())
20  , t_(frames)
21  , robot_(robot)
22  , min_(tf::EigenToKDLVec(robot->getLowerLimits()))
23  , max_(tf::EigenToKDLVec(robot->getUpperLimits()))
24  , weights_(KDL::MatrixXd::Identity(n_, n_))
25  , tasks_(KDL::MatrixXd::Identity(6 * t_, 6 * t_))
26 {
27  // We are doing things in 2D, can ignore unimportant components.
28  for (unsigned int i = 0; i < t_; ++i)
29  {
30  setTask(i, POS_Z, false);
31  setTask(i, ROT_X, false);
32  setTask(i, ROT_Y, false);
33  }
34 }
35 
36 void IKSolver::setRestarts(unsigned int restarts)
37 {
38  restarts_ = restarts + 1; ///< Add one since we do at least one iteration without random restart.
39 }
40 
41 void IKSolver::setJointWeight(const std::string &frame, const Eigen::VectorXd &weights)
42 {
43  const auto &data = robot_->getFrameDataConst(frame);
44 
45  for (unsigned int i = 0; i < data->size; ++i)
46  if (weights[i] < 0)
47  {
48  SE2EZ_ERROR("Tried to set joint weights with value less than 0, %1%", tf::printVector(weights));
49  return;
50  }
51 
52  for (unsigned int i = 0; i < data->size; ++i)
53  weights_(data->index + i, data->index + i) = weights[i];
54 }
55 
56 void IKSolver::setJointWeights(const Eigen::VectorXd &weights)
57 {
58  for (unsigned int i = 0; i < n_; ++i)
59  if (weights[i] < 0)
60  {
61  SE2EZ_ERROR("Tried to set joint weights with value less than 0, %1%", tf::printVector(weights));
62  return;
63  }
64 
65  for (unsigned int i = 0; i < n_; ++i)
66  weights_(i, i) = weights[i];
67 }
68 
69 void IKSolver::setLambda(double lambda)
70 {
71  if (lambda < math::eps)
72  {
73  SE2EZ_ERROR("Tried to set lambda value of %1%, <= 0. Value must be > 0", lambda);
74  return;
75  }
76 
77  lambda_ = lambda;
78 }
79 
80 void IKSolver::setRandom(KDL::JntArray &array) const
81 {
82  double v;
83  for (unsigned int i = 0; i < n_; ++i)
84  {
85  KDL::posrandom(v);
86  array(i) = min_(i) + (max_(i) - min_(i)) * v;
87  }
88 }
89 
90 void IKSolver::setRequest(unsigned int task, Request request)
91 {
92  // Set each component of the task with the bitmask.
93  setTask(task, POS_X, (request & X_AXIS) == X_AXIS);
94  setTask(task, POS_Y, (request & Y_AXIS) == Y_AXIS);
95  setTask(task, ROT_Z, (request & ROTATION) == ROTATION);
96 }
97 
98 void IKSolver::setTask(unsigned int task, Index index, bool active)
99 {
100  // Set the diagonal entry of the task matrix.
101  tasks_(task * 6 + index, task * 6 + index) = (active) ? 1.0 : 0.0;
102 }
103 
104 ///
105 /// TreeIK
106 ///
107 
108 TreeIK::TreeIK(const RobotPtr &robot, const std::vector<std::string> &frames, unsigned int iterations,
109  double eps)
110  : IKSolver(robot, frames.size())
111  , frames_([frames]() {
113  for (unsigned int i = 0; i < frames.size(); ++i)
114  f.emplace(frames[i], i);
115 
116  return f;
117  }())
118  , tree_(robot->getTree())
119  , fk_(tree_)
120  , velIK_(tree_, frames)
121  , posIK_(tree_, frames, min_, max_, fk_, velIK_, iterations, eps)
122 {
123  velIK_.setWeightTS(tasks_);
124  velIK_.setLambda(lambda_);
125 }
126 
127 bool TreeIK::setTask(KDL::Frames &goals, const tf::EigenMap<std::string, Eigen::Isometry2d> &frames,
128  const std::map<std::string, Request> &request)
129 {
130  for (const auto &frame : frames_)
131  setRequest(frame.second, Request::ALL);
132 
133  for (const auto &frame : frames)
134  {
135  const auto &name = frame.first;
136  const auto &entry = frames_.find(name);
137 
138  if (entry == frames_.end())
139  {
140  SE2EZ_ERROR("Frame %1% specified for solve not available!", name);
141  return false;
142  }
143 
144  const unsigned int index = entry->second;
145 
146  // Convert goals into KDL type.
147  goals.emplace(name, tf::EigenToKDLFrame(frame.second));
148 
149  // Set active indices according to request.
150  auto req = request.find(name);
151  if (req == request.end())
152  setRequest(index, Request::ALL);
153  else
154  setRequest(index, req->second);
155  }
156 
157  // Set underlying task matrix.
158  velIK_.setWeightTS(tasks_);
159  return true;
160 }
161 
162 bool TreeIK::doIK(KDL::JntArray &in, KDL::JntArray &out, const KDL::Frames &goals)
163 {
164  // If d < 0, then the routine has failed. Random restart.
165  double d = -1;
166  for (unsigned int i = 0; i < restarts_ && d < 0; ++i)
167  {
168  // Set to random values on all iterations but the first.
169  if (i > 0)
170  setRandom(in);
171 
172  d = posIK_.CartToJnt(in, goals, out);
173  if (d == -2)
174  {
175  SE2EZ_ERROR("Frame specified for solve not available!");
176  return false;
177  }
178  }
179 
180  return d >= 0;
181 }
182 
184  const std::map<std::string, Request> &request)
185 {
187 
188  KDL::Frames goals;
189  if (!setTask(goals, frames, request))
190  return false;
191 
192  // Seed with current state to begin.
193  KDL::JntArray in(tf::EigenToKDLVec(state->data));
194  KDL::JntArray out(n_);
195 
196  if (doIK(in, out, goals))
197  {
198  state->data = tf::KDLToEigenVec(out);
199  state->dirty = true;
200 
201  return true;
202  }
203 
204  return false;
205 }
206 
207 void TreeIK::setJointWeight(const std::string &frame, const Eigen::VectorXd &weights)
208 {
209  IKSolver::setJointWeight(frame, weights);
210  velIK_.setWeightJS(weights_);
211 }
212 
213 void TreeIK::setJointWeights(const Eigen::VectorXd &weights)
214 {
215  IKSolver::setJointWeights(weights);
216  velIK_.setWeightJS(weights_);
217 }
218 
219 void TreeIK::setLambda(double lambda)
220 {
221  IKSolver::setLambda(lambda);
222  velIK_.setLambda(lambda_);
223 }
224 
225 ///
226 /// ChainIK
227 ///
228 
229 ChainIK::ChainIK(const RobotPtr &robot, const std::string &frame, unsigned int iterations, double eps)
230  : TreeIK(robot, {frame}, iterations, eps), frame_(frame)
231 {
232 }
233 
235 {
236 }
237 
238 bool ChainIK::solve(StatePtr state, const Eigen::Isometry2d &frame, Request request)
239 {
240  return TreeIK::solve(state, {{frame_, frame}}, {{frame_, request}});
241 }
242 
243 ///
244 /// CollisionAwareTreeIK
245 ///
246 
248  unsigned int iterations, double eps)
249  : TreeIK(robot, frames, iterations, eps)
250  , cm_(std::make_shared<Box2DCollisionManager>(robot))
251  , state_(std::make_shared<State>(robot))
252 {
253 }
254 
255 bool CollisionAwareTreeIK::doIK(KDL::JntArray &in, KDL::JntArray &out, const KDL::Frames &goals)
256 {
257  // If d < 0, then the routine has failed. Random restart.
258  double d = -1;
259 
260  KDL::JntArray temp(out.columns());
261  for (unsigned int i = 0; i < restarts_; ++i)
262  {
263  // Set to random values on all iterations but the first.
264  if (i > 0)
265  setRandom(in);
266 
267  d = posIK_.CartToJnt(in, goals, temp);
268  if (d == -2)
269  {
270  SE2EZ_ERROR("Frame specified for solve not available!");
271  return false;
272  }
273 
274  if (d >= 0)
275  {
276  state_->data = tf::KDLToEigenVec(temp);
277  state_->dirty = true;
278 
279  if (!cm_->collide(state_))
280  {
281  out = temp;
282  return true;
283  }
284  }
285  }
286 
287  return false;
288 }
289 
290 ///
291 /// CollisionAwareChainIK
292 ///
293 
295  unsigned int iterations, double eps)
296  : CollisionAwareTreeIK(robot, {frame}, iterations, eps), frame_(frame)
297 {
298 }
299 
301 {
302 }
303 
304 bool CollisionAwareChainIK::solve(StatePtr state, const Eigen::Isometry2d &frame, Request request)
305 {
306  return CollisionAwareTreeIK::solve(state, {{frame_, frame}}, {{frame_, request}});
307 }
virtual ~CollisionAwareChainIK()
Destructor.
Definition: ik.cpp:300
std::mutex mutex_
Thread mutex.
Definition: ik.h:201
Index
KDL specific indices for different components of the task matrix.
Definition: ik.h:79
const KDL::JntArray min_
Joint minimums.
Definition: ik.h:115
A shared pointer wrapper for se2ez::State.
A collision aware version of tree IK.
Definition: ik.h:260
const std::string frame_
Task frame.
Definition: ik.h:245
void setRequest(unsigned int task, Request request)
Sets the task matrix values for a task at index task according to a request.
Definition: ik.cpp:90
void setJointWeight(const std::string &frame, const Eigen::VectorXd &weights) override
Sets the weights on a specific joint in the robot for IK solving.
Definition: ik.cpp:207
A representation of a state of a Robot.
Definition: state.h:28
bool solve(StatePtr state, const Eigen::Isometry2d &frame, Request request=ALL)
Solve an IK request.
Definition: ik.cpp:238
Y Position.
Definition: ik.h:82
unsigned int restarts_
Number of random restarts.
Definition: ik.h:122
Rotation component.
Definition: ik.h:46
bool solve(StatePtr state, const tf::EigenMap< std::string, Eigen::Isometry2d > &frames, const std::map< std::string, Request > &request={})
Solve an IK request.
Definition: ik.cpp:183
T end(T... args)
virtual void setLambda(double lambda)
Sets lambda, damping constant in WDLS.
Definition: ik.cpp:69
virtual void setJointWeights(const Eigen::VectorXd &weights)
Sets the weights for all joints in the robot for IK solving.
Definition: ik.cpp:56
X Position.
Definition: ik.h:81
bool solve(StatePtr state, const Eigen::Isometry2d &frame, Request request=ALL)
Solve an IK request.
Definition: ik.cpp:304
const std::string frame_
Task frame.
Definition: ik.h:325
CollisionManagerPtr cm_
Collision Manager for IK.
Definition: ik.h:280
Z Position, Ignored as we are 2D.
Definition: ik.h:83
Eigen::VectorXd KDLToEigenVec(const KDL::JntArray &array)
Converts an KDL vector into a Eigen vector.
Definition: math.cpp:74
A collisions manager that uses Box2D as the underlying collision checking engine. ...
Definition: collision.h:41
const unsigned int t_
Number of tasks.
Definition: ik.h:112
const KDL::JntArray max_
Joint maximums.
Definition: ik.h:116
void setRestarts(unsigned int restarts)
Sets the number of random restarts to use when solving a request.
Definition: ik.cpp:36
CollisionAwareTreeIK(const RobotPtr &robot, const std::vector< std::string > &frames, unsigned int iterations=50, double eps=1e-4)
Constructor.
Definition: ik.cpp:247
const KDL::Tree tree_
KDL tree used for solving.
Definition: ik.h:196
static const double eps
Definition: math.h:36
Y Rotation, Ignored as we are 2D.
Definition: ik.h:85
X Rotation, Ignored as we are 2D.
Definition: ik.h:84
Common components of IK solvers.
Definition: ik.h:36
virtual void setJointWeight(const std::string &frame, const Eigen::VectorXd &weights)
Sets the weights on a specific joint in the robot for IK solving.
Definition: ik.cpp:41
double lambda_
Lambda, WDLS constant.
Definition: ik.h:120
virtual ~ChainIK()
Destructor.
Definition: ik.cpp:234
T find(T... args)
T size(T... args)
virtual bool doIK(KDL::JntArray &in, KDL::JntArray &out, const KDL::Frames &goals)
Actually solve an IK query.
Definition: ik.cpp:162
void setRandom(KDL::JntArray &array) const
Sets a KDL array to random values between joint limits.
Definition: ik.cpp:80
KDL::TreeIkSolverVel_wdls velIK_
Inverse velocity solver.
Definition: ik.h:198
void setJointWeights(const Eigen::VectorXd &weights) override
Sets the weights for all joints in the robot for IK solving.
Definition: ik.cpp:213
TreeIK(const RobotPtr &robot, const std::vector< std::string > &frames, unsigned int iterations=50, double eps=1e-4)
Constructor.
Definition: ik.cpp:108
KDL::JntArray EigenToKDLVec(const Eigen::VectorXd &vec)
Converts an Eigen vector into a KDL vector.
Definition: math.cpp:66
A shared pointer wrapper for se2ez::Robot.
IKSolver(const IKSolver &)=delete
std::string printVector(const Eigen::VectorXd &v, unsigned int precision=4)
Returns a string of a vector&#39;s contents.
Definition: math.cpp:90
T emplace(T... args)
KDL::Frame EigenToKDLFrame(const Eigen::Isometry2d &iso)
Converts an Eigen transformation into a KDL transformation.
Definition: math.cpp:48
KDL::MatrixXd weights_
Joint variable weights.
Definition: ik.h:118
Main namespace.
Definition: collision.h:11
#define SE2EZ_ERROR(fmt,...)
Definition: log.h:39
X component.
Definition: ik.h:44
const unsigned int n_
Number of joint variables.
Definition: ik.h:111
void setLambda(double lambda) override
Sets lambda, damping constant in WDLS.
Definition: ik.cpp:219
KDL::TreeIkSolverPos_NR_JL posIK_
Inverse position solver.
Definition: ik.h:199
KDL::MatrixXd tasks_
Task weights.
Definition: ik.h:119
bool setTask(KDL::Frames &goals, const tf::EigenMap< std::string, Eigen::Isometry2d > &frames, const std::map< std::string, Request > &request)
Sets current task matrix and goals according to request.
Definition: ik.cpp:127
Request
A bitmask specification of what task components should this IK request satisfy.
Definition: ik.h:41
KDL::TreeFkSolverPos_recursive fk_
Forward kinematics solver.
Definition: ik.h:197
CollisionAwareChainIK(const RobotPtr &robot, const std::string &frame, unsigned int iterations=50, double eps=1e-4)
Constructor.
Definition: ik.cpp:294
const RobotPtr robot_
Reference to robot.
Definition: ik.h:113
const std::map< std::string, unsigned int > frames_
Mapping of task frame name to index.
Definition: ik.h:194
bool doIK(KDL::JntArray &in, KDL::JntArray &out, const KDL::Frames &goals) override
Actually solve an IK query.
Definition: ik.cpp:255
ChainIK(const RobotPtr &robot, const std::string &frame, unsigned int iterations=50, double eps=1e-4)
Constructor.
Definition: ik.cpp:229
Y component.
Definition: ik.h:45
StatePtr state_
Work state.
Definition: ik.h:281
void setTask(unsigned int task, Index index, bool active)
Sets the specific index component of a task to active.
Definition: ik.cpp:98
Z Rotation.
Definition: ik.h:86