Skip to content
This repository has been archived by the owner on Oct 1, 2023. It is now read-only.

Commit

Permalink
Add CTRE CANivore and Phoenix Pro support (#455)
Browse files Browse the repository at this point in the history
  • Loading branch information
TytanRock authored Feb 2, 2023
1 parent e837458 commit d062110
Show file tree
Hide file tree
Showing 18 changed files with 312 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ wpi::StringMap<wpi::SmallVector<sysid::HardwareType, 2>>
{std::string{sysid::motorcontroller::kVictorSPX.name}, kGeneralEncs},
{std::string{sysid::motorcontroller::kTalonSRX.name}, kTalonEncs},
{std::string{sysid::motorcontroller::kTalonFX.name}, kBuiltInEncs},
{std::string{sysid::motorcontroller::kTalonFXPro.name}, kBuiltInEncs},
{std::string{sysid::motorcontroller::kSPARKMAXBrushless.name},
kSMaxEncs},
{std::string{sysid::motorcontroller::kSPARKMAXBrushed.name}, kSMaxEncs},
Expand All @@ -66,6 +67,7 @@ wpi::StringMap<wpi::SmallVector<std::string_view, 4>> gyroCtorMap = {
{std::string{sysid::gyro::kAnalogGyro.name}, kAnalogCtors},
{std::string{sysid::gyro::kPigeon.name}, kPigeonCtors},
{std::string{sysid::gyro::kPigeon2.name}, kAnalogCtors},
{std::string{sysid::gyro::kPigeon2Pro.name}, kAnalogCtors},
{std::string{sysid::gyro::kADXRS450.name}, kADXRS450Ctors},
{std::string{sysid::gyro::kNavX.name}, kNavXCtors},
{std::string{sysid::gyro::kADIS16448.name}, kADIS16448Ctors},
Expand Down Expand Up @@ -140,6 +142,8 @@ class GenerationTest : public ::testing::Test {
motorController == sysid::motorcontroller::kVictorSPX.name ||
motorController == sysid::motorcontroller::kTalonFX.name) {
voltageAccessor = "CTRE";
} else if (motorController == sysid::motorcontroller::kTalonFXPro.name) {
voltageAccessor = "CTRE (Pro)";
} else if (motorController == sysid::motorcontroller::kVenom.name) {
voltageAccessor = "Venom";
} else {
Expand Down Expand Up @@ -176,6 +180,8 @@ class GenerationTest : public ::testing::Test {
FindInLog(fmt::format("Pigeon, {}", pigeonPortStr));
} else if (gyro == sysid::gyro::kPigeon2.name) {
FindInLog(fmt::format("Pigeon2, {} (CAN)", gyroCtor));
} else if (gyro == sysid::gyro::kPigeon2Pro.name) {
FindInLog(fmt::format("Pigeon2, {} (CAN) (Pro)", gyroCtor));
} else if (gyro == sysid::gyro::kADXRS450.name ||
gyro == sysid::gyro::kADIS16448.name ||
gyro == sysid::gyro::kADIS16470.name) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ wpi::json ConfigManager::Generate(size_t occupied) {
// Create the JSON to return.
wpi::json json;

// Keep a CANivore name vector around that we can push our names into
std::vector<std::string> canivoreNames;

// Add motor ports.
json["primary motor ports"] =
SliceVector(m_config.primaryMotorPorts, occupied);
Expand All @@ -38,6 +41,13 @@ wpi::json ConfigManager::Generate(size_t occupied) {
}
json["motor controllers"] = motorControllers;

// Add CANivore busses
canivoreNames.clear();
for (size_t i = 0; i < occupied; i++) {
canivoreNames.push_back(std::string(m_config.canivoreNames[i].data()));
}
json["canivore names"] = canivoreNames;

// Add motor inversions.
json["primary motors inverted"] =
SliceVector(m_config.primaryMotorsInverted, occupied);
Expand All @@ -47,6 +57,8 @@ wpi::json ConfigManager::Generate(size_t occupied) {
// Add encoder ports.
json["primary encoder ports"] = m_config.primaryEncoderPorts;
json["secondary encoder ports"] = m_config.secondaryEncoderPorts;
json["encoder canivore name"] =
std::string(m_config.encoderCANivoreName.data());

// Add encoder type.
json["encoder type"] = m_config.encoderType.name;
Expand All @@ -63,6 +75,7 @@ wpi::json ConfigManager::Generate(size_t occupied) {
// Add gyro type and constructor.
json["gyro"] = m_config.gyro.name;
json["gyro ctor"] = m_config.gyroCtor;
json["gyro canivore name"] = std::string(m_config.gyroCANivoreName.data());

// Add advanced encoder settings.
json["encoding"] = m_config.encoding;
Expand All @@ -79,10 +92,12 @@ void ConfigManager::ReadJSON(std::string_view path) {
constexpr const char* json_keys[] = {"primary motor ports",
"secondary motor ports",
"motor controllers",
"canivore names",
"primary motors inverted",
"secondary motors inverted",
"primary encoder ports",
"secondary encoder ports",
"encoder canivore name",
"encoder type",
"primary encoder inverted",
"secondary encoder inverted",
Expand All @@ -91,9 +106,11 @@ void ConfigManager::ReadJSON(std::string_view path) {
"gearing denominator",
"gyro",
"gyro ctor",
"gyro canivore name",
"encoding",
"number of samples per average",
"velocity measurement period"};
"velocity measurement period",
"is drivetrain"};

// Read JSON from the specified path.
std::error_code ec;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ HardwareType sysid::motorcontroller::FromMotorControllerName(
if (name == "TalonFX") {
return sysid::motorcontroller::kTalonFX;
}
if (name == "TalonFX (Pro)") {
return sysid::motorcontroller::kTalonFXPro;
}
if (name == "SPARK MAX (Brushless)") {
return sysid::motorcontroller::kSPARKMAXBrushless;
}
Expand All @@ -45,6 +48,9 @@ HardwareType sysid::encoder::FromEncoderName(std::string_view name) {
if (name == "CANCoder") {
return sysid::encoder::kCANCoder;
}
if (name == "CANcoder (Pro)") {
return sysid::encoder::kCANcoderPro;
}
if (name == "Built-in") {
return sysid::encoder::kBuiltInSetting;
}
Expand Down
1 change: 1 addition & 0 deletions sysid-application/src/main/native/cpp/view/Analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Analyzer::Analyzer(glass::Storage& storage, wpi::Logger& logger)
m_presets["WPILib (Pre-2020)"] = presets::kWPILibOld;
m_presets["CANCoder"] = presets::kCTRECANCoder;
m_presets["CTRE"] = presets::kCTREDefault;
m_presets["CTRE (Pro)"] = presets::kCTREProDefault;
m_presets["REV Brushless Encoder Port"] = presets::kREVNEOBuiltIn;
m_presets["REV Brushed Encoder Port"] = presets::kREVNonNEO;
m_presets["REV Data Port"] = presets::kREVNonNEO;
Expand Down
74 changes: 54 additions & 20 deletions sysid-application/src/main/native/cpp/view/Generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ void Generator::RoboRIOEncoderSetup(bool drive) {
"CTRE Magnetic Encoder and REV Throughbore Encoder");
}

void Generator::CANCoderSetup(bool drive) {
void Generator::CANCoderSetup(bool drive, bool usePro) {
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 2);
ImGui::InputInt(drive ? "L CANCoder Port" : "CANCoder Port",
&m_settings.primaryEncoderPorts[0], 0, 0);
Expand All @@ -142,6 +142,13 @@ void Generator::CANCoderSetup(bool drive) {
ImGui::Checkbox("Right Encoder Inverted",
&m_settings.secondaryEncoderInverted);
}

ImGui::SetNextItemWidth(80);
ImGui::InputText("CANcoder CANivore Name",
m_settings.encoderCANivoreName.data(),
m_settings.encoderCANivoreName.size());

m_settings.cancoderUsingPro = usePro;
}

void Generator::RegularEncoderSetup(bool drive) {
Expand All @@ -167,8 +174,10 @@ void Generator::UpdateFromConfig() {

// Setting right Idxs for the GUI
if (mainMotorController == sysid::motorcontroller::kTalonSRX ||
mainMotorController == sysid::motorcontroller::kTalonFX) {
if (mainMotorController == sysid::motorcontroller::kTalonFX) {
mainMotorController == sysid::motorcontroller::kTalonFX ||
mainMotorController == sysid::motorcontroller::kTalonFXPro) {
if (mainMotorController == sysid::motorcontroller::kTalonFX ||
mainMotorController == sysid::motorcontroller::kTalonFXPro) {
m_encoderIdx = GetNewIdx(ArrayConcat(kBuiltInEncoders, kGeneralEncoders),
encoderTypeName);
} else {
Expand Down Expand Up @@ -292,6 +301,7 @@ void Generator::Display() {
auto& mc = m_settings.motorControllers;
auto& pi = m_settings.primaryMotorsInverted;
auto& si = m_settings.secondaryMotorsInverted;
auto& cn = m_settings.canivoreNames;

// Ensure that our vector contains i+1 elements.
if (pm.size() == i) {
Expand All @@ -300,6 +310,7 @@ void Generator::Display() {
mc.emplace_back(motorControllerNames[0]);
pi.emplace_back(false);
si.emplace_back(false);
cn.emplace_back(std::array<char, 32>{'r', 'i', 'o', '\0'});
}

// Make sure elements have unique IDs.
Expand Down Expand Up @@ -362,6 +373,15 @@ void Generator::Display() {
ImGui::Checkbox("R Inverted", &si[i]);
}

// Add CANivore name if we are using a CTRE motor controller
if (m_settings.motorControllers[i] == sysid::motorcontroller::kTalonFX ||
m_settings.motorControllers[i] == sysid::motorcontroller::kTalonFXPro) {
ImGui::SetNextItemWidth(80);
ImGui::InputText("Motor CANivore Name",
m_settings.canivoreNames[i].data(),
m_settings.canivoreNames[i].size());
}

ImGui::PopID();

// If we selected Spark Max with Brushed mode, set our flag to true.
Expand All @@ -383,22 +403,24 @@ void Generator::Display() {
// Add encoder selection.
ImGui::SetNextItemWidth(ImGui::GetFontSize() * kTextBoxWidthMultiple);
if (mainMotorController == sysid::motorcontroller::kTalonSRX ||
mainMotorController == sysid::motorcontroller::kTalonFX) {
if (mainMotorController == sysid::motorcontroller::kTalonFX) {
mainMotorController == sysid::motorcontroller::kTalonFX ||
mainMotorController == sysid::motorcontroller::kTalonFXPro) {
if (mainMotorController == sysid::motorcontroller::kTalonFX ||
mainMotorController == sysid::motorcontroller::kTalonFXPro) {
GetEncoder(ArrayConcat(kBuiltInEncoders, kGeneralEncoders));
if (m_encoderIdx < 1) {
RegularEncoderSetup(drive);
} else if (m_encoderIdx == 1) {
CANCoderSetup(drive);
} else if (m_encoderIdx == 1 || m_encoderIdx == 2) {
CANCoderSetup(drive, m_encoderIdx == 2);
} else {
RoboRIOEncoderSetup(drive);
}
} else {
GetEncoder(ArrayConcat(kTalonSRXEncoders, kGeneralEncoders));
if (m_encoderIdx <= 1) {
RegularEncoderSetup(drive);
} else if (m_encoderIdx == 2) {
CANCoderSetup(drive);
} else if (m_encoderIdx == 2 || m_encoderIdx == 3) {
CANCoderSetup(drive, m_encoderIdx == 3);
} else {
RoboRIOEncoderSetup(drive);
}
Expand All @@ -414,24 +436,24 @@ void Generator::Display() {
// You're not allowed to invert the NEO Built-in encoder
RegularEncoderSetup(drive);
}
} else if (m_encoderIdx == 2) {
CANCoderSetup(drive);
} else if (m_encoderIdx == 2 || m_encoderIdx == 3) {
CANCoderSetup(drive, m_encoderIdx == 3);
} else {
RoboRIOEncoderSetup(drive);
}
} else if (mainMotorController == sysid::motorcontroller::kVenom) {
GetEncoder(ArrayConcat(kBuiltInEncoders, kGeneralEncoders));
if (m_encoderIdx == 0) {
RegularEncoderSetup(drive);
} else if (m_encoderIdx == 1) {
CANCoderSetup(drive);
} else if (m_encoderIdx == 1 || m_encoderIdx == 2) {
CANCoderSetup(drive, m_encoderIdx == 2);
} else {
RoboRIOEncoderSetup(drive);
}
} else {
GetEncoder(kGeneralEncoders);
if (m_encoderIdx == 0) {
CANCoderSetup(drive);
if (m_encoderIdx == 0 || m_encoderIdx == 1) {
CANCoderSetup(drive, m_encoderIdx == 1);
} else {
RoboRIOEncoderSetup(drive);
}
Expand All @@ -441,7 +463,10 @@ void Generator::Display() {
if (!((mainMotorController == sysid::motorcontroller::kVenom &&
m_settings.encoderType == sysid::encoder::kBuiltInSetting) ||
(mainMotorController == sysid::motorcontroller::kSPARKMAXBrushless &&
m_settings.encoderType == sysid::encoder::kSMaxEncoderPort))) {
m_settings.encoderType == sysid::encoder::kSMaxEncoderPort) ||
(mainMotorController == sysid::motorcontroller::kTalonFXPro &&
m_settings.encoderType == sysid::encoder::kBuiltInSetting) ||
m_settings.encoderType == sysid::encoder::kCANcoderPro)) {
// Samples Per Average Setting
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 2);
ImGui::InputInt("Samples Per Average", &m_settings.numSamples, 0, 0);
Expand All @@ -451,7 +476,8 @@ void Generator::Display() {
"CPRs.");

// Add Velocity Measurement Period
if (m_settings.encoderType != sysid::encoder::kRoboRIO) {
if (m_settings.encoderType != sysid::encoder::kRoboRIO &&
m_settings.encoderType != sysid::encoder::kCANcoderPro) {
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 4);
ImGui::Combo("Time Measurement Window", &m_periodIdx, kCTREPeriods,
IM_ARRAYSIZE(kCTREPeriods));
Expand Down Expand Up @@ -489,9 +515,16 @@ void Generator::Display() {
if (m_isTalon) {
m_settings.gyroCtor = "WPI_TalonSRX-" + m_settings.gyroCtor;
}
} else if (gyroType == sysid::gyro::kPigeon2) {
} else if (gyroType == sysid::gyro::kPigeon2 ||
gyroType == sysid::gyro::kPigeon2Pro) {
ImGui::InputInt("CAN ID", &m_gyroPort, 0, 0);
m_settings.gyroCtor = std::to_string(m_gyroPort);

ImGui::SetNextItemWidth(80);
ImGui::InputText("Gyro CANivore Name", m_settings.gyroCANivoreName.data(),
m_settings.gyroCANivoreName.size());
m_settings.gyroCtor = std::to_string(m_gyroPort) + ", " +
std::string{m_settings.gyroCANivoreName.begin(),
m_settings.gyroCANivoreName.end()};
} else if (gyroType == sysid::gyro::kADXRS450) {
ImGui::Combo("SPI Port", &m_gyroParam, kADXRS450Ctors,
IM_ARRAYSIZE(kADXRS450Ctors));
Expand Down Expand Up @@ -536,7 +569,8 @@ void Generator::Display() {
sysid::CreateTooltip(
"This is the number of encoder counts per revolution for your encoder.\n"
"Common values for this are here:\nCTRE Magnetic Encoder: 4096\nFalcon "
"500 Integrated: 2048\nREV Throughbore: 8192\nNEO (and NEO 550) "
"500 Integrated: 2048\nFalcon 500 running Phoenix Pro (Pro already "
"handles this value): 1\nREV Throughbore: 8192\nNEO (and NEO 550) "
"Integrated "
"Encoders (REV already handles this value): 1");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ constexpr FeedbackControllerPreset kCTRECANCoder{1.0 / 12.0, 60.0, 1_ms, true,
81.5_ms};
constexpr FeedbackControllerPreset kCTREDefault{1023.0 / 12.0, 0.1, 1_ms, false,
81.5_ms};
/**
* https://api.ctr-electronics.com/phoenixpro/release/cpp/classctre_1_1phoenixpro_1_1hardware_1_1core_1_1_core_c_a_ncoder.html#a718a1a214b58d3c4543e88e3cb51ade5
*
* Phoenix Pro uses standard units and Voltage output. This means the output
* is 1.0, time factor is 1.0, and closed loop operates at 1 millisecond. All
* Pro devices make use of Kalman filters default-tuned to lowest latency, which
* in testing is roughly 1 millisecond
*/
constexpr FeedbackControllerPreset kCTREProDefault{1.0, 1.0, 1_ms, true, 1_ms};

/**
* https://github.com/wpilibsuite/sysid/issues/258#issuecomment-1010658237
Expand Down
Loading

0 comments on commit d062110

Please sign in to comment.