Clear, concise best practices for Sparkmax/Neo current limiting?

Since our school doesn’t have weekend robotics meetings anymore & the team is behind with our first event next week, I’m hosting students this weekend, and programming is the task at hand. I am not a programming mentor. Yep, still build season here for us.

I mentioned current limiting being important with brushless motors yesterday, and students implemented limits for each motor in code after tracking down how. However, after searching & reading a few posts this morning, I’m concerned we’re still not set up well. I overheard a programmer say our Neo drive motors are at 30A, for example, which sounds off…

Is there a clear, concise best practice I can point my team to? Other than end game, we have three modes:

  • intaking: 4 Neo drive motors, 1 Neo intake motor, 1 775pro conveyor motor
  • drive to shooting location: 4 Neo drive motors, 1 Neo speed up wheel, 1 Neo shooting motor
  • shooting: 2 775pro conveyor motors, 1 Neo speed up wheel motor, and 1 Neo shooting motor set up to spin two opposing wheels to minimize spin. We should not usually be driving when actually shooting since our shooting spots are hub bumper and 1 robot length back from hub bumper, but it may rarely happen.


Depends how many you have. Brownout occurs at anywhere from 150A to 300A total draw depending on battery health and wiring quality.


Thanks. At the end of my post, I shared what motors run during our primary operating modes, including 4 Neo drive motors.

I’m more concerned about comments that indicate peak current will exceed software limited current at times & cause problems and how to mitigate that. Maybe 30A is too safe for us or maybe it’s better for reliability despite the torque trade-off?

Also, is it better to limit current via software or via the client via USB as described here (thanks to CrimsonRobotics)? I did read something about making sure to burn the settings to flash if SW.

We’re going for simple and reliable, so we will err on the side being conservative to avoid brown outs, but I also don’t want to excessively limit ourselves. I just don’t think any of us has much feel for where to draw those lines for the limits, and I’m interested in a good reference for that if one exists for the overall robot rather than instructions for an individual motor. Thanks.

Judging by motor specs, 30 amperes per motor looks like it’s quite close to the current required to slip the motors, which is the maximum current you’ll ever want to give to your drive. You can increase it slightly if you want but I doubt it’ll help.

1 Like

You definitely want to set a current limit that will avoid brownout; Oblarg is right on the rough total current draw that happens at. It depends some on how long your battery cables are, their gauge, and how good a job you do on your crimps.

I know its a hard sell with the students (more power more better school), but limiting the current to avoid or limit wheel slip is well worth doing and will actually improve your cycle times!

iLite can get you pretty close to the right current limit to start with!

NEO550s MUST be current limited to 20 Amps (IIRC) or so or you WILL fry them.


That’s a big deal - we lost a NEO550 right out of the gate (I didn’t even know we were using it for a specific application because it got done so late) because of this.

The SparkMAX is sized to supply the current to drive a fully loaded NEO; a poor heavily loaded NEO550 will ask for more than it can really take so keeping it from cooking itself is doing it, and you, a favor for sure!


This is a bit beyond what you asked for, but still relevant. By default - our programming team’s directions are as follows:

  • Upon initialization in a subsystem constructor, each spark max is restored to factory defaults. This is because if you change out a spark max in a hurry, you don’t want it to accidentally have some old parameters that it’s using for anything. We also sometimes have had weird, non-replicable issues that seems to be addressed by doing a factory reset every power up.
  • neo550s are set to 20 A limits. If this doesn’t work, we can increment this buy compare against this chart to make sure we don’t allow it to run longer than a certain amount of time NEO 550 Brushless Motor - Locked-rotor Testing. For instance, you could let it pull 40 A if you’ve got other checks that won’t let it run at 40 A for more than say ~20 seconds (but ideally shorter than that). I probably wouldn’t let it run at 60 A at all as it’ll start to fail in about 6 seconds.
  • big neos can be left at the default 80A, but I usually recommend explicitly setting it anyway.
  • I’d recommend a constant for each (set of) motors current limit that you can modify/see all in one place anyway
  • we set all desired parameters on the spark max AND burn to flash. This ensures that if you have any kind of brown out/power issue - the spark max should come up with the same parameters as what you intend for them to.

As for your drivetrain limit, as indicated by others that’s probably because that’s where your wheels would start to slip anyway. You can analytically guess this value based on the iLITE drivetrain simulator, or actually test it by putting your robot up against a wall on carpet, plot the current, and then slowly increase the setpoint until the wheels slip and then take a value a little shy of your peak current as your current limit.

Of course, imo with the number of PDH slots available and the power available in motors now, there’s not usually a good reason to run on the edge of an acceptable current. It’s probably worth it to either gear something a little slower to reduce current, throw another motor on it to share the load, or potentially change from something like a 550 to a big neo or a falcon


For the not-NEO-550: NEO Brushless Motor - Locked-rotor Testing.

We use a C++ class that wraps the SPARK MAX and makes it easier to manage the config stuff (which you can also do by just burning the settings using the REV HW Client). The settings we used for mechanism NEOs and NEO 550s are here:

These are really solid points - especially doing all the setting via software at initialization (and subsequent saving to flash).

This is an especially big deal when something needs to be replaced as mentioned - all you need is the CAN ID set correctly and the rest will take care of itself. Expecting specific settings to be properly configured off-robot, all of them, not missing or mal-configuring even one of them, under the time crunch of competition is asking a lot - a lot that doesn’t need to be asked for.

Plus doing it in the code gives you the real-deal, “as-built” documentation for what is really in effect on that controller - this is important if you ever want to re-use a subsystem or use it as a base for a subsequent generation. It’ll capture all of the non-default settings more reliably than ay external written doc since it will be the source of truth for that controller.


It sometimes feels a bit odd to suggest it, because generally speaking I wouldn’t tell someone to write code that burns the same values to flash every time it initializes (the “proper” way would be to read it and then write it if it’s different than expected)…but unless someone writes some really bad code, no one’s coming close to what I assume is the something like 100,000+ read/write cycles of the flash memory. So for our application, I would definitely argue it’s the “right” way to do it - exchanging the flash memory life time for boot time and reliability of expected behavior.


I was told the SparkMax flash life is FAR shorter than 100k…
Flashing SparkMaxes in code is also vulnerable to race conditions, leading to hard to sort weirdness. Speaking from repeated painful experience :frowning:
I strongly suggest -reading- the state and only flashing if it’s wrong.

1 Like

Hm, maybe @dyanoshak could chime in on what Rev recommends based on the number of usable flash write cycles and/or race conditions? I see a comment actually in the code/api that it’s actually 10,000 write cycles, which would still nearly 80 power cycles a day every day for from Jan 1 through April 30th. But that order of magnitude is definitely relevant.

Seems to me like you can avoid any race conditions with flashing the sparks, but maybe my assumptions on the number of writes is way off.

Ah, yes! That’s where we found it!
Rember, they get cycled every time the code starts, so ever code push, battery swap, turn off, etc…
It got me worrying… especially with the race condition problem.

FWIW, the code I linked above does the read/verify/write only on command thing. We can manually trigger a write from test mode. Also, the config stuff normally all happens when the robot is in disabled mode and the code is designed to spread out CAN bus traffic and blocking config function calls (to avoid loop overruns). It also handles detecting any motor controller restarts and restoring volatile settings (status frame periods), as well as any errors (these are counted and reported on demand, rather than spewing error messages out as the code runs).

Has anyone found any issue with restoring factory default, setting all the needed values, then just not burning to the flash?

If your controller browns out or have a suspect power cable for any reason this could cause inconsistent and unexpected behavior.

Generally speaking, you want your flashed values to be the same as what you’ve set them to - other than while doing testing in your shop to find new values.


The easiest thing to get out of the way is if you’re using NEO 550, I would NEVER set the current limit higher than 25A. Any application where you need more torque than that provides should probably be a NEO anyways.

Generally speaking, a NEO can handle the default 80A current limit (thermally) in normal FRC use. Basically that means the robot can run for 3min and then have a short break and that you aren’t running the motor constantly under load or stalling for long periods of time during the match.

If you plan on running very long practice sessions or the motor is on a mechanism that is stalled (at a high throttle point) for long periods in the match, you will want a lower current limit.

Outside of damaging the motor, there are a couple other concerns:

  1. Current budget. As some have already mentioned, you can only draw so many amps overall before the battery voltage drops so low that critical components turn off or disable. Reducing current limit on motors keeps the peak current draw to a minimum. In reality you aren’t usually running everything on your robot at once so approaching current limiting from the standpoint of “how many amps would I draw if every motor was stalled” is going to lead you down the wrong path. You want to think through what groups of motors will need to run at the same time frequently and set current limits to keep the total current in those groups within acceptable ranges (testing will help you determine what these are, but probably 150-250A). For example, your drivetrain and shooter will probably run at the same time (shooter spin-up happens while driving to go shoot) but your climber and shooter don’t usually run at the same time.

  2. Torque limiting and avoiding wheel slip. If you have a high torque mechanism that is capable of damaging itself in stall conditions, current limiting is a good way to limit the torque the motor produces (torque and current should be considered to be proportional). In addition, you should set current limits on your drivetrain to keep your wheels from slipping. These things really have to be determined with testing. You mentioned 30A on your drivetrain motors which does seem a little low, however it’s in the ballpark. If you have a very low gear ratio 30A could totally be the correct limit. 3005’s drive motors were limited to 55A this year for reference.


It must be nice to be able to retire controllers after one season.

Definitely some privilege in that we try to keep our robots intact for demos, prototypes, programming development from year to year. Not just from a money standpoint, but also from a space standpoint (though we are running out of that).

But I’d also argue most teams aren’t running roborio code that reflashes memory every day jan- April. There are certainly some teams that get to running “real” robot code much sooner than us, but we’re probably doing pretty good if we were to get up to an average of 80 boot ups a meeting 4x a week across March and April, which would only be about 30% of its life cycle (80 * 4 * say 10 weeks).

Now I’m kind of curious and will see if we can keep a counter of boot ups. Can probably do it in code and also saw a neat counter that @Nick_Lawrence had - but I can’t remember if that was run time or power ups

@ahartnet Ours is runtime measured in hours, sorry. It does not count power-on cycles.

1 Like