blob: 8161f5e7572be110588e212aadd1ac85d71aa307 [file] [log] [blame]
Brian Silverman8d3816a2017-07-03 18:52:15 -07001#ifndef MOTORS_MOTOR_H_
2#define MOTORS_MOTOR_H_
3
4#include <limits.h>
5
6#include <array>
7
8#include "motors/algorithms.h"
9#include "motors/core/kinetis.h"
10#include "motors/peripheral/adc.h"
Brian Silverman19ea60f2018-01-03 21:43:15 -080011#include "motors/peripheral/configuration.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -070012#include "motors/util.h"
Brian Silverman19ea60f2018-01-03 21:43:15 -080013#include "motors/usb/cdc.h"
14#include "motors/core/time.h"
Brian Silverman8d3816a2017-07-03 18:52:15 -070015
16namespace frc971 {
17namespace salsa {
18
19class MotorControls {
20 public:
21 MotorControls() = default;
22 virtual ~MotorControls() = default;
23
24 MotorControls(const MotorControls &) = delete;
25 void operator=(const MotorControls &) = delete;
26
Brian Silverman19ea60f2018-01-03 21:43:15 -080027 // Scales a current reading from ADC units to amps.
28 //
29 // Note that this doesn't apply any offset. The common offset will be
30 // automatically removed as part of the balancing process.
31 virtual float scale_current_reading(float reading) const = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -070032
Brian Silverman19ea60f2018-01-03 21:43:15 -080033 virtual int mechanical_counts_per_revolution() const = 0;
34 virtual int electrical_counts_per_revolution() const = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -070035
36 // raw_currents are in amps for each phase.
37 // theta is in electrical counts, which will be less than
38 // counts_per_revolution().
39 virtual ::std::array<uint32_t, 3> DoIteration(
40 const float raw_currents[3], uint32_t theta,
41 const float command_current) = 0;
42
43 virtual int16_t Debug(uint32_t theta) = 0;
44
45 virtual float estimated_velocity() const = 0;
46};
47
48// Controls a single motor.
Brian Silverman19ea60f2018-01-03 21:43:15 -080049class Motor final {
Brian Silverman8d3816a2017-07-03 18:52:15 -070050 public:
51 // pwm_ftm is used to drive the PWM outputs.
52 // encoder_ftm is used for reading the encoder.
Brian Silverman19ea60f2018-01-03 21:43:15 -080053 Motor(BigFTM *pwm_ftm, LittleFTM *encoder_ftm, MotorControls *controls,
54 const ::std::array<volatile uint32_t *, 3> &output_registers);
Brian Silverman8d3816a2017-07-03 18:52:15 -070055
56 Motor(const Motor &) = delete;
57 void operator=(const Motor &) = delete;
58
Brian Silverman19ea60f2018-01-03 21:43:15 -080059 void set_debug_tty(teensy::AcmTty *debug_tty) { debug_tty_ = debug_tty; }
60 void set_deadtime_compensation(int deadtime_compensation) {
61 deadtime_compensation_ = deadtime_compensation;
62 }
63 void set_switching_divisor(int switching_divisor) {
64 switching_divisor_ = switching_divisor;
65 }
66 void set_encoder_offset(int encoder_offset) {
67 encoder_offset_ = encoder_offset;
68 // Add mechanical_counts_per_revolution to the offset so that when we mod
69 // below, we are guaranteed to be > 0 regardless of the encoder multiplier.
70 // % isn't well-defined with negative numbers.
71 while (encoder_offset_ < controls_->mechanical_counts_per_revolution()) {
72 encoder_offset_ += controls_->mechanical_counts_per_revolution();
73 }
74 }
75 void set_encoder_multiplier(int encoder_multiplier) {
76 encoder_multiplier_ = encoder_multiplier;
77 }
78
79 int encoder() {
80 return encoder_multiplier_ * encoder_ftm_->CNT;
81 }
82 uint32_t wrapped_encoder() {
83 return (encoder() + encoder_offset_) %
84 controls_->mechanical_counts_per_revolution();
85 }
86
Brian Silverman8d3816a2017-07-03 18:52:15 -070087 // Sets up everything but doesn't actually start the timers.
88 //
89 // This assumes the global time base configuration happens outside so the
90 // timers for both motors (if applicable) are synced up.
Brian Silverman8d3816a2017-07-03 18:52:15 -070091 void Init();
92
Brian Silverman8d3816a2017-07-03 18:52:15 -070093 // Starts the timers.
Brian Silverman19ea60f2018-01-03 21:43:15 -080094 //
95 // If the global time base is in use, it must be activated after this.
Brian Silverman8d3816a2017-07-03 18:52:15 -070096 void Start();
97
Brian Silverman19ea60f2018-01-03 21:43:15 -080098 void HandleInterrupt(const BalancedReadings &readings,
99 uint32_t captured_wrapped_encoder);
100
101 void SetGoalCurrent(float goal_current) {
102 DisableInterrupts disable_interrupts;
103 goal_current_ = goal_current;
104 last_current_set_time_ = micros();
105 }
Brian Silverman8d3816a2017-07-03 18:52:15 -0700106
107 private:
108 // Represents the ADC reading which is closest to an edge.
109 struct CloseAdcReading {
110 // Adds a new reading to the readings to balance or pushes the previous
111 // closest one there and saves off this one.
112 //
113 // Returns true if it saves off the new reading.
114 bool MaybeUse(int new_distance, const MediumAdcReadings &adc_readings,
115 int phase, int sample, ReadingsToBalance *to_balance) {
116 if (new_distance < distance) {
117 if (distance != INT_MAX) {
118 to_balance->Add(index, value);
119 }
120 distance = new_distance;
121 value = adc_readings.motor_currents[phase][sample];
122 index = phase;
123 return true;
124 }
125 return false;
126 }
127
128 int distance = INT_MAX;
129 int32_t value = 0;
130 int index = 0;
131 };
132
Brian Silverman19ea60f2018-01-03 21:43:15 -0800133 inline int counts_per_cycle() const {
134 return BUS_CLOCK_FREQUENCY / SWITCHING_FREQUENCY / switching_divisor_;
135 }
136
137 uint32_t CalculateOnTime(uint32_t width) const;
138 uint32_t CalculateOffTime(uint32_t width) const;
139
Brian Silverman8d3816a2017-07-03 18:52:15 -0700140 bool flip_time_offset_ = false;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800141 int deadtime_compensation_ = 0;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700142
143 BigFTM *const pwm_ftm_;
144 LittleFTM *const encoder_ftm_;
145 MotorControls *const controls_;
Brian Silverman19ea60f2018-01-03 21:43:15 -0800146 const ::std::array<volatile uint32_t *, 3> output_registers_;
147
148 float goal_current_ = 0;
149 uint32_t last_current_set_time_ = 0;
150 int switching_divisor_ = 1;
151 int encoder_offset_ = 0;
152 int encoder_multiplier_ = 1;
153
154 teensy::AcmTty *debug_tty_ = nullptr;
Brian Silverman8d3816a2017-07-03 18:52:15 -0700155};
156
157} // namespace salsa
158} // namespace frc971
159
160#endif // MOTORS_MOTOR_H_