Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 1 | #ifndef FRC971_WPILIB_ADIS16448_H_ |
| 2 | #define FRC971_WPILIB_ADIS16448_H_ |
| 3 | |
| 4 | #include <stdint.h> |
| 5 | |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 6 | #include <atomic> |
Parker Schuh | d3b7a887 | 2018-02-19 16:42:27 -0800 | [diff] [blame] | 7 | #include <memory> |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 8 | |
Parker Schuh | d3b7a887 | 2018-02-19 16:42:27 -0800 | [diff] [blame] | 9 | #include "frc971/wpilib/ahal/DigitalInput.h" |
| 10 | #include "frc971/wpilib/ahal/DigitalOutput.h" |
| 11 | #include "frc971/wpilib/ahal/SPI.h" |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 12 | #undef ERROR |
| 13 | |
Austin Schuh | df6cbb1 | 2019-02-02 13:46:52 -0800 | [diff] [blame] | 14 | #include "aos/events/event-loop.h" |
John Park | 33858a3 | 2018-09-28 23:05:48 -0700 | [diff] [blame] | 15 | #include "aos/logging/logging.h" |
Austin Schuh | df6cbb1 | 2019-02-02 13:46:52 -0800 | [diff] [blame] | 16 | #include "aos/robot_state/robot_state.q.h" |
Austin Schuh | 73b6e3b | 2019-05-27 16:37:15 -0700 | [diff] [blame^] | 17 | #include "frc971/wpilib/imu.q.h" |
Brian Silverman | 003a473 | 2018-03-11 14:02:15 -0700 | [diff] [blame] | 18 | #include "frc971/wpilib/spi_rx_clearer.h" |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 19 | |
| 20 | namespace frc971 { |
| 21 | namespace wpilib { |
| 22 | |
| 23 | // Handles interfacing with an Analog Devices ADIS16448 Inertial Sensor over |
| 24 | // SPI and sending values out on a queue. |
| 25 | // |
| 26 | // The sensor is configured to generate samples at 204.8 Hz, and the values are |
| 27 | // sent out as each sample is received. |
| 28 | // |
| 29 | // This is designed to be passed into ::std::thread's constructor so it will run |
| 30 | // as a separate thread. |
| 31 | class ADIS16448 { |
| 32 | public: |
| 33 | // port is where to find the sensor over SPI. |
| 34 | // dio1 must be connected to DIO1 on the sensor. |
Austin Schuh | df6cbb1 | 2019-02-02 13:46:52 -0800 | [diff] [blame] | 35 | ADIS16448(::aos::EventLoop *event_loop, frc::SPI::Port port, |
| 36 | frc::DigitalInput *dio1); |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 37 | |
Brian Silverman | a70994f | 2017-03-16 22:32:55 -0700 | [diff] [blame] | 38 | // Sets the dummy SPI port to send values on to make the roboRIO deassert the |
| 39 | // chip select line. This is mainly useful when there are no other devices |
| 40 | // sharing the bus. |
Parker Schuh | d3b7a887 | 2018-02-19 16:42:27 -0800 | [diff] [blame] | 41 | void SetDummySPI(frc::SPI::Port port); |
Brian Silverman | a70994f | 2017-03-16 22:32:55 -0700 | [diff] [blame] | 42 | |
| 43 | // Sets the reset line for the IMU to use for error recovery. |
Parker Schuh | d3b7a887 | 2018-02-19 16:42:27 -0800 | [diff] [blame] | 44 | void set_reset(frc::DigitalOutput *output) { reset_ = output; } |
Brian Silverman | a70994f | 2017-03-16 22:32:55 -0700 | [diff] [blame] | 45 | |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 46 | // For ::std::thread to call. |
| 47 | // |
| 48 | // Initializes the sensor and then loops until Quit() is called taking |
| 49 | // readings. |
| 50 | void operator()(); |
| 51 | |
Brian Silverman | cfc8fa4 | 2019-03-30 21:07:39 -0600 | [diff] [blame] | 52 | // Sets a function to be called immediately after each time this class uses |
| 53 | // the SPI bus. This is a good place to do other things on the bus. |
Brian Silverman | 56c2bcb | 2019-02-24 15:10:18 -0800 | [diff] [blame] | 54 | void set_spi_idle_callback(std::function<void()> spi_idle_callback) { |
| 55 | spi_idle_callback_ = std::move(spi_idle_callback); |
| 56 | } |
| 57 | |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 58 | void Quit() { run_ = false; } |
| 59 | |
Philipp Schrader | 29d54f2 | 2016-04-02 22:14:48 +0000 | [diff] [blame] | 60 | double gyro_x_zeroed_offset() const { return gyro_x_zeroed_offset_; } |
| 61 | double gyro_y_zeroed_offset() const { return gyro_y_zeroed_offset_; } |
| 62 | double gyro_z_zeroed_offset() const { return gyro_z_zeroed_offset_; } |
| 63 | |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 64 | private: |
Brian Silverman | a70994f | 2017-03-16 22:32:55 -0700 | [diff] [blame] | 65 | // Try to initialize repeatedly as long as we're supposed to be running. |
| 66 | void InitializeUntilSuccessful(); |
| 67 | |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 68 | // Converts a 16-bit value at data to a scaled output value where a value of 1 |
| 69 | // corresponds to lsb_per_output. |
| 70 | float ConvertValue(uint8_t *data, double lsb_per_output, bool sign = true); |
| 71 | |
| 72 | // Performs an SPI transaction. |
| 73 | // Returns true if it succeeds. |
| 74 | template <uint8_t size> |
| 75 | bool DoTransaction(uint8_t to_send[size], uint8_t to_receive[size]); |
| 76 | |
| 77 | // Reads one of the gyro's registers and returns the value in value. |
| 78 | // next_address is the address of the *next* register to read. |
| 79 | // Not sure what gets stored in value for the first read, but it should be |
| 80 | // ignored. Passing nullptr for value is allowed to completely ignore it. |
| 81 | // Returns true if it succeeds. |
| 82 | bool ReadRegister(uint8_t next_address, uint16_t *value); |
| 83 | |
| 84 | // Writes a value to one of the registers. |
| 85 | // Returns true if it succeeds. |
| 86 | bool WriteRegister(uint8_t address, uint16_t value); |
| 87 | |
| 88 | // Checks the given value of the DIAG_STAT register and logs any errors. |
| 89 | // Returns true if there are no errors we care about. |
| 90 | bool CheckDiagStatValue(uint16_t value) const; |
| 91 | |
| 92 | // Starts everything up and runs a self test. |
| 93 | // Returns true if it succeeds. |
| 94 | bool Initialize(); |
| 95 | |
Austin Schuh | df6cbb1 | 2019-02-02 13:46:52 -0800 | [diff] [blame] | 96 | ::aos::EventLoop *event_loop_; |
| 97 | ::aos::Fetcher<::aos::JoystickState> joystick_state_fetcher_; |
Austin Schuh | 73b6e3b | 2019-05-27 16:37:15 -0700 | [diff] [blame^] | 98 | ::aos::Sender<::frc971::IMUValues> imu_values_sender_; |
Austin Schuh | df6cbb1 | 2019-02-02 13:46:52 -0800 | [diff] [blame] | 99 | |
Brian Silverman | a70994f | 2017-03-16 22:32:55 -0700 | [diff] [blame] | 100 | // TODO(Brian): This object has no business owning these ones. |
Parker Schuh | d3b7a887 | 2018-02-19 16:42:27 -0800 | [diff] [blame] | 101 | const ::std::unique_ptr<frc::SPI> spi_; |
| 102 | ::std::unique_ptr<frc::SPI> dummy_spi_; |
| 103 | frc::DigitalInput *const dio1_; |
| 104 | frc::DigitalOutput *reset_ = nullptr; |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 105 | |
Brian Silverman | 56c2bcb | 2019-02-24 15:10:18 -0800 | [diff] [blame] | 106 | std::function<void()> spi_idle_callback_ = []() {}; |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 107 | ::std::atomic<bool> run_{true}; |
Philipp Schrader | 29d54f2 | 2016-04-02 22:14:48 +0000 | [diff] [blame] | 108 | |
| 109 | // The averaged values of the gyro over 6 seconds after power up. |
Austin Schuh | 943fcbd | 2016-04-03 21:35:41 -0700 | [diff] [blame] | 110 | bool gyros_are_zeroed_ = false; |
Philipp Schrader | 29d54f2 | 2016-04-02 22:14:48 +0000 | [diff] [blame] | 111 | double gyro_x_zeroed_offset_ = 0.0; |
| 112 | double gyro_y_zeroed_offset_ = 0.0; |
| 113 | double gyro_z_zeroed_offset_ = 0.0; |
Brian Silverman | 003a473 | 2018-03-11 14:02:15 -0700 | [diff] [blame] | 114 | |
| 115 | SpiRxClearer rx_clearer_; |
Brian Silverman | 5f17a97 | 2016-02-28 01:49:32 -0500 | [diff] [blame] | 116 | }; |
| 117 | |
| 118 | } // namespace wpilib |
| 119 | } // namespace frc971 |
| 120 | |
| 121 | #endif // FRC971_WPILIB_ADIS16448_H_ |