Physical force resistance

I’m new to SimpleFOC, but I’ve got an ESP32 controlling a 2204 motor with an AS5048A SPI encoder through a SimpleFOCMini working. It does the usual torque, velocity and angle modes fine, but I think I’m looking to do something different as well.

I’d like to give the motor some “weight”. So it would resist being turned, but once turned it would stay there. I believe that means that it would apply a constant current at the angle that it is currently positioned at instead of at the usual 90 degree electrical offset.

My current thinking is that none of the control modes will work for me as they only apply voltage when necessary to move the motor. Instead, I’ll have to apply the voltage at the right electrical angle manually using (or changing) the setPhaseVoltage(float Uq, float Ud, float angle_el) function?

Does anyone know if this has been done before or have any suggestions on how to go about it?

If you have closed loop control working, you could try velocity mode with a target velocity of 0. Then adjust the voltage limit or current limit (depending on what you’re using) to vary the resistance. The velocity pid variables may also give you options to simulate things like viscous damping when you turn the motor

I can try that, but I don’t think it will have a nice constant drag but will instead depend on the change of speed after the motor has been moved a bit. Also, I am hoping to eliminate the cogging effect of when the motor is turned when no current is being applied to the windings.

There is a reference to this in Karl_Makes_Music’s post in regards to his version of the SmartKnob:

I’m not fully understanding what control you are after.
Are you looking to have rotor point at target (eg 0) and the further away from target you are (either CCW or CW) the greather resistance and then go back to initial positon?
Or do you intend just to introduce a viscose friction effect?

Viscous friction is a new term for me and it does sound like what I am after. But also I am hoping so that when I let go of the motor it stays exactly where I left it. Where now it seems it will sometimes do a little shaft angle shift when I let go depending on where I leave it in between the cogging of the motor. I figure if I have a little current keeping it at that angle, the little angle shift will disappear.

Though in the end, introducing some friction into the mechanics might get rid of that little shift and save on power.

You want to take inverse approach. Not current holding it in position, but current preventing going out of position. If you’re in position no torque/current is applied but if you go out of current position the reverse torque should be applied. Then maybe to avoid cogging you might want to say that if speed is less than X velocity do not update the target.

Alternatively maybe youd want to define 360 or 255 virtual points across the dial and have system that snaps to them. Then raise up Derivative gain and lower output ramp to virtually introduce some friction. but the distance between points should be quite low as P + D gain amplifies nosie from the sensor significantly.

The trouble is I am essentially just using the motor as an encoder knob in this mode. I want the full sensitivity of the encoder (one turn of the little 2204 motor equates to about 10-20 turns of a bigger motor driving a gantry, so those little shifts are noticeable when you let go.) Introducing virtual points will decrease the resolution of the encoder. Using all the other control modes depend on an error in the setpoint (which needs to be able to change). I want to proactively just keep it where it is, like a heavy sensitive control knob on an encoder.

Though the more I think about it, you are right about it being the inverse approach. And with the angle setpoint just floating around at the current angle, the cogging could still happen. Actual friction might still be the best bet for removing the cogging, with viscous friction for the heavy feel.

I’d still like to try inducing some current at the current shaft angle though to see what the motor feels like to turn. I take it you didn’t end up doing that in your smart knob?

Ok so why not to have fine clicks at 1 degree to control gantry.
So let say your gantry resolution is 0.01mm in Y axis, you could have very very fine clicky control.
Each click equals 0.01mm, but you could change the output ratio to move by 10x 100x 1000x fold.
Wouldn’t that be better approach?

This post is a great starter on this type of haptic interface: Haptic textures - #4 by Antun_Skuric

Forget what you are thinking about electrical angle, it is not relevant to the physical angle.


This graph might help you conceptualize how it can work. What you want to do is similar to this, except rather than the shallow slope (spring-like) like this, you want it to be very steep (kind of like a step function, but you still need a bit of hysteresis), so that even small angle error will produce a large, flat (e.g. viscose, friction like) torque response. You could write some code to handle that when the angle starts to recover position (e.g. the knob is let go) then you set that as the center /stable point. I think for your case you don’t need to consider any attractor angle since it’s all continuous in your use case.

As far as cogging goes, you are at the mercy of your motor. For buying low cogging motors, see the ones used in the smartknob project, these seem to be the best on market for now.

Ok, yes that helps. And I do like the idea that I could set the center point dynamically. So maybe monitor that the angle has past the hysteresis point and that the velocity is close enough to zero again to set a new center point. That way I can use the whole encoder address space and not have to divide it into even fine clicks. At slow speeds I will still get clicks, but should stick better where it is left.

1 Like

I think you could try the following:

  • use position mode
  • set a voltage limit (or current limit, if using current sensing) to a value where the resistance to turning the motor feels right
  • update the set-point as the user turns the motor:
    • new set-point = (old set-point + current position) / 2.0
    • e.g. update the set-point to the half-way point between the previous set-point and the current position