-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.hpp
198 lines (149 loc) · 6.07 KB
/
utils.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#ifndef FRC4941_UTILS_HPP
#define FRC4941_UTILS_HPP
#include "WPILib.h"
#include <cmath> // cos, pow, fabs
/* inline lesson in C++
* so new people remember how things work next year
* ternary operators:
* - shorthand if
* - ` condition ? when true : when false;
*
* namespaces
* - accessed using scope operator `::`
* ```
* namespace ns {
* const int num = 5;
* }
*
* std::cout <<ns::num;
* ```
*
* fxn inlining:
* - compiler optimization for short functions
* - Completely optional
*
* function pointers:
* - all functions are technically pointers
* - we used them to pass a function as an argument to a function
*
*/
/// a few useful functions for the robot
namespace utils {
/// remove 'ghost-input' resulting from inaccurate joysticks
// input < +/- 15% gets ignored
inline double removeGhost(const double val)
{ return (val > 0.05 || val < -0.05) ? val : 0.0; }
/// a linear approach to preventing brownout (untested)
// prevents input from changing faster than a certain rate
// could probably be combined with expReduceBrounout to improve effectiveness
double linReduceBrownout(const double limit, const double current, double& past)
{
/// limit = maximum amount of change per cycle
/// current = the most recent value coming from input
/// past = the value returned by this function in the last frame
// null or ghost input doesn't affect robot (also good for breaking)
if (utils::removeGhost(current) == 0.0f) return 0.0;
double change = current - past;
if (change > 0) { // increase speed
if (change > limit) // too much change
return (past += limit);
// nominal change
return (past = current);
} else { // decrease speed
if (change < -limit) // too much change
return (past -= limit);
// nominal change
return (past = current);
}
}
/// plots input on a curve to make driving different
inline double unsignedSqrt(const double val)
{ return val > 0 ? sqrt(val) : -sqrt(-val); }
/// plots input on a curve to make driving different
inline double unsignedPow2(const double val)
{ return val > 0 ? val * val : -val * val; } // change sign to match input
/// a nice function to use for drive curves
inline double huntFunt(const double val)
{ return val > 0 ? -cos(val * M_PI / 2) + 1 : -(-cos(val * M_PI / 2) + 1); }
/// averages in the previous value to make the change less drastic
// TODO: try using a cube-root/cubic/x^2 curve
inline double expReduceBrownout(const double current, double& past)
{ return unsignedPow2( past = (past + current) / 2 ); }
// this way we can use fxns other than unsignedPow2
inline double expReduceBrownout(const double current, double& past, double (*inputCurve)(double))
{ return inputCurve( past = (past + current) / 2 ); }
// recycled from last year's utils.hpp
// drives straight for a set period of time at a set speed
bool driveStraight(frc::ADXRS450_Gyro& gyro, frc::DifferentialDrive& mots, const double time, const double speed = 0.5, RobotBase* robot = nullptr){
std::cout <<"Driving straight for " <<time <<"seconds at " <<speed <<"power... ";
// did some math to guesstimate these values
const double
turningConst = -0.05, // if it doesnt work negate this
cycletime = 0.004,
offset = gyro.GetAngle(); // gyro angle before movement
bool err = false;
// drive forward for the set ammount of time
// cycletime is determined based on the speed of the robot
// slower speed = longer input cycles
// faster speed = shorter input cycles
for (int i = (int) (time / cycletime); i > 0 && robot ? robot->IsAutonomous() : false ; i--) {
// turn to correct heading
mots.ArcadeDrive(speed, (gyro.GetAngle() - offset) * turningConst); // add negatives for inverted steering/drive
// drive straight a bit before readjusting steering
Wait(cycletime);
// more than 15 degrees of error means something bad has happened
if (std::fabs(gyro.GetAngle() - offset) > 15)
err = true;
}
mots.ArcadeDrive(0.0, 0.0);
std::cout <<"done (dif="<<gyro.GetAngle() <<")\n";
// did we fail to keep straight? (5 deg tolerance)
return err || std::fabs(gyro.GetAngle()) > 5;
}
/// this will turn the robot a set number of degrees (can be negative)
// note, this isn't accurate as we aren't using calculus and a feedback loop, but should be good enough
// IsAutonomous points to RobotBase::IsAutonomous() so we can avoid infinite loops which prevent us from ending auto
bool turnDeg(frc::ADXRS450_Gyro& gyro, frc::DifferentialDrive& mots, double angleDeg, RobotBase* robot = nullptr){
const double cycleTime = 0.004, // prevent cpu taxing
tolerance = 3, // how close is "good enough" (values too low cause infinite spinning)
turnSpeed = 0.5;
gyro.Reset();
std::cout <<"turning " <<angleDeg <<" degrees... ";
// turning right
if (angleDeg > 0) {
while (gyro.GetAngle() - angleDeg < -tolerance && robot ? robot->IsAutonomous() : false) {
// turn at 50% speed until u get within 10 deg,
// then lower speed linearly as you approach
// you are not expected to understand this code
mots.ArcadeDrive(0,
std::fabs(angleDeg - (gyro.GetAngle() - offset)) > 10 ?
turnSpeed :
turnSpeed * ((gyro.GetAngle() - offset) - angleDeg) / 10
+ 0.1// * angleDeg - gyro.GetAngle() > 0 ? 1 : -1
);
// prevent CPU taxing
Wait(cycleTime);
}
// turning left
} else {
while (gyro.GetAngle() - angleDeg > tolerance && robot ? robot->IsAutonomous() : false) {
// turn at 50% speed until u get within 10 deg,
// then lower speed linearly as you approach
mots.ArcadeDrive(0,
-(std::fabs(angleDeg - (gyro.GetAngle() - offset)) > 10 ?
turnSpeed :
turnSpeed * -(angleDeg - (gyro.GetAngle() - offset)) / 10
+ 0.1// * angleDeg - gyro.GetAngle() > 0 ? 1 : -1
)
);
// prevent CPU taxing
Wait(cycleTime);
}
}
mots.ArcadeDrive(0.0, 0.0);
std::cout <<"done (dif = " <<(gyro.GetAngle() - offset) - angleDeg <<")\n";
// did we fail to turn the correct angle (5 deg tolerance)
return std::fabs((gyro.GetAngle() - offset) - angleDeg) > 5;
}
}
#endif