Thunderbots Project
Loading...
Searching...
No Matches
motor.h
1#pragma once
2
3#include <Eigen/Dense>
4#include <memory>
5#include <string>
6
7#include "proto/robot_status_msg.pb.h"
8#include "proto/tbots_software_msgs.pb.h"
9#include "shared/constants.h"
10#include "shared/robot_constants.h"
11#include "software/embedded/constants/constants.h"
12#include "software/embedded/gpio.h"
13#include "software/embedded/gpio_char_dev.h"
14#include "software/embedded/gpio_sysfs.h"
15#include "software/embedded/platform.h"
16#include "software/physics/euclidean_to_wheel.h"
17
27{
28 public:
29 // SPI Chip Selects
30 static const uint8_t FRONT_LEFT_MOTOR_CHIP_SELECT = 0;
31 static const uint8_t FRONT_RIGHT_MOTOR_CHIP_SELECT = 3;
32 static const uint8_t BACK_LEFT_MOTOR_CHIP_SELECT = 1;
33 static const uint8_t BACK_RIGHT_MOTOR_CHIP_SELECT = 2;
34
42 MotorService(const RobotConstants_t& robot_constants, int control_loop_frequency_hz);
43
44 virtual ~MotorService();
45
55 TbotsProto::MotorStatus poll(const TbotsProto::MotorControl& motor_control,
56 double time_elapsed_since_last_poll_s);
57
67 uint8_t tmc4671ReadWriteByte(uint8_t motor, uint8_t data, uint8_t last_transfer);
68 uint8_t tmc6100ReadWriteByte(uint8_t motor, uint8_t data, uint8_t last_transfer);
69
70 /*
71 * For FOC to work, the controller needs to know the electical angle of the rotor
72 * relative to the mechanical angle of the rotor. In an incremental-encoder-only
73 * setup, we can energize the motor coils so that the rotor locks itself along
74 * one of its pole-pairs, allowing us to reset the encoder.
75 *
76 * WARNING: Do not try to spin the motor without initializing the encoder!
77 * The motor can overheat if the TMC4671 doesn't auto shut-off.
78 *
79 * There are some safety checks to ensure that the encoder is
80 * initialized, do not tamper with them. You have been warned.
81 *
82 * @param motor The motor to initialize the encoder for
83 */
84 void startEncoderCalibration(uint8_t motor);
85 void endEncoderCalibration(uint8_t motor);
86
103 void runOpenLoopCalibrationRoutine(uint8_t motor, size_t num_samples);
104
109 void resetMotorBoard();
110
114 void setup();
115
121 {
122 bool drive_enabled;
123 std::unordered_set<TbotsProto::MotorFault> motor_faults;
124
128 MotorFaultIndicator() : drive_enabled(true), motor_faults() {}
129
137 MotorFaultIndicator(bool drive_enabled,
138 std::unordered_set<TbotsProto::MotorFault>& motor_faults)
139 : drive_enabled(drive_enabled), motor_faults(motor_faults)
140 {
141 }
142 };
143
152 struct MotorFaultIndicator checkDriverFault(uint8_t motor);
153
159 void setUpDriveMotor(uint8_t motor);
160
169 void writeIntToTMC4671(uint8_t motor, uint8_t address, int32_t value);
170
179 int readIntFromTMC4671(uint8_t motor, uint8_t address);
180
181 private:
188 void motorServiceInit(const RobotConstants_t& robot_constants,
189 int control_loop_frequency_hz);
190
197 void startDriver(uint8_t motor);
198 void startController(uint8_t motor, bool dribbler);
199
218 void configurePWM(uint8_t motor);
219 void configureDribblerPI(uint8_t motor);
220 void configureDrivePI(uint8_t motor);
221 void configureADC(uint8_t motor);
222 void configureEncoder(uint8_t motor);
223 void configureHall(uint8_t motor);
224
238 void writeToControllerOrDieTrying(uint8_t motor, uint8_t address, int32_t value);
239 void writeToDriverOrDieTrying(uint8_t motor, uint8_t address, int32_t value);
240
251 void spiTransfer(int fd, uint8_t const* tx, uint8_t const* rx, unsigned len,
252 uint32_t spi_speed);
253
265 void readThenWriteSpiTransfer(int fd, const uint8_t* read_tx, uint8_t const* write_tx,
266 uint8_t const* read_rx, uint32_t spi_speed);
267
279 int32_t tmc4671ReadThenWriteValue(uint8_t motor, uint8_t read_addr,
280 uint8_t write_addr, int32_t write_data);
281
292 uint8_t readWriteByte(uint8_t motor, uint8_t data, uint8_t last_transfer,
293 uint32_t spi_speed);
294
295
303 void checkEncoderConnections();
304
322 TbotsProto::MotorStatus updateMotorStatus(double front_left_velocity_mps,
323 double front_right_velocity_mps,
324 double back_left_velocity_mps,
325 double back_right_velocity_mps,
326 double dribbler_rpm);
327
338 template <typename T>
339 static std::unique_ptr<Gpio> setupGpio(const T& gpio_number, GpioDirection direction,
340 GpioState initial_state);
341
350 bool requiresMotorReinit(uint8_t motor);
351
352 // All trinamic RPMS are electrical RPMS, they don't factor in the number of pole
353 // pairs of the drive motor.
354 //
355 // TODO (#2720): compute from robot constants (this was computed by hand and is
356 // accurate)
357 static constexpr double MECHANICAL_MPS_PER_ELECTRICAL_RPM = 0.000111;
358 static constexpr double ELECTRICAL_RPM_PER_MECHANICAL_MPS =
359 1 / MECHANICAL_MPS_PER_ELECTRICAL_RPM;
360
361 // to check if the motors have been calibrated
362 bool is_initialized_ = false;
363
364 // Select between driver and controller gpio
365 std::unique_ptr<Gpio> spi_demux_select_0_;
366 std::unique_ptr<Gpio> spi_demux_select_1_;
367
368 // Enable driver gpio
369 std::unique_ptr<Gpio> driver_control_enable_gpio_;
370 std::unique_ptr<Gpio> reset_gpio_;
371
372 // Transfer Buffers for spiTransfer
373 uint8_t tx_[5] = {0};
374 uint8_t rx_[5] = {0};
375
376 // Transfer Buffers for readThenWriteSpiTransfer
377 uint8_t write_tx_[5] = {0};
378 uint8_t read_tx_[5] = {0};
379 uint8_t read_rx_[5] = {0};
380
381 // Transfer State
382 bool transfer_started_ = false;
383 bool currently_writing_ = false;
384 bool currently_reading_ = false;
385 uint8_t position_ = 0;
386
387 // SPI File Descriptors
388 std::unordered_map<int, int> file_descriptors_;
389
390 RobotConstants_t robot_constants_;
391
392 // Drive Motors
393 EuclideanToWheel euclidean_to_four_wheel_;
394 std::unordered_map<int, bool> encoder_calibrated_;
395 std::unordered_map<int, MotorFaultIndicator> cached_motor_faults_;
396
397 // Previous wheel velocities
398 WheelSpace_t prev_wheel_velocities_;
399
400 int front_left_target_rpm = 0;
401 int front_right_target_rpm = 0;
402 int back_left_target_rpm = 0;
403 int back_right_target_rpm = 0;
404
405 // the motor cs id to check for motor faults
406 uint8_t motor_fault_detector_;
407
408 static const int NUM_CALIBRATION_ATTEMPTS = 10;
409
410 int dribbler_ramp_rpm_;
411
412 std::optional<std::chrono::time_point<std::chrono::system_clock>>
413 tracked_motor_fault_start_time_;
414 int num_tracked_motor_resets_;
415
416 static const uint8_t DRIBBLER_MOTOR_CHIP_SELECT = 4;
417
418 static const uint8_t NUM_DRIVE_MOTORS = 4;
419 static const uint8_t NUM_MOTORS = NUM_DRIVE_MOTORS + 1;
420
421 static const int MOTOR_FAULT_TIME_THRESHOLD_S = 60;
422 static const int MOTOR_FAULT_THRESHOLD_COUNT = 3;
423
424 // SPI Trinamic Motor Driver Paths (indexed with chip select above)
425 static constexpr const char* SPI_PATHS[] = {"/dev/spidev0.0", "/dev/spidev0.1",
426 "/dev/spidev0.2", "/dev/spidev0.3",
427 "/dev/spidev0.4"};
428
429 // Motor names (indexed with chip select above)
430 static constexpr const char* MOTOR_NAMES[] = {"front_left", "back_left", "back_right",
431 "front_right", "dribbler"};
432};
433
434template <typename T>
435std::unique_ptr<Gpio> MotorService::setupGpio(const T& gpio_number,
436 GpioDirection direction,
437 GpioState initial_state)
438{
439 if constexpr (PLATFORM == Platform::JETSON_NANO)
440 {
441 return std::make_unique<GpioSysfs>(gpio_number, direction, initial_state);
442 }
443 else
444 {
445 return std::make_unique<GpioCharDev>(gpio_number, direction, initial_state,
446 "/dev/gpiochip4");
447 }
448}
Definition euclidean_to_wheel.h:35
Definition motor.h:27
void runOpenLoopCalibrationRoutine(uint8_t motor, size_t num_samples)
Definition motor.cpp:1002
void resetMotorBoard()
Definition motor.cpp:1196
void writeIntToTMC4671(uint8_t motor, uint8_t address, int32_t value)
Definition motor.cpp:841
void setup()
Definition motor.cpp:130
void setUpDriveMotor(uint8_t motor)
Definition motor.cpp:208
TbotsProto::MotorStatus poll(const TbotsProto::MotorControl &motor_control, double time_elapsed_since_last_poll_s)
Definition motor.cpp:405
int readIntFromTMC4671(uint8_t motor, uint8_t address)
Definition motor.cpp:846
uint8_t tmc4671ReadWriteByte(uint8_t motor, uint8_t data, uint8_t last_transfer)
Definition motor.cpp:694
struct MotorFaultIndicator checkDriverFault(uint8_t motor)
Definition motor.cpp:217
Definition motor.h:121
MotorFaultIndicator(bool drive_enabled, std::unordered_set< TbotsProto::MotorFault > &motor_faults)
Definition motor.h:137
MotorFaultIndicator()
Definition motor.h:128
Definition robot_constants.h:7