Linear scale correction: homing to index

More
09 May 2014 15:46 #46752 by DaBit
I am currently using a linear scale in the feedback loop to correct axis position. This works well, but I do have one problem: how do I synchronise the scale and rotary encoder during a home-to-indexpulse?

Without home to index the situation is simple: when LinuxCNC starts both encoders start at 0 and stay synchronised when the axis moves. Also during homing; LinuxCNC just uses the offset when the switch is latched.

When using the index pulse the situation is different: the moment the index pulse passes by the encoder used for the index homing (the linear scale) resets to zero while the other (roatry encoder on the sefvo motor) does not. At that moment there is a difference in position between the two.

Resetting the rotary encoder when the scale encoder index-enable goes low again using an edge component does not work; that triggers a following error.
Using the high-to-low edge of scalencoder.index-enable to set an offset works half of the time. There is some kind of race condition and I didn't yet figure out when it does work and when it doesn't. Every time I have halscope all set up to catch the bug it works flawless and some random time after that it considers the position where the axis was when LinuxCNC started as '0'.

Now, how would one do this correctly?

Here is the relevant part of my HAL file:
# ################
# X [0] Axis
# ################

# axis enable chain
net xenable <= axis.0.amp-enable-out
net xenable => xservo_pid.enable 
net xenable => hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogena
 
# encoder feedback, rotary
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.00.scale  [AXIS_0]INPUT_SCALE
net xpos-fb hm2_[HOSTMOT2](BOARD).0.encoder.00.position => xservo_pid.feedback => xscale_tristate.in
#net xpos-fb => axis.0.motor-pos-fb 
net xvel <= hm2_[HOSTMOT2](BOARD).0.encoder.00.velocity => xservo_pid.feedback-deriv

# encoder feedback, linear
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.counter-mode 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.filter 1
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.index-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.index-mask 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.index-mask-invert 0
setp hm2_[HOSTMOT2](BOARD).0.encoder.03.scale  [AXIS_0]INPUT_SCALE_LINEAR

# index homing and encoder sync
net xindex_enable hm2_[HOSTMOT2](BOARD).0.encoder.03.index-enable <=> axis.0.index-enable => xscale_edge.in
setp xscale_edge.in-edge TRUE
net xlatch_pos xscale_edge.out => xscale_tristate.enable
net xrotenc_offset xscale_tristate.out => offset_xscale.offset
net xscalepos_raw hm2_[HOSTMOT2](BOARD).0.encoder.03.position => offset_xscale.in 

#net xpos-fb => axis.0.motor-pos-fb
net xscalepos => axis.0.motor-pos-fb

# set PID loop gains from inifile
setp xservo_pid.Pgain [AXIS_0]P
setp xservo_pid.Igain [AXIS_0]I
setp xservo_pid.Dgain [AXIS_0]D
setp xservo_pid.bias [AXIS_0]BIAS
setp xservo_pid.FF0 [AXIS_0]FF0
setp xservo_pid.FF1 [AXIS_0]FF1
setp xservo_pid.FF2 [AXIS_0]FF2
setp xservo_pid.deadband [AXIS_0]DEADBAND
setp xservo_pid.maxoutput [AXIS_0]MAX_OUTPUT
setp xservo_pid.error-previous-target 1

setp xscale_pid.Pgain [AXIS_0]SCALE_P
setp xscale_pid.Igain [AXIS_0]SCALE_I
setp xscale_pid.deadband [AXIS_0]SCALE_DEADBAND
setp xscale_pid.FF0 1.0
setp xscale_pid.maxerrorI [AXIS_0]SCALE_MAXCORR
setp xscale_pid.maxerror [AXIS_0]SCALE_MAXCORR
setp xscale_pid.enable TRUE

# position command signals

# linear scale position PID
net xscalepos offset_xscale.out => xscale_pid.feedback
net xpos-cmd axis.0.motor-pos-cmd => xscale_pid.command
net xpos-scalecorrected xscale_pid.output => xservo_pid.command

setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout0-scalemax [AXIS_0]OUTPUT_SCALE
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout0-maxlim [AXIS_0]OUTPUT_SCALE
setp hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout0-minlim [AXIS_0]OUTPUT_SCALE_NEG
net xmotor-command xservo_pid.output  =>  hm2_[HOSTMOT2](BOARD).0.7i77.0.1.analogout0

# Home switch/index logic
net homesw-x <= hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-08-not => axis.0.home-sw-in

# X-axis limit switch logic
net xminsw-x hm2_[HOSTMOT2](BOARD).0.7i77.0.0.input-09-not => xminsw_and2.in0
net homesw-x xmaxsw_and2.in0
net x-is-homed <= axis.0.homed => xhomed_not.in
net x-not-homed <= xhomed_not.out => xminsw_and2.in1 => xmaxsw_and2.in1
net x-minlimsw <= xminsw_and2.out => axis.0.neg-lim-sw-in
net x-maxlimsw <= xmaxsw_and2.out => axis.0.pos-lim-sw-in

Please Log in or Create an account to join the conversation.

More
09 May 2014 23:12 #46764 by jmelson

DaBit wrote: I am currently using a linear scale in the feedback loop to correct axis position. This works well, but I do have one problem: how do I synchronise the scale and rotary encoder during a home-to-indexpulse?

Without home to index the situation is simple: when LinuxCNC starts both encoders start at 0 and stay synchronised when the axis moves. Also during homing; LinuxCNC just uses the offset when the switch is latched.

When using the index pulse the situation is different: the moment the index pulse passes by the encoder used for the index homing (the linear scale) resets to zero while the other (roatry encoder on the sefvo motor) does not. At that moment there is a difference in position between the two.

Why not wire the index pulse from which ever encoder is the "master" to the encoder counters for
both encoders? That way, they both will zero at very nearly the same time.

Jon

Please Log in or Create an account to join the conversation.

More
10 May 2014 04:11 #46776 by jtc
my suggestion (I don't know in it is possible, but I think so) is to use a MUX to be able to use 2 different following errors...

for example in the *.ini file

[AXIS_0]

ferror_before = 10
ferror_after = 0.001

and now on the hal file, load a mux component

setp mux.in0 [AXIS_0]ferror_before
setp mux.in1 [AXIS_0]ferror_after
net MuxOut mux.out => "where the normal ferror is connected on your hal file"

to the mux selection line you can connect one hal pin that have the information "this axis is homed", so the idea is. use a big following error when start the machine and before homing. After that, and after the reset to one encoder, it changes the Ferror to a lowest value. I think that this approach can work.



Or maybe you can consider program a component that have the inputs of the 2 encoders and after your algorithm outputs just one "virtual" encoder.

João

Please Log in or Create an account to join the conversation.

More
10 May 2014 04:50 - 10 May 2014 04:50 #46777 by DaBit

jmelson wrote: Why not wire the index pulse from which ever encoder is the "master" to the encoder counters for
both encoders? That way, they both will zero at very nearly the same time.


I considered that solution too (and still do), but if possible I would like to solve it in HAL since that is a more flexible solution.
Also that would do about the same as scaleencoder.index_enable -> falling edge detect -> rotaryencoder.reset.

jtc wrote: my suggestion (I don't know in it is possible, but I think so) is to use a MUX to be able to use 2 different following errors...


I don't think that is possible?

Or maybe you can consider program a component that have the inputs of the 2 encoders and after your algorithm outputs just one "virtual" encoder.


I considered that as an option to use rotary encoder counts to interpolate between scale counts since they have a lower resolution. The scale PID is often working with only +/- 1 scale encoder count and it could use a somewhat more finegrained pulse train.
That would possibly also solve this issue.

Not having the position reset when an index pulse occurs would be the easiest way to solve it, but I think this is not possible either?
(use encoder.rawcount, do the scaling to position myself maybe?)
Last edit: 10 May 2014 04:50 by DaBit.

Please Log in or Create an account to join the conversation.

More
10 May 2014 05:01 #46780 by jtc

DaBit wrote: [
Not having the position reset when an index pulse occurs would be the easiest way to solve it, but I think this is not possible either?
(use encoder.rawcount, do the scaling to position myself maybe?)


I'm almost sure that is impossible... if you enable index (its bidirectional), when the encoder reached it, it will reset the encoder. I find this "inconvenient" some months ago...

Please Log in or Create an account to join the conversation.

More
13 May 2014 06:37 #46853 by andypugh

jtc wrote: my suggestion (I don't know in it is possible, but I think so) is to use a MUX to be able to use 2 different following errors.


You can't do that directly, as following-error is not a pin. (it is read directly from the INI file).

It would be possible to do it by simply lying about the feedback position to the motion controller though :-)

For example, if you net fb-loop axis.N.motor-position-fb <= axis.N.motor.position-cmd then no following error can ever happen.

To "lie" about position feedback you would take the difference between the two pins above, scale by a variable scale factor (using mux2 as suggested) then add the scaled f-error back on and pass that to the fb pin.

Please Log in or Create an account to join the conversation.

More
13 May 2014 20:29 #46876 by DaBit
The moment things fail the following error is as large as the position difference between where the axis was when LinuxCNC started and the index pulse. That can be up to full travel. Not very practical to lie about the feedback position; just setting FERROR/FERROR_MIN to ridiculous large values is just as effective. Besides that I'd like to feed the scale position to axis.N.motor-position-fb since that is the position I would like to see on the DROs.

I tried hardwiring the scale index pulse to both the scale encoder input and the rotary encoder input with physical wire and connecting the index-enable of both encoders together in HAL. Doesn't help, 8 out of 10 times it works, 2 out of 10 times it doesn't. There is still a race condition somewhere between the MESA hardware resetting the counter (storing the offset actually; rawcounts does not reset) and LinuxCNC updating it's internal state.

I still have to dive deeper into this but just like a nonworking television the actual failure didn't show up yet when I have all the (HAL)scope probes hooked up.

For now I put it on the 'finishing touch' list and use home-to-switch-only. Inductive proximity switches also repeat within 0,03mm or so, which is good enough for practical purposes. But the index pulse is even more accurate and I get it for free.

Please Log in or Create an account to join the conversation.

More
13 May 2014 22:17 #46883 by PCW
I think connecting the index signal to both encoder counters in hardware is the
easiest way to get it to work since its done in hardware and has no servothread/velocity
dependent errors.

Its probably arguable that LinuxCNC's index logic (Clear-on-index) is a historical artifact
since many older quadrature counters only had the option to clear the count on index
it was the only choice.

Clearing the position count on index has a number of system wide side effects
that require rather ugly work-arounds (note the wiring of index enable into the PID comp for example)

It might be that theres a better solution to handling index that assumes all counters can do latch-on-index
rather than only clear-on-index. ( always latching on index also has the side benefit of providing a encoder
sanity check)

Please Log in or Create an account to join the conversation.

More
13 May 2014 22:30 #46884 by andypugh

DaBit wrote: The moment things fail the following error is as large as the position difference between where the axis was when LinuxCNC started and the index pulse. That can be up to full travel. Not very practical to lie about the feedback position; just setting FERROR/FERROR_MIN to ridiculous large values is just as effective.


Except that if you do that you have no f-error protection at any other time. My proposal would allow you to hav ludicrously big f-error limits during homing, and normal f-error protection the rest of the time.

During conventional homing the system knows to ignore the sudden change in apparent position feedback on encoder index. It may be that the order in which you have the HAL components running is the problem (hence the apparent race condition).

Please Log in or Create an account to join the conversation.

More
13 May 2014 23:27 #46888 by DaBit

PCW wrote: I think connecting the index signal to both encoder counters in hardware is the
easiest way to get it to work since its done in hardware and has no servothread/velocity
dependent errors.


I tried that already.

Its probably arguable that LinuxCNC's index logic (Clear-on-index) is a historical artifact
since many older quadrature counters only had the option to clear the count on index
it was the only choice.


The clear on index is one thing, but I hate the bidirectional logic used :laugh:

Clearing the position count on index has a number of system wide side effects
that require rather ugly work-arounds (note the wiring of index enable into the PID comp for example)


Hmm, did I wire index-enable into the PID controllers? Euhhhh, no, I did not.
That might just be the issue....

It might be that theres a better solution to handling index that assumes all counters can do latch-on-index
rather than only clear-on-index. ( always latching on index also has the side benefit of providing a encoder
sanity check)


I was also considering feeding the index pulse to a GPIO to use that as the 'home switch' during the latch move. Can also be done with a mux and then I don't need to loosen ferror during homing. The only real limitation would be that the index search velocity is limited to less than 15mm/sec in my case (3kHz servo thread, 5um long index pulse). Doing the latching in hardware is even better.

andypugh wrote: Except that if you do that you have no f-error protection at any other time. My proposal would allow you to hav ludicrously big f-error limits during homing, and normal f-error protection the rest of the time.


That is true.

During conventional homing the system knows to ignore the sudden change in apparent position feedback on encoder index. It may be that the order in which you have the HAL components running is the problem (hence the apparent race condition).


It might just be the connection of index-enable to the PID-controllers.

How does HAL determine in what order to execute logic? Start with the component at the source of a signal, end at the destination? That would be hard with bidirectional stuff like index-enable.

Please Log in or Create an account to join the conversation.

Time to create page: 0.096 seconds
Powered by Kunena Forum