Different encoders for commutation and position loop

In some cases it could be usefull to have different encoders for commutation, velocity and position control.

I want to test if it is possible to do a closed loop filament control at a 3D printer with bowden extruder.
Therefore I want to use an additional encoder at the Hotend with measures the filament feed.
The motor encoder is used for commutation and velocity loop.
The filament encoder ist used for position loop.

This configuration is often used in professional servo drives for high precision applications.
For example with an additional direct position scale on a linear axis.
If there is a position deviation caused by process forces or thermal expansions the position loop automatically compensates it.
The velocity loop uses the motor encoder or the linear scale or a combination of both.

For the target position a step/dir Interface would also be interesting. Perhaps this could be implemented as another encoder type.

Hey @Uli,

This is something we have been considering for some time now. And I’ll try to implement it for the next release.
I’ll let you know when it’s in dev branch.

I was thinking to extend linkSensor function to receive optionally second sensor.
And if it does it will demand the velocity and position from this sensor.
We will need one more sensor instance in BLDCMotor and one more getAngle function Wich will be used just for foc.

You can already kind of do this with a normal pid controller on an arduino(or other mcu). Just hook your position encoder to the mcu. Set it as the pid feedback, the output will be the velocity change that commands the simplefoc library. Which then commutates the motor etc.

There may be some limits, depending on hardware used.


The BLDCMotor class does exactly that itself but it is hidden from user.

The class does the motor commutation but not the outer position loop. For that you need an additional pid loop to close it it you have a direct feedback from the encoder.

Imo this isn’t something that simplefoc needs to implement anyway since everything required is already available for the arduino platform. There are various encoder libraries and pid libraries to implement this. It’s kind of a niche case since the position loop is typically closed in the motion controller and not motor driver.

Hey @Roiki,

You are absolutely right. Simplefoc main goal is not really the motion control but the FOC.

But almost 100% of the applications will have some kind of motion control in it and therefore we will support the most standard ones, and the advanced ones that are relatively easy to implement. And multi position sensor is one of them. It requires a minimal change and will introduce an interesting advantage for some users.

There are few applications where this is interesting. Some of them are in the domain of robotics. But one would be also for very smooth rotation of camera gimbals to couple IMU and encoder for example. We currently do not support IMU as position sensor but we intend to, at least as velocity sensor.

So there are some convenient features when using the BLDCMotor class for motion control as velocity and voltage limits and similar. But of course you can implement these yourself and probably even better then we do in our very general implementation.

The one thing I wanted to add is just that the simplefoc library already provides the pid and low pas filter class so build your own control loops without external libraries. Make sure to use your BLDCMotor in voltage mode and define your PID controller and LPF of you need one:

PIDController pid{.P=0.01,.I=0.05,.D=0,.ramp=10000,.limit = 10};
LowPassFilter lpf{.Tf=0.02};

And in the Arduino loop just do something like:

void loop(){
 // calculate the voltage value to be set to the motor
 // this line can be downsampled (called less frequently) if needed
 motor.voltage_q = pid(target_velocity - lpf(other_sensor.getVelocity()));
 // place voltage to the motor phases

You could of course use the functions already implemented in the library to make it easy to implement the outer position loop. If it’s not too much effort.

Also you shouldn’tneed to work with voltage, or did I misunderstand?. The outer loop takes position command and outputs a velocity, which is then input into the inner loop which produces the torque(or voltage in this case). The motor should be in the controltype::velocity mode and you shouldn’t need to touch the torque loop.

You could do this yes.

But usually if you need the external position controller you do not trust not only the position of the first sensor (the one you use for foc) but the velocity it outputs as well.
In my opinion if you add the external sensor you will use it for bot velocity and position control and use the first one for FOC and torque control (current).

Yes you do. That’s how industrial machine control systems work. I’ve done a few.

The motion controller of the machine does the position loop wirh it’s own encoder(like a linear scale) and issues the velocity command to the servo drive which drives the motor with the velocity and torque loops. There’s no need not to trust them. You can do torque calculations yourself but there’s no real need to.

Old machines used to use analog voltage for commanding torque for analog servo amps.

Ok, thank you for the explainations.
I think I can solve my application very simple.
When I use a stepper motor I can try it without FOC.
So I only need one encoder for the filament and a PID loop which calculates the velocity target value.
In combination with a TMC2209 I don’t need to generate steps because it has an internal step generator which can be configured via UART.

I am using these motors which contain both incremental and hall sensors, and an external microswitch as index channel. The hall sensors connect to the driver board for commutation, but the others connect to a higher level path planning controller.
It should be possible to do the same thing all in the motor controller as you suggest, but there are important caveats in your scenario.

The hot end of the bowden tube is only weakly coupled to motor commutation because of backlash, bowden stretch, filament compression, thermal expansion, filament moisture swelling, buckling of filament within tube, mechanical failure, filament empty, filament slippage, manually pushing stuck filament, programmed filament pullback, filament creep, varying filament pressure related to squish factor(width). So you are going to want to adjust the relationship between commutation and position setpoints based on the state of the machine. For that, it makes sense for your printer controller to do the outer(filament position) loop and the driver do the inner(commutation) loop.
The outer loop can notice when filament does not move as it has commanded detecting various problems. That will be handy information if used to improve print quality. However, the outer loop would work better if it also got the commutation signal so it had a more accurate velocity to compare.

Perhaps the driver could generate a quadrature output from the hall input. That would be easier for the print controller to compare to filament encoder.

I don’t want to change the 3D printer controller.
It only delivers the target position for the filament with step an direction signals.

At the moment I use a stepper motor without FOC control, so I don’t have to care about commutation.
I have only a position loop which delivers the target velocity for the stepper motor.

I calculate the deviation between measured position and target position of filament.
In the first test I used only the proportional part.
So I get a target velocity for correction which is proportional to the position deviation.
I think it can be optimised but I was surprised how good this simple controller works.

Up to now I didn’t test it in the printer.
I have a delta printer with a direct extruder.
When I change it to a bowden extruder I can’t print flexible filament any more.
The bowden extruder would be interesting to reduce moving mass.