-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
very simple trapezoidal velocity planner
- Loading branch information
Richard Unger
committed
Mar 28, 2024
1 parent
3a11d58
commit a542a71
Showing
7 changed files
with
163 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
|
||
# Trapezoids | ||
|
||
Classes for trapezoidal motion profiles. Intended as a starting point for your own higher level control schemes. | ||
|
||
## TrapezoidalPlanner | ||
|
||
Produces trapzoidal velocity profiles for the motor, used with `MotionControlMode::velocity`. | ||
|
||
The following graphs show a commanded angle change from 0 to 10 radians executed by the trapezoidal planner. The accelleration limit is set | ||
to 1rad/s/s while the decelleration limit is set to 0.25rad/s/s. The maximum velocity is set to 5rad/s, which is not reached, resulting in a triangular shaped | ||
velocity profile. The position profile is nice smooth shape, as expected. | ||
|
||
|Velocity|Position| | ||
|---|---| | ||
|  |  | | ||
|
||
|
||
In the following example the angle is commanded back from 10 to 0 radians, but this time the velocity limit on the planner is set to 1.25rad/s. You can see the trapezoidal shape of the velocity profile (negative because we're going backwards). | ||
|
||
|Velocity|Position| | ||
|---|---| | ||
|  |  | | ||
|
||
|
||
### Usage | ||
|
||
The following *incomplete* code example shows only the parts relevant to integrating the planner: | ||
|
||
```c++ | ||
|
||
Commander commander = Commander(Serial); | ||
BLDCMotor motor = BLDCMotor(7); // 7 pole pairs | ||
TrapezoidalPlanner trapezoidal = TrapezoidalPlanner(5.0f, 1.0f, 0.25f, 0.2f); | ||
|
||
float target_angle = 0.0f; | ||
|
||
void onTarget(char* cmd){ commander.scalar(&target_angle); trapezoidal.setTarget(target_angle); } | ||
|
||
void setup() { | ||
|
||
... | ||
motor.controller = MotionControlType::velocity; | ||
trapezoidal.linkMotor(motor); | ||
motor.init(); | ||
... | ||
commander.add('T', onTarget, "target angle"); | ||
trapezoidal.setTarget(target_angle); | ||
} | ||
|
||
|
||
|
||
int32_t downsample = 50; // depending on your MCU's speed, you might want a value between 5 and 50... | ||
int32_t downsample_cnt = 0; | ||
|
||
void loop() { | ||
|
||
if (downsample > 0 && --downsample_cnt <= 0) { | ||
motor.target = trapezoidal.run(); | ||
downsample_cnt = downsample; | ||
} | ||
motor.move(); | ||
motor.loopFOC(); | ||
commander.run(); | ||
|
||
} | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
|
||
|
||
#include "./TrapezoidalPlanner.h" | ||
|
||
|
||
TrapezoidalPlanner::TrapezoidalPlanner(float max, float accel, float decel, float min){ | ||
this->max_velocity = max; | ||
this->accel = accel; | ||
this->decel = (decel!=NOT_SET)?decel:accel; | ||
this->min_velocity = (min!=NOT_SET)?min:0.2f; | ||
}; | ||
|
||
|
||
TrapezoidalPlanner::~TrapezoidalPlanner(){}; | ||
|
||
|
||
|
||
void TrapezoidalPlanner::linkMotor(FOCMotor& motor){ | ||
this->motor = &motor; | ||
}; | ||
|
||
|
||
|
||
void TrapezoidalPlanner::setTarget(float target){ | ||
this->target = target; | ||
this->start_ang = motor->shaft_angle; | ||
this->last_target = target; | ||
}; | ||
|
||
|
||
|
||
float TrapezoidalPlanner::run(){ | ||
// given the just current position and the target position, calculate the desired velocity | ||
// assume we're within our acceleration capabilities | ||
float d = target - motor->shaft_angle; | ||
float dd = motor->shaft_angle - start_ang; | ||
// if the target is reached, return 0 | ||
if (abs(d) < arrived_distance && abs(motor->shaft_velocity) < arrived_velocity) return 0; | ||
|
||
// how fast can we be going, based on deceleration? | ||
float max_v_d = sqrt(2.0f * decel * fabs(d)); | ||
// how fast can we be going, based on accelleration? | ||
float max_v_dd = sqrt(2.0f * accel * fabs(dd)); | ||
float max_v = min(max_v_d, max_v_dd); | ||
// how fast can we be going, based on max speed? | ||
max_v = min(max_v, max_velocity); | ||
max_v = max(max_v, min_velocity); | ||
// let's go that speed :-) | ||
return max_v * _sign(d); | ||
}; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
|
||
#pragma once | ||
|
||
#include "common/base_classes/FOCMotor.h" | ||
|
||
/** | ||
* Trapezoidal planner | ||
* | ||
* Very simple class to demonstrate higher level control on top of the FOC library. | ||
* | ||
* This class is used to generate trapezoidal velocity profiles for the motor. | ||
* Configure the motor in MotionControlMode::velocity. Link the motor to the planner, | ||
* and set the target angle. The planner will take care of controlling the motor | ||
* velocity to follow a trapezoidal profile. | ||
* Call the run() method in the loop, and use the return value to update the motor | ||
* target velocity. Call the trapezoidal planner less frequently than the motor.move() | ||
* method, to ensure the motor has time to reach the target velocity. | ||
* | ||
*/ | ||
class TrapezoidalPlanner { | ||
public: | ||
TrapezoidalPlanner(float max, float accel, float decel = NOT_SET, float min = NOT_SET); | ||
~TrapezoidalPlanner(); | ||
|
||
void linkMotor(FOCMotor& motor); | ||
void setTarget(float target); | ||
float getTarget() { return target; }; | ||
|
||
float run(); | ||
|
||
float arrived_distance = 0.02f; | ||
float arrived_velocity = 0.2f; | ||
float max_velocity; | ||
float min_velocity; | ||
float accel; | ||
float decel; | ||
|
||
protected: | ||
FOCMotor* motor; | ||
float target = NOT_SET; | ||
float last_target = NOT_SET; | ||
float start_ang = 0.0f; | ||
}; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.