LinStepAccelerator.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #pragma once
  2. #include <cmath>
  3. #include <cstdint>
  4. #include <algorithm>
  5. class LinStepAccelerator
  6. {
  7. public:
  8. inline int32_t prepareMovement(int32_t currentPos, int32_t targetPos, uint32_t targetSpeed, uint32_t pullInSpeed, uint32_t pullOutSpeed, uint32_t a);
  9. inline int32_t updateSpeed(int32_t currentPosition);
  10. inline uint32_t initiateStopping(int32_t currentPosition);
  11. inline void overrideSpeed(float fac, int32_t currentPosition);
  12. LinStepAccelerator() = default;
  13. protected:
  14. LinStepAccelerator(const LinStepAccelerator &) = delete;
  15. LinStepAccelerator &operator=(const LinStepAccelerator &) = delete;
  16. int32_t s_0, ds;
  17. uint32_t vs, ve, vt;
  18. int64_t vs_sqr, ve_sqr, vt_sqr;
  19. uint32_t two_a;
  20. int32_t accEnd, decStart;
  21. };
  22. // Inline Implementation =====================================================================================================
  23. int32_t LinStepAccelerator::prepareMovement(int32_t currentPos, int32_t targetPos, uint32_t targetSpeed, uint32_t pullInSpeed, uint32_t pullOutSpeed, uint32_t a)
  24. {
  25. vt = targetSpeed;
  26. vs = pullInSpeed; // v_start
  27. ve = pullOutSpeed; // v_end
  28. two_a = 2 * a;
  29. s_0 = currentPos;
  30. ds = std::abs(targetPos - currentPos);
  31. vs_sqr = vs * vs;
  32. ve_sqr = ve * ve;
  33. vt_sqr = vt * vt;
  34. int32_t sm = ((ve_sqr - vs_sqr) / two_a + ds) / 2; // position where acc and dec curves meet
  35. // Serial.printf("ve: %d\n", ve);
  36. // Serial.printf("vs: %d\n", vs);
  37. // Serial.printf("ds: %d\n", ds);
  38. // Serial.printf("sm: %i\n", sm);
  39. if (sm >= 0 && sm <= ds) // we can directly reach the target with the given values vor v0, ve and a
  40. {
  41. int32_t sa = (vt_sqr - vs_sqr) / two_a; // required distance to reach target speed
  42. if (sa < sm) // target speed can be reached
  43. {
  44. accEnd = sa;
  45. decStart = sm + (sm - sa);
  46. //Serial.printf("reachable accEnd: %i decStart:%i\n", accEnd, decStart);
  47. }
  48. else
  49. {
  50. accEnd = decStart = sm;
  51. //Serial.printf("limit accEnd: %i decStart:%i\n", accEnd, decStart);
  52. }
  53. }
  54. else
  55. {
  56. // hack, call some error callback instead
  57. while (1)
  58. {
  59. digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
  60. delay(25);
  61. }
  62. }
  63. return vs;
  64. }
  65. int32_t LinStepAccelerator::updateSpeed(int32_t curPos)
  66. {
  67. int32_t s = std::abs(s_0 - curPos);
  68. // acceleration phase -------------------------------------
  69. if (s < accEnd)
  70. {
  71. return sqrtf(two_a * s + vs_sqr);
  72. }
  73. // constant speed phase ------------------------------------
  74. if (s < decStart)
  75. {
  76. return vt;
  77. }
  78. //deceleration phase --------------------------------------
  79. if (s < ds)
  80. {
  81. // return sqrtf(two_a * ((stepsDone < ds - 1) ? ds - stepsDone - 2 : 0) + vs_sqr);
  82. return sqrtf(ve_sqr + (ds - s - 1) * two_a);
  83. }
  84. //we are done, make sure to return 0 to stop the step timer
  85. return 0;
  86. }
  87. uint32_t LinStepAccelerator::initiateStopping(int32_t curPos)
  88. {
  89. int32_t stepsDone = std::abs(s_0 - curPos);
  90. if (stepsDone < accEnd) // still accelerating
  91. {
  92. accEnd = decStart = 0; // start deceleration
  93. ds = 2 * stepsDone; // we need the same way to decelerate as we traveled so far
  94. return stepsDone; // return steps to go
  95. }
  96. else if (stepsDone < decStart) // constant speed phase
  97. {
  98. decStart = 0; // start deceleration
  99. ds = stepsDone + accEnd; // normal deceleration distance
  100. return accEnd; // return steps to go
  101. }
  102. else // already decelerating
  103. {
  104. return ds - stepsDone; // return steps to go
  105. }
  106. }