Una
vez que la electrónica ha sido realizada lo primero es verificar
su correcto funcionamiento, para ello se debe empezar a programar el
microcontrolador, por lo que necesitaremos un programador serie para
pasar el programa que realicemos en el pc al microcontrolador, un
entorno de programación y en este caso un compilador ya
que se va a programar en C. Menos el programador que está entre
$10-$40 lo demás es gratis.
El entorno de programación lo podemos obtener de manera gratuita
de la página de Atmel, fabricante del microcontrolador que vamos
a usar, se puede descargar de: http://www.atmel.com/avrstudio/
donde en software seleccionamos el AVR Studio de algo más de 100
Megas (la versión a día de hoy que está en la
página : AVR Studio 4.18 (build 684) (116
MB, updated 11/09)), para ello antes debemos de registrarnos rellenando
el formulario que sale y se pasa a la descarga e instalación.
AVR Studio.
A la hora de elegir un compilador hay varias opciones, de pago y
gratuitas, para el micro que tenemos de Atmel hay un compilador
gratuito y bueno, con una comunidad bastante grande que lo usa donde
resolver dudas y de la que leer documentación, por lo que no hay
necesidad de irse a uno de pago. Además el precio de los
compiladores suele ser alto y sería varias veces el coste del
robot que vamos a hacer, por lo que no tiene sentido usar una
alternativa que no sea libre. El compilador es el WinAVR y se puede
obtener en: http://winavr.sourceforge.net/download.html. Una vez descargado e instalado vemos la siguiente pantalla cuando se crea un proyecto nuevo.
Donde se puede seleccionar entre un proyecto en ensamblador y un
proyecto en lenguaje c (AVR GCC). Para este robot en principio
sólo se va a usar c.
Como programador serie podemos elegir la opción de pololu: http://www.pololu.com/catalog/product/1302
al comprar la baby orangutan elegimos la opción con programador
por $12 más, y nos quitamos el problema de tener que comprarlo
por otro lado. Yo en su día compre el oficial de Atmel,
que es mucho más caro que los $12 de la opción anterior.
Este programador lo usaremos para conectar el robot (mediante el
conector de la baby orangutan para tal fin) con el pc y descargar en el
micro el programa que hemos realizado y que gobernará el
funcionamiento del robot.
Programador conectado al robot. El cable ha de conectarse en ese sentido.
Una alternativa a AVR Studio sería el entorno de
programación de los famosos Arduinos que creo haber leído
que son compatibles con estas placas o algunas versiones de ellas.
Puestos a aprender, la alternativa del AVR Studio desde mi punto de
vista es mejor que arduino, ya que tendremos total libertad sobre el
micro y no tenemos que adaptarnos a lo que haya hecho en Arduino.
Programar en el entorno de Arduino es demasiado sencillo, el grado de
abstracción es muy alto y está pensado para los que
buscan una forma sencilla y rápida de hacer las cosas, y para
aprender a usar un microcontrolador sin meternos en ensamblador la
mejor opción desde mi punto de vista es AVR Studio + WinAVR.
Lo primero es probar la placa Baby Orangutan cargando un programa y
viendo su funcionamiento, para ello podemos descargar un ejemplo de la
página de pololu que hace parpadear el led rojo de la baby
orangutan una vez por segundo: http://www.pololu.com/file/0J190/BlinkLED_m328.zip . Lo descargamos y sacamos la carpeta y encontramos los siguiente:
Si pinchamos dos veces sobre BlinkLED se nos abre el entorno del AVR Studio con el proyecto que hemos bajado.
Si nos vamos a Project --> Configuration Options, se nos abre la siguiente ventana.
En ella seleccionamos el microcontrolador que tenemos en nuestra placa,
en el caso de la baby orangutan el atmega328p y en Optimization una
opción distinta de la -O0, ya que algunas de las librerias que
vamos a utilizar requieren de las opciones de optimización
habilitadas, la frecuencia del reloj no es necesario indicarla en esta
ventana, ya está puesto en el porgrama. Una vez hecho lo
anterior aceptamos volviendo a la pantalla principal, pulsamos F7 para
compilar el programa, si todo ha ido bien en el cuadro inferior de
message podemos leer algo como:
Donde podemos ver la cantidad de memoria de programa y datos utilizada,
y también si hay algún Warning. Los warning lo mejor es
siempre solucionarlos (excepto que sea una variable sin usar) porque
siempre acaban dando problemas y luego en el circuito real van a
provocar un funcionamiento incorrecto.
Enchufamos el programador al PC y al robot, en la conexión cable
robot debemos fijarnos en la polaridad del conector (ya que lo podemos
conectar al revés) y damos al botón de conectar con el
programador.
Arriba el botón de un circuito integrado que pone Con, nos abre
la ventana para seleccionar el programdor que vamos a utilizar, en mi
caso el AVRISP mkII, el de pololu creo que también es este ya
que será un clónico del AVRISP, y le damos a Connect (si
ya lo tenemos seleccionados damos al botón de AVR al lado de Con
y nos saltamos este paso). Se nos abre la siguiente ventana.
En esta pestaña seleccionamos el ATmega328P y pasamos a la pestaña de Program.
En Program podemos programar, leer y verificar las distintas memorias
del microcontrolador. La memoria donde hay que grabar el programa que
hemos hecho en el PC es en la Flash, y el fichero a grabar es un .hex
que encontraremos en la carpeta inicial que se descargó, en la
subcarpeta default, fichero BlinkLED.hex, cada vez que le damos a F7 se
crea este fichero. Por lo que seleccionamos el fichero .hex y le damos
a Program.
Si todo ha ido bien nos lo indica en la parte inferior de la ventana y
el led rojo de la baby orangutan se encenderá una vez por
segundo.
En la pantalla de Fuses tenemos la opción para seleccionar la
fuente de reloj externa o interna, en este caso se está usando
un cristal externo.
Aunque aquí no hay que tocar nada, no debemos confundir external
crystal con externar clock, un cristal no es un oscilador que
proporciona una señal de reloj al microcontrolador, con el
cristal junto a una electrónica dentro del microcontrolador se
crea la señal de reloj. Si seleccionamos external clock por
error pues no podremos deshacer lo hecho y volver a programar la placa,
para poder recuperarla habría que generar una señal de
reloj con un dispositivo externo en el pin del microcontrolador
correspondiente, y si no se sabe hacer ésto o no se tienen los
medios pues ya estamos buscando otra baby orangutan.
Hay muchas más pestañas y opciones, sólo comento
los pasos principales para hacer funcionar el robot ya que comentar
todo sería demasiado largo y ya hay mucha información en
internet, además que también llevo unos pocos meses con
estos micros y no conozco demasiado de ellos.
El programa que hemos grabado es el siguiente:
// F_CPU tells util/delay.h our clock frequency
//#define F_CPU 8000000UL // Orangutan frequency (8MHz)
#define F_CPU 20000000UL // Baby Orangutan frequency (20MHz)
#include <avr/io.h>
#include <util/delay.h>
int main( void ) {
DDRD |= 1 << DDD1;
// set LED pin
PD1 to output
while ( 1 ) {
PORTD &= ~( 1 << PORTD1 ); // LED off
delayms( 900 );
// delay 900 ms
PORTD |= 1 << PORTD1; // LED on
delayms( 100 );
// delay 100 ms
}
return 0;
}
Se comienza con los defines e
includes, en #define F_CPU 20000000UL indicamos la frecuencia de reloj,
debe ir antes de los #include que necesitan conocer la frecuencia de
reloj para funcionar, por ejemplo si lo ponemos después del
#include <util/delay.h> pues nos dará un error.
Se declara la función que vamos a utilizar para generar los
retrasos y se entra en la función principal, donde se comienza
configurando el pin PD1 como salida en su registro correspondiente, y
se entra en el bucle principal donde se enciende el led durante 100 ms
cada segundo.
Hace unos meses me puse con los AVR a través de un Arduino Mega,
para montar luego un AVR en los velocistas MiniZ, y todos los avances
con estos micros los voy documentando aquí,
aún me falta meterme con la UART, el SPI y PWM (tengo que hacer
los 3 en breve) para tener más o menos documentados los
principales periféricos que se usan en robótica. El
código es bastante mejorable ya que sólo voy leyendo del
datasheet, probando y programando lo que leo para verificar que
funciona, además programar no es lo mio para que nos vamos
a engañar XD.
Una vez que hemos comprobado que la baby orangutan que nos han mandado
se puede programar y funciona, lo siguiente es verificar el
funcionamiento de la electrónica que se ha creado para el robot
mediante un programa que lea las entradas, muevas los motores, encienda
los leds, etc.. Sobre el proyecto que tenemos abierto en el AVR
Studio escribimos nuestro "hola mundo" o BlinkLED propio, para ellos
borramos todo menos las siguientes líneas:
Estas van en todos los programas que hagamos, el include con los
valores de los registros del micro, la función principal y el
bucle principal y a partir de aquí comenzamos con el "hola
mundo". Un programa sencillo para probar el hardware es el siguiente: #define F_CPU 20000000UL // Baby Orangutan frequency (20MHz) #include <avr/io.h> #include <util/delay.h>
void reset(void) { PORTD |= (1<<LEDP); //Encendemos Led en Baby Orangutan. _delay_ms(300); PORTD &= ~(1<<LEDP);//Apagamos Led en Baby Orangutan. _delay_ms(300); PORTD |= (1<<LEDP); _delay_ms(300); PORTD &= ~(1<<LEDP); _delay_ms(300); PORTD |= (1<<LEDP); _delay_ms(300); PORTD &= ~(1<<LEDP); }
Se comienza dando a los pines del pic un nombre más fácil de identificar que PORTD5, PORTB3, etc.. //Control de motores.Salidas. #define M1A PORTD5 #define M2A PORTD3 #define M1B PORTD6 #define M2B PORTB3 //Leds. Salidas. #define LEDP PORTD1 #define LEDV PORTB1 #define LEDR PORTD0 //Interruptores. Entradas. #define SW1 PORTB0 #define SW2 PORTB2
Tenemos 4 salidas del microcontrolador que van al puente en h, con los
que controlaremos el sentido de giro y la velocidad de los motores.
Tres salidas más que se encargan de enceder diodos leds para
indicar diferentes estados del robot, los que resultan muy
útiles a la hora de programar para detectar errores, y 2
interruptores que son entradas para comunicarnos con el robot. Faltan
los 8 sensores y el puerto I2C pero esos para más adelante.
void reset(void) { PORTD |= (1<<LEDP); //Encendemos Led en Baby Orangutan. _delay_ms(300); PORTD &= ~(1<<LEDP);//Apagamos Led en Baby Orangutan. _delay_ms(300); PORTD |= (1<<LEDP); _delay_ms(300); PORTD &= ~(1<<LEDP); _delay_ms(300); PORTD |= (1<<LEDP); _delay_ms(300); PORTD &= ~(1<<LEDP); }
Declaramos y definimos las funciones
que se van a utilizar. La primera sirve para inicializar los pines del
microcontrolador como entradas o salidas, si no tocamos nada por
defecto los registros que controlar los pines están a 0 y son
entradas, por lo que habrá que poner un uno en el bit
correspondiente del registro donde tengamos un pin que es salida,
más sobre este tema aquí.
La otra función sirve para apagar y encender un led 3 veces, se
usará para detectar posibles reseteos en el robot causado por
diferentes causas, al principio del programa el led rojo de la placa de
la baby orangutan se enciende tres veces, indicando que se ha iniciado
el programa. Si por cualquier motivo no deseado el microcontrolador se
resetea lo detectaremos mediante este led.
int main( void ) { char leer_pin=0;
inicializar_puertos(); reset();
PORTD |= ((1<<M1A)|(1<<M2A));
while ( 1 ) { !!Bucle principal. } return 0; }
Entramos en la función
principal, se declara una variable local que se usará en la
función, se llaman a las funciones de configuración de
los puertos y de reseteo, se establecen un par de salidas a 1 y se
entra en el bucle principal, un bucle infinito del que el
microcontrolador no saldrá, de tal forma que siempre esté
ejecutando el código que le indiquemos en el búcle.
Dentro del bucle lo que haremos para comprobar el funcionamiento de una
primera parte de la electrónica, es leer los dos interruptores,
y en función de sus valores encender y apagar los motores y los
leds.
Para saber como debemos controlar los motores nos fijamos en la
siguiente tabla que se encuentra en la documentación de la baby
orangutan.
Cuando los pines PD5 y PD6 (M1A y M1B) del microcontrolador,
configurados anteriormente como salida, se encuentren a nivel alto el
motor está parado. Cuando tengan valores distintos el motor
girará en un sentido o en el inverso, dependiendo de cuál
de los dos pines sea el 1 ó el 0. Cuando los dos están a
cero el motor se encuentra libre, es decir puede girar sin nada que lo
retenga, no tenemos freno. Comutando entre la opción de brake y
el giro en un sentido, se controla la velocidad del motor, teniendo la
máxima velocidad cuando el motor está en "foward" o
"reverse" de manera constante. M2A y M2B de la misma forma controlarán el otro motor. PORTD |= ((1<<M1A)|(1<<M2A));
Según la tabla anterior
comenzamos fijando un pin de ambos motores a 1 y así va a
permanecer durante todo el programa, cuando el otro pin que va al motor
en su salida tenga un cero el motor correspondiente se mueve y cuando
su salida sea 1 se para. Se comienza leyendo un interruptor, para ello
se hace una AND con la posición del bit del registro que nos
interesa con el registro donde se guardan los valores de la entrada del
puerto. Si el interruptor está apagado la AND nos devuelve un
uno (estamos usando una resistencia de pull-up) por lo que pasamos a
poner el pin que controla el motor a 1, para pararlo, y al mismo tiempo
apagamos un led que sólo estará encendido cuando el motor
esté en marcha. Cuando el interruptor esté encendido
asignamos a leer_pin un valor cero, lo que hace que pasemos a encender
el led y poner un cero en el pin del motor, para que éste se
mueva.
Video del funcionamiento.
El código es muy sencillo y sólo se ponen a uno o a cero
las salidas en función de las entradas para comprobar el
funcionamiento de la placa. A continuación se comprobarán
los sensores, para lo que probablemente haya que implementar un
interfaz por el bus I2C de tal forma que podamos ver los valores que se
obtienen en la lectura, no forma parte del proyecto este interfaz pero
ya está hecho y será útil para compronder como
leen los sensores. Lo siguiente sería controlar en velocidad los
motores mediante PWM, y una vez que se tenga implementada la lectura de
los sensores y el control de velocidad de los motores, lo siguiente y
último es poner el robot sobre la línea e implementar un
algoritmo que permita seguir la línea de la mejor forma posible,
aquí se verá si el robot se acerca al metro por
segundo... o se queda lejos.
Hasta ahora todo ha sido directo y muy sencillo, las tres
últimas partes son más complejas, aunque se pueden mirar
las librerias del robot 3pi y probablemente se pueda reutilizar la
mayoría.
Para cualquier duda de lo anterior, idea, comentario: Foro.