[Home]Psuedo-Absolute Encoders

LinuxCNCKnowledgeBase | RecentChanges | PageIndex | Preferences | LinuxCNC.org

My Holbrook lathe has servo motors with Resolvers and a Mesa 7i49 card. This means that the angular position of the motor shaft is always known with a great degree of accuracy. But the system does not know how many full turns from the home position it is, so has to perform a homing move.

Homing a lathe is a nuisance. Especially if you left it set up with the tailstock centre in place, or the boring bar down a hole.

I have solved this (I think) with a simple Python component (it has to be userspace to have access to the filesystem) which records the axis positions (machine coordinates) at shut-down, then reads the file back at startup and works out the number of full-turns that best fit the current motor shaft angle and the recorded position at system exit.

There are a few changes to make in HAL, and setting it up the first time is a bit of a fiddle:

. A sum2 is needed to add the offset from the component to the resolver/encoder position and pass that number to both pid.L.feedback and joint.N.motor-postion-fb.

 net x-offset  psuedo_absolute_encoder.offset-0 sum2.0.in0
 net x-pos hm2_5i24.0.resolver.00.position sum2.0.in1
 net x-pos-abs sum2.0.out joint.0.motor-position-fb pid.x.feedback
. The component needs to be loaded in the HAL file, and the scales set.
 loadusr pseudo_absolute_encoder num_chans=3
 setp pseudo_absolute_encoder.scale-0 2.54
 setp psuedo_absolute_encoder.scale-1 5
 setp pseudo_absolute_encoder.scale-2 2.5

The INI file should be left as normal for conventional homing, and any psuedo_abs_encoder.var files should be deleted. Home the machine and jog to a position well away from the hard stops. Note the position in machine coordinates. Then exit. Now set HOME_ABSOLUTE_ENCODER=2 for each axis. Restart the machine. You should now see the machine position in the DRO (absolute units) match the position in which the machine was turned off. (possibly off by the INI HOME_OFFSET) If you now press home-all the machine should mark each axis as homed, but not make any movements.

Make sure you have f-error limits set. I had a few runaways getting this working. Which is why you should turn the machine off well clear of the limits while setting it up.

This is the Python component. You just need to make it executable and copy it to /usr/bin

 #!/usr/bin/env python

 import hal, time
 import sys, os

 num_chans = 9
 for s in sys.argv:
     p = s.split('=')
     if p[0] == 'num_chans': num_chans=int(p[1])

 h = hal.component("pseudo_abs_encoder")

 for i in range(0,num_chans):
     h.newpin('encoder-position-%i' % i, hal.HAL_FLOAT, hal.HAL_IN)
     h['encoder-position-%i' % i] = -1e99
     h.newpin('offset-%i' % i, hal.HAL_FLOAT, hal.HAL_OUT)
     h['offset-%i' % i] = 0
     h.newpin('scale-%i' % i, hal.HAL_FLOAT, hal.HAL_IN)
     h['scale-%i' % i] = 1.0

 h.newpin('sleep_time', hal.HAL_FLOAT, hal.HAL_OUT)

 old = [0.0] * num_chans
 flags = [False] * num_chans
 try:
     f = open('pseudo_abs_encoder.var', 'r')
     for i in range(0,num_chans):
         v = f.readline()
         old[i] = float(v)
     f.close()
     # Guarantee file freshness
     os.remove(f.name)
 except IOError:
     print "position file not found. set HOME_ABSOLUTE_ENCODER to zero and home normally"

 h.ready()

 try:
     while 1:
         sleep_time = 3600
         for i in range(0, num_chans):
             if flags[i] == False: sleep_time = 0.1
             s = 1.0 if h['scale-%i' % i] == 0 else h['scale-%i' % i]
             p = h['encoder-position-%i' % i]
             if p > -1e98 and flags[i] == False:
                 # find a combination of full-turns + current value closest to the old value
                 n = round(old[i] / s)
                 if abs(old[i] - (s * n + p)) > abs(old[i] - (s * (n + 1)+ p)):
                     n = n + 1
                 elif abs(old[i] - (s * n + p)) > abs(old[i] - (s * (n - 1)+ p)):
                     n = n - 1
                 h['offset-%i' % i] = s * n
                 flags[i] = True
         h.sleep_time = sleep_time
         time.sleep(sleep_time)

 except KeyboardInterrupt?:
     print 'writing file'
     f = open('pseudo_abs_encoder.var', 'w')
     for i in range(0, num_chans):
         p = h['encoder-position-%i' % i]
         o = h['offset-%i' % i]
         if flags[i]:
             f.write('%0.6f\n' % (o + p))
         else:
             f.write('0.0\n')
     f.close()
     raise SystemExit?

LinuxCNCKnowledgeBase | RecentChanges | PageIndex | Preferences | LinuxCNC.org
This page is read-only. Follow the BasicSteps to edit pages. | View other revisions
Last edited January 4, 2017 3:29 pm by Andyough (diff)
Search:
Published under a Creative Commons License