|
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