Merge "Create camera_monitor to restart camera_reader when stuck"
diff --git a/frc971/autonomous/base_autonomous_actor.cc b/frc971/autonomous/base_autonomous_actor.cc
index 90c1454..22909be 100644
--- a/frc971/autonomous/base_autonomous_actor.cc
+++ b/frc971/autonomous/base_autonomous_actor.cc
@@ -450,6 +450,35 @@
return false;
}
+bool BaseAutonomousActor::SplineHandle::SplineDistanceTraveled(
+ double distance) {
+ base_autonomous_actor_->drivetrain_status_fetcher_.Fetch();
+ if (base_autonomous_actor_->drivetrain_status_fetcher_.get()) {
+ // Confirm that:
+ // (a) The spline has started executiong (is_executing remains true even
+ // when we reach the end of the spline).
+ // (b) The spline that we are executing is the correct one.
+ // (c) There is less than distance distance remaining.
+ if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
+ ->goal_spline_handle() != spline_handle_) {
+ // Never done if we aren't the active spline.
+ return false;
+ }
+
+ if (base_autonomous_actor_->drivetrain_status_fetcher_->trajectory_logging()
+ ->is_executed()) {
+ return true;
+ }
+ return base_autonomous_actor_->drivetrain_status_fetcher_
+ ->trajectory_logging()
+ ->is_executing() &&
+ base_autonomous_actor_->drivetrain_status_fetcher_
+ ->trajectory_logging()
+ ->distance_traveled() > distance;
+ }
+ return false;
+}
+
bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceRemaining(
double distance) {
::aos::time::PhasedLoop phased_loop(
@@ -467,6 +496,23 @@
}
}
+bool BaseAutonomousActor::SplineHandle::WaitForSplineDistanceTraveled(
+ double distance) {
+ ::aos::time::PhasedLoop phased_loop(
+ frc971::controls::kLoopFrequency,
+ base_autonomous_actor_->event_loop()->monotonic_now(),
+ ActorBase::kLoopOffset);
+ while (true) {
+ if (base_autonomous_actor_->ShouldCancel()) {
+ return false;
+ }
+ phased_loop.SleepUntilNext();
+ if (SplineDistanceTraveled(distance)) {
+ return true;
+ }
+ }
+}
+
void BaseAutonomousActor::LineFollowAtVelocity(
double velocity, y2019::control_loops::drivetrain::SelectionHint hint) {
{
diff --git a/frc971/autonomous/base_autonomous_actor.h b/frc971/autonomous/base_autonomous_actor.h
index 5562dde..403854f 100644
--- a/frc971/autonomous/base_autonomous_actor.h
+++ b/frc971/autonomous/base_autonomous_actor.h
@@ -41,7 +41,9 @@
// Whether there is less than a certain distance, in meters, remaining in
// the current spline.
bool SplineDistanceRemaining(double distance);
+ bool SplineDistanceTraveled(double distance);
bool WaitForSplineDistanceRemaining(double distance);
+ bool WaitForSplineDistanceTraveled(double distance);
// Returns [x, y, theta] position of the start.
const Eigen::Vector3d &starting_position() const { return spline_start_; }
diff --git a/frc971/control_loops/drivetrain/drivetrain_status.fbs b/frc971/control_loops/drivetrain/drivetrain_status.fbs
index 89dc3d5..8158e75 100644
--- a/frc971/control_loops/drivetrain/drivetrain_status.fbs
+++ b/frc971/control_loops/drivetrain/drivetrain_status.fbs
@@ -77,6 +77,7 @@
left_velocity:float (id: 9);
right_velocity:float (id: 10);
distance_remaining:float (id: 11);
+ distance_traveled:float (id: 13);
// Splines that we have full plans for.
available_splines:[int] (id: 12);
diff --git a/frc971/control_loops/drivetrain/splinedrivetrain.cc b/frc971/control_loops/drivetrain/splinedrivetrain.cc
index 0f9418c..ddcf63d 100644
--- a/frc971/control_loops/drivetrain/splinedrivetrain.cc
+++ b/frc971/control_loops/drivetrain/splinedrivetrain.cc
@@ -256,6 +256,8 @@
? CHECK_NOTNULL(current_trajectory())->length() - current_xva_.x()
: 0.0);
trajectory_logging_builder.add_available_splines(handles_vector);
+ trajectory_logging_builder.add_distance_traveled(
+ executing_spline_ ? current_xva_.x() : 0.0);
return trajectory_logging_builder.Finish();
}
diff --git a/frc971/vision/BUILD b/frc971/vision/BUILD
index 133281b..84f3be7 100644
--- a/frc971/vision/BUILD
+++ b/frc971/vision/BUILD
@@ -166,6 +166,7 @@
":target_map_fbs",
"//aos/events:simulated_event_loop",
"//frc971/control_loops:control_loop",
+ "//frc971/vision:visualize_robot",
"//frc971/vision/ceres:pose_graph_3d_lib",
"//third_party:opencv",
"@com_google_ceres_solver//:ceres",
diff --git a/frc971/vision/target_mapper.cc b/frc971/vision/target_mapper.cc
index 3eba919..0d6b9e9 100644
--- a/frc971/vision/target_mapper.cc
+++ b/frc971/vision/target_mapper.cc
@@ -10,9 +10,12 @@
DEFINE_double(distortion_noise_scalar, 1.0,
"Scale the target pose distortion factor by this when computing "
"the noise.");
-DEFINE_uint64(
+DEFINE_int32(
frozen_target_id, 1,
"Freeze the pose of this target so the map can have one fixed point.");
+DEFINE_int32(min_target_id, 1, "Minimum target id to solve for");
+DEFINE_int32(max_target_id, 8, "Maximum target id to solve for");
+DEFINE_bool(visualize_solver, false, "If true, visualize the solving process.");
namespace frc971::vision {
Eigen::Affine3d PoseUtils::Pose3dToAffine3d(
@@ -211,19 +214,28 @@
TargetMapper::TargetMapper(
std::string_view target_poses_path,
const ceres::examples::VectorOfConstraints &target_constraints)
- : target_constraints_(target_constraints) {
+ : target_constraints_(target_constraints),
+ T_frozen_actual_(Eigen::Vector3d::Zero()),
+ R_frozen_actual_(Eigen::Quaterniond::Identity()),
+ vis_robot_(cv::Size(1280, 1000)) {
aos::FlatbufferDetachedBuffer<TargetMap> target_map =
aos::JsonFileToFlatbuffer<TargetMap>(target_poses_path);
for (const auto *target_pose_fbs : *target_map.message().target_poses()) {
- target_poses_[target_pose_fbs->id()] =
+ ideal_target_poses_[target_pose_fbs->id()] =
PoseUtils::TargetPoseFromFbs(*target_pose_fbs).pose;
}
+ target_poses_ = ideal_target_poses_;
}
TargetMapper::TargetMapper(
const ceres::examples::MapOfPoses &target_poses,
const ceres::examples::VectorOfConstraints &target_constraints)
- : target_poses_(target_poses), target_constraints_(target_constraints) {}
+ : ideal_target_poses_(target_poses),
+ target_poses_(ideal_target_poses_),
+ target_constraints_(target_constraints),
+ T_frozen_actual_(Eigen::Vector3d::Zero()),
+ R_frozen_actual_(Eigen::Quaterniond::Identity()),
+ vis_robot_(cv::Size(1280, 1000)) {}
std::optional<TargetMapper::TargetPose> TargetMapper::GetTargetPoseById(
std::vector<TargetMapper::TargetPose> target_poses, TargetId target_id) {
@@ -248,7 +260,7 @@
// Taken from ceres/examples/slam/pose_graph_3d/pose_graph_3d.cc
// Constructs the nonlinear least squares optimization problem from the pose
// graph constraints.
-void TargetMapper::BuildOptimizationProblem(
+void TargetMapper::BuildTargetPoseOptimizationProblem(
const ceres::examples::VectorOfConstraints &constraints,
ceres::examples::MapOfPoses *poses, ceres::Problem *problem) {
CHECK(poses != nullptr);
@@ -311,6 +323,33 @@
problem->SetParameterBlockConstant(pose_start_iter->second.q.coeffs().data());
}
+void TargetMapper::BuildMapFittingOptimizationProblem(ceres::Problem *problem) {
+ // Setup robot visualization
+ vis_robot_.ClearImage();
+ constexpr int kImageWidth = 1280;
+ constexpr double kFocalLength = 500.0;
+ vis_robot_.SetDefaultViewpoint(kImageWidth, kFocalLength);
+
+ const size_t num_targets = FLAGS_max_target_id - FLAGS_min_target_id;
+ // Translation and rotation error for each target
+ const size_t num_residuals = num_targets * 6;
+ // Set up the only cost function (also known as residual). This uses
+ // auto-differentiation to obtain the derivative (jacobian).
+ ceres::CostFunction *cost_function =
+ new ceres::AutoDiffCostFunction<TargetMapper, ceres::DYNAMIC, 3, 4>(
+ this, num_residuals, ceres::DO_NOT_TAKE_OWNERSHIP);
+
+ ceres::LossFunction *loss_function = new ceres::HuberLoss(2.0);
+ ceres::LocalParameterization *quaternion_local_parameterization =
+ new ceres::EigenQuaternionParameterization;
+
+ problem->AddResidualBlock(cost_function, loss_function,
+ T_frozen_actual_.vector().data(),
+ R_frozen_actual_.coeffs().data());
+ problem->SetParameterization(R_frozen_actual_.coeffs().data(),
+ quaternion_local_parameterization);
+}
+
// Taken from ceres/examples/slam/pose_graph_3d/pose_graph_3d.cc
bool TargetMapper::SolveOptimizationProblem(ceres::Problem *problem) {
CHECK_NOTNULL(problem);
@@ -330,11 +369,39 @@
void TargetMapper::Solve(std::string_view field_name,
std::optional<std::string_view> output_dir) {
- ceres::Problem problem;
- BuildOptimizationProblem(target_constraints_, &target_poses_, &problem);
+ ceres::Problem target_pose_problem;
+ BuildTargetPoseOptimizationProblem(target_constraints_, &target_poses_,
+ &target_pose_problem);
+ CHECK(SolveOptimizationProblem(&target_pose_problem))
+ << "The target pose solve was not successful, exiting.";
- CHECK(SolveOptimizationProblem(&problem))
- << "The solve was not successful, exiting.";
+ ceres::Problem map_fitting_problem;
+ BuildMapFittingOptimizationProblem(&map_fitting_problem);
+ CHECK(SolveOptimizationProblem(&map_fitting_problem))
+ << "The map fitting solve was not successful, exiting.";
+
+ Eigen::Affine3d H_frozen_actual = T_frozen_actual_ * R_frozen_actual_;
+ LOG(INFO) << "H_frozen_actual: "
+ << PoseUtils::Affine3dToPose3d(H_frozen_actual);
+
+ auto H_world_frozen =
+ PoseUtils::Pose3dToAffine3d(target_poses_[FLAGS_frozen_target_id]);
+ auto H_world_frozenactual = H_world_frozen * H_frozen_actual;
+
+ // Offset the solved poses to become the actual ones
+ for (auto &[id, pose] : target_poses_) {
+ // Don't offset targets we didn't solve for
+ if (id < FLAGS_min_target_id || id > FLAGS_max_target_id) {
+ continue;
+ }
+
+ // Take the delta between the frozen target and the solved target, and put
+ // that on top of the actual pose of the frozen target
+ auto H_world_solved = PoseUtils::Pose3dToAffine3d(pose);
+ auto H_frozen_solved = H_world_frozen.inverse() * H_world_solved;
+ auto H_world_actual = H_world_frozenactual * H_frozen_solved;
+ pose = PoseUtils::Affine3dToPose3d(H_world_actual);
+ }
auto map_json = MapToJson(field_name);
VLOG(1) << "Solved target poses: " << map_json;
@@ -366,6 +433,110 @@
{.multi_line = true});
}
+namespace {
+
+// Hacks to extract a double from a scalar, which is either a ceres jet or a
+// double. Only used for debugging and displaying.
+template <typename S>
+double ScalarToDouble(S s) {
+ const double *ptr = reinterpret_cast<double *>(&s);
+ return *ptr;
+}
+
+template <typename S>
+Eigen::Affine3d ScalarAffineToDouble(Eigen::Transform<S, 3, Eigen::Affine> H) {
+ Eigen::Affine3d H_double;
+ for (size_t i = 0; i < H.rows(); i++) {
+ for (size_t j = 0; j < H.cols(); j++) {
+ H_double(i, j) = ScalarToDouble(H(i, j));
+ }
+ }
+ return H_double;
+}
+
+} // namespace
+
+template <typename S>
+bool TargetMapper::operator()(const S *const translation,
+ const S *const rotation, S *residual) const {
+ using Affine3s = Eigen::Transform<S, 3, Eigen::Affine>;
+ Eigen::Quaternion<S> R_frozen_actual(rotation[3], rotation[1], rotation[2],
+ rotation[0]);
+ Eigen::Translation<S, 3> T_frozen_actual(translation[0], translation[1],
+ translation[2]);
+ // Actual target pose in the frame of the fixed pose.
+ Affine3s H_frozen_actual = T_frozen_actual * R_frozen_actual;
+ VLOG(2) << "H_frozen_actual: "
+ << PoseUtils::Affine3dToPose3d(ScalarAffineToDouble(H_frozen_actual));
+
+ Affine3s H_world_frozen =
+ PoseUtils::Pose3dToAffine3d(target_poses_.at(FLAGS_frozen_target_id))
+ .cast<S>();
+ Affine3s H_world_frozenactual = H_world_frozen * H_frozen_actual;
+
+ size_t residual_index = 0;
+ if (FLAGS_visualize_solver) {
+ vis_robot_.ClearImage();
+ }
+
+ for (const auto &[id, solved_pose] : target_poses_) {
+ if (id < FLAGS_min_target_id || id > FLAGS_max_target_id) {
+ continue;
+ }
+
+ Affine3s H_world_ideal =
+ PoseUtils::Pose3dToAffine3d(ideal_target_poses_.at(id)).cast<S>();
+ Affine3s H_world_solved =
+ PoseUtils::Pose3dToAffine3d(solved_pose).cast<S>();
+ // Take the delta between the frozen target and the solved target, and put
+ // that on top of the actual pose of the frozen target
+ auto H_frozen_solved = H_world_frozen.inverse() * H_world_solved;
+ auto H_world_actual = H_world_frozenactual * H_frozen_solved;
+ VLOG(2) << id << ": " << H_world_actual.translation();
+ Affine3s H_ideal_actual = H_world_ideal.inverse() * H_world_actual;
+ auto T_ideal_actual = H_ideal_actual.translation();
+ VLOG(2) << "T_ideal_actual: " << T_ideal_actual;
+ VLOG(2);
+ auto R_ideal_actual = Eigen::AngleAxis<S>(H_ideal_actual.rotation());
+
+ constexpr double kTranslationScalar = 100.0;
+ constexpr double kRotationScalar = 1000.0;
+
+ // Penalize based on how much our actual poses matches the ideal
+ // ones. We've already solved for the relative poses, now figure out
+ // where all of them fit in the world.
+ residual[residual_index++] = kTranslationScalar * T_ideal_actual(0);
+ residual[residual_index++] = kTranslationScalar * T_ideal_actual(1);
+ residual[residual_index++] = kTranslationScalar * T_ideal_actual(2);
+ residual[residual_index++] =
+ kRotationScalar * R_ideal_actual.angle() * R_ideal_actual.axis().x();
+ residual[residual_index++] =
+ kRotationScalar * R_ideal_actual.angle() * R_ideal_actual.axis().y();
+ residual[residual_index++] =
+ kRotationScalar * R_ideal_actual.angle() * R_ideal_actual.axis().z();
+
+ if (FLAGS_visualize_solver) {
+ vis_robot_.DrawFrameAxes(ScalarAffineToDouble(H_world_actual),
+ std::to_string(id), cv::Scalar(0, 255, 0));
+ vis_robot_.DrawFrameAxes(ScalarAffineToDouble(H_world_ideal),
+ std::to_string(id), cv::Scalar(255, 255, 255));
+ }
+ }
+ if (FLAGS_visualize_solver) {
+ cv::imshow("Target maps", vis_robot_.image_);
+ cv::waitKey(0);
+ }
+
+ // Ceres can't handle residual values of exactly zero
+ for (size_t i = 0; i < residual_index; i++) {
+ if (residual[i] == S(0)) {
+ residual[i] = S(1e-9);
+ }
+ }
+
+ return true;
+}
+
} // namespace frc971::vision
std::ostream &operator<<(std::ostream &os, ceres::examples::Pose3d pose) {
diff --git a/frc971/vision/target_mapper.h b/frc971/vision/target_mapper.h
index c782992..ca36866 100644
--- a/frc971/vision/target_mapper.h
+++ b/frc971/vision/target_mapper.h
@@ -7,6 +7,7 @@
#include "ceres/ceres.h"
#include "frc971/vision/ceres/types.h"
#include "frc971/vision/target_map_generated.h"
+#include "frc971/vision/visualize_robot.h"
namespace frc971::vision {
@@ -51,18 +52,36 @@
ceres::examples::MapOfPoses target_poses() { return target_poses_; }
+ // Cost function for the secondary solver finding out where the whole map fits
+ // in the world
+ template <typename S>
+ bool operator()(const S *const translation, const S *const rotation,
+ S *residual) const;
+
private:
// Constructs the nonlinear least squares optimization problem from the
// pose graph constraints.
- void BuildOptimizationProblem(
+ void BuildTargetPoseOptimizationProblem(
const ceres::examples::VectorOfConstraints &constraints,
ceres::examples::MapOfPoses *poses, ceres::Problem *problem);
+ // Constructs the nonlinear least squares optimization problem for the solved
+ // -> actual pose solver.
+ void BuildMapFittingOptimizationProblem(ceres::Problem *problem);
+
// Returns true if the solve was successful.
bool SolveOptimizationProblem(ceres::Problem *problem);
+ ceres::examples::MapOfPoses ideal_target_poses_;
ceres::examples::MapOfPoses target_poses_;
ceres::examples::VectorOfConstraints target_constraints_;
+
+ // Transformation moving the target map we solved for to where it actually
+ // should be in the world
+ Eigen::Translation3d T_frozen_actual_;
+ Eigen::Quaterniond R_frozen_actual_;
+
+ mutable VisualizeRobot vis_robot_;
};
// Utility functions for dealing with ceres::examples::Pose3d structs
diff --git a/frc971/vision/target_mapper_test.cc b/frc971/vision/target_mapper_test.cc
index cd7d18b..1371f89 100644
--- a/frc971/vision/target_mapper_test.cc
+++ b/frc971/vision/target_mapper_test.cc
@@ -9,6 +9,9 @@
#include "glog/logging.h"
#include "gtest/gtest.h"
+DECLARE_int32(min_target_id);
+DECLARE_int32(max_target_id);
+
namespace frc971::vision {
namespace {
@@ -338,6 +341,9 @@
}
TEST(TargetMapperTest, TwoTargetsOneConstraint) {
+ FLAGS_min_target_id = 0;
+ FLAGS_max_target_id = 1;
+
ceres::examples::MapOfPoses target_poses;
target_poses[0] = Make2dPose(5.0, 0.0, M_PI);
target_poses[1] = Make2dPose(-5.0, 0.0, 0.0);
@@ -361,6 +367,9 @@
}
TEST(TargetMapperTest, TwoTargetsTwoConstraints) {
+ FLAGS_min_target_id = 0;
+ FLAGS_max_target_id = 1;
+
ceres::examples::MapOfPoses target_poses;
target_poses[0] = Make2dPose(5.0, 0.0, M_PI);
target_poses[1] = Make2dPose(-5.0, 0.0, -M_PI_2);
@@ -390,6 +399,9 @@
}
TEST(TargetMapperTest, TwoTargetsOneNoisyConstraint) {
+ FLAGS_min_target_id = 0;
+ FLAGS_max_target_id = 1;
+
ceres::examples::MapOfPoses target_poses;
target_poses[0] = Make2dPose(5.0, 0.0, M_PI);
target_poses[1] = Make2dPose(-5.0, 0.0, 0.0);
@@ -549,33 +561,6 @@
.value();
EXPECT_POSE_NEAR(mapper_target_pose, actual_target_pose.pose);
}
-
- //
- // See what happens when we don't start with the
- // correct values
- //
- for (auto [target_id, target_pose] : target_poses) {
- // Skip first pose, since that needs to be correct
- // and is fixed in the solver
- if (target_id != 1) {
- ceres::examples::Pose3d bad_pose{
- Eigen::Vector3d::Zero(),
- PoseUtils::EulerAnglesToQuaternion(Eigen::Vector3d::Zero())};
- target_poses[target_id] = bad_pose;
- }
- }
-
- frc971::vision::TargetMapper mapper_bad_poses(target_poses,
- target_constraints);
- mapper_bad_poses.Solve(kFieldName);
-
- for (auto [target_pose_id, mapper_target_pose] :
- mapper_bad_poses.target_poses()) {
- TargetMapper::TargetPose actual_target_pose =
- TargetMapper::GetTargetPoseById(actual_target_poses, target_pose_id)
- .value();
- EXPECT_POSE_NEAR(mapper_target_pose, actual_target_pose.pose);
- }
}
} // namespace frc971::vision
diff --git a/scouting/db/db.go b/scouting/db/db.go
index ca1af9e..34f2dac 100644
--- a/scouting/db/db.go
+++ b/scouting/db/db.go
@@ -37,6 +37,7 @@
LowConesAuto, MiddleConesAuto, HighConesAuto, ConesDroppedAuto int32
LowCubes, MiddleCubes, HighCubes, CubesDropped int32
LowCones, MiddleCones, HighCones, ConesDropped int32
+ SuperchargedPieces int32
AvgCycle int64
DockedAuto, EngagedAuto, BalanceAttemptAuto bool
Docked, Engaged, BalanceAttempt bool
@@ -64,7 +65,7 @@
Notes string
GoodDriving bool
BadDriving bool
- SolidPickup bool
+ SolidPlacing bool
SketchyPlacing bool
GoodDefense bool
BadDefense bool
@@ -308,7 +309,7 @@
Notes: data.Notes,
GoodDriving: data.GoodDriving,
BadDriving: data.BadDriving,
- SolidPickup: data.SolidPickup,
+ SolidPlacing: data.SolidPlacing,
SketchyPlacing: data.SketchyPlacing,
GoodDefense: data.GoodDefense,
BadDefense: data.BadDefense,
diff --git a/scouting/db/db_test.go b/scouting/db/db_test.go
index b0d34d8..9c48cba 100644
--- a/scouting/db/db_test.go
+++ b/scouting/db/db_test.go
@@ -150,7 +150,7 @@
LowConesAuto: 1, MiddleConesAuto: 0, HighConesAuto: 2,
ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 2,
HighCubes: 1, CubesDropped: 0, LowCones: 0,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 0, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: false, CollectedBy: "emma",
@@ -162,7 +162,7 @@
LowConesAuto: 2, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 1, MiddleCubes: 0,
HighCubes: 0, CubesDropped: 1, LowCones: 0,
- MiddleCones: 0, HighCones: 1, ConesDropped: 0,
+ MiddleCones: 0, HighCones: 1, ConesDropped: 0, SuperchargedPieces: 1,
AvgCycle: 0, DockedAuto: false, EngagedAuto: false,
BalanceAttemptAuto: true, Docked: true, Engaged: true,
BalanceAttempt: false, CollectedBy: "tyler",
@@ -174,7 +174,7 @@
LowConesAuto: 0, MiddleConesAuto: 2, HighConesAuto: 1,
ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 0,
HighCubes: 2, CubesDropped: 1, LowCones: 1,
- MiddleCones: 1, HighCones: 0, ConesDropped: 1,
+ MiddleCones: 1, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 0, DockedAuto: false, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "isaac",
@@ -186,7 +186,7 @@
LowConesAuto: 1, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 0, LowCubes: 0, MiddleCubes: 1,
HighCubes: 2, CubesDropped: 1, LowCones: 0,
- MiddleCones: 1, HighCones: 0, ConesDropped: 0,
+ MiddleCones: 1, HighCones: 0, ConesDropped: 0, SuperchargedPieces: 0,
AvgCycle: 0, DockedAuto: true, EngagedAuto: true,
BalanceAttemptAuto: true, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "will",
@@ -198,7 +198,7 @@
LowConesAuto: 0, MiddleConesAuto: 1, HighConesAuto: 1,
ConesDroppedAuto: 1, LowCubes: 1, MiddleCubes: 0,
HighCubes: 0, CubesDropped: 2, LowCones: 1,
- MiddleCones: 1, HighCones: 0, ConesDropped: 1,
+ MiddleCones: 1, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 0, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: true, Engaged: false,
BalanceAttempt: false, CollectedBy: "unkown",
@@ -248,7 +248,7 @@
LowConesAuto: 1, MiddleConesAuto: 0, HighConesAuto: 2,
ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 2,
HighCubes: 1, CubesDropped: 0, LowCones: 0,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 0, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: false, CollectedBy: "emma",
@@ -260,7 +260,7 @@
LowConesAuto: 2, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 1, MiddleCubes: 0,
HighCubes: 0, CubesDropped: 1, LowCones: 0,
- MiddleCones: 0, HighCones: 1, ConesDropped: 0,
+ MiddleCones: 0, HighCones: 1, ConesDropped: 0, SuperchargedPieces: 1,
AvgCycle: 0, DockedAuto: true, EngagedAuto: true,
BalanceAttemptAuto: true, Docked: false, Engaged: false,
BalanceAttempt: false, CollectedBy: "tyler",
@@ -272,7 +272,7 @@
LowConesAuto: 1, MiddleConesAuto: 0, HighConesAuto: 2,
ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 2,
HighCubes: 1, CubesDropped: 0, LowCones: 0,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 0, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: true, Engaged: false,
BalanceAttempt: true, CollectedBy: "emma",
@@ -329,7 +329,7 @@
LowConesAuto: 0, MiddleConesAuto: 2, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 1,
HighCubes: 2, CubesDropped: 1, LowCones: 1,
- MiddleCones: 0, HighCones: 1, ConesDropped: 2,
+ MiddleCones: 0, HighCones: 1, ConesDropped: 2, SuperchargedPieces: 0,
AvgCycle: 58, DockedAuto: false, EngagedAuto: false,
BalanceAttemptAuto: true, Docked: true, Engaged: true,
BalanceAttempt: false, CollectedBy: "unknown",
@@ -341,7 +341,7 @@
LowConesAuto: 0, MiddleConesAuto: 1, HighConesAuto: 0,
ConesDroppedAuto: 0, LowCubes: 2, MiddleCubes: 0,
HighCubes: 1, CubesDropped: 0, LowCones: 0,
- MiddleCones: 2, HighCones: 1, ConesDropped: 0,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 0, SuperchargedPieces: 1,
AvgCycle: 34, DockedAuto: true, EngagedAuto: true,
BalanceAttemptAuto: false, Docked: true, Engaged: false,
BalanceAttempt: false, CollectedBy: "simon",
@@ -353,7 +353,7 @@
LowConesAuto: 1, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 2,
HighCubes: 0, CubesDropped: 0, LowCones: 2,
- MiddleCones: 0, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 0, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 50, DockedAuto: false, EngagedAuto: false,
BalanceAttemptAuto: true, Docked: false, Engaged: false,
BalanceAttempt: false, CollectedBy: "eliza",
@@ -365,7 +365,7 @@
LowConesAuto: 0, MiddleConesAuto: 2, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 1,
HighCubes: 2, CubesDropped: 1, LowCones: 0,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 49, DockedAuto: true, EngagedAuto: false,
Docked: false, Engaged: false, CollectedBy: "isaac",
},
@@ -376,7 +376,7 @@
LowConesAuto: 1, MiddleConesAuto: 1, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 1, MiddleCubes: 2,
HighCubes: 0, CubesDropped: 0, LowCones: 1,
- MiddleCones: 1, HighCones: 1, ConesDropped: 0,
+ MiddleCones: 1, HighCones: 1, ConesDropped: 0, SuperchargedPieces: 0,
AvgCycle: 70, DockedAuto: true, EngagedAuto: true,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "sam",
@@ -391,7 +391,7 @@
LowConesAuto: 1, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 2,
HighCubes: 0, CubesDropped: 0, LowCones: 2,
- MiddleCones: 0, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 0, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 50, DockedAuto: false, EngagedAuto: false,
BalanceAttemptAuto: true, Docked: false, Engaged: false,
BalanceAttempt: false, CollectedBy: "eliza",
@@ -403,7 +403,7 @@
LowConesAuto: 1, MiddleConesAuto: 1, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 1, MiddleCubes: 2,
HighCubes: 0, CubesDropped: 0, LowCones: 1,
- MiddleCones: 1, HighCones: 1, ConesDropped: 0,
+ MiddleCones: 1, HighCones: 1, ConesDropped: 0, SuperchargedPieces: 0,
AvgCycle: 70, DockedAuto: true, EngagedAuto: true,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "sam",
@@ -683,7 +683,7 @@
LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 2,
ConesDroppedAuto: 1, LowCubes: 1, MiddleCubes: 2,
HighCubes: 1, CubesDropped: 0, LowCones: 2,
- MiddleCones: 0, HighCones: 2, ConesDropped: 1,
+ MiddleCones: 0, HighCones: 2, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 51, DockedAuto: true, EngagedAuto: true,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "isaac",
@@ -695,7 +695,7 @@
LowConesAuto: 1, MiddleConesAuto: 1, HighConesAuto: 0,
ConesDroppedAuto: 0, LowCubes: 2, MiddleCubes: 2,
HighCubes: 1, CubesDropped: 0, LowCones: 1,
- MiddleCones: 0, HighCones: 2, ConesDropped: 1,
+ MiddleCones: 0, HighCones: 2, ConesDropped: 1, SuperchargedPieces: 1,
AvgCycle: 39, DockedAuto: false, EngagedAuto: false,
BalanceAttemptAuto: true, Docked: false, Engaged: false,
BalanceAttempt: false, CollectedBy: "jack",
@@ -707,7 +707,7 @@
LowConesAuto: 2, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 2, MiddleCubes: 2,
HighCubes: 0, CubesDropped: 0, LowCones: 1,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 45, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: true, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "martin",
@@ -719,7 +719,7 @@
LowConesAuto: 2, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 2, MiddleCubes: 2,
HighCubes: 0, CubesDropped: 0, LowCones: 2,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 34, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: true, Engaged: false,
BalanceAttempt: false, CollectedBy: "unknown",
@@ -875,11 +875,11 @@
expected := []string{"Note 1", "Note 3"}
- err := fixture.db.AddNotes(NotesData{TeamNumber: 1234, Notes: "Note 1", GoodDriving: true, BadDriving: false, SolidPickup: false, SketchyPlacing: true, GoodDefense: false, BadDefense: true, EasilyDefended: true})
+ err := fixture.db.AddNotes(NotesData{TeamNumber: 1234, Notes: "Note 1", GoodDriving: true, BadDriving: false, SolidPlacing: false, SketchyPlacing: true, GoodDefense: false, BadDefense: true, EasilyDefended: true})
check(t, err, "Failed to add Note")
- err = fixture.db.AddNotes(NotesData{TeamNumber: 1235, Notes: "Note 2", GoodDriving: false, BadDriving: true, SolidPickup: false, SketchyPlacing: true, GoodDefense: false, BadDefense: false, EasilyDefended: false})
+ err = fixture.db.AddNotes(NotesData{TeamNumber: 1235, Notes: "Note 2", GoodDriving: false, BadDriving: true, SolidPlacing: false, SketchyPlacing: true, GoodDefense: false, BadDefense: false, EasilyDefended: false})
check(t, err, "Failed to add Note")
- err = fixture.db.AddNotes(NotesData{TeamNumber: 1234, Notes: "Note 3", GoodDriving: true, BadDriving: false, SolidPickup: false, SketchyPlacing: true, GoodDefense: true, BadDefense: false, EasilyDefended: true})
+ err = fixture.db.AddNotes(NotesData{TeamNumber: 1234, Notes: "Note 3", GoodDriving: true, BadDriving: false, SolidPlacing: false, SketchyPlacing: true, GoodDefense: true, BadDefense: false, EasilyDefended: true})
check(t, err, "Failed to add Note")
actual, err := fixture.db.QueryNotes(1234)
diff --git a/scouting/scouting_test.cy.js b/scouting/scouting_test.cy.js
index 8ac1880..1d7620a 100644
--- a/scouting/scouting_test.cy.js
+++ b/scouting/scouting_test.cy.js
@@ -20,6 +20,17 @@
cy.get(fieldSelector).type('{selectAll}' + value);
}
+// Click on a random team in the Match list. The exact details here are not
+// important, but we need to know what they are. This could as well be any
+// other team from any other match.
+function clickSemiFinal2Match3Team5254() {
+ // On the 87th row of matches (index 86) click on the second team
+ // (index 1) which resolves to team 5254 in semi final 2 match 3.
+ cy.get('button.match-item')
+ .eq(86 * 6 + 1)
+ .click();
+}
+
// Moves the nth slider left or right. A positive "adjustBy" value moves the
// slider to the right. A negative value moves the slider to the left.
//
@@ -88,29 +99,26 @@
cy.get('.badge').eq(89).contains('Final 1 Match 3');
});
- it('should: prefill the match information.', () => {
- headerShouldBe('Matches');
+ it('should: be let users enter match information manually.', () => {
+ switchToTab('Entry');
+ headerShouldBe(' Team Selection ');
- // On the 87th row of matches (index 86) click on the second team
- // (index 1) which resolves to team 5254 in semi final 2 match 3.
- cy.get('button.match-item')
- .eq(86 * 6 + 1)
- .click();
+ setInputTo('#match_number', '3');
+ setInputTo('#team_number', '5254');
+ setInputTo('#set_number', '2');
+ setInputTo('#comp_level', '3: sf');
- headerShouldBe('Team Selection');
- cy.get('#match_number').should('have.value', '3');
- cy.get('#team_number').should('have.value', '5254');
- cy.get('#set_number').should('have.value', '2');
- cy.get('#comp_level').should('have.value', '3: sf');
+ clickButton('Next');
+
+ headerShouldBe('5254 Init ');
});
//TODO(FILIP): Verify last action when the last action header gets added.
it('should: be able to submit data scouting.', () => {
- switchToTab('Data Entry');
- headerShouldBe('Team Selection');
- clickButton('Next');
+ clickSemiFinal2Match3Team5254();
// Select Starting Position.
+ headerShouldBe('5254 Init ');
cy.get('[type="radio"]').first().check();
clickButton('Start Match');
@@ -132,16 +140,14 @@
cy.get('[type="checkbox"]').check();
clickButton('End Match');
- headerShouldBe('Review and Submit');
+ headerShouldBe('5254 Review and Submit ');
clickButton('Submit');
- headerShouldBe('Success');
+ headerShouldBe('5254 Success ');
});
it('should: be able to return to correct screen with undo for pick and place.', () => {
- switchToTab('Data Entry');
- headerShouldBe('Team Selection');
- clickButton('Next');
+ clickSemiFinal2Match3Team5254();
// Select Starting Position.
cy.get('[type="radio"]').first().check();
@@ -154,13 +160,13 @@
clickButton('UNDO');
// User should be back on pickup screen.
- headerShouldBe('Pickup');
+ headerShouldBe('5254 Pickup ');
// Check the same thing but for undoing place.
clickButton('CUBE');
clickButton('MID');
clickButton('UNDO');
- headerShouldBe('Place');
+ headerShouldBe('5254 Place ');
});
it('should: submit note scouting for multiple teams', () => {
diff --git a/scouting/webserver/requests/debug/cli/cli_test.py b/scouting/webserver/requests/debug/cli/cli_test.py
index 0c2beab..b944564 100644
--- a/scouting/webserver/requests/debug/cli/cli_test.py
+++ b/scouting/webserver/requests/debug/cli/cli_test.py
@@ -105,7 +105,7 @@
"notes": "A very inspiring and useful comment",
"good_driving": True,
"bad_driving": False,
- "solid_pickup": False,
+ "solid_placing": False,
"sketchy_placing": True,
"good_defense": False,
"bad_defense": False,
@@ -128,7 +128,7 @@
Notes: (string) (len=35) "A very inspiring and useful comment",
GoodDriving: (bool) true,
BadDriving: (bool) false,
- SolidPickup: (bool) false,
+ SolidPlacing: (bool) false,
SketchyPlacing: (bool) true,
GoodDefense: (bool) false,
BadDefense: (bool) false,
diff --git a/scouting/webserver/requests/messages/request_2023_data_scouting_response.fbs b/scouting/webserver/requests/messages/request_2023_data_scouting_response.fbs
index b472c58..341b012 100644
--- a/scouting/webserver/requests/messages/request_2023_data_scouting_response.fbs
+++ b/scouting/webserver/requests/messages/request_2023_data_scouting_response.fbs
@@ -24,6 +24,7 @@
middle_cones:int (id:16);
high_cones:int (id:17);
cones_dropped:int (id:18);
+ supercharged_pieces:int (id:29);
// Time in nanoseconds.
avg_cycle: int64 (id:19);
docked_auto: bool (id:20);
@@ -40,4 +41,4 @@
stats_list:[Stats2023] (id:0);
}
-root_type Request2023DataScoutingResponse;
+root_type Request2023DataScoutingResponse;
\ No newline at end of file
diff --git a/scouting/webserver/requests/messages/request_all_notes_response.fbs b/scouting/webserver/requests/messages/request_all_notes_response.fbs
index 983ff62..70504d3 100644
--- a/scouting/webserver/requests/messages/request_all_notes_response.fbs
+++ b/scouting/webserver/requests/messages/request_all_notes_response.fbs
@@ -5,7 +5,7 @@
notes:string (id: 1);
good_driving:bool (id: 2);
bad_driving:bool (id: 3);
- solid_pickup:bool (id: 4);
+ solid_placing:bool (id: 4);
sketchy_placing:bool (id: 5);
good_defense:bool (id: 6);
bad_defense:bool (id: 7);
diff --git a/scouting/webserver/requests/messages/submit_actions.fbs b/scouting/webserver/requests/messages/submit_actions.fbs
index d8aa98d..d269788 100644
--- a/scouting/webserver/requests/messages/submit_actions.fbs
+++ b/scouting/webserver/requests/messages/submit_actions.fbs
@@ -12,7 +12,8 @@
enum ScoreLevel: short {
kLow,
kMiddle,
- kHigh
+ kHigh,
+ kSupercharged,
}
table AutoBalanceAction {
diff --git a/scouting/webserver/requests/messages/submit_notes.fbs b/scouting/webserver/requests/messages/submit_notes.fbs
index cee4dee..845a601 100644
--- a/scouting/webserver/requests/messages/submit_notes.fbs
+++ b/scouting/webserver/requests/messages/submit_notes.fbs
@@ -5,7 +5,7 @@
notes:string (id: 1);
good_driving:bool (id: 2);
bad_driving:bool (id: 3);
- solid_pickup:bool (id: 4);
+ solid_placing:bool (id: 4);
sketchy_placing:bool (id: 5);
good_defense:bool (id: 6);
bad_defense:bool (id: 7);
diff --git a/scouting/webserver/requests/requests.go b/scouting/webserver/requests/requests.go
index 8646a30..a6ee44c 100644
--- a/scouting/webserver/requests/requests.go
+++ b/scouting/webserver/requests/requests.go
@@ -355,7 +355,7 @@
Notes: string(request.Notes()),
GoodDriving: bool(request.GoodDriving()),
BadDriving: bool(request.BadDriving()),
- SolidPickup: bool(request.SolidPickup()),
+ SolidPlacing: bool(request.SolidPlacing()),
SketchyPlacing: bool(request.SketchyPlacing()),
GoodDefense: bool(request.GoodDefense()),
BadDefense: bool(request.BadDefense()),
@@ -380,7 +380,7 @@
stat := db.Stats2023{TeamNumber: string(submitActions.TeamNumber()), MatchNumber: submitActions.MatchNumber(), SetNumber: submitActions.SetNumber(), CompLevel: string(submitActions.CompLevel()),
StartingQuadrant: 0, LowCubesAuto: 0, MiddleCubesAuto: 0, HighCubesAuto: 0, CubesDroppedAuto: 0,
LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0, ConesDroppedAuto: 0, LowCubes: 0, MiddleCubes: 0, HighCubes: 0,
- CubesDropped: 0, LowCones: 0, MiddleCones: 0, HighCones: 0, ConesDropped: 0, AvgCycle: 0, CollectedBy: string(submitActions.CollectedBy()),
+ CubesDropped: 0, LowCones: 0, MiddleCones: 0, HighCones: 0, ConesDropped: 0, SuperchargedPieces: 0, AvgCycle: 0, CollectedBy: string(submitActions.CollectedBy()),
}
// Loop over all actions.
for i := 0; i < submitActions.ActionsListLength(); i++ {
@@ -460,6 +460,8 @@
stat.HighConesAuto += 1
} else if object == 1 && level == 2 && auto == false {
stat.HighCones += 1
+ } else if level == 3 {
+ stat.SuperchargedPieces += 1
} else {
return db.Stats2023{}, errors.New(fmt.Sprintf("Got unknown ObjectType/ScoreLevel/Auto combination"))
}
@@ -541,6 +543,7 @@
MiddleCones: stat.MiddleCones,
HighCones: stat.HighCones,
ConesDropped: stat.ConesDropped,
+ SuperchargedPieces: stat.SuperchargedPieces,
AvgCycle: stat.AvgCycle,
DockedAuto: stat.DockedAuto,
EngagedAuto: stat.EngagedAuto,
@@ -737,7 +740,7 @@
Notes: note.Notes,
GoodDriving: note.GoodDriving,
BadDriving: note.BadDriving,
- SolidPickup: note.SolidPickup,
+ SolidPlacing: note.SolidPlacing,
SketchyPlacing: note.SketchyPlacing,
GoodDefense: note.GoodDefense,
BadDefense: note.BadDefense,
diff --git a/scouting/webserver/requests/requests_test.go b/scouting/webserver/requests/requests_test.go
index ac644ea..b6f09fc 100644
--- a/scouting/webserver/requests/requests_test.go
+++ b/scouting/webserver/requests/requests_test.go
@@ -129,7 +129,7 @@
LowConesAuto: 1, MiddleConesAuto: 2, HighConesAuto: 1,
ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 1,
HighCubes: 2, CubesDropped: 1, LowCones: 1,
- MiddleCones: 2, HighCones: 0, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 34, DockedAuto: true, EngagedAuto: true,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: false, CollectedBy: "alex",
@@ -141,7 +141,7 @@
LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 0,
HighCubes: 1, CubesDropped: 0, LowCones: 0,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 53, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "bob",
@@ -214,7 +214,7 @@
LowConesAuto: 1, MiddleConesAuto: 2, HighConesAuto: 1,
ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 1,
HighCubes: 2, CubesDropped: 1, LowCones: 1,
- MiddleCones: 2, HighCones: 0, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 34, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "isaac",
@@ -226,7 +226,7 @@
LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 0,
HighCubes: 1, CubesDropped: 0, LowCones: 0,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 53, DockedAuto: false, EngagedAuto: false,
BalanceAttemptAuto: true, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "unknown",
@@ -255,7 +255,7 @@
LowConesAuto: 1, MiddleConesAuto: 2, HighConesAuto: 1,
ConesDroppedAuto: 0, LowCubes: 1, MiddleCubes: 1,
HighCubes: 2, CubesDropped: 1, LowCones: 1,
- MiddleCones: 2, HighCones: 0, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 0, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 34, DockedAuto: true, EngagedAuto: false,
BalanceAttemptAuto: false, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "isaac",
@@ -267,7 +267,7 @@
LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 1, LowCubes: 0, MiddleCubes: 0,
HighCubes: 1, CubesDropped: 0, LowCones: 0,
- MiddleCones: 2, HighCones: 1, ConesDropped: 1,
+ MiddleCones: 2, HighCones: 1, ConesDropped: 1, SuperchargedPieces: 0,
AvgCycle: 53, DockedAuto: false, EngagedAuto: false,
BalanceAttemptAuto: true, Docked: false, Engaged: false,
BalanceAttempt: true, CollectedBy: "unknown",
@@ -368,6 +368,27 @@
},
{
ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePickupObjectAction,
+ Value: &submit_actions.PickupObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ Auto: false,
+ },
+ },
+ Timestamp: 3500,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
+ Type: submit_actions.ActionTypePlaceObjectAction,
+ Value: &submit_actions.PlaceObjectActionT{
+ ObjectType: submit_actions.ObjectTypekCube,
+ ScoreLevel: submit_actions.ScoreLevelkSupercharged,
+ Auto: false,
+ },
+ },
+ Timestamp: 3900,
+ },
+ {
+ ActionTaken: &submit_actions.ActionTypeT{
Type: submit_actions.ActionTypeEndMatchAction,
Value: &submit_actions.EndMatchActionT{
Docked: true,
@@ -375,7 +396,7 @@
BalanceAttempt: true,
},
},
- Timestamp: 4000,
+ Timestamp: 4200,
},
},
}).Pack(builder))
@@ -394,8 +415,8 @@
LowConesAuto: 0, MiddleConesAuto: 0, HighConesAuto: 0,
ConesDroppedAuto: 0, LowCubes: 0, MiddleCubes: 0,
HighCubes: 0, CubesDropped: 0, LowCones: 0,
- MiddleCones: 0, HighCones: 1, ConesDropped: 0,
- AvgCycle: 1100, DockedAuto: true, EngagedAuto: true,
+ MiddleCones: 0, HighCones: 1, ConesDropped: 0, SuperchargedPieces: 1,
+ AvgCycle: 950, DockedAuto: true, EngagedAuto: true,
BalanceAttemptAuto: false, Docked: true, Engaged: false,
BalanceAttempt: true, CollectedBy: "katie",
}
@@ -418,7 +439,7 @@
Notes: "Notes",
GoodDriving: true,
BadDriving: false,
- SolidPickup: true,
+ SolidPlacing: true,
SketchyPlacing: false,
GoodDefense: true,
BadDefense: false,
@@ -436,7 +457,7 @@
Notes: "Notes",
GoodDriving: true,
BadDriving: false,
- SolidPickup: true,
+ SolidPlacing: true,
SketchyPlacing: false,
GoodDefense: true,
BadDefense: false,
@@ -456,7 +477,7 @@
Notes: "Notes",
GoodDriving: true,
BadDriving: false,
- SolidPickup: true,
+ SolidPlacing: true,
SketchyPlacing: false,
GoodDefense: true,
BadDefense: false,
@@ -684,7 +705,7 @@
Notes: "Notes",
GoodDriving: true,
BadDriving: false,
- SolidPickup: true,
+ SolidPlacing: true,
SketchyPlacing: false,
GoodDefense: true,
BadDefense: false,
@@ -695,7 +716,7 @@
Notes: "More Notes",
GoodDriving: false,
BadDriving: false,
- SolidPickup: false,
+ SolidPlacing: false,
SketchyPlacing: true,
GoodDefense: false,
BadDefense: true,
@@ -723,7 +744,7 @@
Notes: "Notes",
GoodDriving: true,
BadDriving: false,
- SolidPickup: true,
+ SolidPlacing: true,
SketchyPlacing: false,
GoodDefense: true,
BadDefense: false,
@@ -734,7 +755,7 @@
Notes: "More Notes",
GoodDriving: false,
BadDriving: false,
- SolidPickup: false,
+ SolidPlacing: false,
SketchyPlacing: true,
GoodDefense: false,
BadDefense: true,
diff --git a/scouting/www/app/app.ng.html b/scouting/www/app/app.ng.html
index 526cd61..b7f1873 100644
--- a/scouting/www/app/app.ng.html
+++ b/scouting/www/app/app.ng.html
@@ -72,18 +72,15 @@
*ngSwitchCase="'MatchList'"
></app-match-list>
<app-entry
- (switchTabsEvent)="switchTabTo($event)"
[teamNumber]="selectedTeamInMatch.teamNumber"
[matchNumber]="selectedTeamInMatch.matchNumber"
[setNumber]="selectedTeamInMatch.setNumber"
[compLevel]="selectedTeamInMatch.compLevel"
+ [skipTeamSelection]="navigatedFromMatchList"
*ngSwitchCase="'Entry'"
></app-entry>
<frc971-notes *ngSwitchCase="'Notes'"></frc971-notes>
<app-driver-ranking *ngSwitchCase="'DriverRanking'"></app-driver-ranking>
<shift-schedule *ngSwitchCase="'ShiftSchedule'"></shift-schedule>
- <app-view
- (switchTabsEvent)="switchTabTo($event)"
- *ngSwitchCase="'View'"
- ></app-view>
+ <app-view *ngSwitchCase="'View'"></app-view>
</ng-container>
diff --git a/scouting/www/app/app.ts b/scouting/www/app/app.ts
index f7d2770..c19895a 100644
--- a/scouting/www/app/app.ts
+++ b/scouting/www/app/app.ts
@@ -30,6 +30,9 @@
setNumber: 1,
compLevel: 'qm',
};
+ // Keep track of the match list automatically navigating the user to the
+ // Entry tab.
+ navigatedFromMatchList: boolean = false;
tab: Tab = 'MatchList';
@ViewChild('block_alerts') block_alerts: ElementRef;
@@ -54,7 +57,8 @@
selectTeamInMatch(teamInMatch: TeamInMatch) {
this.selectedTeamInMatch = teamInMatch;
- this.switchTabTo('Entry');
+ this.navigatedFromMatchList = true;
+ this.switchTabTo('Entry', false);
}
switchTabToGuarded(tab: Tab) {
@@ -69,11 +73,16 @@
}
}
if (shouldSwitch) {
- this.switchTabTo(tab);
+ this.switchTabTo(tab, true);
}
}
- private switchTabTo(tab: Tab) {
+ private switchTabTo(tab: Tab, wasGuarded: boolean) {
+ if (wasGuarded) {
+ // When the user navigated between tabs manually, we want to reset some
+ // state.
+ this.navigatedFromMatchList = false;
+ }
this.tab = tab;
}
}
diff --git a/scouting/www/entry/entry.component.ts b/scouting/www/entry/entry.component.ts
index 71c8de2..b56948a 100644
--- a/scouting/www/entry/entry.component.ts
+++ b/scouting/www/entry/entry.component.ts
@@ -97,7 +97,7 @@
templateUrl: './entry.ng.html',
styleUrls: ['../app/common.css', './entry.component.css'],
})
-export class EntryComponent {
+export class EntryComponent implements OnInit {
// Re-export the type here so that we can use it in the `[value]` attribute
// of radio buttons.
readonly COMP_LEVELS = COMP_LEVELS;
@@ -106,11 +106,11 @@
readonly ScoreLevel = ScoreLevel;
section: Section = 'Team Selection';
- @Output() switchTabsEvent = new EventEmitter<string>();
@Input() matchNumber: number = 1;
@Input() teamNumber: number = 1;
@Input() setNumber: number = 1;
@Input() compLevel: CompLevel = 'qm';
+ @Input() skipTeamSelection = false;
actionList: ActionT[] = [];
errorMessage: string = '';
@@ -119,6 +119,12 @@
matchStartTimestamp: number = 0;
+ ngOnInit() {
+ // When the user navigated from the match list, we can skip the team
+ // selection. I.e. we trust that the user clicked the correct button.
+ this.section = this.skipTeamSelection ? 'Init' : 'Team Selection';
+ }
+
addAction(action: ActionT): void {
if (action.type == 'startMatchAction') {
// Unix nanosecond timestamp.
diff --git a/scouting/www/entry/entry.ng.html b/scouting/www/entry/entry.ng.html
index e304f2a..56056fc 100644
--- a/scouting/www/entry/entry.ng.html
+++ b/scouting/www/entry/entry.ng.html
@@ -1,5 +1,8 @@
<div class="header" #header>
- <h2>{{section}}</h2>
+ <h2>
+ <span *ngIf="section != 'Team Selection'">{{teamNumber}}</span>
+ {{section}}
+ </h2>
</div>
<ng-container [ngSwitch]="section">
<div
@@ -89,7 +92,13 @@
<h6 class="text-muted">
Last Action: {{actionList[actionList.length - 1].type}}
</h6>
- <div class="d-grid gap-5">
+ <!--
+ Decrease distance between buttons during auto to make space for auto balancing
+ selection and keep all buttons visible without scrolling on most devices.
+ -->
+ <div
+ [ngClass]="{'d-grid': true, 'gap-3': autoPhase === true, 'gap-5': autoPhase === false}"
+ >
<button class="btn btn-secondary" (click)="undoLastAction()">UNDO</button>
<button
class="btn btn-danger"
@@ -133,7 +142,7 @@
</div>
<button
*ngIf="autoPhase"
- class="btn btn-info"
+ class="btn btn-dark"
(click)="autoPhase = false; addAction({type: 'endAutoPhase'});"
>
Start Teleop
@@ -151,7 +160,13 @@
<h6 class="text-muted">
Last Action: {{actionList[actionList.length - 1].type}}
</h6>
- <div class="d-grid gap-5">
+ <!--
+ Decrease distance between buttons during auto to make space for auto balancing
+ selection and keep all buttons visible without scrolling on most devices.
+ -->
+ <div
+ [ngClass]="{'d-grid': true, 'gap-3': autoPhase === true, 'gap-5': autoPhase === false}"
+ >
<button class="btn btn-secondary" (click)="undoLastAction()">UNDO</button>
<button
class="btn btn-danger"
@@ -177,6 +192,15 @@
>
LOW
</button>
+ <!-- Impossible to place supercharged pieces in auto. -->
+ <div *ngIf="autoPhase == false" class="d-grid gap-2">
+ <button
+ class="btn btn-dark"
+ (click)="changeSectionTo('Pickup'); addAction({type: 'placeObjectAction', scoreLevel: ScoreLevel.kSupercharged});"
+ >
+ SUPERCHARGED
+ </button>
+ </div>
<!-- 'Balancing' during auto. -->
<div *ngIf="autoPhase" class="d-grid gap-2">
<label>
@@ -201,7 +225,7 @@
</div>
<button
*ngIf="autoPhase"
- class="btn btn-info"
+ class="btn btn-dark"
(click)="autoPhase = false; addAction({type: 'endAutoPhase'});"
>
Start Teleop
diff --git a/scouting/www/notes/notes.component.ts b/scouting/www/notes/notes.component.ts
index 5d1c4a2..2786717 100644
--- a/scouting/www/notes/notes.component.ts
+++ b/scouting/www/notes/notes.component.ts
@@ -40,7 +40,7 @@
interface Keywords {
goodDriving: boolean;
badDriving: boolean;
- solidPickup: boolean;
+ solidPlacing: boolean;
sketchyPlacing: boolean;
goodDefense: boolean;
badDefense: boolean;
@@ -56,7 +56,7 @@
const KEYWORD_CHECKBOX_LABELS = {
goodDriving: 'Good Driving',
badDriving: 'Bad Driving',
- solidPickup: 'Solid Pickup',
+ solidPlacing: 'Solid Placing',
sketchyPlacing: 'Sketchy Placing',
goodDefense: 'Good Defense',
badDefense: 'Bad Defense',
@@ -115,7 +115,7 @@
keywordsData: {
goodDriving: false,
badDriving: false,
- solidPickup: false,
+ solidPlacing: false,
sketchyPlacing: false,
goodDefense: false,
badDefense: false,
@@ -152,7 +152,7 @@
dataFb,
this.newData[i].keywordsData.goodDriving,
this.newData[i].keywordsData.badDriving,
- this.newData[i].keywordsData.solidPickup,
+ this.newData[i].keywordsData.solidPlacing,
this.newData[i].keywordsData.sketchyPlacing,
this.newData[i].keywordsData.goodDefense,
this.newData[i].keywordsData.badDefense,
diff --git a/scouting/www/view/view.component.ts b/scouting/www/view/view.component.ts
index f7d6ce8..561ae08 100644
--- a/scouting/www/view/view.component.ts
+++ b/scouting/www/view/view.component.ts
@@ -171,8 +171,8 @@
if (entry.badDriving()) {
parsedKeywords += 'Bad Driving ';
}
- if (entry.solidPickup()) {
- parsedKeywords += 'Solid Pickup ';
+ if (entry.solidPlacing()) {
+ parsedKeywords += 'Solid Placing ';
}
if (entry.sketchyPlacing()) {
parsedKeywords += 'Sketchy Placing ';
diff --git a/y2023/autonomous/autonomous_actor.cc b/y2023/autonomous/autonomous_actor.cc
index 58c31d0..cd4d4f1 100644
--- a/y2023/autonomous/autonomous_actor.cc
+++ b/y2023/autonomous/autonomous_actor.cc
@@ -475,7 +475,13 @@
splines[1].Start();
std::this_thread::sleep_for(chrono::milliseconds(300));
+ Neutral();
+
+ if (!splines[1].WaitForSplineDistanceTraveled(3.2)) return;
HighCubeScore();
+ AOS_LOG(
+ INFO, "Extending arm %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
if (!splines[1].WaitForSplineDistanceRemaining(0.08)) return;
AOS_LOG(
@@ -521,10 +527,17 @@
if (!splines[3].WaitForPlan()) return;
splines[3].Start();
+ std::this_thread::sleep_for(chrono::milliseconds(400));
+ Neutral();
+
AOS_LOG(
INFO, "Driving back %lf s\n",
aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
+ if (!splines[3].WaitForSplineDistanceTraveled(3.5)) return;
+ AOS_LOG(
+ INFO, "Extending arm %lf s\n",
+ aos::time::DurationInSeconds(aos::monotonic_clock::now() - start_time));
MidCubeScore();
if (!splines[3].WaitForSplineDistanceRemaining(0.07)) return;
diff --git a/y2023/autonomous/splines/splinecable.0.json b/y2023/autonomous/splines/splinecable.0.json
index 3fdcfbe..3a8a1c8 100644
--- a/y2023/autonomous/splines/splinecable.0.json
+++ b/y2023/autonomous/splines/splinecable.0.json
@@ -1 +1 @@
-{"spline_count": 1, "spline_x": [-6.468141183035714, -6.142335156250001, -5.834629464285714, -2.6851712053571433, -2.2145624999999995, -1.7620541294642855], "spline_y": [-3.493364620535714, -3.493364620535714, -3.4752642857142853, -3.0951572544642856, -3.0770569196428568, -3.0770569196428568], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.0}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.0}, {"constraint_type": "VOLTAGE", "value": 10.0}]}
\ No newline at end of file
+{"spline_count": 2, "spline_x": [6.468141183035714, 6.156227508178545, 5.627928372772197, 5.618126908868124, 4.926607785226736, 4.384253622459038, 3.8418994596913407, 3.448710257797334, 2.6702357572801336, 1.9707990587626902, 1.441511105732058], "spline_y": [-3.493364620535714, -3.4921188608837532, -3.431437306632174, -3.364982889102878, -3.381212722774612, -3.3815433034902798, -3.3818738842059477, -3.3663052119655514, -3.293883383936489, -3.2050645805145246, -3.125670625960137], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.5}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.0}, {"constraint_type": "VOLTAGE", "value": 12.0}, {"constraint_type": "VELOCITY", "value": 1.5, "start_distance": 1.6, "end_distance": 2.75}]}
\ No newline at end of file
diff --git a/y2023/autonomous/splines/splinecable.1.json b/y2023/autonomous/splines/splinecable.1.json
index b9b4fdd..bf6838d 100644
--- a/y2023/autonomous/splines/splinecable.1.json
+++ b/y2023/autonomous/splines/splinecable.1.json
@@ -1 +1 @@
-{"spline_count": 1, "spline_x": [-1.7620541294642855, -2.2145624999999995, -2.6851712053571433, -5.8165291294642865, -6.124234821428573, -6.450040848214286], "spline_y": [-3.0770569196428568, -3.0770569196428568, -3.0951572544642856, -2.9141539062499993, -2.932254241071428, -2.932254241071428], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.0}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.0}, {"constraint_type": "VOLTAGE", "value": 10.0}]}
\ No newline at end of file
+{"spline_count": 2, "spline_x": [1.441511105732058, 2.158787794162399, 2.644327791138681, 3.0017835551344163, 3.810734918966552, 4.3709130304548385, 4.931091141943125, 5.242496001087563, 5.544694674297983, 5.965729060465805, 6.444059695844368], "spline_y": [-3.125670625960137, -3.233263161324085, -3.2028042659537914, -3.139500351375334, -3.125566969972238, -3.126688937308022, -3.127810904643806, -3.143988220718469, -2.9893341041515376, -2.943814113563144, -2.9458417329239843], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.0}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.0}, {"constraint_type": "VOLTAGE", "value": 12.0}, {"constraint_type": "VELOCITY", "value": 1.5, "start_distance": 1.9, "end_distance": 10.0}]}
\ No newline at end of file
diff --git a/y2023/autonomous/splines/splinecable.2.json b/y2023/autonomous/splines/splinecable.2.json
index cef0375..1caf288 100644
--- a/y2023/autonomous/splines/splinecable.2.json
+++ b/y2023/autonomous/splines/splinecable.2.json
@@ -1 +1 @@
-{"spline_count": 1, "spline_x": [-6.450040848214286, -6.124234821428573, -5.8165291294642865, -2.9023752232142854, -2.1059604910714285, -1.6353517857142856], "spline_y": [-2.932254241071428, -2.932254241071428, -2.9141539062499993, -3.2218595982142855, -2.6607492187499995, -2.244441517857142], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.0}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.0}, {"constraint_type": "VOLTAGE", "value": 10.0}]}
\ No newline at end of file
+{"spline_count": 2, "spline_x": [6.444059695844368, 5.977202894617023, 5.571532532121525, 5.64631894401731, 5.012590627058541, 4.364949107965309, 3.7173075888720764, 3.0557528676443795, 2.3031869947159427, 1.8583292479008144, 1.389061484581065], "spline_y": [-2.9458417329239843, -2.943862750565559, -2.96219050239874, -3.128181973537357, -3.0803143268366417, -3.079651639654858, -3.0789889524730745, -3.1255312248102225, -2.6948472310294784, -2.234117571800885, -1.9039073778940578], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.0}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.0}, {"constraint_type": "VOLTAGE", "value": 12.0}, {"constraint_type": "VELOCITY", "value": 1.5, "start_distance": 1.6, "end_distance": 2.55}]}
\ No newline at end of file
diff --git a/y2023/autonomous/splines/splinecable.3.json b/y2023/autonomous/splines/splinecable.3.json
index 60821fe..c49c1e8 100644
--- a/y2023/autonomous/splines/splinecable.3.json
+++ b/y2023/autonomous/splines/splinecable.3.json
@@ -1 +1 @@
-{"spline_count": 1, "spline_x": [-1.6353517857142856, -2.1059604910714285, -2.9023752232142854, -5.8165291294642865, -6.124234821428573, -6.450040848214286], "spline_y": [-2.244441517857142, -2.6607492187499995, -3.2218595982142855, -2.9141539062499993, -2.932254241071428, -2.932254241071428], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.0}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.0}, {"constraint_type": "VOLTAGE", "value": 10.0}]}
\ No newline at end of file
+{"spline_count": 2, "spline_x": [1.389061484581065, 2.1138941612201396, 2.2865982233539297, 3.1216159825232483, 3.763030179317507, 4.301019167021117, 4.839008154724727, 5.2735719333376885, 5.59798451182913, 5.734162859875811, 6.443454541551164], "spline_y": [-1.9039073778940578, -2.4139512321954397, -2.680729209318427, -3.1198721507158496, -3.0738965122418085, -3.0726645678919953, -3.071432623542182, -3.1149443733165967, -2.966418143397661, -2.9578217694545557, -2.957336170980663], "constraints": [{"constraint_type": "LONGITUDINAL_ACCELERATION", "value": 3.0}, {"constraint_type": "LATERAL_ACCELERATION", "value": 2.0}, {"constraint_type": "VOLTAGE", "value": 12.0}, {"constraint_type": "VELOCITY", "value": 1.5, "start_distance": 2.5, "end_distance": 3.6}]}
\ No newline at end of file
diff --git a/y2023/constants.cc b/y2023/constants.cc
index b64ac3d..3d3dfc2 100644
--- a/y2023/constants.cc
+++ b/y2023/constants.cc
@@ -95,7 +95,8 @@
0.0220711555235029 - 0.0162945074111813 + 0.00630344935527365 -
0.0164398318919943 - 0.145833494945215 + 0.234878799868491 +
0.125924230298394 + 0.147136306208754 - 0.69167546169753 -
- 0.308761538844425 + 0.610386472488493 + 0.08384162885249 + 0.0262274735196811;
+ 0.308761538844425 + 0.610386472488493 + 0.08384162885249 +
+ 0.0262274735196811 + 0.5153995156153;
arm_distal->zeroing.one_revolution_distance =
M_PI * 2.0 * constants::Values::kDistalEncoderRatio();
diff --git a/y2023/control_loops/python/graph_edit.py b/y2023/control_loops/python/graph_edit.py
index bbc7a1b..99b09af 100644
--- a/y2023/control_loops/python/graph_edit.py
+++ b/y2023/control_loops/python/graph_edit.py
@@ -244,6 +244,7 @@
self.set_size_request(ARM_AREA_WIDTH, ARM_AREA_HEIGHT)
self.center = (0, 0)
self.shape = (ARM_AREA_WIDTH, ARM_AREA_HEIGHT)
+ self.window_shape = (ARM_AREA_WIDTH, ARM_AREA_HEIGHT)
self.theta_version = False
self.init_extents()
@@ -326,9 +327,6 @@
def on_draw(self, widget, event):
cr = self.get_window().cairo_create()
- self.window_shape = (self.get_window().get_geometry().width,
- self.get_window().get_geometry().height)
-
cr.save()
cr.set_font_size(20)
cr.translate(self.window_shape[0] / 2, self.window_shape[1] / 2)
diff --git a/y2023/control_loops/python/graph_paths.py b/y2023/control_loops/python/graph_paths.py
index 93134c7..1efcd93 100644
--- a/y2023/control_loops/python/graph_paths.py
+++ b/y2023/control_loops/python/graph_paths.py
@@ -329,7 +329,7 @@
))
points['HPPickupBackConeUp'] = to_theta_with_circular_index_and_roll(
- -1.1200539, 1.330, np.pi / 2.0, circular_index=0)
+ -1.1200539, 1.325, np.pi / 2.0, circular_index=0)
named_segments.append(
ThetaSplineSegment(
diff --git a/y2023/control_loops/superstructure/arm/trajectory.cc b/y2023/control_loops/superstructure/arm/trajectory.cc
index d216467..88e3d1b 100644
--- a/y2023/control_loops/superstructure/arm/trajectory.cc
+++ b/y2023/control_loops/superstructure/arm/trajectory.cc
@@ -974,8 +974,8 @@
}
// Pull us back to the previous point until we aren't saturated anymore.
- double saturation_goal_velocity;
- double saturation_goal_acceleration;
+ double saturation_goal_velocity = 0.0;
+ double saturation_goal_acceleration = 0.0;
while (step_size > 0.01) {
USaturationSearch(goal_(0), last_goal_(0), goal_(1), last_goal_(1),
saturation_fraction_along_path_, arm_K, X, *trajectory_,
diff --git a/y2023/control_loops/superstructure/arm/trajectory_plot.cc b/y2023/control_loops/superstructure/arm/trajectory_plot.cc
index c56ced9..24bc8dd 100644
--- a/y2023/control_loops/superstructure/arm/trajectory_plot.cc
+++ b/y2023/control_loops/superstructure/arm/trajectory_plot.cc
@@ -15,10 +15,10 @@
DEFINE_bool(plot, true, "If true, plot");
DEFINE_bool(plot_thetas, true, "If true, plot the angles");
-DEFINE_double(alpha0_max, 20.0, "Max acceleration on joint 0.");
-DEFINE_double(alpha1_max, 30.0, "Max acceleration on joint 1.");
-DEFINE_double(alpha2_max, 60.0, "Max acceleration on joint 2.");
-DEFINE_double(vmax_plan, 10.0, "Max voltage to plan.");
+DEFINE_double(alpha0_max, 15.0, "Max acceleration on joint 0.");
+DEFINE_double(alpha1_max, 10.0, "Max acceleration on joint 1.");
+DEFINE_double(alpha2_max, 90.0, "Max acceleration on joint 2.");
+DEFINE_double(vmax_plan, 9.5, "Max voltage to plan.");
DEFINE_double(vmax_battery, 12.0, "Max battery voltage.");
DEFINE_double(time, 2.0, "Simulation time.");
@@ -36,12 +36,20 @@
Eigen::Matrix<double, 2, 4> spline_params;
- spline_params << 0.30426338, 0.42813912, 0.64902386, 0.55127045, -1.73611082,
- -1.64478944, -1.04763868, -0.82624244;
+ spline_params << 3.227752818257, 3.032002509469, 3.131082488348,
+ 3.141592653590, 0.914286433787, 0.436747899287, 0.235917057271,
+ 0.000000000000;
LOG(INFO) << "Spline " << spline_params;
NSpline<4, 2> spline(spline_params);
CosSpline cos_spline(spline,
- {{0.0, 0.1}, {0.3, 0.1}, {0.7, 0.2}, {1.0, 0.2}});
+ {
+ CosSpline::AlphaTheta{.alpha = 0.000000000000,
+ .theta = 1.570796326795},
+ CosSpline::AlphaTheta{.alpha = 0.050000000000,
+ .theta = 1.570796326795},
+ CosSpline::AlphaTheta{.alpha = 1.000000000000,
+ .theta = 0.000000000000},
+ });
Path distance_spline(cos_spline, 100);
Trajectory trajectory(&dynamics, &hybrid_roll.plant(),
@@ -300,10 +308,14 @@
(::Eigen::Matrix<double, 2, 1>() << arm_X(0), arm_X(2)).finished(),
sim_dt);
roll.Correct((::Eigen::Matrix<double, 1, 1>() << roll_X(0)).finished());
+ bool disabled = false;
+ if (t > 0.40 && t < 0.46) {
+ disabled = true;
+ }
follower.Update(
(Eigen::Matrix<double, 9, 1>() << arm_ekf.X_hat(), roll.X_hat())
.finished(),
- false, sim_dt, FLAGS_vmax_plan, FLAGS_vmax_battery);
+ disabled, sim_dt, FLAGS_vmax_plan, FLAGS_vmax_battery);
const ::Eigen::Matrix<double, 3, 1> theta_t =
trajectory.ThetaT(follower.goal()(0));
diff --git a/y2023/vision/target_mapping.cc b/y2023/vision/target_mapping.cc
index ba5f5d9..daba90c 100644
--- a/y2023/vision/target_mapping.cc
+++ b/y2023/vision/target_mapping.cc
@@ -5,7 +5,6 @@
#include "aos/util/mcap_logger.h"
#include "frc971/control_loops/pose.h"
#include "frc971/vision/calibration_generated.h"
-#include "frc971/vision/charuco_lib.h"
#include "frc971/vision/target_mapper.h"
#include "frc971/vision/visualize_robot.h"
#include "opencv2/aruco.hpp"
@@ -49,7 +48,10 @@
DEFINE_bool(solve, true, "Whether to solve for the field's target map.");
DEFINE_string(dump_constraints_to, "/tmp/constraints.txt",
"Write the target constraints to this path");
-DECLARE_uint64(frozen_target_id);
+DECLARE_int32(frozen_target_id);
+DECLARE_int32(min_target_id);
+DECLARE_int32(max_target_id);
+DECLARE_bool(visualize_solver);
namespace y2023 {
namespace vision {
@@ -61,9 +63,6 @@
using frc971::vision::VisualizeRobot;
namespace calibration = frc971::vision::calibration;
-constexpr TargetMapper::TargetId kMinTargetId = 1;
-constexpr TargetMapper::TargetId kMaxTargetId = 8;
-
// Class to handle reading target poses from a replayed log,
// displaying various debug info, and passing the poses to
// frc971::vision::TargetMapper for field mapping.
@@ -203,7 +202,7 @@
});
}
- if (FLAGS_visualize) {
+ if (FLAGS_visualize_solver) {
vis_robot_.ClearImage();
const double kFocalLength = 500.0;
vis_robot_.SetDefaultViewpoint(kImageWidth, kFocalLength);
@@ -229,22 +228,23 @@
for (const auto *target_pose_fbs : *map.target_poses()) {
// Skip detections with invalid ids
- if (target_pose_fbs->id() < kMinTargetId ||
- target_pose_fbs->id() > kMaxTargetId) {
- LOG(WARNING) << "Skipping tag with invalid id of "
- << target_pose_fbs->id();
+ if (static_cast<TargetMapper::TargetId>(target_pose_fbs->id()) <
+ FLAGS_min_target_id ||
+ static_cast<TargetMapper::TargetId>(target_pose_fbs->id()) >
+ FLAGS_max_target_id) {
+ VLOG(1) << "Skipping tag with invalid id of " << target_pose_fbs->id();
continue;
}
// Skip detections with high pose errors
if (target_pose_fbs->pose_error() > FLAGS_max_pose_error) {
- VLOG(1) << " Skipping tag " << target_pose_fbs->id()
+ VLOG(1) << "Skipping tag " << target_pose_fbs->id()
<< " due to pose error of " << target_pose_fbs->pose_error();
continue;
}
// Skip detections with high pose error ratios
if (target_pose_fbs->pose_error_ratio() > FLAGS_max_pose_error_ratio) {
- VLOG(1) << " Skipping tag " << target_pose_fbs->id()
+ VLOG(1) << "Skipping tag " << target_pose_fbs->id()
<< " due to pose error ratio of "
<< target_pose_fbs->pose_error_ratio();
continue;
@@ -274,7 +274,7 @@
.distortion_factor = distortion_factor,
.id = static_cast<TargetMapper::TargetId>(target_pose.id)});
- if (FLAGS_visualize) {
+ if (FLAGS_visualize_solver) {
// If we've already drawn in the current image,
// display it before clearing and adding the new poses
if (drawn_nodes_.count(node_name) != 0) {
@@ -419,10 +419,13 @@
.pose),
.distance_from_camera = kSeedDistanceFromCamera,
.distortion_factor = kSeedDistortionFactor,
- .id = kMinTargetId};
+ .id = FLAGS_frozen_target_id};
- for (TargetMapper::TargetId id = kMinTargetId; id <= kMaxTargetId; id++) {
- if (id == static_cast<TargetMapper::TargetId>(FLAGS_frozen_target_id)) {
+ constexpr TargetMapper::TargetId kAbsMinTargetId = 1;
+ constexpr TargetMapper::TargetId kAbsMaxTargetId = 8;
+ for (TargetMapper::TargetId id = kAbsMinTargetId; id <= kAbsMaxTargetId;
+ id++) {
+ if (id == FLAGS_frozen_target_id) {
continue;
}