PWM en beaglebone (servos)

Servo conectado al beagleboneBuenas!

Buenas!

Como ya sabes, hace un tiempo que estoy jugando con el beaglebone. La verdad es que es un juguete realmente divertido y a fuerza de investigar se acaban aprendiendo bastantes cosillas del kernel de linux (al ser un hardware reciente todavía hay que pulir módulos del núcleo). Una de las cosas que se está mejorando en las últimas versiones del kernel es soporte para procesadores ARM (justo el que lleva el beaglebone), los cuales soportan modulación por pulsos (por lo menos el del beaglebone). En este artículo veremos cómo hacer funcionar los pines PWM y también una biblioteca para utilizarlos de manera sencilla. En el siguiente artículo trataré de explicar cómo utilizarlo sin entrar en demasiados detalles ténicos. Aunque como siempre, puede preguntar si te interesa saber más :)Primero he de decir que el soporte para el PWM está disponible a partir de la versión 3.2.0 del kernel. Yo utilizo debian squeeze donde la última versión es 3.2.17 y funciona sin problemas. También lo he probado con Angstrom Linux (que es la que trae de sere) y funciona igual.

Supongo que en este punto ya tienes todo el software listo! Puedes ejecutar ‘uname -r’ para comprobar la versión de tu kernel. Los pines que actualmente soportan PWM son del banco P9 los pines 14 y 16. Existen otros dos pines PWM algo diferentes pero de momento no he podido hacerlos funcionar…

Recuerda que beaglebone funciona con lógica de 3V mientras que la mayoría de servos lo hacen con 5V. Para el cable de datos esto no es muy importante ya que esos 3V están dentro del rango en el cual tu dispositivo detectará un 1 lógico. Pero con la alimentación cuidado, seguramente puedas enchufarlo a tu beaglebone pero los pines son muy delicados y puedes quemarlos. En mis caso uso miniservos que funcionan tanto a 3.3V como a 5V (evientemente si conectas a 3.3V se disfruta de menos torque). Para conectar la masa puedes utilizar los pines 1,2 tanto de P8 como de P9. Aunque en mis proyectos finales simplemente tengo un regulador de tensión que saca 5V de una batería (de donde se alimenta también el beaglebone). Siempre hay varias opciones.

Bien, ya tenemos el hardware listo! Sólo poner la parte lógica a funcionar.

Una de las maravillas de GNU/Linux (para mi gusto) es que puedes interactuar con cualquier dispositivo como si fuera un fichero. De esta manera, puedes utilizar la biblioteca estándar para manejar ficheros en vez de utilizar unas especiales para cada hardware. Luego es el kernel quien se encarga del trabajo sucio (transmitir a bajo nivel esos datos al dispositivo de la manera que sea). Además, Linux cuenta con debugfs que consiste en un sistema de ficheros especial donde podemos acceder a ciertas partes del kernel a través del sistema de ficheros (es algo como el directorio /proc).

Los directorios en cuestión son /sys/class/pwm/ y /sys/kernel/debug/omap_mux/. El primero nos servirá como interfaz para manejarlos mientras que el segundo es relativo al procesador donde activamos dichos pines. Dentro de /sys/class/pwm/ encontramos varios directorios y los que vamos a utilizar (si sabes cómo se usan los demás te agradecería que me lo dijeras) son ehrpwm.1:0  ehrpwm.1:1 que corresponden respectivamente al pin 14 y 16 del banco 9. Dentro de cada directorio vemos unos cuantos ficheros de los cuales nos interesan:

  • duty_ns: Duración del pulso en nanosegundos. Puedes escribir un número para cambiarlo (echo 200000 > duty_ns por ejemplo) o leerlo para ver cual es el acutal
  • duty_percent: porcentaje del pulso respecto al periodo. Evidentemente sólo admite valores desde 0 a 100. Si escribimos 30 quiere decir que el tiempo del pulso es un 30 del ciclo
  • period_freq: frecuencia que puede ir ser 50hz, 100hz, 400hz…
  • period_ns: frecuencia especificada en nanosegundos
  • run: Si escribimos un 1 lo activamos, si escribimos un 0 lo descativamos

El periodo es constante, pero el ancho del pulso cambia. En los servos cada segundo lo dividimos en 50 trocitos (50Hz) y dependiendo del tiempo que la tensión sea alta en cada trocito el servo lo interpretará como un ángulo. Imagen sacada de http://meteoyelectronica.blogspot.com.es/2010/12/pwm-una-manera-sencilla-de-controlar-un.html

Por normal general, los servos funcionan a 50Hz y los pulsos van desde un 5% a un 20%. Esto viene a ser de 500ms a 2000ms. Desde el sistema de ficheros sólo podemos introducir número enteros, por lo tanto usar el percent sería una mala opción porque sólo tendríamos 15 pasos. En esta caso nos conviene usar la opción que nos permite especificar la duración en nanosegundos ya que de esta manera tenemos precisión de sobra.

Pero si tratamos de escribir ahora mismos… no ocurre nada! El servo no se mueve. Indagando un poco resulta que la modulación por pulsos del procesador no está activada. Supongo que sus motivos tendrán. La solución es realmente sencilla y no es más que cambiar el valor de un registro de la CPU. Una vez cambiado el valor de ese registro ya debería funcionar aunque existen casos (como es el mío) donde además hay que cambiar el modo de multiplexación de los pines. Esto también resulta muy sencillo pero el saber qué hay que tocar es lo que te puede llevar horas.

Ahora podemos escribir en el sistema de ficheros mediante el prompt y por fin el servo se moverá. Pero todo esto es un rollo y sólo es práctico para hacer debug y alguna prueba. Por suerte, he desarrollado una biblioteca que ella sola se encarga de todo ese trabajo sucio para que sólo tengas de preocuparte de tu programa. La biblioteca la he subido a github, donde la acompañan algunos ejemplos y algo más de documentación técnica (tampoco mucho más).

Para continuar haz un clone a https://github.com/maxpowel/BeagleBone-Tools

Los scripts están hechos en python y necesitas instalar el paquete python-nmap (tanto debian como angstrom y ubuntu disponen de ese paquete). Ese paquete es necesario para modificar lo que te comenté antes del registro de la CPU.

Los archivos que nos interesan están en el subdirectorio servo. En ese subdirectorio encontramos el archivo servo.py que es la clase que reprsenta el servo (y la que utilizaremos), el archivo pwm.py que es el encargado de activar la modulación por pulsos y un ejempo de uso. Si tienes curiosidad echa un ojo a pwm.py para ver cómo hace eso de “activar” la modulación por pulsos.

Vamos a centrarnos en el archivo servo.py que contiene la clase que vamos a utilizar. He utilizado la misma interfaz que la clase servo de arduino. El motivo es simplemente que si sabes usar el servo en arduino también también sepas en beaglebone ya que funcionará igual (y viceversa). Entiendo que arduino está muy extendido y seguro que mucha gente que se inicia en beaglebone viene de arduino (y si no, seguro que con el tiempo te acaba interesando).

En la clase servo disponemos de los siguientes métodos:

  • attach(pin): Vinculamos el pin a nuestro objeto servo. A diferencia de arduino, aquí el pin es un string en vez de un entero. Puede ser P9_14 o P9_16 (P9 hace referencia al banco). Al hacer attatch, el configura el pin para ser usado como pwm y la frecuencia correcta.
  • write(angle): Se pasa como parámetro un ángulo entero entre 0 y 180. Es el ángulo de giro del servo. Lo valores por defecto son los que dicta el estandar pero en muchos servos varía un poco. Por ejemplo, o tengo servos que van desde 7 hasta 187 grados. Esto es debido a que el tamaño del pulso es algo diferente para determinados servos. Puedes ajustar la biblioteca a tus servos modificando las variables MIN_DUTY_NS  y MAX_DUTY_NS (duración mínima y máxima del ciclo en nanosegundos respectivamente)
  • writeMicroseconds(microseconds) Aquí puedes indicar el tamaño del pulso en microsegundos. Como la frecuencia utilizada es 50Hz el tamaño máximo es 20000 microsegundos pero recuerda que tu servo sólo funcionará con pulsos de hasta 2000 microsegundos aproximadamente. Éste método es útil para saber los límites de tu servo y ajutar luego las variables MIN_DUTY_NS y MAX_DUTY_NS
  • read Devuelve el último valor utilizado con write
  • attached Verdadero o falos en función de si el objeto está vinculado con un pin
  • detach Liberar el pin. En beaglebone no es necesario ya que no se apropia del pin pero la puse para que sea similar a arduino

 

Con todo esto ya podemos escribir nuestro programa python para manejar el servo.

Primero cargamos las bibliotecas necesarias:

import pwm #Para activar PWM
from servo import Servo

Ahora activamos PWM (recuerda que tienes que tener instalado python-nmap)

pwm.enable();

Instanciamos nuestra clase servo
servo = Servo()
Vinculamos el servo al pin, en este caso el pin 16 del banco 9
servo.attach(“P9_16”)

Así moveríamos el servo a 30 grados

servo.write(30)

Y de la siguiente manera un bucle que mueve de un lado para otro el servo todo el rato

 

while(True):
i = 0 while i <= 180:
servo.write(i)
time.sleep(0.02)
i = i + 1
while i >= 0:
servo.write(i)
time.sleep(0.02)
i = i – 1
Sé que aquí queda un poco feo, pero aquí tienes un ejemplo https://github.com/maxpowel/BeagleBone-Tools/blob/master/servo/example.py
Por cierto, si te tira el error IOError: [Errno 2] No such file or directory: '/sys/kernel/debug/omap_mux/gpmc_a2' es porque no está montado debufs.
Simplemente ejecuta "mount -t debugfs none /sys/kernel/debug" y ya de paso mete en el fstab "debugfs /sys/kernel/debug debugfs 0 0" para que se monte
automáticamente.

Y para terminar, te pongo un par de vídeos.
En este se ve cómo manejo un servo desde el beaglebone, sin más.
[youtube]w-INy__kuk8[/youtube]

En este otro, manejo el soporte de las cámaras (usa 2 para obtener imágenes en 3D)
[youtube]x4JTZ7R3rkw[/youtube]

 

 

 


You may also like...

8 Responses

  1. Alex dice:

    Buenas gran tutorial como siempre, lo que pasa es que tengo un pequeño problema no me sale ningún directorio en /sys/pwm esta totalmente vacío, he probado con la ultima de angstrom y ubuntu que esta en 3.2 y en ninguna me aparecen los directorios y otra cosa es que no me dejaba tampoco clonar el repositorio con https pero si con http una cosa rara. y por ultimo quiera saber cuales son los registros de la CPU y que valor has puesto para que te fuera el pwm ya que creo que no has comentado el registro especifico.
    Nada mas, muchas gracias por tu trabajo.
    Un saludo y nos seguiremos leyendo.

  2. Maxpowel dice:

    Buenas! Parece ser que con la última versión había un problema. No sé si lo han solucionado ya, pero haciendo un opkg upgrade se arrelga (eso sí, lleva un buen rato). El problema es cosa del kernel pero actualizando se arregla.

    Sobre el registro de CPU puedes echar un ojo a este fichero https://github.com/maxpowel/BeagleBone-Tools/blob/master/servo/pwm.py
    El registro es 0x44E000CC y se el pone el valor 0x2. Aunque también en ese fichero se cambia al modo 6 la multiplexación de los pines PWM. Si te interesa entrar más en detalle, aquí comentan bastante de ese tema https://groups.google.com/forum/#!msg/beagleboard/alKf67dwMHI/b9W2igN6Lr4J En ese enlace es de donde he sacado bastante información

  3. Cristopher dice:

    Muy interesante!!! para leer por medio del gpio como lo harias. de antemano un cordial saludo y gracias por los temas.

  4. Maxpowel dice:

    Buenas! Mi próximo post iba a tratar precisamente sobre eso. Lamentablemente mi beaglebone se ha averiado y estoy esperando a que me llegue el recambio. Tengo pensado incluirlo en la biblioteca que menciono en el post así. Si no quieres esperar, puedes echar un ojo aquí http://www.gigamegablog.com/2012/03/16/beaglebone-coding-101-buttons-and-pwm/ en la sección Digital input.
    Pero es bien sencillo, te resumo:
    Para leer del pin 3 del puerto 8 primero haces
    echo 38 > export en el directorio /sys/class/gpio
    Con ese comando activas ese pin. Ahora para leer del pin:
    cd gpio38 (se crea ese directorio justo después de haber puesto el comando anterior) y ahora haces cat value para obtener el valor. Para el caso del pin 3, lee 1 cuando no hay nada conectado, mientras que otros pines (como el 11) leen 1 cuando hay tensión en el pin. Según creo recordar, es configurable pero ahora no te se decir con seguridad. Espero que me llegue pronto el beaglebone para seguir experimentando 😀

  5. Ramon dice:

    Hola a todos, somos una empresa de diseño hardware y software interesada en los procesadores Arm y en estos momentos acabamos de diseñar una placa general para poder conectar vuestra beaglebone o vuestra raspberrypi.
    La placa consta de:
    — 8 I/O digitales gobernadas por el puerto i2c de la beaglebone. Tanto las salidas como las entradas están optoacopladas y las salidas activan relés de 220 y sus bobinas son de 24V. Las entrada están pensadas para detectar 24V.
    — Una Uart para la comunicación puerto serie RS232
    — Una entrada analogica AIN4 de la beaglebone
    — Una salida para el control Paso a Paso a través de 2 pines de salida de la beaglebone. Según el conexionado externo a la bornera se podrá controlar un motor Unipolar o Bipolar.
    — Dos salidas PWM: PWM1 y /PWM1
    Si hay alguien interesado en adquirir una placa o en información de esta, no dudes en preguntar a la siguiente direccion de correo:
    [email protected]

  6. Maycol dice:

    Muy buen aporte. Yo quiero controlar una cámara web por red, en intenet usan logic C920 y librerias para ello. Mi pregunta es si puede modificar esas librerias, tengo una camara C270.

  7. fAnDrEs dice:

    Hola primero felicitarte. Te quería preguntar eh intentado usar tu libreria para un pwm y no lo eh logrado, aparentemente es por que en debian 7.8 cambiaron esas direcciones del kernel.
    /sys/kernel/debug/omap_mux/ no existe sin mensionar el contenido de sys/class/pwm/ Podrías enviarme la imagen del debian/ubuntu/angstrom en donde se encuentre esto. Sino estoy mal en debian 7.2. O porfavor indicarme como se realiza en el kernel mas actualizado. Gracias

  1. 18 julio, 2012

    […] primero es decirte que en beaglebone tienes hasta 66 (8 de los cuales admiten PWM como vimos en el post de manejo de servos) pines digitales de entrada/salida! Digo “hasta” porque en función del modo en el que […]

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *