Neo motors pulling only 5 Amps when stalled?

Ah, interesting. getAppliedOutput() reports the following:
-0.10531937620166631 -0.1130100405896176 0.11291848506118961 0.11673329874568926

So it looks like the MAXs are only sending about 10% power to the NEOs.

So this is what doesn’t make sense to me. At 10% output, the scaled stall current at the motors should be ~10.5A (105A stall current * 10% duty cycle).

Maybe this is one of the areas where brushless motors differ from brushed motors… Probably depends on sensored/sensorless and startup implementation… @Will_Toth or @dyanoshak might have more insight on this.

We set the free current limit to 20A and the stall current limit to 80A and the current config rpm to 10,000, which are the advertised factory defaults, and no surprise, the robot has much more torque to turn with. I believe getAppliedOutput is now reporting up in the 0.30s

Hopefully these defaults are safe enough limits to prevent hardware failure on the neo or spark max. The 40A limit was just not anywhere near enough torque. Also, we are geared for about 13 ft/sec.

Still interested in hearing more from others more knowledgeable than me.

Interesting—the advertised stall current of the NEO is 105A, so I am not sure how the NEO can be pulling nearly 80A at 30% output. Would like to hear from REV on this one as I am certain my understanding is lacking here.

Glad you found a solution!

Edit: I finally found the thread I was looking for, I wonder if the results of the testing described here (NEO equipped bot being pushed by a CIM equipped bot) are a result of this current limiting behavior.

We just published some locked-rotor testing data. Take a look at this post first: NEO Brushless post testing opinion?

NEO controlled by Spark, torque vs speed at constant 100% command, dynamometer bench test data…

Has anyone published such data?

Would like to see actual input amperages and further understand - does current limiting on the Neo affect input amperage?

Current limiting is for the motor current.

Because it’s a 3 phase brushless, the input current =/= output current, and similarly the input voltage =/= output voltage.

A brushless motor at 50% duty cycle pulling 40A will only be pulling 20A from the battery.

From a coding standpoint you can extrapolate the battery current based off of the duty cycle and the output current, however you can already make this measurement from the pdp.

You’re describing the empirical curves in the NEO Datasheet

This thread may be of interest:

My synthesis of the information that has been gathered and shared is as follows:

The NEO has an internal winding resistance of 36.5mOhm from which you can calculate a theoretical stall current of ~330A, but your motor is probably smoking at that point.

My understanding is that folks over at REV did a fair bit of testing and determined that the Spark MAX can safely operate the NEO motor up to around 100A given typical FRC power constraints. The published empirical motor curves reflect the maximum performance of the motor and speed controller that teams can expect under FRC conditions.

Dyno tests (the published theoretical motor curves) with a special no-current-limiting firmware and a robust power supply showed a stall current of 150A with the NEO + Spark MAX. @dyanoshak explained to me that there are a number of factors such as the resistance in the MOSFETs, circuit board and wiring that contribute to power loss at this extreme of an operating point, thus why the current curve intersects the y-axis around 150A rather than 330A.

This said, the Spark MAX controller is not designed to operate above 100A regularly. It appears the default smart current limiting is set to a linear limit from 80A at stall to 0A at free speed. So I guess you could coerce a little more out of the motor by tweaking the current limiting settings up to 100A irrespective of motor speed.

Thank you. I’ve seen that.

The blue (torque) and purple (current) lines on the “empirical” graph are straight as a ruler, so that does not appear to be actual bench test data (unless only 2 points were tested and then a straight line was assumed to connect them).

I was interested in how linear the actual performance is, given the current limiting.


It is likely a linear fit to the measured data. I too would love to see the dyno accel data if REV is okay publicizing it.

The performance of the NEO in practice is very dependent on how your smart current limit is set up. When you send a output of 1.0 at stall, with an 80A smart current limit the duty cycle actually applied to the motor is about 0.3.

Except, in a lot of cases I’m worried about the current the motor controller is pulling from the PDP and I want to limit that proactively. Measuring from the PDP is too late.

When I’m setting up current scheduling (or load scheduling) to make sure that I’m not over-drawing the battery to brownout, I need a way to tell a motor controller to never to attempt to pull above a certain amperage.

Are the sparkmax’s capable of that? I have to admit I’m asking because a lot of this is very confusing - motor current versus motor controller input etc.

This is all just one big p=iv problem.

The reason that motor current matters is that current is what kills brushless motors, not voltage. The current is what generates heat, which is independent of the “Watts” passing through the coils. That’s why the spark controls motor current (and arguably why ALL motor controllers should limit motor current.)

All motor controllers (except spikes) output a PWM modulated motor power. The output voltage is only ever 0V or 12V, it just modulates so that the average voltage can be variable.

Because of this, motor current is ALWAYS different from battery current unless you are running at 1.0 power.

Arguably, the ability to measure motor current is more valuable to us than the battery current. Lots of teams accidentally burn motors. The ability to limit motor current is a good safety measure to ensure you never damage them.

You don’t necessarily need to measure current from the PDP. You can just as easily extrapolate the battery current with this formula: battery current = motor power * motor current with the motor power being 0.0 to 1.0.

Keep in mind that all the “motor current” shenanigans brought upon us by REV is NOT a new thing. It also applies to your standard brushless motors like cims and 775s. REV has just done it this way because this is typically how brushless motors are typically operated, and how most motors have “safety” features applied in industry. Similarly, you can work backwards to find motor current. Motor current = battery current / motor duty cycle.

Again, I’m no expert on the spark max, but I’d hope that they have the ability to limit current from the pdp.

@dyanoshak if I’m correct this should be able to be fixed in firmware. Since the spark max had to have current shunts to measure current on the motor phase wires then you can easily extrapolate battery current based off of the motor duty cycle and the current. A firmware update could allow you to output this over the can bus, or to integrate user programmable limits, correct? I’m under the assumption that this is not already included based off my my initial skim of the datasheet and since users are asking if this is even possible.

The Spark MAX current limiting is motor side, and as far as I know there is no input side current limiting feature. However, we can do a little bit of math to figure out the maximum input current drawn with a given stall current.

We start with the relationships between stall motor current and duty cycle, and input current and motor current:
(1) I_motor = I_stall * (1 - duty_cycle)
(2) I_input = I_motor * duty_cycle

Substituting (1) into (2):
(3) I_input = I_stall * (duty_cycle - duty_cycle^2)

(3) is a quadratic function with zeros at duty_cycle = 0 and 1, so we know that maximum input current is at half duty cycle. Making the substitution duty_cycle = 0.5:

(4) I_stall_max = I_stall * (0.5 - 0.5^2) = I_stall/4

So the maximum input current will be a quarter of the stall current. This quadratic relationship also reveals something else interesting—when operating below at low duty cycle, very little current is actually drawn from the battery.

This isn’t a substitute for input side current limiting, but useful for teams looking to check the possibility of brownout.

Edit: I realize this math is not longer simple with a smart current limit because it controls current through duty cycle. See below post.

Here’s an updated version of the above math to properly account for current limiting. It’s a bit more involved, but the result is more accurate.

The current in the motor is limited by the smart current limit based on the speed of the motor:
(1) I_motor = I_limit * (1 - V_emf/V_batt)

The voltage applied to the motor to maintain that current can be found from the DC motor voltage balance equation:
(2) V_app = V_emf + I_motor * R

The input current is the motor current scaled by the duty cycle, also known as the proportion of battery voltage applied.
(3) I_input = V_app/V_batt * I_motor

(2) can be substituted into (3) to get:
(4) I_input = (V_emf + I_motor * R) / V_batt * I_motor = (V_emf * I_motor + I_motor^2 * R) / V_batt

(1) can be substituted into (4) to get:
(5) I_input = (V_emf * I_limit * (1 - V_emf/V_batt) + I_limit^2 * (1 - V_emf/V_batt)^2 * R) / V_batt

Which (skipping many steps for brevity) has a maximum of the following when the current limit is less than half of the motor stall current:
I_input_max = 1/4 * V_batt * I_limit / (V_batt - R*I_limit)

And a maximum of the following when the current limit is greater than half of the motor stall current (never for NEOs):
I_input_max = I_limit^2 * R / V_batt

Practically speaking this gives us the following theoretical data for the NEO:

Smart Current Limit (A) Maximum Input Current (A)
10 3
20 5
30 8
40 11
50 15
60 18
70 22
80 26
90 31
100 36

Note that this is also the case for brushed motors (this is not unique to brushless motors). We’re working on some documentation for the current limiting that will help clear some of this up.

Here are a few points to help understand (excerpts from our draft)

Input Current vs Output Current

The input current of the controller is the current that flows to the input terminal of the SPARK MAX, the average of this current is the value reported by the PDP. The voltage measurement provided in user logs is also the input voltage to the controller.

In order to drive a motor at different speeds, the motor controller must control the voltage to the motor outputs. To do this, the motor controller includes MOSFET devices (think - electronic switch) to turn on and off the battery voltage to the motor.

Fig. 1 shows a simplified view of a motor controller, using a brushed motor controllable in one direction. This model will assume a lot of ideal conditions, and the MOSFET device is shown as a simple switch, with the PWM_Frequency being how fast the switch is turned on and off. For example, the SPARK MAX switches at 20kHz.

In this case, when the switch is turned ‘on’ the motor voltage is connected to the battery (~12V), and when the switch is turned ‘off’ the motor is connected (through the diode) to ~0V. The effect is an average voltage on the motor can be controlled based on the duty cycle of the switch (how long the switch is on vs how long the switch is off). For example for a duty cycle of 50% (the code equivalent of motor.set(0.5)) the motor will see an average voltage of ~6V. This method of voltage control is called ‘voltage chopping’. But how does this relate to current?

To understand how the current flows in this diagram, we split it up into two states. The first when the switch is closed (12V connected directly to the battery).

In this case the full motor current flows through the battery, through the switch, and through the motor. During this time, the battery current is equal to the motor current, and the current in the motor will increase.

The next case is when the switch is opened (motor connected through diode to ~ground). Note that motor current cannot change instantaneously (detail not covered here). That means after the switch is open current continues to flow, and it must flow in the same direction.

In this case, the current still flows through the motor, since the current direction does not change. However no current flows through the battery since the switch is open. That means when the switch is off, the current through the battery and through the PDP is 0. During this time the current in the motor will decrease.

The figure below shows a simulated example comparing the motor current (blue) and motor voltage (red) vs time, of ~100 microseconds (very zoomed in example).

Therefore the current that the motor ’sees’ will be different than measured by the PDP. During the ‘on’ period the motor current and the input current are equal. However, during the ‘off’ period the current recirculates through the bridge and does not flow back to the PDP, so it is not the same as measuring the input current through the PDP.

This means that the average input current will be lower than the average phase current, unless the duty cycle is 100%. Below shows the motor current (blue) and input current as seen by the PDP (red).

Overlaying the two clearly shows that at 50% duty cycle, the average input current = half the average output current.

This idea also translates to brushless DC motors like the NEO. Here is the link to the simulation that this is based on (switch replaced with the actual MOSFET.)

Note that the default setting is actually 80A across RPM range. The linearlization feature can be enabled by the API by setting the ‘limitRPM’ to 0 using setSmartCurrentLimit(). The limit RPM is the RPM that starts to linearly lower the limit from the stall limit to the free limit. e.g. you could limit to 80A below 1000 RPM, then have it lower from 80A to 10A betwen 1000 RPM and free speed. Set the limit RPM to ‘0’ to have a linear response for the entire RPM range (nice for closed loop).

The existing implementation only allows limiting average output current, not average input current. I’ve added a feature request card on our Trello board for this, as I can definitely see the use case. The idea for limiting output current is to protect the motor and also give a predictable torque response at the limit. Limiting the output current can also be used to prevent breaker trips since input current <= output current. Limiting average input current can be used to prevent breaker trips, and also allow higher output current than a comparable output current limit, but the torque response will depend on the load.


Oh, that is good to know that limitRPM is where the linear response starts. I assumed the “smart” referred to linearization which in turn was enabled by default. Either way, cool feature to have available.

One question is if a certain duty cycle is commanded, is the current limit scaled accordingly? I.E. say there is a stall current limit of 80A and a command of 0.5 is sent to the controller, is the motor seeing the full 80A still or is it scaled down to 40A? This would then truly mimic the behavior of a non-limited motor in closed loop.

The only scaling done is to limit the current to the value at the particular RPM, so in the case of the 80A limit, the motor will still see the 80A. The duty cycle will be scaled down if the user is trying to command more, and how much it is scaled will depend on the load.

1 Like

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