2013-12-15 18:30:16 -05:00
/*----------------------------------------------------------------------------*/
2014-06-19 21:43:31 -04:00
/* Copyright (c) FIRST 2009. All Rights Reserved. */
2013-12-15 18:30:16 -05:00
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
# include "CANJaguar.h"
2014-06-19 21:43:31 -04:00
# include "Timer.h"
2013-12-15 18:30:16 -05:00
# define tNIRIO_i32 int
2014-06-16 10:24:48 -04:00
# include "NetworkCommunication/CANSessionMux.h"
2013-12-15 18:30:16 -05:00
# include "CAN/can_proto.h"
2014-01-06 10:12:21 -05:00
//#include "NetworkCommunication/UsageReporting.h"
2013-12-15 18:30:16 -05:00
# include "WPIErrors.h"
2014-06-19 21:43:31 -04:00
# include <cstdio>
# include <cassert>
2013-12-15 18:30:16 -05:00
# include "LiveWindow/LiveWindow.h"
2014-05-02 17:54:01 -04:00
/* we are on ARM-LE now, not Freescale so no need to swap */
2014-05-16 14:11:30 -04:00
# define swap16(x) (x)
# define swap32(x) (x)
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
/* Compare floats for equality as fixed point numbers */
# define FXP8_EQ(a,b) ((int16_t)((a)*256.0)==(int16_t)((b)*256.0))
2014-07-23 15:22:26 -04:00
# define FXP16_EQ(a,b) ((int32_t)((a)*65536.0)==(int32_t)((b)*65536.0))
2013-12-15 18:30:16 -05:00
const int32_t CANJaguar : : kControllerRate ;
constexpr double CANJaguar : : kApproxBusVoltage ;
2014-06-19 21:43:31 -04:00
static const int32_t kSendMessagePeriod = 20 ;
static const uint32_t kFullMessageIDMask = ( CAN_MSGID_API_M | CAN_MSGID_MFR_M | CAN_MSGID_DTYPE_M ) ;
2014-06-26 17:26:56 -04:00
static const int32_t kReceiveStatusAttempts = 50 ;
2014-06-26 11:54:58 -04:00
2014-07-18 16:06:04 -04:00
static Resource * allocated = NULL ;
2014-06-19 21:43:31 -04:00
static int32_t sendMessageHelper ( uint32_t messageID , const uint8_t * data , uint8_t dataSize , int32_t period )
{
static const uint32_t kTrustedMessages [ ] = {
LM_API_VOLT_T_EN , LM_API_VOLT_T_SET , LM_API_SPD_T_EN , LM_API_SPD_T_SET ,
LM_API_VCOMP_T_EN , LM_API_VCOMP_T_SET , LM_API_POS_T_EN , LM_API_POS_T_SET ,
LM_API_ICTRL_T_EN , LM_API_ICTRL_T_SET } ;
int32_t status = 0 ;
for ( uint8_t i = 0 ; i < ( sizeof ( kTrustedMessages ) / sizeof ( kTrustedMessages [ 0 ] ) ) ; i + + )
{
if ( ( kFullMessageIDMask & messageID ) = = kTrustedMessages [ i ] )
{
uint8_t dataBuffer [ 8 ] ;
dataBuffer [ 0 ] = 0 ;
dataBuffer [ 1 ] = 0 ;
// Make sure the data will still fit after adjusting for the token.
assert ( dataSize < = 6 ) ;
for ( uint8_t j = 0 ; j < dataSize ; j + + )
{
dataBuffer [ j + 2 ] = data [ j ] ;
}
FRC_NetworkCommunication_CANSessionMux_sendMessage ( messageID , dataBuffer , dataSize + 2 , period , & status ) ;
return status ;
}
}
FRC_NetworkCommunication_CANSessionMux_sendMessage ( messageID , data , dataSize , period , & status ) ;
return status ;
}
2014-05-16 14:11:30 -04:00
2013-12-15 18:30:16 -05:00
/**
* Common initialization code called by all constructors .
*/
void CANJaguar : : InitCANJaguar ( )
{
m_table = NULL ;
2014-06-19 21:43:31 -04:00
m_safetyHelper = new MotorSafetyHelper ( this ) ;
m_value = 0.0f ;
2014-06-25 15:42:16 -04:00
m_speedReference = LM_REF_NONE ;
m_positionReference = LM_REF_NONE ;
2014-06-19 21:43:31 -04:00
m_p = 0.0 ;
m_i = 0.0 ;
m_d = 0.0 ;
m_busVoltage = 0.0f ;
m_outputVoltage = 0.0f ;
m_outputCurrent = 0.0f ;
m_temperature = 0.0f ;
m_position = 0.0 ;
m_speed = 0.0 ;
m_limits = 0x00 ;
m_faults = 0x0000 ;
m_firmwareVersion = 0 ;
m_hardwareVersion = 0 ;
m_neutralMode = kNeutralMode_Jumper ;
m_encoderCodesPerRev = 0 ;
m_potentiometerTurns = 0 ;
m_limitMode = kLimitMode_SwitchInputsOnly ;
m_forwardLimit = 0.0 ;
m_reverseLimit = 0.0 ;
m_maxOutputVoltage = 30.0 ;
m_voltageRampRate = 0.0 ;
m_faultTime = 0.0f ;
// Parameters only need to be verified if they are set
m_controlModeVerified = false ; // Needs to be verified because it's set in the constructor
m_speedRefVerified = true ;
m_posRefVerified = true ;
m_pVerified = true ;
m_iVerified = true ;
m_dVerified = true ;
m_neutralModeVerified = true ;
m_encoderCodesPerRevVerified = true ;
m_potentiometerTurnsVerified = true ;
m_limitModeVerified = true ;
m_forwardLimitVerified = true ;
m_reverseLimitVerified = true ;
m_maxOutputVoltageVerified = true ;
m_voltageRampRateVerified = true ;
m_faultTimeVerified = true ;
2014-07-01 12:02:44 -04:00
m_receivedStatusMessage0 = false ;
m_receivedStatusMessage1 = false ;
m_receivedStatusMessage2 = false ;
bool receivedFirmwareVersion = false ;
2014-06-19 21:43:31 -04:00
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
// Request firmware and hardware version only once
requestMessage ( CAN_IS_FRAME_REMOTE | CAN_MSGID_API_FIRMVER ) ;
requestMessage ( LM_API_HWVER ) ;
2014-06-26 11:54:58 -04:00
// Wait until we've gotten all of the status data at least once.
for ( int i = 0 ; i < kReceiveStatusAttempts ; i + + )
{
Wait ( 0.001 ) ;
2014-07-01 12:02:44 -04:00
setupPeriodicStatus ( ) ;
updatePeriodicStatus ( ) ;
if ( ! receivedFirmwareVersion & &
getMessage ( CAN_MSGID_API_FIRMVER , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
m_firmwareVersion = unpackint32_t ( dataBuffer ) ;
receivedFirmwareVersion = true ;
}
if ( m_receivedStatusMessage0 & &
m_receivedStatusMessage1 & &
m_receivedStatusMessage2 & &
receivedFirmwareVersion )
2014-06-26 11:54:58 -04:00
{
break ;
}
}
2014-06-24 11:50:10 -04:00
2014-07-01 12:02:44 -04:00
if ( ! m_receivedStatusMessage0 | |
! m_receivedStatusMessage1 | |
! m_receivedStatusMessage2 | |
! receivedFirmwareVersion )
{
wpi_setWPIErrorWithContext ( JaguarMessageNotFound , " Status data not found " ) ;
}
2014-06-19 21:43:31 -04:00
if ( getMessage ( LM_API_HWVER , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
m_hardwareVersion = dataBuffer [ 0 ] ;
2013-12-15 18:30:16 -05:00
if ( m_deviceNumber < 1 | | m_deviceNumber > 63 )
{
char buf [ 256 ] ;
snprintf ( buf , 256 , " device number \" %d \" must be between 1 and 63 " , m_deviceNumber ) ;
wpi_setWPIErrorWithContext ( ParameterOutOfRange , buf ) ;
return ;
}
2014-06-19 21:43:31 -04:00
2013-12-15 18:30:16 -05:00
if ( StatusIsFatal ( ) )
return ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
// 3330 was the first shipping RDK firmware version for the Jaguar
if ( m_firmwareVersion > = 3330 | | m_firmwareVersion < 101 )
2013-12-15 18:30:16 -05:00
{
char buf [ 256 ] ;
2014-06-19 21:43:31 -04:00
if ( m_firmwareVersion < 3330 )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
snprintf ( buf , 256 , " Jag #%d firmware (%d) is too old (must be at least version 101 of the FIRST approved firmware) " , m_deviceNumber , m_firmwareVersion ) ;
2013-12-15 18:30:16 -05:00
}
else
{
2014-06-19 21:43:31 -04:00
snprintf ( buf , 256 , " Jag #%d firmware (%d) is not FIRST approved (must be at least version 101 of the FIRST approved firmware) " , m_deviceNumber , m_firmwareVersion ) ;
2013-12-15 18:30:16 -05:00
}
wpi_setWPIErrorWithContext ( JaguarVersionError , buf ) ;
return ;
}
2014-06-16 10:24:48 -04:00
2013-12-15 18:30:16 -05:00
switch ( m_controlMode )
{
case kPercentVbus :
case kVoltage :
// No additional configuration required... start enabled.
EnableControl ( ) ;
break ;
default :
break ;
}
2014-06-16 10:24:48 -04:00
2014-01-06 10:12:21 -05:00
HALReport ( HALUsageReporting : : kResourceType_CANJaguar , m_deviceNumber , m_controlMode ) ;
2014-06-13 17:45:10 -04:00
LiveWindow : : GetInstance ( ) - > AddActuator ( " CANJaguar " , m_deviceNumber , this ) ;
2013-12-15 18:30:16 -05:00
}
/**
2014-07-03 12:05:29 -04:00
* Constructor for the CANJaguar device . < br >
* By default the device is configured in Percent mode .
* The control mode can be changed by calling one of the control modes listed below .
2014-06-13 17:45:10 -04:00
*
2014-07-03 12:05:29 -04:00
* @ param deviceNumber The address of the Jaguar on the CAN bus .
* @ see CANJaguar # SetCurrentMode ( double , double , double )
* @ see CANJaguar # SetCurrentMode ( PotentiometerTag , double , double , double )
* @ see CANJaguar # SetCurrentMode ( EncoderTag , int , double , double , double )
* @ see CANJaguar # SetCurrentMode ( QuadEncoderTag , int , double , double , double )
* @ see CANJaguar # SetPercentMode ( )
* @ see CANJaguar # SetPercentMode ( PotentiometerTag )
* @ see CANJaguar # SetPercentMode ( EncoderTag , int )
* @ see CANJaguar # SetPercentMode ( QuadEncoderTag , int )
* @ see CANJaguar # SetPositionMode ( PotentiometerTag , double , double , double )
* @ see CANJaguar # SetPositionMode ( QuadEncoderTag , int , double , double , double )
* @ see CANJaguar # SetSpeedMode ( EncoderTag , int , double , double , double )
* @ see CANJaguar # SetSpeedMode ( QuadEncoderTag , int , double , double , double )
* @ see CANJaguar # SetVoltageMode ( )
* @ see CANJaguar # SetVoltageMode ( PotentiometerTag )
* @ see CANJaguar # SetVoltageMode ( EncoderTag , int )
* @ see CANJaguar # SetVoltageMode ( QuadEncoderTag , int )
2013-12-15 18:30:16 -05:00
*/
2014-06-25 15:42:16 -04:00
CANJaguar : : CANJaguar ( uint8_t deviceNumber )
2013-12-15 18:30:16 -05:00
: m_deviceNumber ( deviceNumber )
, m_maxOutputVoltage ( kApproxBusVoltage )
, m_safetyHelper ( NULL )
{
2014-07-18 16:06:04 -04:00
char buf [ 64 ] ;
snprintf ( buf , 64 , " CANJaguar device number %d " , m_deviceNumber ) ;
Resource : : CreateResourceObject ( & allocated , 63 ) ;
if ( allocated - > Allocate ( m_deviceNumber - 1 , buf ) = = ~ 0ul )
{
CloneError ( allocated ) ;
return ;
}
2014-06-25 15:42:16 -04:00
SetPercentMode ( ) ;
2013-12-15 18:30:16 -05:00
InitCANJaguar ( ) ;
2014-07-03 12:05:29 -04:00
ConfigMaxOutputVoltage ( kApproxBusVoltage ) ;
2013-12-15 18:30:16 -05:00
}
CANJaguar : : ~ CANJaguar ( )
{
2014-07-18 16:06:04 -04:00
allocated - > Free ( m_deviceNumber - 1 ) ;
2014-06-19 21:43:31 -04:00
int32_t status ;
// Disable periodic setpoints
if ( m_controlMode = = kPercentVbus )
FRC_NetworkCommunication_CANSessionMux_sendMessage ( m_deviceNumber | LM_API_VOLT_T_SET , NULL , 0 , CAN_SEND_PERIOD_STOP_REPEATING , & status ) ;
else if ( m_controlMode = = kSpeed )
FRC_NetworkCommunication_CANSessionMux_sendMessage ( m_deviceNumber | LM_API_SPD_T_SET , NULL , 0 , CAN_SEND_PERIOD_STOP_REPEATING , & status ) ;
else if ( m_controlMode = = kPosition )
FRC_NetworkCommunication_CANSessionMux_sendMessage ( m_deviceNumber | LM_API_POS_T_SET , NULL , 0 , CAN_SEND_PERIOD_STOP_REPEATING , & status ) ;
else if ( m_controlMode = = kCurrent )
FRC_NetworkCommunication_CANSessionMux_sendMessage ( m_deviceNumber | LM_API_ICTRL_T_SET , NULL , 0 , CAN_SEND_PERIOD_STOP_REPEATING , & status ) ;
else if ( m_controlMode = = kVoltage )
FRC_NetworkCommunication_CANSessionMux_sendMessage ( m_deviceNumber | LM_API_VCOMP_T_SET , NULL , 0 , CAN_SEND_PERIOD_STOP_REPEATING , & status ) ;
2013-12-15 18:30:16 -05:00
delete m_safetyHelper ;
m_safetyHelper = NULL ;
}
/**
2014-07-03 12:05:29 -04:00
* Sets the output set - point value .
2014-06-13 17:45:10 -04:00
*
2014-07-03 12:05:29 -04:00
* The scale and the units depend on the mode the Jaguar is in . < br >
* In percentVbus Mode , the outputValue is from - 1.0 to 1.0 ( same as PWM Jaguar ) . < br >
* In voltage Mode , the outputValue is in volts . < br >
* In current Mode , the outputValue is in amps . < br >
* In speed Mode , the outputValue is in rotations / minute . < br >
* In position Mode , the outputValue is in rotations .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param outputValue The set - point to sent to the motor controller .
* @ param syncGroup The update group to add this Set ( ) to , pending UpdateSyncGroup ( ) . If 0 , update immediately .
*/
void CANJaguar : : Set ( float outputValue , uint8_t syncGroup )
{
uint32_t messageID ;
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
2014-07-24 17:42:25 -04:00
if ( m_safetyHelper & & ! m_safetyHelper - > IsAlive ( ) & & m_controlEnabled )
2013-12-15 18:30:16 -05:00
{
EnableControl ( ) ;
}
2014-07-24 17:42:25 -04:00
if ( m_controlEnabled )
2013-12-15 18:30:16 -05:00
{
2014-07-24 17:42:25 -04:00
switch ( m_controlMode )
2013-12-15 18:30:16 -05:00
{
2014-07-24 17:42:25 -04:00
case kPercentVbus :
{
messageID = LM_API_VOLT_T_SET ;
if ( outputValue > 1.0 ) outputValue = 1.0 ;
if ( outputValue < - 1.0 ) outputValue = - 1.0 ;
dataSize = packPercentage ( dataBuffer , outputValue ) ;
}
break ;
case kSpeed :
{
messageID = LM_API_SPD_T_SET ;
dataSize = packFXP16_16 ( dataBuffer , outputValue ) ;
}
break ;
case kPosition :
{
messageID = LM_API_POS_T_SET ;
dataSize = packFXP16_16 ( dataBuffer , outputValue ) ;
}
break ;
case kCurrent :
{
messageID = LM_API_ICTRL_T_SET ;
dataSize = packFXP8_8 ( dataBuffer , outputValue ) ;
}
break ;
case kVoltage :
{
messageID = LM_API_VCOMP_T_SET ;
dataSize = packFXP8_8 ( dataBuffer , outputValue ) ;
}
break ;
default :
return ;
2013-12-15 18:30:16 -05:00
}
2014-07-24 17:42:25 -04:00
if ( syncGroup ! = 0 )
2013-12-15 18:30:16 -05:00
{
2014-07-24 17:42:25 -04:00
dataBuffer [ dataSize ] = syncGroup ;
dataSize + + ;
2013-12-15 18:30:16 -05:00
}
2014-06-19 21:43:31 -04:00
2014-07-24 17:42:25 -04:00
sendMessage ( messageID , dataBuffer , dataSize , kSendMessagePeriod ) ;
2014-06-19 21:43:31 -04:00
2014-07-24 17:42:25 -04:00
if ( m_safetyHelper ) m_safetyHelper - > Feed ( ) ;
}
2014-06-19 21:43:31 -04:00
m_value = outputValue ;
verify ( ) ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the recently set outputValue setpoint .
2014-06-13 17:45:10 -04:00
*
2014-07-03 12:05:29 -04:00
* The scale and the units depend on the mode the Jaguar is in . < br >
* In percentVbus Mode , the outputValue is from - 1.0 to 1.0 ( same as PWM Jaguar ) . < br >
* In voltage Mode , the outputValue is in volts . < br >
* In current Mode , the outputValue is in amps . < br >
* In speed Mode , the outputValue is in rotations / minute . < br >
* In position Mode , the outputValue is in rotations . < br >
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The most recently set outputValue setpoint .
*/
float CANJaguar : : Get ( )
{
2014-06-16 10:24:48 -04:00
return m_value ;
2013-12-15 18:30:16 -05:00
}
/**
2014-07-03 12:05:29 -04:00
* Common interface for disabling a motor .
*
* @ deprecated Call { @ link # DisableControl ( ) } instead .
*/
2013-12-15 18:30:16 -05:00
void CANJaguar : : Disable ( )
{
DisableControl ( ) ;
}
/**
* Write out the PID value as seen in the PIDOutput base object .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ deprecated Call Set instead .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param output Write out the PercentVbus value as was computed by the PIDController
*/
void CANJaguar : : PIDWrite ( float output )
{
if ( m_controlMode = = kPercentVbus )
{
Set ( output ) ;
}
else
{
wpi_setWPIErrorWithContext ( IncompatibleMode , " PID only supported in PercentVbus mode " ) ;
}
}
uint8_t CANJaguar : : packPercentage ( uint8_t * buffer , double value )
{
int16_t intValue = ( int16_t ) ( value * 32767.0 ) ;
* ( ( int16_t * ) buffer ) = swap16 ( intValue ) ;
return sizeof ( int16_t ) ;
}
uint8_t CANJaguar : : packFXP8_8 ( uint8_t * buffer , double value )
{
int16_t intValue = ( int16_t ) ( value * 256.0 ) ;
* ( ( int16_t * ) buffer ) = swap16 ( intValue ) ;
return sizeof ( int16_t ) ;
}
uint8_t CANJaguar : : packFXP16_16 ( uint8_t * buffer , double value )
{
int32_t intValue = ( int32_t ) ( value * 65536.0 ) ;
* ( ( int32_t * ) buffer ) = swap32 ( intValue ) ;
return sizeof ( int32_t ) ;
}
uint8_t CANJaguar : : packint16_t ( uint8_t * buffer , int16_t value )
{
* ( ( int16_t * ) buffer ) = swap16 ( value ) ;
return sizeof ( int16_t ) ;
}
uint8_t CANJaguar : : packint32_t ( uint8_t * buffer , int32_t value )
{
* ( ( int32_t * ) buffer ) = swap32 ( value ) ;
return sizeof ( int32_t ) ;
}
double CANJaguar : : unpackPercentage ( uint8_t * buffer )
{
int16_t value = * ( ( int16_t * ) buffer ) ;
value = swap16 ( value ) ;
return value / 32767.0 ;
}
double CANJaguar : : unpackFXP8_8 ( uint8_t * buffer )
{
int16_t value = * ( ( int16_t * ) buffer ) ;
value = swap16 ( value ) ;
return value / 256.0 ;
}
double CANJaguar : : unpackFXP16_16 ( uint8_t * buffer )
{
int32_t value = * ( ( int32_t * ) buffer ) ;
value = swap32 ( value ) ;
return value / 65536.0 ;
}
int16_t CANJaguar : : unpackint16_t ( uint8_t * buffer )
{
int16_t value = * ( ( int16_t * ) buffer ) ;
return swap16 ( value ) ;
}
int32_t CANJaguar : : unpackint32_t ( uint8_t * buffer )
{
int32_t value = * ( ( int32_t * ) buffer ) ;
return swap32 ( value ) ;
}
/**
2014-06-19 21:43:31 -04:00
* Send a message to the Jaguar .
2014-06-13 17:45:10 -04:00
*
2014-06-19 21:43:31 -04:00
* @ param messageID The messageID to be used on the CAN bus ( device number is added internally )
2013-12-15 18:30:16 -05:00
* @ param data The up to 8 bytes of data to be sent with the message
* @ param dataSize Specify how much of the data in " data " to send
2014-06-25 15:42:16 -04:00
* @ param periodic If positive , tell Network Communications to send the message
* every " period " milliseconds .
2013-12-15 18:30:16 -05:00
*/
2014-06-19 21:43:31 -04:00
void CANJaguar : : sendMessage ( uint32_t messageID , const uint8_t * data , uint8_t dataSize , int32_t period )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
int32_t localStatus = sendMessageHelper ( messageID | m_deviceNumber , data , dataSize , period ) ;
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
if ( localStatus < 0 )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
wpi_setErrorWithContext ( localStatus , " sendMessage " ) ;
2013-12-15 18:30:16 -05:00
}
}
/**
2014-06-19 21:43:31 -04:00
* Request a message from the Jaguar , but don ' t wait for it to arrive .
2014-06-13 17:45:10 -04:00
*
2014-06-19 21:43:31 -04:00
* @ param messageID The message to request
2014-06-25 15:42:16 -04:00
* @ param periodic If positive , tell Network Communications to send the message
* every " period " milliseconds .
2013-12-15 18:30:16 -05:00
*/
2014-06-19 21:43:31 -04:00
void CANJaguar : : requestMessage ( uint32_t messageID , int32_t period )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
sendMessageHelper ( messageID | m_deviceNumber , NULL , 0 , period ) ;
2013-12-15 18:30:16 -05:00
}
/**
2014-06-19 21:43:31 -04:00
* Get a previously requested message .
*
* Jaguar always generates a message with the same message ID when replying .
2014-06-13 17:45:10 -04:00
*
2014-06-19 21:43:31 -04:00
* @ param messageID The messageID to read from the CAN bus ( device number is added internally )
* @ param data The up to 8 bytes of data that was received with the message
* @ param dataSize Indicates how much data was received
2014-06-13 17:45:10 -04:00
*
2014-06-19 21:43:31 -04:00
* @ return true if the message was found . Otherwise , no new message is available .
2013-12-15 18:30:16 -05:00
*/
2014-06-19 21:43:31 -04:00
bool CANJaguar : : getMessage ( uint32_t messageID , uint32_t messageMask , uint8_t * data , uint8_t * dataSize )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
uint32_t targetedMessageID = messageID | m_deviceNumber ;
int32_t status = 0 ;
uint32_t timeStamp ;
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
// Caller may have set bit31 for remote frame transmission so clear invalid bits[31-29]
targetedMessageID & = CAN_MSGID_FULL_M ;
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
// Get the data.
FRC_NetworkCommunication_CANSessionMux_receiveMessage ( & targetedMessageID , messageMask , data , dataSize , & timeStamp , & status ) ;
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
// Do we already have the most recent value?
if ( status = = ERR_CANSessionMux_MessageNotFound )
return false ;
else
wpi_setErrorWithContext ( status , " receiveMessage " ) ;
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
return true ;
2013-12-15 18:30:16 -05:00
}
2014-07-01 12:02:44 -04:00
/**
2014-07-03 12:05:29 -04:00
* Enables periodic status updates from the Jaguar .
2014-07-01 12:02:44 -04:00
*/
void CANJaguar : : setupPeriodicStatus ( ) {
uint8_t data [ 8 ] ;
uint8_t dataSize ;
// Message 0 returns bus voltage, output voltage, output current, and
// temperature.
static const uint8_t kMessage0Data [ ] = {
LM_PSTAT_VOLTBUS_B0 , LM_PSTAT_VOLTBUS_B1 ,
2014-07-29 15:19:55 -04:00
LM_PSTAT_VOLTOUT_B0 , LM_PSTAT_VOLTOUT_B1 ,
2014-07-01 12:02:44 -04:00
LM_PSTAT_CURRENT_B0 , LM_PSTAT_CURRENT_B1 ,
LM_PSTAT_TEMP_B0 , LM_PSTAT_TEMP_B1
} ;
// Message 1 returns position and speed
static const uint8_t kMessage1Data [ ] = {
LM_PSTAT_POS_B0 , LM_PSTAT_POS_B1 , LM_PSTAT_POS_B2 , LM_PSTAT_POS_B3 ,
LM_PSTAT_SPD_B0 , LM_PSTAT_SPD_B1 , LM_PSTAT_SPD_B2 , LM_PSTAT_SPD_B3
} ;
// Message 2 returns limits and faults
static const uint8_t kMessage2Data [ ] = {
LM_PSTAT_LIMIT_CLR ,
LM_PSTAT_FAULT ,
LM_PSTAT_END
} ;
dataSize = packint16_t ( data , kSendMessagePeriod / 10 ) ;
sendMessage ( LM_API_PSTAT_PER_EN_S0 , data , dataSize ) ;
sendMessage ( LM_API_PSTAT_PER_EN_S1 , data , dataSize ) ;
sendMessage ( LM_API_PSTAT_PER_EN_S2 , data , dataSize ) ;
dataSize = 8 ;
sendMessage ( LM_API_PSTAT_CFG_S0 , kMessage0Data , dataSize ) ;
sendMessage ( LM_API_PSTAT_CFG_S1 , kMessage1Data , dataSize ) ;
sendMessage ( LM_API_PSTAT_CFG_S2 , kMessage2Data , dataSize ) ;
}
/**
* Check for new periodic status updates and unpack them into local variables
*/
void CANJaguar : : updatePeriodicStatus ( ) {
uint8_t data [ 8 ] ;
uint8_t dataSize ;
// Check if a new bus voltage/output voltage/current/temperature message
// has arrived and unpack the values into the cached member variables
if ( getMessage ( LM_API_PSTAT_DATA_S0 , CAN_MSGID_FULL_M , data , & dataSize ) ) {
m_busVoltage = unpackFXP8_8 ( data ) ;
2014-07-29 15:19:55 -04:00
m_outputVoltage = unpackPercentage ( data + 2 ) * m_busVoltage ;
2014-07-01 12:02:44 -04:00
m_outputCurrent = unpackFXP8_8 ( data + 4 ) ;
m_temperature = unpackFXP8_8 ( data + 6 ) ;
m_receivedStatusMessage0 = true ;
}
// Check if a new position/speed message has arrived and do the same
if ( getMessage ( LM_API_PSTAT_DATA_S1 , CAN_MSGID_FULL_M , data , & dataSize ) ) {
m_position = unpackFXP16_16 ( data ) ;
m_speed = unpackFXP16_16 ( data + 4 ) ;
m_receivedStatusMessage1 = true ;
}
// Check if a new limits/faults message has arrived and do the same
if ( getMessage ( LM_API_PSTAT_DATA_S2 , CAN_MSGID_FULL_M , data , & dataSize ) ) {
m_limits = data [ 0 ] ;
m_faults = data [ 1 ] ;
m_receivedStatusMessage2 = true ;
}
}
2013-12-15 18:30:16 -05:00
/**
2014-06-19 21:43:31 -04:00
* Check all unverified params and make sure they ' re equal to their local
* cached versions . If a value isn ' t available , it gets requested . If a value
* doesn ' t match up , it gets set again .
2013-12-15 18:30:16 -05:00
*/
2014-06-19 21:43:31 -04:00
void CANJaguar : : verify ( )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
// If the Jaguar lost power, everything should be considered unverified.
if ( getMessage ( LM_API_STATUS_POWER , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
bool powerCycled = ( bool ) dataBuffer [ 0 ] ;
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
if ( powerCycled )
{
// Clear the power cycled bit
dataBuffer [ 0 ] = 1 ;
sendMessage ( LM_API_STATUS_POWER , dataBuffer , sizeof ( uint8_t ) ) ;
2014-07-23 15:22:26 -04:00
// Mark everything as unverified
m_controlModeVerified = false ;
m_speedRefVerified = false ;
m_posRefVerified = false ;
m_neutralModeVerified = false ;
m_encoderCodesPerRevVerified = false ;
m_potentiometerTurnsVerified = false ;
m_forwardLimitVerified = false ;
m_reverseLimitVerified = false ;
m_limitModeVerified = false ;
m_maxOutputVoltageVerified = false ;
m_faultTimeVerified = false ;
if ( m_controlMode = = kPercentVbus | | m_controlMode = = kVoltage )
{
m_voltageRampRateVerified = false ;
}
2014-06-19 21:43:31 -04:00
else
2014-07-23 15:22:26 -04:00
{
m_pVerified = false ;
m_iVerified = false ;
m_dVerified = false ;
}
2014-06-19 21:43:31 -04:00
2014-07-23 15:22:26 -04:00
// Verify periodic status messages again
m_receivedStatusMessage0 = false ;
m_receivedStatusMessage1 = false ;
m_receivedStatusMessage2 = false ;
// Remove any old values from netcomms. Otherwise, parameters are
// incorrectly marked as verified based on stale messages.
getMessage ( LM_API_SPD_REF , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_POS_REF , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_SPD_PC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_POS_PC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_ICTRL_PC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_SPD_IC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_POS_IC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_ICTRL_IC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_SPD_DC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_POS_DC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_ICTRL_DC , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_CFG_BRAKE_COAST , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_CFG_ENC_LINES , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_CFG_POT_TURNS , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_CFG_LIMIT_MODE , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_CFG_LIMIT_FWD , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_CFG_LIMIT_REV , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_CFG_MAX_VOUT , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_VOLT_SET_RAMP , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_VCOMP_COMP_RAMP , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
getMessage ( LM_API_CFG_FAULT_TIME , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) ;
2014-06-19 21:43:31 -04:00
}
}
2014-07-23 15:22:26 -04:00
else
{
requestMessage ( LM_API_STATUS_POWER ) ;
}
2014-06-19 21:43:31 -04:00
// Verify that any recently set parameters are correct
2014-07-24 17:42:25 -04:00
if ( ! m_controlModeVerified & & m_controlEnabled )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
if ( getMessage ( LM_API_STATUS_CMODE , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
ControlMode mode = ( ControlMode ) dataBuffer [ 0 ] ;
if ( m_controlMode = = mode )
m_controlModeVerified = true ;
else
// Enable control again to resend the control mode
EnableControl ( ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_STATUS_CMODE ) ;
}
2013-12-15 18:30:16 -05:00
}
2014-06-19 21:43:31 -04:00
if ( ! m_speedRefVerified )
{
if ( getMessage ( LM_API_SPD_REF , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
2014-06-25 15:42:16 -04:00
uint8_t speedRef = dataBuffer [ 0 ] ;
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
if ( m_speedReference = = speedRef )
m_speedRefVerified = true ;
else
// It's wrong - set it again
SetSpeedReference ( m_speedReference ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_SPD_REF ) ;
}
}
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
if ( ! m_posRefVerified )
{
if ( getMessage ( LM_API_POS_REF , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
2014-06-25 15:42:16 -04:00
uint8_t posRef = dataBuffer [ 0 ] ;
2013-12-15 18:30:16 -05:00
2014-06-19 21:43:31 -04:00
if ( m_positionReference = = posRef )
m_posRefVerified = true ;
else
// It's wrong - set it again
SetPositionReference ( m_positionReference ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_POS_REF ) ;
}
}
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
if ( ! m_pVerified )
{
uint32_t message ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
if ( m_controlMode = = kSpeed )
message = LM_API_SPD_PC ;
else if ( m_controlMode = = kPosition )
message = LM_API_POS_PC ;
else if ( m_controlMode = = kCurrent )
message = LM_API_ICTRL_PC ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
if ( getMessage ( message , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
double p = unpackFXP16_16 ( dataBuffer ) ;
if ( FXP16_EQ ( m_p , p ) )
m_pVerified = true ;
else
// It's wrong - set it again
SetP ( m_p ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( message ) ;
}
}
if ( ! m_iVerified )
{
uint32_t message ;
if ( m_controlMode = = kSpeed )
message = LM_API_SPD_IC ;
else if ( m_controlMode = = kPosition )
message = LM_API_POS_IC ;
else if ( m_controlMode = = kCurrent )
message = LM_API_ICTRL_IC ;
if ( getMessage ( message , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
double i = unpackFXP16_16 ( dataBuffer ) ;
if ( FXP16_EQ ( m_i , i ) )
m_iVerified = true ;
else
// It's wrong - set it again
SetI ( m_i ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( message ) ;
}
}
if ( ! m_dVerified )
{
uint32_t message ;
if ( m_controlMode = = kSpeed )
message = LM_API_SPD_DC ;
else if ( m_controlMode = = kPosition )
message = LM_API_POS_DC ;
else if ( m_controlMode = = kCurrent )
message = LM_API_ICTRL_DC ;
if ( getMessage ( message , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
double d = unpackFXP16_16 ( dataBuffer ) ;
if ( FXP16_EQ ( m_d , d ) )
m_dVerified = true ;
else
// It's wrong - set it again
SetD ( m_d ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( message ) ;
}
}
if ( ! m_neutralModeVerified )
{
if ( getMessage ( LM_API_CFG_BRAKE_COAST , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
NeutralMode mode = ( NeutralMode ) dataBuffer [ 0 ] ;
if ( mode = = m_neutralMode )
m_neutralModeVerified = true ;
else
// It's wrong - set it again
ConfigNeutralMode ( m_neutralMode ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_CFG_BRAKE_COAST ) ;
}
}
if ( ! m_encoderCodesPerRevVerified )
{
if ( getMessage ( LM_API_CFG_ENC_LINES , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
uint16_t codes = unpackint16_t ( dataBuffer ) ;
if ( codes = = m_encoderCodesPerRev )
m_encoderCodesPerRevVerified = true ;
else
// It's wrong - set it again
ConfigEncoderCodesPerRev ( m_encoderCodesPerRev ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_CFG_ENC_LINES ) ;
}
}
if ( ! m_potentiometerTurnsVerified )
{
if ( getMessage ( LM_API_CFG_POT_TURNS , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
uint16_t turns = unpackint16_t ( dataBuffer ) ;
if ( turns = = m_potentiometerTurns )
m_potentiometerTurnsVerified = true ;
else
// It's wrong - set it again
ConfigPotentiometerTurns ( m_potentiometerTurns ) ;
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_CFG_POT_TURNS ) ;
}
}
if ( ! m_limitModeVerified )
{
if ( getMessage ( LM_API_CFG_LIMIT_MODE , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
LimitMode mode = ( LimitMode ) dataBuffer [ 0 ] ;
if ( mode = = m_limitMode )
m_limitModeVerified = true ;
else
{
// It's wrong - set it again
ConfigLimitMode ( m_limitMode ) ;
}
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_CFG_LIMIT_MODE ) ;
}
}
if ( ! m_forwardLimitVerified )
{
if ( getMessage ( LM_API_CFG_LIMIT_FWD , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
double limit = unpackFXP16_16 ( dataBuffer ) ;
if ( FXP16_EQ ( limit , m_forwardLimit ) )
m_forwardLimitVerified = true ;
else
{
// It's wrong - set it again
ConfigForwardLimit ( m_forwardLimit ) ;
}
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_CFG_LIMIT_FWD ) ;
}
}
if ( ! m_reverseLimitVerified )
{
if ( getMessage ( LM_API_CFG_LIMIT_REV , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
double limit = unpackFXP16_16 ( dataBuffer ) ;
if ( FXP16_EQ ( limit , m_reverseLimit ) )
m_reverseLimitVerified = true ;
else
{
// It's wrong - set it again
ConfigReverseLimit ( m_reverseLimit ) ;
}
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_CFG_LIMIT_REV ) ;
}
}
if ( ! m_maxOutputVoltageVerified )
{
if ( getMessage ( LM_API_CFG_MAX_VOUT , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
2014-07-23 15:22:26 -04:00
double voltage = unpackFXP8_8 ( dataBuffer ) ;
2014-06-19 21:43:31 -04:00
2014-07-23 15:22:26 -04:00
// The returned max output voltage is sometimes slightly higher or
// lower than what was sent. This should not trigger resending
// the message.
if ( std : : abs ( voltage - m_maxOutputVoltage ) < 0.1 )
2014-06-19 21:43:31 -04:00
m_maxOutputVoltageVerified = true ;
else
{
// It's wrong - set it again
ConfigMaxOutputVoltage ( m_maxOutputVoltage ) ;
}
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_CFG_MAX_VOUT ) ;
}
}
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
if ( ! m_voltageRampRateVerified )
{
if ( m_controlMode = = kPercentVbus )
{
if ( getMessage ( LM_API_VOLT_SET_RAMP , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
double rate = unpackPercentage ( dataBuffer ) ;
if ( FXP16_EQ ( rate , m_voltageRampRate ) )
m_voltageRampRateVerified = true ;
else
{
// It's wrong - set it again
SetVoltageRampRate ( m_voltageRampRate ) ;
}
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_VOLT_SET_RAMP ) ;
}
}
else if ( m_controlMode = = kVoltage )
{
2014-07-16 10:23:46 -04:00
if ( getMessage ( LM_API_VCOMP_COMP_RAMP , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
2014-06-19 21:43:31 -04:00
{
double rate = unpackFXP8_8 ( dataBuffer ) ;
if ( FXP8_EQ ( rate , m_voltageRampRate ) )
m_voltageRampRateVerified = true ;
else
{
// It's wrong - set it again
SetVoltageRampRate ( m_voltageRampRate ) ;
}
}
else
{
// Verification is needed but not available - request it again.
2014-07-16 10:23:46 -04:00
requestMessage ( LM_API_VCOMP_COMP_RAMP ) ;
2014-06-19 21:43:31 -04:00
}
}
}
2014-07-23 15:22:26 -04:00
if ( ! m_faultTimeVerified )
{
if ( getMessage ( LM_API_CFG_FAULT_TIME , CAN_MSGID_FULL_M , dataBuffer , & dataSize ) )
{
uint16_t faultTime = unpackint16_t ( dataBuffer ) ;
if ( ( uint16_t ) ( m_faultTime * 1000.0 ) = = faultTime )
m_faultTimeVerified = true ;
else
{
// It's wrong - set it again
ConfigFaultTime ( m_faultTime ) ;
}
}
else
{
// Verification is needed but not available - request it again.
requestMessage ( LM_API_CFG_FAULT_TIME ) ;
}
}
if ( ! m_receivedStatusMessage0 | |
! m_receivedStatusMessage1 | |
! m_receivedStatusMessage2 )
{
// If the periodic status messages haven't been verified as received,
// request periodic status messages again and attempt to unpack any
// available ones.
setupPeriodicStatus ( ) ;
GetTemperature ( ) ;
GetPosition ( ) ;
GetFaults ( ) ;
}
2013-12-15 18:30:16 -05:00
}
/**
* Set the reference source device for speed controller mode .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* Choose encoder as the source of speed feedback when in speed control mode .
2014-06-13 17:45:10 -04:00
*
2014-06-25 15:42:16 -04:00
* @ param reference Specify a speed reference .
2013-12-15 18:30:16 -05:00
*/
2014-06-25 15:42:16 -04:00
void CANJaguar : : SetSpeedReference ( uint8_t reference )
2013-12-15 18:30:16 -05:00
{
uint8_t dataBuffer [ 8 ] ;
2014-06-19 21:43:31 -04:00
// Send the speed reference parameter
2013-12-15 18:30:16 -05:00
dataBuffer [ 0 ] = reference ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_SPD_REF , dataBuffer , sizeof ( uint8_t ) ) ;
m_speedReference = reference ;
m_speedRefVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the reference source device for speed controller mode .
2014-06-13 17:45:10 -04:00
*
2014-06-25 15:42:16 -04:00
* @ return A speed reference indicating the currently selected reference device
* for speed controller mode .
2013-12-15 18:30:16 -05:00
*/
2014-06-25 15:42:16 -04:00
uint8_t CANJaguar : : GetSpeedReference ( )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
return m_speedReference ;
2013-12-15 18:30:16 -05:00
}
/**
* Set the reference source device for position controller mode .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* Choose between using and encoder and using a potentiometer
* as the source of position feedback when in position control mode .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param reference Specify a PositionReference .
*/
2014-06-25 15:42:16 -04:00
void CANJaguar : : SetPositionReference ( uint8_t reference )
2013-12-15 18:30:16 -05:00
{
uint8_t dataBuffer [ 8 ] ;
2014-06-19 21:43:31 -04:00
// Send the position reference parameter
2013-12-15 18:30:16 -05:00
dataBuffer [ 0 ] = reference ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_POS_REF , dataBuffer , sizeof ( uint8_t ) ) ;
m_positionReference = reference ;
m_posRefVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the reference source device for position controller mode .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return A PositionReference indicating the currently selected reference device for position controller mode .
*/
2014-06-25 15:42:16 -04:00
uint8_t CANJaguar : : GetPositionReference ( )
2014-06-19 21:43:31 -04:00
{
return m_positionReference ;
}
/**
* Set the P , I , and D constants for the closed loop modes .
*
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
*/
void CANJaguar : : SetPID ( double p , double i , double d )
{
SetP ( p ) ;
SetI ( i ) ;
SetD ( d ) ;
}
/**
* Set the P constant for the closed loop modes .
*
* @ param p The proportional gain of the Jaguar ' s PID controller .
*/
void CANJaguar : : SetP ( double p )
2013-12-15 18:30:16 -05:00
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
2014-06-19 21:43:31 -04:00
switch ( m_controlMode )
2013-12-15 18:30:16 -05:00
{
2014-06-19 21:43:31 -04:00
case kPercentVbus :
case kVoltage :
wpi_setWPIErrorWithContext ( IncompatibleMode , " PID constants only apply in Speed, Position, and Current mode " ) ;
break ;
case kSpeed :
dataSize = packFXP16_16 ( dataBuffer , p ) ;
sendMessage ( LM_API_SPD_PC , dataBuffer , dataSize ) ;
break ;
case kPosition :
dataSize = packFXP16_16 ( dataBuffer , p ) ;
sendMessage ( LM_API_POS_PC , dataBuffer , dataSize ) ;
break ;
case kCurrent :
dataSize = packFXP16_16 ( dataBuffer , p ) ;
sendMessage ( LM_API_ICTRL_PC , dataBuffer , dataSize ) ;
break ;
2013-12-15 18:30:16 -05:00
}
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
m_p = p ;
m_pVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
2014-06-19 21:43:31 -04:00
* Set the I constant for the closed loop modes .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param i The integral gain of the Jaguar ' s PID controller .
*/
2014-06-19 21:43:31 -04:00
void CANJaguar : : SetI ( double i )
2013-12-15 18:30:16 -05:00
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
switch ( m_controlMode )
{
case kPercentVbus :
case kVoltage :
wpi_setWPIErrorWithContext ( IncompatibleMode , " PID constants only apply in Speed, Position, and Current mode " ) ;
break ;
case kSpeed :
dataSize = packFXP16_16 ( dataBuffer , i ) ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_SPD_IC , dataBuffer , dataSize ) ;
2013-12-15 18:30:16 -05:00
break ;
case kPosition :
dataSize = packFXP16_16 ( dataBuffer , i ) ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_POS_IC , dataBuffer , dataSize ) ;
2013-12-15 18:30:16 -05:00
break ;
case kCurrent :
dataSize = packFXP16_16 ( dataBuffer , i ) ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_ICTRL_IC , dataBuffer , dataSize ) ;
2013-12-15 18:30:16 -05:00
break ;
}
2014-06-19 21:43:31 -04:00
m_i = i ;
m_iVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
2014-06-19 21:43:31 -04:00
* Set the D constant for the closed loop modes .
2014-06-13 17:45:10 -04:00
*
2014-06-19 21:43:31 -04:00
* @ param d The derivative gain of the Jaguar ' s PID controller .
2013-12-15 18:30:16 -05:00
*/
2014-06-19 21:43:31 -04:00
void CANJaguar : : SetD ( double d )
2013-12-15 18:30:16 -05:00
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
switch ( m_controlMode )
{
case kPercentVbus :
case kVoltage :
wpi_setWPIErrorWithContext ( IncompatibleMode , " PID constants only apply in Speed, Position, and Current mode " ) ;
break ;
case kSpeed :
2014-06-19 21:43:31 -04:00
dataSize = packFXP16_16 ( dataBuffer , d ) ;
sendMessage ( LM_API_SPD_DC , dataBuffer , dataSize ) ;
break ;
2013-12-15 18:30:16 -05:00
case kPosition :
2014-06-19 21:43:31 -04:00
dataSize = packFXP16_16 ( dataBuffer , d ) ;
sendMessage ( LM_API_POS_DC , dataBuffer , dataSize ) ;
break ;
2013-12-15 18:30:16 -05:00
case kCurrent :
2014-06-19 21:43:31 -04:00
dataSize = packFXP16_16 ( dataBuffer , d ) ;
sendMessage ( LM_API_ICTRL_DC , dataBuffer , dataSize ) ;
break ;
}
m_d = d ;
m_dVerified = false ;
}
/**
* Get the Proportional gain of the controller .
*
* @ return The proportional gain .
*/
double CANJaguar : : GetP ( )
{
if ( m_controlMode = = kPercentVbus | | m_controlMode = = kVoltage )
{
wpi_setWPIErrorWithContext ( IncompatibleMode , " PID constants only apply in Speed, Position, and Current mode " ) ;
return 0.0 ;
2013-12-15 18:30:16 -05:00
}
2014-06-16 10:24:48 -04:00
return m_p ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the Intregral gain of the controller .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The integral gain .
*/
double CANJaguar : : GetI ( )
{
2014-06-19 21:43:31 -04:00
if ( m_controlMode = = kPercentVbus | | m_controlMode = = kVoltage )
{
wpi_setWPIErrorWithContext ( IncompatibleMode , " PID constants only apply in Speed, Position, and Current mode " ) ;
return 0.0 ;
}
return m_i ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the Differential gain of the controller .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The differential gain .
*/
double CANJaguar : : GetD ( )
{
2014-06-19 21:43:31 -04:00
if ( m_controlMode = = kPercentVbus | | m_controlMode = = kVoltage )
{
wpi_setWPIErrorWithContext ( IncompatibleMode , " PID constants only apply in Speed, Position, and Current mode " ) ;
return 0.0 ;
}
return m_d ;
2013-12-15 18:30:16 -05:00
}
/**
* Enable the closed loop controller .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* Start actually controlling the output based on the feedback .
* If starting a position controller with an encoder reference ,
* use the encoderInitialPosition parameter to initialize the
* encoder state .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param encoderInitialPosition Encoder position to set if position with encoder reference . Ignored otherwise .
*/
void CANJaguar : : EnableControl ( double encoderInitialPosition )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize = 0 ;
switch ( m_controlMode )
{
case kPercentVbus :
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_VOLT_T_EN , dataBuffer , dataSize ) ;
2013-12-15 18:30:16 -05:00
break ;
case kSpeed :
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_SPD_T_EN , dataBuffer , dataSize ) ;
2013-12-15 18:30:16 -05:00
break ;
case kPosition :
dataSize = packFXP16_16 ( dataBuffer , encoderInitialPosition ) ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_POS_T_EN , dataBuffer , dataSize ) ;
2013-12-15 18:30:16 -05:00
break ;
case kCurrent :
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_ICTRL_T_EN , dataBuffer , dataSize ) ;
2013-12-15 18:30:16 -05:00
break ;
case kVoltage :
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_VCOMP_T_EN , dataBuffer , dataSize ) ;
2013-12-15 18:30:16 -05:00
break ;
}
2014-06-19 21:43:31 -04:00
2014-07-24 17:42:25 -04:00
m_controlEnabled = true ;
2014-06-19 21:43:31 -04:00
m_controlModeVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Disable the closed loop controller .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* Stop driving the output based on the feedback .
*/
void CANJaguar : : DisableControl ( )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize = 0 ;
2014-07-29 11:09:37 -04:00
// Disable all control
sendMessage ( LM_API_VOLT_DIS , dataBuffer , dataSize ) ;
sendMessage ( LM_API_SPD_DIS , dataBuffer , dataSize ) ;
sendMessage ( LM_API_POS_DIS , dataBuffer , dataSize ) ;
sendMessage ( LM_API_ICTRL_DIS , dataBuffer , dataSize ) ;
sendMessage ( LM_API_VCOMP_DIS , dataBuffer , dataSize ) ;
// Stop all periodic setpoints
sendMessage ( LM_API_VOLT_T_SET , dataBuffer , dataSize , CAN_SEND_PERIOD_STOP_REPEATING ) ;
sendMessage ( LM_API_SPD_T_SET , dataBuffer , dataSize , CAN_SEND_PERIOD_STOP_REPEATING ) ;
sendMessage ( LM_API_POS_T_SET , dataBuffer , dataSize , CAN_SEND_PERIOD_STOP_REPEATING ) ;
sendMessage ( LM_API_ICTRL_T_SET , dataBuffer , dataSize , CAN_SEND_PERIOD_STOP_REPEATING ) ;
sendMessage ( LM_API_VCOMP_T_SET , dataBuffer , dataSize , CAN_SEND_PERIOD_STOP_REPEATING ) ;
2014-07-24 17:42:25 -04:00
m_controlEnabled = false ;
2013-12-15 18:30:16 -05:00
}
2014-06-25 15:42:16 -04:00
/**
* Enable controlling the motor voltage as a percentage of the bus voltage
2014-07-03 12:05:29 -04:00
* without any position or speed feedback . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*/
void CANJaguar : : SetPercentMode ( )
{
ChangeControlMode ( kPercentVbus ) ;
SetPositionReference ( LM_REF_NONE ) ;
SetSpeedReference ( LM_REF_NONE ) ;
}
/**
* Enable controlling the motor voltage as a percentage of the bus voltage ,
2014-07-03 12:05:29 -04:00
* and enable speed sensing from a non - quadrature encoder . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
2014-07-03 12:05:29 -04:00
* @ param tag The constant CANJaguar : : Encoder
2014-06-25 15:42:16 -04:00
* @ param codesPerRev The counts per revolution on the encoder
*/
void CANJaguar : : SetPercentMode ( CANJaguar : : EncoderStruct , uint16_t codesPerRev )
{
ChangeControlMode ( kPercentVbus ) ;
SetPositionReference ( LM_REF_NONE ) ;
SetSpeedReference ( LM_REF_ENCODER ) ;
ConfigEncoderCodesPerRev ( codesPerRev ) ;
}
/**
2014-07-03 12:05:29 -04:00
* Enable controlling the motor voltage as a percentage of the bus voltage ,
* and enable speed sensing from a non - quadrature encoder . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
*
* @ param tag The constant CANJaguar : : QuadEncoder
* @ param codesPerRev The counts per revolution on the encoder
*/
2014-06-25 15:42:16 -04:00
void CANJaguar : : SetPercentMode ( CANJaguar : : QuadEncoderStruct , uint16_t codesPerRev )
{
ChangeControlMode ( kPercentVbus ) ;
2014-07-16 10:23:46 -04:00
SetPositionReference ( LM_REF_ENCODER ) ;
2014-06-25 15:42:16 -04:00
SetSpeedReference ( LM_REF_QUAD_ENCODER ) ;
ConfigEncoderCodesPerRev ( codesPerRev ) ;
}
/**
* Enable controlling the motor voltage as a percentage of the bus voltage ,
2014-07-03 12:05:29 -04:00
* and enable position sensing from a potentiometer and no speed feedback . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param potentiometer The constant CANJaguar : : Potentiometer
*/
void CANJaguar : : SetPercentMode ( CANJaguar : : PotentiometerStruct )
{
ChangeControlMode ( kPercentVbus ) ;
SetPositionReference ( LM_REF_POT ) ;
SetSpeedReference ( LM_REF_NONE ) ;
ConfigPotentiometerTurns ( 1 ) ;
}
/**
2014-07-03 12:05:29 -04:00
* Enable controlling the motor current with a PID loop . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
*/
void CANJaguar : : SetCurrentMode ( double p , double i , double d )
{
ChangeControlMode ( kCurrent ) ;
SetPositionReference ( LM_REF_NONE ) ;
SetSpeedReference ( LM_REF_NONE ) ;
SetPID ( p , i , d ) ;
}
/**
* Enable controlling the motor current with a PID loop , and enable speed
2014-07-03 12:05:29 -04:00
* sensing from a non - quadrature encoder . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param encoder The constant CANJaguar : : Encoder
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
*/
void CANJaguar : : SetCurrentMode ( CANJaguar : : EncoderStruct , uint16_t codesPerRev , double p , double i , double d )
{
ChangeControlMode ( kCurrent ) ;
SetPositionReference ( LM_REF_NONE ) ;
SetSpeedReference ( LM_REF_NONE ) ;
ConfigEncoderCodesPerRev ( codesPerRev ) ;
SetPID ( p , i , d ) ;
}
/**
* Enable controlling the motor current with a PID loop , and enable speed and
2014-07-03 12:05:29 -04:00
* position sensing from a quadrature encoder . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param endoer The constant CANJaguar : : QuadEncoder
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
*/
void CANJaguar : : SetCurrentMode ( CANJaguar : : QuadEncoderStruct , uint16_t codesPerRev , double p , double i , double d )
{
ChangeControlMode ( kCurrent ) ;
2014-07-16 10:23:46 -04:00
SetPositionReference ( LM_REF_ENCODER ) ;
2014-06-25 15:42:16 -04:00
SetSpeedReference ( LM_REF_QUAD_ENCODER ) ;
ConfigEncoderCodesPerRev ( codesPerRev ) ;
SetPID ( p , i , d ) ;
}
/**
* Enable controlling the motor current with a PID loop , and enable position
2014-07-03 12:05:29 -04:00
* sensing from a potentiometer . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param potentiometer The constant CANJaguar : : Potentiometer
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
*/
void CANJaguar : : SetCurrentMode ( CANJaguar : : PotentiometerStruct , double p , double i , double d )
{
ChangeControlMode ( kCurrent ) ;
SetPositionReference ( LM_REF_POT ) ;
SetSpeedReference ( LM_REF_NONE ) ;
ConfigPotentiometerTurns ( 1 ) ;
SetPID ( p , i , d ) ;
}
/**
* Enable controlling the speed with a feedback loop from a non - quadrature
2014-07-03 12:05:29 -04:00
* encoder . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param encoder The constant CANJaguar : : Encoder
2014-07-03 12:05:29 -04:00
* @ param codesPerRev The counts per revolution on the encoder .
2014-06-25 15:42:16 -04:00
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
*/
void CANJaguar : : SetSpeedMode ( CANJaguar : : EncoderStruct , uint16_t codesPerRev , double p , double i , double d )
{
ChangeControlMode ( kSpeed ) ;
SetPositionReference ( LM_REF_NONE ) ;
SetSpeedReference ( LM_REF_ENCODER ) ;
ConfigEncoderCodesPerRev ( codesPerRev ) ;
SetPID ( p , i , d ) ;
}
/**
2014-07-03 12:05:29 -04:00
* Enable controlling the speed with a feedback loop from a quadrature encoder . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param encoder The constant CANJaguar : : QuadEncoder
2014-07-03 12:05:29 -04:00
* @ param codesPerRev The counts per revolution on the encoder .
2014-06-25 15:42:16 -04:00
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
*/
void CANJaguar : : SetSpeedMode ( CANJaguar : : QuadEncoderStruct , uint16_t codesPerRev , double p , double i , double d )
{
ChangeControlMode ( kSpeed ) ;
2014-07-16 10:23:46 -04:00
SetPositionReference ( LM_REF_ENCODER ) ;
2014-06-25 15:42:16 -04:00
SetSpeedReference ( LM_REF_QUAD_ENCODER ) ;
ConfigEncoderCodesPerRev ( codesPerRev ) ;
SetPID ( p , i , d ) ;
}
/**
2014-07-03 12:05:29 -04:00
* Enable controlling the position with a feedback loop using an encoder . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param encoder The constant CANJaguar : : QuadEncoder
2014-07-03 12:05:29 -04:00
* @ param codesPerRev The counts per revolution on the encoder .
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
2014-06-25 15:42:16 -04:00
*
*/
void CANJaguar : : SetPositionMode ( CANJaguar : : QuadEncoderStruct , uint16_t codesPerRev , double p , double i , double d )
{
ChangeControlMode ( kPosition ) ;
2014-07-16 10:23:46 -04:00
SetPositionReference ( LM_REF_ENCODER ) ;
2014-06-25 15:42:16 -04:00
ConfigEncoderCodesPerRev ( codesPerRev ) ;
SetPID ( p , i , d ) ;
}
/**
2014-07-03 12:05:29 -04:00
* Enable controlling the position with a feedback loop using a potentiometer . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
* @ param p The proportional gain of the Jaguar ' s PID controller .
* @ param i The integral gain of the Jaguar ' s PID controller .
* @ param d The differential gain of the Jaguar ' s PID controller .
2014-06-25 15:42:16 -04:00
*/
void CANJaguar : : SetPositionMode ( CANJaguar : : PotentiometerStruct , double p , double i , double d )
{
ChangeControlMode ( kPosition ) ;
SetPositionReference ( LM_REF_POT ) ;
ConfigPotentiometerTurns ( 1 ) ;
SetPID ( p , i , d ) ;
}
/**
2014-07-03 12:05:29 -04:00
* Enable controlling the motor voltage without any position or speed feedback . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*/
void CANJaguar : : SetVoltageMode ( )
{
ChangeControlMode ( kVoltage ) ;
SetPositionReference ( LM_REF_NONE ) ;
SetSpeedReference ( LM_REF_NONE ) ;
}
/**
* Enable controlling the motor voltage with speed feedback from a
2014-07-03 12:05:29 -04:00
* non - quadrature encoder and no position feedback . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param encoder The constant CANJaguar : : Encoder
* @ param codesPerRev The counts per revolution on the encoder
*/
void CANJaguar : : SetVoltageMode ( CANJaguar : : EncoderStruct , uint16_t codesPerRev )
{
ChangeControlMode ( kVoltage ) ;
SetPositionReference ( LM_REF_NONE ) ;
SetSpeedReference ( LM_REF_ENCODER ) ;
ConfigEncoderCodesPerRev ( codesPerRev ) ;
}
/**
* Enable controlling the motor voltage with position and speed feedback from a
2014-07-03 12:05:29 -04:00
* quadrature encoder . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param encoder The constant CANJaguar : : QuadEncoder
* @ param codesPerRev The counts per revolution on the encoder
*/
void CANJaguar : : SetVoltageMode ( CANJaguar : : QuadEncoderStruct , uint16_t codesPerRev )
{
ChangeControlMode ( kVoltage ) ;
2014-07-16 10:23:46 -04:00
SetPositionReference ( LM_REF_ENCODER ) ;
2014-06-25 15:42:16 -04:00
SetSpeedReference ( LM_REF_QUAD_ENCODER ) ;
ConfigEncoderCodesPerRev ( codesPerRev ) ;
}
/**
* Enable controlling the motor voltage with position feedback from a
2014-07-03 12:05:29 -04:00
* potentiometer and no speed feedback . < br >
* After calling this you must call { @ link CANJaguar # EnableControl ( ) } or { @ link CANJaguar # EnableControl ( double ) } to enable the device .
2014-06-25 15:42:16 -04:00
*
* @ param potentiometer The constant CANJaguar : : Potentiometer
*/
void CANJaguar : : SetVoltageMode ( CANJaguar : : PotentiometerStruct )
{
ChangeControlMode ( kVoltage ) ;
SetPositionReference ( LM_REF_POT ) ;
SetSpeedReference ( LM_REF_NONE ) ;
ConfigPotentiometerTurns ( 1 ) ;
}
2013-12-15 18:30:16 -05:00
/**
2014-07-03 12:05:29 -04:00
* Used internally . In order to set the control mode see the methods listed below .
2013-12-15 18:30:16 -05:00
* Change the control mode of this Jaguar object .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* After changing modes , configure any PID constants or other settings needed
* and then EnableControl ( ) to actually change the mode on the Jaguar .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param controlMode The new mode .
*/
void CANJaguar : : ChangeControlMode ( ControlMode controlMode )
{
// Disable the previous mode
DisableControl ( ) ;
// Update the local mode
m_controlMode = controlMode ;
2014-07-24 13:23:09 -04:00
m_controlModeVerified = false ;
2013-12-15 18:30:16 -05:00
2014-01-06 10:12:21 -05:00
HALReport ( HALUsageReporting : : kResourceType_CANJaguar , m_deviceNumber , m_controlMode ) ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the active control mode from the Jaguar .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* Ask the Jag what mode it is in .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return ControlMode that the Jag is in .
*/
CANJaguar : : ControlMode CANJaguar : : GetControlMode ( )
{
2014-06-19 21:43:31 -04:00
return m_controlMode ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the voltage at the battery input terminals of the Jaguar .
2014-06-13 17:45:10 -04:00
*
2014-07-03 12:05:29 -04:00
* @ return The bus voltage in volts .
2013-12-15 18:30:16 -05:00
*/
float CANJaguar : : GetBusVoltage ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-16 10:24:48 -04:00
return m_busVoltage ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the voltage being output from the motor terminals of the Jaguar .
2014-06-13 17:45:10 -04:00
*
2014-07-03 12:05:29 -04:00
* @ return The output voltage in volts .
2013-12-15 18:30:16 -05:00
*/
float CANJaguar : : GetOutputVoltage ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
return m_outputVoltage ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the current through the motor terminals of the Jaguar .
2014-06-13 17:45:10 -04:00
*
2014-07-03 12:05:29 -04:00
* @ return The output current in amps .
2013-12-15 18:30:16 -05:00
*/
float CANJaguar : : GetOutputCurrent ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
return m_outputCurrent ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the internal temperature of the Jaguar .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The temperature of the Jaguar in degrees Celsius .
*/
float CANJaguar : : GetTemperature ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
return m_temperature ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the position of the encoder or potentiometer .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The position of the motor in rotations based on the configured feedback .
2014-07-03 12:05:29 -04:00
* @ see CANJaguar # ConfigPotentiometerTurns ( int )
* @ see CANJaguar # ConfigEncoderCodesPerRev ( int )
2013-12-15 18:30:16 -05:00
*/
double CANJaguar : : GetPosition ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
return m_position ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the speed of the encoder .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The speed of the motor in RPM based on the configured feedback .
*/
double CANJaguar : : GetSpeed ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
return m_speed ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the status of the forward limit switch .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The motor is allowed to turn in the forward direction when true .
*/
bool CANJaguar : : GetForwardLimitOK ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-16 10:24:48 -04:00
return m_limits & kForwardLimit ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the status of the reverse limit switch .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The motor is allowed to turn in the reverse direction when true .
*/
bool CANJaguar : : GetReverseLimitOK ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-16 10:24:48 -04:00
2014-06-19 21:43:31 -04:00
return m_limits & kReverseLimit ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the status of any faults the Jaguar has detected .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return A bit - mask of faults defined by the " Faults " enum .
2014-07-03 12:05:29 -04:00
* @ see # kCurrentFault
* @ see # kBusVoltageFault
* @ see # kTemperatureFault
* @ see # kGateDriverFault
2013-12-15 18:30:16 -05:00
*/
uint16_t CANJaguar : : GetFaults ( )
{
2014-07-01 12:02:44 -04:00
updatePeriodicStatus ( ) ;
2014-06-19 21:43:31 -04:00
return m_faults ;
2013-12-15 18:30:16 -05:00
}
/**
* Set the maximum voltage change rate .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* When in PercentVbus or Voltage output mode , the rate at which the voltage changes can
* be limited to reduce current spikes . Set this to 0.0 to disable rate limiting .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param rampRate The maximum rate of voltage change in Percent Voltage mode in V / s .
*/
void CANJaguar : : SetVoltageRampRate ( double rampRate )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
2014-06-19 21:43:31 -04:00
uint32_t message ;
2013-12-15 18:30:16 -05:00
switch ( m_controlMode )
{
case kPercentVbus :
dataSize = packPercentage ( dataBuffer , rampRate / ( m_maxOutputVoltage * kControllerRate ) ) ;
2014-06-19 21:43:31 -04:00
message = LM_API_VOLT_SET_RAMP ;
2013-12-15 18:30:16 -05:00
break ;
case kVoltage :
dataSize = packFXP8_8 ( dataBuffer , rampRate / kControllerRate ) ;
2014-07-16 10:23:46 -04:00
message = LM_API_VCOMP_COMP_RAMP ;
2013-12-15 18:30:16 -05:00
break ;
default :
2014-06-24 11:01:52 -04:00
wpi_setWPIErrorWithContext ( IncompatibleMode , " SetVoltageRampRate only applies in Voltage and Percent mode " ) ;
2013-12-15 18:30:16 -05:00
return ;
}
2014-06-19 21:43:31 -04:00
sendMessage ( message , dataBuffer , dataSize ) ;
m_voltageRampRate = rampRate ;
m_voltageRampRateVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the version of the firmware running on the Jaguar .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The firmware version . 0 if the device did not respond .
*/
uint32_t CANJaguar : : GetFirmwareVersion ( )
{
2014-06-19 21:43:31 -04:00
return m_firmwareVersion ;
2013-12-15 18:30:16 -05:00
}
/**
* Get the version of the Jaguar hardware .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ return The hardware version . 1 : Jaguar , 2 : Black Jaguar
*/
uint8_t CANJaguar : : GetHardwareVersion ( )
{
2014-06-16 10:24:48 -04:00
return m_hardwareVersion ;
2013-12-15 18:30:16 -05:00
}
/**
* Configure what the controller does to the H - Bridge when neutral ( not driving the output ) .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* This allows you to override the jumper configuration for brake or coast .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param mode Select to use the jumper setting or to override it to coast or brake .
*/
void CANJaguar : : ConfigNeutralMode ( NeutralMode mode )
{
uint8_t dataBuffer [ 8 ] ;
2014-06-19 21:43:31 -04:00
// Set the neutral mode
sendMessage ( LM_API_CFG_BRAKE_COAST , dataBuffer , sizeof ( uint8_t ) ) ;
m_neutralMode = mode ;
m_neutralModeVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Configure how many codes per revolution are generated by your encoder .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param codesPerRev The number of counts per revolution in 1 X mode .
*/
void CANJaguar : : ConfigEncoderCodesPerRev ( uint16_t codesPerRev )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
2014-06-19 21:43:31 -04:00
// Set the codes per revolution mode
2013-12-15 18:30:16 -05:00
dataSize = packint16_t ( dataBuffer , codesPerRev ) ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_CFG_ENC_LINES , dataBuffer , sizeof ( uint16_t ) ) ;
m_encoderCodesPerRev = codesPerRev ;
m_encoderCodesPerRevVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Configure the number of turns on the potentiometer .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* There is no special support for continuous turn potentiometers .
* Only integer numbers of turns are supported .
2014-06-13 17:45:10 -04:00
*
2014-07-03 12:05:29 -04:00
* @ param turns The number of turns of the potentiometer .
2013-12-15 18:30:16 -05:00
*/
void CANJaguar : : ConfigPotentiometerTurns ( uint16_t turns )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
2014-06-19 21:43:31 -04:00
// Set the pot turns
2013-12-15 18:30:16 -05:00
dataSize = packint16_t ( dataBuffer , turns ) ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_CFG_POT_TURNS , dataBuffer , dataSize ) ;
m_potentiometerTurns = turns ;
m_potentiometerTurnsVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Configure Soft Position Limits when in Position Controller mode .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* When controlling position , you can add additional limits on top of the limit switch inputs
* that are based on the position feedback . If the position limit is reached or the
* switch is opened , that direction will be disabled .
2014-06-13 17:45:10 -04:00
*
2014-05-16 14:11:30 -04:00
2013-12-15 18:30:16 -05:00
* @ param forwardLimitPosition The position that if exceeded will disable the forward direction .
* @ param reverseLimitPosition The position that if exceeded will disable the reverse direction .
*/
void CANJaguar : : ConfigSoftPositionLimits ( double forwardLimitPosition , double reverseLimitPosition )
{
2014-06-19 21:43:31 -04:00
ConfigLimitMode ( kLimitMode_SoftPositionLimits ) ;
ConfigForwardLimit ( forwardLimitPosition ) ;
ConfigReverseLimit ( reverseLimitPosition ) ;
2013-12-15 18:30:16 -05:00
}
/**
* Disable Soft Position Limits if previously enabled .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* Soft Position Limits are disabled by default .
*/
void CANJaguar : : DisableSoftPositionLimits ( )
2014-06-19 21:43:31 -04:00
{
ConfigLimitMode ( kLimitMode_SwitchInputsOnly ) ;
}
/**
* Set the limit mode for position control mode .
*
* Use ConfigSoftPositionLimits or DisableSoftPositionLimits to set this
* automatically .
*/
void CANJaguar : : ConfigLimitMode ( LimitMode mode )
2013-12-15 18:30:16 -05:00
{
uint8_t dataBuffer [ 8 ] ;
2014-06-19 21:43:31 -04:00
dataBuffer [ 0 ] = mode ;
sendMessage ( LM_API_CFG_LIMIT_MODE , dataBuffer , sizeof ( uint8_t ) ) ;
m_limitMode = mode ;
m_limitModeVerified = false ;
}
/**
* Set the position that if exceeded will disable the forward direction .
*
* Use ConfigSoftPositionLimits to set this and the limit mode automatically .
*/
void CANJaguar : : ConfigForwardLimit ( double forwardLimitPosition )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
dataSize = packFXP16_16 ( dataBuffer , forwardLimitPosition ) ;
dataBuffer [ dataSize + + ] = 1 ;
sendMessage ( LM_API_CFG_LIMIT_FWD , dataBuffer , dataSize ) ;
m_forwardLimit = forwardLimitPosition ;
m_forwardLimitVerified = false ;
}
/**
* Set the position that if exceeded will disable the reverse direction .
*
* Use ConfigSoftPositionLimits to set this and the limit mode automatically .
*/
void CANJaguar : : ConfigReverseLimit ( double reverseLimitPosition )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
dataSize = packFXP16_16 ( dataBuffer , reverseLimitPosition ) ;
dataBuffer [ dataSize + + ] = 0 ;
sendMessage ( LM_API_CFG_LIMIT_REV , dataBuffer , dataSize ) ;
m_reverseLimit = reverseLimitPosition ;
m_reverseLimitVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Configure the maximum voltage that the Jaguar will ever output .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* 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 .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param voltage The maximum voltage output by the Jaguar .
*/
void CANJaguar : : ConfigMaxOutputVoltage ( double voltage )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
dataSize = packFXP8_8 ( dataBuffer , voltage ) ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_CFG_MAX_VOUT , dataBuffer , dataSize ) ;
m_maxOutputVoltage = voltage ;
m_maxOutputVoltageVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Configure how long the Jaguar waits in the case of a fault before resuming operation .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* Faults include over temerature , over current , and bus under voltage .
* The default is 3.0 seconds , but can be reduced to as low as 0.5 seconds .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param faultTime The time to wait before resuming operation , in seconds .
*/
void CANJaguar : : ConfigFaultTime ( float faultTime )
{
uint8_t dataBuffer [ 8 ] ;
uint8_t dataSize ;
2014-07-23 15:22:26 -04:00
if ( faultTime < 0.5 ) faultTime = 0.5 ;
else if ( faultTime > 3.0 ) faultTime = 3.0 ;
2013-12-15 18:30:16 -05:00
// Message takes ms
dataSize = packint16_t ( dataBuffer , ( int16_t ) ( faultTime * 1000.0 ) ) ;
2014-06-19 21:43:31 -04:00
sendMessage ( LM_API_CFG_FAULT_TIME , dataBuffer , dataSize ) ;
m_faultTime = faultTime ;
m_faultTimeVerified = false ;
2013-12-15 18:30:16 -05:00
}
/**
* Update all the motors that have pending sets in the syncGroup .
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ param syncGroup A bitmask of groups to generate synchronous output .
*/
void CANJaguar : : UpdateSyncGroup ( uint8_t syncGroup )
{
2014-06-19 21:43:31 -04:00
sendMessageHelper ( CAN_MSGID_API_SYNC , & syncGroup , sizeof ( syncGroup ) , CAN_SEND_PERIOD_NO_REPEAT ) ;
2013-12-15 18:30:16 -05:00
}
void CANJaguar : : SetExpiration ( float timeout )
{
if ( m_safetyHelper ) m_safetyHelper - > SetExpiration ( timeout ) ;
}
float CANJaguar : : GetExpiration ( )
{
if ( ! m_safetyHelper ) return 0.0 ;
return m_safetyHelper - > GetExpiration ( ) ;
}
bool CANJaguar : : IsAlive ( )
{
if ( ! m_safetyHelper ) return false ;
return m_safetyHelper - > IsAlive ( ) ;
}
bool CANJaguar : : IsSafetyEnabled ( )
{
if ( ! m_safetyHelper ) return false ;
return m_safetyHelper - > IsSafetyEnabled ( ) ;
}
void CANJaguar : : SetSafetyEnabled ( bool enabled )
{
if ( m_safetyHelper ) m_safetyHelper - > SetSafetyEnabled ( enabled ) ;
}
void CANJaguar : : GetDescription ( char * desc )
{
sprintf ( desc , " CANJaguar ID %d " , m_deviceNumber ) ;
}
/**
* Common interface for stopping the motor
* Part of the MotorSafety interface
2014-06-13 17:45:10 -04:00
*
2013-12-15 18:30:16 -05:00
* @ deprecated Call DisableControl instead .
*/
void CANJaguar : : StopMotor ( )
{
DisableControl ( ) ;
}
2014-06-16 10:24:48 -04:00
void CANJaguar : : ValueChanged ( ITable * source , const std : : string & key , EntryValue value , bool isNew )
{
2013-12-15 18:30:16 -05:00
Set ( value . f ) ;
}
2014-06-16 10:24:48 -04:00
void CANJaguar : : UpdateTable ( )
{
if ( m_table ! = NULL )
2014-06-19 21:43:31 -04:00
{
2013-12-15 18:30:16 -05:00
m_table - > PutNumber ( " Value " , Get ( ) ) ;
}
}
2014-06-16 10:24:48 -04:00
void CANJaguar : : StartLiveWindowMode ( )
{
if ( m_table ! = NULL )
2014-06-19 21:43:31 -04:00
{
2013-12-15 18:30:16 -05:00
m_table - > AddTableListener ( " Value " , this , true ) ;
}
}
2014-06-16 10:24:48 -04:00
void CANJaguar : : StopLiveWindowMode ( )
{
if ( m_table ! = NULL )
2014-06-19 21:43:31 -04:00
{
2013-12-15 18:30:16 -05:00
m_table - > RemoveTableListener ( this ) ;
}
}
2014-06-16 10:24:48 -04:00
std : : string CANJaguar : : GetSmartDashboardType ( )
{
2013-12-15 18:30:16 -05:00
return " Speed Controller " ;
}
2014-06-16 10:24:48 -04:00
void CANJaguar : : InitTable ( ITable * subTable )
{
2013-12-15 18:30:16 -05:00
m_table = subTable ;
UpdateTable ( ) ;
}
2014-06-16 10:24:48 -04:00
ITable * CANJaguar : : GetTable ( )
{
2013-12-15 18:30:16 -05:00
return m_table ;
}