Resurgence (PY2022)
Codebase for the Husky Robotics 2021-2022 rover Resurgence
Loading...
Searching...
No Matches
TrapezoidalVelocityProfile.h
1#pragma once
2
3#include "../navtypes.h"
4#include "../utils/time.h"
5#include "../world_interface/data.h"
6
7#include <array>
8#include <cmath>
9#include <optional>
10#include <vector>
11
12#include <Eigen/Core>
13
14namespace control {
15
22template <int dim>
24public:
31 TrapezoidalVelocityProfile(double maxVel, double maxAccel)
32 : maxVel(maxVel), maxAccel(maxAccel) {}
33
37 void reset() {
38 profile.reset();
39 }
40
46 bool hasTarget() const {
47 return profile.has_value();
48 }
49
58 const std::array<double, dim>& endPos) {
59 navtypes::Vectord<dim> startVec, endVec;
60 for (int i = 0; i < dim; i++) {
61 startVec(i) = startPos[i];
62 endVec(i) = endPos[i];
63 }
64 setTarget(currTime, startVec, endVec);
65 }
66
74 void setTarget(robot::types::datatime_t currTime, const navtypes::Vectord<dim>& startPos,
75 const navtypes::Vectord<dim>& endPos) {
76 profile_t profile{.startTime = currTime, .startPos = startPos, .endPos = endPos};
77 // min time required to accelerate to top speed
78 double rampUpTime = maxVel / maxAccel;
79 // min distance required to accelerate to top speed
80 double rampUpDist = std::pow(maxVel, 2) / (2 * maxAccel);
81
82 double dist = (endPos - startPos).norm();
83 if (2 * rampUpDist < dist) {
84 // the profile distance is too short to allow us to get to top speed
85 // so the profile looks like a triangle instead of a trapezoid
86 profile.stopAccelTime = rampUpTime;
87 double coastTime = (dist - 2 * rampUpDist) / maxVel;
88 profile.startDecelTime = rampUpTime + coastTime;
89 profile.totalTime = coastTime + 2 * rampUpTime;
90 } else {
91 // this is the normal case, where we accelerate to top speed, coast for a bit, then
92 // decelerate.
93 double totalTime = 2 * std::sqrt(dist / maxAccel);
94 profile.stopAccelTime = profile.startDecelTime = totalTime / 2;
95 profile.totalTime = totalTime;
96 }
97 this->profile = profile;
98 }
99
107 navtypes::Vectord<dim> getCommand(robot::types::datatime_t currTime) const {
108 if (!profile) {
109 return navtypes::Vectord<dim>::Zero();
110 }
111
112 profile_t profile = this->profile.value();
113 navtypes::Vectord<dim> dir = (profile.endPos - profile.startPos).normalized();
114 double elapsedTime = util::durationToSec(currTime - profile.startTime);
115 if (elapsedTime < 0) {
116 return profile.startPos;
117 } else if (elapsedTime < profile.stopAccelTime) {
118 double dist = 0.5 * maxAccel * std::pow(elapsedTime, 2);
119 return profile.startPos + dir * dist;
120 } else if (elapsedTime < profile.startDecelTime) {
121 // area of trapezoid is average of bases times height
122 double dist = (2 * elapsedTime - profile.stopAccelTime) / 2.0 * maxVel;
123 return profile.startPos + dir * dist;
124 } else if (elapsedTime < profile.totalTime) {
125 double distFromEnd = 0.5 * maxAccel * std::pow(profile.totalTime - elapsedTime, 2);
126 return profile.endPos - dir * distFromEnd;
127 } else {
128 return profile.endPos;
129 }
130 }
131
138 std::optional<util::dseconds> getTotalTime() const {
139 if (profile.has_value()) {
140 return util::dseconds(profile->totalTime);
141 } else {
142 return {};
143 }
144 }
145
146private:
147 struct profile_t {
148 robot::types::datatime_t startTime;
149 double stopAccelTime;
150 double startDecelTime;
151 double totalTime;
152 navtypes::Vectord<dim> startPos;
153 navtypes::Vectord<dim> endPos;
154 };
155 double maxVel, maxAccel;
156 std::optional<profile_t> profile;
157};
158
164public:
171 SingleDimTrapezoidalVelocityProfile(double maxVel, double maxAccel);
172
180 void setTarget(robot::types::datatime_t currTime, double startPos, double endPos);
181
187 bool hasTarget() const;
188
195 double getCommand(robot::types::datatime_t currTime) const;
196
200 void reset();
201
208 std::optional<util::dseconds> getTotalTime() const;
209
210private:
212};
213
214} // namespace control
complex< _Tp > pow(const complex< _Tp > &, int)
complex< _Tp > sqrt(const complex< _Tp > &)
bool hasTarget() const
Check if a profile has been calculated.
Definition TrapezoidalVelocityProfile.cpp:22
std::optional< util::dseconds > getTotalTime() const
Get the total time it takes to perform the profile.
Definition TrapezoidalVelocityProfile.cpp:31
SingleDimTrapezoidalVelocityProfile(double maxVel, double maxAccel)
Construct a new velocity profile.
Definition TrapezoidalVelocityProfile.cpp:7
void setTarget(robot::types::datatime_t currTime, double startPos, double endPos)
Calculate a profile, assuming the mechanism begins and ends at rest.
Definition TrapezoidalVelocityProfile.cpp:15
double getCommand(robot::types::datatime_t currTime) const
Get the target position.
Definition TrapezoidalVelocityProfile.cpp:27
void reset()
Reset the profile and clear any calculated profile.
Definition TrapezoidalVelocityProfile.cpp:11
Trapezoidal velocity profile in multiple dimensions.
Definition TrapezoidalVelocityProfile.h:23
void setTarget(robot::types::datatime_t currTime, const navtypes::Vectord< dim > &startPos, const navtypes::Vectord< dim > &endPos)
Calculate a profile, assuming the mechanism begins and ends at rest.
Definition TrapezoidalVelocityProfile.h:74
TrapezoidalVelocityProfile(double maxVel, double maxAccel)
Construct a new velocity profile object.
Definition TrapezoidalVelocityProfile.h:31
navtypes::Vectord< dim > getCommand(robot::types::datatime_t currTime) const
Get the target position.
Definition TrapezoidalVelocityProfile.h:107
std::optional< util::dseconds > getTotalTime() const
Get the total time it takes to perform the profile.
Definition TrapezoidalVelocityProfile.h:138
void reset()
Reset the profile and clear any calculated profile.
Definition TrapezoidalVelocityProfile.h:37
bool hasTarget() const
Check if a profile has been calculated.
Definition TrapezoidalVelocityProfile.h:46
void setTarget(robot::types::datatime_t currTime, const std::array< double, dim > &startPos, const std::array< double, dim > &endPos)
Calculate a profile, assuming the mechanism begins and ends at rest.
Definition TrapezoidalVelocityProfile.h:57
double norm(InputArray src1, int normType=NORM_L2, InputArray mask=noArray())
std::chrono::time_point< dataclock > datatime_t
A point in time as measured by dataclock.
Definition data.h:31
double durationToSec(std::chrono::duration< Rep, Period > dur)
Convert a duration to seconds, as a double.
Definition time.h:18