|
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