PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/src/man/motion/bhwalk/Modules/Sensing/ArmContactModelProvider.cpp

https://github.com/emamanto/nbites
C++ | 324 lines | 248 code | 51 blank | 25 comment | 61 complexity | 51689f078631da36aadeebbfec23ccbb MD5 | raw file
  1. /**
  2. * @file ArmContactModelProvider.h
  3. *
  4. * Implementation of class ArmContactModelProvider.
  5. * @author <a href="mailto:fynn@informatik.uni-bremen.de">Fynn Feldpausch</a>
  6. * @author <a href="mailto:simont@informatik.uni-bremen.de">Simon Taddiken</a>
  7. * @author <a href="mailto:arneboe@informatik.uni-bremen.de">Arne Böckmann</a>
  8. */
  9. #include "Tools/Debugging/DebugDrawings.h"
  10. #include "Tools/Math/Common.h"
  11. #include "ArmContactModelProvider.h"
  12. #include <sstream>
  13. #include <cmath>
  14. #include <algorithm>
  15. /** Scale factor for debug drawings */
  16. #define SCALE 20
  17. MAKE_MODULE(ArmContactModelProvider, Sensing);
  18. ArmContactModelProvider::ArmContactModelProvider()
  19. : soundDelay(1000), lastSoundTime(0), lastGameState(STATE_INITIAL)
  20. {
  21. }
  22. void ArmContactModelProvider::checkArm(bool left, float factor)
  23. {
  24. Vector2f retVal;
  25. /* Calculate arm diffs */
  26. struct ArmAngles angles = angleBuffer[frameDelay];
  27. retVal.x = left
  28. ? theFilteredJointDataBH.angles[JointDataBH::LShoulderPitch] - angles.leftX
  29. : theFilteredJointDataBH.angles[JointDataBH::RShoulderPitch] - angles.rightX;
  30. retVal.y = left
  31. ? theFilteredJointDataBH.angles[JointDataBH::LShoulderRoll] - angles.leftY
  32. : theFilteredJointDataBH.angles[JointDataBH::RShoulderRoll] - angles.rightY;
  33. retVal *= factor;
  34. if(left)
  35. {
  36. ARROW("module:ArmContactModelProvider:armContact", 0, 0, -(toDegrees(retVal.y) * SCALE), toDegrees(retVal.x) * SCALE, 20, Drawings::ps_solid, ColorClasses::blue);
  37. leftErrorBuffer.add(retVal);
  38. }
  39. else
  40. {
  41. ARROW("module:ArmContactModelProvider:armContact", 0, 0, (toDegrees(retVal.y) * SCALE), toDegrees(retVal.x) * SCALE, 20, Drawings::ps_solid, ColorClasses::blue);
  42. rightErrorBuffer.add(retVal);
  43. }
  44. }
  45. void ArmContactModelProvider::resetAll(ArmContactModelBH& model)
  46. {
  47. model.contactLeft = false;
  48. model.contactRight = false;
  49. angleBuffer.init();
  50. leftErrorBuffer.init();
  51. rightErrorBuffer.init();
  52. }
  53. void ArmContactModelProvider::update(ArmContactModelBH& model)
  54. {
  55. DECLARE_PLOT("module:ArmContactModelProvider:errorLeftX");
  56. DECLARE_PLOT("module:ArmContactModelProvider:errorRightX");
  57. DECLARE_PLOT("module:ArmContactModelProvider:errorLeftY");
  58. DECLARE_PLOT("module:ArmContactModelProvider:errorRightY");
  59. DECLARE_PLOT("module:ArmContactModelProvider:errorDurationLeft");
  60. DECLARE_PLOT("module:ArmContactModelProvider:errorDurationRight");
  61. DECLARE_PLOT("module:ArmContactModelProvider:errorYThreshold");
  62. DECLARE_PLOT("module:ArmContactModelProvider:errorXThreshold");
  63. DECLARE_PLOT("module:ArmContactModelProvider:contactLeft");
  64. DECLARE_PLOT("module:ArmContactModelProvider:contactRight");
  65. DECLARE_DEBUG_DRAWING("module:ArmContactModelProvider:armContact", "drawingOnField");
  66. // If in INITIAL or FINISHED, or we are penalized, we reset all buffered errors and detect no arm contacts
  67. if (theGameInfoBH.state == STATE_INITIAL || theGameInfoBH.state == STATE_FINISHED ||
  68. theFallDownStateBH.state == FallDownStateBH::onGround ||
  69. theFallDownStateBH.state == FallDownStateBH::falling ||
  70. theMotionInfoBH.motion == MotionRequestBH::getUp ||
  71. theMotionInfoBH.motion == MotionRequestBH::specialAction ||
  72. theMotionInfoBH.motion == MotionRequestBH::bike ||
  73. !theGroundContactStateBH.contact ||
  74. (theRobotInfoBH.penalty != PENALTY_NONE && !detectWhilePenalized))
  75. {
  76. resetAll(model);
  77. return;
  78. }
  79. // check if any arm just finished moving, if so reset its error buffer
  80. if(leftMovingLastFrame && !theArmMotionEngineOutputBH.arms[LEFT].move)
  81. {
  82. model.contactLeft = false;
  83. leftErrorBuffer.init();
  84. }
  85. if(rightMovingLastFrame && !theArmMotionEngineOutputBH.arms[RIGHT].move)
  86. {
  87. model.contactLeft = false;
  88. rightErrorBuffer.init();
  89. }
  90. leftMovingLastFrame = theArmMotionEngineOutputBH.arms[LEFT].move;
  91. rightMovingLastFrame = theArmMotionEngineOutputBH.arms[RIGHT].move;
  92. // clear on game state changes
  93. if (lastGameState != theGameInfoBH.state)
  94. {
  95. resetAll(model);
  96. }
  97. lastGameState = theGameInfoBH.state;
  98. CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 200, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  99. CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 400, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  100. CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 600, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  101. CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 800, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  102. CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 1000, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  103. CIRCLE("module:ArmContactModelProvider:armContact", 0, 0, 1200, 30, Drawings::ps_solid, ColorClasses::blue, Drawings::ps_null, ColorClasses::blue);
  104. /* Buffer arm angles */
  105. struct ArmAngles angles;
  106. angles.leftX = theJointRequestBH.angles[JointDataBH::LShoulderPitch];
  107. angles.leftY = theJointRequestBH.angles[JointDataBH::LShoulderRoll];
  108. angles.rightX = theJointRequestBH.angles[JointDataBH::RShoulderPitch];
  109. angles.rightY = theJointRequestBH.angles[JointDataBH::RShoulderRoll];
  110. angleBuffer.add(angles);
  111. Pose2DBH odometryOffset = theOdometryDataBH - lastOdometry;
  112. lastOdometry = theOdometryDataBH;
  113. /* Check for arm contact */
  114. // motion types to take into account: stand, walk (if the robot is upright)
  115. if((theMotionInfoBH.motion == MotionInfoBH::stand || theMotionInfoBH.motion == MotionInfoBH::walk) &&
  116. (theFallDownStateBH.state == FallDownStateBH::upright || theFallDownStateBH.state == FallDownStateBH::staggering) &&
  117. angleBuffer.isFilled())
  118. {
  119. const float leftFactor = calculateCorrectionFactor(theRobotModelBH.limbs[MassCalibrationBH::foreArmLeft], odometryOffset, lastLeftHandPos);
  120. const float rightFactor = calculateCorrectionFactor(theRobotModelBH.limbs[MassCalibrationBH::foreArmRight], odometryOffset, lastRightHandPos);
  121. // determine if arm is not moving and time passed since last arm motion for each arm
  122. // HINT: both conditions should be equivalent as long as waitAfterMovement is > 0
  123. const bool leftValid = !leftMovingLastFrame &&
  124. theFrameInfoBH.getTimeSince(theArmMotionEngineOutputBH.arms[LEFT].lastMovement) > waitAfterMovement;
  125. const bool rightValid = !rightMovingLastFrame &&
  126. theFrameInfoBH.getTimeSince(theArmMotionEngineOutputBH.arms[RIGHT].lastMovement) > waitAfterMovement;
  127. // only integrate new measurement if arm not moving and time passed > waitAfterMovement
  128. if(leftValid)
  129. checkArm(LEFT, leftFactor);
  130. if(rightValid)
  131. checkArm(RIGHT, rightFactor);
  132. const Vector2f left = leftErrorBuffer.getAverageFloat();
  133. const Vector2f right = rightErrorBuffer.getAverageFloat();
  134. //Determine if we are being pushed or not. Can only be true if last arm movement long enough ago
  135. bool leftX = leftValid && fabs(left.x) > fromDegrees(errorXThreshold);
  136. bool leftY = leftValid && fabs(left.y) > fromDegrees(errorYThreshold);
  137. bool rightX = rightValid && fabs(right.x)> fromDegrees(errorXThreshold);
  138. bool rightY = rightValid && fabs(right.y)> fromDegrees(errorYThreshold);
  139. // update the model
  140. model.contactLeft = (leftX || leftY) &&
  141. leftErrorBuffer.isFilled();
  142. model.contactRight = (rightX || rightY) &&
  143. rightErrorBuffer.isFilled();
  144. // There should be no contact for an arm that is currently being moved
  145. ASSERT(model.contactLeft ? !theArmMotionEngineOutputBH.arms[LEFT].move : true);
  146. ASSERT(model.contactRight ? !theArmMotionEngineOutputBH.arms[RIGHT].move : true);
  147. // The duration of the contact is counted upwards as long as the error
  148. // remains. Otherwise it is reseted to 0.
  149. model.durationLeft = model.contactLeft ? model.durationLeft + 1 : 0;
  150. model.durationRight = model.contactRight ? model.durationRight + 1 : 0;
  151. model.contactLeft &= model.durationLeft < malfunctionThreshold;
  152. model.contactRight &= model.durationRight < malfunctionThreshold;
  153. if(model.contactLeft)
  154. {
  155. model.timeOfLastContactLeft = theFrameInfoBH.time;
  156. }
  157. if(model.contactRight)
  158. {
  159. model.timeOfLastContactRight = theFrameInfoBH.time;
  160. }
  161. model.pushDirectionLeft = getDirection(LEFT, leftX, leftY, left);
  162. model.pushDirectionRight = getDirection(RIGHT, rightX, rightY, right);
  163. model.lastPushDirectionLeft = model.pushDirectionLeft != ArmContactModelBH::NONE ? model.pushDirectionLeft : model.lastPushDirectionLeft;
  164. model.lastPushDirectionRight = model.pushDirectionRight != ArmContactModelBH::NONE ? model.pushDirectionRight : model.lastPushDirectionRight;
  165. PLOT("module:ArmContactModelProvider:errorLeftX", toDegrees(left.x));
  166. PLOT("module:ArmContactModelProvider:errorRightX", toDegrees(right.x));
  167. PLOT("module:ArmContactModelProvider:errorLeftY", toDegrees(left.y));
  168. PLOT("module:ArmContactModelProvider:errorRightY", toDegrees(right.y));
  169. PLOT("module:ArmContactModelProvider:errorDurationLeft", model.durationLeft);
  170. PLOT("module:ArmContactModelProvider:errorDurationRight", model.durationRight);
  171. PLOT("module:ArmContactModelProvider:errorYThreshold", errorYThreshold);
  172. PLOT("module:ArmContactModelProvider:errorXThreshold", errorXThreshold);
  173. PLOT("module:ArmContactModelProvider:contactLeft", model.contactLeft ? 10.0 : 0.0);
  174. PLOT("module:ArmContactModelProvider:contactRight", model.contactRight ? 10.0 : 0.0);
  175. ARROW("module:ArmContactModelProvider:armContact", 0, 0, -(toDegrees(left.y) * SCALE), toDegrees(left.x) * SCALE, 20, Drawings::ps_solid, ColorClasses::green);
  176. ARROW("module:ArmContactModelProvider:armContact", 0, 0, toDegrees(right.y) * SCALE, toDegrees(right.x) * SCALE, 20, Drawings::ps_solid, ColorClasses::red);
  177. COMPLEX_DRAWING("module:ArmContactModelProvider:armContact",
  178. {
  179. DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 1300, 200, ColorClasses::black, "LEFT");
  180. DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 1100, 200, ColorClasses::black, "ErrorX: " << toDegrees(left.x));
  181. DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 900, 200, ColorClasses::black, "ErrorY: " << toDegrees(left.y));
  182. DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 500, 200, ColorClasses::black, ArmContactModelBH::getName(model.pushDirectionLeft));
  183. DRAWTEXT("module:ArmContactModelProvider:armContact", -2300, 300, 200, ColorClasses::black, "Time: " << model.timeOfLastContactLeft);
  184. DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 1300, 200, ColorClasses::black, "RIGHT");
  185. DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 1100, 200, ColorClasses::black, "ErrorX: " << toDegrees(right.x));
  186. DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 900, 200, ColorClasses::black, "ErrorY: " << toDegrees(right.y));
  187. DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 500, 200, ColorClasses::black, ArmContactModelBH::getName(model.pushDirectionRight));
  188. DRAWTEXT("module:ArmContactModelProvider:armContact", 1300, 300, 200, ColorClasses::black, "Time: " << model.timeOfLastContactRight);
  189. if (model.contactLeft)
  190. {
  191. CROSS("module:ArmContactModelProvider:armContact", -2000, 0, 100, 20, Drawings::ps_solid, ColorClasses::red);
  192. }
  193. if (model.contactRight)
  194. {
  195. CROSS("module:ArmContactModelProvider:armContact", 2000, 0, 100, 20, Drawings::ps_solid, ColorClasses::red);
  196. }
  197. });
  198. if(debugMode && theFrameInfoBH.getTimeSince(lastSoundTime) > soundDelay &&
  199. (model.contactLeft || model.contactRight))
  200. {
  201. lastSoundTime = theFrameInfoBH.time;
  202. #ifdef TARGET_ROBOT
  203. SystemCall::playSound("arm.wav");
  204. #else
  205. OUTPUT(idText, text, (model.contactLeft ? "Left" : "") << (model.contactRight ? "Right" : "") << " arm!");
  206. #endif
  207. }
  208. }
  209. }
  210. ArmContactModelBH::PushDirection ArmContactModelProvider::getDirection(bool left, bool contactX, bool contactY, Vector2f error)
  211. {
  212. // for the left arm, y directions are mirrored!
  213. if (left)
  214. {
  215. error = Vector2f(error.x, -error.y);
  216. }
  217. ArmContactModelBH::PushDirection result = ArmContactModelBH::NONE;
  218. if (contactX && contactY)
  219. {
  220. if (error.x > 0.0 && error.y < 0.0f)
  221. {
  222. result = ArmContactModelBH::NW;
  223. }
  224. else if (error.x > 0.0 && error.y > 0.0)
  225. {
  226. result = ArmContactModelBH::NE;
  227. }
  228. if (error.x < 0.0 && error.y < 0.0f)
  229. {
  230. result = ArmContactModelBH::SW;
  231. }
  232. else if (error.x < 0.0 && error.y > 0.0)
  233. {
  234. result = ArmContactModelBH::SE;
  235. }
  236. }
  237. else if (contactX)
  238. {
  239. if (error.x < 0.0)
  240. {
  241. result = ArmContactModelBH::S;
  242. }
  243. else
  244. {
  245. result = ArmContactModelBH::N;
  246. }
  247. }
  248. else if (contactY)
  249. {
  250. if (error.y < 0.0)
  251. {
  252. result = ArmContactModelBH::W;
  253. }
  254. else
  255. {
  256. result = ArmContactModelBH::E;
  257. }
  258. }
  259. else
  260. {
  261. result = ArmContactModelBH::NONE;
  262. }
  263. return result;
  264. }
  265. float ArmContactModelProvider::calculateCorrectionFactor(const Pose3DBH foreArm, const Pose2DBH odometryOffset, Vector2BH<> &lastArmPos)
  266. {
  267. const Vector3BH<>& handPos3D = foreArm.translation;
  268. Vector2BH<> handPos(handPos3D.x, handPos3D.y);
  269. Vector2BH<> handSpeed = (odometryOffset + Pose2DBH(handPos) - Pose2DBH(lastArmPos)).translation / theFrameInfoBH.cycleTime;
  270. float factor = std::max(0.f, 1.f - handSpeed.abs() / speedBasedErrorReduction);
  271. lastArmPos = handPos;
  272. return factor;
  273. }