Convert aos over to flatbuffers
Everything builds, and all the tests pass. I suspect that some entries
are missing from the config files, but those will be found pretty
quickly on startup.
There is no logging or live introspection of queue messages.
Change-Id: I496ee01ed68f202c7851bed7e8786cee30df29f5
diff --git a/y2014/control_loops/claw/BUILD b/y2014/control_loops/claw/BUILD
index 6c162e6..670dd76 100644
--- a/y2014/control_loops/claw/BUILD
+++ b/y2014/control_loops/claw/BUILD
@@ -1,16 +1,40 @@
package(default_visibility = ["//visibility:public"])
-load("//aos/build:queues.bzl", "queue_library")
+load("@com_github_google_flatbuffers//:build_defs.bzl", "flatbuffer_cc_library")
-queue_library(
- name = "claw_queue",
+flatbuffer_cc_library(
+ name = "claw_goal_fbs",
srcs = [
- "claw.q",
+ "claw_goal.fbs",
],
- deps = [
- "//aos/controls:control_loop_queues",
- "//frc971/control_loops:queues",
+ gen_reflections = 1,
+)
+
+flatbuffer_cc_library(
+ name = "claw_position_fbs",
+ srcs = [
+ "claw_position.fbs",
],
+ gen_reflections = 1,
+ includes = [
+ "//frc971/control_loops:control_loops_fbs_includes",
+ ],
+)
+
+flatbuffer_cc_library(
+ name = "claw_output_fbs",
+ srcs = [
+ "claw_output.fbs",
+ ],
+ gen_reflections = 1,
+)
+
+flatbuffer_cc_library(
+ name = "claw_status_fbs",
+ srcs = [
+ "claw_status.fbs",
+ ],
+ gen_reflections = 1,
)
genrule(
@@ -40,12 +64,13 @@
"-lm",
],
deps = [
- ":claw_queue",
+ ":claw_goal_fbs",
+ ":claw_output_fbs",
+ ":claw_position_fbs",
+ ":claw_status_fbs",
"//aos:math",
"//aos/controls:control_loop",
"//aos/controls:polytope",
- "//aos/logging:matrix_logging",
- "//aos/logging:queue_logging",
"//frc971/control_loops:coerce_goal",
"//frc971/control_loops:hall_effect_tracker",
"//frc971/control_loops:state_feedback_loop",
@@ -58,9 +83,13 @@
srcs = [
"claw_lib_test.cc",
],
+ data = ["//y2014:config.json"],
deps = [
+ ":claw_goal_fbs",
":claw_lib",
- ":claw_queue",
+ ":claw_output_fbs",
+ ":claw_position_fbs",
+ ":claw_status_fbs",
"//aos/controls:control_loop_test",
"//aos/testing:googletest",
"//frc971/control_loops:state_feedback_loop",
@@ -76,6 +105,6 @@
deps = [
":claw_lib",
"//aos:init",
- "//aos/events:shm-event-loop",
+ "//aos/events:shm_event_loop",
],
)
diff --git a/y2014/control_loops/claw/claw.cc b/y2014/control_loops/claw/claw.cc
index 14dbf11..56ca6b0 100644
--- a/y2014/control_loops/claw/claw.cc
+++ b/y2014/control_loops/claw/claw.cc
@@ -2,10 +2,7 @@
#include <algorithm>
-#include "aos/controls/control_loops.q.h"
#include "aos/logging/logging.h"
-#include "aos/logging/queue_logging.h"
-#include "aos/logging/matrix_logging.h"
#include "aos/commonmath.h"
#include "y2014/constants.h"
@@ -46,11 +43,11 @@
namespace y2014 {
namespace control_loops {
+namespace claw {
using ::frc971::HallEffectTracker;
using ::y2014::control_loops::claw::kDt;
using ::frc971::control_loops::DoCoerceGoal;
-using ::y2014::control_loops::ClawPositionToLog;
static const double kZeroingVoltage = 4.0;
static const double kMaxVoltage = 12.0;
@@ -94,7 +91,7 @@
double max_voltage = is_zeroing_ ? kZeroingVoltage : kMaxVoltage;
if (::std::abs(u_bottom) > max_voltage || ::std::abs(u_top) > max_voltage) {
- AOS_LOG_MATRIX(DEBUG, "U at start", U());
+ VLOG(1) << "U at start " << U();
// H * U <= k
// U = UPos + UVel
// H * (UPos + UVel) <= k
@@ -116,7 +113,7 @@
position_error << error(0, 0), error(1, 0);
Eigen::Matrix<double, 2, 1> velocity_error;
velocity_error << error(2, 0), error(3, 0);
- AOS_LOG_MATRIX(DEBUG, "error", error);
+ VLOG(1) << "error " << error;
const auto &poly = is_zeroing_ ? U_Poly_zeroing_ : U_Poly_;
const Eigen::Matrix<double, 4, 2> pos_poly_H = poly.H() * position_K;
@@ -183,9 +180,9 @@
}
}
- AOS_LOG_MATRIX(DEBUG, "adjusted_pos_error", adjusted_pos_error);
+ VLOG(1) << "adjusted_pos_error " << adjusted_pos_error;
mutable_U() = velocity_K * velocity_error + position_K * adjusted_pos_error;
- AOS_LOG_MATRIX(DEBUG, "U is now", U());
+ VLOG(1) << "U is now" << U();
{
const auto values = constants::GetValues().claw;
@@ -221,69 +218,68 @@
encoder_(0.0),
last_encoder_(0.0) {}
-void ZeroedStateFeedbackLoop::SetPositionValues(
- const ::y2014::control_loops::HalfClawPosition &claw) {
- front_.Update(claw.front);
- calibration_.Update(claw.calibration);
- back_.Update(claw.back);
+void ZeroedStateFeedbackLoop::SetPositionValues(const HalfClawPosition *claw) {
+ front_.Update(claw->front());
+ calibration_.Update(claw->calibration());
+ back_.Update(claw->back());
bool any_sensor_triggered = any_triggered();
if (any_sensor_triggered && any_triggered_last_) {
// We are still on the hall effect and nothing has changed.
min_hall_effect_on_angle_ =
- ::std::min(min_hall_effect_on_angle_, claw.position);
+ ::std::min(min_hall_effect_on_angle_, claw->position());
max_hall_effect_on_angle_ =
- ::std::max(max_hall_effect_on_angle_, claw.position);
+ ::std::max(max_hall_effect_on_angle_, claw->position());
} else if (!any_sensor_triggered && !any_triggered_last_) {
// We are still off the hall effect and nothing has changed.
min_hall_effect_off_angle_ =
- ::std::min(min_hall_effect_off_angle_, claw.position);
+ ::std::min(min_hall_effect_off_angle_, claw->position());
max_hall_effect_off_angle_ =
- ::std::max(max_hall_effect_off_angle_, claw.position);
+ ::std::max(max_hall_effect_off_angle_, claw->position());
}
if (front_.is_posedge()) {
// Saw a posedge on the hall effect. Reset the limits.
min_hall_effect_on_angle_ =
- ::std::min(claw.front.posedge_value, claw.position);
+ ::std::min(claw->front()->posedge_value(), claw->position());
max_hall_effect_on_angle_ =
- ::std::max(claw.front.posedge_value, claw.position);
+ ::std::max(claw->front()->posedge_value(), claw->position());
}
if (calibration_.is_posedge()) {
// Saw a posedge on the hall effect. Reset the limits.
min_hall_effect_on_angle_ =
- ::std::min(claw.calibration.posedge_value, claw.position);
+ ::std::min(claw->calibration()->posedge_value(), claw->position());
max_hall_effect_on_angle_ =
- ::std::max(claw.calibration.posedge_value, claw.position);
+ ::std::max(claw->calibration()->posedge_value(), claw->position());
}
if (back_.is_posedge()) {
// Saw a posedge on the hall effect. Reset the limits.
min_hall_effect_on_angle_ =
- ::std::min(claw.back.posedge_value, claw.position);
+ ::std::min(claw->back()->posedge_value(), claw->position());
max_hall_effect_on_angle_ =
- ::std::max(claw.back.posedge_value, claw.position);
+ ::std::max(claw->back()->posedge_value(), claw->position());
}
if (front_.is_negedge()) {
// Saw a negedge on the hall effect. Reset the limits.
min_hall_effect_off_angle_ =
- ::std::min(claw.front.negedge_value, claw.position);
+ ::std::min(claw->front()->negedge_value(), claw->position());
max_hall_effect_off_angle_ =
- ::std::max(claw.front.negedge_value, claw.position);
+ ::std::max(claw->front()->negedge_value(), claw->position());
}
if (calibration_.is_negedge()) {
// Saw a negedge on the hall effect. Reset the limits.
min_hall_effect_off_angle_ =
- ::std::min(claw.calibration.negedge_value, claw.position);
+ ::std::min(claw->calibration()->negedge_value(), claw->position());
max_hall_effect_off_angle_ =
- ::std::max(claw.calibration.negedge_value, claw.position);
+ ::std::max(claw->calibration()->negedge_value(), claw->position());
}
if (back_.is_negedge()) {
// Saw a negedge on the hall effect. Reset the limits.
min_hall_effect_off_angle_ =
- ::std::min(claw.back.negedge_value, claw.position);
+ ::std::min(claw->back()->negedge_value(), claw->position());
max_hall_effect_off_angle_ =
- ::std::max(claw.back.negedge_value, claw.position);
+ ::std::max(claw->back()->negedge_value(), claw->position());
}
last_encoder_ = encoder_;
@@ -292,23 +288,22 @@
} else {
last_off_encoder_ = encoder_;
}
- encoder_ = claw.position;
+ encoder_ = claw->position();
any_triggered_last_ = any_sensor_triggered;
}
-void ZeroedStateFeedbackLoop::Reset(
- const ::y2014::control_loops::HalfClawPosition &claw) {
+void ZeroedStateFeedbackLoop::Reset(const HalfClawPosition *claw) {
set_zeroing_state(ZeroedStateFeedbackLoop::UNKNOWN_POSITION);
- front_.Reset(claw.front);
- calibration_.Reset(claw.calibration);
- back_.Reset(claw.back);
+ front_.Reset(claw->front());
+ calibration_.Reset(claw->calibration());
+ back_.Reset(claw->back());
// close up the min and max edge positions as they are no longer valid and
// will be expanded in future iterations
- min_hall_effect_on_angle_ = claw.position;
- max_hall_effect_on_angle_ = claw.position;
- min_hall_effect_off_angle_ = claw.position;
- max_hall_effect_off_angle_ = claw.position;
+ min_hall_effect_on_angle_ = claw->position();
+ max_hall_effect_on_angle_ = claw->position();
+ min_hall_effect_off_angle_ = claw->position();
+ max_hall_effect_off_angle_ = claw->position();
any_triggered_last_ = any_triggered();
}
@@ -374,8 +369,8 @@
}
ClawMotor::ClawMotor(::aos::EventLoop *event_loop, const ::std::string &name)
- : aos::controls::ControlLoop<::y2014::control_loops::ClawQueue>(event_loop,
- name),
+ : aos::controls::ControlLoop<Goal, Position, Status, Output>(event_loop,
+ name),
has_top_claw_goal_(false),
top_claw_goal_(0.0),
top_claw_(this),
@@ -563,45 +558,33 @@
// first update position based on angle limit
const double separation = *top_goal - *bottom_goal;
if (separation > values.claw.soft_max_separation) {
- AOS_LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
const double dsep = (separation - values.claw.soft_max_separation) / 2.0;
*bottom_goal += dsep;
*top_goal -= dsep;
- AOS_LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
}
if (separation < values.claw.soft_min_separation) {
- AOS_LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
const double dsep = (separation - values.claw.soft_min_separation) / 2.0;
*bottom_goal += dsep;
*top_goal -= dsep;
- AOS_LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
}
// now move both goals in unison
if (*bottom_goal < values.claw.lower_claw.lower_limit) {
- AOS_LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
*top_goal += values.claw.lower_claw.lower_limit - *bottom_goal;
*bottom_goal = values.claw.lower_claw.lower_limit;
- AOS_LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
}
if (*bottom_goal > values.claw.lower_claw.upper_limit) {
- AOS_LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
*top_goal -= *bottom_goal - values.claw.lower_claw.upper_limit;
*bottom_goal = values.claw.lower_claw.upper_limit;
- AOS_LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
}
if (*top_goal < values.claw.upper_claw.lower_limit) {
- AOS_LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
*bottom_goal += values.claw.upper_claw.lower_limit - *top_goal;
*top_goal = values.claw.upper_claw.lower_limit;
- AOS_LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
}
if (*top_goal > values.claw.upper_claw.upper_limit) {
- AOS_LOG_STRUCT(DEBUG, "before", ClawPositionToLog(*top_goal, *bottom_goal));
*bottom_goal -= *top_goal - values.claw.upper_claw.upper_limit;
*top_goal = values.claw.upper_claw.upper_limit;
- AOS_LOG_STRUCT(DEBUG, "after", ClawPositionToLog(*top_goal, *bottom_goal));
}
}
@@ -609,7 +592,7 @@
return (
(top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED &&
bottom_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED) ||
- ((has_joystick_state() ? joystick_state().autonomous : true) &&
+ ((has_joystick_state() ? joystick_state().autonomous() : true) &&
((top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
top_claw_.zeroing_state() ==
ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
@@ -621,43 +604,45 @@
bool ClawMotor::is_zeroing() const { return !is_ready(); }
// Positive angle is up, and positive power is up.
-void ClawMotor::RunIteration(
- const ::y2014::control_loops::ClawQueue::Goal *goal,
- const ::y2014::control_loops::ClawQueue::Position *position,
- ::y2014::control_loops::ClawQueue::Output *output,
- ::y2014::control_loops::ClawQueue::Status *status) {
+void ClawMotor::RunIteration(const Goal *goal, const Position *position,
+ aos::Sender<Output>::Builder *output,
+ aos::Sender<Status>::Builder *status) {
// Disable the motors now so that all early returns will return with the
// motors disabled.
+ OutputT output_struct;
if (output) {
- output->top_claw_voltage = 0;
- output->bottom_claw_voltage = 0;
- output->intake_voltage = 0;
- output->tusk_voltage = 0;
+ output_struct.top_claw_voltage = 0;
+ output_struct.bottom_claw_voltage = 0;
+ output_struct.intake_voltage = 0;
+ output_struct.tusk_voltage = 0;
}
+ StatusT status_struct;
if (goal) {
- if (::std::isnan(goal->bottom_angle) ||
- ::std::isnan(goal->separation_angle) || ::std::isnan(goal->intake) ||
- ::std::isnan(goal->centering)) {
+ if (::std::isnan(goal->bottom_angle()) ||
+ ::std::isnan(goal->separation_angle()) ||
+ ::std::isnan(goal->intake()) || ::std::isnan(goal->centering())) {
+ status->Send(Status::Pack(*status->fbb(), &status_struct));
+ output->Send(Output::Pack(*output->fbb(), &output_struct));
return;
}
}
if (WasReset()) {
- top_claw_.Reset(position->top);
- bottom_claw_.Reset(position->bottom);
+ top_claw_.Reset(position->top());
+ bottom_claw_.Reset(position->bottom());
}
const constants::Values &values = constants::GetValues();
if (position) {
Eigen::Matrix<double, 2, 1> Y;
- Y << position->bottom.position + bottom_claw_.offset(),
- position->top.position + top_claw_.offset();
+ Y << position->bottom()->position() + bottom_claw_.offset(),
+ position->top()->position() + top_claw_.offset();
claw_.Correct(Y);
- top_claw_.SetPositionValues(position->top);
- bottom_claw_.SetPositionValues(position->bottom);
+ top_claw_.SetPositionValues(position->top());
+ bottom_claw_.SetPositionValues(position->bottom());
if (!has_top_claw_goal_) {
has_top_claw_goal_ = true;
@@ -671,15 +656,12 @@
initial_separation_ =
top_claw_.absolute_position() - bottom_claw_.absolute_position();
}
- AOS_LOG_STRUCT(DEBUG, "absolute position",
- ClawPositionToLog(top_claw_.absolute_position(),
- bottom_claw_.absolute_position()));
}
bool autonomous, enabled;
if (has_joystick_state()) {
- autonomous = joystick_state().autonomous;
- enabled = joystick_state().enabled;
+ autonomous = joystick_state().autonomous();
+ enabled = joystick_state().enabled();
} else {
autonomous = true;
enabled = false;
@@ -700,8 +682,8 @@
ZeroedStateFeedbackLoop::DISABLED_CALIBRATION))))) {
// Ready to use the claw.
// Limit the goals here.
- bottom_claw_goal_ = goal->bottom_angle;
- top_claw_goal_ = goal->bottom_angle + goal->separation_angle;
+ bottom_claw_goal_ = goal->bottom_angle();
+ top_claw_goal_ = goal->bottom_angle() + goal->separation_angle();
has_bottom_claw_goal_ = true;
has_top_claw_goal_ = true;
doing_calibration_fine_tune_ = false;
@@ -759,7 +741,7 @@
bottom_claw_.back())) {
// do calibration
bottom_claw_.SetCalibration(
- position->bottom.calibration.posedge_value,
+ position->bottom()->calibration()->posedge_value(),
values.claw.lower_claw.calibration.lower_angle);
bottom_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
// calibrated so we are done fine tuning bottom
@@ -816,7 +798,7 @@
top_claw_.front(), top_claw_.back())) {
// do calibration
top_claw_.SetCalibration(
- position->top.calibration.posedge_value,
+ position->top()->calibration()->posedge_value(),
values.claw.upper_claw.calibration.lower_angle);
top_claw_.set_zeroing_state(ZeroedStateFeedbackLoop::CALIBRATED);
// calibrated so we are done fine tuning top
@@ -836,10 +818,11 @@
doing_calibration_fine_tune_ = false;
if (!was_enabled_ && enabled) {
if (position) {
- top_claw_goal_ = position->top.position + top_claw_.offset();
- bottom_claw_goal_ = position->bottom.position + bottom_claw_.offset();
+ top_claw_goal_ = position->top()->position() + top_claw_.offset();
+ bottom_claw_goal_ =
+ position->bottom()->position() + bottom_claw_.offset();
initial_separation_ =
- position->top.position - position->bottom.position;
+ position->top()->position() - position->bottom()->position();
} else {
has_top_claw_goal_ = false;
has_bottom_claw_goal_ = false;
@@ -907,7 +890,6 @@
if (has_top_claw_goal_ && has_bottom_claw_goal_) {
claw_.mutable_R() << bottom_claw_goal_, top_claw_goal_ - bottom_claw_goal_,
bottom_claw_velocity_, top_claw_velocity_ - bottom_claw_velocity_;
- AOS_LOG_MATRIX(DEBUG, "actual goal", claw_.R());
// Only cap power when one of the halves of the claw is moving slowly and
// could wind up.
@@ -973,55 +955,60 @@
if (output) {
if (goal) {
//setup the intake
- output->intake_voltage =
- (goal->intake > 12.0) ? 12 : (goal->intake < -12.0) ? -12.0
- : goal->intake;
- output->tusk_voltage = goal->centering;
- output->tusk_voltage =
- (goal->centering > 12.0) ? 12 : (goal->centering < -12.0)
+ output_struct.intake_voltage =
+ (goal->intake() > 12.0)
+ ? 12
+ : (goal->intake() < -12.0) ? -12.0 : goal->intake();
+ output_struct.tusk_voltage = goal->centering();
+ output_struct.tusk_voltage =
+ (goal->centering() > 12.0) ? 12 : (goal->centering() < -12.0)
? -12.0
- : goal->centering;
+ : goal->centering();
}
- output->top_claw_voltage = claw_.U(1, 0);
- output->bottom_claw_voltage = claw_.U(0, 0);
+ output_struct.top_claw_voltage = claw_.U(1, 0);
+ output_struct.bottom_claw_voltage = claw_.U(0, 0);
- if (output->top_claw_voltage > kMaxVoltage) {
- output->top_claw_voltage = kMaxVoltage;
- } else if (output->top_claw_voltage < -kMaxVoltage) {
- output->top_claw_voltage = -kMaxVoltage;
+ if (output_struct.top_claw_voltage > kMaxVoltage) {
+ output_struct.top_claw_voltage = kMaxVoltage;
+ } else if (output_struct.top_claw_voltage < -kMaxVoltage) {
+ output_struct.top_claw_voltage = -kMaxVoltage;
}
- if (output->bottom_claw_voltage > kMaxVoltage) {
- output->bottom_claw_voltage = kMaxVoltage;
- } else if (output->bottom_claw_voltage < -kMaxVoltage) {
- output->bottom_claw_voltage = -kMaxVoltage;
+ if (output_struct.bottom_claw_voltage > kMaxVoltage) {
+ output_struct.bottom_claw_voltage = kMaxVoltage;
+ } else if (output_struct.bottom_claw_voltage < -kMaxVoltage) {
+ output_struct.bottom_claw_voltage = -kMaxVoltage;
}
+
+ output->Send(Output::Pack(*output->fbb(), &output_struct));
}
- status->bottom = bottom_absolute_position();
- status->separation = top_absolute_position() - bottom_absolute_position();
- status->bottom_velocity = claw_.X_hat(2, 0);
- status->separation_velocity = claw_.X_hat(3, 0);
+ status_struct.bottom = bottom_absolute_position();
+ status_struct.separation =
+ top_absolute_position() - bottom_absolute_position();
+ status_struct.bottom_velocity = claw_.X_hat(2, 0);
+ status_struct.separation_velocity = claw_.X_hat(3, 0);
if (goal) {
bool bottom_done =
- ::std::abs(bottom_absolute_position() - goal->bottom_angle) < 0.020;
- bool bottom_velocity_done = ::std::abs(status->bottom_velocity) < 0.2;
+ ::std::abs(bottom_absolute_position() - goal->bottom_angle()) < 0.020;
+ bool bottom_velocity_done = ::std::abs(status_struct.bottom_velocity) < 0.2;
bool separation_done =
::std::abs((top_absolute_position() - bottom_absolute_position()) -
- goal->separation_angle) < 0.020;
+ goal->separation_angle()) < 0.020;
bool separation_done_with_ball =
::std::abs((top_absolute_position() - bottom_absolute_position()) -
- goal->separation_angle) < 0.06;
- status->done = is_ready() && separation_done && bottom_done && bottom_velocity_done;
- status->done_with_ball =
- is_ready() && separation_done_with_ball && bottom_done && bottom_velocity_done;
+ goal->separation_angle()) < 0.06;
+ status_struct.done =
+ is_ready() && separation_done && bottom_done && bottom_velocity_done;
+ status_struct.done_with_ball = is_ready() && separation_done_with_ball &&
+ bottom_done && bottom_velocity_done;
} else {
- status->done = status->done_with_ball = false;
+ status_struct.done = status_struct.done_with_ball = false;
}
- status->zeroed = is_ready();
- status->zeroed_for_auto =
+ status_struct.zeroed = is_ready();
+ status_struct.zeroed_for_auto =
(top_claw_.zeroing_state() == ZeroedStateFeedbackLoop::CALIBRATED ||
top_claw_.zeroing_state() ==
ZeroedStateFeedbackLoop::DISABLED_CALIBRATION) &&
@@ -1029,8 +1016,11 @@
bottom_claw_.zeroing_state() ==
ZeroedStateFeedbackLoop::DISABLED_CALIBRATION);
+ status->Send(Status::Pack(*status->fbb(), &status_struct));
+
was_enabled_ = enabled;
}
+} // namespace claw
} // namespace control_loops
} // namespace y2014
diff --git a/y2014/control_loops/claw/claw.h b/y2014/control_loops/claw/claw.h
index 082ddce..5bcccc1 100644
--- a/y2014/control_loops/claw/claw.h
+++ b/y2014/control_loops/claw/claw.h
@@ -5,15 +5,19 @@
#include "aos/controls/control_loop.h"
#include "aos/controls/polytope.h"
-#include "y2014/constants.h"
-#include "frc971/control_loops/state_feedback_loop.h"
#include "frc971/control_loops/coerce_goal.h"
-#include "y2014/control_loops/claw/claw.q.h"
-#include "y2014/control_loops/claw/claw_motor_plant.h"
#include "frc971/control_loops/hall_effect_tracker.h"
+#include "frc971/control_loops/state_feedback_loop.h"
+#include "y2014/constants.h"
+#include "y2014/control_loops/claw/claw_goal_generated.h"
+#include "y2014/control_loops/claw/claw_motor_plant.h"
+#include "y2014/control_loops/claw/claw_output_generated.h"
+#include "y2014/control_loops/claw/claw_position_generated.h"
+#include "y2014/control_loops/claw/claw_status_generated.h"
namespace y2014 {
namespace control_loops {
+namespace claw {
namespace testing {
class WindupClawTest;
};
@@ -77,9 +81,9 @@
}
JointZeroingState zeroing_state() const { return zeroing_state_; }
- void SetPositionValues(const ::y2014::control_loops::HalfClawPosition &claw);
+ void SetPositionValues(const HalfClawPosition *claw);
- void Reset(const ::y2014::control_loops::HalfClawPosition &claw);
+ void Reset(const HalfClawPosition *claw);
double absolute_position() const { return encoder() + offset(); }
@@ -183,11 +187,10 @@
};
class ClawMotor
- : public aos::controls::ControlLoop<::y2014::control_loops::ClawQueue> {
+ : public aos::controls::ControlLoop<Goal, Position, Status, Output> {
public:
- explicit ClawMotor(
- ::aos::EventLoop *event_loop,
- const ::std::string &name = ".y2014.control_loops.claw_queue");
+ explicit ClawMotor(::aos::EventLoop *event_loop,
+ const ::std::string &name = "/claw");
// True if the state machine is ready.
bool capped_goal() const { return capped_goal_; }
@@ -217,11 +220,9 @@
CalibrationMode mode() const { return mode_; }
protected:
- virtual void RunIteration(
- const ::y2014::control_loops::ClawQueue::Goal *goal,
- const ::y2014::control_loops::ClawQueue::Position *position,
- ::y2014::control_loops::ClawQueue::Output *output,
- ::y2014::control_loops::ClawQueue::Status *status);
+ virtual void RunIteration(const Goal *goal, const Position *position,
+ aos::Sender<Output>::Builder *output,
+ aos::Sender<Status>::Builder *status);
double top_absolute_position() const {
return claw_.X_hat(1, 0) + claw_.X_hat(0, 0);
@@ -262,6 +263,7 @@
void LimitClawGoal(double *bottom_goal, double *top_goal,
const constants::Values &values);
+} // namespace claw
} // namespace control_loops
} // namespace y2014
diff --git a/y2014/control_loops/claw/claw.q b/y2014/control_loops/claw/claw.q
deleted file mode 100644
index ff4c8b8..0000000
--- a/y2014/control_loops/claw/claw.q
+++ /dev/null
@@ -1,74 +0,0 @@
-package y2014.control_loops;
-
-import "aos/controls/control_loops.q";
-import "frc971/control_loops/control_loops.q";
-
-struct HalfClawPosition {
- // The current position of this half of the claw.
- double position;
-
- // The hall effect sensor at the front limit.
- .frc971.HallEffectStruct front;
- // The hall effect sensor in the middle to use for real calibration.
- .frc971.HallEffectStruct calibration;
- // The hall effect at the back limit.
- .frc971.HallEffectStruct back;
-};
-
-// All angles here are 0 vertical, positive "up" (aka backwards).
-// Published on ".y2014.control_loops.claw_queue"
-queue_group ClawQueue {
- implements aos.control_loops.ControlLoop;
-
- message Goal {
- // The angle of the bottom claw.
- double bottom_angle;
- // How much higher the top claw is.
- double separation_angle;
- // top claw intake roller
- double intake;
- // bottom claw tusk centering
- double centering;
- };
-
- message Position {
- // All the top claw information.
- HalfClawPosition top;
- // All the bottom claw information.
- HalfClawPosition bottom;
- };
-
- message Output {
- double intake_voltage;
- double top_claw_voltage;
- double bottom_claw_voltage;
- double tusk_voltage;
- };
-
- message Status {
- // True if zeroed enough for the current period (autonomous or teleop).
- bool zeroed;
- // True if zeroed as much as we will force during autonomous.
- bool zeroed_for_auto;
- // True if zeroed and within tolerance for separation and bottom angle.
- bool done;
- // True if zeroed and within tolerance for separation and bottom angle.
- // seperation allowance much wider as a ball may be included
- bool done_with_ball;
- // Dump the values of the state matrix.
- double bottom;
- double bottom_velocity;
- double separation;
- double separation_velocity;
- };
-
- queue Goal goal;
- queue Position position;
- queue Output output;
- queue Status status;
-};
-
-struct ClawPositionToLog {
- double top;
- double bottom;
-};
diff --git a/y2014/control_loops/claw/claw_goal.fbs b/y2014/control_loops/claw/claw_goal.fbs
new file mode 100644
index 0000000..eb5860c
--- /dev/null
+++ b/y2014/control_loops/claw/claw_goal.fbs
@@ -0,0 +1,15 @@
+namespace y2014.control_loops.claw;
+
+// All angles here are 0 vertical, positive "up" (aka backwards).
+table Goal {
+ // The angle of the bottom claw.
+ bottom_angle:double;
+ // How much higher the top claw is.
+ separation_angle:double;
+ // top claw intake roller
+ intake:double;
+ // bottom claw tusk centering
+ centering:double;
+}
+
+root_type Goal;
diff --git a/y2014/control_loops/claw/claw_lib_test.cc b/y2014/control_loops/claw/claw_lib_test.cc
index 41dbfca..55e186e 100644
--- a/y2014/control_loops/claw/claw_lib_test.cc
+++ b/y2014/control_loops/claw/claw_lib_test.cc
@@ -8,16 +8,18 @@
#include "gtest/gtest.h"
#include "y2014/constants.h"
#include "y2014/control_loops/claw/claw.h"
-#include "y2014/control_loops/claw/claw.q.h"
+#include "y2014/control_loops/claw/claw_goal_generated.h"
#include "y2014/control_loops/claw/claw_motor_plant.h"
+#include "y2014/control_loops/claw/claw_output_generated.h"
+#include "y2014/control_loops/claw/claw_position_generated.h"
+#include "y2014/control_loops/claw/claw_status_generated.h"
namespace y2014 {
namespace control_loops {
+namespace claw {
namespace testing {
-using ::y2014::control_loops::claw::MakeClawPlant;
-using ::frc971::HallEffectStruct;
-using ::y2014::control_loops::HalfClawPosition;
+using ::frc971::HallEffectStructT;
using ::aos::monotonic_clock;
namespace chrono = ::std::chrono;
@@ -38,10 +40,8 @@
double initial_top_position,
double initial_bottom_position)
: event_loop_(event_loop),
- claw_position_sender_(event_loop_->MakeSender<ClawQueue::Position>(
- ".y2014.control_loops.claw_queue.position")),
- claw_output_fetcher_(event_loop_->MakeFetcher<ClawQueue::Output>(
- ".y2014.control_loops.claw_queue.output")),
+ claw_position_sender_(event_loop_->MakeSender<Position>("/claw")),
+ claw_output_fetcher_(event_loop_->MakeFetcher<Output>("/claw")),
claw_plant_(new StateFeedbackPlant<4, 2, 2>(MakeClawPlant())) {
Reinitialize(initial_top_position, initial_bottom_position);
@@ -69,7 +69,9 @@
ReinitializePartial(TOP_CLAW, initial_top_position);
ReinitializePartial(BOTTOM_CLAW, initial_bottom_position);
- last_position_.Zero();
+
+ last_position_.top.reset();
+ last_position_.bottom.reset();
SetPhysicalSensors(&last_position_);
}
@@ -99,44 +101,58 @@
void SetHallEffect(double pos,
const constants::Values::Claws::AnglePair &pair,
- HallEffectStruct *hall_effect) {
+ HallEffectStructT *hall_effect) {
hall_effect->current = CheckRange(pos, pair);
}
void SetClawHallEffects(double pos,
const constants::Values::Claws::Claw &claw,
- HalfClawPosition *half_claw) {
- SetHallEffect(pos, claw.front, &half_claw->front);
- SetHallEffect(pos, claw.calibration, &half_claw->calibration);
- SetHallEffect(pos, claw.back, &half_claw->back);
+ HalfClawPositionT *half_claw) {
+ if (!half_claw->front) {
+ half_claw->front.reset(new HallEffectStructT());
+ }
+ if (!half_claw->calibration) {
+ half_claw->calibration.reset(new HallEffectStructT());
+ }
+ if (!half_claw->back) {
+ half_claw->back.reset(new HallEffectStructT());
+ }
+ SetHallEffect(pos, claw.front, half_claw->front.get());
+ SetHallEffect(pos, claw.calibration, half_claw->calibration.get());
+ SetHallEffect(pos, claw.back, half_claw->back.get());
}
// Sets the values of the physical sensors that can be directly observed
// (encoder, hall effect).
- void SetPhysicalSensors(
- ::y2014::control_loops::ClawQueue::Position *position) {
- position->top.position = GetPosition(TOP_CLAW);
- position->bottom.position = GetPosition(BOTTOM_CLAW);
+ void SetPhysicalSensors(PositionT *position) {
+ if (!position->top) {
+ position->top.reset(new HalfClawPositionT());
+ }
+ if (!position->bottom) {
+ position->bottom.reset(new HalfClawPositionT());
+ }
+
+ position->top->position = GetPosition(TOP_CLAW);
+ position->bottom->position = GetPosition(BOTTOM_CLAW);
double pos[2] = {GetAbsolutePosition(TOP_CLAW),
GetAbsolutePosition(BOTTOM_CLAW)};
AOS_LOG(DEBUG, "Physical claws are at {top: %f, bottom: %f}\n",
pos[TOP_CLAW], pos[BOTTOM_CLAW]);
- const constants::Values& values = constants::GetValues();
+ const constants::Values &values = constants::GetValues();
// Signal that each hall effect sensor has been triggered if it is within
// the correct range.
- SetClawHallEffects(pos[TOP_CLAW], values.claw.upper_claw, &position->top);
+ SetClawHallEffects(pos[TOP_CLAW], values.claw.upper_claw,
+ position->top.get());
SetClawHallEffects(pos[BOTTOM_CLAW], values.claw.lower_claw,
- &position->bottom);
+ position->bottom.get());
}
- void UpdateHallEffect(double angle,
- double last_angle,
- double initial_position,
- HallEffectStruct *position,
- const HallEffectStruct &last_position,
+ void UpdateHallEffect(double angle, double last_angle,
+ double initial_position, HallEffectStructT *position,
+ const HallEffectStructT &last_position,
const constants::Values::Claws::AnglePair &pair,
const char *claw_name, const char *hall_effect_name) {
if (position->current && !last_position.current) {
@@ -167,49 +183,64 @@
}
}
- void UpdateClawHallEffects(
- HalfClawPosition *position,
- const HalfClawPosition &last_position,
- const constants::Values::Claws::Claw &claw, double initial_position,
- const char *claw_name) {
- UpdateHallEffect(position->position + initial_position,
+ void UpdateClawHallEffects(HalfClawPositionT *half_claw,
+ const HalfClawPositionT &last_position,
+ const constants::Values::Claws::Claw &claw,
+ double initial_position, const char *claw_name) {
+ if (!half_claw->front) {
+ half_claw->front.reset(new HallEffectStructT());
+ }
+ if (!half_claw->calibration) {
+ half_claw->calibration.reset(new HallEffectStructT());
+ }
+ if (!half_claw->back) {
+ half_claw->back.reset(new HallEffectStructT());
+ }
+ UpdateHallEffect(half_claw->position + initial_position,
last_position.position + initial_position,
- initial_position, &position->front, last_position.front,
- claw.front, claw_name, "front");
- UpdateHallEffect(position->position + initial_position,
+ initial_position, half_claw->front.get(),
+ *last_position.front.get(), claw.front, claw_name, "front");
+ UpdateHallEffect(half_claw->position + initial_position,
last_position.position + initial_position,
- initial_position, &position->calibration,
- last_position.calibration, claw.calibration, claw_name,
- "calibration");
- UpdateHallEffect(position->position + initial_position,
+ initial_position, half_claw->calibration.get(),
+ *last_position.calibration.get(), claw.calibration,
+ claw_name, "calibration");
+ UpdateHallEffect(half_claw->position + initial_position,
last_position.position + initial_position,
- initial_position, &position->back, last_position.back,
- claw.back, claw_name, "back");
+ initial_position, half_claw->back.get(),
+ *last_position.back.get(), claw.back, claw_name, "back");
}
// Sends out the position queue messages.
void SendPositionMessage() {
- ::aos::Sender<::y2014::control_loops::ClawQueue::Position>::Message
- position = claw_position_sender_.MakeMessage();
+ ::aos::Sender<Position>::Builder builder =
+ claw_position_sender_.MakeBuilder();
// Initialize all the counters to their previous values.
- *position = last_position_;
- SetPhysicalSensors(position.get());
+ PositionT position;
- const constants::Values& values = constants::GetValues();
+ flatbuffers::FlatBufferBuilder fbb;
+ flatbuffers::Offset<Position> position_offset =
+ Position::Pack(fbb, &last_position_);
+ fbb.Finish(position_offset);
- UpdateClawHallEffects(&position->top, last_position_.top,
+ flatbuffers::GetRoot<Position>(fbb.GetBufferPointer())->UnPackTo(&position);
+ SetPhysicalSensors(&position);
+
+ const constants::Values &values = constants::GetValues();
+
+ UpdateClawHallEffects(position.top.get(), *last_position_.top.get(),
values.claw.upper_claw, initial_position_[TOP_CLAW],
"Top");
- UpdateClawHallEffects(&position->bottom, last_position_.bottom,
+ UpdateClawHallEffects(position.bottom.get(), *last_position_.bottom.get(),
values.claw.lower_claw,
initial_position_[BOTTOM_CLAW], "Bottom");
// Only set calibration if it changed last cycle. Calibration starts out
// with a value of 0.
- last_position_ = *position;
- position.Send();
+ builder.Send(Position::Pack(*builder.fbb(), &position));
+ last_position_ = std::move(position);
}
// Simulates the claw moving for one timestep.
@@ -218,8 +249,8 @@
EXPECT_TRUE(claw_output_fetcher_.Fetch());
Eigen::Matrix<double, 2, 1> U;
- U << claw_output_fetcher_->bottom_claw_voltage,
- claw_output_fetcher_->top_claw_voltage;
+ U << claw_output_fetcher_->bottom_claw_voltage(),
+ claw_output_fetcher_->top_claw_voltage();
claw_plant_->Update(U);
// Check that the claw is within the limits.
@@ -237,8 +268,8 @@
private:
::aos::EventLoop *event_loop_;
- ::aos::Sender<ClawQueue::Position> claw_position_sender_;
- ::aos::Fetcher<ClawQueue::Output> claw_output_fetcher_;
+ ::aos::Sender<Position> claw_position_sender_;
+ ::aos::Fetcher<Output> claw_output_fetcher_;
// The whole claw.
::std::unique_ptr<StateFeedbackPlant<4, 2, 2>> claw_plant_;
@@ -252,18 +283,18 @@
double initial_position_[CLAW_COUNT];
- ::y2014::control_loops::ClawQueue::Position last_position_;
+ PositionT last_position_;
};
class ClawTest : public ::aos::testing::ControlLoopTest {
protected:
ClawTest()
- : ::aos::testing::ControlLoopTest(chrono::microseconds(5000)),
+ : ::aos::testing::ControlLoopTest(
+ aos::configuration::ReadConfig("y2014/config.json"),
+ chrono::microseconds(5000)),
test_event_loop_(MakeEventLoop()),
- claw_goal_sender_(test_event_loop_->MakeSender<ClawQueue::Goal>(
- ".y2014.control_loops.claw_queue.goal")),
- claw_goal_fetcher_(test_event_loop_->MakeFetcher<ClawQueue::Goal>(
- ".y2014.control_loops.claw_queue.goal")),
+ claw_goal_sender_(test_event_loop_->MakeSender<Goal>("/claw")),
+ claw_goal_fetcher_(test_event_loop_->MakeFetcher<Goal>("/claw")),
claw_event_loop_(MakeEventLoop()),
claw_motor_(claw_event_loop_.get()),
claw_plant_event_loop_(MakeEventLoop()),
@@ -275,14 +306,14 @@
double bottom = claw_motor_plant_.GetAbsolutePosition(BOTTOM_CLAW);
double separation =
claw_motor_plant_.GetAbsolutePosition(TOP_CLAW) - bottom;
- EXPECT_NEAR(claw_goal_fetcher_->bottom_angle, bottom, 1e-4);
- EXPECT_NEAR(claw_goal_fetcher_->separation_angle, separation, 1e-4);
+ EXPECT_NEAR(claw_goal_fetcher_->bottom_angle(), bottom, 1e-4);
+ EXPECT_NEAR(claw_goal_fetcher_->separation_angle(), separation, 1e-4);
EXPECT_LE(min_separation_, separation);
}
::std::unique_ptr<::aos::EventLoop> test_event_loop_;
- ::aos::Sender<ClawQueue::Goal> claw_goal_sender_;
- ::aos::Fetcher<ClawQueue::Goal> claw_goal_fetcher_;
+ ::aos::Sender<Goal> claw_goal_sender_;
+ ::aos::Fetcher<Goal> claw_goal_fetcher_;
// Create a loop and simulation plant.
::std::unique_ptr<::aos::EventLoop> claw_event_loop_;
@@ -294,15 +325,15 @@
// Minimum amount of acceptable separation between the top and bottom of the
// claw.
double min_separation_;
-
};
TEST_F(ClawTest, HandlesNAN) {
{
- auto message = claw_goal_sender_.MakeMessage();
- message->bottom_angle = ::std::nan("");
- message->separation_angle = ::std::nan("");
- EXPECT_TRUE(message.Send());
+ auto builder = claw_goal_sender_.MakeBuilder();
+ Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+ goal_builder.add_bottom_angle(::std::nan(""));
+ goal_builder.add_separation_angle(::std::nan(""));
+ EXPECT_TRUE(builder.Send(goal_builder.Finish()));
}
SetEnabled(true);
@@ -312,10 +343,11 @@
// Tests that the wrist zeros correctly and goes to a position.
TEST_F(ClawTest, ZerosCorrectly) {
{
- auto message = claw_goal_sender_.MakeMessage();
- message->bottom_angle = 0.1;
- message->separation_angle = 0.2;
- EXPECT_TRUE(message.Send());
+ auto builder = claw_goal_sender_.MakeBuilder();
+ Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+ goal_builder.add_bottom_angle(0.1);
+ goal_builder.add_separation_angle(0.2);
+ EXPECT_TRUE(builder.Send(goal_builder.Finish()));
}
SetEnabled(true);
@@ -409,10 +441,11 @@
claw_motor_plant_.Reinitialize(GetParam().first, GetParam().second);
{
- auto message = claw_goal_sender_.MakeMessage();
- message->bottom_angle = 0.1;
- message->separation_angle = 0.2;
- EXPECT_TRUE(message.Send());
+ auto builder = claw_goal_sender_.MakeBuilder();
+ Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+ goal_builder.add_bottom_angle(0.1);
+ goal_builder.add_separation_angle(0.2);
+ EXPECT_TRUE(builder.Send(goal_builder.Finish()));
}
SetEnabled(true);
@@ -586,10 +619,11 @@
// zeroing position is saturating the goal.
TEST_F(WindupClawTest, NoWindupPositive) {
{
- auto message = claw_goal_sender_.MakeMessage();
- message->bottom_angle = 0.1;
- message->separation_angle = 0.2;
- EXPECT_TRUE(message.Send());
+ auto builder = claw_goal_sender_.MakeBuilder();
+ Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+ goal_builder.add_bottom_angle(0.1);
+ goal_builder.add_separation_angle(0.2);
+ EXPECT_TRUE(builder.Send(goal_builder.Finish()));
}
TestWindup(ClawMotor::UNKNOWN_LOCATION,
@@ -602,10 +636,11 @@
// zeroing position is saturating the goal.
TEST_F(WindupClawTest, NoWindupNegative) {
{
- auto message = claw_goal_sender_.MakeMessage();
- message->bottom_angle = 0.1;
- message->separation_angle = 0.2;
- EXPECT_TRUE(message.Send());
+ auto builder = claw_goal_sender_.MakeBuilder();
+ Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+ goal_builder.add_bottom_angle(0.1);
+ goal_builder.add_separation_angle(0.2);
+ EXPECT_TRUE(builder.Send(goal_builder.Finish()));
}
TestWindup(ClawMotor::UNKNOWN_LOCATION,
@@ -618,10 +653,11 @@
// zeroing position is saturating the goal.
TEST_F(WindupClawTest, NoWindupNegativeFineTune) {
{
- auto message = claw_goal_sender_.MakeMessage();
- message->bottom_angle = 0.1;
- message->separation_angle = 0.2;
- EXPECT_TRUE(message.Send());
+ auto builder = claw_goal_sender_.MakeBuilder();
+ Goal::Builder goal_builder = builder.MakeBuilder<Goal>();
+ goal_builder.add_bottom_angle(0.1);
+ goal_builder.add_separation_angle(0.2);
+ EXPECT_TRUE(builder.Send(goal_builder.Finish()));
}
TestWindup(ClawMotor::FINE_TUNE_BOTTOM,
@@ -631,5 +667,6 @@
}
} // namespace testing
+} // namespace claw
} // namespace control_loops
} // namespace y2014
diff --git a/y2014/control_loops/claw/claw_main.cc b/y2014/control_loops/claw/claw_main.cc
index 65627d5..f21c7c5 100644
--- a/y2014/control_loops/claw/claw_main.cc
+++ b/y2014/control_loops/claw/claw_main.cc
@@ -1,13 +1,16 @@
#include "y2014/control_loops/claw/claw.h"
-#include "aos/events/shm-event-loop.h"
+#include "aos/events/shm_event_loop.h"
#include "aos/init.h"
int main() {
::aos::InitNRT(true);
- ::aos::ShmEventLoop event_loop;
- ::y2014::control_loops::ClawMotor claw(&event_loop);
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig("config.json");
+
+ ::aos::ShmEventLoop event_loop(&config.message());
+ ::y2014::control_loops::claw::ClawMotor claw(&event_loop);
event_loop.Run();
diff --git a/y2014/control_loops/claw/claw_output.fbs b/y2014/control_loops/claw/claw_output.fbs
new file mode 100644
index 0000000..8cb42e0
--- /dev/null
+++ b/y2014/control_loops/claw/claw_output.fbs
@@ -0,0 +1,11 @@
+namespace y2014.control_loops.claw;
+
+// All angles here are 0 vertical, positive "up" (aka backwards).
+table Output {
+ intake_voltage:double;
+ top_claw_voltage:double;
+ bottom_claw_voltage:double;
+ tusk_voltage:double;
+}
+
+root_type Output;
diff --git a/y2014/control_loops/claw/claw_position.fbs b/y2014/control_loops/claw/claw_position.fbs
new file mode 100644
index 0000000..17d9f17
--- /dev/null
+++ b/y2014/control_loops/claw/claw_position.fbs
@@ -0,0 +1,25 @@
+include "frc971/control_loops/control_loops.fbs";
+
+namespace y2014.control_loops.claw;
+
+// All angles here are 0 vertical, positive "up" (aka backwards).
+table HalfClawPosition {
+ // The current position of this half of the claw.
+ position:double;
+
+ // The hall effect sensor at the front limit.
+ front:frc971.HallEffectStruct;
+ // The hall effect sensor in the middle to use for real calibration.
+ calibration:frc971.HallEffectStruct;
+ // The hall effect at the back limit.
+ back:frc971.HallEffectStruct;
+}
+
+table Position {
+ // All the top claw information.
+ top:HalfClawPosition;
+ // All the bottom claw information.
+ bottom:HalfClawPosition;
+}
+
+root_type Position;
diff --git a/y2014/control_loops/claw/claw_status.fbs b/y2014/control_loops/claw/claw_status.fbs
new file mode 100644
index 0000000..eda9279
--- /dev/null
+++ b/y2014/control_loops/claw/claw_status.fbs
@@ -0,0 +1,21 @@
+namespace y2014.control_loops.claw;
+
+// All angles here are 0 vertical, positive "up" (aka backwards).
+table Status {
+ // True if zeroed enough for the current period (autonomous or teleop).
+ zeroed:bool;
+ // True if zeroed as much as we will force during autonomous.
+ zeroed_for_auto:bool;
+ // True if zeroed and within tolerance for separation and bottom angle.
+ done:bool;
+ // True if zeroed and within tolerance for separation and bottom angle.
+ // seperation allowance much wider as a ball may be included
+ done_with_ball:bool;
+ // Dump the values of the state matrix.
+ bottom:double;
+ bottom_velocity:double;
+ separation:double;
+ separation_velocity:double;
+}
+
+root_type Status;