blob: a4f3a35742729f104bf25348de4341d2d6660638 [file] [log] [blame]
#include "y2024/control_loops/superstructure/collision_avoidance.h"
#include <cmath>
#include "absl/functional/bind_front.h"
#include "absl/log/check.h"
#include "absl/log/log.h"
namespace y2024::control_loops::superstructure {
CollisionAvoidance::CollisionAvoidance() {
clear_min_intake_pivot_goal();
clear_max_intake_pivot_goal();
clear_min_turret_goal();
clear_max_turret_goal();
clear_min_extend_goal();
clear_max_extend_goal();
}
bool CollisionAvoidance::IsCollided(const CollisionAvoidance::Status &status) {
// Checks if intake front is collided.
if (TurretCollided(status.intake_pivot_position, status.turret_position,
status.extend_position)) {
return true;
}
return false;
}
bool AngleInRange(double theta, double theta_min, double theta_max) {
return (
(theta >= theta_min && theta <= theta_max) ||
(theta_min > theta_max && (theta >= theta_min || theta <= theta_max)));
}
bool CollisionAvoidance::TurretCollided(double intake_position,
double turret_position,
double extend_position) {
// Checks if turret is in the collision area.
if (AngleInRange(turret_position, kMinCollisionZoneTurret,
kMaxCollisionZoneTurret)) {
// Returns true if the intake is raised.
if (intake_position > kCollisionZoneIntake) {
return true;
}
}
return ExtendCollided(intake_position, turret_position, extend_position);
}
bool CollisionAvoidance::ExtendCollided(double /*intake_position*/,
double turret_position,
double extend_position) {
// Checks if turret is in the collision area.
if (!AngleInRange(turret_position, kSafeTurretExtendedPosition - kEpsTurret,
kSafeTurretExtendedPosition + kEpsTurret)) {
// Returns true if the extend is raised.
if (extend_position > kMinCollisionZoneExtend) {
return true;
}
}
return false;
}
void CollisionAvoidance::UpdateGoal(const CollisionAvoidance::Status &status,
const double turret_goal_position,
const double extend_goal_position) {
// Start with our constraints being wide open.
clear_min_extend_goal();
clear_max_extend_goal();
clear_max_turret_goal();
clear_min_turret_goal();
clear_max_intake_pivot_goal();
clear_min_intake_pivot_goal();
const double intake_pivot_position = status.intake_pivot_position;
const double turret_position = status.turret_position;
const double extend_position = status.extend_position;
const double turret_goal = turret_goal_position;
const double extend_goal = extend_goal_position;
// Calculating the avoidance with the intake
CalculateAvoidance(intake_pivot_position, turret_position, extend_position,
turret_goal, extend_goal);
}
void CollisionAvoidance::CalculateAvoidance(double intake_position,
double turret_position,
double extend_position,
double turret_goal,
double extend_goal) {
// If the turret goal is in a collison zone or moving through one, limit
// intake.
const bool turret_intake_pos_unsafe = AngleInRange(
turret_position, kMinCollisionZoneTurret, kMaxCollisionZoneTurret);
const bool turret_extend_pos_unsafe =
turret_position > kEpsTurret + kSafeTurretExtendedPosition ||
turret_position < -kEpsTurret + kSafeTurretExtendedPosition;
const bool extend_goal_unsafe =
extend_goal > kMinCollisionZoneExtend - kEpsExtend;
const bool extend_position_unsafe =
extend_position > kMinCollisionZoneExtend - kEpsExtend;
// OK, we are trying to move the extend, and need the turret to be at 0.
// Pretend that's the goal.
if (extend_goal_unsafe || extend_position_unsafe) {
turret_goal = kSafeTurretExtendedPosition;
}
const bool turret_moving_forward = (turret_goal > turret_position);
// Check if the closest angles are going to be passed
const bool turret_moving_past_intake =
((turret_moving_forward && (turret_position <= kMaxCollisionZoneTurret &&
turret_goal >= kMinCollisionZoneTurret)) ||
(!turret_moving_forward && (turret_position >= kMinCollisionZoneTurret &&
turret_goal <= kMaxCollisionZoneTurret)));
if (turret_intake_pos_unsafe || turret_moving_past_intake) {
// If the turret is unsafe, limit the intake
update_max_intake_pivot_goal(kCollisionZoneIntake - kEpsIntake);
// If the intake is in the way, limit the turret until moved. Otherwise,
// let'errip!
if (!turret_intake_pos_unsafe && (intake_position > kCollisionZoneIntake)) {
if (turret_position <
(kMinCollisionZoneTurret + kMaxCollisionZoneTurret) / 2.) {
update_max_turret_goal(kMinCollisionZoneTurret - kEpsTurret);
} else {
update_min_turret_goal(kMaxCollisionZoneTurret + kEpsTurret);
}
}
}
// OK, the logic is pretty simple. The turret needs to be at
// kSafeTurretExtendedPosition any time extend is > kMinCollisionZoneExtend.
//
// Extend can't go up if the turret isn't near 0.
if (turret_extend_pos_unsafe) {
update_max_extend_goal(kMinCollisionZoneExtend - kEpsExtend);
}
// Turret is bound to the safe position if extend wants to be, or is unsafe.
if (extend_goal_unsafe || extend_position_unsafe) {
// If the turret isn't allowed to go to 0, don't drive it there.
if (min_turret_goal() < kSafeTurretExtendedPosition &&
max_turret_goal() > kSafeTurretExtendedPosition) {
update_min_turret_goal(kSafeTurretExtendedPosition);
update_max_turret_goal(kSafeTurretExtendedPosition);
}
}
}
} // namespace y2024::control_loops::superstructure