blob: 0b590f943996560a6b44a9c0fc2bac935cde0997 [file] [log] [blame]
#include "frc971/wpilib/gyro_sender.h"
#include <fcntl.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <chrono>
#include "aos/events/shm_event_loop.h"
#include "aos/init.h"
#include "aos/logging/logging.h"
#include "aos/robot_state/robot_state_generated.h"
#include "aos/time/time.h"
#include "frc971/queues/gyro_generated.h"
#include "frc971/zeroing/averager.h"
namespace frc971 {
namespace wpilib {
namespace chrono = ::std::chrono;
using ::aos::monotonic_clock;
GyroSender::GyroSender(::aos::ShmEventLoop *event_loop)
: event_loop_(event_loop),
joystick_state_fetcher_(
event_loop_->MakeFetcher<aos::RobotState>("/aos")),
uid_sender_(event_loop_->MakeSender<frc971::sensors::Uid>("/drivetrain")),
gyro_reading_sender_(
event_loop_->MakeSender<frc971::sensors::GyroReading>(
"/drivetrain")) {
AOS_PCHECK(
system("ps -ef | grep '\\[spi0\\]' | awk '{print $1}' | xargs chrt -f -p "
"33") == 0);
event_loop->set_name("Gyro");
event_loop_->SetRuntimeRealtimePriority(33);
// TODO(austin): This should be synchronized with SensorReader... Pull out
// the sync logic and re-use it here.
event_loop_->AddPhasedLoop([this](int iterations) { Loop(iterations); },
::aos::time::FromRate(kReadingRate),
chrono::milliseconds(4));
}
void GyroSender::Loop(const int iterations) {
switch (state_) {
case State::INITIALIZING: {
const monotonic_clock::time_point monotonic_now =
event_loop_->monotonic_now();
if (last_initialize_time_ + chrono::milliseconds(50) < monotonic_now) {
if (gyro_.InitializeGyro()) {
state_ = State::RUNNING;
AOS_LOG(INFO, "gyro initialized successfully\n");
auto builder = uid_sender_.MakeBuilder();
builder.Send(
frc971::sensors::CreateUid(*builder.fbb(), gyro_.ReadPartID()));
}
last_initialize_time_ = monotonic_now;
}
} break;
case State::RUNNING: {
const uint32_t result = gyro_.GetReading();
if (result == 0) {
AOS_LOG(WARNING, "normal gyro read failed\n");
return;
}
switch (gyro_.ExtractStatus(result)) {
case 0:
AOS_LOG(WARNING, "gyro says data is bad\n");
return;
case 1:
break;
default:
AOS_LOG(WARNING, "gyro gave weird status 0x%" PRIx8 "\n",
gyro_.ExtractStatus(result));
return;
}
if (gyro_.ExtractErrors(result) != 0) {
const uint8_t errors = gyro_.ExtractErrors(result);
if (errors & (1 << 6)) {
AOS_LOG(WARNING, "gyro gave PLL error\n");
}
if (errors & (1 << 5)) {
AOS_LOG(WARNING, "gyro gave quadrature error\n");
}
if (errors & (1 << 4)) {
AOS_LOG(WARNING, "gyro gave non-volatile memory error\n");
}
if (errors & (1 << 3)) {
AOS_LOG(WARNING, "gyro gave volatile memory error\n");
}
if (errors & (1 << 2)) {
AOS_LOG(WARNING, "gyro gave power error\n");
}
if (errors & (1 << 1)) {
AOS_LOG(WARNING, "gyro gave continuous self-test error\n");
}
if (errors & 1) {
AOS_LOG(WARNING, "gyro gave unexpected self-test mode\n");
}
return;
}
if (startup_cycles_left_ > 0) {
--startup_cycles_left_;
return;
}
const double angle_rate = gyro_.ExtractAngle(result);
const double new_angle = angle_rate / static_cast<double>(kReadingRate);
auto builder = gyro_reading_sender_.MakeBuilder();
if (zeroed_) {
angle_ += (new_angle + zero_offset_) * iterations;
sensors::GyroReading::Builder gyro_builder =
builder.MakeBuilder<sensors::GyroReading>();
gyro_builder.add_angle(angle_);
gyro_builder.add_velocity(angle_rate + zero_offset_ * kReadingRate);
builder.Send(gyro_builder.Finish());
} else {
// TODO(brian): Don't break without 6 seconds of standing still before
// enabling. Ideas:
// Don't allow driving until we have at least some data?
// Some kind of indicator light?
{
sensors::GyroReading::Builder gyro_builder =
builder.MakeBuilder<sensors::GyroReading>();
gyro_builder.add_angle(0.0);
gyro_builder.add_velocity(0.0);
builder.Send(gyro_builder.Finish());
}
zeroing_data_.AddData(new_angle);
joystick_state_fetcher_.Fetch();
if (joystick_state_fetcher_.get() &&
joystick_state_fetcher_->outputs_enabled() &&
zeroing_data_.full()) {
zero_offset_ = -zeroing_data_.GetAverage()(0, 0);
AOS_LOG(INFO, "total zero offset %f\n", zero_offset_);
zeroed_ = true;
}
}
} break;
}
}
} // namespace wpilib
} // namespace frc971