Publicado el

Sumobot 32U4 versátil y poderoso ¡Compatible con el IDE de Arduino!

[nextpage title=»Introducción»]
El sumobot 32U4 es un robot completo, versátil, controlado por un microcontrolador ATmega32U4 y compatible con el IDE de Arduino. Cuando está ensamblado, el sumobot rastreado medidas de menos de 10 cm a cada lado. Lo necesario para competiciones.
El sumobot 32U4 cuenta con un microcontrolador integrado ATmega32U4 AVR de Atmel, junto con las conexiones del puente H que alimentan los motores del robot. El robot también cuenta con una variedad de sensores, incluyendo codificadores de cuadratura y sensores como (acelerómetro y el giroscopio) en la placa principal, además cuenta con sensores de reflectancia y de proximidad en la parte delantera. Incluye pulsadores que ofrecen una interfaz de entrada conveniente, una pantalla LCD, zumbador y leds indicadores.
El sumobot 32U4 cuenta con una interfaz USB compatible con Arduino. Con esto se puede programar fácilmente al robot y permite ayudar a su interfaz al hardware incluido. El robot es muy compacto y puede hacer muchas funcionalidades debido a los componentes incluidos.
djcdm-s
El robot es menor de 10 cm x 10 cm pequeño y suficiente para calificar como un Mini Sumo.

[nextpage title=»Componentes del sumobot»]
El robot se compone de partes principales las cuales son:

  • Chasis del sumobot este incluye:
  1. Chasis del sumobot (cuerpo)
  2. Ruedas dentadas de accionamiento
  3. Dos bandas de silicona de 22 dientes
  4. Dos pernos de tope con arandelas y tuercas M3
  5. Cuatro tornillos y tuercas de 1/4″
  6. Terminales de la batería

0j6602-600x480

  • Placa principal 32U4 que incluye:
  1. Zumbador
  2. Zócalos con pines para los leds IR
  3. Pines macho para LCD
  4. Puentes de cable
  5. Dos discos codificadores magnéticos
  6. Conectores hembra para sensores
  7. Cuatro tornillos y tuercas de 3/16″

0j6244-600x480

  • Placa de sensores frontales del sumobot 32U4 que incluye:
  1. Conector macho extendido para un conjunto de sensores
  2. Cabeceras en angulo recto, dos bloques de cortocircuito y puentes para un conjunto de sensores.
  3. Dos cabeceras de ángulo amplio y dos de ángulo estrecho, LEDs infrarrojos a través de hoyos (estos se conectan a la placa principal y sirven como emisores hacia adelante para los detectores del sensor de proximidad situados en la matriz de los sensores frontales).

0j6247-600x480

  • Lamina del sumobot 32U4 incluye:
  1. Soporte de emisor LED IR hacia adelante.
  2. Dos tornillos con rosca 3/16″ para soporte LED

0j6736-600x480

  • LCD 8×2 la asignación de los pines es la siguiente:

nlkfnrlfke
0j438-600x480
La relación de transmisión de los motores incluidos en este sumobot es de 75:1, la velocidad y el torque son medios y ofrece un buen equilibrio en conjunto. A continuación una tabla donde se aprecia algunas características del motor.
frtfcrede
En la ultima columna se aprecia que con un peso de 500 g, alimentado de 6v el sumobot recorre 65cm por segundo de acuerdo al motor se menciona antes.
0j2814-1200

  • Los elementos adicionales que se necesita son los siguientes:
  1. El sumobot 32U4 utiliza cuatro pilas AA. Funciona con pilas alcalinas y de NiMH, aunque se recomienda utilizar pilas recargables.
  2. Un cable USB para Micro-B para conectar el robot al ordenador para la programación y depuración.
  3. Un pequeño destornillador de 2mm para regular el brillo del pantalla LCD.
  4. Se puede añadir sensores ópticos o de distancia para un mayor alcance, aunque ya contiene sensores de proximidad.

NOTA: El sumobot se puede programar desde cualquier ordenador y cualquier sistema operativo que sea compatible con el IDE de Arduino.
Todos los componentes del sumobot son los siguientes faltando los motores antes mencionados:
0j6720-1200
[nextpage title=»Características detalladas del sumobot 32U4″]

  • Microcontrolador

La placa principal del sumo 32U4 cuenta con con la habilitación de USB, un microcontrolador AVR ATmega32U4 de Atmel, ademas cuenta con un oscilador de MHz 16. Esta es la misma frecuencia de reloj y del microcontrolador.
La placa incluye un conector Micro-USB que se puede utilizar para conectar al puerto USB de un ordenador mediante un cable USB a Micro. La conexión USB se puede utilizar para transmitir y recibir datos desde el ordenador y programar la tarjeta a través del mismo. La conexión USB también proporciona la energía para el microcontrolador y la mayoría de los otros equipos en el Zumo (pero no la potencia del motor).
El ATmega32U4 del sumo viene precargado con el mismo gestor de arranque USB compatible con Arduino, lo que le permite programar fácilmente utilizando el IDE de Arduino.

  • Interfaz de usuario

0j6245-1200
El sumo 32U4 tiene ocho indicadores LED.

  1. Un LED amarillo usualmente está conectado al pin digital 13 de Arduino o PC7. Se puede manejar este pin en estado alto. Este LED esta encendido y apagado mientras está a la espera de un código que se quiera cargar.
  2. Un LED verde está conectado al pin PD5 y la luz se enciende cuando es accionado en estado bajo . Mientras que la placa ejecuta el gestor de arranque o un programa compilado en el entorno de Arduino, el LED parpadeará cuando se está transmitiendo datos a través de la conexión USB.
  3. Un LED  rojo está conectado al pin PB0, y la luz se enciende cuando es accionadoen estado bajo . Mientras que la placa ejecuta el gestor de arranque o un programa compilado en el entorno de Arduino, el LED parpadeará cuando se está recibiendo datos a través de la conexión USB.

Los LEDS verde y rojo aprovechan también algunas  líneas de E / S con pulsadores.
4. Dos LED rojos en los bordes izquierdo y derecho de la placa indican cuando los emisores de infrarrojos del robot están activos en el lado correspondiente.
5. Dos LED azules de alimentación debajo de las esquinas traseras de la placa, indican cuando el robot está recibiendo energía de las baterías (el interruptor de alimentación debe estar encendido). El LED izquierdo está conectado a la tensión de la batería inversa, mientras que el LED derecho está conectado a la salida del regulador de 5 V de la placa principal.
NOTA: El LED azul de la izquierda será notablemente más tenue a medida que la tensión total de la batería cae por debajo de aproximadamente 3 V.
6.Un LED verde de alimentación por debajo del borde trasero central de la placa indica cuando está presente la tensión del bus USB.
Botones
Tiene cuatro botones: un botón de reinicio en el borde derecho y tres pulsadores de usuario ubicados a lo largo del borde posterior de la placa principal. Los pulsadores de usuario, están denominados como A, B, y C. Los botones tienen el arreglo correspondiente para no ser dañados. Las librerías del sumo se encargan de la configuración de los pines, lectura y eliminación de rebotes los botones.
LCD
Tiene una cabecera de 2 × 7 donde se puede conectar el LCD. Se puede ajustar el contraste de la pantalla con el potenciómetro a la izquierda del conector LCD. Se recomienda el uso de un destornillador de 2 mm para ajustar el contraste.
La librería proporciona funciones para mostrar los datos en la pantalla LCD conectada. Está diseñada para controlar correctamente el uso alternativo de las líneas de datos LCD con solo cambiar los estados de los pines  cuando sea necesario para un comando de LCD, después automáticamente se restaurará a su estado anterior.
Zumbador
El zumbador se puede utilizar para generar sonidos simples y música. Si alternas entre manejar el pin ene estado alto y bajo a una frecuencia dada, el zumbador producirá sonido en esa frecuencia. Puede reproducir notas y música con el zumbador usando las funciones de la librería del sumo.

  • Motores

Los motorreductores utilizados se encuentran asignados a los pines de la siguiente manera.

  1. Pin digital 15 , o PB1, controla la dirección del motor derecho (LOW acciona el motor adelante, HIGH maneja el motor a la inversa).
  2. Pin digital 16 , o PB2, controla la dirección del motor izquierdo
  3. Pin digital 9, o PB5, controla la velocidad del motor derecho con PWM (modulación por ancho de pulso).
  4. Pin digital 10 , o PB6, controla la velocidad del motor izquierdo con PWM.

La librería del sumo proporciona funciones que le permiten controlar fácilmente los motores. NOTA: A medida que se agotan las pilas, la tensión suministrada a los controladores de motor disminuirá, lo que hará que los motores vayan más lento.

  • Codificadores de cuadratura

Cada motor de accionamiento en el sumo 32U4 tiene un sistema codificador de cuadratura que consiste en un disco magnético unido al eje del motor y un par de sensores de efecto Hall montado en el lado inferior de la placa. Estos se pueden utilizar para realizar un seguimiento de la velocidad de rotación y la dirección de las ruedas dentadas del robot. Los codificadores proporcionan una resolución de 12 pulsos por revolución del eje del motor cuando se cuentan ambos bordes de los dos canales.
0j6254-1200

  • Conjunto de sensores (sensores de linea y de proximidad)

El conjunto de sensores frontales del sumo es un pequeña placa separada que se conecta a la placa principal. La placa cuenta con cinco sensores de línea y tres sensores de proximidad, de forma predeterminada, sólo se puede tener seis de estos ocho sensores conectados al microcontrolador.
Los cinco sensores de línea se encuentran hacia abajo y pueden ayudar al sumo a distinguir entre la luz y las superficies oscuras. También pueden ser utilizados para detectar fuentes de luz infrarroja, como el sol. Cada sensor de reflectancia consiste en un emisor LED infrarrojo se encuentran hacia abajo y se combina con un fototransistor que pueden detectar la luz infrarroja reflejada del LED. Los sensores de reflectancia operan con los mismos principios.
Los tres sensores de proximidad se encuentran en diferentes direcciones del Zumo y pueden ayudar a detectar objetos cercanos. También pueden ser utilizados para detectar los comandos de los controles remotos infrarrojos. Los sensores de proximidad, como los sensores de línea, detectan la luz reflejada de infrarrojos, pero están diseñados para detectar una única luz que se enciende y se apaga rápidamente a una frecuencia de 38 kHz.
Cada salida de los sensores están protegido por una resistencia de 220 ohmios para ayudar a prevenir cortocircuitos. El infrarrojo emitido por los sensores de línea puede interferir con los sensores de proximidad y causar falsas lecturas, por lo que se recomienda desactivar los sensores de línea antes de utilizar los sensores de proximidad.
0j6240-1200
Si desea utilizar los cinco sensores de línea y los tres sensores de proximidad en una sola aplicación, se puede lograr mediante la liberación de dos líneas de E / S y la reasignación de dos de los pines. Una forma de lograr esto es mediante la eliminación de la pantalla LCD.

  • Detección de proximidad

El sumobot 32U4 puede detectar objetos cercanos usando los tres sensores de proximidad en el conjunto de sensores frontales. Los sensores de proximidad no emiten su propia luz; En su lugar, están diseñados para detectar señales de 38 kHz infrarrojos de emisores de la Placa.
La placa base tiene cuatro emisores IR:

  • Los LEDs infrarrojos uno se encuentra en el centro y los otros, están a ambos lados del sumo, dentro de la banda y entre las ruedas. Emiten luz a la izquierda ya la derecha.
  • Los LEDs IR frontal izquierdo y frontal derecho están destinados a mirar hacia la parte delantera, aunque se puede jugar con el ángulo exacto.

Los LEDs claros tienen un ángulo mucho más amplio de visión de 50 °, lo que los hace uno de los mejores en la iluminación de objetos que no se encuentran directamente en frente del sumo.
Cuenta con una protección adecuada para los emisores frontales ya que es importante, la luz de los LED puede activar los sensores de proximidad directamente y causar falsas lecturas. El sumo 32U4 viene con un soporte de LED de plástico que sirve para proteger a los LED y al mismo tiempo ayudar a protegerlos de colisiones con otros robots.
0j6728-600
Los sensores de proximidad pueden detectar un objeto que está cerca del sumo, siempre y cuando la forma del objeto permite una cierta luz de los LEDs que se reflejan en el sensor. La distancia de detección máxima depende del tamaño y reflectividad del objeto que está sintiendo. La distancia de detección máxima es alrededor de 30 cm a 40 cm. El sensor de proximidad delantero explorar objetos cercanos, se enfrentan directamente hacia ellos, y hace un seguimiento si se mueven.

  • Sensores inerciales

El sumobot incluye sensores inerciales que se pueden utilizar en aplicaciones como ayudar al sumo a detectar colisiones y determinar su propia orientación mediante la implementación de una unidad de medición inercial (IMU). Contiene un chip, ST LSM303D es un módulo de brújula que se combina con un acelerómetro de 3 ejes y magnetómetro de 3 ejes en un solo conjunto. El segundo chip es un ST L3GD20H de 3 ejes de giroscopio. Ambos chips comparten un bus I²C conectados a la interfaz I²C del ATmega32U4.
El cambio de niveles integrados en la placa permiten que los sensores de inercia, funcionen a 3,3 V, a diferencia que se conecten al ATmega32U4 (que funciona a 5 V).
NOTA: Hay que tener en cuenta que el magnetómetro se ve afectado por las corrientes de los motores y el zumbador cuando están funcionando, así como el metal en las baterías, y las lecturas son fácilmente influenciado por las distorsiones magnéticas en el ambiente alrededor del sumo.

  • Fuente de poder

El chasis tiene un compartimento interno de cuatro pilas AA. Como se menciono antes se recomienda utilizar pilas recargables que proporcionan aproximadamente 4.8 v. El voltaje negativo de la batería está conectado a GND. El voltaje positivo de la batería se designa VB .
VB alimenta a un circuito que proporciona protección reversa y conmutación de potencia controlado por el interruptor de energía incluido. La salida de este circuito se designa VBAT .
VBAT proporciona energía a los motores a través de los controladores de motor, por lo que los motores sólo pueden funcionar si se instalan las baterías y el interruptor de encendido está en la posición «On».
Cuanta con reguladores que son de 5 v y 3.3 v, el de 5 v trabaja con una tensión de entrada de 2,7 V a 11,8 V el regulador de 3.3 v se utiliza para los sensores inerciales que obtienen energía de la línea de 3,3 V, el resto (hasta unos pocos cientos de miliamperios) este voltaje está disponible para la alimentación de circuitos o dispositivos externos.
Las fuentes de energía alternativas aceptadas por el sumo son una tensión de entrada de 2,7 V a 10 V . Puede elevar la tensión máxima permisible para el límite de 11 V a los conductores de los motores ‘desconectando o modificar el divisor de tensión de la batería.
NOTA: No se recomienda el uso de una batería de litio de 3 celdas para alimentar el Zumo

  • Áreas de expansión 

Se puede expandir la placa principal obteniendo mas pines de entrada o salida en este enlace muestra los tipos de expansión que se puede realizar en el sumobot.

  • Asignación de los pines principales

Es importante saber la asignación de los pines si se desea añadir algunos componentes electrónicos o escribir un código propio. Para ello en este enlace se encuentra una tabla que contiene la asignación de los pines y sus funciones en el sumobot.
Si se desea añadir mas electrónica al sumobot como por ejemplo sensores, se tiene que establecer las entradas y salidas no ocupadas ademas de realizar algunos arreglos, para ello se tiene que adentrar mas a fondo al agregar nuevos componentes. Aquí se encuentra información mas avanzada si se desea realizarlo.

  • Temporizadores   

El ATmega32U4 tiene 4 temporizadores: Temporizador 0, Temporizador 1, Temporizador 3 y Temporizador 4. Cada temporizador tiene un conjunto de diferente características.

  1. Temporizador 0 es utilizado normalmente en  Arduino para funciones relacionados con el tiempo en millis().
  2. Temporizador 1 es utilizado por la librería del sumo 32U4 en Arduino, para motores de accionamiento.
  3. Temporizador 3 es utilizado por la librería del sumo 32U4 en Arduino para emitir pulsos de 38 kHz para los sensores de proximidad, pero puede ser utilizado para otros fines entre las lecturas de los sensores.
  4. Temporizador 4 es utilizado por la librería del sumo 32U4 en Arduino para controlar el zumbador.
  • Esquemas y dimensiones

El diagrama esquemático para el sumobot 32U4 se puede visualizar aqui.
El plano o bien las dimensiones de la placa base se puede visualizar en este enlace. A continuación las dimensiones del chasis.
0j3930-1200
0j3931-1200
El sumobot es muy pequeño y contiene características importantes que lo hacen muy versátil y potente.
[nextpage title=»Instalación de los controladores»]
Antes de de conectar el sumobot a un equipo con windows se debe instalar sus controladores.
NOTA: Si se presenta algunos problemas se debe actualizar el service pack 3 o bien la actualización nombrada como KB918365 antes de instalar los controladores.
Puedes descargar los archivos desde aquí.
1.- Se abre la carpeta «drivers». Hacemos clic en «A-star.inf» e instalamos.
efdfe3w
Se abrirá una venta y preguntará si queremos continuar con la instalación, hacemos clic en instalar o continuar.
2.- Windows no le dirá cuando la instalación se haya completado, pero esta debe estar realizada después de unos segundos.
Los usuarios de Windows 10, Windows 8, Windows 7 y Windows Vista: Después de instalar los controladores, el equipo debe reconocer automáticamente el dispositivo cuando se conecta a través del USB. Sin embargo, la primera vez que se conecta el dispositivo al equipo, Windows tardará varios segundos en reconocer el dispositivo y configurarse correctamente. La primera vez que se programe el dispositivo, Windows volverá a tardar varios segundos en reconocer el gestor de arranque USB, y esto podría causar que la operación de programación falle la primera vez. Además, Windows tendrá que volver a reconocer el dispositivo y el gestor de arranque si se conecta el dispositivo a otro puerto USB que no se ha conectado anteriormente.
Si se utiliza Windows xp se debe de realizar una serie de pasos cada vez que se conecte el dispositivo a la computadora «pasos».

  • Detalles del puerto COM

Después de instalar los controladores y conectar el dispositivo, en los «Puertos (COM y LPT)» en Administrador de dispositivos, debería aparecer un puerto COM llamado «Pololu A-Star 32U4».
Es posible que el puerto COM se denomine «Dispositivo USB serie» en el Administrador de dispositivos. Esto puede ocurrir si está utilizando Windows 10 o posterior y se ha conectado el dispositivo en el ordenador antes de instalar los controladores. En ese caso, Windows configurará el sumo usando el controlador serie predeterminado de, y se mostrará «serial del dispositivo USB» como nombre para el puerto. El puerto seguirá siendo útil. Pero se recomienda fijar los nombres en el administrador de dispositivos.
[nextpage title=»Programación utilizando el IDE de Arduino»]
Como mencionamos anteriormente el sumo es compatible para programar con el IDE de Arduino.
1.- En los controladores descargados dentro de la carpeta «add-on» se encontrará otra carpeta llamada Pololu esta tendrá que ser copiada o instalada a la siguiente ruta:
C:\Users\<tu-nombre-de-usuario>\Documentos\Arduino\hardware\pololu
o bien si no se encuentra la ruta anterior basta con encontrar la ubicación de su carpeta de Arduino y ahi se encontrara la carpeta hardware dentro de ella pondremos la carpeta Pololu.
2.- Si el Arduino se encuentra abierto deberá cerrarlo y abrirlo nuevamente.
3.- En el menu Herramientas> Placa, seleccione «Pololu A-Star 32U4». Si no ve el dispositivo, probablemente, no se ha instalado correctamente la carpeta Pololu. Trate de hacer el paso 2 de nuevo y reiniciar el IDE de Arduino.
ejfoelnjw
4.- En el administrador de dispositivos de Windows al conectar el sumobot se le asignará un puerto COM este debe ser seleccionado en el IDE de Arduino en Herramientas>Puerto.
ccewcc
5.- Para comprobar que todo se ha instalado correctamente cargamos el ejemplo básico del parpadeo del led que se encuentra en  Archivo> Ejemplos> Basico> Blink . En este ejemplo parpadeará el LED amarillo. Cargamos el código al sumobot.
Si no se ha programado previamente este dispositivo en este puerto USB, Windows puede tardar varios segundos en reconocer el gestor de arranque. Los tiempos del gestor de arranque puede tardar unos segundos, por lo que la carga del código puede fallar si Windows no detecta la suficiente rapidez. Si esto sucede, vuelve a cargar el código.
6.- Si ha cargado el código del parpadeo, el LED amarillo debe estar parpadeando.

Si por el contrario se pretende usar la programación con avr-gcc y AVRDUDE, que es una programación mas avanzada para el usuario y si no se desea usar el IDE de Arduino. En este enlace esta la información acerca de como instalar el software en los distintos sistemas operativos ademas de un ejemplo para entender un poco el entorno.

  • Liberia en Arduino

El sumo 32U4 se puede programar desde el IDE de Arduino como se describe anteriormente. Para ayudar a la interfaz, con el hardware incorporado en el sumo 32U4, se encuentra la librería del  sumo32U4 . La documentación de la librería sumo 32U4 proporciona información detallada acerca de la librería, y esta viene con varios ejemplos de códigos.
Librería
lrknjfnledk
Una vez descargada se debe descomprimir, la carpeta obtenida se le debe cambiar el nombre por «Zumo32U4». Después esta se debe de mover a la carpeta de nuestro Arduino, dentro de la carpeta «libraries» una vez colocada la carpeta adentro se puede abrir Arduino y se podrá visualizar los ejemplos.
kjlhfklrjfe
[nextpage title=»Funcionamiento del sumobot»]
A continuación se presentan algunos códigos y se podrá visualizar como funcionan.
En el siguiente código el robot leerá el angulo de inclinación y automáticamente el robot forzara a los motores a sostenerse de acuerdo al angulo de inclinación leído.

#include <Wire.h>
#include <Zumo32U4.h>
const int16_t maxSpeed = 150;
LSM303 lsm303;
Zumo32U4Motors motors;
Zumo32U4LCD lcd;
Zumo32U4ButtonA buttonA;
Zumo32U4Encoders encoders;
void setup()
{
// Inicia el acelerometro.
Wire.begin();
lsm303.init();
lsm303.enableDefault();
lcd.clear();
lcd.print(F("Press A"));
buttonA.waitForPress();
lcd.clear();
}
void loop()
{
// Lee la aceleracion.
lsm303.read();
int16_t x = lsm303.a.x;
int16_t y = lsm303.a.y;
int32_t magnitudeSquared = (int32_t)x * x + (int32_t)y * y;
// Mensajes en LCD
static uint8_t lastDisplayTime;
if ((uint8_t)(millis() - lastDisplayTime) > 150)
{
lastDisplayTime = millis();
lcd.gotoXY(0, 0);
lcd.print(x);
lcd.print(F(" "));
lcd.gotoXY(0, 1);
lcd.print(y);
lcd.print(F(" "));
}
int16_t forwardSpeed = -(encoders.getCountsLeft() + encoders.getCountsRight());
forwardSpeed = constrain(forwardSpeed, -maxSpeed, maxSpeed);
// Vee el angulo de inclinacion
// 16384 * sin(5 deg) = 1427
int16_t turnSpeed;
if (magnitudeSquared > (int32_t)1427 * 1427)
{
// We are on an incline of more than 5 degrees, so
// try to face uphill using a feedback algorithm.
turnSpeed = y / 16;
ledYellow(1);
}
else
{
// We not on a noticeable incline, so don't turn.
turnSpeed = 0;
ledYellow(0);
}
int16_t leftSpeed = forwardSpeed - turnSpeed;
int16_t rightSpeed = forwardSpeed + turnSpeed;
leftSpeed = constrain(leftSpeed, -maxSpeed, maxSpeed);
rightSpeed = constrain(rightSpeed, -maxSpeed, maxSpeed);
motors.setSpeeds(leftSpeed, rightSpeed);
}

En el siguiente código el sumobot, utilizando los sensores de proximidad este se mantendrá siempre de frente al objeto rotando siempre cuando el objeto se mueva y siempre seguirlo.

#include <Wire.h>
#include <Zumo32U4.h>
Zumo32U4LCD lcd;
Zumo32U4Motors motors;
Zumo32U4ProximitySensors proxSensors;
Zumo32U4ButtonA buttonA;
//Constantes maximas y minimas
const uint8_t sensorThreshold = 1;
const uint16_t turnSpeedMax = 400;
const uint16_t turnSpeedMin = 100;
const uint16_t deceleration = 10;
const uint16_t acceleration = 10;
#define LEFT 0
#define RIGHT 1
// Indicando desde el sensor la ubicacion del objeto
bool senseDir = RIGHT;
// True if the robot is turning left (counter-clockwise).
bool turningLeft = false;
// True if the robot is turning right (clockwise).
bool turningRight = false;
// If the robot is turning, this is the speed it will use.
uint16_t turnSpeed = turnSpeedMax;
// The time, in milliseconds, when an object was last seen.
uint16_t lastTimeObjectSeen = 0;
void setup()
{
proxSensors.initFrontSensor();
// Espera a presionar el boton A para iniciar.
lcd.clear();
lcd.print(F("Press A"));
buttonA.waitForButton();
lcd.clear();
}
void turnRight()
{
motors.setSpeeds(turnSpeed, -turnSpeed);
turningLeft = false;
turningRight = true;
}
void turnLeft()
{
motors.setSpeeds(-turnSpeed, turnSpeed);
turningLeft = true;
turningRight = false;
}
void stop()
{
motors.setSpeeds(0, 0);
turningLeft = false;
turningRight = false;
}
void loop()
{
// Lee el sensor y girara izquierda o derecha
proxSensors.read();
uint8_t leftValue = proxSensors.countsFrontWithLeftLeds();
uint8_t rightValue = proxSensors.countsFrontWithRightLeds();
// Determina si el objeto es visible o no
bool objectSeen = leftValue >= sensorThreshold || rightValue >= sensorThreshold;
if (objectSeen)
{
// An object is visible, so we will start decelerating in
// order to help the robot find the object without
// overshooting or oscillating.
turnSpeed -= deceleration;
}
else
{
// An object is not visible, so we will accelerate in order
// to help find the object sooner.
turnSpeed += acceleration;
}
turnSpeed = constrain(turnSpeed, turnSpeedMin, turnSpeedMax);
if (objectSeen)
{
// An object seen.
ledYellow(1);
lastTimeObjectSeen = millis();
bool lastTurnRight = turnRight;
if (leftValue < rightValue) { // The right value is greater, so the object is probably // closer to the robot's right LEDs, which means the robot // is not facing it directly. Turn to the right to try to // make it more even. turnRight(); senseDir = RIGHT; } else if (leftValue > rightValue)
{
// The left value is greater, so turn to the left.
turnLeft();
senseDir = LEFT;
}
else
{
// The values are equal, so stop the motors.
stop();
}
}
else
{
ledYellow(0);
if (senseDir == RIGHT)
{
turnRight();
}
else
{
turnLeft();
}
}
lcd.gotoXY(0, 0);
lcd.print(leftValue);
lcd.print(' ');
lcd.print(rightValue);
lcd.gotoXY(0, 1);
lcd.print(turningRight ? 'R' : (turningLeft ? 'L' : ' '));
lcd.print(' ');
lcd.print(turnSpeed);
lcd.print(' ');
lcd.print(' ');
}

En este ultimo mediante los botones se podrá seleccionar distintas funcionalidades que se pueden realizar.

#include <Wire.h>
#include <Zumo32U4.h>
Zumo32U4LCD lcd;
Zumo32U4Buzzer buzzer;
Zumo32U4ButtonA buttonA;
Zumo32U4ButtonB buttonB;
Zumo32U4ButtonC buttonC;
Zumo32U4LineSensors lineSensors;
Zumo32U4ProximitySensors proxSensors;
LSM303 compass;
L3G gyro;
Zumo32U4Motors motors;
Zumo32U4Encoders encoders;
char buttonMonitor();
class Menu
{
public:
struct Item
{
const char * name;
void (* action)();
};
Menu(Item * items, uint8_t itemCount)
{
this->items = items;
this->itemCount = itemCount;
lcdItemIndex = 0;
}
void lcdUpdate(uint8_t index)
{
lcd.clear();
lcd.print(items[index].name);
lcd.gotoXY(0, 1);
lcd.print(F("\x7f" "A \xa5" "B C\x7e"));
}
void action(uint8_t index)
{
items[index].action();
}
// Prompts the user to choose one of the menu items,
// then runs it, then returns.
void select()
{
lcdUpdate(lcdItemIndex);
while (1)
{
switch (buttonMonitor())
{
case 'A':
// The A button was pressed so decrement the index.
if (lcdItemIndex == 0)
{
lcdItemIndex = itemCount - 1;
}
else
{
lcdItemIndex--;
}
lcdUpdate(lcdItemIndex);
break;
case 'C':
// The C button was pressed so increase the index.
if (lcdItemIndex >= itemCount - 1)
{
lcdItemIndex = 0;
}
else
{
lcdItemIndex++;
}
lcdUpdate(lcdItemIndex);
break;
case 'B':
// The B button was pressed so run the item and return.
action(lcdItemIndex);
return;
}
}
}
private:
Item * items;
uint8_t itemCount;
uint8_t lcdItemIndex;
};
// A couple of simple tunes, stored in program space.
const char beepBrownout[] PROGMEM = "<c32<e32#<g32"; const char beepWelcome[] PROGMEM = ">g32>>c32";
const char beepThankYou[] PROGMEM = ">>c32>g32";
const char beepButtonA[] PROGMEM = "!c32";
const char beepButtonB[] PROGMEM = "!e32";
const char beepButtonC[] PROGMEM = "!g32";
// Custom characters for the LCD:
// This character is a back arrow.
const char backArrow[] PROGMEM = {
0b00000,
0b00010,
0b00001,
0b00101,
0b01001,
0b11110,
0b01000,
0b00100,
};
// This character is two chevrons pointing up.
const char forwardArrows[] PROGMEM = {
0b00000,
0b00100,
0b01010,
0b10001,
0b00100,
0b01010,
0b10001,
0b00000,
};
// This character is two chevrons pointing down.
const char reverseArrows[] PROGMEM = {
0b00000,
0b10001,
0b01010,
0b00100,
0b10001,
0b01010,
0b00100,
0b00000,
};
// This character is two solid arrows pointing up.
const char forwardArrowsSolid[] PROGMEM = {
0b00000,
0b00100,
0b01110,
0b11111,
0b00100,
0b01110,
0b11111,
0b00000,
};
// This character is two solid arrows pointing down.
const char reverseArrowsSolid[] PROGMEM = {
0b00000,
0b11111,
0b01110,
0b00100,
0b11111,
0b01110,
0b00100,
0b00000,
};
void loadCustomCharacters()
{
// The LCD supports up to 8 custom characters. Each character
// has a number between 0 and 7. We assign #7 to be the back
// arrow; other characters are loaded by individual demos as
// needed.
lcd.loadCustomCharacter(backArrow, 7);
}
// Assigns #0-6 to be bar graph characters.
void loadCustomCharactersBarGraph()
{
static const char levels[] PROGMEM = {
0, 0, 0, 0, 0, 0, 0, 63, 63, 63, 63, 63, 63, 63
};
lcd.loadCustomCharacter(levels + 0, 0); // 1 bar
lcd.loadCustomCharacter(levels + 1, 1); // 2 bars
lcd.loadCustomCharacter(levels + 2, 2); // 3 bars
lcd.loadCustomCharacter(levels + 3, 3); // 4 bars
lcd.loadCustomCharacter(levels + 4, 4); // 5 bars
lcd.loadCustomCharacter(levels + 5, 5); // 6 bars
lcd.loadCustomCharacter(levels + 6, 6); // 7 bars
}
// Assigns #0-4 to be arrow symbols.
void loadCustomCharactersMotorDirs()
{
lcd.loadCustomCharacter(forwardArrows, 0);
lcd.loadCustomCharacter(reverseArrows, 1);
lcd.loadCustomCharacter(forwardArrowsSolid, 2);
lcd.loadCustomCharacter(reverseArrowsSolid, 3);
}
// Clears the LCD and puts [back_arrow]B on the second line
// to indicate to the user that the B button goes back.
void displayBackArrow()
{
lcd.clear();
lcd.gotoXY(0,1);
lcd.print(F("\7B"));
lcd.gotoXY(0,0);
}
// Blinks all three LEDs in sequence.
void ledDemo()
{
displayBackArrow();
uint8_t state = 3;
static uint16_t lastUpdateTime = millis() - 2000;
while (buttonMonitor() != 'B')
{
if ((uint16_t)(millis() - lastUpdateTime) >= 500)
{
lastUpdateTime = millis();
state = state + 1;
if (state >= 4) { state = 0; }
switch (state)
{
case 0:
buzzer.play("c32");
lcd.gotoXY(0, 0);
lcd.print(F("Red "));
ledRed(1);
ledGreen(0);
ledYellow(0);
break;
case 1:
buzzer.play("e32");
lcd.gotoXY(0, 0);
lcd.print(F("Green"));
ledRed(0);
ledGreen(1);
ledYellow(0);
break;
case 2:
buzzer.play("g32");
lcd.gotoXY(0, 0);
lcd.print(F("Yellow"));
ledRed(0);
ledGreen(0);
ledYellow(1);
break;
}
}
}
ledRed(0);
ledYellow(0);
ledGreen(0);
}
void printBar(uint8_t height)
{
if (height > 8) { height = 8; }
static const char barChars[] = {' ', 0, 1, 2, 3, 4, 5, 6, 255};
lcd.print(barChars[height]);
}
// Display line sensor readings. Holding button C turns off
// the IR emitters.
void lineSensorDemo()
{
loadCustomCharactersBarGraph();
displayBackArrow();
lcd.gotoXY(6, 1);
lcd.print('C');
uint16_t lineSensorValues[3];
char c;
while (buttonMonitor() != 'B')
{
bool emittersOff = buttonC.isPressed();
if (emittersOff)
{
lineSensors.read(lineSensorValues, QTR_EMITTERS_OFF);
}
else
{
lineSensors.read(lineSensorValues, QTR_EMITTERS_ON);
}
lcd.gotoXY(1, 0);
for (uint8_t i = 0; i < 3; i++) { uint8_t barHeight = map(lineSensorValues[i], 0, 2000, 0, 8); printBar(barHeight); lcd.print(' '); } // Display an indicator of whether emitters are on or // off. lcd.gotoXY(7, 1); if (emittersOff) { lcd.print('\xa5'); // centered dot } else { lcd.print('*'); } } } // Display proximity sensor readings. void proxSensorDemo() { loadCustomCharactersBarGraph(); displayBackArrow(); while (buttonMonitor() != 'B') { bool proxLeftActive = proxSensors.readBasicLeft(); bool proxFrontActive = proxSensors.readBasicFront(); bool proxRightActive = proxSensors.readBasicRight(); proxSensors.read(); lcd.gotoXY(0, 0); printBar(proxSensors.countsLeftWithLeftLeds()); printBar(proxSensors.countsLeftWithRightLeds()); lcd.print(' '); printBar(proxSensors.countsFrontWithLeftLeds()); printBar(proxSensors.countsFrontWithRightLeds()); lcd.print(' '); printBar(proxSensors.countsRightWithLeftLeds()); printBar(proxSensors.countsRightWithRightLeds()); // On the last 3 characters of the second line, display // basic readings of the sensors taken without sending // IR pulses. lcd.gotoXY(5, 1); printBar(proxLeftActive); printBar(proxFrontActive); printBar(proxRightActive); } } // Starts I2C and initializes the inertial sensors. void initInertialSensors() { Wire.begin(); compass.init(); compass.enableDefault(); gyro.init(); gyro.enableDefault(); } // Given 3 readings for axes x, y, and z, prints the sign // and axis of the largest reading unless it is below the // given threshold. void printLargestAxis(int16_t x, int16_t y, int16_t z, uint16_t threshold) { int16_t largest = x; char axis = 'X'; if (abs(y) > abs(largest))
{
largest = y;
axis = 'Y';
}
if (abs(z) > abs(largest))
{
largest = z;
axis = 'Z';
}
if (abs(largest) < threshold) { lcd.print(" "); } else { bool positive = (largest > 0);
lcd.print(positive ? '+' : '-');
lcd.print(axis);
}
}
// Print the direction of the largest rotation rate measured
// by the gyro and the up direction based on the
// accelerometer's measurement of gravitational acceleration
// (assuming gravity is the dominant force acting on the
// Zumo).
void inertialDemo()
{
displayBackArrow();
lcd.gotoXY(3, 0);
lcd.print(F("Rot"));
lcd.gotoXY(4, 1);
lcd.print(F("Up"));
while (buttonMonitor() != 'B')
{
compass.read();
gyro.read();
lcd.gotoXY(6, 0);
printLargestAxis(gyro.g.x, gyro.g.y, gyro.g.z, 2000);
lcd.gotoXY(6, 1);
printLargestAxis(compass.a.x, compass.a.y, compass.a.z, 200);
}
}
// Provides an interface to test the motors. Holding button A or C
// causes the left or right motor to accelerate; releasing the
// button causes the motor to decelerate. Tapping the button while
// the motor is not running reverses the direction it runs.
//
// If the showEncoders argument is true, encoder counts are
// displayed on the first line of the LCD; otherwise, an
// instructional message is shown.
void motorDemoHelper(bool showEncoders)
{
loadCustomCharactersMotorDirs();
lcd.clear();
lcd.gotoXY(1, 1);
lcd.print(F("A \7B C"));
int16_t leftSpeed = 0, rightSpeed = 0;
int8_t leftDir = 1, rightDir = 1;
uint16_t lastUpdateTime = millis() - 100;
uint8_t btnCountA = 0, btnCountC = 0, instructCount = 0;
int16_t encCountsLeft = 0, encCountsRight = 0;
char buf[4];
while (buttonMonitor() != 'B')
{
encCountsLeft += encoders.getCountsAndResetLeft();
if (encCountsLeft < 0) { encCountsLeft += 1000; } if (encCountsLeft > 999) { encCountsLeft -= 1000; }
encCountsRight += encoders.getCountsAndResetRight();
if (encCountsRight < 0) { encCountsRight += 1000; } if (encCountsRight > 999) { encCountsRight -= 1000; }
// Update the LCD and motors every 50 ms.
if ((uint16_t)(millis() - lastUpdateTime) > 50)
{
lastUpdateTime = millis();
lcd.gotoXY(0, 0);
if (showEncoders)
{
sprintf(buf, "%03d", encCountsLeft);
lcd.print(buf);
lcd.gotoXY(5, 0);
sprintf(buf, "%03d", encCountsRight);
lcd.print(buf);
}
else
{
// Cycle the instructions every 2 seconds.
if (instructCount == 0)
{
lcd.print("Hold=run");
}
else if (instructCount == 40)
{
lcd.print("Tap=flip");
}
if (++instructCount == 80) { instructCount = 0; }
}
if (buttonA.isPressed())
{
if (btnCountA < 4) { btnCountA++; } else { // Button has been held for more than 200 ms, so // start running the motor. leftSpeed += 15; } } else { if (leftSpeed == 0 && btnCountA > 0 && btnCountA < 4)
{
// Motor isn't running and button was pressed for
// 200 ms or less, so flip the motor direction.
leftDir = -leftDir;
}
btnCountA = 0;
leftSpeed -= 30;
}
if (buttonC.isPressed())
{
if (btnCountC < 4) { btnCountC++; } else { // Button has been held for more than 200 ms, so // start running the motor. rightSpeed += 15; } } else { if (rightSpeed == 0 && btnCountC > 0 && btnCountC < 4) { // Motor isn't running and button was pressed for // 200 ms or less, so flip the motor direction. rightDir = -rightDir; } btnCountC = 0; rightSpeed -= 30; } leftSpeed = constrain(leftSpeed, 0, 400); rightSpeed = constrain(rightSpeed, 0, 400); motors.setSpeeds(leftSpeed * leftDir, rightSpeed * rightDir); // Display arrows pointing the appropriate direction // (solid if the motor is running, chevrons if not). lcd.gotoXY(0, 1); if (leftSpeed == 0) { lcd.print((leftDir > 0) ? '\0' : '\1');
}
else
{
lcd.print((leftDir > 0) ? '\2' : '\3');
}
lcd.gotoXY(7, 1);
if (rightSpeed == 0)
{
lcd.print((rightDir > 0) ? '\0' : '\1');
}
else
{
lcd.print((rightDir > 0) ? '\2' : '\3');
}
}
}
motors.setSpeeds(0, 0);
}
// Motor demo with instructions.
void motorDemo()
{
motorDemoHelper(false);
}
// Motor demo with encoder counts.
void encoderDemo()
{
motorDemoHelper(true);
}
const char fugue[] PROGMEM =
"! T120O5L16agafaea dac+adaea fa<aa<bac#a dac#adaea f"
"O6dcd<b-d<ad<g d<f+d<gd<ad<b- d<dd<ed<f+d<g d<f+d<gd<ad"
"L8MS<b-d<b-d MLe-<ge-<g MSc<ac<a MLd<fd<f O5MSb-gb-g" "ML>c#e>c#e MS afaf ML gc#gc# MS fdfd ML e<b-e<b-"
"O6L16ragafaea dac#adaea fa<aa<bac#a dac#adaea faeadaca"
"<b-acadg<b-g egdgcg<b-g <ag<b-gcf<af dfcf<b-f<af"
"<gf<af<b-e<ge c#e<b-e<ae<ge <fe<ge<ad<fd" "O5e>ee>ef>df>d b->c#b->c#a>df>d e>ee>ef>df>d"
"e>d>c#>db>d>c#b >c#agaegfe fO6dc#dfdc#<b c#4"; const char fugueTitle[] PROGMEM = " Fugue in D Minor - by J.S. Bach "; // Play a song on the buzzer and display its title. void musicDemo() { displayBackArrow(); uint8_t fugueTitlePos = 0; uint16_t lastShiftTime = millis() - 2000; while (buttonMonitor() != 'B') { // Shift the song title to the left every 250 ms. if ((uint16_t)(millis() - lastShiftTime) > 250)
{
lastShiftTime = millis();
lcd.gotoXY(0, 0);
for (uint8_t i = 0; i < 8; i++) { char c = pgm_read_byte(fugueTitle + fugueTitlePos + i); lcd.print(c); } fugueTitlePos++; if (fugueTitlePos + 8 >= strlen(fugueTitle))
{
fugueTitlePos = 0;
}
}
if (!buzzer.isPlaying())
{
buzzer.playFromProgramSpace(fugue);
}
}
}
// Display the the battery (VIN) voltage and indicate whether USB
// power is detected.
void powerDemo()
{
displayBackArrow();
uint16_t lastDisplayTime = millis() - 2000;
char buf[6];
while (buttonMonitor() != 'B')
{
if ((uint16_t)(millis() - lastDisplayTime) > 250)
{
bool usbPower = usbPowerPresent();
uint16_t batteryLevel = readBatteryMillivolts();
lastDisplayTime = millis();
lcd.gotoXY(0, 0);
sprintf(buf, "%5d", batteryLevel);
lcd.print(buf);
lcd.print(F(" mV"));
lcd.gotoXY(3, 1);
lcd.print(F("USB="));
lcd.print(usbPower ? 'Y' : 'N');
}
}
}
Menu::Item mainMenuItems[] = {
{ "LEDs", ledDemo },
{ "LineSens", lineSensorDemo },
{ "ProxSens", proxSensorDemo },
{ "Inertial", inertialDemo },
{ "Motors", motorDemo },
{ "Encoders", encoderDemo },
{ "Music", musicDemo },
{ "Power", powerDemo },
};
Menu mainMenu(mainMenuItems, 8);
// This function watches for button presses. If a button is
// pressed, it beeps a corresponding beep and it returns 'A',
// 'B', or 'C' depending on what button was pressed. If no
// button was pressed, it returns 0. This function is meant to
// be called repeatedly in a loop.
char buttonMonitor()
{
if (buttonA.getSingleDebouncedPress())
{
buzzer.playFromProgramSpace(beepButtonA);
return 'A';
}
if (buttonB.getSingleDebouncedPress())
{
buzzer.playFromProgramSpace(beepButtonB);
return 'B';
}
if (buttonC.getSingleDebouncedPress())
{
buzzer.playFromProgramSpace(beepButtonC);
return 'C';
}
return 0;
}
void setup()
{
lineSensors.initThreeSensors();
proxSensors.initThreeSensors();
initInertialSensors();
loadCustomCharacters();
// The brownout threshold on the ATmega32U4 is set to 4.3
// V. If VCC drops below this, a brownout reset will
// occur, preventing the AVR from operating out of spec.
//
// Note: Brownout resets usually do not happen on the Zumo
// 32U4 because the voltage regulator goes straight from 5
// V to 0 V when VIN drops too low.
//
// The bootloader is designed so that you can detect
// brownout resets from your sketch using the following
// code:
bool brownout = MCUSR >> BORF & 1;
MCUSR = 0;
if (brownout)
{
// The board was reset by a brownout reset
// (VCC dropped below 4.3 V).
// Play a special sound and display a note to the user.
buzzer.playFromProgramSpace(beepBrownout);
lcd.clear();
lcd.print(F("Brownout"));
lcd.gotoXY(0, 1);
lcd.print(F(" reset! "));
delay(1000);
}
else
{
buzzer.playFromProgramSpace(beepWelcome);
}
lcd.clear();
lcd.print(F(" Zumo"));
lcd.gotoXY(2, 1);
lcd.print(F("32U4"));
delay(1000);
lcd.clear();
lcd.print(F("Demo"));
lcd.gotoXY(0, 1);
lcd.print(F("Program"));
delay(1000);
lcd.clear();
lcd.print(F("Use B to"));
lcd.gotoXY(0, 1);
lcd.print(F("select."));
delay(1000);
lcd.clear();
lcd.print(F("Press B"));
lcd.gotoXY(0, 1);
lcd.print(F("-try it!"));
while (buttonMonitor() != 'B'){}
buzzer.playFromProgramSpace(beepThankYou);
lcd.clear();
lcd.print(F(" Thank"));
lcd.gotoXY(0, 1);
lcd.print(F(" you!"));
delay(1000);
}
// This function prompts the user to choose something from the
// main menu, runs their selection, and then returns.
void mainMenuSelect()
{
lcd.clear();
lcd.print(F(" Main"));
lcd.gotoXY(0, 1);
lcd.print(F(" Menu"));
delay(1000);
mainMenu.select();
}
void loop()
{
mainMenuSelect();
}


Aquí
algunos ejemplos muy interesantes como el seguidor de linea, manejo con control remoto, etc.

Compartir ahora:
Deja una respuesta