S-curve acceleration / deceleration model generator (using FPU)

Dependents:   2021NHK_B_main

Revision:
2:2c5e4f521390
Parent:
1:aed2cca33061
Child:
3:65ae32169b33
diff -r aed2cca33061 -r 2c5e4f521390 position_controller.cpp
--- a/position_controller.cpp	Fri Aug 03 03:57:44 2018 +0000
+++ b/position_controller.cpp	Mon Aug 20 13:54:33 2018 +0900
@@ -1,70 +1,78 @@
 #include "position_controller.h"
 
-PositionController::PositionController(int accDist, float maxV, int targetX, int targetY) :
-    accelerationDistance(accDist),
-    maxVelocity(maxV),
-    targetDistance(hypot(targetX, targetY)),
-    targetDistanceX(targetX),
-    targetDistanceY(targetY),
-    targetRadians(atan2(targetY, targetX))
+PositionController::PositionController(double accDistance_, double decDistance_, double initialVelocity_, double terminalVelocity_, float maxVelocity_, int targetX_, int targetY_) :
+    accDistance(accDistance_),
+    decDistance(decDistance_),
+    initialVelocity(initialVelocity_),
+    terminalVelocity(terminalVelocity_),
+    maxVelocity(maxVelocity_),
+    targetX(targetX_),
+    targetY(targetY_)
 {
-    if(targetDistance > accelerationDistance * 2.0) {
-        maxJerk = (maxVelocity / 2.0) / (pow(accelerationDistance / 2.0, 2));
+    target = hypot(targetX, targetY);
+    radians = atan2(targetY, targetX);
+    if(accDistance * fabs(maxVelocity - initialVelocity) + decDistance * fabs(maxVelocity - terminalVelocity) < target) {
+        enoughDistance = true;
     } else {
-        maxJerk = (maxVelocity * ((targetDistance/4.0)/(accelerationDistance/2.0))/2.0) / (pow(targetDistance / 4.0, 2));
+        enoughDistance = false;
+        maxVelocity = initialVelocity + (maxVelocity - initialVelocity) * (target/(accDistance+decDistance));
+        accTrue = accDistance * (target/(accDistance+decDistance));
+        decTrue = decDistance * (target/(accDistance+decDistance));
     }
+
+}
+
+double PositionController::generateSineWave(double x, double initV, double termV, double start, double length)
+{
+    return ((termV - initV) * sin(M_PI * ((2.0 * x - 2.0 * start - length)/(2.0 * length))) + termV + initV)/2.0;
 }
 
-float PositionController::generateVelocity(int position)
-{
-    float vel;
-    if(targetDistance > accelerationDistance * 2.0) {
-        if(position >= 0 && position < accelerationDistance / 2.0) {
-            //acc acc
-            vel = pow(position, 2) * maxJerk;
-        } else if(position >= accelerationDistance / 2.0 && position < accelerationDistance) {
-            //acc dec
-            vel = pow(position - accelerationDistance, 2) * (-maxJerk) + maxVelocity;
-        } else if(position >= accelerationDistance && position < targetDistance - accelerationDistance) {
-            //max velocity
+double PositionController::getVelocity(int position)
+{   
+    double vel = 0;
+    if(enoughDistance) {
+        if(position < 0) {
+            vel = initialVelocity;
+        } else if(position < accDistance * fabs(maxVelocity - initialVelocity)) {
+            vel = generateSineWave(position, initialVelocity, maxVelocity, 0, accDistance * fabs(maxVelocity - initialVelocity));
+        } else if(position < target - (decDistance * fabs(maxVelocity - terminalVelocity))) {
             vel = maxVelocity;
-        } else if(position >= targetDistance - accelerationDistance && position < targetDistance - accelerationDistance / 2.0) {
-            //dec acc
-            vel = pow(position - (targetDistance - accelerationDistance), 2) * (-maxJerk) + maxVelocity;
-        } else if(position >= targetDistance - accelerationDistance / 2.0){
-            //dec dec
-            vel = pow(position - targetDistance, 2) * maxJerk;
+        } else if(position < target) {
+            vel = -generateSineWave(position, -maxVelocity, -terminalVelocity, target - decDistance * fabs(maxVelocity - terminalVelocity), decDistance * fabs(maxVelocity - terminalVelocity));
+        } else if(position < 2 * target){
+            vel = -generateSineWave(position, -terminalVelocity, maxVelocity, target, target);
+        } else {
+            vel = -maxVelocity;
         }
     } else {
-        if(position >= 0 && position < targetDistance / 4.0) {
-            vel = pow(position, 2) * maxJerk;
-        } else if(position >= targetDistance / 4.0 && position < targetDistance / 2.0) {
-            //acc dec
-            vel = pow(position - targetDistance / 2.0, 2) * (-maxJerk) + maxVelocity * ((targetDistance/4.0)/(accelerationDistance/2.0));
-        } else if(position >= targetDistance / 2.0 && position < targetDistance * (3.0/4.0)) {
-            //dec acc
-            vel = pow(position - targetDistance / 2.0, 2) * (-maxJerk) + maxVelocity * ((targetDistance/4.0)/(accelerationDistance/2.0));
-        } else if(position >= targetDistance * (3.0 / 4.0)){
-            //dec dec
-            vel = pow(position - targetDistance, 2) * maxJerk;
+        if(position < 0) {
+            vel = initialVelocity;
+        } else if(position < accTrue) {
+            vel = generateSineWave(position, initialVelocity, maxVelocity, 0, accTrue); 
+        } else if(position < target) {
+            vel = -generateSineWave(position, -maxVelocity, -terminalVelocity, target - decTrue, decTrue);
+        } else if(position < 2 * target){
+            vel = -generateSineWave(position, -terminalVelocity, maxVelocity, target, target);
+        } else {
+            vel = -maxVelocity;
         }
     }
-
     return vel;
 }
 
 void PositionController::compute(int positionX, int positionY)
 {
-    velocity[0] = generateVelocity(((double)positionX / (double)targetDistanceX) * targetDistance) * cos(targetRadians);
-    velocity[1] = generateVelocity(((double)positionY / (double)targetDistanceY) * targetDistance) * sin(targetRadians);
+    velocity[0] = getVelocity(((double)positionX / (double)targetX)*target) * cos(radians);
+    velocity[1] = getVelocity(((double)positionY / (double)targetY)*target) * sin(radians);
 }
 
-float PositionController::getVelocityX()
+double PositionController::getVelocityX()
 {
     return velocity[0];
 }
 
-float PositionController::getVelocityY()
+double PositionController::getVelocityY()
 {
     return velocity[1];
 }
+