blob: 3cbff00590adbfd7a4b16b1d7fbc555fd5572b85 [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/logging/logging.h"
#include "aos/logging/queue_logging.h"
#include "aos/util/phased_loop.h"
#include "aos/robot_state/robot_state.q.h"
#include "aos/time/time.h"
#include "aos/init.h"
#include "frc971/queues/gyro.q.h"
#include "frc971/zeroing/averager.h"
namespace frc971 {
namespace wpilib {
namespace chrono = ::std::chrono;
using ::aos::monotonic_clock;
GyroSender::GyroSender() {
PCHECK(system(
"ps -ef | grep '\\[spi0\\]' | awk '{print $1}' | xargs chrt -f -p "
"33") == 0);
}
void GyroSender::operator()() {
::aos::SetCurrentThreadName("Gyro");
// Try to initialize repeatedly as long as we're supposed to be running.
while (run_ && !gyro_.InitializeGyro()) {
::std::this_thread::sleep_for(::std::chrono::milliseconds(50));
}
LOG(INFO, "gyro initialized successfully\n");
auto message = ::frc971::sensors::gyro_part_id.MakeMessage();
message->uid = gyro_.ReadPartID();
LOG_STRUCT(INFO, "gyro ID", *message);
message.Send();
// In radians, ready to send out.
double angle = 0;
int startup_cycles_left = 2 * kReadingRate;
zeroing::Averager<double, 6 * kReadingRate> zeroing_data;
bool zeroed = false;
double zero_offset = 0;
::aos::SetCurrentThreadRealtimePriority(33);
::aos::time::PhasedLoop phased_loop(::aos::time::FromRate(kReadingRate),
chrono::milliseconds(4));
// How many timesteps the next reading represents.
int number_readings = 0;
::aos::SetCurrentThreadRealtimePriority(33);
while (run_) {
number_readings += phased_loop.SleepUntilNext();
const uint32_t result = gyro_.GetReading();
if (result == 0) {
LOG(WARNING, "normal gyro read failed\n");
continue;
}
switch (gyro_.ExtractStatus(result)) {
case 0:
LOG(WARNING, "gyro says data is bad\n");
continue;
case 1:
break;
default:
LOG(WARNING, "gyro gave weird status 0x%" PRIx8 "\n",
gyro_.ExtractStatus(result));
continue;
}
if (gyro_.ExtractErrors(result) != 0) {
const uint8_t errors = gyro_.ExtractErrors(result);
if (errors & (1 << 6)) {
LOG(WARNING, "gyro gave PLL error\n");
}
if (errors & (1 << 5)) {
LOG(WARNING, "gyro gave quadrature error\n");
}
if (errors & (1 << 4)) {
LOG(WARNING, "gyro gave non-volatile memory error\n");
}
if (errors & (1 << 3)) {
LOG(WARNING, "gyro gave volatile memory error\n");
}
if (errors & (1 << 2)) {
LOG(WARNING, "gyro gave power error\n");
}
if (errors & (1 << 1)) {
LOG(WARNING, "gyro gave continuous self-test error\n");
}
if (errors & 1) {
LOG(WARNING, "gyro gave unexpected self-test mode\n");
}
continue;
}
if (startup_cycles_left > 0) {
--startup_cycles_left;
continue;
}
const double angle_rate = gyro_.ExtractAngle(result);
const double new_angle = angle_rate / static_cast<double>(kReadingRate);
auto message = ::frc971::sensors::gyro_reading.MakeMessage();
if (zeroed) {
angle += (new_angle + zero_offset) * number_readings;
message->angle = angle;
message->velocity = angle_rate + zero_offset * kReadingRate;
LOG_STRUCT(DEBUG, "sending", *message);
message.Send();
} 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?
{
message->angle = new_angle;
message->velocity = angle_rate;
LOG_STRUCT(DEBUG, "collected while zeroing", *message);
message->angle = 0.0;
message->velocity = 0.0;
message.Send();
}
zeroing_data.AddData(new_angle);
::aos::joystick_state.FetchLatest();
if (::aos::joystick_state.get() && ::aos::joystick_state->enabled &&
zeroing_data.full()) {
zero_offset = -zeroing_data.GetAverage();
LOG(INFO, "total zero offset %f\n", zero_offset);
zeroed = true;
}
}
number_readings = 0;
}
}
} // namespace wpilib
} // namespace frc971