Programación del giróscopo

modeloYa hicimos un artículo de introducción al giróscopo, ahora vamos a trabajar con la programación del giróscopo mediante NXT-G, robotC y LeJOS. La información que recibimos del sensor nos indica tanto la velocidad de giro como el sentido en el que se produce. Veamos cómo emplear dicha información con un ejemplo sencillo.

El primer problema que se nos plantea es el de la calibración. Necesitamos determinar el valor de offset y tener en cuenta el drift (o deriva) tal y como se explicaba en la teoría.

Para determinar el offset basta con mostrar en pantalla las medidas de giróscopo durante unos segundos cuando éste se encuentra en reposo, veremos que el giróscopo se mantiene estable en un punto cercano al 0 (en NXT-G) o a 600 en RobotC/LeJOS. Para evitar el error de una sola medición, podemos tomar una serie de medidas y promediar.

En NXT-G podemos indicarle el valor de offset bien directamente en el bloque, o bien mediante un cable de datos. El programa de calibrado es el siguiente.

Calibrado NXT-G

Tomamos varias medidas de nuestro giróscopo (recordemos que debe estar en reposo), calculamos su promedio y guardamos su valor en la variable offset.

En RobotC

//Calibrado del offset
int offset = 0;
for(int i = 0; i < 10; i++){
offset = offset + SensorValue(GyroSensor);
}
offset = offset / 10;
nxtDisplayCenteredTextLine(4, "Offset: %d", offset);
wait1Msec(3000);

Para hacer uso del offset calculado, tendríamos que añadir esta línea de código al tomar la medición:

valor_gyro = SensorValue(GyroSensor) - offset;

En LeJOS

//Calibrado del offset
for(int i = 0; i <= 9; i++){
med = med + gyro.readValue();
}
med = med / 10;
med = med + 600;

El calibrado del offset se ha hecho mediante una media absoluta de diez mediciones del giroscópio; en caso de LeJOS es necesario sumarle 600 a este offset inicial. Para usar ese valor de offset calculado deberemos añadir esta línea de código:

gyro.setOffset((int)med);
Esta línea nos permitirá fijar el valor de offset para el giróscopo durante todo el programa, no será necesario descontarla de cada medición, como en RobotC.

Ejemplo: ¿Cuánto ha girado nuestro motor?

Nuestro programa de ejemplo nos tiene que mostrar lo que ha girado nuestro motor, pero medido por el giróscopo. Para ello, tras la calibración que hemos visto anteriormente, tendremos que tomar una serie de mediciones que nos permitirán mostrar en pantalla el ángulo en grados que ha girado el motor. Recordemos que el valor que nos devuelve el giróscopo está en grados/segundo, por lo que serán necesarias algunas operaciones para obtener los grados finales. En nuestro experimento programaremos el motor para que realice un giro determinado y presentaremos en el display tanto el valor del giro devuelto por el tacómetro como el valor de giro calculado por nuestro programa. Nuestro objetivo es que exista la menor disparidad entre ellos.

La toma de varias medidas a lo largo del movimiento del motor es importante, pues con el cálculo de la media tendremos mucha más precisión. Para el cálculo del ángulo recorrido, y dado que se trata del primer ejemplo de uso del giróscopo, aproximaremos realizando un muestreo de la velocidad angular equiespaciado en el tiempo mientras dura el experimento y supondremos que el ángulo recorrido es el producto de la velocidad angular media, calculada a partir de los datos anteriores, y multiplicada por el tiempo empleado.

En NXT-G

Programa NXT-G

En RobotC

const tSensors GyroSensor= (tSensors) S4;
long valor_gyro;
int grados_total = 0;

task main()
{
// Calibrado del offset
int offset = 0;
for(int i = 0; i < 10; i++){
offset = offset + SensorValue(GyroSensor);
}
offset = offset / 10;
nxtDisplayCenteredTextLine(4, “Offset: %d”, offset);
wait1Msec(3000);

// Mediciones
motor[motorC] = 20;
for(int j = 0; j < 20; j++){
valor_gyro = SensorValue(GyroSensor) – offset;
grados_total = grados_total + valor_gyro;
wait1Msec(50);
}
motor[motorC] = 0;

// Cálculo y muestra de mediciones
grados_total = grados_total / 20;
nxtDisplayCenteredTextLine(3, “El valor es %d”, grados_total);
nxtDisplayCenteredTextLine(5, “El valor es %d”, nMotorEncoder[motorC]);
wait1Msec(4000);
}

En LeJOS

import lejos.nxt.Button;
import lejos.nxt.LCD;
import lejos.nxt.Motor;
import lejos.nxt.SensorPort;
import lejos.nxt.addon.GyroSensor;

public class Giroscopo {
public static void main(String[] args) throws Exception {
GyroSensor gyro = new GyroSensor(SensorPort.S4);
float med = 0;
int cont = 0, vgyro = 0;

Motor.C.setSpeed(200);
Thread.sleep(100);

// Calibrado del offset
for(int i = 0; i <= 9; i++){
med = med + gyro.readValue();
}
med = med / 10;
med = med + 600;

gyro.setOffset((int)med);
LCD.drawInt(gyro.readValue(), 6, 4);
Thread.sleep(2000);
Motor.C.forward();

// Mediciones
while(cont < 20){
vgyro = vgyro + gyro.readValue();
cont++;
Thread.sleep(50);
}
Motor.C.stop();

// Cálculo y muestra de mediciones
vgyro = vgyro / cont;
LCD.drawInt(vgyro, 6, 4);
Thread.sleep(2000);
Motor.C.rotateTo(0);
}
}

Aquí tenéis el vídeo del programa en NXT-G, tened en cuenta que todos los programas muestran prácticamente lo mismo, por eso nos hemos limitado a poner un sólo vídeo.

A continuación una foto de la pantalla al finalizar el programa, ya que en el vídeo no se aprecia bien.

pantalla

Problemas que hemos encontrado:

Para calcular el ángulo girado tenemos que tener en cuenta el tiempo que el motor ha estado girando además de la media de velocidad angular calculada anteriormente. En este caso sabemos que es de aproximadamente un segundo ya que tenemos esperas de 50 ms dentro de un búcle de 20 repeticiones. Esta espera es la que aparece en los ejemplos de código en las líneas 22 de RobotC y 32 de Java. En las pruebas realizadas obtenemos siempre que el ángulo mostrado por el giróscopo es superior al recorrido en realidad, y esto nos conduce a pensar que las esperas anteriores son, en la práctica, intervalos de mayor longitud puesto que debe incluirse el tiempo que el procesador emplea en su ejecución. Estos tiempos serán seguramente dependientes de factores como la tensión de alimentación (valor de carga de la batería) o temperatura. Hemos comprobado que suponiendo que el tiempo empleado en la ejecución de las líneas de código internas al bucle es de 3 ms los resultados obtenidos entre giróscopo y tacómetro coinciden (es decir, los tiempos de espera en el código son de 47 en lugar de 50 ms). Con objeto de eliminar las dependencias citadas anteriormente deberíamos medir el tiempo exacto empleado en la ejecución de cada bucle y así poder aplicar la corrección adecuada.

Otro problema es la deriva. Podemos observar que a pesar de haber calibrado el dispositivo, si lo dejamos en reposo mostrando en pantalla los grados de giro (con los programas que hemos visto anteriormente) descubriremos que no siempre se mantiene en el 0. Dedicaremos un artículo posterior para obtener mejores resultados con el giróscopo.

Comments are closed.