Request for anyone using Neo BLDCs and SparkMAX controllers over CAN


The problem:

We’re trying to use the SparkMax Controller with the NEO brushless motors and are running into issues when trying to interface with them over CAN. (PWM works fine)

Part of this probably comes down to us not using them for the FRC comp, we’re a group of uni students using them for an entry into the university rover challenge but more importantly the software is based around ROS and Arduino – not the RoboRIO and the FRC libraries.

We can’t seem to get any sort of response, currently the bus isn’t being pulled dominant in the ACK slot, we’re not sure if this is because the message is invalid or some other control isn’t being set – eg the RTR slot.

The current test message involves trying to set periodic_status_1 period to 3855ms (0x0F0F). So based off of the code in CANSparkMaxFrames.h (line 48) and CANSparkMaxLowLevel.cpp (lines 214 and 228) and the FRC CAN docs that needs to be addressed to the following id: [28:24] = 2; motor controller id [23:16] = 5; rev robotics id [15:6] = 0x060; Api class & index, index isn’t used, value taken from driver code [5:0] = 2; ID of motor controller, set to 2 using windows client

Putting those bits together we get 0x02051842, which is what we see being transmitted on the CANbus physically (oscilloscope trace: along with the correct data, length and CRC. Yellow is CAN_H, magenta CAN_L, green and blue are rx and tx respectively of the MCP2562 transceiver connected to a Teensy 3.6. The code used to generate this can be found here:

The request: If you’ve had success configuring these controllers over CAN would you mind capturing an oscilloscope trace of the CAN bus? The docs on rev robotics site don’t dig into any of those details as I assume they only expect FRC people to use their stuff :stuck_out_tongue:



I would encourage you to contact REV Robotics - I’m sure they’d be more than happy to give you a hand.

The arbitration ID and the frame data you have seems correct to me… You may want to double-check that the SPARK MAX supports the data rate you’re specifying though, maybe. Maybe also double-check that the firmware on the SPARK MAX is also valid.

One problem I suspect you’ll run into very soon is that the SPARK MAX will require a heartbeat to be regularly sent before it’ll run the motor. Unfortunately FIRST requires that the heartbeat details are kept closed.

@Will_Toth from REV might be able to give you some more details.

1 Like


I replied to your support request, I’ll also paste it here. I also took a scope capture of receiving one of the periodic frames (i.e. a frame originating from the SPARK MAX):

It sounds like something is not quite right with the CAN frame. The SPARK MAX will ACK any valid CAN frame , even if the address is not for that particular device. If the CAN frame is valid with an incorrect address for that device, or if it is a valid frame but not a message recognized by the device, it will ACK, but ignore the frame. If you are not getting the ACK, make sure you are using an extended ID (29-bit) instead of a standard ID, and check your encoding/decoding.

One thing to note that I didn’t include in the email is the current firmware will latch into CAN mode once a valid CAN frame is received, otherwise PWM mode is assumed. So you’ll start getting these periodic frames once a valid frame is received.



It should be trivial to find the new heartbeat through the spark max Java API, considering the ease of decompiling java (unless it was moved to a CCI library like ctre does)



The heartbeat format changed after it was moved into the separate driver library (which is called from Java via JNI).



Hmmm, that note about the heartbeat has me worried. @Will_Toth how would that effect the controller? I imagine would would present an issue in actually controlling the motors but even so we should still be able to get an ACK out of it?

@Redrield thankfully Rev have provided the C++ source which is what I’ve using to figure out the API class/index values since those weren’t documented anywhere. I can’t find anything when grepping for heartbeat in either their drivers or the WPILib source however…

On the other hand if the heartbeat is required 100% I guess the only option is try and decompile code on the RoboRio image? From quick reading that seems to be the linux part whilst the ‘firmware’ is the FPGA bitsream - and that’s not getting undone.



@ASymonds honestly if you have the budget I’d recommend you switch to using some V4.12 VESC’s instead.

They’re completely open source with their PCB, firmware, and schematics. There’s also lots of documentation on Benjamin vedders website.

You can also connect them in series with CAN and control them that way.

You can ALSO control them over UART, and there are already loads of libraries on GitHub made to do this over Arduino.

You can also connect to one “master” device over UART, and have the rest be Daisy chained over the CAN bus, and command them individually that way.



I can confirm that our heartbeat implementation is closed. We have a ‘non-FRC’ version of the firmware in the works, something that doesn’t run with the roboRIO for competition, but opens the heartbeat to a simple/open implementation for non-FRC use. This should work for your application.

The VESC is definitely a cool project as long as you are ok with the price and form factor, and the NEO will work with it.



Open heartbeat/non-FRC firmware sounds like what we need, the Odom info for ROS from encoders isn’t super critical to have straight away since we’ll have plenty of IMUs to cover that. We’ve reimplemented some of the more general features in software using the IMU info as feedback for PWM so can wait for that firmware to be released, as long as it’s on its way we can make do.

The VESC is a tempting backup, we’ll have to see if the uni’s FRC team (4774, if any dropbear people are reading this and interested) feels like buying the sparkmax controller off us though, darn budget constraints.

1 Like


Didn’t you buy them from us in the first place? :stuck_out_tongue:

1 Like


That’s quite possible ahahaha, I was working over the summer when the mech related electronics were ordered/acquired :stuck_out_tongue: oooops



I have the compiled driver lib, including functions that process and send the heartbeat CAN packet, unfortunately I’m not that good at deciphering compiled code. I don’t know the exact structure but basically it’s just a byte that’s set when the RIO has outputs enabled. I can keep digging but i make no promises



If anyone wants to try reverse engineering libSparkMaxDriver (not that I am endorsing this), the two functions you will want to look at are void REV_CANSparkMaxRegisterDevice(int deviceID) (from rev/CANSparkMaxHeartbeat.h) and HeartbeatDaemon::Main().

(I would not recommend publishing any further findings from this - nobody wants forced incompatible firmware updates.)



Or forced mid season RoboRIO image updates for all teams. For a real world example of consequences of releasing workarounds to security features.



NI had plenty of time to get that fix right, don’t shoot the messenger cause they screwed up.