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

1986 lines
61 KiB
C++
Raw Normal View History

/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2009. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "CANJaguar.h"
#include "Timer.h"
#define tNIRIO_i32 int
#include "NetworkCommunication/CANSessionMux.h"
//#include "NetworkCommunication/UsageReporting.h"
#include "WPIErrors.h"
#include <cstdio>
#include <cassert>
#include "LiveWindow/LiveWindow.h"
/* we are on ARM-LE now, not Freescale so no need to swap */
#define swap16(x) (x)
#define swap32(x) (x)
/* Compare floats for equality as fixed point numbers */
#define FXP8_EQ(a, b) ((int16_t)((a)*256.0) == (int16_t)((b)*256.0))
#define FXP16_EQ(a, b) ((int32_t)((a)*65536.0) == (int32_t)((b)*65536.0))
const int32_t CANJaguar::kControllerRate;
constexpr double CANJaguar::kApproxBusVoltage;
static const int32_t kSendMessagePeriod = 20;
static const uint32_t kFullMessageIDMask =
(CAN_MSGID_API_M | CAN_MSGID_MFR_M | CAN_MSGID_DTYPE_M);
static const int32_t kReceiveStatusAttempts = 50;
static std::unique_ptr<Resource> allocated;
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 (auto& kTrustedMessage : kTrustedMessages) {
if ((kFullMessageIDMask & messageID) == kTrustedMessage) {
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;
}
/**
* Common initialization code called by all constructors.
*/
void CANJaguar::InitCANJaguar() {
artf4154: Get rid of raw pointers in C++. This deals with the majority of the user-facing code in wpilibC++Devices and a substantial portion of it in wpilibC++. wpilibC++Sim and wpilibC++IntegrationTests are untouched except where it is necessary to make them work with the rest of the libraries. There is still a lot to do in the following areas: -The HAL (which we may not want to touch at all). -The I2C, Serial, and SPI interfaces in wpilibC++Devices, which I haven't gotten around to doing yet. -Most wpilibC++Devices classes have void* pointers for interacting with the HAL. -InterruptableSensorBase passes a void *params for the interrupt handler. -I haven't converted all the const char* to std::strings. -There are plenty of other cases of raw pointers still existing. -This doesn't fall directly under raw pointer stuff, but move syntax and rvalue references could be introduced in many places. -I haven't touched vision code. -The Resource classes conflict (one is in the hal, the other in wpilibC++). Someone should figure out a more permanent fix (eg, just renaming them), then doing what I did (making a new namespace for one of them, essentially the same as renaming it). A few other things: -I created a NullDeleter class which is marked as deprecated. What this does is it can be passed as the deleter to a std::shared_ptr so that when you are converting raw pointers to shared_ptrs the shared_ptr doesn't do any deletion if someone else owns the raw pointer. This should only be used in making old raw pointer UIs. -I had to alter the build.gradle so that it did not emit errors when deprecated functions called deprecated functions. Unfortunately, gradle doesn't appear to be actually printing out gcc warnigns for some reason. The best way I have found to fix this is to patch the toolchains (https://bitbucket.org/byteit101/toolchain-builder/pull-request/5/make-gcc-not-throw-warnings-for-nested/diff) so that a deprecated function calling a deprecated function is fine but a non-deprecated function calling a deprecated function will throw a warning (which we then elevate with -Werror). I believe that clang deals with this properly, although I have not tried it myself. Change-Id: Ib8090c66893576fe73654f4e9d268f9d37be06a2
2015-06-30 15:01:20 -04:00
m_safetyHelper = std::make_unique<MotorSafetyHelper>(this);
bool receivedFirmwareVersion = false;
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);
// Wait until we've gotten all of the status data at least once.
for (int i = 0; i < kReceiveStatusAttempts; i++) {
Wait(0.001);
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) {
break;
}
}
if (!m_receivedStatusMessage0 || !m_receivedStatusMessage1 ||
!m_receivedStatusMessage2 || !receivedFirmwareVersion) {
wpi_setWPIErrorWithContext(JaguarMessageNotFound, "Status data not found");
}
if (getMessage(LM_API_HWVER, CAN_MSGID_FULL_M, dataBuffer, &dataSize))
m_hardwareVersion = dataBuffer[0];
if (m_deviceNumber < 1 || m_deviceNumber > 63) {
std::stringstream buf;
buf << "device number \"" << m_deviceNumber
<< "\" must be between 1 and 63";
wpi_setWPIErrorWithContext(ParameterOutOfRange, buf.str());
return;
}
if (StatusIsFatal()) return;
// 3330 was the first shipping RDK firmware version for the Jaguar
if (m_firmwareVersion >= 3330 || m_firmwareVersion < 108) {
std::stringstream buf;
if (m_firmwareVersion < 3330) {
buf << "Jag #" << m_deviceNumber << " firmware (" << m_firmwareVersion
<< ") is too old (must be at least version 108 "
"of the FIRST approved firmware)";
} else {
buf << "Jag #" << m_deviceNumber << " firmware (" << m_firmwareVersion
<< ") is not FIRST approved (must be at least "
"version 108 of the FIRST approved firmware)";
}
wpi_setWPIErrorWithContext(JaguarVersionError, buf.str());
return;
}
switch (m_controlMode) {
case kPercentVbus:
case kVoltage:
// No additional configuration required... start enabled.
EnableControl();
break;
default:
break;
}
HALReport(HALUsageReporting::kResourceType_CANJaguar, m_deviceNumber,
m_controlMode);
artf4154: Get rid of raw pointers in C++. This deals with the majority of the user-facing code in wpilibC++Devices and a substantial portion of it in wpilibC++. wpilibC++Sim and wpilibC++IntegrationTests are untouched except where it is necessary to make them work with the rest of the libraries. There is still a lot to do in the following areas: -The HAL (which we may not want to touch at all). -The I2C, Serial, and SPI interfaces in wpilibC++Devices, which I haven't gotten around to doing yet. -Most wpilibC++Devices classes have void* pointers for interacting with the HAL. -InterruptableSensorBase passes a void *params for the interrupt handler. -I haven't converted all the const char* to std::strings. -There are plenty of other cases of raw pointers still existing. -This doesn't fall directly under raw pointer stuff, but move syntax and rvalue references could be introduced in many places. -I haven't touched vision code. -The Resource classes conflict (one is in the hal, the other in wpilibC++). Someone should figure out a more permanent fix (eg, just renaming them), then doing what I did (making a new namespace for one of them, essentially the same as renaming it). A few other things: -I created a NullDeleter class which is marked as deprecated. What this does is it can be passed as the deleter to a std::shared_ptr so that when you are converting raw pointers to shared_ptrs the shared_ptr doesn't do any deletion if someone else owns the raw pointer. This should only be used in making old raw pointer UIs. -I had to alter the build.gradle so that it did not emit errors when deprecated functions called deprecated functions. Unfortunately, gradle doesn't appear to be actually printing out gcc warnigns for some reason. The best way I have found to fix this is to patch the toolchains (https://bitbucket.org/byteit101/toolchain-builder/pull-request/5/make-gcc-not-throw-warnings-for-nested/diff) so that a deprecated function calling a deprecated function is fine but a non-deprecated function calling a deprecated function will throw a warning (which we then elevate with -Werror). I believe that clang deals with this properly, although I have not tried it myself. Change-Id: Ib8090c66893576fe73654f4e9d268f9d37be06a2
2015-06-30 15:01:20 -04:00
LiveWindow::GetInstance().AddActuator("CANJaguar", m_deviceNumber, this);
}
/**
* 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.
*
* @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)
*/
CANJaguar::CANJaguar(uint8_t deviceNumber)
: m_deviceNumber(deviceNumber) {
std::stringstream buf;
buf << "CANJaguar device number " << m_deviceNumber;
artf4154: Get rid of raw pointers in C++. This deals with the majority of the user-facing code in wpilibC++Devices and a substantial portion of it in wpilibC++. wpilibC++Sim and wpilibC++IntegrationTests are untouched except where it is necessary to make them work with the rest of the libraries. There is still a lot to do in the following areas: -The HAL (which we may not want to touch at all). -The I2C, Serial, and SPI interfaces in wpilibC++Devices, which I haven't gotten around to doing yet. -Most wpilibC++Devices classes have void* pointers for interacting with the HAL. -InterruptableSensorBase passes a void *params for the interrupt handler. -I haven't converted all the const char* to std::strings. -There are plenty of other cases of raw pointers still existing. -This doesn't fall directly under raw pointer stuff, but move syntax and rvalue references could be introduced in many places. -I haven't touched vision code. -The Resource classes conflict (one is in the hal, the other in wpilibC++). Someone should figure out a more permanent fix (eg, just renaming them), then doing what I did (making a new namespace for one of them, essentially the same as renaming it). A few other things: -I created a NullDeleter class which is marked as deprecated. What this does is it can be passed as the deleter to a std::shared_ptr so that when you are converting raw pointers to shared_ptrs the shared_ptr doesn't do any deletion if someone else owns the raw pointer. This should only be used in making old raw pointer UIs. -I had to alter the build.gradle so that it did not emit errors when deprecated functions called deprecated functions. Unfortunately, gradle doesn't appear to be actually printing out gcc warnigns for some reason. The best way I have found to fix this is to patch the toolchains (https://bitbucket.org/byteit101/toolchain-builder/pull-request/5/make-gcc-not-throw-warnings-for-nested/diff) so that a deprecated function calling a deprecated function is fine but a non-deprecated function calling a deprecated function will throw a warning (which we then elevate with -Werror). I believe that clang deals with this properly, although I have not tried it myself. Change-Id: Ib8090c66893576fe73654f4e9d268f9d37be06a2
2015-06-30 15:01:20 -04:00
Resource::CreateResourceObject(allocated, 63);
if (allocated->Allocate(m_deviceNumber - 1, buf.str()) == ~0ul) {
artf4154: Get rid of raw pointers in C++. This deals with the majority of the user-facing code in wpilibC++Devices and a substantial portion of it in wpilibC++. wpilibC++Sim and wpilibC++IntegrationTests are untouched except where it is necessary to make them work with the rest of the libraries. There is still a lot to do in the following areas: -The HAL (which we may not want to touch at all). -The I2C, Serial, and SPI interfaces in wpilibC++Devices, which I haven't gotten around to doing yet. -Most wpilibC++Devices classes have void* pointers for interacting with the HAL. -InterruptableSensorBase passes a void *params for the interrupt handler. -I haven't converted all the const char* to std::strings. -There are plenty of other cases of raw pointers still existing. -This doesn't fall directly under raw pointer stuff, but move syntax and rvalue references could be introduced in many places. -I haven't touched vision code. -The Resource classes conflict (one is in the hal, the other in wpilibC++). Someone should figure out a more permanent fix (eg, just renaming them), then doing what I did (making a new namespace for one of them, essentially the same as renaming it). A few other things: -I created a NullDeleter class which is marked as deprecated. What this does is it can be passed as the deleter to a std::shared_ptr so that when you are converting raw pointers to shared_ptrs the shared_ptr doesn't do any deletion if someone else owns the raw pointer. This should only be used in making old raw pointer UIs. -I had to alter the build.gradle so that it did not emit errors when deprecated functions called deprecated functions. Unfortunately, gradle doesn't appear to be actually printing out gcc warnigns for some reason. The best way I have found to fix this is to patch the toolchains (https://bitbucket.org/byteit101/toolchain-builder/pull-request/5/make-gcc-not-throw-warnings-for-nested/diff) so that a deprecated function calling a deprecated function is fine but a non-deprecated function calling a deprecated function will throw a warning (which we then elevate with -Werror). I believe that clang deals with this properly, although I have not tried it myself. Change-Id: Ib8090c66893576fe73654f4e9d268f9d37be06a2
2015-06-30 15:01:20 -04:00
CloneError(*allocated);
return;
}
SetPercentMode();
InitCANJaguar();
ConfigMaxOutputVoltage(kApproxBusVoltage);
}
CANJaguar::~CANJaguar() {
allocated->Free(m_deviceNumber - 1);
int32_t status;
// Disable periodic setpoints
if (m_controlMode == kPercentVbus)
FRC_NetworkCommunication_CANSessionMux_sendMessage(
m_deviceNumber | LM_API_VOLT_T_SET, nullptr, 0,
CAN_SEND_PERIOD_STOP_REPEATING, &status);
else if (m_controlMode == kSpeed)
FRC_NetworkCommunication_CANSessionMux_sendMessage(
m_deviceNumber | LM_API_SPD_T_SET, nullptr, 0,
CAN_SEND_PERIOD_STOP_REPEATING, &status);
else if (m_controlMode == kPosition)
FRC_NetworkCommunication_CANSessionMux_sendMessage(
m_deviceNumber | LM_API_POS_T_SET, nullptr, 0,
CAN_SEND_PERIOD_STOP_REPEATING, &status);
else if (m_controlMode == kCurrent)
FRC_NetworkCommunication_CANSessionMux_sendMessage(
m_deviceNumber | LM_API_ICTRL_T_SET, nullptr, 0,
CAN_SEND_PERIOD_STOP_REPEATING, &status);
else if (m_controlMode == kVoltage)
FRC_NetworkCommunication_CANSessionMux_sendMessage(
m_deviceNumber | LM_API_VCOMP_T_SET, nullptr, 0,
CAN_SEND_PERIOD_STOP_REPEATING, &status);
}
/**
* @return The CAN ID passed in the constructor
*/
uint8_t CANJaguar::getDeviceNumber() const { return m_deviceNumber; }
/**
* Sets the output set-point value.
*
* 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.
*
* @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;
if (m_safetyHelper && !m_safetyHelper->IsAlive() && m_controlEnabled) {
EnableControl();
}
if (m_controlEnabled) {
switch (m_controlMode) {
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,
(m_isInverted ? -outputValue : outputValue));
} break;
case kSpeed: {
messageID = LM_API_SPD_T_SET;
dataSize = packFXP16_16(dataBuffer,
(m_isInverted ? -outputValue : 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, (m_isInverted ? -outputValue : outputValue));
} break;
default:
wpi_setWPIErrorWithContext(IncompatibleMode,
"The Jaguar only supports Current, Voltage, "
"Position, Speed, and Percent (Throttle) "
"modes.");
return;
}
if (syncGroup != 0) {
dataBuffer[dataSize] = syncGroup;
dataSize++;
}
sendMessage(messageID, dataBuffer, dataSize, kSendMessagePeriod);
if (m_safetyHelper) m_safetyHelper->Feed();
}
m_value = outputValue;
verify();
}
/**
* Get the recently set outputValue setpoint.
*
* 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>
*
* @return The most recently set outputValue setpoint.
*/
float CANJaguar::Get() const { return m_value; }
/**
* Common interface for disabling a motor.
*
* @deprecated Call {@link #DisableControl()} instead.
*/
void CANJaguar::Disable() { DisableControl(); }
/**
* Write out the PID value as seen in the PIDOutput base object.
*
* @deprecated Call Set instead.
*
* @param output Write out the PercentVbus value as was computed by the
* PIDController
*/
void 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) const {
int16_t value = *((int16_t *)buffer);
value = swap16(value);
return value / 32767.0;
}
double CANJaguar::unpackFXP8_8(uint8_t *buffer) const {
int16_t value = *((int16_t *)buffer);
value = swap16(value);
return value / 256.0;
}
double CANJaguar::unpackFXP16_16(uint8_t *buffer) const {
int32_t value = *((int32_t *)buffer);
value = swap32(value);
return value / 65536.0;
}
int16_t CANJaguar::unpackint16_t(uint8_t *buffer) const {
int16_t value = *((int16_t *)buffer);
return swap16(value);
}
int32_t CANJaguar::unpackint32_t(uint8_t *buffer) const {
int32_t value = *((int32_t *)buffer);
return swap32(value);
}
/**
* Send a message to the Jaguar.
*
* @param messageID The messageID to be used on the CAN bus (device number is
* added internally)
* @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
* @param periodic If positive, tell Network Communications to send the message
* every "period" milliseconds.
*/
void CANJaguar::sendMessage(uint32_t messageID, const uint8_t *data,
uint8_t dataSize, int32_t period) {
int32_t localStatus =
sendMessageHelper(messageID | m_deviceNumber, data, dataSize, period);
if (localStatus < 0) {
wpi_setErrorWithContext(localStatus, "sendMessage");
}
}
/**
* Request a message from the Jaguar, but don't wait for it to arrive.
*
* @param messageID The message to request
* @param periodic If positive, tell Network Communications to send the message
* every "period" milliseconds.
*/
void CANJaguar::requestMessage(uint32_t messageID, int32_t period) {
sendMessageHelper(messageID | m_deviceNumber, nullptr, 0, period);
}
/**
* Get a previously requested message.
*
* Jaguar always generates a message with the same message ID when replying.
*
* @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
*
* @return true if the message was found. Otherwise, no new message is
* available.
*/
bool CANJaguar::getMessage(uint32_t messageID, uint32_t messageMask,
uint8_t *data, uint8_t *dataSize) const {
uint32_t targetedMessageID = messageID | m_deviceNumber;
int32_t status = 0;
uint32_t timeStamp;
// Caller may have set bit31 for remote frame transmission so clear invalid
// bits[31-29]
targetedMessageID &= CAN_MSGID_FULL_M;
// Get the data.
FRC_NetworkCommunication_CANSessionMux_receiveMessage(
&targetedMessageID, messageMask, data, dataSize, &timeStamp, &status);
// Do we already have the most recent value?
if (status == ERR_CANSessionMux_MessageNotFound)
return false;
else
wpi_setErrorWithContext(status, "receiveMessage");
return true;
}
/**
* Enables periodic status updates from the Jaguar.
*/
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, LM_PSTAT_VOLTOUT_B0,
LM_PSTAT_VOLTOUT_B1, 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);
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() const {
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_mutex.lock();
m_busVoltage = unpackFXP8_8(data);
m_outputVoltage = unpackPercentage(data + 2) * m_busVoltage;
m_outputCurrent = unpackFXP8_8(data + 4);
m_temperature = unpackFXP8_8(data + 6);
m_mutex.unlock();
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_mutex.lock();
m_position = unpackFXP16_16(data);
m_speed = unpackFXP16_16(data + 4);
m_mutex.unlock();
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_mutex.lock();
m_limits = data[0];
m_faults = data[1];
m_mutex.unlock();
m_receivedStatusMessage2 = true;
}
}
/**
* 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.
*/
void CANJaguar::verify() {
uint8_t dataBuffer[8];
uint8_t dataSize;
// 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];
if (powerCycled) {
// Clear the power cycled bit
dataBuffer[0] = 1;
sendMessage(LM_API_STATUS_POWER, dataBuffer, sizeof(uint8_t));
// 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;
} else {
m_pVerified = false;
m_iVerified = false;
m_dVerified = false;
}
// 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);
}
} else {
requestMessage(LM_API_STATUS_POWER);
}
// Verify that any recently set parameters are correct
if (!m_controlModeVerified && m_controlEnabled) {
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);
}
}
if (!m_speedRefVerified) {
if (getMessage(LM_API_SPD_REF, CAN_MSGID_FULL_M, dataBuffer, &dataSize)) {
uint8_t speedRef = dataBuffer[0];
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);
}
}
if (!m_posRefVerified) {
if (getMessage(LM_API_POS_REF, CAN_MSGID_FULL_M, dataBuffer, &dataSize)) {
uint8_t posRef = dataBuffer[0];
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);
}
}
if (!m_pVerified) {
uint32_t message = 0;
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;
else {
wpi_setWPIErrorWithContext(
IncompatibleMode,
"PID constants only apply in Speed, Position, and Current mode");
return;
}
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 = 0;
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;
else {
wpi_setWPIErrorWithContext(
IncompatibleMode,
"PID constants only apply in Speed, Position, and Current mode");
return;
}
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 = 0;
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;
else {
wpi_setWPIErrorWithContext(
IncompatibleMode,
"PID constants only apply in Speed, Position, and Current mode");
return;
}
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)) {
double voltage = unpackFXP8_8(dataBuffer);
// 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)
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);
}
}
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) {
if (getMessage(LM_API_VCOMP_COMP_RAMP, CAN_MSGID_FULL_M, dataBuffer,
&dataSize)) {
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.
requestMessage(LM_API_VCOMP_COMP_RAMP);
}
}
}
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();
}
}
/**
* Set the reference source device for speed controller mode.
*
* Choose encoder as the source of speed feedback when in speed control mode.
*
* @param reference Specify a speed reference.
*/
void CANJaguar::SetSpeedReference(uint8_t reference) {
uint8_t dataBuffer[8];
// Send the speed reference parameter
dataBuffer[0] = reference;
sendMessage(LM_API_SPD_REF, dataBuffer, sizeof(uint8_t));
m_speedReference = reference;
m_speedRefVerified = false;
}
/**
* Get the reference source device for speed controller mode.
*
* @return A speed reference indicating the currently selected reference device
* for speed controller mode.
*/
uint8_t CANJaguar::GetSpeedReference() const { return m_speedReference; }
/**
* Set the reference source device for position controller mode.
*
* Choose between using and encoder and using a potentiometer
* as the source of position feedback when in position control mode.
*
* @param reference Specify a PositionReference.
*/
void CANJaguar::SetPositionReference(uint8_t reference) {
uint8_t dataBuffer[8];
// Send the position reference parameter
dataBuffer[0] = reference;
sendMessage(LM_API_POS_REF, dataBuffer, sizeof(uint8_t));
m_positionReference = reference;
m_posRefVerified = false;
}
/**
* Get the reference source device for position controller mode.
*
* @return A PositionReference indicating the currently selected reference
* device for position controller mode.
*/
uint8_t CANJaguar::GetPositionReference() const { 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) {
uint8_t dataBuffer[8];
uint8_t dataSize;
switch (m_controlMode) {
case kPercentVbus:
case kVoltage:
case kFollower:
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;
}
m_p = p;
m_pVerified = false;
}
/**
* Set the I constant for the closed loop modes.
*
* @param i The integral gain of the Jaguar's PID controller.
*/
void CANJaguar::SetI(double i) {
uint8_t dataBuffer[8];
uint8_t dataSize;
switch (m_controlMode) {
case kPercentVbus:
case kVoltage:
case kFollower:
wpi_setWPIErrorWithContext(
IncompatibleMode,
"PID constants only apply in Speed, Position, and Current mode");
break;
case kSpeed:
dataSize = packFXP16_16(dataBuffer, i);
sendMessage(LM_API_SPD_IC, dataBuffer, dataSize);
break;
case kPosition:
dataSize = packFXP16_16(dataBuffer, i);
sendMessage(LM_API_POS_IC, dataBuffer, dataSize);
break;
case kCurrent:
dataSize = packFXP16_16(dataBuffer, i);
sendMessage(LM_API_ICTRL_IC, dataBuffer, dataSize);
break;
}
m_i = i;
m_iVerified = false;
}
/**
* Set the D constant for the closed loop modes.
*
* @param d The derivative gain of the Jaguar's PID controller.
*/
void CANJaguar::SetD(double d) {
uint8_t dataBuffer[8];
uint8_t dataSize;
switch (m_controlMode) {
case kPercentVbus:
case kVoltage:
case kFollower:
wpi_setWPIErrorWithContext(
IncompatibleMode,
"PID constants only apply in Speed, Position, and Current mode");
break;
case kSpeed:
dataSize = packFXP16_16(dataBuffer, d);
sendMessage(LM_API_SPD_DC, dataBuffer, dataSize);
break;
case kPosition:
dataSize = packFXP16_16(dataBuffer, d);
sendMessage(LM_API_POS_DC, dataBuffer, dataSize);
break;
case kCurrent:
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() const {
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_p;
}
/**
* Get the Intregral gain of the controller.
*
* @return The integral gain.
*/
double CANJaguar::GetI() const {
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;
}
/**
* Get the Differential gain of the controller.
*
* @return The differential gain.
*/
double CANJaguar::GetD() const {
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;
}
/**
* Enable the closed loop controller.
*
* 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.
*
* @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:
sendMessage(LM_API_VOLT_T_EN, dataBuffer, dataSize);
break;
case kSpeed:
sendMessage(LM_API_SPD_T_EN, dataBuffer, dataSize);
break;
case kPosition:
dataSize = packFXP16_16(dataBuffer, encoderInitialPosition);
sendMessage(LM_API_POS_T_EN, dataBuffer, dataSize);
break;
case kCurrent:
sendMessage(LM_API_ICTRL_T_EN, dataBuffer, dataSize);
break;
case kVoltage:
sendMessage(LM_API_VCOMP_T_EN, dataBuffer, dataSize);
break;
default:
wpi_setWPIErrorWithContext(IncompatibleMode,
"The Jaguar only supports Current, Voltage, "
"Position, Speed, and Percent (Throttle) "
"modes.");
return;
}
m_controlEnabled = true;
m_controlModeVerified = false;
}
/**
* Disable the closed loop controller.
*
* Stop driving the output based on the feedback.
*/
void CANJaguar::DisableControl() {
uint8_t dataBuffer[8];
uint8_t dataSize = 0;
// 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);
m_controlEnabled = false;
}
/**
* Enable controlling the motor voltage as a percentage of the bus 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.
*/
void CANJaguar::SetPercentMode() {
SetControlMode(kPercentVbus);
SetPositionReference(LM_REF_NONE);
SetSpeedReference(LM_REF_NONE);
}
/**
* 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::Encoder
* @param codesPerRev The counts per revolution on the encoder
*/
void CANJaguar::SetPercentMode(CANJaguar::EncoderStruct, uint16_t codesPerRev) {
SetControlMode(kPercentVbus);
SetPositionReference(LM_REF_NONE);
SetSpeedReference(LM_REF_ENCODER);
ConfigEncoderCodesPerRev(codesPerRev);
}
/**
* 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
*/
void CANJaguar::SetPercentMode(CANJaguar::QuadEncoderStruct,
uint16_t codesPerRev) {
SetControlMode(kPercentVbus);
SetPositionReference(LM_REF_ENCODER);
SetSpeedReference(LM_REF_QUAD_ENCODER);
ConfigEncoderCodesPerRev(codesPerRev);
}
/**
* Enable controlling the motor voltage as a percentage of the bus voltage,
* 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.
*
* @param potentiometer The constant CANJaguar::Potentiometer
*/
void CANJaguar::SetPercentMode(CANJaguar::PotentiometerStruct) {
SetControlMode(kPercentVbus);
SetPositionReference(LM_REF_POT);
SetSpeedReference(LM_REF_NONE);
ConfigPotentiometerTurns(1);
}
/**
* 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.
*
* @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) {
SetControlMode(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
* 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 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) {
SetControlMode(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
* 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.
*
* @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) {
SetControlMode(kCurrent);
SetPositionReference(LM_REF_ENCODER);
SetSpeedReference(LM_REF_QUAD_ENCODER);
ConfigEncoderCodesPerRev(codesPerRev);
SetPID(p, i, d);
}
/**
* Enable controlling the motor current with a PID loop, and enable position
* sensing from a potentiometer.<br>
* After calling this you must call {@link CANJaguar#EnableControl()} or {@link
* CANJaguar#EnableControl(double)} to enable the device.
*
* @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) {
SetControlMode(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
* encoder.<br>
* After calling this you must call {@link CANJaguar#EnableControl()} or {@link
* CANJaguar#EnableControl(double)} to enable the device.
*
* @param encoder The constant CANJaguar::Encoder
* @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.
*/
void CANJaguar::SetSpeedMode(CANJaguar::EncoderStruct, uint16_t codesPerRev,
double p, double i, double d) {
SetControlMode(kSpeed);
SetPositionReference(LM_REF_NONE);
SetSpeedReference(LM_REF_ENCODER);
ConfigEncoderCodesPerRev(codesPerRev);
SetPID(p, i, d);
}
/**
* 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.
*
* @param encoder The constant CANJaguar::QuadEncoder
* @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.
*/
void CANJaguar::SetSpeedMode(CANJaguar::QuadEncoderStruct, uint16_t codesPerRev,
double p, double i, double d) {
SetControlMode(kSpeed);
SetPositionReference(LM_REF_ENCODER);
SetSpeedReference(LM_REF_QUAD_ENCODER);
ConfigEncoderCodesPerRev(codesPerRev);
SetPID(p, i, d);
}
/**
* 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.
*
* @param encoder The constant CANJaguar::QuadEncoder
* @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.
*
*/
void CANJaguar::SetPositionMode(CANJaguar::QuadEncoderStruct,
uint16_t codesPerRev, double p, double i,
double d) {
SetControlMode(kPosition);
SetPositionReference(LM_REF_ENCODER);
ConfigEncoderCodesPerRev(codesPerRev);
SetPID(p, i, d);
}
/**
* 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.
*/
void CANJaguar::SetPositionMode(CANJaguar::PotentiometerStruct, double p,
double i, double d) {
SetControlMode(kPosition);
SetPositionReference(LM_REF_POT);
ConfigPotentiometerTurns(1);
SetPID(p, i, d);
}
/**
* 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.
*/
void CANJaguar::SetVoltageMode() {
SetControlMode(kVoltage);
SetPositionReference(LM_REF_NONE);
SetSpeedReference(LM_REF_NONE);
}
/**
* Enable controlling the motor voltage with speed feedback from a
* 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.
*
* @param encoder The constant CANJaguar::Encoder
* @param codesPerRev The counts per revolution on the encoder
*/
void CANJaguar::SetVoltageMode(CANJaguar::EncoderStruct, uint16_t codesPerRev) {
SetControlMode(kVoltage);
SetPositionReference(LM_REF_NONE);
SetSpeedReference(LM_REF_ENCODER);
ConfigEncoderCodesPerRev(codesPerRev);
}
/**
* Enable controlling the motor voltage with position and speed feedback from a
* quadrature encoder.<br>
* After calling this you must call {@link CANJaguar#EnableControl()} or {@link
* CANJaguar#EnableControl(double)} to enable the device.
*
* @param encoder The constant CANJaguar::QuadEncoder
* @param codesPerRev The counts per revolution on the encoder
*/
void CANJaguar::SetVoltageMode(CANJaguar::QuadEncoderStruct,
uint16_t codesPerRev) {
SetControlMode(kVoltage);
SetPositionReference(LM_REF_ENCODER);
SetSpeedReference(LM_REF_QUAD_ENCODER);
ConfigEncoderCodesPerRev(codesPerRev);
}
/**
* Enable controlling the motor voltage with position feedback 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.
*
* @param potentiometer The constant CANJaguar::Potentiometer
*/
void CANJaguar::SetVoltageMode(CANJaguar::PotentiometerStruct) {
SetControlMode(kVoltage);
SetPositionReference(LM_REF_POT);
SetSpeedReference(LM_REF_NONE);
ConfigPotentiometerTurns(1);
}
/**
* Used internally. In order to set the control mode see the methods listed
* below.
* Change the control mode of this Jaguar object.
*
* After changing modes, configure any PID constants or other settings needed
* and then EnableControl() to actually change the mode on the Jaguar.
*
* @param controlMode The new mode.
*/
void CANJaguar::SetControlMode(ControlMode controlMode) {
// Disable the previous mode
DisableControl();
if (controlMode == kFollower)
wpi_setWPIErrorWithContext(IncompatibleMode,
"The Jaguar only supports Current, Voltage, "
"Position, Speed, and Percent (Throttle) "
"modes.");
// Update the local mode
m_controlMode = controlMode;
m_controlModeVerified = false;
HALReport(HALUsageReporting::kResourceType_CANJaguar, m_deviceNumber,
m_controlMode);
}
/**
* Get the active control mode from the Jaguar.
*
* Ask the Jag what mode it is in.
*
* @return ControlMode that the Jag is in.
*/
CANJaguar::ControlMode CANJaguar::GetControlMode() const {
return m_controlMode;
}
/**
* Get the voltage at the battery input terminals of the Jaguar.
*
* @return The bus voltage in volts.
*/
float CANJaguar::GetBusVoltage() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_busVoltage;
}
/**
* Get the voltage being output from the motor terminals of the Jaguar.
*
* @return The output voltage in volts.
*/
float CANJaguar::GetOutputVoltage() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_outputVoltage;
}
/**
* Get the current through the motor terminals of the Jaguar.
*
* @return The output current in amps.
*/
float CANJaguar::GetOutputCurrent() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_outputCurrent;
}
/**
* Get the internal temperature of the Jaguar.
*
* @return The temperature of the Jaguar in degrees Celsius.
*/
float CANJaguar::GetTemperature() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_temperature;
}
/**
* Get the position of the encoder or potentiometer.
*
* @return The position of the motor in rotations based on the configured
* feedback.
* @see CANJaguar#ConfigPotentiometerTurns(int)
* @see CANJaguar#ConfigEncoderCodesPerRev(int)
*/
double CANJaguar::GetPosition() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_position;
}
/**
* Get the speed of the encoder.
*
* @return The speed of the motor in RPM based on the configured feedback.
*/
double CANJaguar::GetSpeed() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_speed;
}
/**
* Get the status of the forward limit switch.
*
* @return The motor is allowed to turn in the forward direction when true.
*/
bool CANJaguar::GetForwardLimitOK() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_limits & kForwardLimit;
}
/**
* Get the status of the reverse limit switch.
*
* @return The motor is allowed to turn in the reverse direction when true.
*/
bool CANJaguar::GetReverseLimitOK() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_limits & kReverseLimit;
}
/**
* Get the status of any faults the Jaguar has detected.
*
* @return A bit-mask of faults defined by the "Faults" enum.
* @see #kCurrentFault
* @see #kBusVoltageFault
* @see #kTemperatureFault
* @see #kGateDriverFault
*/
uint16_t CANJaguar::GetFaults() const {
updatePeriodicStatus();
std::lock_guard<priority_recursive_mutex> lock(m_mutex);
return m_faults;
}
/**
* Set the maximum voltage change rate.
*
* 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.
*
* @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;
uint32_t message;
switch (m_controlMode) {
case kPercentVbus:
dataSize = packPercentage(
dataBuffer, rampRate / (m_maxOutputVoltage * kControllerRate));
message = LM_API_VOLT_SET_RAMP;
break;
case kVoltage:
dataSize = packFXP8_8(dataBuffer, rampRate / kControllerRate);
message = LM_API_VCOMP_COMP_RAMP;
break;
default:
wpi_setWPIErrorWithContext(
IncompatibleMode,
"SetVoltageRampRate only applies in Voltage and Percent mode");
return;
}
sendMessage(message, dataBuffer, dataSize);
m_voltageRampRate = rampRate;
m_voltageRampRateVerified = false;
}
/**
* Get the version of the firmware running on the Jaguar.
*
* @return The firmware version. 0 if the device did not respond.
*/
uint32_t CANJaguar::GetFirmwareVersion() const { return m_firmwareVersion; }
/**
* Get the version of the Jaguar hardware.
*
* @return The hardware version. 1: Jaguar, 2: Black Jaguar
*/
uint8_t CANJaguar::GetHardwareVersion() const { return m_hardwareVersion; }
/**
* Configure what the controller does to the H-Bridge when neutral (not driving
* the output).
*
* This allows you to override the jumper configuration for brake or coast.
*
* @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];
// Set the neutral mode
sendMessage(LM_API_CFG_BRAKE_COAST, dataBuffer, sizeof(uint8_t));
m_neutralMode = mode;
m_neutralModeVerified = false;
}
/**
* Configure how many codes per revolution are generated by your encoder.
*
* @param codesPerRev The number of counts per revolution in 1X mode.
*/
void CANJaguar::ConfigEncoderCodesPerRev(uint16_t codesPerRev) {
uint8_t dataBuffer[8];
// Set the codes per revolution mode
packint16_t(dataBuffer, codesPerRev);
sendMessage(LM_API_CFG_ENC_LINES, dataBuffer, sizeof(uint16_t));
m_encoderCodesPerRev = codesPerRev;
m_encoderCodesPerRevVerified = false;
}
/**
* Configure the number of turns on the potentiometer.
*
* There is no special support for continuous turn potentiometers.
* Only integer numbers of turns are supported.
*
* @param turns The number of turns of the potentiometer.
*/
void CANJaguar::ConfigPotentiometerTurns(uint16_t turns) {
uint8_t dataBuffer[8];
uint8_t dataSize;
// Set the pot turns
dataSize = packint16_t(dataBuffer, turns);
sendMessage(LM_API_CFG_POT_TURNS, dataBuffer, dataSize);
m_potentiometerTurns = turns;
m_potentiometerTurnsVerified = false;
}
/**
* Configure Soft Position Limits when in Position Controller mode.
*
* 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.
*
* @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) {
ConfigLimitMode(kLimitMode_SoftPositionLimits);
ConfigForwardLimit(forwardLimitPosition);
ConfigReverseLimit(reverseLimitPosition);
}
/**
* Disable Soft Position Limits if previously enabled.
*
* Soft Position Limits are disabled by default.
*/
void CANJaguar::DisableSoftPositionLimits() {
ConfigLimitMode(kLimitMode_SwitchInputsOnly);
}
/**
* Set the limit mode for position control mode.
*
* Use ConfigSoftPositionLimits or DisableSoftPositionLimits to set this
* automatically.
*/
void CANJaguar::ConfigLimitMode(LimitMode mode) {
uint8_t dataBuffer[8];
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;
}
/**
* 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.
*/
void CANJaguar::ConfigMaxOutputVoltage(double voltage) {
uint8_t dataBuffer[8];
uint8_t dataSize;
dataSize = packFXP8_8(dataBuffer, voltage);
sendMessage(LM_API_CFG_MAX_VOUT, dataBuffer, dataSize);
m_maxOutputVoltage = voltage;
m_maxOutputVoltageVerified = false;
}
/**
* Configure how long the Jaguar waits in the case of a fault before resuming
* operation.
*
* 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.
*
* @param faultTime The time to wait before resuming operation, in seconds.
*/
void CANJaguar::ConfigFaultTime(float faultTime) {
uint8_t dataBuffer[8];
uint8_t dataSize;
if (faultTime < 0.5)
faultTime = 0.5;
else if (faultTime > 3.0)
faultTime = 3.0;
// Message takes ms
dataSize = packint16_t(dataBuffer, (int16_t)(faultTime * 1000.0));
sendMessage(LM_API_CFG_FAULT_TIME, dataBuffer, dataSize);
m_faultTime = faultTime;
m_faultTimeVerified = false;
}
/**
* Update all the motors that have pending sets in the syncGroup.
*
* @param syncGroup A bitmask of groups to generate synchronous output.
*/
void CANJaguar::UpdateSyncGroup(uint8_t syncGroup) {
sendMessageHelper(CAN_MSGID_API_SYNC, &syncGroup, sizeof(syncGroup),
CAN_SEND_PERIOD_NO_REPEAT);
}
void CANJaguar::SetExpiration(float timeout) {
if (m_safetyHelper) m_safetyHelper->SetExpiration(timeout);
}
float CANJaguar::GetExpiration() const {
if (!m_safetyHelper) return 0.0;
return m_safetyHelper->GetExpiration();
}
bool CANJaguar::IsAlive() const {
if (!m_safetyHelper) return false;
return m_safetyHelper->IsAlive();
}
bool CANJaguar::IsSafetyEnabled() const {
if (!m_safetyHelper) return false;
return m_safetyHelper->IsSafetyEnabled();
}
void CANJaguar::SetSafetyEnabled(bool enabled) {
if (m_safetyHelper) m_safetyHelper->SetSafetyEnabled(enabled);
}
artf4154: Get rid of raw pointers in C++. This deals with the majority of the user-facing code in wpilibC++Devices and a substantial portion of it in wpilibC++. wpilibC++Sim and wpilibC++IntegrationTests are untouched except where it is necessary to make them work with the rest of the libraries. There is still a lot to do in the following areas: -The HAL (which we may not want to touch at all). -The I2C, Serial, and SPI interfaces in wpilibC++Devices, which I haven't gotten around to doing yet. -Most wpilibC++Devices classes have void* pointers for interacting with the HAL. -InterruptableSensorBase passes a void *params for the interrupt handler. -I haven't converted all the const char* to std::strings. -There are plenty of other cases of raw pointers still existing. -This doesn't fall directly under raw pointer stuff, but move syntax and rvalue references could be introduced in many places. -I haven't touched vision code. -The Resource classes conflict (one is in the hal, the other in wpilibC++). Someone should figure out a more permanent fix (eg, just renaming them), then doing what I did (making a new namespace for one of them, essentially the same as renaming it). A few other things: -I created a NullDeleter class which is marked as deprecated. What this does is it can be passed as the deleter to a std::shared_ptr so that when you are converting raw pointers to shared_ptrs the shared_ptr doesn't do any deletion if someone else owns the raw pointer. This should only be used in making old raw pointer UIs. -I had to alter the build.gradle so that it did not emit errors when deprecated functions called deprecated functions. Unfortunately, gradle doesn't appear to be actually printing out gcc warnigns for some reason. The best way I have found to fix this is to patch the toolchains (https://bitbucket.org/byteit101/toolchain-builder/pull-request/5/make-gcc-not-throw-warnings-for-nested/diff) so that a deprecated function calling a deprecated function is fine but a non-deprecated function calling a deprecated function will throw a warning (which we then elevate with -Werror). I believe that clang deals with this properly, although I have not tried it myself. Change-Id: Ib8090c66893576fe73654f4e9d268f9d37be06a2
2015-06-30 15:01:20 -04:00
void CANJaguar::GetDescription(std::ostringstream& desc) const {
desc << "CANJaguar ID " << m_deviceNumber;
}
uint8_t CANJaguar::GetDeviceID() const { return m_deviceNumber; }
/**
* Common interface for stopping the motor
* Part of the MotorSafety interface
*
* @deprecated Call DisableControl instead.
*/
void CANJaguar::StopMotor() { DisableControl(); }
void CANJaguar::ValueChanged(std::shared_ptr<ITable> source, const std::string &key,
EntryValue value, bool isNew) {
Set(value.f);
}
void CANJaguar::UpdateTable() {
if (m_table != nullptr) {
m_table->PutNumber("Value", Get());
}
}
void CANJaguar::StartLiveWindowMode() {
if (m_table != nullptr) {
m_table->AddTableListener("Value", this, true);
}
}
void CANJaguar::StopLiveWindowMode() {
if (m_table != nullptr) {
m_table->RemoveTableListener(this);
}
}
Added tests for motor inversions. This commit squashes all of Patrick's eleven commits into one so that things are a bit more sane. The original commit messages and change ids (for gerrit) can be found below. Testing Motor Inversion Feature (Java tests only so far) Change-Id: I44cd9b5a3fe066e1071316831dde14bff5ec3bd9 Test 2 of java testing for Motor Inverting Change-Id: I96cc0534bb1d28a70d10c582f0b40ea3a2d83cab Added another test to try to track down issue with InvertingMotor jaguar and Talon Change-Id: I9b5292315c93ec0d568d53a6bcdac5b998a6d857 More Testing on the Inverting motors with jaguars and talons. Change-Id: I896210a54903e3c0af68e8c41360c165cf9c3122 Added C++ integration Tests for the motor inversion. Change-Id: I81af5d4aab78d755340d99608b838046bf7ddda1 C++ tests for Motor Inversion now without crashing Change-Id: Ifdecdbfc1aeb18aafb2b4c63709b27636074a274 More testing of inverted motors (now with c++ tests) Talon seems not to be working on test rig Also added a CANJaguartest file in java since was missing Currently porting the CANJaguar tests from c++ to java Change-Id: Ib578d6ee1256ac31ddf20603aa6f24adde08065b Another attempt at adding java tests for can jaguar inversion. Change-Id: I971a886a4e555ada5bd15a814094da2a1eb5c8e1 Minor changes and attempt to rerun tests after yesterday's jenkins crash. Change-Id: I7ed0904d4243499c3246e9c39e5493d0d9c962c5 All motor inversion tests should be working now. Talon on the test rig has been fixed. Change-Id: I20bd6d7486b758ce1ce47ac799150475b3152b6f Updated Inversion tests again. Should work this time. (worked on the test rig prior) Change-Id: Ifdf222d5e5733fe802f29e7d939b72e84972e8da Added tests for motor inversions. This commit squashes all of Patrick's eleven commits into one so that things are a bit more sane. The original commit messages and change ids (for gerrit) can be found below. Testing Motor Inversion Feature (Java tests only so far) Change-Id: I44cd9b5a3fe066e1071316831dde14bff5ec3bd9 Test 2 of java testing for Motor Inverting Change-Id: I96cc0534bb1d28a70d10c582f0b40ea3a2d83cab Added another test to try to track down issue with InvertingMotor jaguar and Talon Change-Id: I9b5292315c93ec0d568d53a6bcdac5b998a6d857 More Testing on the Inverting motors with jaguars and talons. Change-Id: I896210a54903e3c0af68e8c41360c165cf9c3122 Added C++ integration Tests for the motor inversion. Change-Id: I81af5d4aab78d755340d99608b838046bf7ddda1 C++ tests for Motor Inversion now without crashing Change-Id: Ifdecdbfc1aeb18aafb2b4c63709b27636074a274 More testing of inverted motors (now with c++ tests) Talon seems not to be working on test rig Also added a CANJaguartest file in java since was missing Currently porting the CANJaguar tests from c++ to java Change-Id: Ib578d6ee1256ac31ddf20603aa6f24adde08065b Another attempt at adding java tests for can jaguar inversion. Change-Id: I971a886a4e555ada5bd15a814094da2a1eb5c8e1 Minor changes and attempt to rerun tests after yesterday's jenkins crash. Change-Id: I7ed0904d4243499c3246e9c39e5493d0d9c962c5 All motor inversion tests should be working now. Talon on the test rig has been fixed. Change-Id: I20bd6d7486b758ce1ce47ac799150475b3152b6f Updated Inversion tests again. Should work this time. (worked on the test rig prior) Change-Id: Ifdf222d5e5733fe802f29e7d939b72e84972e8da
2015-03-24 15:01:17 -04:00
/**
* Common interface for inverting direction of a speed controller.
* Only works in PercentVbus, speed, and Voltage modes.
* @param isInverted The state of inversion, true is inverted
Added tests for motor inversions. This commit squashes all of Patrick's eleven commits into one so that things are a bit more sane. The original commit messages and change ids (for gerrit) can be found below. Testing Motor Inversion Feature (Java tests only so far) Change-Id: I44cd9b5a3fe066e1071316831dde14bff5ec3bd9 Test 2 of java testing for Motor Inverting Change-Id: I96cc0534bb1d28a70d10c582f0b40ea3a2d83cab Added another test to try to track down issue with InvertingMotor jaguar and Talon Change-Id: I9b5292315c93ec0d568d53a6bcdac5b998a6d857 More Testing on the Inverting motors with jaguars and talons. Change-Id: I896210a54903e3c0af68e8c41360c165cf9c3122 Added C++ integration Tests for the motor inversion. Change-Id: I81af5d4aab78d755340d99608b838046bf7ddda1 C++ tests for Motor Inversion now without crashing Change-Id: Ifdecdbfc1aeb18aafb2b4c63709b27636074a274 More testing of inverted motors (now with c++ tests) Talon seems not to be working on test rig Also added a CANJaguartest file in java since was missing Currently porting the CANJaguar tests from c++ to java Change-Id: Ib578d6ee1256ac31ddf20603aa6f24adde08065b Another attempt at adding java tests for can jaguar inversion. Change-Id: I971a886a4e555ada5bd15a814094da2a1eb5c8e1 Minor changes and attempt to rerun tests after yesterday's jenkins crash. Change-Id: I7ed0904d4243499c3246e9c39e5493d0d9c962c5 All motor inversion tests should be working now. Talon on the test rig has been fixed. Change-Id: I20bd6d7486b758ce1ce47ac799150475b3152b6f Updated Inversion tests again. Should work this time. (worked on the test rig prior) Change-Id: Ifdf222d5e5733fe802f29e7d939b72e84972e8da Added tests for motor inversions. This commit squashes all of Patrick's eleven commits into one so that things are a bit more sane. The original commit messages and change ids (for gerrit) can be found below. Testing Motor Inversion Feature (Java tests only so far) Change-Id: I44cd9b5a3fe066e1071316831dde14bff5ec3bd9 Test 2 of java testing for Motor Inverting Change-Id: I96cc0534bb1d28a70d10c582f0b40ea3a2d83cab Added another test to try to track down issue with InvertingMotor jaguar and Talon Change-Id: I9b5292315c93ec0d568d53a6bcdac5b998a6d857 More Testing on the Inverting motors with jaguars and talons. Change-Id: I896210a54903e3c0af68e8c41360c165cf9c3122 Added C++ integration Tests for the motor inversion. Change-Id: I81af5d4aab78d755340d99608b838046bf7ddda1 C++ tests for Motor Inversion now without crashing Change-Id: Ifdecdbfc1aeb18aafb2b4c63709b27636074a274 More testing of inverted motors (now with c++ tests) Talon seems not to be working on test rig Also added a CANJaguartest file in java since was missing Currently porting the CANJaguar tests from c++ to java Change-Id: Ib578d6ee1256ac31ddf20603aa6f24adde08065b Another attempt at adding java tests for can jaguar inversion. Change-Id: I971a886a4e555ada5bd15a814094da2a1eb5c8e1 Minor changes and attempt to rerun tests after yesterday's jenkins crash. Change-Id: I7ed0904d4243499c3246e9c39e5493d0d9c962c5 All motor inversion tests should be working now. Talon on the test rig has been fixed. Change-Id: I20bd6d7486b758ce1ce47ac799150475b3152b6f Updated Inversion tests again. Should work this time. (worked on the test rig prior) Change-Id: Ifdf222d5e5733fe802f29e7d939b72e84972e8da
2015-03-24 15:01:17 -04:00
*/
void CANJaguar::SetInverted(bool isInverted) { m_isInverted = isInverted; }
Added tests for motor inversions. This commit squashes all of Patrick's eleven commits into one so that things are a bit more sane. The original commit messages and change ids (for gerrit) can be found below. Testing Motor Inversion Feature (Java tests only so far) Change-Id: I44cd9b5a3fe066e1071316831dde14bff5ec3bd9 Test 2 of java testing for Motor Inverting Change-Id: I96cc0534bb1d28a70d10c582f0b40ea3a2d83cab Added another test to try to track down issue with InvertingMotor jaguar and Talon Change-Id: I9b5292315c93ec0d568d53a6bcdac5b998a6d857 More Testing on the Inverting motors with jaguars and talons. Change-Id: I896210a54903e3c0af68e8c41360c165cf9c3122 Added C++ integration Tests for the motor inversion. Change-Id: I81af5d4aab78d755340d99608b838046bf7ddda1 C++ tests for Motor Inversion now without crashing Change-Id: Ifdecdbfc1aeb18aafb2b4c63709b27636074a274 More testing of inverted motors (now with c++ tests) Talon seems not to be working on test rig Also added a CANJaguartest file in java since was missing Currently porting the CANJaguar tests from c++ to java Change-Id: Ib578d6ee1256ac31ddf20603aa6f24adde08065b Another attempt at adding java tests for can jaguar inversion. Change-Id: I971a886a4e555ada5bd15a814094da2a1eb5c8e1 Minor changes and attempt to rerun tests after yesterday's jenkins crash. Change-Id: I7ed0904d4243499c3246e9c39e5493d0d9c962c5 All motor inversion tests should be working now. Talon on the test rig has been fixed. Change-Id: I20bd6d7486b758ce1ce47ac799150475b3152b6f Updated Inversion tests again. Should work this time. (worked on the test rig prior) Change-Id: Ifdf222d5e5733fe802f29e7d939b72e84972e8da Added tests for motor inversions. This commit squashes all of Patrick's eleven commits into one so that things are a bit more sane. The original commit messages and change ids (for gerrit) can be found below. Testing Motor Inversion Feature (Java tests only so far) Change-Id: I44cd9b5a3fe066e1071316831dde14bff5ec3bd9 Test 2 of java testing for Motor Inverting Change-Id: I96cc0534bb1d28a70d10c582f0b40ea3a2d83cab Added another test to try to track down issue with InvertingMotor jaguar and Talon Change-Id: I9b5292315c93ec0d568d53a6bcdac5b998a6d857 More Testing on the Inverting motors with jaguars and talons. Change-Id: I896210a54903e3c0af68e8c41360c165cf9c3122 Added C++ integration Tests for the motor inversion. Change-Id: I81af5d4aab78d755340d99608b838046bf7ddda1 C++ tests for Motor Inversion now without crashing Change-Id: Ifdecdbfc1aeb18aafb2b4c63709b27636074a274 More testing of inverted motors (now with c++ tests) Talon seems not to be working on test rig Also added a CANJaguartest file in java since was missing Currently porting the CANJaguar tests from c++ to java Change-Id: Ib578d6ee1256ac31ddf20603aa6f24adde08065b Another attempt at adding java tests for can jaguar inversion. Change-Id: I971a886a4e555ada5bd15a814094da2a1eb5c8e1 Minor changes and attempt to rerun tests after yesterday's jenkins crash. Change-Id: I7ed0904d4243499c3246e9c39e5493d0d9c962c5 All motor inversion tests should be working now. Talon on the test rig has been fixed. Change-Id: I20bd6d7486b758ce1ce47ac799150475b3152b6f Updated Inversion tests again. Should work this time. (worked on the test rig prior) Change-Id: Ifdf222d5e5733fe802f29e7d939b72e84972e8da
2015-03-24 15:01:17 -04:00
/**
* Common interface for the inverting direction of a speed controller.
*
* @return isInverted The state of inversion, true is inverted.
*
*/
bool CANJaguar::GetInverted() const { return m_isInverted; }
std::string CANJaguar::GetSmartDashboardType() const {
return "Speed Controller";
}
void CANJaguar::InitTable(std::shared_ptr<ITable> subTable) {
m_table = subTable;
UpdateTable();
}
std::shared_ptr<ITable> CANJaguar::GetTable() const { return m_table; }