Самый эффективный алгоритм чтения оптического квадратурного энкодера в 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()? Печать на терминал — удивительно медленная операция, поэтому лучше всего просто сохранить значения кодировщика в локальной переменной и печатать ее каждые несколько тысяч итераций или около того.

Другие вопросы по тегам