Skip to content

Commit a542a71

Browse files
author
Richard Unger
committed
very simple trapezoidal velocity planner
1 parent 3a11d58 commit a542a71

File tree

7 files changed

+163
-0
lines changed

7 files changed

+163
-0
lines changed

src/utilities/trapezoids/README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
# Trapezoids
3+
4+
Classes for trapezoidal motion profiles. Intended as a starting point for your own higher level control schemes.
5+
6+
## TrapezoidalPlanner
7+
8+
Produces trapzoidal velocity profiles for the motor, used with `MotionControlMode::velocity`.
9+
10+
The following graphs show a commanded angle change from 0 to 10 radians executed by the trapezoidal planner. The accelleration limit is set
11+
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
12+
velocity profile. The position profile is nice smooth shape, as expected.
13+
14+
|Velocity|Position|
15+
|---|---|
16+
| ![Velocity Graph](vel_0to10.png) | ![Angle Graph](pos_0to10.png) |
17+
18+
19+
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).
20+
21+
|Velocity|Position|
22+
|---|---|
23+
| ![Velocity Graph](vel_10to0.png) | ![Angle Graph](pos_10to0.png) |
24+
25+
26+
### Usage
27+
28+
The following *incomplete* code example shows only the parts relevant to integrating the planner:
29+
30+
```c++
31+
32+
Commander commander = Commander(Serial);
33+
BLDCMotor motor = BLDCMotor(7); // 7 pole pairs
34+
TrapezoidalPlanner trapezoidal = TrapezoidalPlanner(5.0f, 1.0f, 0.25f, 0.2f);
35+
36+
float target_angle = 0.0f;
37+
38+
void onTarget(char* cmd){ commander.scalar(&target_angle); trapezoidal.setTarget(target_angle); }
39+
40+
void setup() {
41+
42+
...
43+
motor.controller = MotionControlType::velocity;
44+
trapezoidal.linkMotor(motor);
45+
motor.init();
46+
...
47+
commander.add('T', onTarget, "target angle");
48+
trapezoidal.setTarget(target_angle);
49+
}
50+
51+
52+
53+
int32_t downsample = 50; // depending on your MCU's speed, you might want a value between 5 and 50...
54+
int32_t downsample_cnt = 0;
55+
56+
void loop() {
57+
58+
if (downsample > 0 && --downsample_cnt <= 0) {
59+
motor.target = trapezoidal.run();
60+
downsample_cnt = downsample;
61+
}
62+
motor.move();
63+
motor.loopFOC();
64+
commander.run();
65+
66+
}
67+
68+
```
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
3+
#include "./TrapezoidalPlanner.h"
4+
5+
6+
TrapezoidalPlanner::TrapezoidalPlanner(float max, float accel, float decel, float min){
7+
this->max_velocity = max;
8+
this->accel = accel;
9+
this->decel = (decel!=NOT_SET)?decel:accel;
10+
this->min_velocity = (min!=NOT_SET)?min:0.2f;
11+
};
12+
13+
14+
TrapezoidalPlanner::~TrapezoidalPlanner(){};
15+
16+
17+
18+
void TrapezoidalPlanner::linkMotor(FOCMotor& motor){
19+
this->motor = &motor;
20+
};
21+
22+
23+
24+
void TrapezoidalPlanner::setTarget(float target){
25+
this->target = target;
26+
this->start_ang = motor->shaft_angle;
27+
this->last_target = target;
28+
};
29+
30+
31+
32+
float TrapezoidalPlanner::run(){
33+
// given the just current position and the target position, calculate the desired velocity
34+
// assume we're within our acceleration capabilities
35+
float d = target - motor->shaft_angle;
36+
float dd = motor->shaft_angle - start_ang;
37+
// if the target is reached, return 0
38+
if (abs(d) < arrived_distance && abs(motor->shaft_velocity) < arrived_velocity) return 0;
39+
40+
// how fast can we be going, based on deceleration?
41+
float max_v_d = sqrt(2.0f * decel * fabs(d));
42+
// how fast can we be going, based on accelleration?
43+
float max_v_dd = sqrt(2.0f * accel * fabs(dd));
44+
float max_v = min(max_v_d, max_v_dd);
45+
// how fast can we be going, based on max speed?
46+
max_v = min(max_v, max_velocity);
47+
max_v = max(max_v, min_velocity);
48+
// let's go that speed :-)
49+
return max_v * _sign(d);
50+
};
51+
52+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
#pragma once
3+
4+
#include "common/base_classes/FOCMotor.h"
5+
6+
/**
7+
* Trapezoidal planner
8+
*
9+
* Very simple class to demonstrate higher level control on top of the FOC library.
10+
*
11+
* This class is used to generate trapezoidal velocity profiles for the motor.
12+
* Configure the motor in MotionControlMode::velocity. Link the motor to the planner,
13+
* and set the target angle. The planner will take care of controlling the motor
14+
* velocity to follow a trapezoidal profile.
15+
* Call the run() method in the loop, and use the return value to update the motor
16+
* target velocity. Call the trapezoidal planner less frequently than the motor.move()
17+
* method, to ensure the motor has time to reach the target velocity.
18+
*
19+
*/
20+
class TrapezoidalPlanner {
21+
public:
22+
TrapezoidalPlanner(float max, float accel, float decel = NOT_SET, float min = NOT_SET);
23+
~TrapezoidalPlanner();
24+
25+
void linkMotor(FOCMotor& motor);
26+
void setTarget(float target);
27+
float getTarget() { return target; };
28+
29+
float run();
30+
31+
float arrived_distance = 0.02f;
32+
float arrived_velocity = 0.2f;
33+
float max_velocity;
34+
float min_velocity;
35+
float accel;
36+
float decel;
37+
38+
protected:
39+
FOCMotor* motor;
40+
float target = NOT_SET;
41+
float last_target = NOT_SET;
42+
float start_ang = 0.0f;
43+
};
10.8 KB
Loading
11.4 KB
Loading
12.2 KB
Loading
14 KB
Loading

0 commit comments

Comments
 (0)