Sumo CNDR

Sumo CNDR

Pelea de Robots Sumo

La pelea de robots sumo consiste en dos robots que luchan por sacar al contrincante de un circulo. Los robots están diseñados bajo reglas especificas de diseño que limitan sus posibilidades y ponen en equidad la batalla; por tal motivo, se crean diferentes ligas de pelea para sumo. El desafío que afronta el ingeniero a la hora de crear y programar el sumo, es darle la capacidad de encontrar y reaccionar oportunamente al enemigo. Para esto se usan sensores que le permiten al sumo ubicarse en el espacio y poder manejarse en la pelea.. 1

RoboCore_Robot_Sumo.jpg

Diseño del Proyecto

El diseño del sumo, se ve limitado por las reglas de la batalla, como sigue:

El robot debe ser Autónomo. El mecanismo no debe interactuar con sistemas de control externo (radiocontrol, medios infrarrojos, bluetooth, computadoras, etc.).
Dimensiones máximas: Ancho 20cms x largo 20cms sin límite de altura.
Peso Máximo: 3Kg.
Materiales mecánicos: Libre Elección.
Materiales electrónicos: Libre Elección.
El robot no debe tener conexiones externas de alimentación
Deberá tener un interruptor de encendido visible, con una secuencia de espera inicial de al menos 5 segundos antes de comenzar la lucha.

Ahora bien, el diseño se ramifica en tres partes principales: El control electrónico, la lógica y la mecánica.

Mecánica

El diseño mecánico de un robot, es uno de los factores de mayor importancia, y también, uno de los mas tardado, por tal motivo, se usa un chasis pololu, ahorrando así tiempo, y estableciendo limitantes para el diseño y montaje electrónico.

91269-Pololu-Basic-Sumo-Blade-for-Zumo-Chassis-Pic003-700x700.jpg

Motores con engranajes reductores

La utilización de un motor con engranes reductores se tomo como la mejor opción para la construcción de el robot zumo, debido a que este tipo de motores presenta una relación de reducción basada en la ganancia de torque a cambio de una velocidad mas baja; siendo esta la relación optima para el funcionamiento de CNDR, ya que sin la relación de reducción que presentan los engranajes el motor giraría a una velocidad muy alta, colocando como ejemplo los motores de corriente continua y esto derivaría un descontrol en los sensores haciendo que no tuvieran el tiempo apropiado de respuesta desacoplando así la comunicación entre el sistema de detección y la mecánica.

images?q=tbn:ANd9GcTIUQnyFcLM0GVbAHOww8KwtdJGkDAEIYwMp8C50KZzooRuBlxiUA

Control Electronico

En este sistema de detección se encuentran dos tipos de sensores utilizados en el robot zumo, el primero es el CNY70 el cual se encarga de darle una ubicación al robot en el campo de batalla y el segundo el SHARP con el cual se obtendrá la ubicación del contrincante y así poder implementar el tipo de estrategia para derrotarlo.
En esta parte de la construcción del sumo se encuentra el ¨cerebro¨ de nuestro robot, el cual es el encargado de recibir las señales del sistema de detección (sensores), luego se encarga de procesarlas y las envía a los actuadores, es decir, a la parte mecánica el cual le da el movimiento apropiado al CNDR. Esto se realiza mediante la utilización de un microcontrolador ATMEGA 16A.

ATMEGA16%201-500x500.jpg

CNY70

El sensor CNY70 es un led y un transistor encapsulados. El led emite una onda infrarroja, y la base del transistor esta conectado a un receptor. Cuando la luz del led refleja, abre la base del transistor y permite obtener valores de voltaje para ciertos niveles de reflectancia. Ahora bien, para lograr esto, se necesita acoplar al ensamble una resistencia que proteja el led, y una resistencia en el emisor que correspondan a los valores de voltaje que se le envían al sensor.
Para reflectancia en negro, se puede obtener un valor digital 0, y para blanco de 1. Esto hace que el sensor sea precisamente util para detectar cambios en el color de una superficie.

cny1.jpg
  • Sensor optico reflectivo
  • Formado: Fotodiodo y fototransistor
  • Longitud de onda: 950nm
  • Distancia: 5 mm
cny8.jpg

La distancia optima en el sensor que es utilizada es de 4 mm ya que como se puede ver en la gráfica lo ideal es llevar los sensores lo más cerca posible del suelo, cuánto más alejados estén necesitaremos emitir más luz (mayor consumo), una R de transistor mayor (mayores tiempos de encendido y apagado) y nos afectará más la luz ambiente. Ahí se puede ver como a partir de 6 mm la intensidad ha caído más de un 80% del valor inicial.

Este sensor es utilizado para darle una cierta ubicación dentro del campo de batalla al robot, ya que su funcionamiento consiste en la detección de superficie no reflectiva, en este caso de color negro en la cual la luz infrarroja del sensor no es reflectada ,es decir, en su periodo de funcionamiento el sensor envía una señal al microntrolador que a la vez es enviada a los motores para que el robot este en movimiento mientras no sea reflectada la luz infrarroja, de lo contrario si el sensor no detecta la superficie de color negro, sino de cualquier otro color en la cual pueda ser reflectada la luz infrarroja que envía el sensor, este mandara una señal contraria al microcontrolador y por lo tanto cambiara su dirección haciendo que uno de los motores se detenga o gire a menos velocidad, ya que se usan 4 sensores repartidos en cada uno de los lados del robot para obtener una ubicación completa.

Sharp 2y0a21

images?q=tbn:ANd9GcTzLgab9p6lyLDJpibBcwj7QWeew3IzmliM2iimEitTVMMF6Pck
  • Voltaje de operación: 4.5V - 5,5V
  • Consumo de corriente promedio
  • Tipo de salida: Voltage analogo
  • Rango de distancia de medición: 10 cm a 80 cm
  • Periodo de actualización: 38 ± 10ms
  • Tamaño: 44.5 mm × 18.9 mm × 13.5 mm
  • Peso: 3,5g

Puente H L293D

figura_2.gif

El integrado L293D incluye cuatro circuitos para manejar cargas de potencia media, en especial pequeños motores y cargas inductivas, con la capacidad de controlar corriente hasta 600 mA en cada circuito y una tensión entre 4,5 V a 36 V.

Los circuitos individuales se pueden usar de manera independiente para controlar cargas de todo tipo y, en el caso de ser motores, manejar un único sentido de giro. Pero además, cualquiera de estos cuatro circuitos sirve para configurar la mitad de un puente H.

El integrado permite formar, entonces, dos puentes H completos, con los que se puede realizar el manejo de dos motores. En este caso el manejo será bidireccional, con frenado rápido y con posibilidad de implementar fácilmente el control de velocidad.

Es así como mediante la utilización de dos motores con engranajes reductores se utiliza este circuito integrado con el cual se logra controlar la dirección de giro de los motores y así lograr el optimo rendimiento.

Logica

La programación del Atmega16 se realiza en código avr-c, que es un lenguaje de programación de C++. Se incluyen librerías que permiten al programa compilar el código de forma que sea usable para el mcu.

Main

El sistema se basa en el uso de sensores cny70, que permite que el robot se mantenga en la arena. Así pues, el control lógico del sistema es:

#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "libLCD.h"
 
// Conexion Cables Motor
// Azul Motor --> Rojo PH ---> PINC4
// Cafe Motor --> Cafe PH ---> PINC5
// Blanco Motor ---> Amarillo PH ---> PINC6
// Negro Motor ---> Naranja PH ---> PINC7
 
int cny1, cny2, cny3, cny4, cny11, cny12, cny13, cny14;
 
int main(void) {
 
    _delay_ms(5000);
 
    DDRC |= 1<<7;   //Motor PuenteH1
    DDRC |= 1<<6;   //Motor PuenteH2
    DDRC |= 1<<5;   //Motor PuenteH3
    DDRC |= 1<<4;   //Motor PuenteH4
 
    ADCSRA |= 1 <<ADPS2;
    ADMUX |= 1 <<ADLAR;
    ADMUX |= 1 <<REFS0;
    ADCSRA |= 1 <<ADIE;
    ADCSRA |= 1 <<ADEN;
 
    sei();
 
    ADCSRA |= 1 <<ADSC;
 
    while (1)
    {
 
    }    
}

Aqui se presenta los comando de inicialización del conversor analógico a digital, y es establecen variables publicas con las que se puede trabajar a lo largo de todo el código. En orden, se tiene la inclusion de librerías básicas para el funcionamiento, inicialización de las variables donde se guardaran los valores de lectura del cny70. Al entrar al main, el mcu esperara 5 segundos, que son por regla, para que el sumo empiece a trabajar. Se determinan las salidas para los motores al puente h. Sigue la inicialización del ADC, y termina realizando la primera conversion, esto redirigira el código a la interrupción global del ADC.

ISR 1

ISR(ADC_vect)
{
    _delay_ms(25);
    PORTC = 0b10100000;
    //Lectura de Datos de ADC Multiplexado
    switch (ADMUX)
    {
        //Sensores CNY70
        case 0b01100000: //Caso 1
        {
 
            cny1 = ADCH;
            char sensor1char[4];
            itoa(ADCH, sensor1char, 10);
            LCD_goTo(1, 1);
            LCD_write("S1 ");
            LCD_goTo(1, 1);
            LCD_write(sensor1char);
            LCD_goTo(1, 1);
            LCD_write(" ");
            ADMUX = 0b01100001;
            ADCSRA |= 1 <<ADSC;
            break;
        }
 
        case 0b01100001: //Caso 2
        {
            cny2 = ADCH;
            char sensor2char[4];
            itoa(ADCH, sensor2char, 10);
            LCD_goTo(1, 2);
            LCD_write("S2 ");
            LCD_goTo(1, 2);
            LCD_write(sensor2char);
            LCD_goTo(1, 1);
            LCD_write(" ");
            ADMUX = 0b01100010;
            ADCSRA |= 1 <<ADSC;
            break;
        }
 
        case 0b01100010:  //Caso 3
        {
            cny3 = ADCH;
            char sensor3char[4];
            itoa(ADCH, sensor3char, 10);
            LCD_goTo(8, 1);
            LCD_write("S3 ");
            LCD_goTo(8, 1);
            LCD_write(sensor3char);
            LCD_goTo(8, 1);
            LCD_write(" ");
            ADMUX = 0b01100011;
            ADCSRA |= 1 <<ADSC;
            break;
        }
 
        case 0b01100011: //Caso 4
        {
            cny4 = ADCH;
            char sensor4char[4];
            itoa(ADCH, sensor4char, 10);
            LCD_goTo(8, 2);
            LCD_write("S4 ");
            LCD_goTo(8, 2);
            LCD_write(sensor4char);
            LCD_goTo(8, 1);
            LCD_write(" ");
            ADMUX = 0b01100000;
            ADCSRA |= 1 <<ADSC;
            break;
        }
 
        default:
            ADMUX = 0b01100000;
            ADCSRA |= 1 <<ADSC;
    }

En ISR, para enterlo mejor, se separa en 2 partes, ISR 1 y 2.
En ISR 1, se realiza la multiplexion de los datos de conversion del ADC y los guarda en las variables cny1, cny2, cny3 y cny4. Adicionalmente para realizar la calibración, se muestran los datos en la pantalla lcd. Cabe destacar que este ultimo no es necesario para el funcionamiento del robot.

ISR 2

    //Variables de Lectura ON/OFF
 
    //Si esta en negro, lectura es <10, es decir, ON --> 1
    //Si esta en blanco, lectura es >10, es decir, OFF --> 0
 
    int cny11;
    int cny12;
    int cny13;
    int cny14;
 
    if (cny1 <=10){cny11 = 1;}
    if (cny1 > 10){cny11 = 0;}
 
    if (cny2 <=10){cny12 = 1;}
    if (cny2 > 10){cny12 = 0;}
 
    if (cny3 <=10){cny14 = 1;}
    if (cny3 > 10){cny14 = 0;}
 
    if (cny4 <=10){cny13 = 1;}
    if (cny4 > 10){cny13 = 0;}
 
    //Sentencia de Movimiento Global
    //Generales
 
    while ((cny11 == 1)&&(cny12==1)&&(cny13 == 1)&&(cny14==1))      //Hacia Adelante
    {
        PORTC = 0b01010000;
        break;
    }
 
    while ((cny11 == 0)&&(cny12==0)&&(cny13 == 0)&&(cny14==0))      //Stop
    {
        PORTC = 0b00000000;
        break;
    }
 
    while ((cny11 == 0)&&(cny12==0)&&(cny13 == 1)&&(cny14==1))      //Hacia Atras
    {
        PORTC = 0b10100000;
        break;
    }
 
    while ((cny11 == 1)&&(cny12==1)&&(cny13 == 0)&&(cny14==0))      //Hacia Adelante
    {
        PORTC = 0b01010000;
        break;
    }
 
    while ((cny11 == 0)&&(cny12==1)&&(cny13 == 0)&&(cny14==1))      //Giro Derecha
    {
        PORTC = 0b10010000;
        _delay_ms(75);
        break;
    }
 
    while ((cny11 == 1)&&(cny12==0)&&(cny13 == 1)&&(cny14==0))      //Giro Izquierda
    {
        PORTC = 0b01100000;
        _delay_ms(75);
        break;
    }
 
    //Especiales
 
    while ((cny11 == 0)&&(cny12==1)&&(cny13 == 1)&&(cny14==1))      //Hacia Atras
    {
        PORTC = 0b10100000;
        break;
    }
 
    while ((cny11 == 1)&&(cny12==0)&&(cny13 == 1)&&(cny14==1))      //Hacia Atras
    {
        PORTC = 0b10100000;
        break;
    }
 
    while ((cny11 == 1)&&(cny12==1)&&(cny13 == 0)&&(cny14==1))      //Hacia Adelante
    {
        PORTC = 0b01010000;
        break;
    }
 
    while ((cny11 == 1)&&(cny12==1)&&(cny13 == 1)&&(cny14==0))      //Hacia Adelante
    {
        PORTC = 0b01010000;
        break;
    }
 }

En ISR 2, se estable la logica con que el mcu permitirá que los motores se muevan o no. Primero captura el valor del ADC, y dependiendo del rango en que esten, le dará un valor de 0 para cuando el sensor esta detectando blanco o 1 para cuando esta detectando negro. Con esto, se establecen sentencias que determinan el movimiento.

Libreria Pantalla LCD

Adicionalmente, se encuentra la librería para que el mcu envíe datos a la LCD

//#include <avr/io.h>
//#include <avr/delay.h>
#define LCD_RS 0
#define LCD_RW 1
#define LCD_E 2
 
//LCD_putchar writes a character to the LCD at the current address,
//no busy flag check is done before or after
//the character is written!
//usage: LCD_putchar('A'); or LCD_putchar(0x55);
void LCD_putchar(char data)
{
    //PortD is output
    DDRD = 0xFF;
    //put data on bus
    PORTD = data;
    //RW low, E low
    PORTC &= ~((1<<LCD_RW)|(1<<LCD_E));
    //RS high, strobe E
    PORTC |= ((1<<LCD_RS)|(1<<LCD_E));
    //the number of nops required varies with your clock frequency, try it out!
    asm volatile ("nop");
    asm volatile ("nop");
    asm volatile ("nop");
    asm volatile ("nop");
    //RS low again, E low (belongs to strobe)
    PORTC &= ~((1<<LCD_RS)|(1<<LCD_E));
    //release bus
    DDRD = 0;
}
 
//LCD_getaddress reads the address counter and busy flag. For the address only,
//mask off bit7 of the return value.
char LCD_getaddr(void)
{
    //make var for the return value
    char address;
    //PortD is input
    DDRD = 0;
    //RW high, strobe enable
    PORTC |= ((1<<LCD_RW)|(1<<LCD_E));
    asm volatile ("nop");
    asm volatile ("nop");
    //while E is high, get data from LCD
    address = PIND;
    //reset RW to low, E low (for strobe)
    PORTC &= ~((1<<LCD_RW)|(1<<LCD_E));
    //return address and busy flag
    return address;
}
 
//LCD_wait reads the address counter (which contains the busy flag) and loops until
//the busy flag is cleared.
void LCD_wait(void)
{
    //get address and busy flag
    //and loop until busy flag cleared
    while((LCD_getaddr() & 0x80) == 0x80);
}
 
//LCD_command works EXACTLY like LCD_putchar, but takes RS low for accessing the command reg
//see LCD_putchar for details on the code
void LCD_command(char command)
{
    DDRD = 0xFF;
    PORTD = command;
    PORTC &= ~((1<<LCD_RS)|(1<<LCD_RW)|(1<<LCD_E));
    PORTC |= (1<<LCD_E);
    asm volatile ("nop");
    asm volatile ("nop");
    asm volatile ("nop");
    asm volatile ("nop");
    PORTC &= ~(1<<LCD_E);
    DDRD = 0;
}
 
/*LCD_init initialises the LCD with the following paramters:
8 bit mode, 5*7 font, 2 lines (also for 4 lines)
auto-inc cursor after write and read
cursor and didsplay on, cursor blinking.
*/
void LCD_init(void)
{
    //setup the LCD control signals on PortC
    DDRC |= ((1<<LCD_RS)|(1<<LCD_RW)|(1<<LCD_E));
    PORTC = 0x00;
    //if called right after power-up, we'll have to wait a bit (fine-tune for faster execution)
    _delay_loop_2(0xFFFF);
    //tell the LCD that it's used in 8-bit mode 3 times, each with a delay inbetween.
    LCD_command(0x30);
    _delay_loop_2(0xFFFF);
    LCD_command(0x30);
    _delay_loop_2(0xFFFF);
    LCD_command(0x30);
    _delay_loop_2(0xFFFF);
    //now: 8 bit interface, 5*7 font, 2 lines.
    LCD_command(0x38);
    //wait until command finished
    LCD_wait();
    //display on, cursor on (blinking)
    LCD_command(0x0F);
    LCD_wait();
    //now clear the display, cursor home
    LCD_command(0x01);
    LCD_wait();
    //cursor auto-inc
    LCD_command(0x06);
}
 
//now it's time for a simple function for showing strings on the LCD. It uses the low-level
//functions above. usage example: LCD_write("Hello World!");
void LCD_write(char* dstring)
{
    //is the character pointed at by dstring a zero? If not, write character to LCD
    while(*dstring)
    {
        //if the LCD is bus, let it finish the current operation
        LCD_wait();
        //the write the character from dstring to the LCD, then post-inc the dstring is pointing at.
        LCD_putchar(*dstring++);
    }
}
 
//LCD goTo defined position
char firstColumnPositionsForLCD[4] = {0, 64, 20, 84};
void LCD_goTo(uint8_t x, uint8_t y)
{
    LCD_command(0x80 + firstColumnPositionsForLCD[y-1] + (x-1));
}

Con esta libreria, se tiene que los datos del LCD, se conectan al puerto D, y el RS, RW, y EN a los pines 0,1 y 2 del puerto C respectivamente.

Ensamblaje Final

Usando el siguiente montaje electronico, y la configuracion logica, se obtiene el sumo final

Montaje Electronico

Capture.PNG

Diagrama de Estados

des.png?attachauth=ANoY7cqCnRT44PQDwUijq76-nctYX4NidTWuIVajGAb5Cp2-jWsVdfwq32ahNsY4yyxqv1BVEiRJipawRT9XaXKoOtrctw99RdgUgOOndWTquwJMoA3iNdlSmbAlOM8Hcq-8aH19RTr89FNtNLEQadrl4zCq1ZIXZB-yE7l1giI7yZyX2xpIZdKiZGpIhKXYrgAx37rCSVlRP7IGpE4_j5ksw-tdvRDxNA%3D%3D&attredirects=0

Diagrama de Bloques

dbs.png

Ensamble

IMG_20151110_131250.jpg

IMG_20151110_131308.jpg

IMG_20151110_131435.jpg

IMG_20151110_131459.jpg
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License