Ir al contenido principal

Programación estructurada

¿Qué es la programación estructurada?

La programación estructurada es la forma de escribir programas en la que el flujo de ejecución se puede leer de arriba hacia abajo, sin saltos inesperados. Un programa estructurado tiene un solo punto de entrada, un solo punto de salida, y está armado combinando tres estructuras que se pueden anidar entre sí sin límite.

La idea parece obvia hoy, pero no lo era. En los años sesenta los programas se escribían con saltos libres: la ejecución podía brincar a cualquier línea en cualquier momento. Un programa de mil líneas con veinte saltos era imposible de seguir, y peor de corregir, porque no se podía saber por dónde había pasado el flujo. A fines de esa década varios autores demostraron que cualquier programa se puede escribir sin un solo salto, usando solo tres estructuras. Lo que parecía una limitación terminó siendo una ventaja enorme.

Por qué a un robot le importa

En un robot, la claridad del programa no es una cuestión de elegancia: es la diferencia entre poder arreglarlo y no poder. Un robot que se mueve tiene comportamientos que aparecen solo en ciertas combinaciones de sensores y estados, y si el código no se puede seguir leyéndolo, encontrar el error se vuelve cuestión de suerte.

Hay otra razón más práctica: cuando un robot falla, casi nunca falla el hardware. Y un programa desordenado hace imposible distinguir si el problema es el sensor, la conexión o la lógica.

Las tres estructuras

Con estas tres alcanza para escribir cualquier programa, por complicado que sea. Todo lo demás —el if, el while, el for— son formas concretas de escribirlas.

Las tres estructuras de control de la programación estructurada: secuencia, en la que las instrucciones se ejecutan una tras otra; selección, en la que el programa elige entre dos caminos; e iteración, en la que se repite un bloque Secuencia leer el sensor calcular mover el motor una instrucción tras otra Selección leer el sensor ¿hay algo? sí esquivar no seguir el programa elige entre dos caminos Iteración leer el sensor ¿hay algo? sí esquivar se repite mientras haga falta
Los tres casos están dibujados con el mismo robot: leer un sensor y decidir. La secuencia hace todo siempre; la selección elige un camino; la iteración vuelve atrás y repite. La línea punteada es el regreso.
Estructura Qué hace Cómo se escribe
Secuencia Ejecuta una instrucción después de otra, en orden. Escribir las líneas una debajo de la otra.
Selección Evalúa una condición y elige entre dos caminos. if y else
Iteración Repite un bloque mientras se cumpla una condición, o una cantidad de veces. while, do while, for

Orden y coherencia del código

Que un programa use las tres estructuras no alcanza para que sea legible. Estas son las prácticas que hacen la diferencia en un proyecto de robot, donde el código lo va a leer otra persona: tu compañero, tu profesor, o vos mismo dentro de dos semanas.

Los valores van arriba, con nombre

Los números que definen el comportamiento del robot —el pin de un sensor, la velocidad de los motores, el umbral de distancia— van al principio del programa, con un nombre que explique qué son:

const int PIN_SENSOR = 7;
const int VELOCIDAD    = 150;
const int DISTANCIA_MINIMA = 20;

En lugar de repartir el número 20 por todo el programa, queda en un solo lugar. Cuando haya que cambiarlo —y siempre hay que cambiarlo— se toca una línea en vez de diez. A esos números sueltos se los llama números mágicos, justamente porque nadie sabe de dónde salieron.

La indentación no es estética

El sangrado muestra qué está adentro de qué. Sin él, encontrar el final de un bloque anidado dentro de otro es cuestión de contar llaves. Con él, se ve de un vistazo.

Comentarios que expliquen el porqué

Un comentario útil no repite lo que ya dice el código, sino que explica una decisión:

  • Inútil: // sumo uno a la variable — ya se ve en el código.
  • Útil: // el motor no arranca por debajo de 60 — explica por qué ese número está ahí.

Los comentarios que más valen en robótica son los que registran mediciones: "en el aula con luz artificial el sensor devuelve 780". Ese dato no se deduce del código y se pierde si no está escrito.

Funciones: dividir para ordenar

Una función es un bloque de código con un nombre, que hace una sola tarea. En un robot son la herramienta principal para que el programa se entienda: si cada tarea está adentro de una función con un nombre claro, el programa principal se convierte en una lista de lo que el robot hace.

Así se lee el programa principal de un robot que esquiva obstáculos:

void loop() {
  int distancia = medirDistancia();

  if (distancia < DISTANCIA_MINIMA) {
    esquivar();
  } else {
    avanzar();
  }
}

Cuatro líneas, y se entiende todo el comportamiento del robot: mide, y según lo que mida esquiva o avanza. No hace falta saber cómo mide ni cómo esquiva. Eso es programación estructurada aplicada.

Y si hay un problema con la medición, se sabe exactamente en qué función buscarlo: en medirDistancia(), no en todo el programa.

Variables y estados

Este es el concepto que separa un robot que funciona de uno que se comporta de forma errática, y casi nunca se enseña de forma explícita.

Una variable es un lugar donde el programa guarda un valor. La mayoría son temporales: se usan dentro de una función y desaparecen. Pero hay otras que cumplen una función distinta: recordar algo entre un ciclo del programa y el siguiente. A eso se lo llama estado.

Por qué hace falta recordar

El programa del robot se repite miles de veces por segundo y, en cada vuelta, empieza de cero. No sabe qué pasó en la vuelta anterior. Si el robot tiene que "ir al punto B después de haber pasado por A", eso no se puede deducir del sensor en este instante: hay que haberlo guardado.

Ejemplos de estado en un robot real:

  • Hacia dónde va ahora mismo, para no cambiar de rumbo en cada vuelta.
  • Cuántas vueltas lleva dadas una rueda, para saber cuánto avanzó.
  • Qué estaba haciendo antes de perder la línea, para intentar recuperarla.

El cuidado que hay que tener

Las variables de estado son globales: se declaran fuera de las funciones para que todas las puedan ver. Y ahí está el riesgo: si el programa se llena de variables globales, cualquier función puede cambiarlas en cualquier momento, y vuelve el problema que la programación estructurada vino a resolver. La regla es simple: global solo lo que realmente tiene que sobrevivir entre ciclos; todo lo demás, adentro de su función.

Una máquina de estados

Cuando un robot tiene varios comportamientos, la forma más clara de organizarlos es la máquina de estados. La idea es simple: el robot está siempre en un estado de una lista corta, y las transiciones a otro estado dependen de lo que leen los sensores.

Un ejemplo: seguir una línea

Un robot seguidor de línea puede estar en cuatro situaciones distintas. Cada una tiene una acción y una condición para pasar a la siguiente:

Estado Qué hace Cuándo cambia
Buscando Gira despacio sobre su eje, barriendo con los sensores Cuando alguno de los sensores ve la línea
Siguiendo Avanza corrigiendo el rumbo según qué sensor esté sobre la línea Cuando ningún sensor ve la línea
Perdido Retrocede un poco y busca, porque la línea se cortó Si la vuelve a encontrar, o si pasa demasiado tiempo
Detenido Se queda quieto Cuando el usuario lo apaga o se acabó el recorrido

Cómo se escribe

Cada estado es una constante con nombre, y el programa principal decide qué hacer según cuál esté activo:

const int BUSCANDO  = 0;
const int SIGUIENDO = 1;
const int PERDIDO   = 2;

int estado = BUSCANDO;

void loop() {
  int linea = leerSensores();

  switch (estado) {
    case BUSCANDO:
      girarDespacio();
      if (linea > 0) estado = SIGUIENDO;
      break;

    case SIGUIENDO:
      avanzarCorrigiendo(linea);
      if (linea == 0) estado = PERDIDO;
      break;

    case PERDIDO:
      retroceder();
      if (linea > 0) estado = SIGUIENDO;
      break;
  }
}

Comparado con la alternativa —una cadena de if anidados dentro de otro if— esta versión tiene tres ventajas concretas:

  • Se lee como una lista. Cada estado es un caso, y no hay que seguir el rastro de condiciones para saber qué puede hacer el robot.
  • Agregar un comportamiento no rompe nada. Un estado nuevo es un caso más.
  • Al depurar, se sabe dónde está el robot. Si se imprime el estado por el monitor serie, se ve en qué situación está en cada momento, en lugar de adivinar.

Este tipo de organización es exactamente lo que hace que un robot con varios comportamientos siga siendo un programa entendible en lugar de un conjunto de condiciones que se pisan entre sí.

Resumen

Concepto La idea que hay que recordar
Programación estructuradaEl flujo se lee de arriba hacia abajo, sin saltos.
Las tres estructurasSecuencia, selección e iteración. Con esas tres se escribe cualquier programa.
Constantes con nombreLos valores del robot van arriba, no repartidos como números mágicos.
Una función, una tarealoop() debería leerse como un índice de lo que hace el robot.
EstadoLo que el robot recuerda entre un ciclo y el siguiente. Sin eso, empieza de cero cada vez.
Máquina de estadosUn estado por comportamiento, y transiciones según los sensores. Es la forma más clara de organizar un robot con varias conductas.

Ver las sentencias IF, FOR y WHILE (EFSI I)