Dual PID loops with motor encoder + scale encoder per axis

More
2 years 6 months ago #297865 by TangentAudio
Greetings,
I'm working on a new conversion project, modernizing an old Bridgeport Series 1 2HP that has a working Prototrak Plus system on it.  For "phase 1" of the project I am keeping the original Trak servo motors/drives/encoders and the Trak "wheel" style encoders for table position.  The machine has ballscrews, though they are a bit worn and have some backlash.  I know this isn't ideal and may present some problems, but I hope to tackle that later.  My goal is to get it up and running for close to zero cost initially, then figure out what I want to improve later.

My past conversions have all been open-loop stepper systems, and while I'm quite comfortable with LinuxCNC down to the programming level, closed loop config and tuning with LinuxCNC is new to me.  I've been focused on getting one axis working first.  I was able to at least get a basic tune on a single loop using just the motor encoder.  But I'd like to take the next step and use the axis position encoders in a dual loop setup to improve positional accuracy.

I'm using a Mesa 7i43 parallel port FPGA card that I had left over from my first CNC conversion 12+ years ago.  I designed and hand-wired a board to handle the differential signal conversion to/from the servo drives and encoders.  I've got that all working just fine on the bench - all of the encoders and servo outputs work through Hostmot2 and HAL as expected.

 

Attachment not found



I did a bunch of searching on the forum but there seems to be fairly sparse info on this topic.  I followed the guide that's on the wiki , but it's also a bit light on details.  I've got a rough config put together based on the steps in that guide, but I know it still has some problems and I could use a more experienced set of eyes.  My controls engineering class was almost 30 years ago at this point (!), and while I do have some basic experience and understanding of PID control, I'm getting a little ahead of my skis on this dual loop implementation.

Happy to share full configs, but I figured I'd start with just the X axis snippets.  My guess is my config problems are in the feedback part near the bottom of the HAL config, that's where the wiki guide seemed most vague.

Thanks!

Here's the INI:
Code:
#****************************************** [AXIS_X] MAX_VELOCITY = 2.0 MAX_ACCELERATION = 10.0 MIN_LIMIT = -12.0 MAX_LIMIT = 12.0 [JOINT_0] TYPE = LINEAR HOME = 0.0 FERROR = 0.025 MIN_FERROR = 0.008 MAX_VELOCITY = 2.0 MAX_ACCELERATION = 10.0 P = 650 I = 0 D = 25 FF0 = 0 FF1 = 0.1 FF2 = 0.01 BIAS = 0 DEADBAND = 2e-06 MAX_OUTPUT = 10 ENCODER_MOTOR_SCALE = 27940 ENCODER_LINEAR_SCALE = 5080 OUTPUT_SCALE = 10 MIN_LIMIT = -12.0 MAX_LIMIT = 12.0 HOME_OFFSET = 0.0 HOME_SEQUENCE = 2 #******************************************

and the HAL:
Code:
#******************* #  AXIS X JOINT 0 #******************* # PWM Generator # The ProtoTrak Plus servo drives use offset mode PWM, 50% duty = off, 0% duty = -100%, 100% duty = +100% # HostMot2 PWM generator supports this natively by setting offset-mode to true setp   [HMOT](CARD0).pwmgen.00.output-type 1 setp   [HMOT](CARD0).pwmgen.00.offset-mode true setp   [HMOT](CARD0).pwmgen.00.scale  [JOINT_0]OUTPUT_SCALE # Velocity Loop (P, D, FF1) setp   pid.vx.Pgain     [JOINT_0]P setp   pid.vx.Igain      0 setp   pid.vx.Dgain     [JOINT_0]D setp   pid.vx.bias      [JOINT_0]BIAS setp   pid.vx.FF0       [JOINT_0]FF0 setp   pid.vx.FF1       [JOINT_0]FF1 setp   pid.vx.FF2       [JOINT_0]FF2 setp   pid.vx.deadband  [JOINT_0]DEADBAND setp   pid.vx.maxoutput [JOINT_0]MAX_OUTPUT setp   pid.vx.error-previous-target true # Position Loop (I only) setp   pid.px.Pgain     0 setp   pid.px.Igain     [JOINT_0]I setp   pid.px.Dgain     0 setp   pid.px.bias      0 setp   pid.px.FF0       0 setp   pid.px.FF1       0 setp   pid.px.FF2       0 setp   pid.px.deadband  [JOINT_0]DEADBAND setp   pid.px.maxoutput [JOINT_0]MAX_OUTPUT setp   pid.px.error-previous-target true # Sum output of the two PID loops together to produce the PWM output signal net x-output-motor pid.vx.output <= sum2.x.in0 net x-output-linear pid.px.output <= sum2.x.in1 net x-output <= sum2.x.out => [HMOT](CARD0).pwmgen.00.value # Motor encoder setp    [HMOT](CARD0).encoder.00.counter-mode 0 setp    [HMOT](CARD0).encoder.00.filter 1 setp    [HMOT](CARD0).encoder.00.index-invert 0 setp    [HMOT](CARD0).encoder.00.index-mask 0 setp    [HMOT](CARD0).encoder.00.index-mask-invert 0 setp    [HMOT](CARD0).encoder.00.scale  [JOINT_0]ENCODER_MOTOR_SCALE # Axis scale encoder setp    [HMOT](CARD0).encoder.02.counter-mode 0 setp    [HMOT](CARD0).encoder.02.filter 1 setp    [HMOT](CARD0).encoder.02.index-invert 0 setp    [HMOT](CARD0).encoder.02.index-mask 0 setp    [HMOT](CARD0).encoder.02.index-mask-invert 0 setp    [HMOT](CARD0).encoder.02.scale  [JOINT_0]ENCODER_LINEAR_SCALE # Neither of the ProtoTrak encoders have index signals, should this always be forced off? net x-index-enable           joint.0.index-enable  <=>  [HMOT](CARD0).encoder.00.index-enable [HMOT](CARD0).encoder.02.index-enable net x-index-enable       => pid.vx.index-enable pid.px.index-enable # Velocity and position feedback into the PIDs net x-motor-fb                  pid.vx.feedback <= [HMOT](CARD0).encoder.00.position => joint.0.motor-pos-fb net x-linear-fb                 pid.px.feedback <= [HMOT](CARD0).encoder.02.position # Home / limit switch signals - none yet. net x-home-sw                 => joint.0.home-sw-in net x-neg-limit            => joint.0.neg-lim-sw-in net x-pos-limit            => joint.0.pos-lim-sw-in

Please Log in to join the conversation.

More
2 years 6 months ago #297867 by TangentAudio

Please Log in to join the conversation.

More
2 years 6 months ago #297872 by TangentAudio
Just for fun, here are some of the first moves it made when I got a very rough tuning on a single loop working.  Crusty motors and drives circa 1989!  Pardon my shop disaster, everything is a mess from recently moving the machine in.


 

Please Log in to join the conversation.

More
2 years 6 months ago #297921 by andypugh
One thing that might be worth trying would be to use the motor encoder velocity output and the linuxcnc PID velocity feedforward terms (pid.N.command-deriv) and then use the bed encoder for the position parts of the loop.
(This assumes that the bed encoder is accurate, maybe it isn't and _that_ one is intended to be the velocity feedback? )

Please Log in to join the conversation.

More
2 years 6 months ago #297924 by TangentAudio
Thanks for the reply, Andy.

So if I'm understanding, you're suggesting to use a single HAL PID component per axis but connecting outputs from both of the encoders into that loop?  Interesting idea, I hadn't thought of that.  I have to do some reading up on the PID component and sketch out what the HAL connections would look like.

From linuxcnc.org/docs/html/man/man9/pid.9.html
Code:
pid.N.command-deriv float in The derivative of the desired (commanded) value for the control loop. If no signal is connected then the derivative will be estimated numerically. pid.N.feedback-deriv float in The derivative of the actual (feedback) value for the control loop. If no signal is connected then the derivative will be estimated numerically. When the feedback is from a quantized position source (e.g., encoder feedback position), behavior of the D term can be improved by using a better velocity estimate here, such as the velocity output of encoder(9) or hostmot2(9).

The gage wheel encoders for the table are not perfect due to their age and design, but I think they should be accurate enough. The motor encoders do have more effective resolution, but that doesn't directly translate to positioning due to where they are located in the mechanical system (i.e., behind timing belts and a ball screw with some backlash).

My long term thinking is replacing the table wheel encoders with magnetic scales, but I want to see how far I can get with these wheel encoders since they're already on the machine and they're already paid for .
 

Please Log in to join the conversation.

More
2 years 6 months ago #298165 by TangentAudio
It's been a busy week here, but I'm still working to wrap my head around this.  I posted a link earlier to a Galil video about dual loop compensation, and finally had a chance to watch it in detail.  It gives a good overview of the approaches and problems.  The proposed "improved dual loop" seems to be more or less the same approach that was described rather sparsely in the wiki.

Here's the video again: www.galil.com/learn/online-videos/dual-l...compensation-methods

And my re-drawing of their simplified dual loop.

 

Attachment not found



To better my understanding I've been working through the process of translating that simplified loop to show the actual relevant HAL components and signals.  Here's my first approach.  It's much easier to understand and learn in diagram form than just seeing it as a pile of HAL commands.

 

Attachment not found



I have not yet taken this back down to my shop to rework the config to match the drawing, but hopefully this weekend.  Anyone see any glaring mistakes or have other comments?

cheers,
Steve

Please Log in to join the conversation.

More
2 years 6 months ago #298168 by TangentAudio
One thing I'm questioning is whether both the inner and outer PIDs should receive the same position command signal. It isn't really shown explicitly in the simplified Galil drawing, though the wiki example definitely does it this way.

Also, I want to make sure I understand the nomenclature. I think I wrongfully assumed this type of dual loop was a velocity loop (inner) and position loop (outer), but the outputs from both loops are velocities, so I think that's wrong. You can see my confusion in the initial configs I posted as I called the PIDs "vx" and "px".

Next up, the Prototrak DC servo amps are PWM input -> motor output voltage. Varying the voltage on an unloaded DC motor varies its speed (velocity). These are just amps and not closed loop drives - the motor encoder output just comes straight into the Mesa card. I am a bit confused on whether this is called "velocity mode," however. Is that term reserved for a drive which itself runs a loop with the motor encoder to maintain the commanded velocity?

Which leads me to wondering whether the velocity outputs from the motor encoders should be used. Andy, you kind of hinted at that the other day. I'm curious how you would see that fitting into this diagram.

Thanks in advance.

Please Log in to join the conversation.

More
2 years 6 months ago #298172 by rodw
I thought the intention was to close the velocity loop on the drive/amp and to close the position loop from the scales in linuxcnc.
But I've not got any experience to add.

Please Log in to join the conversation.

More
2 years 6 months ago #298173 by TangentAudio
Hi Rod,
These 35 year old drives/amps don't have any way to close the loop internally. They're just offset PWM in -> +/- DC voltage out as far as I know. There's no microcontroller in them, and the motor encoders don't connect to them. The signals were passed directly to the primitive Prototrak Plus controller/DRO box.

cheers,
Steve

Please Log in to join the conversation.

Time to create page: 0.146 seconds
Powered by Kunena Forum