Raspberry Pi. Encender/Apagar LED desde PHP. Acceso directo a los puertos GPIO ultrarápido.

 

Encender / Apagar Led en PHP Acceso directo a GPIO Raspberry pi


Objetivo:  Encender y apagar un led a muy alta velocidad, SIN realizar llamadas al sistema shell_exec(). Control directo de los GPIO con puro PHP. Acceso directo a los puertos GPIO con PHP nativo.

No, tranquil@s. Este no es un tutorial más que te enseña a encender o a apagar un led y ya está. La misión de este artículo es la de enseñar a hacerlo con PHP de forma optimizada, accediendo directamente a los puertos GPIO sin utilizar shell_exec() para incrementar el rendimiento de nuestras aplicaciones, sobre todo en los las primeras raspberry pi que aparecieron, con una velocidad de proceso limitada, pero que, lejos de desaparecer, aún siguen funcionando tan bien como el primer día. 😀

Existen muchas maneras de utilizar los LEDS con los puertos GPIO en nuestra Raspberry Pi. Pero hoy os voy a mostrar una técnica que en PHP nativo y puro que es con muchísima diferencia la que consigue el tiempo de respuesta más rápido de acceso a los puertos GPIO. Lo que aquí encontraréis lo podréis aplicar a cualquier tipo de acceso GPIO, pero como ejemplo, nos centraremos en este caso típico de encender y apagar 1 led. Cuando ves la magia y el brillo del LED, quedas cautivado. Supongo que es por eso que casi todos los ejemplos enseñan lo mismo, o sea, apagar y encender un LED. Todo se reduce en ..... BRILLO Y MAGIA!!!!🌟🎩

Me gustaría añadir antes de entrar de lleno que, como todos sabemos, PHP no es uno de los lenguajes más rápidos que existen, pero sí es un lenguaje muy extenso y utilizado en servidores Web. El objetivo es aprovechar esta capacidad para optimizar su uso en estos entornos, así que el resultado que veréis al final, no tiene nada que envidiar con las velocidades conseguidas con otros lenguajes como podría ser Python (sin entrar en discusiones entre lenguajes de programación).

REQUISITOS:

- Raspberry pi (cualquier modelo con acceso a los GPIO es suficiente. Yo lo he probado con la Raspberry Pi Model B+ y funciona a la perfección).
- Targeta SD para el sistema operativo.
- Alimentador de corriente.
- Placa de pruebas.
- Cableado.
- 1 led.
- 1 resistencia.
- Cable hdmi, monitor y teclado (para la instalación).


CONOCIMIENTOS NECESARIOS PREVIOS:

- Instalación básica de sistema operativo Raspbian con PHP.
- Conexionado y uso de leds y resistencias.

No me detendré en explicar la instalación básica. Supondremos que tenéis los conocimientos básicos necesarios. Lógicamente, y bajo ningún concepto se atribuirá ninguna responsabilidad por el uso o daños del hardware con vuestra raspberry a nadie, por lo que tan solo tenéis que ir con un poco de cuidado con lo que hacéis. Toda la responsabilidad es vuestra. Aquí solo nos centraremos en explicar la manera de acceder rápidamente a los puertos GPIO con esta técnica en puro PHP.


INSTALACIÓN:

Tendréis que tener vuestra raspberry ya preparada y funcionando con:

- Raspbian (lite, por ejemplo)
- PHP
- SSH (Opcional. Yo suelo trabajar siempre así porque es muy práctico)

Solo recordar que debéis activar el acceso del hardware de los GPIO en la utilidad raspi-config para poder utilizarlos.


UN POCO DE TEORÍA. ACCESO STANDARD A LOS PUERTOS GPIO DESDE PHP.

Cuando utilizamos un servidor web con PHP para que en algún momento acceda a los puertos GPIO, como usos comunes de encender o apagar leds, lo más normal es utilizar una llamada al sistema con shell_exec().

Un ejemplo:

$setmode17 = shell_exec(“/usr/local/bin/gpio -g mode 17 out”);
$gpio_on = shell_exec("/usr/local/bin/gpio -g write 17 1");

Esto sería lo más fácil y normal.

Para todo proyecto que acceda a los puertos GPIO,  es necesario hacer un paso al principio y otro al final, que es la exportación de los puertos y la UNExportación. A partir de la exportación ya podemos configurar cada puerto para poder ser utilizado como entrada/salida, y a partir de aquí, ya se pueden utilizar las operaciones de lectura/escritura en cada puerto GPIO. Cada una de estas operaciones por separado consumen un tiempo de procesador en el momento de que el sistema PHP debe realizar llamadas de shell, por lo que los recursos que consumen estos procesos individuales se transforma en tiempo de proceso para nosotros, donde el sistema está utilizando sus recursos de memoria, procesos, hilos, sistema, etc.... en crear estas llamadas, luego está la carga y ejecución del software realizando la el proceso de encendido/apagado del LED en sí, y posteriormente liberar de nuevo los recursos empleados, en lugar de realizar y centrarse única y exclusivamente en la tarea que a nosotros realmente nos interesa (en este caso encender o apagar un LED). El motivo de tener que preparar cada llamada al sistema operativo con shell_exec() es lo que consume ese tiempo tan crucial a veces.

El sistema operativo Linux trata a todos los dispositivos de hardware como si fuesen ficheros, escribiendo y leyendo en ellos. Entonces.... ¿por qué no tratar a los puertos GPIO de igual manera??? PHP incorpora librerías nativas de acceso a ficheros. Podríamos pensar que podemos utilizar esto para acceder directamente al hardware tratando cada puerto GPIO como si fuese un fichero.

Pues sí. Se puede acceder a los puertos GPIO tratándolos como si fuesen ficheros, leyendo y escribiendo en ellos los estados de activo/inactivo, encendido/apagado, 1/0. Fácil, ¿no?

En este sentido, si podemos acceder directamente a ellos leyendo o escribiendo los estados de encendido/apagado (1 ó 0) como si fuesen ficheros, ya no tenemos por qué utilizar las llamadas a sistema operativo shell_exec() para poder acceder a ellos mediante la ejecución de  un software externo, ahorrándonos todos estos tiempos de ejecución intermedios. Ahora ya sabemos que podemos acceder directamente a los puertos GPIO y cómo hacerlo de una manera fácil, rápida y además, nada complicada, ya que es natural del sistema😀, así que... continuemos leyendo.


De la teoría a la práctica. Veamos directamente el código, y como dijo Jack el Destripador..... vayamos por partes.


EXPORT:

Antes de nada es necesario realizar un 'export' del puerto GPIO para poderlo utilizar físicamente, así que..... realizaremos un EXPORT. En nuestro caso utilizaremos el puerto GPIO 17:

$fp = fopen( '/sys/class/gpio/export', 'w' );
fwrite( $fp, '17' );
fclose( $fp );


INDICAR EL MODO DE USO DE PUERTO GPIO 17 COMO SALIDA:

Ahora nos toca indicar el modo de funcionamiento del puerto 17, para saber si va a ser de entrada o de salida. Como sería lógico, un LED recibe un pulso de salida desde el puerto GPIO. Configuraremos el número de PUERTO GPIO 17 como SALIDA:

$fp = fopen( '/sys/class/gpio/gpio17/direction', 'w' );
fwrite( $fp, 'out' );
fclose( $fp );


ENCENDER LED:

Ahora le diremos al puerto que se active para encender el LED, enviando un pulso '1' al puerto 17:

$fp = fopen( '/sys/class/gpio/gpio17/value', 'w' );
fwrite( $fp, '1' );
fclose( $fp );


ESPERAR 5 SEGUNDOS:

Si ahora lo apagáramos, no veríamos el efecto de haberlo encendido, ya que la velocidad de ejecución haría que se encendiera y apagara tan rápido que sería imperceptible para el ojo humano, entonces, para que podamos ver el efecto, esperaremos 5 segundos:

sleep( 5 );


APAGAR LED:

Ya solo nos toca decirle al puerto GPIO 17 que apague el led, así que enviamos un pulso '0' al puerto 17:

$fp = fopen( '/sys/class/gpio/gpio17/value', 'w' );
fwrite( $fp, '0' );
fclose( $fp );


UNEXPORT:

Y ya para finalizar lo que haremos será realizar un UNEXPORT del puerto GPIO 17 para liberarlo:

$fp = fopen( '/sys/class/gpio/unexport', 'w' );
fwrite( $fp, '17' );
fclose( $fp );


Este sería el código final para que lo podáis probar:

<?php

// EXPORT

$fp = fopen('/sys/class/gpio/export', 'w');
fwrite ( $fp, '17');
fclose( $fp );


// SET GPIO17 => OUT

$fp = fopen( '/sys/class/gpio/gpio17/direction', 'w' );
fwrite ( $fp, 'out' );
fclose( $fp );


// TURN LED ON

$fp = fopen( '/sys/class/gpio/gpio17/value', 'w' );
fwrite ( $fp, '1' );
fclose( $fp );


// WAIT 5 SECONDS

sleep(5);


// TURN LED OFF

$fp = fopen( '/sys/class/gpio/gpio17/value', 'w' );
fwrite( $fp, '0' );
fclose( $fp );


// UNEXPORT

$fp = fopen( '/sys/class/gpio/unexport', 'w' );
fwrite( $fp, '17');
fclose( $fp );

?>


Y ya está.... este sería nuestro código de acceso directo a los GPIO super mega ultra extra rápido con PHP puro. Total, ¿solo para encender un LED, esperar 5 segundos para luego apagarlo.... ? ¿y para qué necesitamos tanta velocidad para hacer esto? Bueno, realmente aquí no se aprecia. Esto es un ejemplo de uso. Miraré de preparar algún Benchmark para que podáis ver las diferencias.

Veréis que el código es muy sencillo, pero todo y así se podría optimizar. Si os habéis fijado, tanto para encender el LED como para apagarlo, hemos abierto el fichero del led , escrito el valor y cerrarlo. No haría falta abrirlo y cerrarlo cada vez que deseamos escribir un valor. Bastaría con abrirlo al principio de nuestra aplicación, encender y apagar las veces que necesitemos y cerrarlo al final. El código optimizado quedaría así:

<?php

// EXPORT

$fp = fopen( '/sys/class/gpio/export', 'w' );
fwrite( $fp, '17');
fclose( $fp );


// SET GPIO17 => OUT

$fp = fopen( '/sys/class/gpio/gpio17/direction', 'w' );
fwrite( $fp, 'out' );
fclose( $fp );


// OPEN FILE HANDLE FOR WRITE LED

$fpWriteLed17 = fopen( '/sys/class/gpio/gpio17/value', 'w' );


// TURN LED ON

fwrite( $fpWriteLed17, '1' );


// WAIT 5 SECONDS

sleep( 5 );


// TURN LED OFF

fwrite( $fpWriteLed17, '0' );


// CLOSE FILE HANDLE FOR WRITE LED

fclose( $fpWriteLed17 );


// UNEXPORT

$fp = fopen( '/sys/class/gpio/unexport', 'w' );
fwrite( $fp, '17');
fclose( $fp );

?>

En este artículo que os he preparado, os explico cómo crear una clase orientada a objetos en PHP para poder acceder a los puertos GPIO, especializada en los LEDS y de una manera más organizada, optimizando también el uso de las llamadas de esta misma clase en el momento de abrir y cerrar ficheros como hemos aprendido en este tutorial.

Como nota final: Si utilizáis el servidor web, es posible que tengáis que dar permisos al usuario web para acceder a los GPIO. Googlear un poco, pero os dejo alguna pista que os ahorrará tiempo:

sudo adduser www-data i2c
sudo adduser www-data spi
sudo adduser www-data gpio

Foto: Wikipedia & Openclipart

Comentarios

Artículos más populares

Clase en PHP para encender/apagar LED en Raspberry pi

Ja es poden veure els programes de 'REDES' de TVE2 per internet