El objetivo de este artículo es realizar un vehículo NXT controlado remotamente con LeJOS a través de bluetooth. La novedad de este proyecto es que es el primero que realizamos cuya tracción no es diferencial (como los anteriores).
Mientras que los vehículos con tracción diferencial como el tribot son capaces de cambiar su dirección ajustando la velocidad de los motores, este vehículo cuenta con un motor que se encarga exclusivamente de la dirección ya que los otros dos se encargarán exclusivamente de dar potencia (para dar tracción emplearemos dos motores en lugar de uno solo).
Como mando usaremos el joystick que ya hemos empleado en otros artículos, que se comunicará con nuestro kart mediante bluetooth. Cada vez que haya una diferencia significativa en los tacómetros de los motores del joystick (lo que significará que hemos movido el joystick), este enviará una señal al kart para que gire la dirección, o acelere, según el eje del joystick que hayamos movido.
Comunicación Bluetooth en LeJOS:
En primer lugar os recomiendo que os leáis el artículo Manejo de Bluetooth en LeJOS en el que se explica como comunicar dos NXT mediante bluetooth para enviar cualquier tipo de información. En este caso lo que enviaremos serán datos del valor de los tacómetros de los motores del joystick, los cuales nos indican la cantidad de de grados que queremos girar, o cuanto aumentar la velocidad.
El envío de los datos entre los NXT se hace mediante un buffer, una especie de túnel en el que un NXT va metiendo datos por un lado y el otro los recoge por el otro lado. Es posible que la comunicación no desarrolle como queramos debido a diversos factores. Uno de los más comunes es que el NXT que envía información lo haga más rápido que el tiempo que tarda el NXT que la recibe en procesarla. Esto crea un problema serio, ya que el buffer se irá llenando de información, y llegará un momento que no pueda meter más y se empiecen a perder datos. Además como el receptor recibe más datos de los que tiene tiempo de procesar, se generará un retardo que irá en aumento, traduciéndose en un comportamiento no deseado.
Este es nuestro vehículo:
Control del Kart:
El control de la velocidad del Kart esta manejado por la clase navigator de LeJOS (que nos asegura que los dos motores A y C, que se encargan de la velocidad del Kart, se muevan a la misma velocidad). El control no es directo, sino que tiene velocidad aumentada gracias a un sistema de engranajes. La velocidad del kart se basa en el giro que experimenta el joystick en uno de sus ejes (el controlado por el motor A).
Detalle de los motores de tracción:
El control de la dirección es directo desde el motor B del NXT. Dado que existe una limitación mecánica del angulo máximo de giro, el programa debe tenerla en cuenta para evitar que el motor intente girar más de lo que mecánicamente es posible, bloqueándose. El ángulo girado pretende seguir al giro que experimenta el joystick en uno de sus ejes (el controlado por el motor B).
Detalle del sistema de dirección:
Programa:
La implementación consiste en dos programas, uno para el kart y otro para el joystick. Ambos programas se comunicarán mediante bluetooth por un buffer. El joystick será el encargado de enviarle cuantos grados ha girado en sus ejes, y el kart el encargado de recibir dicha información, procesarla, y transformarla en movimiento.
Los primeros experimentos que hicimos intentando controlar la dirección no daban el resultado que pretendíamos. Esto era debido a que estábamos enviando una gran cantidad de datos por el buffer, y el kart no era capaz de procesarlos a la velocidad suficiente, lo que creaba un retardo cada vez mayor entre el movimiento del joystick y la respuesta del kart. Por eso hemos hecho un método en el que el joystick solo envía información cada cierto tiempo, y si la posición del joystick a cambiado, por lo que no estará enviando datos todo el rato aunque el joystick esté quieto.
También se han resuelto otros problemas como el de la transmisión comentado anteriormente, y se han hecho procesamientos con los datos para que el control fuera más sencillo. Aún así los programas son aún mejorables, y los modificaremos para reducir problemas como el del retardo, y para finalmente poder participar en la competición de karts de la semana que viene con el único kart controlado remotamente hecho en exclusiva con NXT.
Aquí os dejo el código del mando:
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.Motor;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;
import java.io.*;
import javax.bluetooth.*;
public class Mando {
/**
* @param args
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String nombre = “NXT1”;
LCD.drawString(“Conectando…”, 2, 1);
LCD.refresh();
int ant_gir = 0;
int ant = 0;
RemoteDevice bt = Bluetooth.getKnownDevice(nombre);
if (bt == null){
LCD.clear();
LCD.drawString(“No existe ese dispositivo”, 0, 1);
Thread.sleep(2000);
System.exit(1);
}
BTConnection btc = Bluetooth.connect(bt);
if (btc == null){
LCD.clear();
LCD.drawString(“Conexión fallida”, 1, 1);
Thread.sleep(2000);
System.exit(1);
}
LCD.clear();
LCD.drawString(“Conectado”, 2, 1);
Thread.sleep(2000);
DataOutputStream dos = btc.openDataOutputStream();
LCD.clear();
LCD.drawString(“Mando en funcionamiento”, 2, 1);
while(!Button.ESCAPE.isPressed()){
Thread.sleep(150);
//Giro
int i = Motor.B.getTachoCount();
if ((i > (ant_gir + 5)) || (i < (ant_gir – 5))){
dos.writeInt(i);
dos.flush();
}
ant_gir = i;
//Aceleración
int j = Motor.C.getTachoCount();
if ((j > (ant + 4)) || (j < (ant – 4))){
dos.writeInt(j + 1000);
dos.flush();
}
ant = i;
}
LCD.clear();
LCD.drawString(“Cerrando conexion”, 0, 1);
dos.close();
btc.close();
LCD.clear();
LCD.drawString(“Finalizado”, 0, 1);
Thread.sleep(2000);
}
}
Y el del kart:
import lejos.nxt.Motor;
import lejos.robotics.navigation.Pilot;
import lejos.robotics.navigation.TachoPilot;
import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.comm.BTConnection;
import lejos.nxt.comm.Bluetooth;
import java.io.*;
import java.lang.Math;
public class Kart {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
Pilot navigator = new TachoPilot(5.4f, 17.8f, Motor.A, Motor.C, true);
LCD.clear();
LCD.drawString(“Esperando…”, 2, 1);
LCD.refresh();
BTConnection btc = Bluetooth.waitForConnection();
LCD.clear();
LCD.drawString(“Conectado”, 2, 1);
Motor.B.setPower(100);
DataInputStream dis = btc.openDataInputStream();
while(!Button.ESCAPE.isPressed()){
int i = dis.readInt();
if (i > 1000){
//Acelerar
navigator.backward();
navigator.setMoveSpeed((i – 1000)/2);
}else if (i > 800){
navigator.forward();
navigator.setMoveSpeed(Math.abs(i – 1000)/2);
}else{
//Girar
boolean signo;
if (i >= 0)
signo = true;
else
signo = false;
i = i/10;
i = i*i;
if (i < 40){
if (signo)
Motor.B.rotateTo(-i);
else
Motor.B.rotateTo(i);
}else{
if (signo)
Motor.B.rotateTo(-40);
else
Motor.B.rotateTo(40);
}
}
}
Thread.sleep(2000);
LCD.clear();
LCD.drawString(“Cerrando conexion”, 0, 1);
dis.close();
btc.close();
Thread.sleep(2000);
}
}
Aquí tenéis un vídeo del funcionamiento
Son códigos de cierta complejidad, así que si tenéis alguna duda podéis preguntarnos en el foro.