Docsity
Docsity

Prepara tus exámenes
Prepara tus exámenes

Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity


Consigue puntos base para descargar
Consigue puntos base para descargar

Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium


Orientación Universidad
Orientación Universidad

PROGRAMACION DE ROBOTS, Apuntes de Medicina

Asignatura: Informática en Medicina, Profesor: , Carrera: Medicina, Universidad: UPV-EHU

Tipo: Apuntes

2016/2017

Subido el 17/07/2017

aitor_gonzalez
aitor_gonzalez 🇪🇸

4.3

(3)

7 documentos

1 / 106

Toggle sidebar

Normalmente descargados juntos


Documentos relacionados


Vista previa parcial del texto

¡Descarga PROGRAMACION DE ROBOTS y más Apuntes en PDF de Medicina solo en Docsity! TE y MAA ANA + Python + Lihuen GNU/Linux Javier Diaz Claudia Banchoff Sofía Martin Joaquín Bogado Damian Mel Fernando López Equipo de soporte y desarrollo de Linuen GNU/Linux Versión del manual 1.0 Manual de programación con robots para la escuela. Claudia Banchoff, Joaquín Bogado, Damián Mel, Sofía Martin, Fernando López. Agosto 2012 - Versión 0.1.5 e-mail: soportelihuen@linti.unlp.edu.ar web: http://robots.linti.unlp.edu.ar Las imágenes que ilustran los capítulos son de dominio público y fueron obtenidas en los sitios Esta obra se distribuye bajo una licencia de Creative Commons Atribución- CompartirDerivadasIgual 3.0 Unported. Es decir, se permite compartir, copiar, distribuir, ejecutar y comunicar públicamente, hacer obras derivadas e incluso usos comerciales de esta obra, siempre que se reconozca expresamente la autoría original y el trabajo derivado se distribuya bajo una licencia idéntica a ésta. Índice general Prefacio IX 1. Trabajar con Software Libre 1 1.1. Software libre en la escuela . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2. ¿Por qué programar? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3. Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.4. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.5. Actividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2. Introducción 5 2.1. El robot Multiplo N6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2.2. Introducción al entorno de Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2.1. Usando el intérprete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.2.2. PyShell (del proyecto wxPython) . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.3. El ejemplo más sencillo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4. ¿Qué necesitamos para empezar? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.5. Conectando el robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.6. La primera actividad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.7. Cambiando el número de identificación del robot . . . . . . . . . . . . . . . . . . . . . 14 2.8. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 2.9. Actividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3. En movimiento 17 3.1. ¿Movemos al robot? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1.1. Hacia adelante y hacia atrás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 3.1.2. ¿Giramos? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.2. Dibujando figuras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.2.1. Mi primer programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 3.2.2. Guardando mis programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.3. Agrupando instrucciones en funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.3.1. Nombres de función válidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.3.2. Funciones con argumento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.4. Agrupar funciones en módulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.4.1. Mi primer módulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.4.2. Uso de import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.5. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.6. Actividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 v Índice general 4. Los valores y sus tipos 31 4.1. Utilizando variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 4.1.1. Variables en funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 4.2. Tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 4.2.1. Tipos Básicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 4.2.2. Conversión de tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 4.2.3. Las Listas: las colecciones más simples . . . . . . . . . . . . . . . . . . . . . . . 39 4.2.4. Trabajando con listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 4.3. Ingreso datos desde el teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.4. Imprimiendo por pantalla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 4.5. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 4.6. Actividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 5. Robots que deciden 45 5.1. Los valores de verdad en Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 5.1.1. Expresiones simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 5.1.2. Operadores lógicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 5.2. Condicionando nuestros movimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 5.3. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 5.4. Actividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 6. Simplificando pasos 55 6.1. Sentencia de iteración for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 6.2. Sentencia de iteración while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 6.3. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 6.4. Actividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 7. ¿Hacemos una pausa? 63 7.1. Estructura de un programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 7.2. Algo más sobre funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 7.2.1. Definición de una función y argumentos . . . . . . . . . . . . . . . . . . . . . . 64 7.2.2. Retornando valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 7.3. Importando módulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 7.4. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 7.5. Actividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 8. Utilizando los sensores 71 8.1. Conociendo los sensores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 8.2. Evitando choques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 8.2.1. Midiendo distancias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 8.2.2. Detectando obstáculos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 8.3. Sensores de línea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 8.4. Normalizando valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 8.5. Velocidad proporcional a la distancia . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 8.6. Resumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 8.7. Actividades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 A. Instalación de paquetes 79 A.1. Instalador de Paquetes Synaptic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 A.2. Instalación de la API del Robot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 A.2.1. En distribuciones basadas en Debian con Python 2.5 . . . . . . . . . . . . . . . 81 A.2.2. En distribuciones basadas en Debian con Python 2.6 o superior . . . . . . . . . 81 A.2.3. En Lihuen 4.x . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 vi Índice general A.2.4. En otras distribuciones GNU/Linux y otros sistemas operativos . . . . . . . . . 82 B. Especificaciones de los robots 83 B.1. Multiplo N6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 B.1.1. Otras formas de programarlo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84 B.2. Otros robots similares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 B.2.1. Robots artesanales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 B.2.2. Icaro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 B.2.3. Myro Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 C. Resumen de instrucciones 89 D. Enlaces útiles 93 vii Capítulo 0. Prefacio Estructura del libro En el capítulo 1, vamos a hablar sobre el Software Libre y por qué creemos que es importante utilizarlo y difundirlo, especialmente, en el ámbito educativo. Veremos por qué pensamos que es importante la enseñanza de la programación y por qué elegimos Python como opción. En el capítulo 2 presentaremos a nuestro robot y nos ocuparemos de instalar y configurar las herramientas necesarias para comenzar a trabajar. Si bien, como veremos más adelante, Python es un lenguaje que puede utilizarse tanto el sistemas Microsoft Windows como GNU/Linux, nosotros enfocaremos las prácticas al uso sobre Linux, con lo cual hemos agregado al final de este libro el apéndice A donde mostramos una guía de cómo instalar aplicaciones en este sistema operativo. En el capítulo 3 comenzaremos con las primeras actividades. Hemos elegido las más sencillas, donde el foco es familiarizarse con el entorno de trabajo y las funciones básicas del robot. El capítulo 4 presenta los tipos básicos de valores con los que podemos trabajar en Python y los primeros mecanismos de interación con el usuario. En los capítulos 5 y 6 daremos algunos conceptos de lógica sencillos que nos permitirán escribir programas utilizando las estructuras condicionales e iterativas del lenguaje. En el capítulo 7 hacemos una pausa y mostramos formas de mejorar la organización de nuestros programas. Escribiremos módulos que contengan funciones y veremos cómo utilizarlos desde otros programas. Por último, el capítulo 8, describe los distintos sensores que provee el robot básico y presenta actividades integradoras como culminación del curso. Sobre los autores Los autores responsables de este libro, pertencecen al Laboratorio de Investigación de Nuevas Tecnologías Informáticas de la Facultad de Informática de la Universidad Nacional de La Plata. Este laboratorio mantiene a instancias del Lic. Javier Díaz,director del LINTI2 desde el año 1994, una línea de trabajo permanente sobre Software Libre. Los proyectos más destacados son Lihuen GNU/Linux3 y Programando con Robots4. La experiencia contenida en este libro resume la aspiración de este grupo de trabajo cuyo objetivo es llevar a las escuelas públicas el conocimiento sobre Software Libre. 2http://linti.unlp.edu.ar 3http://lihuen.info.unlp.edu.ar 4http://robots.linti.unlp.edu.ar/ x Capítulo 1 Trabajar con Software Libre En este capítulo vamos a hablar sobre el Software Libre y por qué creemos que es importante utilizarlo y difundirlo. Primero vamos a dar algunas definiciones básicas y luego nos introduciremos en las herramientas que utilizaremos a lo largo del libro. 1.1. Software libre en la escuela El software libre no es una “nueva moda” o una nueva tendencia. Es una manera de pensar la tecnología, su construcción, uso y distribución. Cuando hablamos de software libre, decimos que los usuarios son libres de (les está permitido) utilizar, distribuir, estudiar y modificar el software que poseen. Una definición más precisa de este concepto la podemos encontrar en el sitio web del proyecto GNU1: El software libre es una cuestión de la libertad de los usuarios de ejecutar, copiar, distribuir, estudiar, cambiar y mejorar el software. Más precisamente, significa que los usuarios de programas tienen las cuatro libertades esenciales. En todos los casos, es necesario contar con el código fuente del software para poder modificarlo y estudiarlo. No se habla de un software que no tiene licencia de uso, sino que se distribuye con “licencias 1http://www.gnu.org/ 1 Capítulo 1. Trabajar con Software Libre libres”, es decir, con licencias que le dan a los usuarios todas las libertades que enuncia su definición. Al tratarse de una comunidad muy amplia, de la que participan una gran diversidad de personas (no sólo programadores sino también usuarios) comienzan a surgir distintas posiciones y, hacia el año 1998, surge un movimiento denominado “código abierto”, u “open source” en inglés. El problema es que el término “software libre”, en inglés, “free software”, trae algunas confusiones, dado que el término “free” también puede interpretarse como “gratis”, y el software libre es mucho más que un software gratuito. Es así que, en esa época, la corriente del software libre se abre en dos ramas: una más orientada a la “definición conceptual y filosófica” y otra, un poco más práctica. Las dos concepciones hacen referencia a casi el mismo tipo de aplicaciones, pero se basan en principios distintos. Richard Stallman, en su artículo “Por qué el código abierto pierde el punto de vista del software libre”2, destaca las diferencias principales. Para el movimiento del software libre, el software libre es un imperativo ético porque solamente el software libre respeta la libertad del usuario de elegir. En cambio, los seguidores del código abierto consideran los asuntos bajo los términos de cómo hacer «mejor» al software, en un sentido práctico operativo, instrumental solamente. Plantean que el software que no es libre no es una solución óptima. Para el movimiento del software libre, sin embargo, el software que no es libre es un problema social, y la solución es parar de usarlo y migrar al software libre. ýGoogleame: Software libre vs. código abierto ¿Qué opinan de esta diferencia? Para evitar estas diferencias, se suele hablar también de FLOSS(“Free/Libre/Open Source Software”), para designar este tipo de software sin entrar en las discusiones planteadas anteriormente. A modo de síntesis, podemos decir que nosotros hablaremos de “software libre” porque creemos que es muy importante destacar que la gran ventaja de su adopción, especialmente en ámbitos educativos, se basa en las cuatro libertades de su definición. Para poder elegir qué aplicación se adapta mejor a nuestras necesidades, es necesario conocer la mayor cantidad posible de opciones. Además, si contamos con acceso a los códigos fuentes, en caso de ser necesario, también podriamos adaptarlos y tener una versión propia del programa. Por último, cuando usamos software libre, participamos de una gran comunidad dentro de la cual podemos jugar distintos roles, lo que fomenta el trabajo colaborativo. 1.2. ¿Por qué programar? Introducir aspectos de programación no sólo apunta a un aprendizaje técnico, sino que permite desarrollar una serie de habilidades, como el pensamiento analítico o de solución de problemas, que son muy requeridos en los trabajos que tienen que ver con tecnología y ciencia, pero que también se pueden aplicar a otras áreas. Estos programas que se ejecutan en nuestras computadoras, celulares, televisores, etc. fueron escritos por programadores en diferentes lenguajes que le indican al dispositivo cómo hacer una acción determinada, es por esto que es importante saber antes que nada qué es un programa: Un programa es un conjunto de instrucciones u órdenes que le indican a la computadora cómo se realiza una tarea. 2http://www.gnu.org/philosophy/open-source-misses-the-point.es.html 2 Capítulo 2 Introducción En este capítulo vamos a describir las herramientas que necesitamos para comenzar. En primer lugar vamos a describir el robot y los accesorios necesarios para trabajar con él y luego, vamos a ver la forma de interactuar con Python. Si bien no es la única manera de trabajar, comenzaremos con los mecanismos más sencillos y luego incorporaremos otros a medida que avancemos. 2.1. El robot Multiplo N6 El robot Multiplo N6, es un robot educativo extensible basado en la plataforma de prototipado Arduino. Tanto el hardware como el software utilizado son libres, es decir que tanto las especificaciones de la electrónica necesaria como la de los programas necesarios para su utilización están accesibles y pueden utilizarse libremente. En el Anexo D podrán encontrar las direcciones desde donde descargar todas las especificaciones y las aplicaciones utilizadas en este libro, como así también los códigos de los ejemplos presentados. ýGoogleame: Arduino ¿Qué es Arduino? Como se ve en la Figura 2.1 nuestro robot cuenta con 3 ruedas que le permiten desplazarse: dos delanteras con tracción y una rueda trasera que le permite girar. 5 Capítulo 2. Introducción Figura 2.1. Robot Múltiplo N6 Figura 2.2. Módulo de comunicaciones XBee para la computadora El robot se mueve gracias a dos motores de corriente continua, cuyas respectivas cajas de reducción permiten al robot alcanzar velocidades respetables. Algo muy interesante es que este robot Multiplo N6 cuenta también con algunos sensores que nos permitirán realizar distintas actividades. El robot básico1, posee dos sensores de línea que pueden desensamblarse y acoplarse para recibir información del movimiento de las ruedas, además de la posición clásica para hacer seguimiento de líneas basado en los cambios de contraste. Además de los sensores de línea, el robot tiene un sensor ultrasónico que permite detectar obstáculos u objetos con centímetros de precisión hasta una distancia de 6 metros. El robot se mueve de forma independiente, sin cable, utilizando tres pilas AA. La conexión para el manejo se realiza a través del protocolo XBee (IEEE 802.15.4) que permite la utilización del robot de manera inalámbrica. Esta conexión se realiza utilizando el módulo de comunicaciones XBee, similar al que se ve en la Figura 2.2. Este módulo se conecta a la computadora por medio de un conector USB, y permite la comunicación con uno o más robots al mismo tiempo (utilizando una misma computadora). Más adelante, en este capítulo mostraremos cuáles son los pasos que debemos seguir para conectar el robot y la computadora. Antes veremos cuál será el entorno de trabajo. Recuerden que la forma de enviarle órdenes al robot es escribiendo programas en el lenguaje Python. Por lo tanto, veremos qué entornos podemos usar para escribir nuestros programas. 1Para una primer experiencia, hemos utilizado un robot básico, con unos pocos sensores que nos permitirán realizar actividades interesantes, pero sin introducir demasiada complejidad a la hora de empezar a programar. Pero es importante destacar que es posible agregarle más sensores y, de esta manera, plantear otro tipo de actividades más complejas. 6 2.2. Introducción al entorno de Python Figura 2.3. Entorno Interactivo 2.2. Introducción al entorno de Python Como mencionamos al comienzo de este libro, Python es un lenguaje interpretado, con lo cual necesitamos de un intérprete que nos permita ejecutar nuestros programas. Para esto, tenemos dos opciones: si se trata de un programa sencillo, podríamos ir ejecutándolo línea a línea a través de las llamadas “sesiones interactivas”, esto significa que cada orden que introducimos se ejecuta instantáneamente. La otra opción es utilizar un editor de textos cualquiera o un entorno de desarrollo (lo que se conoce como IDE, por sus siglas en inglés de lntegrated Development Environment) y luego invocar al intérprete Python para que ejecute todo el código. Cualquier de las dos opciones son válidas, aunque nosotros vamos a sugerir comenzar por la primera, para ir acostumbrándonos al lenguaje y luego pasaremos a un entorno más completo. Respecto a la primer opción, los lenguajes interpretados suelen ofrecer una herramienta de ejecución interactiva, que permite dar órdenes directamente al intérprete e ir obteniendo respuestas inmediatas para cada una de ellas. Esta manera de ejecución nos permite ir probando cosas y viendo el resultado de manera inmediata sin necesidad de codificar todo el programa completo. El entorno interactivo es de gran ayuda para probar con fragmentos de programa antes de incluirlos en una versión definitiva. Tanto para una manera u otra necesitamos de herramientas básicas como ser un intérprete Python y una consola interactiva, ya sea para poder ejecutar línea a línea el código como para contar con un editor de textos, en el caso de escribir todo el programa completo. Todo esto forma parte del llamado “entorno de programación”. Como también mencionamos en varias ocasiones, Python es software libre, por lo que contamos con un intérprete para prácticamente cualquier plataforma en uso (computadoras con Linux, Windows, Macintosh, etc) sin pagar costos de licencias por ello. El intérprete estándar nos da también la posibilidad de trabajar en modo interactivo, pero podemos instalar programas como PyShell, Geany u otros que agregan funcionalidades extra al modo interactivo, como ser auto-completado de código, coloreado de la sintaxis del lenguaje, etc. Esto permite hacer más fácil la tarea de programar. Como mencionamos antes, hay distintos entornos de trabajo. La Figura 2.3 muestra el entorno interactivo provisto por el lenguaje, mientras que la Figura 2.4 muestra un entorno un poco más amigable, denominado PyShell que será el que utilizaremos en un comienzo. Se pueden observar claramente las ventajas que ofrece el uso de este tipo de ambientes. Para mostrar el ejemplo se ejecutó una sesión interactiva, se escribió la sentencia de impresión en la línea dónde aparece el “prompt” (en este caso la instrucción print “hola” y se ejecutó con el sólo hecho de presionar la tecla Enter. El resultado se pudo ver al instante. 7 Capítulo 2. Introducción Acción Combinación Auto-completar texto Shift+Enter Repetir línea anterior del historial Ctrl+Arriba Repetir línea siguiente del historial Ctrl+Abajo Auto-completar después de un “.” Ctrl+Enter Incrementar o decrementar el tamaño de la fuente Ctrl y la ruedita del mouse Tabla 2.1. Combinaciones de teclas importantes de PyShell la instalación estará bajo nuestra responsabilidad. En el caso de necesitar instalarlo por primera vez o actualizar la versión que tenemos instalada en nuestra máquina podemos acceder a la página oficial del lenguaje http://www.python.org, donde encontraremos versiones y documentación correspondiente a diferentes sistemas operativos. Para ejecutarlo, simplemente debemos cliquear sobre el nombre del programa de la lista de programas que tengamos instalado. En la Figura 2.5 podemos ver como abrirlo desde el menú de Gnome en Lihuen GNU/Linux, en otras distribuciones GNU/Linux la forma de abrirlo es similar. . En distribuciones GNU/Linux basadas en Debian (como Lihuen y Ubuntu) el paquete que contiene PyShell se llama python-wxtools. 2.3. El ejemplo más sencillo Cada vez que se aprende un lenguaje de programación el primer programa dado como ejemplo se conoce como “Hola Mundo”. Este programa permite mostrar el mensaje “Hola Mundo” en la pantalla de la computadora. En nuestro caso, esto se realiza simplemente escribiendo la siguiente sentencia en el entorno y ejecutándola con el sólo hecho de presionar la tecla Enter. >>> print "Hola Mundo" El resultado, que puede verse al instante, se mostró en la Figura 2.3. 2.4. ¿Qué necesitamos para empezar? Con respecto al hardware, necesitamos un computadora, preferentemente con un sistema GNU/- Linux3, un robot y el módulo de comunicaciones XBee. Como dijimos antes, Python es un lenguaje multiplataforma, es decir, que puede usarse tanto en sistemas Microsoft Windows como en sistemas Linux o Mac, pero, como nosotros vamos a usar Linux como sistema operativo les detallamos qué aplicaciones deberemos instalar para empezar a trabajar. Igualmente, en cada caso, les vamos a indicar dónde pueden encontrar información si es que quieren trabajar sobre otra plataforma. Primero y principal, necesitamos el intérprete Python y las librerías para utilizar el robot. Después, aunque no menos importante, un entorno para desarrollar nuestros programas. 3Nosotros trabajamos con Lihuen GNU/Linux http://lihuen.info.unlp.edu.ar 10 2.5. Conectando el robot . ¿Cómo puede saber si tengo instalado el intérprete Python? En muchas distribuciones de GNU/Linux Python ya se incluye en la instalación por defecto. Para saber si ya está instalado pueden probar con los siguientes comandos: en la consola 4. # aptitude search python => muestra los paquetes instalados y posibles de instalar que contengan la palabra python. # dpkg -l | grep python => muestra solamente los paquetes instalados que contengan la palabra python. # python -V => muestra la versión de python instalada La librería que vamos a utilizar para realizar la comunicación con el robot se llama robot y debemos instalarla junto con un paquete de software especial denominado python-serial. En el Apéndice I: Guía de instalación de paquetes. se muestra la forma de instalar paquetes en un sistema Linux basado e Debian, como lo son Ubuntu y Lihuen. 2.5. Conectando el robot Antes de realizar cualquier acción con el robot, primero debemos “comunicarlo” con la computadora que estemos usando. Esto lo hacemos a través del módulo de comunicaciones XBee que mencionamos en secciones previas. Este módulo se conecta a la computadora por medio de una interfaz USB, y permite la comunicación con uno o más robots al mismo tiempo. Primero es necesario conectar el módulo de comunicaciones a la computadora, utilizando para esto alguno de los puertos USB disponibles. Al hacerlo, se creará un dispositivo con un nombre similar a /dev/ttyUSB05 en el sistema, el número (en este caso 0) puede variar. Podemos comprobar esto desde una terminal de la siguiente manera: usuario@host:~$ ls /dev/ttyUSB* /dev/ttyUSB0 Luego es necesario encender el robot. Una vez presionado el botón I/O para encender el robot, es necesario esperar a que el LED de estado naranja de la esquina inferior derecha deje de parpadear. Luego, hay que presionar el botón “Run”, cuando este LED se apague podremos empezar a usar el robot. Podemos ver la ubicación de estos botones en la Figura 2.6 y el LED de estado en la Figura 2.7. . Algo muy importante a tener en cuenta es que se debe verificar que las pilas estén correctamente colocadas y bien cargadas. Esto es crítico para un correcto funcionamiento del robot. Como mencionamos anteriormente para poder trabajar con el robot, primero debemos conectarlo con nuestra computadora. Para ello, debemos ingresar al entorno de Python (cualquier de los entornos mencionados) y, como vamos a trabajar con el robot en modo interactivo, todos los mensajes que le enviemos se ejecutarán inmediatamente. Dentro del entorno, ahora debemos importar las funciones que nos permiten trabajar con el robot. Esto se debe a que las funciones propias del robot no vienen integradas con el lenguaje Python y, para poder usarlas, debemos incorporarlas al entorno. Esto se hace utilizando la sentencia import del lenguaje Python: 4Algunas veces, vamos a indicar que utilicen la consola o terminal de Linux para probar o ejecutar algunos comandos. La terminal, por lo general se encuentra en el menú Accesorios 5Recuerden que en este libro, estamos trabajando sobre una plataforma Linux, en Windows el dispositivo tendrá un nombre del estilo com0, el número correcto se puede ver en el ‘Panel de control”, dentro del “Administrador de dispositivos”, en el desplegable “Puertos (COM y LPT)” 11 Capítulo 2. Introducción Figura 2.6. Botones del robot N6 Figura 2.7. LED de estado 12 2.9. Actividades 2.9. Actividades Ejercicio 2.1 Verifiquen qué versión de Python tienen instalada en su computadora. Si tienen una computadora con doble booteo (es decir con dos sistemas operativos), hagan esta comprobación en ambos sistemas. Ejercicio 2.2 Compruebe los dos entornos de trabajo descriptos en este capítulo. Si no los tiene instalado, instálenlos. Recuerden que pueden consultar el apéndice A con las guías de instalación en Linux. ¿Cuál le parece más cómodo? Ejercicio 2.3 Enumeren las aplicaciones y librerías que deben tener instalado en sus sistemas para comenzar a trabajar. Verifiquen cuáles están instaladas y cuáles no. Instalen las que hagan falta para comenzar a trabajar. Nuevamente, pueden consultar en apéndice A para obtener ayuda. Ejercicio 2.4 Conecten el robot a la computadora. ¿Cómo nos damos cuenta que el robot está conectado? ¿Le ponemos un nombre? Ejercicio 2.5 Intente que el robot emita una melodía. Prueben distintas frecuencias de sonidos con distintas duraciones. 15 Capítulo 3 En movimiento En el capítulo anterior comenzamos a interactuar tanto con el entorno de Python como con nuestro robot. Ahora ya estamos listos para hacer algo más interesante con él. En este capítulo vamos a ver de qué manera podemos indicarle al robot cómo moverse, girar y parar. De esta manera, podremos abordar actividades un poco más entretenidas, a la par que nos introducimos en el mundo de la programación. 3.1. ¿Movemos al robot? Hay 6 órdenes básicas de movimiento que permiten al robot avanzar, retroceder, doblar a la izquierda, doblar a la derecha, parar y controlar las ruedas independientemente. Para indicarle al robot que realice cualquiera de las tareas anteriores, primero debemos conectarlo con la computadora de la forma detallada en el capítulo 2 y, recién ahí, podremos comenzar a darle las instrucciones. 3.1.1. Hacia adelante y hacia atrás Si queremos que nuestro robot avance a velocidad media por un tiempo indeterminado, le debemos dar la orden forward(). 17 Capítulo 3. En movimiento Utilización Bloqueante forward(10,5) si forward(seconds = 2) si forward(20) no forward() no Tabla 3.1. Funciones bloqueantes y no bloqueantes Una orden que puede sernos de mucha utilidad es wait(). Esta orden hace que nuestro programa se detenga (bloquee) durante una cierta cantidad de segundos. En el siguiente ejemplo usamos wait() para simular el comportamiento del ejemplo anterior pero usando las versiones no bloqueantes de turnLeft() y turnRight(). Código 3.2. Muevo y espero >>> mi_robot.turnLeft(100) >>> wait(3) >>> mi_robot.turnRight(30) >>> wait(2) \index{wait} 3.2. Dibujando figuras Ya aprendimos cómo mover el robot en cualquier dirección. Si todavía no probaron los ejemplos que les mostramos, pruebenlos jugando y haciendo que el robot se mueva en distintas direcciones y con distintas velocidades. Una vez que se familiaricen con las formas en que podemos girar, avanzar y retroceder pueden empezar a combinarlas para hacer cosas más interesantes, por ejemplo, podemos hacer que nuestro robot dibuje un cuadrado en el piso. Para dibujar un cuadrado el robot tiene que avanzar una cierta distancia, girar 90 grados, repitiendo esto mismo cuatro veces. Un recurso que usamos los programadores para bosquejar un programa es lo que llamamos pseudocódigo. Esto es, básicamente, describir cuáles son las órdenes que debemos introducir en nuestro programa, pero descriptas con palabras en lenguaje natural, sin usar ningún lenguaje de programación en particular. Pensemos entonces cómo deberíamos indicarle al robot que realice un cuadrado de 20x20 cm en este pseudocódigo: avanzar 20 centímetros girar 90° avanzar 20 centímetros girar 90° avanzar 20 centímetros girar 90° avanzar 20 centímetros girar 90° Si intentaron probar esto en el intérprete Python, se habrán dado cuenta que se produjeron varios errores. ¿Por qué? Es muy fácil, estas órdenes no son sentencias propias de Python, de hecho es un lenguaje inventado, solamente utilizaremos esta estrategia para tener una idea de cómo quedará el programa una vez escrito. En este caso, se trata de un programa muy sencillo, pero esto puede sernos de mucha utilidad cuando tengamos que pensar algoritmos más complejos. 20 3.2. Dibujando figuras Revisemos las órdenes que desplazan y giran al robot. ¿Alguna de ellas, permite indicarle al robot que avance 20 cm y gire 90°? No. Por lo tanto, vamos a tener que experimentar el uso de forward() con distintas velocidades y tiempos para calcular el tamaño del lado del cuadrado que nos parezca adecuado. En general es recomendable que sea una figura chica así es más fácil darse cuenta si lo estamos dibujando bien o no. Lo mismo deberemos hacer con turnRight() o turnLeft(), para lograr un ángulo lo más parecido posible a 90 grados. Estos valores pueden variar según el robot que estemos utilizando y es recomendable que cada uno haga estas pruebas con el robot que usará para dibujar el cuadrado. No se preocupe porque las formas de las figuras sean perfectas, el robot no está diseñado para tener movimientos tan precisos como para hacer un cuadrado perfecto, lo importante es que se asemeje a la figura deseada. 3.2.1. Mi primer programa Una vez que encontramos cuáles son los valores adecuados para indicarle al robot que avance tanto centímetros y gire 90 grados, debemos escribir nuestro programa en Python. Una posible versión podría ser parecida a la que les mostramos a continuación: Código 3.3. Nuestro primer programa from duinobot import * b = Board("/dev/ttyUSB0") mi_robot = Robot(b, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) b.exit() Como pueden ver, en el código pueden notar que cada tanto usamos la función wait() para que detenga (o bloquee) el programa hasta que el robot termine de detenerse (normalmente las ruedas del robot se mueven unos milímetros de más por inercia). Existe una orden, denominada motors() que permite controlar las ruedas del robot de forma independiente. motors() puede recibir 2 argumentos indicando la velocidad de los motores derecho e izquierdo. Como en los casos anteriores, la velocidad es un valor en el rango entre -100 y 100, indicando con el signo la dirección en la que girará cada rueda. Probemos el siguiente ejemplo: >>> mi_robot.motors(-50, 50) >>> mi_robot.stop() ¿Qué pasó? ¡El robot gira! También es posible indicar cuántos segundos debe moverse el robot con un tercer argumento a motors(). Probemos: >>> mi_robot.motors(-50, 50, 1) 21 Capítulo 3. En movimiento 3.2.2. Guardando mis programas Si por algún motivo decidimos continuar más tarde y apagamos nuestra computadora, ¿qué creen que pasa con el programita que hicimos recién? En realidad, como sólo fueron órdenes dadas al intérprete de Python y nunca fueron almacenadas en ningún lado, deberíamos volver a ingresarlas nuevamente si quisiéramos repetir nuestro cuadrado. Como pueden ver, obviamente esto es muy poco práctico. Cuando escribimos programas, queremos que éstos puedan guardarse en nuestra computadora para que los podamos ejecutar cuantas veces queramos. Es más, podría copiar nuestro programa en otra computadora con Python y ejecutarlo allí. Ahora bien, ¿cómo hacemos esto? Un programa Python es simplemente un archivo de texto que contiene las órdenes escritas anteriormente. En este punto, es interesante contar con un entorno que nos facilite estas tareas. Estos entornos se conocen como IDEs (por las siglas en inglés de Integrated Development Environment) y nosotros vamos a usar uno denominado Geany1 , cuya interfaz podemos ver en la Figura 3.1, si bien utilizamos Geany para escribir el código cualquier otro editor de texto podría servir, como el Block de Notas de Windows o el Gedit de Linux. Figura 3.1. Entorno de Desarrollo Geany Antes de avanzar vamos a darles algunas ayudas para trabajar. Las órdenes se introducen en la zona de edición. Debemos guardar esto en un archivo cuya extensión debe ser “.py”. Ejemplo: holaMundo.py. Al terminar en py, Geany asocia estas órdenes con el lenguaje Python, con lo cual van a notar que algunas palabras aparecerán resaltadas y con distintos colores. Si prestan atención, en los ejemplos anteriores, al introducir una orden, la misma se ejecutaba en ese preciso momento y ahora no es así. Si queremos ejecutar nuestro programa debemos hacerlo a través del menú “Construir→Ejecutar” o usando el atajo en la tecla “F5”. Al ejecutar la orden de construir se abre una ventana con la ejecución de nuestro programa, como se puede ver en la Figura 3.2. . Pueden observar lo anterior en el vídeo http://vimeo.com/47518326 en el sitio web del proyecto2. Otra ventaja de escribir mi programa en un archivo es que lo podemos ejecutar directamente desde la terminal. Por ejemplo, podemos tipear el comando python seguido del nombre del archivo que acabamos de generar (holaMundo.py) como se muestra en el siguiente código: 1En el apéndice A les vamos a mostrar cómo instalarlo en sus máquinas. 2http://robots.linti.unlp.edu.ar 22 3.3. Agrupando instrucciones en funciones quedó más legible. En Python una función se define usando el constructor def seguido por un nombre que identificará la función y que permitirá luego invocarla tantas veces como sea necesario. La forma más simple de explicar esto es con un ejemplo: Código 3.4. Función cuadrado from duinobot import * b = Board("/dev/ttyUSB0") mi_robot = Robot(b, 1) def cuadrado(): mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) # Dibujamos 3 cuadrados cuadrado() cuadrado() cuadrado() b.exit() En el ejemplo anterior, definimos una función llamada cuadrado y luego la invocamos tres veces. La primer línea de la definición de cualquier función comienza con la palabra clave def, seguida del nombre de la función y finalmente ():. Luego, se escriben las instrucciones asociadas a la función. Cada línea tiene que comenzar con una tabulación o con dos espacios. Desplazar el texto hacia la derecha, se denomina "indentar" y, como veremos muchas veces es muy importante respetar esto en Python. . Se debe ser consistente con la forma elegida para indentar el código. Escoger una forma y hacerlo siempre así, de lo contrario el programa puede fallar. 3.3.1. Nombres de función válidos En la sección anterior, le dimos un nombre a una función. En Python, estos nombres (tanto de funciones como de variables) deben respetar algunas normas: Los nombres pueden contener letras del alfabeto inglés (es decir no puede haber ñ ni vocales con tilde). Los nombres pueden contener números y guión bajo. Los nombres pueden empezar con una letra o un guión bajo (nunca con un número). 25 Capítulo 3. En movimiento Nombres Válidos Nombres Inválidos mi_funcion funcion_ñ _mi_funcion _mi_función _3_mifuncion 3_mifuncion mi3funcion mi3 funcion Tabla 3.2. Nombres válidos e inválidos de funciones No pueden usarse palabras reservadas como nombre. Estas palabras son utilizadas por Python para acciones específicas, por ejemplo: def. En la Tabla 3.2 mostramos nombres válidos e inválidos de funciones válidos 3.3.2. Funciones con argumento Volviendo al ejemplo sobre cómo dibujar un cuadrado de la sección 3.3, pensemos ¿qué tendríamos que hacer si ahora quisiéramos hacer cuadrados de distintos tamaños? Tendríamos que modificar la velocidad (y/o el tiempo) en cada invocación a forward(). Además de ser bastante incómodo, ya que hay que invocar a forward() cuatro veces para dibujar un cuadrado, no es recomendable porque cuando tenemos que modificar muchas partes distintas de un programa es muy fácil equivocarse y generar errores nuevos. Ya vimos en la sección 3.3 que podemos escribir una sola vez el fragmento de código para dibujar cuadrados y usarlo muchas veces definiendo una función. El problema es que esa función hace siempre cuadrados del mismo tamaño, por lo tanto no nos sirve. Para lograr esto, podemos escribir una función e indicarle, a través de un parámetro, el dato necesario para dibujar cuadrados de distintos tamaños. De forma similar como le indicamos la velocidad o el tiempo a forward(). Veamos el siguiente ejemplo: Código 3.5. Cuadrado con argumento def cuadrado(tiempo): mi_robot.forward(50, tiempo) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, tiempo) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, tiempo) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, tiempo) wait(1) mi_robot.turnRight(35, 1) cuadrado(0.5) cuadrado(1) cuadrado(2) En la primera línea podemos ver que entre los paréntesis de la definición de cuadrado() tenemos que escribir un nombre para el parámetro, en este caso usamos “tiempo”. El nombre “tiempo” representa el valor pasado al invocar la función. Dentro de la misma podemos usar “tiempo” como si fuera el valor que representa y luego, en cada invocación a forward(), reemplazamos el valor que usábamos para la duración del movimiento por el nombre del parámetro. 26 3.4. Agrupar funciones en módulos Como vimos anteriormente las órdenes forward() y turnLeft() pueden recibir más de un parámetro. Estas órdenes se implementan con funciones, así que una función cualquiera también puede recibir más de un parámetro. En nuestro caso,podemos mejorar aún más nuestra función cuadrado() de manera tal que podamos indicar también qué robot querríamos que dibujara el cuadrado. Pensemos que de la manera que está implementada hasta ahora, sirve para un único robot, que debe llamarse siempre “mi_robot”. Por lo tanto, podemos pensar en agregar otro argumento que represente al robot. Esto nos va a permitir ponerle distintos nombres a la variable que hace referencia al robot e incluso usar la función cuadrado con distintos robots en el mismo programa. En el siguiente ejemplo se puede ver una implementación de la función cuadrado que recibe el robot como argumento, y en las últimas líneas de este ejemplo se puede ver que se usa cuadrado para 2 robots distintos. Código 3.6. Dos robots haciendo cuadrados from duinobot import * def cuadrado(r, tiempo): r.forward(50, tiempo) wait(1) r.turnRight(35, 1) r.forward(50, tiempo) wait(1) r.turnRight(35, 1) r.forward(50, tiempo) wait(1) r.turnRight(35, 1) r.forward(50, tiempo) wait(1) r.turnRight(35, 1) b = Board("/dev/ttyUSB0") robot1 = Robot(b, 1) robot2 = Robot(b, 10) cuadrado(robot1, 0.5) cuadrado(robot2, 1) b.exit() 3.4. Agrupar funciones en módulos En las actividades anteriores escribimos varias funciones que pueden combinarse de distintas formas para hacer programas distintos. Si juntamos todas estas funciones en un único archivo (teniendo cuidado de que cada función tenga un nombre distinto) tenemos, lo que en Python se conoce como un módulo. Módulo: son archivos con instrucciones de Python guardados con extensión “.py”, se los puede ejecutar cuantas veces se quiera, se pueden importar y usar desde otros módulos. Durante el transcurso de este libro ya vimos y usamos el módulo robot. El objetivo de esta sección es que aprendamos a hacer y a utilizar nuestros propios módulos. 3.4.1. Mi primer módulo Si copiamos las funciones que escribimos hasta ahora y las guardamos en un archivo “.py” podemos utilizarlas en muchos programas sin tener que copiarlas cada vez. Copien los siguientes ejemplos en un archivo denominado “movimientos.py”. 27 Capítulo 3. En movimiento 3.6. Actividades Ejercicio 3.1 Usando lo experimentado hasta ahora escriba un programa para dibujar un triángulo equilátero (los ángulos internos miden 60 grados), no se preocupen porque el triángulo quede perfecto, es muy difícil lograrlo. Ejercicio 3.2 Escriban un programa que haga que el robot avance en zigzag durante 1 minuto. Ejercicio 3.3 Usando motors() se puede indicar que una rueda se mueva más lenta que la otra. Controlando la diferencia de velocidad se pueden hacer círculos más grandes o más chicos. Experimente el mensaje motors() para crear círculos de distintos tamaños. Ejercicio 3.4 Implemente una función para dibujar triángulos, aprovechando el código que escribió en las actividades anteriores y ejecútela. Esta función no debe recibir parámetros. Ejercicio 3.5 Modifique la función anterior para que el robot y la longitud de los lados del triángulo se pasen como argumentos. Ejercicio 3.6 Implemente la función mareado() que haga girar el robot varias veces en una y otra dirección. Ejercicio 3.7 Implemente una función que reciba 2 robots como argumentos, y envíe uno hacia la derecha y el otro hacia la izquierda a velocidad máxima durante un número de segundos pasados como parámetros. Ejercicio 3.8 Cree la función carrera que reciba 2 robots y los haga avanzar a velocidad máxima durante una cantidad de segundos que se recibe como parámetro. Ayuda: use forward() con un sólo argumento y el mensaje wait() de alguno de los 2 robots para que ambos avancen al mismo tiempo. Ejercicio 3.9 Usando las funciones de movimiento realice un programa que recorra un laberinto realizado sobre el piso con obstáculos físicos o con líneas. Ejercicio 3.10 Para hacer un paso de baile, un robot debe realizar alguna figura, por ejemplo, un círculo, un cuadrado, un triángulo, un 8, una vueltita, etc. Un baile completo entre 2 robots, consiste en una secuencia de varios pasos de baile. Realice un módulo baile. El módulo debe contener los pasos de diferentes bailes, además de algunos bailes predefinidos. Prueben, filmen y suban a nuestro canal de youtube el resultado de este ejercicio. 30 Capítulo 4 Los valores y sus tipos Ya vimos cómo mover el robot dibujando algunas figuras. También vimos que, al incorporar el uso de funciones, podemos reutilizar código agrupando instrucciones y construir programas que sean más fáciles de leer. Ahora, en este capítulo, veremos la facilidad que nos aporta el uso de variables, de manera tal de poder utilizar nuestros datos en varias instancias de nuestro código sin necesidad de repetir sus valores, y cómo pedirle al usuario que ingrese datos desde el teclado para usarlos en nuestros programas. 4.1. Utilizando variables Repasando lo que vimos en el capítulo 3, recordamos que cuando quisimos dibujar un cuadrado, necesitamos probar con distintos valores de velocidad y de tiempo hasta dar con los adecuados para que el robot dibuje la figura deseada. Debido a que debemos escribir estos datos en cada instrucción, cada vez que quisimos probar con valores distintos, debimos modificar los mismos en cada una de sus ocurrencias. Para evitar la repetición de escritura o modificación de datos podemos guardar estos valores para luego utilizarlos tantas veces como necesitemos. ¿Qué usamos para realizar esto? Usamos variable. Una variable es un nombre que representa o refiere a un valor. 31 Capítulo 4. Los valores y sus tipos Seguramente han usado variables en matemáticas, cuando resuelven ecuaciones. ¿Cuál es la idea en ese caso? Las variables son cantidades desconocidas que se nombran con una letra (x, y, z, por ejemplo). En Python, podemos utilizar variables para representar valores. Por ejemplo: mi_robot = Robot(b, 1) La instrucción anterior la hemos utilizado cada vez que conectamos el robot a la computadora. Para manejar el robot usamos dos variables: mi_robot y b. La primera, nos representa al robot y la segunda, al módulo de comunicaciones. De esta manera cada vez que necesitamos referenciar al robot, lo hacemos utilizando la variable mi_robot. Usamos variables también cuando enviamos información a las funciones. ¿Se acuerdan? En el capítulo anterior, escribimos funciones que recibían parámetros. Estos parámetros se representan también con variables. Por ejemplo: >>> from duinobot import * >>> from movimientos import * >>> b = Board("/dev/ttyUSB0") >>> robotazo = Robot(b, 1) >>> mareado(robotazo) >>> zigzag(robotazo) . ¿Cuáles son las variables que usamos en el código anterior? ¿Qué representan cada una? Asociamos un valor a una variable a través de la sentencia de asignación. En Python, esto se representa con el =. Por ejemplo: velocidad=100. Mediante la asignación podemos almacenar resultados de operaciones matemáticas u operaciones de otro tipo en variables, lo cual nos permite modificar valores rápidamente y de forma más ordenada: Código 4.1. Guardando datos en variables proporcion = 2 esperar = 2 * proporcion velocidad = 25 * proporcion vuelta = velocidad / 2 mi_robot.forward(velocidad, tiempo) mi_robot.turnRight(vuelta, 1) wait(esperar) mi_robot.forward(velocidad, tiempo) mi_robot.turnRight(vuelta, 1) wait(esperar) mi_robot.forward(velocidad, tiempo) mi_robot.turnRight(vuelta, 1) wait(esperar) mi_robot.forward(velocidad, tiempo) mi_robot.turnRight(vuelta, 1) wait(esperar) Miremos el ejemplo anterior. Podemos modificar alguna de las 4 variables definidas al principio y alterar así el comportamiento de todo el programa sin necesidad de modificar el código línea por línea. La forma general de asignarle un valor a una variables en Python es: 32 4.2. Tipos de datos 4.2. Tipos de datos Hasta ahora vimos que los valores que manejamos no son siempre iguales y, de acuerdo a estos valores, son las operaciones que podemos hacer con los mismos. Cada variable, de acuerdo al valor que le asignemos tendrá asociado un determinado tipo de dato. Un tipo de datos define el conjunto de valores y las operaciones válidas que pueden realizarse sobre esos valores. El conjunto de valores representa todos los valores posibles que puede llegar a tomar una variable de ese tipo. Las operaciones permitidas, son todas aquellas operaciones válidas para los datos pertenecientes a dicho tipo. Python maneja muchos tipos de datos. Algunos de ellos corresponden a valores simples como ser números y cadenas de caracteres (los tipos de datos que usamos hasta el momento) y otros, corresponden a colecciones de valores, como son las listas. A continuación, les mostramos los tipos de datos utilizados en Python: Tipos Básicos • Números: Enteros - Flotantes • Lógicos (Booleanos) • Cadenas de texto (Strings) Colecciones • Listas • Tuplas • Conjuntos • Diccionarios Como habrán podido notar, en ningún momento hemos asignado o asociado un tipo a una variable. Simplemente le asignamos un valor y, a partir de este valor, inferimos su tipo. . Antes de utilizar una variables, primero debemos asignarle un valor. Si no es así, Python informa un error. >>> print x Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'x' is not defined ¿Qué pasó en este ejemplo? Como la variable x no tiene ningún valor asignado, Python no la conoce aún. Por este motivo, el mensaje de error es “name 'x' is not defined”, que significa que el nombre “x” no está definido. Como dijimos anteriormente, el tipo de datos también define qué operaciones están permitidas. Algunas operaciones tienen asociados símbolos que las representan. En el Tabla 4.1 podemos ver algunos de los operadores disponibles en Python y la operación que representan. Vamos a volver sobre estos operadores cuando veamos en detalle cada uno de los tipos con los cuales trabajaremos a lo largo de este primer curso. 35 Capítulo 4. Los valores y sus tipos Operador Operación + Suma de números o concatenación de cadenas - Resta * Multiplicación e números o repetición de cadenas / División entera o no entera % Resto de la división entera > , < Comparación mayor - menor == Comparación por igualdad Tabla 4.1. Operadores en Python Ejemplos Interpretación Tipo 1230, -98, 0 Enteros normales int 999999999999L Enteros largos long 1.45, 3.14e-10, 4E210 Punto flotante float 0177, 0x9ff, 0XFF Literales octales y hexadecimales int 3+4j, 3.0+4.0j Números literales complejos complex Tabla 4.2. Tipos de números enteros y flotantes 4.2.1. Tipos Básicos Los números son los datos que utilizamos diariamente para referirnos a medidas, distancias, etc. Para representar los mismos necesitamos diferentes tipos. Para utilizar números que no necesitan valores decimales, Python posee tipos de números enteros que varían su rango según para lo que se esté empleando, en la Tabla 4.2 podemos ver los tipos de enteros y flotantes disponibles en el lenguaje. Ya que en el lenguaje Python las variables no se declaran asociándoles un tipo de dato antes de su utilización (a diferencia de otros lenguajes) el tipo de una variable se define en el momento en que le asignamos un valor. En la Tabla 4.1 se listaron los operadores que puede utilizarse con los datos numéricos. Muchos de estos operadores ya se conocen del área de las matemáticas, como +, -, * y /. Pero, hay algunas cosas interesantes de destacar. Por ejemplo, debemos prestar particular atención al momento de utilizar /, ya que el resultado depende del tipo de los datos que se están usando en el momento de la operación. Si se dividen dos números enteros, el resultado que se obtiene es la parte entera de la división, pero si en cambio uno de los números es del tipo float (es decir, que contiene una parte decimal), retorna un valor con punto decimal. Por lo tanto, el valor resultante tendrá tipo float. En la Tabla 4.3 veremos algunos ejemplos de uso de los operadores vistos entre números enteros y flotantes. El orden en que usamos los operadores influyen en el resultado final de la operación. A este orden Operación Resultado 5+10 15 10 / (2+3) 2 10 > 5 True 10/3.5 2.8571428571 10/3 3 10%3 1 Tabla 4.3. Ejemplos Operadores matemáticos y com- paración en Python 36 4.2. Tipos de datos Operadores Descripción <, <=, >, >=, ==, !=, x in y Operadores de comparación x + y, x - y Suma y resta x * y, x% y, x / y Multiplicación/repetición, resto, división -x Negación unitaria Tabla 4.4. Orden de precedencia de operadores mate- máticos se lo conoce como precedencia. Como hemos visto en matemáticas cuando tenemos expresiones con cálculos combinados en los que intervienen operaciones de multiplicación, división y sumas y restas, si no se utilizan paréntesis, primero se resuelven las divisiones y multiplicaciones y luego las sumas y restas. En Python existe una precedencia que hay tener en cuenta al momento de realizar operaciones en la Tabla 4.4 se describe la precedencia de los operadores vistos. Esto es muy importante tener en cuenta, dado que debemos saber exactamente cómo Python resolverá un cálculo matemático. Otro tipo de datos básico es el string o cadena de caracteres. Como mencionamos antes, se pueden definir cadenas encerrando el texto entre comillas simples(') o dobles ("). Las cadenas también tiene operaciones asociadas. Veamos el siguiente ejemplo: >>> ciudad='La Plata, ' >>> provincia = "Buenos Aires" >>> ciudad + provincia 'La Plata, Buenos Aires' >>> cadena = ciudad*5 'La Plata, La Plata, La Plata, La Plata, La Plata, ' ¿Ven algo extraño? Estamos usando operadores matemáticos con cadenas y ¡no hubo un error! Esto es porque el símbolo + se utiliza también para la concatenación de cadenas y el símbolo * para la repetición de las mismas. ¿Qué pasa si necesitamos saber, por ejemplo si una cadena comienza con cierta letra, por ejemplo, vamos a necesitar acceder a una posición exacta dentro de la cadena (en nuestro ejemplo, la primera). Para esto, podemos hacerlo utilizando corchetes y un número llamado índice que indica a qué carácter queremos acceder. Se puede pensar una cadena como una sucesión de cajas donde cada una guarda un carácter: L a P l a t a 0 1 2 3 4 5 6 7 De esta manera, Python almacena los string, reservando una posición para cada carácter correspondiente a la cadena de texto. Por lo tanto, para acceder a un carácter indicado lo haremos indicando su posición. . En Python, el primer carácter de una cadena se encuentra en la posición 0 (CERO). En nuestro ejemplo, ciudad[0] corresponde a la letra “L”. También es posible acceder a fragmentos de una cadena, especificando el principio y el fin de la subcadena. Veamos cómo funciona: 37 Capítulo 4. Los valores y sus tipos 4.2.4. Trabajando con listas Las listas son estructuras dinámicas. Es decir, que podemos agregar y quitar elementos a medida que así lo necesitemos. Supongamos que tenemos la lista con los siguientes elementos: >>> lista = [43, 'Buenos Aires', [3,7,9]] Para agregar un elemento al final de la lista utilizamos la sentencia append >>> lista = [43, 'Buenos Aires', [3,7,9]] >>> lista.append(5) >>> print lista [43, 'Buenos Aires', [3, 7, 9], 5] En caso que necesitemos insertar un elemento en una posición determinada utilizamos la sentencia insert indicando como primer argumento la posición y como segundo argumento el elemento a insertar: lista.insert(posicion,elemento_nuevo) En nuestro caso veamos la inserción del número 333 en la posición 2 de la lista: >>> lista = [43, 'Buenos Aires', [3,7,9]] >>> lista.insert(2,333) >>> print lista [43, 'Buenos Aires', 333, [3, 7, 9]] Para eliminar elementos de una lista Python provee la sentencia remove, la cual elimina el primer elemento de la lista que coincida con el valor pasado como argumento. >>> lista.remove(333) Otra forma de eliminar elementos es utilizando la sentencia pop(i), pero a diferencia de remove elimina el elemento que se encuentra en la posición i, o bien se puede utilizar sin argumentos, con lo cual elimina el último elemento. >>> lista = [43, 'Buenos Aires', 333, [3, 7, 9]] >>> lista.pop(2) 333 >>> lista = [43, 'Buenos Aires', [3,7,9]] >>> lista.pop() [3, 7, 9] >>> print lista [43, 'Buenos Aires'] Para conocer la cantidad de veces que aparece un elemento en una lista contamos con la sentencia count >>> print lista [43, 'Buenos Aires', 5, 57, 5, 'era', 55, 'era'] >>> lista.count(5) 2 Para conocer la cantidad de elementos que contiene la lista recurrimos a la función len que vimos con las cadenas: >>> lista = [43, 'Buenos Aires', 5, 57, 5, 'era', 55, 'era'] >>> len(lista) 8 A modo de resumen les dejamos la Tabla 4.6 con las operaciones básicas de listas. 40 4.3. Ingreso datos desde el teclado Operación Descripción Ejemplo append Agrega un elemento a la lista lista.append(10) remove Elimina la primera ocurrencia del elemento dado como pará- metro lista.remove(10) pop Elimina y retorna el elemento ubicado en la posición dada como parámetro lista.pop(1) count Retorna la cantidad de ocurrencias del elemento dado como parámetro lista.count(1) len Retorna la cantidad de elementos de la lista len(lista) Tabla 4.6. Operaciones básicas de listas 4.3. Ingreso datos desde el teclado Hasta ahora, todos los valores que utilizamos en los ejemplos fueron escritos en el texto de nuestros programas. La realidad es que en muchos casos estos valores no se conocen de movida y es el usuario de nuestros programas quien los ingresa desde el teclado. Para ingresar un valor desde el teclado utilizaremos la función raw_input. Con esta función solicitamos los valores en el momento de ejecución. Código 4.5. Solicitando valores por teclado mi_personaje = raw_input("¿Cuál es tu personaje favorito?") def imprimirPersonaje(personaje): print personaje imprimirPersonaje(mi_personaje) Como pudieron observar, la función raw_input puede recibir un texto como argumento que se muestra en el momento que se solicita el ingreso de datos. Este texto es opcional, puedo no querer mostrar ningún texto y, simplemente usarla de la siguiente manera: print "¿Cuál es tu personaje favorito?" mi_personaje = raw_input() def imprimirPersonaje(personaje): print personaje imprimirPersonajel(mi_personaje) Algo muy importante es que raw_input retorna siempre una cadena de caracteres. Miren el siguiente ejemplo: >>> mi_edad = raw_input("¿Cuál es tu edad?") "¿Cuál es tu edad?" 23 >>> print mi_edad 23 >>> print "El doble de tu edad es ", mi_edad*2 El doble de tu edad es 2323 ¿Qué pasó? El problema es que mi_edad es una cadena de caracteres y Python utilizó el operador * como operador de repetición de cadenas. Si necesito el valor numérico de esta cadena, deberé utilizar las funciones de conversión que mencionamos antes (int). >>> mi_edad = raw_input("¿Cuál es tu edad?") "¿Cuál es tu edad?" 23 >>> print mi_edad 23 41 Capítulo 4. Los valores y sus tipos >>> print "El doble de tu edad es ", int(mi_edad)*2 El doble de tu edad es 46 Otra función que podemos utilizar para ingresar datos desde el teclado es input, pero la misma genera en algunas ocasiones errores de lectura de lo ingresado por teclado. Para evitar esto, usaremos siempre raw_input y en caso que se esté solicitando un tipo de datos diferente a string se lo convertirá que ya se explicó en la sección 4.2.2. Veamos otro ejemplo: Código 4.6. Ingresando un valor entero desde el teclado print "Ingrese los valores necesarios para hacer el cuadrado" velocidad = int(raw_input("velocidad: ")) vuelta = int(raw_input ("Velocidad para dar la vuelta: " )) def cuadrado(robot, lado, esquina): tiempo = 3 robot.forward(veloc, tiempo) robot.turnRight(esquina, 2) wait(esperar) robot.forward(lado, tiempo) robot.turnRight(esquina, 2) wait(esperar) robot.forward(lado, tiempo) robot.turnRight(esquina, 2) wait(esperar) robot.forward(lado, tiempo) robot.turnRight(esquina, 2) wait(esperar) cuadrado(robot, velocidad, vuelta) 4.4. Imprimiendo por pantalla Ya usamos en muchas ocasiones la función print para mostrar en la pantalla datos. En esta sección, veremos la sentencia print con mayor detalle. En forma general se indica la expresión luego de la sentencia: >>> x = 3 >>> print x 3 Si estamos trabajando en el intérprete de Python, también podemos utilizar el nombre de la variable directamente sin la sentencia print delante: >>> x 3 En caso que se necesite mostrar un texto determinado recurrimos a las " " o ' ' para abarcar el texto: >>> print "x" x . En Python es indistinto el uso de las comillas simples ' ' o las comillas dobles " " dentro de la sentencia print 42 Capítulo 5 Robots que deciden Hasta ahora, nuestros robots siguieron órdenes estrictas de acuerdo a una secuencia de instrucciones preestablecidas. En ningún momento fueron capaces de tomar ningún tipo de decisión en base al planteo de una situación dada. A partir de ahora, vamos trabajar para dotarlos de cierta "inteligencia" para que puedan ser capaces de decidir ante ciertas circunstancias. Para poder decidir, es necesario que se puedan expresar distintas situaciones de manera tal que nos podamos preguntar su "valor de verdad". Esto es, poder escribir expresiones que representen preguntas tales como: ¿esta situación está pasando?, ¿es cierto que hay un obstáculo delante?, ¿ya recorrimos 10 cm?, etc. En este capítulo veremos cómo expresar estas situaciones o condiciones y, en base a si se cumplen o no, tomar las decisiones necesarias. 5.1. Los valores de verdad en Python En Python existe un tipo cuyos valores representan valores de verdad. Este tipo se denomina Booleano y sus valores pueden ser True o False que representan a los valores verdadero y falso. Las variables booleanas son tan simples que sólo pueden tomar estos dos valores, sin embargo resultan muy útiles para indicar al robot qué decisiones tomar. Antes de profundizar en este tema, es muy importante conocer algunos aspectos básicos de lógica, dado que el robot deberá tomar decisiones de acuerdo a ciertas condiciones que se les presente y debemos saber exactamente cómo las evaluará. 45 Capítulo 5. Robots que deciden ýGoogleame: Buscá información sobre quién es George Boole y por qué se les dicen booleanos a los tipos de datos que representan valores de verdad. En esta sección veremos cómo escribir expresiones que devuelven valores de verdad y cómo combinar distintos valores de verdad para crear otros más complejos. 5.1.1. Expresiones simples Seguramente ya han tratado con este tipo de expresiones, aunque no sabían cómo se llamaban. Veamos los siguiente ejemplos: >>> 5 < 10 True >>> 5 > 10 False >>> 5 + 1 > 5 True >>> 2 * 20 == 41 False >>> "Gato" < "Pato" True >>> "Gato" == "Pato" False >>> "Gato" != "Pato" True Cuando comparamos dos números, en nuestro ejemplo 5 y 10, el resultado es un valor de verdad: verdadero o falso, de acuerdo a la comparación realizada. Todos sabemos que es verdad (True) que 5 es más chico que 10. Cuando comparamos cadenas de caracteres, usamos el orden alfabético de los caracteres para compararlos. Así decimos que "Gato" es más chico que "Pato", dado que la letra "G" está antes en el abecedario que la letra "P". . Prueben qué pasa con el siguiente ejemplo. Analicen el resultado. >>> "gato" < "Pato" False ¿Qué pasó? Como habrán visto, hay varios operadores que me permiten comparar valores y, en base a dicha comparación, retornar el valor de verdad correspondiente. La Tabla 5.1. muestra la lista de operadores de comparación que pueden usarse en Python y en la Tabla 5.2 les mostramos algunos ejemplos del uso de dichos operadores y el valor de verdad que retornan al evaluarse. 5.1.2. Operadores lógicos Hasta ahora, los operadores presentados sólo nos permiten evaluar o consultar por una única condición. Por ejemplo: ¿la velocidad es menor que 100? (velocidad<100) o el ¿tiempo es menor a 5? (tiempo<5). ¿Qué pasa si se nos plantea una situación donde el robot deba decidir actuar en función de que la velocidad no sea la máxima (es decir, que sea menor que 100) y el tiempo no supere los 5 46 5.1. Los valores de verdad en Python Operador Descripción Ejemplo == Verifica si el valor de dos operadores son iguales o no, si los valores son iguales la condición es verdadera (n == 4) != Verifica si el valor de dos operadores son distintos o no, si los valores son distintos la condición es verdadera (n != 0) <> Similar a != (no se puede usar en Python 3) (n <> 0) > Verifica si el operando de la izquierda es mayor que el de la derecha (n > 0) < Verifica si el operando de la izquierda es menor que el de la derecha (n < 0) >= Verifica si el operando de la izquierda es mayor o igual que el de la derecha (n >= 0) <= Verifica si el operando de la izquierda es menor o igual que el de la derecha (n <= 0) Tabla 5.1. Operadores de comparación Operación Valor de la expresión ’dos’ > ’cero’ True len(’diez’) < len(’cinco’) True 3+5 > 10 False 3+5 == 8 True ’dos’==’dos’ True ’dos’!=’tres’ True Tabla 5.2. Ejemplos operadores de comparación segundos (tiempo<5). En este caso, es evidente que con los operadores de comparación vistos hasta ahora no es suficiente dado que tenemos que verificar dos condiciones a la vez. Sabemos resolver el problema por partes, pero nos faltan herramientas para combinar los resultados. Si evaluamos ambas partes de nuestra condición y ambas son verdaderas (True), entonces podemos decir que la condición general se cumpliría, pero si alguna (o ambas) no lo fuera, la condición general dejaría de serlo también. Existe un operador lógico que nos permite evaluar situaciones de estas características: el and (o conjunción). Así, si queremos saber si dos condiciones son simultáneamente verdaderas, como en el caso anterior, podemos escribir: >>> velocidad < 100 and tiempo<5 Así como existe el operador and, existe otro operador que nos permite expresar situaciones en las cuales sólo nos interesa saber si alguna (o ambas) de las expresiones son verdaderas, con que una de ellas lo sea, es suficiente. Este operador es el or. Veamos el siguiente ejemplo y las diferencias con el anterior. >>> velocidad < 100 or tiempo<5 En este caso, si el robot va a una velocidad menor a 100 “o” el tiempo es menor a 5, el valor de verdad de la expresión general será verdadero. Sólo la consideramos falsa, cuando ambas condiciones sean falsas. En algunas situaciones queremos expresar una condición, negando una situación dada. Por ejemplo, podríamos querer expresiones tales como: ¿la velocidad no es máxima?, o ¿no llegué al final del camino? Para expresar estas condiciones, Python provee el operador not. Este operador, niega el valor de verdad del operando. Veamos el siguiente ejemplo: 47 Capítulo 5. Robots que deciden Veamos la expresión anterior. ¿Notan algo extraño? Si se aplican las precedencias que les presentamos antes, estamos comparando 2 == 24 lo cuál obviamente es falso y, al resultado de esto que es False, lo multiplica por 12. Aunque parezca raro, en Python esto no da un error (piensen que sería lógico pensar en un error ya que estamos multiplicando un valor booleano con un entero). En Python, el valor de verdad False es equivalente al entero 0 y el true a 1. Por lo tanto multiplicar False por cualquier número dará False (¡¡¡es como multiplicar por 0!!!). 5.2. Condicionando nuestros movimientos Ahora que ya vimos cómo podemos plantear condiciones, podemos ver de qué manera nuestro robot podrá tomar decisiones. Estas decisiones pueden estar dadas por datos ingresados desde el teclado, o datos recibidos desde los sensores propios del robot. Para indicarle al robot que realice una u otra instrucción de acuerdo a si una condición es verdadera o falsa, utilizamos una sentencia de Python que se denomina if. La sentencia if es una estructura de control que evalúa una condición, y ejecuta un conjunto de instrucciones en caso que condición sea verdadera u (opcionalmente) otro conjunto de instrucciones si la condición es falsa. Veamos cómo utilizamos esta sentencia en Python. Vamos a escribir una función que reciba la velocidad a la que quiero que el robot se mueva, pero, siendo 20 la velocidad mínima de movimiento. Veamos cómo expresamos esto en un programa Python. Código 5.1. Avanzando. . . def avanzar(robot, velocidad, tiempo): if velocidad < 20: robot.forward(20, tiempo) else: robot.forward(velocidad, tiempo) En el ejemplo anterior, si se usa la función avanzar() para mover el robot, no se lo podrá hacer avanzar a una velocidad inferior a 20 aunque lo invoquemos con una velocidad menor. La forma general de la sentencia if es: Código 5.2. Definición del if if condición: instrucciones por evaluación verdadera else: instrucciones por evaluación falsa La condición la expresamos usando expresiones booleanas (como las que vimos al comienzo de este capítulo) que pueden contener operador relacionales y lógicos. . Cada “rama” del if termina con : y las instrucciones asociadas se encuentran indentadas. Ambas características son obligatorias. En caso de no respetarlas, Python indicará un error de sintaxis. Podemos usar varios if para tomar decisiones que no estén relacionadas, y como en este caso en particular no precisamos ninguno de los bloques else directamente no los escribiremos: 50 5.2. Condicionando nuestros movimientos Código 5.3. Avanzar controlando la variable tiempo def avanzar_limitado(robot, velocidad, tiempo): if tiempo > 1): print "Más de 10 segundos es demasiado, asumo que elegiste 10" tiempo = 10 if velocidad > 100: print str(velocidad) + " no es una velocidad válida, asumo que elegiste 100" velocidad = 100 robot.forward(velocidad, tiempo) Hasta ahora, sólo podríamos plantear dos posibilidades o dos caminos seguir. Muchas veces esto no nos alcanza. Supongamos que queremos dejar que el usuario elija qué hacer con el robot a través de un menú de opciones. Por ejemplo: Indicanos hacia qué dirección te gustaría mover el robot: 1.- Girar a la derecha 2.- Girar a la izquierda 3.- Avanzar 4.- Retroceder 5.- Dejarlo en la misma posición Opción: Una forma de plantear esto en Python es utilizando una versión de la sentencia if que permite plantear múltiples caminos. La forma general es: if <condicion1>: Instrucciones elif <condicion2>: Instrucciones elif <condicion3>: Instrucciones elif <condicion4>: Instrucciones else: Instrucciones El else final nos permite considerar todas las posibilidades que no fueron contempladas en las anteriores condiciones. De esta manera, nuestro ejemplo podría implementarse de la siguiente manera: Código 5.4. Elijo hacia donde avanzar print "Indicanos hacia qué dirección te gustaría mover el robot:" print "1.- Girar a la derecha" print "2.- Girar a la izquierda" print "3.- Avanzar" print "4.- Retroceder" print "5.- Dejarlo en la misma posición" opcion=raw_input("Opción:") if opcion==1: robot.turnRight(100,1) elif opcion==2: 51 Capítulo 5. Robots que deciden robot.turnLeft(100,1) elif opcion==3: robot.forward(100,1) elif opcion==4: robot.backward(100,1) else: robot.stop() O podríamos haber definido una función que reciba la orden (de acuerdo a la opción elegida) y mueva el robot acorde a dicha orden: Código 5.5. Elijo hacia donde avanzar con función def mover(robot, accion): if accion == "avanzar": robot.forward(100, 1) elif accion == "retroceder": robot.backward(100, 1) elif accion == "derecha": robot.turnRight(100, 1) else: robot.turnLeft(100, 1) mover("avanzar") mover("izquierda") mover("derecha") mover("retroceder") ¿Cuáles son las todas las órdenes posibles? ¿Qué pasa si introduzco la orden: “Doblar”? 5.3. Resumen En este capítulo aprendimos a trabajar con otro tipo de valores: los valores lógicos o booleanos y las formas de combinar estos valores para expresar condiciones más complejas. También vimos cómo utilizar la sentencia if (con sus distintas variantes) que permite que un programa escrito en Python ejecute un conjunto de acciones si se cumple una determinada condición u otro conjunto distinto si la condición no se cumple. 5.4. Actividades Ejercicio 5.1 Implemente la función bailar que recibe el tipo de baile que el robot realizará. Para esto, defina tres tipos de baile (con sus movimientos asociados) implementándolos en tres funciones distintas. La función bailar deberá invocar las otras funciones de acuerdo al parámetro recibido. Ejercicio 5.2 Implemente la función entonando_raro que recibe un número y si el número es par o es mayor que 100 el robot debe hacer un beep agudo, caso contrario el robot debe hacer un beep grave. Ejercicio 5.3 Vamos a plantear distintos estados de ánimo para nuestro robot. Vamos a suponer que si el robot está contento, avanzará a velocidad máxima y dará dos vueltas, si se encuentra enojado, hará esto mismo pero hacia atrás y si se encuentra deprimido sólo avanzará hacia adelante a na velocidad mínima. Escriba las tres funciones que implementen estos tres estados y un menú de opciones por el cual el usuario elegirá qué estado de ánimo tiene el robot. De acuerdo a la opción elegida es cómo se moverá. 52 Capítulo 6 Simplificando pasos Hasta ahora hemos aprendido a codificar funciones y a escribir programas de manera tal que nuestro robot pueda tomar decisiones. Hay mucho más que aprender, tanto sobre el uso del robot, como de Python. En este capítulo vamos a trabajar con otras estructuras de control de Python que nos permitirán mejorar los programas que realizamos hasta el momento y plantear otros nuevos que se acercarán más a la programación real. En particular, vamos a trabajar con las sentencias iterativas o de repetición. Recordemos nuestro primer programa con el robot. ¿Se acuerdan? Hicimos que el robot dibuje un cuadrado. El programa que planteamos era el siguiente: Código 6.1. Haciendo un cuadrado from duinobot import * b = Board("/dev/ttyUSB0") mi_robot = Robot(b, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) 55 Capítulo 6. Simplificando pasos mi_robot.turnRight(35, 1) mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) b.exit() ¿Notan algo con respecto a este código? Hay varias secciones que se repiten. En realidad, es lógico que sea así, dado que para construir un cuadrado se debe dibujar cada lado exactamente de la misma manera. En muchas ocasiones vamos a trabajar con iteraciones. Pensemos también en el menú de opciones del capítulo anterior: Código 6.2. Elijo hacia donde va print "Indicanos hacia qué dirección te gustaría mover el robot:" print "1.- Girar a la derecha" print "2.- Girar a la izquierda" print "3.- Avanzar" print "4.- Retroceder" print "5.- Dejarlo en la misma posición" opcion=raw_input("Opción:") if opcion==1: robot.turnRight(100,1) elif opcion==2: robot.turnLeft(100,1) elif opcion==3: robot.forward(100,1) elif opcion==4: robot.backward(100,1) else: robot.stop() En realidad el código anterior sería mucho más útil y real si permitiéramos que el usuario utilice este menú varias veces, inclusive ante un ingreso de una opción equivocada, que tenga la opción de volver a ingresarla. ¿Cómo podríamos escribir esto? Obviamente este caso es más complicado que el anterior. En el ejemplo del cuadrado, sabemos exactamente cuántas veces queremos repetir nuestro código en cambio en este ejemplo no lo sabemos. Para plantear estas situaciones contamos con dos sentencias que nos permiten codificar iteraciones. Éstas son: la sentencia for y la sentencia while. A lo largo de este capítulo veremos ejemplos de usos de cada una. 6.1. Sentencia de iteración for Pensemos en el ejemplo del cuadrado. Aquí sabemos exactamente cuántas veces tenemos que repetir la secuencia de instrucciones que nos permite dibujar un lado y girar. Esto es, debemos repetir cuatro (4) veces ese código. Para implementar esto usaremos la sentencia for. En general, la forma de usar esta sentencia es la siguiente: for <variable> in <lista>: <instrucciones> La variable tomará cada uno de los valores de la lista y en cada paso, ejecutará el conjunto de instrucciones. Esto se repetirá hasta que no queden más valores en la lista. 56 6.1. Sentencia de iteración for . Algo muy importante a tener en cuenta que las instrucciones que queremos que se repitan deben estar indentadas (con el mismo margen) dentro del for. En el ejemplo anterior, podríamos escribir nuestro programa de la siguiente forma: Código 6.3. Usando for para dibujar un cuadrado from duinobot import * b = Board("/dev/ttyUSB0") mi_robot = Robot(b, 1) for i in [1,2,3,4]: mi_robot.forward(50, 0.5) wait(1) mi_robot.turnRight(35, 1) b.exit() Como pueden ver, esto es muy práctico y nos permite simplificar nuestros programas. Veamos otro ejemplo donde es muy útil esta sentencia: for x in 'Entre Ríos': print x E n t r e R i o s En este caso, la variable x toma todos los valores de la cadena de caracteres “Entre Ríos”. Igualmente, seguimos teniendo un problema con esta estructura: la cantidad de veces que se itera depende de la lista de valores que planteemos. Pensemos en el siguiente problema: vamos a inventar un nuevo baile para nuestro robot. En el mismo, el robot debe ir hacia adelante y hacia atrás y luego girar, repitiendo esto 3 veces. Una posible implementación de esto, usando la sentencia for que recién aprendimos sería: Código 6.4. Usando for para bailar from duinobot import * b = Board("/dev/ttyUSB0") mi_robot = Robot(b, 1) for i in [1,2,3]: mi_robot.forward(50, 0.5) mi_robot.bakckward(50, 0.5) mi_robot.turnRight(35, 1) mi_robot.turnLeft(35, 1) wait(1) b.exit() 57 Capítulo 6. Simplificando pasos En cada repetición se evalúa la condición y, si es verdadera, se ejecutan las instrucciones. Veamos un ejemplo sencillo en el cual el robot avanza mientras se encuentre a más de 15 cm. de un obstáculo. Cuando detecta que se acercó a un obstáculo, se detendrá. Para esto vamos a utilizar la orden ping, que veremos más adelante con más detalle, que nos devuelve la distancia que existe entre el robot y un obstáculo. while (mi_robot.ping() > 15): mi_robot.forward() mi_robot.stop() . Al igual que en el caso de la sentencia for, las instrucciones que queremos que se repitan deben estar indentadas dentro del while. Volvamos a nuestro menú de opciones. Conociendo esta sentencia, podríamos modificar nuestro ejemplo para que el menú se presente mientras el usuario no elija finalizar el programa. Veamos cómo quedaría: Código 6.7. Decido movimientos... def decido_movimiento(robot): print('''Indicanos hacia qué dirección te gustaría mover el robot: 1.- Girar a la derecha 2.- Girar a la izquierda 3.- Avanzar 4.- Retrocede 5.- Salir ''') opcion=raw_input("Opción:") while (opcion!= '5'): if opcion==1: robot.turnRight(100,1) elif opcion==2: robot.turnLeft(100,1) elif opcion==3: robot.forward(100,1) elif opcion==4: robot.backward(100,1) else: print "Ingresaste una opción no válida." opcion = raw_input("Opción: ") Antes que nada, cambiamos la última opción del menú para incluir la opción “Salir” para controlar cuándo termina nuestro programa. La condición planteada en el while es una expresión booleana. Es decir que puede incluir todos los operadores vistos en el capítulo anterior cuando trabajamos con la sentencia if. La evaluación de las diferentes expresiones se realiza de izquierda a derecha, por lo tanto si la primera expresión resulta False y se están combinando dos expresiones con el operando and no se evaluará la que se encuentra a la derecha de la misma. Esto se denomina “evaluación de circuito corto”. Veamos un ejemplo que muestra esta situación: n = input('Ingresá un valor entre 6 y 9: ') while (n > 5) and (n < 10): sumo = sumo + n n = input('Ingresá un valor entre 6 y 9: ') print sumo 60 6.3. Resumen En este ejemplo si se ingresa un valor menor que 5, ya no se evaluará la segunda expresión que verifica si el valor es menor que 10. Podemos usar una sentencia while para implementar la función que dibuja un cuadrado. Veamos cómo quedaría: Código 6.8. Usando while para dibujar un cuadrado from duinobot import * b = Board("/dev/ttyUSB0") mi_robot = Robot(b, 1) cant_lados=4 lado while lado<=cant_lados]: mi_robot.forward(50, 0.5) mi_robot.wait(1) mi_robot.turnRight(35, 1) b.exit() En este caso, usar una u otra sentencia es indistinto. No así en el caso del menú. En el caso que puedan usarse cualquiera de las dos sentencias, dependerá de cada uno de uds. elegir la que más adecuada. 6.3. Resumen En este capítulo hemos usado las dos estructuras de control que nos permite repetir instrucciones. Vimos que usando while, podemos repetir un conjunto de instrucciones mientras una condición lógica se cumpla y usando el for podemos repetir las instrucciones un número fijo de veces. Usamos la función range() para generar una lista de valores automática que nos facilitó el uso de for, aunque su uso no es exclusivo de este contexto. 6.4. Actividades Ejercicio 6.1 Reescriban los ejercicios 1 y 3 del capítulo anterior, planteando los distintos en un menú que el usuario puede elegir. No se olviden de incluir una opción “Salir” para concluir con el programa. Ejercicio 6.2 Arme una lista con distintas frecuencias de sonidos y escriba una función que le indique al robot que “entone” esa melodía. Sugerencia: Pueden pasar la lista como parámetro a la función. Ejercicio 6.3 Usando ping realice una función que obligue al robot a avanzar durante 10 segundos a una velocidad dada, pero que se detenga si es que encuentra un obstáculo a 20 cm. 61 7.2. Algo más sobre funciones En el caso que la función posea más de un parámetro, al invocarla, los mismos se asocian en el mismo orden en que fueron definidos. Esto es, en el caso de la funcion4, cuando invocamos con los valores 22 y 11. se asume que 22 será el valor asociado al parámetro arg1 y 24 será el valor de arg2. Si conocemos el nombre de los parámetros, entonces podemos invocar a la función enviando los valores independientemente del orden en que la función los espera asociando los valores a los correspondientes nombres de argumentos, como se muestra en la última invocación a la funcion4. Si bien esto último no es lo más adecuado, muchas veces es útil cuando queremos que la función utilice alguno de los valores por defecto de sus parámetros, y sólo enviarle los que necesitemos1 . Los parámetros que poseen valores por defecto deben ir al final de la lista de parámetros. Veamos un ejemplo donde invocamos a una misma función de distintas formas. Presten especial atención a las tres últimas, ya que son incorrectas. ¿Pueden explicar la causa del error? Código 7.1. Funciones con argumento # Sea f una función cualquiera con 3 argumentos de la forma: f(a, b, c) def f(a, b, c): return [a, b, c] # Podemos enviar todos los argumentos en orden f(23, 10, 100) # Lo anterior es equivalente a: f(a=23, b=10, c=100) # pero cuando usamos nombres el orden no importa: f(c=100, a=23, b=10) # Podemos mezclar algunos con nombre, con otros que no tienen: f(23, c=100, b=10) f(23, b=10, c=100) # Pero todas las líneas que siguen son INCORRECTAS: f(a=23, 10, 100) f(23, c=10, 100) f(100, a=23, c=100) Veamos otro ejemplo donde definimos una función con varios argumentos: def imprimir_datos_vehiculo(patente, marca, color, tipo_motor, ruedas): print("Patente: " + patente) print("Marca: " + marca) print("Color: " + color) print("Tipo de motor: " + tipo_motor) print("Cantidad de ruedas: " + str(ruedas)) print("-" * 80) # Separador Podemos invocar a esta función enviando los parámetros por posición, es decir, el primer parámetro se corresponde con patente, el segundo parámetro se corresponde con marca, etc... imprimir_datos_vehiculo("xcz 001", "Chevrord", "rojo", "naftero", 4) imprimir_datos_vehiculo("bsc 120", "Fioen", "blanco", "naftero", 4) imprimir_datos_vehiculo("xzc 100", "Forvrolet", "azul", "gasolero", 4) imprimir_datos_vehiculo("czx 010", "ScanBenz", "blanco", "gasolero", 6) imprimir_datos_vehiculo("aaa 023", "Mercenia", "negro", "gasolero", 10) 1Recuerden en el capítulo 3 cuando definimos las funciones forward y backward 65 Capítulo 7. ¿Hacemos una pausa? En este caso, hay que recordar el orden de los 5 argumentos al invocar a la función. De no hacerlo, se asociarán en forma incorrecta. Si conocemos el nombre de los parámetros, entonces podría utilizar sus nombres y esto me permitiría ponerlos en cualquier orden: imprimir_datos_vehiculo("xcz 001", tipo_motor = "naftero", marca = "Chevrord", ruedas = 4, color = "rojo") . Como se mencionó anteriormente cuando mezclamos parámetros con nombre y sin nombre en la invocación de una función, los que no tienen nombre tienen que estar en orden y deben situarse al principio de la lista de argumentos Teniendo en cuenta lo anterior, es incorrecto invocar a imprimir_datos_vehiculo() de la siguiente forma: # Lo siguiente es un ERROR y no funciona: imprimir_datos_vehiculo("xcz 001", tipo_motor = "naftero", marca = "Chevrord", ruedas = 4, "rojo") ¿Se dan cuenta cuál es el error? 7.2.2. Retornando valores En muchos casos, definimos funciones que nos deben retornar valores. En este caso, utilizaremos la sentencia return, que nos permite especificar qué valor retornará la ejecución de la función. Si bien no es obligatorio usar return (sino, piensen en todos los ejemplos que les presentamos hasta el momento), es muy útil en muchos casos. Veamos el siguiente ejemplo: Código 7.2. ¿Qué movimiento nos gusta más? def movimiento_mas_elegido(r): avanzo=0 retrocedo=0 print('''Indicanos hacia qué dirección te gustaría mover el robot: 1.- Avanzar 2.- Retroceder 3.- Salir ''') opcion=raw_input("Opción:") while (opcion!= '3'): if opcion==1: robot.forward(100,1) avanzo=avanzo+1 elif opcion==2: robot.backward(100,1) retrocedo=retrocedo+1 else: print "Ingresaste una opción no válida." opcion = raw_input("Opción: ") if avzano>retrocedo: return "más avances que retrocesos" else: return "más retrocesos que avances" 66 7.3. Importando módulos La función que definimos, además de permitirle al usuario que elija la dirección en la que queremos mover al robot, nos retorna qué movimiento fue el que más elegimos. ¿Cómo deberíamos invocar y usar este valor retornado? Código 7.3. Invocación a movimiento_mas_elegido() ... mas_elegido=movimiento_mas_elegido(mi_robot) print "Al final de las pruebas, hubo "+ mas_elegido ... La sentencia return corta la ejecución de la función que la contiene. Esto significa que si detrás de esta sentencia escribimos otras, las mismas no se ejecutarán. En el siguiente ejemplo lo único que hace funcion_poco_util() es retornar el valor True, nunca realiza ninguna cuenta ni imprime nada en pantalla: def funcion_poco_util(a, b): return True print("Esto no se ejecuta nunca") x = a * b x = x / 3 print("esto tampoco") 7.3. Importando módulos Lo primero que vimos cuando comenzamos a trabajar con el robot tenía que ver con “agregar” al entorno de Python el módulo que contiene las funciones y los elementos para trabajar con los robots. Esto lo hacíamos utilizando la sentencia import. Hay dos formas de importar un módulo. La forma vista hasta el momento: from duinobot import * O, también podemos indicar: import duinobot Si bien con ambas sentencias logramos incorporar las funcionalidades necesarias para manejar el robot en nuestros programas, las diferencias están en cómo voy a utilizar esas funciones. Antes de seguir, veamos un concepto importante que debemos tener claro: los espacios de nombres. Un espacio de nombres es una tabla que indica a qué objetos hace referencia cada nombre. En el caso de la función del ejemplo último, funcion_poco_util(), el espacio de nombres asociado a la función tendrá una entrada para cada variable y parámetro que define, indicando que el nombre a, representa a tal o cual elemento (según sea el parámetro con el que invoque a la función). Supongamos que definimos el siguiente módulo: #Archivo: bailes.py def baile_lento(): # Implementación de la función... ..... def baile_rock(): # Implementación de la función... 67 Capítulo 8 Utilizando los sensores En capítulos anteriores escribimos programas para que el robot realice distintos movimientos y aprendimos a organizar nuestros códigos de distintas formas para hacer nuestro trabajo más eficiente y prolijo. Pero el robot aún no percibe el entorno, realiza literalmente lo que le indicamos sin importar si existen obstáculos o si, por ejemplo, alguna situación del contexto no le permite moverse. El robot que utilizamos posee varios sensores que podrían ser de suma utilidad para incorporarle algún tipo de “inteligencia” que le permita tomar decisiones en función del contexto. En la Figura 8.1 se puede observar que el robot tiene un sensor para detectar obstáculos y dos sensores para superficies claras y oscuras (que normalmente usaremos para detectar líneas). Veremos cómo hacer a nuestro robot más inteligente y autónomo usando estos sensores. 8.1. Conociendo los sensores Para saber qué valores podemos esperar de los sensores podemos usar la orden senses() que, en una ventana separada muestra los valores retornados por los sensores. Esto lo podemos ver en el siguiente código: 71 Capítulo 8. Utilizando los sensores Figura 8.1. Sensores del robot usuario@host:~$ python Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from duinobot import * >>> b = Board("/dev/ttyUSB0") >>> b.report() Robot 1 prendido >>> robot = Robot(b, 1) >>> robot.senses() La Figura 8.2 nos muestra cómo es esta ventana y qué información presenta. Como pueden ver, además de mostrar los valores de los sensores de distancia y de línea, muestra el estado de las baterías. Esta información es importante tener en cuenta dado que, cuando las baterías están descargadas, el robot puede no funcionar correctamente. Prueben acercar su mano frente al robot (delante de los sensores de distancia) para ver cómo cambia el valor de ping o apoyen el robot en distintas superficies para ver cómo varían los valores de los sensores de línea. Figura 8.2. Ventana de información de sensores La Tabla 8.1 muestra los rangos de valores retornados por los sensores. 8.2. Evitando choques A partir de esta sección vamos a utilizar la información obtenida a través de los sensores para indicarle al robot que él decida si puede o no avanzar, retroceder o girar. En realidad, intentamos 72 8.5. Velocidad proporcional a la distancia n(x) = (x/maxOrigen) ·maxDestino Donde: maxOrigen: es el valor máximo original maxDestino: es el valor máximo al cual queremos convertir x: es el valor que queremos convertir Básicamente al dividir el valor original por el máximo del rango de origen, nos da un valor con decimales entre 0 y 1. Si luego multiplicamos este valor por el máximo del valor destino obtenemos el valor que queremos. Si no nos creen, escriban una función que realice este cálculo y prueben con los siguientes valores: maxOrigen = 601 y maxDestino = 100: n(0) = 0 n(20) = 3.3277870216306153 n(200) = 33.277870216306155 n(560) = 93.178036605657226 n(601) = 100 8.5. Velocidad proporcional a la distancia Podemos modificar un poco el programa visto al comienzo del capítulo para frenar gradualmente cuando se acerca un obstáculo, podemos usar el valor del sensor de obstáculo para determinar la velocidad. Si seguimos con el criterio anterior cuando estemos a 15 centímetros la velocidad debería ser cero, podemos hacer que el robot comience a frenar a 55 centímetros del obstáculo por ejemplo para que el efecto sea más visible. Una posible solución sería: mientras los objetos estén a más de 55 cm. simplemente avanzamos pero, cuando estén a menos de 55 y más de 15 centímetros deberíamos ir bajando la velocidad para que, cuando finalmente lleguemos a los 15 cm. le indicamos al robot que se detenga. Para que frene gradualmente podemos normalizar el valor de ping() a un valor entre 0 y 100 para poder utilizarlo como argumento de forward(). En realidad, esto será una aplicación de lo visto en la sección anterior. El código 8.3 muestra una implementación en Python. Código 8.3. Programa: Velocidad proporcional a la distancia from duinobot import * from mis_funciones import normalizar board = Board("/dev/ttyUSB0") robot = Robot(board, 1) 75 Capítulo 8. Utilizando los sensores robot.forward(100) while robot.ping() > 55: pass while robot.ping() > 15: robot.forward(normalizar(robot.ping(), 55, 100)) robot.stop() board.exit() Asumimos que la función normalizar() está almacenada en el módulo mis_funciones, por eso la sentencia1: from mis_funciones import normalizar Para probar si esto funciona correctamente pueden levantar el robot y acercarlo y alejarlo lentamente de un obstáculo para ver cómo cambia la velocidad de las ruedas. 8.6. Resumen En este capítulo hemos trabajado con los sensores del robot. Vimos cómo detectar obstáculos utilizando las órdenes robot.getObstacle() que nos devuelve True si hay algún objeto cerca y False en otro caso y la orden robot.ping() que devuelve la distancia en centímetros al objeto más cercano al frente del robot. También vimos cómo obtener los valores de los sensores de línea con la orden robot.getLine() y que podemos visualizar los valores de todos los sensores utilizando la orden robot.senses(). 8.7. Actividades Ejercicio 8.1 Vamos a sumar un nuevo estado a nuestro robot: robot_miedoso. En este caso, el robot se escapará cuando algún objeto se le acerque a menos de 20cm. Para esto, agregue una nueva función que implemente esto en el módulo tipos_de_robots Ejercicio 8.2 Escriban un programa que permita al robot recorrer una habitación sin chocar. En caso de encontrar un obstáculo el robot debe retroceder, girar y luego avanzar en la nueva dirección. El programa debe terminar luego de encontrar 5 obstáculos. Ejercicio 8.3 Escriban un programa que permita al robot avanzar hasta encontrar una superficie oscura. Ubiquen al robot en una superficie clara para probar esto. (pueden probar esto al revés, es decir, sobre una superficie oscura, buscar una clara). Ejercicio 8.4 Implementen la función normalizar1() que recibe como argumentos el valor, el máximo del rango origen y el máximo del rango destino y retorne el valor normalizado. Por ejemplo, para el caso anterior normalizar1(20, 601, 100) ≈ 3.33. Ejercicio 8.5 Modifique la función anterior, para contemplar valores fuera de rango. Es decir que si el valor es negativo debe hacer las cuentas como si el valor fuera 0 y si el valor es mayor que el máximo permitido debe hacer las cuentas como si el valor fuera el máximo permitido. Ejemplos: normalizar(−20, 601, 100) = 0 normalizar(−1, 601, 100)) = 0 normalizar(602, 601, 100) = 100 1Si uds. usan otros nombres, simplemente adecúen este código. 76 8.7. Actividades normalizar(1000, 601, 100) = 100 normalizar(600, 601, 100) ≈ 99.83 77 Apéndice A. Instalación de paquetes Podemos notar en la Figura A.2 que se encuentra dividida en 4 partes. En el margen izquierdo tenemos distribuido por categoría (N° 1 Lista de categorías), abajo se encuentran los filtros (N° 2), a nuestra derecha arriba se encuentran todos los paquetes que pertenecen a esa categoría (N° 3 paquetes para instalar) y abajo una breve descripción del paquete seleccionado(N° 4 Descripción de la aplicación). Figura A.2. Secciones de la Synaptic Para instalar un paquete podemos seleccionar una categoría y luego hacer doble clic sobre él o clic derecho, “Marcar para instalar”. De esta forma, podemos marcar todos los paquete deseados y luego pulsamos en el botón “Aplicar para instalar”. Synaptic comenzará la descarga de los paquetes necesarios desde los repositorios en Internet o desde el CD de instalación. También podemos realizar una búsqueda rápida. En la barra de menú, tenemos un buscador donde podemos ingresar el nombre del paquete que queremos instalar, abajo nos muestra el resultado de la búsqueda. Para instalar los paquetes repetimos el proceso ya mencionado. Figura A.3. Buscar un paquete 80 A.2. Instalación de la API del Robot A.2. Instalación de la API del Robot La API del robot puede ser instalada en distintas distribuciones GNU/Linux, el método de instalación varía dependiendo de la distribución que usemos, en particular el paquete de la API fue probado en distintas versiones de Lihuen, Debian, Ubuntu y RxArt. Para tener un funcionamiento completo de la API recomendamos la versión de Python 2.6 o 2.7, aunque la API está preparada para funcionar en un modo con funcionalidad reducida en Python 2.5 y posiblemente 2.4. Esta guía es solo ilustrativa y hace referencia a la versión del paquete al momento de ser escrita, es muy probable que cuando lean esto existan versiones más nuevas y mejores de los paquetes. Les recomendamos leer la versión actual de la guía en la página del proyecto (si en enlace anterior está roto buscá “instalación” con el buscador de la página del proyecto). A.2.1. En distribuciones basadas en Debian con Python 2.5 Dentro de esta categoría entran: Debian Lenny Lihuen 3 Ubuntu 8.04 Algunas versiones de RxArt En estas distribuciones se debe descargar nuestro paquete para Python 2.5 y abrirlo con la aplicación GDebi que nos permitirá instalarlo. A.2.2. En distribuciones basadas en Debian con Python 2.6 o superior Dentro de esta categoría entran: Debian Squeeze a Wheezy Lihuen 4.01 (ver A.2.3) Ubuntu 10.04 a 12.04 Algunas versiones de RxArt En estas distribuciones hay que descargar el paquete para Python 2.6 e, igual que en el otro caso, hay que abrirlo con la aplicación GDebi que nos permitirá instalarlo o bien con Software Center. A.2.3. En Lihuen 4.x En Lihuen 4 el paquete robot se encuentra en nuestros repositorios oficiales, así que basta con seguir la guía de uso de Synaptic, buscar el paquete y marcarlo para instalar. 81 Apéndice A. Instalación de paquetes A.2.4. En otras distribuciones GNU/Linux y otros sistemas operativos Si bien no está del todo probada no tendría que haber ningún inconveniente con instalar la API en cualquier otra distribución GNU/Linux. En el caso de otros sistemas operativos como FreeBSD o en sistemas propietarios es posible que la API funcione ya que fue desarrollada con la intención de ser multiplataforma (excepto la función boards() que no es portable y seguramente no funcione en otros sistemas). El método de instalación genérico consiste en usar Python Distutils, para esto hay que tener instalado: Python 2.6 (recomendado, pero puede ser cualquier versión mayor a 2.4 y menor que 3.0) PySerial (python-serial) PyGame (python-pygame) Python-Tk (python-tk) Es necesario descargar el paquete con el “código fuente” del módulo DuinoBot, descomprimirlo, entrar a la carpeta creada y ejecutar el siguiente comando en una terminal como usuario administrador: python setup.py install En sistemas Unix-like se puede usar el siguiente script: #!/bin/sh wget http://repo.lihuen.linti.unlp.edu.ar/lihuen/pool/lihuen4/main/r/robot/ robot_0.10.tar.gz tar -xzf robot_0.10.tar.gz cd duinobot python setup.py install 82 B.2. Otros robots similares Figura B.1. Conexión al board usando el cable USB Figura B.2. Mover el robot con Minibloq void setup() { motor0.setSpeed(100); motor1.setSpeed(100); delay(1000); motor0.setSpeed(0); motor1.setSpeed(0); } void loop() { } Estos programas se pueden compilar y cargar con DuinoPack (una versión modificada de Arduino IDE) conectando el robot a la computadora usando un cable USB. También se puede hacer lo mismo con Minibloq como se ve en la figura B.2. B.2. Otros robots similares Existen otros robots similares que tienen el objetivo de ser herramientas para enseñar a programar, algunos de ellos tienen especificaciones abiertas, algunos están planteados como kits de construcción, 85 Apéndice B. Especificaciones de los robots algunos deben ser construidos por alguien con nociones de electrónica y otros vienen ya armados. B.2.1. Robots artesanales Existen distintos modelos de microcontroladores que pueden ser utilizados para crear robots que tengan una funcionalidad similar a los robots de este curso, entre los más populares están los PIC 6 y los AVR 7, algunos de estos dispositivos precisan montarse temporalmente en placas especiales (programadores8) para ser programados, pero actualmente existen muchos que se pueden programar estando ya montados en la placa en la que funcionarán sin usar programadores especiales. La plataforma Arduino 9 y proyectos derivados como Freeduino 10 actualmente son muy usados para este tipo de proyectos, Arduino y Freeduino están compuestos de software libre y hardware abierto. El sitio http://hackaday.com es un gran recurso para encontrar información sobre construcción de robots. B.2.2. Icaro El proyecto argentino Icaro 11 plantea la construcción de placas fáciles de usar al estilo de Arduino y robots controlados por esas placas, también provee distintas modalidades de programación: Con bloques, con el robot funcionando de forma autónoma, con “icaro-bloques”. Con bloques, si el robot está conectado a una notebook con “turtleart” (“tortucaro”). Con C++ con “ICARO C++”. A modo control remoto con la interfaz gráfica “pycaro”. Los robots de Icaro se programan usando una API en español y en el caso de usar “icaro-bloques” los nombres de las estructuras de control también están en español. El software de Icaro es libre y el hardware es de especificaciones abiertas. El hardware de Icaro es fácil de construir con herramientas al alcance de cualquier aficionado a la electrónica y está basado en microcontroladores PIC en lugar de los AVR de Arduino. B.2.3. Myro Hardware Anteriormente utilizamos los robots propuestos por Institute for Personal Robots in Education (IPRE), en particular los robots Scribbler con una placa conocida como IPRE Fluke que permite controlarlos a través de bluetooth y le agrega sensores extra, como ser más sensores de obstáculos y una cámara para tomar fotografías. Para controlarlos desde el intérprete de Python usamos el paquete Myro que provee una interfaz de comandos similar a la propuesta por el curso pero más orientada a la programación procedural con un solo robot (si bien es posible instanciar varios robots y controlarlos desde un solo programa). Actualmente el Scribbler 2 fabricado por Parallax es hardware de especificaciones abiertas y el Institute for Personal Robots in Education está promoviendo otra API para reemplazar a Myro conocida como Calico Myro o simplemente Calico. 6http://es.wikipedia.org/wiki/Microcontrolador_PIC 7http://es.wikipedia.org/wiki/AVR 8http://es.wikipedia.org/wiki/Programador_(dispositivo) 9http://www.arduino.cc/ 10http://www.freeduino.org/ 11http://roboticaro.org/ 86 B.2. Otros robots similares Figura B.3. Icaro-bloques Figura B.4. Robot del proyecto Icaro El IPRE es un esfuerzo conjunto entre Georgia Tech y Bryn Mawr College con el sponsor de Microsoft Research. El Scribbler también puede ser programado a través de un puerto serie usando programación por bloques o con distintos lenguajes de programación dependiendo de la versión del robot, se pueden ver ejemplos en la página de Parallax 12. 12http://www.parallax.com/ 87
Docsity logo



Copyright © 2024 Ladybird Srl - Via Leonardo da Vinci 16, 10126, Torino, Italy - VAT 10816460017 - All rights reserved