|
4 | 4 | import os
|
5 | 5 | import logging
|
6 | 6 | import itertools
|
| 7 | +import platform |
| 8 | + |
| 9 | +if not platform.release().startswith('4.4'): |
| 10 | + raise ImportError( |
| 11 | + 'The Encoder module requires Linux kernel version >= 4.4.x.\n' |
| 12 | + 'Please upgrade your kernel to use this module.\n' |
| 13 | + 'Your Linux kernel version is {}.'.format(platform.release())) |
7 | 14 |
|
8 | 15 | eQEP0 = 0
|
9 | 16 | eQEP1 = 1
|
@@ -60,193 +67,179 @@ def __init__(self, channel, pin_A, pin_B, sys_path):
|
60 | 67 |
|
61 | 68 | class RotaryEncoder(object):
|
62 | 69 |
|
63 |
| - def _run_cmd(self, cmd): |
64 |
| - '''Runs a command. If not successful (i.e. error code different than zero), |
65 |
| - print the stderr output as a warning. |
66 |
| - ''' |
67 |
| - |
68 |
| - try: |
69 |
| - output = check_output(cmd, stderr=STDOUT) |
70 |
| - self._logger.info("_run_cmd(): cmd='{}' return code={} output={}".format( |
71 |
| - " ".join(cmd), 0, output)) |
72 |
| - except CalledProcessError as e: |
73 |
| - self._logger.warning( |
74 |
| - "_run_cmd(): cmd='{}' return code={} output={}".format( |
75 |
| - " ".join(cmd), e.returncode, e.output)) |
76 |
| - |
77 |
| - def config_pin(self, pin): |
78 |
| - ''' |
79 |
| - config_pin() |
80 |
| - Config pin for QEP |
81 |
| - ''' |
82 |
| - |
83 |
| - self._run_cmd(["config-pin", pin, "qep"]) |
84 |
| - |
85 |
| - def cat_file(self, path): |
86 |
| - ''' |
87 |
| - cat_file() |
88 |
| - Print contents of file |
89 |
| - ''' |
90 |
| - |
91 |
| - self._run_cmd(["cat", path]) |
92 |
| - |
93 |
| - def __init__(self, eqep_num): |
94 |
| - ''' |
95 |
| - RotaryEncoder(eqep_num) |
96 |
| - Creates an instance of the class RotaryEncoder. |
97 |
| - eqep_num determines which eQEP pins are set up. |
98 |
| - eqep_num can be: EQEP0, EQEP1, EQEP2 or EQEP2b based on which pins \ |
99 |
| - the rotary encoder is connected to. |
100 |
| - ''' |
101 |
| - |
102 |
| - self._logger = logging.getLogger(__name__) |
103 |
| - self._logger.addHandler(logging.NullHandler()) |
104 |
| - |
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)) |
111 |
| - |
112 |
| - self.config_pin(self._eqep.pin_A) |
113 |
| - self.config_pin(self._eqep.pin_B) |
114 |
| - |
115 |
| - self.base_dir = self._eqep.sys_path |
116 |
| - self._logger.debug( |
117 |
| - "RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) |
118 |
| - |
119 |
| - self.enable() |
120 |
| - |
121 |
| - def enable(self): |
122 |
| - ''' |
123 |
| - enable() |
124 |
| - Turns the eQEP hardware ON |
125 |
| - ''' |
126 |
| - enable_file = "%s/enabled" % self.base_dir |
127 |
| - self._logger.debug("enable(): enable_file: {0}".format(enable_file)) |
128 |
| - self._logger.warning( |
129 |
| - "enable(): TODO: not implemented, write 1 to {}".format(enable_file)) |
130 |
| - #return sysfs.kernelFileIO(enable_file, '1') |
131 |
| - |
132 |
| - def disable(self): |
133 |
| - ''' |
134 |
| - disable() |
135 |
| - Turns the eQEP hardware OFF |
136 |
| - ''' |
137 |
| - enable_file = "%s/enabled" % self.base_dir |
138 |
| - self._logger.debug("disable(): enable_file: {0}".format(enable_file)) |
139 |
| - self._logger.warning( |
140 |
| - "disable(): TODO: not implemented, write 0 to {}".format(enable_file)) |
141 |
| - #return sysfs.kernelFileIO(enable_file, '0') |
142 |
| - |
143 |
| - def setAbsolute(self): |
144 |
| - ''' |
145 |
| - setAbsolute() |
146 |
| - Set mode as Absolute |
147 |
| - The position starts at zero and is incremented or |
148 |
| - decremented by the encoder's movement |
149 |
| - ''' |
150 |
| - mode_file = "%s/mode" % self.base_dir |
151 |
| - self._logger.debug("setAbsolute(): mode_file: {0}".format(mode_file)) |
152 |
| - self._logger.warning( |
153 |
| - "setAbsolute(): TODO: not implemented, write 0 to {}".format(mode_file)) |
154 |
| - #return sysfs.kernelFileIO(mode_file, '0') |
155 |
| - |
156 |
| - def setRelative(self): |
157 |
| - ''' |
158 |
| - setRelative() |
159 |
| - Set mode as Relative |
160 |
| - The position is reset when the unit timer overflows. |
161 |
| - ''' |
162 |
| - mode_file = "%s/mode" % self.base_dir |
163 |
| - self._logger.debug("setRelative(): mode_file: {0}".format(mode_file)) |
164 |
| - self._logger.warning( |
165 |
| - "setRelative(): TODO: not implemented, write 1 to {}".format(mode_file)) |
166 |
| - #return sysfs.kernelFileIO(mode_file, '1') |
167 |
| - |
168 |
| - def getMode(self): |
169 |
| - ''' |
170 |
| - getMode() |
171 |
| - Returns the mode the eQEP hardware is in. |
172 |
| - ''' |
173 |
| - mode_file = "%s/mode" % self.base_dir |
174 |
| - self._logger.debug("getMode(): mode_file: {0}".format(mode_file)) |
175 |
| - self._logger.warning("getMode(): TODO: read mode_file") |
176 |
| - #return sysfs.kernelFileIO(mode_file) |
177 |
| - |
178 |
| - def getPosition(self): |
179 |
| - ''' |
180 |
| - getPosition() |
181 |
| - Get the current position of the encoder. |
182 |
| - In absolute mode, this attribute represents the current position |
183 |
| - of the encoder. |
184 |
| - In relative mode, this attribute represents the position of the |
185 |
| - encoder at the last unit timer overflow. |
186 |
| - ''' |
187 |
| - self._logger.debug("Channel: {}".format(self._eqep.channel)) |
188 |
| - position_file = "%s/position" % self.base_dir |
189 |
| - self._logger.debug("getPosition(): position_file: {0}".format(position_file)) |
190 |
| - position_handle = open(position_file, 'r') |
191 |
| - self._logger.debug("getPosition(): position_handle: {0}".format(position_handle)) |
192 |
| - position = position_handle.read() |
193 |
| - self._logger.debug("getPosition(): position: {0}".format(position)) |
194 |
| - #return sysfs.kernelFileIO(position_file) |
195 |
| - |
196 |
| - return position |
197 |
| - |
198 |
| - def setFrequency(self, freq): |
199 |
| - ''' |
200 |
| - setFrequency(freq) |
201 |
| - Set the frequency in Hz at which the driver reports new positions. |
202 |
| - ''' |
203 |
| - period_file = "%s/period" % self.base_dir |
204 |
| - self._logger.debug("setFrequency(): period_file: {0}".format(period_file)) |
205 |
| - self._logger.debug("setFrequency(): freq: {0}".format(freq)) |
206 |
| - self._logger.debug("setFrequency(): 1000000000/freq: {0}".format(1000000000/freq)) |
207 |
| - self._logger.debug("setFrequency(): str(1000000000/freq)): {0}".format(str(1000000000/freq))) |
208 |
| - self._logger.warning( |
209 |
| - "setFrequency(): TODO: not implemented, set {} to {}".format( |
210 |
| - period_file, str(1000000000/freq))) |
211 |
| - #return sysfs.kernelFileIO(period_file, str(1000000000/freq)) |
212 |
| - |
213 |
| - def setPosition(self, val): |
214 |
| - ''' |
215 |
| - setPosition(value) |
216 |
| - Give a new value to the current position |
217 |
| - ''' |
218 |
| - position_file = "%s/position" % self.base_dir |
219 |
| - self._logger.warning( |
220 |
| - "setPosition(): TODO: not implemented, write position to {}".format( |
221 |
| - position_file)) |
222 |
| - #return sysfs.kernelFileIO(position_file, str(val)) |
223 |
| - |
224 |
| - def zero(self): |
225 |
| - ''' |
226 |
| - zero()s |
227 |
| - Set the current position to 0 |
228 |
| - ''' |
229 |
| - return self.setPosition(0) |
230 |
| - |
231 |
| - |
232 |
| -#""" |
233 |
| -# encoder_test.py |
234 |
| -# Rekha Seethamraju |
235 |
| -# An example to demonstrate the use of the eQEP library |
236 |
| -# for PyBBIO. |
237 |
| -# This example program is in the public domain. |
238 |
| -#""" |
239 |
| -#from bbio import * |
240 |
| -#from bbio.libraries.RotaryEncoder import RotaryEncoder |
241 |
| -# |
242 |
| -#encoder = RotaryEncoder(RotaryEncoder.EQEP2b) |
243 |
| -# |
244 |
| -#def setup(): |
245 |
| -# encoder.setAbsolute() |
246 |
| -# encoder.zero() |
247 |
| -# |
248 |
| -#def loop(): |
249 |
| -# print("encoder position : "+encoder.getPosition()) |
250 |
| -# delay(1000) |
251 |
| -# |
252 |
| -#run(setup, loop) |
| 70 | + def _run_cmd(self, cmd): |
| 71 | + '''Runs a command. If not successful (i.e. error code different than |
| 72 | + zero), print the stderr output as a warning. |
| 73 | + ''' |
| 74 | + |
| 75 | + try: |
| 76 | + output = check_output(cmd, stderr=STDOUT) |
| 77 | + self._logger.info( |
| 78 | + "_run_cmd(): cmd='{}' return code={} output={}".format( |
| 79 | + " ".join(cmd), 0, output)) |
| 80 | + except CalledProcessError as e: |
| 81 | + self._logger.warning( |
| 82 | + "_run_cmd(): cmd='{}' return code={} output={}".format( |
| 83 | + " ".join(cmd), e.returncode, e.output)) |
| 84 | + |
| 85 | + def config_pin(self, pin): |
| 86 | + ''' |
| 87 | + config_pin() |
| 88 | + Config pin for QEP |
| 89 | + ''' |
| 90 | + |
| 91 | + self._run_cmd(["config-pin", pin, "qep"]) |
| 92 | + |
| 93 | + def cat_file(self, path): |
| 94 | + ''' |
| 95 | + cat_file() |
| 96 | + Print contents of file |
| 97 | + ''' |
| 98 | + |
| 99 | + self._run_cmd(["cat", path]) |
| 100 | + |
| 101 | + def __init__(self, eqep_num): |
| 102 | + ''' |
| 103 | + RotaryEncoder(eqep_num) |
| 104 | + Creates an instance of the class RotaryEncoder. |
| 105 | + eqep_num determines which eQEP pins are set up. |
| 106 | + eqep_num can be: EQEP0, EQEP1, EQEP2 or EQEP2b based on which pins \ |
| 107 | + the rotary encoder is connected to. |
| 108 | + ''' |
| 109 | + |
| 110 | + self._logger = logging.getLogger(__name__) |
| 111 | + self._logger.addHandler(logging.NullHandler()) |
| 112 | + |
| 113 | + # Configure eqep module |
| 114 | + self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) |
| 115 | + self._logger.info( |
| 116 | + "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( |
| 117 | + self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, |
| 118 | + self._eqep.sys_path)) |
| 119 | + |
| 120 | + self.config_pin(self._eqep.pin_A) |
| 121 | + self.config_pin(self._eqep.pin_B) |
| 122 | + |
| 123 | + self.base_dir = self._eqep.sys_path |
| 124 | + self._logger.debug( |
| 125 | + "RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) |
| 126 | + |
| 127 | + self.enable() |
| 128 | + |
| 129 | + def enable(self): |
| 130 | + ''' |
| 131 | + enable() |
| 132 | + Turns the eQEP hardware ON |
| 133 | + ''' |
| 134 | + enable_file = "%s/enabled" % self.base_dir |
| 135 | + self._logger.debug("enable(): enable_file: {0}".format(enable_file)) |
| 136 | + self._logger.warning( |
| 137 | + "enable(): TODO: not implemented, write 1 to {}".format(enable_file)) |
| 138 | + # return sysfs.kernelFileIO(enable_file, '1') |
| 139 | + |
| 140 | + def disable(self): |
| 141 | + ''' |
| 142 | + disable() |
| 143 | + Turns the eQEP hardware OFF |
| 144 | + ''' |
| 145 | + enable_file = "%s/enabled" % self.base_dir |
| 146 | + self._logger.debug("disable(): enable_file: {0}".format(enable_file)) |
| 147 | + self._logger.warning( |
| 148 | + "disable(): TODO: not implemented, write 0 to {}".format( |
| 149 | + enable_file)) |
| 150 | + # return sysfs.kernelFileIO(enable_file, '0') |
| 151 | + |
| 152 | + def setAbsolute(self): |
| 153 | + ''' |
| 154 | + setAbsolute() |
| 155 | + Set mode as Absolute |
| 156 | + The position starts at zero and is incremented or |
| 157 | + decremented by the encoder's movement |
| 158 | + ''' |
| 159 | + mode_file = "%s/mode" % self.base_dir |
| 160 | + self._logger.debug("setAbsolute(): mode_file: {0}".format(mode_file)) |
| 161 | + self._logger.warning( |
| 162 | + "setAbsolute(): TODO: not implemented, write 0 to {}".format( |
| 163 | + mode_file)) |
| 164 | + # return sysfs.kernelFileIO(mode_file, '0') |
| 165 | + |
| 166 | + def setRelative(self): |
| 167 | + ''' |
| 168 | + setRelative() |
| 169 | + Set mode as Relative |
| 170 | + The position is reset when the unit timer overflows. |
| 171 | + ''' |
| 172 | + mode_file = "%s/mode" % self.base_dir |
| 173 | + self._logger.debug("setRelative(): mode_file: {0}".format(mode_file)) |
| 174 | + self._logger.warning( |
| 175 | + "setRelative(): TODO: not implemented, write 1 to {}".format( |
| 176 | + mode_file)) |
| 177 | + # return sysfs.kernelFileIO(mode_file, '1') |
| 178 | + |
| 179 | + def getMode(self): |
| 180 | + ''' |
| 181 | + getMode() |
| 182 | + Returns the mode the eQEP hardware is in. |
| 183 | + ''' |
| 184 | + mode_file = "%s/mode" % self.base_dir |
| 185 | + self._logger.debug("getMode(): mode_file: {0}".format(mode_file)) |
| 186 | + self._logger.warning("getMode(): TODO: read mode_file") |
| 187 | + # return sysfs.kernelFileIO(mode_file) |
| 188 | + |
| 189 | + def getPosition(self): |
| 190 | + ''' |
| 191 | + getPosition() |
| 192 | + Get the current position of the encoder. |
| 193 | + In absolute mode, this attribute represents the current position |
| 194 | + of the encoder. |
| 195 | + In relative mode, this attribute represents the position of the |
| 196 | + encoder at the last unit timer overflow. |
| 197 | + ''' |
| 198 | + self._logger.debug("Channel: {}".format(self._eqep.channel)) |
| 199 | + position_file = "%s/position" % self.base_dir |
| 200 | + self._logger.debug( |
| 201 | + "getPosition(): position_file: {0}".format(position_file)) |
| 202 | + position_handle = open(position_file, 'r') |
| 203 | + self._logger.debug( |
| 204 | + "getPosition(): position_handle: {0}".format(position_handle)) |
| 205 | + position = position_handle.read() |
| 206 | + self._logger.debug("getPosition(): position: {0}".format(position)) |
| 207 | + # return sysfs.kernelFileIO(position_file) |
| 208 | + |
| 209 | + return position |
| 210 | + |
| 211 | + def setFrequency(self, freq): |
| 212 | + ''' |
| 213 | + setFrequency(freq) |
| 214 | + Set the frequency in Hz at which the driver reports new positions. |
| 215 | + ''' |
| 216 | + period_file = "%s/period" % self.base_dir |
| 217 | + self._logger.debug( |
| 218 | + "setFrequency(): period_file: {0}".format(period_file)) |
| 219 | + self._logger.debug("setFrequency(): freq: {0}".format(freq)) |
| 220 | + self._logger.debug( |
| 221 | + "setFrequency(): 1000000000/freq: {0}".format(1000000000/freq)) |
| 222 | + self._logger.debug("setFrequency(): str(1000000000/freq)): {0}".format( |
| 223 | + str(1000000000/freq))) |
| 224 | + self._logger.warning( |
| 225 | + "setFrequency(): TODO: not implemented, set {} to {}".format( |
| 226 | + period_file, str(1000000000/freq))) |
| 227 | + # return sysfs.kernelFileIO(period_file, str(1000000000/freq)) |
| 228 | + |
| 229 | + def setPosition(self, val): |
| 230 | + ''' |
| 231 | + setPosition(value) |
| 232 | + Give a new value to the current position |
| 233 | + ''' |
| 234 | + position_file = "%s/position" % self.base_dir |
| 235 | + self._logger.warning( |
| 236 | + "setPosition(): TODO: not implemented, write position to {}".format( |
| 237 | + position_file)) |
| 238 | + # return sysfs.kernelFileIO(position_file, str(val)) |
| 239 | + |
| 240 | + def zero(self): |
| 241 | + ''' |
| 242 | + zero()s |
| 243 | + Set the current position to 0 |
| 244 | + ''' |
| 245 | + return self.setPosition(0) |
0 commit comments