Distance.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /** \file itasc/Distance.cpp
  2. * \ingroup itasc
  3. */
  4. /*
  5. * Distance.cpp
  6. *
  7. * Created on: Jan 30, 2009
  8. * Author: rsmits
  9. */
  10. #include "Distance.hpp"
  11. #include "kdl/kinfam_io.hpp"
  12. #include <math.h>
  13. #include <string.h>
  14. namespace iTaSC
  15. {
  16. // a distance constraint is characterized by 5 values: alpha, tolerance, K, yd, yddot
  17. static const unsigned int distanceCacheSize = sizeof(double)*5 + sizeof(e_scalar)*6;
  18. Distance::Distance(double armlength, double accuracy, unsigned int maximum_iterations):
  19. ConstraintSet(1,accuracy,maximum_iterations),
  20. m_chiKdl(6),m_jac(6),m_cache(NULL),
  21. m_distCCh(-1),m_distCTs(0)
  22. {
  23. m_chain.addSegment(Segment(Joint(Joint::RotZ)));
  24. m_chain.addSegment(Segment(Joint(Joint::RotX)));
  25. m_chain.addSegment(Segment(Joint(Joint::TransY)));
  26. m_chain.addSegment(Segment(Joint(Joint::RotZ)));
  27. m_chain.addSegment(Segment(Joint(Joint::RotY)));
  28. m_chain.addSegment(Segment(Joint(Joint::RotX)));
  29. m_fksolver = new KDL::ChainFkSolverPos_recursive(m_chain);
  30. m_jacsolver = new KDL::ChainJntToJacSolver(m_chain);
  31. m_Cf(0,2)=1.0;
  32. m_alpha = 1.0;
  33. m_tolerance = 0.05;
  34. m_maxerror = armlength/2.0;
  35. m_K = 20.0;
  36. m_Wy(0) = m_alpha/*/(m_tolerance*m_K)*/;
  37. m_yddot = m_nextyddot = 0.0;
  38. m_yd = m_nextyd = KDL::epsilon;
  39. memset(&m_data, 0, sizeof(m_data));
  40. // initialize the data with normally fixed values
  41. m_data.id = ID_DISTANCE;
  42. m_values.id = ID_DISTANCE;
  43. m_values.number = 1;
  44. m_values.alpha = m_alpha;
  45. m_values.feedback = m_K;
  46. m_values.tolerance = m_tolerance;
  47. m_values.values = &m_data;
  48. }
  49. Distance::~Distance()
  50. {
  51. delete m_fksolver;
  52. delete m_jacsolver;
  53. }
  54. bool Distance::computeChi(Frame& pose)
  55. {
  56. double dist, alpha, beta, gamma;
  57. dist = pose.p.Norm();
  58. Rotation basis;
  59. if (dist < KDL::epsilon) {
  60. // distance is almost 0, no need for initial rotation
  61. m_chi(0) = 0.0;
  62. m_chi(1) = 0.0;
  63. } else {
  64. // find the XZ angles that bring the Y axis to point to init_pose.p
  65. Vector axis(pose.p/dist);
  66. beta = 0.0;
  67. if (fabs(axis(2)) > 1-KDL::epsilon) {
  68. // direction is aligned on Z axis, just rotation on X
  69. alpha = 0.0;
  70. gamma = KDL::sign(axis(2))*KDL::PI/2;
  71. } else {
  72. alpha = -KDL::atan2(axis(0), axis(1));
  73. gamma = KDL::atan2(axis(2), KDL::sqrt(KDL::sqr(axis(0))+KDL::sqr(axis(1))));
  74. }
  75. // rotation after first 2 joints
  76. basis = Rotation::EulerZYX(alpha, beta, gamma);
  77. m_chi(0) = alpha;
  78. m_chi(1) = gamma;
  79. }
  80. m_chi(2) = dist;
  81. basis = basis.Inverse()*pose.M;
  82. basis.GetEulerZYX(alpha, beta, gamma);
  83. // alpha = rotation on Z
  84. // beta = rotation on Y
  85. // gamma = rotation on X in that order
  86. // it corresponds to the joint order, so just assign
  87. m_chi(3) = alpha;
  88. m_chi(4) = beta;
  89. m_chi(5) = gamma;
  90. return true;
  91. }
  92. bool Distance::initialise(Frame& init_pose)
  93. {
  94. // we will initialize m_chi to values that match the pose
  95. m_externalPose=init_pose;
  96. computeChi(m_externalPose);
  97. // get current Jf and update internal pose
  98. updateJacobian();
  99. return true;
  100. }
  101. bool Distance::closeLoop()
  102. {
  103. if (!Equal(m_internalPose.Inverse()*m_externalPose,F_identity,m_threshold)){
  104. computeChi(m_externalPose);
  105. updateJacobian();
  106. }
  107. return true;
  108. }
  109. void Distance::initCache(Cache *_cache)
  110. {
  111. m_cache = _cache;
  112. m_distCCh = -1;
  113. if (m_cache) {
  114. // create one channel for the coordinates
  115. m_distCCh = m_cache->addChannel(this, "Xf", distanceCacheSize);
  116. // save initial constraint in cache position 0
  117. pushDist(0);
  118. }
  119. }
  120. void Distance::pushDist(CacheTS timestamp)
  121. {
  122. if (m_distCCh >= 0) {
  123. double *item = (double*)m_cache->addCacheItem(this, m_distCCh, timestamp, NULL, distanceCacheSize);
  124. if (item) {
  125. *item++ = m_K;
  126. *item++ = m_tolerance;
  127. *item++ = m_yd;
  128. *item++ = m_yddot;
  129. *item++ = m_alpha;
  130. memcpy(item, &m_chi[0], 6*sizeof(e_scalar));
  131. }
  132. m_distCTs = timestamp;
  133. }
  134. }
  135. bool Distance::popDist(CacheTS timestamp)
  136. {
  137. if (m_distCCh >= 0) {
  138. double *item = (double*)m_cache->getPreviousCacheItem(this, m_distCCh, &timestamp);
  139. if (item && timestamp != m_distCTs) {
  140. m_values.feedback = m_K = *item++;
  141. m_values.tolerance = m_tolerance = *item++;
  142. m_yd = *item++;
  143. m_yddot = *item++;
  144. m_values.alpha = m_alpha = *item++;
  145. memcpy(&m_chi[0], item, 6*sizeof(e_scalar));
  146. m_distCTs = timestamp;
  147. m_Wy(0) = m_alpha/*/(m_tolerance*m_K)*/;
  148. updateJacobian();
  149. }
  150. return (item) ? true : false;
  151. }
  152. return true;
  153. }
  154. void Distance::pushCache(const Timestamp& timestamp)
  155. {
  156. if (!timestamp.substep && timestamp.cache)
  157. pushDist(timestamp.cacheTimestamp);
  158. }
  159. void Distance::updateKinematics(const Timestamp& timestamp)
  160. {
  161. if (timestamp.interpolate) {
  162. //the internal pose and Jf is already up to date (see model_update)
  163. //update the desired output based on yddot
  164. if (timestamp.substep) {
  165. m_yd += m_yddot*timestamp.realTimestep;
  166. if (m_yd < KDL::epsilon)
  167. m_yd = KDL::epsilon;
  168. } else {
  169. m_yd = m_nextyd;
  170. m_yddot = m_nextyddot;
  171. }
  172. }
  173. pushCache(timestamp);
  174. }
  175. void Distance::updateJacobian()
  176. {
  177. for(unsigned int i=0;i<6;i++)
  178. m_chiKdl[i]=m_chi[i];
  179. m_fksolver->JntToCart(m_chiKdl,m_internalPose);
  180. m_jacsolver->JntToJac(m_chiKdl,m_jac);
  181. changeRefPoint(m_jac,-m_internalPose.p,m_jac);
  182. for(unsigned int i=0;i<6;i++)
  183. for(unsigned int j=0;j<6;j++)
  184. m_Jf(i,j)=m_jac(i,j);
  185. }
  186. bool Distance::setControlParameters(struct ConstraintValues* _values, unsigned int _nvalues, double timestep)
  187. {
  188. int action = 0;
  189. int i;
  190. ConstraintSingleValue* _data;
  191. while (_nvalues > 0) {
  192. if (_values->id == ID_DISTANCE) {
  193. if ((_values->action & ACT_ALPHA) && _values->alpha >= 0.0) {
  194. m_alpha = _values->alpha;
  195. action |= ACT_ALPHA;
  196. }
  197. if ((_values->action & ACT_TOLERANCE) && _values->tolerance > KDL::epsilon) {
  198. m_tolerance = _values->tolerance;
  199. action |= ACT_TOLERANCE;
  200. }
  201. if ((_values->action & ACT_FEEDBACK) && _values->feedback > KDL::epsilon) {
  202. m_K = _values->feedback;
  203. action |= ACT_FEEDBACK;
  204. }
  205. for (_data = _values->values, i=0; i<_values->number; i++, _data++) {
  206. if (_data->id == ID_DISTANCE) {
  207. switch (_data->action & (ACT_VALUE|ACT_VELOCITY)) {
  208. case 0:
  209. // no indication, keep current values
  210. break;
  211. case ACT_VELOCITY:
  212. // only the velocity is given estimate the new value by integration
  213. _data->yd = m_yd+_data->yddot*timestep;
  214. // walkthrough for negative value correction
  215. case ACT_VALUE:
  216. // only the value is given, estimate the velocity from previous value
  217. if (_data->yd < KDL::epsilon)
  218. _data->yd = KDL::epsilon;
  219. m_nextyd = _data->yd;
  220. // if the user sets the value, we assume future velocity is zero
  221. // (until the user changes the value again)
  222. m_nextyddot = (_data->action & ACT_VALUE) ? 0.0 : _data->yddot;
  223. if (timestep>0.0) {
  224. m_yddot = (_data->yd-m_yd)/timestep;
  225. } else {
  226. // allow the user to change target instantenously when this function
  227. // if called from setControlParameter with timestep = 0
  228. m_yddot = m_nextyddot;
  229. m_yd = m_nextyd;
  230. }
  231. break;
  232. case (ACT_VALUE|ACT_VELOCITY):
  233. // the user should not set the value and velocity at the same time.
  234. // In this case, we will assume that he want to set the future value
  235. // and we compute the current value to match the velocity
  236. if (_data->yd < KDL::epsilon)
  237. _data->yd = KDL::epsilon;
  238. m_yd = _data->yd - _data->yddot*timestep;
  239. if (m_yd < KDL::epsilon)
  240. m_yd = KDL::epsilon;
  241. m_nextyd = _data->yd;
  242. m_nextyddot = _data->yddot;
  243. if (timestep>0.0) {
  244. m_yddot = (_data->yd-m_yd)/timestep;
  245. } else {
  246. m_yd = m_nextyd;
  247. m_yddot = m_nextyddot;
  248. }
  249. break;
  250. }
  251. }
  252. }
  253. }
  254. _nvalues--;
  255. _values++;
  256. }
  257. if (action & (ACT_TOLERANCE|ACT_FEEDBACK|ACT_ALPHA)) {
  258. // recompute the weight
  259. m_Wy(0) = m_alpha/*/(m_tolerance*m_K)*/;
  260. }
  261. return true;
  262. }
  263. const ConstraintValues* Distance::getControlParameters(unsigned int* _nvalues)
  264. {
  265. *(double*)&m_data.y = m_chi(2);
  266. *(double*)&m_data.ydot = m_ydot(0);
  267. m_data.yd = m_yd;
  268. m_data.yddot = m_yddot;
  269. m_data.action = 0;
  270. m_values.action = 0;
  271. if (_nvalues)
  272. *_nvalues=1;
  273. return &m_values;
  274. }
  275. void Distance::updateControlOutput(const Timestamp& timestamp)
  276. {
  277. bool cacheAvail = true;
  278. if (!timestamp.substep) {
  279. if (!timestamp.reiterate)
  280. cacheAvail = popDist(timestamp.cacheTimestamp);
  281. }
  282. if (m_constraintCallback && (m_substep || (!timestamp.reiterate && !timestamp.substep))) {
  283. // initialize first callback the application to get the current values
  284. *(double*)&m_data.y = m_chi(2);
  285. *(double*)&m_data.ydot = m_ydot(0);
  286. m_data.yd = m_yd;
  287. m_data.yddot = m_yddot;
  288. m_data.action = 0;
  289. m_values.action = 0;
  290. if ((*m_constraintCallback)(timestamp, &m_values, 1, m_constraintParam)) {
  291. setControlParameters(&m_values, 1, timestamp.realTimestep);
  292. }
  293. }
  294. if (!cacheAvail || !timestamp.interpolate) {
  295. // first position in cache: set the desired output immediately as we cannot interpolate
  296. m_yd = m_nextyd;
  297. m_yddot = m_nextyddot;
  298. }
  299. double error = m_yd-m_chi(2);
  300. if (KDL::Norm(error) > m_maxerror)
  301. error = KDL::sign(error)*m_maxerror;
  302. m_ydot(0)=m_yddot+m_K*error;
  303. }
  304. }