jueves, 31 de enero de 2013

Aprender a programar: una breve introducción

Este mes hace 20 años que me dedico profesionalmente al mundo del desarrollo de software, la mitad de ellos programando distintas aplicaciones en C++. Aunque desde 2006 no participo directamente en la parte de programación, me sigue fascinando tanto como el primer día (hacia junio de 1983) que escribí mi primer programa en un ZX-81 (increíble, tenía 1 KB de memoria y la CPU procesaba a 3,25Mhz).

[caption id="attachment_902" align="alignright" width="115"]Sinclair ZX81 Sinclair ZX81[/caption]

Tanto me fascina que en mi tiempo libre sigo ampliando conocimientos y habilidades en programación, realizando software para la creación de comportamientos para robots.

Esta fascinación me lleva también a compartir lo aprendido y ayudar a otras personas a que se animen a programar, especialmente robots, y de aquí todos estos artículos y mi participación en distintos foros de robótica.

Un poco de perspectiva: programación y desarrollo de software

Una parte fundamental del desarrollo de software es la programación, durante la cual se crea el código fuente con el que se generará el ejecutable a utilizar. Pero para crear este código fuente hemos de tener muy claro:

- qué ha de hacer y cómo sabemos que lo hace correctamente

- cómo vamos a estructurar este código fuente

- qué pruebas hacer para asegurarnos que el programa funciona correctamente

Sin obtener unas respuestas claras y reales a estas preguntas la programación se complicará tanto que en lugar de disfrutar programando nos parecerá un suplicio; probablemente sin conseguir que el programa funcione correctamente.

¿Qué necesito aprender para poder programar?

Igual que en un iceberg, la mayor parte no está a la vista.

1.- La parte obvia y más visible es aprender a utilizar:

  • un lenguaje de programación, como C, C++, C# o Java, por mencionar sólo los más conocidos,



  • las herramientas necesarias para crear un ejecutable con el programa escrito, como, por ejemplo, GNU C/C++ o Visual Studio de Microsoft


2.- Pero, realmente, mientras se aprende el lenguaje escogido es imprescindible aprender algunas cuestiones básicas y comunes a todos ellos:

  • cómo secuenciar las instrucciones a ejecutar (condiciones, bucles, etc.)



  • cómo guardar los datos (variables, objetos, arrays, listas, etc.)


3.- Y, donde empieza realmente la diversión, buscando el resultado correcto con sencillez, eficiencia y/o eficacia:

  • qué pasos ha de realizar el programa para que el resultado sea correcto (algoritmos)



  • cual es la mejor forma de estructurar el programa (arquitectura general del programa, diseño de clases y métodos o funciones)


Un ejemplo muy sencillo

[caption id="attachment_921" align="alignright" width="126"]Dynamixel AX12 Dynamixel AX12[/caption]

Ejemplo extraído de leyendo y moviendo Dynamixel AX-12 (I)  (Dynamixel son servomotores fabricados por Robotis)

Respecto el punto anterior 1:

  • El lenguaje utilizado es C



  • la herramienta utilizada para generar el ejecutable (un .hex para un microcontrolador en este caso) es Win AVR que utiliza, a su vez, GNU C.


[sourcecode language="c"]

int main(void)
{
init();

while(true) // repetiremos eternamente este bucle
{
int id=obtenerId(); // obtenemos el ID del AX-12 a utilizar
int posicion=obtenerPosicion(); // obtenemos la posición en la que situar el AX-12 seleccionado
dxl_write_word( id, P_GOAL_POSITION_L, posicion); // enviamos la orden al Dynamixel
}

return 0;
}
[/sourcecode]

Respecto el punto 2:

  • La secuencia principal es muy sencilla. Una repetición eterna ejecutando tres funciones: obtenerId, obtenerPosicion y dxl_write_word. Pero revisando qué hacen estas funciones veréis que a su vez incluyen, cada una de ellas, otras secuencias y llamadas a otras funciones. La estructura general es como un árbol, donde del tronco (main o parte principal) salen diversas ramas de las cuales pueden aparecer otras nuevas y así hasta varios niveles.



  • Los datos utilizados en este nivel principal son muy sencillos, guardaremos números enteros, uno con el identificador del servo a utilizar, id y otro con la  posición donde lo situaremos, posicion.


Veamos el contenido de obtenerId:

[sourcecode language="c"]
int obtenerId()
{
/*
Creamos una variable de un tamaño amplio, 256 bytes (posiciones de un carácter), aunque con 4
valdría, pero si se introdujeran más carácteres de los definidos provocaría un error.
*/
char cadena[256];

/*
Y otra variable de tipo entero, es recomendable asignar siempre un valor, en este caso
la inicializamos con el valor mínimo, 1
*/
int ax12Id=1;

// puts es muy similar a printf, muestra la cadena que recibe como parámetro por la pantalla
puts ("nVamos a mover un Dynamixel a voluntad. V02");

do
{// inicio del bucle
puts ("Introduce el ID del servo a mover, entre 1 y 18, ");
ax12Id=leerEnteroComoCadena(cadena); // llamamos a esta función; para entrar por pantalla el valor
// la admiración (!) es el operador lógico NOT. Repetiremos el bucle mientras el rango NO sea valido
}while(!enRangoValido(ax12Id, 1, 18));

// Mostramos el valor introducido
printf("ID del AX12: %in", ax12Id);

return ax12Id;
}
[/sourcecode]

Y, finalmente, respecto el punto 3:

  • como el ejemplo es muy sencillo el algoritmo utilizado también lo es:




    • inicializar (init)

    • eternamente hacer:

      • obtener datos del usuario (obtenerId y obtenerPosicion)

      • posicionar el servomotor con el identificador y posición introducidas (dxl_write_word)






  •  el programa está estructurado en distintas funciones que encapsulan el trabajo a realizar en pequeñas tareas, compartiendo información a través de los parámetros que reciben y el valor que retornan.



  • estas funciones están estructuradas en tres ficheros:

    • moviendoDynamixel.c

    • entrarDatos.c

    • myCM510.c


    ¿Por qué dividir en ficheros .c (módulos) y clases o funciones? Porque cuanto más modularizada y lógica sea la estructura más fácil es crearla, mantenerla y corregirla, pudiéndose reutilizar los elementos (módulos, clases, métodos y funciones) en distintos programas o partes de un mismo programa.

  • un detalle importante, la función init. Esta función está pensada para ser utilizada en muchos programas, no sólo en éste, ya que inicializa el controlador CM-510. Está incluida en el fichero myCM510.c , que contiene las funciones básicas necesarias para utilizar el controlador CM-510 (LEDs, teclas, zumbador,...)


Esquema del orden de la la ejecución de las funciones:

  1. main

    1. init

    2. <inicio bucle eterno>

    3. obtenerId

      1. leerEnteroComoCadena

      2. enRangoValido



    4. obtenerPosicion

      1. leerEnteroComoCadena

      2. enRangoValido



    5. dxl_write_word

    6. <fin bucle eterno>


     


Tutoriales más detallados

Robomind, programa gratuito, para uso personal, para empezar a programar de una forma muy fácil. Se puede utilizar con Lego Mindstorms.

[caption id="attachment_2279" align="aligncenter" width="150"]RoboMind RoboMind[/caption]

 

Introducción a la programación con C, libro/curso de la UOC (Universidad abierta de Cataluña) práctico y muy fácil de seguir.

La UPV /EHU tiene publicado este fantástico tutorial de programación (web. pdfs, zips,...)

Aprenda ANSI C como si estuviera en primero (pdf)

Curso de introducción a C de 13 páginas

Impresionante explicación sobre algoritmos (pdf)

Libros gratuitos y libres

Impresionante colección de libros gratuitos y libres, sobre programación y otros temas. Dos que me han parecido especialmente interesantes son:

- Introducción a la programación utilizando C, libro/curso de la UOC (Univ. Abierta de Cataluña)

- Programación orientada a objetos

- Práctica introducción a C++

- Divertido tutorial de C++

¿Y la programación Orientada a Objetos?

La programación orientada a objetos es un paso más para alcanzar una mejor concepción y estructuración del código fuente. Fundamentalmente consiste en encapsular en clases, y los objetos que se generan de ellas, agrupando datos y las operaciones que los manejan. Pero la riqueza que se puede alcanzar es mucho mayor de lo que puede parecer. Ver, por ejemplo, los famosos patrones de diseño

Artículo continuación: Programación orientada a objetos y robótica

[caption id="attachment_929" align="aligncenter" width="464"]Design patterns (patrones de diseño) Design patterns (patrones de diseño)[/caption]