Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Sometimes you might need to reset your Thrifty Nova motor controller back to its original settings. The factory reset feature lets you do this with just one line of code!
That's it! This command will reset almost all settings back to their factory defaults.
When you perform a factory reset, these settings will return to their default values:
Motor inversion (returns to false
)
Brake mode (returns to false
)
Maximum output (returns to 100%)
Ramp rates (returns to 0.1 seconds)
Current limits (returns to 40 amps)
PID values (returns to 0)
Soft limits
Temperature throttling
Some settings will stay the same even after a factory reset:
CAN ID
Device name
Serial number
Here's a complete example showing how you might use factory reset in your robot code:
Factory reset is useful when:
You're setting up a new motor controller
You want to start fresh with default settings
You're troubleshooting motor issues
You're not sure what settings might have been changed before
💡 Tip: It's a good practice to call factoryReset()
during your robot's initialization if you want to ensure you're starting with known default values.
⚠️ Important: Remember that after doing a factory reset, you'll need to reconfigure any special settings your robot needs. Don't just reset and forget!
There are many options to configuring on the Thrifty Nova. These can be configured in the constructor using a variety of configuration setters. These setters can be chained together to make for a very clean configuration style. The following is an example of this configuration strategy.
After you are done setting your configurations you can check for any errors reported from the motor controllers. The motor controller will provide a list of errors encountered while configuring values. Errors are represented by a status enum. The following examples show how to access these error codes, check for certain error codes, and clear the error list.
In this example we get a list of all errors, then iterate through the errors and printing them out.
You can also check if a given error is present. Here we are checking if configuring brake mode has failed.
You can also clear this error list. It will repopulate if more errors are encountered
There are two types of behaviors that the motor can take when the user specifies that it should idle. These modes are called Brake Mode and Coast Mode.
Coast Mode is the most simple behavior, and the default mode. When the motor wants to idle, power is cut from the phases, letting the kinetic energy of the motor disipate through friction until the system comes to rest.
Brake Mode turns the motor into an electric generator, which converts the kinetic energy from the system into electric energy into the circuit. It accomplishes this by shorting the phases together anytime the motor is requested to be idle.
Set the brake mode status of the motor to be either in brake mode or not in brake mode.
Parameters:
inverted
If the motor should be in brake mode or not.
One configuration that can be easily changed is the direction the motor turns forward. This can be set using the following method, and by providing a boolean for weather or not the motor should be inverted.
Set the inversion status of the motor to be either inverted or not inverted.
Parameters:
inverted
If the motor be inverted or not.
Due to differences in motor phase wire colors, the Minion motor must run with a special config settable in Thrifty Config. This will allow teams to run either REV motors or CTRE motors without changing phase wires.
Thrifty Config has a dropdown allowing users to select between the default REV option (for Neo-type motors) and the CTRE (Minion) mode.
You can also change motor types after initialization:
⚠️ Important: Always verify your motor type matches your physical hardware before running your robot.
To get started using the Thrifty Nova you must use the ThriftyLib.
ThriftyLib only has support for Java at this time. Support for C++ and Python are coming soon.
To install the ThriftyLib beta, please paste the following link into the WPILIB VSCode:
https://docs.home.thethriftybot.com/ThriftyLib/Latest/ThriftyLib.json
Before we break it down, here is a template to demonstrate simple ThriftyNova API usage.
Each Thrifty Nova is represented by an object. You must create a ThriftyNova instance variable in your subsystem to hold this object.
To actually instantiate the motor we call the ThrifyNova constructor. The constructor takes the CAN ID of the motor as a parameter.
In order to command the motor we use various setters. To set the output percentage of the motor we use the setPercent method. The method takes an argument from -1.0, full reverse, to 1.0, full forward, where 0 is idle.
The user can constrain the maximum forward and reverse percent output of the motor.
If you wanted some motor to only be able to apply 25% power in both directions, I could use the following.
If you want some motor to have no constraint in going forward, but only 30% power in reverse, then you could use the second method overload.
You could also specify a limit of 50% power going forward, and not let the motor drive in reverse.
Set the maximum percent output.
Parameters
maxOutput
The maximum absolute output in both directions in range 0 to 1.
Parameters
maxFwd
The maximum forward output in range 0 to 1.
maxRev
The maximum reverse output in range 0 to 1.
The user can specify the amount of time the motor should take to ramp up to full power and to ramp down to idle. The maximum amount of time is 10 seconds.
To set the motor to ramp up to 100% from idle over a period of 2s, use the following method.
To set the motor to ramp up to idle from 100% output over a period of 3.75s, use the following method.
Sets the time to ramp up in seconds from 0 to 10. For example, an input of 0.5 will ramp the motor from idle to 100% over the course of 0.5 seconds.
Parameters:
rampUp
The ramp up time.
Sets the time to ramp down in seconds from 0 to 10. For example, an input of 0.5 will ramp the motor from 100% to idle over the course of 0.5 seconds.
Parameters:
rampDown
The ramp up time.
The Thrifty Nova provides for the user to define a maximum current, where the motor will not draw any more power once a certain current threshold is crossed on either the stator or supply side.
Stator: Uses the total draw of phase a, b, and c from the motor side.
Supply: Uses the draw from the supply side
Think about current limits as protective boundaries - kind of like having both a speed limit and a weight limit on a bridge. Your motor controller needs two different types of these limits because of how brushless motors work.
When your motor is running slowly or just starting up, something interesting happens - the windings inside the motor (stator) can actually draw more current than what's coming from your battery. This gets especially important in pushing matches or when your motor is nearly stalled. Imagine your robot is in a head-to-head pushing match - your motors are working super hard but barely moving. In these near-stall conditions, they're pulling tons of current through their windings while hardly drawing anything from the battery. Without both limits in place, you could easily cook your motors without even realizing it. That's why we need both a supply current limit (protecting your battery) and a stator current limit (protecting the motor's insides). This dual protection becomes crucial when you're running at those really low speeds or in tough pushing situations.
For the Neo 550 - since it's one of the smaller motors in the family - you'll want to keep those current limits between 25-30 amps. Yes, your controller might be set to 40 amps by default, but that's too much for these little guys. The full-size Neo motors are different - they can handle brief bursts up to 60 amps, but you'll still want to keep them around 40 amps for normal match use to avoid burning them up.
To set a limit of 24 amps on stator side.
To set a limit of 60 amps on stator side.
To set a limit of 50 amps on supply side.
Set the max current the motor can draw in amps. Motor speed will be capped to satisfy the max current. Also set what current reading is used for limiting calculations, between:
Parameters:
currentType
The current reading used for limiting calculations.
maxCurrent
The max current.
Hard limits can be configured by connecting limit switches to the Thrifty Nova. Call the enableHardLimits
method to enable limit switch hard limits.
Enable the hard limits.
Disable the hard limits.
Enable / disable hard limits.
Parameters:
enable
If hard limits should be enabled.
Hard limits work through physical switches or sensors connected to your motor controller's 10-pin connector. When you hit the switch or trigger the Hall effect sensor at the end of your mechanism's travel, it immediately cuts power to the motor to prevent damage. Think of these as your last line of defense - they're your fail-safe that physically prevents the motor from pushing past its mechanical limits even if your code or soft limits somehow fail. You'll typically wire normally-closed limit switches or Hall effect sensors to these pins, so if a wire gets disconnected, the motor will safely stop instead of potentially running past its limits. These are especially important on mechanisms like elevators or arms where running past the end of travel could cause serious damage.
Soft limits are positions on the motor's encoder that the motor will not pass. This allows you to constrain motion between two points, helpful in many mechanisms where overrotation or overextension are dangerous.
First you must set the soft limits, the following constrains the motor between -18 and 24 encoder ticks.
This example constrains the motor between 3 and 9 encoder ticks.
Then one must physically enable the soft limits to take effect.
You can also turn off soft limts, but still leave the limits configured on the motor controller.
Sets the soft limits that the motor will not cross if soft limits are enabled.
Parameters:
revLimit
The reverse position the motor will not go past.
fwdLimit
The forward position the motor will not go past.
Enable / disable soft limits.
Parameters:
enable
If soft limits should be enabled.
Soft limits tell your motor controller how many revolutions your motor can safely turn before it needs to stop. Unlike hard limit switches that physically cut power at the end of travel, soft limits use the motor's built-in encoder to count rotations. You set these in your controller to match your mechanism's actual range of motion - for example, if your arm can only rotate 3.5 times before it hits its mechanical stop, you'd set your soft limit to something like 3.4 rotations. This prevents your mechanism from binding up or damaging itself by trying to push past its mechanical limits. Since these are programmed into the controller itself using encoder counts, they're always enforced - you can't override them, and they'll work consistently every time.
You can reset the encoder on the Thrifty Nova to be at some specific value. The current position of the encoder will real as the set value, and all the other readings will be adjusted accordingly. The position needs to be passed in encoder units, so it can be wise to use conversions.
The Thrifty Nova supports three types of encoders, each with different capabilities:
INTERNAL
42 counts/rev
✓
✓
Built into NEO motors
QUAD
4096 counts/rev
✓
✓
External quadrature encoder
ABS
4096 counts/rev
✓
X
External absolute encoder
First, tell the motor which encoder type you're using:
The following example sets the encoder to be currently at the zero position.
And this example sets the current position to read as 21 encoder units.
setEncoderPosition
Sets the encoder position.
Parameters:
position The position to set the encoder to.
The Thrifty Nova supports follower mode, allowing one motor controller to mirror the behavior of another. This is useful for mechanisms that need multiple synchronized motors, like a drive train or elevator.
To make a motor follow another:
Followers can be configured like any other motor. Here's a typical setup for a drive train:
The follower will mirror whatever control mode the leader is using (percent output, position, velocity)
Follower updates depend on the fault status frame rate - slower rates mean slower follower updates
A motor can only follow one leader at a time
If you call other control methods (like setPercent()
) on a follower, it will stop following
Like other configurations, you can check if setting up follower mode failed:
The Thrifty Nova provides various ways to set the output of the motor, percent, positional, and velocity control. The following examples highlight various applications of these three control modes.
Simplest control mode - directly sets motor power:
Moves to specific encoder positions using PID control:
Maintains specific speeds using PID control:
Configure encoder type with useEncoderType()
(Optional) Set initial position with setEncoderPosition()
Use control methods:
setPercent()
for direct power control
setPosition()
for position control (requires PID)
setVelocity()
for velocity control (requires PID)
Read feedback with:
getPosition()
for current position
getVelocity()
for current speed
Position and velocity units are always in encoder-native units
Use the Conversion
class to convert between encoder units and real-world units
Position/velocity control require properly configured PID
setPosition()
sets a target for closed-loop control
getPosition()
reads the actual measured position
Current readings are always in amps
All encoder readings are relative to the last setEncoderPosition()
call
Managing CAN bus bandwidth is crucial as you add more devices to your robot. CAN 2.0 has a finite amount of bandwidth available, and each message takes up space on the bus. At 1Mbps (typical for FRC), you can theoretically transmit about 1000 frames per second under perfect conditions, but you'll want to stay well below this to avoid bus congestion.
One key way to reduce unnecessary traffic is to disable polling for sensors you aren't using. If you're not using the internal encoder, set setSensor to zero. Similarly, if you're not using an external encoder, setQuadSensor should be zero. There's no reason to waste bus bandwidth requesting data from sensors that aren't connected!
Remember that control loops (position and velocity PID) run directly on the motor controller itself at 1kHz - you don't need super fast feedback just for the control to work. However, if other mechanisms on your robot are sequencing based on position or velocity values from this motor, you'll want to set appropriate feedback rates to ensure smooth coordination. Just remember - there's rarely a reason to set any feedback faster than 10ms (100Hz).
Similarly, current limiting runs directly on the motor controller - you don't need frequent current feedback just for the limiting to work. If you're not actively monitoring current draw for debugging or logging, you can set this to a much lower frequency (like 0.2s) or even zero. The controller will still protect your motors, but you'll free up valuable bus bandwidth.
When you're first testing a mechanism, it can be helpful to temporarily increase these frequencies for debugging. But once you've verified everything works, dial those frequencies back down for competition. Think about what data you actually need and when. Position feedback for coordinated mechanisms? Keep that at 100Hz. Fault data? That can probably run at 4Hz or even slower.
Remember that every motor controller on your CAN bus adds up. If you've got six motors each sending five different types of frames, that's 30 potential messages fighting for bandwidth! And that's before counting other devices like the PDP/PDH, pneumatics hub, or other sensors. Being smart about your CAN frequencies isn't just good practice - it can mean the difference between smooth operation and weird timing hiccups in the middle of a match.
Remember: All these values represent the period in seconds between transmissions. Smaller numbers mean more frequent updates but more CAN bus utilization.
The Thrifty Nova provides functionality to modify the frequency at which each of the five categories of CAN frames are transmitted at.
These configurations can be set by accessing the motors canFreq
configuration object, and by calling the appropriate method by providing the period, or the time between consecutive transmissions, in seconds.
The following example demonstrates how to modify these values.
Set CAN frame frequency for faults.
Parameters:
per
The period in seconds.
Set CAN frame frequency for encoder feedback.
Parameters:
per
The period in seconds.
Set CAN frame frequency for quadrature encoder feedback.
Parameters:
per
The period in seconds.
Set CAN frame frequency for control commands.
Parameters:
per
The period in seconds.
Set CAN frame frequency for current measurements.
Parameters:
per
The period in seconds.
The Thrifty Nova provides both position and velocity control using an onboard control loop, running on the motor controller at 1kHz. A PID must be configured in order to use position and velocity control functionality. The PID controller has an additional feed-forward term.
There are two separate builtin PID configurations. These can be individually configured, and then the active PID configuration can be selected by .
Below is how to set individual PID settings on the controller's first PID slot. Note that these can be chained together just like standard configuration functions.
Setting the configuration for the second PID slot is as simple as changing pid0
to pid1
.
To select the first PID configuration, pid0
, as active, use the following code.
And to select the second PID configuration, pid1
, as active, use the following code
Set the PID slot to use for feedback control.
Parameters:
encoderType
The PID slot to use.
Functionality for configuring the Integral Zone is currently in progress on the Thrifty Nova firmware.
Set the PID controller terms from a PIDController object.
Parameters:
pid
The PIDController object.
Sets the proportional term for the PID controller.
Parameters:
p
The proportional term.
Sets the integral term for the PID controller.
Parameters:
i
The integral term.
Sets the derivative term for the PID controller.
Parameters:
d
The derivative term.
Sets the feed forward term for the PID controller.
Parameters:
ff
The feed forward term.
The Thrifty Nova position and velocity feedback methods return using encoder units. Closed loop control uses these units as well. However oftentimes programmers want to convert to a more user friendly unit. For this we can use the Conversion
class.
We can create a converter by providing a human readable unit from the PositionUnit
or VelocityUnit
types, and the EncoderType
of the encoder we are using.
To convert to encoder units for setting a value we use the toMotor
method.
To convert from encoder units for reading a value we use the fromMotor
method.
RADIANS
Angular position in radians
Mathematical calculations, arms
DEGREES
Angular position in degrees
Human-readable angles, swerve modules
ROTATIONS
Complete rotations
Wheel rotations, continuous mechanisms
RADIANS_PER_SEC
Angular velocity in radians/s
Mathematical calculations
DEGREES_PER_SEC
Angular velocity in degrees/s
Angular motion control
ROTATIONS_PER_SEC
Rotations per second
High-speed mechanisms
ROTATIONS_PER_MIN
Rotations per minute
Shooters, intakes
The Thrifty Nova provides various types of feedback including encoder feedback, and current feedback.
For encoder feedback to report correctly the user must specify which encoder is being utilized. This can be set using the useEncoderType
method.
One encoder type is the encoder inside the BLDC motor attached to the controller.
The encoder type can also be set to an external quadrature encoder.
In addition, the encoder type can also be set to an external absolute encoder, but currently only for position control and feedback.
The following encoder functionality is work in progress:
Direct CAN encoder to motor controller
Set the encoder type to use for feedback control.
Parameters:
encoderType The encoder type to use.
You can access encoder feedback for both position and velocity measurements.
Below is the method for retrieving the position feedback measurement from the encoder. This is returned as a double representing encoder units.
Below is the method for retrieving the velocity feedback measurement from the encoder. This is returned as a double representing encoder units per second.
The Thrifty Nova also provides current feedback on both stator and supply side current. The difference is as follows:
Stator: Uses the total current draw of phase a, b, and c.
Supply: Uses the stator current draw plus the current draw of the controller itself.
Below is the method for retrieving the stator current feedback measurement from the motor. This is returned as an integer representing amps.
Below is the method for retrieving the supply current feedback measurement from the motor. This is returned as an integer representing amps.
Here is an example implementation of a swerve module using Nova. The turn controller is configured with an external absolute encoder. You would create a swerve module by calling the constructor as follows.
Below is the swerve class definition.
The following table describes the LED status indicator patterns and their meanings:
Red
Alternating sides
500ms
Fatal fault
Blue
Synchronous flashing
100ms
Encoder not connected or invalid
Yellow
Alternating
500ms
Enabled but output power is 0%
Yellow
Synchronous flashing
500ms
No CAN data detected
Yellow
Solid
N/A
CAN detected but no control frames
Green
Flashing
Variable
Forward motion (flash rate = speed)
Red
Flashing
Variable
Reverse motion (flash rate = speed)
Orange
Synchronous flashing
500ms
Motor halted - high temperature (>90°C)
Orange
Synchronous flashing
50ms
Warning - approaching thermal limit (>75°C)
Note: For direction indicators (Green/Red), a solid light indicates maximum speed in the respective direction (forward for green, reverse for red).
Below is an example of a simple arm subsystem. Visualize the arm from the side as overlaying unit circle, where zeroed arm lies on the +x axis.
Sometimes, you may need to restore your Thrifty Nova controller to its factory firmware. This can be done by following these steps:
Prepare the USB Cable:
Make sure you have a USB-C cable ready.
Hold Down the Reset Button:
Press and hold the reset button on the Thrifty Nova.
Connect the USB Cable:
While holding the reset button, plug the USB-C cable into the Thrifty Nova and then into your computer.
The Thrifty Nova will appear on your computer as a removable storage device, just like a flash drive.
Transfer the Reset File:
Drag and drop the provided .TBFW
file onto the Thrifty Nova "flash drive."
The controller will automatically reset the firmware
Why Reset?
Starting Fresh: If the controller loses power when flashing firmware, the firmware can be corrupted. Restoring to default will fix this corruption.
Below is an example of a simple elevator subsystem. Forward motion pulls the elevator up.
The following sections contain example implementations for various subsystems using the Thrifty Nova.
To use the Thrifty Nova motor controller, you need to connect the power, communication, hall sensors, and phase wires. For the larger wires, we recommend Inline Wago Connectors, sold here. Follow these steps for proper setup:
Power Lines:
Connect the 12 AWG red wire to the positive power supply terminal.
Connect the 12 AWG black wire to the negative power supply terminal.
Communication:
CAN Connection: Use the 4-pin CAN connector for CAN communication. Ensure it is properly attached.
USB Connection: Alternatively, use the USB-C port for USB communication. You will typically use either CAN or USB, not both.
Hall Sensor Cable:
Connect the 6-pin JST encoder cable to the Brushless Hall Sensor Connector. This cable is necessary for reading the motor's hall sensors.
Phase Wires:
Connect the three 12 AWG phase wires:
Red wire to red motor phase.
Black wire to black motor phase.
White wire to the white motor phase.
These wires should match the corresponding terminals on a NEO motor.
Data Port Connector
For wiring external sensors like encoders and limit switches, not needed for initial bring up
More info found at Data Port Connector
Required Connections:
Power: Red and black power lines.
Communication: Either the CAN connector or the USB-C port.
Hall Sensors: 6-pin JST encoder cable.
Phase Wires: Three 12 AWG wires (red, black, and white).
By following these steps, you ensure that your Thrifty Nova is correctly powered and wired for operation.
The Brushless Hall Sensor Connector is a 6-pin Port. This port is designed to accept the built-in hall-sesnors from legal FRC brushless motors.
The pinout is specified below.
The motor runner board allows for reversing (via switch) and powering the motor (via the integrated slide potentiometer. The board sends a signal to the processor to enable it in "Slider Mode", turning off USB and CAN control. We designed this to make prototyping with brushless easier, just wire a ribbon cable to it and away you go!
The USB-C Port is located on the corner of the Thrifty Nova. It provides a USB 2.0 interface and power for the Nova's internal microcontroller. For more info, see .
Although you can configure your Thrifty Nova using Thrifty Config without connecting the main power, you won’t be able to spin a motor until main power is connected.
A limit switch is a device that detects the presence, absence, or position of an object by opening or closing an electrical circuit when a physical force is applied to its actuator (like a lever or button).
The Thifty Bot sells a normally closed version of this called the Thrifty Hall Effect, which is a contactless magnet-based limit switch that is omnidirectional with an LED for user feedback. For more info, see the product page
Position Sensing: Detects when the system reaches the end of its range.
Safety: Stops motors if the system they control moves into an unsafe position.
Protection: Prevents parts from moving too far and getting damaged.
Quadrature encoders are sensors that measure the position, speed, and direction of a rotating object using two signals that are 90 degrees apart.
Signal Generation: The rotating shaft produces two square waves.
Direction Detection: The order of the signals shows which way the shaft is turning.
Position Counting: Counts the pulses of the signals to determine position.
Resolution: More pulses per revolution mean more accurate measurements.
Absolute encoders provide a unique position value for each shaft angle, ensuring that the exact position is always known, even after a power cycle.
These encoders use Pulse Width Modulation (PWM) to convey position information. The position is encoded in the width of the pulses generated by the index pin.
Signal Generation: The encoder generates pulses with varying widths corresponding to the shaft's position.
Position Detection: The width of the PWM signal is measured to determine the exact position of the shaft.
Uses:
Precise Positioning: Ideal for applications requiring accurate and repeatable positioning. Think about controlling a swerve module's rotation or an arm's position.
These encoders provide position feedback as a continuous analog signal, typically a voltage or current that varies linearly with the position.
Signal Generation: The encoder produces a continuous analog signal (in the Nova's case, 0-3.3V) proportional to the shaft position.
Position Detection: The control system reads the analog signal to determine the exact position.
Continuous Feedback: Provides smooth and continuous position information.
Precise Positioning: Ideal for applications requiring accurate and repeatable positioning. Think about controlling a swerve module's rotation or an arm's position.
The Breakout Board exists to run limit switches, encoders, and analog sensors into the Thrifty Nova. This board breaks the 10 pin Data Port Connector into individual 3 pin connectors which break out 5V, the signal, and ground.
For the digital signals, a normally closed sensor will trigger a green LED when the sensor is opened. This was designed to compliment the Thrifty Hall Effect, so when the red LED on the Thrifty Hall Effect (normally on) turns off at the presence of a magnet, a green LED on this board turns on.
For the analog signal, an analog buffer and a resistor divider are present to gain the full resolution of a 5V signal such as the Thrifty Absolute Magnetic Encoder.
We are actively working on our release for the Thrifty Config app, and we are excited to share more with you soon. In the meantime, here is a sneak preview of the existing functionality.
The Nova contains 2 tapped 10-32 holes for mounting on grid pattern tubing, 1 inch apart. There are 2 additional 6-32 holes for mounting add-on boards on top or for a lower weight mounting option.
is a link to the OnShape with the printed case included.
The Thrifty Bot sells one of these, and more info can be found at the product page
Connector Pin
Pin Type
Pin Function
1
Power
Ground
2
Digital
Hall Sensor C
3
Digital
Hall Sensor B
4
Digital
Hall Sensor A
5
NC
Not Internally Connected
6
Power
+5V
Connector Pin
Pin Type
Pin Function
1
Power
+3.3V
2
Power
+5V
3
Analog
Analog Input (0-3.3V)
4
Digital
Forward Limit Switch Input
5
Digital
Encoder B
6
Digital
Multi-function Pin
7
Digital
Encoder A
8
Digital
Reverse Limit Switch Input
9
Digital
Absolute Encoder Index
10
Ground
Ground
Software releases will be made available here, along with a Javadoc.