mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-28 02:11:43 +00:00
[wpimath] Replace Speeds with Velocities (#8479)
I left "free speed" alone since that's the technical term for it. In general, velocity is a vector quantity, and speed is a magnitude (i.e., a strictly positive value). This PR also replaces the speed verbiage in MotorController with duty cycle. Fixes #8423.
This commit is contained in:
@@ -23,7 +23,7 @@ namespace wpi::math {
|
||||
*
|
||||
* <p>Note that this is an *asymmetric* bang-bang controller - it will not exert
|
||||
* any control effort in the reverse direction (e.g. it won't try to slow down
|
||||
* an over-speeding shooter wheel). This asymmetry is *extremely important.*
|
||||
* an overspeeding shooter wheel). This asymmetry is *extremely important*.
|
||||
* Bang-bang control is extremely simple, but also potentially hazardous. Always
|
||||
* ensure that your motor controllers are set to "coast" before attempting to
|
||||
* control them with a bang-bang controller.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <Eigen/Core>
|
||||
|
||||
#include "wpi/math/geometry/Pose2d.hpp"
|
||||
#include "wpi/math/kinematics/ChassisSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/ChassisVelocities.hpp"
|
||||
#include "wpi/math/trajectory/Trajectory.hpp"
|
||||
#include "wpi/math/util/StateSpaceUtil.hpp"
|
||||
#include "wpi/units/angular_velocity.hpp"
|
||||
@@ -104,9 +104,10 @@ class WPILIB_DLLEXPORT LTVUnicycleController {
|
||||
* @param linearVelocityRef The desired linear velocity.
|
||||
* @param angularVelocityRef The desired angular velocity.
|
||||
*/
|
||||
ChassisSpeeds Calculate(const Pose2d& currentPose, const Pose2d& poseRef,
|
||||
wpi::units::meters_per_second_t linearVelocityRef,
|
||||
wpi::units::radians_per_second_t angularVelocityRef);
|
||||
ChassisVelocities Calculate(
|
||||
const Pose2d& currentPose, const Pose2d& poseRef,
|
||||
wpi::units::meters_per_second_t linearVelocityRef,
|
||||
wpi::units::radians_per_second_t angularVelocityRef);
|
||||
|
||||
/**
|
||||
* Returns the linear and angular velocity outputs of the LTV controller.
|
||||
@@ -118,8 +119,8 @@ class WPILIB_DLLEXPORT LTVUnicycleController {
|
||||
* @param desiredState The desired pose, linear velocity, and angular velocity
|
||||
* from a trajectory.
|
||||
*/
|
||||
ChassisSpeeds Calculate(const Pose2d& currentPose,
|
||||
const Trajectory::State& desiredState) {
|
||||
ChassisVelocities Calculate(const Pose2d& currentPose,
|
||||
const Trajectory::State& desiredState) {
|
||||
return Calculate(currentPose, desiredState.pose, desiredState.velocity,
|
||||
desiredState.velocity * desiredState.curvature);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace wpi::math {
|
||||
*/
|
||||
class WPILIB_DLLEXPORT DifferentialDrivePoseEstimator
|
||||
: public PoseEstimator<DifferentialDriveWheelPositions,
|
||||
DifferentialDriveWheelSpeeds,
|
||||
DifferentialDriveWheelVelocities,
|
||||
DifferentialDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace wpi::math {
|
||||
*/
|
||||
class WPILIB_DLLEXPORT DifferentialDrivePoseEstimator3d
|
||||
: public PoseEstimator3d<DifferentialDriveWheelPositions,
|
||||
DifferentialDriveWheelSpeeds,
|
||||
DifferentialDriveWheelVelocities,
|
||||
DifferentialDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -28,7 +28,8 @@ namespace wpi::math {
|
||||
* odometry.
|
||||
*/
|
||||
class WPILIB_DLLEXPORT MecanumDrivePoseEstimator
|
||||
: public PoseEstimator<MecanumDriveWheelPositions, MecanumDriveWheelSpeeds,
|
||||
: public PoseEstimator<MecanumDriveWheelPositions,
|
||||
MecanumDriveWheelVelocities,
|
||||
MecanumDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace wpi::math {
|
||||
*/
|
||||
class WPILIB_DLLEXPORT MecanumDrivePoseEstimator3d
|
||||
: public PoseEstimator3d<MecanumDriveWheelPositions,
|
||||
MecanumDriveWheelSpeeds,
|
||||
MecanumDriveWheelVelocities,
|
||||
MecanumDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -39,10 +39,10 @@ namespace wpi::math {
|
||||
* never call it, then this class will behave like regular encoder odometry.
|
||||
*
|
||||
* @tparam WheelPositions Wheel positions type.
|
||||
* @tparam WheelSpeeds Wheel speeds type.
|
||||
* @tparam WheelVelocities Wheel velocities type.
|
||||
* @tparam WheelAccelerations Wheel accelerations type.
|
||||
*/
|
||||
template <typename WheelPositions, typename WheelSpeeds,
|
||||
template <typename WheelPositions, typename WheelVelocities,
|
||||
typename WheelAccelerations>
|
||||
class WPILIB_DLLEXPORT PoseEstimator {
|
||||
public:
|
||||
@@ -64,8 +64,9 @@ class WPILIB_DLLEXPORT PoseEstimator {
|
||||
* less.
|
||||
*/
|
||||
PoseEstimator(
|
||||
Kinematics<WheelPositions, WheelSpeeds, WheelAccelerations>& kinematics,
|
||||
Odometry<WheelPositions, WheelSpeeds, WheelAccelerations>& odometry,
|
||||
Kinematics<WheelPositions, WheelVelocities, WheelAccelerations>&
|
||||
kinematics,
|
||||
Odometry<WheelPositions, WheelVelocities, WheelAccelerations>& odometry,
|
||||
const wpi::util::array<double, 3>& stateStdDevs,
|
||||
const wpi::util::array<double, 3>& visionMeasurementStdDevs)
|
||||
: m_odometry(odometry) {
|
||||
@@ -478,7 +479,7 @@ class WPILIB_DLLEXPORT PoseEstimator {
|
||||
|
||||
static constexpr wpi::units::second_t kBufferDuration = 1.5_s;
|
||||
|
||||
Odometry<WheelPositions, WheelSpeeds, WheelAccelerations>& m_odometry;
|
||||
Odometry<WheelPositions, WheelVelocities, WheelAccelerations>& m_odometry;
|
||||
|
||||
// Diagonal of process noise covariance matrix Q
|
||||
wpi::util::array<double, 3> m_q{wpi::util::empty_array};
|
||||
|
||||
@@ -44,10 +44,10 @@ namespace wpi::math {
|
||||
* never call it, then this class will behave like regular encoder odometry.
|
||||
*
|
||||
* @tparam WheelPositions Wheel positions type.
|
||||
* @tparam WheelSpeeds Wheel speeds type.
|
||||
* @tparam WheelVelocities Wheel velocities type.
|
||||
* @tparam WheelAccelerations Wheel accelerations type.
|
||||
*/
|
||||
template <typename WheelPositions, typename WheelSpeeds,
|
||||
template <typename WheelPositions, typename WheelVelocities,
|
||||
typename WheelAccelerations>
|
||||
class WPILIB_DLLEXPORT PoseEstimator3d {
|
||||
public:
|
||||
@@ -69,8 +69,9 @@ class WPILIB_DLLEXPORT PoseEstimator3d {
|
||||
* vision pose measurement less.
|
||||
*/
|
||||
PoseEstimator3d(
|
||||
Kinematics<WheelPositions, WheelSpeeds, WheelAccelerations>& kinematics,
|
||||
Odometry3d<WheelPositions, WheelSpeeds, WheelAccelerations>& odometry,
|
||||
Kinematics<WheelPositions, WheelVelocities, WheelAccelerations>&
|
||||
kinematics,
|
||||
Odometry3d<WheelPositions, WheelVelocities, WheelAccelerations>& odometry,
|
||||
const wpi::util::array<double, 4>& stateStdDevs,
|
||||
const wpi::util::array<double, 4>& visionMeasurementStdDevs)
|
||||
: m_odometry(odometry) {
|
||||
@@ -492,7 +493,7 @@ class WPILIB_DLLEXPORT PoseEstimator3d {
|
||||
|
||||
static constexpr wpi::units::second_t kBufferDuration = 1.5_s;
|
||||
|
||||
Odometry3d<WheelPositions, WheelSpeeds, WheelAccelerations>& m_odometry;
|
||||
Odometry3d<WheelPositions, WheelVelocities, WheelAccelerations>& m_odometry;
|
||||
|
||||
// Diagonal of process noise covariance matrix Q
|
||||
wpi::util::array<double, 4> m_q{wpi::util::empty_array};
|
||||
|
||||
@@ -29,7 +29,7 @@ template <size_t NumModules>
|
||||
class SwerveDrivePoseEstimator
|
||||
: public PoseEstimator<
|
||||
wpi::util::array<SwerveModulePosition, NumModules>,
|
||||
wpi::util::array<SwerveModuleState, NumModules>,
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules>,
|
||||
wpi::util::array<SwerveModuleAcceleration, NumModules>> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@ template <size_t NumModules>
|
||||
class SwerveDrivePoseEstimator3d
|
||||
: public PoseEstimator3d<
|
||||
wpi::util::array<SwerveModulePosition, NumModules>,
|
||||
wpi::util::array<SwerveModuleState, NumModules>,
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules>,
|
||||
wpi::util::array<SwerveModuleAcceleration, NumModules>> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -12,10 +12,7 @@
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Represents the acceleration of a robot chassis. Although this struct contains
|
||||
* similar members compared to a ChassisSpeeds, they do NOT represent the same
|
||||
* thing. Whereas a ChassisSpeeds object represents a robot's velocity, a
|
||||
* ChassisAccelerations object represents a robot's acceleration.
|
||||
* Represents robot chassis accelerations.
|
||||
*
|
||||
* A strictly non-holonomic drivetrain, such as a differential drive, should
|
||||
* never have an ay component because it can never move sideways. Holonomic
|
||||
@@ -82,7 +79,7 @@ struct WPILIB_DLLEXPORT ChassisAccelerations {
|
||||
/**
|
||||
* Adds two ChassisAccelerations and returns the sum.
|
||||
*
|
||||
* <p>For example, ChassisAccelerations{1.0, 0.5, 1.5} +
|
||||
* For example, ChassisAccelerations{1.0, 0.5, 1.5} +
|
||||
* ChassisAccelerations{2.0, 1.5, 0.5} = ChassisAccelerations{3.0, 2.0, 2.0}
|
||||
*
|
||||
* @param other The ChassisAccelerations to add.
|
||||
@@ -98,7 +95,7 @@ struct WPILIB_DLLEXPORT ChassisAccelerations {
|
||||
* Subtracts the other ChassisAccelerations from the current
|
||||
* ChassisAccelerations and returns the difference.
|
||||
*
|
||||
* <p>For example, ChassisAccelerations{5.0, 4.0, 2.0} -
|
||||
* For example, ChassisAccelerations{5.0, 4.0, 2.0} -
|
||||
* ChassisAccelerations{1.0, 2.0, 1.0} = ChassisAccelerations{4.0, 2.0, 1.0}
|
||||
*
|
||||
* @param other The ChassisAccelerations to subtract.
|
||||
@@ -124,7 +121,7 @@ struct WPILIB_DLLEXPORT ChassisAccelerations {
|
||||
* Multiplies the ChassisAccelerations by a scalar and returns the new
|
||||
* ChassisAccelerations.
|
||||
*
|
||||
* <p>For example, ChassisAccelerations{2.0, 2.5, 1.0} * 2
|
||||
* For example, ChassisAccelerations{2.0, 2.5, 1.0} * 2
|
||||
* = ChassisAccelerations{4.0, 5.0, 2.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
@@ -139,7 +136,7 @@ struct WPILIB_DLLEXPORT ChassisAccelerations {
|
||||
* Divides the ChassisAccelerations by a scalar and returns the new
|
||||
* ChassisAccelerations.
|
||||
*
|
||||
* <p>For example, ChassisAccelerations{2.0, 2.5, 1.0} / 2
|
||||
* For example, ChassisAccelerations{2.0, 2.5, 1.0} / 2
|
||||
* = ChassisAccelerations{1.0, 1.25, 0.5}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/geometry/Pose2d.hpp"
|
||||
#include "wpi/math/geometry/Rotation2d.hpp"
|
||||
#include "wpi/units/angular_velocity.hpp"
|
||||
#include "wpi/units/velocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Represents the speed of a robot chassis. Although this struct contains
|
||||
* similar members compared to a Twist2d, they do NOT represent the same thing.
|
||||
* Whereas a Twist2d represents a change in pose w.r.t to the robot frame of
|
||||
* reference, a ChassisSpeeds struct represents a robot's velocity.
|
||||
*
|
||||
* A strictly non-holonomic drivetrain, such as a differential drive, should
|
||||
* never have a dy component because it can never move sideways. Holonomic
|
||||
* drivetrains such as swerve and mecanum will often have all three components.
|
||||
*/
|
||||
struct WPILIB_DLLEXPORT ChassisSpeeds {
|
||||
/**
|
||||
* Velocity along the x-axis. (Fwd is +)
|
||||
*/
|
||||
wpi::units::meters_per_second_t vx = 0_mps;
|
||||
|
||||
/**
|
||||
* Velocity along the y-axis. (Left is +)
|
||||
*/
|
||||
wpi::units::meters_per_second_t vy = 0_mps;
|
||||
|
||||
/**
|
||||
* Represents the angular velocity of the robot frame. (CCW is +)
|
||||
*/
|
||||
wpi::units::radians_per_second_t omega = 0_rad_per_s;
|
||||
|
||||
/**
|
||||
* Creates a Twist2d from ChassisSpeeds.
|
||||
*
|
||||
* @param dt The duration of the timestep.
|
||||
*
|
||||
* @return Twist2d.
|
||||
*/
|
||||
constexpr Twist2d ToTwist2d(wpi::units::second_t dt) const {
|
||||
return Twist2d{vx * dt, vy * dt, omega * dt};
|
||||
}
|
||||
|
||||
/**
|
||||
* Discretizes a continuous-time chassis speed.
|
||||
*
|
||||
* This function converts a continuous-time chassis speed into a discrete-time
|
||||
* one such that when the discrete-time chassis speed is applied for one
|
||||
* timestep, the robot moves as if the velocity components are independent
|
||||
* (i.e., the robot moves v_x * dt along the x-axis, v_y * dt along the
|
||||
* y-axis, and omega * dt around the z-axis).
|
||||
*
|
||||
* This is useful for compensating for translational skew when translating and
|
||||
* rotating a holonomic (swerve or mecanum) drivetrain. However, scaling down
|
||||
* the ChassisSpeeds after discretizing (e.g., when desaturating swerve module
|
||||
* speeds) rotates the direction of net motion in the opposite direction of
|
||||
* rotational velocity, introducing a different translational skew which is
|
||||
* not accounted for by discretization.
|
||||
*
|
||||
* @param dt The duration of the timestep the speeds should be applied for.
|
||||
* @return Discretized ChassisSpeeds.
|
||||
*/
|
||||
constexpr ChassisSpeeds Discretize(wpi::units::second_t dt) const {
|
||||
// Construct the desired pose after a timestep, relative to the current
|
||||
// pose. The desired pose has decoupled translation and rotation.
|
||||
Transform2d desiredTransform{vx * dt, vy * dt, omega * dt};
|
||||
|
||||
// Find the chassis translation/rotation deltas in the robot frame that move
|
||||
// the robot from its current pose to the desired pose
|
||||
auto twist = desiredTransform.Log();
|
||||
|
||||
// Turn the chassis translation/rotation deltas into average velocities
|
||||
return {twist.dx / dt, twist.dy / dt, twist.dtheta / dt};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this field-relative set of speeds into a robot-relative
|
||||
* ChassisSpeeds object.
|
||||
*
|
||||
* @param robotAngle The angle of the robot as measured by a gyroscope. The
|
||||
* robot's angle is considered to be zero when it is facing directly away
|
||||
* from your alliance station wall. Remember that this should be CCW
|
||||
* positive.
|
||||
* @return ChassisSpeeds object representing the speeds in the robot's frame
|
||||
* of reference.
|
||||
*/
|
||||
constexpr ChassisSpeeds ToRobotRelative(const Rotation2d& robotAngle) const {
|
||||
// CW rotation into chassis frame
|
||||
auto rotated = Translation2d{wpi::units::meter_t{vx.value()},
|
||||
wpi::units::meter_t{vy.value()}}
|
||||
.RotateBy(-robotAngle);
|
||||
return {wpi::units::meters_per_second_t{rotated.X().value()},
|
||||
wpi::units::meters_per_second_t{rotated.Y().value()}, omega};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this robot-relative set of speeds into a field-relative
|
||||
* ChassisSpeeds object.
|
||||
*
|
||||
* @param robotAngle The angle of the robot as measured by a gyroscope. The
|
||||
* robot's angle is considered to be zero when it is facing directly away
|
||||
* from your alliance station wall. Remember that this should be CCW
|
||||
* positive.
|
||||
* @return ChassisSpeeds object representing the speeds in the field's frame
|
||||
* of reference.
|
||||
*/
|
||||
constexpr ChassisSpeeds ToFieldRelative(const Rotation2d& robotAngle) const {
|
||||
// CCW rotation out of chassis frame
|
||||
auto rotated = Translation2d{wpi::units::meter_t{vx.value()},
|
||||
wpi::units::meter_t{vy.value()}}
|
||||
.RotateBy(robotAngle);
|
||||
return {wpi::units::meters_per_second_t{rotated.X().value()},
|
||||
wpi::units::meters_per_second_t{rotated.Y().value()}, omega};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two ChassisSpeeds and returns the sum.
|
||||
*
|
||||
* <p>For example, ChassisSpeeds{1.0, 0.5, 1.5} + ChassisSpeeds{2.0, 1.5, 0.5}
|
||||
* = ChassisSpeeds{3.0, 2.0, 2.0}
|
||||
*
|
||||
* @param other The ChassisSpeeds to add.
|
||||
*
|
||||
* @return The sum of the ChassisSpeeds.
|
||||
*/
|
||||
constexpr ChassisSpeeds operator+(const ChassisSpeeds& other) const {
|
||||
return {vx + other.vx, vy + other.vy, omega + other.omega};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the other ChassisSpeeds from the current ChassisSpeeds and
|
||||
* returns the difference.
|
||||
*
|
||||
* <p>For example, ChassisSpeeds{5.0, 4.0, 2.0} - ChassisSpeeds{1.0, 2.0, 1.0}
|
||||
* = ChassisSpeeds{4.0, 2.0, 1.0}
|
||||
*
|
||||
* @param other The ChassisSpeeds to subtract.
|
||||
*
|
||||
* @return The difference between the two ChassisSpeeds.
|
||||
*/
|
||||
constexpr ChassisSpeeds operator-(const ChassisSpeeds& other) const {
|
||||
return *this + -other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inverse of the current ChassisSpeeds.
|
||||
* This is equivalent to negating all components of the ChassisSpeeds.
|
||||
*
|
||||
* @return The inverse of the current ChassisSpeeds.
|
||||
*/
|
||||
constexpr ChassisSpeeds operator-() const { return {-vx, -vy, -omega}; }
|
||||
|
||||
/**
|
||||
* Multiplies the ChassisSpeeds by a scalar and returns the new ChassisSpeeds.
|
||||
*
|
||||
* <p>For example, ChassisSpeeds{2.0, 2.5, 1.0} * 2
|
||||
* = ChassisSpeeds{4.0, 5.0, 1.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
*
|
||||
* @return The scaled ChassisSpeeds.
|
||||
*/
|
||||
constexpr ChassisSpeeds operator*(double scalar) const {
|
||||
return {scalar * vx, scalar * vy, scalar * omega};
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the ChassisSpeeds by a scalar and returns the new ChassisSpeeds.
|
||||
*
|
||||
* <p>For example, ChassisSpeeds{2.0, 2.5, 1.0} / 2
|
||||
* = ChassisSpeeds{1.0, 1.25, 0.5}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
*
|
||||
* @return The scaled ChassisSpeeds.
|
||||
*/
|
||||
constexpr ChassisSpeeds operator/(double scalar) const {
|
||||
return operator*(1.0 / scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the ChassisSpeeds with another ChassisSpeed.
|
||||
*
|
||||
* @param other The other ChassisSpeeds.
|
||||
*
|
||||
* @return The result of the comparison. Is true if they are the same.
|
||||
*/
|
||||
constexpr bool operator==(const ChassisSpeeds& other) const = default;
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
#include "wpi/math/kinematics/proto/ChassisSpeedsProto.hpp"
|
||||
#include "wpi/math/kinematics/struct/ChassisSpeedsStruct.hpp"
|
||||
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/geometry/Pose2d.hpp"
|
||||
#include "wpi/math/geometry/Rotation2d.hpp"
|
||||
#include "wpi/units/angular_velocity.hpp"
|
||||
#include "wpi/units/velocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Represents robot chassis velocities.
|
||||
*
|
||||
* Although this struct contains similar members compared to a Twist2d, they do
|
||||
* NOT represent the same thing. Whereas a Twist2d represents a change in pose
|
||||
* w.r.t to the robot frame of reference, a ChassisVelocities struct represents
|
||||
* a robot's velocities.
|
||||
*
|
||||
* A strictly non-holonomic drivetrain, such as a differential drive, should
|
||||
* never have a dy component because it can never move sideways. Holonomic
|
||||
* drivetrains such as swerve and mecanum will often have all three components.
|
||||
*/
|
||||
struct WPILIB_DLLEXPORT ChassisVelocities {
|
||||
/**
|
||||
* Velocity along the x-axis. (Fwd is +)
|
||||
*/
|
||||
wpi::units::meters_per_second_t vx = 0_mps;
|
||||
|
||||
/**
|
||||
* Velocity along the y-axis. (Left is +)
|
||||
*/
|
||||
wpi::units::meters_per_second_t vy = 0_mps;
|
||||
|
||||
/**
|
||||
* Represents the angular velocity of the robot frame. (CCW is +)
|
||||
*/
|
||||
wpi::units::radians_per_second_t omega = 0_rad_per_s;
|
||||
|
||||
/**
|
||||
* Creates a Twist2d from ChassisVelocities.
|
||||
*
|
||||
* @param dt The duration of the timestep.
|
||||
*
|
||||
* @return Twist2d.
|
||||
*/
|
||||
constexpr Twist2d ToTwist2d(wpi::units::second_t dt) const {
|
||||
return Twist2d{vx * dt, vy * dt, omega * dt};
|
||||
}
|
||||
|
||||
/**
|
||||
* Discretizes continuous-time chassis velocities.
|
||||
*
|
||||
* This function converts continuous-time chassis velocities into
|
||||
* discrete-time ones such that when the discrete-time chassis velocities are
|
||||
* applied for one timestep, the robot moves as if the velocity components are
|
||||
* independent (i.e., the robot moves v_x * dt along the x-axis, v_y * dt
|
||||
* along the y-axis, and omega * dt around the z-axis).
|
||||
*
|
||||
* This is useful for compensating for translational skew when translating and
|
||||
* rotating a holonomic (swerve or mecanum) drivetrain. However, scaling down
|
||||
* the ChassisVelocities after discretizing (e.g., when desaturating swerve
|
||||
* module velocities) rotates the direction of net motion in the opposite
|
||||
* direction of rotational velocity, introducing a different translational
|
||||
* skew which is not accounted for by discretization.
|
||||
*
|
||||
* @param dt The duration of the timestep the velocities should be applied
|
||||
* for.
|
||||
* @return Discretized ChassisVelocities.
|
||||
*/
|
||||
constexpr ChassisVelocities Discretize(wpi::units::second_t dt) const {
|
||||
// Construct the desired pose after a timestep, relative to the current
|
||||
// pose. The desired pose has decoupled translation and rotation.
|
||||
Transform2d desiredTransform{vx * dt, vy * dt, omega * dt};
|
||||
|
||||
// Find the chassis translation/rotation deltas in the robot frame that move
|
||||
// the robot from its current pose to the desired pose
|
||||
auto twist = desiredTransform.Log();
|
||||
|
||||
// Turn the chassis translation/rotation deltas into average velocities
|
||||
return {twist.dx / dt, twist.dy / dt, twist.dtheta / dt};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this field-relative set of velocities into a robot-relative
|
||||
* ChassisVelocities object.
|
||||
*
|
||||
* @param robotAngle The angle of the robot as measured by a gyroscope. The
|
||||
* robot's angle is considered to be zero when it is facing directly away
|
||||
* from your alliance station wall. Remember that this should be CCW
|
||||
* positive.
|
||||
* @return ChassisVelocities object representing the velocities in the robot's
|
||||
* frame of reference.
|
||||
*/
|
||||
constexpr ChassisVelocities ToRobotRelative(
|
||||
const Rotation2d& robotAngle) const {
|
||||
// CW rotation into chassis frame
|
||||
auto rotated = Translation2d{wpi::units::meter_t{vx.value()},
|
||||
wpi::units::meter_t{vy.value()}}
|
||||
.RotateBy(-robotAngle);
|
||||
return {wpi::units::meters_per_second_t{rotated.X().value()},
|
||||
wpi::units::meters_per_second_t{rotated.Y().value()}, omega};
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this robot-relative set of velocities into a field-relative
|
||||
* ChassisVelocities object.
|
||||
*
|
||||
* @param robotAngle The angle of the robot as measured by a gyroscope. The
|
||||
* robot's angle is considered to be zero when it is facing directly away
|
||||
* from your alliance station wall. Remember that this should be CCW
|
||||
* positive.
|
||||
* @return ChassisVelocities object representing the velocities in the field's
|
||||
* frame of reference.
|
||||
*/
|
||||
constexpr ChassisVelocities ToFieldRelative(
|
||||
const Rotation2d& robotAngle) const {
|
||||
// CCW rotation out of chassis frame
|
||||
auto rotated = Translation2d{wpi::units::meter_t{vx.value()},
|
||||
wpi::units::meter_t{vy.value()}}
|
||||
.RotateBy(robotAngle);
|
||||
return {wpi::units::meters_per_second_t{rotated.X().value()},
|
||||
wpi::units::meters_per_second_t{rotated.Y().value()}, omega};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two ChassisVelocities and returns the sum.
|
||||
*
|
||||
* For example, ChassisVelocities{1.0, 0.5, 1.5} +
|
||||
* ChassisVelocities{2.0, 1.5, 0.5} = ChassisVelocities{3.0, 2.0, 2.0}
|
||||
*
|
||||
* @param other The ChassisVelocities to add.
|
||||
*
|
||||
* @return The sum of the ChassisVelocities.
|
||||
*/
|
||||
constexpr ChassisVelocities operator+(const ChassisVelocities& other) const {
|
||||
return {vx + other.vx, vy + other.vy, omega + other.omega};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the other ChassisVelocities from the current ChassisVelocities
|
||||
* and returns the difference.
|
||||
*
|
||||
* For example, ChassisVelocities{5.0, 4.0, 2.0} -
|
||||
* ChassisVelocities{1.0, 2.0, 1.0} = ChassisVelocities{4.0, 2.0, 1.0}
|
||||
*
|
||||
* @param other The ChassisVelocities to subtract.
|
||||
*
|
||||
* @return The difference between the two ChassisVelocities.
|
||||
*/
|
||||
constexpr ChassisVelocities operator-(const ChassisVelocities& other) const {
|
||||
return *this + -other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inverse of the current ChassisVelocities.
|
||||
* This is equivalent to negating all components of the ChassisVelocities.
|
||||
*
|
||||
* @return The inverse of the current ChassisVelocities.
|
||||
*/
|
||||
constexpr ChassisVelocities operator-() const { return {-vx, -vy, -omega}; }
|
||||
|
||||
/**
|
||||
* Multiplies the ChassisVelocities by a scalar and returns the new
|
||||
* ChassisVelocities.
|
||||
*
|
||||
* For example, ChassisVelocities{2.0, 2.5, 1.0} * 2
|
||||
* = ChassisVelocities{4.0, 5.0, 1.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
*
|
||||
* @return The scaled ChassisVelocities.
|
||||
*/
|
||||
constexpr ChassisVelocities operator*(double scalar) const {
|
||||
return {scalar * vx, scalar * vy, scalar * omega};
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the ChassisVelocities by a scalar and returns the new
|
||||
* ChassisVelocities.
|
||||
*
|
||||
* For example, ChassisVelocities{2.0, 2.5, 1.0} / 2
|
||||
* = ChassisVelocities{1.0, 1.25, 0.5}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
*
|
||||
* @return The scaled ChassisVelocities.
|
||||
*/
|
||||
constexpr ChassisVelocities operator/(double scalar) const {
|
||||
return operator*(1.0 / scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the ChassisVelocities with another ChassisVelocity.
|
||||
*
|
||||
* @param other The other ChassisVelocities.
|
||||
*
|
||||
* @return The result of the comparison. Is true if they are the same.
|
||||
*/
|
||||
constexpr bool operator==(const ChassisVelocities& other) const = default;
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
#include "wpi/math/kinematics/proto/ChassisVelocitiesProto.hpp"
|
||||
#include "wpi/math/kinematics/struct/ChassisVelocitiesStruct.hpp"
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
#include "wpi/math/geometry/Twist2d.hpp"
|
||||
#include "wpi/math/kinematics/ChassisAccelerations.hpp"
|
||||
#include "wpi/math/kinematics/ChassisSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/ChassisVelocities.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelAccelerations.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelPositions.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelVelocities.hpp"
|
||||
#include "wpi/math/kinematics/Kinematics.hpp"
|
||||
#include "wpi/math/util/MathShared.hpp"
|
||||
#include "wpi/units/angle.hpp"
|
||||
@@ -23,22 +23,22 @@ namespace wpi::math {
|
||||
* Helper class that converts a chassis velocity (dx and dtheta components) to
|
||||
* left and right wheel velocities for a differential drive.
|
||||
*
|
||||
* Inverse kinematics converts a desired chassis speed into left and right
|
||||
* Inverse kinematics converts a desired chassis velocity into left and right
|
||||
* velocity components whereas forward kinematics converts left and right
|
||||
* component velocities into a linear and angular chassis speed.
|
||||
* component velocities into a linear and angular chassis velocity.
|
||||
*/
|
||||
class WPILIB_DLLEXPORT DifferentialDriveKinematics
|
||||
: public Kinematics<DifferentialDriveWheelPositions,
|
||||
DifferentialDriveWheelSpeeds,
|
||||
DifferentialDriveWheelVelocities,
|
||||
DifferentialDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
* Constructs a differential drive kinematics object.
|
||||
*
|
||||
* @param trackwidth The trackwidth of the drivetrain. Theoretically, this is
|
||||
* the distance between the left wheels and right wheels. However, the
|
||||
* empirical value may be larger than the physical measured value due to
|
||||
* scrubbing effects.
|
||||
* the distance between the left wheels and right wheels. However, the
|
||||
* empirical value may be larger than the physical measured value due to
|
||||
* scrubbing effects.
|
||||
*/
|
||||
constexpr explicit DifferentialDriveKinematics(wpi::units::meter_t trackwidth)
|
||||
: trackwidth(trackwidth) {
|
||||
@@ -49,30 +49,33 @@ class WPILIB_DLLEXPORT DifferentialDriveKinematics
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a chassis speed from left and right component velocities using
|
||||
* Returns a chassis velocity from left and right component velocities using
|
||||
* forward kinematics.
|
||||
*
|
||||
* @param wheelSpeeds The left and right velocities.
|
||||
* @return The chassis speed.
|
||||
* @param wheelVelocities The left and right velocities.
|
||||
* @return The chassis velocity.
|
||||
*/
|
||||
constexpr ChassisSpeeds ToChassisSpeeds(
|
||||
const DifferentialDriveWheelSpeeds& wheelSpeeds) const override {
|
||||
return {(wheelSpeeds.left + wheelSpeeds.right) / 2.0, 0_mps,
|
||||
(wheelSpeeds.right - wheelSpeeds.left) / trackwidth * 1_rad};
|
||||
constexpr ChassisVelocities ToChassisVelocities(
|
||||
const DifferentialDriveWheelVelocities& wheelVelocities) const override {
|
||||
return {
|
||||
(wheelVelocities.left + wheelVelocities.right) / 2.0, 0_mps,
|
||||
(wheelVelocities.right - wheelVelocities.left) / trackwidth * 1_rad};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns left and right component velocities from a chassis speed using
|
||||
* Returns left and right component velocities from a chassis velocity using
|
||||
* inverse kinematics.
|
||||
*
|
||||
* @param chassisSpeeds The linear and angular (dx and dtheta) components that
|
||||
* represent the chassis' speed.
|
||||
* @param chassisVelocities The linear and angular (dx and dtheta) components
|
||||
* that represent the chassis' velocity.
|
||||
* @return The left and right velocities.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelSpeeds ToWheelSpeeds(
|
||||
const ChassisSpeeds& chassisSpeeds) const override {
|
||||
return {chassisSpeeds.vx - trackwidth / 2 * chassisSpeeds.omega / 1_rad,
|
||||
chassisSpeeds.vx + trackwidth / 2 * chassisSpeeds.omega / 1_rad};
|
||||
constexpr DifferentialDriveWheelVelocities ToWheelVelocities(
|
||||
const ChassisVelocities& chassisVelocities) const override {
|
||||
return {
|
||||
chassisVelocities.vx - trackwidth / 2 * chassisVelocities.omega / 1_rad,
|
||||
chassisVelocities.vx +
|
||||
trackwidth / 2 * chassisVelocities.omega / 1_rad};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "wpi/math/geometry/Pose2d.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveKinematics.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelPositions.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelVelocities.hpp"
|
||||
#include "wpi/math/kinematics/Odometry.hpp"
|
||||
#include "wpi/units/length.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
@@ -27,7 +27,7 @@ namespace wpi::math {
|
||||
*/
|
||||
class WPILIB_DLLEXPORT DifferentialDriveOdometry
|
||||
: public Odometry<DifferentialDriveWheelPositions,
|
||||
DifferentialDriveWheelSpeeds,
|
||||
DifferentialDriveWheelVelocities,
|
||||
DifferentialDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "wpi/math/geometry/Pose3d.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveKinematics.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelPositions.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelVelocities.hpp"
|
||||
#include "wpi/math/kinematics/Odometry3d.hpp"
|
||||
#include "wpi/units/length.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
@@ -27,7 +27,7 @@ namespace wpi::math {
|
||||
*/
|
||||
class WPILIB_DLLEXPORT DifferentialDriveOdometry3d
|
||||
: public Odometry3d<DifferentialDriveWheelPositions,
|
||||
DifferentialDriveWheelSpeeds,
|
||||
DifferentialDriveWheelVelocities,
|
||||
DifferentialDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,7 @@ struct WPILIB_DLLEXPORT DifferentialDriveWheelAccelerations {
|
||||
/**
|
||||
* Adds two DifferentialDriveWheelAccelerations and returns the sum.
|
||||
*
|
||||
* <p>For example, DifferentialDriveWheelAccelerations{1.0, 0.5} +
|
||||
* For example, DifferentialDriveWheelAccelerations{1.0, 0.5} +
|
||||
* DifferentialDriveWheelAccelerations{2.0, 1.5} =
|
||||
* DifferentialDriveWheelAccelerations{3.0, 2.0}
|
||||
*
|
||||
@@ -42,7 +42,7 @@ struct WPILIB_DLLEXPORT DifferentialDriveWheelAccelerations {
|
||||
* Subtracts the other DifferentialDriveWheelAccelerations from the current
|
||||
* DifferentialDriveWheelAccelerations and returns the difference.
|
||||
*
|
||||
* <p>For example, DifferentialDriveWheelAccelerations{5.0, 4.0} -
|
||||
* For example, DifferentialDriveWheelAccelerations{5.0, 4.0} -
|
||||
* DifferentialDriveWheelAccelerations{1.0, 2.0} =
|
||||
* DifferentialDriveWheelAccelerations{4.0, 2.0}
|
||||
*
|
||||
@@ -70,7 +70,7 @@ struct WPILIB_DLLEXPORT DifferentialDriveWheelAccelerations {
|
||||
* Multiplies the DifferentialDriveWheelAccelerations by a scalar and returns
|
||||
* the new DifferentialDriveWheelAccelerations.
|
||||
*
|
||||
* <p>For example, DifferentialDriveWheelAccelerations{2.0, 2.5} * 2
|
||||
* For example, DifferentialDriveWheelAccelerations{2.0, 2.5} * 2
|
||||
* = DifferentialDriveWheelAccelerations{4.0, 5.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
@@ -85,7 +85,7 @@ struct WPILIB_DLLEXPORT DifferentialDriveWheelAccelerations {
|
||||
* Divides the DifferentialDriveWheelAccelerations by a scalar and returns the
|
||||
* new DifferentialDriveWheelAccelerations.
|
||||
*
|
||||
* <p>For example, DifferentialDriveWheelAccelerations{2.0, 2.5} / 2
|
||||
* For example, DifferentialDriveWheelAccelerations{2.0, 2.5} / 2
|
||||
* = DifferentialDriveWheelAccelerations{1.0, 1.25}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/units/math.hpp"
|
||||
#include "wpi/units/velocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Represents the wheel speeds for a differential drive drivetrain.
|
||||
*/
|
||||
struct WPILIB_DLLEXPORT DifferentialDriveWheelSpeeds {
|
||||
/**
|
||||
* Speed of the left side of the robot.
|
||||
*/
|
||||
wpi::units::meters_per_second_t left = 0_mps;
|
||||
|
||||
/**
|
||||
* Speed of the right side of the robot.
|
||||
*/
|
||||
wpi::units::meters_per_second_t right = 0_mps;
|
||||
|
||||
/**
|
||||
* Renormalizes the wheel speeds if either side is above the specified
|
||||
* maximum.
|
||||
*
|
||||
* Sometimes, after inverse kinematics, the requested speed from one or more
|
||||
* wheels may be above the max attainable speed for the driving motor on that
|
||||
* wheel. To fix this issue, one can reduce all the wheel speeds to make sure
|
||||
* that all requested module speeds are at-or-below the absolute threshold,
|
||||
* while maintaining the ratio of speeds between wheels.
|
||||
*
|
||||
* @param attainableMaxSpeed The absolute max speed that a wheel can reach.
|
||||
*/
|
||||
constexpr void Desaturate(
|
||||
wpi::units::meters_per_second_t attainableMaxSpeed) {
|
||||
auto realMaxSpeed = wpi::units::math::max(wpi::units::math::abs(left),
|
||||
wpi::units::math::abs(right));
|
||||
|
||||
if (realMaxSpeed > attainableMaxSpeed) {
|
||||
left = left / realMaxSpeed * attainableMaxSpeed;
|
||||
right = right / realMaxSpeed * attainableMaxSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two DifferentialDriveWheelSpeeds and returns the sum.
|
||||
*
|
||||
* <p>For example, DifferentialDriveWheelSpeeds{1.0, 0.5} +
|
||||
* DifferentialDriveWheelSpeeds{2.0, 1.5} =
|
||||
* DifferentialDriveWheelSpeeds{3.0, 2.0}
|
||||
*
|
||||
* @param other The DifferentialDriveWheelSpeeds to add.
|
||||
*
|
||||
* @return The sum of the DifferentialDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelSpeeds operator+(
|
||||
const DifferentialDriveWheelSpeeds& other) const {
|
||||
return {left + other.left, right + other.right};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the other DifferentialDriveWheelSpeeds from the current
|
||||
* DifferentialDriveWheelSpeeds and returns the difference.
|
||||
*
|
||||
* <p>For example, DifferentialDriveWheelSpeeds{5.0, 4.0} -
|
||||
* DifferentialDriveWheelSpeeds{1.0, 2.0} =
|
||||
* DifferentialDriveWheelSpeeds{4.0, 2.0}
|
||||
*
|
||||
* @param other The DifferentialDriveWheelSpeeds to subtract.
|
||||
*
|
||||
* @return The difference between the two DifferentialDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelSpeeds operator-(
|
||||
const DifferentialDriveWheelSpeeds& other) const {
|
||||
return *this + -other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inverse of the current DifferentialDriveWheelSpeeds.
|
||||
* This is equivalent to negating all components of the
|
||||
* DifferentialDriveWheelSpeeds.
|
||||
*
|
||||
* @return The inverse of the current DifferentialDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelSpeeds operator-() const {
|
||||
return {-left, -right};
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the DifferentialDriveWheelSpeeds by a scalar and returns the new
|
||||
* DifferentialDriveWheelSpeeds.
|
||||
*
|
||||
* <p>For example, DifferentialDriveWheelSpeeds{2.0, 2.5} * 2
|
||||
* = DifferentialDriveWheelSpeeds{4.0, 5.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
*
|
||||
* @return The scaled DifferentialDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelSpeeds operator*(double scalar) const {
|
||||
return {scalar * left, scalar * right};
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the DifferentialDriveWheelSpeeds by a scalar and returns the new
|
||||
* DifferentialDriveWheelSpeeds.
|
||||
*
|
||||
* <p>For example, DifferentialDriveWheelSpeeds{2.0, 2.5} / 2
|
||||
* = DifferentialDriveWheelSpeeds{1.0, 1.25}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
*
|
||||
* @return The scaled DifferentialDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelSpeeds operator/(double scalar) const {
|
||||
return operator*(1.0 / scalar);
|
||||
}
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
#include "wpi/math/kinematics/proto/DifferentialDriveWheelSpeedsProto.hpp"
|
||||
#include "wpi/math/kinematics/struct/DifferentialDriveWheelSpeedsStruct.hpp"
|
||||
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/units/math.hpp"
|
||||
#include "wpi/units/velocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Represents the wheel velocities for a differential drive drivetrain.
|
||||
*/
|
||||
struct WPILIB_DLLEXPORT DifferentialDriveWheelVelocities {
|
||||
/**
|
||||
* Velocity of the left side of the robot.
|
||||
*/
|
||||
wpi::units::meters_per_second_t left = 0_mps;
|
||||
|
||||
/**
|
||||
* Velocity of the right side of the robot.
|
||||
*/
|
||||
wpi::units::meters_per_second_t right = 0_mps;
|
||||
|
||||
/**
|
||||
* Renormalizes the wheel velocities if either side is above the specified
|
||||
* maximum.
|
||||
*
|
||||
* Sometimes, after inverse kinematics, the requested velocity from one or
|
||||
* more wheels may be above the max attainable velocity for the driving motor
|
||||
* on that wheel. To fix this issue, one can reduce all the wheel velocities
|
||||
* to make sure that all requested module velocities are at-or-below the
|
||||
* absolute threshold, while maintaining the ratio of velocities between
|
||||
* wheels.
|
||||
*
|
||||
* @param attainableMaxVelocity The absolute max velocity that a wheel can
|
||||
* reach.
|
||||
*/
|
||||
constexpr void Desaturate(
|
||||
wpi::units::meters_per_second_t attainableMaxVelocity) {
|
||||
auto realMaxVelocity = wpi::units::math::max(wpi::units::math::abs(left),
|
||||
wpi::units::math::abs(right));
|
||||
|
||||
if (realMaxVelocity > attainableMaxVelocity) {
|
||||
left = left / realMaxVelocity * attainableMaxVelocity;
|
||||
right = right / realMaxVelocity * attainableMaxVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two DifferentialDriveWheelVelocities and returns the sum.
|
||||
*
|
||||
* For example, DifferentialDriveWheelVelocities{1.0, 0.5} +
|
||||
* DifferentialDriveWheelVelocities{2.0, 1.5} =
|
||||
* DifferentialDriveWheelVelocities{3.0, 2.0}
|
||||
*
|
||||
* @param other The DifferentialDriveWheelVelocities to add.
|
||||
* @return The sum of the DifferentialDriveWheelVelocities.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelVelocities operator+(
|
||||
const DifferentialDriveWheelVelocities& other) const {
|
||||
return {left + other.left, right + other.right};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the other DifferentialDriveWheelVelocities from the current
|
||||
* DifferentialDriveWheelVelocities and returns the difference.
|
||||
*
|
||||
* For example, DifferentialDriveWheelVelocities{5.0, 4.0} -
|
||||
* DifferentialDriveWheelVelocities{1.0, 2.0} =
|
||||
* DifferentialDriveWheelVelocities{4.0, 2.0}
|
||||
*
|
||||
* @param other The DifferentialDriveWheelVelocities to subtract.
|
||||
* @return The difference between the two DifferentialDriveWheelVelocities.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelVelocities operator-(
|
||||
const DifferentialDriveWheelVelocities& other) const {
|
||||
return *this + -other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inverse of the current DifferentialDriveWheelVelocities.
|
||||
* This is equivalent to negating all components of the
|
||||
* DifferentialDriveWheelVelocities.
|
||||
*
|
||||
* @return The inverse of the current DifferentialDriveWheelVelocities.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelVelocities operator-() const {
|
||||
return {-left, -right};
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the DifferentialDriveWheelVelocities by a scalar and returns the
|
||||
* new DifferentialDriveWheelVelocities.
|
||||
*
|
||||
* For example, DifferentialDriveWheelVelocities{2.0, 2.5} * 2
|
||||
* = DifferentialDriveWheelVelocities{4.0, 5.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
* @return The scaled DifferentialDriveWheelVelocities.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelVelocities operator*(double scalar) const {
|
||||
return {scalar * left, scalar * right};
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the DifferentialDriveWheelVelocities by a scalar and returns the
|
||||
* new DifferentialDriveWheelVelocities.
|
||||
*
|
||||
* For example, DifferentialDriveWheelVelocities{2.0, 2.5} / 2
|
||||
* = DifferentialDriveWheelVelocities{1.0, 1.25}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
* @return The scaled DifferentialDriveWheelVelocities.
|
||||
*/
|
||||
constexpr DifferentialDriveWheelVelocities operator/(double scalar) const {
|
||||
return operator*(1.0 / scalar);
|
||||
}
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
#include "wpi/math/kinematics/proto/DifferentialDriveWheelVelocitiesProto.hpp"
|
||||
#include "wpi/math/kinematics/struct/DifferentialDriveWheelVelocitiesStruct.hpp"
|
||||
@@ -6,20 +6,20 @@
|
||||
|
||||
#include "wpi/math/geometry/Twist2d.hpp"
|
||||
#include "wpi/math/kinematics/ChassisAccelerations.hpp"
|
||||
#include "wpi/math/kinematics/ChassisSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/ChassisVelocities.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Helper class that converts a chassis velocity (dx, dy, and dtheta components)
|
||||
* into individual wheel speeds. Robot code should not use this directly-
|
||||
* into individual wheel velocities. Robot code should not use this directly-
|
||||
* Instead, use the particular type for your drivetrain (e.g.,
|
||||
* DifferentialDriveKinematics).
|
||||
*
|
||||
* Inverse kinematics converts a desired chassis speed into wheel speeds whereas
|
||||
* forward kinematics converts wheel speeds into chassis speed.
|
||||
* Inverse kinematics converts a desired chassis velocity into wheel velocities
|
||||
* whereas forward kinematics converts wheel velocities into chassis velocity.
|
||||
*/
|
||||
template <typename WheelPositions, typename WheelSpeeds,
|
||||
template <typename WheelPositions, typename WheelVelocities,
|
||||
typename WheelAccelerations>
|
||||
requires std::copy_constructible<WheelPositions> &&
|
||||
std::assignable_from<WheelPositions&, const WheelPositions&>
|
||||
@@ -28,27 +28,27 @@ class WPILIB_DLLEXPORT Kinematics {
|
||||
virtual ~Kinematics() noexcept = default;
|
||||
|
||||
/**
|
||||
* Performs forward kinematics to return the resulting chassis speed from the
|
||||
* wheel speeds. This method is often used for odometry -- determining the
|
||||
* robot's position on the field using data from the real-world speed of each
|
||||
* wheel on the robot.
|
||||
* Performs forward kinematics to return the resulting chassis velocity from
|
||||
* the wheel velocities. This method is often used for odometry -- determining
|
||||
* the robot's position on the field using data from the real-world velocity
|
||||
* of each wheel on the robot.
|
||||
*
|
||||
* @param wheelSpeeds The speeds of the wheels.
|
||||
* @return The chassis speed.
|
||||
* @param wheelVelocities The velocities of the wheels.
|
||||
* @return The chassis velocity.
|
||||
*/
|
||||
virtual ChassisSpeeds ToChassisSpeeds(
|
||||
const WheelSpeeds& wheelSpeeds) const = 0;
|
||||
virtual ChassisVelocities ToChassisVelocities(
|
||||
const WheelVelocities& wheelVelocities) const = 0;
|
||||
|
||||
/**
|
||||
* Performs inverse kinematics to return the wheel speeds from a desired
|
||||
* Performs inverse kinematics to return the wheel velocities from a desired
|
||||
* chassis velocity. This method is often used to convert joystick values into
|
||||
* wheel speeds.
|
||||
* wheel velocities.
|
||||
*
|
||||
* @param chassisSpeeds The desired chassis speed.
|
||||
* @return The wheel speeds.
|
||||
* @param chassisVelocities The desired chassis velocity.
|
||||
* @return The wheel velocities.
|
||||
*/
|
||||
virtual WheelSpeeds ToWheelSpeeds(
|
||||
const ChassisSpeeds& chassisSpeeds) const = 0;
|
||||
virtual WheelVelocities ToWheelVelocities(
|
||||
const ChassisVelocities& chassisVelocities) const = 0;
|
||||
|
||||
/**
|
||||
* Performs forward kinematics to return the resulting Twist2d from the given
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
#include "wpi/math/geometry/Translation2d.hpp"
|
||||
#include "wpi/math/geometry/Twist2d.hpp"
|
||||
#include "wpi/math/kinematics/ChassisAccelerations.hpp"
|
||||
#include "wpi/math/kinematics/ChassisSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/ChassisVelocities.hpp"
|
||||
#include "wpi/math/kinematics/Kinematics.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelAccelerations.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelPositions.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelVelocities.hpp"
|
||||
#include "wpi/math/linalg/EigenCore.hpp"
|
||||
#include "wpi/math/util/MathShared.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
@@ -22,41 +22,42 @@ namespace wpi::math {
|
||||
|
||||
/**
|
||||
* Helper class that converts a chassis velocity (dx, dy, and dtheta components)
|
||||
* into individual wheel speeds.
|
||||
* into individual wheel velocities.
|
||||
*
|
||||
* The inverse kinematics (converting from a desired chassis velocity to
|
||||
* individual wheel speeds) uses the relative locations of the wheels with
|
||||
* individual wheel velocities) uses the relative locations of the wheels with
|
||||
* respect to the center of rotation. The center of rotation for inverse
|
||||
* kinematics is also variable. This means that you can set your set your center
|
||||
* of rotation in a corner of the robot to perform special evasion maneuvers.
|
||||
*
|
||||
* Forward kinematics (converting an array of wheel speeds into the overall
|
||||
* Forward kinematics (converting an array of wheel velocities into the overall
|
||||
* chassis motion) is performs the exact opposite of what inverse kinematics
|
||||
* does. Since this is an overdetermined system (more equations than variables),
|
||||
* we use a least-squares approximation.
|
||||
*
|
||||
* The inverse kinematics: [wheelSpeeds] = [wheelLocations] * [chassisSpeeds]
|
||||
* We take the Moore-Penrose pseudoinverse of [wheelLocations] and then
|
||||
* multiply by [wheelSpeeds] to get our chassis speeds.
|
||||
* The inverse kinematics: [wheelVelocities] = [wheelLocations] *
|
||||
* [chassisVelocities] We take the Moore-Penrose pseudoinverse of
|
||||
* [wheelLocations] and then multiply by [wheelVelocities] to get our chassis
|
||||
* velocities.
|
||||
*
|
||||
* Forward kinematics is also used for odometry -- determining the position of
|
||||
* the robot on the field using encoders and a gyro.
|
||||
*/
|
||||
class WPILIB_DLLEXPORT MecanumDriveKinematics
|
||||
: public Kinematics<MecanumDriveWheelPositions, MecanumDriveWheelSpeeds,
|
||||
: public Kinematics<MecanumDriveWheelPositions, MecanumDriveWheelVelocities,
|
||||
MecanumDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
* Constructs a mecanum drive kinematics object.
|
||||
*
|
||||
* @param frontLeftWheel The location of the front-left wheel relative to the
|
||||
* physical center of the robot.
|
||||
* physical center of the robot.
|
||||
* @param frontRightWheel The location of the front-right wheel relative to
|
||||
* the physical center of the robot.
|
||||
* the physical center of the robot.
|
||||
* @param rearLeftWheel The location of the rear-left wheel relative to the
|
||||
* physical center of the robot.
|
||||
* physical center of the robot.
|
||||
* @param rearRightWheel The location of the rear-right wheel relative to the
|
||||
* physical center of the robot.
|
||||
* physical center of the robot.
|
||||
*/
|
||||
explicit MecanumDriveKinematics(Translation2d frontLeftWheel,
|
||||
Translation2d frontRightWheel,
|
||||
@@ -75,9 +76,9 @@ class WPILIB_DLLEXPORT MecanumDriveKinematics
|
||||
MecanumDriveKinematics(const MecanumDriveKinematics&) = default;
|
||||
|
||||
/**
|
||||
* Performs inverse kinematics to return the wheel speeds from a desired
|
||||
* Performs inverse kinematics to return the wheel velocities from a desired
|
||||
* chassis velocity. This method is often used to convert joystick values into
|
||||
* wheel speeds.
|
||||
* wheel velocities.
|
||||
*
|
||||
* This function also supports variable centers of rotation. During normal
|
||||
* operations, the center of rotation is usually the same as the physical
|
||||
@@ -85,45 +86,44 @@ class WPILIB_DLLEXPORT MecanumDriveKinematics
|
||||
* However, if you wish to change the center of rotation for evasive
|
||||
* maneuvers, vision alignment, or for any other use case, you can do so.
|
||||
*
|
||||
* @param chassisSpeeds The desired chassis speed.
|
||||
* @param chassisVelocities The desired chassis velocity.
|
||||
* @param centerOfRotation The center of rotation. For example, if you set the
|
||||
* center of rotation at one corner of the robot and
|
||||
* provide a chassis speed that only has a dtheta
|
||||
* component, the robot will rotate around that
|
||||
* corner.
|
||||
* center of rotation at one corner of the robot and provide a chassis
|
||||
* velocity that only has a dtheta component, the robot will rotate around
|
||||
* that corner.
|
||||
*
|
||||
* @return The wheel speeds. Use caution because they are not normalized.
|
||||
* Sometimes, a user input may cause one of the wheel speeds to go
|
||||
* above the attainable max velocity. Use the
|
||||
* MecanumDriveWheelSpeeds::Normalize() function to rectify this
|
||||
* issue. In addition, you can leverage the power of C++17 to directly
|
||||
* assign the wheel speeds to variables:
|
||||
* @return The wheel velocities. Use caution because they are not normalized.
|
||||
* Sometimes, a user input may cause one of the wheel velocities to go
|
||||
* above the attainable max velocity. Use the
|
||||
* MecanumDriveWheelVelocities::Normalize() function to rectify this
|
||||
* issue. In addition, you can leverage the power of C++17 to directly
|
||||
* assign the wheel velocities to variables:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto [fl, fr, bl, br] = kinematics.ToWheelSpeeds(chassisSpeeds);
|
||||
* auto [fl, fr, bl, br] = kinematics.ToWheelVelocities(chassisVelocities);
|
||||
* @endcode
|
||||
*/
|
||||
MecanumDriveWheelSpeeds ToWheelSpeeds(
|
||||
const ChassisSpeeds& chassisSpeeds,
|
||||
MecanumDriveWheelVelocities ToWheelVelocities(
|
||||
const ChassisVelocities& chassisVelocities,
|
||||
const Translation2d& centerOfRotation) const;
|
||||
|
||||
MecanumDriveWheelSpeeds ToWheelSpeeds(
|
||||
const ChassisSpeeds& chassisSpeeds) const override {
|
||||
return ToWheelSpeeds(chassisSpeeds, {});
|
||||
MecanumDriveWheelVelocities ToWheelVelocities(
|
||||
const ChassisVelocities& chassisVelocities) const override {
|
||||
return ToWheelVelocities(chassisVelocities, {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs forward kinematics to return the resulting chassis state from the
|
||||
* given wheel speeds. This method is often used for odometry -- determining
|
||||
* the robot's position on the field using data from the real-world speed of
|
||||
* each wheel on the robot.
|
||||
* given wheel velocities. This method is often used for odometry --
|
||||
* determining the robot's position on the field using data from the
|
||||
* real-world velocity of each wheel on the robot.
|
||||
*
|
||||
* @param wheelSpeeds The current mecanum drive wheel speeds.
|
||||
* @param wheelVelocities The current mecanum drive wheel velocities.
|
||||
*
|
||||
* @return The resulting chassis speed.
|
||||
* @return The resulting chassis velocity.
|
||||
*/
|
||||
ChassisSpeeds ToChassisSpeeds(
|
||||
const MecanumDriveWheelSpeeds& wheelSpeeds) const override;
|
||||
ChassisVelocities ToChassisVelocities(
|
||||
const MecanumDriveWheelVelocities& wheelVelocities) const override;
|
||||
|
||||
Twist2d ToTwist2d(const MecanumDriveWheelPositions& start,
|
||||
const MecanumDriveWheelPositions& end) const override;
|
||||
@@ -136,7 +136,7 @@ class WPILIB_DLLEXPORT MecanumDriveKinematics
|
||||
*
|
||||
* @param wheelDeltas The change in distance driven by each wheel.
|
||||
*
|
||||
* @return The resulting chassis speed.
|
||||
* @return The resulting chassis velocity.
|
||||
*/
|
||||
Twist2d ToTwist2d(const MecanumDriveWheelPositions& wheelDeltas) const;
|
||||
|
||||
@@ -200,13 +200,13 @@ class WPILIB_DLLEXPORT MecanumDriveKinematics
|
||||
* Construct inverse kinematics matrix from wheel locations.
|
||||
*
|
||||
* @param fl The location of the front-left wheel relative to the physical
|
||||
* center of the robot.
|
||||
* center of the robot.
|
||||
* @param fr The location of the front-right wheel relative to the physical
|
||||
* center of the robot.
|
||||
* center of the robot.
|
||||
* @param rl The location of the rear-left wheel relative to the physical
|
||||
* center of the robot.
|
||||
* center of the robot.
|
||||
* @param rr The location of the rear-right wheel relative to the physical
|
||||
* center of the robot.
|
||||
* center of the robot.
|
||||
*/
|
||||
void SetInverseKinematics(Translation2d fl, Translation2d fr,
|
||||
Translation2d rl, Translation2d rr) const;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "wpi/math/geometry/Pose2d.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveKinematics.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelPositions.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelVelocities.hpp"
|
||||
#include "wpi/math/kinematics/Odometry.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace wpi::math {
|
||||
* when using computer-vision systems.
|
||||
*/
|
||||
class WPILIB_DLLEXPORT MecanumDriveOdometry
|
||||
: public Odometry<MecanumDriveWheelPositions, MecanumDriveWheelSpeeds,
|
||||
: public Odometry<MecanumDriveWheelPositions, MecanumDriveWheelVelocities,
|
||||
MecanumDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "wpi/math/geometry/Pose3d.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveKinematics.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelPositions.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelVelocities.hpp"
|
||||
#include "wpi/math/kinematics/Odometry3d.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace wpi::math {
|
||||
* when using computer-vision systems.
|
||||
*/
|
||||
class WPILIB_DLLEXPORT MecanumDriveOdometry3d
|
||||
: public Odometry3d<MecanumDriveWheelPositions, MecanumDriveWheelSpeeds,
|
||||
: public Odometry3d<MecanumDriveWheelPositions, MecanumDriveWheelVelocities,
|
||||
MecanumDriveWheelAccelerations> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,7 @@ struct WPILIB_DLLEXPORT MecanumDriveWheelAccelerations {
|
||||
/**
|
||||
* Adds two MecanumDriveWheelAccelerations and returns the sum.
|
||||
*
|
||||
* <p>For example, MecanumDriveWheelAccelerations{1.0, 0.5, 2.0, 1.5} +
|
||||
* For example, MecanumDriveWheelAccelerations{1.0, 0.5, 2.0, 1.5} +
|
||||
* MecanumDriveWheelAccelerations{2.0, 1.5, 0.5, 1.0} =
|
||||
* MecanumDriveWheelAccelerations{3.0, 2.0, 2.5, 2.5}
|
||||
*
|
||||
@@ -52,7 +52,7 @@ struct WPILIB_DLLEXPORT MecanumDriveWheelAccelerations {
|
||||
* Subtracts the other MecanumDriveWheelAccelerations from the current
|
||||
* MecanumDriveWheelAccelerations and returns the difference.
|
||||
*
|
||||
* <p>For example, MecanumDriveWheelAccelerations{5.0, 4.0, 6.0, 2.5} -
|
||||
* For example, MecanumDriveWheelAccelerations{5.0, 4.0, 6.0, 2.5} -
|
||||
* MecanumDriveWheelAccelerations{1.0, 2.0, 3.0, 0.5} =
|
||||
* MecanumDriveWheelAccelerations{4.0, 2.0, 3.0, 2.0}
|
||||
*
|
||||
@@ -79,7 +79,7 @@ struct WPILIB_DLLEXPORT MecanumDriveWheelAccelerations {
|
||||
* Multiplies the MecanumDriveWheelAccelerations by a scalar and returns the
|
||||
* new MecanumDriveWheelAccelerations.
|
||||
*
|
||||
* <p>For example, MecanumDriveWheelAccelerations{2.0, 2.5, 3.0, 3.5} * 2 =
|
||||
* For example, MecanumDriveWheelAccelerations{2.0, 2.5, 3.0, 3.5} * 2 =
|
||||
* MecanumDriveWheelAccelerations{4.0, 5.0, 6.0, 7.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
@@ -94,7 +94,7 @@ struct WPILIB_DLLEXPORT MecanumDriveWheelAccelerations {
|
||||
* Divides the MecanumDriveWheelAccelerations by a scalar and returns the new
|
||||
* MecanumDriveWheelAccelerations.
|
||||
*
|
||||
* <p>For example, MecanumDriveWheelAccelerations{2.0, 2.5, 1.5, 1.0} / 2 =
|
||||
* For example, MecanumDriveWheelAccelerations{2.0, 2.5, 1.5, 1.0} / 2 =
|
||||
* MecanumDriveWheelAccelerations{1.0, 1.25, 0.75, 0.5}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include "wpi/units/math.hpp"
|
||||
#include "wpi/units/velocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Represents the wheel speeds for a mecanum drive drivetrain.
|
||||
*/
|
||||
struct WPILIB_DLLEXPORT MecanumDriveWheelSpeeds {
|
||||
/**
|
||||
* Speed of the front-left wheel.
|
||||
*/
|
||||
wpi::units::meters_per_second_t frontLeft = 0_mps;
|
||||
|
||||
/**
|
||||
* Speed of the front-right wheel.
|
||||
*/
|
||||
wpi::units::meters_per_second_t frontRight = 0_mps;
|
||||
|
||||
/**
|
||||
* Speed of the rear-left wheel.
|
||||
*/
|
||||
wpi::units::meters_per_second_t rearLeft = 0_mps;
|
||||
|
||||
/**
|
||||
* Speed of the rear-right wheel.
|
||||
*/
|
||||
wpi::units::meters_per_second_t rearRight = 0_mps;
|
||||
|
||||
/**
|
||||
* Renormalizes the wheel speeds if any individual speed is above the
|
||||
* specified maximum.
|
||||
*
|
||||
* Sometimes, after inverse kinematics, the requested speed from one or
|
||||
* more wheels may be above the max attainable speed for the driving motor on
|
||||
* that wheel. To fix this issue, one can reduce all the wheel speeds to make
|
||||
* sure that all requested module speeds are at-or-below the absolute
|
||||
* threshold, while maintaining the ratio of speeds between wheels.
|
||||
*
|
||||
* @param attainableMaxSpeed The absolute max speed that a wheel can reach.
|
||||
* @return Desaturated MecanumDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr MecanumDriveWheelSpeeds Desaturate(
|
||||
wpi::units::meters_per_second_t attainableMaxSpeed) const {
|
||||
std::array<wpi::units::meters_per_second_t, 4> wheelSpeeds{
|
||||
frontLeft, frontRight, rearLeft, rearRight};
|
||||
wpi::units::meters_per_second_t realMaxSpeed =
|
||||
wpi::units::math::abs(*std::max_element(
|
||||
wheelSpeeds.begin(), wheelSpeeds.end(),
|
||||
[](const auto& a, const auto& b) {
|
||||
return wpi::units::math::abs(a) < wpi::units::math::abs(b);
|
||||
}));
|
||||
|
||||
if (realMaxSpeed > attainableMaxSpeed) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
wheelSpeeds[i] = wheelSpeeds[i] / realMaxSpeed * attainableMaxSpeed;
|
||||
}
|
||||
return MecanumDriveWheelSpeeds{wheelSpeeds[0], wheelSpeeds[1],
|
||||
wheelSpeeds[2], wheelSpeeds[3]};
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two MecanumDriveWheelSpeeds and returns the sum.
|
||||
*
|
||||
* <p>For example, MecanumDriveWheelSpeeds{1.0, 0.5, 2.0, 1.5} +
|
||||
* MecanumDriveWheelSpeeds{2.0, 1.5, 0.5, 1.0} =
|
||||
* MecanumDriveWheelSpeeds{3.0, 2.0, 2.5, 2.5}
|
||||
*
|
||||
* @param other The MecanumDriveWheelSpeeds to add.
|
||||
* @return The sum of the MecanumDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr MecanumDriveWheelSpeeds operator+(
|
||||
const MecanumDriveWheelSpeeds& other) const {
|
||||
return {frontLeft + other.frontLeft, frontRight + other.frontRight,
|
||||
rearLeft + other.rearLeft, rearRight + other.rearRight};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the other MecanumDriveWheelSpeeds from the current
|
||||
* MecanumDriveWheelSpeeds and returns the difference.
|
||||
*
|
||||
* <p>For example, MecanumDriveWheelSpeeds{5.0, 4.0, 6.0, 2.5} -
|
||||
* MecanumDriveWheelSpeeds{1.0, 2.0, 3.0, 0.5} =
|
||||
* MecanumDriveWheelSpeeds{4.0, 2.0, 3.0, 2.0}
|
||||
*
|
||||
* @param other The MecanumDriveWheelSpeeds to subtract.
|
||||
* @return The difference between the two MecanumDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr MecanumDriveWheelSpeeds operator-(
|
||||
const MecanumDriveWheelSpeeds& other) const {
|
||||
return *this + -other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inverse of the current MecanumDriveWheelSpeeds.
|
||||
* This is equivalent to negating all components of the
|
||||
* MecanumDriveWheelSpeeds.
|
||||
*
|
||||
* @return The inverse of the current MecanumDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr MecanumDriveWheelSpeeds operator-() const {
|
||||
return {-frontLeft, -frontRight, -rearLeft, -rearRight};
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the MecanumDriveWheelSpeeds by a scalar and returns the new
|
||||
* MecanumDriveWheelSpeeds.
|
||||
*
|
||||
* <p>For example, MecanumDriveWheelSpeeds{2.0, 2.5, 3.0, 3.5} * 2 =
|
||||
* MecanumDriveWheelSpeeds{4.0, 5.0, 6.0, 7.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
* @return The scaled MecanumDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr MecanumDriveWheelSpeeds operator*(double scalar) const {
|
||||
return {scalar * frontLeft, scalar * frontRight, scalar * rearLeft,
|
||||
scalar * rearRight};
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the MecanumDriveWheelSpeeds by a scalar and returns the new
|
||||
* MecanumDriveWheelSpeeds.
|
||||
*
|
||||
* <p>For example, MecanumDriveWheelSpeeds{2.0, 2.5, 1.5, 1.0} / 2 =
|
||||
* MecanumDriveWheelSpeeds{1.0, 1.25, 0.75, 0.5}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
* @return The scaled MecanumDriveWheelSpeeds.
|
||||
*/
|
||||
constexpr MecanumDriveWheelSpeeds operator/(double scalar) const {
|
||||
return operator*(1.0 / scalar);
|
||||
}
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
#include "wpi/math/kinematics/proto/MecanumDriveWheelSpeedsProto.hpp"
|
||||
#include "wpi/math/kinematics/struct/MecanumDriveWheelSpeedsStruct.hpp"
|
||||
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include "wpi/units/math.hpp"
|
||||
#include "wpi/units/velocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Represents the wheel velocities for a mecanum drive drivetrain.
|
||||
*/
|
||||
struct WPILIB_DLLEXPORT MecanumDriveWheelVelocities {
|
||||
/**
|
||||
* Velocity of the front-left wheel.
|
||||
*/
|
||||
wpi::units::meters_per_second_t frontLeft = 0_mps;
|
||||
|
||||
/**
|
||||
* Velocity of the front-right wheel.
|
||||
*/
|
||||
wpi::units::meters_per_second_t frontRight = 0_mps;
|
||||
|
||||
/**
|
||||
* Velocity of the rear-left wheel.
|
||||
*/
|
||||
wpi::units::meters_per_second_t rearLeft = 0_mps;
|
||||
|
||||
/**
|
||||
* Velocity of the rear-right wheel.
|
||||
*/
|
||||
wpi::units::meters_per_second_t rearRight = 0_mps;
|
||||
|
||||
/**
|
||||
* Renormalizes the wheel velocities if any individual velocity is above the
|
||||
* specified maximum.
|
||||
*
|
||||
* Sometimes, after inverse kinematics, the requested velocity from one or
|
||||
* more wheels may be above the max attainable velocity for the driving motor
|
||||
* on that wheel. To fix this issue, one can reduce all the wheel velocities
|
||||
* to make sure that all requested module velocities are at-or-below the
|
||||
* absolute threshold, while maintaining the ratio of velocities between
|
||||
* wheels.
|
||||
*
|
||||
* @param attainableMaxVelocity The absolute max velocity that a wheel can
|
||||
* reach.
|
||||
* @return Desaturated MecanumDriveWheelVelocities.
|
||||
*/
|
||||
constexpr MecanumDriveWheelVelocities Desaturate(
|
||||
wpi::units::meters_per_second_t attainableMaxVelocity) const {
|
||||
std::array<wpi::units::meters_per_second_t, 4> wheelVelocities{
|
||||
frontLeft, frontRight, rearLeft, rearRight};
|
||||
wpi::units::meters_per_second_t realMaxVelocity =
|
||||
wpi::units::math::abs(*std::max_element(
|
||||
wheelVelocities.begin(), wheelVelocities.end(),
|
||||
[](const auto& a, const auto& b) {
|
||||
return wpi::units::math::abs(a) < wpi::units::math::abs(b);
|
||||
}));
|
||||
|
||||
if (realMaxVelocity > attainableMaxVelocity) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
wheelVelocities[i] =
|
||||
wheelVelocities[i] / realMaxVelocity * attainableMaxVelocity;
|
||||
}
|
||||
return MecanumDriveWheelVelocities{wheelVelocities[0], wheelVelocities[1],
|
||||
wheelVelocities[2],
|
||||
wheelVelocities[3]};
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds two MecanumDriveWheelVelocities and returns the sum.
|
||||
*
|
||||
* For example, MecanumDriveWheelVelocities{1.0, 0.5, 2.0, 1.5} +
|
||||
* MecanumDriveWheelVelocities{2.0, 1.5, 0.5, 1.0} =
|
||||
* MecanumDriveWheelVelocities{3.0, 2.0, 2.5, 2.5}
|
||||
*
|
||||
* @param other The MecanumDriveWheelVelocities to add.
|
||||
* @return The sum of the MecanumDriveWheelVelocities.
|
||||
*/
|
||||
constexpr MecanumDriveWheelVelocities operator+(
|
||||
const MecanumDriveWheelVelocities& other) const {
|
||||
return {frontLeft + other.frontLeft, frontRight + other.frontRight,
|
||||
rearLeft + other.rearLeft, rearRight + other.rearRight};
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts the other MecanumDriveWheelVelocities from the current
|
||||
* MecanumDriveWheelVelocities and returns the difference.
|
||||
*
|
||||
* For example, MecanumDriveWheelVelocities{5.0, 4.0, 6.0, 2.5} -
|
||||
* MecanumDriveWheelVelocities{1.0, 2.0, 3.0, 0.5} =
|
||||
* MecanumDriveWheelVelocities{4.0, 2.0, 3.0, 2.0}
|
||||
*
|
||||
* @param other The MecanumDriveWheelVelocities to subtract.
|
||||
* @return The difference between the two MecanumDriveWheelVelocities.
|
||||
*/
|
||||
constexpr MecanumDriveWheelVelocities operator-(
|
||||
const MecanumDriveWheelVelocities& other) const {
|
||||
return *this + -other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the inverse of the current MecanumDriveWheelVelocities.
|
||||
* This is equivalent to negating all components of the
|
||||
* MecanumDriveWheelVelocities.
|
||||
*
|
||||
* @return The inverse of the current MecanumDriveWheelVelocities.
|
||||
*/
|
||||
constexpr MecanumDriveWheelVelocities operator-() const {
|
||||
return {-frontLeft, -frontRight, -rearLeft, -rearRight};
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies the MecanumDriveWheelVelocities by a scalar and returns the new
|
||||
* MecanumDriveWheelVelocities.
|
||||
*
|
||||
* For example, MecanumDriveWheelVelocities{2.0, 2.5, 3.0, 3.5} * 2 =
|
||||
* MecanumDriveWheelVelocities{4.0, 5.0, 6.0, 7.0}
|
||||
*
|
||||
* @param scalar The scalar to multiply by.
|
||||
* @return The scaled MecanumDriveWheelVelocities.
|
||||
*/
|
||||
constexpr MecanumDriveWheelVelocities operator*(double scalar) const {
|
||||
return {scalar * frontLeft, scalar * frontRight, scalar * rearLeft,
|
||||
scalar * rearRight};
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides the MecanumDriveWheelVelocities by a scalar and returns the new
|
||||
* MecanumDriveWheelVelocities.
|
||||
*
|
||||
* For example, MecanumDriveWheelVelocities{2.0, 2.5, 1.5, 1.0} / 2 =
|
||||
* MecanumDriveWheelVelocities{1.0, 1.25, 0.75, 0.5}
|
||||
*
|
||||
* @param scalar The scalar to divide by.
|
||||
* @return The scaled MecanumDriveWheelVelocities.
|
||||
*/
|
||||
constexpr MecanumDriveWheelVelocities operator/(double scalar) const {
|
||||
return operator*(1.0 / scalar);
|
||||
}
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
#include "wpi/math/kinematics/proto/MecanumDriveWheelVelocitiesProto.hpp"
|
||||
#include "wpi/math/kinematics/struct/MecanumDriveWheelVelocitiesStruct.hpp"
|
||||
@@ -23,10 +23,10 @@ namespace wpi::math {
|
||||
* when using computer-vision systems.
|
||||
*
|
||||
* @tparam WheelPositions Wheel positions type.
|
||||
* @tparam WheelSpeeds Wheel speeds type.
|
||||
* @tparam WheelVelocities Wheel velocities type.
|
||||
* @tparam WheelAccelerations Wheel accelerations type.
|
||||
*/
|
||||
template <typename WheelPositions, typename WheelSpeeds,
|
||||
template <typename WheelPositions, typename WheelVelocities,
|
||||
typename WheelAccelerations>
|
||||
class WPILIB_DLLEXPORT Odometry {
|
||||
public:
|
||||
@@ -38,7 +38,7 @@ class WPILIB_DLLEXPORT Odometry {
|
||||
* @param wheelPositions The current distances measured by each wheel.
|
||||
* @param initialPose The starting position of the robot on the field.
|
||||
*/
|
||||
explicit Odometry(const Kinematics<WheelPositions, WheelSpeeds,
|
||||
explicit Odometry(const Kinematics<WheelPositions, WheelVelocities,
|
||||
WheelAccelerations>& kinematics,
|
||||
const Rotation2d& gyroAngle,
|
||||
const WheelPositions& wheelPositions,
|
||||
@@ -135,7 +135,7 @@ class WPILIB_DLLEXPORT Odometry {
|
||||
}
|
||||
|
||||
private:
|
||||
const Kinematics<WheelPositions, WheelSpeeds, WheelAccelerations>&
|
||||
const Kinematics<WheelPositions, WheelVelocities, WheelAccelerations>&
|
||||
m_kinematics;
|
||||
Pose2d m_pose;
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ namespace wpi::math {
|
||||
* when using computer-vision systems.
|
||||
*
|
||||
* @tparam WheelPositions Wheel positions type.
|
||||
* @tparam WheelSpeeds Wheel speeds type.
|
||||
* @tparam WheelVelocities Wheel velocities type.
|
||||
* @tparam WheelAccelerations Wheel accelerations type.
|
||||
*/
|
||||
template <typename WheelPositions, typename WheelSpeeds,
|
||||
template <typename WheelPositions, typename WheelVelocities,
|
||||
typename WheelAccelerations>
|
||||
class WPILIB_DLLEXPORT Odometry3d {
|
||||
public:
|
||||
@@ -38,7 +38,7 @@ class WPILIB_DLLEXPORT Odometry3d {
|
||||
* @param wheelPositions The current distances measured by each wheel.
|
||||
* @param initialPose The starting position of the robot on the field.
|
||||
*/
|
||||
explicit Odometry3d(const Kinematics<WheelPositions, WheelSpeeds,
|
||||
explicit Odometry3d(const Kinematics<WheelPositions, WheelVelocities,
|
||||
WheelAccelerations>& kinematics,
|
||||
const Rotation3d& gyroAngle,
|
||||
const WheelPositions& wheelPositions,
|
||||
@@ -147,7 +147,7 @@ class WPILIB_DLLEXPORT Odometry3d {
|
||||
}
|
||||
|
||||
private:
|
||||
const Kinematics<WheelPositions, WheelSpeeds, WheelAccelerations>&
|
||||
const Kinematics<WheelPositions, WheelVelocities, WheelAccelerations>&
|
||||
m_kinematics;
|
||||
Pose3d m_pose;
|
||||
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
#include "wpi/math/geometry/Translation2d.hpp"
|
||||
#include "wpi/math/geometry/Twist2d.hpp"
|
||||
#include "wpi/math/kinematics/ChassisAccelerations.hpp"
|
||||
#include "wpi/math/kinematics/ChassisSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/ChassisVelocities.hpp"
|
||||
#include "wpi/math/kinematics/Kinematics.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleAcceleration.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModulePosition.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleState.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleVelocity.hpp"
|
||||
#include "wpi/math/linalg/EigenCore.hpp"
|
||||
#include "wpi/math/util/MathShared.hpp"
|
||||
#include "wpi/units/math.hpp"
|
||||
@@ -30,7 +30,7 @@ namespace wpi::math {
|
||||
|
||||
/**
|
||||
* Helper class that converts a chassis velocity (dx, dy, and dtheta components)
|
||||
* into individual module states (speed and angle).
|
||||
* into individual module states (velocity and angle).
|
||||
*
|
||||
* The inverse kinematics (converting from a desired chassis velocity to
|
||||
* individual module states) uses the relative locations of the modules with
|
||||
@@ -43,9 +43,10 @@ namespace wpi::math {
|
||||
* does. Since this is an overdetermined system (more equations than variables),
|
||||
* we use a least-squares approximation.
|
||||
*
|
||||
* The inverse kinematics: [moduleStates] = [moduleLocations] * [chassisSpeeds]
|
||||
* We take the Moore-Penrose pseudoinverse of [moduleLocations] and then
|
||||
* multiply by [moduleStates] to get our chassis speeds.
|
||||
* The inverse kinematics: [moduleVelocities] = [moduleLocations] *
|
||||
* [chassisVelocities] We take the Moore-Penrose pseudoinverse of
|
||||
* [moduleLocations] and then multiply by [moduleVelocities] to get our chassis
|
||||
* velocities.
|
||||
*
|
||||
* Forward kinematics is also used for odometry -- determining the position of
|
||||
* the robot on the field using encoders and a gyro.
|
||||
@@ -54,7 +55,7 @@ template <size_t NumModules>
|
||||
class SwerveDriveKinematics
|
||||
: public Kinematics<
|
||||
wpi::util::array<SwerveModulePosition, NumModules>,
|
||||
wpi::util::array<SwerveModuleState, NumModules>,
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules>,
|
||||
wpi::util::array<SwerveModuleAcceleration, NumModules>> {
|
||||
public:
|
||||
/**
|
||||
@@ -66,7 +67,7 @@ class SwerveDriveKinematics
|
||||
* kinematics methods.
|
||||
*
|
||||
* @param moduleTranslations The locations of the modules relative to the
|
||||
* physical center of the robot.
|
||||
* physical center of the robot.
|
||||
*/
|
||||
template <std::convertible_to<Translation2d>... ModuleTranslations>
|
||||
requires(sizeof...(ModuleTranslations) == NumModules)
|
||||
@@ -120,8 +121,9 @@ class SwerveDriveKinematics
|
||||
|
||||
/**
|
||||
* Reset the internal swerve module headings.
|
||||
*
|
||||
* @param moduleHeadings The swerve module headings. The order of the module
|
||||
* headings should be same as passed into the constructor of this class.
|
||||
* headings should be same as passed into the constructor of this class.
|
||||
*/
|
||||
template <std::convertible_to<Rotation2d>... ModuleHeadings>
|
||||
requires(sizeof...(ModuleHeadings) == NumModules)
|
||||
@@ -132,8 +134,9 @@ class SwerveDriveKinematics
|
||||
|
||||
/**
|
||||
* Reset the internal swerve module headings.
|
||||
*
|
||||
* @param moduleHeadings The swerve module headings. The order of the module
|
||||
* headings should be same as passed into the constructor of this class.
|
||||
* headings should be same as passed into the constructor of this class.
|
||||
*/
|
||||
void ResetHeadings(wpi::util::array<Rotation2d, NumModules> moduleHeadings) {
|
||||
for (size_t i = 0; i < NumModules; i++) {
|
||||
@@ -144,7 +147,7 @@ class SwerveDriveKinematics
|
||||
/**
|
||||
* Performs inverse kinematics to return the module states from a desired
|
||||
* chassis velocity. This method is often used to convert joystick values into
|
||||
* module speeds and angles.
|
||||
* module velocities and angles.
|
||||
*
|
||||
* This function also supports variable centers of rotation. During normal
|
||||
* operations, the center of rotation is usually the same as the physical
|
||||
@@ -152,39 +155,41 @@ class SwerveDriveKinematics
|
||||
* However, if you wish to change the center of rotation for evasive
|
||||
* maneuvers, vision alignment, or for any other use case, you can do so.
|
||||
*
|
||||
* In the case that the desired chassis speeds are zero (i.e. the robot will
|
||||
* be stationary), the previously calculated module angle will be maintained.
|
||||
* In the case that the desired chassis velocities are zero (i.e. the robot
|
||||
* will be stationary), the previously calculated module angle will be
|
||||
* maintained.
|
||||
*
|
||||
* @param chassisSpeeds The desired chassis speed.
|
||||
* @param chassisVelocities The desired chassis velocity.
|
||||
* @param centerOfRotation The center of rotation. For example, if you set the
|
||||
* center of rotation at one corner of the robot and provide a chassis speed
|
||||
* that only has a dtheta component, the robot will rotate around that corner.
|
||||
*
|
||||
* center of rotation at one corner of the robot and provide a chassis
|
||||
* velocity that only has a dtheta component, the robot will rotate around
|
||||
* that corner.
|
||||
* @return An array containing the module states. Use caution because these
|
||||
* module states are not normalized. Sometimes, a user input may cause one of
|
||||
* the module speeds to go above the attainable max velocity. Use the
|
||||
* DesaturateWheelSpeeds(wpi::util::array<SwerveModuleState, NumModules>*,
|
||||
* wpi::units::meters_per_second_t) function to rectify this issue. In
|
||||
* addition, you can leverage the power of C++17 to directly assign the module
|
||||
* states to variables:
|
||||
* module states are not normalized. Sometimes, a user input may cause one
|
||||
* of the module velocities to go above the attainable max velocity. Use
|
||||
* the DesaturateWheelVelocities(wpi::util::array<SwerveModuleVelocity,
|
||||
* NumModules>*, wpi::units::meters_per_second_t) function to rectify this
|
||||
* issue. In addition, you can leverage the power of C++17 to directly
|
||||
* assign the module states to variables:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* auto [fl, fr, bl, br] = kinematics.ToSwerveModuleStates(chassisSpeeds);
|
||||
* auto [fl, fr, bl, br] =
|
||||
* kinematics.ToSwerveModuleVelocities(chassisVelocities);
|
||||
* @endcode
|
||||
*/
|
||||
wpi::util::array<SwerveModuleState, NumModules> ToSwerveModuleStates(
|
||||
const ChassisSpeeds& chassisSpeeds,
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules> ToSwerveModuleVelocities(
|
||||
const ChassisVelocities& chassisVelocities,
|
||||
const Translation2d& centerOfRotation = Translation2d{}) const {
|
||||
wpi::util::array<SwerveModuleState, NumModules> moduleStates(
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules> moduleVelocities(
|
||||
wpi::util::empty_array);
|
||||
|
||||
if (chassisSpeeds.vx == 0_mps && chassisSpeeds.vy == 0_mps &&
|
||||
chassisSpeeds.omega == 0_rad_per_s) {
|
||||
if (chassisVelocities.vx == 0_mps && chassisVelocities.vy == 0_mps &&
|
||||
chassisVelocities.omega == 0_rad_per_s) {
|
||||
for (size_t i = 0; i < NumModules; i++) {
|
||||
moduleStates[i] = {0_mps, m_moduleHeadings[i]};
|
||||
moduleVelocities[i] = {0_mps, m_moduleHeadings[i]};
|
||||
}
|
||||
|
||||
return moduleStates;
|
||||
return moduleVelocities;
|
||||
}
|
||||
|
||||
// We have a new center of rotation. We need to compute the matrix again.
|
||||
@@ -192,83 +197,85 @@ class SwerveDriveKinematics
|
||||
SetInverseKinematics(centerOfRotation);
|
||||
}
|
||||
|
||||
Eigen::Vector3d chassisSpeedsVector{chassisSpeeds.vx.value(),
|
||||
chassisSpeeds.vy.value(),
|
||||
chassisSpeeds.omega.value()};
|
||||
Eigen::Vector3d chassisVelocitiesVector{chassisVelocities.vx.value(),
|
||||
chassisVelocities.vy.value(),
|
||||
chassisVelocities.omega.value()};
|
||||
|
||||
Matrixd<NumModules * 2, 1> moduleStateMatrix =
|
||||
m_firstOrderInverseKinematics * chassisSpeedsVector;
|
||||
Matrixd<NumModules * 2, 1> moduleVelocityMatrix =
|
||||
m_firstOrderInverseKinematics * chassisVelocitiesVector;
|
||||
|
||||
for (size_t i = 0; i < NumModules; i++) {
|
||||
wpi::units::meters_per_second_t x{moduleStateMatrix(i * 2, 0)};
|
||||
wpi::units::meters_per_second_t y{moduleStateMatrix(i * 2 + 1, 0)};
|
||||
wpi::units::meters_per_second_t x{moduleVelocityMatrix(i * 2, 0)};
|
||||
wpi::units::meters_per_second_t y{moduleVelocityMatrix(i * 2 + 1, 0)};
|
||||
|
||||
auto speed = wpi::units::math::hypot(x, y);
|
||||
auto rotation = speed > 1e-6_mps ? Rotation2d{x.value(), y.value()}
|
||||
: m_moduleHeadings[i];
|
||||
auto velocity = wpi::units::math::hypot(x, y);
|
||||
auto rotation = velocity > 1e-6_mps ? Rotation2d{x.value(), y.value()}
|
||||
: m_moduleHeadings[i];
|
||||
|
||||
moduleStates[i] = {speed, rotation};
|
||||
moduleVelocities[i] = {velocity, rotation};
|
||||
m_moduleHeadings[i] = rotation;
|
||||
}
|
||||
|
||||
return moduleStates;
|
||||
return moduleVelocities;
|
||||
}
|
||||
|
||||
wpi::util::array<SwerveModuleState, NumModules> ToWheelSpeeds(
|
||||
const ChassisSpeeds& chassisSpeeds) const override {
|
||||
return ToSwerveModuleStates(chassisSpeeds);
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules> ToWheelVelocities(
|
||||
const ChassisVelocities& chassisVelocities) const override {
|
||||
return ToSwerveModuleVelocities(chassisVelocities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs forward kinematics to return the resulting chassis state from the
|
||||
* given module states. This method is often used for odometry -- determining
|
||||
* the robot's position on the field using data from the real-world speed and
|
||||
* angle of each module on the robot.
|
||||
* the robot's position on the field using data from the real-world velocity
|
||||
* and angle of each module on the robot.
|
||||
*
|
||||
* @param moduleStates The state of the modules (as a SwerveModuleState type)
|
||||
* as measured from respective encoders and gyros. The order of the swerve
|
||||
* module states should be same as passed into the constructor of this class.
|
||||
*
|
||||
* @return The resulting chassis speed.
|
||||
* @param moduleVelocities The state of the modules (as a SwerveModuleVelocity
|
||||
* type) as measured from respective encoders and gyros. The order of the
|
||||
* swerve module states should be same as passed into the constructor of
|
||||
* this class.
|
||||
* @return The resulting chassis velocity.
|
||||
*/
|
||||
template <std::convertible_to<SwerveModuleState>... ModuleStates>
|
||||
requires(sizeof...(ModuleStates) == NumModules)
|
||||
ChassisSpeeds ToChassisSpeeds(ModuleStates&&... moduleStates) const {
|
||||
return this->ToChassisSpeeds(
|
||||
wpi::util::array<SwerveModuleState, NumModules>{moduleStates...});
|
||||
template <std::convertible_to<SwerveModuleVelocity>... ModuleVelocities>
|
||||
requires(sizeof...(ModuleVelocities) == NumModules)
|
||||
ChassisVelocities ToChassisVelocities(
|
||||
ModuleVelocities&&... moduleVelocities) const {
|
||||
return this->ToChassisVelocities(
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules>{
|
||||
moduleVelocities...});
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs forward kinematics to return the resulting chassis state from the
|
||||
* given module states. This method is often used for odometry -- determining
|
||||
* the robot's position on the field using data from the real-world speed and
|
||||
* angle of each module on the robot.
|
||||
* the robot's position on the field using data from the real-world velocity
|
||||
* and angle of each module on the robot.
|
||||
*
|
||||
* @param moduleStates The state of the modules as an wpi::util::array of type
|
||||
* SwerveModuleState, NumModules long as measured from respective encoders
|
||||
* and gyros. The order of the swerve module states should be same as passed
|
||||
* into the constructor of this class.
|
||||
*
|
||||
* @return The resulting chassis speed.
|
||||
* @param moduleVelocities The state of the modules as an wpi::util::array of
|
||||
* type SwerveModuleVelocity, NumModules long as measured from respective
|
||||
* encoders and gyros. The order of the swerve module states should be
|
||||
* same as passed into the constructor of this class.
|
||||
* @return The resulting chassis velocity.
|
||||
*/
|
||||
ChassisSpeeds ToChassisSpeeds(
|
||||
const wpi::util::array<SwerveModuleState, NumModules>& moduleStates)
|
||||
const override {
|
||||
Matrixd<NumModules * 2, 1> moduleStateMatrix;
|
||||
ChassisVelocities ToChassisVelocities(
|
||||
const wpi::util::array<SwerveModuleVelocity, NumModules>&
|
||||
moduleVelocities) const override {
|
||||
Matrixd<NumModules * 2, 1> moduleVelocityMatrix;
|
||||
|
||||
for (size_t i = 0; i < NumModules; ++i) {
|
||||
SwerveModuleState module = moduleStates[i];
|
||||
moduleStateMatrix(i * 2, 0) = module.speed.value() * module.angle.Cos();
|
||||
moduleStateMatrix(i * 2 + 1, 0) =
|
||||
module.speed.value() * module.angle.Sin();
|
||||
SwerveModuleVelocity module = moduleVelocities[i];
|
||||
moduleVelocityMatrix(i * 2, 0) =
|
||||
module.velocity.value() * module.angle.Cos();
|
||||
moduleVelocityMatrix(i * 2 + 1, 0) =
|
||||
module.velocity.value() * module.angle.Sin();
|
||||
}
|
||||
|
||||
Eigen::Vector3d chassisSpeedsVector =
|
||||
m_firstOrderForwardKinematics.solve(moduleStateMatrix);
|
||||
Eigen::Vector3d chassisVelocitiesVector =
|
||||
m_firstOrderForwardKinematics.solve(moduleVelocityMatrix);
|
||||
|
||||
return {wpi::units::meters_per_second_t{chassisSpeedsVector(0)},
|
||||
wpi::units::meters_per_second_t{chassisSpeedsVector(1)},
|
||||
wpi::units::radians_per_second_t{chassisSpeedsVector(2)}};
|
||||
return {wpi::units::meters_per_second_t{chassisVelocitiesVector(0)},
|
||||
wpi::units::meters_per_second_t{chassisVelocitiesVector(1)},
|
||||
wpi::units::radians_per_second_t{chassisVelocitiesVector(2)}};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,10 +285,9 @@ class SwerveDriveKinematics
|
||||
* real-world position delta and angle of each module on the robot.
|
||||
*
|
||||
* @param moduleDeltas The latest change in position of the modules (as a
|
||||
* SwerveModulePosition type) as measured from respective encoders and gyros.
|
||||
* The order of the swerve module states should be same as passed into the
|
||||
* constructor of this class.
|
||||
*
|
||||
* SwerveModulePosition type) as measured from respective encoders and
|
||||
* gyros. The order of the swerve module states should be same as passed
|
||||
* into the constructor of this class.
|
||||
* @return The resulting Twist2d.
|
||||
*/
|
||||
template <std::convertible_to<SwerveModulePosition>... ModuleDeltas>
|
||||
@@ -298,10 +304,9 @@ class SwerveDriveKinematics
|
||||
* real-world position delta and angle of each module on the robot.
|
||||
*
|
||||
* @param moduleDeltas The latest change in position of the modules (as a
|
||||
* SwerveModulePosition type) as measured from respective encoders and gyros.
|
||||
* The order of the swerve module states should be same as passed into the
|
||||
* constructor of this class.
|
||||
*
|
||||
* SwerveModulePosition type) as measured from respective encoders and
|
||||
* gyros. The order of the swerve module states should be same as passed
|
||||
* into the constructor of this class.
|
||||
* @return The resulting Twist2d.
|
||||
*/
|
||||
Twist2d ToTwist2d(
|
||||
@@ -337,105 +342,109 @@ class SwerveDriveKinematics
|
||||
}
|
||||
|
||||
/**
|
||||
* Renormalizes the wheel speeds if any individual speed is above the
|
||||
* Renormalizes the wheel velocities if any individual velocity is above the
|
||||
* specified maximum.
|
||||
*
|
||||
* Sometimes, after inverse kinematics, the requested speed
|
||||
* from one or more modules may be above the max attainable speed for the
|
||||
* Sometimes, after inverse kinematics, the requested velocity
|
||||
* from one or more modules may be above the max attainable velocity for the
|
||||
* driving motor on that module. To fix this issue, one can reduce all the
|
||||
* wheel speeds to make sure that all requested module speeds are at-or-below
|
||||
* the absolute threshold, while maintaining the ratio of speeds between
|
||||
* modules.
|
||||
* wheel velocities to make sure that all requested module velocities are
|
||||
* at-or-below the absolute threshold, while maintaining the ratio of
|
||||
* velocities between modules.
|
||||
*
|
||||
* Scaling down the module speeds rotates the direction of net motion in the
|
||||
* opposite direction of rotational velocity, which makes discretizing the
|
||||
* chassis speeds inaccurate because the discretization did not account for
|
||||
* this translational skew.
|
||||
* Scaling down the module velocities rotates the direction of net motion in
|
||||
* the opposite direction of rotational velocity, which makes discretizing the
|
||||
* chassis velocities inaccurate because the discretization did not account
|
||||
* for this translational skew.
|
||||
*
|
||||
* @param moduleStates Reference to array of module states. The array will be
|
||||
* mutated with the normalized speeds!
|
||||
* @param attainableMaxSpeed The absolute max speed that a module can reach.
|
||||
* @param moduleVelocities Reference to array of module states. The array will
|
||||
* be mutated with the normalized velocities!
|
||||
* @param attainableMaxVelocity The absolute max velocity that a module can
|
||||
* reach.
|
||||
*/
|
||||
static void DesaturateWheelSpeeds(
|
||||
wpi::util::array<SwerveModuleState, NumModules>* moduleStates,
|
||||
wpi::units::meters_per_second_t attainableMaxSpeed) {
|
||||
auto& states = *moduleStates;
|
||||
auto realMaxSpeed = wpi::units::math::abs(
|
||||
static void DesaturateWheelVelocities(
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules>* moduleVelocities,
|
||||
wpi::units::meters_per_second_t attainableMaxVelocity) {
|
||||
auto& states = *moduleVelocities;
|
||||
auto realMaxVelocity = wpi::units::math::abs(
|
||||
std::max_element(states.begin(), states.end(),
|
||||
[](const auto& a, const auto& b) {
|
||||
return wpi::units::math::abs(a.speed) <
|
||||
wpi::units::math::abs(b.speed);
|
||||
return wpi::units::math::abs(a.velocity) <
|
||||
wpi::units::math::abs(b.velocity);
|
||||
})
|
||||
->speed);
|
||||
->velocity);
|
||||
|
||||
if (realMaxSpeed > attainableMaxSpeed) {
|
||||
if (realMaxVelocity > attainableMaxVelocity) {
|
||||
for (auto& module : states) {
|
||||
module.speed = module.speed / realMaxSpeed * attainableMaxSpeed;
|
||||
module.velocity =
|
||||
module.velocity / realMaxVelocity * attainableMaxVelocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renormalizes the wheel speeds if any individual speed is above the
|
||||
* Renormalizes the wheel velocities if any individual velocity is above the
|
||||
* specified maximum, as well as getting rid of joystick saturation at edges
|
||||
* of joystick.
|
||||
*
|
||||
* Sometimes, after inverse kinematics, the requested speed
|
||||
* from one or more modules may be above the max attainable speed for the
|
||||
* Sometimes, after inverse kinematics, the requested velocity
|
||||
* from one or more modules may be above the max attainable velocity for the
|
||||
* driving motor on that module. To fix this issue, one can reduce all the
|
||||
* wheel speeds to make sure that all requested module speeds are at-or-below
|
||||
* the absolute threshold, while maintaining the ratio of speeds between
|
||||
* modules.
|
||||
* wheel velocities to make sure that all requested module velocities are
|
||||
* at-or-below the absolute threshold, while maintaining the ratio of
|
||||
* velocities between modules.
|
||||
*
|
||||
* Scaling down the module speeds rotates the direction of net motion in the
|
||||
* opposite direction of rotational velocity, which makes discretizing the
|
||||
* chassis speeds inaccurate because the discretization did not account for
|
||||
* this translational skew.
|
||||
* Scaling down the module velocities rotates the direction of net motion in
|
||||
* the opposite direction of rotational velocity, which makes discretizing the
|
||||
* chassis velocities inaccurate because the discretization did not account
|
||||
* for this translational skew.
|
||||
*
|
||||
* @param moduleStates Reference to array of module states. The array will be
|
||||
* mutated with the normalized speeds!
|
||||
* @param desiredChassisSpeed The desired speed of the robot
|
||||
* @param attainableMaxModuleSpeed The absolute max speed a module can reach
|
||||
* @param attainableMaxRobotTranslationSpeed The absolute max speed the robot
|
||||
* can reach while translating
|
||||
* @param attainableMaxRobotRotationSpeed The absolute max speed the robot can
|
||||
* reach while rotating
|
||||
* @param moduleVelocities Reference to array of module states. The array will
|
||||
* be mutated with the normalized velocities!
|
||||
* @param desiredChassisVelocity The desired velocity of the robot
|
||||
* @param attainableMaxModuleVelocity The absolute max velocity a module can
|
||||
* reach
|
||||
* @param attainableMaxRobotTranslationVelocity The absolute max velocity the
|
||||
* robot can reach while translating
|
||||
* @param attainableMaxRobotRotationVelocity The absolute max velocity the
|
||||
* robot can reach while rotating
|
||||
*/
|
||||
static void DesaturateWheelSpeeds(
|
||||
wpi::util::array<SwerveModuleState, NumModules>* moduleStates,
|
||||
ChassisSpeeds desiredChassisSpeed,
|
||||
wpi::units::meters_per_second_t attainableMaxModuleSpeed,
|
||||
wpi::units::meters_per_second_t attainableMaxRobotTranslationSpeed,
|
||||
wpi::units::radians_per_second_t attainableMaxRobotRotationSpeed) {
|
||||
auto& states = *moduleStates;
|
||||
static void DesaturateWheelVelocities(
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules>* moduleVelocities,
|
||||
ChassisVelocities desiredChassisVelocity,
|
||||
wpi::units::meters_per_second_t attainableMaxModuleVelocity,
|
||||
wpi::units::meters_per_second_t attainableMaxRobotTranslationVelocity,
|
||||
wpi::units::radians_per_second_t attainableMaxRobotRotationVelocity) {
|
||||
auto& states = *moduleVelocities;
|
||||
|
||||
auto realMaxSpeed = wpi::units::math::abs(
|
||||
auto realMaxVelocity = wpi::units::math::abs(
|
||||
std::max_element(states.begin(), states.end(),
|
||||
[](const auto& a, const auto& b) {
|
||||
return wpi::units::math::abs(a.speed) <
|
||||
wpi::units::math::abs(b.speed);
|
||||
return wpi::units::math::abs(a.velocity) <
|
||||
wpi::units::math::abs(b.velocity);
|
||||
})
|
||||
->speed);
|
||||
->velocity);
|
||||
|
||||
if (attainableMaxRobotTranslationSpeed == 0_mps ||
|
||||
attainableMaxRobotRotationSpeed == 0_rad_per_s ||
|
||||
realMaxSpeed == 0_mps) {
|
||||
if (attainableMaxRobotTranslationVelocity == 0_mps ||
|
||||
attainableMaxRobotRotationVelocity == 0_rad_per_s ||
|
||||
realMaxVelocity == 0_mps) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto translationalK = wpi::units::math::hypot(desiredChassisSpeed.vx,
|
||||
desiredChassisSpeed.vy) /
|
||||
attainableMaxRobotTranslationSpeed;
|
||||
auto translationalK = wpi::units::math::hypot(desiredChassisVelocity.vx,
|
||||
desiredChassisVelocity.vy) /
|
||||
attainableMaxRobotTranslationVelocity;
|
||||
|
||||
auto rotationalK = wpi::units::math::abs(desiredChassisSpeed.omega) /
|
||||
attainableMaxRobotRotationSpeed;
|
||||
auto rotationalK = wpi::units::math::abs(desiredChassisVelocity.omega) /
|
||||
attainableMaxRobotRotationVelocity;
|
||||
|
||||
auto k = wpi::units::math::max(translationalK, rotationalK);
|
||||
|
||||
auto scale = wpi::units::math::min(
|
||||
k * attainableMaxModuleSpeed / realMaxSpeed, wpi::units::scalar_t{1});
|
||||
auto scale =
|
||||
wpi::units::math::min(k * attainableMaxModuleVelocity / realMaxVelocity,
|
||||
wpi::units::scalar_t{1});
|
||||
for (auto& module : states) {
|
||||
module.speed = module.speed * scale;
|
||||
module.velocity = module.velocity * scale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,7 +470,7 @@ class SwerveDriveKinematics
|
||||
* calculations -- converting desired robot accelerations into individual
|
||||
* module accelerations.
|
||||
*
|
||||
* <p>This function also supports variable centers of rotation. During normal
|
||||
* This function also supports variable centers of rotation. During normal
|
||||
* operations, the center of rotation is usually the same as the physical
|
||||
* center of the robot; therefore, the argument is defaulted to that use case.
|
||||
* However, if you wish to change the center of rotation for evasive
|
||||
@@ -470,9 +479,9 @@ class SwerveDriveKinematics
|
||||
* @param chassisAccelerations The desired chassis accelerations.
|
||||
* @param angularVelocity The desired robot angular velocity.
|
||||
* @param centerOfRotation The center of rotation. For example, if you set the
|
||||
* center of rotation at one corner of the robot and provide a chassis
|
||||
* acceleration that only has a dtheta component, the robot will rotate around
|
||||
* that corner.
|
||||
* center of rotation at one corner of the robot and provide a chassis
|
||||
* acceleration that only has a dtheta component, the robot will rotate
|
||||
* around that corner.
|
||||
* @return An array containing the module accelerations.
|
||||
*/
|
||||
wpi::util::array<SwerveModuleAcceleration, NumModules>
|
||||
@@ -551,8 +560,9 @@ class SwerveDriveKinematics
|
||||
* data from the real-world acceleration of each module on the robot.
|
||||
*
|
||||
* @param moduleAccelerations The accelerations of the modules as measured
|
||||
* from respective encoders and gyros. The order of the swerve module
|
||||
* accelerations should be same as passed into the constructor of this class.
|
||||
* from respective encoders and gyros. The order of the swerve module
|
||||
* accelerations should be same as passed into the constructor of this
|
||||
* class.
|
||||
* @return The resulting chassis accelerations.
|
||||
*/
|
||||
template <
|
||||
@@ -572,8 +582,9 @@ class SwerveDriveKinematics
|
||||
* data from the real-world acceleration of each module on the robot.
|
||||
*
|
||||
* @param moduleAccelerations The accelerations of the modules as measured
|
||||
* from respective encoders and gyros. The order of the swerve module
|
||||
* accelerations should be same as passed into the constructor of this class.
|
||||
* from respective encoders and gyros. The order of the swerve module
|
||||
* accelerations should be same as passed into the constructor of this
|
||||
* class.
|
||||
* @return The resulting chassis accelerations.
|
||||
*/
|
||||
ChassisAccelerations ToChassisAccelerations(
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "wpi/math/kinematics/Odometry.hpp"
|
||||
#include "wpi/math/kinematics/SwerveDriveKinematics.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModulePosition.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleState.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleVelocity.hpp"
|
||||
#include "wpi/math/util/MathShared.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace wpi::math {
|
||||
template <size_t NumModules>
|
||||
class SwerveDriveOdometry
|
||||
: public Odometry<wpi::util::array<SwerveModulePosition, NumModules>,
|
||||
wpi::util::array<SwerveModuleState, NumModules>,
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules>,
|
||||
wpi::util::array<SwerveModuleAcceleration, NumModules>> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "wpi/math/kinematics/Odometry3d.hpp"
|
||||
#include "wpi/math/kinematics/SwerveDriveKinematics.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModulePosition.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleState.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleVelocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
|
||||
namespace wpi::math {
|
||||
@@ -28,7 +28,7 @@ template <size_t NumModules>
|
||||
class SwerveDriveOdometry3d
|
||||
: public Odometry3d<
|
||||
wpi::util::array<SwerveModulePosition, NumModules>,
|
||||
wpi::util::array<SwerveModuleState, NumModules>,
|
||||
wpi::util::array<SwerveModuleVelocity, NumModules>,
|
||||
wpi::util::array<SwerveModuleAcceleration, NumModules>> {
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
|
||||
namespace wpi::math {
|
||||
/**
|
||||
* Represents the state of one swerve module.
|
||||
* Represents the velocity of one swerve module.
|
||||
*/
|
||||
struct WPILIB_DLLEXPORT SwerveModuleState {
|
||||
struct WPILIB_DLLEXPORT SwerveModuleVelocity {
|
||||
/**
|
||||
* Speed of the wheel of the module.
|
||||
* Velocity of the wheel of the module.
|
||||
*/
|
||||
wpi::units::meters_per_second_t speed = 0_mps;
|
||||
wpi::units::meters_per_second_t velocity = 0_mps;
|
||||
|
||||
/**
|
||||
* Angle of the module.
|
||||
@@ -26,18 +26,18 @@ struct WPILIB_DLLEXPORT SwerveModuleState {
|
||||
Rotation2d angle;
|
||||
|
||||
/**
|
||||
* Checks equality between this SwerveModuleState and another object.
|
||||
* Checks equality between this SwerveModuleVelocity and another object.
|
||||
*
|
||||
* @param other The other object.
|
||||
* @return Whether the two objects are equal.
|
||||
*/
|
||||
constexpr bool operator==(const SwerveModuleState& other) const {
|
||||
return wpi::units::math::abs(speed - other.speed) < 1E-9_mps &&
|
||||
constexpr bool operator==(const SwerveModuleVelocity& other) const {
|
||||
return wpi::units::math::abs(velocity - other.velocity) < 1E-9_mps &&
|
||||
angle == other.angle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimize the change in the heading this swerve module state would
|
||||
* Minimize the change in the heading this swerve module velocity would
|
||||
* require by potentially reversing the direction the wheel spins. If this is
|
||||
* used with the PIDController class's continuous input functionality, the
|
||||
* furthest a wheel will ever rotate is 90 degrees.
|
||||
@@ -47,43 +47,45 @@ struct WPILIB_DLLEXPORT SwerveModuleState {
|
||||
constexpr void Optimize(const Rotation2d& currentAngle) {
|
||||
auto delta = angle - currentAngle;
|
||||
if (wpi::units::math::abs(delta.Degrees()) > 90_deg) {
|
||||
speed *= -1;
|
||||
velocity *= -1;
|
||||
angle = angle + Rotation2d{180_deg};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimize the change in heading the desired swerve module state would
|
||||
* Minimize the change in heading the desired swerve module velocity would
|
||||
* require by potentially reversing the direction the wheel spins. If this is
|
||||
* used with the PIDController class's continuous input functionality, the
|
||||
* furthest a wheel will ever rotate is 90 degrees.
|
||||
*
|
||||
* @param desiredState The desired state.
|
||||
* @param desiredVelocity The desired velocity.
|
||||
* @param currentAngle The current module angle.
|
||||
*/
|
||||
[[deprecated("Use instance method instead.")]]
|
||||
constexpr static SwerveModuleState Optimize(
|
||||
const SwerveModuleState& desiredState, const Rotation2d& currentAngle) {
|
||||
auto delta = desiredState.angle - currentAngle;
|
||||
constexpr static SwerveModuleVelocity Optimize(
|
||||
const SwerveModuleVelocity& desiredVelocity,
|
||||
const Rotation2d& currentAngle) {
|
||||
auto delta = desiredVelocity.angle - currentAngle;
|
||||
if (wpi::units::math::abs(delta.Degrees()) > 90_deg) {
|
||||
return {-desiredState.speed, desiredState.angle + Rotation2d{180_deg}};
|
||||
return {-desiredVelocity.velocity,
|
||||
desiredVelocity.angle + Rotation2d{180_deg}};
|
||||
} else {
|
||||
return {desiredState.speed, desiredState.angle};
|
||||
return {desiredVelocity.velocity, desiredVelocity.angle};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scales speed by cosine of angle error. This scales down movement
|
||||
* Scales velocity by cosine of angle error. This scales down movement
|
||||
* perpendicular to the desired direction of travel that can occur when
|
||||
* modules change directions. This results in smoother driving.
|
||||
*
|
||||
* @param currentAngle The current module angle.
|
||||
*/
|
||||
constexpr void CosineScale(const Rotation2d& currentAngle) {
|
||||
speed *= (angle - currentAngle).Cos();
|
||||
velocity *= (angle - currentAngle).Cos();
|
||||
}
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
#include "wpi/math/kinematics/proto/SwerveModuleStateProto.hpp"
|
||||
#include "wpi/math/kinematics/struct/SwerveModuleStateStruct.hpp"
|
||||
#include "wpi/math/kinematics/proto/SwerveModuleVelocityProto.hpp"
|
||||
#include "wpi/math/kinematics/struct/SwerveModuleVelocityStruct.hpp"
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/ChassisSpeeds.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/protobuf/Protobuf.hpp"
|
||||
#include "wpimath/protobuf/kinematics.npb.h"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT wpi::util::Protobuf<wpi::math::ChassisSpeeds> {
|
||||
using MessageStruct = wpi_proto_ProtobufChassisSpeeds;
|
||||
using InputStream = wpi::util::ProtoInputStream<wpi::math::ChassisSpeeds>;
|
||||
using OutputStream = wpi::util::ProtoOutputStream<wpi::math::ChassisSpeeds>;
|
||||
static std::optional<wpi::math::ChassisSpeeds> Unpack(InputStream& stream);
|
||||
static bool Pack(OutputStream& stream, const wpi::math::ChassisSpeeds& value);
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/ChassisVelocities.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/protobuf/Protobuf.hpp"
|
||||
#include "wpimath/protobuf/kinematics.npb.h"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT wpi::util::Protobuf<wpi::math::ChassisVelocities> {
|
||||
using MessageStruct = wpi_proto_ProtobufChassisVelocities;
|
||||
using InputStream = wpi::util::ProtoInputStream<wpi::math::ChassisVelocities>;
|
||||
using OutputStream =
|
||||
wpi::util::ProtoOutputStream<wpi::math::ChassisVelocities>;
|
||||
static std::optional<wpi::math::ChassisVelocities> Unpack(
|
||||
InputStream& stream);
|
||||
static bool Pack(OutputStream& stream,
|
||||
const wpi::math::ChassisVelocities& value);
|
||||
};
|
||||
@@ -4,21 +4,21 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelVelocities.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/protobuf/Protobuf.hpp"
|
||||
#include "wpimath/protobuf/kinematics.npb.h"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT
|
||||
wpi::util::Protobuf<wpi::math::DifferentialDriveWheelSpeeds> {
|
||||
using MessageStruct = wpi_proto_ProtobufDifferentialDriveWheelSpeeds;
|
||||
wpi::util::Protobuf<wpi::math::DifferentialDriveWheelVelocities> {
|
||||
using MessageStruct = wpi_proto_ProtobufDifferentialDriveWheelVelocities;
|
||||
using InputStream =
|
||||
wpi::util::ProtoInputStream<wpi::math::DifferentialDriveWheelSpeeds>;
|
||||
wpi::util::ProtoInputStream<wpi::math::DifferentialDriveWheelVelocities>;
|
||||
using OutputStream =
|
||||
wpi::util::ProtoOutputStream<wpi::math::DifferentialDriveWheelSpeeds>;
|
||||
static std::optional<wpi::math::DifferentialDriveWheelSpeeds> Unpack(
|
||||
wpi::util::ProtoOutputStream<wpi::math::DifferentialDriveWheelVelocities>;
|
||||
static std::optional<wpi::math::DifferentialDriveWheelVelocities> Unpack(
|
||||
InputStream& stream);
|
||||
static bool Pack(OutputStream& stream,
|
||||
const wpi::math::DifferentialDriveWheelSpeeds& value);
|
||||
const wpi::math::DifferentialDriveWheelVelocities& value);
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelSpeeds.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/protobuf/Protobuf.hpp"
|
||||
#include "wpimath/protobuf/kinematics.npb.h"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT
|
||||
wpi::util::Protobuf<wpi::math::MecanumDriveWheelSpeeds> {
|
||||
using MessageStruct = wpi_proto_ProtobufMecanumDriveWheelSpeeds;
|
||||
using InputStream =
|
||||
wpi::util::ProtoInputStream<wpi::math::MecanumDriveWheelSpeeds>;
|
||||
using OutputStream =
|
||||
wpi::util::ProtoOutputStream<wpi::math::MecanumDriveWheelSpeeds>;
|
||||
static std::optional<wpi::math::MecanumDriveWheelSpeeds> Unpack(
|
||||
InputStream& stream);
|
||||
static bool Pack(OutputStream& stream,
|
||||
const wpi::math::MecanumDriveWheelSpeeds& value);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelVelocities.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/protobuf/Protobuf.hpp"
|
||||
#include "wpimath/protobuf/kinematics.npb.h"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT
|
||||
wpi::util::Protobuf<wpi::math::MecanumDriveWheelVelocities> {
|
||||
using MessageStruct = wpi_proto_ProtobufMecanumDriveWheelVelocities;
|
||||
using InputStream =
|
||||
wpi::util::ProtoInputStream<wpi::math::MecanumDriveWheelVelocities>;
|
||||
using OutputStream =
|
||||
wpi::util::ProtoOutputStream<wpi::math::MecanumDriveWheelVelocities>;
|
||||
static std::optional<wpi::math::MecanumDriveWheelVelocities> Unpack(
|
||||
InputStream& stream);
|
||||
static bool Pack(OutputStream& stream,
|
||||
const wpi::math::MecanumDriveWheelVelocities& value);
|
||||
};
|
||||
@@ -4,19 +4,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/SwerveModuleState.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleVelocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/protobuf/Protobuf.hpp"
|
||||
#include "wpimath/protobuf/kinematics.npb.h"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT wpi::util::Protobuf<wpi::math::SwerveModuleState> {
|
||||
using MessageStruct = wpi_proto_ProtobufSwerveModuleState;
|
||||
using InputStream = wpi::util::ProtoInputStream<wpi::math::SwerveModuleState>;
|
||||
struct WPILIB_DLLEXPORT wpi::util::Protobuf<wpi::math::SwerveModuleVelocity> {
|
||||
using MessageStruct = wpi_proto_ProtobufSwerveModuleVelocity;
|
||||
using InputStream =
|
||||
wpi::util::ProtoInputStream<wpi::math::SwerveModuleVelocity>;
|
||||
using OutputStream =
|
||||
wpi::util::ProtoOutputStream<wpi::math::SwerveModuleState>;
|
||||
static std::optional<wpi::math::SwerveModuleState> Unpack(
|
||||
wpi::util::ProtoOutputStream<wpi::math::SwerveModuleVelocity>;
|
||||
static std::optional<wpi::math::SwerveModuleVelocity> Unpack(
|
||||
InputStream& stream);
|
||||
static bool Pack(OutputStream& stream,
|
||||
const wpi::math::SwerveModuleState& value);
|
||||
const wpi::math::SwerveModuleVelocity& value);
|
||||
};
|
||||
@@ -4,21 +4,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/ChassisSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/ChassisVelocities.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/struct/Struct.hpp"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT wpi::util::Struct<wpi::math::ChassisSpeeds> {
|
||||
static constexpr std::string_view GetTypeName() { return "ChassisSpeeds"; }
|
||||
struct WPILIB_DLLEXPORT wpi::util::Struct<wpi::math::ChassisVelocities> {
|
||||
static constexpr std::string_view GetTypeName() {
|
||||
return "ChassisVelocities";
|
||||
}
|
||||
static constexpr size_t GetSize() { return 24; }
|
||||
static constexpr std::string_view GetSchema() {
|
||||
return "double vx;double vy;double omega";
|
||||
}
|
||||
|
||||
static wpi::math::ChassisSpeeds Unpack(std::span<const uint8_t> data);
|
||||
static wpi::math::ChassisVelocities Unpack(std::span<const uint8_t> data);
|
||||
static void Pack(std::span<uint8_t> data,
|
||||
const wpi::math::ChassisSpeeds& value);
|
||||
const wpi::math::ChassisVelocities& value);
|
||||
};
|
||||
|
||||
static_assert(wpi::util::StructSerializable<wpi::math::ChassisSpeeds>);
|
||||
static_assert(wpi::util::StructSerializable<wpi::math::ChassisVelocities>);
|
||||
@@ -4,26 +4,26 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/DifferentialDriveWheelVelocities.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/struct/Struct.hpp"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT
|
||||
wpi::util::Struct<wpi::math::DifferentialDriveWheelSpeeds> {
|
||||
wpi::util::Struct<wpi::math::DifferentialDriveWheelVelocities> {
|
||||
static constexpr std::string_view GetTypeName() {
|
||||
return "DifferentialDriveWheelSpeeds";
|
||||
return "DifferentialDriveWheelVelocities";
|
||||
}
|
||||
static constexpr size_t GetSize() { return 16; }
|
||||
static constexpr std::string_view GetSchema() {
|
||||
return "double left;double right";
|
||||
}
|
||||
|
||||
static wpi::math::DifferentialDriveWheelSpeeds Unpack(
|
||||
static wpi::math::DifferentialDriveWheelVelocities Unpack(
|
||||
std::span<const uint8_t> data);
|
||||
static void Pack(std::span<uint8_t> data,
|
||||
const wpi::math::DifferentialDriveWheelSpeeds& value);
|
||||
const wpi::math::DifferentialDriveWheelVelocities& value);
|
||||
};
|
||||
|
||||
static_assert(
|
||||
wpi::util::StructSerializable<wpi::math::DifferentialDriveWheelSpeeds>);
|
||||
wpi::util::StructSerializable<wpi::math::DifferentialDriveWheelVelocities>);
|
||||
@@ -4,14 +4,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelSpeeds.hpp"
|
||||
#include "wpi/math/kinematics/MecanumDriveWheelVelocities.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/struct/Struct.hpp"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT wpi::util::Struct<wpi::math::MecanumDriveWheelSpeeds> {
|
||||
struct WPILIB_DLLEXPORT
|
||||
wpi::util::Struct<wpi::math::MecanumDriveWheelVelocities> {
|
||||
static constexpr std::string_view GetTypeName() {
|
||||
return "MecanumDriveWheelSpeeds";
|
||||
return "MecanumDriveWheelVelocities";
|
||||
}
|
||||
static constexpr size_t GetSize() { return 32; }
|
||||
static constexpr std::string_view GetSchema() {
|
||||
@@ -19,11 +20,11 @@ struct WPILIB_DLLEXPORT wpi::util::Struct<wpi::math::MecanumDriveWheelSpeeds> {
|
||||
"double rear_right";
|
||||
}
|
||||
|
||||
static wpi::math::MecanumDriveWheelSpeeds Unpack(
|
||||
static wpi::math::MecanumDriveWheelVelocities Unpack(
|
||||
std::span<const uint8_t> data);
|
||||
static void Pack(std::span<uint8_t> data,
|
||||
const wpi::math::MecanumDriveWheelSpeeds& value);
|
||||
const wpi::math::MecanumDriveWheelVelocities& value);
|
||||
};
|
||||
|
||||
static_assert(
|
||||
wpi::util::StructSerializable<wpi::math::MecanumDriveWheelSpeeds>);
|
||||
wpi::util::StructSerializable<wpi::math::MecanumDriveWheelVelocities>);
|
||||
@@ -4,30 +4,30 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "wpi/math/kinematics/SwerveModuleState.hpp"
|
||||
#include "wpi/math/kinematics/SwerveModuleVelocity.hpp"
|
||||
#include "wpi/util/SymbolExports.hpp"
|
||||
#include "wpi/util/struct/Struct.hpp"
|
||||
|
||||
template <>
|
||||
struct WPILIB_DLLEXPORT wpi::util::Struct<wpi::math::SwerveModuleState> {
|
||||
struct WPILIB_DLLEXPORT wpi::util::Struct<wpi::math::SwerveModuleVelocity> {
|
||||
static constexpr std::string_view GetTypeName() {
|
||||
return "SwerveModuleState";
|
||||
return "SwerveModuleVelocity";
|
||||
}
|
||||
static constexpr size_t GetSize() {
|
||||
return 8 + wpi::util::GetStructSize<wpi::math::Rotation2d>();
|
||||
}
|
||||
static constexpr std::string_view GetSchema() {
|
||||
return "double speed;Rotation2d angle";
|
||||
return "double velocity;Rotation2d angle";
|
||||
}
|
||||
|
||||
static wpi::math::SwerveModuleState Unpack(std::span<const uint8_t> data);
|
||||
static wpi::math::SwerveModuleVelocity Unpack(std::span<const uint8_t> data);
|
||||
static void Pack(std::span<uint8_t> data,
|
||||
const wpi::math::SwerveModuleState& value);
|
||||
const wpi::math::SwerveModuleVelocity& value);
|
||||
static void ForEachNested(
|
||||
std::invocable<std::string_view, std::string_view> auto fn) {
|
||||
wpi::util::ForEachStructSchema<wpi::math::Rotation2d>(fn);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(wpi::util::StructSerializable<wpi::math::SwerveModuleState>);
|
||||
static_assert(wpi::util::HasNestedStruct<wpi::math::SwerveModuleState>);
|
||||
static_assert(wpi::util::StructSerializable<wpi::math::SwerveModuleVelocity>);
|
||||
static_assert(wpi::util::HasNestedStruct<wpi::math::SwerveModuleVelocity>);
|
||||
@@ -53,11 +53,11 @@ class WPILIB_DLLEXPORT DCMotor {
|
||||
* Constructs a DC motor.
|
||||
*
|
||||
* @param nominalVoltage Voltage at which the motor constants were measured.
|
||||
* @param stallTorque Torque when stalled.
|
||||
* @param stallCurrent Current draw when stalled.
|
||||
* @param freeCurrent Current draw under no load.
|
||||
* @param freeSpeed Angular velocity under no load.
|
||||
* @param numMotors Number of motors in a gearbox.
|
||||
* @param stallTorque Torque when stalled.
|
||||
* @param stallCurrent Current draw when stalled.
|
||||
* @param freeCurrent Current draw under no load.
|
||||
* @param freeSpeed Angular velocity under no load.
|
||||
* @param numMotors Number of motors in a gearbox.
|
||||
*/
|
||||
constexpr DCMotor(wpi::units::volt_t nominalVoltage,
|
||||
wpi::units::newton_meter_t stallTorque,
|
||||
@@ -75,15 +75,15 @@ class WPILIB_DLLEXPORT DCMotor {
|
||||
Kt(this->stallTorque / this->stallCurrent) {}
|
||||
|
||||
/**
|
||||
* Returns current drawn by motor with given speed and input voltage.
|
||||
* Returns current drawn by motor with given velocity and input voltage.
|
||||
*
|
||||
* @param speed The current angular velocity of the motor.
|
||||
* @param velocity The current angular velocity of the motor.
|
||||
* @param inputVoltage The voltage being applied to the motor.
|
||||
*/
|
||||
constexpr wpi::units::ampere_t Current(
|
||||
wpi::units::radians_per_second_t speed,
|
||||
wpi::units::radians_per_second_t velocity,
|
||||
wpi::units::volt_t inputVoltage) const {
|
||||
return -1.0 / Kv / R * speed + 1.0 / R * inputVoltage;
|
||||
return -1.0 / Kv / R * velocity + 1.0 / R * inputVoltage;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +99,7 @@ class WPILIB_DLLEXPORT DCMotor {
|
||||
/**
|
||||
* Returns torque produced by the motor with a given current.
|
||||
*
|
||||
* @param current The current drawn by the motor.
|
||||
* @param current The current drawn by the motor.
|
||||
*/
|
||||
constexpr wpi::units::newton_meter_t Torque(
|
||||
wpi::units::ampere_t current) const {
|
||||
@@ -110,23 +110,23 @@ class WPILIB_DLLEXPORT DCMotor {
|
||||
* Returns the voltage provided to the motor for a given torque and
|
||||
* angular velocity.
|
||||
*
|
||||
* @param torque The torque produced by the motor.
|
||||
* @param speed The current angular velocity of the motor.
|
||||
* @param torque The torque produced by the motor.
|
||||
* @param velocity The current angular velocity of the motor.
|
||||
*/
|
||||
constexpr wpi::units::volt_t Voltage(
|
||||
wpi::units::newton_meter_t torque,
|
||||
wpi::units::radians_per_second_t speed) const {
|
||||
return 1.0 / Kv * speed + 1.0 / Kt * R * torque;
|
||||
wpi::units::radians_per_second_t velocity) const {
|
||||
return 1.0 / Kv * velocity + 1.0 / Kt * R * torque;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the angular speed produced by the motor at a given torque and input
|
||||
* voltage.
|
||||
* Returns the angular velocity produced by the motor at a given torque and
|
||||
* input voltage.
|
||||
*
|
||||
* @param torque The torque produced by the motor.
|
||||
* @param inputVoltage The input voltage provided to the motor.
|
||||
* @param torque The torque produced by the motor.
|
||||
* @param inputVoltage The input voltage provided to the motor.
|
||||
*/
|
||||
constexpr wpi::units::radians_per_second_t Speed(
|
||||
constexpr wpi::units::radians_per_second_t Velocity(
|
||||
wpi::units::newton_meter_t torque,
|
||||
wpi::units::volt_t inputVoltage) const {
|
||||
return inputVoltage * Kv - 1.0 / Kt * torque * R * Kv;
|
||||
@@ -135,7 +135,7 @@ class WPILIB_DLLEXPORT DCMotor {
|
||||
/**
|
||||
* Returns a copy of this motor with the given gearbox reduction applied.
|
||||
*
|
||||
* @param gearboxReduction The gearbox reduction.
|
||||
* @param gearboxReduction The gearbox reduction.
|
||||
*/
|
||||
constexpr DCMotor WithReduction(double gearboxReduction) {
|
||||
return DCMotor(nominalVoltage, stallTorque * gearboxReduction, stallCurrent,
|
||||
|
||||
@@ -34,7 +34,7 @@ class WPILIB_DLLEXPORT Trajectory {
|
||||
/// The time elapsed since the beginning of the trajectory.
|
||||
wpi::units::second_t t = 0_s;
|
||||
|
||||
/// The speed at that point of the trajectory.
|
||||
/// The velocity at that point of the trajectory.
|
||||
wpi::units::meters_per_second_t velocity = 0_mps;
|
||||
|
||||
/// The acceleration at that point of the trajectory.
|
||||
|
||||
@@ -161,27 +161,28 @@ class TrapezoidProfile {
|
||||
wpi::units::second_t accelerationTime =
|
||||
m_constraints.maxVelocity / m_constraints.maxAcceleration;
|
||||
|
||||
Distance_t fullSpeedDist =
|
||||
Distance_t fullVelocityDist =
|
||||
fullTrapezoidDist -
|
||||
accelerationTime * accelerationTime * m_constraints.maxAcceleration;
|
||||
|
||||
// Handle the case where the profile never reaches full speed
|
||||
if (fullSpeedDist < Distance_t{0}) {
|
||||
// Handle the case where the profile never reaches full velocity
|
||||
if (fullVelocityDist < Distance_t{0}) {
|
||||
accelerationTime = wpi::units::math::sqrt(fullTrapezoidDist /
|
||||
m_constraints.maxAcceleration);
|
||||
fullSpeedDist = Distance_t{0};
|
||||
fullVelocityDist = Distance_t{0};
|
||||
}
|
||||
|
||||
m_endAccel = accelerationTime - cutoffBegin;
|
||||
m_endFullSpeed = m_endAccel + fullSpeedDist / m_constraints.maxVelocity;
|
||||
m_endDecel = m_endFullSpeed + accelerationTime - cutoffEnd;
|
||||
m_endFullVelocity =
|
||||
m_endAccel + fullVelocityDist / m_constraints.maxVelocity;
|
||||
m_endDecel = m_endFullVelocity + accelerationTime - cutoffEnd;
|
||||
State result = m_current;
|
||||
|
||||
if (t < m_endAccel) {
|
||||
result.velocity += t * m_constraints.maxAcceleration;
|
||||
result.position +=
|
||||
(m_current.velocity + t * m_constraints.maxAcceleration / 2.0) * t;
|
||||
} else if (t < m_endFullSpeed) {
|
||||
} else if (t < m_endFullVelocity) {
|
||||
result.velocity = m_constraints.maxVelocity;
|
||||
result.position += (m_current.velocity +
|
||||
m_endAccel * m_constraints.maxAcceleration / 2.0) *
|
||||
@@ -214,16 +215,17 @@ class TrapezoidProfile {
|
||||
Velocity_t velocity = m_current.velocity * m_direction;
|
||||
|
||||
wpi::units::second_t endAccel = m_endAccel * m_direction;
|
||||
wpi::units::second_t endFullSpeed = m_endFullSpeed * m_direction - endAccel;
|
||||
wpi::units::second_t endFullVelocity =
|
||||
m_endFullVelocity * m_direction - endAccel;
|
||||
|
||||
if (target < position) {
|
||||
endAccel *= -1.0;
|
||||
endFullSpeed *= -1.0;
|
||||
endFullVelocity *= -1.0;
|
||||
velocity *= -1.0;
|
||||
}
|
||||
|
||||
endAccel = wpi::units::math::max(endAccel, 0_s);
|
||||
endFullSpeed = wpi::units::math::max(endFullSpeed, 0_s);
|
||||
endFullVelocity = wpi::units::math::max(endFullVelocity, 0_s);
|
||||
|
||||
const Acceleration_t acceleration = m_constraints.maxAcceleration;
|
||||
const Acceleration_t deceleration = -m_constraints.maxAcceleration;
|
||||
@@ -245,18 +247,18 @@ class TrapezoidProfile {
|
||||
decelVelocity = velocity;
|
||||
}
|
||||
|
||||
Distance_t fullSpeedDist = m_constraints.maxVelocity * endFullSpeed;
|
||||
Distance_t fullVelocityDist = m_constraints.maxVelocity * endFullVelocity;
|
||||
Distance_t decelDist;
|
||||
|
||||
if (accelDist > distToTarget) {
|
||||
accelDist = distToTarget;
|
||||
fullSpeedDist = Distance_t{0};
|
||||
fullVelocityDist = Distance_t{0};
|
||||
decelDist = Distance_t{0};
|
||||
} else if (accelDist + fullSpeedDist > distToTarget) {
|
||||
fullSpeedDist = distToTarget - accelDist;
|
||||
} else if (accelDist + fullVelocityDist > distToTarget) {
|
||||
fullVelocityDist = distToTarget - accelDist;
|
||||
decelDist = Distance_t{0};
|
||||
} else {
|
||||
decelDist = distToTarget - fullSpeedDist - accelDist;
|
||||
decelDist = distToTarget - fullVelocityDist - accelDist;
|
||||
}
|
||||
|
||||
wpi::units::second_t accelTime =
|
||||
@@ -270,10 +272,10 @@ class TrapezoidProfile {
|
||||
decelVelocity * decelVelocity + 2 * deceleration * decelDist))) /
|
||||
deceleration;
|
||||
|
||||
wpi::units::second_t fullSpeedTime =
|
||||
fullSpeedDist / m_constraints.maxVelocity;
|
||||
wpi::units::second_t fullVelocityTime =
|
||||
fullVelocityDist / m_constraints.maxVelocity;
|
||||
|
||||
return accelTime + fullSpeedTime + decelTime;
|
||||
return accelTime + fullVelocityTime + decelTime;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,7 +328,7 @@ class TrapezoidProfile {
|
||||
State m_current;
|
||||
|
||||
wpi::units::second_t m_endAccel = 0_s;
|
||||
wpi::units::second_t m_endFullSpeed = 0_s;
|
||||
wpi::units::second_t m_endFullVelocity = 0_s;
|
||||
wpi::units::second_t m_endDecel = 0_s;
|
||||
};
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class WPILIB_DLLEXPORT CentripetalAccelerationConstraint
|
||||
|
||||
constexpr MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const override {
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
// The acceleration of the robot has no impact on the centripetal
|
||||
// acceleration of the robot.
|
||||
return {};
|
||||
|
||||
@@ -23,27 +23,27 @@ class WPILIB_DLLEXPORT DifferentialDriveKinematicsConstraint
|
||||
public:
|
||||
constexpr DifferentialDriveKinematicsConstraint(
|
||||
DifferentialDriveKinematics kinematics,
|
||||
wpi::units::meters_per_second_t maxSpeed)
|
||||
: m_kinematics(std::move(kinematics)), m_maxSpeed(maxSpeed) {}
|
||||
wpi::units::meters_per_second_t maxVelocity)
|
||||
: m_kinematics(std::move(kinematics)), m_maxVelocity(maxVelocity) {}
|
||||
|
||||
constexpr wpi::units::meters_per_second_t MaxVelocity(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
auto wheelSpeeds =
|
||||
m_kinematics.ToWheelSpeeds({velocity, 0_mps, velocity * curvature});
|
||||
wheelSpeeds.Desaturate(m_maxSpeed);
|
||||
auto wheelVelocities =
|
||||
m_kinematics.ToWheelVelocities({velocity, 0_mps, velocity * curvature});
|
||||
wheelVelocities.Desaturate(m_maxVelocity);
|
||||
|
||||
return m_kinematics.ToChassisSpeeds(wheelSpeeds).vx;
|
||||
return m_kinematics.ToChassisVelocities(wheelVelocities).vx;
|
||||
}
|
||||
|
||||
constexpr MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const override {
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
DifferentialDriveKinematics m_kinematics;
|
||||
wpi::units::meters_per_second_t m_maxSpeed;
|
||||
wpi::units::meters_per_second_t m_maxVelocity;
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
@@ -52,19 +52,21 @@ class WPILIB_DLLEXPORT DifferentialDriveVoltageConstraint
|
||||
|
||||
constexpr MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const override {
|
||||
auto wheelSpeeds =
|
||||
m_kinematics.ToWheelSpeeds({speed, 0_mps, speed * curvature});
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
auto wheelVelocities =
|
||||
m_kinematics.ToWheelVelocities({velocity, 0_mps, velocity * curvature});
|
||||
|
||||
auto maxWheelSpeed = (std::max)(wheelSpeeds.left, wheelSpeeds.right);
|
||||
auto minWheelSpeed = (std::min)(wheelSpeeds.left, wheelSpeeds.right);
|
||||
auto maxWheelVelocity =
|
||||
(std::max)(wheelVelocities.left, wheelVelocities.right);
|
||||
auto minWheelVelocity =
|
||||
(std::min)(wheelVelocities.left, wheelVelocities.right);
|
||||
|
||||
// Calculate maximum/minimum possible accelerations from motor dynamics
|
||||
// and max/min wheel speeds
|
||||
// and max/min wheel velocities
|
||||
auto maxWheelAcceleration =
|
||||
m_feedforward.MaxAchievableAcceleration(m_maxVoltage, maxWheelSpeed);
|
||||
m_feedforward.MaxAchievableAcceleration(m_maxVoltage, maxWheelVelocity);
|
||||
auto minWheelAcceleration =
|
||||
m_feedforward.MinAchievableAcceleration(m_maxVoltage, minWheelSpeed);
|
||||
m_feedforward.MinAchievableAcceleration(m_maxVoltage, minWheelVelocity);
|
||||
|
||||
// Robot chassis turning on radius = 1/|curvature|. Outer wheel has radius
|
||||
// increased by half of the trackwidth T. Inner wheel has radius decreased
|
||||
@@ -72,7 +74,7 @@ class WPILIB_DLLEXPORT DifferentialDriveVoltageConstraint
|
||||
// so Achassis = Aouter * radius / (radius + T/2) = Aouter / (1 +
|
||||
// |curvature|T/2). Inner wheel is similar.
|
||||
|
||||
// sgn(speed) term added to correctly account for which wheel is on
|
||||
// sgn(velocity) term added to correctly account for which wheel is on
|
||||
// outside of turn:
|
||||
// If moving forward, max acceleration constraint corresponds to wheel on
|
||||
// outside of turn If moving backward, max acceleration constraint
|
||||
@@ -86,7 +88,7 @@ class WPILIB_DLLEXPORT DifferentialDriveVoltageConstraint
|
||||
wpi::units::meters_per_second_squared_t maxChassisAcceleration;
|
||||
wpi::units::meters_per_second_squared_t minChassisAcceleration;
|
||||
|
||||
if (speed == 0_mps) {
|
||||
if (velocity == 0_mps) {
|
||||
maxChassisAcceleration =
|
||||
maxWheelAcceleration /
|
||||
(1 + m_kinematics.trackwidth * wpi::units::math::abs(curvature) /
|
||||
@@ -99,11 +101,11 @@ class WPILIB_DLLEXPORT DifferentialDriveVoltageConstraint
|
||||
maxChassisAcceleration =
|
||||
maxWheelAcceleration /
|
||||
(1 + m_kinematics.trackwidth * wpi::units::math::abs(curvature) *
|
||||
wpi::util::sgn(speed) / (2_rad));
|
||||
wpi::util::sgn(velocity) / (2_rad));
|
||||
minChassisAcceleration =
|
||||
minWheelAcceleration /
|
||||
(1 - m_kinematics.trackwidth * wpi::units::math::abs(curvature) *
|
||||
wpi::util::sgn(speed) / (2_rad));
|
||||
wpi::util::sgn(velocity) / (2_rad));
|
||||
}
|
||||
|
||||
// When turning about a point inside of the wheelbase (i.e. radius less than
|
||||
@@ -114,9 +116,9 @@ class WPILIB_DLLEXPORT DifferentialDriveVoltageConstraint
|
||||
|
||||
if ((m_kinematics.trackwidth / 2) >
|
||||
1_rad / wpi::units::math::abs(curvature)) {
|
||||
if (speed > 0_mps) {
|
||||
if (velocity > 0_mps) {
|
||||
minChassisAcceleration = -minChassisAcceleration;
|
||||
} else if (speed < 0_mps) {
|
||||
} else if (velocity < 0_mps) {
|
||||
maxChassisAcceleration = -maxChassisAcceleration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,9 +65,9 @@ class EllipticalRegionConstraint : public TrajectoryConstraint {
|
||||
|
||||
constexpr MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const override {
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
if (m_ellipse.Contains(pose.Translation())) {
|
||||
return m_constraint.MinMaxAcceleration(pose, curvature, speed);
|
||||
return m_constraint.MinMaxAcceleration(pose, curvature, velocity);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class WPILIB_DLLEXPORT MaxVelocityConstraint : public TrajectoryConstraint {
|
||||
|
||||
constexpr MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const override {
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -21,31 +21,32 @@ class WPILIB_DLLEXPORT MecanumDriveKinematicsConstraint
|
||||
: public TrajectoryConstraint {
|
||||
public:
|
||||
MecanumDriveKinematicsConstraint(const MecanumDriveKinematics& kinematics,
|
||||
wpi::units::meters_per_second_t maxSpeed)
|
||||
: m_kinematics(kinematics), m_maxSpeed(maxSpeed) {}
|
||||
wpi::units::meters_per_second_t maxVelocity)
|
||||
: m_kinematics(kinematics), m_maxVelocity(maxVelocity) {}
|
||||
|
||||
wpi::units::meters_per_second_t MaxVelocity(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
auto xVelocity = velocity * pose.Rotation().Cos();
|
||||
auto yVelocity = velocity * pose.Rotation().Sin();
|
||||
auto wheelSpeeds =
|
||||
m_kinematics.ToWheelSpeeds({xVelocity, yVelocity, velocity * curvature})
|
||||
.Desaturate(m_maxSpeed);
|
||||
auto wheelVelocities =
|
||||
m_kinematics
|
||||
.ToWheelVelocities({xVelocity, yVelocity, velocity * curvature})
|
||||
.Desaturate(m_maxVelocity);
|
||||
|
||||
auto normSpeeds = m_kinematics.ToChassisSpeeds(wheelSpeeds);
|
||||
auto normVelocities = m_kinematics.ToChassisVelocities(wheelVelocities);
|
||||
|
||||
return wpi::units::math::hypot(normSpeeds.vx, normSpeeds.vy);
|
||||
return wpi::units::math::hypot(normVelocities.vx, normVelocities.vy);
|
||||
}
|
||||
|
||||
MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const override {
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
MecanumDriveKinematics m_kinematics;
|
||||
wpi::units::meters_per_second_t m_maxSpeed;
|
||||
wpi::units::meters_per_second_t m_maxVelocity;
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
@@ -60,9 +60,9 @@ class RectangularRegionConstraint : public TrajectoryConstraint {
|
||||
|
||||
constexpr MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const override {
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
if (m_rectangle.Contains(pose.Translation())) {
|
||||
return m_constraint.MinMaxAcceleration(pose, curvature, speed);
|
||||
return m_constraint.MinMaxAcceleration(pose, curvature, velocity);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -21,32 +21,32 @@ class SwerveDriveKinematicsConstraint : public TrajectoryConstraint {
|
||||
public:
|
||||
SwerveDriveKinematicsConstraint(
|
||||
const wpi::math::SwerveDriveKinematics<NumModules>& kinematics,
|
||||
wpi::units::meters_per_second_t maxSpeed)
|
||||
: m_kinematics(kinematics), m_maxSpeed(maxSpeed) {}
|
||||
wpi::units::meters_per_second_t maxVelocity)
|
||||
: m_kinematics(kinematics), m_maxVelocity(maxVelocity) {}
|
||||
|
||||
wpi::units::meters_per_second_t MaxVelocity(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
auto xVelocity = velocity * pose.Rotation().Cos();
|
||||
auto yVelocity = velocity * pose.Rotation().Sin();
|
||||
auto wheelSpeeds = m_kinematics.ToSwerveModuleStates(
|
||||
auto wheelVelocities = m_kinematics.ToSwerveModuleVelocities(
|
||||
{xVelocity, yVelocity, velocity * curvature});
|
||||
m_kinematics.DesaturateWheelSpeeds(&wheelSpeeds, m_maxSpeed);
|
||||
m_kinematics.DesaturateWheelVelocities(&wheelVelocities, m_maxVelocity);
|
||||
|
||||
auto normSpeeds = m_kinematics.ToChassisSpeeds(wheelSpeeds);
|
||||
auto normVelocities = m_kinematics.ToChassisVelocities(wheelVelocities);
|
||||
|
||||
return wpi::units::math::hypot(normSpeeds.vx, normSpeeds.vy);
|
||||
return wpi::units::math::hypot(normVelocities.vx, normVelocities.vy);
|
||||
}
|
||||
|
||||
MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const override {
|
||||
wpi::units::meters_per_second_t velocity) const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
wpi::math::SwerveDriveKinematics<NumModules> m_kinematics;
|
||||
wpi::units::meters_per_second_t m_maxSpeed;
|
||||
wpi::units::meters_per_second_t m_maxVelocity;
|
||||
};
|
||||
|
||||
} // namespace wpi::math
|
||||
|
||||
@@ -63,16 +63,16 @@ class WPILIB_DLLEXPORT TrajectoryConstraint {
|
||||
|
||||
/**
|
||||
* Returns the minimum and maximum allowable acceleration for the trajectory
|
||||
* given pose, curvature, and speed.
|
||||
* given pose, curvature, and velocity.
|
||||
*
|
||||
* @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.
|
||||
* @param velocity The velocity at the current point in the trajectory.
|
||||
*
|
||||
* @return The min and max acceleration bounds.
|
||||
*/
|
||||
constexpr virtual MinMax MinMaxAcceleration(
|
||||
const Pose2d& pose, wpi::units::curvature_t curvature,
|
||||
wpi::units::meters_per_second_t speed) const = 0;
|
||||
wpi::units::meters_per_second_t velocity) const = 0;
|
||||
};
|
||||
} // namespace wpi::math
|
||||
|
||||
@@ -54,7 +54,7 @@ using PI = unit<std::ratio<1>, dimensionless::scalar, std::ratio<1>>;
|
||||
static constexpr const unit_t<PI> pi(
|
||||
1); ///< Ratio of a circle's circumference to its diameter.
|
||||
static constexpr const velocity::meters_per_second_t c(
|
||||
299792458.0); ///< Speed of light in vacuum.
|
||||
299792458.0); ///< Velocity of light in vacuum.
|
||||
static constexpr const unit_t<
|
||||
compound_unit<cubed<length::meters>, inverse<mass::kilogram>,
|
||||
inverse<squared<time::seconds>>>>
|
||||
|
||||
Reference in New Issue
Block a user