El sensor de ultrasonidos puede ser muy útil, aunque su poca precisión debe de tenerse en cuenta para evitar ciertos problemas. Así mismo, un uso mejorado de los motores puede incrementar nuestra precisión a la hora de realizar movimientos complicados. Un mejor uso del LCD puede ayudarnos a mostrar valores que son complicados de imaginar sin más que viendo como actúa el robot. En este artículo ahondaré en temas ya vistos, como los motores y el LCD, introduciré el sensor de ultrasonido, y finalmente haré un programa de prueba para que se vea todo esto.
Sensor de ultrasonido:
Basado en un sistema parecido al que usan los murciélagos, el sensor de ultrasonidos lanza ondas de sonido a la espera de que reboten en objetos y vuelvan, y finalmente halla la distancia al objeto calculando el tiempo que ha tardado en regresar dicha onda. La precisión del sensor de ultrasonidos del NXT es bastante reducida, pero a pesar de ello se le puede sacar partido. La clase UltrasonicSensor de LeJOS tiene bastantes métodos que nos ayudan a la hora de tomar medidas. Los más básicos son los siguientes:
int continuous(): Pone el sensor de ultrasonidos en funcionamiento continuo.
int off(): Detiene el funcionamiento continuo.
int getDistance(): Calcula y devuelve la distancia en centímetros hasta el objeto más cercano. El valor máximo es de 255 cm, aunque muchas veces devuelve este valor como error.
int getDistances(int[] dist): Devuelve un array con las últimas 8 distancias calculadas. Es útil para cuando se requiere mayor precisión, ya que podemos tomar estas 8 medidas sobre un mismo objetivo, y hallar la media, con los que incrementamos la precisión en la medida.
Al igual que los demás sensores, el sensor de ultrasonido se debe definir con su método constructor, indicando el puerto en el que va a estar conectado. Se definiría de la siguiente manera:
UltrasonicSensor nombre = new UltrasonicSensor(SensorPort.S1);
Una vez definido ya estará listo para su uso.
Nota: Si tenéis el NXT 2.0 no uséis el puerto 4 de sensores, LeJOS no tiene compatibilidad con el sensor de ultrasonidos en este puerto. Este puerto tiene unas características especiales, que no trataremos ahora.
Ampliación del manejo de motores:
Los motores cuentan con una buena cantidad de métodos en LeJOS. Hoy voy a añadir unos pocos más a los que hemos visto. El motor de los NXT tiene un tacómetro interno, gracias al que se puede saber cuántos grados ha girado el motor desde que se inicio el programa, o se reseteo el contador de dicho tacómetro. La forma más precisa de girar hasta cierto ángulo y luego volver a su posición inicial es diciendo al motor que regrese al grado 0, en vez de que vuelva a girar los mismos grados en dirección opuesta. Los métodos para el uso del tacómetro son:
int getTachoCount(): Devuelve el valor del contador del tacómetro (grados recorridos desde que se inicio el programa o se reinicio dicho contador).
void resetTachoCount(): Resetea el valor del contador a 0.
void rotateTo(int grados) : Gira el motor hasta que el contador alcance dicho número de grados. (Ej.: Si estamos en el grado 45 y quiere girar al 10, rotará -35 grados).
void rotateTo(int grados, boolean devolverControl) : Gira el motor hasta que el contador alcance dicho número de grados. Además devuelve el control al programa inmediatamente para que pueda ejecutar otros métodos mientras está girando (en caso de que devolverControl sea true).
Gracias a los métodos anteriores podemos crear programas que requieran mayor precisión.
Ampliación del manejo del LCD:
Hemos visto métodos para escribir tipos String e int en la pantalla del NXT. Sin embargo me gustaría repasar algunos de los atributos del LCD que facilitan su manejo así como un método más. Recordemos que los atributos eran propiedades de la clase. Empezaré por el método:
void setPixel(int rgbColor, int x, int y): Dibuja el píxel de la pantalla cuyas coordenadas son x,y del color deseado (rgbColor = 255 es negro, y rgbColor = 0 es blanco).
Gracias a este método podemos dibujar formas en la pantalla LCD del NXT, pero al igual que os habréis preguntado con el método drawString(), ¿qué tamaño tiene la pantalla?, ¿cuál es el máximo x e y?. Pues todo eso está en los atributos de la clase LCD. Para saber la altura y anchura en píxeles de la pantalla (que nos servirá para el método setPixel()) tenémos los atributos SCREEN_WIDTH, y SCREEN_HEIGHT. Un ejemplo de su uso sería:
int anchuramax = LCD.SCREEN_WIDTH;
int alturamax = LCD.SCREEN_HEIGHT;
También podemos disponer de los atributos CELL_WIDTH, y CELL_HEIGHT para saber cuántos caracteres de ancho y líneas de alto tenemos cuando escribimos en el LCD con los métodos drawString() y drawInt().
Con estos métodos y atributos tendremos un mejor manejo del LCD.
Radar Simple:
Para probar todo lo anterior he ideado un pequeño radar. Se trata de un robot tipo tribot que va girando a la par que va toma medidas de la distancia a la que se encuentra el objeto más cercano frontalmente. Para ello se hace uso del sensor de ultrasonidos. El robot va representando en pantalla lo que detecta. Realizado un giro de 180 grados el robot volverá a su posición original. La complejidad de este programa no radica tanto es sus métodos, sino en la complejidad de cómo calcular la relación entre el valor en distancia que nos da el sensor de ultrasonidos y qué dibujar en la pantalla. A pesar de podíamos haber elegido realizar una presentación en el display tipo radar mediante el uso de funciones trigonométricas, hemos preferido no hacer tan denso este artículo. La distancia que detecta el sensor de ultrasonido se va presentando como rayas verticales que van desde la base una altura que representa la distancia detectada. El código del programa no es muy largo:
import lejos.nxt.*;
public class RadarSimple {
public static void main(String[] args) throws Exception
{
UltrasonicSensor u1 = new UltrasonicSensor(SensorPort.S1);
int dist, x = 0 ,y = 0;
u1.continuous();
for(int i = 0; i <= 180; i++){
dist = u1.getDistance();
x= (i*LCD.SCREEN_WIDTH)/180;
y= (dist*LCD.SCREEN_HEIGHT)/255;
for(int j = y; j <= LCD.SCREEN_HEIGHT; j++){
LCD.setPixel(255, x, j);
}
Motor.A.rotateTo(-2*i,true);
Motor.B.rotateTo(2*i);
}
Motor.A.rotateTo(0,true);
Motor.B.rotateTo(0);
Button.ESCAPE.waitForPressAndRelease();
Thread.sleep(1000);
}
}
Ahora explicaré su funcionamiento:
07 – Ponemos el sensor de ultrasonido en modo continuo.
08 – Esto es un búcle for. Como se ve la definición de los for esta dividida en tres partes: en la primera se define un entero llamado i cuyo valor inicial será 0, el segundo es la condición (mientras i sea menor o igual a 180 se repetirá todo lo que hay dentro), la tercera parte es de cuanto en cuanto incrementará i, en este caso de uno en uno (i++ es lo mismo que decir i = i +1)). Este búcle lo utilizaremos para tomar unas 180 medidas del sensor de ultrasonidos y dibujarlas.
09 – Guardamos en dist la distancia que ha medido el sensor de ultrasonidos.
10 – Aquí calculamos en que posición x de la pantalla del LCD dibujaremos. Es una simple regla de 3: Si la pantalla mide SCREEN_WIDTH y vamos por la medida i de 180 tendremos que dibujar el la posición (i*LCD.SCREEN_WIDTH)/180. Asi por ejemplo cuando i sea igual a 180, dibujaremos en la posición SCREEN_WIDTH, o sea, en la parte más a la derecha del LCD.
11 – Igual que la línea anterior, pero con la posición y. En este caso nos centraremos en la medida calculada con el sensor de ultrasonidos, por lo que el valor máximo será 255.
12 – Este búcle lo usaremos para dibujar una linea desde la posición x, y hasta la posición x, SCREEN_HEIGHT. Para ello recorreremos esa línea dibujando píxel por píxel.
15 y 16 – Giramos un poco las ruedas, lo que nos servirá para tomar nuevas medidas con el sensor de ultrasonidos en la siguiente iteración del búcle.
18 y 19 – Una vez termina todas las medidas y el dibujo hacemos que el robot regrese a su posición original.
Y aquí os pongo un video de su funcionamiento:
El resultado de lo que hemos presentado en el display lo podéis apreciar a continuación. En negro se dibuja el objeto que se supone es un obstáculo.
Espero que más o menos os haya quedado claro. Solo me queda comentaros que como siempre si tenéis alguna duda podéis acudir al foro. Un saludo y hasta el próximo artículo.
Hola,
muchas gracias por la serie de articulos. Yo uso Mac OSX y preparar todo con eclipse me costo un poco. En los foros de LeJOS encontre la ayuda necesaria. Los articulos me han servido de gran ayuda para no tenerle miedo a LeJOS, gracias, a ver si de vez en cuando sacas alguno mas.
Me alegro que haya gente a la que le sirvan estos artículos. Iré publicando varios semanalmente, aunque ahora también estoy empezando con una serie de robotC. Un saludo :P.