blob: 034f72ff0f1d5f7d7e2b51b233731ba4495b5ccc [file] [log] [blame]
#ifndef Y2022_CONTROL_LOOPS_SUPERSTRUCTURE_COLLISION_AVOIDENCE_H_
#define Y2022_CONTROL_LOOPS_SUPERSTRUCTURE_COLLISION_AVOIDENCE_H_
#include <cmath>
#include "frc971/control_loops/control_loops_generated.h"
#include "frc971/control_loops/profiled_subsystem_generated.h"
#include "y2022/control_loops/superstructure/superstructure_goal_generated.h"
#include "y2022/control_loops/superstructure/superstructure_status_generated.h"
namespace y2022::control_loops::superstructure {
// Returns the wrapped angle as well as number of wraps (positive or negative).
// The returned angle will be inside [0.0, 2 * M_PI).
std::pair<double, int> WrapTurretAngle(double turret_angle);
// Returns the absolute angle given the wrapped angle and number of wraps.
double UnwrapTurretAngle(double wrapped, int wraps);
// Checks if theta is between theta_min and theta_max. Expects all angles to be
// wrapped from 0 to 2pi
bool AngleInRange(double theta, double theta_min, double theta_max);
// 1. Prevent the turret from moving if the intake is up
// and prevent the back of the turret (where the catapult is)
// from colliding with the intake when it's up.
// 2. If the intake is up, drop it so it is not in the way
// 3. Move the turret to the desired position.
// 4. When the turret moves away, if the intake is down, move it back up.
class CollisionAvoidance {
public:
struct Status {
double intake_front_position;
double intake_back_position;
double turret_position;
bool shooting;
bool operator==(const Status &s) const {
return (intake_front_position == s.intake_front_position &&
intake_back_position == s.intake_back_position &&
turret_position == s.turret_position && shooting == s.shooting);
}
bool operator!=(const Status &s) const { return !(*this == s); }
};
// TODO(henry): put actual constants here.
// Reference angles between which the turret will be careful
static constexpr double kCollisionZoneTurret = M_PI * 7.0 / 18.0;
// For the turret, 0 rad is pointing straight forwards
static constexpr double kMinCollisionZoneFrontTurret =
M_PI - kCollisionZoneTurret;
static constexpr double kMaxCollisionZoneFrontTurret =
M_PI + kCollisionZoneTurret;
static constexpr double kMinCollisionZoneBackTurret =
(2.0 * M_PI) - kCollisionZoneTurret;
static constexpr double kMaxCollisionZoneBackTurret = kCollisionZoneTurret;
// Maximum position of the intake to avoid collisions
static constexpr double kCollisionZoneIntake = 1.30;
// Tolerances for the subsystems
static constexpr double kEpsTurret = 0.05;
static constexpr double kEpsIntake = 0.05;
CollisionAvoidance();
// Reports if the superstructure is collided.
bool IsCollided(const Status &status);
// Checks if there is a collision on either intake.
bool TurretCollided(double intake_position, double turret_position,
double min_turret_collision_position,
double max_turret_collision_position);
// Checks and alters goals to make sure they're safe.
void UpdateGoal(
const Status &status,
const frc971::control_loops::StaticZeroingSingleDOFProfiledSubsystemGoal
*unsafe_turret_goal);
// Limits if goal is in collision spots.
void CalculateAvoidance(bool intake_front, bool catapult,
double intake_position, double turret_position,
double turret_goal, double min_turret_collision_goal,
double max_turret_collision_goal);
// Returns the goals to give to the respective control loops in
// superstructure.
double min_turret_goal() const { return min_turret_goal_; }
double max_turret_goal() const { return max_turret_goal_; }
double min_intake_front_goal() const { return min_intake_front_goal_; }
double max_intake_front_goal() const { return max_intake_front_goal_; }
double min_intake_back_goal() const { return min_intake_back_goal_; }
double max_intake_back_goal() const { return max_intake_back_goal_; }
void update_max_turret_goal(double max_turret_goal) {
max_turret_goal_ = ::std::min(max_turret_goal, max_turret_goal_);
}
void update_min_turret_goal(double min_turret_goal) {
min_turret_goal_ = ::std::max(min_turret_goal, min_turret_goal_);
}
void update_max_intake_front_goal(double max_intake_front_goal) {
max_intake_front_goal_ =
::std::min(max_intake_front_goal, max_intake_front_goal_);
}
void update_min_intake_front_goal(double min_intake_front_goal) {
min_intake_front_goal_ =
::std::max(min_intake_front_goal, min_intake_front_goal_);
}
void update_max_intake_back_goal(double max_intake_back_goal) {
max_intake_back_goal_ =
::std::min(max_intake_back_goal, max_intake_back_goal_);
}
void update_min_intake_back_goal(double min_intake_back_goal) {
min_intake_back_goal_ =
::std::max(min_intake_back_goal, min_intake_back_goal_);
}
private:
void clear_min_intake_front_goal() {
min_intake_front_goal_ = -::std::numeric_limits<double>::infinity();
}
void clear_max_intake_front_goal() {
max_intake_front_goal_ = ::std::numeric_limits<double>::infinity();
}
void clear_min_intake_back_goal() {
min_intake_back_goal_ = -::std::numeric_limits<double>::infinity();
}
void clear_max_intake_back_goal() {
max_intake_back_goal_ = ::std::numeric_limits<double>::infinity();
}
void clear_min_turret_goal() {
min_turret_goal_ = -::std::numeric_limits<double>::infinity();
}
void clear_max_turret_goal() {
max_turret_goal_ = ::std::numeric_limits<double>::infinity();
}
double min_intake_front_goal_;
double max_intake_front_goal_;
double min_intake_back_goal_;
double max_intake_back_goal_;
double min_turret_goal_;
double max_turret_goal_;
};
} // namespace y2022::control_loops::superstructure
#endif