333 lines
11 KiB
C++
333 lines
11 KiB
C++
/*
|
|
This Source Code Form is subject to the terms of the Mozilla Public
|
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include "drive.hpp"
|
|
|
|
#include <list>
|
|
|
|
#include "main.h"
|
|
#include "pros/llemu.hpp"
|
|
#include "pros/screen.hpp"
|
|
|
|
using namespace ary;
|
|
|
|
// Constructor for integrated encoders
|
|
Drive::Drive(std::vector<int> left_motor_ports, std::vector<int> right_motor_ports,
|
|
int imu_port, double wheel_diameter, double ticks, double ratio)
|
|
: imu(imu_port),
|
|
left_tracker(-1, -1, false), // Default value
|
|
right_tracker(-1, -1, false), // Default value
|
|
left_rotation(-1),
|
|
right_rotation(-1),
|
|
ez_auto([this] { this->ez_auto_task(); }) {
|
|
is_tracker = DRIVE_INTEGRATED;
|
|
|
|
// Set ports to a global vector
|
|
for (auto i : left_motor_ports) {
|
|
pros::Motor temp(abs(i), util::is_reversed(i));
|
|
left_motors.push_back(temp);
|
|
}
|
|
for (auto i : right_motor_ports) {
|
|
pros::Motor temp(abs(i), util::is_reversed(i));
|
|
right_motors.push_back(temp);
|
|
}
|
|
|
|
// Set constants for tick_per_inch calculation
|
|
WHEEL_DIAMETER = wheel_diameter;
|
|
RATIO = ratio;
|
|
CARTRIDGE = ticks;
|
|
TICK_PER_INCH = get_tick_per_inch();
|
|
|
|
set_defaults();
|
|
}
|
|
|
|
// Constructor for tracking wheels plugged into the brain
|
|
Drive::Drive(std::vector<int> left_motor_ports, std::vector<int> right_motor_ports,
|
|
int imu_port, double wheel_diameter, double ticks, double ratio,
|
|
std::vector<int> left_tracker_ports, std::vector<int> right_tracker_ports)
|
|
: imu(imu_port),
|
|
left_tracker(abs(left_tracker_ports[0]), abs(left_tracker_ports[1]), util::is_reversed(left_tracker_ports[0])),
|
|
right_tracker(abs(right_tracker_ports[0]), abs(right_tracker_ports[1]), util::is_reversed(right_tracker_ports[0])),
|
|
left_rotation(-1),
|
|
right_rotation(-1),
|
|
ez_auto([this] { this->ez_auto_task(); }) {
|
|
is_tracker = DRIVE_ADI_ENCODER;
|
|
|
|
// Set ports to a global vector
|
|
for (auto i : left_motor_ports) {
|
|
pros::Motor temp(abs(i), util::is_reversed(i));
|
|
left_motors.push_back(temp);
|
|
}
|
|
for (auto i : right_motor_ports) {
|
|
pros::Motor temp(abs(i), util::is_reversed(i));
|
|
right_motors.push_back(temp);
|
|
}
|
|
|
|
// Set constants for tick_per_inch calculation
|
|
WHEEL_DIAMETER = wheel_diameter;
|
|
RATIO = ratio;
|
|
CARTRIDGE = ticks;
|
|
TICK_PER_INCH = get_tick_per_inch();
|
|
|
|
set_defaults();
|
|
}
|
|
|
|
// Constructor for tracking wheels plugged into a 3 wire expander
|
|
Drive::Drive(std::vector<int> left_motor_ports, std::vector<int> right_motor_ports,
|
|
int imu_port, double wheel_diameter, double ticks, double ratio,
|
|
std::vector<int> left_tracker_ports, std::vector<int> right_tracker_ports, int expander_smart_port)
|
|
: imu(imu_port),
|
|
left_tracker({expander_smart_port, abs(left_tracker_ports[0]), abs(left_tracker_ports[1])}, util::is_reversed(left_tracker_ports[0])),
|
|
right_tracker({expander_smart_port, abs(right_tracker_ports[0]), abs(right_tracker_ports[1])}, util::is_reversed(right_tracker_ports[0])),
|
|
left_rotation(-1),
|
|
right_rotation(-1),
|
|
ez_auto([this] { this->ez_auto_task(); }) {
|
|
is_tracker = DRIVE_ADI_ENCODER;
|
|
|
|
// Set ports to a global vector
|
|
for (auto i : left_motor_ports) {
|
|
pros::Motor temp(abs(i), util::is_reversed(i));
|
|
left_motors.push_back(temp);
|
|
}
|
|
for (auto i : right_motor_ports) {
|
|
pros::Motor temp(abs(i), util::is_reversed(i));
|
|
right_motors.push_back(temp);
|
|
}
|
|
|
|
// Set constants for tick_per_inch calculation
|
|
WHEEL_DIAMETER = wheel_diameter;
|
|
RATIO = ratio;
|
|
CARTRIDGE = ticks;
|
|
TICK_PER_INCH = get_tick_per_inch();
|
|
|
|
set_defaults();
|
|
}
|
|
|
|
// Constructor for rotation sensors
|
|
Drive::Drive(std::vector<int> left_motor_ports, std::vector<int> right_motor_ports,
|
|
int imu_port, double wheel_diameter, double ratio,
|
|
int left_rotation_port, int right_rotation_port)
|
|
: imu(imu_port),
|
|
left_tracker(-1, -1, false), // Default value
|
|
right_tracker(-1, -1, false), // Default value
|
|
left_rotation(abs(left_rotation_port)),
|
|
right_rotation(abs(right_rotation_port)),
|
|
ez_auto([this] { this->ez_auto_task(); }) {
|
|
is_tracker = DRIVE_ROTATION;
|
|
left_rotation.set_reversed(util::is_reversed(left_rotation_port));
|
|
right_rotation.set_reversed(util::is_reversed(right_rotation_port));
|
|
|
|
// Set ports to a global vector
|
|
for (auto i : left_motor_ports) {
|
|
pros::Motor temp(abs(i), util::is_reversed(i));
|
|
left_motors.push_back(temp);
|
|
}
|
|
for (auto i : right_motor_ports) {
|
|
pros::Motor temp(abs(i), util::is_reversed(i));
|
|
right_motors.push_back(temp);
|
|
}
|
|
|
|
// Set constants for tick_per_inch calculation
|
|
WHEEL_DIAMETER = wheel_diameter;
|
|
RATIO = ratio;
|
|
CARTRIDGE = 4096;
|
|
TICK_PER_INCH = get_tick_per_inch();
|
|
|
|
set_defaults();
|
|
}
|
|
|
|
void Drive::set_defaults() {
|
|
// PID Constants
|
|
headingPID = {11, 0, 20, 0};
|
|
forward_drivePID = {0.45, 0, 5, 0};
|
|
backward_drivePID = {0.45, 0, 5, 0};
|
|
turnPID = {5, 0.003, 35, 15};
|
|
swingPID = {7, 0, 45, 0};
|
|
leftPID = {0.45, 0, 5, 0};
|
|
rightPID = {0.45, 0, 5, 0};
|
|
set_turn_min(30);
|
|
set_swing_min(30);
|
|
|
|
// Slew constants
|
|
set_slew_min_power(80, 80);
|
|
set_slew_distance(7, 7);
|
|
|
|
// Exit condition constants
|
|
set_exit_condition(turn_exit, 100, 3, 500, 7, 500, 500);
|
|
set_exit_condition(swing_exit, 100, 3, 500, 7, 500, 500);
|
|
set_exit_condition(drive_exit, 80, 50, 300, 150, 500, 500);
|
|
|
|
// Modify joystick curve on controller (defaults to disabled)
|
|
toggle_modify_curve_with_controller(true);
|
|
|
|
// Left / Right modify buttons
|
|
set_left_curve_buttons(pros::E_CONTROLLER_DIGITAL_LEFT, pros::E_CONTROLLER_DIGITAL_RIGHT);
|
|
set_right_curve_buttons(pros::E_CONTROLLER_DIGITAL_Y, pros::E_CONTROLLER_DIGITAL_A);
|
|
|
|
set_curve_buttons(pros::E_CONTROLLER_DIGITAL_LEFT, pros::E_CONTROLLER_DIGITAL_RIGHT);
|
|
|
|
// Enable auto printing and drive motors moving
|
|
toggle_auto_drive(true);
|
|
toggle_auto_print(true);
|
|
|
|
// Disables limit switch for auto selector
|
|
autonselector::limit_switch_lcd_initialize(nullptr, nullptr);
|
|
}
|
|
|
|
double Drive::get_tick_per_inch() {
|
|
CIRCUMFERENCE = WHEEL_DIAMETER * 3.141;
|
|
|
|
if (is_tracker == DRIVE_ADI_ENCODER || is_tracker == DRIVE_ROTATION)
|
|
TICK_PER_REV = CARTRIDGE * RATIO;
|
|
else
|
|
TICK_PER_REV = (50.0 * (3600.0 / CARTRIDGE)) * RATIO; // with no cart, the encoder reads 50 counts per rotation
|
|
|
|
TICK_PER_INCH = (TICK_PER_REV / CIRCUMFERENCE);
|
|
return TICK_PER_INCH;
|
|
}
|
|
|
|
void Drive::set_pid_constants(PID* pid, double p, double i, double d, double p_start_i) {
|
|
pid->set_constants(p, i, d, p_start_i);
|
|
}
|
|
|
|
void Drive::set_tank(int left, int right) {
|
|
if (pros::millis() < 1500) return;
|
|
|
|
for (auto i : left_motors) {
|
|
if (!pto_check(i)) i.move_voltage(left * (12000.0 / 127.0)); // If the motor is in the pto list, don't do anything to the motor.
|
|
}
|
|
for (auto i : right_motors) {
|
|
if (!pto_check(i)) i.move_voltage(right * (12000.0 / 127.0)); // If the motor is in the pto list, don't do anything to the motor.
|
|
}
|
|
}
|
|
|
|
void Drive::set_drive_current_limit(int mA) {
|
|
if (abs(mA) > 2500) {
|
|
mA = 2500;
|
|
}
|
|
CURRENT_MA = mA;
|
|
for (auto i : left_motors) {
|
|
if (!pto_check(i)) i.set_current_limit(abs(mA)); // If the motor is in the pto list, don't do anything to the motor.
|
|
}
|
|
for (auto i : right_motors) {
|
|
if (!pto_check(i)) i.set_current_limit(abs(mA)); // If the motor is in the pto list, don't do anything to the motor.
|
|
}
|
|
}
|
|
|
|
// Motor telemetry
|
|
void Drive::reset_drive_sensor() {
|
|
left_motors.front().tare_position();
|
|
right_motors.front().tare_position();
|
|
if (is_tracker == DRIVE_ADI_ENCODER) {
|
|
left_tracker.reset();
|
|
right_tracker.reset();
|
|
return;
|
|
} else if (is_tracker == DRIVE_ROTATION) {
|
|
left_rotation.reset_position();
|
|
right_rotation.reset_position();
|
|
return;
|
|
}
|
|
}
|
|
|
|
int Drive::right_sensor() {
|
|
if (is_tracker == DRIVE_ADI_ENCODER)
|
|
return right_tracker.get_value();
|
|
else if (is_tracker == DRIVE_ROTATION)
|
|
return right_rotation.get_position();
|
|
return right_motors.front().get_position();
|
|
}
|
|
int Drive::right_velocity() { return right_motors.front().get_actual_velocity(); }
|
|
double Drive::right_mA() { return right_motors.front().get_current_draw(); }
|
|
bool Drive::right_over_current() { return right_motors.front().is_over_current(); }
|
|
|
|
int Drive::left_sensor() {
|
|
if (is_tracker == DRIVE_ADI_ENCODER)
|
|
return left_tracker.get_value();
|
|
else if (is_tracker == DRIVE_ROTATION)
|
|
return left_rotation.get_position();
|
|
return left_motors.front().get_position();
|
|
}
|
|
int Drive::left_velocity() { return left_motors.front().get_actual_velocity(); }
|
|
double Drive::left_mA() { return left_motors.front().get_current_draw(); }
|
|
bool Drive::left_over_current() { return left_motors.front().is_over_current(); }
|
|
|
|
void Drive::reset_gyro(double new_heading) { imu.set_rotation(new_heading); }
|
|
double Drive::get_gyro() { return imu.get_rotation(); }
|
|
|
|
void Drive::imu_loading_display(int iter) {
|
|
// If the lcd is already initialized, don't run this function
|
|
if (pros::lcd::is_initialized()) return;
|
|
|
|
// Boarder
|
|
int boarder = 50;
|
|
|
|
// Create the boarder
|
|
pros::screen::set_pen(COLOR_WHITE);
|
|
for (int i = 1; i < 3; i++) {
|
|
pros::screen::draw_rect(boarder + i, boarder + i, 480 - boarder - i, 240 - boarder - i);
|
|
}
|
|
|
|
// While IMU is loading
|
|
if (iter < 2000) {
|
|
static int last_x1 = boarder;
|
|
pros::screen::set_pen(0x00FF6EC7); // EZ Pink
|
|
int x1 = (iter * ((480 - (boarder * 2)) / 2000.0)) + boarder;
|
|
pros::screen::fill_rect(last_x1, boarder, x1, 240 - boarder);
|
|
last_x1 = x1;
|
|
}
|
|
// Failsafe time
|
|
else {
|
|
static int last_x1 = boarder;
|
|
pros::screen::set_pen(COLOR_RED);
|
|
int x1 = ((iter - 2000) * ((480 - (boarder * 2)) / 1000.0)) + boarder;
|
|
pros::screen::fill_rect(last_x1, boarder, x1, 240 - boarder);
|
|
last_x1 = x1;
|
|
}
|
|
}
|
|
|
|
bool Drive::imu_calibrate(bool run_loading_animation) {
|
|
imu.reset();
|
|
int iter = 0;
|
|
while (true) {
|
|
iter += util::DELAY_TIME;
|
|
|
|
if (run_loading_animation) imu_loading_display(iter);
|
|
|
|
if (iter >= 2000) {
|
|
if (!(imu.get_status() & pros::c::E_IMU_STATUS_CALIBRATING)) {
|
|
break;
|
|
}
|
|
if (iter >= 3000) {
|
|
printf("No IMU plugged in, (took %d ms to realize that)\n", iter);
|
|
return false;
|
|
}
|
|
}
|
|
pros::delay(util::DELAY_TIME);
|
|
}
|
|
master.rumble(".");
|
|
printf("IMU is done calibrating (took %d ms)\n", iter);
|
|
return true;
|
|
}
|
|
|
|
// Brake modes
|
|
void Drive::set_drive_brake(pros::motor_brake_mode_e_t brake_type) {
|
|
CURRENT_BRAKE = brake_type;
|
|
for (auto i : left_motors) {
|
|
if (!pto_check(i)) i.set_brake_mode(brake_type); // If the motor is in the pto list, don't do anything to the motor.
|
|
}
|
|
for (auto i : right_motors) {
|
|
if (!pto_check(i)) i.set_brake_mode(brake_type); // If the motor is in the pto list, don't do anything to the motor.
|
|
}
|
|
}
|
|
|
|
void Drive::initialize() {
|
|
init_curve_sd();
|
|
imu_calibrate();
|
|
reset_drive_sensor();
|
|
}
|
|
|
|
void Drive::toggle_auto_drive(bool toggle) { drive_toggle = toggle; }
|
|
void Drive::toggle_auto_print(bool toggle) { print_toggle = toggle; } |