bio_ik
MoveIt kinematics_base plugin based on particle optimization & GA
utils.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 <csignal>
38 #include <iostream>
39 
40 #include <ros/ros.h>
41 
42 #include <atomic>
43 #include <mutex>
44 #include <thread>
45 #include <typeindex>
46 #include <unordered_map>
47 #include <unordered_set>
48 
49 #include <malloc.h>
50 #include <stdlib.h>
51 
52 #include <tf_conversions/tf_kdl.h>
53 
54 #include <XmlRpcException.h>
55 
56 //#include <link.h>
57 
58 //#include <boost/align/aligned_allocator.hpp>
59 //#include <Eigen/Eigen>
60 
61 namespace bio_ik
62 {
63 
64 struct IKParams
65 {
66  moveit::core::RobotModelConstPtr robot_model;
67  const moveit::core::JointModelGroup* joint_model_group;
68 
69  // IKParallel parameters
70  std::string solver_class_name;
71  bool enable_counter;
72  int thread_count;
73 
74  //Problem parameters
75  double dpos;
76  double drot;
77  double dtwist;
78 
79  // ik_evolution_1 parameters
80  bool opt_no_wipeout;
81  int population_size;
82  int elite_count;
83  bool linear_fitness;
84 };
85 
86 // Uncomment to enable logging
87 //#define ENABLE_LOG
88 
89 // Uncomment to enable profiling
90 //#define ENABLE_PROFILER
91 
92 // logging
93 
94 //#define LOG_STREAM (std::cerr << std::fixed)
95 //#define LOG_STREAM (std::cerr << std::scientific)
96 #define LOG_STREAM (std::cerr)
97 
98 template <class T> inline void vprint(std::ostream& s, const T& a) { s << a << std::endl; }
99 template <class T, class... AA> inline void vprint(std::ostream& s, const T& a, const AA&... aa)
100 {
101  s << a << " ";
102  vprint(s, aa...);
103 };
104 
105 #define LOG2(...) vprint(LOG_STREAM, "ikbio ", __VA_ARGS__)
106 
107 #ifdef ENABLE_LOG
108 #define LOG(...) LOG2(__VA_ARGS__)
109 #else
110 #define LOG(...)
111 #endif
112 
113 #define LOG_VAR(v) LOG2(#v, (v));
114 
115 //#define LOG_FNC() LOG("fun", __func__, __LINE__)
116 #define LOG_FNC()
117 
118 // show error and abort
119 // #define ERROR(...) { LOG("ERROR", __VA_ARGS__); exit(-1); }
120 // #define ERROR(a, ...) { LOG(a, __VA_ARGS__); LOG_STREAM.flush(); throw std::runtime_error(a); }
121 #define ERROR(...) \
122  { \
123  LOG2(__VA_ARGS__); \
124  LOG_STREAM.flush(); \
125  std::stringstream ss; \
126  vprint(ss, __VA_ARGS__); \
127  throw std::runtime_error(ss.str()); \
128  }
129 // #define ERROR(...) { LOG_ALWAYS(__VA_ARGS__); std::raise(SIGINT); }
130 
131 // profiler
132 
133 #ifdef ENABLE_PROFILER
134 
135 // embeddable sampling profiler
136 
137 // profiled block or function
138 struct ProfilerBin
139 {
140  const char* volatile name; // name of scope or function, also used as indicator if it is currently being executed
141  std::atomic<int> counter; // only used by CounterScope / COUNTERPROFILER
142  ProfilerBin()
143  : name(0)
144  {
145  }
146 };
147 
148 // allocate globally unique profiler buffer via template
149 template <class force_weak_linker_symbol = void> ProfilerBin* getProfilerBuffer()
150 {
151  static std::vector<ProfilerBin> buffer(10000);
152  return buffer.data();
153 }
154 
155 // reserve profiler buffer segment for current compilation unit
156 template <class force_weak_linker_symbol = void> ProfilerBin* getProfilerSegment()
157 {
158  static size_t index = 0;
159  return getProfilerBuffer() + (index++) * 20;
160 }
161 static ProfilerBin* profiler_segment = getProfilerSegment();
162 
163 // identifies currently profiled thread
164 // null if profiler is disabled
165 struct ProfilerInfo
166 {
167  void* stack_begin;
168  void* stack_end;
169 };
170 
171 // declare globally unique profiler info via template
172 template <class force_weak_linker_symbol = void> ProfilerInfo& getProfilerInfo()
173 {
174  static ProfilerInfo info;
175  return info;
176 }
177 static ProfilerInfo& profiler_info = getProfilerInfo();
178 
179 // profiles a scope or function
180 template <size_t ID> struct ProfilerScope
181 {
182  __attribute__((always_inline)) inline ProfilerScope(const char* name)
183  {
184  if(profiler_info.stack_begin == 0) return;
185  if(this < profiler_info.stack_begin || this > profiler_info.stack_end) return;
186  profiler_segment[ID].name = name;
187  }
188  __attribute__((always_inline)) inline ~ProfilerScope()
189  {
190  if(profiler_info.stack_begin == 0) return;
191  if(this < profiler_info.stack_begin || this > profiler_info.stack_end) return;
192  profiler_segment[ID].name = 0;
193  }
194 };
195 #define FNPROFILER() volatile ProfilerScope<__COUNTER__> _profilerscope(__func__);
196 #define BLOCKPROFILER(name) volatile ProfilerScope<__COUNTER__> _profilerscope(name);
197 
198 // per-thread profiling
199 struct ThreadScope
200 {
201  size_t id;
202  __attribute__((always_inline)) inline ThreadScope(const char* name, size_t id)
203  : id(id)
204  {
205  if(profiler_info.stack_begin == 0) return;
206  profiler_segment[id].name = name;
207  }
208  __attribute__((always_inline)) inline ~ThreadScope()
209  {
210  if(profiler_info.stack_begin == 0) return;
211  profiler_segment[id].name = 0;
212  }
213 };
214 #define THREADPROFILER(name, id) \
215  static const char* _threadscope_names[] = {name "0", name "1", name "2", name "3"}; \
216  volatile ThreadScope _threadscope(_threadscope_names[id], __COUNTER__ + id); \
217  (__COUNTER__, __COUNTER__, __COUNTER__, __COUNTER__, __COUNTER__);
218 
219 // profiling across multiple threads
220 struct CounterScope
221 {
222  size_t id;
223  __attribute__((always_inline)) inline CounterScope(const char* name, size_t id)
224  : id(id)
225  {
226  if(profiler_info.stack_begin == 0) return;
227  if((profiler_segment[id].counter++) == 0) profiler_segment[id].name = name;
228  }
229  __attribute__((always_inline)) inline ~CounterScope()
230  {
231  if(profiler_info.stack_begin == 0) return;
232  if((--profiler_segment[id].counter) == 0) profiler_segment[id].name = 0;
233  }
234 };
235 #define COUNTERPROFILER(name) volatile CounterScope _counterscope(name, __COUNTER__);
236 
237 // starts profiler and periodically writes results to log
238 struct Profiler
239 {
240  std::thread thread;
241  volatile int exit_flag;
242  Profiler()
243  {
244  pthread_attr_t attr;
245  pthread_getattr_np(pthread_self(), &attr);
246  void* stack_addr;
247  size_t stack_size;
248  pthread_attr_getstack(&attr, &stack_addr, &stack_size);
249  profiler_info.stack_begin = stack_addr;
250  profiler_info.stack_end = (char*)stack_addr + stack_size;
251  const size_t maxbin = 1000;
252  static std::mutex mutex;
253  static std::unordered_map<const char*, size_t> samples;
254  exit_flag = 0;
255  std::thread t([this]() {
256  auto* profiler_bins = getProfilerBuffer();
257  while(true)
258  {
259  for(int iter = 0; iter < 100; iter++)
260  {
261  for(int iter = 0; iter < 100; iter++)
262  {
263  int i = rand() % maxbin;
264  const char* p = profiler_bins[i].name;
265  if(p) samples[p]++;
266  }
267  if(exit_flag) break;
268  std::this_thread::sleep_for(std::chrono::duration<size_t, std::micro>(rand() % 1000));
269  }
270  {
271  double thistime = ros::WallTime::now().toSec();
272  static double lasttime = 0.0;
273  if(thistime < lasttime + 1) continue;
274  lasttime = thistime;
275  static std::vector<std::pair<const char*, size_t>> data;
276  data.clear();
277  for(auto& p : samples)
278  data.push_back(p);
279  std::sort(data.begin(), data.end(), [](const std::pair<const char*, size_t>& a, const std::pair<const char*, size_t>& b) { return a.second > b.second; });
280  LOG("");
281  LOG("profiler");
282  for(auto& d : data)
283  {
284  double v = d.second * 100.0 / data[0].second;
285  char s[32];
286  sprintf(s, "%6.2f%%", v);
287  LOG("p", s, d.first);
288  }
289  LOG("");
290  }
291  if(exit_flag) break;
292  }
293  });
294  std::swap(thread, t);
295  }
296  ~Profiler()
297  {
298  exit_flag = true;
299  thread.join();
300  }
301  static void start() { static Profiler profiler; }
302 };
303 
304 #else
305 
306 #define FNPROFILER()
307 #define BLOCKPROFILER(name)
308 #define THREADPROFILER(name, id)
309 #define COUNTERPROFILER(name)
310 
311 struct Profiler
312 {
313  static void start() {}
314 };
315 
316 #endif
317 
318 __attribute__((always_inline)) inline double mix(double a, double b, double f) { return a * (1.0 - f) + b * f; }
319 
320 __attribute__((always_inline)) inline double clamp(double v, double lo, double hi)
321 {
322  if(v < lo) v = lo;
323  if(v > hi) v = hi;
324  return v;
325 }
326 
327 __attribute__((always_inline)) inline double clamp2(double v, double lo, double hi)
328 {
329  if(__builtin_expect(v < lo, 0)) v = lo;
330  if(__builtin_expect(v > hi, 0)) v = hi;
331  return v;
332 }
333 
334 __attribute__((always_inline)) inline double smoothstep(float a, float b, float v)
335 {
336  v = clamp((v - a) / (b - a), 0.0, 1.0);
337  return v * v * (3.0 - 2.0 * v);
338 }
339 
340 __attribute__((always_inline)) inline double sign(double f)
341 {
342  if(f < 0.0) f = -1.0;
343  if(f > 0.0) f = +1.0;
344  return f;
345 }
346 
347 template <class t> class linear_int_distribution
348 {
349  std::uniform_int_distribution<t> base;
350  t n;
351 
352 public:
353  inline linear_int_distribution(t vrange)
354  : n(vrange)
355  , base(0, vrange)
356  {
357  }
358  template <class generator> inline t operator()(generator& g)
359  {
360  while(true)
361  {
362  t v = base(g) + base(g);
363  if(v < n) return n - v - 1;
364  }
365  }
366 };
367 
369 {
370  uint64_t v;
371 
372 public:
373  XORShift64()
374  : v(88172645463325252ull)
375  {
376  }
377  __attribute__((always_inline)) inline uint64_t operator()()
378  {
379  v ^= v << 13;
380  v ^= v >> 7;
381  v ^= v << 17;
382  return v;
383  }
384 };
385 
386 // class factory
387 //
388 // registering a class:
389 // static Factory<Base>::Class<Derived> reg("Derived");
390 //
391 // instantiation:
392 // Base* obj = Factory<Base>::create("Derived");
393 //
394 // cloning and object:
395 // p = Factory<Base>::clone(o);
396 //
397 template <class BASE, class... ARGS> class Factory
398 {
399  typedef BASE* (*Constructor)(ARGS...);
400  struct ClassBase
401  {
402  std::string name;
403  std::type_index type;
404  virtual BASE* create(ARGS... args) const = 0;
405  virtual BASE* clone(const BASE*) const = 0;
406  ClassBase()
407  : type(typeid(void))
408  {
409  }
410  };
411  typedef std::set<ClassBase*> MapType;
412  static MapType& classes()
413  {
414  static MapType ff;
415  return ff;
416  }
417 
418 public:
419  template <class DERIVED> struct Class : ClassBase
420  {
421  BASE* create(ARGS... args) const { return new DERIVED(args...); }
422  BASE* clone(const BASE* o) const { return new DERIVED(*(const DERIVED*)o); }
423  Class(const std::string& name)
424  {
425  this->name = name;
426  this->type = typeid(DERIVED);
427  classes().insert(this);
428  }
429  ~Class() { classes().erase(this); }
430  };
431  static BASE* create(const std::string& name, ARGS... args)
432  {
433  for(auto* f : classes())
434  if(f->name == name) return f->create(args...);
435  ERROR("class not found", name);
436  }
437  template <class DERIVED> static DERIVED* clone(const DERIVED* o)
438  {
439  for(auto* f : classes())
440  if(f->type == typeid(*o)) return (DERIVED*)f->clone(o);
441  ERROR("class not found", typeid(*o).name());
442  }
443 };
444 
445 // Alloctes memory properly aligned for SIMD operations
446 template <class T, size_t A> struct aligned_allocator : public std::allocator<T>
447 {
448  typedef size_t size_type;
449  typedef ptrdiff_t difference_type;
450  typedef T* pointer;
451  typedef const T* const_pointer;
452  typedef T& reference;
453  typedef const T& const_reference;
454  typedef T value_type;
455  T* allocate(size_t s, const void* hint = 0)
456  {
457  void* p;
458  if(posix_memalign(&p, A, sizeof(T) * s + 64)) throw std::bad_alloc();
459  return (T*)p;
460  }
461  void deallocate(T* ptr, size_t s) { free(ptr); }
462  template <class U> struct rebind
463  {
465  };
466 };
467 
468 // std::vector typedef with proper memory alignment for SIMD operations
469 template <class T> struct aligned_vector : std::vector<T, aligned_allocator<T, 32>>
470 {
471 };
472 
473 // Helper class for reading structured data from ROS parameter server
475 {
476  typedef XmlRpc::XmlRpcValue var;
477  var& v;
478 
479 public:
480  XmlRpcReader(var& v)
481  : v(v)
482  {
483  }
484 
485 private:
486  XmlRpcReader at(int i) { return v[i]; }
487  void conv(bool& r) { r = (bool)v; }
488  void conv(double& r) { r = (v.getType() == var::TypeInt) ? ((double)(int)v) : ((double)v); }
489  void conv(tf2::Vector3& r)
490  {
491  double x, y, z;
492  at(0).conv(x);
493  at(1).conv(y);
494  at(2).conv(z);
495  r = tf2::Vector3(x, y, z);
496  }
497  void conv(tf2::Quaternion& r)
498  {
499  double x, y, z, w;
500  at(0).conv(x);
501  at(1).conv(y);
502  at(2).conv(z);
503  at(3).conv(w);
504  r = tf2::Quaternion(x, y, z, w).normalized();
505  }
506  void conv(std::string& r) { r = (std::string)v; }
507 
508 public:
509  template <class T> void param(const char* key, T& r)
510  {
511  if(!v.hasMember(key)) return;
512  try
513  {
514  XmlRpcReader(v[key]).conv(r);
515  }
516  catch(const XmlRpc::XmlRpcException& e)
517  {
518  LOG(key);
519  throw;
520  }
521  }
522 };
523 }