CanControl is a library for controlling CAN-based motor controllers (REV Spark MAX, CTRE Talon SRX, Victor SPX) from Arduino boards using an MCP2515 CAN Shield. CanControl currently supports:
- REV Robotics Spark MAX (full support)
- CTRE Talon SRX (PercentOutput only)
- CTRE Victor SPX (PercentOutput only)
It handles the necessary FRC-style "Heartbeat" frames and providing high-level wrappers, so you can control FRC motor controllers without a roboRIO.
- High-level C++ wrappers:
CanControl::SparkMaxCanControl::TalonSrxMotorCanControl::VictorSpxMotor
- Universal heartbeat frames to keep FRC motor controllers enabled.
- Full features from the SparkMax
- Low-level Spark MAX CAN protocol is auto-generated from REV's JSON spec (see
gen.pyandthird_party/REV-Specs/).
- Low-level Spark MAX CAN protocol is auto-generated from REV's JSON spec (see
- CTRE (Talon SRX / Victor SPX) support — percent/duty-cycle only
- CTRE integration is implemented from the only available public example for percent output; no further official CAN protocol docs were provided by CTRE.
- Arduino Board: tested with Arduino Uno and Arduino Mega 2560.
- MCP2515 CAN Module: Standard SPI-based CAN controller board (often labeled "TJA1050 + MCP2515").
- CAN Motor Controller: REV Spark MAX, CTRE Talon SRX, or Victor SPX.
- 120Ω Termination Resistor: CRITICAL. You MUST have a 120Ω resistor connected between CAN-H and CAN-L at the ends of your bus to prevent signal reflection.
The MCP2515 communicates via SPI. Connect it to your Arduino as follows:
| Pin Name | Arduino Uno Pin | Arduino Mega Pin | Description |
|---|---|---|---|
| VCC | 5V | 5V | Power |
| GND | GND | GND | Ground |
| CS | 10 | 53 | Chip Select (Configurable in main.cpp) |
| SO / MISO | 12 | 50 | Master In Slave Out |
| SI / MOSI | 11 | 51 | Master Out Slave In |
| SCK | 13 | 52 | SPI Clock |
| INT | 2 (Optional) | 2 (Optional) | Interrupt (not strictly required for basic TX) |
- CAN High (H): Connect MCP2515
Hto Motor ControllerYellowwire. - CAN Low (L): Connect MCP2515
Lto Motor ControllerGreenwire. - Termination: Ensure a 120Ω resistor connects
HandLat the furthers point of the bus (often the MCP2515 itself has a jumper for this, check your module). In any case, you must have a resistor on both ends of the bus.
Note: Spark MAX controllers do not have built-in termination. You must add the resistor yourself if it's the last device in the chain.
In your own platformio.ini:
[env:mega]
platform = atmelavr
framework = arduino
board = megaatmega2560
lib_deps =
https://github.com/willGuimont/CanControl.gitComing soon...
git clone https://github.com/willGuimont/CanControl.git
cd CanControl
git submodule update --init --recursiveOpen the project in VS Code with PlatformIO.
For Arduino Uno:
pio run -e uno -t uploadFor Arduino Mega:
pio run -e mega -t uploadThe example sketch (examples/main.cpp) immediately starts a "Heartbeat" to keep motors enabled. You can control a motor using the Serial Monitor (Baud Rate: 115200).
Serial Commands:
s0.5: Set Speed to 50%s-0.5: Set Speed to -50%s0: Stop Motorh: Help menu
Using CTRE devices requires that they be "FRC unlocked" to accept non-FRC frames. The FRC lock will be enabled by default and be persistent across power cycles if the device was ever connected to an FRC roboRIO. To unlock the device, you need to disconnect it from the roboRIO and power it while holding the reset button for about 5 seconds until the LED blinks green.
The low-level Spark MAX protocol bindings are generated from
doc/spark-frames-2.1.0.json (available from REVrobotics/REV-Specs) by gen.py and live in:
include/low_level/low_sparkmax.hsrc/low_level/low_sparkmax.cpp
These files are auto-generated (see the header comment) and should not be
edited by hand. Instead, update the JSON spec or generator and re-run gen.py.
The high-level SparkMax class in include/sparkmax.h wraps these generated structures to provide a user-friendly C++ API.
Located in the tools/ directory (install requirements with pip install pyserial):
-
can_monitor.py: Live monitor that talks to the Arduino sketch to print/log CAN traffic.python tools/can_monitor.py --port COM3 --output log.csv
-
compare_logs.py: Compare two CSV logs to find timing differences or missing messages.python tools/compare_logs.py good_log.csv bad_log.csv
This project uses PlatformIO's Unity-based test framework.
Run tests on your host (native):
pio test -e native -vRun embedded tests on the board (e.g. Mega 2560):
pio test -e mega -vThe native tests live under test/test_native, and embedded tests under
test/test_embedded.
- "Sticky Fault for CAN Bus Error": This usually means missing termination. Add a 120Ω resistor between Green/Yellow wires.
- Motor LEDs Flashing Orange/Green: The motor is seeing some valid frames but timing out frequently. Check wiring and termination or heartbeat frequency.
- CTRE Motors: Must be Factory Defaulted or not "FRC Locked". If they were used on a roboRIO, hold the B/C button on boot to factory reset.