En esta anotación aprenderemos a programar las maniobras fundamentales del robot: hacia delante, atrás, giros y rotaciones. Es fundamental que comprendamos bien estas maniobras y sus técnicas de programación porque las utilizaremos de ahora en adelante, aunque ahora el robot andará “a ciegas” porque aún no hemos instalado los sensores que le permitan informarse acerca del entorno que lo rodea. Nuestra tarea en los próximos pasos será instalar estos dispositivos que permitirán a nuestro robot esquivar obstáculos o seguir un camino marcado en el suelo.
Como parte indispensable de este paso, también vamos a aprender a poner a punto y calibrar la navegación del robot para que se mueva en línea recta, haga giros precisos y podamos hacer cálculos de distancias. Al final hay un vídeo donde se muestran en la práctica los mismos pasos que iremos dando.
En la imagen inferior vemos los diferentes movimientos que puede hacer el robot (como ya indicamos en pasos anteriores, debemos recordar que cuando el robot se mueve hacia delante su rueda derecha gira en el sentido de las agujas del reloj, mientras que la izquierda lo hace en sentido contrario):
Movimiento hacia delante
Con el programa que indicamos a continuación el robot avanzará en línea recta durante tres segundos.
Recordemos que el argumento Duración del comando PULSOUT controla la velocidad y la dirección de giro de los servos. Los argumentos StartValue y EndValue del bucle FOR…NEXT controlan por su parte el número de pulsos que se envían. Dado que cada pulso tiene la misma duración, el argumento EndValue también controla el tiempo que funcionan los servos.
- ‘ Programa de movimiento. Avancetressegundos.bs2
- ‘ El robot avanza hacia delante durante tres segundos
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- Counter VAR Word
- FREQOUT 4, 2000, 3000 ‘señal de inicio/reset
- FOR counter = 1 TO 122 ‘marcha hacia delante durante 3 s
- PULSOUT 13, 650
- PULSOUT 12, 850
- PAUSE 20
- NEXT
- END
Controlando la distancia y la velocidad
Si cambiamos por ejemplo el valor EndValue del bucle FOR…NEXT de 122 a 61, haremos que el robot se desplace hacia delante durante la mitad de tiempo, y que recorra, por tanto, la mitad de la distancia.
Hagamos la comprobación:
Ahora podemos repetir lo mismo pero cambiando el valor EndValue a 244. ¿Qué ocurre?
Los cambios que hemos hecho están relacionados con la distancia que recorre el robot, pero también podemos modificar su velocidad. Por ejemplo, si ajustamos el parámetro Duración de PULSOUT cerca de 650 o 850, los servos girarán a su máxima velocidad; mientras que si se aproximan a 750, haremos que se muevan más lentos.
Modificamos el programa de la siguiente forma:
PULSOUT 13, 720
PULSOUT 12, 780
Mover el robot hacia atrás, rotarlo y pivotarlo
Todo lo que tenemos que hacer para conseguir otros movimientos del robot es utilizar diferentes combinaciones del parámetro Duración del comando PULSOUT. Por ejemplo, estas dos instrucciones hacen que el robot vaya hacia atrás:
PULSOUT 13, 850
PULSOUT 12, 650
Estas dos para que el robot gire a la izquierda:
PULSOUT 13, 650
PULSOUT 12, 650
Y éstas para que lo haga a la derecha:
PULSOUT 13, 850
PULSOUT 12, 850
Podemos combinar estos comandos para el robot vaya en diferentes direcciones como muestra el ejemplo del siguiente programa:
- ‘ Programa de movimiento. Delanteizquierdaderechaatras.bs2
- ‘ Hacer que el robot realice los cuatro movimientos básicos
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- Counter VAR Word
- FREQOUT 4, 2000, 3000 ‘señal de inicio/reset
- FOR counter = 1 TO 122 ‘marcha hacia delante durante 3s
- PULSOUT 13, 650
- PULSOUT 12, 850
- PAUSE 20
- NEXT
- PAUSE 200 ‘espera
- FOR counter = 1 TO 24 ‘rotación izquierda ¼ de vuelta
- PULSOUT 13, 650
- PULSOUT 12, 650
- PAUSE 20
- NEXT
- PAUSE 200 ‘espera
- FOR counter = 1 TO 24 ‘rotación derecha ¼ de vuelta
- PULSOUT 13, 850
- PULSOUT 12, 850
- PAUSE 20
- NEXT
- PAUSE 200 ‘espera
- FOR counter = 1 TO 122 ‘retroceso
- PULSOUT 13, 850
- PULSOUT 12, 650
- PAUSE 20
- NEXT
- END
También podemos hacer que el robot pivote sobre una rueda. Para ello basta con que sólo gire una rueda mientras la otra permanece parada. Por ejemplo, si se quiere que la rueda izquierda permanezca parada y la derecha gire hacia delante para que el robot pivote, se deberán utilizar las siguientes líneas de código:
PULSOUT 13, 750
PULSOUT 12, 650
Si por el contrario se quiere que pivote hacia delante y a la derecha, simplemente se detiene la rueda derecha y hacemos que la rueda izquierda gire hacia delante:
PULSOUT 13, 850
PULSOUT 12, 750
Hacia atrás y la derecha:
PULSOUT 13, 650
PULSOUT 12, 750
Hacia atrás y a la izquierda:
PULSOUT 13, 750
PULSOUT 12, 850
Retocando las maniobras básicas
Más abajo veremos un vídeo con todas estas maniobras realizadas en la práctica y comprobamos que, a pesar de que el robot está programado para avanzar en línea recta, es frecuente que se vaya desviando ligeramente hacia uno de los lados. Vamos a corregir este desajuste mediante el software, para lo cual deberemos modificar el programa Avancetressegundos.bs2 para que en vez de 3 segundos se mueva durante 10, tiempo necesario para comprobar si se desvía o no. Esta modificación se hace cambiando el valor de EndValue en el comando FOR Counter de 122 a 407:
- ‘ Programa de movimiento. Avancediezsegundos.bs2
- ‘ El robot avanza hacia delante durante diez segundos
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- Counter VAR Word
- FREQOUT 4, 2000, 3000 ‘señal de inicio/reset
- FOR counter = 1 TO 407 ‘giro hacia delante durante 10 s
- PULSOUT 13, 650 ‘servo izquierdo máxima velocidad
- PULSOUT 12, 850 ‘servo derecho máxima velocidad
- PAUSE 20
- NEXT
- END
Pongamos por caso que el robot se desvía hacia la izquierda. Esto puede pasar por dos motivos: o bien la rueda izquierda gira más lenta, o es la rueda derecha la que lo hace más rápido. Como el robot está programado para que cada servo gire a la máxima velocidad, lo más lógico será pensar que la rueda derecha debería girar un poco más despacio.
Ya hemos visto que la velocidad de los servos está determinada por el argumento Duración del comando PULSOUT. Cuanto más se acerque este valor a 750, más lento girará el servo. Esto significa que hay que cambiar el valor 850 del comando PULSOUT 12 a un valor más cercano a 750. Si el robot no se desvía demasiado, con un valor de 837 será suficiente. Si por el contrario el grado de desvío es grande, habrá que poner como mínimo un valor de 810. Como vemos, será necesario hacer varias pruebas modificando este argumento hasta lograr que el robot siga una línea completamente recta.
En nuestro caso, ha sido necesario un valor de 800 para conseguir un movimiento rectilíneo.
Al igual que hemos hecho para el avance, tendremos que hacer los mismos ajustes para el movimiento hacia atrás.
También es posible regular los giros del robot mediante el software. El tiempo que dura el movimiento de las ruedas del robot es lo que determina el ángulo de giro. Como ya hemos visto que el comando que controla el tiempo de giro en el programa es el bucle FOR … NEXT, lo que tenemos que hacer es modificar el argumento EndValue para que gire más o menos según queramos.
En el programa Delanteizquierdaderechaatras.bs2 introdujimos una serie de órdenes para que el robot realizase distintos giros, por lo que si hay cualquier tipo de desviación deberemos modificar el contador del bucle FOR counter = 1 TO 24 y disminuir el tiempo de giro (probamos primero con 23, 22 etc.) Si sigue sin girar los 90o exactos, modificaremos el comando PULSOUT a un valor más cercano a 750, como hicimos para que fuese recto. Repetiremos la acción hasta que gire los 90o exactos.
Cálculo de distancias
Es frecuente que en las competiciones que se organizan los robots tengan que seguir un recorrido desde un punto inicial hasta un destino situado a cierta distancia, para luego regresar al punto de partida. Vamos a aprender a calcular distancias, para lo cual aplicamos la fórmula general de la velocidad:
Tiempo = distancia / velocidad
Distancia = velocidad x tiempo
Lo que traducido al funcionamiento de nuestro robot sería:
Tiempo de movimiento del servo = distancia recorrida / velocidad del robot
Para poder aplicar esta sencilla fórmula debemos calcular en primer lugar la velocidad del robot. La forma más fácil de hacerlo es poner una regla a su lado y ver qué distancia recorre en un tiempo dado (un segundo por ejemplo). Conociendo los centímetros que ha recorrido y el tiempo en segundos empleado en ello, podremos determinar la velocidad del robot en centímetros por segundo. Emplearemos para ello el siguiente programa:
- ‘ Programa de movimiento. Avanceunsegundo.bs2
- ‘ El robot avanza hacia delante durante un segundo
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- Counter VAR Word
- FREQOUT 4, 2000, 3000 ‘señal de inicio/reset
- FOR counter = 1 TO 41 ‘marcha hacia delante durante 1s
- PULSOUT 13, 650
- PULSOUT 12, 800
- PAUSE 20
- NEXT
- END
Este programa controla el movimiento del robot durante un segundo por lo que si ha recorrido 23 cm durante su ejecución, la velocidad será de 23 cm/s (es conveniente recordar que en un paso anterior aprendimos que los servos tardan 24,6 milisegundos (0,0246 segundos) en completar un ciclo de ejecución del bucle FOR … NEXT, por lo que el microcontrolador envía 40,65 pulsos cada segundo a los servos (1/0,0246 pulsos por segundo).
Una vez aclarado este concepto, podemos hacer que el robot se desplace en cualquier dirección una distancia concreta. Por ejemplo, sabiendo la velocidad que alcanza, podemos calcular el tiempo que necesitaría el robot para recorrer una distancia de 51 centímetros:
Tiempo = 51 cm / 23 cm/s = 2,22 s
Cuando tenemos este dato, basta calcular los pulsos que han de enviarse a los servos para que el robot recorra esa distancia, teniendo en cuenta que para que el robot se mueva durante un segundo son necesarios 40,65 pulsos:
Pulsos = 2,22 s x 40,65 pulsos/s = 90,24 pulsos = 90 pulsos
90 es el valor que tendremos que usar en el argumento EndValue del bucle FOR … NEXT
En cualquier caso tenemos que tener presente que estas mediciones no son completamente exactas. No hemos tenido en cuenta, por ejemplo, que el robot necesita un determinado número de pulsos para alcanzar la máxima velocidad, ni tampoco la distancia que recorre hasta que se detiene por completo o el hecho de que los servos girarán más despacio cuando las baterías pierdan potencia.
Maniobras de aceleración y desaceleración
Lo que pretendemos es que el robot acelere y desacelere de forma gradual. De esta forma conseguiremos que los servos y las baterías duren más y que el arranque y la parada no sean tan bruscos.
La clave para acelerar es ajustar el parámetro Duración del comando PULSOUT. Gracias al bucle FOR … NEXT podemos hacer que el robot acelere:
PulseCount VAR Word
FOR pulseCount = 1 TO 100
PULSOUT 13, 750 – pulseCount
PULSOUT 12, 750 + pulseCount
PAUSE 20
NEXT
Cada vez que se ejecuta el bucle FOR … NEXT la variable pulseCount se incrementa en 1. A medida que el valor de pulseCount es mayor, la velocidad de los servos también. La primera vez que se ejecuta el bucle, la variable pulseCount vale 1, que es lo mismo que usar los comandos PULSOUT 13, 749 y PULSOUT 12, 751. La segunda vez, la variable valdrá 2, y así, a la centésima vez que hemos ejecutaado el bucle, la variable pulseCount valdrá 100 que es lo mismo que usar los comandos PULSOUT 13, 650 y PULSOUT 12, 850 (máxima velocidad hacia delante)
Si por el contrario hacemos que el bucle FOR … NEXT reduzca la variable pulseCount, el robot desacelerará hasta pararse. Hagamos las pruebas:
- ‘ Programa de movimiento. Arranqueyparo.bs2
- ‘ El robot acelera y luego decelera hasta pararse
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- pulseCount VAR Word ‘contador del bucle FOR … NEXT
- FREQOUT 4, 2000, 3000 ‘señal de inicio/reset
- ‘aceleración gradual
- FOR pulseCount = 1 TO 100 ‘bucle aceleración de 100 pulsos
- PULSOUT 13, 750 – pulseCount
- PULSOUT 12, 747 + pulseCount
- PAUSE 20
- NEXT
- ‘avance constante de 75 pulsos
- FOR pulseCount = 1 TO 75
- PULSOUT 13, 650
- PULSOUT 12, 800
- PAUSE 20
- NEXT
- ‘desaceleración hasta detenerse
- FOR pulseCount = 100 TO 1 ‘bucle desaceleración de 100 pulsos
- PULSOUT 13, 750 – pulseCount
- PULSOUT 12, 747 + pulseCount
- PAUSE 20
- NEXT
- END
Facilitar los movimientos con subrutinas
En los siguientes pasos de la construcción del robot vamos a programarlo para que sea capaz de realizar maniobras con el fin de evitar obstáculos. Una de las formas más eficientes de hacerlo es realizando maniobras pre-programadas mediante el empleo de subrutinas. Ahora vamos a aprender a crear y utilizar esta herramienta.
Una subrutina es una secuencia de instrucciones que se repite en diversas ocasiones a lo largo del programa principal. Para no tener que reescribirla e insertarla cada vez que se necesite, lo que hacemos es ponerla como un programa independiente al que se “llama” cada vez que sea preciso.
Hay dos partes dentro de una subrutina en PBASIC. La primera es la “llamada a la subrutina”, es decir, la instrucción que hace que una vez que el programa llegue allí, se ejecute la parte de código que se contiene dentro de la subrutina. La otra parte es la propia subrutina en sí, la parte reutilizable del código. La subrutina comienza cuando se referencia con GOSUB su nombre (también llamado etiqueta) y finaliza con el comando RETURN, que devuelve el control a la siguiente instrucción después de GOSUB. El código que hay entre la etiqueta del nombre de la subrutina y RETURN es lo que se ejecutará en cada llamada a esa subrutina:
DO
DEBUG “Antes de la subrutina”, CR
PAUSE 1000
GOSUB Mi_subrutina
DEBUG “Después de la subrutina”, CR
PAUSE 1000
LOOP
Mi_subrutina:
DEBUG “Subrutina en ejecución”, CR
PAUSE 1000
RETURN
Este trozo de código nos muestra una llamada a una subrutina y la propia subrutina. Como hemos dicho, la llamada a la subrutina se realiza con el comando GOSUB y el nombre de la subrutina, en nuestro caso “Mi_subrutina” (ojo con los espacios en blanco). Una vez se inicia la subrutina se ejecuta línea a línea hasta encontrar el comando RETURN que obliga a salir de la subrutina y continuar ejecutando el programa en el punto en que se dejó.
Vamos a usar esta herramienta para manejar los movimientos del robot:
- ‘ Programa de movimiento con subrutinas. Movimientoconsubrutina.bs2
- ‘ El robot realiza los movimientos básicos mediante subrutinas
- ‘ {$STAMP BS2}
- ‘ {$PBASIC 2.5}
- Counter VAR Word
- FREQOUT 4, 2000, 3000 ‘señal de inicio/reset
- GOSUB Delante
- GOSUB Izquierda
- GOSUB Derecha
- GOSUB Atras
- END
- ‘movimiento hacia delante
- Delante:
- FOR counter = 1 TO 64
- PULSOUT 13, 650
- PULSOUT 12, 800
- PAUSE 20
- NEXT
- PAUSE 200
- RETURN
- ‘giro a la izquierda
- Izquierda:
- FOR counter = 1 TO 24
- PULSOUT 13, 650
- PULSOUT 12, 650
- PAUSE 20
- NEXT
- PAUSE 200
- RETURN
- ‘giro a la derecha
- Derecha:
- FOR counter = 1 TO 24
- PULSOUT 13, 850
- PULSOUT 12, 850
- PAUSE 20
- NEXT
- PAUSE 200
- RETURN
- ‘movimiento hacia atrás
- Atras:
- FOR counter = 1 TO 64
- PULSOUT 13, 840
- PULSOUT 12, 650
- PAUSE 20
- NEXT
- RETURN