Sunteți pe pagina 1din 18

http://www.hackplayers.

com/2013/12/construye-tu-
propio-rover-teledirigido-con-rpi-webiopi.html

Construye tu propio rover teledirigido con Raspberry Pi y


WebIOPi
PUBLICADO POR VICENTE MOTOS ON MARTES, 10 DE DICIEMBRE DE

2013 ETIQUETAS: ELECTRÓNICA , GADGETS , HARDWARE ,PROGRAMACIÓN , RASPBERRY PI , TUTORIALES

Para aprender cómo funciona la GPIO (General-purpose


input/output) de Raspberry Pi he montado un pequeño rover
motorizado que captura vídeo en tiempo real mediante una cámara USB
y que puede ser controlado remotamente.

Quiero advertir que ya existen trabajos similares


y productos prefabricados mejor acabados y seguramente con mayor
rendimiento, pero si te interesara diseñar y hacer funcionar tu propio
robot casero entonces te invito a que sigas leyendo :D

Eligiendo el hardware y conectando todo

La base es un viejo coche de control remoto por radiofrecuencia que


compré hace años en un bazar chino. Sobre éste gira el proyecto: dos
motores de corriente continua (DC) moviendo dos ejes para las ruedas
de marcha adelante/atrás y dirección derecha/ izquierda:
Para mover los motores necesitamos un controlador H-Bridge o
puente en H que no es más que un circuito electrónico que permite
aplicar un voltaje a través de una carga en cualquier dirección, es decir,
invertir la polaridad a nuestra elección para mover el motor en una
dirección u otra. Además estos puentes en H permiten cortocircuitar
para frenar en seco el motor o desconectar hasta su detención libre
(free-run).

En este caso he elegido el módulo L298N, un controlador dual H-


Bridge bastante popular y económico (4,35€) pero lo suficientemente
potente como para impulsar motores de 5 a 35V y de hasta 2A.

Además proporciona un regulador de 5V integrado que puede ser


utilizado para alimentar otras partes de la circuitería del robot:
En la base del coche de control remoto encastamos los dos módulos.

La Raspberry Pi es alimentada a través del conector micro USB con


una batería SWPKPOWER SW-A22617 (6,20€) que ofrece una salida
de 5V/800mA y una capacidad de 2600mAh y el controlador L298N
recibe el suministro eléctrico mediante una pila de petaca Duracell de
9V alcalina (2,55€) con 565 mAh conectada al pin VCC y a GND.
También es necesario conectar el pin 6 de la RPi a tierra.

Después conectamos los motores del coche a los pines de las salidas
correspondientes: Motor A o izquierdo y Motor B o derecho e
interconectamos los pines IN1, 2, 3 y 4 a las salidas digitales de la GPIO
de la RPi (17, 27 y 10, 9 respectivamente).

El siguiente paso es puentear con jumpers los pines ENA y ENB a 5V


para activar cada uno de los canales.

Una opción interesante sería no usar los jumpers y conectar 2 pines de


la GPIO de la Raspberry Pi a los pines ENA y ENB del controlador y
configurarlos como PWM (modulación por ancho de pulsos) para regular
el consumo y la velocidad de los motores. Si bien lo he descartado en
este proyecto porque con los motores actuales al disminuir la cantidad
de energía apenas podían arrancar y llevar la carga (mover el robot).

El esquema físico queda entonces de la siguiente manera:


Fijaros también que aprovecharemos los dos puertos USB para conectar
un nano adaptador inalámbrico modelo RaLink RT5370 (6,75€)
mediante el cual controlaremos nuestro rover y una webcam de 1,3M
con micrófono integrado (6,20€) para el stream de video.

Si sumamos cables y la carcasa para la pila de petaca, el coste total


aproximado del hardware utilizado ronda los 80€. El resultado final es
este:

Configurando la red inalámbrica de nuestro


robot
Damos un giro a la parte del software. El sistema operativo de la
Raspberry Pi para este proyecto es Raspbian con un kernel 3.6:

pi@escorial ~ $ uname -a
Linux escorial 3.6.11+ #538 PREEMPT Fri Aug 30 20:42:08 BST 2013 armv6l
GNU/Linux

Lo primero que vamos a hacer es configurar la red inalámbrica para


poder controlar nuestro rover remotamente por ssh. Para ello
conectamos el dongle USB y comprobamos que se detecta
correctamente:

pi@escorial ~ $ lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 148f:5370 Ralink Technology, Corp. RT5370 Wireless
Adapter

[root@escorial ~]# lsusb -vs 001:004

Ahora, para conectarnos a nuestra red WiFi, tenemos que editar el


fichero wpa_supplicant.conf y configurar el SSID con la clave
compartida correspondiente:

pi@escorial ~ $ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf


ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
ssid="WLAN_AB"
psk="****************"
}

Después paramos el interfaz inalámbrico y volvemos a levantarlo para


recargar la configuración:

pi@escorial ~ $ sudo wpa_action wlan0 stop


wpa_action: ifdown wlan0
Configuring interface wlan0=wlan0 (inet)
run-parts --verbose /etc/network/if-down.d
run-parts: executing /etc/network/if-down.d/upstart
run-parts: executing /etc/network/if-down.d/wpasupplicant
run-parts --verbose /etc/network/if-post-down.d
run-parts: executing /etc/network/if-post-down.d/wireless-tools
run-parts: executing /etc/network/if-post-down.d/wpasupplicant
wpa_supplicant: terminating wpa_supplicant daemon via pidfile
/var/run/wpa_supplicant.wlan0.pid
Stopped /sbin/wpa_supplicant (pid 1755).
wpa_supplicant: removing
/run/sendsigs.omit.d/wpasupplicant.wpa_supplicant.wlan0.pid
wpa_action: removing sendsigs omission pidfile:
/run/sendsigs.omit.d/wpasupplicant.wpa_supplicant.wlan0.pid
pi@escorial ~ $ sudo ifup wlan0

A continuación comprobamos la conectividad:

pi@escorial ~ $ sudo wpa_cli status


Selected interface 'wlan0'
bssid=d0:71:33:21:d3:c6
ssid=WLAN_AB
id=0
mode=station
pairwise_cipher=CCMP
group_cipher=CCMP
key_mgmt=WPA2-PSK
wpa_state=COMPLETED
ip_address=192.168.1.39
address=7c:de:70:42:6f:38
do

Preparando el streaming de video

Para el streaming de vídeo con la webcam USB utilizamos MJPG-


streamer, una aplicación que captura JPG de webcams compatibles con
Linux-UVC, sistema de archivos u otros plugins de entrada y los
distribuye como M-JPEG a través de HTTP para navegadores web, VLC y
otros programas. Es el sucesor de uvc-streamer, una aplicación de
streaming de Linux-UVC con Pan/Tilt.

La instalación sólo requiere unos sencillos pasos:

apt-get install libjpeg8-dev imagemagick subversion


cd /usr/src/
svn checkout svn://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer-
code
cd mjpg-streamer/mjpg-streamer
make

Para probarlo ejecutamos el siguiente comando:

pi@escorial /usr/src/mjpg-streamer-code/mjpg-streamer $ sudo


./mjpg_streamer -i "./input_uvc.so -y -n " -o "./output_http.so -n -w
./www"
MJPG Streamer Version: svn rev: 3:172
i: Using V4L2 device.: /dev/video0
i: Desired Resolution: 640 x 480
i: Frames Per Second.: 5
i: Format............: YUV
i: JPEG Quality......: 80
o: www-folder-path...: ./www/
o: HTTP TCP port.....: 8080
o: username:password.: disabled
o: commands..........: disabled

Ahora configuramos un pequeño script para cuando queramos lanzar el


stream de video en background:

#!/bin/sh

PLUGINPATH=/usr/src/mjpg-streamer-code/mjpg-streamer
STREAMER=$PLUGINPATH/mjpg_streamer
DEVICE=/dev/video0
RESOLUTION=320x240
FRAMERATE=25
HTTP_PORT=8001

# check for existing webcam device


if [ ! -e "/dev/video0" ]; then
echo "stream.sh: Error - NO /dev/video0 device" 2>&1 | logger
exit 2
fi

#PLUGINPATH=/usr/local/lib

$STREAMER -i "$PLUGINPATH/input_uvc.so -y -n -d $DEVICE -r $RESOLUTION -f


$FRAMERATE" -o "$PLUGINPATH/output_http.so -n -p $HTTP_PORT" -b

Controlando la GPIO de Raspberry Pi con


WebIOPI
Webiopi es un API escrita en Python para controlar, depurar y utilizar la
GPIO de la RPi localmente o de forma remota, desde un navegador o
desde cualquier aplicación.

La utilizaremos porque nos permite ejecutar el proyecto muy


rápidamente sin necesidad de tener demasiados conocimientos.

Su licencia es Apache License 2.0 y sus características son:

- API REST a través de HTTP y COAP (draft-14) con soporte multicast


- Servidor escrito en Python con cero dependencias
- Soporta GPIO, Serial, I2C, SPI, 1-Wire con cero dependencias
- Soporta más de 30 dispositivos, incluyendo DAC, ADC, sensores ...
- Completa biblioteca de Python para el servidor, GPIO, I2C, SPI,
conductores y dispositivos de serie
- Compatible con Python 2 y 3
- Extensible y altamente personalizable
- Incluye protección de Usuario / clave
- Compatible con dispositivos móviles
- Incluye las aplicaciones web de depuración
. GPIO Header
. Lista GPIO
. Monitor Serial
. Monitor Dispositivos
- Biblioteca cliente Javascript construida sobre jQuery
- Biblioteca cliente Python con HTTP y soporte CoAP

Para instalarlo sólo necesitaremos Python, ya sea la versión 2.7 o la 3.2.


Simplemente hay que descargar y extraer el paquete. El script de
instalación se encargará automáticamente de descargar e instalar las
dependencias requeridas usando apt-get.
Si no utilizas Raspbian es posible que tengas que instalar los
encabezados de desarrollo de GCC y Python.

$ wget http://webiopi.googlecode.com/files/WebIOPi-0.6.0.tar.gz
$ tar xvzf WebIOPi-0.6.0.tar.gz
$ cd WebIOPi-0.6.0
$ sudo ./setup.sh

Ahora podemos llamar a webiopi directamente desde la línea de


comandos:

$ sudo webiopi [-h] [-c config] [-l log] [-s script] [-d] [port]

Options:
-h, --help Display this help
-c, --config file Load config from file
-l, --log file Log to file
-s, --script file Load script from file
-d, --debug Enable DEBUG

Arguments:
port Port to bind the HTTP Server

Sin embargo perderemos el servidor y el estado de la GPIO tan pronto


como paremos el script (CTRL-C) o cerremos el terminal.

Por ello es necesario iniciar el servicio en background mediante:

$ sudo /etc/init.d/webiopi start


y
$ sudo /etc/init.d/webiopi stop

Si queremos que webiopi se inicie automáticamente cuando arranque de


la RPi podemos utilizar el siguiente comando:

$ sudo update-rc.d webiopi defaults

La base del código fuente se basa en dos artículos publicados en


la revista MagPI (Cambot). Primero modificaremos su script en
Python en /home/pi/cambot/cambot.py en el que definiremos el estado
inicial de los pines de la GPIO y las macros que podrán ser llamadas
externamente:

#imports
import webiopi

# Libreria GPIO
GPIO = webiopi.GPIO

# -------------------------------------------------- #
# Definicion constantes #
# -------------------------------------------------- #

# GPIOs motor izquierdo


L1=17 # H-Bridge 1
L2=27 # H-Bridge 2

# GPIOs motor derecho


R1=10 # H-Bridge 3
R2=9 # H-Bridge 4

# -------------------------------------------------- #
# Funciones motor izquierdo #
# -------------------------------------------------- #

def left_stop():
GPIO.output(L1, GPIO.LOW)
GPIO.output(L2, GPIO.LOW)

def left_forward():
GPIO.output(L1, GPIO.HIGH)
GPIO.output(L2, GPIO.LOW)

def left_backward():
GPIO.output(L1, GPIO.LOW)
GPIO.output(L2, GPIO.HIGH)

# -------------------------------------------------- #
# Funciones motor derecho #
# -------------------------------------------------- #

def right_stop():
GPIO.output(R1, GPIO.LOW)
GPIO.output(R2, GPIO.LOW)

def right_forward():
GPIO.output(R1, GPIO.HIGH)
GPIO.output(R2, GPIO.LOW)

def right_backward():
GPIO.output(R1, GPIO.LOW)
GPIO.output(R2, GPIO.HIGH)

# -------------------------------------------------- #
# Definicion macros #
# -------------------------------------------------- #
@webiopi.macro
def go_forward():
left_forward()

@webiopi.macro
def go_backward():
left_backward()

@webiopi.macro
def turn_left():
right_forward()

@webiopi.macro
def turn_right():
right_backward()

@webiopi.macro
def stop():
left_stop()
right_stop()

# -------------------------------------------------- #
# Iniciacializacion #
# -------------------------------------------------- #

def setup():
# Instalacion GPIOs
GPIO.setFunction(L1, GPIO.OUT)
GPIO.setFunction(L2, GPIO.OUT)

GPIO.setFunction(R1, GPIO.OUT)
GPIO.setFunction(R2, GPIO.OUT)

def destroy():
# Resetea las funciones GPIO
GPIO.setFunction(L1, GPIO.IN)
GPIO.setFunction(L2, GPIO.IN)

GPIO.setFunction(R1, GPIO.IN)
GPIO.setFunction(R2, GPIO.IN)

Como podéis ver en el código la configuración es sumamente sencilla.


Se inicializan en OUT un par de pines para controlar cada motor y
simplemente cambiando su estado (HIGH o LOW) es posible definir
macros para cada movimiento.

Para que este script sea llamado al iniciar el servidor webiopi tendremos
que especificarlo en el fichero de configuración /etc/webiopi/config.
Para ello vamos al fichero config y especificamos la ruta en la sección de
scripts:

[SCRIPTS]
# Load custom scripts syntax :
# name = sourcefile
# each sourcefile may have setup, loop and destroy functions and macros
#myscript = /home/pi/webiopi/examples/scripts/macros/script.py
cambot = /home/pi/cambot/cambot.py

Y aprovechando en este mismo fichero revisaremos el document root y


el fichero index e indicaremos que se utilicen las credenciales del fichero
passwd:

[HTTP]
# HTTP Server configuration
enabled = true
port = 8000

# File containing sha256(base64("user:password"))


# Use webiopi-passwd command to generate it
passwd-file = /etc/webiopi/passwd

# Use doc-root to change default HTML and resource files location


#doc-root = /home/pi/webiopi/examples/scripts/macros
doc-root = /home/pi/cambot

# Use welcome-file to change the default "Welcome" file


welcome-file = index.html

Para ello posteriormente generaremos el fichero passwd mediante el


comando webiopi-passwd:

$ sudo webiopi-passwd
WebIOPi passwd file generator
Enter Login: webiopi
Enter Password:
Confirm password:

Hash: e70c940a189251e9cd4515b3a1a6c6f02aa05c744a456ce360fe14bf2c5c0353
Saved to /etc/webiopi/passwd

Una buena idea teniendo en cuenta que de esta manera no


almacenaremos en claro la contraseña de acceso…
Finalmente creamos el fichero index.html en el document root
especificado con los controles correspondientes usando jQuery y todas
las funciones de javascript para a llamar a las macros escritas en
Python. Fijaros que también incrustaremos (IMG) el streaming de video:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"


"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content = "height = device-height, width = 420,
user-scalable = no" />
<title>CamBot</title>
<script type="text/javascript" src="/webiopi.js"></script>
<script type="text/javascript">
function init() {
var button;

button = webiopi().createButton("bt_up", "/\\", go_forward,


stop);
$("#up").append(button);

button = webiopi().createButton("bt_left", "<", turn_left, stop);


$("#middle").append(button);

button = webiopi().createButton("bt_stop", "X", stop);


$("#middle").append(button);

button = webiopi().createButton("bt_right", ">", turn_right,


stop);
$("#middle").append(button);

button = webiopi().createButton("bt_down", "\\/", go_backward,


stop);
$("#down").append(button);
}

function go_forward() {
webiopi().callMacro("go_forward");
}

function go_backward() {
webiopi().callMacro("go_backward");
}

function turn_right() {
webiopi().callMacro("turn_right");
}

function turn_left() {
webiopi().callMacro("turn_left");
}
function stop() {
webiopi().callMacro("stop");
}

webiopi().ready(init);

</script>
<style type="text/css">
button {
margin: 5px 5px 5px 5px;
width: 50px;
height: 50px;
font-size: 24pt;
font-weight: bold;
color: black;
}
</style>
</head>
<body>
<div id="content" align="center">
<img width="320" height="240"
src="http://192.168.1.37:8001/?action=stream"><br/>
<div id="up"></div>
<div id="middle"></div>
<div id="down"></div>
</div>
</body>
</html>

Y ya está. Sólo nos queda reiniciar el servidor webiopi para cargar la


nueva configuración:

$ sudo /etc/init.d/webiopi restart

¡A jugar!

Antes de empezar os animo a ver la aplicación GPIO Header que permite


visualizar y controlar cada uno de los pines de la RPi. Para ello abrimos
en el navegador la URL:

http://raspberry:8000/app/gpio-header
Como podéis comprobar es posible cambiar el estado de cada pin sólo
mediante un clic.

Ahora abriremos la url principal de nuestro frontal web:

http://raspberry:8000/
Y bueno, aquí os dejo un breve vídeo con el resultado:

Carencias, mejoras y próximos pasos

Como comentaba al principio quien decida basarse en esta entrada o


similares para crear un rover de estas características tendrá que tener
como objetivo principal el aprendizaje y no un rendimiento demasiado
excelso.

Primero, las limitaciones de la webcam y del interfaz USB mediante el


cual se conecta a la RPi harán que el streaming de vídeo denote un
retardo que degradará en parte la experiencia del usuario. Si se quiere
mejorar en este aspecto se tendría que pensar en la compra de
la cámara por hardware que se conecta internamente y directa al
procesador sin hacer uso de ningún chipset intermedio, utilizando el
interfaz CSi dedicado que trae de serie. Con esto se mejorará
ostensiblemente la tasa de fps (imágenes por segundo).

A parte del streaming de vídeo también se podría añadir al frontal web


un botón para realizar una instantánea (a mayor resolución) y una
opción para respaldar estas capturas (video y fotos) a algún servicio de
almacenamiento en la nube tipo Dropbox.

Segundo, los motores del coche de radiocontrol reciclados son algo


"vagos" y en cuanto la capacidad de las baterías disminuye sufren para
mover la carga.
En este caso también podrían sustituirse y se podría modular por pulsos
para controlar la velocidad del giro.
Si os dais cuenta en la protoboard delantera he realizado algunas
conexiones para poner en serie la pila de 9V con las tres pilas AA (4,5V)
que originalmente tenía el coche para ganar algo de potencia.

Por último, aunque eso ya será en otras entradas, tengo pendiente


añadir más funcionalidades mediante sensores de ultrasonidos,
detección de movimiento, leds, laser y reconocimiento por voz.

S-ar putea să vă placă și