Cuadratura más rápida en bucles con código Python

0

Estoy trabajando con un BeagleBone Black y utilizando la biblioteca IO Python de Adafruit. Escribió una simple función de decodificación en cuadratura y funciona perfectamente bien cuando el motor funciona a aproximadamente 1800 RPM. Pero cuando el motor funciona a velocidades más altas, el código comienza a perder algunas de las interrupciones y el conteo del codificador comienza a acumular errores. ¿Tienen alguna sugerencia sobre cómo puedo hacer que el código sea más eficiente o si hay funciones que puedan hacer un ciclo de las interrupciones a una frecuencia mayor?

Gracias, Kel

Aquí está el código:

# Define encoder count function
def encodercount(term):
global counts       
global Encoder_A
global Encoder_A_old
global Encoder_B
global Encoder_B_old
global error


Encoder_A = GPIO.input('P8_7')  # stores the value of the encoders at time of interrupt
Encoder_B = GPIO.input('P8_8')

if Encoder_A == Encoder_A_old and Encoder_B == Encoder_B_old:
# this will be an error
    error += 1
    print 'Error count is %s' %error

elif (Encoder_A == 1 and Encoder_B_old == 0) or (Encoder_A == 0 and Encoder_B_old == 1):
# this will be clockwise rotation
    counts += 1
    print 'Encoder count is %s' %counts
    print 'AB is %s %s' % (Encoder_A, Encoder_B)

elif (Encoder_A == 1 and Encoder_B_old == 1) or (Encoder_A == 0 and Encoder_B_old == 0):
# this will be counter-clockwise rotation
    counts -= 1
    print 'Encoder count is %s' %counts
    print 'AB is %s %s' % (Encoder_A, Encoder_B)

else:
#this will be an error as well
    error += 1
    print 'Error count is %s' %error

Encoder_A_old = Encoder_A     # store the current encoder values as old values to be used as comparison in the next loop
Encoder_B_old = Encoder_B       

# Initialize the interrupts - these trigger on the both the rising and falling 
GPIO.add_event_detect('P8_7', GPIO.BOTH, callback = encodercount)   # Encoder A
GPIO.add_event_detect('P8_8', GPIO.BOTH, callback = encodercount)   # Encoder B

# This is the part of the code which runs normally in the background
while True:
    time.sleep(1)
    
pregunta Kelei

3 respuestas

2

Tenga en cuenta que el BBB tiene tres decodificadores de cuadratura de hardware en el chip, y dos parecen ser accesibles a través de los conectores. Busque las funciones eQEP. Algunos programas de soporte técnico parecen estar disponibles ahora para estos, busque la cuadratura negra de Beaglebone, etc.

    
respondido por el Dynode
1

Recomendaría descargarlo en un FPGA o CPLD pequeño, y luego leer los conteos a través de un puerto serie de algún tipo, por ejemplo. SPI. Un pequeño Spartan FPGA podría realizar un seguimiento de una gran cantidad de codificadores que funcionan a alta velocidad, y el procesador simplemente puede leer los contadores según sea necesario. GPIO no está diseñado para esta aplicación. A menos que desee dedicar un núcleo completo solo en los pines y sondeando continuamente con un bucle while, la mejor solución es descargar esto en un dispositivo externo.

    
respondido por el alex.forencich
0

Se han unido bastantes pruebas lógicas, lo que ralentizará las cosas:

if (Encoder_A == 1 and Encoder_B_old == 0) or (Encoder_A == 0 and Encoder_B_old == 1):

Esa línea requiere SIETE pruebas (==, y, ==, o, ==, y, ==).

Además, esto no parece ser una verdadera rutina de interrupción, ya que explícitamente tienes que comprobar si los pines realmente han cambiado de estado en la parte superior. Si esto fue una interrupción real provocada por un cambio de pin, entonces la prueba es redundante.

Las declaraciones de impresión en una rutina de interrupción son un gran no-no en situaciones como esta, ya que ralentizan toda la rutina, la impresión en la consola requiere tiempo; de hecho, CUALQUIER llamada a una función externa lleva tiempo. Establezca una bandera y continúe, ejecute la rutina de impresión en otro lugar marcando la bandera, y no deje que le detenga la interrupción.

No sé cuán eficientemente funciona Python y qué patrones pueden ser "los más óptimos" pero (en C) estaría inclinado a algo como esto:

if(a != old_a) // A has changed
{
    if(a == 1)
    {
        if(b == 0)
        {
            count++; // Encoder moved fwd
        }
        else // We don't care what else, anything is an error
        {
            error; // b cannot == a
        }
    }
    else // Must be 0, no need to check
    {
        if(b == 1)
        {
            count--; // Encoder moved back
        }
        else
        {
            error; // b cannot == a
        }
    }
}
else if(b != old_b) // B has changed
{
    if(b == 1)
    {
        if(a == 0)
        {
            count++; // Encoder moved fwd
        }
        else
        {
            error; // b cannot == a
        }
    }
    else
    {
        if(a == 1)
        {
            count--; // Encoder moved bbck
        }
        else
        {
            error; // b cannot == a
        }
    }
}
else // neither has changed
{
    error;
}
old_a = a;
old_b = b;

Puede observar que esto está anidado para que el procesador realice el número mínimo de pruebas para llegar al resultado, y tratamos de evitar un error como resultado de no tener éxito, en lugar de detectar errores explícitamente con cuidado. (y mucho tiempo) pruebas.

Sin saber qué tan eficientemente / inteligentemente compila Python, es difícil adivinar formas más eficientes de hacer esto.

    
respondido por el John U

Lea otras preguntas en las etiquetas