Files
allwpilib/wpilibc/wpilibC++Devices/src/CANTalon.cpp

676 lines
14 KiB
C++
Raw Normal View History

/*----------------------------------------------------------------------------*/
/* 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"
#include "ctre/CanTalonSRX.h"
/**
* The CANTalon object is currently incomplete. As of Nov 14 2014, we only know
* for sure that sending a throttle and checking basic values (eg current,
* temperature) work.
*/
/**
* Constructor for the CANTalon device.
* @param deviceNumber The CAN ID of the Talon SRX
*/
CANTalon::CANTalon(int deviceNumber)
: m_deviceNumber(deviceNumber)
, m_impl(new CanTalonSRX(deviceNumber))
, m_safetyHelper(new MotorSafetyHelper(this))
, m_profile(0)
, m_controlEnabled(true)
, m_controlMode(kPercentVbus)
{
// The control mode may already have been set; GetControlMode will reset
// m_controlMode to match the Talon.
GetControlMode();
m_impl->SetProfileSlotSelect(m_profile);
}
CANTalon::~CANTalon() {
delete m_impl;
delete m_safetyHelper;
}
/**
* Write out the PID value as seen in the PIDOutput base object.
*
* @deprecated Call Set instead.
*
* @param output Write out the PercentVbus value as was computed by the PIDController
*/
void CANTalon::PIDWrite(float output)
{
if (GetControlMode() == kPercentVbus)
{
Set(output);
}
else
{
wpi_setWPIErrorWithContext(IncompatibleMode, "PID only supported in PercentVbus mode");
}
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
float CANTalon::Get()
{
int value;
switch(m_controlMode) {
case kVoltage:
return GetOutputVoltage();
case kCurrent:
return GetOutputCurrent();
case kSpeed:
m_impl->GetSensorVelocity(value);
return value;
case kPosition:
m_impl->GetSensorPosition(value);
return value;
case kPercentVbus:
default:
m_impl->GetAppliedThrottle(value);
return (float)value / 1023.0;
}
}
/**
* 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.
* In Voltage mode, outputValue is in volts.
* In Current mode, outputValue is in amperes.
* In Speed mode, outputValue is in position change / 10ms.
* In Position mode, outputValue is in encoder ticks or an analog value,
* depending on the sensor.
*
* @param outputValue The setpoint value, as described above.
*/
void CANTalon::Set(float value, uint8_t syncGroup)
{
if(m_controlEnabled) {
CTR_Code status;
switch(GetControlMode()) {
case CANSpeedController::kPercentVbus:
{
m_impl->Set(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(value * 256);
status = m_impl->SetDemand(volts);
}
break;
case CANSpeedController::kSpeed:
status = m_impl->SetDemand(value);
break;
case CANSpeedController::kPosition:
status = m_impl->SetDemand(value);
break;
default:
break;
}
if (status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
}
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::Disable()
{
// Until Modes other than throttle work, just disable by setting throttle to 0.0.
m_impl->SetModeSelect((int)CANTalon::kDisabled);
m_controlEnabled = false;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::EnableControl() {
SetControlMode(m_controlMode);
m_controlEnabled = true;
}
/**
* @param p Proportional constant to use in PID loop.
*/
void CANTalon::SetP(double p)
{
CTR_Code status = m_impl->SetPgain(m_profile, p);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::SetI(double i)
{
CTR_Code status = m_impl->SetIgain(m_profile, i);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::SetD(double d)
{
CTR_Code status = m_impl->SetDgain(m_profile, d);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::SetPID(double p, double i, double d)
{
SetP(p);
SetI(i);
SetD(d);
}
/**
* Select the feedback device to use in closed-loop
*/
void CANTalon::SetFeedbackDevice(FeedbackDevice device)
{
CTR_Code status = m_impl->SetFeedbackDeviceSelect((int)device);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
double CANTalon::GetP()
{
// Update the info in m_impl.
CTR_Code status = m_impl->RequestParam(CanTalonSRX::eProfileParamSlot0_P);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
double p;
status = m_impl->GetPgain(m_profile, p);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return p;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
double CANTalon::GetI()
{
// Update the info in m_impl.
CTR_Code status = m_impl->RequestParam(CanTalonSRX::eProfileParamSlot0_I);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
double i;
status = m_impl->GetIgain(m_profile, i);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return i;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
double CANTalon::GetD()
{
// Update the info in m_impl.
CTR_Code status = m_impl->RequestParam(CanTalonSRX::eProfileParamSlot0_D);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
double d;
status = m_impl->GetDgain(m_profile, d);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return d;
}
/**
* Returns the voltage coming in from the battery.
*
* @return The input voltage in vols.
*/
float CANTalon::GetBusVoltage()
{
double voltage;
CTR_Code status = m_impl->GetBatteryV(voltage);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return voltage;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
float CANTalon::GetOutputVoltage()
{
int throttle11;
CTR_Code status = m_impl->GetAppliedThrottle(throttle11);
float voltage = GetBusVoltage() * (float(throttle11) / 1023.0);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return voltage;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
float CANTalon::GetOutputCurrent()
{
double current;
CTR_Code status = m_impl->GetCurrent(current);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return current;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
float CANTalon::GetTemperature()
{
double temp;
CTR_Code status = m_impl->GetTemp(temp);
if(temp != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return temp;
}
/**
* TODO documentation (see CANJaguar.cpp)
*
* @return The position of the sensor currently providing feedback.
*/
double CANTalon::GetPosition()
{
int postition;
// TODO convert from int to appropriate units (or at least document it).
CTR_Code status = m_impl->GetSensorPosition(postition);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return (double)postition;
}
/**
* Returns the current error in the controller.
*
* @return the difference between the setpoint and the sensor value.
*/
int CANTalon::GetClosedLoopError() {
int error;
CTR_Code status = m_impl->GetCloseLoopErr(error);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return error;
}
/**
* TODO documentation (see CANJaguar.cpp)
*
* @returns The speed of the sensor currently providing feedback.
*/
double CANTalon::GetSpeed()
{
int speed;
// TODO convert from int to appropriate units (or at least document it).
CTR_Code status = m_impl->GetSensorVelocity(speed);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return (double)speed;
}
/**
* 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.
*/
int CANTalon::GetAnalogIn()
{
int position;
CTR_Code status = m_impl->GetAnalogInWithOv(position);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
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.
*/
int CANTalon::GetAnalogInVel()
{
int vel;
CTR_Code status = m_impl->GetAnalogInVel(vel);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
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.
*/
int CANTalon::GetEncPosition()
{
int position;
CTR_Code status = m_impl->GetEncPosition(position);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
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.
*/
int CANTalon::GetEncVel()
{
int vel;
CTR_Code status = m_impl->GetEncVel(vel);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return vel;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
bool CANTalon::GetForwardLimitOK()
{
// TODO
return false;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
bool CANTalon::GetReverseLimitOK()
{
// TODO
return false;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
uint16_t CANTalon::GetFaults()
{
// TODO
return 0;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::SetVoltageRampRate(double rampRate)
{
// TODO
}
/**
* @return The version of the firmware running on the Talon
*/
uint32_t CANTalon::GetFirmwareVersion()
{
int firmwareVersion;
CTR_Code status = m_impl->GetFirmVers(firmwareVersion);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
return firmwareVersion;
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::ConfigNeutralMode(NeutralMode mode)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::ConfigEncoderCodesPerRev(uint16_t codesPerRev)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::ConfigPotentiometerTurns(uint16_t turns)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::ConfigSoftPositionLimits(double forwardLimitPosition, double reverseLimitPosition)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::DisableSoftPositionLimits()
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::ConfigLimitMode(LimitMode mode)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::ConfigForwardLimit(double forwardLimitPosition)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::ConfigReverseLimit(double reverseLimitPosition)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
* Does this exist on the Talon?
*/
void CANTalon::ConfigMaxOutputVoltage(double voltage)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
* Does this exist on the Talon?
*/
void CANTalon::ConfigFaultTime(float faultTime)
{
// TODO
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
void CANTalon::SetControlMode(CANSpeedController::ControlMode mode)
{
m_controlMode = mode;
TalonControlMode sendMode;
switch (mode) {
case kPercentVbus:
sendMode = kThrottle;
break;
case kCurrent:
sendMode = kCurrentMode;
break;
case kSpeed:
sendMode = kSpeedMode;
break;
case kPosition:
sendMode = kPositionMode;
break;
case kVoltage:
sendMode = kVoltageMode;
break;
case kFollower:
sendMode = kFollowerMode;
break;
}
CTR_Code status = m_impl->SetModeSelect((int)sendMode);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
}
/**
* TODO documentation (see CANJaguar.cpp)
*/
CANSpeedController::ControlMode CANTalon::GetControlMode()
{
// Take the opportunity to check that the control mode is what we think it is.
int temp;
CTR_Code status = m_impl->GetModeSelect(temp);
if(status != CTR_OKAY) {
wpi_setErrorWithContext(status, getHALErrorMessage(status));
}
switch ((TalonControlMode)temp) {
case kThrottle:
m_controlMode = kPercentVbus;
break;
case kCurrentMode:
m_controlMode = kCurrent;
break;
case kSpeedMode:
m_controlMode = kSpeed;
break;
case kPositionMode:
m_controlMode = kPosition;
break;
case kVoltageMode:
m_controlMode = kVoltage;
break;
case kFollowerMode:
m_controlMode = kFollower;
break;
case kDisabled:
m_controlEnabled = false;
break;
}
return m_controlMode;
}
void CANTalon::SetExpiration(float timeout)
{
m_safetyHelper->SetExpiration(timeout);
}
float CANTalon::GetExpiration()
{
return m_safetyHelper->GetExpiration();
}
bool CANTalon::IsAlive()
{
return m_safetyHelper->IsAlive();
}
bool CANTalon::IsSafetyEnabled()
{
return m_safetyHelper->IsSafetyEnabled();
}
void CANTalon::SetSafetyEnabled(bool enabled)
{
m_safetyHelper->SetSafetyEnabled(enabled);
}
void CANTalon::GetDescription(char *desc)
{
sprintf(desc, "CANTalon ID %d", m_deviceNumber);
}
/**
* Common interface for stopping the motor
* Part of the MotorSafety interface
*
* @deprecated Call Disable instead.
*/
void CANTalon::StopMotor()
{
Disable();
}