dls-controls / pmac

Driver for the Delta Tau PMAC motion controller family.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

EPICS way for "Closed Loop"

georgekontogiorgos opened this issue · comments

Hi!

I would like to know if it is possible to do "closed loop" by iterations as EPICS usually do, on its level or I have to write a custom plc script to perform that movement?

Thanks!
George

Hi George,

if I understand your question correctly then you simply need to configure the axis on the ppmac to be open loop and configure the motor record to close the loop for you .

If I recall correctly this requires setting the .RTRY retry field to non zero and make sure the .RDBD Retry Deadband is a sensible value.

Hi Giles!

Yes, you are correct on my question.

How could I configure an encoder using this method? I pass it as "virtual motor" to the IOC? Is this approach common at Diamond and native on IOC?

Thanks
George

Hi George,

I had forgotten about this since I have not done it for a very long time and it was for turbo pmac. You need to configure the encoder on a separate axis on the ppmac and then tell the driver in the startup script as follows:

#Setup closed loop control for Delta and Gamma (card, axis, encoder_axis)
pmacSetOpenLoopEncoderAxis(0, 14, 15)
pmacSetOpenLoopEncoderAxis(0, 17, 16)

in the above example motor 14 is using the encoder on channel 15 and motor 17 is using the encoder on channel 16.

This is untested on Power Pmac but I would expect it to work.

Thank you Giles for the explanation. I am worried about kinematics and how to deal with on this "closed loop" mode. It seems I have to do a lot of non native adaptations to get this behaviour.

In this case, maybe using a robust control instead of a high performance PID gains suits well for my application.

Here I would like to ask you, how Diamond Light Source engineers deal with systems which have a very big backlash on their mechanisms?

Hi George, in situations with high backlash I have usually used the motor record's own backlash compensation mechanism (which arranges to always drive to every point from the same direction by at least the backlash distance)

Hi Giles, maybe we are talking about different problems. Imagine one system where one motor drives a mechanical transmission with backlash and them it moves the load, which has an encoder. The transmission act as a non-linear element on our system thus the encoder reading is not linear relative to motor movement. Do you have similar systems ther on Diamond?

The backlash compensation is useful on cases that our encoder can read the same movement as motor (e.g. the encoder is installed on axis). Therefore there is a non-linearity about the real position and the desired position, so we could use the backlash compensation mechanism.

Hi George, yes we are talking about a different problem. I'll ask our motion team if they have dealt with this situation before.

Hi George, I got the following answer from the motion team. It just suggests modifying the PID parameters to cope with the slack :-)
We would use a small amount of Kp and a rather larger amount of Vff velocity feedforward, de-tune it until it behaves. The integral action at the end of the move would take the slack away. Or if it was me, I would buy better mechanics.

Hello Giles and George.
Me and a colleague are implementing this approach on a deltatau to control a slit device, on Sirius synchrotron facility, with help from George. We have succesfully setup a virtual channel for hte encoder and run the epics code using
pmacSetOpenLoopEncoderAxis
However, when we activate this line on the startup code, the motor becomes unresponsive: it moves upwards, no matter what direction we command for the movement, and doesn't stop until it reaches the limit switch.
What could justify this behaviour? We have set RTRY to 5 and RDBD to 1mm
Do we need to configure anything else? Do we need to configure motor 11 on the EPICS code? Also, do we need to configure RRES, ERES and SREV?

Also, do we need to set CNEN to 1?

CNEN R/W Enable control RECCHOICE (0:"Disable", 1:"Enable")  Enable/Disable closed-loop position control.  This field is active only if the GAIN_SUPPORT bit in the MSTA is true.  This field is set by both the user and device support.  CNEN is set to Disable by device support when it detects a motion controller error; e.g. maximum following error exceeded.

Thank you for your attention

@gjmontagner the EPICS driver does not know the difference between open and closed loop since the ppmac controller settings are managing this - it always looks closed loop.

At Diamond I think we always have CNEN enabled and I believe that this just implies that the motor record will also have a go at closing the loop if RTRY and RDBD are set and RDBD is not achieved within RTRY.

The only RES setting required is MRES in steps/EGU (where steps are motor steps in an open loop motor and encoder steps in a closed loop).

To diagnose the issue: are you able to run with just the encoded channel set up in the standard fashion? If not then it is simply that your encoder settings are incorrect. I don't have any knowledge of that level of configuration but can speak to our motion team for additional help.

Hi Giles, good morning.
It turned out our encoder axis position was set to 250mm, while the sensible range for motion would be -6.5 to 6.5 mm approximately. That's why the motor was always moving up when we commanded it to something near 250mm.
After using a offset and a scale factor, this is resolved. The issue now is the motor is not closing the loop.

I have set CNEN=1, but apparently the loop isn't closed.
I say this because we did a test: When we command a movement and hold the motor axis using our hands and forcing it to "lose counts", the motor doesnt't reach its desired position, as informed by the associated encoder, even though we let the axis go after a short time. We cannot see the motor retrying the movement, as can be confirmed by the number of counts commanded to the motor: it is always the exact theoretical ammount of counts for that movement. e.g. if we command a positive movement ov 1mm, we can see the motor is commanded a positive quantity of 102400 counts, and nothing more, even if the motor hasn't reached its position with the first movement attempt, because we forced it to hold position for a period of time.
Is there any other configuration we need to make in order to close the loop? Is it possible the IOC is closing the loop using our motor open loop position (channel 1) and not the configured open loop encoder (channel 11)?

Thank you for your attention

By " are you able to run with just the encoded channel set up in the standard fashion?" you mean using the motor with its encoder on the same axis and configuring it to close the loop on the controller, using epics on the usual way without pmacSetOpenLoopEncoder, right?

Also, the RCNT is increasing up to the value on RTRY field. I know because I saw it on epics with dbgf
Then the indicator on EPICS shows the motor is not moving anymore.
However the field DIFF still contains the right difference between commanded and actual position, thus the motor should be attempting to move more torwards its goal!
But it's not moving

Hello Giles and George, good morning.
I'd like to give you an update of our attempts to make this approach work.

Our .cmd is configured as follows:

#****************************************************************************************

CONFIGURE MODEL 3 CONTROLLER DRIVER

pmacCreateController("$(PPMAC_PORT)", "$(PPMAC_SSH_PORT)", 0 , 16, 100, 1000)

#****************************************************************************************

CREATE THE MODEL 3 MOTION AXIS DRIVERS

pmacCreateAxes("$(PPMAC_PORT)", 8)
pmacCreateAxis("$(PPMAC_PORT)", 11)

#****************************************************************************************

CREATE VIRTUAL ENCODER AXES

pmacSetOpenLoopEncoderAxis("$(PPMAC_PORT)", 1, 11)

And this is a snippet of our substitutions file:

pattern { P , M , PORT , ADDR , DESC , MRES , VELO , PREC, EGU , TWV, DTYP , DIR, VBAS, VMAX , ACCL
{ "CNB:E:PB01", ":m1", "Brick", "1" , "MBS1 - Top" , "9.765625e-6" , "0.5" , "10" , "mm", "1" , "asynMotor", "0" , "0" , "0.5" , "0.1"
image

...
SREV, RRES , ERES , JAR, UEIP, URIP, RDBL, RTRY , DLY, OFF, RDBD, FOFF, ADEL, NTM,
"1" , "" , "" , "" , "0" , "0" , "" , "100" , "0" , "0" , "0.3" , "0" , "0" , "1" ,
image

You can see we have set up RTRY as 100 and RDBD as 0.3mm Also, MRES is at 1/102400
Our configuration on the motor controller is:
M1 is the actual motor that we want to move. It is in open loop.
M11 is the axis we created and associated with the EncTable for the encoder 1 (resolution is 20000 counts per mm). That is, motor 11 position reflects the position of the encoder connected to motor 1. We also have setup a home offset for this axis, so the position is on a sensible range.

What happens when we test this configurartion is:
Initially, the motor commanded position in EPICS and the read value for position are the same, as shown in mm on the GUI.
image

Suppose the motor is at 2.5mm, and also the read position value is at 2.5mm
If we put the value 3mm in the commanded position field, Supposedly the motor should try to move 0.5mm/102400 counts upwards, and then compare the encoder position with the 3mm target and try to move again, if necessary.
That is not what we observed.
What happens is the controller sets 3mm*102400 = 307200 to its desired position and move to this target in open loop, regardless of the encoder position. That is, for example, if for some reason M1 position was at 0 counts before the movement starts, the motor would move 307200 counts upwards = 3mm, instead of 0.5mm!

It seems the controller is implementing an absolute movement, instead of relative (It should be based on the DIFF field, which does contain the correct movement quantity to be commanded). We observed that the DIFF field is being used by EPICS, since the fact that DIFF is different from zero results in new movement attempts, after the first movement. We know this because the RCNT field is increasing. However these attempts result in no movement, that is, zero additional counts issued to M1

What could justify this behaviour? Are we implementing this approach correctly? Apparently EPICS uses the open loop encoder position to display a value on our GUI, and also to calculate DIFF. However, when calculating how many counts to issue to the motor controller, EPICS considers M1 position as an absolute value, as if it was being read from an encoder), and disregards the real encoder position, on motor 11. That is: If M1 position is already at 102400 counts, and the commanded position is 1mm, even though the encoder at M11 reads 0.8mm, for example, the controller doesn't command any new movement (since 102400 is already equivalent to 1mm)

Thank you for your attention

Hi Giles and George.
An update:
It worked!
I needed to use RDBL and URIP=1, and set the readback resolution in RRES, besides defining axis 11 in the substitutions file.
Now I have just one issue to address:
When I command the position, the motor goes to its target, using a few retries.
However, after it's already in position, if I move the axis manually out of its position, the motor doesn't try to correct itself. Shouldn't it do it? Is it possible to implement it in EPICS?

Thanks again

Hi @gjmontagner sorry for the late reply.

That is good news.

I think you have found a different way to fix what I forgot I needed to tell you: you should set UEIP to 1 (use encoder if present) and ERES.

Regarding holding position on the encoder, I'm not sure how to do that. I think the motor record retry logic only activates as the motor completes a move.

One other thing to look out for is that the soft limits are provided to the controller in counts and consequently, manual moves like you mention will cause the counts and encoder to get out of sync such that you will hit soft limits late or early. To re-sync you can toggle the value of UEIP.

I am closing this issue since our proof of concept was successful.