blob: f5b731f3b0f6d6b025f6b3060301aac2fac300cc [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"
11#include "motors/util.h"
12
13namespace frc971 {
14namespace salsa {
15
16class MotorControls {
17 public:
18 MotorControls() = default;
19 virtual ~MotorControls() = default;
20
21 MotorControls(const MotorControls &) = delete;
22 void operator=(const MotorControls &) = delete;
23
24 static constexpr float scale_current_reading(float reading) {
25 return reading *
26 static_cast<float>(1.0 / 4096.0 /* Full-scale ADC reading */ *
27 3.3 /* ADC reference voltage */ /
28 (1.47 / (0.768 + 1.47)) /* 5V -> 3.3V divider */ /
29 50.0 /* Current sense amplification */ /
30 0.0003 /* Sense resistor */);
31 }
32
33 static constexpr int counts_per_revolution() { return 2048 / 2; }
34
35 // raw_currents are in amps for each phase.
36 // theta is in electrical counts, which will be less than
37 // counts_per_revolution().
38 virtual ::std::array<uint32_t, 3> DoIteration(
39 const float raw_currents[3], uint32_t theta,
40 const float command_current) = 0;
41
42 virtual int16_t Debug(uint32_t theta) = 0;
43
44 virtual float estimated_velocity() const = 0;
45};
46
47// Controls a single motor.
48class Motor {
49 public:
50 // pwm_ftm is used to drive the PWM outputs.
51 // encoder_ftm is used for reading the encoder.
52 Motor(BigFTM *pwm_ftm, LittleFTM *encoder_ftm, MotorControls *controls);
53
54 Motor(const Motor &) = delete;
55 void operator=(const Motor &) = delete;
56
57 // Sets up everything but doesn't actually start the timers.
58 //
59 // This assumes the global time base configuration happens outside so the
60 // timers for both motors (if applicable) are synced up.
61 // TODO(Brian): "40.4.28.1 Enabling the global time base (GTB)" says something
62 // about needing to do stuff in a specific order, so this API might need
63 // revising.
64 void Init();
65
66 // Zeros the encoder. This involves blocking for an arbitrary length of time
67 // with interrupts disabled.
68 void Zero();
69
70 // Starts the timers.
71 void Start();
72
73 void HandleInterrupt();
74
75 private:
76 // Represents the ADC reading which is closest to an edge.
77 struct CloseAdcReading {
78 // Adds a new reading to the readings to balance or pushes the previous
79 // closest one there and saves off this one.
80 //
81 // Returns true if it saves off the new reading.
82 bool MaybeUse(int new_distance, const MediumAdcReadings &adc_readings,
83 int phase, int sample, ReadingsToBalance *to_balance) {
84 if (new_distance < distance) {
85 if (distance != INT_MAX) {
86 to_balance->Add(index, value);
87 }
88 distance = new_distance;
89 value = adc_readings.motor_currents[phase][sample];
90 index = phase;
91 return true;
92 }
93 return false;
94 }
95
96 int distance = INT_MAX;
97 int32_t value = 0;
98 int index = 0;
99 };
100
101 bool flip_time_offset_ = false;
102
103 BigFTM *const pwm_ftm_;
104 LittleFTM *const encoder_ftm_;
105 MotorControls *const controls_;
106};
107
108} // namespace salsa
109} // namespace frc971
110
111#endif // MOTORS_MOTOR_H_