Understanding various currents and their usage in torque control

Hello there,

I finally received my new driver boards with current sensing hardware (it’s like fifth take :smiley:). While being super happy that the driver redesigned to use STM32 is finally working I found myself struggling with interpreting the “various currents” that I can get from the LowsideCurrentSense class instance.

Just to provide some info about the hardware:

  • DRV8302 based driver
  • 2x 10mΩ shunt resistors in lowside current sense configuration
  • op-amps used are built into the DRV chip
  • sensing only phases A and B
  • STM32F103CB MCU
  • AS5048A magnetic encoder connected over SPI

I’ll try to divide the question into multiple sections to make it more readable:
(all the measurements provided were done in torque-voltage mode)

Part one: PSU current draw vs. getDCCurrent()
So these two are apparently not the same thing at all :smiley: . When I measure the current going from my PSU to the driver board I get 80mA at 20V. This result is completely different from the one I get from calling getDCCurrent():


This is something that resembles a sine wave (with a lot of imagination :smiley: ) with average value of about 2A. With the motor.voltage.q equal to 0.6V (the target of torque-voltage mode) the power output is more or less matching here (0.08A*20V=1.6W and 2A*0.6V=1.2W). Also the measurement from the PSU includes consumption of the MCU, CAN transciever etc.. so the difference is reasonable. This part comes down to: Am I right here? And what does the graph really mean? Is it a sum of all the phase currents?

Part two: Phase currents with/without load
During further testing I stumbled upon a major difference between phase currents graph when the motor is and isn’t loaded.
Unloaded:


Loaded:

Is the first one just a property of the current sensing hardware? Is this difference normal?

Part three: Correct understanding of Id and Iq currents
If I get this one right the Id and Iq are obtained by measuring the phase currents and applying Park+Clark transformation (the Park guy also needs the rotor position). So essentially they’re just a representation of the “currently measured phase currents” in DQ coordinate space. Id and Iq are both numbers which when put together make up a vector that points in a direction of the magnetic field induced by the stator. And the goal is to move this vector so that it is always 90° ahead of rotor’s magnetic field vector thus creating maximum torque :smiley: .

If I stop the rotor by hand (thus fixing the rotor’s magnetic field direction) I also fix the Id and Iq values since they have to be 90° from the fixed vector, right?
I feel like this screenshot supports it:


To make this part into a question again: Am I thinking about this correctly?

Part four: What am I getting with more advanced torque controllers
As of now, I am using TorqueControlType::voltage controller. The set-point here is voltage and my understanding is, that it is trying to mimic the behavior of regular DC motor. More voltage → more torque (but more RPM as well). And I cannot get rid of the dependency between RPM and torque, right?

If I move further to TorqueControlType::dc_current I get a behavior of a DC motor powered from constant current source, yes? But my physics intuition fails here. I would say that the motor will keep accelerating until the voltage generated by the motor (Back-EMF) is equal to the voltage created by the driver to sustain the constant current flow maybeeee?? Also the set-point with this mode is current Id and I’m really getting lost. How can I just set this? It will just mess up the vector of stator’s magnetic field and cause it not to be 90° ahead of the rotor’s one. I know I have to be extremely wrong here, but I can’t really figure it out based on reading documentation and watching youtube videos anymore :smiley:

The ultimate goal is to separate torque and speed from what I understand. So I can spin the motor with constant speed but alter it’s torque which should be what TorqueControlType::foc_current is doing, right?

I know that this isn’t a standard format for forum question, but I hope someone will find time to go through it and clarify some of it.

Thanks,

Adam

I think you’ve got it. getDCCurrent is the magnitude of the ab current vector (which is equal to the magnitude of the dq vector), and theoretically should give a straight line if the load on the motor isn’t varying. But since your phase currents are all squirrely when unloaded, the DC is too. It should flatten out when the motor is loaded, like your Id and Iq when stopping the rotor by hand. Although it is odd that you’re getting Id = -8… I thought it should be near-zero.

It’s confusing because TorqueControlType::voltage can either be voltage control or estimated current control depending on whether you specify the resistance and kv parameters which are required for the estimated current calculation.

But if we’re only speaking of TorqueControlType::dc_current and foc_current, then MotionControlType::torque does give the behavior you describe. motor.voltage_limit determines the top speed where it reaches equilibrium with back EMF and can’t produce torque anymore.

The setpoint is Iq, not Id. You’re setting the target current in dq space, which is 90 degrees ahead of the rotor. foc_current automatically compensates for current lag at high speed by applying some d voltage to regulate Id toward 0, whereas dc_current normally just sets d voltage 0 and allows Id to vary with speed. Though it can estimate the required d voltage if you give it the motor inductance.

I’m not entirely sure what TorqueControlType::dc_current is meant for. It seems like it should be usable even if you only have a single current sensor between all the lowside mosfets and ground, but the code for it requires at least two phase currents to calculate the DC current. Maybe just hasn’t been implemented yet? Or maybe it’s just meant to reduce CPU usage compared to foc_current.

Thank you for the detailed answer @dekutree64 ! Today I tried to tune the gains for the foc_current mode and sort of “succeeded”. I mean both currents (Iq and Id) follow the desired values just fine (Iq follows motor.target and Id is around 0).

Now I would just like to check with you whether the behavior in real life is right. It sort of resembles what we talked about. When I set the target to 1A (corresponds to the picture) the motor does indeed accelerate to a speed determined by motor.voltage_limit (or maybe motor.PID_current_q.limit, I’m not sure… I’ve set them to be equal :smiley: ). Now the thing is, that this speed is already veryyy high and the torque is what I would call funny (almost none).

But at the same time the current Iq at 1A is pretty low (compared to the voltage mode where it was somewhere around 4A). The obvious step is to go higher with the target, but the motor will skyrocket if I do that.

What if I want high torque with low speed? Or is this only possible in MotionControlType::velocity mode with torque controller set to foc_current? But I sort of feel like that would only allow me to control the speed and not the torque again

I’m glad you noticed that :slight_smile: I always forget the PID limit has to be updated when you change voltage limit.

Set target = motor.current_limit or whatever torque you want, and use motor.voltage_limit to control the speed. It’s a good control mode that I use on my milling machine spindle, but it would be nice if it were more properly supported. You have to ramp changes to the voltage limit because decreasing it too quickly will make a back EMF spike and try to kill the power supply. I just copy-pasted the ramping code from PIDController, but I think we should pull it out into its own little class. Although it would create yet another duplication of the dt calculation (incorrectly called Ts throughout the code…). There’s a github issue for removing the duplication, but it’s complicated by the motion downsampling option which results in different delta for loopFOC() and move().

Man, this works great, thank you!!

So now I can control the torque independently of the speed, but only to a certain, still very low amount of torque.

Even thought my motor.current_limit is 7A and motor.target is also 7A the Iq current saturates somewhere around 5A (when I hold the rotor in place). Themotor.voltage_limit (+ all PID limits) are now set to 0.3V.

I can get more torque unless I increase the voltage_limit, which also increases the speed. Does this mean, that the motor is unable to reach higher torque with this voltage_limit due to it’s construction?

It is a 40 pole (20PP) pancake BLDC motor with phase resistance (phase to phase) of 0.15Ω. It should be quite viable for low speed high torque applications (or am I mistaken?).

Yeah, it sounds like you’ll need to add a little more logic to get the behavior you want. Maybe a constant high voltage limit, but stop applying torque above your desired top speed. Probably with a ramp-out to avoid jerky behavior. So above some threshold speed, decrease the target current in proportion to speed, down to 0 current if >= max speed. And below threshold speed, apply full current.

Either that or decrease voltage limit as you approach top speed. Or just use velocity control.