Самый эффективный алгоритм чтения оптического квадратурного энкодера в Python
Я работаю над проектом, в котором я использую управление частотой вращения для 3 двигателей с оптическими квадратурными энкодерами, и эффективность необходима, потому что я не хочу терять счет и разрушать позиционирование.
Сначала я создал класс CMotor, где я определяю некоторые атрибуты и методы. Среди методов я определил RotaryDeal, который отвечает за счет.
В начале это выглядело так:
class CMotor:
def RotaryDeal(self):
self.LastB = GPIO.input(self.PinB)
self.LastA = GPIO.input(self.PinA)
while (self.LastA==GPIO.input(self.PinA) and self.LastB==GPIO.input(self.PinB) ):
flag = 1
self.CurrentB = GPIO.input(self.PinB)
self.CurrentA = GPIO.input(self.PinA)
if self.CurrentA:
if self.CurrentB:
if self.LastA:
self.Cuentas-=1
else:
self.Cuentas+=1
else:
if self.LastA:
self.Cuentas+=1
else:
self.Cuentas-=1
else:
if self.CurrentB:
if self.LastA:
self.Cuentas-=1
else:
self.Cuentas+=1
else:
if self.LastA:
self.Cuentas+=1
else:
self.Cuentas-=1
print 'Cuentas %s = %d' % (self.Nombre, self.Cuentas)
#(Cuentas is Counts btw)
И чтобы использовать его, я импортирую этот файл и создаю объект с именем M3. Затем:
try:
while 1:
M3.RotaryDeal()
except KeyboardInterrupt:
GPIO.cleanup()
Тем не менее, мой код был неэффективным и не работал с несколькими двигателями, а также стал очень неэффективным при использовании rospy. Вот почему я попытался использовать add_event_detect, как предложено здесь
Я наконец получил что-то вроде этого:
class CMotor:
#Some other functions and the __init__
def RotaryDeal(self, ev = None):
self.CurrentB = GPIO.input(self.PinB)
self.CurrentA = GPIO.input(self.PinA)
if self.CurrentA:
if self.CurrentB:
if self.LastA:
self.Cuentas-=1
else:
self.Cuentas+=1
else:
if self.LastA:
self.Cuentas+=1
else:
self.Cuentas-=1
else:
if self.CurrentB:
if self.LastA:
self.Cuentas-=1
else:
self.Cuentas+=1
else:
if self.LastA:
self.Cuentas+=1
else:
self.Cuentas-=1
self.LastA = self.CurrentA
self.LastB = self.CurrentB
print 'Cuentas %s = %d' % (self.Nombre, self.Cuentas)
#sorry for the indentation, im copying it from the terminal (using ubuntu mate)
И назвал это так:
try:
GPIO.add_event_detect(M3.PinA, GPIO.BOTH, callback=M3.RotaryDeal)
GPIO.add_event_detect(M3.PinB, GPIO.BOTH, callback=M3.RotaryDeal)
while 1:
pass
except KeyBoardInterrupt:
GPIO.cleanup()
Несмотря на то, что он должен быть более эффективным, он сделал с точностью до наоборот. Когда я попытался повернуть его, я получил совершенно другие результаты от оригинала. Предполагается прочитать 3200 отсчетов за оборот, если вы прочитали целые 4 ситуации, но "эффективный" алгоритм потерял все мои отсчеты. Кроме того, чем быстрее я вращал ротор, тем больше отсчетов он пропустил.
Пожалуйста, если есть более эффективный способ считывания счетчика со всеми четырьмя ситуациями кодировщика, или я допускаю ошибку, я был бы более чем благодарен, если бы вы опубликовали ее.
П.Д.: Для тех, кто не понимает, что я имел в виду для 4 ситуаций:
|PinA|PinB|
1| 0 | 0 |
2| 0 | 1 |
3| 1 | 0 |
4| 1 | 1 |
PD 2: я собираюсь использовать rospy и посылать это количество в тему, а процесс публикации занимает некоторое время, поэтому мне нужно, чтобы код был максимально эффективным
1 ответ
Выполняется ли оператор печати каждый раз, когда выполняется RotaryDeal()? Печать на терминал — удивительно медленная операция, поэтому лучше всего просто сохранить значения кодировщика в локальной переменной и печатать ее каждые несколько тысяч итераций или около того.