The double Gordian knot of current_sense

Hi guys,
for the last two days I tried to make inline_current_sense work on a MKS Dual FOC PLUS.

I tried to follow the docs-guide, how and when to initialize the partaking modules. I missed a word about motor.linkDriver and also motor.linkSensor in the doc.
I was also looking for examples using any kind of currentSense and found the B_G-431B-ESC1 example.
Guess what? I doesn’t use the strict order of .links and .inits.
motor.linkCurrentSense(&currentSense); doesn’t comes after motor.init, although that is said to be “very important”
That was the first gordian knot to solve.
I always reached success 2, maybe because I only have two shunts?
Anyway, I switched pin-orders back and forth to figure out the right definition. But even when I skipped current_sense.align and got success 1, it never seem to use any current limit I set.
The docs don’t even mention anything about current_limit in that respect.

The second Gordian knot was the alignment itself.
On one side, we are looking for low_cogging motors, so the position sensor-aligning works.
But after that we want to align the current sensor and the algorithm tries to provoke a current spike on each phase, which doesn’t work well with a free running/low cogging motor.
I even tried to block the motor to increase current-spikes, but never had the feeling the FOCloop runs current-controlled.

;TLDR I wish there was a working example with all sensors and actuators with .links / .inits / .limits in the right order. :pray:

Success 2 means the phase currents are swapped ?
I think Torque control is not reflecting what you see on your power supply.
So what do you call a current limit ?

Are they swapped, or does success 2 only reflect that the third shunt is missing or the current spikes were too low? (the PLUS version has high current capability for the little gimbal motor I use for testing)
I’m pretty sure I have the two pins for the shunts right. I even beeped them to confirm that.

I’ve set the torque_controller to foc_current and dc_current. So I expected to see some difference when I set a low target or high target.

With foc_current you should feel the torque is increasing if you block the motor with your hand

The default current limit is 2A and it seems I always reach this limit with the small gimbal motor, getting very hot over time.
I tried to reduce current_limit and also current_sd (whatever that is). But it never showed any effect.
That’s why I think, the whole current align process failed and the torque is always maxing out.
target = T0.1 => motor running full speed
target = T2.0 => same behavior

Current_limit is only used for voltage mode with current estimation

Current align is just making sure you have the phase current pin of current sense driver is matching with the phase pin of the 6PWM driver, and that the gain has the right sign.

With no load your motor will run at full speed with little torque input.
You should feel a difference if you apply load with your hand.

1 Like

Yes! I finally figured it out when I read here about phase resistance and kV.

That was the missing puzzle piece for me.
I don’t need current sensing, if I want current controlled torque.
It’s just, that the target value is so much lower now, that it was already full_on with T0.1

But reducing the motor.current_limit with the commander still doesn’t reduce the target :thinking:

I was bitten by that too. PID_velocity.limit is what you want to change. current_limit is only used during BLDCMotor::init to set the PID limit. It should probably be removed entirely, or at least changed to a reference.

1 Like

That’s really funny! :rofl:
To get current based torque control, I have to use motor.controller in voltage mode and limit the current, by reducing the velocity.limit

I’m glad I figured it out with all your help.

Double checking the code, PID_velocity.limit is only used in velocity and angle mode. There is no current limit in torque control mode. is in Amps so it’s your own fault if you tell it to use more current than you want :slight_smile:

As with the other modes, you do still need to call motor.move to update the target.

Thanks for the update.
I think, I have to wrap motor.move in a function which cuts the target to a newly set max.current then. Could also be useful for a temp-controlled current limit…

Next step is to connect it to a step/dir listener. I checked the source and it seems, a simple dir-change doesn’t send an interrupt. I have to digest the step-count to figure out the torque direction

Ok, i have a partial success.
I can control the motor with inlineCurrentSense and dc_current.
When I use motor.move(target), I can spin the motor in both directions.
But it never stops!
I’ve read the docs about that and I have to reduce kV.
The story about kV so far:

  • The motor-spec says 2208-80 ( might be 80 turns or kV80? )
  • The “1Volt kV test” says 160kV. That’s what I put in the BLDC constructor
    BLDCMotor motor = BLDCMotor ( 7, 17, 160, NOT_SET);
  • But Serial.println(motor.KV_rating); shows something like kV226 ?! :thinking:

I tried to set lower kV values, but the motor spins. When I stop it by hand, it starts spinning again.

Here are my PID settings:

  // foc current control parameters (ESP32)
  motor.PID_current_q.P = 3;
  motor.PID_current_q.I= 300;
  motor.PID_current_q.output_ramp = 1e6;
  motor.PID_current_q.limit = 6;
  motor.LPF_current_q.Tf = 0.005; 

What else can I try?
THX for reading

Almost forgot.
When I use motor.move( motor.PID_current_q.limit)
It also spins nicely, but only in one direction. I can’t set neg. values here.
But of course I can set it to zero and the motor stops…weird

Keep lowering the kv until it acts right. Although you shouldn’t have to fiddle with the voltage-based current control anyway if you have hardware current sense. foc_current should be best.

The 226kv is because someone changed the BLDCMotor constructor to multiply the specified value by sqrt2. Previously we usually had to use higher than nominal kv to get it to act right, but now the variable name is confusing. From a logical standpoint, the sqrt2 multiply should be done during the BEMF calculation so KV_rating remains in proper units, but from a performance standpoint it’s better to do it once at initialization. We could rename the variable to bemf_constant or something, but that’s not much less confusing…

I played with the KV_rating, down to “2” and nothing changed.

So I wrote a little code to detect target = 0 but shaft.velocity > 0
It works in “slow-motion” and also has the ability to adjust max. current on the fly.
It still needs a way to do slow direction changes from pos. target to neg. target (and vice versa) without the need to set target =0.
When that’s done, I feel confident enough to try it on a hoverboard motor :crossed_fingers:

void loop() {

  if (accel2target == 0.0f && sq(motor.shaft_velocity) > 0.5f){
    motor.PID_current_q.limit = motor.PID_current_q.limit /1.005f;  //  gradually reduce current
  else if (motor.PID_current_q.limit < max_current){
    motor.PID_current_q.limit += 0.005f ;  //  back to normal, waiting for new target
  else if (motor.PID_current_q.limit > max_current){
    motor.PID_current_q.limit -= 0.005f ;  //  back to normal, waiting for new target

  // user communication SerialComm instead of Commander
  if(Serial.available() > 0){

Are you sure the LPF is not good enough for all that ? :sweat_smile:

If I had a working system, I would try the LPF or the PID_current_q.output_ramp.
But the motor won’t stop spinning, no matter how low I set the kV_rating.
So I was forced to find a workaround. And because I wrote it myself, I know exactly what to do to change the behavior.

Just looking at your BLDC constructor again, is the resistance of your motor really 17 Ohms? That seems awfully high, and could be causing over-estimation of the necessary voltage voltage.q = target*phase_resistance + voltage_bemf;

And to follow up on my previous post, it turns out moving the sqrt2 multiply into the BEMF calculation won’t cost any CPU cycles at all because it already is dividing by a constant, so they can be combined at compile time voltage_bemf = shaft_velocity/KV_rating/_RPM_TO_RADS;
I wonder why it was done the confusing way in the first place.

1 Like

It should be something like 0.17

I’ve measured from pin to pin and it says 17R. It’s a small gimbal motor.
I wasn’t sure if I had to do some calculations to get the “real” coil reistance?
But I read somewhere, that sFOC expects the motorcoils are connected in “wye” and do the math internally.

Just to confirm my multimeter is OK: The phase resistance of a hoverboard motor is about 0.3R?