This repository contains the code used for the PYR series. Below is a FAQ containined many commonly-asked questions for programming robots with Talons and Victors. Note that if Talon.xxx or Victor.xxx is used in a method call, the configuration can be used with either motor controller unless otherwise specified.
Table of contents generated with markdown-toc
This section goes over many of the common open-loop configurations found on FRC robots.
In your command's execute(), use the line
Talon.set(DemandType.PercentOutput, double throttle)
to set a Talon’s or Victor’s output. throttle should be a on the scale -1.0 to 1.0. Talon should be an instance of a TalonSRX or VictorSPX motor controller. Find API documentation here.
See this section from CTRE on inverting the output of a Talon/Victor
In your subsystem constructor, invert the output of a motor controller by calling
Talon.setInverted(boolean invert)
where invert is whether or not to invert the motor controller’s output (i.e. reverse the direction). If you have any follower motor controllers, such as a Victor following a Talon, then you can also use
Victor.setInverted(InvertType.FollowMaster)
Or
Victor.setInverted(InvertType.OpposeMaster)
This is more robust than manually setting the inverted mode for each motor controller, as the follower will invert its output if the master is inverted.
In your command's execute(), use the method
Talon.set(DemandType.PercentOutput, double throttle, DemandType.ArbitraryFeedforward, double gravityComp)
The throttle output is from -1.0 to 1.0 as normal. ArbitraryFeedforward
will apply an extra gravityComp to your throttle to determine the output of the motor controller. So, if gravityComp is equal to 0.1, your output throttle will always have 0.1 added to it, making your effective output range -0.9 to 1.1. Of course, you can’t go over an output of 1.0, so your range is really -0.9 to 1.0.
This will effectively stop your elevator from falling by adding a small output to keep it in place. However, it is better to also use an encoder and closed-loop control.
See this section on using current limits
There are four methods that are used to limit current. These are typically called in the subsystem constructor, but can also be called in command constructors if the limit needs to be changed or disabled/enabled.
Talon.configContinuousCurrentLimit(int amps, int timeoutMs)
Talon.configPeakCurrentDuration(int milliseconds, int timeoutMs)
Talon.configPeakCurrentLimit(int amps, int timeoutMs)
Talon.enableCurrentLimit(boolean enable)
There are timeouts for these methods. Note that the Victor SPX does not support current sensing and limiting, but if it is following a Talon that is current limiting, it will have its output limited in such a way as to effectively limit the current.
configContinuousCurrentLimit
will set the current limit in amps.
configPeakCurrentLimit
will set the peak current limit, if one is used.
configPeakCurrentDuration
will set the time that the current is allowed to be at the peak current limit until the Talon throttles the output to to continuous current limit.
enableCurrentLimit
will enable current limiting if true is passed in, or disable it with a false argument.
Below is a plot showing current vs. time when all of the current limiting settings are used.
Using open-loop ramping can help make robot motion smother. See documentation here.
In your subsystem constructor, call the method
Talon.configOpenloopRamp(double secondsFromNeutralToFull, timeoutMs)
to configure the ramp rate. secondsFromNeutralToFull is the number of seconds to go from an output of 0.0 to 1.0 (or -1.0). The maximum ramp time is 10 seconds, but this is ridiculously slow. Open loop ramps can make your robot run smoother and prevent battery voltage from dropping and browning out your robot. Make sure to use the timeout.
Using voltage compensation is helpful to keep your motor controller output consistent throughout a match. See CTRE's documentation here.
In the subsystem constructor, call
Talon.configVoltageCompSaturation(double voltage, int timeout)
Talon.enableVoltageCompensation(boolean enable)
configVoltageCompSaturation
will configure the voltage that corresponds to the "max" output of the motor controller. So if voltage
is set to 11.0, calling set(0.5)
will result in an output of 5.5 V. This means that regardless of the state of the battery, your motors will spin at the same speed and perform the same.
enableVoltageCompensation
enables/disables the compensation mode. Pass in true
to enable voltage compensation.
As usual, use timeouts when possible.
See CTRE’s documentation on closed-loop control here.
To set up a position PID command, you only need configure a few settings on your Talon (or Victor). In the case of a Talon, you’ll need to call these three methods in your subsystem constructor to configure the Talon for closed-looping:
Talon.setSensorPhase(boolean phase)
Talon.configSelectedFeedbackSensor(FeedbackDevice.[sensor], int pidIdx, int timeout)
Talon.config_kP(int slotIdx, double value, int timeout) // also IDF
Talon.setSelectedSensorPosition(int position, int pidIdx, int timeoutMs)
In your command constructor, use these two methods:
Talon.selectProfileSlot(int slotIdx, int pidIdx);
Talon.set(ControlMode.Position, double position);
The set
command can also be called in the execute() of your command.
setSensorPhase
will set the “phase” of the sensor, such that positive output of your motor controller corresponds to positive movement and sensor readings. See CTRE’s guide here.
configSelectedFeedbackSensor configures the sensor. The Talon can take sensor readings from many sources including remote sensors not directly plugged into it. In many cases, [sensor] will either be Quadrature or CTRE_MagEncoder_Relative for quadrature encoders or SRX Mag encoders.
config_kP
, config_kI
, config_kD
, and config_kF
will configure the PIDF constants. Tuning constants in Phoenix Tuner before putting them in code can be convenient. For position, F will usually be 0. slotIdx is which PID slot to store the constants in (0-3). The Talon can store up to 4 sets of PIDF constants, but most applications will only need to use a single one.
setSelectedSensorPosition
will set the position of the sensor when the mechanism is in a known location. Typically, setSelectedSensorPosition(0, pidIdx, timeout)
is called to “zero” a sensor at one of the extremes of travel. For something like a drivetrain with no limit, it can be helpful to zero the sensor in your subsystem constructor.
selectProfileSlot
will link one of the four PID slots to one of the two PID loops. The first argument is which set of PID constants to use (0-3). See below for info about pidIdx.
Finally, set
will set the target of the PID loop. Note that position is in terms of sensor units, so you’ll need to convert from other units.
For all of the above,the pidIdx argument will select either the Inner (0) or Outer (1) PID loop, if your are using multiple PID loops to drive a mechanism. Typically a user will only use the Inner loop, so if there is uncertainty on what to put here, put a “0” to select the inner loop.
As usual, use timeouts when possible.
Motion Magic is similar to Position PID, but drives the mechanism at a given acceleration and velocity to get smoother motion on the way to the target. This results in smoother and more controlled motion. See CTRE's documentation here.
To use Motion Magic, you need the same settings as you do for regular closed-loop. However, add two more lines to your setup in your subsystem constructor:
Talon.configMotionCruiseVelocity(int velocity, int timeout)
Talon.configMotionAcceleration(int acceleration, int timeout)
You'll also need to add a kF as described in CTRE's walkthrough, and modify your set()
line to use the ControlMode.MotionMagic control type. kF = 1023 * duty-cycle / sensor-velocity-sensor-units-per-100ms, so if you measure a velocity of 7500 ticks/100ms at 100% throttle, your kF should be 0.1364. kF can also be tuned slightly to get the open-loop performance of MotionMagic closer to the target. Note that this is written as of 2019- the "1023" will likely disappear by 2020.
configMotionCruiseVelocity
sets the cruise velocity of the mechanism on its way to the target, in units of ticks/100ms. A 4096 PPR encoder on a 1000RPM shaft would have a velocity of 1000 rot/min * 4096 ticks/rot * 1min / 60sec * 0.1sec / 100ms = 6,827 ticks/100ms.
configMotionAcceleration
sets the acceleration of the mechanism on its way to the target, in units of ticks/100ms/sec. That means that if your acceleration is set to 1000 and your cruise velocity is set to 500, the mechanism will take 0.5 seconds to accelerate to the cruise velocity, and take another 0.5 seconds to decelerate from cruise velocity to a full stop.
As usual, use timeouts when possible.
Here's an annotated picture of what Motion Magic does to your position.
Source: James Pearman on the Vex Forum.
This section will cover some miscellaneous methods and questions.
Whenever a method allows you to use the timeout argument, that means it will keep trying to configure the target until the timeout (in milliseconds) is over. For example, calling
Talon.configContinuousCurrentLimit(10, 15);
will try and set a current limit of 10 amps. If, for some reason, the command to set the current limit fails (e.g. the CAN bus doesn’t transmit correctly), then it will retry setting the limit over and over again until it succeeds, or until 15 ms passes- whichever comes first. Generally speaking, whenever a timeout argument is available, use it. A setting of 5ms to 25ms is common.