bio_ik
MoveIt kinematics_base plugin based on particle optimization & GA
forward_kinematics.h
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 #pragma once
36 
37 #include "utils.h"
38 #include <bio_ik/goal.h>
39 #include <bio_ik/robot_info.h>
40 #include <kdl/treefksolverpos_recursive.hpp>
41 #include <kdl_parser/kdl_parser.hpp>
42 
43 #if defined(__x86_64__) || defined(__i386__)
44 
45 #include <emmintrin.h>
46 #include <immintrin.h>
47 #include <x86intrin.h>
48 
49 #if(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))
50 #define FUNCTION_MULTIVERSIONING 1
51 #else
52 #define FUNCTION_MULTIVERSIONING 0
53 #endif
54 
55 #else
56 
57 #define FUNCTION_MULTIVERSIONING 0
58 
59 #endif
60 
61 namespace bio_ik
62 {
63 
64 // computes and caches local joint frames
66 {
67 private:
68  std::vector<double> joint_cache_variables;
69  std::vector<Frame> joint_cache_frames;
70  std::vector<Frame> link_frames;
71 
72 protected:
73  std::vector<Vector3> joint_axis_list;
74  moveit::core::RobotModelConstPtr robot_model;
75  std::vector<double> variables;
76 
77 public:
78  inline void getJointFrame(const moveit::core::JointModel* joint_model, const double* variables, Frame& frame)
79  {
80  auto joint_type = joint_model->getType();
81  if(joint_type == moveit::core::JointModel::FIXED)
82  {
83  frame = Frame::identity();
84  return;
85  }
86  size_t joint_index = joint_model->getJointIndex();
87  switch(joint_type)
88  {
89  case moveit::core::JointModel::REVOLUTE:
90  {
91  auto axis = joint_axis_list[joint_index];
92 
93  auto v = variables[joint_model->getFirstVariableIndex()];
94 
95  /*v *= 1.0 / (2 * M_PI);
96  v -= std::floor(v);
97  v *= (2 * M_PI);*/
98 
99  auto half_angle = v * 0.5;
100 
101  // TODO: optimize sin cos
102 
103  auto fcos = cos(half_angle);
104  auto fsin = sin(half_angle);
105 
106  // auto fsin = half_angle;
107  // auto fcos = 1.0 - half_angle * half_angle * 0.5;
108 
109  frame = Frame(Vector3(0.0, 0.0, 0.0), Quaternion(axis.x() * fsin, axis.y() * fsin, axis.z() * fsin, fcos));
110 
111  break;
112  }
113  case moveit::core::JointModel::PRISMATIC:
114  {
115  auto axis = joint_axis_list[joint_index];
116  auto v = variables[joint_model->getFirstVariableIndex()];
117  frame = Frame(axis * v, Quaternion(0.0, 0.0, 0.0, 1.0));
118  break;
119  }
120  case moveit::core::JointModel::FLOATING:
121  {
122  auto* vv = variables + joint_model->getFirstVariableIndex();
123  frame.pos = Vector3(vv[0], vv[1], vv[2]);
124  frame.rot = Quaternion(vv[3], vv[4], vv[5], vv[6]).normalized();
125  // LOG("floating", joint_model->getFirstVariableIndex(), vv[0], vv[1], vv[2], vv[3], vv[4], vv[5], vv[6]);
126  break;
127  }
128  default:
129  {
130  auto* joint_variables = variables + joint_model->getFirstVariableIndex();
131  Eigen::Isometry3d joint_transform;
132  joint_model->computeTransform(joint_variables, joint_transform);
133  frame = Frame(joint_transform);
134  break;
135  }
136  }
137 
138  // LOG("local joint frame", joint_model->getType(), joint_model->getName(), frame);
139  }
140  inline void getJointFrame(const moveit::core::JointModel* joint_model, const std::vector<double>& variables, Frame& frame) { getJointFrame(joint_model, variables.data(), frame); }
141 
142 protected:
143  inline const Frame& getLinkFrame(const moveit::core::LinkModel* link_model) { return link_frames[link_model->getLinkIndex()]; }
144 
145  inline bool checkJointMoved(const moveit::core::JointModel* joint_model)
146  {
147  size_t i0 = joint_model->getFirstVariableIndex();
148  size_t cnt = joint_model->getVariableCount();
149  if(cnt == 0) return true;
150  if(cnt == 1) return !(variables[i0] == joint_cache_variables[i0]);
151  for(size_t i = i0; i < i0 + cnt; i++)
152  if(!(variables[i] == joint_cache_variables[i])) return true;
153  return false;
154  }
155  inline void putJointCache(const moveit::core::JointModel* joint_model, const Frame& frame)
156  {
157  joint_cache_frames[joint_model->getJointIndex()] = frame;
158  size_t i0 = joint_model->getFirstVariableIndex();
159  size_t cnt = joint_model->getVariableCount();
160  for(size_t i = i0; i < i0 + cnt; i++)
161  joint_cache_variables[i] = variables[i];
162  }
163  inline const Frame& getJointFrame(const moveit::core::JointModel* joint_model)
164  {
165  size_t joint_index = joint_model->getJointIndex();
166 
167  if(!checkJointMoved(joint_model)) return joint_cache_frames[joint_index];
168 
169  getJointFrame(joint_model, variables, joint_cache_frames[joint_index]);
170 
171  size_t cnt = joint_model->getVariableCount();
172  if(cnt)
173  {
174  size_t i0 = joint_model->getFirstVariableIndex();
175  if(cnt == 1)
176  joint_cache_variables[i0] = variables[i0];
177  else
178  for(size_t i = i0; i < i0 + cnt; i++)
179  joint_cache_variables[i] = variables[i];
180  }
181 
182  // TODO: optimize copy
183 
184  /*size_t cnt = joint_model->getVariableCount();
185  size_t i0 = joint_model->getFirstVariableIndex();
186  memcpy(joint_cache_variables.data() + i0, variables.data() + i0, cnt * 8);*/
187 
188  return joint_cache_frames[joint_index];
189  }
190 
191 public:
192  RobotJointEvaluator(moveit::core::RobotModelConstPtr model)
193  : robot_model(model)
194  {
195  joint_cache_variables.clear();
196  joint_cache_variables.resize(model->getVariableCount(), DBL_MAX);
197 
198  joint_cache_frames.clear();
199  joint_cache_frames.resize(model->getJointModelCount());
200 
201  link_frames.clear();
202  for(auto* link_model : model->getLinkModels())
203  link_frames.push_back(Frame(link_model->getJointOriginTransform()));
204 
205  joint_axis_list.clear();
206  joint_axis_list.resize(robot_model->getJointModelCount());
207  for(size_t i = 0; i < joint_axis_list.size(); i++)
208  {
209  auto* joint_model = robot_model->getJointModel(i);
210  if(auto* j = dynamic_cast<const moveit::core::RevoluteJointModel*>(joint_model)) joint_axis_list[i] = Vector3(j->getAxis().x(), j->getAxis().y(), j->getAxis().z());
211  if(auto* j = dynamic_cast<const moveit::core::PrismaticJointModel*>(joint_model)) joint_axis_list[i] = Vector3(j->getAxis().x(), j->getAxis().y(), j->getAxis().z());
212  }
213  }
214 };
215 
216 // fast tree fk
218 {
219 protected:
220  std::vector<std::string> tip_names;
221  std::vector<Frame> tip_frames;
222  std::vector<const moveit::core::LinkModel*> tip_links;
223  std::vector<const moveit::core::LinkModel*> link_schedule;
224  std::vector<Frame> global_frames;
225  std::vector<std::vector<const moveit::core::LinkModel*>> link_chains;
226  std::vector<size_t> active_variables;
227  std::vector<std::pair<size_t, size_t>> variable_to_link_map;
228  std::vector<size_t> variable_to_link_map_2;
229  std::vector<std::pair<size_t, size_t>> variable_to_link_chain_map;
230  inline void updateMimic(std::vector<double>& values)
231  {
232  for(auto* joint : robot_model->getMimicJointModels())
233  {
234  auto src = joint->getMimic()->getFirstVariableIndex();
235  auto dest = joint->getFirstVariableIndex();
236 
237  // TODO: more dimensions ???
238  values[dest] = values[src] * joint->getMimicFactor() + joint->getMimicOffset();
239 
240  // moveit doesn't seem to support multiple mimic dimensions either... ???
241 
242  // TODO: ok???
243  // for(size_t base = 0; base < joint->getVariableCount(); base++)
244  // values[base + dest] = values[base + src] * joint->getMimicFactor() + joint->getMimicOffset();
245  }
246  }
247 
248 public:
249  RobotFK_Fast_Base(moveit::core::RobotModelConstPtr model)
250  : RobotJointEvaluator(model)
251  {
252  }
253  void initialize(const std::vector<size_t>& tip_link_indices)
254  {
255 
256  tip_names.resize(tip_link_indices.size());
257  for(size_t i = 0; i < tip_link_indices.size(); i++)
258  tip_names[i] = robot_model->getLinkModelNames()[tip_link_indices[i]];
259 
260  tip_frames.resize(tip_names.size());
261 
262  tip_links.clear();
263  for(const auto& n : tip_names)
264  tip_links.push_back(robot_model->getLinkModel(n));
265 
266  global_frames.resize(robot_model->getLinkModelCount());
267 
268  link_chains.clear();
269  link_schedule.clear();
270  for(auto* tip_link : tip_links)
271  {
272  std::vector<const moveit::core::LinkModel*> chain;
273  for(auto* link = tip_link; link; link = link->getParentLinkModel())
274  chain.push_back(link);
275  reverse(chain.begin(), chain.end());
276  link_chains.push_back(chain);
277  for(auto* link : chain)
278  {
279  if(find(link_schedule.begin(), link_schedule.end(), link) != link_schedule.end()) continue;
280  link_schedule.push_back(link);
281  }
282  }
283 
284  active_variables.clear();
285  for(auto* link_model : link_schedule)
286  {
287  auto link_index = link_model->getLinkIndex();
288  auto* joint_model = link_model->getParentJointModel();
289  size_t vstart = joint_model->getFirstVariableIndex();
290  size_t vcount = joint_model->getVariableCount();
291  for(size_t vi = vstart; vi < vstart + vcount; vi++)
292  {
293  variable_to_link_map.push_back(std::make_pair(vi, link_index));
294 
295  if(find(active_variables.begin(), active_variables.end(), vi) != active_variables.end()) continue;
296  active_variables.push_back(vi);
297  }
298  }
299 
300  variable_to_link_map_2.resize(robot_model->getVariableCount());
301  for(auto* link_model : link_schedule)
302  {
303  auto link_index = link_model->getLinkIndex();
304  auto* joint_model = link_model->getParentJointModel();
305  size_t vstart = joint_model->getFirstVariableIndex();
306  size_t vcount = joint_model->getVariableCount();
307  for(size_t vi = vstart; vi < vstart + vcount; vi++)
308  {
309  variable_to_link_map_2[vi] = link_index;
310  }
311  }
312 
313  variable_to_link_chain_map.resize(robot_model->getVariableCount());
314  for(size_t chain_index = 0; chain_index < link_chains.size(); chain_index++)
315  {
316  auto& link_chain = link_chains[chain_index];
317  for(size_t ipos = 0; ipos < link_chain.size(); ipos++)
318  {
319  auto* link_model = link_chain[ipos];
320  auto* joint_model = link_model->getParentJointModel();
321  size_t vstart = joint_model->getFirstVariableIndex();
322  size_t vcount = joint_model->getVariableCount();
323  for(size_t vi = vstart; vi < vstart + vcount; vi++)
324  {
325  variable_to_link_chain_map[vi] = std::make_pair(chain_index, ipos);
326  }
327  }
328  }
329  }
330  void applyConfiguration(const std::vector<double>& jj0)
331  {
332  FNPROFILER();
333  variables = jj0;
334  updateMimic(variables);
335  for(auto* link_model : link_schedule)
336  {
337  auto* joint_model = link_model->getParentJointModel();
338  auto* parent_link_model = joint_model->getParentLinkModel();
339  if(parent_link_model)
340  {
341  concat(global_frames[parent_link_model->getLinkIndex()], getLinkFrame(link_model), getJointFrame(joint_model), global_frames[link_model->getLinkIndex()]);
342  }
343  else
344  {
345  concat(getLinkFrame(link_model), getJointFrame(joint_model), global_frames[link_model->getLinkIndex()]);
346  }
347  // if(linkModel->getParentLinkModel() && linkModel->getParentLinkModel()->getLinkIndex() > linkModel->getLinkIndex()) { LOG("wrong link order"); throw runtime_error("wrong link order"); }
348  }
349  for(size_t itip = 0; itip < tip_links.size(); itip++)
350  {
351  tip_frames[itip] = global_frames[tip_links[itip]->getLinkIndex()];
352  }
353  }
354  inline const Frame& getTipFrame(size_t fi) const { return tip_frames[fi]; }
355  inline const std::vector<Frame>& getTipFrames() const { return tip_frames; }
356  inline void incrementalBegin(const std::vector<double>& jj) { applyConfiguration(jj); }
357  inline void incrementalEnd() {}
358  inline const Frame& getJointVariableFrame(size_t variable_index) { return global_frames[variable_to_link_map_2[variable_index]]; }
359 };
360 
361 // incremental tip frame updates without full recomputation
363 {
364 protected:
365  std::vector<std::vector<Frame>> chain_cache;
366  std::vector<double> vars, variables0;
367  std::vector<Frame> test_tips;
368  std::vector<uint8_t> links_changed;
369  bool use_incremental;
370  bool last_use_incremental;
371  void updateIncremental(const std::vector<double>& vars0)
372  {
373  FNPROFILER();
374 
375  // PROFILER_COUNTER("incremental update count");
376 
377  // init variable lists
378  vars = vars0;
379  updateMimic(vars);
380  for(auto& vi : active_variables)
381  {
382  // vars[vi] = vars0[vi];
383  variables0[vi] = variables[vi];
384  }
385 
386  // find moved links
387  for(auto* link_model : link_schedule)
388  links_changed[link_model->getLinkIndex()] = false;
389  for(auto& x : variable_to_link_map)
390  {
391  auto variable_index = x.first;
392  auto link_index = x.second;
393  if(vars[variable_index] != variables[variable_index]) links_changed[link_index] = true;
394  }
395 
396  // update
397  for(size_t ichain = 0; ichain < link_chains.size(); ichain++)
398  {
399  auto& link_chain = link_chains[ichain];
400  auto& cache_chain = chain_cache[ichain];
401 
402  size_t iposmax = 0;
403  for(size_t ipos = 0; ipos < link_chain.size(); ipos++)
404  {
405  auto* link_model = link_chain[ipos];
406  bool changed = links_changed[link_model->getLinkIndex()];
407  if(changed) iposmax = ipos;
408  }
409 
410  for(size_t ipos = 0; ipos <= iposmax; ipos++)
411  {
412  auto* link_model = link_chain[ipos];
413  auto* joint_model = link_model->getParentJointModel();
414 
415  bool changed = links_changed[link_model->getLinkIndex()];
416 
417  if(cache_chain.size() <= ipos || changed)
418  {
419  Frame before, after;
420 
421  if(ipos < cache_chain.size())
422  {
423  before = cache_chain[ipos];
424  }
425  else
426  {
427  if(ipos > 0)
428  {
429  concat(cache_chain[ipos - 1], getLinkFrame(link_model), getJointFrame(joint_model), before);
430  }
431  else
432  {
433  concat(getLinkFrame(link_model), getJointFrame(joint_model), before);
434  }
435  }
436 
437  chain_cache[ichain].resize(ipos + 1, Frame::identity());
438 
439  if(changed)
440  {
441  if(ichain > 0 && ipos < link_chains[ichain - 1].size() && link_chains[ichain][ipos] == link_chains[ichain - 1][ipos])
442  {
443  after = chain_cache[ichain - 1][ipos];
444  }
445  else
446  {
447  size_t vstart = joint_model->getFirstVariableIndex();
448  size_t vcount = joint_model->getVariableCount();
449 
450  if(vcount == 1)
451  variables[vstart] = vars[vstart];
452  else
453  for(size_t vi = vstart; vi < vstart + vcount; vi++)
454  variables[vi] = vars[vi];
455 
456  if(ipos > 0)
457  {
458  concat(cache_chain[ipos - 1], getLinkFrame(link_model), getJointFrame(joint_model), after);
459  }
460  else
461  {
462  concat(getLinkFrame(link_model), getJointFrame(joint_model), after);
463  }
464 
465  if(vcount == 1)
466  variables[vstart] = variables0[vstart];
467  else
468  for(size_t vi = vstart; vi < vstart + vcount; vi++)
469  variables[vi] = variables0[vi];
470 
471  // PROFILER_COUNTER("incremental update transforms");
472  }
473  chain_cache[ichain][ipos] = after;
474 
475  // tipFrames[ichain] = inverse(before) * tipFrames[ichain];
476  // tipFrames[ichain] = after * tipFrames[ichain];
477 
478  /*Frame before_inverse;
479  invert(before, before_inverse);
480 
481  //tipFrames[ichain] = after * before_inverse * tipFrames[ichain];
482  {
483  concat(after, before_inverse, tip_frames[ichain], tip_frames[ichain]);
484  }*/
485 
486  change(after, before, tip_frames[ichain], tip_frames[ichain]);
487  }
488  else
489  {
490  after = before;
491  chain_cache[ichain][ipos] = after;
492  }
493  }
494  }
495  }
496 
497  // set new vars
498  // variables = vars;
499  for(auto& vi : active_variables)
500  variables[vi] = vars[vi];
501 
502  // test
503  if(0)
504  {
505  test_tips = tip_frames;
506  RobotFK_Fast_Base::applyConfiguration(vars);
507  for(size_t i = 0; i < tip_frames.size(); i++)
508  {
509  auto dist = tip_frames[i].pos.distance(test_tips[i].pos);
510  LOG_VAR(dist);
511  if(dist > 0.001)
512  {
513  LOG(tip_frames[i].pos.x(), tip_frames[i].pos.y(), tip_frames[i].pos.z());
514  LOG(test_tips[i].pos.x(), test_tips[i].pos.y(), test_tips[i].pos.z());
515  ERROR("incremental update error");
516  }
517  }
518  }
519  }
520 
521 public:
522  RobotFK_Fast(moveit::core::RobotModelConstPtr model)
523  : RobotFK_Fast_Base(model)
524  , use_incremental(false)
525  {
526  }
527  inline void incrementalBegin(const std::vector<double>& jj)
528  {
529  applyConfiguration(jj);
530  chain_cache.clear();
531  chain_cache.resize(tip_frames.size());
532  links_changed.resize(robot_model->getLinkModelCount());
533  vars.resize(jj.size());
534  variables0.resize(jj.size());
535  use_incremental = true;
536  }
537  inline void incrementalEnd()
538  {
539  use_incremental = false;
540  // applyConfiguration(variables);
541  }
542  inline void applyConfiguration(const std::vector<double>& jj)
543  {
544  if(use_incremental)
545  updateIncremental(jj);
546  else
547  RobotFK_Fast_Base::applyConfiguration(jj);
548  }
549 };
550 
551 // fast tree fk jacobian
553 {
554  typedef RobotFK_Fast Base;
555 
556 protected:
557  std::vector<std::vector<const moveit::core::JointModel*>> joint_dependencies;
558  std::vector<int> tip_dependencies;
559 
560 public:
561  RobotFK_Jacobian(moveit::core::RobotModelConstPtr model)
562  : RobotFK_Fast(model)
563  {
564  }
565  void initialize(const std::vector<size_t>& tip_link_indices)
566  {
567  Base::initialize(tip_link_indices);
568  auto tip_count = tip_names.size();
569  joint_dependencies.resize(robot_model->getJointModelCount());
570  for(auto& x : joint_dependencies)
571  x.clear();
572  for(auto* link_model : link_schedule)
573  {
574  auto* joint_model = link_model->getParentJointModel();
575  joint_dependencies[joint_model->getJointIndex()].push_back(joint_model);
576  }
577  for(auto* link_model : link_schedule)
578  {
579  auto* joint_model = link_model->getParentJointModel();
580  if(auto* mimic = joint_model->getMimic())
581  {
582  while(mimic->getMimic() && mimic->getMimic() != joint_model)
583  mimic = mimic->getMimic();
584  joint_dependencies[mimic->getJointIndex()].push_back(joint_model);
585  }
586  }
587  tip_dependencies.resize(robot_model->getJointModelCount() * tip_count);
588  for(auto& x : tip_dependencies)
589  x = 0;
590  for(size_t tip_index = 0; tip_index < tip_count; tip_index++)
591  {
592  for(auto* link_model = tip_links[tip_index]; link_model; link_model = link_model->getParentLinkModel())
593  {
594  auto* joint_model = link_model->getParentJointModel();
595  tip_dependencies[joint_model->getJointIndex() * tip_count + tip_index] = 1;
596  }
597  }
598  }
599  void computeJacobian(const std::vector<size_t>& variable_indices, Eigen::MatrixXd& jacobian)
600  {
601  double step_size = 0.00001;
602  double half_step_size = step_size * 0.5;
603  double inv_step_size = 1.0 / step_size;
604  auto tip_count = tip_frames.size();
605  jacobian.resize(tip_count * 6, variable_indices.size());
606  for(size_t icol = 0; icol < variable_indices.size(); icol++)
607  {
608  for(size_t itip = 0; itip < tip_count; itip++)
609  {
610  jacobian(itip * 6 + 0, icol) = 0;
611  jacobian(itip * 6 + 1, icol) = 0;
612  jacobian(itip * 6 + 2, icol) = 0;
613  jacobian(itip * 6 + 3, icol) = 0;
614  jacobian(itip * 6 + 4, icol) = 0;
615  jacobian(itip * 6 + 5, icol) = 0;
616  }
617  }
618  for(size_t icol = 0; icol < variable_indices.size(); icol++)
619  {
620  auto ivar = variable_indices[icol];
621  auto* var_joint_model = robot_model->getJointOfVariable(ivar);
622  if(var_joint_model->getMimic()) continue;
623  for(auto* joint_model : joint_dependencies[var_joint_model->getJointIndex()])
624  {
625  double scale = 1;
626  for(auto* m = joint_model; m->getMimic() && m->getMimic() != joint_model; m = m->getMimic())
627  {
628  scale *= m->getMimicFactor();
629  }
630  auto* link_model = joint_model->getChildLinkModel();
631  switch(joint_model->getType())
632  {
633  case moveit::core::JointModel::FIXED:
634  {
635  // fixed joint: zero gradient (do nothing)
636  continue;
637  }
638  case moveit::core::JointModel::REVOLUTE:
639  {
640  auto& link_frame = global_frames[link_model->getLinkIndex()];
641  for(size_t itip = 0; itip < tip_count; itip++)
642  {
643  if(!tip_dependencies[joint_model->getJointIndex() * tip_count + itip]) continue;
644 
645  auto& tip_frame = tip_frames[itip];
646 
647  auto q = link_frame.rot.inverse() * tip_frame.rot;
648  q = q.inverse();
649 
650  auto rot = joint_axis_list[joint_model->getJointIndex()];
651  quat_mul_vec(q, rot, rot);
652 
653  auto vel = link_frame.pos - tip_frame.pos;
654  quat_mul_vec(tip_frame.rot.inverse(), vel, vel);
655 
656  vel = vel.cross(rot);
657 
658  jacobian(itip * 6 + 0, icol) += vel.x() * scale;
659  jacobian(itip * 6 + 1, icol) += vel.y() * scale;
660  jacobian(itip * 6 + 2, icol) += vel.z() * scale;
661 
662  jacobian(itip * 6 + 3, icol) += rot.x() * scale;
663  jacobian(itip * 6 + 4, icol) += rot.y() * scale;
664  jacobian(itip * 6 + 5, icol) += rot.z() * scale;
665 
666  // LOG("a", vel.x(), vel.y(), vel.z(), rot.x(), rot.y(), rot.z());
667  }
668  continue;
669  }
670  case moveit::core::JointModel::PRISMATIC:
671  {
672  auto& link_frame = global_frames[link_model->getLinkIndex()];
673  for(size_t itip = 0; itip < tip_count; itip++)
674  {
675  if(!tip_dependencies[joint_model->getJointIndex() * tip_count + itip]) continue;
676 
677  auto& tip_frame = tip_frames[itip];
678 
679  auto q = link_frame.rot.inverse() * tip_frame.rot;
680  q = q.inverse();
681 
682  auto axis = joint_axis_list[joint_model->getJointIndex()];
683  auto v = axis;
684  quat_mul_vec(q, axis, v);
685 
686  jacobian(itip * 6 + 0, icol) += v.x() * scale;
687  jacobian(itip * 6 + 1, icol) += v.y() * scale;
688  jacobian(itip * 6 + 2, icol) += v.z() * scale;
689 
690  // LOG("a", v.x(), v.y(), v.z(), 0, 0, 0);
691  }
692  continue;
693  }
694  default:
695  {
696  // numeric differentiation for joint types that are not yet implemented / or joint types that might be added to moveit in the future
697  auto ivar2 = ivar;
698  if(joint_model->getMimic()) ivar2 = ivar2 - var_joint_model->getFirstVariableIndex() + joint_model->getFirstVariableIndex();
699  auto& link_frame_1 = global_frames[link_model->getLinkIndex()];
700  auto v0 = variables[ivar2];
701  // auto joint_frame_1 = getJointFrame(joint_model);
702  variables[ivar2] = v0 + step_size;
703  auto joint_frame_2 = getJointFrame(joint_model);
704  variables[ivar2] = v0;
705  Frame link_frame_2;
706  if(auto* parent_link_model = joint_model->getParentLinkModel())
707  concat(global_frames[parent_link_model->getLinkIndex()], getLinkFrame(link_model), joint_frame_2, link_frame_2);
708  else
709  concat(getLinkFrame(link_model), joint_frame_2, link_frame_2);
710  for(size_t itip = 0; itip < tip_count; itip++)
711  {
712  if(!tip_dependencies[joint_model->getJointIndex() * tip_count + itip]) continue;
713  auto tip_frame_1 = tip_frames[itip];
714  Frame tip_frame_2;
715  change(link_frame_2, link_frame_1, tip_frame_1, tip_frame_2);
716  auto twist = frameTwist(tip_frame_1, tip_frame_2);
717  jacobian(itip * 6 + 0, icol) += twist.vel.x() * inv_step_size * scale;
718  jacobian(itip * 6 + 1, icol) += twist.vel.y() * inv_step_size * scale;
719  jacobian(itip * 6 + 2, icol) += twist.vel.z() * inv_step_size * scale;
720  jacobian(itip * 6 + 3, icol) += twist.rot.x() * inv_step_size * scale;
721  jacobian(itip * 6 + 4, icol) += twist.rot.y() * inv_step_size * scale;
722  jacobian(itip * 6 + 5, icol) += twist.rot.z() * inv_step_size * scale;
723  }
724  continue;
725  }
726  }
727  }
728  }
729  }
730 };
731 
732 #if 0
733 
734 struct RobotFK : public RobotFK_Jacobian
735 {
736  std::vector<size_t> mutation_variable_indices;
737  std::vector<double> mutation_initial_variable_positions;
738  std::vector<double> mutation_temp;
739  RobotFK(moveit::core::RobotModelConstPtr model)
740  : RobotFK_Jacobian(model)
741  {
742  }
743  void initializeMutationApproximator(const std::vector<size_t>& variable_indices)
744  {
745  mutation_variable_indices = variable_indices;
746  mutation_initial_variable_positions = variables;
747  }
748  void computeApproximateMutation1(size_t variable_index, double variable_delta, const aligned_vector<Frame>& input, aligned_vector<Frame>& output)
749  {
750  mutation_temp = mutation_initial_variable_positions;
751  mutation_temp[variable_index] += variable_delta;
752  applyConfiguration(mutation_temp);
753  output.clear();
754  for(auto& f : tip_frames) output.push_back(f);
755  }
756  void computeApproximateMutations(size_t mutation_count, const double* const* mutation_values, std::vector<aligned_vector<Frame>>& tip_frame_mutations)
757  {
758  auto tip_count = tip_names.size();
759  tip_frame_mutations.resize(mutation_count);
760  for(auto& m : tip_frame_mutations)
761  m.resize(tip_count);
762  for(size_t mutation_index = 0; mutation_index < mutation_count; mutation_index++)
763  {
764  mutation_temp = mutation_initial_variable_positions;
765  for(size_t i = 0; i < mutation_variable_indices.size(); i++)
766  {
767  mutation_temp[mutation_variable_indices[i]] = mutation_values[mutation_index][i];
768  }
769  applyConfiguration(mutation_temp);
770  for(size_t tip_index = 0; tip_index < tip_count; tip_index++)
771  {
772  tip_frame_mutations[mutation_index][tip_index] = tip_frames[tip_index];
773  }
774  }
775  }
776 };
777 
778 #else
779 
780 #define USE_QUADRATIC_EXTRAPOLATION 0
781 
783 {
784  typedef RobotFK_Jacobian Base;
785  Eigen::MatrixXd mutation_approx_jacobian;
786  std::vector<aligned_vector<Frame>> mutation_approx_frames;
787 #if USE_QUADRATIC_EXTRAPOLATION
788  std::vector<aligned_vector<Frame>> mutation_approx_quadratics;
789 #endif
790  std::vector<size_t> mutation_approx_variable_indices;
791  std::vector<std::vector<int>> mutation_approx_mask;
792  std::vector<std::vector<size_t>> mutation_approx_map;
793  aligned_vector<Frame> tip_frames_aligned;
794 
795 public:
796  RobotFK_Mutator(moveit::core::RobotModelConstPtr model)
797  : RobotFK_Jacobian(model)
798  {
799  }
800 
801  void initializeMutationApproximator(const std::vector<size_t>& variable_indices)
802  {
803  FNPROFILER();
804 
805  mutation_approx_variable_indices = variable_indices;
806 
807  auto tip_count = tip_names.size();
808 
809  tip_frames_aligned.resize(tip_frames.size());
810  for(size_t i = 0; i < tip_frames.size(); i++)
811  tip_frames_aligned[i] = tip_frames[i];
812 
813  // init first order approximators
814  {
815  if(mutation_approx_frames.size() < tip_count) mutation_approx_frames.resize(tip_count);
816 
817  for(size_t itip = 0; itip < tip_count; itip++)
818  mutation_approx_frames[itip].resize(robot_model->getVariableCount());
819 
820  for(size_t itip = 0; itip < tip_count; itip++)
821  for(auto ivar : variable_indices)
822  mutation_approx_frames[itip][ivar] = Frame::identity();
823 
824  computeJacobian(variable_indices, mutation_approx_jacobian);
825 
826  for(size_t icol = 0; icol < variable_indices.size(); icol++)
827  {
828  size_t ivar = variable_indices[icol];
829  for(size_t itip = 0; itip < tip_count; itip++)
830  {
831  {
832  Vector3 t;
833  t.setX(mutation_approx_jacobian(itip * 6 + 0, icol));
834  t.setY(mutation_approx_jacobian(itip * 6 + 1, icol));
835  t.setZ(mutation_approx_jacobian(itip * 6 + 2, icol));
836  quat_mul_vec(tip_frames[itip].rot, t, t);
837  mutation_approx_frames[itip][ivar].pos = t;
838  }
839 
840  {
841  Quaternion q;
842  q.setX(mutation_approx_jacobian(itip * 6 + 3, icol) * 0.5);
843  q.setY(mutation_approx_jacobian(itip * 6 + 4, icol) * 0.5);
844  q.setZ(mutation_approx_jacobian(itip * 6 + 5, icol) * 0.5);
845  q.setW(1.0);
846  quat_mul_quat(tip_frames[itip].rot, q, q);
847  q -= tip_frames[itip].rot;
848  mutation_approx_frames[itip][ivar].rot = q;
849  }
850  }
851  }
852  }
853 
854 // init second order approximators
855 #if USE_QUADRATIC_EXTRAPOLATION
856  {
857  if(mutation_approx_quadratics.size() < tip_count) mutation_approx_quadratics.resize(tip_count);
858  for(size_t itip = 0; itip < tip_count; itip++)
859  mutation_approx_quadratics[itip].resize(robot_model->getVariableCount());
860  for(size_t itip = 0; itip < tip_count; itip++)
861  for(auto ivar : variable_indices)
862  mutation_approx_quadratics[itip][ivar].pos = Vector3(0, 0, 0);
863  for(auto ivar : variable_indices)
864  {
865  auto* var_joint_model = robot_model->getJointOfVariable(ivar);
866  if(var_joint_model->getMimic()) continue;
867  for(auto* joint_model : joint_dependencies[var_joint_model->getJointIndex()])
868  {
869  double scale = 1;
870  for(auto* m = joint_model; m->getMimic() && m->getMimic() != joint_model; m = m->getMimic())
871  {
872  scale *= m->getMimicFactor();
873  }
874  auto* link_model = joint_model->getChildLinkModel();
875  switch(joint_model->getType())
876  {
877  case moveit::core::JointModel::REVOLUTE:
878  {
879  auto& link_frame = global_frames[link_model->getLinkIndex()];
880  for(size_t itip = 0; itip < tip_count; itip++)
881  {
882  if(!tip_dependencies[joint_model->getJointIndex() * tip_count + itip]) continue;
883 
884  auto& tip_frame = tip_frames[itip];
885 
886  auto axis = joint_axis_list[joint_model->getJointIndex()];
887  quat_mul_vec(link_frame.rot, axis, axis);
888 
889  auto v = link_frame.pos - tip_frame.pos;
890  v -= axis * v.dot(axis);
891 
892  mutation_approx_quadratics[itip][ivar].pos = v * 0.5 * (scale * scale);
893  }
894  continue;
895  }
896  default:
897  {
898  continue;
899  }
900  }
901  }
902  }
903  }
904 #endif
905 
906  // init mask
907  if(mutation_approx_mask.size() < tip_count) mutation_approx_mask.resize(tip_count);
908  if(mutation_approx_map.size() < tip_count) mutation_approx_map.resize(tip_count);
909  for(size_t itip = 0; itip < tip_count; itip++)
910  {
911  if(mutation_approx_mask[itip].size() < robot_model->getVariableCount()) mutation_approx_mask[itip].resize(robot_model->getVariableCount());
912  mutation_approx_map[itip].clear();
913  for(size_t ii = 0; ii < variable_indices.size(); ii++)
914  // for(size_t ivar : variable_indices)
915  {
916  auto ivar = variable_indices[ii];
917  auto& frame = mutation_approx_frames[itip][ivar];
918  bool b = false;
919  b |= (frame.pos.x() != 0.0);
920  b |= (frame.pos.y() != 0.0);
921  b |= (frame.pos.z() != 0.0);
922  b |= (frame.rot.x() != 0.0);
923  b |= (frame.rot.y() != 0.0);
924  b |= (frame.rot.z() != 0.0);
925  mutation_approx_mask[itip][ivar] = b;
926  if(b) mutation_approx_map[itip].push_back(ii);
927  }
928  }
929  }
930 
931 #if FUNCTION_MULTIVERSIONING
932  __attribute__((hot)) __attribute__((noinline)) __attribute__((target("fma", "avx"))) void computeApproximateMutation1(size_t variable_index, double variable_delta, const aligned_vector<Frame>& input, aligned_vector<Frame>& output) const
933  {
934  // BLOCKPROFILER("computeApproximateMutations C");
935  auto tip_count = tip_names.size();
936  output.resize(tip_count);
937  for(size_t itip = 0; itip < tip_count; itip++)
938  {
939  if(mutation_approx_mask[itip][variable_index] == 0) continue;
940  auto& joint_delta = mutation_approx_frames[itip][variable_index];
941  const Frame& tip_frame = input[itip];
942  const double* tip_frame_ptr = (const double*)&tip_frame;
943  __m256d p = _mm256_load_pd(tip_frame_ptr + 0);
944  __m256d r = _mm256_load_pd(tip_frame_ptr + 4);
945  {
946  auto joint_delta_ptr = (const double* __restrict__) & (joint_delta);
947  __m256d ff = _mm256_set1_pd(variable_delta);
948  p = _mm256_fmadd_pd(ff, _mm256_load_pd(joint_delta_ptr + 0), p);
949  r = _mm256_fmadd_pd(ff, _mm256_load_pd(joint_delta_ptr + 4), r);
950  }
951 #if USE_QUADRATIC_EXTRAPOLATION
952  {
953  auto joint_delta_ptr = (const double* __restrict__) & (mutation_approx_quadratics[itip][variable_index]);
954  __m256d ff = _mm256_set1_pd(variable_delta * variable_delta);
955  p = _mm256_fmadd_pd(ff, _mm256_load_pd(joint_delta_ptr + 0), p);
956  }
957 #endif
958  auto& tip_mutation = output[itip];
959  double* __restrict__ tip_mutation_ptr = (double*)&tip_mutation;
960  _mm256_store_pd(tip_mutation_ptr + 0, p);
961  _mm256_store_pd(tip_mutation_ptr + 4, r);
962  }
963  }
964 
965  __attribute__((hot)) __attribute__((noinline)) __attribute__((target("sse2"))) void computeApproximateMutation1(size_t variable_index, double variable_delta, const aligned_vector<Frame>& input, aligned_vector<Frame>& output) const
966  {
967  // BLOCKPROFILER("computeApproximateMutations C");
968  auto tip_count = tip_names.size();
969  output.resize(tip_count);
970  for(size_t itip = 0; itip < tip_count; itip++)
971  {
972  if(mutation_approx_mask[itip][variable_index] == 0) continue;
973  auto& joint_delta = mutation_approx_frames[itip][variable_index];
974  const Frame& tip_frame = input[itip];
975  const double* tip_frame_ptr = (const double*)&tip_frame;
976  __m128d pxy = _mm_load_pd(tip_frame_ptr + 0);
977  __m128d pzw = _mm_load_sd(tip_frame_ptr + 2);
978  __m128d rxy = _mm_load_pd(tip_frame_ptr + 4);
979  __m128d rzw = _mm_load_pd(tip_frame_ptr + 6);
980  {
981  auto joint_delta_ptr = (const double* __restrict__) & (joint_delta);
982  __m128d ff = _mm_set1_pd(variable_delta);
983  pxy = _mm_add_pd(pxy, _mm_mul_pd(ff, _mm_load_pd(joint_delta_ptr + 0)));
984  pzw = _mm_add_sd(pzw, _mm_mul_sd(ff, _mm_load_sd(joint_delta_ptr + 2)));
985  rxy = _mm_add_pd(rxy, _mm_mul_pd(ff, _mm_load_pd(joint_delta_ptr + 4)));
986  rzw = _mm_add_pd(rzw, _mm_mul_pd(ff, _mm_load_pd(joint_delta_ptr + 6)));
987  }
988 #if USE_QUADRATIC_EXTRAPOLATION
989  {
990  auto joint_delta_ptr = (const double* __restrict__) & (mutation_approx_quadratics[itip][variable_index]);
991  __m128d ff = _mm_set1_pd(variable_delta * variable_delta);
992  pxy = _mm_add_pd(pxy, _mm_mul_pd(ff, _mm_load_pd(joint_delta_ptr + 0)));
993  pzw = _mm_add_sd(pzw, _mm_mul_sd(ff, _mm_load_sd(joint_delta_ptr + 2)));
994  }
995 #endif
996  auto& tip_mutation = output[itip];
997  double* __restrict__ tip_mutation_ptr = (double*)&tip_mutation;
998  _mm_store_pd(tip_mutation_ptr + 0, pxy);
999  _mm_store_sd(tip_mutation_ptr + 2, pzw);
1000  _mm_store_pd(tip_mutation_ptr + 4, rxy);
1001  _mm_store_pd(tip_mutation_ptr + 6, rzw);
1002  }
1003  }
1004 
1005  __attribute__((hot)) __attribute__((noinline)) __attribute__((target("default")))
1006 #endif
1007  void
1008  computeApproximateMutation1(size_t variable_index, double variable_delta, const aligned_vector<Frame>& input, aligned_vector<Frame>& output) const
1009  {
1010  // BLOCKPROFILER("computeApproximateMutations C");
1011  auto tip_count = tip_names.size();
1012  output.resize(tip_count);
1013  for(size_t itip = 0; itip < tip_count; itip++)
1014  {
1015  if(mutation_approx_mask[itip][variable_index] == 0) continue;
1016 
1017  auto& joint_delta = mutation_approx_frames[itip][variable_index];
1018 
1019  const Frame& tip_frame = input[itip];
1020 
1021  double px = tip_frame.pos.x();
1022  double py = tip_frame.pos.y();
1023  double pz = tip_frame.pos.z();
1024 
1025  double rx = tip_frame.rot.x();
1026  double ry = tip_frame.rot.y();
1027  double rz = tip_frame.rot.z();
1028  double rw = tip_frame.rot.w();
1029 
1030  px += joint_delta.pos.x() * variable_delta;
1031  py += joint_delta.pos.y() * variable_delta;
1032  pz += joint_delta.pos.z() * variable_delta;
1033 
1034 #if USE_QUADRATIC_EXTRAPOLATION
1035  double variable_delta_sq = variable_delta * variable_delta;
1036  px += mutation_approx_quadratics[itip][variable_index].pos.x() * variable_delta_sq;
1037  py += mutation_approx_quadratics[itip][variable_index].pos.y() * variable_delta_sq;
1038  pz += mutation_approx_quadratics[itip][variable_index].pos.z() * variable_delta_sq;
1039 #endif
1040 
1041  rx += joint_delta.rot.x() * variable_delta;
1042  ry += joint_delta.rot.y() * variable_delta;
1043  rz += joint_delta.rot.z() * variable_delta;
1044  rw += joint_delta.rot.w() * variable_delta;
1045 
1046  auto& tip_mutation = output[itip];
1047 
1048  tip_mutation.pos.setX(px);
1049  tip_mutation.pos.setY(py);
1050  tip_mutation.pos.setZ(pz);
1051 
1052  tip_mutation.rot.setX(rx);
1053  tip_mutation.rot.setY(ry);
1054  tip_mutation.rot.setZ(rz);
1055  tip_mutation.rot.setW(rw);
1056  }
1057  }
1058 
1059 #if FUNCTION_MULTIVERSIONING
1060  __attribute__((hot)) __attribute__((noinline)) __attribute__((target("fma", "avx"))) void computeApproximateMutations(size_t mutation_count, const double* const* mutation_values, std::vector<aligned_vector<Frame>>& tip_frame_mutations) const
1061  {
1062  const double* p_variables = variables.data();
1063  auto tip_count = tip_names.size();
1064  tip_frame_mutations.resize(mutation_count);
1065  for(auto& m : tip_frame_mutations)
1066  m.resize(tip_count);
1067  for(size_t itip = 0; itip < tip_count; itip++)
1068  {
1069  auto& joint_deltas = mutation_approx_frames[itip];
1070 
1071  const Frame& tip_frame = tip_frames_aligned[itip];
1072 
1073  const double* tip_frame_ptr = (const double*)&tip_frame;
1074  __m256d p0 = _mm256_load_pd(tip_frame_ptr + 0);
1075  __m256d r0 = _mm256_load_pd(tip_frame_ptr + 4);
1076 
1077  for(size_t imutation = 0; imutation < mutation_count; imutation++)
1078  {
1079  auto p = p0;
1080  auto r = r0;
1081 
1082  for(size_t vii : mutation_approx_map[itip])
1083  {
1084  size_t variable_index = mutation_approx_variable_indices[vii];
1085  double variable_delta = mutation_values[imutation][vii] - p_variables[variable_index];
1086 
1087  {
1088  auto joint_delta_ptr = (const double* __restrict__) & (joint_deltas[variable_index]);
1089  __m256d ff = _mm256_set1_pd(variable_delta);
1090  p = _mm256_fmadd_pd(ff, _mm256_load_pd(joint_delta_ptr + 0), p);
1091  r = _mm256_fmadd_pd(ff, _mm256_load_pd(joint_delta_ptr + 4), r);
1092  }
1093 
1094 #if USE_QUADRATIC_EXTRAPOLATION
1095  {
1096  auto joint_delta_ptr = (const double* __restrict__) & (mutation_approx_quadratics[itip][variable_index]);
1097  __m256d ff = _mm256_set1_pd(variable_delta * variable_delta);
1098  p = _mm256_fmadd_pd(ff, _mm256_load_pd(joint_delta_ptr + 0), p);
1099  }
1100 #endif
1101  }
1102 
1103  auto& tip_mutation = tip_frame_mutations[imutation][itip];
1104  double* __restrict__ tip_mutation_ptr = (double*)&tip_mutation;
1105  _mm256_store_pd(tip_mutation_ptr + 0, p);
1106  _mm256_store_pd(tip_mutation_ptr + 4, r);
1107  }
1108  }
1109  }
1110 
1111  __attribute__((hot)) __attribute__((noinline)) __attribute__((target("sse2"))) void computeApproximateMutations(size_t mutation_count, const double* const* mutation_values, std::vector<aligned_vector<Frame>>& tip_frame_mutations) const
1112  {
1113  const double* p_variables = variables.data();
1114  auto tip_count = tip_names.size();
1115  tip_frame_mutations.resize(mutation_count);
1116  for(auto& m : tip_frame_mutations)
1117  m.resize(tip_count);
1118  for(size_t itip = 0; itip < tip_count; itip++)
1119  {
1120  auto& joint_deltas = mutation_approx_frames[itip];
1121 
1122  const Frame& tip_frame = tip_frames_aligned[itip];
1123 
1124  const double* tip_frame_ptr = (const double*)&tip_frame;
1125  __m128d pxy0 = _mm_load_pd(tip_frame_ptr + 0);
1126  __m128d pzw0 = _mm_load_sd(tip_frame_ptr + 2);
1127  __m128d rxy0 = _mm_load_pd(tip_frame_ptr + 4);
1128  __m128d rzw0 = _mm_load_pd(tip_frame_ptr + 6);
1129 
1130  for(size_t imutation = 0; imutation < mutation_count; imutation++)
1131  {
1132  auto pxy = pxy0;
1133  auto pzw = pzw0;
1134  auto rxy = rxy0;
1135  auto rzw = rzw0;
1136 
1137  for(size_t vii : mutation_approx_map[itip])
1138  {
1139  size_t variable_index = mutation_approx_variable_indices[vii];
1140  double variable_delta = mutation_values[imutation][vii] - p_variables[variable_index];
1141 
1142  {
1143  auto joint_delta_ptr = (const double* __restrict__) & (joint_deltas[variable_index]);
1144  __m128d ff = _mm_set1_pd(variable_delta);
1145  pxy = _mm_add_pd(_mm_mul_pd(ff, _mm_load_pd(joint_delta_ptr + 0)), pxy);
1146  pzw = _mm_add_sd(_mm_mul_sd(ff, _mm_load_sd(joint_delta_ptr + 2)), pzw);
1147  rxy = _mm_add_pd(_mm_mul_pd(ff, _mm_load_pd(joint_delta_ptr + 4)), rxy);
1148  rzw = _mm_add_pd(_mm_mul_pd(ff, _mm_load_pd(joint_delta_ptr + 6)), rzw);
1149  }
1150 
1151 #if USE_QUADRATIC_EXTRAPOLATION
1152  {
1153  auto joint_delta_ptr = (const double* __restrict__) & (mutation_approx_quadratics[itip][variable_index]);
1154  __m128d ff = _mm_set1_pd(variable_delta * variable_delta);
1155  pxy = _mm_add_pd(_mm_mul_pd(ff, _mm_load_pd(joint_delta_ptr + 0)), pxy);
1156  pzw = _mm_add_sd(_mm_mul_sd(ff, _mm_load_sd(joint_delta_ptr + 2)), pzw);
1157  }
1158 #endif
1159  }
1160 
1161  auto& tip_mutation = tip_frame_mutations[imutation][itip];
1162  double* __restrict__ tip_mutation_ptr = (double*)&tip_mutation;
1163  _mm_store_pd(tip_mutation_ptr + 0, pxy);
1164  _mm_store_sd(tip_mutation_ptr + 2, pzw);
1165  _mm_store_pd(tip_mutation_ptr + 4, rxy);
1166  _mm_store_pd(tip_mutation_ptr + 6, rzw);
1167  }
1168  }
1169  }
1170 
1171  __attribute__((hot)) __attribute__((noinline)) __attribute__((target("default")))
1172 #endif
1173  void
1174  computeApproximateMutations(size_t mutation_count, const double* const* mutation_values, std::vector<aligned_vector<Frame>>& tip_frame_mutations) const
1175  {
1176  const double* p_variables = variables.data();
1177  auto tip_count = tip_names.size();
1178  tip_frame_mutations.resize(mutation_count);
1179  for(auto& m : tip_frame_mutations)
1180  m.resize(tip_count);
1181  for(size_t itip = 0; itip < tip_count; itip++)
1182  {
1183  auto& joint_deltas = mutation_approx_frames[itip];
1184 
1185  const Frame& tip_frame = tip_frames[itip];
1186  for(size_t imutation = 0; imutation < mutation_count; imutation++)
1187  {
1188  double px = tip_frame.pos.x();
1189  double py = tip_frame.pos.y();
1190  double pz = tip_frame.pos.z();
1191 
1192  double rx = tip_frame.rot.x();
1193  double ry = tip_frame.rot.y();
1194  double rz = tip_frame.rot.z();
1195  double rw = tip_frame.rot.w();
1196 
1197  for(size_t vii : mutation_approx_map[itip])
1198  {
1199  size_t variable_index = mutation_approx_variable_indices[vii];
1200 
1201  double variable_delta = mutation_values[imutation][vii] - p_variables[variable_index];
1202 
1203  px += joint_deltas[variable_index].pos.x() * variable_delta;
1204  py += joint_deltas[variable_index].pos.y() * variable_delta;
1205  pz += joint_deltas[variable_index].pos.z() * variable_delta;
1206 
1207 #if USE_QUADRATIC_EXTRAPOLATION
1208  double variable_delta_sq = variable_delta * variable_delta;
1209  px += mutation_approx_quadratics[itip][variable_index].pos.x() * variable_delta_sq;
1210  py += mutation_approx_quadratics[itip][variable_index].pos.y() * variable_delta_sq;
1211  pz += mutation_approx_quadratics[itip][variable_index].pos.z() * variable_delta_sq;
1212 #endif
1213 
1214  rx += joint_deltas[variable_index].rot.x() * variable_delta;
1215  ry += joint_deltas[variable_index].rot.y() * variable_delta;
1216  rz += joint_deltas[variable_index].rot.z() * variable_delta;
1217  rw += joint_deltas[variable_index].rot.w() * variable_delta;
1218  }
1219 
1220  auto& tip_mutation = tip_frame_mutations[imutation][itip];
1221 
1222  tip_mutation.pos.setX(px);
1223  tip_mutation.pos.setY(py);
1224  tip_mutation.pos.setZ(pz);
1225 
1226  tip_mutation.rot.setX(rx);
1227  tip_mutation.rot.setY(ry);
1228  tip_mutation.rot.setZ(rz);
1229  tip_mutation.rot.setW(rw);
1230  }
1231  }
1232  }
1233 };
1234 
1235 #if 0
1236 class RobotFK_Mutator_2 : public RobotFK_Mutator
1237 {
1238  struct JointApprox
1239  {
1240  ssize_t mutation_index;
1241  ssize_t variable_index;
1242  Vector3 delta_position;
1243  Vector3 delta_rotation;
1244  size_t link_index;
1245  size_t parent_link_index;
1246  Vector3 link_position;
1247  };
1248  std::vector<JointApprox> joint_approximators;
1249 
1250  struct LinkApprox
1251  {
1252  Vector3 position;
1253  Vector3 rotation;
1254  };
1255  std::vector<LinkApprox> link_approximators;
1256 
1257  std::vector<int> link_approx_mask;
1258 
1259  std::vector<std::vector<size_t>> variable_to_approximator_index_map;
1260 
1261 public:
1262  RobotFK_Mutator_2(moveit::core::RobotModelConstPtr model)
1263  : RobotFK_Mutator(model)
1264  {
1265  }
1266 
1267  void initializeMutationApproximator(const std::vector<size_t>& variable_indices)
1268  {
1269  RobotFK_Mutator::initializeMutationApproximator(variable_indices);
1270 
1271  BLOCKPROFILER("initializeMutationApproximator tree");
1272 
1273  auto tip_count = tip_names.size();
1274 
1275  link_approximators.resize(robot_model->getLinkModelCount() + 1);
1276  for(auto& l : link_approximators)
1277  {
1278  l.position = Vector3(0, 0, 0);
1279  l.rotation = Vector3(0, 0, 0);
1280  }
1281 
1282  link_approx_mask.clear();
1283  link_approx_mask.resize(robot_model->getLinkModelCount(), 0);
1284 
1285  joint_approximators.clear();
1286 
1287  // build joint approximators
1288  for(size_t imut = 0; imut < variable_indices.size(); imut++)
1289  {
1290  size_t ivar = variable_indices[imut];
1291  auto* joint_model = robot_model->getJointOfVariable(ivar);
1292  {
1293  auto* link_model = joint_model->getChildLinkModel();
1294  // if(link_approx_mask[link_model->getLinkIndex()]) continue;
1295  joint_approximators.emplace_back();
1296  auto& joint = joint_approximators.back();
1297  joint.mutation_index = imut;
1298  joint.variable_index = ivar;
1299  joint.link_index = link_model->getLinkIndex();
1300  link_approx_mask[link_model->getLinkIndex()] = 1;
1301  }
1302  for(auto* mimic_joint_model : joint_model->getMimicRequests())
1303  {
1304  // LOG("mimic", mimic_joint_model);
1305  auto* joint_model = mimic_joint_model;
1306  auto* link_model = joint_model->getChildLinkModel();
1307  // if(link_approx_mask[link_model->getLinkIndex()]) continue;
1308  joint_approximators.emplace_back();
1309  auto& joint = joint_approximators.back();
1310  joint.mutation_index = imut;
1311  joint.variable_index = ivar;
1312  joint.link_index = link_model->getLinkIndex();
1313  link_approx_mask[link_model->getLinkIndex()] = 1;
1314  }
1315  }
1316 
1317  for(auto& joint : joint_approximators)
1318  {
1319  // size_t imut = joint.mutation_index;
1320  // size_t ivar = joint.variable_index;
1321  auto* link_model = robot_model->getLinkModel(joint.link_index);
1322  auto* joint_model = link_model->getParentJointModel();
1323  joint.delta_position = Vector3(0, 0, 0);
1324  joint.delta_rotation = Vector3(0, 0, 0);
1325  auto& link_frame = global_frames[link_model->getLinkIndex()];
1326  switch(joint_model->getType())
1327  {
1328  case moveit::core::JointModel::REVOLUTE:
1329  quat_mul_vec(link_frame.rot, joint_axis_list[joint_model->getJointIndex()], joint.delta_rotation);
1330  break;
1331  case moveit::core::JointModel::PRISMATIC:
1332  quat_mul_vec(link_frame.rot, joint_axis_list[joint_model->getJointIndex()], joint.delta_position);
1333  break;
1334  }
1335  for(auto* j = joint_model; j->getMimic(); j = j->getMimic())
1336  {
1337  joint.delta_rotation *= j->getMimicFactor();
1338  joint.delta_position *= j->getMimicFactor();
1339  break;
1340  }
1341  }
1342 
1343  // continue extrapolation to tip frames, if not already done
1344  for(auto* link_model : tip_links)
1345  {
1346  if(link_approx_mask[link_model->getLinkIndex()]) continue;
1347  joint_approximators.emplace_back();
1348  auto& joint = joint_approximators.back();
1349  joint.mutation_index = 0;
1350  joint.variable_index = 0;
1351  joint.link_index = link_model->getLinkIndex();
1352  joint.delta_position = Vector3(0, 0, 0);
1353  joint.delta_rotation = Vector3(0, 0, 0);
1354  link_approx_mask[link_model->getLinkIndex()] = 1;
1355  }
1356 
1357  std::sort(joint_approximators.begin(), joint_approximators.end(), [](const JointApprox& a, const JointApprox& b) { return a.link_index < b.link_index; });
1358 
1359  for(auto& joint : joint_approximators)
1360  {
1361  for(auto* link_model = robot_model->getLinkModel(joint.link_index); link_model;)
1362  {
1363  if(link_approx_mask[link_model->getLinkIndex()] >= 2)
1364  {
1365  joint.parent_link_index = link_model->getLinkIndex();
1366  joint.link_position = global_frames[joint.link_index].pos - global_frames[joint.parent_link_index].pos;
1367  link_approx_mask[joint.link_index] = 2;
1368  break;
1369  }
1370  link_model = link_model->getParentLinkModel();
1371  if(link_model == 0)
1372  {
1373  joint.parent_link_index = robot_model->getLinkModelCount();
1374  joint.link_position = global_frames[joint.link_index].pos;
1375  link_approx_mask[joint.link_index] = 2;
1376  break;
1377  }
1378  }
1379  }
1380 
1381  variable_to_approximator_index_map.resize(robot_model->getVariableCount());
1382  for(auto& l : variable_to_approximator_index_map)
1383  l.clear();
1384  for(size_t approximator_index = 0; approximator_index < joint_approximators.size(); approximator_index++)
1385  {
1386  if(joint_approximators[approximator_index].variable_index < 0) continue;
1387  variable_to_approximator_index_map[joint_approximators[approximator_index].variable_index].push_back(approximator_index);
1388  }
1389  }
1390 
1391  void computeApproximateMutations(size_t mutation_count, const double* const* mutation_values, std::vector<aligned_vector<Frame>>& tip_frame_mutations)
1392  {
1393  auto tip_count = tip_names.size();
1394  tip_frame_mutations.resize(mutation_count);
1395  for(auto& m : tip_frame_mutations)
1396  m.resize(tip_count);
1397  for(size_t imutation = 0; imutation < mutation_count; imutation++)
1398  {
1399  for(auto& joint : joint_approximators)
1400  {
1401  double dvar;
1402  /*if(joint.mutation_index < 0)
1403  dvar = 0;
1404  else*/
1405  dvar = mutation_values[imutation][joint.mutation_index] - variables[joint.variable_index];
1406 
1407  Vector3 dpos = joint.delta_position * dvar + joint.link_position;
1408 
1409  auto& parent = link_approximators[joint.parent_link_index];
1410 
1411  // if(dpos.x() || dpos.y() || dpos.z())
1412  {
1413  Vector3 dpos1 = Vector3(parent.rotation.y() * dpos.z() - parent.rotation.z() * dpos.y(), parent.rotation.z() * dpos.x() - parent.rotation.x() * dpos.z(), parent.rotation.x() * dpos.y() - parent.rotation.y() * dpos.x());
1414 
1415  /*double xx = 0.5 * parent.rotation.x() * parent.rotation.x();
1416  double yy = 0.5 * parent.rotation.y() * parent.rotation.y();
1417  double zz = 0.5 * parent.rotation.z() * parent.rotation.z();
1418 
1419  Vector3 dpos2 = Vector3(
1420  dpos.x() * (yy + zz),
1421  dpos.y() * (xx + zz),
1422  dpos.z() * (xx + yy)
1423  );*/
1424 
1425  dpos += dpos1;
1426  }
1427 
1428  // dpos -= dpos2;
1429 
1430  auto& link = link_approximators[joint.link_index];
1431  link.position = parent.position + dpos;
1432  link.rotation = parent.rotation + joint.delta_rotation * dvar;
1433  }
1434 
1435  for(size_t itip = 0; itip < tip_count; itip++)
1436  {
1437  const Frame& tip_frame = tip_frames[itip];
1438  auto& tip_mutation = tip_frame_mutations[imutation][itip];
1439  auto& link = link_approximators[tip_links[itip]->getLinkIndex()];
1440  tip_mutation.pos = link.position;
1441 
1442  tip_mutation.rot = tf2::Quaternion(link.rotation.x() * 0.5, link.rotation.y() * 0.5, link.rotation.z() * 0.5, 1.0) * tip_frame.rot;
1443 
1444  /*tip_mutation.rot = tf2::Quaternion(
1445  link.rotation.x() * 0.5,
1446  link.rotation.y() * 0.5,
1447  link.rotation.z() * 0.5,
1448  1.0
1449  - link.rotation.length2() * 0.125
1450  ) * tip_frame.rot;*/
1451  }
1452  }
1453  }
1454 };
1455 
1456 typedef RobotFK_Mutator_2 RobotFK;
1457 
1458 #else
1459 
1460 typedef RobotFK_Mutator RobotFK;
1461 
1462 #endif
1463 
1464 #endif
1465 
1466 // for comparison
1468 {
1469  moveit::core::RobotModelConstPtr robot_model;
1470  moveit::core::RobotState robot_state;
1471  std::vector<Frame> tipFrames;
1472  std::vector<const moveit::core::LinkModel*> tipLinks;
1473  std::vector<double> jj;
1474 
1475 public:
1476  RobotFK_MoveIt(moveit::core::RobotModelConstPtr model)
1477  : robot_model(model)
1478  , robot_state(model)
1479  {
1480  }
1481  void initialize(const std::vector<size_t>& tip_link_indices)
1482  {
1483  tipFrames.resize(tip_link_indices.size());
1484  tipLinks.resize(tip_link_indices.size());
1485  for(size_t i = 0; i < tip_link_indices.size(); i++)
1486  tipLinks[i] = robot_model->getLinkModel(tip_link_indices[i]);
1487  }
1488  void applyConfiguration(const std::vector<double>& jj0)
1489  {
1490  BLOCKPROFILER("RobotFK_MoveIt applyConfiguration");
1491  jj = jj0;
1492  robot_model->interpolate(jj0.data(), jj0.data(), 0.5, jj.data()); // force mimic update
1493  robot_state.setVariablePositions(jj);
1494  robot_state.update();
1495  for(size_t i = 0; i < tipFrames.size(); i++)
1496  tipFrames[i] = Frame(robot_state.getGlobalLinkTransform(tipLinks[i]));
1497  }
1498  inline void incrementalBegin(const std::vector<double>& jj) {}
1499  inline void incrementalEnd() {}
1500  const Frame& getTipFrame(size_t fi) const { return tipFrames[fi]; }
1501  const std::vector<Frame>& getTipFrames() const { return tipFrames; }
1502 };
1503 }