From a0cc45a8f0cf65ee7ba57de30010013a671a3e66 Mon Sep 17 00:00:00 2001 From: Omar Zrien Date: Sun, 11 Oct 2015 14:49:39 -0400 Subject: [PATCH] Format and style changes. Rebuilt last SRX-related commit with latest checkout. Change-Id: I9f10418580275dae5cd07d740d401d45ee44e276 C++: Added Magnetic Encoder sensor types C++: API for changing status frame rates updated to use paramEnums. C++: Added Setting nominal and peak outputs for closed loop modes. C++: Added current-closed loop C++: added vcomp mode C++: Added unit scaling (rotations and rpm) C++ Added allowableclosedlooperr C++: Added auto zero position on index pin C++: Added pulse width decoder API C++: Added multiplicands in status frames, increasing the max reported pos and max rpm. C++: Added SetClosedLoopOutputDirection() for reversing slave output and reversing single-direction closed loopoutput. C++: Added generic ConfigSet and ConfigGet for future flexibility/features. C++: Added IsSensorPresent Java: Added Magnetic Encoder sensor types Java: Added unit scaling (rotations and rpm) Java: Added current-closed loop Java: added vcomp mode Java Added allowableclosedlooperr Java: Added auto zero position on index pin Java: Added pulse width decoder API Java: setForwardSoftLimit and setReverseSoftLimit takes double instead of int so underneath we can support rotations instead of native units. Java: Added generic SetParam and GetParam for future flexibility/features. Java Added isSensorPresent Change-Id: I800251510e411624dce5ee10272606c31764b8ab --- hal/include/HAL/CanTalonSRX.h | 35 +- hal/lib/Athena/ctre/CanTalonSRX.cpp | 224 ++++++-- wpilibc/wpilibC++Devices/include/CANTalon.h | 108 +++- wpilibc/wpilibC++Devices/src/CANTalon.cpp | 531 ++++++++++++++++-- .../java/edu/wpi/first/wpilibj/CANTalon.java | 469 +++++++++++++++- .../edu/wpi/first/wpilibj/CanTalonSRX.java | 78 ++- .../wpi/first/wpilibj/hal/CanTalonJNI.java | 60 ++ wpilibj/wpilibJavaJNI/lib/CanTalonSRXJNI.cpp | 387 +++++++++++++ 8 files changed, 1773 insertions(+), 119 deletions(-) diff --git a/hal/include/HAL/CanTalonSRX.h b/hal/include/HAL/CanTalonSRX.h index d23954a8c6..3ef520dbc8 100644 --- a/hal/include/HAL/CanTalonSRX.h +++ b/hal/include/HAL/CanTalonSRX.h @@ -91,9 +91,6 @@ private: operator bool() const { return moved; } } m_hasBeenMoved; - /** just in case user wants to modify periods of certain status frames. - * Default the vars to match the firmware default. */ - uint32_t _statusRateMs[4]; //---------------------- Vars for opening a CAN stream if caller needs signals that require soliciting */ uint32_t _can_h; //!< Session handle for catching response params. int32_t _can_stat; //!< Session handle status. @@ -154,6 +151,7 @@ public: static const int kStatusFrame_Feedback = 1; static const int kStatusFrame_Encoder = 2; static const int kStatusFrame_AnalogTempVbat = 3; + static const int kStatusFrame_PulseWidthMeas = 4; /** * Signal enumeration for generic signal access. * Although every signal is enumerated, only use this for traffic that must be solicited. @@ -225,6 +223,30 @@ public: eSettingsChanged=90, eQuadFilterEn=91, ePidIaccum=93, + eStatus1FrameRate=94, // TALON_Status_1_General_10ms_t + eStatus2FrameRate=95, // TALON_Status_2_Feedback_20ms_t + eStatus3FrameRate=96, // TALON_Status_3_Enc_100ms_t + eStatus4FrameRate=97, // TALON_Status_4_AinTempVbat_100ms_t + eStatus6FrameRate=98, // TALON_Status_6_Eol_t + eStatus7FrameRate=99, // TALON_Status_7_Debug_200ms_t + eClearPositionOnIdx=100, + //reserved, + //reserved, + //reserved, + ePeakPosOutput=104, + eNominalPosOutput=105, + ePeakNegOutput=106, + eNominalNegOutput=107, + eQuadIdxPolarity=108, + eStatus8FrameRate=109, // TALON_Status_8_PulseWid_100ms_t + eAllowPosOverflow=110, + eProfileParamSlot0_AllowableClosedLoopErr=111, + eNumberPotTurns=112, + eNumberEncoderCPR=113, + ePwdPosition=114, + eAinPosition=115, + eProfileParamVcompRate=116, + eProfileParamSlot1_AllowableClosedLoopErr=117, }param_t; /*---------------------setters and getters that use the solicated param request/response-------------*//** * Send a one shot frame to set an arbitrary signal. @@ -253,6 +275,7 @@ public: CTR_Code SetFgain(unsigned slotIdx,double gain); CTR_Code SetIzone(unsigned slotIdx,int zone); CTR_Code SetCloseLoopRampRate(unsigned slotIdx,int closeLoopRampRate); + CTR_Code SetVoltageCompensationRate(double voltagePerMs); CTR_Code SetSensorPosition(int pos); CTR_Code SetForwardSoftLimit(int forwardLimit); CTR_Code SetReverseSoftLimit(int reverseLimit); @@ -264,6 +287,7 @@ public: CTR_Code GetFgain(unsigned slotIdx,double & gain); CTR_Code GetIzone(unsigned slotIdx,int & zone); CTR_Code GetCloseLoopRampRate(unsigned slotIdx,int & closeLoopRampRate); + CTR_Code GetVoltageCompensationRate(double & voltagePerMs); CTR_Code GetForwardSoftLimit(int & forwardLimit); CTR_Code GetReverseSoftLimit(int & reverseLimit); CTR_Code GetForwardSoftEnable(int & enable); @@ -325,6 +349,11 @@ public: CTR_Code SetProfileSlotSelect(int param); CTR_Code SetRampThrottle(int param); CTR_Code SetRevFeedbackSensor(int param); + CTR_Code GetPulseWidthPosition(int ¶m); + CTR_Code GetPulseWidthVelocity(int ¶m); + CTR_Code GetPulseWidthRiseToFallUs(int ¶m); + CTR_Code GetPulseWidthRiseToRiseUs(int ¶m); + CTR_Code IsPulseWidthSensorPresent(int ¶m); }; extern "C" { void *c_TalonSRX_Create(int deviceNumber, int controlPeriodMs); diff --git a/hal/lib/Athena/ctre/CanTalonSRX.cpp b/hal/lib/Athena/ctre/CanTalonSRX.cpp index c1d21fca1e..5fe551840f 100644 --- a/hal/lib/Athena/ctre/CanTalonSRX.cpp +++ b/hal/lib/Athena/ctre/CanTalonSRX.cpp @@ -20,6 +20,13 @@ * they will only need to set them in a periodic fashion as a function of what motion the application is attempting. * If this API is used, be mindful of the CAN utilization reported in the driver station. * + * If calling application has used the config routines to configure the selected feedback sensor, then all positions are measured in + * floating point precision rotations. All sensor velocities are specified in floating point precision RPM. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * HOWEVER, if calling application has not called the config routine for selected feedback sensor, then all getters/setters for + * position/velocity use the native engineering units of the Talon SRX firm (just like in 2015). Signals explained below. + * * Encoder position is measured in encoder edges. Every edge is counted (similar to roboRIO 4X mode). * Analog position is 10 bits, meaning 1024 ticks per rotation (0V => 3.3V). * Use SetFeedbackDeviceSelect to select which sensor type you need. Once you do that you can use GetSensorPosition() @@ -81,6 +88,7 @@ #define STATUS_5 0x02041500 #define STATUS_6 0x02041540 #define STATUS_7 0x02041580 +#define STATUS_8 0x020415C0 #define CONTROL_1 0x02040000 #define CONTROL_2 0x02040040 @@ -94,6 +102,7 @@ #define GET_STATUS5() CtreCanNode::recMsg rx = GetRx(STATUS_5 | GetDeviceNumber(), EXPECTED_RESPONSE_TIMEOUT_MS) #define GET_STATUS6() CtreCanNode::recMsg rx = GetRx(STATUS_6 | GetDeviceNumber(), EXPECTED_RESPONSE_TIMEOUT_MS) #define GET_STATUS7() CtreCanNode::recMsg rx = GetRx(STATUS_7 | GetDeviceNumber(), EXPECTED_RESPONSE_TIMEOUT_MS) +#define GET_STATUS8() CtreCanNode::recMsg rx = GetRx(STATUS_8 | GetDeviceNumber(), EXPECTED_RESPONSE_TIMEOUT_MS) #define PARAM_REQUEST 0x02041800 #define PARAM_RESPONSE 0x02041840 @@ -102,8 +111,11 @@ const int kParamArbIdValue = PARAM_RESPONSE; const int kParamArbIdMask = 0xFFFFFFFF; -const double FLOAT_TO_FXP = (double)0x400000; -const double FXP_TO_FLOAT = 0.0000002384185791015625; +const double FLOAT_TO_FXP_10_22 = (double)0x400000; +const double FXP_TO_FLOAT_10_22 = 0.0000002384185791015625; + +const double FLOAT_TO_FXP_0_8 = (double)0x100; +const double FXP_TO_FLOAT_0_8 = 0.00390625; /* encoder/decoders */ /** control */ @@ -127,6 +139,7 @@ typedef struct _TALON_Control_2_Rates_OneShot_t { unsigned Status2Ms:8; unsigned Status3Ms:8; unsigned Status4Ms:8; + unsigned StatusPulWidMs:8; // TALON_Status_8_PulseWid_100ms_t } TALON_Control_2_Rates_OneShot_t ; typedef struct _TALON_Control_3_ClearFlags_OneShot_t { unsigned ZeroFeedbackSensor:1; @@ -170,7 +183,9 @@ typedef struct _TALON_Status_2_Feedback_20ms_t { unsigned StckyFault_UnderVoltage:1; unsigned StckyFault_OverTemp:1; unsigned Current_l2:2; - unsigned reserved:6; + unsigned reserved2:4; + unsigned VelDiv4:1; + unsigned PosDiv8:1; unsigned ProfileSlotSelect:1; unsigned BrakeIsEnabled:1; } TALON_Status_2_Feedback_20ms_t ; @@ -182,7 +197,9 @@ typedef struct _TALON_Status_3_Enc_100ms_t { unsigned EncVelL:8; unsigned EncIndexRiseEventsH:8; unsigned EncIndexRiseEventsL:8; - unsigned reserved:5; + unsigned reserved:3; + unsigned VelDiv4:1; + unsigned PosDiv8:1; unsigned QuadIdxpin:1; unsigned QuadBpin:1; unsigned QuadApin:1; @@ -195,7 +212,9 @@ typedef struct _TALON_Status_4_AinTempVbat_100ms_t { unsigned AnalogInVelL:8; unsigned Temp:8; unsigned BatteryV:8; - unsigned reserved:8; + unsigned reserved:6; + unsigned VelDiv4:1; + unsigned PosDiv8:1; } TALON_Status_4_AinTempVbat_100ms_t ; typedef struct _TALON_Status_5_Startup_OneShot_t { unsigned ResetCountH:8; @@ -228,6 +247,18 @@ typedef struct _TALON_Status_7_Debug_200ms_t { unsigned TokenizationSucceses_h8:8; unsigned TokenizationSucceses_l8:8; } TALON_Status_7_Debug_200ms_t ; +typedef struct _TALON_Status_8_PulseWid_100ms_t { + unsigned PulseWidPositionH:8; + unsigned PulseWidPositionM:8; + unsigned PulseWidPositionL:8; + unsigned reserved:6; + unsigned VelDiv4:1; + unsigned PosDiv8:1; + unsigned PeriodUsM8:8; + unsigned PeriodUsL8:8; + unsigned PulseWidVelH:8; + unsigned PulseWidVelL:8; +} TALON_Status_8_PulseWid_100ms_t ; typedef struct _TALON_Param_Request_t { unsigned ParamEnum:8; } TALON_Param_Request_t ; @@ -239,7 +270,6 @@ typedef struct _TALON_Param_Response_t { unsigned ParamValueH:8; } TALON_Param_Response_t ; - CanTalonSRX::CanTalonSRX(int deviceNumber,int controlPeriodMs): CtreCanNode(deviceNumber), _can_h(0), _can_stat(0) { /* bound period to be within [1 ms,95 ms] */ @@ -255,11 +285,6 @@ CanTalonSRX::CanTalonSRX(int deviceNumber,int controlPeriodMs): CtreCanNode(devi RegisterRx(STATUS_6 | (UINT8)deviceNumber ); RegisterRx(STATUS_7 | (UINT8)deviceNumber ); RegisterTx(CONTROL_1 | (UINT8)deviceNumber, (UINT8)controlPeriodMs); - /* default our frame rate table to what firmware defaults to. */ - _statusRateMs[0] = 10; /* TALON_Status_1_General_10ms_t */ - _statusRateMs[1] = 20; /* TALON_Status_2_Feedback_20ms_t */ - _statusRateMs[2] = 100; /* TALON_Status_3_Enc_100ms_t */ - _statusRateMs[3] = 100; /* TALON_Status_4_AinTempVbat_100ms_t */ /* the only default param that is nonzero is limit switch. * Default to using the flash settings. */ SetOverrideLimitSwitchEn(kLimitSwitchOverride_UseDefaultsFromFlash); @@ -268,8 +293,14 @@ CanTalonSRX::CanTalonSRX(int deviceNumber,int controlPeriodMs): CtreCanNode(devi */ CanTalonSRX::~CanTalonSRX() { - if (m_hasBeenMoved) return; - RegisterTx(CONTROL_1 | (UINT8)GetDeviceNumber(), 0); + if (m_hasBeenMoved){ + /* Another CANTalonSRX still exists, so + don't un-register the periodic control frame */ + }else{ + /* un-register the control frame so Talon is disabled */ + RegisterTx(CONTROL_1 | (UINT8)GetDeviceNumber(), 0); + } + /* free the stream we used for SetParam/GetParamResponse */ if(_can_h){ FRC_NetworkCommunication_CANSessionMux_closeStreamSession(_can_h); _can_h = 0; @@ -408,14 +439,36 @@ CTR_Code CanTalonSRX::SetParam(param_t paramEnum, double value) uint32_t urawbits; value = std::min(value,1023.0); /* bounds check doubles that are outside u10.22 */ value = std::max(value,0.0); - urawbits = value * FLOAT_TO_FXP; /* perform unsign arithmetic */ + urawbits = value * FLOAT_TO_FXP_10_22; /* perform unsign arithmetic */ rawbits = urawbits; /* copy bits over. SetParamRaw just stuffs into CAN frame with no sense of signedness */ } break; case eProfileParamSlot1_F: /* signed 10.22 fixed pt value */ case eProfileParamSlot0_F: value = std::min(value, 512.0); /* bounds check doubles that are outside s10.22 */ value = std::max(value,-512.0); - rawbits = value * FLOAT_TO_FXP; + rawbits = value * FLOAT_TO_FXP_10_22; + break; + case eProfileParamVcompRate: /* unsigned 0.8 fixed pt value volts per ms */ + /* within [0,1) volts per ms. + Slowest ramp is 1/256 VperMilliSec or 3.072 seconds from 0-to-12V. + Fastest ramp is 255/256 VperMilliSec or 12.1ms from 0-to-12V. + */ + if(value <= 0){ + /* negative or zero (disable), send raw value of zero */ + rawbits = 0; + }else{ + /* nonzero ramping */ + rawbits = value * FLOAT_TO_FXP_0_8; + /* since whole part is cleared, cap to just under whole unit */ + if(rawbits > (FLOAT_TO_FXP_0_8-1) ) + rawbits = (FLOAT_TO_FXP_0_8-1); + /* since ramping is nonzero, cap to smallest ramp rate possible */ + if(rawbits == 0){ + /* caller is providing a nonzero ramp rate that's too small + to serialize, so cap to smallest possible */ + rawbits = 1; + } + } break; default: /* everything else is integral */ rawbits = (int32_t)value; @@ -439,7 +492,10 @@ CTR_Code CanTalonSRX::GetParamResponse(param_t paramEnum, double & value) case eCurrent: case eTemp: case eBatteryV: - value = ((double)rawbits) * FXP_TO_FLOAT; + value = ((double)rawbits) * FXP_TO_FLOAT_10_22; + break; + case eProfileParamVcompRate: + value = ((double)rawbits) * FXP_TO_FLOAT_0_8; break; default: /* everything else is integral */ value = (double)rawbits; @@ -494,6 +550,10 @@ CTR_Code CanTalonSRX::SetCloseLoopRampRate(unsigned slotIdx,int closeLoopRampRat return SetParam(eProfileParamSlot0_CloseLoopRampRate, closeLoopRampRate); return SetParam(eProfileParamSlot1_CloseLoopRampRate, closeLoopRampRate); } +CTR_Code CanTalonSRX::SetVoltageCompensationRate(double voltagePerMs) +{ + return SetParam(eProfileParamVcompRate, voltagePerMs); +} CTR_Code CanTalonSRX::GetPgain(unsigned slotIdx,double & gain) { if(slotIdx == 0) @@ -530,7 +590,10 @@ CTR_Code CanTalonSRX::GetCloseLoopRampRate(unsigned slotIdx,int & closeLoopRampR return GetParamResponseInt32(eProfileParamSlot0_CloseLoopRampRate, closeLoopRampRate); return GetParamResponseInt32(eProfileParamSlot1_CloseLoopRampRate, closeLoopRampRate); } - +CTR_Code CanTalonSRX::GetVoltageCompensationRate(double & voltagePerMs) +{ + return GetParamResponse(eProfileParamVcompRate, voltagePerMs); +} CTR_Code CanTalonSRX::SetSensorPosition(int pos) { return SetParam(eSensorPosition, pos); @@ -572,39 +635,42 @@ CTR_Code CanTalonSRX::GetReverseSoftEnable(int & enable) */ CTR_Code CanTalonSRX::SetStatusFrameRate(unsigned frameEnum, unsigned periodMs) { - int32_t status = 0; + CTR_Code retval = CTR_OKAY; + int32_t paramEnum = 0; /* bounds check the period */ if(periodMs < 1) periodMs = 1; else if (periodMs > 255) periodMs = 255; - uint8_t period = (uint8_t)periodMs; - /* tweak just the status messsage rate the caller cares about */ + uint8_t period = (uint8_t)periodMs; + /* lookup the correct param enum based on what frame to rate-change */ switch(frameEnum){ case kStatusFrame_General: - _statusRateMs[0] = period; + paramEnum = eStatus1FrameRate; break; case kStatusFrame_Feedback: - _statusRateMs[1] = period; + paramEnum = eStatus2FrameRate; break; case kStatusFrame_Encoder: - _statusRateMs[2] = period; + paramEnum = eStatus3FrameRate; break; case kStatusFrame_AnalogTempVbat: - _statusRateMs[3] = period; + paramEnum = eStatus4FrameRate; + break; + case kStatusFrame_PulseWidthMeas: + paramEnum = eStatus8FrameRate; + break; + default: + /* caller's request is not support, return an error code */ + retval = CTR_InvalidParamValue; break; } - /* build our request frame */ - TALON_Control_2_Rates_OneShot_t frame; - memset(&frame,0,sizeof(frame)); - frame.Status1Ms = _statusRateMs[0]; - frame.Status2Ms = _statusRateMs[1]; - frame.Status3Ms = _statusRateMs[2]; - frame.Status4Ms = _statusRateMs[3]; - FRC_NetworkCommunication_CANSessionMux_sendMessage(CONTROL_2 | GetDeviceNumber(), (const uint8_t*)&frame, sizeof(frame), 0, &status); - if(status) - return CTR_TxFailed; - return CTR_OKAY; + /* if lookup was succesful, send set-request out */ + if(retval == CTR_OKAY){ + /* paramEnum is updated, sent it out */ + retval = SetParamRaw(paramEnum, period); + } + return retval; } /** * Clear all sticky faults in TALON. @@ -772,6 +838,8 @@ CTR_Code CanTalonSRX::GetSensorPosition(int ¶m) raw |= rx->SensorPositionL; raw <<= (32-24); /* sign extend */ raw >>= (32-24); /* sign extend */ + if(rx->PosDiv8) + raw *= 8; param = (int)raw; return rx.err; } @@ -784,6 +852,8 @@ CTR_Code CanTalonSRX::GetSensorVelocity(int ¶m) raw |= rx->SensorVelocityL; raw <<= (32-16); /* sign extend */ raw >>= (32-16); /* sign extend */ + if(rx->VelDiv4) + raw *= 4; param = (int)raw; return rx.err; } @@ -814,6 +884,8 @@ CTR_Code CanTalonSRX::GetEncPosition(int ¶m) raw |= rx->EncPositionL; raw <<= (32-24); /* sign extend */ raw >>= (32-24); /* sign extend */ + if(rx->PosDiv8) + raw *= 8; param = (int)raw; return rx.err; } @@ -826,6 +898,8 @@ CTR_Code CanTalonSRX::GetEncVel(int ¶m) raw |= rx->EncVelL; raw <<= (32-16); /* sign extend */ raw >>= (32-16); /* sign extend */ + if(rx->VelDiv4) + raw *= 4; param = (int)raw; return rx.err; } @@ -868,6 +942,8 @@ CTR_Code CanTalonSRX::GetAnalogInWithOv(int ¶m) raw |= rx->AnalogInWithOvL; raw <<= (32-24); /* sign extend */ raw >>= (32-24); /* sign extend */ + if(rx->PosDiv8) + raw *= 8; param = (int)raw; return rx.err; } @@ -880,6 +956,8 @@ CTR_Code CanTalonSRX::GetAnalogInVel(int ¶m) raw |= rx->AnalogInVelL; raw <<= (32-16); /* sign extend */ raw >>= (32-16); /* sign extend */ + if(rx->VelDiv4) + raw *= 4; param = (int)raw; return rx.err; } @@ -1018,6 +1096,82 @@ CTR_Code CanTalonSRX::SetRevFeedbackSensor(int param) FlushTx(toFill); return CTR_OKAY; } +CTR_Code CanTalonSRX::GetPulseWidthPosition(int ¶m) +{ + GET_STATUS8(); + int32_t raw = 0; + raw |= rx->PulseWidPositionH; + raw <<= 8; + raw |= rx->PulseWidPositionM; + raw <<= 8; + raw |= rx->PulseWidPositionL; + raw <<= (32-24); /* sign extend */ + raw >>= (32-24); /* sign extend */ + if(rx->PosDiv8) + raw *= 8; + param = (int)raw; + return rx.err; +} +CTR_Code CanTalonSRX::GetPulseWidthVelocity(int ¶m) +{ + GET_STATUS8(); + int32_t raw = 0; + raw |= rx->PulseWidVelH; + raw <<= 8; + raw |= rx->PulseWidVelL; + raw <<= (32-16); /* sign extend */ + raw >>= (32-16); /* sign extend */ + if(rx->VelDiv4) + raw *= 4; + param = (int)raw; + return rx.err; +} +/** + * @param param [out] Rise to rise timeperiod in microseconds. + */ +CTR_Code CanTalonSRX::GetPulseWidthRiseToRiseUs(int ¶m) +{ + GET_STATUS8(); + uint32_t raw = 0; + raw |= rx->PeriodUsM8; + raw <<= 8; + raw |= rx->PeriodUsL8; + param = (int)raw; + return rx.err; +} +/** + * @param param [out] Rise to fall time period in microseconds. + */ +CTR_Code CanTalonSRX::GetPulseWidthRiseToFallUs(int ¶m) +{ + int temp = 0; + int periodUs = 0; + /* first grab our 12.12 position */ + CTR_Code retval1 = GetPulseWidthPosition(temp); + /* mask off number of turns */ + temp &= 0xFFF; + /* next grab the waveform period. This value + * will be zero if we stop getting pulses **/ + CTR_Code retval2 = GetPulseWidthRiseToRiseUs(periodUs); + /* now we have 0.12 position that is scaled to the waveform period. + Use fixed pt multiply to scale our 0.16 period into us.*/ + param = (temp * periodUs) / BIT12; + /* pass the worst error code to caller. + Assume largest value is the most pressing error code.*/ + return (CTR_Code)std::max((int)retval1, (int)retval2); +} +CTR_Code CanTalonSRX::IsPulseWidthSensorPresent(int ¶m) +{ + int periodUs = 0; + CTR_Code retval = GetPulseWidthRiseToRiseUs(periodUs); + /* if a nonzero period is present, we are getting good pules. + Otherwise the sensor is not present. */ + if(periodUs != 0) + param = 1; + else + param = 0; + return retval; +} //------------------ C interface --------------------------------------------// extern "C" { void *c_TalonSRX_Create(int deviceNumber, int controlPeriodMs) diff --git a/wpilibc/wpilibC++Devices/include/CANTalon.h b/wpilibc/wpilibC++Devices/include/CANTalon.h index 498d067709..15ebbe258a 100644 --- a/wpilibc/wpilibC++Devices/include/CANTalon.h +++ b/wpilibc/wpilibC++Devices/include/CANTalon.h @@ -33,13 +33,25 @@ class CANTalon : public MotorSafety, AnalogPot = 2, AnalogEncoder = 3, EncRising = 4, - EncFalling = 5 + EncFalling = 5, + CtreMagEncoder_Relative = 6, //!< Cross The Road Electronics Magnetic Encoder in Absolute/PulseWidth Mode + CtreMagEncoder_Absolute = 7, //!< Cross The Road Electronics Magnetic Encoder in Relative/Quadrature Mode + PulseWidth = 8, + }; + /** + * Depending on the sensor type, Talon can determine if sensor is plugged in ot not. + */ + enum FeedbackDeviceStatus { + FeedbackStatusUnknown = 0, //!< Sensor status could not be determined. Not all sensors can do this. + FeedbackStatusPresent = 1, //!< Sensor is present and working okay. + FeedbackStatusNotPresent = 2, //!< Sensor is not present, not plugged in, not powered, etc... }; enum StatusFrameRate { StatusFrameRateGeneral = 0, StatusFrameRateFeedback = 1, StatusFrameRateQuadEncoder = 2, StatusFrameRateAnalogTempVbat = 3, + StatusFrameRatePulseWidthMeas = 4, }; explicit CANTalon(int deviceNumber); explicit CANTalon(int deviceNumber, int controlPeriodMs); @@ -89,10 +101,13 @@ class CANTalon : public MotorSafety, virtual double GetPosition() const override; virtual double GetSpeed() const override; virtual int GetClosedLoopError() const; + virtual void SetAllowableClosedLoopErr(uint32_t allowableCloseLoopError); virtual int GetAnalogIn() const; + virtual void SetAnalogPosition(int newPosition); virtual int GetAnalogInRaw() const; virtual int GetAnalogInVel() const; virtual int GetEncPosition() const; + virtual void SetEncPosition(int); virtual int GetEncVel() const; int GetPinStateQuadA() const; int GetPinStateQuadB() const; @@ -101,12 +116,19 @@ class CANTalon : public MotorSafety, int IsRevLimitSwitchClosed() const; int GetNumberOfQuadIdxRises() const; void SetNumberOfQuadIdxRises(int rises); + virtual int GetPulseWidthPosition() const; + virtual void SetPulseWidthPosition(int newpos); + virtual int GetPulseWidthVelocity() const; + virtual int GetPulseWidthRiseToFallUs() const; + virtual int GetPulseWidthRiseToRiseUs() const; + virtual FeedbackDeviceStatus IsSensorPresent(FeedbackDevice feedbackDevice)const; virtual bool GetForwardLimitOK() const override; virtual bool GetReverseLimitOK() const override; virtual uint16_t GetFaults() const override; uint16_t GetStickyFaults() const; void ClearStickyFaults(); virtual void SetVoltageRampRate(double rampRate) override; + virtual void SetVoltageCompensationRampRate(double rampRate); virtual uint32_t GetFirmwareVersion() const override; virtual void ConfigNeutralMode(NeutralMode mode) override; virtual void ConfigEncoderCodesPerRev(uint16_t codesPerRev) override; @@ -140,12 +162,26 @@ class CANTalon : public MotorSafety, */ void ConfigRevLimitSwitchNormallyOpen(bool normallyOpen); virtual void ConfigMaxOutputVoltage(double voltage) override; + void ConfigPeakOutputVoltage(double forwardVoltage,double reverseVoltage); + void ConfigNominalOutputVoltage(double forwardVoltage,double reverseVoltage); + /** + * Enables Talon SRX to automatically zero the Sensor Position whenever an + * edge is detected on the index signal. + * @param enable boolean input, pass true to enable feature or false to disable. + * @param risingEdge boolean input, pass true to clear the position on rising edge, + * pass false to clear the position on falling edge. + */ + void EnableZeroSensorPositionOnIndex(bool enable, bool risingEdge); + void ConfigSetParameter(uint32_t paramEnum, double value); + bool GetParameter(uint32_t paramEnum, double & dvalue) const; + virtual void ConfigFaultTime(float faultTime) override; virtual void SetControlMode(ControlMode mode); void SetFeedbackDevice(FeedbackDevice device); void SetStatusFrameRateMs(StatusFrameRate stateFrame, int periodMs); virtual ControlMode GetControlMode() const; void SetSensorDirection(bool reverseSensor); + void SetClosedLoopOutputDirection(bool reverseOutput); void SetCloseLoopRampRate(double rampRate); void SelectProfileSlot(int slotIdx); int GetIzone() const; @@ -194,7 +230,39 @@ class CANTalon : public MotorSafety, TalonControlMode m_sendMode; double m_setPoint = 0; + /** + * Encoder CPR, counts per rotations, also called codes per revoluion. + * Default value of zero means the API behaves as it did during the 2015 season, each position + * unit is a single pulse and there are four pulses per count (4X). + * Caller can use ConfigEncoderCodesPerRev to set the quadrature encoder CPR. + */ + uint32_t m_codesPerRev = 0; + /** + * Number of turns per rotation. For example, a 10-turn pot spins ten full rotations from + * a wiper voltage of zero to 3.3 volts. Therefore knowing the + * number of turns a full voltage sweep represents is necessary for calculating rotations + * and velocity. + * A default value of zero means the API behaves as it did during the 2015 season, there are 1024 + * position units from zero to 3.3V. + */ + uint32_t m_numPotTurns = 0; + /** + * Although the Talon handles feedback selection, caching the feedback selection is helpful at the API level + * for scaling into rotations and RPM. + */ + FeedbackDevice m_feedbackDevice = QuadEncoder; + static const unsigned int kDelayForSolicitedSignalsUs = 4000; + /** + * @param devToLookup FeedbackDevice to lookup the scalar for. Because Talon + * allows multiple sensors to be attached simultaneously, caller must + * specify which sensor to lookup. + * @return The number of native Talon units per rotation of the selected sensor. + * Zero if the necessary sensor information is not available. + * @see ConfigEncoderCodesPerRev + * @see ConfigPotentiometerTurns + */ + double GetNativeUnitsPerRotationScalar(FeedbackDevice devToLookup)const; /** * Fixup the sendMode so Set() serializes the correct demand value. * Also fills the modeSelecet in the control frame to disabled. @@ -202,6 +270,44 @@ class CANTalon : public MotorSafety, * @see Set() */ void ApplyControlMode(CANSpeedController::ControlMode mode); + /** + * @param fullRotations double precision value representing number of rotations of selected feedback sensor. + * If user has never called the config routine for the selected sensor, then the caller + * is likely passing rotations in engineering units already, in which case it is returned + * as is. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * @return fullRotations in native engineering units of the Talon SRX firmware. + */ + int32_t ScaleRotationsToNativeUnits(FeedbackDevice devToLookup, double fullRotations) const; + /** + * @param rpm double precision value representing number of rotations per minute of selected feedback sensor. + * If user has never called the config routine for the selected sensor, then the caller + * is likely passing rotations in engineering units already, in which case it is returned + * as is. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * @return sensor velocity in native engineering units of the Talon SRX firmware. + */ + int32_t ScaleVelocityToNativeUnits(FeedbackDevice devToLookup, double rpm) const; + /** + * @param nativePos integral position of the feedback sensor in native Talon SRX units. + * If user has never called the config routine for the selected sensor, then the return + * will be in TALON SRX units as well to match the behavior in the 2015 season. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * @return double precision number of rotations, unless config was never performed. + */ + double ScaleNativeUnitsToRotations(FeedbackDevice devToLookup, int32_t nativePos) const; + /** + * @param nativeVel integral velocity of the feedback sensor in native Talon SRX units. + * If user has never called the config routine for the selected sensor, then the return + * will be in TALON SRX units as well to match the behavior in the 2015 season. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * @return double precision of sensor velocity in RPM, unless config was never performed. + */ + double ScaleNativeUnitsToRpm(FeedbackDevice devToLookup, int32_t nativeVel) const; // LiveWindow stuff. std::shared_ptr m_table; diff --git a/wpilibc/wpilibC++Devices/src/CANTalon.cpp b/wpilibc/wpilibC++Devices/src/CANTalon.cpp index 466a8b1d93..f9372129d5 100644 --- a/wpilibc/wpilibC++Devices/src/CANTalon.cpp +++ b/wpilibc/wpilibC++Devices/src/CANTalon.cpp @@ -8,6 +8,21 @@ #include "WPIErrors.h" #include // usleep #include +/** + * Number of adc engineering units per 0 to 3.3V sweep. + * This is necessary for scaling Analog Position in rotations/RPM. + */ +const double kNativeAdcUnitsPerRotation = 1024.0; +/** + * Number of pulse width engineering units per full rotation. + * This is necessary for scaling Pulse Width Decoded Position in rotations/RPM. + */ +const double kNativePwdUnitsPerRotation = 4096.0; +/** + * Number of minutes per 100ms unit. Useful for scaling velocities + * measured by Talon's 100ms timebase to rotations per minute. + */ +const double kMinutesPer100msUnit = 1.0/600.0; /** * Constructor for the CANTalon device. @@ -25,20 +40,12 @@ CANTalon::CANTalon(int deviceNumber) * 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. - * Period is bounded to [1ms, - * 95ms]. + * 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) { + m_impl(new CanTalonSRX(deviceNumber,controlPeriodMs)), + m_safetyHelper(new MotorSafetyHelper(this)) { ApplyControlMode(m_controlMode); m_impl->SetProfileSlotSelect(m_profile); } @@ -92,10 +99,10 @@ float CANTalon::Get() const { return GetOutputCurrent(); case kSpeed: m_impl->GetSensorVelocity(value); - return value; + return ScaleNativeUnitsToRpm(m_feedbackDevice, value); case kPosition: m_impl->GetSensorPosition(value); - return value; + return ScaleNativeUnitsToRotations(m_feedbackDevice, value); case kPercentVbus: case kFollower: default: @@ -123,7 +130,7 @@ void CANTalon::Set(float value, uint8_t syncGroup) { /* feed safety helper since caller just updated our output */ m_safetyHelper->Feed(); if (m_controlEnabled) { - m_setPoint = value; + m_setPoint = value; /* cache set point for GetSetpoint() */ CTR_Code status = CTR_OKAY; switch (m_controlMode) { case CANSpeedController::kPercentVbus: { @@ -135,20 +142,24 @@ void CANTalon::Set(float value, uint8_t syncGroup) { } break; case CANSpeedController::kVoltage: { // Voltage is an 8.8 fixed point number. - int volts = int((m_isInverted ? value : -value) * 256); + int volts = int((m_isInverted ? -value : value) * 256); status = m_impl->SetDemand(volts); } break; case CANSpeedController::kSpeed: - status = m_impl->SetDemand(m_isInverted ? -value : value); + /* if the caller has provided scaling info, apply it */ + status = m_impl->SetDemand(ScaleVelocityToNativeUnits(m_feedbackDevice, m_isInverted ? -value : value)); break; case CANSpeedController::kPosition: - status = m_impl->SetDemand(value); + status = m_impl->SetDemand(ScaleRotationsToNativeUnits(m_feedbackDevice, value)); break; - case CANSpeedController::kCurrent: + case CANSpeedController::kCurrent: { + double milliamperes = (m_isInverted ? -value : value) * 1000.0; /* mA*/ + status = m_impl->SetDemand(milliamperes); + } break; default: wpi_setWPIErrorWithContext( IncompatibleMode, - "The CAN Talon does not support Current Mode at this time."); + "The CAN Talon does not support this control mode."); break; } if (status != CTR_OKAY) { @@ -259,7 +270,7 @@ void CANTalon::SetF(double f) { } /** * Set the Izone to a nonzero value to auto clear the integral accumulator - * when the absolute value of CloseLoopError exceeds Izone. + * when the absolute value of CloseLoopError exceeds Izone. * * @see SelectProfileSlot to choose between the two sets of gains. */ @@ -312,8 +323,11 @@ void CANTalon::SetPID(double p, double i, double d, double f) { /** * Select the feedback device to use in closed-loop */ -void CANTalon::SetFeedbackDevice(FeedbackDevice device) { - CTR_Code status = m_impl->SetFeedbackDeviceSelect((int)device); +void CANTalon::SetFeedbackDevice(FeedbackDevice feedbackDevice) { + /* save the selection so that future setters/getters know which scalars to apply */ + m_feedbackDevice = feedbackDevice; + /* pass feedback to actual CAN frame */ + CTR_Code status = m_impl->SetFeedbackDeviceSelect((int)feedbackDevice); if (status != CTR_OKAY) { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } @@ -501,26 +515,31 @@ float CANTalon::GetTemperature() const { * Continuous sensors (like analog encoderes) can also partially be set (the * portion of the postion based on overflows). */ -void CANTalon::SetPosition(double pos) { m_impl->SetSensorPosition(pos); } +void CANTalon::SetPosition(double pos) { + int32_t nativePos = ScaleRotationsToNativeUnits(m_feedbackDevice, pos); + CTR_Code status = m_impl->SetSensorPosition(nativePos); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + } +} /** * TODO documentation (see CANJaguar.cpp) * * @return The position of the sensor currently providing feedback. - * When using analog sensors, 0 units corresponds to 0V, 1023 + * 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 + * 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) + * When using quadrature, each unit is a quadrature edge (4X) * mode. */ double CANTalon::GetPosition() const { - int postition; - - CTR_Code status = m_impl->GetSensorPosition(postition); + int32_t position; + CTR_Code status = m_impl->GetSensorPosition(position); if (status != CTR_OKAY) { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } - return (double)postition; + return ScaleNativeUnitsToRotations(m_feedbackDevice, position); } /** * If sensor and motor are out of phase, sensor can be inverted @@ -533,7 +552,23 @@ void CANTalon::SetSensorDirection(bool reverseSensor) { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } } - +/** + * Flips the sign (multiplies by negative one) the throttle values going into + * the motor on the talon in closed loop modes. Typically the application + * should use SetSensorDirection to keep sensor and motor in phase. + * @see SetSensorDirection + * However this routine is helpful for reversing the motor direction + * when Talon is in slave mode, or when using a single-direction position + * sensor in a closed-loop mode. + * + * @param reverseOutput True if motor output should be flipped; False if not. + */ +void CANTalon::SetClosedLoopOutputDirection(bool reverseOutput) { + CTR_Code status = m_impl->SetRevMotDuringCloseLoopEn(reverseOutput ? 1 : 0); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + } +} /** * Returns the current error in the controller. * @@ -541,12 +576,31 @@ void CANTalon::SetSensorDirection(bool reverseSensor) { */ int CANTalon::GetClosedLoopError() const { int error; + /* retrieve the closed loop error in native units */ CTR_Code status = m_impl->GetCloseLoopErr(error); if (status != CTR_OKAY) { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } return error; } +/** + * Set the allowable closed loop error. + * @param allowableCloseLoopError allowable closed loop error for selected profile. + * mA for Curent closed loop. + * Talon Native Units for position and velocity. + */ +void CANTalon::SetAllowableClosedLoopErr(uint32_t allowableCloseLoopError) +{ + /* grab param enum */ + CanTalonSRX::param_t param; + if (m_profile == 1) { + param = CanTalonSRX::eProfileParamSlot1_AllowableClosedLoopErr; + } else { + param = CanTalonSRX::eProfileParamSlot0_AllowableClosedLoopErr; + } + /* send allowable close loop er in native units */ + ConfigSetParameter(param, allowableCloseLoopError); +} /** * TODO documentation (see CANJaguar.cpp) @@ -556,26 +610,24 @@ int CANTalon::GetClosedLoopError() const { * The speed units will be in the sensor's native ticks per 100ms. * * For analog sensors, 3.3V corresponds to 1023 units. - * So a speed of 200 equates to ~0.645 dV per 100ms or 6.451 dV per + * 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 + * If this is an analog encoder, that likely means 1.9548 rotations * per sec. * For quadrature encoders, each unit corresponds a quadrature edge (4X). - * So a 250 count encoder will produce 1000 edge events per + * 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 + * An example speed of 200 would then equate to 20% of a rotation * per 100ms, - * or 10 rotations per second. + * or 10 rotations per second. */ double CANTalon::GetSpeed() const { - int speed; - // TODO convert from int to appropriate units (or at least document it). - + int32_t speed; CTR_Code status = m_impl->GetSensorVelocity(speed); if (status != CTR_OKAY) { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } - return (double)speed; + return ScaleNativeUnitsToRpm(m_feedbackDevice, speed); } /** @@ -583,10 +635,8 @@ double CANTalon::GetSpeed() const { * whether it is actually being used for feedback. * * @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 + * on the analog pin of the Talon. + * The upper 14 bits tracks the overflows and * underflows (continuous sensor). */ int CANTalon::GetAnalogIn() const { @@ -597,6 +647,13 @@ int CANTalon::GetAnalogIn() const { } return position; } + +void CANTalon::SetAnalogPosition(int newPosition) { + CTR_Code status = m_impl->SetParam(CanTalonSRX::eAinPosition, newPosition); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + } +} /** * Get the position of whatever is in the analog pin of the Talon, regardless of * whether it is actually being used for feedback. @@ -633,6 +690,12 @@ int CANTalon::GetEncPosition() const { } return position; } +void CANTalon::SetEncPosition(int newPosition) { + CTR_Code status = m_impl->SetParam(CanTalonSRX::eEncPosition, newPosition); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + } +} /** * Get the position of whatever is in the analog pin of the Talon, regardless of @@ -648,6 +711,84 @@ int CANTalon::GetEncVel() const { } return vel; } +int CANTalon::GetPulseWidthPosition() const { + int param; + CTR_Code status = m_impl->GetPulseWidthPosition(param); + if (status != CTR_OKAY) + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + return param; +} +void CANTalon::SetPulseWidthPosition(int newPosition) +{ + CTR_Code status = m_impl->SetParam(CanTalonSRX::ePwdPosition, newPosition); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + } +} +int CANTalon::GetPulseWidthVelocity()const +{ + int param; + CTR_Code status = m_impl->GetPulseWidthVelocity(param); + if (status != CTR_OKAY) + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + return param; +} +int CANTalon::GetPulseWidthRiseToFallUs()const +{ + int param; + CTR_Code status = m_impl->GetPulseWidthRiseToFallUs(param); + if (status != CTR_OKAY) + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + return param; +} +int CANTalon::GetPulseWidthRiseToRiseUs()const +{ + int param; + CTR_Code status = m_impl->GetPulseWidthRiseToRiseUs(param); + if (status != CTR_OKAY) + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + return param; +} +/** + * @param which feedback sensor to check it if is connected. + * @return status of caller's specified sensor type. + */ +CANTalon::FeedbackDeviceStatus CANTalon::IsSensorPresent(FeedbackDevice feedbackDevice)const +{ + FeedbackDeviceStatus retval = FeedbackStatusUnknown; + int param; + /* detecting sensor health depends on which sensor caller cares about */ + switch (feedbackDevice) { + case QuadEncoder: + case AnalogPot: + case AnalogEncoder: + case EncRising: + case EncFalling: + /* no real good way to tell if these sensor + are actually present so return status unknown. */ + break; + case PulseWidth: + case CtreMagEncoder_Relative: + case CtreMagEncoder_Absolute: + /* all of these require pulse width signal to be present. */ + CTR_Code status = m_impl->IsPulseWidthSensorPresent(param); + if (status != CTR_OKAY) { + /* we're not getting status info, signal unknown status */ + } else { + /* param is updated */ + if (param) { + /* pulse signal is present, sensor must be working since it always + generates a pulse waveform.*/ + retval = FeedbackStatusPresent; + } else { + /* no pulse present, sensor disconnected */ + retval = FeedbackStatusNotPresent; + } + } + break; + } + return retval; +} /** * @return IO level of QUADA pin. */ @@ -899,6 +1040,15 @@ void CANTalon::SetVoltageRampRate(double rampRate) { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } } +void CANTalon::SetVoltageCompensationRampRate(double rampRate) { + /* when in voltage compensation mode, the voltage compensation rate + directly caps the change in target voltage */ + CTR_Code status = CTR_OKAY; + status = m_impl->SetVoltageCompensationRate(rampRate / 1000); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + } +} /** * Sets a voltage change rate that applies only when a close loop contorl mode * is enabled. @@ -933,8 +1083,8 @@ uint32_t CANTalon::GetFirmwareVersion() const { /* only sent once on boot */ // CTR_Code status = m_impl->GetFirmVers(firmwareVersion); - // if(status != CTR_OKAY) { - // wpi_setErrorWithContext(status, getHALErrorMessage(status)); + // if (status != CTR_OKAY) { + // wpi_setErrorWithContext(status, getHALErrorMessage(status)); //} return firmwareVersion; @@ -1003,19 +1153,31 @@ int CANTalon::GetBrakeEnableDuringNeutral() const { return brakeEn; } /** - * @deprecated not implemented + * Configure how many codes per revolution are generated by your encoder. + * + * @param codesPerRev The number of counts per revolution. */ 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 */ + /* first save the scalar so that all getters/setter work as the user expects */ + m_codesPerRev = codesPerRev; + /* next send the scalar to the Talon over CAN. This is so that the Talon can report + it to whoever needs it, like the webdash. Don't bother checking the return, + this is only for instrumentation and is not necessary for Talon functionality. */ + (void)m_impl->SetParam(CanTalonSRX::eNumberEncoderCPR, m_codesPerRev); } /** - * @deprecated not implemented + * Configure the number of turns on the potentiometer. + * + * @param turns The number of turns of the potentiometer. */ 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 */ + /* first save the scalar so that all getters/setter work as the user expects */ + m_numPotTurns = turns; + /* next send the scalar to the Talon over CAN. This is so that the Talon can report + it to whoever needs it, like the webdash. Don't bother checking the return, + this is only for instrumentation and is not necessary for Talon functionality. */ + (void)m_impl->SetParam(CanTalonSRX::eNumberPotTurns, m_numPotTurns); } /** @@ -1107,7 +1269,8 @@ void CANTalon::ConfigLimitMode(LimitMode mode) { */ void CANTalon::ConfigForwardLimit(double forwardLimitPosition) { CTR_Code status = CTR_OKAY; - status = m_impl->SetForwardSoftLimit(forwardLimitPosition); + int32_t nativeLimitPos = ScaleRotationsToNativeUnits(m_feedbackDevice, forwardLimitPosition); + status = m_impl->SetForwardSoftLimit(nativeLimitPos); if (status != CTR_OKAY) { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } @@ -1153,19 +1316,80 @@ void CANTalon::ConfigRevLimitSwitchNormallyOpen(bool normallyOpen) { */ void CANTalon::ConfigReverseLimit(double reverseLimitPosition) { CTR_Code status = CTR_OKAY; - status = m_impl->SetReverseSoftLimit(reverseLimitPosition); + int32_t nativeLimitPos = ScaleRotationsToNativeUnits(m_feedbackDevice, reverseLimitPosition); + status = m_impl->SetReverseSoftLimit(nativeLimitPos); if (status != CTR_OKAY) { wpi_setErrorWithContext(status, getHALErrorMessage(status)); } } - /** * TODO documentation (see CANJaguar.cpp) */ void CANTalon::ConfigMaxOutputVoltage(double voltage) { - /* SRX does not support max output */ - wpi_setWPIErrorWithContext(IncompatibleMode, - "MaxOutputVoltage not supported."); + /* config peak throttle when in closed-loop mode in the fwd and rev direction. */ + ConfigPeakOutputVoltage(voltage, -voltage); +} +void CANTalon::ConfigPeakOutputVoltage(double forwardVoltage,double reverseVoltage) { + /* bounds checking */ + if (forwardVoltage > 12) + forwardVoltage = 12; + else if (forwardVoltage < 0) + forwardVoltage = 0; + if (reverseVoltage > 0) + reverseVoltage = 0; + else if (reverseVoltage < -12) + reverseVoltage = -12; + /* config calls */ + ConfigSetParameter(CanTalonSRX::ePeakPosOutput, 1023 * forwardVoltage / 12.0); + ConfigSetParameter(CanTalonSRX::ePeakNegOutput, 1023 * reverseVoltage / 12.0); +} +void CANTalon::ConfigNominalOutputVoltage(double forwardVoltage,double reverseVoltage) { + /* bounds checking */ + if (forwardVoltage > 12) + forwardVoltage = 12; + else if (forwardVoltage < 0) + forwardVoltage = 0; + if (reverseVoltage > 0) + reverseVoltage = 0; + else if (reverseVoltage < -12) + reverseVoltage = -12; + /* config calls */ + ConfigSetParameter(CanTalonSRX::eNominalPosOutput,1023*forwardVoltage/12.0); + ConfigSetParameter(CanTalonSRX::eNominalNegOutput,1023*reverseVoltage/12.0); +} +/** + * General set frame. Since the parameter is a general integral type, this can + * be used for testing future features. + */ +void CANTalon::ConfigSetParameter(uint32_t paramEnum, double value) { + CTR_Code status; + /* config peak throttle when in closed-loop mode in the positive direction. */ + status = m_impl->SetParam((CanTalonSRX::param_t)paramEnum,value); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + } +} +/** + * General get frame. Since the parameter is a general integral type, this can + * be used for testing future features. + */ +bool CANTalon::GetParameter(uint32_t paramEnum, double & dvalue) const { + bool retval = true; + /* send the request frame */ + CTR_Code status = m_impl->RequestParam((CanTalonSRX::param_t)paramEnum); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + retval = false; + } + /* small yield for getting response */ + usleep(kDelayForSolicitedSignalsUs); + /* get the last received update */ + status = m_impl->GetParamResponse((CanTalonSRX::param_t)paramEnum, dvalue); + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + retval = false; + } + return retval; } /** @@ -1252,7 +1476,198 @@ void CANTalon::SetSafetyEnabled(bool enabled) { void CANTalon::GetDescription(std::ostringstream& desc) const { desc << "CANTalon ID " << m_deviceNumber; } +/** + * @param devToLookup FeedbackDevice to lookup the scalar for. Because Talon + * allows multiple sensors to be attached simultaneously, caller must + * specify which sensor to lookup. + * @return The number of native Talon units per rotation of the selected sensor. + * Zero if the necessary sensor information is not available. + * @see ConfigEncoderCodesPerRev + * @see ConfigPotentiometerTurns + */ +double CANTalon::GetNativeUnitsPerRotationScalar(FeedbackDevice devToLookup)const +{ + bool scalingAvail = false; + CTR_Code status = CTR_OKAY; + double retval = 0; + switch (devToLookup) { + case QuadEncoder: + { /* When caller wants to lookup Quadrature, the QEI may be in 1x if the selected feedback is edge counter. + * Additionally if the quadrature source is the CTRE Mag encoder, then the CPR is known. + * This is nice in that the calling app does not require knowing the CPR at all. + * So do both checks here. + */ + int32_t qeiPulsePerCount = 4; /* default to 4x */ + switch (m_feedbackDevice) { + case CtreMagEncoder_Relative: + case CtreMagEncoder_Absolute: + /* we assume the quadrature signal comes from the MagEnc, + of which we know the CPR already */ + retval = kNativePwdUnitsPerRotation; + scalingAvail = true; + break; + case EncRising: /* Talon's QEI is setup for 1x, so perform 1x math */ + case EncFalling: + qeiPulsePerCount = 1; + break; + case QuadEncoder: /* Talon's QEI is 4x */ + default: /* pulse width and everything else, assume its regular quad use. */ + break; + } + if (scalingAvail) { + /* already deduced the scalar above, we're done. */ + } else { + /* we couldn't deduce the scalar just based on the selection */ + if (0 == m_codesPerRev) { + /* caller has never set the CPR. Most likely caller + is just using engineering units so fall to the + bottom of this func.*/ + } else { + /* Talon expects PPR units */ + retval = qeiPulsePerCount * m_codesPerRev; + scalingAvail = true; + } + } + } break; + case EncRising: + case EncFalling: + if (0 == m_codesPerRev) { + /* caller has never set the CPR. Most likely caller + is just using engineering units so fall to the + bottom of this func.*/ + } else { + /* Talon expects PPR units */ + retval = 1 * m_codesPerRev; + scalingAvail = true; + } + break; + case AnalogPot: + case AnalogEncoder: + if (0 == m_numPotTurns) { + /* caller has never set the CPR. Most likely caller + is just using engineering units so fall to the + bottom of this func.*/ + } else { + retval = (double)kNativeAdcUnitsPerRotation / m_numPotTurns; + scalingAvail = true; + } + break; + case CtreMagEncoder_Relative: + case CtreMagEncoder_Absolute: + case PulseWidth: + retval = kNativePwdUnitsPerRotation; + scalingAvail = true; + break; + } + /* handle any detected errors */ + if (status != CTR_OKAY) { + wpi_setErrorWithContext(status, getHALErrorMessage(status)); + } + /* if scaling information is not possible, signal caller + by returning zero */ + if (false == scalingAvail) + retval = 0; + return retval; +} +/** + * @param fullRotations double precision value representing number of rotations of selected feedback sensor. + * If user has never called the config routine for the selected sensor, then the caller + * is likely passing rotations in engineering units already, in which case it is returned + * as is. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * @return fullRotations in native engineering units of the Talon SRX firmware. + */ +int32_t CANTalon::ScaleRotationsToNativeUnits(FeedbackDevice devToLookup,double fullRotations)const +{ + /* first assume we don't have config info, prep the default return */ + int32_t retval = (int32_t)fullRotations; + /* retrieve scaling info */ + double scalar = GetNativeUnitsPerRotationScalar(devToLookup); + /* apply scalar if its available */ + if (scalar > 0) + retval = (int32_t)(fullRotations*scalar); + return retval; +} +/** + * @param rpm double precision value representing number of rotations per minute of selected feedback sensor. + * If user has never called the config routine for the selected sensor, then the caller + * is likely passing rotations in engineering units already, in which case it is returned + * as is. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * @return sensor velocity in native engineering units of the Talon SRX firmware. + */ +int32_t CANTalon::ScaleVelocityToNativeUnits(FeedbackDevice devToLookup,double rpm)const +{ + /* first assume we don't have config info, prep the default return */ + int32_t retval = (int32_t)rpm; + /* retrieve scaling info */ + double scalar = GetNativeUnitsPerRotationScalar(devToLookup); + /* apply scalar if its available */ + if (scalar > 0) + retval = (int32_t)(rpm * kMinutesPer100msUnit * scalar); + return retval; +} +/** + * @param nativePos integral position of the feedback sensor in native Talon SRX units. + * If user has never called the config routine for the selected sensor, then the return + * will be in TALON SRX units as well to match the behavior in the 2015 season. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * @return double precision number of rotations, unless config was never performed. + */ +double CANTalon::ScaleNativeUnitsToRotations(FeedbackDevice devToLookup,int32_t nativePos)const +{ + /* first assume we don't have config info, prep the default return */ + double retval = (double)nativePos; + /* retrieve scaling info */ + double scalar = GetNativeUnitsPerRotationScalar(devToLookup); + /* apply scalar if its available */ + if (scalar > 0) + retval = ((double)nativePos) / scalar; + return retval; +} +/** + * @param nativeVel integral velocity of the feedback sensor in native Talon SRX units. + * If user has never called the config routine for the selected sensor, then the return + * will be in TALON SRX units as well to match the behavior in the 2015 season. + * @see ConfigPotentiometerTurns + * @see ConfigEncoderCodesPerRev + * @return double precision of sensor velocity in RPM, unless config was never performed. + */ +double CANTalon::ScaleNativeUnitsToRpm(FeedbackDevice devToLookup, int32_t nativeVel)const +{ + /* first assume we don't have config info, prep the default return */ + double retval = (double)nativeVel; + /* retrieve scaling info */ + double scalar = GetNativeUnitsPerRotationScalar(devToLookup); + /* apply scalar if its available */ + if (scalar > 0) + retval = (double)(nativeVel) / (scalar*kMinutesPer100msUnit); + return retval; +} +/** + * Enables Talon SRX to automatically zero the Sensor Position whenever an + * edge is detected on the index signal. + * @param enable boolean input, pass true to enable feature or false to disable. + * @param risingEdge boolean input, pass true to clear the position on rising edge, + * pass false to clear the position on falling edge. + */ +void CANTalon::EnableZeroSensorPositionOnIndex(bool enable, bool risingEdge) +{ + if (enable) { + /* enable the feature, update the edge polarity first to ensure + it is correct before the feature is enabled. */ + ConfigSetParameter(CanTalonSRX::eQuadIdxPolarity,risingEdge ? 1 : 0); + ConfigSetParameter(CanTalonSRX::eClearPositionOnIdx,1); + } else { + /* disable the feature first, then update the edge polarity. */ + ConfigSetParameter(CanTalonSRX::eClearPositionOnIdx,0); + ConfigSetParameter(CanTalonSRX::eQuadIdxPolarity,risingEdge ? 1 : 0); + } +} /** * Common interface for inverting direction of a speed controller. * Only works in PercentVbus, speed, and Voltage modes. diff --git a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CANTalon.java b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CANTalon.java index 689f3ca8e3..d03fd7fd40 100644 --- a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CANTalon.java +++ b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CANTalon.java @@ -14,6 +14,21 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont private MotorSafetyHelper m_safetyHelper; private boolean isInverted = false; protected PIDSourceType m_pidSource = PIDSourceType.kDisplacement; + /** + * Number of adc engineering units per 0 to 3.3V sweep. + * This is necessary for scaling Analog Position in rotations/RPM. + */ + private final int kNativeAdcUnitsPerRotation = 1024; + /** + * Number of pulse width engineering units per full rotation. + * This is necessary for scaling Pulse Width Decoded Position in rotations/RPM. + */ + private final double kNativePwdUnitsPerRotation = 4096.0; + /** + * Number of minutes per 100ms unit. Useful for scaling velocities + * measured by Talon's 100ms timebase to rotations per minute. + */ + private final double kMinutesPer100msUnit = 1.0/600.0; public enum TalonControlMode implements CANSpeedController.ControlMode { PercentVbus(0), Position(1), Speed(2), Current(3), Voltage(4), Follower(5), Disabled(15); @@ -44,9 +59,8 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont return value; } } - public enum FeedbackDevice { - QuadEncoder(0), AnalogPot(2), AnalogEncoder(3), EncRising(4), EncFalling(5); + QuadEncoder(0), AnalogPot(2), AnalogEncoder(3), EncRising(4), EncFalling(5), CtreMagEncoder_Relative(6), CtreMagEncoder_Absolute(7), PulseWidth(8); public int value; @@ -64,9 +78,27 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont this.value = value; } } + /** + * Depending on the sensor type, Talon can determine if sensor is plugged in ot not. + */ + public enum FeedbackDeviceStatus { + FeedbackStatusUnknown(0), FeedbackStatusPresent(1), FeedbackStatusNotPresent(2); + public int value; + public static FeedbackDeviceStatus valueOf(int value) { + for (FeedbackDeviceStatus mode : values()) { + if (mode.value == value) { + return mode; + } + } + return null; + } + private FeedbackDeviceStatus(int value) { + this.value = value; + } + } /** enumerated types for frame rate ms */ public enum StatusFrameRate { - General(0), Feedback(1), QuadEncoder(2), AnalogTempVbat(3); + General(0), Feedback(1), QuadEncoder(2), AnalogTempVbat(3), PulseWidth(4); public int value; public static StatusFrameRate valueOf(int value) { @@ -95,6 +127,27 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont int m_profile; double m_setPoint; + /** + * Encoder CPR, counts per rotations, also called codes per revoluion. + * Default value of zero means the API behaves as it did during the 2015 season, each position + * unit is a single pulse and there are four pulses per count (4X). + * Caller can use configEncoderCodesPerRev to set the quadrature encoder CPR. + */ + int m_codesPerRev; + /** + * Number of turns per rotation. For example, a 10-turn pot spins ten full rotations from + * a wiper voltage of zero to 3.3 volts. Therefore knowing the + * number of turns a full voltage sweep represents is necessary for calculating rotations + * and velocity. + * A default value of zero means the API behaves as it did during the 2015 season, there are 1024 + * position units from zero to 3.3V. + */ + int m_numPotTurns; + /** + * Although the Talon handles feedback selection, caching the feedback selection is helpful at the API level + * for scaling into rotations and RPM. + */ + FeedbackDevice m_feedbackDevice; public CANTalon(int deviceNumber) { m_deviceNumber = deviceNumber; @@ -103,6 +156,9 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont m_controlEnabled = true; m_profile = 0; m_setPoint = 0; + m_codesPerRev = 0; + m_numPotTurns = 0; + m_feedbackDevice = FeedbackDevice.QuadEncoder; setProfile(m_profile); applyControlMode(TalonControlMode.PercentVbus); } @@ -118,6 +174,9 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont m_controlEnabled = true; m_profile = 0; m_setPoint = 0; + m_codesPerRev = 0; + m_numPotTurns = 0; + m_feedbackDevice = FeedbackDevice.QuadEncoder; setProfile(m_profile); applyControlMode(TalonControlMode.PercentVbus); } @@ -171,7 +230,7 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont /* feed safety helper since caller just updated our output */ m_safetyHelper.feed(); if (m_controlEnabled) { - m_setPoint = outputValue; + m_setPoint = outputValue; /* cache set point for getSetpoint() */ switch (m_controlMode) { case PercentVbus: m_impl.Set(isInverted ? -outputValue : outputValue); @@ -185,10 +244,14 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont m_impl.SetDemand(volts); break; case Speed: - m_impl.SetDemand((int) (isInverted ? -outputValue : outputValue)); + m_impl.SetDemand(ScaleVelocityToNativeUnits(m_feedbackDevice,(isInverted ? -outputValue : outputValue))); break; case Position: - m_impl.SetDemand((int) outputValue); + m_impl.SetDemand(ScaleRotationsToNativeUnits(m_feedbackDevice,outputValue)); + break; + case Current: + double milliamperes = (isInverted ? -outputValue : outputValue) * 1000.0; /* mA*/ + m_impl.SetDemand((int)milliamperes); break; default: break; @@ -303,24 +366,31 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont * @return The current sensor value of the Talon. */ public double get() { + double retval = 0; long valuep = CanTalonJNI.new_intp(); SWIGTYPE_p_int swigp = new SWIGTYPE_p_int(valuep, true); switch (m_controlMode) { case Voltage: - return getOutputVoltage(); + retval = getOutputVoltage(); + break; case Current: - return getOutputCurrent(); + retval = getOutputCurrent(); + break; case Speed: m_impl.GetSensorVelocity(swigp); - return (double) CanTalonJNI.intp_value(valuep); + retval = ScaleNativeUnitsToRpm(m_feedbackDevice,CanTalonJNI.intp_value(valuep)); + break; case Position: m_impl.GetSensorPosition(swigp); - return (double) CanTalonJNI.intp_value(valuep); + retval = ScaleNativeUnitsToRotations(m_feedbackDevice,CanTalonJNI.intp_value(valuep)); + break; case PercentVbus: default: m_impl.GetAppliedThrottle(swigp); - return (double) CanTalonJNI.intp_value(valuep) / 1023.0; + retval = (double) CanTalonJNI.intp_value(valuep) / 1023.0; + break; } + return retval; } /** @@ -336,6 +406,10 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont return CanTalonJNI.intp_value(valuep); } + public void setEncPosition(int newPosition) { + setParameter(CanTalonSRX.param_t.eEncPosition, newPosition); + } + /** * Get the current encoder velocity, regardless of whether it is the current * feedback device. @@ -348,7 +422,68 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont m_impl.GetEncVel(swigp); return CanTalonJNI.intp_value(valuep); } - + public int getPulseWidthPosition() { + long valuep = CanTalonJNI.new_intp(); + SWIGTYPE_p_int swigp = new SWIGTYPE_p_int(valuep, true); + m_impl.GetPulseWidthPosition(swigp); + return CanTalonJNI.intp_value(valuep); + } + public void setPulseWidthPosition(int newPosition) { + setParameter(CanTalonSRX.param_t.ePwdPosition, newPosition); + } + public int getPulseWidthVelocity() { + long valuep = CanTalonJNI.new_intp(); + SWIGTYPE_p_int swigp = new SWIGTYPE_p_int(valuep, true); + m_impl.GetPulseWidthVelocity(swigp); + return CanTalonJNI.intp_value(valuep); + } + public int getPulseWidthRiseToFallUs() { + long valuep = CanTalonJNI.new_intp(); + SWIGTYPE_p_int swigp = new SWIGTYPE_p_int(valuep, true); + m_impl.GetPulseWidthRiseToFallUs(swigp); + return CanTalonJNI.intp_value(valuep); + } + public int getPulseWidthRiseToRiseUs() { + long valuep = CanTalonJNI.new_intp(); + SWIGTYPE_p_int swigp = new SWIGTYPE_p_int(valuep, true); + m_impl.GetPulseWidthRiseToRiseUs(swigp); + return CanTalonJNI.intp_value(valuep); + } + /** + * @param which feedback sensor to check it if is connected. + * @return status of caller's specified sensor type. + */ + public FeedbackDeviceStatus isSensorPresent(FeedbackDevice feedbackDevice) { + FeedbackDeviceStatus retval = FeedbackDeviceStatus.FeedbackStatusUnknown; + /* detecting sensor health depends on which sensor caller cares about */ + switch(feedbackDevice){ + case QuadEncoder: + case AnalogPot: + case AnalogEncoder: + case EncRising: + case EncFalling: + /* no real good way to tell if these sensor + are actually present so return status unknown. */ + break; + case PulseWidth: + case CtreMagEncoder_Relative: + case CtreMagEncoder_Absolute: + /* all of these require pulse width signal to be present. */ + long valuep = CanTalonJNI.new_intp(); + SWIGTYPE_p_int swigp = new SWIGTYPE_p_int(valuep, true); + SWIGTYPE_p_CTR_Code status = m_impl.IsPulseWidthSensorPresent(swigp); + /* TODO: add a check for CanTalonJNI.CTR_Codep_value(status) */ + if( CanTalonJNI.intp_value(valuep) == 0 ){ + /* Talon not getting a signal */ + retval = FeedbackDeviceStatus.FeedbackStatusNotPresent; + }else{ + /* getting good signal */ + retval = FeedbackDeviceStatus.FeedbackStatusPresent; + } + break; + } + return retval; + } /** * Get the number of of rising edges seen on the index pin. * @@ -391,6 +526,9 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont return CanTalonJNI.intp_value(valuep); } + public void setAnalogPosition(int newPosition){ + setParameter(CanTalonSRX.param_t.eAinPosition, (double)newPosition); + } /** * Get the current analog in position, regardless of whether it is the current * feedback device. @@ -436,10 +574,25 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont */ public int getClosedLoopError() { long valuep = CanTalonJNI.new_intp(); + /* retrieve the closed loop error in native units */ SWIGTYPE_p_int swigp = new SWIGTYPE_p_int(valuep, true); m_impl.GetCloseLoopErr(swigp); return CanTalonJNI.intp_value(valuep); } + /** + * Set the allowable closed loop error. + * @param allowableCloseLoopError allowable closed loop error for selected profile. + * mA for Curent closed loop. + * Talon Native Units for position and velocity. + */ + public void setAllowableClosedLoopErr(int allowableCloseLoopError) + { + if(m_profile == 0){ + setParameter(CanTalonSRX.param_t.eProfileParamSlot0_AllowableClosedLoopErr, (double)allowableCloseLoopError); + }else{ + setParameter(CanTalonSRX.param_t.eProfileParamSlot1_AllowableClosedLoopErr, (double)allowableCloseLoopError); + } + } // Returns true if limit switch is closed. false if open. public boolean isFwdLimitSwitchClosed() { @@ -465,6 +618,32 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont return (CanTalonJNI.intp_value(valuep) == 0) ? false : true; } + /** + * Configure how many codes per revolution are generated by your encoder. + * + * @param codesPerRev The number of counts per revolution. + */ + public void configEncoderCodesPerRev(int codesPerRev) { + /* first save the scalar so that all getters/setter work as the user expects */ + m_codesPerRev = codesPerRev; + /* next send the scalar to the Talon over CAN. This is so that the Talon can report + it to whoever needs it, like the webdash. Don't bother checking the return, + this is only for instrumentation and is not necessary for Talon functionality. */ + setParameter(CanTalonSRX.param_t.eNumberEncoderCPR, m_codesPerRev); + } + /** + * Configure the number of turns on the potentiometer. + * + * @param turns The number of turns of the potentiometer. + */ + public void configPotentiometerTurns(int turns) { + /* first save the scalar so that all getters/setter work as the user expects */ + m_numPotTurns = turns; + /* next send the scalar to the Talon over CAN. This is so that the Talon can report + it to whoever needs it, like the webdash. Don't bother checking the return, + this is only for instrumentation and is not necessary for Talon functionality. */ + setParameter(CanTalonSRX.param_t.eNumberPotTurns, m_numPotTurns); + } /** * Returns temperature of Talon, in degrees Celsius. */ @@ -521,11 +700,12 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont public double getPosition() { long positionp = CanTalonJNI.new_intp(); m_impl.GetSensorPosition(new SWIGTYPE_p_int(positionp, true)); - return CanTalonJNI.intp_value(positionp); + return ScaleNativeUnitsToRotations(m_feedbackDevice,CanTalonJNI.intp_value(positionp)); } public void setPosition(double pos) { - m_impl.SetSensorPosition((int) pos); + int nativePos = ScaleRotationsToNativeUnits(m_feedbackDevice,pos); + m_impl.SetSensorPosition(nativePos); } /** @@ -546,7 +726,7 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont public double getSpeed() { long speedp = CanTalonJNI.new_intp(); m_impl.GetSensorVelocity(new SWIGTYPE_p_int(speedp, true)); - return CanTalonJNI.intp_value(speedp); + return ScaleNativeUnitsToRpm(m_feedbackDevice,CanTalonJNI.intp_value(speedp)); } public TalonControlMode getControlMode() { @@ -586,6 +766,9 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont } public void setFeedbackDevice(FeedbackDevice device) { + /* save the selection so that future setters/getters know which scalars to apply */ + m_feedbackDevice = device; + /* pass feedback to actual CAN frame */ m_impl.SetFeedbackDeviceSelect(device.value); } @@ -864,6 +1047,9 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont m_impl.SetRampThrottle(rate); } + public void setVoltageCompensationRampRate(double rampRate) { + m_impl.SetVoltageCompensationRate(rampRate / 1000); + } /** * Clear the accumulator for I gain. */ @@ -948,8 +1134,9 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont SWIGTYPE_p_CTR_Code status = m_impl.SetParam(CanTalonSRX.param_t.ePidIaccum, 0); } - public void setForwardSoftLimit(int forwardLimit) { - m_impl.SetForwardSoftLimit(forwardLimit); + public void setForwardSoftLimit(double forwardLimit) { + int nativeLimitPos = ScaleRotationsToNativeUnits(m_feedbackDevice,forwardLimit); + m_impl.SetForwardSoftLimit(nativeLimitPos); } public int getForwardSoftLimit() { @@ -968,8 +1155,9 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont return (CanTalonJNI.intp_value(valuep) == 0) ? false : true; } - public void setReverseSoftLimit(int reverseLimit) { - m_impl.SetReverseSoftLimit(reverseLimit); + public void setReverseSoftLimit(double reverseLimit) { + int nativeLimitPos = ScaleRotationsToNativeUnits(m_feedbackDevice,reverseLimit); + m_impl.SetReverseSoftLimit(nativeLimitPos); } public int getReverseSoftLimit() { @@ -987,7 +1175,70 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont m_impl.GetReverseSoftEnable(new SWIGTYPE_p_int(valuep, true)); return (CanTalonJNI.intp_value(valuep) == 0) ? false : true; } + /** + * Configure the maximum voltage that the Jaguar will ever output. + * + * This can be used to limit the maximum output voltage in all modes so that + * motors which cannot withstand full bus voltage can be used safely. + * + * @param voltage The maximum voltage output by the Jaguar. + */ + public void configMaxOutputVoltage(double voltage) { + /* config peak throttle when in closed-loop mode in the fwd and rev direction. */ + configPeakOutputVoltage(voltage, -voltage); + } + public void configPeakOutputVoltage(double forwardVoltage,double reverseVoltage) { + /* bounds checking */ + if(forwardVoltage > 12) + forwardVoltage = 12; + else if(forwardVoltage < 0) + forwardVoltage = 0; + if(reverseVoltage > 0) + reverseVoltage = 0; + else if(reverseVoltage < -12) + reverseVoltage = -12; + /* config calls */ + setParameter(CanTalonSRX.param_t.ePeakPosOutput,1023*forwardVoltage/12.0); + setParameter(CanTalonSRX.param_t.ePeakNegOutput,1023*reverseVoltage/12.0); + } + public void configNominalOutputVoltage(double forwardVoltage,double reverseVoltage) { + /* bounds checking */ + if(forwardVoltage > 12) + forwardVoltage = 12; + else if(forwardVoltage < 0) + forwardVoltage = 0; + if(reverseVoltage > 0) + reverseVoltage = 0; + else if(reverseVoltage < -12) + reverseVoltage = -12; + /* config calls */ + setParameter(CanTalonSRX.param_t.eNominalPosOutput,1023*forwardVoltage/12.0); + setParameter(CanTalonSRX.param_t.eNominalNegOutput,1023*reverseVoltage/12.0); + } + /** + * General set frame. Since the parameter is a general integral type, this can + * be used for testing future features. + */ + public void setParameter(CanTalonSRX.param_t paramEnum, double value){ + SWIGTYPE_p_CTR_Code status = m_impl.SetParam(paramEnum,value); + /* TODO: error report to driver station */ + } + /** + * General get frame. Since the parameter is a general integral type, this can + * be used for testing future features. + */ + public double getParameter(CanTalonSRX.param_t paramEnum) { + /* transmit a request for this param */ + m_impl.RequestParam(paramEnum); + /* Briefly wait for new values from the Talon. */ + Timer.delay(kDelayForSolicitedSignals); + /* poll out latest response value */ + long pp = CanTalonJNI.new_doublep(); + SWIGTYPE_p_CTR_Code status = m_impl.GetParamResponse(paramEnum, new SWIGTYPE_p_double(pp, true)); + /* pass latest value back to caller */ + return CanTalonJNI.doublep_value(pp); + } public void clearStickyFaults() { m_impl.ClearStickyFaults(); } @@ -1110,8 +1361,186 @@ public class CANTalon implements MotorSafety, PIDOutput, PIDSource, CANSpeedCont m_impl.GetStckyFault_RevSoftLim(new SWIGTYPE_p_int(valuep, true)); return CanTalonJNI.intp_value(valuep); } + /** + * @return Number of native units per rotation if scaling info is available. + * Zero if scaling information is not available. + */ + double GetNativeUnitsPerRotationScalar(FeedbackDevice devToLookup) + { + double retval = 0; + boolean scalingAvail = false; + switch(devToLookup){ + case QuadEncoder: + { /* When caller wants to lookup Quadrature, the QEI may be in 1x if the selected feedback is edge counter. + * Additionally if the quadrature source is the CTRE Mag encoder, then the CPR is known. + * This is nice in that the calling app does not require knowing the CPR at all. + * So do both checks here. + */ + int qeiPulsePerCount = 4; /* default to 4x */ + switch(m_feedbackDevice){ + case CtreMagEncoder_Relative: + case CtreMagEncoder_Absolute: + /* we assume the quadrature signal comes from the MagEnc, + of which we know the CPR already */ + retval = kNativePwdUnitsPerRotation; + scalingAvail = true; + break; + case EncRising: /* Talon's QEI is setup for 1x, so perform 1x math */ + case EncFalling: + qeiPulsePerCount = 1; + break; + case QuadEncoder: /* Talon's QEI is 4x */ + default: /* pulse width and everything else, assume its regular quad use. */ + break; + } + if(scalingAvail){ + /* already deduced the scalar above, we're done. */ + }else{ + /* we couldn't deduce the scalar just based on the selection */ + if(0 == m_codesPerRev){ + /* caller has never set the CPR. Most likely caller + is just using engineering units so fall to the + bottom of this func.*/ + }else{ + /* Talon expects PPR units */ + retval = 4 * m_codesPerRev; + scalingAvail = true; + } + } + } break; + case EncRising: + case EncFalling: + if(0 == m_codesPerRev){ + /* caller has never set the CPR. Most likely caller + is just using engineering units so fall to the + bottom of this func.*/ + }else{ + /* Talon expects PPR units */ + retval = 1 * m_codesPerRev; + scalingAvail = true; + } + break; + case AnalogPot: + case AnalogEncoder: + if(0 == m_numPotTurns){ + /* caller has never set the CPR. Most likely caller + is just using engineering units so fall to the + bottom of this func.*/ + }else { + retval = (double)kNativeAdcUnitsPerRotation / m_numPotTurns; + scalingAvail = true; + } + break; + case CtreMagEncoder_Relative: + case CtreMagEncoder_Absolute: + case PulseWidth: + retval = kNativePwdUnitsPerRotation; + scalingAvail = true; + break; + } + /* if scaling info is not available give caller zero */ + if(false == scalingAvail) + return 0; + return retval; + } + /** + * @param fullRotations double precision value representing number of rotations of selected feedback sensor. + * If user has never called the config routine for the selected sensor, then the caller + * is likely passing rotations in engineering units already, in which case it is returned + * as is. + * @see configPotentiometerTurns + * @see configEncoderCodesPerRev + * @return fullRotations in native engineering units of the Talon SRX firmware. + */ + int ScaleRotationsToNativeUnits(FeedbackDevice devToLookup, double fullRotations) + { + /* first assume we don't have config info, prep the default return */ + int retval = (int)fullRotations; + /* retrieve scaling info */ + double scalar = GetNativeUnitsPerRotationScalar(devToLookup); + /* apply scalar if its available */ + if(scalar > 0) + retval = (int)(fullRotations*scalar); + return retval; + } + /** + * @param rpm double precision value representing number of rotations per minute of selected feedback sensor. + * If user has never called the config routine for the selected sensor, then the caller + * is likely passing rotations in engineering units already, in which case it is returned + * as is. + * @see configPotentiometerTurns + * @see configEncoderCodesPerRev + * @return sensor velocity in native engineering units of the Talon SRX firmware. + */ + int ScaleVelocityToNativeUnits(FeedbackDevice devToLookup, double rpm) + { + /* first assume we don't have config info, prep the default return */ + int retval = (int)rpm; + /* retrieve scaling info */ + double scalar = GetNativeUnitsPerRotationScalar(devToLookup); + /* apply scalar if its available */ + if(scalar > 0) + retval = (int)(rpm * kMinutesPer100msUnit * scalar); + return retval; + } + /** + * @param nativePos integral position of the feedback sensor in native Talon SRX units. + * If user has never called the config routine for the selected sensor, then the return + * will be in TALON SRX units as well to match the behavior in the 2015 season. + * @see configPotentiometerTurns + * @see configEncoderCodesPerRev + * @return double precision number of rotations, unless config was never performed. + */ + double ScaleNativeUnitsToRotations(FeedbackDevice devToLookup, int nativePos) + { + /* first assume we don't have config info, prep the default return */ + double retval = (double)nativePos; + /* retrieve scaling info */ + double scalar = GetNativeUnitsPerRotationScalar(devToLookup); + /* apply scalar if its available */ + if(scalar > 0) + retval = ((double)nativePos) / scalar; + return retval; + } + /** + * @param nativeVel integral velocity of the feedback sensor in native Talon SRX units. + * If user has never called the config routine for the selected sensor, then the return + * will be in TALON SRX units as well to match the behavior in the 2015 season. + * @see configPotentiometerTurns + * @see configEncoderCodesPerRev + * @return double precision of sensor velocity in RPM, unless config was never performed. + */ + double ScaleNativeUnitsToRpm(FeedbackDevice devToLookup, long nativeVel) + { + /* first assume we don't have config info, prep the default return */ + double retval = (double)nativeVel; + /* retrieve scaling info */ + double scalar = GetNativeUnitsPerRotationScalar(devToLookup); + /* apply scalar if its available */ + if(scalar > 0) + retval = (double)(nativeVel) / (scalar*kMinutesPer100msUnit); + return retval; + } - + /** + * Enables Talon SRX to automatically zero the Sensor Position whenever an + * edge is detected on the index signal. + * @param enable boolean input, pass true to enable feature or false to disable. + * @param risingEdge boolean input, pass true to clear the position on rising edge, + * pass false to clear the position on falling edge. + */ + public void enableZeroSensorPositionOnIndex(boolean enable, boolean risingEdge) { + if(enable){ + /* enable the feature, update the edge polarity first to ensure + it is correct before the feature is enabled. */ + setParameter(CanTalonSRX.param_t.eQuadIdxPolarity,risingEdge ? 1 : 0); + setParameter(CanTalonSRX.param_t.eClearPositionOnIdx,1); + }else{ + /* disable the feature first, then update the edge polarity. */ + setParameter(CanTalonSRX.param_t.eClearPositionOnIdx,0); + setParameter(CanTalonSRX.param_t.eQuadIdxPolarity,risingEdge ? 1 : 0); + } + } @Override public void setExpiration(double timeout) { m_safetyHelper.setExpiration(timeout); diff --git a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CanTalonSRX.java b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CanTalonSRX.java index 9f303536cb..078d0d17f9 100644 --- a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CanTalonSRX.java +++ b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/CanTalonSRX.java @@ -104,9 +104,12 @@ public class CanTalonSRX extends CtreCanNode { slotIdx, closeLoopRampRate), true); } + public SWIGTYPE_p_CTR_Code SetVoltageCompensationRate(double vpers) { + return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_SetVoltageCompensationRate(swigCPtr, this,vpers), true); + } + public SWIGTYPE_p_CTR_Code SetSensorPosition(int pos) { - return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_SetSensorPosition(swigCPtr, this, pos), - true); + return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_SetSensorPosition(swigCPtr, this, pos),true); } public SWIGTYPE_p_CTR_Code SetForwardSoftLimit(int forwardLimit) { @@ -159,6 +162,11 @@ public class CanTalonSRX extends CtreCanNode { slotIdx, SWIGTYPE_p_int.getCPtr(closeLoopRampRate)), true); } + public SWIGTYPE_p_CTR_Code GetVoltageCompensationRate(SWIGTYPE_p_double vpers) { + return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_GetVoltageCompensationRate(swigCPtr, this, + SWIGTYPE_p_double.getCPtr(vpers)), true); + } + public SWIGTYPE_p_CTR_Code GetForwardSoftLimit(SWIGTYPE_p_int forwardLimit) { return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_GetForwardSoftLimit(swigCPtr, this, SWIGTYPE_p_int.getCPtr(forwardLimit)), true); @@ -417,6 +425,27 @@ public class CanTalonSRX extends CtreCanNode { param), true); } + public SWIGTYPE_p_CTR_Code GetPulseWidthPosition(SWIGTYPE_p_int param) { + return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_GetPulseWidthPosition(swigCPtr, this, + SWIGTYPE_p_int.getCPtr(param)), true); + } + public SWIGTYPE_p_CTR_Code GetPulseWidthVelocity(SWIGTYPE_p_int param) { + return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_GetPulseWidthVelocity(swigCPtr, this, + SWIGTYPE_p_int.getCPtr(param)), true); + } + public SWIGTYPE_p_CTR_Code GetPulseWidthRiseToFallUs(SWIGTYPE_p_int param) { + return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_GetPulseWidthRiseToFallUs(swigCPtr, this, + SWIGTYPE_p_int.getCPtr(param)), true); + } + public SWIGTYPE_p_CTR_Code GetPulseWidthRiseToRiseUs(SWIGTYPE_p_int param) { + return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_GetPulseWidthRiseToRiseUs(swigCPtr, this, + SWIGTYPE_p_int.getCPtr(param)), true); + } + public SWIGTYPE_p_CTR_Code IsPulseWidthSensorPresent(SWIGTYPE_p_int param) { + return new SWIGTYPE_p_CTR_Code(CanTalonJNI.CanTalonSRX_IsPulseWidthSensorPresent(swigCPtr, this, + SWIGTYPE_p_int.getCPtr(param)), true); + } + public final static int kDefaultControlPeriodMs = CanTalonJNI .CanTalonSRX_kDefaultControlPeriodMs_get(); public final static int kMode_DutyCycle = CanTalonJNI.CanTalonSRX_kMode_DutyCycle_get(); @@ -467,6 +496,8 @@ public class CanTalonSRX extends CtreCanNode { public final static int kStatusFrame_Encoder = CanTalonJNI.CanTalonSRX_kStatusFrame_Encoder_get(); public final static int kStatusFrame_AnalogTempVbat = CanTalonJNI .CanTalonSRX_kStatusFrame_AnalogTempVbat_get(); + public final static int kStatusFrame_PulseWidthMeas = CanTalonJNI + .CanTalonSRX_kStatusFrame_PulseWidthMeas_get(); public final static class param_t { public final static CanTalonSRX.param_t eProfileParamSlot0_P = new CanTalonSRX.param_t( @@ -610,6 +641,49 @@ public class CanTalonSRX extends CtreCanNode { public final static CanTalonSRX.param_t ePidIaccum = new CanTalonSRX.param_t("ePidIaccum", CanTalonJNI.CanTalonSRX_ePidIaccum_get()); + public final static CanTalonSRX.param_t eStatus1FrameRate = new CanTalonSRX.param_t("eStatus1FrameRate", + CanTalonJNI.CanTalonSRX_eStatus1FrameRate_get()); + public final static CanTalonSRX.param_t eStatus2FrameRate = new CanTalonSRX.param_t("eStatus2FrameRate", + CanTalonJNI.CanTalonSRX_eStatus2FrameRate_get()); + public final static CanTalonSRX.param_t eStatus3FrameRate = new CanTalonSRX.param_t("eStatus3FrameRate", + CanTalonJNI.CanTalonSRX_eStatus3FrameRate_get()); + public final static CanTalonSRX.param_t eStatus4FrameRate = new CanTalonSRX.param_t("eStatus4FrameRate", + CanTalonJNI.CanTalonSRX_eStatus4FrameRate_get()); + public final static CanTalonSRX.param_t eStatus6FrameRate = new CanTalonSRX.param_t("eStatus6FrameRate", + CanTalonJNI.CanTalonSRX_eStatus6FrameRate_get()); + public final static CanTalonSRX.param_t eStatus7FrameRate = new CanTalonSRX.param_t("eStatus7FrameRate", + CanTalonJNI.CanTalonSRX_eStatus7FrameRate_get()); + public final static CanTalonSRX.param_t eClearPositionOnIdx = new CanTalonSRX.param_t("eClearPositionOnIdx", + CanTalonJNI.CanTalonSRX_eClearPositionOnIdx_get()); + public final static CanTalonSRX.param_t ePeakPosOutput = new CanTalonSRX.param_t("ePeakPosOutput", + CanTalonJNI.CanTalonSRX_ePeakPosOutput_get()); + public final static CanTalonSRX.param_t eNominalPosOutput = new CanTalonSRX.param_t("eNominalPosOutput", + CanTalonJNI.CanTalonSRX_eNominalPosOutput_get()); + public final static CanTalonSRX.param_t ePeakNegOutput = new CanTalonSRX.param_t("ePeakNegOutput", + CanTalonJNI.CanTalonSRX_ePeakNegOutput_get()); + public final static CanTalonSRX.param_t eNominalNegOutput = new CanTalonSRX.param_t("eNominalNegOutput", + CanTalonJNI.CanTalonSRX_eNominalNegOutput_get()); + public final static CanTalonSRX.param_t eQuadIdxPolarity = new CanTalonSRX.param_t("eQuadIdxPolarity", + CanTalonJNI.CanTalonSRX_eQuadIdxPolarity_get()); + public final static CanTalonSRX.param_t eStatus8FrameRate = new CanTalonSRX.param_t("eStatus8FrameRate", + CanTalonJNI.CanTalonSRX_eStatus8FrameRate_get()); + public final static CanTalonSRX.param_t eAllowPosOverflow = new CanTalonSRX.param_t("eAllowPosOverflow", + CanTalonJNI.CanTalonSRX_eAllowPosOverflow_get()); + public final static CanTalonSRX.param_t eProfileParamSlot0_AllowableClosedLoopErr = new CanTalonSRX.param_t("eProfileParamSlot0_AllowableClosedLoopErr", + CanTalonJNI.CanTalonSRX_eProfileParamSlot0_AllowableClosedLoopErr_get()); + public final static CanTalonSRX.param_t eNumberPotTurns = new CanTalonSRX.param_t("eNumberPotTurns", + CanTalonJNI.CanTalonSRX_eNumberPotTurns_get()); + public final static CanTalonSRX.param_t eNumberEncoderCPR = new CanTalonSRX.param_t("eNumberEncoderCPR", + CanTalonJNI.CanTalonSRX_eNumberEncoderCPR_get()); + public final static CanTalonSRX.param_t ePwdPosition = new CanTalonSRX.param_t("ePwdPosition", + CanTalonJNI.CanTalonSRX_ePwdPosition_get()); + public final static CanTalonSRX.param_t eAinPosition = new CanTalonSRX.param_t("eAinPosition", + CanTalonJNI.CanTalonSRX_eAinPosition_get()); + public final static CanTalonSRX.param_t eProfileParamVcompRate = new CanTalonSRX.param_t("eProfileParamVcompRate", + CanTalonJNI.CanTalonSRX_eProfileParamVcompRate_get()); + public final static CanTalonSRX.param_t eProfileParamSlot1_AllowableClosedLoopErr = new CanTalonSRX.param_t("eProfileParamSlot1_AllowableClosedLoopErr", + CanTalonJNI.CanTalonSRX_eProfileParamSlot1_AllowableClosedLoopErr_get()); + public final int swigValue() { return swigValue; } diff --git a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/hal/CanTalonJNI.java b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/hal/CanTalonJNI.java index 529e48b85f..b194cf6579 100644 --- a/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/hal/CanTalonJNI.java +++ b/wpilibj/wpilibJavaDevices/src/main/java/edu/wpi/first/wpilibj/hal/CanTalonJNI.java @@ -153,6 +153,8 @@ public class CanTalonJNI { public final static native int CanTalonSRX_kStatusFrame_AnalogTempVbat_get(); + public final static native int CanTalonSRX_kStatusFrame_PulseWidthMeas_get(); + public final static native int CanTalonSRX_eProfileParamSlot0_P_get(); public final static native int CanTalonSRX_eProfileParamSlot0_I_get(); @@ -283,6 +285,48 @@ public class CanTalonJNI { public final static native int CanTalonSRX_ePidIaccum_get(); + public final static native int CanTalonSRX_eStatus1FrameRate_get(); + + public final static native int CanTalonSRX_eStatus2FrameRate_get(); + + public final static native int CanTalonSRX_eStatus3FrameRate_get(); + + public final static native int CanTalonSRX_eStatus4FrameRate_get(); + + public final static native int CanTalonSRX_eStatus6FrameRate_get(); + + public final static native int CanTalonSRX_eStatus7FrameRate_get(); + + public final static native int CanTalonSRX_eClearPositionOnIdx_get(); + + public final static native int CanTalonSRX_ePeakPosOutput_get(); + + public final static native int CanTalonSRX_eNominalPosOutput_get(); + + public final static native int CanTalonSRX_ePeakNegOutput_get(); + + public final static native int CanTalonSRX_eNominalNegOutput_get(); + + public final static native int CanTalonSRX_eQuadIdxPolarity_get(); + + public final static native int CanTalonSRX_eStatus8FrameRate_get(); + + public final static native int CanTalonSRX_eAllowPosOverflow_get(); + + public final static native int CanTalonSRX_eProfileParamSlot0_AllowableClosedLoopErr_get(); + + public final static native int CanTalonSRX_eNumberPotTurns_get(); + + public final static native int CanTalonSRX_eNumberEncoderCPR_get(); + + public final static native int CanTalonSRX_ePwdPosition_get(); + + public final static native int CanTalonSRX_eAinPosition_get(); + + public final static native int CanTalonSRX_eProfileParamVcompRate_get(); + + public final static native int CanTalonSRX_eProfileParamSlot1_AllowableClosedLoopErr_get(); + public final static native long CanTalonSRX_SetParam(long jarg1, CanTalonSRX jarg1_, int jarg2, double jarg3); @@ -345,6 +389,9 @@ public class CanTalonJNI { public final static native long CanTalonSRX_GetCloseLoopRampRate(long jarg1, CanTalonSRX jarg1_, long jarg2, long jarg3); + public final static native long CanTalonSRX_GetVoltageCompensationRate(long jarg1, + CanTalonSRX jarg1_, long jarg2); + public final static native long CanTalonSRX_GetForwardSoftLimit(long jarg1, CanTalonSRX jarg1_, long jarg2); @@ -489,8 +536,21 @@ public class CanTalonJNI { public final static native long CanTalonSRX_SetRampThrottle(long jarg1, CanTalonSRX jarg1_, int jarg2); + public final static native long CanTalonSRX_SetVoltageCompensationRate(long jarg1, CanTalonSRX jarg1_, + double jarg2); + public final static native long CanTalonSRX_SetRevFeedbackSensor(long jarg1, CanTalonSRX jarg1_, int jarg2); + public final static native long CanTalonSRX_GetPulseWidthPosition(long jarg1, CanTalonSRX jarg1_, long jarg2); + + public final static native long CanTalonSRX_GetPulseWidthVelocity(long jarg1, CanTalonSRX jarg1_, long jarg2); + + public final static native long CanTalonSRX_GetPulseWidthRiseToFallUs(long jarg1, CanTalonSRX jarg1_, long jarg2); + + public final static native long CanTalonSRX_GetPulseWidthRiseToRiseUs(long jarg1, CanTalonSRX jarg1_, long jarg2); + + public final static native long CanTalonSRX_IsPulseWidthSensorPresent(long jarg1, CanTalonSRX jarg1_, long jarg2); + public final static native long CanTalonSRX_SWIGUpcast(long jarg1); } diff --git a/wpilibj/wpilibJavaJNI/lib/CanTalonSRXJNI.cpp b/wpilibj/wpilibJavaJNI/lib/CanTalonSRXJNI.cpp index bdf64faa5a..0acf12db95 100644 --- a/wpilibj/wpilibJavaJNI/lib/CanTalonSRXJNI.cpp +++ b/wpilibj/wpilibJavaJNI/lib/CanTalonSRXJNI.cpp @@ -1293,6 +1293,18 @@ SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1 } +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1kStatusFrame_1PulseWidthMeas_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + int result; + + (void)jenv; + (void)jcls; + result = (int)CanTalonSRX::kStatusFrame_PulseWidthMeas; + jresult = (jint)result; + return jresult; +} + + SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eProfileParamSlot0_1P_1get(JNIEnv *jenv, jclass jcls) { jint jresult = 0 ; CanTalonSRX::_param_t result; @@ -2073,6 +2085,240 @@ SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1 } +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eStatus1FrameRate_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eStatus1FrameRate; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eStatus2FrameRate_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eStatus2FrameRate; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eStatus3FrameRate_1get(JNIEnv *jenv, jclass jcls) { + + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eStatus3FrameRate; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eStatus4FrameRate_1get(JNIEnv *jenv, jclass jcls) { + + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eStatus4FrameRate; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eStatus6FrameRate_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eStatus6FrameRate; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eStatus7FrameRate_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eStatus7FrameRate; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eClearPositionOnIdx_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eClearPositionOnIdx; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1ePeakPosOutput_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::ePeakPosOutput; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eNominalPosOutput_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eNominalPosOutput; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1ePeakNegOutput_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::ePeakNegOutput; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eNominalNegOutput_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eNominalNegOutput; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eQuadIdxPolarity_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eQuadIdxPolarity; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eStatus8FrameRate_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eStatus8FrameRate; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eAllowPosOverflow_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eAllowPosOverflow; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eProfileParamSlot0_1AllowableClosedLoopErr_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eProfileParamSlot0_AllowableClosedLoopErr; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eNumberPotTurns_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eNumberPotTurns; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eNumberEncoderCPR_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eNumberEncoderCPR; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1ePwdPosition_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::ePwdPosition; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eAinPosition_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eAinPosition; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eProfileParamVcompRate_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eProfileParamVcompRate; + jresult = (jint)result; + return jresult; +} + +SWIGEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1eProfileParamSlot1_1AllowableClosedLoopErr_1get(JNIEnv *jenv, jclass jcls) { + jint jresult = 0 ; + CanTalonSRX::_param_t result; + + (void)jenv; + (void)jcls; + result = (CanTalonSRX::_param_t)CanTalonSRX::eProfileParamSlot1_AllowableClosedLoopErr; + jresult = (jint)result; + return jresult; +} + + SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1SetParam(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jint jarg2, jdouble jarg3) { jlong jresult = 0 ; CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; @@ -2491,6 +2737,25 @@ SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_ return jresult; } +SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1GetVoltageCompensationRate(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2) { + jlong jresult = 0 ; + CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; + double *arg2 = 0 ; + CTR_Code result; + + (void)jenv; + (void)jcls; + (void)jarg1_; + arg1 = *(CanTalonSRX **)&jarg1; + arg2 = *(double **)&jarg2; + if (!arg2) { + SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "double & reference is null"); + return 0; + } + result = (arg1)->GetVoltageCompensationRate(*arg2); + *(CTR_Code **)&jresult = new CTR_Code((const CTR_Code &)result); + return jresult; +} SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1GetForwardSoftLimit(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2) { jlong jresult = 0 ; @@ -3523,6 +3788,23 @@ SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_ } +SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1SetVoltageCompensationRate(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jdouble jarg2) { + jlong jresult = 0 ; + CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; + double arg2 ; + CTR_Code result; + + (void)jenv; + (void)jcls; + (void)jarg1_; + arg1 = *(CanTalonSRX **)&jarg1; + arg2 = (double)jarg2; + result = (arg1)->SetVoltageCompensationRate(arg2); + *(CTR_Code **)&jresult = new CTR_Code((const CTR_Code &)result); + return jresult; +} + + SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1SetRevFeedbackSensor(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jint jarg2) { jlong jresult = 0 ; CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; @@ -3540,6 +3822,111 @@ SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_ } +SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1GetPulseWidthPosition(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2) { + jlong jresult = 0 ; + CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; + int *arg2 = 0 ; + CTR_Code result; + + (void)jenv; + (void)jcls; + (void)jarg1_; + arg1 = *(CanTalonSRX **)&jarg1; + arg2 = *(int **)&jarg2; + if (!arg2) { + SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "int & reference is null"); + return 0; + } + result = (arg1)->GetPulseWidthPosition(*arg2); + *(CTR_Code **)&jresult = new CTR_Code((const CTR_Code &)result); + return jresult; +} + + +SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1GetPulseWidthVelocity(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2) { + jlong jresult = 0 ; + CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; + int *arg2 = 0 ; + CTR_Code result; + + (void)jenv; + (void)jcls; + (void)jarg1_; + arg1 = *(CanTalonSRX **)&jarg1; + arg2 = *(int **)&jarg2; + if (!arg2) { + SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "int & reference is null"); + return 0; + } + result = (arg1)->GetPulseWidthVelocity(*arg2); + *(CTR_Code **)&jresult = new CTR_Code((const CTR_Code &)result); + return jresult; +} + + +SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1GetPulseWidthRiseToFallUs(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2) { + jlong jresult = 0 ; + CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; + int *arg2 = 0 ; + CTR_Code result; + + (void)jenv; + (void)jcls; + (void)jarg1_; + arg1 = *(CanTalonSRX **)&jarg1; + arg2 = *(int **)&jarg2; + if (!arg2) { + SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "int & reference is null"); + return 0; + } + result = (arg1)->GetPulseWidthRiseToFallUs(*arg2); + *(CTR_Code **)&jresult = new CTR_Code((const CTR_Code &)result); + return jresult; +} + + +SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1GetPulseWidthRiseToRiseUs(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2) { + jlong jresult = 0 ; + CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; + int *arg2 = 0 ; + CTR_Code result; + + (void)jenv; + (void)jcls; + (void)jarg1_; + arg1 = *(CanTalonSRX **)&jarg1; + arg2 = *(int **)&jarg2; + if (!arg2) { + SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "int & reference is null"); + return 0; + } + result = (arg1)->GetPulseWidthRiseToRiseUs(*arg2); + *(CTR_Code **)&jresult = new CTR_Code((const CTR_Code &)result); + return jresult; +} + + +SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1IsPulseWidthSensorPresent(JNIEnv *jenv, jclass jcls, jlong jarg1, jobject jarg1_, jlong jarg2) { + jlong jresult = 0 ; + CanTalonSRX *arg1 = (CanTalonSRX *) 0 ; + int *arg2 = 0 ; + CTR_Code result; + + (void)jenv; + (void)jcls; + (void)jarg1_; + arg1 = *(CanTalonSRX **)&jarg1; + arg2 = *(int **)&jarg2; + if (!arg2) { + SWIG_JavaThrowException(jenv, SWIG_JavaNullPointerException, "int & reference is null"); + return 0; + } + result = (arg1)->IsPulseWidthSensorPresent(*arg2); + *(CTR_Code **)&jresult = new CTR_Code((const CTR_Code &)result); + return jresult; +} + + SWIGEXPORT jlong JNICALL Java_edu_wpi_first_wpilibj_hal_CanTalonJNI_CanTalonSRX_1SWIGUpcast(JNIEnv *jenv, jclass jcls, jlong jarg1) { jlong baseptr = 0; (void)jenv;