bio_ik
MoveIt kinematics_base plugin based on particle optimization & GA
problem.cpp
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2016-2017, Philipp Sebastian Ruppel
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #include "ik_base.h"
36 
37 #include <geometric_shapes/bodies.h>
38 #include <geometric_shapes/shapes.h>
39 
40 #include <unordered_set>
41 
42 #include <mutex>
43 
44 #include <bio_ik/goal_types.h>
45 
46 namespace bio_ik
47 {
48 
49 enum class Problem::GoalType
50 {
51  Unknown,
52  Position,
53  Orientation,
54  Pose,
55 };
56 
57 size_t Problem::addTipLink(const moveit::core::LinkModel* link_model)
58 {
59  if(link_tip_indices[link_model->getLinkIndex()] < 0)
60  {
61  link_tip_indices[link_model->getLinkIndex()] = tip_link_indices.size();
62  tip_link_indices.push_back(link_model->getLinkIndex());
63  }
64  return link_tip_indices[link_model->getLinkIndex()];
65 }
66 
67 Problem::Problem()
68  : ros_params_initrd(false)
69 {
70 }
71 
72 void Problem::initialize(moveit::core::RobotModelConstPtr robot_model, const moveit::core::JointModelGroup* joint_model_group, const IKParams& params, const std::vector<const Goal*>& goals2, const BioIKKinematicsQueryOptions* options)
73 {
74  if(robot_model != this->robot_model)
75  {
76  modelInfo = RobotInfo(robot_model);
77 #if (MOVEIT_FCL_VERSION < FCL_VERSION_CHECK(0, 6, 0))
78  collision_links.clear();
79  collision_links.resize(robot_model->getLinkModelCount());
80 #endif
81  }
82 
83  this->robot_model = robot_model;
84  this->joint_model_group = joint_model_group;
85  this->params = params;
86 
87  if(!ros_params_initrd)
88  {
89  ros_params_initrd = true;
90  dpos = params.dpos;
91  drot = params.drot;
92  dtwist = params.dtwist;
93  if(dpos < 0.0 || dpos >= FLT_MAX || !std::isfinite(dpos)) dpos = DBL_MAX;
94  if(drot < 0.0 || drot >= FLT_MAX || !std::isfinite(drot)) drot = DBL_MAX;
95  if(dtwist < 0.0 || dtwist >= FLT_MAX || !std::isfinite(dtwist)) dtwist = DBL_MAX;
96  }
97 
98  link_tip_indices.clear();
99  link_tip_indices.resize(robot_model->getLinkModelCount(), -1);
100  tip_link_indices.clear();
101 
102  active_variables.clear();
103  auto addActiveVariable = [this, robot_model, joint_model_group, options](const std::string& name) -> ssize_t {
104  if(options)
105  {
106  auto& joint_name = robot_model->getJointOfVariable(name)->getName();
107  for(auto& fixed_joint_name : options->fixed_joints)
108  {
109  if(fixed_joint_name == joint_name)
110  {
111  return (ssize_t)-1 - (ssize_t)robot_model->getVariableIndex(name);
112  }
113  }
114  }
115  for(size_t i = 0; i < active_variables.size(); i++)
116  if(name == robot_model->getVariableNames()[active_variables[i]]) return i;
117  for(auto& n : joint_model_group->getVariableNames())
118  {
119  if(n == name)
120  {
121  active_variables.push_back(robot_model->getVariableIndex(name));
122  return active_variables.size() - 1;
123  }
124  }
125  ERROR("joint variable not found", name);
126  };
127 
128  goals.clear();
129  secondary_goals.clear();
130  for(auto& goal : goals2)
131  {
132  GoalInfo goal_info;
133 
134  goal_info.goal = goal;
135 
136  goal->describe(goal_info.goal_context);
137 
138  for(auto& link_name : goal_info.goal_context.goal_link_names_)
139  {
140  auto* link_model = robot_model->getLinkModel(link_name);
141  if(!link_model) ERROR("link not found", link_name);
142  goal_info.goal_context.goal_link_indices_.push_back(addTipLink(link_model));
143  }
144 
145  for(auto& variable_name : goal_info.goal_context.goal_variable_names_)
146  {
147  goal_info.goal_context.goal_variable_indices_.push_back(addActiveVariable(variable_name));
148  }
149 
150  goal_info.weight = goal_info.goal_context.goal_weight_;
151  goal_info.weight_sq = goal_info.weight * goal_info.weight;
152 
153  goal_info.goal_type = GoalType::Unknown;
154 
155  goal_info.frame = Frame::identity();
156  goal_info.tip_index = 0;
157  if(goal_info.goal_context.goal_link_indices_.size()) goal_info.tip_index = goal_info.goal_context.goal_link_indices_[0];
158 
159  if(auto* g = dynamic_cast<const PositionGoal*>(goal_info.goal))
160  {
161  goal_info.goal_type = GoalType::Position;
162  goal_info.frame.pos = g->getPosition();
163  }
164 
165  if(auto* g = dynamic_cast<const OrientationGoal*>(goal_info.goal))
166  {
167  goal_info.goal_type = GoalType::Orientation;
168  goal_info.frame.rot = g->getOrientation();
169  }
170 
171  if(auto* g = dynamic_cast<const PoseGoal*>(goal_info.goal))
172  {
173  goal_info.goal_type = GoalType::Pose;
174  goal_info.frame.pos = g->getPosition();
175  goal_info.frame.rot = g->getOrientation();
176  }
177 
178  goal_info.goal_context.joint_model_group_ = joint_model_group;
179  goal_info.goal_context.initial_guess_ = initial_guess;
180 
181  if(goal_info.goal_context.goal_secondary_)
182  secondary_goals.push_back(goal_info);
183  else
184  goals.push_back(goal_info);
185 
186  // if(goal_info.variable_indices.size() > temp_variables.size()) temp_variables.resize(goal_info.variable_indices.size());
187 
188  // if(goal_info.link_indices.size() > temp_frames.size()) temp_frames.resize(goal_info.link_indices.size());
189  }
190 
191  // update active variables from active subtree
192  joint_usage.resize(robot_model->getJointModelCount());
193  for(auto& u : joint_usage)
194  u = 0;
195  for(auto tip_index : tip_link_indices)
196  for(auto* link_model = robot_model->getLinkModels()[tip_index]; link_model; link_model = link_model->getParentLinkModel())
197  joint_usage[link_model->getParentJointModel()->getJointIndex()] = 1;
198  if(options)
199  for(auto& fixed_joint_name : options->fixed_joints)
200  joint_usage[robot_model->getJointModel(fixed_joint_name)->getJointIndex()] = 0;
201  for(auto* joint_model : joint_model_group->getActiveJointModels())
202  if(joint_usage[joint_model->getJointIndex()] && !joint_model->getMimic())
203  for(auto& n : joint_model->getVariableNames())
204  addActiveVariable(n);
205 
206  // init weights for minimal displacement goals
207  {
208  minimal_displacement_factors.resize(active_variables.size());
209  double s = 0;
210  for(auto ivar : active_variables)
211  s += modelInfo.getMaxVelocityRcp(ivar);
212  if(s > 0)
213  {
214  for(size_t i = 0; i < active_variables.size(); i++)
215  {
216  auto ivar = active_variables[i];
217  minimal_displacement_factors[i] = modelInfo.getMaxVelocityRcp(ivar) / s;
218  }
219  }
220  else
221  {
222  for(size_t i = 0; i < active_variables.size(); i++)
223  minimal_displacement_factors[i] = 1.0 / active_variables.size();
224  }
225  }
226 
227  initialize2();
228 }
229 
230 void Problem::initialize2()
231 {
232  for(auto* gg : {&goals, &secondary_goals})
233  {
234  for(auto& g : *gg)
235  {
236  g.goal_context.problem_active_variables_ = active_variables;
237  g.goal_context.problem_tip_link_indices_ = tip_link_indices;
238  g.goal_context.velocity_weights_ = minimal_displacement_factors;
239  g.goal_context.robot_info_ = &modelInfo;
240  }
241  }
242 }
243 
244 double Problem::computeGoalFitness(GoalInfo& goal_info, const Frame* tip_frames, const double* active_variable_positions)
245 {
246  goal_info.goal_context.tip_link_frames_ = tip_frames;
247  goal_info.goal_context.active_variable_positions_ = active_variable_positions;
248  return goal_info.goal->evaluate(goal_info.goal_context) * goal_info.weight_sq;
249 }
250 
251 double Problem::computeGoalFitness(std::vector<GoalInfo>& goals, const Frame* tip_frames, const double* active_variable_positions)
252 {
253  double sum = 0.0;
254  for(auto& goal : goals)
255  sum += computeGoalFitness(goal, tip_frames, active_variable_positions);
256  return sum;
257 }
258 
259 bool Problem::checkSolutionActiveVariables(const std::vector<Frame>& tip_frames, const double* active_variable_positions)
260 {
261  for(auto& goal : goals)
262  {
263  const auto& fa = goal.frame;
264  const auto& fb = tip_frames[goal.tip_index];
265 
266  switch(goal.goal_type)
267  {
268 
269  case GoalType::Position:
270  {
271  if(dpos != DBL_MAX)
272  {
273  double p_dist = (fb.pos - fa.pos).length();
274  if(!(p_dist <= dpos)) return false;
275  }
276  if(dtwist != DBL_MAX)
277  {
278  KDL::Frame fk_kdl, ik_kdl;
279  frameToKDL(fa, fk_kdl);
280  frameToKDL(fb, ik_kdl);
281  KDL::Twist kdl_diff(fk_kdl.M.Inverse() * KDL::diff(fk_kdl.p, ik_kdl.p), fk_kdl.M.Inverse() * KDL::diff(fk_kdl.M, ik_kdl.M));
282  if(!KDL::Equal(kdl_diff.vel, KDL::Twist::Zero().vel, dtwist)) return false;
283  }
284  continue;
285  }
286 
287  case GoalType::Orientation:
288  {
289  if(drot != DBL_MAX)
290  {
291  double r_dist = fb.rot.angleShortestPath(fa.rot);
292  r_dist = r_dist * 180 / M_PI;
293  if(!(r_dist <= drot)) return false;
294  }
295  if(dtwist != DBL_MAX)
296  {
297  KDL::Frame fk_kdl, ik_kdl;
298  frameToKDL(fa, fk_kdl);
299  frameToKDL(fb, ik_kdl);
300  KDL::Twist kdl_diff(fk_kdl.M.Inverse() * KDL::diff(fk_kdl.p, ik_kdl.p), fk_kdl.M.Inverse() * KDL::diff(fk_kdl.M, ik_kdl.M));
301  if(!KDL::Equal(kdl_diff.rot, KDL::Twist::Zero().rot, dtwist)) return false;
302  }
303  continue;
304  }
305 
306  case GoalType::Pose:
307  {
308  if(dpos != DBL_MAX || drot != DBL_MAX)
309  {
310  double p_dist = (fb.pos - fa.pos).length();
311  double r_dist = fb.rot.angleShortestPath(fa.rot);
312  r_dist = r_dist * 180 / M_PI;
313  if(!(p_dist <= dpos)) return false;
314  if(!(r_dist <= drot)) return false;
315  }
316  if(dtwist != DBL_MAX)
317  {
318  KDL::Frame fk_kdl, ik_kdl;
319  frameToKDL(fa, fk_kdl);
320  frameToKDL(fb, ik_kdl);
321  KDL::Twist kdl_diff(fk_kdl.M.Inverse() * KDL::diff(fk_kdl.p, ik_kdl.p), fk_kdl.M.Inverse() * KDL::diff(fk_kdl.M, ik_kdl.M));
322  if(!KDL::Equal(kdl_diff, KDL::Twist::Zero(), dtwist)) return false;
323  }
324  continue;
325  }
326 
327  default:
328  {
329  double dmax = DBL_MAX;
330  dmax = std::fmin(dmax, dpos);
331  dmax = std::fmin(dmax, dtwist);
332  double d = computeGoalFitness(goal, tip_frames.data(), active_variable_positions);
333  if(!(d < dmax * dmax)) return false;
334  }
335  }
336  }
337 
338  // LOG("checkSolutionActiveVariables true");
339 
340  return true;
341 }
342 }