Los espejos deberían pensárselo dos veces antes de devolver una imagen…
Jean Cocteu
En la lección anterior aprendimos qué era una función y para qué se utilizaba. También nombramos un tipo de función: Las funciones con retorno, que son en las que profundizaremos en este post. ¿Estáis preparados para dominar aún más el arte de las funciones?¿Queréis ser unos magos del flujo de programación? ¿O simplemente queréis hacer los programas más bonitos de la comunidad bitbloq? ¡Vamos a ello!
Para realizar los ejemplos de hoy, necesitarás:
- 1 x ZumBloq miniservo
- 1 x ZumBloq Potenciómetro
- 1 x ZumBloq Sensor de luz
- 1 x ZumBloq Zumbador
- 1 x ZumBloq LCD
- Una placa controladora ZUM BT 328 o compatible con Arduino UNO
- Un cable USB
El bloque “función con retorno” y el bloque “llamar a función con retorno”
Las funciones con retorno son muy parecidas a las funciones sin retorno pero su diferencia radica en para qué se utilizan.
Las funciones con retorno crean un “mini-programa” que se encarga de obtener, preparar o modificar una variable. La función con retorno nos devuelve ese valor justo cuando se lo pidamos, sin tenerle que decir una y otra vez al programa como obtener ese dato que necesitamos. Un ejemplo podría ser una función que se encargue de mapear el valor del potenciómetro y después retorne el valor ya mapeado del mismo componente, o también se podría hacer una función que según la distancia que viera el sensor de ultrasonidos te dijera si estás más o menos cerca del objeto que tienes delante (un programita así podría haber salvado el Titanic, por ejemplo).
Estas variables con las que jugamos en nuestras funciones con retorno pueden ser de cualquier tipo: numéricas, de texto o incluso vectores (esas variables con tres compartimentos que explicábamos en la lección del Joystick).
¿Veis el hueco que hay en el bloque “función con retorno”? Ahí debe ir la variable que la función va a devolver cuando se la llame. Poned un bloque de variable para indicarle qué es lo que tiene que devolver, aunque a veces puede ser útil poner un número o un texto que siempre sea el mismo (usando un bloque número o texto) como veremos más adelante.
¿Quién se ha fijado en que el bloque “llamar a una función con retorno” tiene la misma forma que el bloque “usar una variable”?
Exacto, tienen la misma forma porque el bloque de “llamar a función con retorno” encaja en cualquier sitio donde encajaría una variable. De hecho, si entendéis las variables, las funciones con retorno podrían ser como una variable que, antes de ver qué tienen dentro de la caja, justo antes de abrir la caja, ocurren cosas dentro de ella y después ya te permite ver el contenido.
Vamos a ver si lo entendemos del todo:
Ejemplo con los bloques de funciones con retorno
Programa que mueve el miniservo con el potenciómetro, en este caso usando una función
¿Recordáis como funcionaba el bloque mapear? Echarle un vistazo al ejemplo del link, os ayudará a entender cómo funciona el ejemplo.
Como podéis ver, de nuevo tenemos dos columnas de bloques: el programa principal a la izquierda y la declaración de la función “Recibir_valor_del_potenciómetro” a la derecha. Esta función tiene el cometido que indica su nombre, cuando la llamemos (con el bloque de “llamar a una función con retorno” del programa principal) va a crear una variable en la que almacenará el valor actual del potenciómetro. Después va a crear otra variable para guardar el valor del mapeado de la variable potenciómetro entre 0 y 180 (que son los grados que puede girar el miniservo) y por último, le hemos indicado que tiene que devolvernos el valor de la variable que tiene el mapeo guardado. De esta forma, cuando en el programa principal usamos el bloque “Recibir_valor_del_potenciometro”, se ejecuta rápidamente la función de arriba a abajo y ponemos el valor del mapeado en el hueco del servo de “Grados(0-180)”
El bloque “Si…devuelve…”
¿Y si quisiéramos que una misma función nos devolviera algo diferente dependiendo de, por ejemplo, la luz que hubiese en la sala o si tenemos o no pulsado el botón?
Al igual que en el bloque de control “Si…ejecutar”, tenemos un bloque para dotar de inteligencia a nuestras funciones, para conseguir que decidan algo en función de otro algo. Este es el bloque “Si…devuelve…”
Este bloque solo puede ir dentro de una función con retorno (tranquilo, bitbloq te lo recordará si se te olvida). En el primer hueco ha de ir una expresión lógica (de los bloques de lógica), y si esta es verdadera, la función terminará inmediatamente y devolverá el valor que le hayas puesto en el segundo bloque en forma de variable o un número o texto fijo.
Digo lo del número o texto fijo porque con este bloque tiene un montón de aplicaciones. Seguid con el siguiente ejemplo para ver uno muy útil.
Ejemplo con el bloque “Si…devuelve”
Antes de analizar el ejemplo, voy a explicaros la gracia del programa. Supongamos que estamos usando un sensor de iluminación que no es el de “Mi primer Kit de Robótica” (puesto que ya sabemos que éste devuelve valores entre 0 y 500 en función de la luz que incide sobre el sensor), pero, ¿y si desconocemos ese valor? Ahora supongamos que si te equivocases y el valor del sensor diera más de 500, el servo que esté usando se cortocircuitase y tuvieses que despedirte de tu preciado servo. ¿No creéis que sería perfecto crear una función que comprobase este valor antes de usar el servo? Vamos a ampliar un ejemplo que ya usamos en la lección del miniservo.
Programa con sensor de luz y comprobación de errores
Empecemos estudiando la pequeña función de abajo a la derecha. Muy simple ¿no? Si el sensor de luz da un valor mayor o igual que 500, la función devolverá la palabra “ERROR” y si no es así, no ejecutará el bloque “Si…devuelve” y pasará a devolver lo que que le corresponde por defecto: “CORRECTO”.
A continuación, en el programa principal, podemos ver como consta solo de un “Si…ejecutar…en cambio si…ejecutar” y lo que hay en las comprobaciones de los bloques de lógica son llamadas a la función de “Comprobación_valor_luz”, así que cuando el programa llegue a este bloque, se ejecutará la función y devolverá “CORRECTO” o “ERROR”, entrando así al bucle que nos interese: Si es correcto, moverá el servo, si no, avisará con el zumbador.
Como supongo que vosotros contaréis con un chachi-sensor-de-luz de nuestro kit de robótica, para probar este ejemplo podéis usar el potenciómetro (que os devolverá valores de entre 0 y 1023)
El bloque “Devuelve…”
Este bloque tiene la misma función que el anterior. Sin embargo, no incluye la expresión lógica, por lo que le da un poco más de versatilidad. De esta forma, podemos meter el bloque dentro de un condicional “Si..Ejecutar”, pero hacer más cosas antes de devolver el valor que nos interese. Vamos a ver un ejemplo en el cual creamos una función para saber si tenemos un objeto cerca, a media distancia o lejos del sensor de ultrasonidos.
Programa avisador de marcha atrás de los coches
En este ejemplo hemos creado una función con retorno que primero lee la distancia del sensor de ultrasonidos y la almacena en una variable. Tras esto, entra a un bloque “Si…Ejecutar” en el cual, según la distancia que haya en la variable, enciende un LED si esta muy cerca o lo apaga si esta más lejos. Además, cuando esta cerca devuelve la palabra “Cerca”, si esta a media distancia devuelve “Medio” y si esta lejos, no entra al condicional y ejecuta el devolver del final de la función, devolviendo “Lejos”.
En el programa principal tenemos únicamente un bloque zumbador, el cual va a sonar y sonar pero esperando un tiempo entre medias, y este tiempo dependerá de la palabra que nos devuelva la función anterior.
Mejorando las funciones: Funciones con parámetros de entrada
Estoy seguro de que en algún momento os habéis fijado en esa estrellita que acompañan a los bloques de “función con retorno” y “función sin retorno”. Al igual que en los bloques de control, no esta ahí solo para adornar.
La estrellita nos permite mejorar los bloques de función para hacerlos aún más potentes. Con ella podemos añadir…¡Parámetros de entrada!
-¿De qué me estás hablando? ¿Qué es eso de parámetros de entrada? ¡Suena a magia negra!
-Tranquilos, perdón, sí que suena difícil, pero vamos a ver que no lo es tanto.
Un parámetro de entrada es una variable de nuestro programa principal que le dejamos usar a la función, de esta forma podemos crear una función muy inteligente y reutilizable. Por ejemplo, podemos hacer una función que haga varias operaciones matemáticas a partir de dos valores que le demos como parámetros de entrada. O una función que si le damos como parámetro de entrada un 3 parpadee un LED 3 veces.
Cuando creamos un parámetro de entrada en el bloque “función con retorno” o “función sin retorno”, a su vez aparece en el bloque “llamar a función…” (del tipo correspondiente) un hueco para colocar una variable o número, que será la que estemos introduciendo en la función para ser usada. A su vez, se está creando una variable asociada al parámetro de entrada, que valdrá lo mismo que lo que pongáis en el hueco del que os acabo de hablar. Es importante saber que estas variable que se han creado con los parámetros de entrada, solo pueden ser usadas dentro de la función.
Vamos a ver un ejemplo para entenderlo mejor,
Ejemplo con funciones con parámetros de entrada
Programa que hace operaciones con dos parámetros de entrada y muestra el resultado en el LCD
En este ejemplo podemos ver cómo se ha creado una función con retorno y con parámetros de entrada. Los parámetros de entrada son “entrada_1″ y “entrada_2″ y se ha colocado en los huecos dos variables: “dato 1″ y “dato 2″. Ahora “entrada_1″ vale lo mismo que “dato 1″ y “entrada_2″ lo mismo que “dato 2″, pero ahora podemos usar “entrada_1″ y “entrada_2″ dentro de la función para realizar operaciones matemáticas con ellas.
Al final, la función devuelve el valor final de la operación al programa principal, donde se imprime en el LCD. (para ver como funciona ésta última, pincha aquí)
Ahora que ya sabemos la teoría sólo nos queda practicar para acabar de dominarlas del todo. Intentad usarlas siempre que podáis y ya veréis como empezáis a verlas como una gran ayuda.
-
Ejemplo funciones con retorno Potenciometro y servo
Programa que mueve el miniservo con el potenciómetro, pero usando una función | CC-BY-SA
-
Ejemplo Si...devuelve Comprobacion de Errores
Programa con sensor de luz y comprobación de errores | CC-BY-SA
-
Ejemplo Devuelve Sensor de aparcar
Programa que simula un sensor de aparcamiento del coche, usando el bloque devuelve | CC-BY-SA
-
Ejemplo Funciones con parámetros
Programa que hace operaciones con dos parámetros de entrada y muestra el resultado en el LCD | CC-BY-SA