En este proyecto de desarrollo se elaborará un carro “espía” con el cual se podrá navegar mientras se tiene una imagen en vivo del lugar por el cual se está trasladando el carro. Este carro de podrá mover en cualquier dirección debido las llantas omnidireccionales que este posee. El mismo se podrá controlar inalámbricamente con la computadora mediante conexión WI Fi y un Joystick que estará conectado a la computadora; el cual nos permitirá el control de una manera más fácil y dinámica. El objetivo de este será por ejemplo para ver partes de tu casa sin tener que levantarte de la cama o sillón, para recorrer lugares donde no podrías accesar fácilmente, o ser usado como vigilante de tu casa .
Lo primero que se debe hacer es instalar Raspbian en una tarjeta SD de al menos 4 GB, esto se puede hacer siguiendo los pasos del siguiente link
http://www.linuxito.com.ar/gnu-linux/nivel-medio/241-como-instalar-raspbian-en-raspberry-pi
En la parte de habilitar directamente el escritorio LXDE desde el menú “Enable Boot to Desktop”, lo mejor es ignorarla, asi cuando reinicias el Pi caes en la consola, haces LogIn y ejecutas “Startx”, lo cual te enviará al escritorio, esto es porque dependiendo de la versión de Rapsbian que descargues, al entrar a esa opcion aparecen cosas q no se mencionan es este tutorial.
Uno de los problemas mas frecuentes al trabajar con el Pi es que no tiene pantalla, por lo que hay que buscar una pantalla o TV con entrada HDMI para conectarlo, o buscar convertidores de HDMI para las diferentes entradas de los monitores de computadora usuales. Esto es muy sencillo de solucionar si usamos SSH
Para Windows seguir los pasos de este tutorial
http://www.youtube.com/watch?v=RFqLIBSxFqE
Para Debian solo debes conectarlo a un monitor, para averiguar si IP, y teniendo la computadora que vas a usar conectada al mismo enrutador a la que esta conectado el Pi, teniendo esto te vas a la consola de debia y ejecutas
ssh -x user@IPdelPi
WiringPi es una biblioteca de acceso GPIO para el BCM2835 escrito en C utilizado en el Raspberry Pi. Está liberado bajo la licencia GNU LGPLv3 y se puede utilizar desde C y C + + y otros lenguajes adecuados (Ver más abajo). Está diseñado para que le sea familiar a las personas que han utilizado el Arduino. WiringPi incluye una utilidad de línea de comandos GPIO que se puede utilizar para programar y configurar los pines GPIO. Usted puede utilizar esto para leer y escribir los pines e incluso utilizarlo para controlarlos desde “shell scripts”.
WiringPi es extensible y se proporcionan módulos para extender wiringPi el uso de dispositivos de interfaz analógica en la Gertboard, y para utilizar los chips populares MCP23x17/MCP23x08 (7 I2C SPI) GPIO de expansión, así como del módulo que permitirá bloques de hasta 4 × 74 595 registros de desplazamiento para ser conectados en serie por un valor de 32 bits adicionales de la producción como una sola unidad. (Puede tener varios bloques de 4 74x595s si es necesario) Uno de los módulos de extensión le permite utilizar un ATmega (por ejemplo Arduino o el Gertboard) como una mayor expansión GPIO también a través del puerto serie del Pi. Adicionalmente, usted puede escribir sus propios módulos de expansión para integrar sus propios dispositivos periféricos con wiringPi según sea necesario. WiringPi soporta lectura analógica y la escritura, y si bien no hay hardware analógico nativo en un Pi de forma predeterminada, se proporcionan módulos para apoyar los Gertboards chips analógicos y otros A / D y D / A dispositivos pueden aplicarse con relativa facilidad.
WiringPi se mantiene bajo GIT para facilitar el seguimiento de cambios . Si usted no tiene instalado GIT, a continuación, en cualquiera de las versiones de Debian (por ejemplo Raspbian), puede instalarlo con:
sudo apt-get install git-core
Si tienes cualquier error aquí, asegúrese de que su Pi está al día con las últimas versiones de Raspbian:
sudo apt-get update sudo apt-get upgrade
Para obtener WirinPi usando GIT:
git clone git://git.drogon.net/wiringPi
Si esta utilizado la operación de clonación, por primera vez, a continuación,
cd wiringPi git pull origin
Con esto obtendrá una versión actualizada, entonces usted puede volver a ejecutar el script de compilación a continuación.
Para compilar/instalar hay una nueva secuencia de comandos simplificado:
cd wiringPi ./build
El nuevo script build compilará e instalará todo por tí. Si utiliza el comando sudo en un momento dado, lomejor es revisar el guión antes de ejecutarlo.
El STM32 es una familia de circuitos integrados basados en microcontroladores de 32 bits con núcleos RISC ARM Cortex-M4F, Cortex-M3 y Cortex-M0 de STMicroelectronics y el procesador ARM IP de ARM Holdings. Los diseños de núcleo ARM tienen numerosas opciones configurables, y ST elige la configuración individual de uso para cada diseño. ST concede sus propios periféricos al núcleo antes de convertir el diseño en una pastilla de silicio.
El STM32 serie F4 es el primer grupo de microcontroladores STM32 basado en el núcleo ARM Cortex-M4F. El F4 es también la primera serie STM32 en tener DSP y las instrucciones de coma flotante. La F4 es pin a pin compatible con el F2 de la serie STM32 y añade una mayor velocidad de reloj, 64K CCM RAM estática, full duplex I ² S, mejorado en tiempo real, y ADCs más rápido.
Necesitamos añadir la arquitectura i386
dpkg --add-architecture i386
haga un apt-get update
Ahora obtenga las dependencias
apt-get install libncurses5 apt-get install libncurses5:i386
Descargue el último tarball de instalación de Herramientas de GNU para procesadores embebidos ARM y descomprimir:
cd ~/local/src wget https://launchpad.net/gcc-arm-embedded/4.7/4.7-2013-q1-update/+download/gcc-arm-none-eabi-4_7-2013q1-20130313-linux.tar.bz2 tar -xjf gcc-arm-none-eabi-4_7-2013q1-20130313-linux.tar.bz2
Hacer que los ejecutables de herramientas a disposición de los usuarios, agregue el directorio bin a la PATH variable:
echo 'export PATH=$PATH:/home/****user****/local/src/gcc-arm-none-eabi-4_7-2013q1/bin/' >> /home/****user****/.bashrc
Recordemos que para recargar el archivo .bashrc tenemos 2 opciones:
. .bashrc
Instale openocd
sudo apt-get install openocd
Primero debemos tener instalado python-yaml , si no esta instalado hacemos
sudo apt-get install python-yaml
Luego creamos la librería
cd ~/local/src/ git clone https://github.com/libopencm3/libopencm3-examples cd libopencm3-examples git submodule init git submodule update cd libopencm3 make
Primero necesitamos tener instalado el paquete: libusb-1.0
Ahora ingresamos a la carpeta
cd ~/local/src/
Se descarga con git
git clone https://github.com/texane/stlink
Ingresamos a la carpeta
cd stlink
Ejecutamos el programa (para que funcione debe tener el paquete pkg-config)
./autogen.sh
Configuramos
./configure --prefix=/home/**user**/local/DIR/stlink
Copiamos y compilamos
make make install cd cd local/DIR xstow stlink
Ahora necesitamos copiar las siguientes reglas (tenemos que estar ubicados en /local/src/stlink),
sudo cp 49-stlinkv1.rules /etc/udev/rules.d/ sudo cp 49-stlinkv2.rules /etc/udev/rules.d/ sudo /etc/init.d/udev restart
Ahora antes de Flashear el STM realizamos los siguiente:
Nos vamos a la dirección local/src/libopencm3-examples/examples/stm32/f4 y aqui editamos el archivo Makefile.include
ifeq ($(BMP_PORT),) ifeq ($(OOCD_SERIAL),) %.flash: %.hex @printf " FLASH $<\n" @# IMPORTANT: Don't use "resume", only "reset" will work correctly! $(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \ -f board/$(OOCD_BOARD).cfg \ -c "init" -c "reset init" \ **-c "stm32x mass_erase 0" \** -c "flash write_image $(*).hex" \ -c "reset" \ -c "shutdown" $(NULL) else
Y en la primera parte donde veamos el texto antesrior borramos la parte señalada entre asteriscos y luego guardamos
Luego dentro de la carpeta de cada unos de los diferentes ejemplos hay un archivo Makefile al cual le tenemos que agregar las siguientes lineas antes de la ultima linea de código
OOCD_INTERFACE=stlink-v2 OOCD_BOARD=stm32f4discovery
Hacemos un mass erase con el STM conectado
st-flash erase
Ahora si podemos proceder a Flashear alguno de los ejemplos, desde dentro de alguno de los ejemplos y con el stm conectado hacemos
make make flash
O para ver en consola lo que sucede hacemos
make V=1 flash
Y verás los Leds del STM encenderse según el ejemplo que hallas escogido
Para generar el PWM que se enviará a los puentes H, se utilizó como base un ejemplo llamado src1 que se encuentra en la página
https://github.com/arcoslab/open-coroco
Este repositorio debemos descargarlo a la computadora, por lo que hacemos
cd /local/src git clone https://github.com/arcoslab/open-coroco
A este se le realizaron algunos cambios y se adaptó para el proyecto que se estaba realizando, a continuación se mostrarán algunas de las partes más importantes del código utilizado:
void tim1_init(void) {
/* Enable TIM1 clock. and Port E clock (for outputs) */ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_TIM1EN); rcc_peripheral_enable_clock(&RCC_AHB1ENR, RCC_AHB1ENR_IOPEEN); //Set TIM1 channel (and complementary) output to alternate function push-pull'. gpio_mode_setup(GPIOE, GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO9 | GPIO11 | GPIO13); gpio_set_af(GPIOE, GPIO_AF1, GPIO9 | GPIO11 | GPIO13); gpio_mode_setup(GPIOE, GPIO_MODE_AF,GPIO_PUPD_NONE,GPIO8 | GPIO10 | GPIO12); gpio_set_af(GPIOE, GPIO_AF1, GPIO8 | GPIO10 | GPIO12);
Con este código lo que se hace es inicializar los pines correspondientes al reloj del TIM1 y a los canales a utilizar, en este caso se activaron los 3 canales y su respectiva negación. Aquí también se le designa la función alternativa que se quiere que realicen los pines seleccionados, que en este caso es la de timers.
/* Disable outputs. */
timer_disable_oc_output(TIM1, TIM_OC1); timer_disable_oc_output(TIM1, TIM_OC1N); timer_disable_oc_output(TIM1, TIM_OC2); timer_disable_oc_output(TIM1, TIM_OC2N); timer_disable_oc_output(TIM1, TIM_OC3); timer_disable_oc_output(TIM1, TIM_OC3N); /* -- OC1 and OC1N configuration -- */ /* Configure global mode of line 1. */ timer_enable_oc_preload(TIM1, TIM_OC1); timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1); /* Configure OC1. */ timer_set_oc_polarity_high(TIM1, TIM_OC1); timer_set_oc_idle_state_unset(TIM1, TIM_OC1); //When idle (braked) put 0 on output /* Configure OC1N. */ timer_set_oc_polarity_high(TIM1, TIM_OC1N); timer_set_oc_idle_state_unset(TIM1, TIM_OC1N); /* Set the capture compare value for OC1. */ timer_set_oc_value(TIM1, TIM_OC1, INIT_DUTY*PWM_PERIOD_ARR);//initial_duty_cycle*pwm_period_ARR); /* -- OC2 and OC2N configuration -- */ /* Configure global mode of line 2. */ timer_enable_oc_preload(TIM1, TIM_OC2); timer_set_oc_mode(TIM1, TIM_OC2, TIM_OCM_PWM1); /* Configure OC2. */ timer_set_oc_polarity_high(TIM1, TIM_OC2); timer_set_oc_idle_state_unset(TIM1, TIM_OC2); /* Configure OC2N. */ timer_set_oc_polarity_high(TIM1, TIM_OC2N); timer_set_oc_idle_state_unset(TIM1, TIM_OC2N); /* Set the capture compare value for OC2. */ timer_set_oc_value(TIM1, TIM_OC2, INIT_DUTY*PWM_PERIOD_ARR);//initial_duty_cycle*pwm_period_ARR); /* -- OC3 and OC3N configuration -- */ /* Configure global mode of line 3. */ timer_enable_oc_preload(TIM1, TIM_OC3); timer_set_oc_mode(TIM1, TIM_OC3, TIM_OCM_PWM1); /* Configure OC3. */ timer_set_oc_polarity_high(TIM1, TIM_OC3); timer_set_oc_idle_state_unset(TIM1, TIM_OC3); /* Configure OC3N. */ timer_set_oc_polarity_high(TIM1, TIM_OC3N); timer_set_oc_idle_state_unset(TIM1, TIM_OC3N); /* Set the capture compare value for OC3. */ timer_set_oc_value(TIM1, TIM_OC3,INIT_DUTY*PWM_PERIOD_ARR);//initial_duty_cycle*pwm_period_ARR);//100); /* Reenable outputs. */ timer_enable_oc_output(TIM1, TIM_OC1); timer_enable_oc_output(TIM1, TIM_OC1N); timer_enable_oc_output(TIM1, TIM_OC2); timer_enable_oc_output(TIM1, TIM_OC2N); timer_enable_oc_output(TIM1, TIM_OC3); timer_enable_oc_output(TIM1, TIM_OC3N);
Este pedazo de código lo que hace es configurar las salidas de los canales del TIM1 y sus respectivas salidas negadas las cuales son llamadas como OC1 ó OC1N según corresponda el canal. cabe destacar que para el funcionamiento del TIM8 se realizó algo muy parecido, lo que cambian son los pines a utilizar y algunas funciones que son diferentes para el TIM8 respecto al TIM1, como por ejemplo la función que realiza las interrupciones. A continuación se mostrará la diferencia
void tim1_up_tim10_isr(void) { // Clear the update interrupt flag timer_clear_flag(TIM1, TIM_SR_UIF); gen_pwm(); } void tim8_up_tim13_isr(void) { // Clear the update interrupt flag timer_clear_flag(TIM8, TIM_SR_UIF); gen_pwm1(); }
Ahora les voy a mostrar el código que realiza el PWM dependiendo de las entradas que tenga
void gen_pwm(void) { duty_a=ref_freqA/10.0f; duty_b=ref_freqB/10.0f; duty_c=ref_freqC/10.0f; if (duty_a < 0.0f) { timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1); timer_disable_oc_output(TIM1,TIM_OC1); timer_enable_oc_output (TIM1, TIM_OC1N); duty_a=-duty_a; } else { timer_set_oc_mode(TIM1, TIM_OC1, TIM_OCM_PWM1); timer_enable_oc_output(TIM1, TIM_OC1 ); timer_disable_oc_output (TIM1, TIM_OC1N); }
Aquí podemos ver que si la entrada que recibe duty_a que es el valor que se le designó a una de las llantas en específico es menor que cero lo que hace es que activa la salida negada del canal correspondiente, lo que hará que el motor gire hacia atrás.esto se realiza para cada una de los canales utilizados.
Teniendo el código listo, procedemos a guardarlo en una carpeta dentro de la carpeta de open-coroco, luego de esto podemos copiar del ejemplo antes mencionado (src1) el archivo Makefile y el Makefile.include. Al Make hay que realizarle un cambio importante; lo que hacemos es que abrimos el documento y veremos algo como esto
BINARY = "nombre de su archivo .c" OBJS := LDSCRIPT = ../libopencm3-plus/lib/libopencm3_plus_stm32f4discovery.ld OOCD_INTERFACE = stlink-v2 OOCD_BOARD = stm32f4discovery include Makefile.include
Y lo que hacemos es que donde dice “BINARY=” colocamos el nombre de nuestro archivo.c
Cuando hacemos en make en la carpeta de nuestro código veremos que nos da unos “warnings” de que las funciones utilizadas no están previamente definidas, esto se debe a que hace falta un archivo con el nombre de nuestro archivo.c, pero con la extención .h ; este archivo lo que contiene es las funciones creadas por nosotros en el archivo.c, deberá contener algo similar a esto
void tim8_init(void); void tim1_init(void); void gen_pwm(void);
Y aqui debe estar cualquier otra función que hallamos creado. Luego de tener todo esto prodecemos a flashear nuestro STM32 como se explicó anterirmente.
Estas salidas de PWM serán enviadas a los puentes H. Para este proyecto se utilizó el puente H L298n, que es un integrado que posee 2 puentes H. La conexión que se realizó la podemos ver en la hoja del fabricante que se puede encontrar en el siguiente link
https://www.sparkfun.com/datasheets/Robotics/L298_H_Bridge.pdf
Las llantas omnidireccionales basan su movimiento en las siguientes ecuaciones
A continuación vamos a ver que significa cada una de ellas
Cada uno de los datos los vamos a leer de los Joysticks, estos rigen sus movimientos dentro de un círculo unitario, estos datos las vamos a obtener mediante coordenadas polares, tomando en cuenta que los joysticks lo que nos da es una lectura de “x” y “y”, hacemos
* Vd = sqtr(x²+y²) * Ø = atan2(x+y)
Sabiendo esto lo que ahora necesitamos es es leer los datos del joystick, esto lo hacemos mediante Pygame, para lo que necesitamos instalar lo siguiente
sudo apt-get install python sudo apt-get install python-pygame
Con esto instalado y el siguiente código obtendremos los datos deseados
#!/usr/bin/env python import pygame import math # Define some colors BLACK = ( 0, 0, 0) WHITE = ( 255, 255, 255) # This is a simple class that will help us print to the screen # It has nothing to do with the joysticks, just outputing the # information. class TextPrint: def __init__(self): self.reset() self.font = pygame.font.Font(None, 20) def printd (self, screen, textString): textBitmap = self.font.render(textString, True, BLACK) screen.blit(textBitmap, [self.x, self.y]) self.y += self.line_height def reset(self): self.x = 10 self.y = 10 self.line_height = 15 def indent(self): self.x += 10 def unindent(self): self.x -= 10 pygame.init() #Loop until the user clicks the close button. done = False # Used to manage how fast the screen updates clock = pygame.time.Clock() # Initialize the joysticks pygame.joystick.init() # Get ready to print textPrint = TextPrint() # -------- Main Program Loop ----------- while done==False: # EVENT PROCESSING STEP for event in pygame.event.get(): # User did something if event.type == pygame.QUIT: # If user clicked close done=True # Flag that we are done so we exit this loop # Possible joystick actions: JOYAXISMOTION JOYBALLMOTION JOYBUTTONDOWN JOYBUTTONUP JOYHATMOTION if event.type == pygame.JOYBUTTONDOWN: print("Joystick button pressed.") if event.type == pygame.JOYBUTTONUP: print("Joystick button released.") # Get count of joysticks joystick_count = pygame.joystick.get_count() # For each joystick: for i in range(joystick_count): joystick = pygame.joystick.Joystick(i) joystick.init() #Usually axis run in pairs, up/down for one, and left/right for the other axes = joystick.get_numaxes() for i in range( axes ): axis = joystick.get_axis( i ) y=joystick.get_axis(3); x=joystick.get_axis(2); velocidad= math.sqrt(x**2+y**2); direccion=math.atan2(y,x); v1=-(velocidad*math.sin(direccion+(math.pi/4))); v2=velocidad*math.cos(direccion+(math.pi/4)); v3=velocidad*math.cos(direccion+(math.pi/4)); v4=-(velocidad*math.sin(direccion+(math.pi/4))); print v1 print v2 print v3 print v4 # Limit to 20 frames per second clock.tick(20) pygame.quit ()
Ya con esto vamos a obtener los datos y de una vez la velocidades necesitadas para el funcionamiento de las llantas omnidireccionales
Como la comunicacion entre la computadora y el RaspberryPi será mediante WI FI, se utilizará YARP para poder enviar los datos de las velocidades y dirección tomadas del joystick, por lo que tendremos que instarlar los siguiente tanto en el raspberrypi como en la computadora
Esto se hará siguiendo la siguiente guía
http://arcoslab.eie.ucr.ac.cr/dokuwiki/doku.php?id=using_xstow_for_local_installations
Esto se hará siguiendo la siguiente guía
http://arcoslab.eie.ucr.ac.cr/dokuwiki/doku.php?id=installing_yarp_in_debian
Con esto instalado, se enviarán los datos de las velocidades mediante un bottle
esta se realizará mediante Piserial
Para probar el streaming del Rpi se utilizó Raspivid junto con NetCat en el Raspberry Pi lo que va a transmitir video a través de un puerto específico y en una computadora, con NetCat y algún reproductor de video como MPlayer o VLC, se puede ver el video que se transmite en tiempo real.
raspivid -t 0 -o - | nc -l 5001
El 5001 es un puerto que se escoje para hacer la transmisión, se puede escoger cualquier otro puerto, de preferencia de 4 dígitos porque los puertos de menos dígitos generalmente están reservados para alguna función. El -l transmite a cualquier computadora que esté “escuchando” a ese puerto en específico.
nc [dirección IP del Rpi] 5001 | mplayer -fps 200 -demuxer h264es -
El comando demuxer h264es descomprime la imagen proveniente del Rpi para que se pueda ver correctamente.