#! /usr/bin/python import sys import getopt import xml.etree.ElementTree as ET import hal import time from collections import namedtuple class Pin: """ Representation of a Pin and it's data""" def __init__(self, type, dir): self.val = 0 # current value of pin, e.g. 1 - on, 0 - off self.type = type # type (string read from xml) self.dir = dir def __repr__(self): return 'val: ' + str(self.val) + '\ttype: ' + self.type + '\tdir: ' + self.dir class HalAdapter: def __init__(self, name): self.h = hal.component(name) self.h.newpin("velocity", hal.HAL_FLOAT, hal.HAL_OUT) self.h.newpin('x-vel', hal.HAL_FLOAT, hal.HAL_IN) self.h.newpin('y-vel', hal.HAL_FLOAT, hal.HAL_IN) self.h.newpin('z-vel', hal.HAL_FLOAT, hal.HAL_IN) self.h.newpin('lube-level-ok',hal.HAL_BIT, hal.HAL_IN) self.h.newpin('reset', hal.HAL_BIT, hal.HAL_IN) self.h.newpin('lube-ext-req', hal.HAL_BIT, hal.HAL_IN) self.h.newpin('lube-cmd', hal.HAL_BIT, hal.HAL_OUT) self.h.newpin('lube-level-alarm', hal.HAL_BIT, hal.HAL_OUT) self.h.newpin('accumulated-distance', hal.HAL_FLOAT, hal.HAL_OUT) self.h.ready() def __repr__(self): tmp_str = '' return tmp_str def is_lube_level_ok(self): return self.h['lube-level-ok'] def is_reset(self): return self.h['reset'] def is_lube_ext_req(self): return self.h['lube-ext-req'] def get_velocities(self): velocities = namedtuple("velocities", ["x", "y", "z"]) return velocities( self.h['x-vel'], self.h['y-vel'], self.h['z-vel']) def set_lube_on(self, request): if request >= 1: self.h['lube-cmd'] = 1 else: self.h['lube-cmd'] = 0 def set_lube_level_alarm(self, level_ok): if level_ok >= 1: self.h['lube-level-alarm'] = 1 else: self.h['lube-level-alarm'] = 0 def set_accumulated_distance(self, d): self.h['accumulated-distance'] = d class parameterContainer: def __init__(self, xml_file): self.paramDict = {} self._xmlFile = xml_file self.tree = ET.parse(self._xmlFile) self._parse() def _parse(self): root = self.tree.getroot() for param in root.iter('parameter'): #print param.attrib['name'], param.attrib['value'] self.paramDict[param.attrib['name']] = float(param.attrib['value']) def getParam(self, name): if name in self.paramDict: return self.paramDict[name] else: return None def getParams(self): return self.paramDict def writeToFile(self): for parName in self.paramDict: self._writeToTree(parName, self.paramDict[parName]) self.tree.write(self._xmlFile) def writeParam(self, parName, value): if parName in self.paramDict: self.paramDict[parName] = value def _writeToTree(self, parName, value): """update parameter in xml-tree""" root = self.tree.getroot() for param in root.iter('parameter'): if param.attrib['name'] == parName: param.attrib['value'] = str(round(value, 2)) break class LubeControl: def __init__(self, lube_on_time, accumulated_distance, distance_threshold, number_of_lubings): self.lubeOnTime = lube_on_time # [sec] self.total_distance = accumulated_distance # [mm] self.distance_threshold = distance_threshold # [mm] self.numberOfLubings = number_of_lubings self.state = 'OFF' self.lubeLevelOkOut = True self._lubeLevelOkIn = True self.prev_time = time.time() def calc_dist_from_vel(self, v_x, v_y, v_z): current_time = time.time() time_delta = current_time - self.prev_time self.total_distance += abs(v_x) * time_delta self.total_distance += abs(v_y) * time_delta self.total_distance += abs(v_z) * time_delta self.prev_time = current_time def runStateMachine(self, ext_req): currentTime = time.time() if self.total_distance >= self.distance_threshold or ext_req == True: self.state = 'ON' self.timeout = self.lubeOnTime + currentTime self.total_distance = 0 self.numberOfLubings += 1 if self.state == 'ON': if currentTime > self.timeout: #check lube pressure sensor self.lubeLevelOkOut = self._lubeLevelOkIn self.state = 'OFF' def setLubeLevelOK(self, levelOk): self._lubeLevelOkIn = levelOk def reset(self): self.total_distance = 0 self.state = 'OFF' self.lubeLevelOkOut = True def _usage(): """ print command line options """ print "usage luber.py -h -c in_file.xml\n"\ "in_file # input xml-file describing what knobs and/or button are on the pendant\n"\ "-c # name of component in HAL. 'my-luber' default\n"\ "-h # Help test" def main(): xmlFile = 'luber.xml' #xmlFile = '' name = 'my-luber' # default name of component in HAL try: opts, args = getopt.getopt(sys.argv[1:], "hc:", ["input="]) except getopt.GetoptError as err: # print help information and exit: print(err) # will print something like "option -a not recognized" sys.exit(2) for o, a in opts: if o == "-h": _usage() sys.exit() elif o == "-c": name = a elif o == "--input": xmlFile = a else: print o assert False, "unhandled option" if xmlFile == '': if len(sys.argv) < 2: _usage() sys.exit(2) else: xmlFile = sys.argv[-1] p = parameterContainer(xmlFile) h = HalAdapter(name) totalDistance = p.getParam('totalDistance') distanceThreshold = p.getParam('distanceThreshold') lubeOnTime = p.getParam('lubePulseTime') nbrOfLubings = p.getParam('numberOfLubings') lubeCtrl = LubeControl(lubeOnTime, totalDistance, distanceThreshold, nbrOfLubings) try: while 1: if h.is_reset(): lubeCtrl.reset() lubeCtrl.setLubeLevelOK(h.is_lube_level_ok()) v = h.get_velocities() lubing_external_request = h.is_lube_ext_req() lubeCtrl.calc_dist_from_vel(v.x, v.y, v.z) lubeCtrl.runStateMachine(lubing_external_request) h.set_lube_on(lubeCtrl.state == 'ON') h.set_lube_level_alarm(lubeCtrl.lubeLevelOkOut) h.set_accumulated_distance(lubeCtrl.total_distance) time.sleep(0.1) except KeyboardInterrupt: p.writeParam('totalDistance', lubeCtrl.total_distance) p.writeParam('numberOfLubings', lubeCtrl.numberOfLubings) p.writeToFile() raise SystemExit if __name__ == '__main__': main()