WPILibC++ 2024.1.1-beta-4
ADIS16470_IMU.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5/*----------------------------------------------------------------------------*/
6/* Copyright (c) 2016-2020 Analog Devices Inc. All Rights Reserved. */
7/* Open Source Software - may be modified and shared by FRC teams. The code */
8/* must be accompanied by the FIRST BSD license file in the root directory of */
9/* the project. */
10/* */
11/* Juan Chong - frcsupport@analog.com */
12/*----------------------------------------------------------------------------*/
13
14#pragma once
15
16#include <stdint.h>
17
18#include <atomic>
19#include <memory>
20#include <thread>
21
22#include <hal/SimDevice.h>
23#include <units/acceleration.h>
24#include <units/angle.h>
27#include <wpi/mutex.h>
30
31#include "frc/DigitalInput.h"
32#include "frc/DigitalOutput.h"
33#include "frc/DigitalSource.h"
34#include "frc/SPI.h"
35
36namespace frc {
37/**
38 * Use DMA SPI to read rate and acceleration data from the ADIS16470 IMU and
39 * return the robot's heading relative to a starting position and instant
40 * measurements
41 *
42 * The ADIS16470 gyro angle outputs track the robot's heading based on the
43 * starting position. As the robot rotates the new heading is computed by
44 * integrating the rate of rotation returned by the IMU. When the class is
45 * instantiated, a short calibration routine is performed where the IMU samples
46 * the gyros while at rest to determine the initial offset. This is subtracted
47 * from each sample to determine the heading.
48 *
49 * This class is for the ADIS16470 IMU connected via the primary SPI port
50 * available on the RoboRIO.
51 */
52
54 public wpi::SendableHelper<ADIS16470_IMU> {
55 public:
56 /* ADIS16470 Calibration Time Enum Class */
57 enum class CalibrationTime {
58 _32ms = 0,
59 _64ms = 1,
60 _128ms = 2,
61 _256ms = 3,
62 _512ms = 4,
63 _1s = 5,
64 _2s = 6,
65 _4s = 7,
66 _8s = 8,
67 _16s = 9,
68 _32s = 10,
69 _64s = 11
70 };
71
72 enum IMUAxis { kX, kY, kZ };
73
74 /**
75 * @brief Default constructor. Uses CS0 on the 10-pin SPI port, the yaw axis
76 * is set to the IMU Z axis, and calibration time is defaulted to 4 seconds.
77 */
79
80 /**
81 * @brief Customizable constructor. Allows the SPI port and CS to be
82 * customized, the yaw axis used for GetAngle() is adjustable, and initial
83 * calibration time can be modified.
84 *
85 * @param yaw_axis Selects the "default" axis to use for GetAngle() and
86 * GetRate()
87 *
88 * @param port The SPI port and CS where the IMU is connected.
89 *
90 * @param cal_time The calibration time that should be used on start-up.
91 */
92 explicit ADIS16470_IMU(IMUAxis yaw_axis, SPI::Port port,
93 CalibrationTime cal_time);
94
95 /**
96 * @brief Destructor. Kills the acquisition loop and closes the SPI
97 * peripheral.
98 */
99 ~ADIS16470_IMU() override;
100
103
104 int ConfigDecRate(uint16_t reg);
105
106 /**
107 * @brief Switches the active SPI port to standard SPI mode, writes the
108 * command to activate the new null configuration, and re-enables auto SPI.
109 */
110 void Calibrate();
111
112 /**
113 * @brief Switches the active SPI port to standard SPI mode, writes a new
114 * value to the NULL_CNFG register in the IMU, and re-enables auto SPI.
115 */
117
118 /**
119 * @brief Resets (zeros) the xgyro, ygyro, and zgyro angle integrations.
120 *
121 * Resets the gyro accumulations to a heading of zero. This can be used if
122 * the "zero" orientation of the sensor needs to be changed in runtime.
123 */
124 void Reset();
125
126 /**
127 * Returns the yaw axis angle in degrees (CCW positive).
128 */
129 units::degree_t GetAngle() const;
130
131 /**
132 * Returns the yaw axis angular rate in degrees per second (CCW positive).
133 */
134 units::degrees_per_second_t GetRate() const;
135
136 /**
137 * Returns the acceleration in the X axis.
138 */
139 units::meters_per_second_squared_t GetAccelX() const;
140
141 /**
142 * Returns the acceleration in the Y axis.
143 */
144 units::meters_per_second_squared_t GetAccelY() const;
145
146 /**
147 * Returns the acceleration in the Z axis.
148 */
149 units::meters_per_second_squared_t GetAccelZ() const;
150
151 units::degree_t GetXComplementaryAngle() const;
152
153 units::degree_t GetYComplementaryAngle() const;
154
155 units::degree_t GetXFilteredAccelAngle() const;
156
157 units::degree_t GetYFilteredAccelAngle() const;
158
160
161 int SetYawAxis(IMUAxis yaw_axis);
162
163 bool IsConnected() const;
164
165 // IMU yaw axis
167
168 /**
169 * Get the SPI port number.
170 *
171 * @return The SPI port number.
172 */
173 int GetPort() const;
174
175 void InitSendable(wpi::SendableBuilder& builder) override;
176
177 private:
178 /* ADIS16470 Register Map Declaration */
179 static constexpr uint8_t FLASH_CNT = 0x00; // Flash memory write count
180 static constexpr uint8_t DIAG_STAT =
181 0x02; // Diagnostic and operational status
182 static constexpr uint8_t X_GYRO_LOW =
183 0x04; // X-axis gyroscope output, lower word
184 static constexpr uint8_t X_GYRO_OUT =
185 0x06; // X-axis gyroscope output, upper word
186 static constexpr uint8_t Y_GYRO_LOW =
187 0x08; // Y-axis gyroscope output, lower word
188 static constexpr uint8_t Y_GYRO_OUT =
189 0x0A; // Y-axis gyroscope output, upper word
190 static constexpr uint8_t Z_GYRO_LOW =
191 0x0C; // Z-axis gyroscope output, lower word
192 static constexpr uint8_t Z_GYRO_OUT =
193 0x0E; // Z-axis gyroscope output, upper word
194 static constexpr uint8_t X_ACCL_LOW =
195 0x10; // X-axis accelerometer output, lower word
196 static constexpr uint8_t X_ACCL_OUT =
197 0x12; // X-axis accelerometer output, upper word
198 static constexpr uint8_t Y_ACCL_LOW =
199 0x14; // Y-axis accelerometer output, lower word
200 static constexpr uint8_t Y_ACCL_OUT =
201 0x16; // Y-axis accelerometer output, upper word
202 static constexpr uint8_t Z_ACCL_LOW =
203 0x18; // Z-axis accelerometer output, lower word
204 static constexpr uint8_t Z_ACCL_OUT =
205 0x1A; // Z-axis accelerometer output, upper word
206 static constexpr uint8_t TEMP_OUT =
207 0x1C; // Temperature output (internal, not calibrated)
208 static constexpr uint8_t TIME_STAMP = 0x1E; // PPS mode time stamp
209 static constexpr uint8_t X_DELTANG_LOW =
210 0x24; // X-axis delta angle output, lower word
211 static constexpr uint8_t X_DELTANG_OUT =
212 0x26; // X-axis delta angle output, upper word
213 static constexpr uint8_t Y_DELTANG_LOW =
214 0x28; // Y-axis delta angle output, lower word
215 static constexpr uint8_t Y_DELTANG_OUT =
216 0x2A; // Y-axis delta angle output, upper word
217 static constexpr uint8_t Z_DELTANG_LOW =
218 0x2C; // Z-axis delta angle output, lower word
219 static constexpr uint8_t Z_DELTANG_OUT =
220 0x2E; // Z-axis delta angle output, upper word
221 static constexpr uint8_t X_DELTVEL_LOW =
222 0x30; // X-axis delta velocity output, lower word
223 static constexpr uint8_t X_DELTVEL_OUT =
224 0x32; // X-axis delta velocity output, upper word
225 static constexpr uint8_t Y_DELTVEL_LOW =
226 0x34; // Y-axis delta velocity output, lower word
227 static constexpr uint8_t Y_DELTVEL_OUT =
228 0x36; // Y-axis delta velocity output, upper word
229 static constexpr uint8_t Z_DELTVEL_LOW =
230 0x38; // Z-axis delta velocity output, lower word
231 static constexpr uint8_t Z_DELTVEL_OUT =
232 0x3A; // Z-axis delta velocity output, upper word
233 static constexpr uint8_t XG_BIAS_LOW =
234 0x40; // X-axis gyroscope bias offset correction, lower word
235 static constexpr uint8_t XG_BIAS_HIGH =
236 0x42; // X-axis gyroscope bias offset correction, upper word
237 static constexpr uint8_t YG_BIAS_LOW =
238 0x44; // Y-axis gyroscope bias offset correction, lower word
239 static constexpr uint8_t YG_BIAS_HIGH =
240 0x46; // Y-axis gyroscope bias offset correction, upper word
241 static constexpr uint8_t ZG_BIAS_LOW =
242 0x48; // Z-axis gyroscope bias offset correction, lower word
243 static constexpr uint8_t ZG_BIAS_HIGH =
244 0x4A; // Z-axis gyroscope bias offset correction, upper word
245 static constexpr uint8_t XA_BIAS_LOW =
246 0x4C; // X-axis accelerometer bias offset correction, lower word
247 static constexpr uint8_t XA_BIAS_HIGH =
248 0x4E; // X-axis accelerometer bias offset correction, upper word
249 static constexpr uint8_t YA_BIAS_LOW =
250 0x50; // Y-axis accelerometer bias offset correction, lower word
251 static constexpr uint8_t YA_BIAS_HIGH =
252 0x52; // Y-axis accelerometer bias offset correction, upper word
253 static constexpr uint8_t ZA_BIAS_LOW =
254 0x54; // Z-axis accelerometer bias offset correction, lower word
255 static constexpr uint8_t ZA_BIAS_HIGH =
256 0x56; // Z-axis accelerometer bias offset correction, upper word
257 static constexpr uint8_t FILT_CTRL = 0x5C; // Filter control
258 static constexpr uint8_t MSC_CTRL = 0x60; // Miscellaneous control
259 static constexpr uint8_t UP_SCALE = 0x62; // Clock scale factor, PPS mode
260 static constexpr uint8_t DEC_RATE =
261 0x64; // Decimation rate control (output data rate)
262 static constexpr uint8_t NULL_CNFG = 0x66; // Auto-null configuration control
263 static constexpr uint8_t GLOB_CMD = 0x68; // Global commands
264 static constexpr uint8_t FIRM_REV = 0x6C; // Firmware revision
265 static constexpr uint8_t FIRM_DM =
266 0x6E; // Firmware revision date, month and day
267 static constexpr uint8_t FIRM_Y = 0x70; // Firmware revision date, year
268 static constexpr uint8_t PROD_ID = 0x72; // Product identification
269 static constexpr uint8_t SERIAL_NUM =
270 0x74; // Serial number (relative to assembly lot)
271 static constexpr uint8_t USER_SCR1 = 0x76; // User scratch register 1
272 static constexpr uint8_t USER_SCR2 = 0x78; // User scratch register 2
273 static constexpr uint8_t USER_SCR3 = 0x7A; // User scratch register 3
274 static constexpr uint8_t FLSHCNT_LOW =
275 0x7C; // Flash update count, lower word
276 static constexpr uint8_t FLSHCNT_HIGH =
277 0x7E; // Flash update count, upper word
278
279 /* ADIS16470 Auto SPI Data Packets */
280 static constexpr uint8_t m_autospi_x_packet[16] = {
281 X_DELTANG_OUT, FLASH_CNT, X_DELTANG_LOW, FLASH_CNT, X_GYRO_OUT, FLASH_CNT,
282 Y_GYRO_OUT, FLASH_CNT, Z_GYRO_OUT, FLASH_CNT, X_ACCL_OUT, FLASH_CNT,
283 Y_ACCL_OUT, FLASH_CNT, Z_ACCL_OUT, FLASH_CNT};
284
285 static constexpr uint8_t m_autospi_y_packet[16] = {
286 Y_DELTANG_OUT, FLASH_CNT, Y_DELTANG_LOW, FLASH_CNT, X_GYRO_OUT, FLASH_CNT,
287 Y_GYRO_OUT, FLASH_CNT, Z_GYRO_OUT, FLASH_CNT, X_ACCL_OUT, FLASH_CNT,
288 Y_ACCL_OUT, FLASH_CNT, Z_ACCL_OUT, FLASH_CNT};
289
290 static constexpr uint8_t m_autospi_z_packet[16] = {
291 Z_DELTANG_OUT, FLASH_CNT, Z_DELTANG_LOW, FLASH_CNT, X_GYRO_OUT, FLASH_CNT,
292 Y_GYRO_OUT, FLASH_CNT, Z_GYRO_OUT, FLASH_CNT, X_ACCL_OUT, FLASH_CNT,
293 Y_ACCL_OUT, FLASH_CNT, Z_ACCL_OUT, FLASH_CNT};
294
295 /* ADIS16470 Constants */
296 static constexpr double delta_angle_sf =
297 2160.0 / 2147483648.0; /* 2160 / (2^31) */
298 static constexpr double rad_to_deg = 57.2957795;
299 static constexpr double deg_to_rad = 0.0174532;
300 static constexpr double grav = 9.81;
301
302 /** @brief Resources **/
303 DigitalInput* m_reset_in;
304 DigitalOutput* m_status_led;
305
306 /**
307 * @brief Switches to standard SPI operation. Primarily used when exiting auto
308 * SPI mode.
309 *
310 * @return A boolean indicating the success or failure of setting up the SPI
311 * peripheral in standard SPI mode.
312 */
313 bool SwitchToStandardSPI();
314
315 /**
316 * @brief Switches to auto SPI operation. Primarily used when exiting standard
317 * SPI mode.
318 *
319 * @return A boolean indicating the success or failure of setting up the SPI
320 * peripheral in auto SPI mode.
321 */
322 bool SwitchToAutoSPI();
323
324 /**
325 * @brief Reads the contents of a specified register location over SPI.
326 *
327 * @param reg An unsigned, 8-bit register location.
328 *
329 * @return An unsigned, 16-bit number representing the contents of the
330 * requested register location.
331 */
332 uint16_t ReadRegister(uint8_t reg);
333
334 /**
335 * @brief Writes an unsigned, 16-bit value to two adjacent, 8-bit register
336 * locations over SPI.
337 *
338 * @param reg An unsigned, 8-bit register location.
339 *
340 * @param val An unsigned, 16-bit value to be written to the specified
341 * register location.
342 */
343 void WriteRegister(uint8_t reg, uint16_t val);
344
345 /**
346 * @brief Main acquisition loop. Typically called asynchronously and
347 * free-wheels while the robot code is active.
348 */
349 void Acquire();
350
351 void Close();
352
353 // Integrated gyro value
354 double m_integ_angle = 0.0;
355
356 // Instant raw outputs
357 double m_gyro_rate_x = 0.0;
358 double m_gyro_rate_y = 0.0;
359 double m_gyro_rate_z = 0.0;
360 double m_accel_x = 0.0;
361 double m_accel_y = 0.0;
362 double m_accel_z = 0.0;
363
364 // Complementary filter variables
365 double m_tau = 1.0;
366 double m_dt, m_alpha = 0.0;
367 double m_compAngleX, m_compAngleY, m_accelAngleX, m_accelAngleY = 0.0;
368
369 // Complementary filter functions
370 double FormatFastConverge(double compAngle, double accAngle);
371
372 double FormatRange0to2PI(double compAngle);
373
374 double FormatAccelRange(double accelAngle, double accelZ);
375
376 double CompFilterProcess(double compAngle, double accelAngle, double omega);
377
378 // State and resource variables
379 volatile bool m_thread_active = false;
380 volatile bool m_first_run = true;
381 volatile bool m_thread_idle = false;
382 bool m_auto_configured = false;
383 SPI::Port m_spi_port;
384 uint16_t m_calibration_time = 0;
385 SPI* m_spi = nullptr;
386 DigitalInput* m_auto_interrupt = nullptr;
387 double m_scaled_sample_rate = 2500.0; // Default sample rate setting
388 bool m_connected{false};
389
390 std::thread m_acquire_task;
391
392 hal::SimDevice m_simDevice;
393 hal::SimBoolean m_simConnected;
394 hal::SimDouble m_simGyroAngleX;
395 hal::SimDouble m_simGyroAngleY;
396 hal::SimDouble m_simGyroAngleZ;
397 hal::SimDouble m_simGyroRateX;
398 hal::SimDouble m_simGyroRateY;
399 hal::SimDouble m_simGyroRateZ;
400 hal::SimDouble m_simAccelX;
401 hal::SimDouble m_simAccelY;
402 hal::SimDouble m_simAccelZ;
403
404 struct NonMovableMutexWrapper {
405 wpi::mutex mutex;
406 NonMovableMutexWrapper() = default;
407
408 NonMovableMutexWrapper(const NonMovableMutexWrapper&) = delete;
409 NonMovableMutexWrapper& operator=(const NonMovableMutexWrapper&) = delete;
410
411 NonMovableMutexWrapper(NonMovableMutexWrapper&&) {}
412 NonMovableMutexWrapper& operator=(NonMovableMutexWrapper&&) {
413 return *this;
414 }
415
416 void lock() { mutex.lock(); }
417
418 void unlock() { mutex.unlock(); }
419
420 bool try_lock() noexcept { return mutex.try_lock(); }
421 };
422
423 mutable NonMovableMutexWrapper m_mutex;
424};
425
426} // namespace frc
Use DMA SPI to read rate and acceleration data from the ADIS16470 IMU and return the robot's heading ...
Definition: ADIS16470_IMU.h:54
~ADIS16470_IMU() override
Destructor.
ADIS16470_IMU(IMUAxis yaw_axis, SPI::Port port, CalibrationTime cal_time)
Customizable constructor.
units::degree_t GetAngle() const
Returns the yaw axis angle in degrees (CCW positive).
ADIS16470_IMU(ADIS16470_IMU &&)=default
ADIS16470_IMU()
Default constructor.
bool IsConnected() const
units::degree_t GetYFilteredAccelAngle() const
IMUAxis
Definition: ADIS16470_IMU.h:72
@ kX
Definition: ADIS16470_IMU.h:72
@ kZ
Definition: ADIS16470_IMU.h:72
@ kY
Definition: ADIS16470_IMU.h:72
units::degrees_per_second_t GetRate() const
Returns the yaw axis angular rate in degrees per second (CCW positive).
void Calibrate()
Switches the active SPI port to standard SPI mode, writes the command to activate the new null config...
CalibrationTime
Definition: ADIS16470_IMU.h:57
int SetYawAxis(IMUAxis yaw_axis)
void InitSendable(wpi::SendableBuilder &builder) override
Initializes this Sendable object.
units::degree_t GetXFilteredAccelAngle() const
units::degree_t GetYComplementaryAngle() const
int GetPort() const
Get the SPI port number.
ADIS16470_IMU & operator=(ADIS16470_IMU &&)=default
int ConfigCalTime(CalibrationTime new_cal_time)
Switches the active SPI port to standard SPI mode, writes a new value to the NULL_CNFG register in th...
IMUAxis m_yaw_axis
Definition: ADIS16470_IMU.h:166
IMUAxis GetYawAxis() const
void Reset()
Resets (zeros) the xgyro, ygyro, and zgyro angle integrations.
units::meters_per_second_squared_t GetAccelX() const
Returns the acceleration in the X axis.
units::meters_per_second_squared_t GetAccelY() const
Returns the acceleration in the Y axis.
int ConfigDecRate(uint16_t reg)
units::meters_per_second_squared_t GetAccelZ() const
Returns the acceleration in the Z axis.
units::degree_t GetXComplementaryAngle() const
Port
Definition: SPI.h:28
C++ wrapper around a HAL simulator boolean value handle.
Definition: SimDevice.h:610
A move-only C++ wrapper around a HAL simulator device handle.
Definition: SimDevice.h:644
C++ wrapper around a HAL simulator double value handle.
Definition: SimDevice.h:535
Definition: SendableBuilder.h:18
A helper class for use with objects that add themselves to SendableRegistry.
Definition: SendableHelper.h:19
Interface for Sendable objects.
Definition: Sendable.h:16
Definition: AprilTagPoseEstimator.h:15
::std::mutex mutex
Definition: mutex.h:17