[CAN SPARK MAX] Unable to retrieve SPARK MAX firmware version for CAN ID: 0

We’re trying to use 4 SparkMax speed controllers for our chassis, and we keep getting this error whenever we deploy our code:

[CAN SPARK MAX] Unable to retrieve SPARK MAX firmware version for CAN ID: 0. Please verify 
the deviceID field matches the configured CAN ID of the controller, and that the controller is 
connected to the CAN Bus.

We’ve updated the firmware to 1.5.2, and when we tried setting their IDs to 0, 1, 2, and 3, it told us there was already a CAN device of the same type connected to ID 0. We opened the Phoenix Tuner to see if any of the TalonSRXs we’re using were connected to ID 0, and none of them are. The only things connected to ID 0 are the PDP and the PCM, which shouldn’t be affecting our SparkMax’s. Here’s our Drivetrain code as it is, trying to use IDs 1, 2, 3, and 4 for our SparkMax’s, which still didn’t work:

package frc.robot.drive; 

import com.revrobotics.CANSparkMax;
import com.revrobotics.CANSparkMaxLowLevel.MotorType;

import frc.robot.OI.Controller; // import Xbox 360 controller inputs
import frc.robot.Robot; // import robot script

public class Drivetrain {
private final int[][] motorID = { { 4, 1 }, { 2, 3 } }; // motor ids for the motor controllers
public CANSparkMax[][] motors = { { null, null }, { null, null } }; // actual motor controller objects, not defined yet
private double wheelSpeed = 0.5; // default driving speed for the robot (set to slowest)
public int reverseMultiplier;

public Drivetrain() {                                   // Drivetrain constructor, assigns motor controller IDs
    for (int a = 0; a < 2; a++) {                       // nested for loop (a "2D" loop, essentially) that assigns a variable to each motor based on position on the robot (a = left & right, b = front & back)
        for (int b = 0; b < 2; b++) {                   
            motors[a][b] = new CANSparkMax(motorID[a][b], MotorType.kBrushless); // sets the ids for each motor depending on its position
            System.out.println(motorID[a][b]); // attempt at troubleshooting the situation

    motors[0][1].follow(motors[0][0]); // makes the rear-left motor (the left "slave") follow the front-left motor (the left "master")
    motors[1][1].follow(motors[1][0]); // same as above for the right side

public void run() {                     // called every "frame"
    controlSpeed(); // run the speed controls
    tankDrive();    // run the direction controls

private void controlSpeed() {

    if(Robot.oi.getButtonDown(Controller.Pilot, 6)) { // if right bumper is pressed down
        wheelSpeed += 0.25; // increase the speed by 0.25 ONCE
    } else if(Robot.oi.getButtonDown(Controller.Pilot, 5))  { // if left bumper is pressed down
        wheelSpeed -= 0.25; // decrease the speed by 0.25 ONCE

    if(wheelSpeed >= 1) { // clamp that limits the min and max values of the speed to 0.5 and 1 respectively
        wheelSpeed = 1;
    } else if (wheelSpeed <= 0.5) {
        wheelSpeed = 0.5;

private void tankDrive() {
    double x = Robot.oi.getAxis(Controller.Pilot, 0); // value for where the joystick is on the x-axis
    double y = Robot.oi.getAxis(Controller.Pilot, 1); // same as above for the y-axis
    double left = (y*reverseMultiplier) - x / 2;
    double right = (y*reverseMultiplier) + x / 2;
    set(left, right);
    //set(((x*reverseMultiplier) + Robot.oi.getAxis(Controller.Pilot, 3) - Robot.oi.getAxis(Controller.Pilot, 2))*reverseMultiplier, ((x*reverseMultiplier) - Robot.oi.getAxis(Controller.Pilot, 3) + Robot.oi.getAxis(Controller.Pilot, 2))*reverseMultiplier); // this was for using the triggers as controls

private void set(double left, double right) {
    motors[0][0].set(-left*wheelSpeed); // sets the value for the left master motor
    motors[1][0].set(right*wheelSpeed); // sets the value for the right master motor

There are a couple of things.

First, CAN Ids ought to be unique, so don’t use zero, and don’t use anything the Talons are using. Make them unique numbers that no other devices are using.

Second, you will get that same error for any attempt to contact a Spark Max if the CAN Bus isn’t properly wired or has some related issue. (I happen to know this because I was getting it for an hour or so last night.) Check the STATUS light on the PCM to make sure it’s the right color. (Green, if I recall from when I looked it up last night.) If it isn’t, then there’s a wiring problem. That message appears to be the generic “I tried to talk to a SPARK MAX at the address you told me, but I couldn’t” message. Make sure your wiring is correct and that your CAN IDs are unique for each device.

1 Like

Don’t use 0 for a SparkMax. We’ve had trouble with that. However, reusing the same CAN id across types should be okay (eg, a SparkMax 1 and a Talon 1 should work fine.

With firmware 1.5.2 a CAN ID of 0 is considered “unconfigured”, so don’t try to use 0.

You didn’t mention in your post if you had used the USB-C cable and Spark Max Client to set the IDs, you only mention Phoenix Tuner. Be sure you’re setting the IDs with the Spark Max Client, and that you press the SAVE button at the bottom. We found on one of our laptops that the window didn’t fit on the screen and the SAVE button wasn’t visible.

I think that storing everything in arrays has a lot of downsides for readability and maintainability. It isn’t obvious which motor ID is left and right.

Here’s how I would write it:

public class Drivetrain {
   public static final int FRONT_LEFT_SPARKMAX_ID = 4;
   public static final int REAR_LEFT_SPARKMAX_ID = 1;
   public static final int FRONT_RIGHT_SPARKMAX_ID = 2;
   public static final int REAR_RIGHT_SPARKMAX_ID = 3;
   CANSparkMax frontLeftSparkMax = new CANSparkMax(FRONT_LEFT_SPARKMAX_ID, MotorType.kBrushless);
   CANSparkMax rearLeftSparkMax = new CANSparkMax(REAR_LEFT_SPARKMAX_ID, MotorType.kBrushless);
   CANSparkMax frontRightSparkMax = new CANSparkMax(FRONT_RIGHT_SPARKMAX_ID, MotorType.kBrushless);
   CANSparkMax rearRightSparkMax = new CANSparkMax(REAR_RIGHT_SPARKMAX_ID, MotorType.kBrushless);

  public Drivetrain() {

Despite getting confused a few times, I don’t see anywhere in the code that you posted that tries to access a CANSparkMax at ID 0, which is what would cause that message. Be sure to look through all your code for a CANSparkMax at ID 0, maybe in some place you added for debugging.

1 Like

I agree with @Joe_Ross. The perceived flexibility of the arrays is outweighed by the loss in readability of two 2-dimensional arrays, and a for loop in a for loop. But it does look like the code is correct.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.