blob: a16dfc4c15b098df38334c72d99be54c82a5136f [file] [log] [blame]
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "aos/atom_code/output/motor_output.h"
#include "aos/common/logging/logging.h"
#include "aos/atom_code/init.h"
#include "frc971/queues/Piston.q.h"
#include "bot3/control_loops/drivetrain/drivetrain.q.h"
#include "bot3/control_loops/shooter/shooter_motor.q.h"
using ::bot3::control_loops::drivetrain;
using ::bot3::control_loops::shooter;
using ::frc971::control_loops::shifters;
namespace bot3 {
namespace output {
class MotorWriter : public ::aos::MotorOutput {
// Maximum age of an output packet before the motors get zeroed instead.
static const int kOutputMaxAgeMS = 20;
static const int kEnableDrivetrain = true;
virtual void RunIteration() {
values_.digital_module = 0;
values_.pressure_switch_channel = 1;
values_.compressor_channel = 1; //spike
values_.solenoid_module = 0;
drivetrain.output.FetchLatest();
if (drivetrain.output.IsNewerThanMS(kOutputMaxAgeMS) && kEnableDrivetrain) {
SetPWMOutput(4, drivetrain.output->right_voltage / 12.0, kTalonBounds);
SetPWMOutput(3, -drivetrain.output->left_voltage / 12.0, kTalonBounds);
} else {
DisablePWMOutput(3);
DisablePWMOutput(4);
if (kEnableDrivetrain) {
LOG(WARNING, "drivetrain not new enough\n");
}
}
shifters.FetchLatest();
if (shifters.get()) {
SetSolenoid(7, shifters->set);
SetSolenoid(8, !shifters->set);
}
shooter.output.FetchLatest();
if (shooter.output.IsNewerThanMS(kOutputMaxAgeMS)) {
SetPWMOutput(1, LinearizeVictor(shooter.output->voltage / 12.0), kVictorBounds);
SetPWMOutput(7, shooter.output->intake, kVictorBounds);
SetSolenoid(4, shooter.output->push);
LOG(DEBUG, "shooter: %lf, intake: %lf, push: %d", shooter.output->voltage, shooter.output->intake, shooter.output->push);
} else {
DisablePWMOutput(2);
DisablePWMOutput(1);
LOG(WARNING, "shooter not new enough\n");
}
// TODO(danielp): Add stuff for intake and shooter.
}
// This linearizes the value from the victor.
// Copied form the 2012 code.
double LinearizeVictor(double goal_speed) {
// These values were derived by putting the robot up on blocks, and driving it
// at various speeds. The power required to drive at these speeds was then
// recorded and fit with gnuplot.
const double deadband_value = 0.082;
// If we are outside the range such that the motor is actually moving,
// subtract off the constant offset from the deadband. This makes the
// function odd and intersect the origin, making the fitting easier to do.
if (goal_speed > deadband_value) {
goal_speed -= deadband_value;
} else if (goal_speed < -deadband_value) {
goal_speed += deadband_value;
} else {
goal_speed = 0.0;
}
goal_speed = goal_speed / (1.0 - deadband_value);
double goal_speed2 = goal_speed * goal_speed;
double goal_speed3 = goal_speed2 * goal_speed;
double goal_speed4 = goal_speed3 * goal_speed;
double goal_speed5 = goal_speed4 * goal_speed;
double goal_speed6 = goal_speed5 * goal_speed;
double goal_speed7 = goal_speed6 * goal_speed;
// Constants for the 5th order polynomial
double victor_fit_e1 = 0.437239;
double victor_fit_c1 = -1.56847;
double victor_fit_a1 = (- (125.0 * victor_fit_e1 + 125.0
* victor_fit_c1 - 116.0) / 125.0);
double answer_5th_order = (victor_fit_a1 * goal_speed5
+ victor_fit_c1 * goal_speed3
+ victor_fit_e1 * goal_speed);
// Constants for the 7th order polynomial
double victor_fit_c2 = -5.46889;
double victor_fit_e2 = 2.24214;
double victor_fit_g2 = -0.042375;
double victor_fit_a2 = (- (125.0 * (victor_fit_c2 + victor_fit_e2
+ victor_fit_g2) - 116.0) / 125.0);
double answer_7th_order = (victor_fit_a2 * goal_speed7
+ victor_fit_c2 * goal_speed5
+ victor_fit_e2 * goal_speed3
+ victor_fit_g2 * goal_speed);
// Average the 5th and 7th order polynomials, and add a bit of linear power in
// as well. The average turns out to nicely fit the data in gnuplot with nice
// smooth curves, and the linear power gives it a bit more punch at low speeds
// again. Stupid victors.
double answer = 0.85 * 0.5 * (answer_7th_order + answer_5th_order)
+ .15 * goal_speed * (1.0 - deadband_value);
// Add the deadband power back in to make it so that the motor starts moving
// when any power is applied. This is what the fitting assumes.
if (answer > 0.001) {
answer += deadband_value;
} else if (answer < -0.001) {
answer -= deadband_value;
}
return answer;
}
};
} // namespace output
} // namespace bot3
int main() {
::aos::Init();
::bot3::output::MotorWriter writer;
writer.Run();
::aos::Cleanup();
}