Add 3rd Robot Auto
- 3 Cube (High, mid, low) cable side tested at MTTD
- 1 Cube middle with mobility over charge untested
- 1 High Cube tested at MTTD
Signed-off-by: Filip Kujawa <filip.j.kujawa@gmail.com>
Change-Id: Ia4db6bea9559fe77f5fca6e866179ef866f37715
diff --git a/y2023_bot3/autonomous/auto_splines.cc b/y2023_bot3/autonomous/auto_splines.cc
index e2779c4..25277e9 100644
--- a/y2023_bot3/autonomous/auto_splines.cc
+++ b/y2023_bot3/autonomous/auto_splines.cc
@@ -102,6 +102,56 @@
alliance);
}
+flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::Spline1(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance) {
+ return FixSpline(
+ builder,
+ aos::CopyFlatBuffer<frc971::MultiSpline>(spline_1_, builder->fbb()),
+ alliance);
+}
+
+flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::Spline2(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance) {
+ return FixSpline(
+ builder,
+ aos::CopyFlatBuffer<frc971::MultiSpline>(spline_2_, builder->fbb()),
+ alliance);
+}
+
+flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::Spline3(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance) {
+ return FixSpline(
+ builder,
+ aos::CopyFlatBuffer<frc971::MultiSpline>(spline_3_, builder->fbb()),
+ alliance);
+}
+
+flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::Spline4(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance) {
+ return FixSpline(
+ builder,
+ aos::CopyFlatBuffer<frc971::MultiSpline>(spline_4_, builder->fbb()),
+ alliance);
+}
+
+flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::SplineMiddle1(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance) {
+ return FixSpline(builder,
+ aos::CopyFlatBuffer<frc971::MultiSpline>(spline_middle_1_,
+ builder->fbb()),
+ alliance);
+}
+
flatbuffers::Offset<frc971::MultiSpline> AutonomousSplines::StraightLine(
aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
*builder,
diff --git a/y2023_bot3/autonomous/auto_splines.h b/y2023_bot3/autonomous/auto_splines.h
index 0c9d92f..daa39b7 100644
--- a/y2023_bot3/autonomous/auto_splines.h
+++ b/y2023_bot3/autonomous/auto_splines.h
@@ -1,5 +1,5 @@
-#ifndef Y2023_AUTONOMOUS_AUTO_SPLINES_H_
-#define Y2023_AUTONOMOUS_AUTO_SPLINES_H_
+#ifndef Y2023_BOT3_AUTONOMOUS_AUTO_SPLINES_H_
+#define Y2023_BOT3_AUTONOMOUS_AUTO_SPLINES_H_
#include "aos/events/event_loop.h"
#include "aos/flatbuffer_merge.h"
@@ -20,7 +20,17 @@
public:
AutonomousSplines()
: test_spline_(aos::JsonFileToFlatbuffer<frc971::MultiSpline>(
- "splines/test_spline.json")) {}
+ "splines/test_spline.json")),
+ spline_1_(aos::JsonFileToFlatbuffer<frc971::MultiSpline>(
+ "splines/charged_up.0.json")),
+ spline_2_(aos::JsonFileToFlatbuffer<frc971::MultiSpline>(
+ "splines/charged_up.1.json")),
+ spline_3_(aos::JsonFileToFlatbuffer<frc971::MultiSpline>(
+ "splines/charged_up.2.json")),
+ spline_4_(aos::JsonFileToFlatbuffer<frc971::MultiSpline>(
+ "splines/charged_up.3.json")),
+ spline_middle_1_(aos::JsonFileToFlatbuffer<frc971::MultiSpline>(
+ "splines/charged_up_middle.0.json")) {}
static flatbuffers::Offset<frc971::MultiSpline> BasicSSpline(
aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
*builder,
@@ -34,9 +44,34 @@
aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
*builder,
aos::Alliance alliance);
+ flatbuffers::Offset<frc971::MultiSpline> Spline1(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance);
+ flatbuffers::Offset<frc971::MultiSpline> Spline2(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance);
+ flatbuffers::Offset<frc971::MultiSpline> Spline3(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance);
+ flatbuffers::Offset<frc971::MultiSpline> Spline4(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance);
+ flatbuffers::Offset<frc971::MultiSpline> SplineMiddle1(
+ aos::Sender<frc971::control_loops::drivetrain::SplineGoal>::Builder
+ *builder,
+ aos::Alliance alliance);
private:
aos::FlatbufferDetachedBuffer<frc971::MultiSpline> test_spline_;
+ aos::FlatbufferDetachedBuffer<frc971::MultiSpline> spline_1_;
+ aos::FlatbufferDetachedBuffer<frc971::MultiSpline> spline_2_;
+ aos::FlatbufferDetachedBuffer<frc971::MultiSpline> spline_3_;
+ aos::FlatbufferDetachedBuffer<frc971::MultiSpline> spline_4_;
+ aos::FlatbufferDetachedBuffer<frc971::MultiSpline> spline_middle_1_;
};
} // namespace autonomous
diff --git a/y2023_bot3/autonomous/autonomous_actor.cc b/y2023_bot3/autonomous/autonomous_actor.cc
index 0aacbd1..fc794b1 100644
--- a/y2023_bot3/autonomous/autonomous_actor.cc
+++ b/y2023_bot3/autonomous/autonomous_actor.cc
@@ -12,6 +12,13 @@
#include "y2023_bot3/control_loops/drivetrain/drivetrain_base.h"
DEFINE_bool(spline_auto, false, "Run simple test S-spline auto mode.");
+DEFINE_bool(charged_up, true,
+ "If true run charged up autonomous mode. 2 Piece non-cable side");
+DEFINE_bool(charged_up_middle, false,
+ "If true run charged up middle autonomous mode. Starts middle, "
+ "places cube mid, mobility");
+DEFINE_bool(one_piece, false,
+ "End charged_up autonomous after first cube is placed.");
namespace y2023_bot3 {
namespace autonomous {
@@ -110,11 +117,32 @@
SplineDirection::kForward);
starting_position_ = test_spline_->starting_position();
+ } else if (FLAGS_charged_up) {
+ charged_up_splines_ = {
+ PlanSpline(std::bind(&AutonomousSplines::Spline1, &auto_splines_,
+ std::placeholders::_1, alliance_),
+ SplineDirection::kBackward),
+ PlanSpline(std::bind(&AutonomousSplines::Spline2, &auto_splines_,
+ std::placeholders::_1, alliance_),
+ SplineDirection::kForward),
+ PlanSpline(std::bind(&AutonomousSplines::Spline3, &auto_splines_,
+ std::placeholders::_1, alliance_),
+ SplineDirection::kBackward),
+ PlanSpline(std::bind(&AutonomousSplines::Spline4, &auto_splines_,
+ std::placeholders::_1, alliance_),
+ SplineDirection::kForward)};
+ starting_position_ = charged_up_splines_.value()[0].starting_position();
+ CHECK(starting_position_);
+ } else if (FLAGS_charged_up_middle) {
+ charged_up_middle_splines_ = {
+ PlanSpline(std::bind(&AutonomousSplines::SplineMiddle1, &auto_splines_,
+ std::placeholders::_1, alliance_),
+ SplineDirection::kForward)};
}
is_planned_ = true;
MaybeSendStartingPosition();
-}
+} // namespace autonomous
void AutonomousActor::MaybeSendStartingPosition() {
if (is_planned_ && user_indicated_safe_to_reset_ &&
@@ -134,6 +162,8 @@
alliance_ = joystick_state_fetcher_->alliance();
preloaded_ = false;
+ roller_goal_ = control_loops::superstructure::RollerGoal::IDLE;
+ pivot_goal_ = control_loops::superstructure::PivotGoal::NEUTRAL;
SendSuperstructureGoal();
}
@@ -160,6 +190,13 @@
return false;
}
+ if (FLAGS_charged_up) {
+ ChargedUp();
+ } else {
+ AOS_LOG(INFO, "No autonomous mode selected.");
+ return false;
+ }
+
return true;
}
@@ -182,17 +219,263 @@
}
}
+// Charged Up 2 Game Object Autonomous (non-cable side)
+void AutonomousActor::ChargedUp() {
+ aos::monotonic_clock::time_point start_time = aos::monotonic_clock::now();
+
+ CHECK(charged_up_splines_);
+
+ auto &splines = *charged_up_splines_;
+
+ AOS_LOG(INFO, "Going to preload");
+
+ // Tell the superstructure that a cube was preloaded
+ if (!WaitForPreloaded()) {
+ return;
+ }
+
+ // Place & Spit firt cube high
+ AOS_LOG(INFO, "Moving arm to front high scoring position");
+
+ HighScore();
+ std::this_thread::sleep_for(chrono::milliseconds(600));
+
+ SpitHigh();
+ std::this_thread::sleep_for(chrono::milliseconds(600));
+
+ StopSpitting();
+
+ std::this_thread::sleep_for(chrono::milliseconds(200));
+ AOS_LOG(
+ INFO, "Placed first cube (HIGH) %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+
+ if (FLAGS_one_piece) {
+ return;
+ }
+
+ // Drive to second cube
+ if (!splines[0].WaitForPlan()) {
+ return;
+ }
+ splines[0].Start();
+
+ // Move arm into position to intake cube and intake.
+ AOS_LOG(INFO, "Moving arm to back pickup position");
+
+ Pickup();
+
+ std::this_thread::sleep_for(chrono::milliseconds(500));
+ Intake();
+
+ AOS_LOG(
+ INFO, "Turning on rollers %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+
+ if (!splines[0].WaitForSplineDistanceRemaining(0.02)) {
+ return;
+ }
+
+ AOS_LOG(
+ INFO, "Got there %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+
+ // Drive back to grid
+ if (!splines[1].WaitForPlan()) {
+ return;
+ }
+ splines[1].Start();
+ std::this_thread::sleep_for(chrono::milliseconds(600));
+
+ // Place Low
+ AOS_LOG(INFO, "Moving arm to front mid scoring position");
+
+ MidScore();
+
+ std::this_thread::sleep_for(chrono::milliseconds(600));
+ if (!splines[1].WaitForSplineDistanceRemaining(0.1)) return;
+
+ Spit();
+ std::this_thread::sleep_for(chrono::milliseconds(400));
+ StopSpitting();
+
+ AOS_LOG(
+ INFO, "Placed second cube (MID) %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+
+ // Drive to third cube
+ if (!splines[2].WaitForPlan()) {
+ return;
+ }
+ splines[2].Start();
+
+ std::this_thread::sleep_for(chrono::milliseconds(500));
+ // Move arm into position to intake cube and intake.
+ AOS_LOG(INFO, "Moving arm to back pickup position");
+
+ Pickup();
+
+ std::this_thread::sleep_for(chrono::milliseconds(250));
+ Intake();
+
+ AOS_LOG(
+ INFO, "Turning on rollers %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+
+ if (!splines[2].WaitForSplineDistanceRemaining(0.02)) {
+ return;
+ }
+
+ AOS_LOG(
+ INFO, "Got there %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+
+ // Drive back to grid
+ if (!splines[3].WaitForPlan()) {
+ return;
+ }
+ splines[3].Start();
+ std::this_thread::sleep_for(chrono::milliseconds(600));
+
+ // Place Low
+ AOS_LOG(INFO, "Moving arm to front low scoring position");
+
+ LowScore();
+
+ std::this_thread::sleep_for(chrono::milliseconds(600));
+ if (!splines[3].WaitForSplineDistanceRemaining(0.1)) return;
+
+ Spit();
+ std::this_thread::sleep_for(chrono::milliseconds(600));
+ StopSpitting();
+
+ AOS_LOG(
+ INFO, "Placed low cube (LOW) %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+}
+
+// Charged Up Place and Mobility Autonomous (middle)
+void AutonomousActor::ChargedUpMiddle() {
+ aos::monotonic_clock::time_point start_time = aos::monotonic_clock::now();
+
+ CHECK(charged_up_middle_splines_);
+
+ auto &splines = *charged_up_middle_splines_;
+
+ AOS_LOG(INFO, "Going to preload");
+
+ // Tell the superstructure that a cube was preloaded
+ if (!WaitForPreloaded()) {
+ return;
+ }
+
+ // Place & Spit firt cube mid
+ AOS_LOG(INFO, "Moving arm to front mid scoring position");
+
+ MidScore();
+ std::this_thread::sleep_for(chrono::milliseconds(300));
+
+ Spit();
+ std::this_thread::sleep_for(chrono::milliseconds(300));
+
+ StopSpitting();
+
+ std::this_thread::sleep_for(chrono::milliseconds(100));
+ AOS_LOG(
+ INFO, "Placed first cube (Mid) %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+
+ // Drive to second cube
+
+ if (!splines[0].WaitForPlan()) {
+ return;
+ }
+ splines[0].Start();
+}
+
void AutonomousActor::SendSuperstructureGoal() {
auto builder = superstructure_goal_sender_.MakeBuilder();
control_loops::superstructure::Goal::Builder superstructure_builder =
builder.MakeBuilder<control_loops::superstructure::Goal>();
+ superstructure_builder.add_pivot_goal(pivot_goal_);
+ superstructure_builder.add_roller_goal(roller_goal_);
+ superstructure_builder.add_preloaded_with_cube(preloaded_);
+
if (builder.Send(superstructure_builder.Finish()) !=
aos::RawSender::Error::kOk) {
AOS_LOG(ERROR, "Sending superstructure goal failed.\n");
}
}
+[[nodiscard]] bool AutonomousActor::WaitForPreloaded() {
+ set_preloaded(true);
+ SendSuperstructureGoal();
+
+ ::aos::time::PhasedLoop phased_loop(frc971::controls::kLoopFrequency,
+ event_loop()->monotonic_now(),
+ ActorBase::kLoopOffset);
+
+ bool loaded = false;
+ while (!loaded) {
+ if (ShouldCancel()) {
+ return false;
+ }
+
+ phased_loop.SleepUntilNext();
+ superstructure_status_fetcher_.Fetch();
+ CHECK(superstructure_status_fetcher_.get() != nullptr);
+
+ loaded = (superstructure_status_fetcher_->end_effector_state() ==
+ control_loops::superstructure::EndEffectorState::LOADED);
+ }
+
+ set_preloaded(false);
+ SendSuperstructureGoal();
+
+ return true;
+}
+
+void AutonomousActor::HighScore() {
+ set_pivot_goal(control_loops::superstructure::PivotGoal::SCORE_HIGH_FRONT);
+ SendSuperstructureGoal();
+}
+void AutonomousActor::MidScore() {
+ set_pivot_goal(control_loops::superstructure::PivotGoal::SCORE_MID_FRONT);
+ SendSuperstructureGoal();
+}
+void AutonomousActor::LowScore() {
+ set_pivot_goal(control_loops::superstructure::PivotGoal::SCORE_LOW_FRONT);
+ SendSuperstructureGoal();
+}
+void AutonomousActor::Spit() {
+ set_roller_goal(control_loops::superstructure::RollerGoal::SPIT);
+ SendSuperstructureGoal();
+}
+void AutonomousActor::SpitHigh() {
+ set_roller_goal(control_loops::superstructure::RollerGoal::SPIT_HIGH);
+ SendSuperstructureGoal();
+}
+
+void AutonomousActor::StopSpitting() {
+ set_roller_goal(control_loops::superstructure::RollerGoal::IDLE);
+ SendSuperstructureGoal();
+}
+void AutonomousActor::Intake() {
+ set_roller_goal(control_loops::superstructure::RollerGoal::INTAKE_CUBE);
+ SendSuperstructureGoal();
+}
+
+void AutonomousActor::Pickup() {
+ set_pivot_goal(control_loops::superstructure::PivotGoal::PICKUP_BACK);
+ SendSuperstructureGoal();
+}
+
+void AutonomousActor::Neutral() {
+ set_pivot_goal(control_loops::superstructure::PivotGoal::NEUTRAL);
+ SendSuperstructureGoal();
+}
+
} // namespace autonomous
} // namespace y2023_bot3
diff --git a/y2023_bot3/autonomous/autonomous_actor.h b/y2023_bot3/autonomous/autonomous_actor.h
index b7978c7..ad33eed 100644
--- a/y2023_bot3/autonomous/autonomous_actor.h
+++ b/y2023_bot3/autonomous/autonomous_actor.h
@@ -1,5 +1,5 @@
-#ifndef Y2023_AUTONOMOUS_AUTONOMOUS_ACTOR_H_
-#define Y2023_AUTONOMOUS_AUTONOMOUS_ACTOR_H_
+#ifndef Y2023_BOT3_AUTONOMOUS_AUTONOMOUS_ACTOR_H_
+#define Y2023_BOT3_AUTONOMOUS_AUTONOMOUS_ACTOR_H_
#include "aos/actions/actions.h"
#include "aos/actions/actor.h"
@@ -11,6 +11,8 @@
#include "y2023_bot3/control_loops/superstructure/superstructure_goal_generated.h"
#include "y2023_bot3/control_loops/superstructure/superstructure_status_generated.h"
+// TODO<FILIP>: Add NEUTRAL pivot pose.
+
namespace y2023_bot3 {
namespace autonomous {
@@ -24,13 +26,38 @@
private:
void set_preloaded(bool preloaded) { preloaded_ = preloaded; }
+ void set_pivot_goal(
+ control_loops::superstructure::PivotGoal requested_pivot_goal) {
+ pivot_goal_ = requested_pivot_goal;
+ }
+
+ void set_roller_goal(
+ control_loops::superstructure::RollerGoal requested_roller_goal) {
+ roller_goal_ = requested_roller_goal;
+ }
+
void SendSuperstructureGoal();
+ [[nodiscard]] bool WaitForPreloaded();
+
+ void HighScore();
+ void MidScore();
+ void LowScore();
+ void Spit();
+ void SpitHigh();
+ void StopSpitting();
+ void Pickup();
+ void Intake();
+ void Neutral();
+
void Reset();
void SendStartingPosition(const Eigen::Vector3d &start);
void MaybeSendStartingPosition();
void Replan();
+ void ChargedUp();
+ void ChargedUpMiddle();
+ void OnePieceMiddle();
aos::Sender<frc971::control_loops::drivetrain::LocalizerControl>
localizer_control_sender_;
@@ -51,11 +78,16 @@
bool preloaded_ = false;
+ control_loops::superstructure::PivotGoal pivot_goal_;
+ control_loops::superstructure::RollerGoal roller_goal_;
+
aos::Sender<control_loops::superstructure::Goal> superstructure_goal_sender_;
aos::Fetcher<y2023_bot3::control_loops::superstructure::Status>
superstructure_status_fetcher_;
std::optional<SplineHandle> test_spline_;
+ std::optional<std::array<SplineHandle, 4>> charged_up_splines_;
+ std::optional<std::array<SplineHandle, 1>> charged_up_middle_splines_;
};
} // namespace autonomous
diff --git a/y2023_bot3/autonomous/splines/charged_up.0.json b/y2023_bot3/autonomous/splines/charged_up.0.json
new file mode 100644
index 0000000..92457db
--- /dev/null
+++ b/y2023_bot3/autonomous/splines/charged_up.0.json
@@ -0,0 +1 @@
+{"spline_count": 1, "spline_x": [-6.445692607996035, -5.415058675142317, -4.209411432936082, -3.2465463700565964, -2.4298175930781793, -1.3618353380388033], "spline_y": [0.4209511918970197, 0.4209511918970197, 0.362613422112847, 0.6813475323823923, 0.5646719928140473, 0.5783738080079003], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 2.5}, {"constraint_type": "LATERAL_ACCELERATION", "value": 1.5}, {"constraint_type": "VOLTAGE", "value": 10.0}]}
diff --git a/y2023_bot3/autonomous/splines/charged_up.1.json b/y2023_bot3/autonomous/splines/charged_up.1.json
new file mode 100644
index 0000000..dcb5199
--- /dev/null
+++ b/y2023_bot3/autonomous/splines/charged_up.1.json
@@ -0,0 +1 @@
+{"spline_count": 1, "spline_x": [-1.3618353380388033, -2.3872501162751885, -3.2039788932536055, -4.203904851957984, -5.409552094164219, -6.440186027017937], "spline_y": [0.5783738080079003, 0.5652181177123508, 0.6818936572806957, 0.34998739215158625, 0.40832516193575896, 0.40832516193575896], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 2.5}, {"constraint_type": "LATERAL_ACCELERATION", "value": 1.5}, {"constraint_type": "VOLTAGE", "value": 10.0}]}
diff --git a/y2023_bot3/autonomous/splines/charged_up.2.json b/y2023_bot3/autonomous/splines/charged_up.2.json
new file mode 100644
index 0000000..59d6be9
--- /dev/null
+++ b/y2023_bot3/autonomous/splines/charged_up.2.json
@@ -0,0 +1 @@
+{"spline_count": 1, "spline_x": [-6.454553325309534, -4.460161354045205, -1.5509007918193776, -2.0414882541240535, -1.561168539005604, -1.2111154074787347], "spline_y": [0.5453682144642946, 0.5546337154126451, 0.8131021132876166, 0.19103636149376457, -0.3361640874334603, -0.6272868229790012], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 1.2}, {"constraint_type": "LATERAL_ACCELERATION", "value": 1}, {"constraint_type": "VOLTAGE", "value": 10.0}]}
\ No newline at end of file
diff --git a/y2023_bot3/autonomous/splines/charged_up.3.json b/y2023_bot3/autonomous/splines/charged_up.3.json
new file mode 100644
index 0000000..8429898
--- /dev/null
+++ b/y2023_bot3/autonomous/splines/charged_up.3.json
@@ -0,0 +1 @@
+{"spline_count": 1, "spline_x": [-1.2111154074787347, -2.14291716567915, -3.156528585717081, -5.403636264390716, -4.837378001437765, -6.451325108951964], "spline_y": [-0.6272868229790012, 0.14764890077877224, 0.8014128668038034, 0.3355527717509894, 0.46308586049140743, 0.44756341283790313], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 1.2}, {"constraint_type": "LATERAL_ACCELERATION", "value": 1}, {"constraint_type": "VOLTAGE", "value": 10}]}
\ No newline at end of file
diff --git a/y2023_bot3/autonomous/splines/charged_up_middle.0.json b/y2023_bot3/autonomous/splines/charged_up_middle.0.json
new file mode 100644
index 0000000..745672f
--- /dev/null
+++ b/y2023_bot3/autonomous/splines/charged_up_middle.0.json
@@ -0,0 +1 @@
+{"spline_count": 1, "spline_x": [-6.473051792628953, -5.825415380863309, -5.094212980482744, -4.2376615971797955, -3.04684625941716, -2.190294876114212], "spline_y": [-1.2754706248451688, -1.2754706248451688, -1.2754706248451688, -1.2754706248451688, -1.2754706248451688, -1.2754706248451688], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2}, {"constraint_type": "VOLTAGE", "value": 10}]}