Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Switching Encoder Algorithm
#1
My control loop uses as feedback two different encoders, but at different times. For higher rates, it uses and absolute encoder, but on slower rotation rates it uses an incremental encoder which has a much finer resolution. Right now the motor position register is switched between the two different encoder registers. The scale factor of the incremental is set so that the absolute and incremental encoder registers read about the same. However, over time the incremental slips and the registers become off from each other. Therefore when switching the motor register back to the absolute position, there is a fake jump in position.

The servo loop sometimes sees this jump and responds slightly (but usually not much) also the following error jumps.

I was thinking about doing the following algorithm, but I don't know how to exactly implement it(indicated by "***DONT KNOW***"):

1. Stop using the motor register feedback
***DONT KNOW****
2. Disable following error calculation
temp = Motor[0].FEFata;l
Motor[0].FEFatal = 0;
3. Change the assignment of the motor register to different encoder.
4. Enable following error calculation
Motor[0].FEFatal = temp;
5. Start using the motor register to feedback.
***DONT KNOW***
6. Continue operation like normal.

Does anyone know how I do this properly? Also is there anything that I might be overlooking?

thanks
windell
Reply
#2
Hi,

Customers have needed to do this in the past and I have almost finished writing a full response/example for you, but encountered a hiccup and it's late here on Friday, so I'll finish up on Monday.

For now I'll just say that you can definitely switch encoders on the fly, but I would NEVER disable fatal following error because you could accidentally literally kill someone on a large machine. You have to leave the motor in closed-loop mode and change all the encoder settings in a single servo cycle to do it safely.

I'll explain the details next week and give you an example.
Reply
#3
Here is the solution.

Assuming you have already defined encoder conversion table entries for the "old" encoder and the "new" encoder (i.e. the encoder to which you want to switch), you can use the method below to change encoder feedback on the fly:

1. Keep the motor in closed loop mode.
2. Switch Motor[x].pEnc (and/or Motor[x].pEnc2 if the same encoder is used for the velocity loop as well) to EncTable[n].a of the "new" encoder.
3. Change Motor[x].PosSf (and/or Motor[x].pEnc2 if this encoder is used for the velocity loop as well) to match the new encoder's resolution.
4. Make sure this all happens within one servo cycle.

My example uses Motor 4 going from EncTable[4] to EncTable[5], so be sure to change these indices to yours:

Code:
Sys.MaxRtPlc = 1; // Allow PLCs 0 and 1 to run at the real-time interrupt
Sys.RtIntPeriod = 0; // Set the real-time interrupt rate to servo rate <--- very important!

// The following define forces the PLC to run at real-time
#define SwitchEncodersPLC 0
global Mtr4OldPosSf = 1;

// EncTable[5]'s scale factor is 10x that of EncTable[4]'s in this example (may be different from your case)
global Mtr4NewPosSf = EncTable[4].ScaleFactor / EncTable[5].ScaleFactor;

open plc SwitchEncodersPLC
// Switching motor 4's feedback from ECT entry 4 to ECT entry 5 on the fly
Motor[4].pEnc = EncTable[5].a;
Motor[4].pEnc2 = EncTable[5].a;
Motor[4].PosSf = Mtr4NewPosSf;
Motor[4].Pos2Sf = Mtr4NewPosSf;
disable plc SwitchEncodersPLC;
close

// This define forces the PLC to run at real-time
#define SwitchEncodersBackPLC 1
open plc SwitchEncodersBackPLC
// Switching motor 4's feedback from ECT entry 5 back to ECT entry 4 on the fly
Motor[4].pEnc = EncTable[4].a;
Motor[4].pEnc2 = EncTable[4].a;
Motor[4].PosSf = Mtr4OldPosSf;
Motor[4].Pos2Sf = Mtr4OldPosSf;
disable plc SwitchEncodersBackPLC;
close

Something important to note is that in my example, I was assuming that the output of EncTable[5] is 10x larger than EncTable[4]'s output, so I scaled Motor[x].PosSf and Pos2Sf accordingly. You could alternatively have scaled EncTable[5].ScaleFactor to be 10x smaller so that its result had the same resolution as EncTable[4]. In that case, you would not have to change Motor[x].PosSf and Pos2Sf. If, however, you do have a scaling discrepancy, you will have to change PosSf and Pos2Sf or else retune your servo loop gains.
Reply
#4
Thank you very much Charles. This is extremely helpful. I still have yet to try the code out, but do you know if there is a difference in the encoder readings at the switch, will there be a spike in the following error? I guess I'm not sure how the following error is calculated and when.

(05-04-2015, 10:13 AM)CharlesP Wrote: Here is the solution.

Assuming you have already defined encoder conversion table entries for the "old" encoder and the "new" encoder (i.e. the encoder to which you want to switch), you can use the method below to change encoder feedback on the fly:

1. Keep the motor in closed loop mode.
2. Switch Motor[x].pEnc (and/or Motor[x].pEnc2 if the same encoder is used for the velocity loop as well) to EncTable[n].a of the "new" encoder.
3. Change Motor[x].PosSf (and/or Motor[x].pEnc2 if this encoder is used for the velocity loop as well) to match the new encoder's resolution.
4. Make sure this all happens within one servo cycle.

My example uses Motor 4 going from EncTable[4] to EncTable[5], so be sure to change these indices to yours:

Code:
Sys.MaxRtPlc = 1; // Allow PLCs 0 and 1 to run at the real-time interrupt
Sys.RtIntPeriod = 0; // Set the real-time interrupt rate to servo rate <--- very important!

// The following define forces the PLC to run at real-time
#define SwitchEncodersPLC 0
global Mtr4OldPosSf = 1;

// EncTable[5]'s scale factor is 10x that of EncTable[4]'s in this example (may be different from your case)
global Mtr4NewPosSf = EncTable[4].ScaleFactor / EncTable[5].ScaleFactor;

open plc SwitchEncodersPLC
// Switching motor 4's feedback from ECT entry 4 to ECT entry 5 on the fly
Motor[4].pEnc = EncTable[5].a;
Motor[4].pEnc2 = EncTable[5].a;
Motor[4].PosSf = Mtr4NewPosSf;
Motor[4].Pos2Sf = Mtr4NewPosSf;
disable plc SwitchEncodersPLC;
close

// This define forces the PLC to run at real-time
#define SwitchEncodersBackPLC 1
open plc SwitchEncodersBackPLC
// Switching motor 4's feedback from ECT entry 5 back to ECT entry 4 on the fly
Motor[4].pEnc = EncTable[4].a;
Motor[4].pEnc2 = EncTable[4].a;
Motor[4].PosSf = Mtr4OldPosSf;
Motor[4].Pos2Sf = Mtr4OldPosSf;
disable plc SwitchEncodersBackPLC;
close

Something important to note is that in my example, I was assuming that the output of EncTable[5] is 10x larger than EncTable[4]'s output, so I scaled Motor[x].PosSf and Pos2Sf accordingly. You could alternatively have scaled EncTable[5].ScaleFactor to be 10x smaller so that its result had the same resolution as EncTable[4]. In that case, you would not have to change Motor[x].PosSf and Pos2Sf. If, however, you do have a scaling discrepancy, you will have to change PosSf and Pos2Sf or else retune your servo loop gains.
Reply
#5
If you have properly dealt with the difference in scale factors between the two encoders, there will be no jump. I just tested it while jogging a motor and there's no issue.

I want to ask though -- I'm assuming you're using PMAC with a telescope, right?

Why exactly do you need to change encoders? Are you finding that you are exceeding the frequency limitation of our encoder processing hardware?

Would it be possible to use dual feedback (i.e. the incremental motor encoder for velocity and the absolute encoder for position)?

Some telescope customers have also used cascaded loop control -- basically the inner loop uses the incremental motor encoder for position/velocity feedback, and the outer loop uses the absolute encoder.

In both of these methods, you would not have to switch encoders.
Reply
#6
A little bit of background here:

In the older PMAC and Turbo PMAC controllers, the encoder conversion table put out a sensor position value. When the motor read this value for feedback, it subtracted the previous servo cycle's stored value to get the "delta", checked for possible rollover, and added this delta to the motor position (which could have a different zero position).

If you wanted to change feedback on the fly in these systems, you had to overwrite the motor's stored "previous position" value in the same cycle as you changed the source address for the feedback.

In the Power PMAC, the ECT puts out the "delta position" of the sensor, not the sensor position value itself. So when the motor picks up this value for its feedback, it just adds this delta (multiplied by the motor scale factor) to the motor position.

But in both cases, the motor position is just incremented by the delta value each servo cycle. In your case, this means that if one of your sensors (incremental) "slips" relative to the true physical position, going back to the other (absolute) sensor that has not slipped will NOT cause the motor position to be corrected. You will need another strategy.
Reply
#7
Thanks Charles and Wilson for your invaluable input.

I'll answer both your questions in a single response.

We use the incremental encoder during slow motions for both the dec and ha axes. On the hour axis the incremental encoder is mated via a friction drive and directly observes the HA rotation. The absolute encoder is mount to a pinion gear that also drives the HA axis. Historically it was done this way because the incremental observes the HA motion directly without backlash. The gear reductions are such that we get about 200 counts on the incremental for every count on the absolute (absolutes: approx 1000 counts/arc-sec, incremental: 200,000 counts/arc-sec) so the added resolution provides tighter control during star tracks. We have not done a study however that indicates that this resolution in in fact required. Due to slight misalignment between the HA axis of rotation and the axis of rotation for the encoder, the incremental every so often slips by a few counts.

I honestly haven't evaluated if were missing counts due to moving the telescope too fast, but that would be good to look into. It would seem that we're ok since for the most part, the motion seems to be conserved. Unless the bumps are really do to moving too fast on the incremental.

When we do quick motions between the star tracks, we switch the motor position register to read the absolute encoder so effectively we erase the "bump" due to the slip.

I hope this answers your questions. Thanks again for your help!


(05-07-2015, 11:35 AM)curtwilson Wrote: A little bit of background here:

In the older PMAC and Turbo PMAC controllers, the encoder conversion table put out a sensor position value. When the motor read this value for feedback, it subtracted the previous servo cycle's stored value to get the "delta", checked for possible rollover, and added this delta to the motor position (which could have a different zero position).

If you wanted to change feedback on the fly in these systems, you had to overwrite the motor's stored "previous position" value in the same cycle as you changed the source address for the feedback.

In the Power PMAC, the ECT puts out the "delta position" of the sensor, not the sensor position value itself. So when the motor picks up this value for its feedback, it just adds this delta (multiplied by the motor scale factor) to the motor position.

But in both cases, the motor position is just incremented by the delta value each servo cycle. In your case, this means that if one of your sensors (incremental) "slips" relative to the true physical position, going back to the other (absolute) sensor that has not slipped will NOT cause the motor position to be corrected. You will need another strategy.
Reply
#8
I want to emphasize again that, because the motor feedback algorithms use "delta" values (whether the delta is computed in the ECT or by the motor), that just switching back to the absolute encoder will NOT correct for any slippage that occurred when using the motor incremental encoder for feedback.

If you want to get back to the correct position value after you switch back to the absolute encoder, you will need to do another specific absolute position read, just as was done at power-on/reset.
Reply
#9
Aloha,

How do you do a specific absolute read? I'm sorry if this is mentioned in the manual and I haven't seen it. If so can you point me to the page?

Thanks
Windell
Reply
#10
If the following have been properly set up the motor specific homez (both on-line and program) command will execute an absolute read:
Motor[x].pAbsPos
Motor[x].AbsPosFormat
Motor[x].AbsPosSf
Motor[x].HomeOffset
See the description of the "homez" on-line command in the "Power PMAC Software Reference Manual", page 942.
Reply
#11
Aloha Steve,

When I try the homez command, it actually zeros out the counts for that encoder. Am I doing something wrong?

thanks,
windell
Reply
#12
This would indicate that Motor[x].pAbsPos is probably set to zero or is pointing to a register that always reads zero. Please send me an email with your motor settings for this as described in the previous post as this is a technical support issue. This will also get a faster response as I monitor emails at a higher update rate (phase vs RTI, lol).
Reply
#13
Note that Motor[x].AbsPosSf's default value is 0. You will have to set it nonzero (and to the appropriate value for your encoder) to use this feature.
Reply
#14
Thanks Charles. So for motor 0 if I want to do an absolute read of the encoder then I should pretty much set Motor[0].AbsPosSf to the same value as EncTable[0].ScaleFactor?


(03-22-2016, 04:05 PM)CharlesP Wrote: Note that Motor[x].AbsPosSf's default value is 0. You will have to set it nonzero (and to the appropriate value for your encoder) to use this feature.
Reply
#15
You should typically set Motor[x].AbsPosSf=1 when used with serial encoders. Make sure you have configured Motor[x].AbsPosFormat properly such that it shifts out the non-data bits and scales the result to motor units. Then, no additional scaling usually needs to be done, hence AbsPosSf=1.

See the PPMAC SRM for details on setting up AbsPosFormat.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)