|
3 | 3 | from subprocess import check_output, STDOUT, CalledProcessError
|
4 | 4 | import os
|
5 | 5 | import logging
|
6 |
| - |
7 |
| - |
8 |
| -class QEP : |
9 |
| - |
10 |
| - def __init__(self, channel=1, debug=False): |
11 |
| - self.channel = channel |
12 |
| - self.debug = debug |
13 |
| - |
14 |
| - def errMsg(self): |
15 |
| - print("Error accessing 0x%02X: Check your QEP channel" % self.address) |
16 |
| - return -1 |
17 |
| - |
18 |
| -# example method from Adafruit_I2C |
19 |
| -# TODO: delete this |
20 |
| -# def write8(self, reg, value): |
21 |
| -# "Writes an 8-bit value to the specified register/address" |
22 |
| -# try: |
23 |
| -# self.bus.write_byte_data(self.address, reg, value) |
24 |
| -# if self.debug: |
25 |
| -# print("Rotary: Wrote 0x%02X to register 0x%02X" % (value, reg)) |
26 |
| -# except IOError as err: |
27 |
| -# return self.errMsg() |
28 |
| -# |
29 |
| -# |
30 |
| -#if __name__ == '__main__': |
31 |
| -# try: |
32 |
| -# qep = Adafruit_BBIO.Encoder.QEP() |
33 |
| -# print("Default QEP channel is accessible") |
34 |
| -# except: |
35 |
| -# print("Error accessing default Rotary bus") |
36 |
| - |
| 6 | +import itertools |
| 7 | + |
| 8 | +eQEP0 = 0 |
| 9 | +eQEP1 = 1 |
| 10 | +eQEP2 = 2 |
| 11 | +eQEP2b = 3 |
| 12 | + |
| 13 | +_OCP_PATH = "/sys/devices/platform/ocp" |
| 14 | +_eQEP_DEFS = [ |
| 15 | + {'channel': 'eQEP0', 'pin_A': 'P9_92', 'pin_B': 'P9_27', |
| 16 | + 'sys_path': os.path.join(_OCP_PATH, '48300000.epwmss/48300180.eqep')}, |
| 17 | + {'channel': 'eQEP1', 'pin_A': 'P8_35', 'pin_B': 'P8_33', |
| 18 | + 'sys_path': os.path.join(_OCP_PATH, '48302000.epwmss/48302180.eqep')}, |
| 19 | + {'channel': 'eQEP2', 'pin_A': 'P8_12', 'pin_B': 'P8_11', |
| 20 | + 'sys_path': os.path.join(_OCP_PATH, '48304000.epwmss/48304180.eqep')}, |
| 21 | + {'channel': 'eQEP2b', 'pin_A': 'P8_41', 'pin_B': 'P8_42', |
| 22 | + 'sys_path': os.path.join(_OCP_PATH, '48304000.epwmss/48304180.eqep')} |
| 23 | +] |
| 24 | + |
| 25 | + |
| 26 | +class eQEP(object): |
| 27 | + '''Enhanced Quadrature Encoder Pulse (eQEP) module class. Abstraction |
| 28 | + for either of the three available channels (eQEP0, eQEP1, eQEP2) on |
| 29 | + the Beaglebone''' |
| 30 | + |
| 31 | + @classmethod |
| 32 | + def fromdict(cls, d): |
| 33 | + '''Creates a class instance from a dictionary''' |
| 34 | + |
| 35 | + allowed = ('channel', 'pin_A', 'pin_B', 'sys_path') |
| 36 | + df = {k: v for k, v in d.iteritems() if k in allowed} |
| 37 | + return cls(**df) |
| 38 | + |
| 39 | + def __init__(self, channel, pin_A, pin_B, sys_path): |
| 40 | + '''Initialize the eQEP module |
| 41 | +
|
| 42 | + Attributes: |
| 43 | + channel (str): eQEP channel name. E.g. "eQEP0", "eQEP1", etc. |
| 44 | + Note that "eQEP2" and "eQEP2b" are channel aliases for the |
| 45 | + same module, but on different (mutually-exclusive) sets of |
| 46 | + pins |
| 47 | + pin_A (str): physical input pin for the A signal of the |
| 48 | + rotary encoder |
| 49 | + pin_B (str): physical input pin for the B signal of the |
| 50 | + rotary encoder |
| 51 | + sys_path (str): sys filesystem path to access the attributes |
| 52 | + of this eQEP module |
| 53 | +
|
| 54 | + ''' |
| 55 | + self.channel = channel |
| 56 | + self.pin_A = pin_A |
| 57 | + self.pin_B = pin_B |
| 58 | + self.sys_path = sys_path |
37 | 59 |
|
38 | 60 |
|
39 | 61 | class RotaryEncoder(object):
|
40 |
| - # TODO: check that kernel 4.1+ |
41 |
| - # TODO: use config-pin to set qep mode |
42 |
| - OCP_PATH = "/sys/devices/platform/ocp" |
43 |
| - _eqep_dirs = [ |
44 |
| - '%s/48300000.epwmss/48300180.eqep' % OCP_PATH, |
45 |
| - '%s/48302000.epwmss/48302180.eqep' % OCP_PATH, |
46 |
| - '%s/48304000.epwmss/48304180.eqep' % OCP_PATH |
47 |
| - ] |
48 |
| - |
49 |
| - EQEP0 = 0 |
50 |
| - EQEP1 = 1 |
51 |
| - EQEP2 = 2 |
52 |
| - EQEP2b = 3 |
53 | 62 |
|
54 | 63 | def _run_cmd(self, cmd):
|
55 | 64 | '''Runs a command. If not successful (i.e. error code different than zero),
|
@@ -93,64 +102,19 @@ def __init__(self, eqep_num):
|
93 | 102 | self._logger = logging.getLogger(__name__)
|
94 | 103 | self._logger.addHandler(logging.NullHandler())
|
95 | 104 |
|
96 |
| - # Configure eqep0 |
97 |
| - self._logger.info("Configuring eqep0, pins: P9.27, P9.92") |
98 |
| - |
99 |
| - pin = "P9_27" |
100 |
| - self.config_pin(pin) |
101 |
| - |
102 |
| - pin = "P9_92" |
103 |
| - self.config_pin(pin) |
104 |
| - |
105 |
| - path = "/sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position" |
106 |
| - self.cat_file(path) |
107 |
| - |
108 |
| - # Configure eqep1 |
109 |
| - self._logger.info("Configuring eqep1, pins: P8.33, P8.35") |
110 |
| - |
111 |
| - pin = "P8.33" |
112 |
| - self.config_pin(pin) |
113 |
| - |
114 |
| - pin = "P8.35" |
115 |
| - self.config_pin(pin) |
116 |
| - |
117 |
| - path = "/sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position" |
118 |
| - self.cat_file(path); |
119 |
| - |
120 |
| - # Configure eqep2 |
121 |
| - self._logger.info("Configuring eqep2, pins: P8.11, P8.12") |
122 |
| - |
123 |
| - pin = "P8.11" |
124 |
| - self.config_pin(pin) |
125 |
| - |
126 |
| - pin = "P8.12" |
127 |
| - self.config_pin(pin) |
128 |
| - |
129 |
| - path = "/sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position" |
130 |
| - self.cat_file(path); |
131 |
| - |
132 |
| - # Configure eqep2b |
133 |
| - self._logger.info("Configuring eqep2, pins: P8.41, P8.42") |
134 |
| - |
135 |
| - pin = "P8.41" |
136 |
| - self.config_pin(pin) |
137 |
| - |
138 |
| - pin = "P8.42" |
139 |
| - self.config_pin(pin) |
140 |
| - |
141 |
| - path = "/sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position" |
142 |
| - self.cat_file(path); |
143 |
| - |
144 |
| - self._logger.debug("RotaryEncoder(): eqep_num: {0}".format(eqep_num)) |
145 |
| - self._logger.debug("RotaryEncoder(): self._eqep_dirs[0]: {0}".format(self._eqep_dirs[0])) |
146 |
| - self._logger.debug("RotaryEncoder(): self._eqep_dirs[1]: {0}".format(self._eqep_dirs[1])) |
147 |
| - self._logger.debug("RotaryEncoder(): self._eqep_dirs[2]: {0}".format(self._eqep_dirs[2])) |
148 |
| - self._logger.debug("RotaryEncoder(): self._eqep_dirs[eqep_num: {0}]: {1}".format(eqep_num, self._eqep_dirs[eqep_num])) |
| 105 | + # Configure eqep module |
| 106 | + self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) |
| 107 | + self._logger.info( |
| 108 | + "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( |
| 109 | + self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, |
| 110 | + self._eqep.sys_path)) |
149 | 111 |
|
150 |
| - assert 0 <= eqep_num <= 3 , "eqep_num must be between 0 and 3" |
| 112 | + self.config_pin(self._eqep.pin_A) |
| 113 | + self.config_pin(self._eqep.pin_B) |
151 | 114 |
|
152 |
| - self.base_dir = self._eqep_dirs[eqep_num] |
153 |
| - self._logger.debug("RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) |
| 115 | + self.base_dir = self._eqep.sys_path |
| 116 | + self._logger.debug( |
| 117 | + "RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) |
154 | 118 |
|
155 | 119 | self.enable()
|
156 | 120 |
|
@@ -220,6 +184,7 @@ def getPosition(self):
|
220 | 184 | In relative mode, this attribute represents the position of the
|
221 | 185 | encoder at the last unit timer overflow.
|
222 | 186 | '''
|
| 187 | + self._logger.debug("Channel: {}".format(self._eqep.channel)) |
223 | 188 | position_file = "%s/position" % self.base_dir
|
224 | 189 | self._logger.debug("getPosition(): position_file: {0}".format(position_file))
|
225 | 190 | position_handle = open(position_file, 'r')
|
|
0 commit comments