2014-11-17 16:02:41 -05:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
/* Copyright (c) FIRST 2014. All Rights Reserved. */
|
|
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
|
|
|
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
#include "CANTalon.h"
|
|
|
|
|
#include "WPIErrors.h"
|
2015-06-25 15:07:55 -04:00
|
|
|
#include <unistd.h> // usleep
|
artf4154: Get rid of raw pointers in C++.
This deals with the majority of the user-facing code
in wpilibC++Devices and a substantial portion of it in
wpilibC++. wpilibC++Sim and wpilibC++IntegrationTests
are untouched except where it is necessary to make them
work with the rest of the libraries.
There is still a lot to do in the following areas:
-The HAL (which we may not want to touch at all).
-The I2C, Serial, and SPI interfaces in wpilibC++Devices,
which I haven't gotten around to doing yet.
-Most wpilibC++Devices classes have void* pointers
for interacting with the HAL.
-InterruptableSensorBase passes a void *params for
the interrupt handler.
-I haven't converted all the const char* to std::strings.
-There are plenty of other cases of raw pointers still
existing.
-This doesn't fall directly under raw pointer stuff,
but move syntax and rvalue references could be introduced
in many places.
-I haven't touched vision code.
-The Resource classes conflict (one is in the hal, the other
in wpilibC++). Someone should figure out a more
permanent fix (eg, just renaming them), then doing
what I did (making a new namespace for one of them,
essentially the same as renaming it).
A few other things:
-I created a NullDeleter class which is marked as deprecated.
What this does is it can be passed as the deleter to a
std::shared_ptr so that when you are converting raw pointers
to shared_ptrs the shared_ptr doesn't do any deletion if
someone else owns the raw pointer. This should only be
used in making old raw pointer UIs.
-I had to alter the build.gradle so that it did not
emit errors when deprecated functions called deprecated
functions. Unfortunately, gradle doesn't appear to be
actually printing out gcc warnigns for some reason.
The best way I have found to fix this is to patch
the toolchains (https://bitbucket.org/byteit101/toolchain-builder/pull-request/5/make-gcc-not-throw-warnings-for-nested/diff)
so that a deprecated function calling a deprecated
function is fine but a non-deprecated function calling
a deprecated function will throw a warning (which we
then elevate with -Werror). I believe that clang
deals with this properly, although I have not
tried it myself.
Change-Id: Ib8090c66893576fe73654f4e9d268f9d37be06a2
2015-06-30 15:01:20 -04:00
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor for the CANTalon device.
|
|
|
|
|
* @param deviceNumber The CAN ID of the Talon SRX
|
|
|
|
|
*/
|
2014-11-17 16:02:41 -05:00
|
|
|
CANTalon::CANTalon(int deviceNumber)
|
2015-06-25 15:07:55 -04:00
|
|
|
: m_deviceNumber(deviceNumber),
|
|
|
|
|
m_impl(new CanTalonSRX(deviceNumber)),
|
2015-06-24 01:06:29 -07:00
|
|
|
m_safetyHelper(new MotorSafetyHelper(this)) {
|
2014-12-16 21:37:20 -05:00
|
|
|
ApplyControlMode(m_controlMode);
|
2014-12-01 14:05:26 -05:00
|
|
|
m_impl->SetProfileSlotSelect(m_profile);
|
2015-06-25 15:07:55 -04:00
|
|
|
m_isInverted = false;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-14 17:09:52 -05:00
|
|
|
/**
|
|
|
|
|
* Constructor for the CANTalon device.
|
|
|
|
|
* @param deviceNumber The CAN ID of the Talon SRX
|
|
|
|
|
* @param controlPeriodMs The period in ms to send the CAN control frame.
|
2015-06-25 15:07:55 -04:00
|
|
|
* Period is bounded to [1ms,
|
|
|
|
|
* 95ms].
|
|
|
|
|
*/
|
|
|
|
|
CANTalon::CANTalon(int deviceNumber, int controlPeriodMs)
|
|
|
|
|
: m_deviceNumber(deviceNumber),
|
|
|
|
|
m_impl(new CanTalonSRX(
|
|
|
|
|
deviceNumber,
|
|
|
|
|
controlPeriodMs)) /* bounded underneath to be within [1 ms,95 ms] */
|
|
|
|
|
,
|
|
|
|
|
m_safetyHelper(new MotorSafetyHelper(this)),
|
|
|
|
|
m_profile(0),
|
|
|
|
|
m_controlEnabled(true),
|
|
|
|
|
m_controlMode(kPercentVbus),
|
|
|
|
|
m_setPoint(0) {
|
2014-12-16 21:37:20 -05:00
|
|
|
ApplyControlMode(m_controlMode);
|
2014-12-14 17:09:52 -05:00
|
|
|
m_impl->SetProfileSlotSelect(m_profile);
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
|
2015-07-24 09:11:15 -04:00
|
|
|
CANTalon::~CANTalon() {
|
2015-08-13 23:17:19 -07:00
|
|
|
if (m_table != nullptr) m_table->RemoveTableListener(this);
|
2015-07-24 09:11:15 -04:00
|
|
|
if (m_hasBeenMoved) return;
|
|
|
|
|
Disable();
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
|
|
|
|
* Write out the PID value as seen in the PIDOutput base object.
|
|
|
|
|
*
|
|
|
|
|
* @deprecated Call Set instead.
|
|
|
|
|
*
|
2015-06-25 15:07:55 -04:00
|
|
|
* @param output Write out the PercentVbus value as was computed by the
|
|
|
|
|
* PIDController
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::PIDWrite(float output) {
|
|
|
|
|
if (GetControlMode() == kPercentVbus) {
|
|
|
|
|
Set(output);
|
|
|
|
|
} else {
|
|
|
|
|
wpi_setWPIErrorWithContext(IncompatibleMode,
|
|
|
|
|
"PID only supported in PercentVbus mode");
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-15 13:48:53 -04:00
|
|
|
/**
|
|
|
|
|
* Retrieve the current sensor value. Equivalent to Get().
|
|
|
|
|
*
|
|
|
|
|
* @return The current sensor value of the Talon.
|
|
|
|
|
*/
|
Revert changes preventing old user code from compiling.
I'm not 100% sure whether we want these, but they are a quick
find and replace to do.
Basically, there are two primary things that we have done
this summer that break existing user code:
-Changing GetInstance() calls to return references instead
of pointers. This forces users to change from doing something
like LiveWindow::GetInstance()->AddSensor() to LiveWindow::GetInstance().AddSensor().
-Making PIDGet() and related calls const, forcing users to change
the function signatures wherever they override them.
The GetInstance() calls don't really matter to me either way,
especially since there are no real ownership issues going on there,
unlike the rest of the smart pointer-related changes.
For the const stuff, it is certainly more correct to mandate that
user PIDGet() functions be const and the such, but at the same time,
I'm not sure that there is any strong need for it, and the errors
generated are not the most helpful. While this wouldn't necessarily
be an issue for more experienced teams or completely new teams (who
don't have any old code to be reusing), it may cause issues for more
average teams who aren't familiar with the intricacies of C++ anything.
Change-Id: I6e7007982069292ea70e6d0fc8ca40203340df1b
2015-07-24 19:19:40 -04:00
|
|
|
double CANTalon::PIDGet() { return Get(); }
|
2015-06-15 13:48:53 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Gets the current status of the Talon (usually a sensor value).
|
|
|
|
|
*
|
|
|
|
|
* In Current mode: returns output current.
|
|
|
|
|
* In Speed mode: returns current speed.
|
|
|
|
|
* In Position mode: returns current sensor position.
|
|
|
|
|
* In PercentVbus and Follower modes: returns current applied throttle.
|
|
|
|
|
*
|
|
|
|
|
* @return The current sensor value of the Talon.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
float CANTalon::Get() const {
|
2014-11-26 15:15:52 -05:00
|
|
|
int value;
|
2015-06-25 15:07:55 -04:00
|
|
|
switch (m_controlMode) {
|
2014-11-26 15:15:52 -05:00
|
|
|
case kVoltage:
|
|
|
|
|
return GetOutputVoltage();
|
|
|
|
|
case kCurrent:
|
|
|
|
|
return GetOutputCurrent();
|
|
|
|
|
case kSpeed:
|
|
|
|
|
m_impl->GetSensorVelocity(value);
|
|
|
|
|
return value;
|
|
|
|
|
case kPosition:
|
|
|
|
|
m_impl->GetSensorPosition(value);
|
|
|
|
|
return value;
|
2014-12-01 14:05:26 -05:00
|
|
|
case kPercentVbus:
|
2015-01-24 18:02:06 -05:00
|
|
|
case kFollower:
|
2014-11-26 15:15:52 -05:00
|
|
|
default:
|
2014-12-01 14:05:26 -05:00
|
|
|
m_impl->GetAppliedThrottle(value);
|
|
|
|
|
return (float)value / 1023.0;
|
2014-11-26 15:15:52 -05:00
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-01 14:05:26 -05:00
|
|
|
* Sets the appropriate output on the talon, depending on the mode.
|
|
|
|
|
*
|
|
|
|
|
* In PercentVbus, the output is between -1.0 and 1.0, with 0.0 as stopped.
|
2014-12-31 19:18:52 -08:00
|
|
|
* In Voltage mode, output value is in volts.
|
|
|
|
|
* In Current mode, output value is in amperes.
|
|
|
|
|
* In Speed mode, output value is in position change / 10ms.
|
|
|
|
|
* In Position mode, output value is in encoder ticks or an analog value,
|
2014-12-01 14:05:26 -05:00
|
|
|
* depending on the sensor.
|
2015-06-25 15:07:55 -04:00
|
|
|
* In Follower mode, the output value is the integer device ID of the talon to
|
|
|
|
|
* duplicate.
|
2014-12-01 14:05:26 -05:00
|
|
|
*
|
|
|
|
|
* @param outputValue The setpoint value, as described above.
|
2014-12-05 05:08:10 -05:00
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::Set(float value, uint8_t syncGroup) {
|
2014-12-21 16:47:03 -05:00
|
|
|
/* feed safety helper since caller just updated our output */
|
|
|
|
|
m_safetyHelper->Feed();
|
2015-06-25 15:07:55 -04:00
|
|
|
if (m_controlEnabled) {
|
2014-12-08 15:22:15 -05:00
|
|
|
m_setPoint = value;
|
2015-01-10 22:07:27 -08:00
|
|
|
CTR_Code status = CTR_OKAY;
|
2015-06-25 15:07:55 -04:00
|
|
|
switch (m_controlMode) {
|
|
|
|
|
case CANSpeedController::kPercentVbus: {
|
|
|
|
|
m_impl->Set(m_isInverted ? -value : value);
|
|
|
|
|
status = CTR_OKAY;
|
|
|
|
|
} break;
|
|
|
|
|
case CANSpeedController::kFollower: {
|
|
|
|
|
status = m_impl->SetDemand((int)value);
|
|
|
|
|
} break;
|
|
|
|
|
case CANSpeedController::kVoltage: {
|
|
|
|
|
// Voltage is an 8.8 fixed point number.
|
|
|
|
|
int volts = int((m_isInverted ? value : -value) * 256);
|
|
|
|
|
status = m_impl->SetDemand(volts);
|
|
|
|
|
} break;
|
2014-11-27 02:22:01 -05:00
|
|
|
case CANSpeedController::kSpeed:
|
2015-03-24 15:01:17 -04:00
|
|
|
status = m_impl->SetDemand(m_isInverted ? -value : value);
|
2014-11-27 02:22:01 -05:00
|
|
|
break;
|
|
|
|
|
case CANSpeedController::kPosition:
|
|
|
|
|
status = m_impl->SetDemand(value);
|
|
|
|
|
break;
|
2015-01-24 18:02:06 -05:00
|
|
|
case CANSpeedController::kCurrent:
|
2014-11-17 16:02:41 -05:00
|
|
|
default:
|
2015-01-24 18:02:06 -05:00
|
|
|
wpi_setWPIErrorWithContext(
|
|
|
|
|
IncompatibleMode,
|
|
|
|
|
"The CAN Talon does not support Current Mode at this time.");
|
2014-11-17 16:02:41 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-06 16:06:15 -05:00
|
|
|
|
|
|
|
|
status = m_impl->SetModeSelect(m_sendMode);
|
|
|
|
|
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2015-06-15 13:48:53 -04:00
|
|
|
* Sets the setpoint to value. Equivalent to Set().
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetSetpoint(float value) { Set(value); }
|
2015-06-15 13:48:53 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resets the integral term and disables the controller.
|
|
|
|
|
*/
|
|
|
|
|
void CANTalon::Reset() {
|
|
|
|
|
ClearIaccum();
|
|
|
|
|
Disable();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Disables control of the talon, causing the motor to brake or coast
|
|
|
|
|
* depending on its mode (see the Talon SRX Software Reference manual
|
|
|
|
|
* for more information).
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::Disable() {
|
2014-12-01 14:05:26 -05:00
|
|
|
m_impl->SetModeSelect((int)CANTalon::kDisabled);
|
2014-11-17 16:02:41 -05:00
|
|
|
m_controlEnabled = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2015-06-15 13:48:53 -04:00
|
|
|
* Enables control of the Talon, allowing the motor to move.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
|
|
|
|
void CANTalon::EnableControl() {
|
|
|
|
|
SetControlMode(m_controlMode);
|
|
|
|
|
m_controlEnabled = true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-15 13:48:53 -04:00
|
|
|
/**
|
|
|
|
|
* Enables control of the Talon, allowing the motor to move.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::Enable() { EnableControl(); }
|
2015-06-15 13:48:53 -04:00
|
|
|
|
2014-12-08 15:22:15 -05:00
|
|
|
/**
|
|
|
|
|
* @return Whether the Talon is currently enabled.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool CANTalon::IsControlEnabled() const { return m_controlEnabled; }
|
2014-12-08 15:22:15 -05:00
|
|
|
|
2015-06-15 13:48:53 -04:00
|
|
|
/**
|
|
|
|
|
* @return Whether the Talon is currently enabled.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool CANTalon::IsEnabled() const { return IsControlEnabled(); }
|
2015-06-15 13:48:53 -04:00
|
|
|
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
2014-12-01 14:05:26 -05:00
|
|
|
* @param p Proportional constant to use in PID loop.
|
2014-12-05 05:08:10 -05:00
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetP(double p) {
|
2014-11-26 15:15:52 -05:00
|
|
|
CTR_Code status = m_impl->SetPgain(m_profile, p);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the integration constant of the currently selected profile.
|
|
|
|
|
*
|
|
|
|
|
* @param i Integration constant for the currently selected PID profile.
|
|
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
|
|
|
|
*/
|
|
|
|
|
void CANTalon::SetI(double i) {
|
2014-11-26 15:15:52 -05:00
|
|
|
CTR_Code status = m_impl->SetIgain(m_profile, i);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* Set the derivative constant of the currently selected profile.
|
|
|
|
|
*
|
|
|
|
|
* @param d Derivative constant for the currently selected PID profile.
|
2014-12-05 05:08:10 -05:00
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetD(double d) {
|
2014-11-26 15:15:52 -05:00
|
|
|
CTR_Code status = m_impl->SetDgain(m_profile, d);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* Set the feedforward value of the currently selected profile.
|
2014-12-05 05:08:10 -05:00
|
|
|
*
|
2014-12-31 19:18:52 -08:00
|
|
|
* @param f Feedforward constant for the currently selected PID profile.
|
2014-12-05 05:08:10 -05:00
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetF(double f) {
|
2014-12-05 05:08:10 -05:00
|
|
|
CTR_Code status = m_impl->SetFgain(m_profile, f);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
2014-12-17 18:35:00 -05:00
|
|
|
/**
|
|
|
|
|
* Set the Izone to a nonzero value to auto clear the integral accumulator
|
2015-06-25 15:07:55 -04:00
|
|
|
* when the absolute value of CloseLoopError exceeds Izone.
|
2014-12-17 18:35:00 -05:00
|
|
|
*
|
|
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetIzone(unsigned iz) {
|
2014-12-17 18:35:00 -05:00
|
|
|
CTR_Code status = m_impl->SetIzone(m_profile, iz);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-17 18:35:00 -05:00
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
/**
|
|
|
|
|
* SRX has two available slots for PID.
|
|
|
|
|
* @param slotIdx one or zero depending on which slot caller wants.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SelectProfileSlot(int slotIdx) {
|
|
|
|
|
m_profile = (slotIdx == 0) ? 0 : 1; /* only get two slots for now */
|
|
|
|
|
CTR_Code status = m_impl->SetProfileSlotSelect(m_profile);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* Sets control values for closed loop control.
|
|
|
|
|
*
|
|
|
|
|
* @param p Proportional constant.
|
|
|
|
|
* @param i Integration constant.
|
|
|
|
|
* @param d Differential constant.
|
2015-06-25 15:07:55 -04:00
|
|
|
* This function does not modify F-gain. Considerable passing a zero for f
|
|
|
|
|
* using
|
2014-12-05 05:08:10 -05:00
|
|
|
* the four-parameter function.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetPID(double p, double i, double d) {
|
|
|
|
|
SetP(p);
|
|
|
|
|
SetI(i);
|
|
|
|
|
SetD(d);
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-31 19:18:52 -08:00
|
|
|
/**
|
|
|
|
|
* Sets control values for closed loop control.
|
|
|
|
|
*
|
|
|
|
|
* @param p Proportional constant.
|
|
|
|
|
* @param i Integration constant.
|
|
|
|
|
* @param d Differential constant.
|
|
|
|
|
* @param f Feedforward constant.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetPID(double p, double i, double d, double f) {
|
|
|
|
|
SetP(p);
|
|
|
|
|
SetI(i);
|
|
|
|
|
SetD(d);
|
|
|
|
|
SetF(f);
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
2014-12-01 14:05:26 -05:00
|
|
|
/**
|
|
|
|
|
* Select the feedback device to use in closed-loop
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetFeedbackDevice(FeedbackDevice device) {
|
|
|
|
|
CTR_Code status = m_impl->SetFeedbackDeviceSelect((int)device);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-01 14:05:26 -05:00
|
|
|
}
|
2014-12-15 02:21:54 -05:00
|
|
|
/**
|
|
|
|
|
* Select the feedback device to use in closed-loop
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetStatusFrameRateMs(StatusFrameRate stateFrame, int periodMs) {
|
|
|
|
|
CTR_Code status = m_impl->SetStatusFrameRate((int)stateFrame, periodMs);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-15 02:21:54 -05:00
|
|
|
}
|
2014-12-01 14:05:26 -05:00
|
|
|
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* Get the current proportional constant.
|
|
|
|
|
*
|
|
|
|
|
* @return double proportional constant for current profile.
|
2014-12-05 05:08:10 -05:00
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
double CANTalon::GetP() const {
|
|
|
|
|
CanTalonSRX::param_t param = m_profile ? CanTalonSRX::eProfileParamSlot1_P
|
|
|
|
|
: CanTalonSRX::eProfileParamSlot0_P;
|
2014-12-01 14:05:26 -05:00
|
|
|
// Update the info in m_impl.
|
2014-12-05 05:08:10 -05:00
|
|
|
CTR_Code status = m_impl->RequestParam(param);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
2014-12-01 14:05:26 -05:00
|
|
|
}
|
2014-12-14 17:39:35 -05:00
|
|
|
usleep(kDelayForSolicitedSignalsUs); /* small yield for getting response */
|
2014-11-26 15:15:52 -05:00
|
|
|
double p;
|
2014-12-01 14:05:26 -05:00
|
|
|
status = m_impl->GetPgain(m_profile, p);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return p;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
2014-12-05 05:08:10 -05:00
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
double CANTalon::GetI() const {
|
|
|
|
|
CanTalonSRX::param_t param = m_profile ? CanTalonSRX::eProfileParamSlot1_I
|
|
|
|
|
: CanTalonSRX::eProfileParamSlot0_I;
|
2014-12-01 14:05:26 -05:00
|
|
|
// Update the info in m_impl.
|
2014-12-05 05:08:10 -05:00
|
|
|
CTR_Code status = m_impl->RequestParam(param);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
2014-12-01 14:05:26 -05:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
usleep(kDelayForSolicitedSignalsUs); /* small yield for getting response */
|
2014-12-01 14:05:26 -05:00
|
|
|
|
2014-11-26 15:15:52 -05:00
|
|
|
double i;
|
2014-12-01 14:05:26 -05:00
|
|
|
status = m_impl->GetIgain(m_profile, i);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return i;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
2014-12-05 05:08:10 -05:00
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
double CANTalon::GetD() const {
|
|
|
|
|
CanTalonSRX::param_t param = m_profile ? CanTalonSRX::eProfileParamSlot1_D
|
|
|
|
|
: CanTalonSRX::eProfileParamSlot0_D;
|
2014-12-01 14:05:26 -05:00
|
|
|
// Update the info in m_impl.
|
2014-12-05 05:08:10 -05:00
|
|
|
CTR_Code status = m_impl->RequestParam(param);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
2014-12-01 14:05:26 -05:00
|
|
|
}
|
2015-06-25 15:07:55 -04:00
|
|
|
usleep(kDelayForSolicitedSignalsUs); /* small yield for getting response */
|
2014-12-01 14:05:26 -05:00
|
|
|
|
2014-11-26 15:15:52 -05:00
|
|
|
double d;
|
2014-12-01 14:05:26 -05:00
|
|
|
status = m_impl->GetDgain(m_profile, d);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return d;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
double CANTalon::GetF() const {
|
|
|
|
|
CanTalonSRX::param_t param = m_profile ? CanTalonSRX::eProfileParamSlot1_F
|
|
|
|
|
: CanTalonSRX::eProfileParamSlot0_F;
|
2014-12-05 05:08:10 -05:00
|
|
|
// Update the info in m_impl.
|
|
|
|
|
CTR_Code status = m_impl->RequestParam(param);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
usleep(kDelayForSolicitedSignalsUs); /* small yield for getting response */
|
2014-12-05 05:08:10 -05:00
|
|
|
double f;
|
|
|
|
|
status = m_impl->GetFgain(m_profile, f);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return f;
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @see SelectProfileSlot to choose between the two sets of gains.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetIzone() const {
|
|
|
|
|
CanTalonSRX::param_t param = m_profile
|
|
|
|
|
? CanTalonSRX::eProfileParamSlot1_IZone
|
|
|
|
|
: CanTalonSRX::eProfileParamSlot0_IZone;
|
|
|
|
|
// Update the info in m_impl.
|
|
|
|
|
CTR_Code status = m_impl->RequestParam(param);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
usleep(kDelayForSolicitedSignalsUs);
|
2014-12-05 05:08:10 -05:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
int iz;
|
|
|
|
|
status = m_impl->GetIzone(m_profile, iz);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return iz;
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
|
2014-12-08 15:22:15 -05:00
|
|
|
/**
|
|
|
|
|
* @return the current setpoint; ie, whatever was last passed to Set().
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
double CANTalon::GetSetpoint() const { return m_setPoint; }
|
2014-12-08 15:22:15 -05:00
|
|
|
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
|
|
|
|
* Returns the voltage coming in from the battery.
|
|
|
|
|
*
|
2014-12-31 19:18:52 -08:00
|
|
|
* @return The input voltage in volts.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
float CANTalon::GetBusVoltage() const {
|
2014-11-17 16:02:41 -05:00
|
|
|
double voltage;
|
|
|
|
|
CTR_Code status = m_impl->GetBatteryV(voltage);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
return voltage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* @return The voltage being output by the Talon, in Volts.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
float CANTalon::GetOutputVoltage() const {
|
2014-11-17 16:02:41 -05:00
|
|
|
int throttle11;
|
2014-11-26 15:15:52 -05:00
|
|
|
CTR_Code status = m_impl->GetAppliedThrottle(throttle11);
|
2014-12-01 14:05:26 -05:00
|
|
|
float voltage = GetBusVoltage() * (float(throttle11) / 1023.0);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return voltage;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* Returns the current going through the Talon, in Amperes.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
float CANTalon::GetOutputCurrent() const {
|
2014-11-17 16:02:41 -05:00
|
|
|
double current;
|
|
|
|
|
|
|
|
|
|
CTR_Code status = m_impl->GetCurrent(current);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
return current;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
/**
|
|
|
|
|
* Returns temperature of Talon, in degrees Celsius.
|
|
|
|
|
*/
|
|
|
|
|
float CANTalon::GetTemperature() const {
|
2014-11-17 16:02:41 -05:00
|
|
|
double temp;
|
|
|
|
|
|
|
|
|
|
CTR_Code status = m_impl->GetTemp(temp);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (temp != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return temp;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
/**
|
2015-06-25 15:07:55 -04:00
|
|
|
* Set the position value of the selected sensor. This is useful for zero-ing
|
|
|
|
|
* quadrature encoders.
|
|
|
|
|
* Continuous sensors (like analog encoderes) can also partially be set (the
|
|
|
|
|
* portion of the postion based on overflows).
|
2014-12-05 05:08:10 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetPosition(double pos) { m_impl->SetSensorPosition(pos); }
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*
|
|
|
|
|
* @return The position of the sensor currently providing feedback.
|
2015-06-25 15:07:55 -04:00
|
|
|
* When using analog sensors, 0 units corresponds to 0V, 1023
|
|
|
|
|
* units corresponds to 3.3V
|
|
|
|
|
* When using an analog encoder (wrapping around 1023 => 0 is
|
|
|
|
|
* possible) the units are still 3.3V per 1023 units.
|
|
|
|
|
* When using quadrature, each unit is a quadrature edge (4X)
|
|
|
|
|
* mode.
|
|
|
|
|
*/
|
|
|
|
|
double CANTalon::GetPosition() const {
|
2014-11-17 16:02:41 -05:00
|
|
|
int postition;
|
|
|
|
|
|
|
|
|
|
CTR_Code status = m_impl->GetSensorPosition(postition);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return (double)postition;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
/**
|
2015-01-24 18:02:06 -05:00
|
|
|
* If sensor and motor are out of phase, sensor can be inverted
|
2014-12-05 05:08:10 -05:00
|
|
|
* (position and velocity multiplied by -1).
|
|
|
|
|
* @see GetPosition and @see GetSpeed.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetSensorDirection(bool reverseSensor) {
|
2014-12-05 05:08:10 -05:00
|
|
|
CTR_Code status = m_impl->SetRevFeedbackSensor(reverseSensor ? 1 : 0);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
|
2014-12-01 14:05:26 -05:00
|
|
|
/**
|
|
|
|
|
* Returns the current error in the controller.
|
|
|
|
|
*
|
|
|
|
|
* @return the difference between the setpoint and the sensor value.
|
|
|
|
|
*/
|
2015-06-19 17:23:54 -07:00
|
|
|
int CANTalon::GetClosedLoopError() const {
|
2014-12-01 14:05:26 -05:00
|
|
|
int error;
|
|
|
|
|
CTR_Code status = m_impl->GetCloseLoopErr(error);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-01 14:05:26 -05:00
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*
|
|
|
|
|
* @returns The speed of the sensor currently providing feedback.
|
2014-12-05 05:08:10 -05:00
|
|
|
*
|
|
|
|
|
* The speed units will be in the sensor's native ticks per 100ms.
|
|
|
|
|
*
|
|
|
|
|
* For analog sensors, 3.3V corresponds to 1023 units.
|
2015-06-25 15:07:55 -04:00
|
|
|
* So a speed of 200 equates to ~0.645 dV per 100ms or 6.451 dV per
|
|
|
|
|
* second.
|
|
|
|
|
* If this is an analog encoder, that likely means 1.9548 rotations
|
|
|
|
|
* per sec.
|
2014-12-05 05:08:10 -05:00
|
|
|
* For quadrature encoders, each unit corresponds a quadrature edge (4X).
|
2015-06-25 15:07:55 -04:00
|
|
|
* So a 250 count encoder will produce 1000 edge events per
|
|
|
|
|
* rotation.
|
|
|
|
|
* An example speed of 200 would then equate to 20% of a rotation
|
|
|
|
|
* per 100ms,
|
2014-12-05 05:08:10 -05:00
|
|
|
* or 10 rotations per second.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
double CANTalon::GetSpeed() const {
|
2014-11-17 16:02:41 -05:00
|
|
|
int speed;
|
|
|
|
|
// TODO convert from int to appropriate units (or at least document it).
|
|
|
|
|
|
|
|
|
|
CTR_Code status = m_impl->GetSensorVelocity(speed);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return (double)speed;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
2014-12-01 14:05:26 -05:00
|
|
|
/**
|
|
|
|
|
* Get the position of whatever is in the analog pin of the Talon, regardless of
|
|
|
|
|
* whether it is actually being used for feedback.
|
|
|
|
|
*
|
2015-06-25 15:07:55 -04:00
|
|
|
* @returns The 24bit analog value. The bottom ten bits is the ADC (0 - 1023)
|
|
|
|
|
* on
|
|
|
|
|
* the analog pin of the Talon.
|
|
|
|
|
* The upper 14 bits
|
|
|
|
|
* tracks the overflows and
|
|
|
|
|
* underflows (continuous sensor).
|
|
|
|
|
*/
|
|
|
|
|
int CANTalon::GetAnalogIn() const {
|
2014-12-01 14:05:26 -05:00
|
|
|
int position;
|
|
|
|
|
CTR_Code status = m_impl->GetAnalogInWithOv(position);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-01 14:05:26 -05:00
|
|
|
return position;
|
|
|
|
|
}
|
2014-12-15 02:21:54 -05:00
|
|
|
/**
|
|
|
|
|
* Get the position of whatever is in the analog pin of the Talon, regardless of
|
|
|
|
|
* whether it is actually being used for feedback.
|
|
|
|
|
*
|
|
|
|
|
* @returns The ADC (0 - 1023) on analog pin of the Talon.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetAnalogInRaw() const { return GetAnalogIn() & 0x3FF; }
|
2014-12-01 14:05:26 -05:00
|
|
|
/**
|
|
|
|
|
* Get the position of whatever is in the analog pin of the Talon, regardless of
|
|
|
|
|
* whether it is actually being used for feedback.
|
|
|
|
|
*
|
|
|
|
|
* @returns The value (0 - 1023) on the analog pin of the Talon.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetAnalogInVel() const {
|
2014-12-01 14:05:26 -05:00
|
|
|
int vel;
|
|
|
|
|
CTR_Code status = m_impl->GetAnalogInVel(vel);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-01 14:05:26 -05:00
|
|
|
return vel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the position of whatever is in the analog pin of the Talon, regardless of
|
|
|
|
|
* whether it is actually being used for feedback.
|
|
|
|
|
*
|
|
|
|
|
* @returns The value (0 - 1023) on the analog pin of the Talon.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetEncPosition() const {
|
2014-12-01 14:05:26 -05:00
|
|
|
int position;
|
|
|
|
|
CTR_Code status = m_impl->GetEncPosition(position);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-01 14:05:26 -05:00
|
|
|
return position;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the position of whatever is in the analog pin of the Talon, regardless of
|
|
|
|
|
* whether it is actually being used for feedback.
|
|
|
|
|
*
|
|
|
|
|
* @returns The value (0 - 1023) on the analog pin of the Talon.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetEncVel() const {
|
2014-12-01 14:05:26 -05:00
|
|
|
int vel;
|
|
|
|
|
CTR_Code status = m_impl->GetEncVel(vel);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-01 14:05:26 -05:00
|
|
|
return vel;
|
|
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
/**
|
|
|
|
|
* @return IO level of QUADA pin.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetPinStateQuadA() const {
|
|
|
|
|
int retval;
|
|
|
|
|
CTR_Code status = m_impl->GetQuadApin(retval);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return retval;
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @return IO level of QUADB pin.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetPinStateQuadB() const {
|
|
|
|
|
int retval;
|
|
|
|
|
CTR_Code status = m_impl->GetQuadBpin(retval);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return retval;
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @return IO level of QUAD Index pin.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetPinStateQuadIdx() const {
|
|
|
|
|
int retval;
|
|
|
|
|
CTR_Code status = m_impl->GetQuadIdxpin(retval);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return retval;
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @return '1' iff forward limit switch is closed, 0 iff switch is open.
|
|
|
|
|
* This function works regardless if limit switch feature is enabled.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::IsFwdLimitSwitchClosed() const {
|
|
|
|
|
int retval;
|
|
|
|
|
CTR_Code status = m_impl->GetLimitSwitchClosedFor(
|
|
|
|
|
retval); /* rename this func, '1' => open, '0' => closed */
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return retval ? 0 : 1;
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @return '1' iff reverse limit switch is closed, 0 iff switch is open.
|
|
|
|
|
* This function works regardless if limit switch feature is enabled.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::IsRevLimitSwitchClosed() const {
|
|
|
|
|
int retval;
|
|
|
|
|
CTR_Code status = m_impl->GetLimitSwitchClosedRev(
|
|
|
|
|
retval); /* rename this func, '1' => open, '0' => closed */
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return retval ? 0 : 1;
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Simple accessor for tracked rise eventso index pin.
|
|
|
|
|
* @return number of rising edges on idx pin.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetNumberOfQuadIdxRises() const {
|
|
|
|
|
int rises;
|
|
|
|
|
CTR_Code status = m_impl->GetEncIndexRiseEvents(
|
|
|
|
|
rises); /* rename this func, '1' => open, '0' => closed */
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return rises;
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
/*
|
2015-06-25 15:07:55 -04:00
|
|
|
* @param rises integral value to set into index-rises register. Great way to
|
|
|
|
|
* zero the index count.
|
|
|
|
|
*/
|
|
|
|
|
void CANTalon::SetNumberOfQuadIdxRises(int rises) {
|
|
|
|
|
CTR_Code status = m_impl->SetParam(
|
|
|
|
|
CanTalonSRX::eEncIndexRiseEvents,
|
|
|
|
|
rises); /* rename this func, '1' => open, '0' => closed */
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool CANTalon::GetForwardLimitOK() const {
|
|
|
|
|
int limSwit = 0;
|
|
|
|
|
int softLim = 0;
|
|
|
|
|
CTR_Code status = CTR_OKAY;
|
|
|
|
|
status = m_impl->GetFault_ForSoftLim(softLim);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
status = m_impl->GetFault_ForLim(limSwit);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
/* If either fault is asserted, signal caller we are disabled (with false?) */
|
|
|
|
|
return (softLim | limSwit) ? false : true;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool CANTalon::GetReverseLimitOK() const {
|
|
|
|
|
int limSwit = 0;
|
|
|
|
|
int softLim = 0;
|
|
|
|
|
CTR_Code status = CTR_OKAY;
|
|
|
|
|
status = m_impl->GetFault_RevSoftLim(softLim);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
status = m_impl->GetFault_RevLim(limSwit);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
/* If either fault is asserted, signal caller we are disabled (with false?) */
|
|
|
|
|
return (softLim | limSwit) ? false : true;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
uint16_t CANTalon::GetFaults() const {
|
|
|
|
|
uint16_t retval = 0;
|
|
|
|
|
int val;
|
|
|
|
|
CTR_Code status = CTR_OKAY;
|
|
|
|
|
|
|
|
|
|
/* temperature */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetFault_OverTemp(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kTemperatureFault : 0;
|
|
|
|
|
|
|
|
|
|
/* voltage */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetFault_UnderVoltage(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kBusVoltageFault : 0;
|
|
|
|
|
|
|
|
|
|
/* fwd-limit-switch */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetFault_ForLim(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kFwdLimitSwitch : 0;
|
|
|
|
|
|
|
|
|
|
/* rev-limit-switch */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetFault_RevLim(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kRevLimitSwitch : 0;
|
|
|
|
|
|
|
|
|
|
/* fwd-soft-limit */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetFault_ForSoftLim(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kFwdSoftLimit : 0;
|
|
|
|
|
|
|
|
|
|
/* rev-soft-limit */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetFault_RevSoftLim(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kRevSoftLimit : 0;
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
uint16_t CANTalon::GetStickyFaults() const {
|
|
|
|
|
uint16_t retval = 0;
|
|
|
|
|
int val;
|
|
|
|
|
CTR_Code status = CTR_OKAY;
|
|
|
|
|
|
|
|
|
|
/* temperature */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetStckyFault_OverTemp(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kTemperatureFault : 0;
|
|
|
|
|
|
|
|
|
|
/* voltage */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetStckyFault_UnderVoltage(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kBusVoltageFault : 0;
|
|
|
|
|
|
|
|
|
|
/* fwd-limit-switch */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetStckyFault_ForLim(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kFwdLimitSwitch : 0;
|
|
|
|
|
|
|
|
|
|
/* rev-limit-switch */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetStckyFault_RevLim(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kRevLimitSwitch : 0;
|
|
|
|
|
|
|
|
|
|
/* fwd-soft-limit */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetStckyFault_ForSoftLim(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kFwdSoftLimit : 0;
|
|
|
|
|
|
|
|
|
|
/* rev-soft-limit */
|
|
|
|
|
val = 0;
|
|
|
|
|
status = m_impl->GetStckyFault_RevSoftLim(val);
|
|
|
|
|
if (status != CTR_OKAY)
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
retval |= (val) ? CANSpeedController::kRevSoftLimit : 0;
|
|
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
|
}
|
|
|
|
|
void CANTalon::ClearStickyFaults() {
|
|
|
|
|
CTR_Code status = m_impl->ClearStickyFaults();
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Set the maximum voltage change rate. This ramp rate is in affect regardless
|
|
|
|
|
* of which control mode
|
2014-12-05 05:08:10 -05:00
|
|
|
* the TALON is in.
|
|
|
|
|
*
|
2015-06-25 15:07:55 -04:00
|
|
|
* When in PercentVbus or Voltage output mode, the rate at which the voltage
|
|
|
|
|
* changes can
|
|
|
|
|
* be limited to reduce current spikes. Set this to 0.0 to disable rate
|
|
|
|
|
* limiting.
|
2014-12-05 05:08:10 -05:00
|
|
|
*
|
2015-06-25 15:07:55 -04:00
|
|
|
* @param rampRate The maximum rate of voltage change in Percent Voltage mode in
|
|
|
|
|
* V/s.
|
|
|
|
|
*/
|
|
|
|
|
void CANTalon::SetVoltageRampRate(double rampRate) {
|
|
|
|
|
/* Caller is expressing ramp as Voltage per sec, assuming 12V is full.
|
|
|
|
|
Talon's throttle ramp is in dThrot/d10ms. 1023 is full fwd, -1023 is
|
|
|
|
|
full rev. */
|
|
|
|
|
double rampRatedThrotPer10ms = (rampRate * 1023.0 / 12.0) / 100;
|
|
|
|
|
CTR_Code status = m_impl->SetRampThrottle((int)rampRatedThrotPer10ms);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-05 05:08:10 -05:00
|
|
|
}
|
|
|
|
|
/**
|
2015-06-25 15:07:55 -04:00
|
|
|
* Sets a voltage change rate that applies only when a close loop contorl mode
|
|
|
|
|
* is enabled.
|
2014-12-05 05:08:10 -05:00
|
|
|
* This allows close loop specific ramp behavior.
|
|
|
|
|
*
|
2015-06-25 15:07:55 -04:00
|
|
|
* @param rampRate The maximum rate of voltage change in Percent Voltage mode in
|
|
|
|
|
* V/s.
|
|
|
|
|
*/
|
|
|
|
|
void CANTalon::SetCloseLoopRampRate(double rampRate) {
|
|
|
|
|
CTR_Code status = m_impl->SetCloseLoopRampRate(
|
|
|
|
|
m_profile, rampRate * 1023.0 / 12.0 / 1000.0);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return The version of the firmware running on the Talon
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
uint32_t CANTalon::GetFirmwareVersion() const {
|
|
|
|
|
int firmwareVersion;
|
|
|
|
|
CTR_Code status = m_impl->RequestParam(CanTalonSRX::eFirmVers);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
usleep(kDelayForSolicitedSignalsUs);
|
|
|
|
|
status =
|
|
|
|
|
m_impl->GetParamResponseInt32(CanTalonSRX::eFirmVers, firmwareVersion);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
/* only sent once on boot */
|
|
|
|
|
// CTR_Code status = m_impl->GetFirmVers(firmwareVersion);
|
|
|
|
|
// if(status != CTR_OKAY) {
|
|
|
|
|
// wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
//}
|
2014-12-05 05:08:10 -05:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
return firmwareVersion;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-06 21:59:44 -05:00
|
|
|
/**
|
|
|
|
|
* @return The accumulator for I gain.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
int CANTalon::GetIaccum() const {
|
|
|
|
|
CTR_Code status = m_impl->RequestParam(CanTalonSRX::ePidIaccum);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
usleep(kDelayForSolicitedSignalsUs); /* small yield for getting response */
|
|
|
|
|
int iaccum;
|
|
|
|
|
status = m_impl->GetParamResponseInt32(CanTalonSRX::ePidIaccum, iaccum);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return iaccum;
|
2014-12-06 21:59:44 -05:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Clear the accumulator for I gain.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ClearIaccum() {
|
|
|
|
|
CTR_Code status = m_impl->SetParam(CanTalonSRX::ePidIaccum, 0);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-06 21:59:44 -05:00
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigNeutralMode(NeutralMode mode) {
|
|
|
|
|
CTR_Code status = CTR_OKAY;
|
|
|
|
|
switch (mode) {
|
|
|
|
|
default:
|
|
|
|
|
case kNeutralMode_Jumper: /* use default setting in flash based on
|
|
|
|
|
webdash/BrakeCal button selection */
|
|
|
|
|
status = m_impl->SetOverrideBrakeType(
|
|
|
|
|
CanTalonSRX::kBrakeOverride_UseDefaultsFromFlash);
|
|
|
|
|
break;
|
|
|
|
|
case kNeutralMode_Brake:
|
|
|
|
|
status = m_impl->SetOverrideBrakeType(
|
|
|
|
|
CanTalonSRX::kBrakeOverride_OverrideBrake);
|
|
|
|
|
break;
|
|
|
|
|
case kNeutralMode_Coast:
|
|
|
|
|
status = m_impl->SetOverrideBrakeType(
|
|
|
|
|
CanTalonSRX::kBrakeOverride_OverrideCoast);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* @return nonzero if brake is enabled during neutral. Zero if coast is enabled
|
|
|
|
|
* during neutral.
|
|
|
|
|
*/
|
|
|
|
|
int CANTalon::GetBrakeEnableDuringNeutral() const {
|
2014-12-15 02:21:54 -05:00
|
|
|
int brakeEn = 0;
|
|
|
|
|
CTR_Code status = m_impl->GetBrakeIsEnabled(brakeEn);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
return brakeEn;
|
2014-12-15 02:21:54 -05:00
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* @deprecated not implemented
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigEncoderCodesPerRev(uint16_t codesPerRev) {
|
|
|
|
|
/* TALON SRX does not scale units, they are raw from the sensor. Unit scaling
|
|
|
|
|
* can be done in API or by caller */
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* @deprecated not implemented
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigPotentiometerTurns(uint16_t turns) {
|
|
|
|
|
/* TALON SRX does not scale units, they are raw from the sensor. Unit scaling
|
|
|
|
|
* can be done in API or by caller */
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-31 19:18:52 -08:00
|
|
|
* @deprecated not implemented
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigSoftPositionLimits(double forwardLimitPosition,
|
|
|
|
|
double reverseLimitPosition) {
|
|
|
|
|
ConfigLimitMode(kLimitMode_SoftPositionLimits);
|
|
|
|
|
ConfigForwardLimit(forwardLimitPosition);
|
|
|
|
|
ConfigReverseLimit(reverseLimitPosition);
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::DisableSoftPositionLimits() {
|
|
|
|
|
ConfigLimitMode(kLimitMode_SwitchInputsOnly);
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
2014-12-05 05:08:10 -05:00
|
|
|
* Configures the soft limit enable (wear leveled persistent memory).
|
|
|
|
|
* Also sets the limit switch overrides.
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigLimitMode(LimitMode mode) {
|
|
|
|
|
CTR_Code status = CTR_OKAY;
|
|
|
|
|
switch (mode) {
|
|
|
|
|
case kLimitMode_SwitchInputsOnly: /** Only use switches for limits */
|
|
|
|
|
/* turn OFF both limits. SRX has individual enables and polarity for each
|
|
|
|
|
* limit switch.*/
|
|
|
|
|
status = m_impl->SetForwardSoftEnable(false);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
status = m_impl->SetReverseSoftEnable(false);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
/* override enable the limit switches, this circumvents the webdash */
|
|
|
|
|
status = m_impl->SetOverrideLimitSwitchEn(
|
|
|
|
|
CanTalonSRX::kLimitSwitchOverride_EnableFwd_EnableRev);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case kLimitMode_SoftPositionLimits: /** Use both switches and soft limits */
|
|
|
|
|
/* turn on both limits. SRX has individual enables and polarity for each
|
|
|
|
|
* limit switch.*/
|
|
|
|
|
status = m_impl->SetForwardSoftEnable(true);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
status = m_impl->SetReverseSoftEnable(true);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
/* override enable the limit switches, this circumvents the webdash */
|
|
|
|
|
status = m_impl->SetOverrideLimitSwitchEn(
|
|
|
|
|
CanTalonSRX::kLimitSwitchOverride_EnableFwd_EnableRev);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case kLimitMode_SrxDisableSwitchInputs: /** disable both limit switches and
|
|
|
|
|
soft limits */
|
|
|
|
|
/* turn on both limits. SRX has individual enables and polarity for each
|
|
|
|
|
* limit switch.*/
|
|
|
|
|
status = m_impl->SetForwardSoftEnable(false);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
status = m_impl->SetReverseSoftEnable(false);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
/* override enable the limit switches, this circumvents the webdash */
|
|
|
|
|
status = m_impl->SetOverrideLimitSwitchEn(
|
|
|
|
|
CanTalonSRX::kLimitSwitchOverride_DisableFwd_DisableRev);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigForwardLimit(double forwardLimitPosition) {
|
|
|
|
|
CTR_Code status = CTR_OKAY;
|
|
|
|
|
status = m_impl->SetForwardSoftLimit(forwardLimitPosition);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-17 23:15:24 -05:00
|
|
|
/**
|
|
|
|
|
* Change the fwd limit switch setting to normally open or closed.
|
|
|
|
|
* Talon will disable momentarilly if the Talon's current setting
|
|
|
|
|
* is dissimilar to the caller's requested setting.
|
|
|
|
|
*
|
|
|
|
|
* Since Talon saves setting to flash this should only affect
|
|
|
|
|
* a given Talon initially during robot install.
|
|
|
|
|
*
|
|
|
|
|
* @param normallyOpen true for normally open. false for normally closed.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigFwdLimitSwitchNormallyOpen(bool normallyOpen) {
|
|
|
|
|
CTR_Code status =
|
|
|
|
|
m_impl->SetParam(CanTalonSRX::eOnBoot_LimitSwitch_Forward_NormallyClosed,
|
|
|
|
|
normallyOpen ? 0 : 1);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-17 23:15:24 -05:00
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Change the rev limit switch setting to normally open or closed.
|
|
|
|
|
* Talon will disable momentarilly if the Talon's current setting
|
|
|
|
|
* is dissimilar to the caller's requested setting.
|
|
|
|
|
*
|
|
|
|
|
* Since Talon saves setting to flash this should only affect
|
|
|
|
|
* a given Talon initially during robot install.
|
|
|
|
|
*
|
|
|
|
|
* @param normallyOpen true for normally open. false for normally closed.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigRevLimitSwitchNormallyOpen(bool normallyOpen) {
|
|
|
|
|
CTR_Code status =
|
|
|
|
|
m_impl->SetParam(CanTalonSRX::eOnBoot_LimitSwitch_Reverse_NormallyClosed,
|
|
|
|
|
normallyOpen ? 0 : 1);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-12-17 23:15:24 -05:00
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigReverseLimit(double reverseLimitPosition) {
|
|
|
|
|
CTR_Code status = CTR_OKAY;
|
|
|
|
|
status = m_impl->SetReverseSoftLimit(reverseLimitPosition);
|
|
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigMaxOutputVoltage(double voltage) {
|
|
|
|
|
/* SRX does not support max output */
|
|
|
|
|
wpi_setWPIErrorWithContext(IncompatibleMode,
|
|
|
|
|
"MaxOutputVoltage not supported.");
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ConfigFaultTime(float faultTime) {
|
|
|
|
|
/* SRX does not have fault time. SRX motor drive is only disabled for soft
|
|
|
|
|
* limits and limit-switch faults. */
|
|
|
|
|
wpi_setWPIErrorWithContext(IncompatibleMode, "Fault Time not supported.");
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-12-16 21:37:20 -05:00
|
|
|
* Fixup the sendMode so Set() serializes the correct demand value.
|
|
|
|
|
* Also fills the modeSelecet in the control frame to disabled.
|
|
|
|
|
* @param mode Control mode to ultimately enter once user calls Set().
|
|
|
|
|
* @see Set()
|
2014-11-17 16:02:41 -05:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::ApplyControlMode(CANSpeedController::ControlMode mode) {
|
2014-11-17 16:02:41 -05:00
|
|
|
m_controlMode = mode;
|
2015-06-25 15:07:55 -04:00
|
|
|
HALReport(HALUsageReporting::kResourceType_CANTalonSRX, m_deviceNumber + 1,
|
|
|
|
|
mode);
|
2014-11-17 16:02:41 -05:00
|
|
|
switch (mode) {
|
|
|
|
|
case kPercentVbus:
|
2014-12-06 16:06:15 -05:00
|
|
|
m_sendMode = kThrottle;
|
2014-11-17 16:02:41 -05:00
|
|
|
break;
|
|
|
|
|
case kCurrent:
|
2014-12-06 16:06:15 -05:00
|
|
|
m_sendMode = kCurrentMode;
|
2014-11-17 16:02:41 -05:00
|
|
|
break;
|
|
|
|
|
case kSpeed:
|
2014-12-06 16:06:15 -05:00
|
|
|
m_sendMode = kSpeedMode;
|
2014-11-17 16:02:41 -05:00
|
|
|
break;
|
|
|
|
|
case kPosition:
|
2014-12-06 16:06:15 -05:00
|
|
|
m_sendMode = kPositionMode;
|
2014-11-17 16:02:41 -05:00
|
|
|
break;
|
|
|
|
|
case kVoltage:
|
2014-12-06 16:06:15 -05:00
|
|
|
m_sendMode = kVoltageMode;
|
2014-11-17 16:02:41 -05:00
|
|
|
break;
|
|
|
|
|
case kFollower:
|
2014-12-06 16:06:15 -05:00
|
|
|
m_sendMode = kFollowerMode;
|
2014-11-17 16:02:41 -05:00
|
|
|
break;
|
|
|
|
|
}
|
2014-12-06 16:06:15 -05:00
|
|
|
// Keep the talon disabled until Set() is called.
|
|
|
|
|
CTR_Code status = m_impl->SetModeSelect((int)kDisabled);
|
2015-06-25 15:07:55 -04:00
|
|
|
if (status != CTR_OKAY) {
|
|
|
|
|
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2014-12-16 21:37:20 -05:00
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetControlMode(CANSpeedController::ControlMode mode) {
|
|
|
|
|
if (m_controlMode == mode) {
|
2014-12-16 21:37:20 -05:00
|
|
|
/* we already are in this mode, don't perform disable workaround */
|
2015-06-25 15:07:55 -04:00
|
|
|
} else {
|
2014-12-16 21:37:20 -05:00
|
|
|
ApplyControlMode(mode);
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-11-17 16:02:41 -05:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO documentation (see CANJaguar.cpp)
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
CANSpeedController::ControlMode CANTalon::GetControlMode() const {
|
2014-11-17 16:02:41 -05:00
|
|
|
return m_controlMode;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetExpiration(float timeout) {
|
|
|
|
|
m_safetyHelper->SetExpiration(timeout);
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
float CANTalon::GetExpiration() const {
|
|
|
|
|
return m_safetyHelper->GetExpiration();
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
bool CANTalon::IsAlive() const { return m_safetyHelper->IsAlive(); }
|
2014-11-17 16:02:41 -05:00
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
bool CANTalon::IsSafetyEnabled() const {
|
|
|
|
|
return m_safetyHelper->IsSafetyEnabled();
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetSafetyEnabled(bool enabled) {
|
|
|
|
|
m_safetyHelper->SetSafetyEnabled(enabled);
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
|
|
|
|
|
artf4154: Get rid of raw pointers in C++.
This deals with the majority of the user-facing code
in wpilibC++Devices and a substantial portion of it in
wpilibC++. wpilibC++Sim and wpilibC++IntegrationTests
are untouched except where it is necessary to make them
work with the rest of the libraries.
There is still a lot to do in the following areas:
-The HAL (which we may not want to touch at all).
-The I2C, Serial, and SPI interfaces in wpilibC++Devices,
which I haven't gotten around to doing yet.
-Most wpilibC++Devices classes have void* pointers
for interacting with the HAL.
-InterruptableSensorBase passes a void *params for
the interrupt handler.
-I haven't converted all the const char* to std::strings.
-There are plenty of other cases of raw pointers still
existing.
-This doesn't fall directly under raw pointer stuff,
but move syntax and rvalue references could be introduced
in many places.
-I haven't touched vision code.
-The Resource classes conflict (one is in the hal, the other
in wpilibC++). Someone should figure out a more
permanent fix (eg, just renaming them), then doing
what I did (making a new namespace for one of them,
essentially the same as renaming it).
A few other things:
-I created a NullDeleter class which is marked as deprecated.
What this does is it can be passed as the deleter to a
std::shared_ptr so that when you are converting raw pointers
to shared_ptrs the shared_ptr doesn't do any deletion if
someone else owns the raw pointer. This should only be
used in making old raw pointer UIs.
-I had to alter the build.gradle so that it did not
emit errors when deprecated functions called deprecated
functions. Unfortunately, gradle doesn't appear to be
actually printing out gcc warnigns for some reason.
The best way I have found to fix this is to patch
the toolchains (https://bitbucket.org/byteit101/toolchain-builder/pull-request/5/make-gcc-not-throw-warnings-for-nested/diff)
so that a deprecated function calling a deprecated
function is fine but a non-deprecated function calling
a deprecated function will throw a warning (which we
then elevate with -Werror). I believe that clang
deals with this properly, although I have not
tried it myself.
Change-Id: Ib8090c66893576fe73654f4e9d268f9d37be06a2
2015-06-30 15:01:20 -04:00
|
|
|
void CANTalon::GetDescription(std::ostringstream& desc) const {
|
|
|
|
|
desc << "CANTalon ID " << m_deviceNumber;
|
2014-11-17 16:02:41 -05:00
|
|
|
}
|
2015-06-15 15:32:47 -04:00
|
|
|
|
2015-03-24 15:01:17 -04:00
|
|
|
/**
|
2015-06-15 15:32:47 -04:00
|
|
|
* Common interface for inverting direction of a speed controller.
|
|
|
|
|
* Only works in PercentVbus, speed, and Voltage modes.
|
|
|
|
|
* @param isInverted The state of inversion, true is inverted.
|
2015-03-24 15:01:17 -04:00
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::SetInverted(bool isInverted) { m_isInverted = isInverted; }
|
2015-06-15 15:32:47 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Common interface for the inverting direction of a speed controller.
|
|
|
|
|
*
|
|
|
|
|
* @return isInverted The state of inversion, true is inverted.
|
|
|
|
|
*
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
bool CANTalon::GetInverted() const { return m_isInverted; }
|
2015-06-15 15:32:47 -04:00
|
|
|
|
2014-11-17 16:02:41 -05:00
|
|
|
/**
|
|
|
|
|
* Common interface for stopping the motor
|
|
|
|
|
* Part of the MotorSafety interface
|
|
|
|
|
*
|
|
|
|
|
* @deprecated Call Disable instead.
|
|
|
|
|
*/
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::StopMotor() { Disable(); }
|
2015-06-17 14:38:16 -04:00
|
|
|
|
2015-08-13 23:17:19 -07:00
|
|
|
void CANTalon::ValueChanged(ITable* source, llvm::StringRef key,
|
|
|
|
|
std::shared_ptr<nt::Value> value, bool isNew) {
|
|
|
|
|
if (!value->IsDouble()) return;
|
|
|
|
|
Set(value->GetDouble());
|
2015-06-17 14:38:16 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::UpdateTable() {
|
2015-06-23 04:49:51 -07:00
|
|
|
if (m_table != nullptr) {
|
2015-06-25 15:07:55 -04:00
|
|
|
m_table->PutNumber("Value", Get());
|
|
|
|
|
}
|
2015-06-17 14:38:16 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::StartLiveWindowMode() {
|
2015-06-23 04:49:51 -07:00
|
|
|
if (m_table != nullptr) {
|
2015-06-25 15:07:55 -04:00
|
|
|
m_table->AddTableListener("Value", this, true);
|
|
|
|
|
}
|
2015-06-17 14:38:16 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
void CANTalon::StopLiveWindowMode() {
|
2015-06-23 04:49:51 -07:00
|
|
|
if (m_table != nullptr) {
|
2015-06-25 15:07:55 -04:00
|
|
|
m_table->RemoveTableListener(this);
|
|
|
|
|
}
|
2015-06-17 14:38:16 -04:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 15:07:55 -04:00
|
|
|
std::string CANTalon::GetSmartDashboardType() const {
|
|
|
|
|
return "Speed Controller";
|
2015-06-17 14:38:16 -04:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 16:48:04 -04:00
|
|
|
void CANTalon::InitTable(std::shared_ptr<ITable> subTable) {
|
2015-06-25 15:07:55 -04:00
|
|
|
m_table = subTable;
|
|
|
|
|
UpdateTable();
|
2015-06-17 14:38:16 -04:00
|
|
|
}
|
|
|
|
|
|
2015-07-29 16:48:04 -04:00
|
|
|
std::shared_ptr<ITable> CANTalon::GetTable() const { return m_table; }
|