[wpimath] Move math functionality into new wpimath library (#2629)

The wpimath library is a new library designed to separate the reusable math functionality
from the common utility library (wpiutil) and the hardware-dependent library (wpilibc/j).

Package names / include file names were NOT changed to minimize breakage.  In a future year
it would be good to revamp these for a more uniform user experience and to reduce the risk
of accidental naming conflicts.

While theoretically all of this functionality could be placed into wpiutil, several pieces
of this library (e.g. DARE) are very time-consuming to compile, so it's nice to avoid this
expense for users who only want cscore or ntcore.  It also allows for easy future separation
of build tasks vs number of workers on memory-constrained machines.

This moves the following functionality from wpiutil into wpimath:
- Eigen
- ejml
- Drake
- DARE
- wpiutil.math package (Matrix etc)
- units

And the following functionality from wpilibc/j into wpimath:
- Geometry
- Kinematics
- Spline
- Trajectory
- LinearFilter
- MedianFilter
- Feed-forward controllers
This commit is contained in:
Peter Johnson
2020-08-06 23:57:39 -07:00
committed by GitHub
parent ad817d4f23
commit 42993b15c6
463 changed files with 1006 additions and 399 deletions

View File

@@ -0,0 +1,171 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <vector>
#include "frc/geometry/Pose2d.h"
#include "frc/geometry/Transform2d.h"
#include "units/acceleration.h"
#include "units/curvature.h"
#include "units/time.h"
#include "units/velocity.h"
namespace wpi {
class json;
} // namespace wpi
namespace frc {
/**
* Represents a time-parameterized trajectory. The trajectory contains of
* various States that represent the pose, curvature, time elapsed, velocity,
* and acceleration at that point.
*/
class Trajectory {
public:
/**
* Represents one point on the trajectory.
*/
struct State {
// The time elapsed since the beginning of the trajectory.
units::second_t t = 0_s;
// The speed at that point of the trajectory.
units::meters_per_second_t velocity = 0_mps;
// The acceleration at that point of the trajectory.
units::meters_per_second_squared_t acceleration = 0_mps_sq;
// The pose at that point of the trajectory.
Pose2d pose;
// The curvature at that point of the trajectory.
units::curvature_t curvature{0.0};
/**
* Checks equality between this State and another object.
*
* @param other The other object.
* @return Whether the two objects are equal.
*/
bool operator==(const State& other) const;
/**
* Checks inequality between this State and another object.
*
* @param other The other object.
* @return Whether the two objects are not equal.
*/
bool operator!=(const State& other) const;
/**
* Interpolates between two States.
*
* @param endValue The end value for the interpolation.
* @param i The interpolant (fraction).
*
* @return The interpolated state.
*/
State Interpolate(State endValue, double i) const;
};
Trajectory() = default;
/**
* Constructs a trajectory from a vector of states.
*/
explicit Trajectory(const std::vector<State>& states);
/**
* Returns the overall duration of the trajectory.
* @return The duration of the trajectory.
*/
units::second_t TotalTime() const { return m_totalTime; }
/**
* Return the states of the trajectory.
* @return The states of the trajectory.
*/
const std::vector<State>& States() const { return m_states; }
/**
* Sample the trajectory at a point in time.
*
* @param t The point in time since the beginning of the trajectory to sample.
* @return The state at that point in time.
*/
State Sample(units::second_t t) const;
/**
* Transforms all poses in the trajectory by the given transform. This is
* useful for converting a robot-relative trajectory into a field-relative
* trajectory. This works with respect to the first pose in the trajectory.
*
* @param transform The transform to transform the trajectory by.
* @return The transformed trajectory.
*/
Trajectory TransformBy(const Transform2d& transform);
/**
* Transforms all poses in the trajectory so that they are relative to the
* given pose. This is useful for converting a field-relative trajectory
* into a robot-relative trajectory.
*
* @param pose The pose that is the origin of the coordinate frame that
* the current trajectory will be transformed into.
* @return The transformed trajectory.
*/
Trajectory RelativeTo(const Pose2d& pose);
/**
* Returns the initial pose of the trajectory.
*
* @return The initial pose of the trajectory.
*/
Pose2d InitialPose() const { return Sample(0_s).pose; }
/**
* Checks equality between this Trajectory and another object.
*
* @param other The other object.
* @return Whether the two objects are equal.
*/
bool operator==(const Trajectory& other) const;
/**
* Checks inequality between this Trajectory and another object.
*
* @param other The other object.
* @return Whether the two objects are inequal.
*/
bool operator!=(const Trajectory& other) const;
private:
std::vector<State> m_states;
units::second_t m_totalTime = 0_s;
/**
* Linearly interpolates between two values.
*
* @param startValue The start value.
* @param endValue The end value.
* @param t The fraction for interpolation.
*
* @return The interpolated value.
*/
template <typename T>
static T Lerp(const T& startValue, const T& endValue, const double t) {
return startValue + (endValue - startValue) * t;
}
};
void to_json(wpi::json& json, const Trajectory::State& state);
void from_json(const wpi::json& json, Trajectory::State& state);
} // namespace frc

View File

@@ -0,0 +1,165 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <memory>
#include <utility>
#include <vector>
#include "frc/kinematics/DifferentialDriveKinematics.h"
#include "frc/kinematics/MecanumDriveKinematics.h"
#include "frc/kinematics/SwerveDriveKinematics.h"
#include "frc/trajectory/constraint/DifferentialDriveKinematicsConstraint.h"
#include "frc/trajectory/constraint/MecanumDriveKinematicsConstraint.h"
#include "frc/trajectory/constraint/SwerveDriveKinematicsConstraint.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
#include "units/acceleration.h"
#include "units/velocity.h"
namespace frc {
/**
* Represents the configuration for generating a trajectory. This class stores
* the start velocity, end velocity, max velocity, max acceleration, custom
* constraints, and the reversed flag.
*
* The class must be constructed with a max velocity and max acceleration.
* The other parameters (start velocity, end velocity, constraints, reversed)
* have been defaulted to reasonable values (0, 0, {}, false). These values can
* be changed via the SetXXX methods.
*/
class TrajectoryConfig {
public:
/**
* Constructs a config object.
* @param maxVelocity The max velocity of the trajectory.
* @param maxAcceleration The max acceleration of the trajectory.
*/
TrajectoryConfig(units::meters_per_second_t maxVelocity,
units::meters_per_second_squared_t maxAcceleration)
: m_maxVelocity(maxVelocity), m_maxAcceleration(maxAcceleration) {}
TrajectoryConfig(const TrajectoryConfig&) = delete;
TrajectoryConfig& operator=(const TrajectoryConfig&) = delete;
TrajectoryConfig(TrajectoryConfig&&) = default;
TrajectoryConfig& operator=(TrajectoryConfig&&) = default;
/**
* Sets the start velocity of the trajectory.
* @param startVelocity The start velocity of the trajectory.
*/
void SetStartVelocity(units::meters_per_second_t startVelocity) {
m_startVelocity = startVelocity;
}
/**
* Sets the end velocity of the trajectory.
* @param endVelocity The end velocity of the trajectory.
*/
void SetEndVelocity(units::meters_per_second_t endVelocity) {
m_endVelocity = endVelocity;
}
/**
* Sets the reversed flag of the trajectory.
* @param reversed Whether the trajectory should be reversed or not.
*/
void SetReversed(bool reversed) { m_reversed = reversed; }
/**
* Adds a user-defined constraint to the trajectory.
* @param constraint The user-defined constraint.
*/
template <typename Constraint, typename = std::enable_if_t<std::is_base_of_v<
TrajectoryConstraint, Constraint>>>
void AddConstraint(Constraint constraint) {
m_constraints.emplace_back(std::make_unique<Constraint>(constraint));
}
/**
* Adds a differential drive kinematics constraint to ensure that
* no wheel velocity of a differential drive goes above the max velocity.
*
* @param kinematics The differential drive kinematics.
*/
void SetKinematics(const DifferentialDriveKinematics& kinematics) {
AddConstraint(
DifferentialDriveKinematicsConstraint(kinematics, m_maxVelocity));
}
/**
* Adds a mecanum drive kinematics constraint to ensure that
* no wheel velocity of a mecanum drive goes above the max velocity.
*
* @param kinematics The mecanum drive kinematics.
*/
void SetKinematics(MecanumDriveKinematics kinematics) {
AddConstraint(MecanumDriveKinematicsConstraint(kinematics, m_maxVelocity));
}
/**
* Adds a swerve drive kinematics constraint to ensure that
* no wheel velocity of a swerve drive goes above the max velocity.
*
* @param kinematics The swerve drive kinematics.
*/
template <size_t NumModules>
void SetKinematics(SwerveDriveKinematics<NumModules>& kinematics) {
AddConstraint(SwerveDriveKinematicsConstraint(kinematics, m_maxVelocity));
}
/**
* Returns the starting velocity of the trajectory.
* @return The starting velocity of the trajectory.
*/
units::meters_per_second_t StartVelocity() const { return m_startVelocity; }
/**
* Returns the ending velocity of the trajectory.
* @return The ending velocity of the trajectory.
*/
units::meters_per_second_t EndVelocity() const { return m_endVelocity; }
/**
* Returns the maximum velocity of the trajectory.
* @return The maximum velocity of the trajectory.
*/
units::meters_per_second_t MaxVelocity() const { return m_maxVelocity; }
/**
* Returns the maximum acceleration of the trajectory.
* @return The maximum acceleration of the trajectory.
*/
units::meters_per_second_squared_t MaxAcceleration() const {
return m_maxAcceleration;
}
/**
* Returns the user-defined constraints of the trajectory.
* @return The user-defined constraints of the trajectory.
*/
const std::vector<std::unique_ptr<TrajectoryConstraint>>& Constraints()
const {
return m_constraints;
}
/**
* Returns whether the trajectory is reversed or not.
* @return whether the trajectory is reversed or not.
*/
bool IsReversed() const { return m_reversed; }
private:
units::meters_per_second_t m_startVelocity = 0_mps;
units::meters_per_second_t m_endVelocity = 0_mps;
units::meters_per_second_t m_maxVelocity;
units::meters_per_second_squared_t m_maxAcceleration;
std::vector<std::unique_ptr<TrajectoryConstraint>> m_constraints;
bool m_reversed = false;
};
} // namespace frc

View File

@@ -0,0 +1,133 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <functional>
#include <memory>
#include <utility>
#include <vector>
#include "frc/spline/SplineParameterizer.h"
#include "frc/trajectory/Trajectory.h"
#include "frc/trajectory/TrajectoryConfig.h"
#include "frc/trajectory/constraint/DifferentialDriveKinematicsConstraint.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
namespace frc {
/**
* Helper class used to generate trajectories with various constraints.
*/
class TrajectoryGenerator {
public:
using PoseWithCurvature = std::pair<Pose2d, units::curvature_t>;
/**
* Generates a trajectory from the given control vectors and config. This
* method uses clamped cubic splines -- a method in which the exterior control
* vectors and interior waypoints are provided. The headings are automatically
* determined at the interior points to ensure continuous curvature.
*
* @param initial The initial control vector.
* @param interiorWaypoints The interior waypoints.
* @param end The ending control vector.
* @param config The configuration for the trajectory.
* @return The generated trajectory.
*/
static Trajectory GenerateTrajectory(
Spline<3>::ControlVector initial,
const std::vector<Translation2d>& interiorWaypoints,
Spline<3>::ControlVector end, const TrajectoryConfig& config);
/**
* Generates a trajectory from the given waypoints and config. This method
* uses clamped cubic splines -- a method in which the initial pose, final
* pose, and interior waypoints are provided. The headings are automatically
* determined at the interior points to ensure continuous curvature.
*
* @param start The starting pose.
* @param interiorWaypoints The interior waypoints.
* @param end The ending pose.
* @param config The configuration for the trajectory.
* @return The generated trajectory.
*/
static Trajectory GenerateTrajectory(
const Pose2d& start, const std::vector<Translation2d>& interiorWaypoints,
const Pose2d& end, const TrajectoryConfig& config);
/**
* Generates a trajectory from the given quintic control vectors and config.
* This method uses quintic hermite splines -- therefore, all points must be
* represented by control vectors. Continuous curvature is guaranteed in this
* method.
*
* @param controlVectors List of quintic control vectors.
* @param config The configuration for the trajectory.
* @return The generated trajectory.
*/
static Trajectory GenerateTrajectory(
std::vector<Spline<5>::ControlVector> controlVectors,
const TrajectoryConfig& config);
/**
* Generates a trajectory from the given waypoints and config. This method
* uses quintic hermite splines -- therefore, all points must be represented
* by Pose2d objects. Continuous curvature is guaranteed in this method.
*
* @param waypoints List of waypoints..
* @param config The configuration for the trajectory.
* @return The generated trajectory.
*/
static Trajectory GenerateTrajectory(const std::vector<Pose2d>& waypoints,
const TrajectoryConfig& config);
/**
* Generate spline points from a vector of splines by parameterizing the
* splines.
*
* @param splines The splines to parameterize.
*
* @return The spline points for use in time parameterization of a trajectory.
*/
template <typename Spline>
static std::vector<PoseWithCurvature> SplinePointsFromSplines(
const std::vector<Spline>& splines) {
// Create the vector of spline points.
std::vector<PoseWithCurvature> splinePoints;
// Add the first point to the vector.
splinePoints.push_back(splines.front().GetPoint(0.0));
// Iterate through the vector and parameterize each spline, adding the
// parameterized points to the final vector.
for (auto&& spline : splines) {
auto points = SplineParameterizer::Parameterize(spline);
// Append the array of poses to the vector. We are removing the first
// point because it's a duplicate of the last point from the previous
// spline.
splinePoints.insert(std::end(splinePoints), std::begin(points) + 1,
std::end(points));
}
return splinePoints;
}
/**
* Set error reporting function. By default, it is output to stderr.
*
* @param func Error reporting function.
*/
static void SetErrorHandler(std::function<void(const char*)> func) {
s_errorFunc = std::move(func);
}
private:
static void ReportError(const char* error);
static const Trajectory kDoNothingTrajectory;
static std::function<void(const char*)> s_errorFunc;
};
} // namespace frc

View File

@@ -0,0 +1,107 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
/*
* MIT License
*
* Copyright (c) 2018 Team 254
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
#include <memory>
#include <utility>
#include <vector>
#include "frc/trajectory/Trajectory.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
namespace frc {
/**
* Class used to parameterize a trajectory by time.
*/
class TrajectoryParameterizer {
public:
using PoseWithCurvature = std::pair<Pose2d, units::curvature_t>;
/**
* Parameterize the trajectory by time. This is where the velocity profile is
* generated.
*
* The derivation of the algorithm used can be found here:
* <http://www2.informatik.uni-freiburg.de/~lau/students/Sprunk2008.pdf>
*
* @param points Reference to the spline points.
* @param constraints A vector of various velocity and acceleration
* constraints.
* @param startVelocity The start velocity for the trajectory.
* @param endVelocity The end velocity for the trajectory.
* @param maxVelocity The max velocity for the trajectory.
* @param maxAcceleration The max acceleration for the trajectory.
* @param reversed Whether the robot should move backwards. Note that the
* robot will still move from a -> b -> ... -> z as defined in the waypoints.
*
* @return The trajectory.
*/
static Trajectory TimeParameterizeTrajectory(
const std::vector<PoseWithCurvature>& points,
const std::vector<std::unique_ptr<TrajectoryConstraint>>& constraints,
units::meters_per_second_t startVelocity,
units::meters_per_second_t endVelocity,
units::meters_per_second_t maxVelocity,
units::meters_per_second_squared_t maxAcceleration, bool reversed);
private:
constexpr static double kEpsilon = 1E-6;
/**
* Represents a constrained state that is used when time parameterizing a
* trajectory. Each state has the pose, curvature, distance from the start of
* the trajectory, max velocity, min acceleration and max acceleration.
*/
struct ConstrainedState {
PoseWithCurvature pose = {Pose2d(), units::curvature_t(0.0)};
units::meter_t distance = 0_m;
units::meters_per_second_t maxVelocity = 0_mps;
units::meters_per_second_squared_t minAcceleration = 0_mps_sq;
units::meters_per_second_squared_t maxAcceleration = 0_mps_sq;
};
/**
* Enforces acceleration limits as defined by the constraints. This function
* is used when time parameterizing a trajectory.
*
* @param reverse Whether the robot is traveling backwards.
* @param constraints A vector of the user-defined velocity and acceleration
* constraints.
* @param state Pointer to the constrained state that we are operating on.
* This is mutated in place.
*/
static void EnforceAccelerationLimits(
bool reverse,
const std::vector<std::unique_ptr<TrajectoryConstraint>>& constraints,
ConstrainedState* state);
};
} // namespace frc

View File

@@ -0,0 +1,59 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <string>
#include <wpi/StringRef.h>
#include <wpi/Twine.h>
#include "frc/trajectory/Trajectory.h"
namespace frc {
class TrajectoryUtil {
public:
TrajectoryUtil() = delete;
/**
* Exports a Trajectory to a PathWeaver-style JSON file.
*
* @param trajectory the trajectory to export
* @param path the path of the file to export to
*
* @return The interpolated state.
*/
static void ToPathweaverJson(const Trajectory& trajectory,
const wpi::Twine& path);
/**
* Imports a Trajectory from a PathWeaver-style JSON file.
*
* @param path The path of the json file to import from.
*
* @return The trajectory represented by the file.
*/
static Trajectory FromPathweaverJson(const wpi::Twine& path);
/**
* Deserializes a Trajectory from PathWeaver-style JSON.
* @param json the string containing the serialized JSON
* @return the trajectory represented by the JSON
*/
static std::string SerializeTrajectory(const Trajectory& trajectory);
/**
* Serializes a Trajectory to PathWeaver-style JSON.
* @param trajectory the trajectory to export
* @return the string containing the serialized JSON
*/
static Trajectory DeserializeTrajectory(wpi::StringRef json_str);
};
} // namespace frc

View File

@@ -0,0 +1,159 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "math/MathShared.h"
#include "units/time.h"
namespace frc {
/**
* A trapezoid-shaped velocity profile.
*
* While this class can be used for a profiled movement from start to finish,
* the intended usage is to filter a reference's dynamics based on trapezoidal
* velocity constraints. To compute the reference obeying this constraint, do
* the following.
*
* Initialization:
* @code{.cpp}
* TrapezoidalMotionProfile::Constraints constraints{kMaxV, kMaxA};
* double previousProfiledReference = initialReference;
* @endcode
*
* Run on update:
* @code{.cpp}
* TrapezoidalMotionProfile profile{constraints, unprofiledReference,
* previousProfiledReference};
* previousProfiledReference = profile.Calculate(timeSincePreviousUpdate);
* @endcode
*
* where `unprofiledReference` is free to change between calls. Note that when
* the unprofiled reference is within the constraints, `Calculate()` returns the
* unprofiled reference unchanged.
*
* Otherwise, a timer can be started to provide monotonic values for
* `Calculate()` and to determine when the profile has completed via
* `IsFinished()`.
*/
template <class Distance>
class TrapezoidProfile {
public:
using Distance_t = units::unit_t<Distance>;
using Velocity =
units::compound_unit<Distance, units::inverse<units::seconds>>;
using Velocity_t = units::unit_t<Velocity>;
using Acceleration =
units::compound_unit<Velocity, units::inverse<units::seconds>>;
using Acceleration_t = units::unit_t<Acceleration>;
class Constraints {
public:
Constraints() {
wpi::math::MathSharedStore::ReportUsage(
wpi::math::MathUsageId::kTrajectory_TrapezoidProfile, 1);
}
Constraints(Velocity_t maxVelocity_, Acceleration_t maxAcceleration_)
: maxVelocity{maxVelocity_}, maxAcceleration{maxAcceleration_} {
wpi::math::MathSharedStore::ReportUsage(
wpi::math::MathUsageId::kTrajectory_TrapezoidProfile, 1);
}
Velocity_t maxVelocity{0};
Acceleration_t maxAcceleration{0};
};
class State {
public:
Distance_t position{0};
Velocity_t velocity{0};
bool operator==(const State& rhs) const {
return position == rhs.position && velocity == rhs.velocity;
}
bool operator!=(const State& rhs) const { return !(*this == rhs); }
};
/**
* Construct a TrapezoidProfile.
*
* @param constraints The constraints on the profile, like maximum velocity.
* @param goal The desired state when the profile is complete.
* @param initial The initial state (usually the current state).
*/
TrapezoidProfile(Constraints constraints, State goal,
State initial = State{Distance_t(0), Velocity_t(0)});
TrapezoidProfile(const TrapezoidProfile&) = default;
TrapezoidProfile& operator=(const TrapezoidProfile&) = default;
TrapezoidProfile(TrapezoidProfile&&) = default;
TrapezoidProfile& operator=(TrapezoidProfile&&) = default;
/**
* Calculate the correct position and velocity for the profile at a time t
* where the beginning of the profile was at time t = 0.
*
* @param t The time since the beginning of the profile.
*/
State Calculate(units::second_t t) const;
/**
* Returns the time left until a target distance in the profile is reached.
*
* @param target The target distance.
*/
units::second_t TimeLeftUntil(Distance_t target) const;
/**
* Returns the total time the profile takes to reach the goal.
*/
units::second_t TotalTime() const { return m_endDeccel; }
/**
* Returns true if the profile has reached the goal.
*
* The profile has reached the goal if the time since the profile started
* has exceeded the profile's total time.
*
* @param t The time since the beginning of the profile.
*/
bool IsFinished(units::second_t t) const { return t >= TotalTime(); }
private:
/**
* Returns true if the profile inverted.
*
* The profile is inverted if goal position is less than the initial position.
*
* @param initial The initial state (usually the current state).
* @param goal The desired state when the profile is complete.
*/
static bool ShouldFlipAcceleration(const State& initial, const State& goal) {
return initial.position > goal.position;
}
// Flip the sign of the velocity and position if the profile is inverted
State Direct(const State& in) const {
State result = in;
result.position *= m_direction;
result.velocity *= m_direction;
return result;
}
// The direction of the profile, either 1 for forwards or -1 for inverted
int m_direction;
Constraints m_constraints;
State m_initial;
State m_goal;
units::second_t m_endAccel;
units::second_t m_endFullSpeed;
units::second_t m_endDeccel;
};
} // namespace frc
#include "TrapezoidProfile.inc"

View File

@@ -0,0 +1,165 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <algorithm>
#include "units/math.h"
namespace frc {
template <class Distance>
TrapezoidProfile<Distance>::TrapezoidProfile(Constraints constraints,
State goal, State initial)
: m_direction{ShouldFlipAcceleration(initial, goal) ? -1 : 1},
m_constraints(constraints),
m_initial(Direct(initial)),
m_goal(Direct(goal)) {
if (m_initial.velocity > m_constraints.maxVelocity) {
m_initial.velocity = m_constraints.maxVelocity;
}
// Deal with a possibly truncated motion profile (with nonzero initial or
// final velocity) by calculating the parameters as if the profile began and
// ended at zero velocity
units::second_t cutoffBegin =
m_initial.velocity / m_constraints.maxAcceleration;
Distance_t cutoffDistBegin =
cutoffBegin * cutoffBegin * m_constraints.maxAcceleration / 2.0;
units::second_t cutoffEnd = m_goal.velocity / m_constraints.maxAcceleration;
Distance_t cutoffDistEnd =
cutoffEnd * cutoffEnd * m_constraints.maxAcceleration / 2.0;
// Now we can calculate the parameters as if it was a full trapezoid instead
// of a truncated one
Distance_t fullTrapezoidDist =
cutoffDistBegin + (m_goal.position - m_initial.position) + cutoffDistEnd;
units::second_t accelerationTime =
m_constraints.maxVelocity / m_constraints.maxAcceleration;
Distance_t fullSpeedDist =
fullTrapezoidDist -
accelerationTime * accelerationTime * m_constraints.maxAcceleration;
// Handle the case where the profile never reaches full speed
if (fullSpeedDist < Distance_t(0)) {
accelerationTime =
units::math::sqrt(fullTrapezoidDist / m_constraints.maxAcceleration);
fullSpeedDist = Distance_t(0);
}
m_endAccel = accelerationTime - cutoffBegin;
m_endFullSpeed = m_endAccel + fullSpeedDist / m_constraints.maxVelocity;
m_endDeccel = m_endFullSpeed + accelerationTime - cutoffEnd;
}
template <class Distance>
typename TrapezoidProfile<Distance>::State
TrapezoidProfile<Distance>::Calculate(units::second_t t) const {
State result = m_initial;
if (t < m_endAccel) {
result.velocity += t * m_constraints.maxAcceleration;
result.position +=
(m_initial.velocity + t * m_constraints.maxAcceleration / 2.0) * t;
} else if (t < m_endFullSpeed) {
result.velocity = m_constraints.maxVelocity;
result.position += (m_initial.velocity +
m_endAccel * m_constraints.maxAcceleration / 2.0) *
m_endAccel +
m_constraints.maxVelocity * (t - m_endAccel);
} else if (t <= m_endDeccel) {
result.velocity =
m_goal.velocity + (m_endDeccel - t) * m_constraints.maxAcceleration;
units::second_t timeLeft = m_endDeccel - t;
result.position =
m_goal.position -
(m_goal.velocity + timeLeft * m_constraints.maxAcceleration / 2.0) *
timeLeft;
} else {
result = m_goal;
}
return Direct(result);
}
template <class Distance>
units::second_t TrapezoidProfile<Distance>::TimeLeftUntil(
Distance_t target) const {
Distance_t position = m_initial.position * m_direction;
Velocity_t velocity = m_initial.velocity * m_direction;
units::second_t endAccel = m_endAccel * m_direction;
units::second_t endFullSpeed = m_endFullSpeed * m_direction - endAccel;
if (target < position) {
endAccel *= -1.0;
endFullSpeed *= -1.0;
velocity *= -1.0;
}
endAccel = units::math::max(endAccel, 0_s);
endFullSpeed = units::math::max(endFullSpeed, 0_s);
units::second_t endDeccel = m_endDeccel - endAccel - endFullSpeed;
endDeccel = units::math::max(endDeccel, 0_s);
const Acceleration_t acceleration = m_constraints.maxAcceleration;
const Acceleration_t decceleration = -m_constraints.maxAcceleration;
Distance_t distToTarget = units::math::abs(target - position);
if (distToTarget < Distance_t(1e-6)) {
return 0_s;
}
Distance_t accelDist =
velocity * endAccel + 0.5 * acceleration * endAccel * endAccel;
Velocity_t deccelVelocity;
if (endAccel > 0_s) {
deccelVelocity = units::math::sqrt(
units::math::abs(velocity * velocity + 2 * acceleration * accelDist));
} else {
deccelVelocity = velocity;
}
Distance_t deccelDist =
deccelVelocity * endDeccel + 0.5 * decceleration * endDeccel * endDeccel;
deccelDist = units::math::max(deccelDist, Distance_t(0));
Distance_t fullSpeedDist = m_constraints.maxVelocity * endFullSpeed;
if (accelDist > distToTarget) {
accelDist = distToTarget;
fullSpeedDist = Distance_t(0);
deccelDist = Distance_t(0);
} else if (accelDist + fullSpeedDist > distToTarget) {
fullSpeedDist = distToTarget - accelDist;
deccelDist = Distance_t(0);
} else {
deccelDist = distToTarget - fullSpeedDist - accelDist;
}
units::second_t accelTime =
(-velocity + units::math::sqrt(units::math::abs(
velocity * velocity + 2 * acceleration * accelDist))) /
acceleration;
units::second_t deccelTime =
(-deccelVelocity +
units::math::sqrt(units::math::abs(deccelVelocity * deccelVelocity +
2 * decceleration * deccelDist))) /
decceleration;
units::second_t fullSpeedTime = fullSpeedDist / m_constraints.maxVelocity;
return accelTime + fullSpeedTime + deccelTime;
}
} // namespace frc

View File

@@ -0,0 +1,41 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
#include "units/acceleration.h"
#include "units/curvature.h"
#include "units/velocity.h"
namespace frc {
/**
* A constraint on the maximum absolute centripetal acceleration allowed when
* traversing a trajectory. The centripetal acceleration of a robot is defined
* as the velocity squared divided by the radius of curvature.
*
* Effectively, limiting the maximum centripetal acceleration will cause the
* robot to slow down around tight turns, making it easier to track trajectories
* with sharp turns.
*/
class CentripetalAccelerationConstraint : public TrajectoryConstraint {
public:
explicit CentripetalAccelerationConstraint(
units::meters_per_second_squared_t maxCentripetalAcceleration);
units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const override;
MinMax MinMaxAcceleration(const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const override;
private:
units::meters_per_second_squared_t m_maxCentripetalAcceleration;
};
} // namespace frc

View File

@@ -0,0 +1,37 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "frc/kinematics/DifferentialDriveKinematics.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
#include "units/velocity.h"
namespace frc {
/**
* A class that enforces constraints on the differential drive kinematics.
* This can be used to ensure that the trajectory is constructed so that the
* commanded velocities for both sides of the drivetrain stay below a certain
* limit.
*/
class DifferentialDriveKinematicsConstraint : public TrajectoryConstraint {
public:
DifferentialDriveKinematicsConstraint(DifferentialDriveKinematics kinematics,
units::meters_per_second_t maxSpeed);
units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const override;
MinMax MinMaxAcceleration(const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const override;
private:
DifferentialDriveKinematics m_kinematics;
units::meters_per_second_t m_maxSpeed;
};
} // namespace frc

View File

@@ -0,0 +1,51 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "frc/controller/SimpleMotorFeedforward.h"
#include "frc/kinematics/DifferentialDriveKinematics.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
#include "units/length.h"
#include "units/voltage.h"
namespace frc {
/**
* A class that enforces constraints on differential drive voltage expenditure
* based on the motor dynamics and the drive kinematics. Ensures that the
* acceleration of any wheel of the robot while following the trajectory is
* never higher than what can be achieved with the given maximum voltage.
*/
class DifferentialDriveVoltageConstraint : public TrajectoryConstraint {
public:
/**
* Creates a new DifferentialDriveVoltageConstraint.
*
* @param feedforward A feedforward component describing the behavior of the
* drive.
* @param kinematics A kinematics component describing the drive geometry.
* @param maxVoltage The maximum voltage available to the motors while
* following the path. Should be somewhat less than the nominal battery
* voltage (12V) to account for "voltage sag" due to current draw.
*/
DifferentialDriveVoltageConstraint(
SimpleMotorFeedforward<units::meter> feedforward,
DifferentialDriveKinematics kinematics, units::volt_t maxVoltage);
units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const override;
MinMax MinMaxAcceleration(const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const override;
private:
SimpleMotorFeedforward<units::meter> m_feedforward;
DifferentialDriveKinematics m_kinematics;
units::volt_t m_maxVoltage;
};
} // namespace frc

View File

@@ -0,0 +1,56 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "frc/geometry/Rotation2d.h"
#include "frc/geometry/Translation2d.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
#include "units/length.h"
namespace frc {
/**
* Enforces a particular constraint only within an elliptical region.
*/
class EllipticalRegionConstraint : public TrajectoryConstraint {
public:
/**
* Constructs a new EllipticalRegionConstraint.
*
* @param center The center of the ellipse in which to enforce the constraint.
* @param xWidth The width of the ellipse in which to enforce the constraint.
* @param yWidth The height of the ellipse in which to enforce the constraint.
* @param rotation The rotation to apply to all radii around the origin.
* @param constraint The constraint to enforce when the robot is within the
* region.
*/
EllipticalRegionConstraint(const Translation2d& center, units::meter_t xWidth,
units::meter_t yWidth, const Rotation2d& rotation,
const TrajectoryConstraint& constraint);
units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const override;
MinMax MinMaxAcceleration(const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const override;
/**
* Returns whether the specified robot pose is within the region that the
* constraint is enforced in.
*
* @param pose The robot pose.
* @return Whether the robot pose is within the constraint region.
*/
bool IsPoseInRegion(const Pose2d& pose) const;
private:
Translation2d m_center;
Translation2d m_radii;
const TrajectoryConstraint& m_constraint;
};
} // namespace frc

View File

@@ -0,0 +1,44 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
#include "units/math.h"
#include "units/velocity.h"
namespace frc {
/**
* Represents a constraint that enforces a max velocity. This can be composed
* with the EllipticalRegionConstraint or RectangularRegionConstraint to enforce
* a max velocity within a region.
*/
class MaxVelocityConstraint : public TrajectoryConstraint {
public:
/**
* Constructs a new MaxVelocityConstraint.
*
* @param maxVelocity The max velocity.
*/
explicit MaxVelocityConstraint(units::meters_per_second_t maxVelocity)
: m_maxVelocity(units::math::abs(maxVelocity)) {}
units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const override {
return m_maxVelocity;
}
MinMax MinMaxAcceleration(const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const override {
return {};
}
private:
units::meters_per_second_t m_maxVelocity;
};
} // namespace frc

View File

@@ -0,0 +1,39 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <cmath>
#include "frc/kinematics/MecanumDriveKinematics.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
#include "units/velocity.h"
namespace frc {
/**
* A class that enforces constraints on the mecanum drive kinematics.
* This can be used to ensure that the trajectory is constructed so that the
* commanded velocities for wheels of the drivetrain stay below a certain
* limit.
*/
class MecanumDriveKinematicsConstraint : public TrajectoryConstraint {
public:
MecanumDriveKinematicsConstraint(MecanumDriveKinematics kinematics,
units::meters_per_second_t maxSpeed);
units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const override;
MinMax MinMaxAcceleration(const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const override;
private:
MecanumDriveKinematics m_kinematics;
units::meters_per_second_t m_maxSpeed;
};
} // namespace frc

View File

@@ -0,0 +1,55 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include "frc/geometry/Rotation2d.h"
#include "frc/geometry/Translation2d.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
namespace frc {
/**
* Enforces a particular constraint only within a rectangular region.
*/
class RectangularRegionConstraint : public TrajectoryConstraint {
public:
/**
* Constructs a new RectangularRegionConstraint.
*
* @param bottomLeftPoint The bottom left point of the rectangular region in
* which to enforce the constraint.
* @param topRightPoint The top right point of the rectangular region in which
* to enforce the constraint.
* @param constraint The constraint to enforce when the robot is within the
* region.
*/
RectangularRegionConstraint(const Translation2d& bottomLeftPoint,
const Translation2d& topRightPoint,
const TrajectoryConstraint& constraint);
units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const override;
MinMax MinMaxAcceleration(const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const override;
/**
* Returns whether the specified robot pose is within the region that the
* constraint is enforced in.
*
* @param pose The robot pose.
* @return Whether the robot pose is within the constraint region.
*/
bool IsPoseInRegion(const Pose2d& pose) const;
private:
Translation2d m_bottomLeftPoint;
Translation2d m_topRightPoint;
const TrajectoryConstraint& m_constraint;
};
} // namespace frc

View File

@@ -0,0 +1,44 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <cmath>
#include "frc/kinematics/SwerveDriveKinematics.h"
#include "frc/trajectory/constraint/TrajectoryConstraint.h"
#include "units/velocity.h"
namespace frc {
template <size_t NumModules>
/**
* A class that enforces constraints on the swerve drive kinematics.
* This can be used to ensure that the trajectory is constructed so that the
* commanded velocities of the wheels stay below a certain limit.
*/
class SwerveDriveKinematicsConstraint : public TrajectoryConstraint {
public:
SwerveDriveKinematicsConstraint(
frc::SwerveDriveKinematics<NumModules> kinematics,
units::meters_per_second_t maxSpeed);
units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const override;
MinMax MinMaxAcceleration(const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const override;
private:
frc::SwerveDriveKinematics<NumModules> m_kinematics;
units::meters_per_second_t m_maxSpeed;
};
} // namespace frc
#include "SwerveDriveKinematicsConstraint.inc"

View File

@@ -0,0 +1,50 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <units/math.h>
namespace frc {
template <size_t NumModules>
/**
* A class that enforces constraints on the swerve drive kinematics.
* This can be used to ensure that the trajectory is constructed so that the
* commanded velocities of the wheels stay below a certain limit.
*/
SwerveDriveKinematicsConstraint<NumModules>::SwerveDriveKinematicsConstraint(
frc::SwerveDriveKinematics<NumModules> kinematics,
units::meters_per_second_t maxSpeed)
: m_kinematics(kinematics), m_maxSpeed(maxSpeed) {}
template <size_t NumModules>
units::meters_per_second_t
SwerveDriveKinematicsConstraint<NumModules>::MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const {
auto xVelocity = velocity * pose.Rotation().Cos();
auto yVelocity = velocity * pose.Rotation().Sin();
auto wheelSpeeds = m_kinematics.ToSwerveModuleStates(
{xVelocity, yVelocity, velocity * curvature});
m_kinematics.NormalizeWheelSpeeds(&wheelSpeeds, m_maxSpeed);
auto normSpeeds = m_kinematics.ToChassisSpeeds(wheelSpeeds);
return units::math::hypot(normSpeeds.vx, normSpeeds.vy);
}
template <size_t NumModules>
TrajectoryConstraint::MinMax
SwerveDriveKinematicsConstraint<NumModules>::MinMaxAcceleration(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t speed) const {
return {};
}
} // namespace frc

View File

@@ -0,0 +1,80 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <limits>
#include "frc/geometry/Pose2d.h"
#include "frc/spline/Spline.h"
#include "units/acceleration.h"
#include "units/curvature.h"
#include "units/velocity.h"
namespace frc {
/**
* An interface for defining user-defined velocity and acceleration constraints
* while generating trajectories.
*/
class TrajectoryConstraint {
public:
TrajectoryConstraint() = default;
TrajectoryConstraint(const TrajectoryConstraint&) = default;
TrajectoryConstraint& operator=(const TrajectoryConstraint&) = default;
TrajectoryConstraint(TrajectoryConstraint&&) = default;
TrajectoryConstraint& operator=(TrajectoryConstraint&&) = default;
virtual ~TrajectoryConstraint() = default;
/**
* Represents a minimum and maximum acceleration.
*/
struct MinMax {
/**
* The minimum acceleration.
*/
units::meters_per_second_squared_t minAcceleration{
-std::numeric_limits<double>::max()};
/**
* The maximum acceleration.
*/
units::meters_per_second_squared_t maxAcceleration{
std::numeric_limits<double>::max()};
};
/**
* Returns the max velocity given the current pose and curvature.
*
* @param pose The pose at the current point in the trajectory.
* @param curvature The curvature at the current point in the trajectory.
* @param velocity The velocity at the current point in the trajectory before
* constraints are applied.
*
* @return The absolute maximum velocity.
*/
virtual units::meters_per_second_t MaxVelocity(
const Pose2d& pose, units::curvature_t curvature,
units::meters_per_second_t velocity) const = 0;
/**
* Returns the minimum and maximum allowable acceleration for the trajectory
* given pose, curvature, and speed.
*
* @param pose The pose at the current point in the trajectory.
* @param curvature The curvature at the current point in the trajectory.
* @param speed The speed at the current point in the trajectory.
*
* @return The min and max acceleration bounds.
*/
virtual MinMax MinMaxAcceleration(const Pose2d& pose,
units::curvature_t curvature,
units::meters_per_second_t speed) const = 0;
};
} // namespace frc