<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="es">
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?feed=atom&amp;namespace=0&amp;title=Especial%3AP%C3%A1ginasNuevas</id>
		<title>Proyecto Butiá - Páginas nuevas [es]</title>
		<link rel="self" type="application/atom+xml" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php?feed=atom&amp;namespace=0&amp;title=Especial%3AP%C3%A1ginasNuevas"/>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Especial:P%C3%A1ginasNuevas"/>
		<updated>2026-04-05T22:29:53Z</updated>
		<subtitle>De Proyecto Butiá</subtitle>
		<generator>MediaWiki 1.26.2</generator>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Taller_de_Rob%C3%B3tica_educativa</id>
		<title>Taller de Robótica educativa</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Taller_de_Rob%C3%B3tica_educativa"/>
				<updated>2021-06-25T19:22:36Z</updated>
		
		<summary type="html">&lt;p&gt;Leandromesaprofesional: /* Clase 5 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introducción del proyecto==&lt;br /&gt;
La idea principal por la que se eligió este tipo de proyecto fue por querer seguir la linea de proyectos anteriores del curso de Robótica, la cual era impartir clases en un centro educativo.&lt;br /&gt;
En este caso se está impartiendo clases a un grupo del instituto tecnológico de informática (ITI), en el cual hay rangos diversos de edades y conocimientos previos sobre temas de robótica, programación e informática.&lt;br /&gt;
Por lo anterior es importante trazar una linea que permita que todos se sientan cómodos con los temas presentados, en cuanto a dificultad.&lt;br /&gt;
Debido a la institución, no es un tema nuevo totalmente hablar de programación, sin embargo si para algunos, los cuales toman este taller como primer acercamiento a la programación y por supuesto a la robótica.&lt;br /&gt;
&lt;br /&gt;
La programación es bien sabido que ayuda a la lógica y al desarrollo de habilidades para solventar problemas, en mayor o menor medida, juntar esta disciplina con la robótica ayuda a que se pueda visualizar mas fácilmente los algoritmos desarrollados, pudiendo ver como el robot sigue las ordenes que nosotros le damos, por otro lado, si nuestra lógica es incorrecta se reflejará en una acción errónea por parte del robot.&lt;br /&gt;
Desgraciadamente por el tema de la emergencia sanitaria no estamos pudiendo realizar el taller de forma presencial por lo que se pierde el trabajo de ellos de forma directa con el robot, lo cual es lo mas llamativo e interesante, se pierde el sentido de pertenencia, sin embargo cuando se retome ellos van a poder experimentar con el robot, armarlo y ejecutar programas.&lt;br /&gt;
&lt;br /&gt;
==Modalidad de trabajo==&lt;br /&gt;
La problemática que se alza por encima de las demás con diferencia es la virtualidad, lo ideal seria que ellos pudiesen experimentar con el robot, sin embargo hasta no retomar la presencialidad esto no es posible.&lt;br /&gt;
Por tanto para poder llevar adelante el taller por lo que se optó fue de hacerlo de forma virtual, presentando proyectos con el robot y esperando a la presencialidad para que pudiesen ellos poner en practica lo aprendido con el mismo. Sin embargo se usaron otros entornos para emular el desarrollo con el robot.&lt;br /&gt;
&lt;br /&gt;
Las clases son dadas los días Sábado, de 08:00 a 10:00, a través de Google Meets, se utilizan presentaciones de Power Point para exponer los temas que se trataran en la clase y entre medias de esto se realizan ejemplos en el ambiente que se este trabajando en ese momento.&lt;br /&gt;
Si hay que mostrar algo del robot se hace con la cámara de la computadora, como armarlo por ejemplo, si es necesario verlo en funcionamiento se utiliza la cámara del celular con un usuario propio metido en la sección.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Materiales para la realización del proyecto==&lt;br /&gt;
&lt;br /&gt;
El material principal es el kit de robótica Butiá, dado a que en torno a él gira el taller.&lt;br /&gt;
&lt;br /&gt;
Debido a la virtualidad otro material necesario es un ordenador y conexión a internet.&lt;br /&gt;
&lt;br /&gt;
El ordenador debe contar con distribución Linux dado que en este sistema corre TurtleBots.&lt;br /&gt;
&lt;br /&gt;
A futuro para la presencialidad se necesitarán mas kits para que los estudiantes puedan intervenir en el taller.&lt;br /&gt;
&lt;br /&gt;
Aquellos estudiantes que por tema de tiempos no pueden ir al taller pero quieren participar en él, también se graban las clases y se suben a YouTube, para poder seguir el curso de forma asíncrona.&lt;br /&gt;
&lt;br /&gt;
==Clase 1==&lt;br /&gt;
En esta clase se presentó el taller, se dieron pautas de trabajo y objetivos del mismo.&lt;br /&gt;
&lt;br /&gt;
Se presentó el robot Butiá y sus componentes, antes de esto se preguntó a los estudiantes si conocían robots y si podían nombrarlos.&lt;br /&gt;
&lt;br /&gt;
Se presentaron en los componentes del Butiá los sensores y actuadores, se expuso las características de cada uno de los sensores y ser preguntó posibles usos para ellos. Para los actuadores se presentó el motor, dado a que es el que vamos a estar trabajando, y se expuso la misma pregunta que para los sensores.&lt;br /&gt;
&lt;br /&gt;
Se presentó el primer ambiente de trabajo el cual es TurtleBots, se dijo la razón de su elecciñon y se explicó que era.&lt;br /&gt;
&lt;br /&gt;
Se presentó el segundo ambiente de trabajo el cual es OpenRoberta, el cual se usará debido a la virtualidad, dando la oportunidad de hacer seguidores de linea y evitar colisiones. Nuevamente se explico el por que de su elección.&lt;br /&gt;
&lt;br /&gt;
Se presentó el lenguaje Python el cual vamos a estar trabajando al finalizar los otros dos entornos, se explico algunos programas que se realizarían y que era el lenguaje en rasgos muy generales.&lt;br /&gt;
&lt;br /&gt;
Debido a que se trabajaría con TurtleBots, se necesita del entorno de desarrollo Linux o en su defecto una maquina virtual, se explicó al final de la clase como instalar la maquina virtual con Linux o en su defecto el que quisiese pudiera hacerlo a través de la BIOS.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;youtube&amp;gt;AGk2GGNYjJQ&amp;lt;/youtube&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Clase 2==&lt;br /&gt;
En esta clase la idea era que todos ya contaran con la máquina con su entorno Linux y TurtleBots instalado.&lt;br /&gt;
Se presento el primer ambiente de desarrollo, se profundizó en que era y el por que de su elección.&lt;br /&gt;
Se presentaron las paletas que maneja TurtleBots, la primera que se trabajó fue la paleta de movimientos de la tortuga, se mostraron los bloques por medio de una presentación de Power Point y se incitaba a la participación de los estudiantes preguntándoles que era cada bloque, se propuso como desafío en TurbleBots generar cuadrados y triángulos.&lt;br /&gt;
&lt;br /&gt;
Se presentó la paleta de operadores de flujo, se ejemplificó los diferentes ciclos y condicionales, y se puso énfasis en el bloque &amp;quot;esperar&amp;quot;, junto con esta paleta se mostró la de operadores numéricos, lo que nos permitió dar vida a los ciclos y condicionales.&lt;br /&gt;
Se ejemplificó el funcionamiento de los booleanos por medio de los operadores relacionales de la paleta de operadores numéricos y se explicó los operadores lógicos por medio de una tabla de verdad.&lt;br /&gt;
Ya conociendo los ciclos y los operadores numéricos se necesitaba poder optimizar el código para que no fuese tan largo y repetitivo, para esto se presento la paleta de funciones, la cual nos permitió reutilizar código ya escrito, se presentó el mismo ejemplo del cuadrado pero utilizando una función que lleve ese nombre.&lt;br /&gt;
&lt;br /&gt;
Se hicieron programas con el bloque de variables, se explicó que era una variable y se ejemplificó por medio de programas, esta vez el ejemplo del cuadrado debía tener un tamaño dado a partir de una variable creada por los estudiantes.&lt;br /&gt;
A partir de acá se realizaron un par de ejercicios con la tortuga, se presentó la ultima paleta que es la que se usa para que la tortuga pueda dibujar.&lt;br /&gt;
&lt;br /&gt;
Se realizó un programa que haga que la tortuga dibuje, estilo lápiz de paint.&lt;br /&gt;
&lt;br /&gt;
Se realizó un programa que imita el balde de pintura de paint, la tortuga dibuja un cuadrado y lo rellena del color que nosotros indiquemos.&lt;br /&gt;
&lt;br /&gt;
Se realizo un programa para hacer un cohete, por medio de cuadrados y triángulos, utilizando todo lo aprendido anteriormente.&lt;br /&gt;
&lt;br /&gt;
Se finalizo la clase realizando un programa que permitiese que la tortuga &amp;quot;copiara&amp;quot; en pantalla una imagen extraída de una carpeta (se presento para esto la paleta respectiva), como si fuese una impresión, una vez realizado este programa, se incitó a que los estudiantes a realizar una modificación al código para que sin importar la imagen dada el resultado de la copia fuese visualizado en forma de triangulo, y luego para un circulo.&lt;br /&gt;
&lt;br /&gt;
Para terminar la clase, se armó el robot Butiá a través de la cámara de la computadora.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;youtube&amp;gt;QrOZtn0j19M&amp;lt;/youtube&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Clase 3==&lt;br /&gt;
En esta clase se continuo trabajando con TurtleBots, pero enfocado exclusivamente en el robot Butiá, se presentó la paleta Butiá, los bloques que lo conforman y su funcionamiento.&lt;br /&gt;
Comprobamos que se podían colocar varios sensores del mismo tipo en el Butiá, tantos como la placa permita.&lt;br /&gt;
&lt;br /&gt;
Se realizó como ejercicio la creación de un cuadrado usando el robot Butiá, se presentaron los inconvenientes que tenia esta implementación, ¿Como indicar cuánto es 90 grados?, ¿Cómo le indicamos cuánto avanzar?, se dio respuesta a estas problemáticas.&lt;br /&gt;
&lt;br /&gt;
Se realizaron lecturas por parte de los sensores, se explico como calcular un umbral para hacer programas.&lt;br /&gt;
Se utilizo el bloque &amp;quot;Por siempre&amp;quot; y el bloque &amp;quot;Imprimir&amp;quot; para generar un programa que diera infinitas lecturas del sensor conectado.&lt;br /&gt;
Se comparó las lecturas de dos sensores iguales, notando el cambio drástico que pueden tener dos sensores sobre la misma superficie.&lt;br /&gt;
&lt;br /&gt;
Estudiamos el comportamiento de los seguidores de linea, se explicó que era un seguidor de línea, tanto seguidor con un solo sensor como con dos, se realizó la codificación en TurtleBots en ambos casos, y se mostró el funcionamiento para el sensor único.&lt;br /&gt;
&lt;br /&gt;
El funcionamiento para dos sensores quedo grabado en el canal de YouTube para aquellos que quieran ver su funcionamiento, o los que siguen el curso de forma asíncrona.&lt;br /&gt;
&lt;br /&gt;
Se realizó un programa que detecte cuando un objeto esta a X distancia del robot, cuando esto pase debía tomar otra dirección, se codificó y mostró el resultado.&lt;br /&gt;
Se explicó como cambiando la posición del sensor de distancia y la condición del ciclo, se podía generar un detector de caída.&lt;br /&gt;
&lt;br /&gt;
Se introdujo el ambiente OpenRoberta, se explicó el funcionamiento de los bloques y se programó como ejemplo un seguidor de lineas con dos sensores de dos maneras distintas. La primera es leyendo el color por el que pasa el sensor, la segunda leyendo la cantidad de luz que recibe el sensor.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Se mandaron cuatro tareas relacionadas a OpenRoberta para que puedan experimentar con el entorno y practicar la generación de algoritmos.&lt;br /&gt;
&lt;br /&gt;
La primer tarea consiste en realizar un seguidor de línea igual al del ejemplo planteado en la clase pero usando solamente un sensor.&lt;br /&gt;
&lt;br /&gt;
De forma similar la segunda es un seguidor de línea (usando dos sensores), que sea capaz de esquivar un obstáculo que se encuentre en el camino y retome la línea.&lt;br /&gt;
&lt;br /&gt;
La tercer tarea es simular un robot aspiradora que detecte las colisiones con los objetos y tome un rumbo aleatorio por el escenario.&lt;br /&gt;
&lt;br /&gt;
La cuarta y última es sobre un escenario dado con bloques de colores, utilizando direcciones absolutas (o relativas) lograr que al robot pasar sobre los bloques de colores, llegue hacia una línea de meta, el código debe ser replicable para ambas pistas proporcionadas.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;youtube&amp;gt;NqTcoxu9v9I&amp;lt;/youtube&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Los siguientes videos serían el resultado de los programas realizados en el taller: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;2cBMiq9wf90&amp;amp;list=PLpGDMoCLxQv3VKnOhjYN9S8_ZpI8iJuIp&amp;amp;index=6&amp;lt;/youtube&amp;gt;&amp;lt;youtube&amp;gt;2EuFxgTjgA0&amp;amp;list=PLpGDMoCLxQv3VKnOhjYN9S8_ZpI8iJuIp&amp;amp;index=3&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&amp;lt;youtube&amp;gt;DwxMU5_1HrI&amp;amp;list=PLpGDMoCLxQv3VKnOhjYN9S8_ZpI8iJuIp&amp;amp;index=2&amp;lt;/youtube&amp;gt;&amp;lt;youtube&amp;gt;uytmjbCBG7U&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Clase 4==&lt;br /&gt;
Se introdujo el lenguaje Python, utilizamos como entorno para programar el intérprete de Python en la terminal y luego utilizamos el editor de código VSCode, dimos un panorama general del lenguaje desde variables hasta funciones.&lt;br /&gt;
&lt;br /&gt;
Comenzamos hablando de las variables existentes en Python, enteros, flotantes, booleans, strings, se explicó que este lenguaje tiene tipado dinámico, por lo que las variables no precisan declaraciones de tipo, se explicó la funcionalidad de la función type().&lt;br /&gt;
&lt;br /&gt;
Se introdujo en concepto de arreglos y listas, se explicó cómo crear cada una y como recorrer las diferentes posiciones para acceder a los elementos, reemplazarlos, eliminarlos, etc.&lt;br /&gt;
Se introdujo la noción de métodos para arreglos, strings y listas, algunos de ellos por ejemplo, el método sort para ordenar los elementos y se explicó la funcionalidad de los parámetros predefinidos como por ejemplo el “reverse = True” que permite que el método sort ordene de forma decreciente los elementos. Se mostraron métodos para insertar elementos (append, insert, extend) y métodos para eliminar elementos (pop, remove).&lt;br /&gt;
Se explicó el funcionamiento de las comparaciones y la noción de rangos de equivalencia.&lt;br /&gt;
&lt;br /&gt;
Se realizaron operaciones usando los operadores aritméticos que trae el lenguaje y se realizaron cuentas usando booleanos.&lt;br /&gt;
Se introdujeron los comandos print e input para mostrar y pedir información al usuario, se explicó la conversión de tipos con diferentes funciones (int(), str()) y el formateo, que permite mostrar información de forma más amigable de cara al usuario.&lt;br /&gt;
&lt;br /&gt;
Se explicó el condicional if, junto con el elif y else. Se explicó cómo es la sintaxis del código y se puso un ejemplo para ver su funcionamiento.&lt;br /&gt;
Se introdujo el ciclo while y el ciclo for, se realizaron un par de ejercicios para mostrar su funcionamiento y diferencias.&lt;br /&gt;
Para los condicionales y ciclos se utilizó el editor de código para poder mostrar cómo guardar archivos del lenguaje y editarlos a través de terminal, cosa que no es necesaria con el intérprete.&lt;br /&gt;
&lt;br /&gt;
Se introdujo el concepto de función y procedimiento en Python, los cuales se definen a partir de la palabra reservada “def”, se ejemplificó el funcionamiento de cada uno de ellos.&lt;br /&gt;
&lt;br /&gt;
Se resaltó la noción de parámetros predefinidos, los cuales son usados cuando la entrada que le damos a la función es incorrecta, y se mostró una de las razones por la que el lenguaje de tipado dinámico puede fallar, al mandar tipos incorrectos y generar errores en ejecución. Mostramos ejemplos de cómo pasar una cantidad indefinida de parámetros usando “*” y concluimos con algunos ejemplos más generales.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;youtube&amp;gt;https://www.youtube.com/watch?v=r3wZqPGNg_g&amp;lt;/youtube&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Clase 5==&lt;br /&gt;
Se realizaron cuatro ejercicios que se plantearon en la clase anterior en el lenguaje Python, se mostraron varias soluciones.&lt;br /&gt;
&lt;br /&gt;
Se introdujo la API Butiá, se explicó como generar un archivo para poder compilar a través de Python un programa para realizar acciones sobre el robot, se explicó la función de las palabras predefinidas &amp;quot;import&amp;quot;, &amp;quot;from&amp;quot;, &amp;quot;as&amp;quot;, se introdujo la librería sys y la librería pyboy de la que se extrae usb4butia.&lt;br /&gt;
&lt;br /&gt;
Se generó una instancia en la placa Butiá a través de la librería anterior para poder acceder a todos los comandos que nos permiten controlar los sensores y los motores. Se mostraron los comandos que se utilizan para obtener medidas de los sensores y mover los motores.&lt;br /&gt;
&lt;br /&gt;
Se explicó como guardar los valores censados por los sensores en variables en Python, para poder utilizarlos en un programa.&lt;br /&gt;
Se mostró el funcionamiento de la bandera &amp;quot;debug = True&amp;quot; al instanciar la placa, que nos permite ver los dispositivos conectados a la placa, así como saber en que puerto están, lo que nos permite saber si hay algún problema, ya que en caso de haberlo este comando nos arrojará un error.&lt;br /&gt;
&lt;br /&gt;
Se mostró un código que hace que el robot se mueva hacia adelante hasta que se presione un botón, se explicó cada parte del código. Mostramos en el código anterior el funcionamiento del &amp;quot;While(True)&amp;quot;, que emula el &amp;quot;Por Siempre&amp;quot; de TurtleBots.&lt;br /&gt;
&lt;br /&gt;
Se mostró y codificó un programa que permite seguir una línea con un solo sensor, utilizamos para mostrarlo una hoja de papel blanco que simulaba una pista sobre fondo marrón, el robot se colocó en paralelo a la hoja de papel y al detectarla comenzaba a girar.&lt;br /&gt;
Se realizó el mismo procedimiento para dos sensores, la idea en ambos casos era seguir textualmente el código hecho en TurtleBots.&lt;br /&gt;
&lt;br /&gt;
Se mostró y codificó un programa que evita que el robot se caiga de la mesa, se siguió como base el código utilizado en TurtleBots y se fue programando poco a poco.&lt;br /&gt;
&lt;br /&gt;
Se introdujeron las librerías de matplotlib y numpy las cuales nos permiten por un lado generar gráficas en el caso de matplotlib y trabajar con vectores y matrices en el caso de numpy. Se explico como generar una gráfica de una recta, tomando como recorrido del eje x e y el arreglo [1, 2, 3, 4].&lt;br /&gt;
Se explicó como generar y cargar los ejes con estos valores y mostrar la gráfica en pantalla.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;youtube&amp;gt;https://www.youtube.com/watch?v=1tkCOgBpEJI&amp;amp;&amp;lt;/youtube&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Próximas clases==&lt;br /&gt;
Esto es un boceto de lo que serán las próximas clases:&lt;br /&gt;
&lt;br /&gt;
Clase 3: Continuamos trabajando con TurtleBots, pero utilizando el robot Butiá, haremos programas con él, detector de caída, seguidores de línea, detector de objetos, censar con los sensores entre otros.&lt;br /&gt;
&lt;br /&gt;
Clase 4: Se corregirán los ejercicios planteados en OpenRoberta, se les dará una solución y se introducirá el lenguaje Python. Se explicará desde cero, se dejarán tareas para que se practiquen los conocimientos planteados. (Variables, condicionales, ciclos, arreglos, funciones)&lt;br /&gt;
&lt;br /&gt;
//A PARTIR DE ACÁ SE ESPERA TENER PRESENCIALIDAD//&lt;br /&gt;
&lt;br /&gt;
Clase 5: Se continuará con el lenguaje Python, se espera que la clase anterior se haya dado lo básico del lenguaje, con esto se realizaran algunos programas básicos sobre el lenguaje. Se introducirá la API de Butiá y algún programa con esta.&lt;br /&gt;
&lt;br /&gt;
Clase 6: Se continuará con programas sobre el Butiá, se realizaran los programas hechos en TurtleBots, si da el tiempo se realizara el encoder.&lt;br /&gt;
&lt;br /&gt;
Clase 7: Se espera que sea una clase presencial para que ellos experimenten con el robot y puedan realizar ejercicios con el, los planteados hasta el momento.&lt;br /&gt;
&lt;br /&gt;
//A PARTIR DE ACÁ DEPENDE DE ELLOS SI SEGUIR O NO CON PROYECTOS COMO SUMO O LO RELACIONADO CON LA CLASE 8//&lt;br /&gt;
&lt;br /&gt;
Clase 8: Si completamos los ejercicios planteados en TurtleBots se continuara con Python mas avanzado (clases, POO) para la realización de plugis e IA.&lt;br /&gt;
&lt;br /&gt;
==Conclusiones del proyecto==&lt;br /&gt;
Por el momento el proyecto sigue siendo realizado pero las expectativas son muy buenas, los estudiantes están bastante interesados y prestan atención a los temas presentados.&lt;br /&gt;
Personalmente me esta gustando mucho la experiencia.&lt;br /&gt;
Se espera que quieran continuar con algún proyecto a futuro y de ser a sí sería algo muy bueno.&lt;br /&gt;
&lt;br /&gt;
//Pendiente de ampliación//&lt;/div&gt;</summary>
		<author><name>Leandromesaprofesional</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Introduciendo_la_rob%C3%B3tica_a_j%C3%B3venes_y_adolescentes</id>
		<title>Introduciendo la robótica a jóvenes y adolescentes</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Introduciendo_la_rob%C3%B3tica_a_j%C3%B3venes_y_adolescentes"/>
				<updated>2021-06-24T18:28:47Z</updated>
		
		<summary type="html">&lt;p&gt;Lucia.de.oliveira: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==INTRODUCCIÓN==&lt;br /&gt;
Las últimas investigaciones han demostrado que la robótica educativa es un buen sistema de enseñanza que beneficia a los alumnos y les es útil en el desarrollo de habilidades y competencias necesarias para un futuro personal y laboral, fomentando un interés por la ciencia, la tecnología, la ingenieria y las matemáticas así como en la área de lingüística y de la creatividad.&lt;br /&gt;
&lt;br /&gt;
En este caso se trabajó con chicos que van a la Universidad del Trabajo del Uruguay (UTU), en especial al Instituto Tecnológico de Informática (ITI), que comienzan a aprender sobre la programación. Esta es una excelente oportunidad para motivar a los estudiantes a aprender matemáticas y ciencias mediante la utilización y programación de robots. A pesar de ser un curso en principio virtual, se pueden obtener muchos conocimientos y herramientas del mismo.&lt;br /&gt;
&lt;br /&gt;
En el bachillerato tecnológico comienzan a tomar gusto por las áreas de programación, mecánica y diseño entre otras. Con los conocimientos ya adquiridos en estas áreas más los nuevos conocimientos que fueron y van a seguir siendo desarrollados mediante este taller, los alumnos serán capaces de explotar al máximo sus capacidades a la hora de desarollar programas para los robots. &lt;br /&gt;
&lt;br /&gt;
Estos programas pueden ser sencillos, pero también se pueden desarrollar otros que los alumnos consideren necesarios para ayudar en las tareas del día a día, mostrando así como los robots pueden formar parte de nuestra vida cotidiana.&lt;br /&gt;
&lt;br /&gt;
Este taller los ayudará en su futuro profesional dadas las capacidades que logra desarrollar, como la resolución de problemas y el trabajo en equipo. Además los chicos al sentirse capaces de resolver distintos problemas en el área de robótica se sentirán más autónomos y mejorarán la confianza en si mismos. &lt;br /&gt;
&lt;br /&gt;
La robótica ayuda a crear un buen clima de trabajo donde reina el compañerismo y el respeto, donde además se les inculca la noción de responsabilidad al tener que manipular el material ellos mismos.&lt;br /&gt;
&lt;br /&gt;
==MATERIALES==&lt;br /&gt;
*Kit Robótico Butiá&lt;br /&gt;
*XO/pc con TurtleBots y el Plugin de Butia y Python&lt;br /&gt;
*Sensores básicos (luz, grises, distancia y botón)&lt;br /&gt;
*Cinta aisladora (blanca o negra)&lt;br /&gt;
*Cartulina (negra o blanca)&lt;br /&gt;
&lt;br /&gt;
==PRIMER ENCUENTRO==&lt;br /&gt;
&lt;br /&gt;
La idea del primer encuentro era introducir la robótica a los chicos, así como el robot que vamos a utilizar, el Butiá. Para ello se utilizó [https://prezi.com/view/vG7LGkStO2duhmsbFxLf una presentación]. A su vez, se explicaron los conocimientos básicos de programación necesarios para manipular el robot. Se explicó el concepto de booleano, una variable que puede ser true o false, las sentencias and y or. Los bucles como repetir por siempre, for y while. Por último los condicionales if-then e if-then-else.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En la clase participaron 10 chicos y chicas de 15 años en adelante, desde el primer momento se mostraron interesados en el taller, realizando diversas preguntas, como por ejemplo, cuantos if-then-else se pueden encadenar y como se hace, cuantos and y or se pueden encadenar, entre otras. Incluso algunos de ellos ya habían trabajo con robots anteriormente, o al menos los conocían. &lt;br /&gt;
&lt;br /&gt;
Por último, como íbamos a trabajar con TurtleBots y muchos no tenían un sistema Linux donde instalarlo, aprovechamos el taller y cada alumno que no contaba con sistema Linux, o una virtual machine con Linux, la instaló. Seguimos [https://eva.fing.edu.uy/mod/page/view.php?id=80191 este instructivo] para la instalación de la máquina virtual y luego descargamos a instalamos TurtleBots.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==SEGUNDO ENCUENTRO==&lt;br /&gt;
&lt;br /&gt;
En este encuentro la idea fue empezar a conocer el ambiente de TurtleBots, cómo realizar programas con la tortuga y familiarizarse con la paleta Butiá. Se utilizo la [https://prezi.com/view/KVNRKkiJuNJo7a2XQm8z siguiente presentación]. Se detallaron las acciones que se pueden realizar, los comandos para la tortuga, las operaciones matemáticas que se pueden realizar. También se mostró como se ve en TurtleBots las estructuras previaente vistas como el while, for, por siempre, if-then e if-then-else. Sobre la paleta del Butiá se mostró que las opciones aparecen en verde cuando el robot está conectado, como se ven los sensores y cuántos sensores se pueden conectar.&lt;br /&gt;
&lt;br /&gt;
Para mostrar como funcionan los sensores y el rango de valores en el cual trabajan, fui conectando los sensores al Butiá, tomando muestras y contándoles qué valores iba dando. Mostraba que al cambiar las condiciones (luz, distancia, color) también cambiaban los valores que reflejaba el sensor.&lt;br /&gt;
&lt;br /&gt;
Luego se explicó como funcionaban las cajas en TurtleBots y se planteó un pequeño desafío en el cual la idea era realizar un cuadrado, cuyo lado valiera lo mismo que una variable llamada lado. Lo que mas le costó en este caso fue entender que al comando &amp;quot;derecha&amp;quot; o &amp;quot;izquierda&amp;quot; se le pasa un ángulo, y no cuánto debe avanzar luego de doblar a la derecha o a la izquierda. Los chicos que tenían el TurtleBots en su computadora lo hicieron de forma individual, dos alumnos que no contaban con el programa me indicaban que bloques poner y lo fuimos armando juntos.&lt;br /&gt;
&lt;br /&gt;
Por último se presentó [https://lab.open-roberta.org/ OpenRoberta], se utilizó OpenRoberta Sim para que los chicos pudieran trabajar con un simulador de robot. En principio les plantee como desafío crear un seguidor de línea para la pista que aparece predeterminada en el simulador, de forma que el robot diera una vuelta completa a la pista (sin utilizar el obstáculo que allí aparece). A continuación se puede ver la implementación de uno de los estudiantes:&lt;br /&gt;
[[Archivo:alumno.png|1200px]]&lt;br /&gt;
&lt;br /&gt;
Usó tres sensores de color para la implementación como les había recomendado, de forma que se les hiciera más sencilla. &lt;br /&gt;
Luego de la clase se plantearon otros dos desafíos para los alumnos, lograr que el robot tenga el comportamiento de una aspiradora (trasladarse por todo el espacio sin chocarse con los obstáculos), en este caso se usaron círculos negros para representar los obstáculos:&lt;br /&gt;
[[Archivo:obstaculos.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Luego se planteó un circuito en donde el robot tenía que partir de START y llegar a GOAL, en donde los siguientes cuadrados de colores representaban &amp;quot;norte&amp;quot;, &amp;quot;sur&amp;quot;, &amp;quot;este&amp;quot; y &amp;quot;oeste&amp;quot;. La idea es que ellos identificaran que color está relacionado con que punto cardinal, aun así, como a idea era que trabajaran programando el robot, les escribí qué color implicaba que punto cardinal para que pudieran realizar el ejercicio aunque no pudieran identificarlo por si mismos.&lt;br /&gt;
[[Archivo:cuadrados.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Esta clase se encuentra grabada y se puede acceder con el siguiente [https://youtu.be/cuz02uX0sfs link]&lt;br /&gt;
&lt;br /&gt;
==TERCER ENCUENTRO==&lt;br /&gt;
&lt;br /&gt;
Para este tercer encuentro se empezó a utilizar el robot Butiá con el TurtleBots para generar diferentes programas y conocer dos de los sensores: sensor de grises y sensor de distancia. Se utilizó la siguiente [https://prezi.com/view/tmuDtVYvyomDcO4SjhU0 presentación]. Se plantearon dos desafíos, lograr un seguidor de línea con dos sensores de grises y lograr que el Butiá ande sobre una mesa sin caerse con dos sensores de distancia.&lt;br /&gt;
&lt;br /&gt;
Primero pensamos entre todos cómo tenía que ser el seguidor de línea, la idea es que el robot se mantenga en la línea blanca y siga el recorrido marcado. Luego pensamos qué sensor nos iba a permitir detectar esa línea blanca (sobre un piso marrón).&lt;br /&gt;
&lt;br /&gt;
Luego de definir que vamos a usar el sensor de grises pensamos en un pseudo-código. Explicamos la importancia del comando &amp;quot;repetir por siempre&amp;quot; y nos dimos cuenta que si el sensor de la izquierda empieza a ver la línea blanca tenemos que girar a la izquierda y, en cambio, si el sensor de la derecha ve la línea blanca, tenemos que girar a la derecha.&lt;br /&gt;
&lt;br /&gt;
El siguiente paso fue calibrar el sensor de grises para ver en que valor detectaba blanco y en cual el marrón. (Acá tuvimos un problema con los sensores y no lo pudimos realizar). Aún así, pensamos en un código con valores genéricos para el sensor de grises:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Grises.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Por último planteamos un segundo desafío, la idea es que el robot ande por una mesa sin caerse. Primero pensamos entre todos cómo tenía que actuar el robot, cuando se acercara a un borde, tenía que tomar otra dirección para no caer. &lt;br /&gt;
&lt;br /&gt;
Pensamos en un pseudo-código, la idea era que el robot avance y, cuando llegue a un borde, retroceda un poco y gire (en algún dirección algún ángulo). Tenemos que poner que el robot retroceda un poco porque si no, no le da para doblar sin caerse.&lt;br /&gt;
&lt;br /&gt;
Le pregunté a los chicos cómo hacíamos para darnos cuenta que el robot había llegado al final de la mesa, decidimos que teníamos que usar el sensor de distancia, y como la medida que toma el sensor sobre la mesa es mucho menor a la que toma el sensor cuando está en el borde de la mesa (mirando al piso). La idea era que entonces cuando el sensor tome una medida mayor a un cierto número, retroceda y gire.&lt;br /&gt;
&lt;br /&gt;
Tomamos varias medidas con ambos sensores, en principio habíamos puesto un sensor en la parte delantera y otra en la trasera, pero luego nos dimos cuenta que la mejor forma era poner ambos adelante, uno en cada costado, y llegamos al siguiente código:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Distancia.png|400px]]&lt;br /&gt;
&lt;br /&gt;
A continuación que un link donde se ve cómo debería funcionar el [https://www.youtube.com/watch?v=s8etV8OsWvw sensores de grises], cómo funciona el robot [https://www.youtube.com/watch?v=1UlRKShgOcE sobre la mesa] y a la clase grabada.&lt;br /&gt;
&lt;br /&gt;
==PRÓXIMOS ENCUENTROS==&lt;br /&gt;
&lt;br /&gt;
Tengo planificadas al menos cuatro clases más las cuales, en principio, se desarrollarían según es detallado a continuación:&lt;br /&gt;
&lt;br /&gt;
Clase 4: Introducción a Python, lenguaje de programación de alto nivel. Conceptos básicos. Comparación entre aspectos de Java y de Python. Explicación del concepto de tipado dinámico. Utilización de la API para controlar el Butiá.&lt;br /&gt;
&lt;br /&gt;
Clase 5: Realización de programas con Python para controlar el robot Butiá similares a los realizados en TurtleBots.&lt;br /&gt;
&lt;br /&gt;
Clase 6: Realización de programas más avanzados que no son posibles con TurtleBots pero que Python da otras herramientas para poder hacerlos. Por ejemplo, un programa que cuenta las revoluciones por minuto del Butiá para distintas velocidades.&lt;br /&gt;
&lt;br /&gt;
Clase 7: Proyectos. Planteamos a los alumnos la posibilidad de presentarse en el Sumo de robótica, que son competencias a nivel nacional de Robótica en el Uruguay. En caso de que esten interesados seguiremos con esos alumnos el taller realizando un robot a fines de presentarlo en la competencia. En caso de estar interesados en otros tipos de proyecto con el Butiá también los ayudaremos a desarrollarlos en las próximas clases.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==CONCLUSIONES==&lt;br /&gt;
&lt;br /&gt;
Aunque solo van tres clases del taller veo que los alumnos están realmente enganchados con la propuesta, a pesar de la dificultad que conlleva tener un taller de robótica virtual, los chicos se adaptaron bien a la modalidad. Luego de vacaciones de invierno la idea es poder volver a la presencialidad con ellos. &lt;br /&gt;
Creo que volver a la presencialidad va a hacerlos enganchar más aún con la propuesta. Todos están ansiosos por poder controlar un robot ellos mismos y no usar un simulador o verlo por la camarita.&lt;br /&gt;
Me asombró la buena participación que tienen los estudiantes y el lindo intercambio que se da todas las clases, donde plantean sus inquietudes y además intentan realizar ejercicios por si mismos.&lt;br /&gt;
En lo personal me encantó la experiencia de dar clase en un centro educativo, me di cuenta que realmente me gusta enseñar y que los chicos se enganchen con la propuesta que planteo semana a semana.&lt;/div&gt;</summary>
		<author><name>Lucia.de.oliveira</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Robot_para_el_cuidado_de_plantas</id>
		<title>Robot para el cuidado de plantas</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Robot_para_el_cuidado_de_plantas"/>
				<updated>2021-06-24T14:14:44Z</updated>
		
		<summary type="html">&lt;p&gt;Alejandro.wurm: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Archivo:Robot para el cuidado de plantas.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
== Introducción ==&lt;br /&gt;
&lt;br /&gt;
La idea de este proyecto es crear una estructura en la cual se puede colocar tu planta (en una maceta) la cual recibirá dos cuidados centrales del proyecto. De estas dos funciones se encarga el robot Butiá.&lt;br /&gt;
La primer función de estas es un sistema de riego automático en el cual el robot toma agua de un recipiente, y con una bomba de agua la envía a través de una manguera para regar la planta.&lt;br /&gt;
Mientras tanto, la segunda función es un techo automático el cual se encarga de levantarse por el día, permitiendo la llegada de luz solar a nuestra planta, y bajando por la noche de modo que proteja a la planta de las heladas.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Motivaciones ==&lt;br /&gt;
&lt;br /&gt;
Esta idea surgió de ver a gente de mi entorno con problemas como olvidar regar su plata, o entrarla antes de la noche cuando cae la helada. Pensé que era una buena idea para una problemática de este estilo y además se puede considerar una solución para otras problemáticas. Un ejemplo de esto es una persona cuyo horario de trabajo es extenso durante el día y no pasa mucho tiempo en su hogar por lo que la automatización de los cuidados de su planta le puede venir muy bien. También para gente que se va de vacaciones y no tiene nadie quien le cuide las plantas durante ese tiempo.&lt;br /&gt;
A su vez, me pareció interesante a modo de proyecto educativo ya que no requiere de mucho conocimiento previo en la forma en que se programa, por lo tanto es una buena forma de aprender a la vez que se crea y una forma de aplicar la programación del robot a un tema de la vida real.&lt;br /&gt;
En conclusión, me gustó como idea para hacer mi primer proyecto ya que es muy diferente a lo que han sido mis experiencias anteriores con robots y es un planteamiento interesante de resolver.&lt;br /&gt;
&lt;br /&gt;
== Materiales ==&lt;br /&gt;
&lt;br /&gt;
* Placa USB4Butia&lt;br /&gt;
* Computadora con Linux (o una máquina virtual de Linux) y el programa TurtleBots instalado&lt;br /&gt;
* Shield&lt;br /&gt;
* Tornillos y tuercas (vienen incluidos en el kit Butiá)&lt;br /&gt;
* Un motor&lt;br /&gt;
* Una batería&lt;br /&gt;
* Un sensor de grises&lt;br /&gt;
* Un botón&lt;br /&gt;
* Un actuador genérico con módulo relé&lt;br /&gt;
* Pack de 4 baterías &lt;br /&gt;
* Una caja de plástico&lt;br /&gt;
* Una varilla hueca (con largo igual o mayor al ancho de la caja)&lt;br /&gt;
* Una bomba de agua pequeña&lt;br /&gt;
* Una manguera (que sirva para la bomba)&lt;br /&gt;
* Recipiente con agua&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Tutorial ==&lt;br /&gt;
&lt;br /&gt;
=== Estructura ===&lt;br /&gt;
&lt;br /&gt;
'''Paso 1'''&lt;br /&gt;
&lt;br /&gt;
Tomar la caja de plástico y recortarle una de las caras paredes chicas&lt;br /&gt;
&lt;br /&gt;
[[Archivo:RobCuidadoPlantasStep1.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
'''Paso 2'''&lt;br /&gt;
&lt;br /&gt;
Recortar unos centímetros de la base de la caja (11 cm en este caso, a partir del lado recortado).&lt;br /&gt;
Luego, parar la caja e incrustar el motor en la parte de arriba de la cara izquierda (en este caso, se incrustó a 1cm de alto y 3cm de ancho de la esquina).&lt;br /&gt;
Después, atornillarlo para que quede bien asegurado.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:RobCuidadoPlantasStep2-1.jpg|200px]] [[Archivo:RobCuidadoPlantasStep2-2.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 3'''&lt;br /&gt;
&lt;br /&gt;
Incrustar el motor en la varilla de modo que atraviese todo el ancho de la caja,y del otro lado, poner un tornillo desde afuera que conecte con la varilla. Esto permitirá que la varilla gire con el motor, y del otro lado se asegure en la pared y pueda girar. Se puede asegurar en el motor con cinta.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Step3.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
'''Paso 4'''&lt;br /&gt;
&lt;br /&gt;
Atornillar la cara removida en el caso 1 a la varilla, de modo que esta sea la tapa.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:RobCuidadoPlantasStep4.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
'''Paso 5'''&lt;br /&gt;
&lt;br /&gt;
Asegurar la placa y la batería del lado del motor. En este caso lo atornillé con los tornillos y tuercas que vienen con el kit. También agregar al lado el sensor de grises.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:RobCuidadoPlantasStep5.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
'''Paso 6'''&lt;br /&gt;
&lt;br /&gt;
Conectar el actuador con módulo relé a la bomba de agua y darle energía con el pack de 4 pilas. Para este paso es recomendable recibir ayuda de alguien que sepa manejar circuitería, en mi caso fue el docente quien me brindó asistencia para conectar las cosas.&lt;br /&gt;
Adjuntarlo al proyecto, debajo de la placa.&lt;br /&gt;
Conectar la manguera a la bomba.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:RobCuidadoPlantasStep5-1.jpg|200px]] [[Archivo:RobCuidadoPlantasStep5-2.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
'''Paso 7'''&lt;br /&gt;
&lt;br /&gt;
Hacer un agujero en la parte de abajo de la caja, por el cual pase la manguera, hacer que &amp;quot;trepe&amp;quot; la pared hasta un poco antes de la varilla y asegurarla. Luego extenderla horizontalmente y hacer un agujero del otro lado en donde meterla para que quede fija.&lt;br /&gt;
Luego de esto, se le tapa la salida a la manguera, y se hacen agujeros en la parte que quede mirando para abajo, de este modo el agua caerá en forma de lluvia.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:RobCuidadoPlantasStep7-1.jpg|200px]] [[Archivo:RobCuidadoPlantasStep7-2.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
Con esto estaría finalizada la estructura del robot.&lt;br /&gt;
&lt;br /&gt;
=== Código ===&lt;br /&gt;
&lt;br /&gt;
Primero utilizaremos esta parte de la paleta de TurtleBots en la cual podemos crear funciones y variables, las cuales nos facilitarán el manejo del programa.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:PaletaFunciones.png]]&lt;br /&gt;
&lt;br /&gt;
Usando el bloque &amp;quot;action&amp;quot; se puede crear una función, agregarle bloques y darle un nombre, para luego poder invocar esa porción de bloques solo con llamar el nombre de la función.&lt;br /&gt;
Con el bloque de &amp;quot;store in&amp;quot; podemos asignarle un nombre a la variable en el parámetro &amp;quot;box&amp;quot; y asignarle un valor en el parámetro &amp;quot;value&amp;quot;&lt;br /&gt;
&lt;br /&gt;
'''Subir y bajar techo'''&lt;br /&gt;
&lt;br /&gt;
Estas dos funciones son análogas.&lt;br /&gt;
En la función subir techo lo que hacemos es, inicializar la velocidad del motor en 300, y hacer que se mueva hacia atrás, de este modo este se moverá en dirección a abrir la tapa. La función espera un segundo y detiene al motor.&lt;br /&gt;
Luego de esto, se asigna a una variable llamada techoBajo, el valor 0, lo cual nos indica que el techo está alto.&lt;br /&gt;
Para la función de bajar el techo se cambia la función de que se mueva hacia atrás por la función de que se mueva hacia adelante, de modo que baje el techo, y se almacena al finalizar el movimiento, el valor 1 en la variable de techoBajo.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:BajarTecho.jpg]] [[Archivo:SubirTecho.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Regar'''&lt;br /&gt;
&lt;br /&gt;
El procedimiento de esta función es muy simple. Activamos el actuador del butiá, que representa la bomba de agua, esperamos 4 segundos (o el tiempo que se quiera que dure el regado) y luego la desactivamos.&lt;br /&gt;
En este caso el actuador se activa en 0 por lo tanto se empieza con la asignación del valor 0 y luego se asigna el valor 1.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Regar.png]]&lt;br /&gt;
&lt;br /&gt;
Ahora, es momento de crear la función principal.&lt;br /&gt;
Dentro del bloque de start se adjunta una inicialización en 1 del actuador, esto es porque al iniciar en 0, este inicia prendido, por lo comentado anteriormente. También inicializamos el techo bajo en 1.&lt;br /&gt;
Luego agregamos un bloque forever, este crea un loop infinito con las cosas que vayamos a agregar dentro. Utilizamos el boque de if, then, else.&lt;br /&gt;
En el primer if, colocamos un bloque de and, en el primer argumento del and ponemos un bloque de igual, que tome el valor de la variable &amp;quot;techoBajo&amp;quot; y el 1. El segundo argumento llevará un comparador &amp;lt; para comparar si el valor tomado por el sensor de grises es menor a 39000. Este número se puede testear porque a veces puede cambiar dependiendo del sensor los valores tomados por lo tanto es mejor si prueban los valores prendiendo y apagando la luz (esto pueden verlo con un print-&amp;gt;gray Butiá). Por lo tanto, este bloque de if evalúa si el techo está bajo y además la luz es menor al valor 39000, y en caso de que sea cierto, llama a la función de subir techo en el then.&lt;br /&gt;
En la parte del else, agregamos un nuevo bloque de if then, con una operación lógica similar a la de recién. Los cambios serían el comparador por uno de &amp;gt;, y en el bloque de igual la comparación del valor de la caja a 0. Esto hará que si el techo está alto y la luz baja de 39000, se llamará a la función de bajar techo.&lt;br /&gt;
Por último, saliendo de este if, then, else, colocamos un nuevo if then. Como condición agregamos un bloque de igual, y los argumentos botón Butiá, y el valor 1. En la parte del then invocamos a la función regar. Entonces en este bloque tenemos que si se aprieta el botón, se activa el regado.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:ProgramaRiegoYTechoCompleto.png]]&lt;br /&gt;
&lt;br /&gt;
Ahora solo queda conectar los sensores y la placa y darle vida clickeando la función start.&lt;br /&gt;
&lt;br /&gt;
==Cambios a futuro==&lt;br /&gt;
&lt;br /&gt;
La automatización es algo importante para cualquier cosa relacionada a la robótica por lo tanto una buena mejora a futuro sería automatizar el momento de riego. Para esto se podría utilizar la librería de Python &amp;quot;datatime&amp;quot; y crear un bloque de Python dentro de TurtleBots.&lt;br /&gt;
Otra posible mejora sería cambiar la condición de riego por un sensor de humedad que detecte cuando sea necesario el regado.&lt;br /&gt;
Para finalizar, el cambio del sensor de grises por uno de luz, ya que esto daría una mayor precisión a las variables de luz obtenidas.&lt;br /&gt;
&lt;br /&gt;
==Video==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://www.youtube.com/watch?v=5q0QdH8r0ZY&amp;lt;/youtube&amp;gt;&lt;/div&gt;</summary>
		<author><name>Alejandro.wurm</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Tbpy:_Creaci%C3%B3n_de_paletas_y_bloques_en_TurtleBlocks_utilizando_Python_a_alto_nivel</id>
		<title>Tbpy: Creación de paletas y bloques en TurtleBlocks utilizando Python a alto nivel</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Tbpy:_Creaci%C3%B3n_de_paletas_y_bloques_en_TurtleBlocks_utilizando_Python_a_alto_nivel"/>
				<updated>2021-06-22T07:45:13Z</updated>
		
		<summary type="html">&lt;p&gt;Tomas.caram: /* Instalación */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Resumen y motivación ==&lt;br /&gt;
Las herramientas que permiten programar con bloques, como TurtleBlocks, son instrumentos muy valiosos para facilitar el proceso de aprendizaje de programación en niños y jóvenes. Pero a veces, a medida que el estudiante está más avanzado pueden llegar a resultar demasiado básicas. En TurtleBlocks podemos extender las funcionalidades predeterminadas mediante plugins, por ejemplo, con algunos plugins podemos leer la entrada del micrófono, tomar una foto con la webcam o incluso manejar un robot como el Butiá. La creación de estos plugins requieren un conocimiento muy amplio sobre la base del código de TurtleBlocks y un manejo de la programación orientada a objetos, que es muy probable que dicho público objetivo no posea. El objetivo de tbpy es proveer una solución que permita agregar bloques a TurtleBlocks sin la necesidad de conocer cómo funciona TurtleBlocks &amp;quot;por debajo&amp;quot;, es decir, una solución a alto nivel. El usuario podrá, solamente creando simples funciones en Python agregar sus propios bloques a TurtleBlocks. Tbpy se encargará, entre otras funcionalidades, de cargar automáticamente las funciones, traducir los tipos primitivos de Python a primitivas de TurtleArts, seleccionar los estilos de los bloques, elegir el tipo de salida, etc. En la mayoría de los casos podrá inferir por sí sólo según la función introducida por el usuario muchas de estas opciones, quitándole así la responsabilidad de hacerlo al usuario y simplificando dicha tarea. También se incluye una funcionalidad de galería, que se integra con la libería de ejemplos de TurtleBlocks que permitirá compartir y consultar otros ejemplos de proyectos creados por otros usuarios.&lt;br /&gt;
&lt;br /&gt;
== Utilizando tbpy (documentación para usuarios) ==&lt;br /&gt;
==== Prerrequisitos ====&lt;br /&gt;
* [http://activities.sugarlabs.org/en-US/sugar/addon/4027 TurtleBlocks 218] o [https://www.fing.edu.uy/inco/proyectos/butia/files/package/ TurtleBots 31]&lt;br /&gt;
* [https://git-scm.com/downloads git] para clonar el repositorio o unzip para descomprimirlo. &lt;br /&gt;
* Conocimiento básico en Python&lt;br /&gt;
&lt;br /&gt;
==== Instalación ====&lt;br /&gt;
El plugin se puede instalar clonando el repositorio (o [https://github.com/tcaram/tbpy/archive/refs/heads/main.zip descargándolo] y descomprimiéndolo manualmente) sobre la carpeta TurtleBlocks.activity/plugins. Se necesitará un usuario con permisos de superusuario (sudo).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Clonando&lt;br /&gt;
cd &amp;quot;/usr/share/sugar/activities/TurtleBlocks.activity/plugins&amp;quot;&lt;br /&gt;
sudo git clone &amp;quot;https://github.com/tcaram/tbpy.git&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Descargando&lt;br /&gt;
cd &amp;quot;/usr/share/sugar/activities/TurtleBlocks.activity/plugins&amp;quot;&lt;br /&gt;
sudo wget &amp;quot;https://github.com/tcaram/tbpy/archive/refs/heads/main.zip&amp;quot;&lt;br /&gt;
sudo unzip main.zip&lt;br /&gt;
sudo mv tbpy-main tbpy #renombramos &lt;br /&gt;
sudo rm main.zip&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(se asume que TurtleBlocks está en el directorio predeterminado)&lt;br /&gt;
&lt;br /&gt;
Algunos bloques incluidos por defecto pueden requerir librerías de Python como requests, request-oauth, que hay que instalar por separado:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
# Instalar librerias de Python&lt;br /&gt;
python2 -m pip install requests requests-oauthlib&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En algunas versiones antiguas de TurtleBlocks, es necesario además habilitar el plugin desde la interfaz.&lt;br /&gt;
&lt;br /&gt;
==== Agregando bloques ====&lt;br /&gt;
Para agregar nuevos bloques se debe crear un archivo {nombre_grupo}.py dentro del directorio TurtleBlocks.activity/plugins/tbpy/groups que contendrá las funciones a ejecutar. Cada función debe contener en su docstring ([https://www.python.org/dev/peps/pep-0257/#what-is-a-docstring ¿qué es un docstring?]) una serie de parámetros. Referirse a la siguiente sección [[Tbpy:_Creación_de_paletas_y_bloques_en_TurtleBlocks_utilizando_Python_a_alto_nivel#Parámetros_del_docstring|Parámetros del docstring]] para más información.&lt;br /&gt;
&lt;br /&gt;
====== Ejemplo sin parámetros ======&lt;br /&gt;
En este ejemplo crearemos un grupo llamado &amp;quot;datentime&amp;quot; que agregará bloques relacionados a la fecha y hora del sistema.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki2.png|500px]]&lt;br /&gt;
&lt;br /&gt;
Todos los grupos deben contener las siguientes variables globales en la parte superior del archivo (debajo de los ''import'' si los hubiese):&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki3.png|500px]]&lt;br /&gt;
&lt;br /&gt;
Ahora crearemos las funciones. Definiremos la función get_date que devolverá la fecha actual del sistema (proveída por la biblioteca datetime de Python). No posee parámetros de entrada y devuelve la fecha como un string, así que necesitaremos la siguiente configuración:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki4.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Luego de colocarla en el docstring de nuestra función nos quedaría algo así:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki5.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Después de guardar el archivo y abrir TurtleBlocks, veremos lo siguiente en la paleta de tbpy:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki6.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Al ejecutar el bloque (con clic izquierdo) veremos la salida de la función:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki7.png|500px]]&lt;br /&gt;
&lt;br /&gt;
Ahora podremos utilizar y operar con el bloque como si fuera un bloque normal de TurtleBlocks:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki8.png|500px]]&lt;br /&gt;
&lt;br /&gt;
====== Ejemplo con parámetros ======&lt;br /&gt;
En este ejemplo crearemos un bloque que calcule la distancia entre dos puntos, el programa recibirá dos parámetros x1 y x2 de tipo float. También utilizaremos una función auxiliar &amp;quot;abs&amp;quot;, la cual se debe indicar con un guión bajo &amp;quot;_&amp;quot; al comienzo de su identificador.  &lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki9.png|500px]]&lt;br /&gt;
&lt;br /&gt;
Como agregamos un @Example en el docstring, al seleccionar el bloque se completará automáticamente:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki10.png|500px]]&lt;br /&gt;
&lt;br /&gt;
Podemos descartar el ejemplo y crear nuestro propio programa: &lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki11.png|500px]]&lt;br /&gt;
&lt;br /&gt;
==== Parámetros del docstring ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! Nombre&lt;br /&gt;
! Obligatoria&lt;br /&gt;
! Tipo&lt;br /&gt;
! Descripción&lt;br /&gt;
! Ejemplo&lt;br /&gt;
! Observación&lt;br /&gt;
|-&lt;br /&gt;
| Label&lt;br /&gt;
| Sí&lt;br /&gt;
| str&lt;br /&gt;
| Nombre del bloque. Es el nombre que aparecerá en el bloque en la interfaz de TurtleBlocks&lt;br /&gt;
| distance_between_3d_points&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| Description&lt;br /&gt;
| Sí&lt;br /&gt;
| str&lt;br /&gt;
| Descripción del bloque. Le indicará al usuario la función que cumple nuestro bloque en la interfaz de TurtleBlocks&lt;br /&gt;
| Calcula la distancia entre dos puntos con tres coordenadas.&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| Parameters&lt;br /&gt;
| No&lt;br /&gt;
| array de tuplas (type, paramName)&amp;lt;br /&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
| Parámetros del bloque con su respectivo tipo. Indica los parámetros que recibirá nuestro bloque.&lt;br /&gt;
| float x1, float y1, float z1, float x2, float y2, float z2&amp;lt;br /&amp;gt;&lt;br /&gt;
| Puede ser vacío.&lt;br /&gt;
|-&lt;br /&gt;
| Color&lt;br /&gt;
| No&lt;br /&gt;
| str&lt;br /&gt;
| Color del bloque en su representación hexadecimal. Color con el que aparecerá el bloque en la interfaz de TurtleBlocks&lt;br /&gt;
| #00ff00&amp;lt;br /&amp;gt;&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| Return&lt;br /&gt;
| No&lt;br /&gt;
| chr|str|int|bool|float|none&amp;lt;br /&amp;gt;&lt;br /&gt;
| Tipo de dato que devolverá el bloque.&lt;br /&gt;
| float&lt;br /&gt;
| Puede ser vacío (procedimiento).&lt;br /&gt;
|-&lt;br /&gt;
| Example&lt;br /&gt;
| No&lt;br /&gt;
| array&amp;lt;br /&amp;gt;&lt;br /&gt;
| Valores de ejemplo para cada parámetro. Cuando el usuario seleccione el bloque en la interfaz de TurtleBlocks, se cargarán esos valores en los parámetros&lt;br /&gt;
| 104.6, 826.67, -67.4, 25.02, 24.07, 26.06&amp;lt;br /&amp;gt;&lt;br /&gt;
| Aplica solamente si Parameters no es vacío.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Troubleshooting ====&lt;br /&gt;
A continuación se detallan los errores más frecuentes junto a su respectiva solución&lt;br /&gt;
&lt;br /&gt;
====== No aparece la paleta de tbpy ======&lt;br /&gt;
# Revisar que tbpy se encuentra dentro de la carpeta &amp;quot;TurtleBlocks.activity/plugins&amp;quot;, sino instalar nuevamente.&lt;br /&gt;
# Revisar que se está ejecutando la misma versión de TurtleBlocks donde se instaló el plugin.&lt;br /&gt;
# Revisar la consola de Python por errores en tiempo de ejecución. Si se agregó una función que no compila, puede que el plugin no cargue. Intentar ejecutarla por separado con &amp;quot;python2 -B plugins/tbpy/groups/xxxx.py&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
====== No aparece en la paleta de tbpy la función que agregué ======&lt;br /&gt;
# Revisar que se agregó la función en plugins/tbpy/groups.&lt;br /&gt;
# Revisar la consola de Python por errores en tiempo de ejecución. Si se agregó una función con errores, no aparecerá en la paleta. Intentar ejecutarla por separado con &amp;quot;python2 -B plugins/tbpy/groups/xxxx.py&amp;quot;.&lt;br /&gt;
# Asegurarse de que toda la metadata obligatoria del docstring está presente y con el formato correcto. Referirse a [[Tbpy:_Creación_de_paletas_y_bloques_en_TurtleBlocks_utilizando_Python_a_alto_nivel#Parámetros_del_docstring|Parámetros del docstring]].&lt;br /&gt;
# Revisar que los tipos de los parámetros y de la salida están soportados por tbpy (que sean primitivos de Python). Referirse a [[Tbpy:_Creación_de_paletas_y_bloques_en_TurtleBlocks_utilizando_Python_a_alto_nivel#Parámetros_del_docstring|Parámetros del docstring]].&lt;br /&gt;
&lt;br /&gt;
====== Mi función no devuelve ningún resultado/TurtleBlocks se cuelga ======&lt;br /&gt;
# Revisar la consola de Python por errores en tiempo de ejecución. Si se agregó una función que falla, TurtleBlocks se puede colgar.&lt;br /&gt;
# Revisar que se haya introducido un tipo de salida válido y que el valor del &amp;quot;return&amp;quot; de nuestra función coincida con nuestro tipo o sea casteable (ej. un int a string).&lt;br /&gt;
# Asegurarse de que nuestro código (o las librerías que incluye) no utilicen procesamiento en paralelo/multithreading, ya que no es compatible con TurtleBlocks.&lt;br /&gt;
&lt;br /&gt;
==== Galería de bloques ====&lt;br /&gt;
La galería de tbpy está basada en git, y se ubica en el [https://github.com/tcaram/tbpy/pulls?q=is%3Apr+label%3Agaler%C3%ADa repositorio] del proyecto. Será necesaria una cuenta en GitHub para subir bloques a la galería.&lt;br /&gt;
&lt;br /&gt;
====== Subiendo bloques a la galería ======&lt;br /&gt;
Para subir un bloque a la galería será necesario hacer un fork del proyecto, agregar nuestro bloque (en groups), un ejemplo (en samples) y luego crear un pull request con el label &amp;quot;galería&amp;quot;. Para que el pull request sea aceptado, se deberá incluir una breve descripción para que luego otros usuarios puedan navegar fácilmente a través de los ejemplos sin tener que revisar el código para conocer las funcionalidades de cada uno. Se recomienda [https://docs.github.com/es/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork este tutorial] de GitHub que explica cómo hacer un pull request a partir de un fork. &lt;br /&gt;
&lt;br /&gt;
====== Descargando bloques desde la galería ======&lt;br /&gt;
Los bloques aceptados se encontrarán en el branch main, entonces para actualizarla y recibir las nuevas actualizaciones se puede ejecutar:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki13.png|500px]]&lt;br /&gt;
&lt;br /&gt;
Luego, los ejemplos aparecerán en File -&amp;gt; Show sample projects, junto a los de TurtleBlocks.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki14.png|300px]]&lt;br /&gt;
&lt;br /&gt;
[[Archivo:wiki15.png|500px]]&lt;br /&gt;
&lt;br /&gt;
== Desarrollando sobre tbpy (documentación para desarrolladores) == &lt;br /&gt;
&lt;br /&gt;
==== Introducción y nomenclaturas ====&lt;br /&gt;
tbpy se encuentra modularizado para que su extensión y comprensión por parte de otros desarrolladores sea fácil y rápida. A continuación se explica la nomenclatura interna del proyecto que será necesaria manejar para poder programar sobre el código de tbpy:&lt;br /&gt;
 &lt;br /&gt;
* '''Group''': grupo de funciones definidas por el usuario, que se cargarán a posteriori por tbpy.&lt;br /&gt;
* '''Function''': clase que representa las funciones definidas por el usuario con su información (nombre, parámetros, ejemplos, color, tipo de salida y función Python).&lt;br /&gt;
* '''Metadata''': información que se encuentra en el docstring de las funciones definidas por el usuario y que luego será parseada y procesada por tbpy.&lt;br /&gt;
&lt;br /&gt;
==== Módulos de tbpy ====&lt;br /&gt;
El código de tbpy se basa en los siguientes módulos:&lt;br /&gt;
&lt;br /&gt;
* '''tbpy''': Es el módulo principal. Se encarga de comunicarse con TurtleBlocks y nuestras representaciones propias.&lt;br /&gt;
* '''grouploader''': Carga los scripts agregados por el usuario en el directorio &amp;quot;groups&amp;quot;. Crea los objetos para los grupos.&lt;br /&gt;
* '''group''': Carga, parsea y define la representación en Python de los grupoas agregados por el usuario en el directorio &amp;quot;groups&amp;quot;. Crea los objetos para las funciones.&lt;br /&gt;
* '''function''': Carga, parsea y define la representación en Python de las funciones agregadas por el usuario en cada script (con sus parámetros, ejemplos, etc.).&lt;br /&gt;
&lt;br /&gt;
== Autor ==&lt;br /&gt;
* Tomás Caram [mailto:tomas.caram@fing.edu.uy &amp;lt;tomas.caram@fing.edu.uy&amp;gt;]&lt;br /&gt;
&lt;br /&gt;
== Tutores ==&lt;br /&gt;
* Guillermo Trinidad&lt;br /&gt;
* Gonzalo Tejera&lt;/div&gt;</summary>
		<author><name>Tomas.caram</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Tbpy</id>
		<title>Tbpy</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Tbpy"/>
				<updated>2021-06-22T07:43:33Z</updated>
		
		<summary type="html">&lt;p&gt;Tomas.caram: Página blanqueada&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tomas.caram</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Programando_el_Butia_desde_el_celular</id>
		<title>Programando el Butia desde el celular</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Programando_el_Butia_desde_el_celular"/>
				<updated>2021-06-21T19:10:44Z</updated>
		
		<summary type="html">&lt;p&gt;German.moreira: /* Archivos de uso */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Introducción ==&lt;br /&gt;
&lt;br /&gt;
La idea del proyecto en un principio era usar el celular como medio para controlar el robot Butiá para que resulte más atractivo para los estudiantes que no les guste la programación.&lt;br /&gt;
&lt;br /&gt;
Luego, la idea se modifico un poco debido a que descubrimos que con esta implementación, podíamos hacer mas sencilla la resolución de algunos ejercicios básicos mediante algoritmos mas simplificados, tomamos el trabajo que teníamos hecho hasta el momento y lo adaptamos a un menú con distintas acciones simples como avanzar un determinado tiempo, avanzar hasta chocar contra un objeto o rotar a la izquierda o derecha un determinado tiempo.&lt;br /&gt;
&lt;br /&gt;
Estas funciones básicas y bastante sencillas de entender más una interfaz amigable y fácil de usar, se implementaron para que el rango de edad de uso de esta aplicación vaya de 3 años en adelante.&lt;br /&gt;
&lt;br /&gt;
Como resultado obtuvimos una aplicación que se puede usar para que niños de:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
- 4 / 5 / 6 años resuelvan ejercicios sencillos como puede ser llegar de un punto a otro, buscar el camino a un objeto o resolver un laberinto sencillo.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
- 7 / 8 / 9 años puedan resolver ejercicios un poco más complejos como puede ser resolver un laberinto del más sencillo al mas complejo.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
- 10 años en adelante tengan la capacidad de adaptar una parte personal de código al programa y puedan resolver cualquier ejercicio que se pueda plantear con el robot Butiá.&lt;br /&gt;
&lt;br /&gt;
== Objetivo y motivación==&lt;br /&gt;
&lt;br /&gt;
Los objetivos del proyecto eran, como dice el nombre, poder conectar remotamente el robot Butiá a un celular y buscar una abstracción de la mayor cantidad de problemas que puedan ser resueltos con el robot Butiá.&lt;br /&gt;
&lt;br /&gt;
Esto, para poder crear un método de uso del robot Butiá más dinámico y con funciones que permiten realizar, mediante algoritmos mas sencillos, la solución de la mayor cantidad de puzles particulares, abstrayéndose de la programación directa, lo que puede ser tedioso o abrumador para personas que tienen su primer acercamiento a la programación.&lt;br /&gt;
&lt;br /&gt;
Al hacer esto, el nivel de uso en aulas del robot Butiá, puede simplificarse hasta clases desde 3 años de jardinera en adelante, debido a que la aplicación simplifica la parte de codificación y los algoritmos de solución de ejercicios se convierten simplemente en una serie de pasos básicos a ejecutar linealmente.&lt;br /&gt;
&lt;br /&gt;
Lo que se busca con este proyecto, es despertar la curiosidad e interés en niños y adolescentes en el área de la programación de una forma didáctica, en donde estos pueden experimentar directamente con el robot y potenciar la creatividad para resolver problemas. &lt;br /&gt;
&lt;br /&gt;
La aplicación esta inspirada en el lenguaje &amp;quot;Sratch&amp;quot;, el cual es un lenguaje ideal para los primeros acercamientos a la programación. &lt;br /&gt;
&lt;br /&gt;
Este ''software'' permite ademas, introducir conceptos como, instrucciones, secuencialidad de código, algoritmos, secuencias de control, estructuras de repetición, etc. Como ejercicio, se puede plantear por ejemplo, hacer el pasaje a Python de algoritmos diseñados en la aplicación.&lt;br /&gt;
&lt;br /&gt;
== Armado del Butiá ==&lt;br /&gt;
&lt;br /&gt;
* Paso 1: Armar el Butiá a partir de esta [https://www.fing.edu.uy/inco/proyectos/butia/files/docs_butia2/armando_paso_a_paso_motores_CC_rev1.pdf guía oficial]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Paso 2: Instalar el sensor de grises&lt;br /&gt;
&lt;br /&gt;
1:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:GrisesP1.jpeg]] &lt;br /&gt;
&lt;br /&gt;
2:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:GrisesP2.jpeg]]&lt;br /&gt;
&lt;br /&gt;
3:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:GrisesP3.jpeg]]&lt;br /&gt;
&lt;br /&gt;
4:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:GrisesP4.jpeg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Paso 3: Instalar el sensor de distancia&lt;br /&gt;
&lt;br /&gt;
1:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:DistanciaP1.png]]&lt;br /&gt;
&lt;br /&gt;
2:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:DistanciaP2.png]]&lt;br /&gt;
&lt;br /&gt;
3:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:DistanciaP3.png]]&lt;br /&gt;
&lt;br /&gt;
4:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:DistanciaP4.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Observación''': Es indispensable que los componentes del robot se encuentren en condiciones optimas para que este tenga el comportamiento deseado al momento de ejecutar las acciones enviadas desde la app. Esto incluye a los motores, debido a que una diferencia de comportamiento entre estos no permitiría por ejemplo, que el robot se desplace en linea recta.&lt;br /&gt;
&lt;br /&gt;
== Protocolo de comunicación ==&lt;br /&gt;
El protocolo de comunicaron diseñado para la comunicación entre Servidor y Aplicación ''Mobile'' es el siguiente:&lt;br /&gt;
&lt;br /&gt;
'''''Accion0-S0\nAccion1-S1\nAccion2-S2\nAccion3\nAccion4-S4\nVelocidad'''''&lt;br /&gt;
&lt;br /&gt;
Donde, este ''string'' representa la serie encadenada de acciones que el servidor recibe para ejecutar en el robot desde la aplicación por medio de un ''WebSocket'' (socket que utiliza protocolo http).&lt;br /&gt;
Cada acción esta separada de la que se encuentra a continuación por el símbolo &amp;quot;''\n''&amp;quot;.&lt;br /&gt;
Podemos diferenciar dos tipos de acciones, las que requieren parámetro y las que no, estas se comunican de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
'''-Acción con parámetro''': NombreAccion-Parametro&lt;br /&gt;
&lt;br /&gt;
'''-Acción sin parámetro''': NombreAccion&lt;br /&gt;
&lt;br /&gt;
== Implementación código Python ==&lt;br /&gt;
&lt;br /&gt;
Antes de empezar a programar o usar el código, es necesario instalar las librerías a usar, esto se puede hacer escribiendo &lt;br /&gt;
&lt;br /&gt;
'''''pip install [nombre de la librería]''''' en el interprete de comandos del sistema.&lt;br /&gt;
&lt;br /&gt;
Entonces instalamos la librería a utilizar, en este caso:&lt;br /&gt;
&lt;br /&gt;
'''''pip install simple_websocket_server'''''&lt;br /&gt;
&lt;br /&gt;
Una vez instalada la librería, hay que empezar a escribir el código.&lt;br /&gt;
&lt;br /&gt;
El encabezado del código es el siguiente&lt;br /&gt;
El uso de cada librería se explica con detalle mas adelante&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Encabezado.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A partir de la librería '''sys''' se define el camino del sistema para utilizar los plugin Butiá.&lt;br /&gt;
En nuestro caso, la ruta es ''' '/home/trerb/TurtleBots.activity/plugins/butia' ''', eso se tiene que modificar dependiendo de donde se encuentren el directorio ''' TurtleBots.activity/ ''' en su sistema de archivos&lt;br /&gt;
&lt;br /&gt;
[[Archivo:UsoPluginButia.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Luego se encuentra la función ''' clearConsole ''',&lt;br /&gt;
Esta función sirve únicamente para limpiar el interprete de Python usando la librería ''' os ''' y tener una ejecución mas limpia&lt;br /&gt;
&lt;br /&gt;
[[Archivo:clearConsole().png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
El siguiente código utiliza la librería ''' socket ''' para conectarse a la web y preguntar la ip del ordenador que ejecuta el archivo y la muestra en pantalla, esto se usa para facilitar la conexión con la App Mobile&lt;br /&gt;
&lt;br /&gt;
[[Archivo:conexionSocket.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Las siguientes líneas de código preguntan al usuario que puerto va a utilizar para la conexión, este código verifica que se ingrese un dato numérico, dentro del rango de los puertos, y que el puerto este disponible.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:tryPuerto.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Luego se declaran las variables: ''' Speed, Puerto_Gris y Puerto_Distancia ''', se verifica que los sensores de distancia y de grises estén conectados y asigna el puerto en el que estén conectados a las variables ''' Puerto_Distancia ''' y ''' Puerto_Gris ''' respectivamente. La variable ''' Speed ''' es una variable global que se lee al inicio de cada cadena de acciones y la utiliza para todos los movimientos del Butiá de esa cadena.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:declaracionVariables.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Seguimos con la declaración de las funciones básicas del Butiá, en este caso son ''' Avanzar, Rotar, AvanzarHastaVerColor y AvanzarHastaObstaculo ''' &lt;br /&gt;
&lt;br /&gt;
-La función ''' Avanzar ''' recibe un parámetro de tiempo y el Butiá avanza ese determinado tiempo.&lt;br /&gt;
&lt;br /&gt;
-La función ''' Retroceder ''' recibe un parámetro de tiempo y el Butiá retrocede ese determinado tiempo.&lt;br /&gt;
&lt;br /&gt;
-La función ''' Rotar ''' recibe dos parámetros, una dirección que puede ser Izquierda o Derecha y un tiempo que indica la duración de la rotación del Butiá.&lt;br /&gt;
&lt;br /&gt;
-La función ''' AvanzarHastaVerColor ''' recibe un parámetro que varia entre Blanco o Negro, el robot va a avanzar hasta detectar el color seleccionado.&lt;br /&gt;
Esta función solo se puede usar si el sensor de grises esta conectado.&lt;br /&gt;
&lt;br /&gt;
-Por ultimo, la función ''' AvanzarHastaObstaculo ''' no recibe parámetros, en este caso el Butiá va a avanzar hasta estar a unos pocos centímetros de un obstáculo.&lt;br /&gt;
Esta función solo se puede usar si el sensor de distancia esta conectado.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:FuncionesBasicas.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Luego se encuentra una función ''' Accion1 ''' esta función la puede definir el usuario a gusto, se puede implementar desde una función básica hasta un seguidor de líneas avanzado. La única condición que se necesita para implementar esta ''' Accion1 ''' es que no puede recibir parámetros&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Accion1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ahora tenemos que definir el menú principal del programa, este se divide en dos funciones&lt;br /&gt;
&lt;br /&gt;
- ''' handle ''': Esta es una función predeterminada de la librería ''' simple_web_socket ''' y se llama cada vez que el servidor recibe un dato del cliente. En este caso la función crea una lista de las acciones que le llegan de la App Mobile, y las va ejecutando ordenadamente&lt;br /&gt;
&lt;br /&gt;
- ''' handle_close ''': Al igual que la función anterior, esta también es una función predeterminada de la librería ''' simple_web_socket ''' y se llama cuando el cliente se desconecta del servidor&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Screenshot from 2021-06-27 03-58-56.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Y por ultimo tenemos el dos líneas de codigo, la primera se encarga de abrir el servidor y la segunda lo mantiene abierto infinitamente&lt;br /&gt;
&lt;br /&gt;
[[Archivo:abrirServidor.png]]&lt;br /&gt;
&lt;br /&gt;
== Implementación código React ==&lt;br /&gt;
&lt;br /&gt;
La aplicación ''mobile'' esta implementada con React Native, ademas, se utiliza el ''framework'' [https://docs.expo.io/ Expo]. Este ''framework'' nos brinda un conjunto de herramientas que facilita el desarrollo de aplicaciones ''mobile''. &lt;br /&gt;
En caso de querer agregar, o modificar cualidades, es necesario proceder de la siguiente forma:&lt;br /&gt;
&lt;br /&gt;
Descargar el archivo comprimido adjunto.&lt;br /&gt;
&lt;br /&gt;
Extraerlo, posicionarse en el directorio raiz de la carpeta descomprimida, y ejecutar desde la terminal lo siguiente (tener en cuenta que es necesario tener en la maquina, el gestor de paquetes [https://docs.npmjs.com/ npm]).&lt;br /&gt;
&lt;br /&gt;
''''npm install'''' &lt;br /&gt;
&lt;br /&gt;
Esto descarga las dependencias que utiliza la aplicación, luego de esto podemos empezar a desarrollar.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Para visualizar los cambios en tiempo real mientras desarrollamos, es necesario instalar la aplicación Expo Go para [https://play.google.com/store/apps/details?id=host.exp.exponent&amp;amp;hl=es_UY&amp;amp;gl=US Android] o para [https://apps.apple.com/es/app/expo-go/id982107779 iOS] según sea el caso.&lt;br /&gt;
&lt;br /&gt;
Para a visualizar la app en desarrollo desde Expo Go, procedemos de la siguiente forma:&lt;br /&gt;
Desde el directorio raíz de la aplicación ejecutamos desde la terminal lo siguiente:&lt;br /&gt;
&lt;br /&gt;
''''npm start''''&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Luego, desde la aplicación Expo Go, con el celular conectado en la misma red local accedemos a la aplicación seleccionando lo siguiente:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Expo.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hecho esto, podemos cambiar el código de la aplicación y ver reflejados los cambios de forma casi instantánea.&lt;br /&gt;
&lt;br /&gt;
La aplicación esta compuesta por dos pantallas, la pantalla de configuración (''ConfigScreen.js''), donde se ingresa la dirección ip y puerto del servidor, y la pantalla principal (''MainScreen.js''), donde se lleva a cabo la programación del robot mediante acciones.&lt;br /&gt;
&lt;br /&gt;
Esta ultima pantalla esta compuesta por los componentes ''TopList.js'' y ''BottomList.js''.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Untitled presentation.png]]&lt;br /&gt;
&lt;br /&gt;
Para agregar una nueva accion al sistema, es necesario programarla en el servidor con un determinado nombre, supondremos &amp;quot;AccionN&amp;quot;, esto resulta fácil si se toma como ejemplo las acciones ya implementadas.&lt;br /&gt;
&lt;br /&gt;
En la aplicación, esta nueva acción se agrega en el ''array'' &amp;quot;''actionsData''&amp;quot;, dicho ''array'' se encuentra en la pantalla principal, es decir en el archivo &amp;quot;''MainScreen.js''&amp;quot;, cada acción cuenta con los siguientes datos:&lt;br /&gt;
&lt;br /&gt;
-'''idAccion:''' Identificador (indice) de la acción en dicho arreglo (actionsData). Esto permite identificar a la acción y hacer referencia a su ''overlay'' cuando se requiere modificar un parámetro de la accion en la app.&lt;br /&gt;
&lt;br /&gt;
-'''title:''': Titulo de la acción que se muestra en el panel superior (componente TopList).&lt;br /&gt;
&lt;br /&gt;
-'''actionId:''' Nombre identificador de la acción en el servidor (en el ejemplo, &amp;quot;AccionN&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
-'''overlay:''' ''Overlay'' que se despliega al seleccionar la acción en la app (si esta requiere cierto parámetro), esta función lleva como parámetro &amp;quot;''editOverlay''&amp;quot; y &amp;quot;''id''&amp;quot;, estos se utilizan cuando se requiere cambiar el parametro de una acción que ya fue seleccionada y se encuentra en el panel inferior (componente BottomList) de la aplicación, como por ejemplo pueden ser segundos en el caso de la acción &amp;quot;Avanzar&amp;quot;, o colores en el caso de &amp;quot;Avanzar hasta obstáculo&amp;quot;. Este parámetro puede ser que no sea necesario, como es en el caso de la acción &amp;quot;Avanzar hasta obstáculo&amp;quot;, en este ultimo caso el valor de este campo es ''null''.&lt;br /&gt;
&lt;br /&gt;
Ejemplo de la acción &amp;quot;Avanzar&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Screenshot from 2021-06-27 04-18-42.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ejemplo de la acción &amp;quot;Avanzar hasta obstáculo&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Screenshot_from_2021-06-27_00-28-32.png]]&lt;br /&gt;
&lt;br /&gt;
== Manual de uso de la aplicación ==&lt;br /&gt;
&lt;br /&gt;
Aunque la aplicación resulta intuitiva y fácil de usar se describe a continuación una serie de pasos para utilizarla correctamente.&lt;br /&gt;
&lt;br /&gt;
Para comenzar a utilizar la aplicación es necesario configurar la conexión de la aplicación con el servidor (recordar que ambos se deben encontrar ejecutándose en la misma red local), el servidor ejecutando en una computadora que esté conectada correctamente al butiá (con los sensores descritos anteriormente) y la aplicación ejecutándose en el celular.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Conectando.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Luego que la conexión haya resultado exitosa, nos encontramos en la pantalla principal. En el panel superior, como se muestra a continuación, se encuentran las aplicaciones disponibles que podemos ejecutar en el robot butiá.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Acciones.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Para agregar una serie de acciones al robot, simplemente presionamos la que queramos, a continuación esta aparecerá en el panel inferior, a medida de que vayamos seleccionando acciones, estas se irán encadenando una tras otras, estas estarán prontas para ejecutarse secuencialmente, desde la parte inferior, a la parte superior, en el momento que presionemos el botón &amp;quot;Empezar&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Agregando.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Como la aplicación está pensada para planificar algoritmos para resolver desafíos o ''puzzles'', es probable que nos equivoquemos y seleccionemos una acción o insertemos un parámetro incorrectamente, ¡pero no te preocupes!. Para editar el parámetro que le hayamos ingresado a una acción, simplemente mantenemos pulsado la que deseamos corregir e ingresamos el nuevo valor.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Editando.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
También es posible eliminar una acción, para hacer esto, nuevamente mantenemos pulsada la acción que queremos eliminar, pero esta vez, seleccionamos la acción eliminar. A continuación la acción seleccionada desaparecerá del panel inferior. También es posible que deseemos eliminar todas las acciones que habíamos ingresado, en este caso seleccionamos el botón &amp;quot;Eliminar acciones&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Eliminando.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Es posible que queremos que el robot se desplace a ciertas velocidades, teniendo en cuenta que al modificar la velocidad, el robot tendrá un comportamiento totalmente diferente, debido a que gran parte de las acciones se ejecutan por un tiempo asignado, a mayor velocidad, más desplazamiento.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Velocidad.gif]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En caso de que exista un error en la conexión, podemos intentar volver a conectar la aplicación al servidor, para esto seleccionamos la opción configuración.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:A configuracion.gif]]&lt;br /&gt;
&lt;br /&gt;
== Mejoras a futuro ==&lt;br /&gt;
&lt;br /&gt;
* Implementar una forma para que las función ''' Accion1 ''' pueda recibir parámetros, para así ampliar la gama de problemas que se puedan solucionar a través de esta aplicación.&lt;br /&gt;
&lt;br /&gt;
* Implementación de código que permita añadir a través del código, una mayor cantidad de funciones genéricas a la aplicación.&lt;br /&gt;
&lt;br /&gt;
* Desarrollar una forma de comunicación bilateral entre la ''App Mobile'' y Python para mejorar el ''debug'' en tiempo de ejecución.&lt;br /&gt;
&lt;br /&gt;
== Archivos de uso ==&lt;br /&gt;
&lt;br /&gt;
- [[Archivo:Server Code.zip]]&lt;br /&gt;
&lt;br /&gt;
- [[Archivo:App Code.zip]]&lt;br /&gt;
&lt;br /&gt;
- [[Archivo:Apk app.zip ]]&lt;/div&gt;</summary>
		<author><name>German.moreira</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Incuba-Dora</id>
		<title>Incuba-Dora</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Incuba-Dora"/>
				<updated>2021-06-21T15:39:04Z</updated>
		
		<summary type="html">&lt;p&gt;Georgeinza: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==''' Introducción '''==&lt;br /&gt;
En la enseñanza primaria se estudia en la currícula el ciclo de incubación del huevo de la gallina, donde los estudiantes investigan cuáles son las condiciones necesarias para que a partir de un huevo fértil se desarrolle un embrión hasta que se produzca su nacimiento.&lt;br /&gt;
&lt;br /&gt;
En el proyecto denominado Incuba-Dora se busca por medio de la temática del ciclo de incubación del huevo abordar el aprendizaje de la robótica de una forma natural para el alumno.&lt;br /&gt;
&lt;br /&gt;
Uno de los objetivos principales del proyecto es que el alumno se involucre en el ciclo de incubación y en la robótica de forma paralela, ya que cuando vea un elemento de una de estas dos temáticas indirectamente estará viendo un elemento de la otra. Además el proyecto Incuba-Dora también busca conectar al alumno con la naturaleza por medio del aprendizaje de la robótica.&lt;br /&gt;
&lt;br /&gt;
El público objetivo del proyecto Incuba-Dora principalmente es el de la enseñanza primaria, en donde se estudia y trabaja el proceso de gestación del pollito dentro del huevo de la gallina. Pero también el proyecto puede ser incorporado para el trabajo en grupos de enseñanza de robótica, ya que puede complejizarse el proyecto al sumar más elementos y dispositivos para controlar en la incubadora.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Algunos de los objetivos que busca el proyecto son: '''===&lt;br /&gt;
&lt;br /&gt;
* Acercar a los alumnos con la naturaleza a través de la robótica.&lt;br /&gt;
* Vivir la experiencia de ver a los pollitos salir de su cascarón.&lt;br /&gt;
* Aprender el cuidado y responsabilidad en el trato con los animales.&lt;br /&gt;
* La experiencia comprende días de incubación, en los que los niños pueden seguir el desarrollo del embrión y días de observación y cuidado de los pollitos.&lt;br /&gt;
* Compartir ideas y experiencias con los compañeros, educadores y familia.&lt;br /&gt;
* Estimular la curiosidad sobre la naturaleza, los ciclos de vida y  los animales.&lt;br /&gt;
* Fomentar la interrelación entre alumnos, educadores y la familia.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Incuba01.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==''' Descripción e investigación '''== &lt;br /&gt;
Una incubadora automática de huevos es un dispositivo electrónico en donde se busca replicar las condiciones dentro de un ecosistema controlado de todo lo que necesitan los huevos para su correcto desarrollo.&lt;br /&gt;
La incubadora de huevos proporciona un ambiente similar al que proporcionan las aves, luego de la puesta en marcha de la incubadora sólo hay que tener en cuenta el nivel de agua dentro de la misma, que disponga de energía eléctrica y que los huevos que se van a incubar se encuentren fecundados.&lt;br /&gt;
&lt;br /&gt;
Los factores físicos necesarios a tener en cuenta para una incubación exitosa son la temperatura, la humedad, la ventilación y la rotación de los huevos. &lt;br /&gt;
Una temperatura óptima y uniforme, junto con la correcta humedad en el interior de la incubadora son los factores más importantes para obtener los mejores resultados. La temperatura de la incubadora debe mantenerse constante desde el inicio hasta los últimos 3 días, normalmente varía entre 37,2°C y 37,8°C.&lt;br /&gt;
&lt;br /&gt;
En el caso particular de la incubación que realizan las gallinas, el control constante de la temperatura depende de muchos factores como el propio estrés de los animales. Es por este motivo, que se debe tener en cuenta que las bajas temperaturas retrasan el desarrollo del embrión y las temperaturas más altas que las recomendadas aceleran el desarrollo embrionario. Cuando las condiciones de temperatura anormal durante los procesos de incubación son prolongadas en el tiempo, el desarrollo del embrión y la efectividad se ven alterados de forma negativa por el aumento de la mortalidad embrionaria y por la debilidad y deformación de los pollitos.&lt;br /&gt;
&lt;br /&gt;
Así como la temperatura, el parámetro de la humedad en la incubadora afecta a la eficiencia de la misma en forma directa. En el caso de una incubadora automática este proceso se debe realizar de forma autónoma por la propia incubadora. &lt;br /&gt;
&lt;br /&gt;
De forma casi general en todas las aves, el huevo tarda unos 21 días en eclosionar. Con respecto a la humedad relativa debe ser de alrededor del 60% durante los primeros 18 días de incubación y del 70% en los últimos 3 días para un rendimiento óptimo y tener el máximo de eclosiones al finalizar el proceso de incubación. Un dato importante a tener en cuenta es que cuando la humedad aumenta es necesario que la temperatura disminuya.&lt;br /&gt;
&lt;br /&gt;
Es fundamental la correcta posición de los huevos dentro de la incubadora. La correcta forma de colocar los huevos en la incubadora es con el extremo de mayor diámetro hacia arriba. De esta forma la posición del huevo en la incubadora favorece el desarrollo de los embriones para eclosionar correctamente. Además mediante el uso de una incubadora de huevos es posible realizar la incubación de varios huevos al mismo tiempo.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Pasos para incubar huevos de gallina en la incubadora '''===&lt;br /&gt;
&lt;br /&gt;
'''* Paso 1: Configurar la incubadora de huevos'''&lt;br /&gt;
&lt;br /&gt;
Es importante tener claro los factores físicos de humedad, temperatura y ventilación, ya que estos parámetros son las principales condicionantes para que el proceso sea exitoso o no. &lt;br /&gt;
&lt;br /&gt;
Se debe controlar que todos estos valores se comporten de forma correcta y luego la propia incubadora debe controlar las variaciones de los mismos. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''* Paso 2: Fertilidad de los huevos'''&lt;br /&gt;
&lt;br /&gt;
Para incubar huevos en la incubadora es muy importante que los huevos sean fértiles, es decir que hayan sido fecundados. &lt;br /&gt;
&lt;br /&gt;
Se deben realizar las comprobaciones oportunas antes de introducir los huevos en la incubadora para garantizar que éstos son fértiles y poder seguir con el proceso de incubación.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''* Paso 3: Incubación de los huevos'''&lt;br /&gt;
&lt;br /&gt;
El promedio de incubación de huevos es de 21 días hasta su eclosión. Es muy recomendable encender la incubadora 24 horas antes y ponerla a funcionar en vacío, controlando los ciclos de temperatura y humedad para ajustar el ambiente y hacerlo óptimo para la posterior incubación de los huevos. &lt;br /&gt;
&lt;br /&gt;
Cuando la incubadora esté con la ambientación correcta, es el momento de colocar los huevos dentro de la incubadora. &lt;br /&gt;
&lt;br /&gt;
Se debe recordar que el día 18 se deberá agregar más agua para aumentar la humedad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''* Paso 4: La eclosión'''&lt;br /&gt;
&lt;br /&gt;
En el día 21, los polluelos ya están dando señales de su nacimiento. Se puede observar un pequeño picotazo en una parte del huevo y después de 6 a 12 horas se podrán ir viendo más movimientos, de este modo, los polluelos van adaptando sus pulmones y respiración. &lt;br /&gt;
&lt;br /&gt;
Es importante darle a los polluelos este tiempo para garantizar su supervivencia y se debe evitar toda ayuda en el proceso de eclosión ya que los polluelos podrían verse afectados, a menos que se observe que el polluelo no puede romper la cáscara del huevo por sí mismo.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Incuba02.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Incuba03.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Posición de los huevos en la incubadora '''===&lt;br /&gt;
&lt;br /&gt;
Un factor principal al momento de colocar los huevos dentro de la incubadora, es saber la correcta posición de los mismos. En casi todas las ocasiones una incorrecta colocación de estos puede derivar en una mala incubación y un alto número de huevos sin eclosionar al final del período.&lt;br /&gt;
&lt;br /&gt;
Se recomienda voltear manualmente los huevos al menos 3 veces al día, aunque si se hace de 4 a 6 veces es mucho mejor. Para que sea más fácil de identificar se puede marcar una de las caras del huevo con una una ‘X’ en la parte más ancha con un lápiz (nunca con bolígrafo u otro tipo de tinta). De esta forma se puede saber todos los huevos que se han rotado y los que quedan por rotar. Hay que recordar que después del día número 18 de incubación, los huevos no se deben rotar.&lt;br /&gt;
&lt;br /&gt;
La rotación de los huevos en todos los casos es una parte esencial para evitar causar daño en el embrión y que éste no muera. Principalmente con la rotación se busca que los polluelos no se queden pegados a la cáscara, de este modo se va rotando su posición para que siempre estén en la posición correcta.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Preparación de la incubadora '''===&lt;br /&gt;
&lt;br /&gt;
La preparación dependerá del tipo de huevo a introducir en la incubadora, en el caso de los huevos de gallina tienen una temperatura, humedad y días de incubación diferentes al resto, se puede observar este dato particular en la Tabla 01 - Incubación por especie.&lt;br /&gt;
&lt;br /&gt;
El proceso de utilización de la incubadora es sencillo pero requiere precisión en algunos momentos del período de incubación, se debe ajustar la temperatura según el tipo de huevo que se quiera incubar y agregar agua para que la incubadora ajuste la temperatura. &lt;br /&gt;
&lt;br /&gt;
Algo importante a tener en cuenta es que 24 horas antes de introducir los huevos en la incubadora se debe tener encendida con la humedad y temperatura adecuadas para que se ambiente de forma correcta y controlar además que todo funcione correctamente. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Funcionamiento durante el proceso de la incubación '''===&lt;br /&gt;
&lt;br /&gt;
Luego de haber configurado los parámetros según el tipo de huevo a incubar, los parámetros de humedad y de temperatura los controlará la incubadora en ciclos programados. Pero se debe estar pendiente de que cuente con el agua necesaria para así poder adaptar correctamente la humedad interna del ambiente.&lt;br /&gt;
   &lt;br /&gt;
&lt;br /&gt;
===''' Puntos a recordar al utilizar la incubadora de huevos '''===&lt;br /&gt;
&lt;br /&gt;
* Configuración correcta de los parámetros de temperatura y humedad según el tipo de huevo a incubar.&lt;br /&gt;
* Dejar la incubadora 24 horas antes de su utilización con los parámetros configurados y funcionando, para de esta forma aclimatarse y controlar que todo funcione de forma correcta.&lt;br /&gt;
* Luego de iniciado el proceso de incubación, revisar el correcto funcionamiento de los parámetros al menos 1 vez al día.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Para tener en cuenta antes de la incubación '''===&lt;br /&gt;
&lt;br /&gt;
* Se debe decidir la ubicación física de donde se va colocar la incubadora, de ser posible lo ideal es un lugar, en una habitación donde la temperatura se encuentre entre 21º y 27º.&lt;br /&gt;
* Con el fin de verificar que todos los parámetros son los correctos para la incubación, se debe dejar encendida la incubadora entre 12 y 24 horas antes de colocar los huevos. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Recomendaciones durante la incubación '''===&lt;br /&gt;
&lt;br /&gt;
* Se recomienda con un termómetro manual verificar que la temperatura interior de la incubadora corresponde a la que marca en el monitor.&lt;br /&gt;
&lt;br /&gt;
* A medida que los días transcurren la temperatura interior irá en ascenso, por lo que será necesario ajustar la máquina a 37.5º, a su vez el agua del interior se irá evaporando y se deberá añadir agua (preferiblemente tibia) cada dos días aproximadamente.&lt;br /&gt;
&lt;br /&gt;
* Referente a la humedad, siempre es preferible un bajo nivel de humedad que un exceso, a excepción de los últimos tres días en los que se debe subir notablemente el nivel de humedad, esto es para ayudar a que la cáscara del huevo sea más fácil de romper.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Incuba05.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' En los últimos días de la incubación '''===&lt;br /&gt;
&lt;br /&gt;
Entre los dos o tres días antes de la eclosión de los huevos, se debe detener la rotación de los huevos, retirar la huevera y depositar los huevos en alguna rejilla en el piso de la incubadora. &lt;br /&gt;
&lt;br /&gt;
Desde el momento en que los polluelos salgan del cascarón, la incubadora pasará a cumplir la función siguiente a la incubación, y los podremos dejar hasta dos semanas dentro de la propia incubadora garantizando así la supervivencia de los pollitos pues se van a mantener en las mismas condiciones que han eclosionado del huevo, sin sufrir ningún cambio brusco de temperatura.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Ventilación '''===&lt;br /&gt;
&lt;br /&gt;
Durante el período de incubación los huevos absorben oxígeno y desprenden anhídrido carbónico, por lo que requiere una circulación de aire con el fin de conseguir que el calor y la humedad necesaria llegue a los huevos. Es por este motivo que de ser posible se dispone en la incubadora de un ventilador central para distribuir y homogeneizar la temperatura del aire en el interior de la misma.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Temperatura '''===&lt;br /&gt;
&lt;br /&gt;
La temperatura es el factor fundamental en la incubación, debido al intercambio de calor entre los huevos y el aire. Durante el periodo de incubación por norma general debe fijarse entre 37º y 37.9ª (dependiendo de cada especie de ave) y en los últimos tres días reducir la temperatura.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Humedad '''===&lt;br /&gt;
&lt;br /&gt;
Se debe tener presente el siguiente factor que es un dato muy importante en la incubación artificial, el humedecimiento del aire se debe a la evaporación del agua que se encuentra dentro de la incubadora, por esa razón a causa de las diferencias en la evaporación del agua en distintas zonas de la incubadora se puede observar embriones en diferentes estados de gestación.&lt;br /&gt;
&lt;br /&gt;
El factor de la húmedad del ambiente dentro de la incubadora depende de cada especie de ave que se quiera incubar, los parámetros de humedad pueden estar entre el 45% y el 70% pero siendo la humedad óptima el 55%, aunque en los tres últimos días de incubación debemos de subir la humedad entre el 65% y el 70% con el fin de ablandar la cáscara del huevo y que el polluelo pueda salir sin ninguna dificultad.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Rotación de los huevos '''===&lt;br /&gt;
&lt;br /&gt;
Es importante el volteo de los huevos cada dos horas intentando asemejarse a una incubación natural, ya que un ave en el estado de incubación natural voltea los huevos con una frecuencia de entre 1 a 2 horas los primeros 18 días en el caso de las gallinas.&lt;br /&gt;
&lt;br /&gt;
La rotación es un paso imprescindible pues sin él todos los embriones quedarían pegados a la cáscara provocando la muerte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Eclosión '''===&lt;br /&gt;
&lt;br /&gt;
La eclosión del huevo comienza en el mismo momento que el pollito empieza a picar la cáscara, para que este acontecimiento no tenga ninguna dificultad tres días antes se habrá tenido que dejar de voltear los huevos, bajar unas décimas la temperatura y subir la humedad.&lt;br /&gt;
&lt;br /&gt;
Dependiendo de cada tipo de ave, si se observa que ha transcurrido el tiempo más de lo normal desde el picado del cascarón se recomienda ayudar al polluelo con mucho cuidado rompiendo con las manos el huevo.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Algunos consejos útiles '''===&lt;br /&gt;
&lt;br /&gt;
* No introducir más huevos que la capacidad de la incubadora permite.&lt;br /&gt;
* No introducir huevos sucios.&lt;br /&gt;
* Se recomienda antes de poner los huevos en la incubadora, observarlos con una linterna y no introducir huevos no fecundados.&lt;br /&gt;
* Después de cada período de incubación se debe desinfectar y limpiar la incubadora con productos no corrosivos.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==''' Implementación '''== &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:incuba_mat00.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:incuba_mat_soft.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Implementación del módulo de Temperatura '''===&lt;br /&gt;
&lt;br /&gt;
El módulo de temperatura fue realizado con el sensor LM35, el cual envía un valor analogico que para su procesamiento con la placa Butiá  lo que se hizó fue una relación de temperatura entre el valor del sensor y la temperatura obtenida en la placa Arduino UNO con el LM35. &lt;br /&gt;
&lt;br /&gt;
De esta relación se obtuvo que se debe multiplicar el valor que se obtiene del sensor LM35 en la placa Butiá por 0,003039216 para obtener la temperatura de la incubadora en grados Celsius. Ver Imagen del algoritmo en TurtleBots&lt;br /&gt;
&lt;br /&gt;
En caso de que el valor recibido sea -1 se deben revisar las conexiones del sensor con la placa Butiá.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:PIC3 LM35.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Implementación del módulo de Humedad en Arduino '''===&lt;br /&gt;
&lt;br /&gt;
El módulo de humedad fue realizado con el sensor DHT11, el cual envía los valores de humedad y temperatura por el mismo PIN. &lt;br /&gt;
&lt;br /&gt;
No fue posible hacer funcionar el DHT11 del mismo modo que funciona el sensor LM35 con el Butiá, por esta razón se utilizó la placa Arduino UNO solamente para integrar el sensor DHT11 al sistema completo de la incubadora.&lt;br /&gt;
&lt;br /&gt;
Entonces por medio de ARDUINO UNO se envía el valor de humedad en un sketch al PC y este lo recibe en un algoritmo codificado en Python.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''' Sketch en Arduino: '''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:incuba_cod01.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:PIC1 DHT11.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Implementación del módulo control de lámpara '''===&lt;br /&gt;
&lt;br /&gt;
En el módulo de control de la lámpara se utilizó un relay de corte que puede ser utilizado conectado a una batería de 12v para mayor seguridad del usuario, aunque este relay de corte puede ser conectado también a 220v.&lt;br /&gt;
&lt;br /&gt;
Con el relay de corte se busca encender y apagar la lámpara para de esta forma aumentar ó reducir la temperatura dentro de la incubadora. Lo cual también traerá como consecuencia del aumento de la temperatura que la humedad aumente o disminuya. Ver Imagen del algoritmo en TurtleBots&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:PIC2 RELE.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===''' Implementación del módulo Temperatura y Lámpara en TurtleBots '''===&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Tortu3.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En el bloque lampara: 6 Butia cuando se usa ‘ALTO’ la lámpara se apaga y el bloque ‘BAJO’ enciende la lámpara, esto puede variar dependiendo del tipo y conexión de relay de corte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==''' Incubadora en funcionamiento '''==&lt;br /&gt;
&lt;br /&gt;
[[Archivo:AAA01.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[Archivo:AAA02.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[Archivo:AAA03.jpg]]&lt;br /&gt;
&lt;br /&gt;
[[Archivo:AAA04.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==''' Video del funcionamiento de la incubadora '''==&lt;br /&gt;
&lt;br /&gt;
[https://youtu.be/OjrBI4r8yaY Video Incubadora funcionando]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==''' PDF '''==&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Incubadora_Proyecto_Final_TREB_2021.pdf]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==''' Trabajo a futuro '''==&lt;br /&gt;
&lt;br /&gt;
El proyecto tiene un gran potencial para continuar creciendo y agregarle nuevas funcionalidades. Entre algunas de ellas se encuentran las siguientes:&lt;br /&gt;
&lt;br /&gt;
*Rotación de los huevos automáticamente cada ‘x’ cantidad de tiempo y que debe ser programado con anterioridad. Se puede utilizar para esto los motores del Kit Butiá y esto se podría hacer rotando toda la caja de la incubadora.&lt;br /&gt;
&lt;br /&gt;
*Alarma sonora mediante un speaker si el nivel de temperatura excede o disminuye el nivel normal.&lt;br /&gt;
&lt;br /&gt;
*Alarma visual si el nivel de temperatura excede o disminuye el nivel normal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==''' Bibliografía y referencias  '''==&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/contenido/14-como-funciona-una-incubadora-de-pollos-y-huevos-paso-a-paso&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/categoria/53-incubadoras-de-huevos&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/contenido/8-guia-rapida-para-la-incubacion-&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/contenido/12-como-incubar-huevos-de-gallina-en-incubadora-incubacion&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/contenido/13-como-se-colocan-los-huevos-en-una-incubadora&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/contenido/14-como-funciona-una-incubadora-de-pollos-y-huevos-paso-a-paso&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/contenido/6-problemas-comunes&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/contenido/7-tabla-de-incubacion&lt;br /&gt;
&lt;br /&gt;
https://www.incubarbarato.com/categoria/4-incubadoras-automaticas&lt;/div&gt;</summary>
		<author><name>Georgeinza</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Mindstorms</id>
		<title>Mindstorms</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Mindstorms"/>
				<updated>2021-06-20T14:42:30Z</updated>
		
		<summary type="html">&lt;p&gt;Florieppi: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
==INTRODUCCIÓN==&lt;br /&gt;
El proyecto se basa en brindar herramientas y acercar conocimientos sobre robótica y computación a un equipo de estudiantes del Liceo N°2 del Pinar. &lt;br /&gt;
El objetivo principal es lograr alguno de los desafíos propuestos por la competencia &amp;quot;Sumo&amp;quot; organizada por la FING. El nombre del proyecto, ‘MINDSTORMS’ (Lluvia de ideas), refiere a que serán tomadas en cuenta todas las propuestas de los estudiantes, además de que el proceso de aprendizaje tiene como fin el objetivo que ellos se plantearon. También es parte del nombre del kit robótico que será utilizado. &lt;br /&gt;
Se realizaron tres encuentros presenciales los días viernes de 9 a 11 hrs. &lt;br /&gt;
&lt;br /&gt;
==MATERIALES==&lt;br /&gt;
Los materiales necesarios son los kit de NXT Lego que se encuentran en el liceo y las ‘ceibalitas’ de los estudiantes. Además se requiere de materiales para realizar los distintos desafíos, cómo puede ser la pista para el seguidor de línea o el ‘dojo’ para el desafío de sumo. &lt;br /&gt;
&lt;br /&gt;
==PRIMER ENCUENTRO==&lt;br /&gt;
&lt;br /&gt;
'''PLANIFICACIÓN:'''&lt;br /&gt;
&lt;br /&gt;
El objetivo del primer encuentro es conocernos, conocer el kit y presentar algunos &lt;br /&gt;
aspectos teóricos acerca de los kit robóticos, para lo cual realizo una [https://drive.google.com/file/d/15FE7pZIDZiYu8nILjedbr366iULzDrwA/view?usp=sharing pequeña presentación]. &lt;br /&gt;
&lt;br /&gt;
'''EXPERIENCIA:'''&lt;br /&gt;
&lt;br /&gt;
Concurrieron 3 estudiantes, Rodrigo, Megan y Luana. Si bien la dinámica de trabajo no se adecuaba a hacer una clase expositora como tenía pensado con la presentación, pudimos aprovechar un tiempo en el que no contábamos con los kit para leerla entre todos e ir conociendo los nombres de algunas partes del robot, así también como para que sirven. &lt;br /&gt;
A los minutos cuando tuvimos acceso a los kit, pudimos identificar dichas partes en el kit NXT lego. &lt;br /&gt;
Comenzamos ordenando un poco los kit, y luego nos pusimos a armar un robot entre todos. El elegido fue ‘Mini Sumo Bot’ [https://www.nxtprograms.com/mini_sumo/index.html]&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Mindstorms armado del robot.jpeg|200px]]&lt;br /&gt;
[[Archivo:Mindstorms armado del robot2.jpeg|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==SEGUNDO ENCUENTRO==&lt;br /&gt;
&lt;br /&gt;
'''PLANIFICACIÓN'''&lt;br /&gt;
&lt;br /&gt;
El objetivo de este encuentro es comenzar a mover el robot. &lt;br /&gt;
Dado que me comentaron que ya habían trabajado con ‘Open Roberta’ creí que no era necesario hacer una introducción al programa. &lt;br /&gt;
Por lo tanto, plantee una serie de ejercicios, comenzando por algunos básicos en los que no se requería utilizar estructuras de control para su solución. &lt;br /&gt;
Para los últimos era necesario utilizar el ‘IF’. [https://drive.google.com/file/d/1OPywXDyhqi9RHjzBdj6cxlsNj2Tct7Xe/view?usp=sharing Desafíos]&lt;br /&gt;
&lt;br /&gt;
'''EXPERIENCIA'''&lt;br /&gt;
&lt;br /&gt;
A este encuentro concurrieron los tres estudiantes del encuentro anterior y se sumó Nahir. &lt;br /&gt;
Utilizamos ‘Open Roberta USB’ para conectar el robot con ‘Open Roberta’ y así transferir el programa. Este paso lo entendieron rápidamente los 4. &lt;br /&gt;
Los primeros pasos de probar los distintos valores que recibía el robot de los sensores no les resultó tan llamativo, por lo que lo trabajamos muy por arriba. Luego se propuso realizar un cuadrado, con este desafío se notó un gran entusiasmo, pensaron cómo realizar el código y luego de algunas pruebas lo hicieron perfectamente sin utilizar estructuras de control, aunque el robot no logró hacer el cuadrado porque no dobló los 90°, el objetivo se cumplió. &lt;br /&gt;
Luego quisieron pasear con el robot por el liceo, para mostrarselo principalmente a la guardia de seguridad, por lo que le indicaron al robot que se moviera hacia adelante una distancia considerada. Lo cual dio para pasear por todo el liceo, uno de ellos lo iba guiando manualmente ya que la indicación era solamente ir hacia adelante. &lt;br /&gt;
Finalmente, adentrándonos un poco en el sumo realizamos los últimos desafíos. El primero en que el robot debía avanzar hasta detectar blanco y el segundo hasta detectar un objeto. Dado que no conocían la estructura condicional ‘If-Then-Else’ y la iterativa ‘Repeat’, las explique brevemente, obteniendo una muy buena comprensión por algunos de ellos que se interesaron más que otros. &lt;br /&gt;
Lograron realizar todos los desafíos con mucho éxito y lo más importante es que quedaron muy entusiasmados. &lt;br /&gt;
&lt;br /&gt;
'''Paseando el robot por el liceo'''&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:Mindstorms paseo por el liceo.jpeg|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''A continuación se muestra un video de los primeros pasos con el robot, se le indicó que se moviera hacia adelante una determinada distancia'''.&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://youtu.be/r8fKTA4tw4U&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''El primer intento de realizar el cuadrado...'''&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://youtu.be/0WDtGa26weI&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Otro intento de realizar el cuadrado'''&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://youtu.be/XFUGft2xCLo&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==TERCER ENCUENTRO== &lt;br /&gt;
&lt;br /&gt;
'''PLANIFICACIÓN'''&lt;br /&gt;
&lt;br /&gt;
Para este encuentro la idea era terminar de aproximarnos al sumo. Por lo que en principio se planteó unir los últimos dos desafíos del encuentro anterior y agregar a este la búsqueda del rival. [https://docs.google.com/document/d/1iIyYUGc80traDVwYIUFzIhAd13tjzDJADVtQ3VAZLl0/edit?usp=sharing Desafíos]&lt;br /&gt;
&lt;br /&gt;
'''EXPERIENCIA'''&lt;br /&gt;
&lt;br /&gt;
Concurrieron Rodrigo, Nahir y Megan. Lograron determinar rápidamente que era más importante no salir del ‘dojo’ que empujar al rival. Además pudieron integrar ambas cosas sin problema. Luego pensaron en cómo buscar al rival. Me asombró lo rápido que lograron cumplir los objetivos. Por lo que propuse que una vez que el robot detectara la línea blanca, hicieran algo para salir de esa situación. Uno de ellos me pedía más desafíos por lo que le propuse que siguiera la línea blanca del ‘dojo’. Lo realizó con un sensor de luz exitosamente. Mientras que los otros dos estudiantes continuaron armando el otro robot, que aún no lo han terminado, para poder realizar la pelea tan deseada.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Mindstorms tercer encuentro.jpeg|400px]]&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
'''Desafío de avanzar si detecta algo cerca y frenar al detectar el color blanco'''&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://youtu.be/Jt_lxJL6vAw&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Integramos la búsqueda del rival'''&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://youtu.be/SDm4zpUem1A&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Comenzando el desafío de seguir la línea blanca'''&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://youtu.be/A3slJXGrILI&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==PRÓXIMOS ENCUENTROS==&lt;br /&gt;
Tengo acordado ir al menos dos viernes más para continuar con el proyecto. Como objetivo nos planteamos terminar de realizar otro robot, que ya comenzaron a armar para poder realizar una pelea. Además de continuar trabajando con el seguidor de línea para lo cual mi idea es llevar cinta y realizar pistas más complejas. Si los estudiantes se entusiasman en ir a la competencia ‘Sumo’ y ésta no se realiza demasiado tarde, me gustaría acompañarlos en el proceso para brindar apoyo. &lt;br /&gt;
&lt;br /&gt;
==CONCLUSIONES==&lt;br /&gt;
La experiencia me resultó muy enriquecedora. Además, logramos cumplir muchos de los desafíos planteados. Aprendí que la robótica no es solo programar. Estaba preocupada porque no todos se interesaron en programar el robot, pero me di cuenta que cada uno cumplía su función. Por ejemplo a uno de los que le gustaba programar no le gustaba  armar el robot ni cambiar los sensores de lugar. Entre todos lograron armar un lindo equipo, cada uno cumpliendo alguna función importante en él.&lt;/div&gt;</summary>
		<author><name>Florieppi</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Sip%26Puff4Buti%C3%A1_-_Haciendo_la_computaci%C3%B3n_m%C3%A1s_accesible</id>
		<title>Sip&amp;Puff4Butiá - Haciendo la computación más accesible</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Sip%26Puff4Buti%C3%A1_-_Haciendo_la_computaci%C3%B3n_m%C3%A1s_accesible"/>
				<updated>2021-06-19T20:41:31Z</updated>
		
		<summary type="html">&lt;p&gt;Sfreirelp: /* Reflexiones finales */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Preámbulo ==&lt;br /&gt;
&lt;br /&gt;
Pocas personas podrían afirmar que la informática no ha tenido impacto alguno sobre el mundo en general. Actualmente el mundo gira alrededor de ella, ya sea en medios portátiles como teléfonos celulares o fija en caso de las computadoras personales; muchos profesionales han migrado sus rutinas de trabajo a medios electrónicos, y los estudiantes dependen de ella para sus clases y evaluaciones en este tiempo de pandemia.&lt;br /&gt;
&lt;br /&gt;
Esto puede tener ventajas y desventajas según las situaciones particulares de cada persona. Sin embargo, quienes indefectiblemente salen desfavorecidas son aquellas que no tienen acceso a estos medios, independientemente de la razón que lo cause. Dejando de lado las razones económicas, una de ellas es el no poder utilizar estos dispositivos por limitaciones físicas. Por ejemplo, una persona con un grave caso de parálisis no tiene forma de utilizar una computadora, pues no puede mover el mouse ni ingresar texto mediante el teclado.&lt;br /&gt;
&lt;br /&gt;
A lo largo de los años se han desarrollado distintas soluciones para este tipo de situaciones, como puede ser reconocimiento de voz, uso de aparatos auxiliares para aquellas personas que tienen movilidad parcial, entre otros. En el caso de los individuos con problemas de movilidad importantes, como por ejemplo cuadriplegia, puede que en algunos casos estas alternativas no les sean suficientes, ya que puede ser difícil para ellos utilizarlas por limitaciones físicas.&lt;br /&gt;
&lt;br /&gt;
Sin embargo, hay una acción que es casi universalmente posible de hacer; y esto es, soplar y aspirar con la boca.&lt;br /&gt;
&lt;br /&gt;
== Sensores Sip and Puff ==&lt;br /&gt;
&lt;br /&gt;
Se han desarrollado sensores que permiten detectar estas dos señales y realizar diferentes acciones en base a ellas. Esto permite a sus usuarios realizar actividades que antes les eran imposibles, y consecuentemente mejorar su calidad de vida. A modo de ejemplo, en el año 2020 la ciudadana inglesa Natasha Lambert, de 23 años de edad y con cuadriplegia, cruzó el océano Atlántico en un viaje de más de 5.000 kilómetros en un velero controlado por ella mediante un sensor de este tipo.&lt;br /&gt;
&lt;br /&gt;
Además de ser generalmente más accesibles, este tipo de sensores tienen otras ventajas con respecto a otras alternativas. A modo de ejemplo, por su modo de ingresar datos es menos propenso a falsas activaciones, y en casos como el control del velero mencionado antes, donde la precisión es clave, cualquier orden enviada 'en falso' puede tener consecuencias muy serias. Además, es más confiable en situaciones como grandes ruidos, es económico y puede ser instalado y mantenido por cualquier persona con conocimientos básicos de electricidad y/o electrónica.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Sipandpuff.jpg]]&lt;br /&gt;
&lt;br /&gt;
''Persona utilizando un dispositivo Sip and Puff. Fuente de imagen: [https://www.orin.com/access/sip_puff Ver]''&lt;br /&gt;
&lt;br /&gt;
== Sip and Puff y el robot Butiá ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En el año 2014 un grupo de estudiantes junto a sus tutores implementaron un sensor de este tipo controlado mediante la placa USB4Butiá (véase [https://www.fing.edu.uy/inco/proyectos/butia/mediawiki/index.php/Accesibilidad aquí]), en donde además de hacer el sensor propiamente dicho lograron controlar el mouse con él mediante, y crearon una nueva paleta para TurtleBots con la que se pueden controlar diferentes aspectos del cursor, como por ejemplo moverlo, obtener su posición actual, hacer click, etc. Además, se dejó un espacio de trabajo a futuro con ideas que se tuvieron pero no se llevaron a cabo en esa ocasión en particular. Esto incluye, por ejemplo, el poder controlar el teclado.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Sensor.jpg | 600px]]&lt;br /&gt;
&lt;br /&gt;
''Sensor Sip&amp;amp;Puff''&lt;br /&gt;
&lt;br /&gt;
== Sip&amp;amp;Puff4Butiá ==&lt;br /&gt;
&lt;br /&gt;
[[Archivo:ProgramaGui.png | 750px]]&lt;br /&gt;
&lt;br /&gt;
Sip&amp;amp;Puff4Butiá surge como una idea de avanzar en lo que ya se había desarrollado, agregándole características que la implementación anterior no poseía, como por ejemplo el control de teclado. Además, el enfoque fue más a una aplicación de uso doméstico y directo, sin necesidad obligatoria de programación ni configuración para poder utilizarla. De esta forma, los usuarios solamente deben descargar y ejecutarla, y ya podrán realizar las tareas que ella permite a través de una interfaz amigable e intuitiva. &lt;br /&gt;
&lt;br /&gt;
Ella está programada en su totalidad con Python, tanto el backend como la interfaz gráfica. De esta forma, es utilizable fácilmente, pero al ser de código y hardware abiertos cualquier persona con el conocimiento técnico necesario puede modificarla o incluso mejorarla para agregar funcionalidades.&lt;br /&gt;
&lt;br /&gt;
Ella posee dos módulos principales, uno para control de mouse y otro para control de teclado, además de una sección de ajustes para personalizar ciertos aspectos del programa. Se cambia de módulo con cierta acción especial dentro de cada uno, que serán explicadas en sus respectivas secciones.&lt;br /&gt;
&lt;br /&gt;
La interfaz principal consiste en el título del programa, un subtítulo que informa el módulo actual y cambia según cuál se esté ejecutando y dos columnas, la primera con un elemento y la segunda con tres. &lt;br /&gt;
&lt;br /&gt;
En el caso de la primera, contiene en su totalidad el cuadro de texto de instrucciones, ubicado en la parte izquierda del programa. El propósito de él es brindarle información e instrucciones de cómo usar el módulo actual, de forma de tener una documentación resumida y accesible directamente en el programa. De esta manera, los usuarios que lo usen por primera vez no tendrán que recurrir a ningún sitio externo, ya sea físico o virtual, para aprender a usarlo. El texto es específico para cada módulo, y al cambiar entre ellos el texto cambia también.&lt;br /&gt;
&lt;br /&gt;
En la segunda, el primero es un cuadro informativo para uso del módulo teclado, que incluye un indicador de tiempo, la secuencia Morse que se ingresa hasta el momento y, una vez interpretado por el programa, a qué caracter o comando especial equivale. Mientras se utiliza el módulo mouse estos espacios no son utilizados, dejando solamente el texto estático y la barra vacía.&lt;br /&gt;
&lt;br /&gt;
Debajo de él se encuentra la sección de ajustes, donde se pueden modificar ciertos aspectos de los módulos para adaptarlos más a las necesidades particulares de cada usuario, con botones para guardar los ajustes o restablecerlos a sus valores predeterminados.&lt;br /&gt;
&lt;br /&gt;
El tercer elemento es la barra de botones, interactuables solamente en el módulo Mouse, que permiten cambiar al módulo Teclado, abrir una tabla de equivalencias de código Morse a caracteres o salir del programa.&lt;br /&gt;
&lt;br /&gt;
Cada una de estas partes será explicada más a profundidad en las secciones siguientes, y más específicamente en las que corresponden a los módulos o secciones que las utilizan.&lt;br /&gt;
&lt;br /&gt;
Es importante destacar que si al abrir el programa detecta que el sensor de soplido o aspirado no están conectados no dejará abrirlo, informando al usuario cuál no se encuentra, para luego cerrarse automáticamente.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Error.png]]&lt;br /&gt;
&lt;br /&gt;
'''Importante:''' Para que este programa funcione correctamente, el sensor de botón correspondiente al aspirado debe ser conectado al puerto 4 de la placa USB4Butiá, y el correspondiente al soplido al puerto 5.&lt;br /&gt;
&lt;br /&gt;
===Módulo Mouse===&lt;br /&gt;
&lt;br /&gt;
[[Archivo:MouseGui.png | 750px]]&lt;br /&gt;
&lt;br /&gt;
El módulo de mouse funciona haciendo dos barridos separados, uno en el eje de las X y el otro en el de las Y. Para ello, el programa pasa por tres etapas, cambiando entre ellas mediante un soplido.&lt;br /&gt;
&lt;br /&gt;
En la primera etapa, el cursor se mantiene quieto. Esta es la etapa inicial, y es en la que se encuentra el programa cuando se abre. Al soplar y pasar a la segunda, el cursor comienza a moverse hacia la derecha a una velocidad fijada por el usuario; al llegar al borde de la pantalla, vuelve al otro extremo manteniendo la posición vertical. Esto continúa hasta que se sopla nuevamente y se pasa a la tercera etapa, donde el cursor deja de moverse hacia los lados y comienza a hacerlo hacia abajo. Al soplar nuevamente, se pasa a la etapa inicial, y el cursor se mantendrá estático hasta que reciba nuevamente órdenes de moverse.&lt;br /&gt;
&lt;br /&gt;
Sin embargo,esto es solo para posicionarlo en un lugar específico de la pantalla. Para hacer click, se debe aspirar. Es importante destacar que esto se puede hacer en cualquier momento, sin importar en qué etapa se esté; sin embargo, al hacer esto se vuelve a la etapa inicial, por lo que para reanudar el movimiento se debe soplar nuevamente acordemente a lo que se desee.&lt;br /&gt;
&lt;br /&gt;
La idea de movimiento del mouse por etapas fue parcialmente inspirada por el barrido hecho en el proyecto anterior de Sip&amp;amp;Puff con la placa USB4Butiá. Sin embargo, esta implementación tiene algunos cambios como el click únicamente mediante aspirado, y no obligatoriamente al volver a la etapa inicial.&lt;br /&gt;
&lt;br /&gt;
Para cambiar al módulo de teclado se tienen dos opciones: la primera es hacer click en el botón &amp;quot;Cambiar a teclado&amp;quot; presente en la interfaz, y la segunda es aspirar de forma sostenida por una cantidad de segundos determinada por el usuario, que por defecto son 3. Esto, junto a la velocidad de movimiento del cursor, son  modificables en la sección de Ajustes del programa.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:CambiarTeclado.png]]&lt;br /&gt;
&lt;br /&gt;
Mientras se está en el modo Mouse es posible utilizar los diferentes botones disponibles en el programa principal. Al cambiar al modo Teclado se deshabilitan, y al reingresar al modo Mouse se habilitan nuevamente. Cada uno cumple una función determinada. La hilera de arriba corresponde al guardado y restablecimiento de ajustes, que será explicado en la sección de Ajustes. En la hilera de abajo se encuentran tres botones; con &amp;quot;Cambiar a teclado&amp;quot; se cambia al módulo teclado sin necesidad de enviar la orden de cambio mediante aspirado, con &amp;quot;Guía Morse&amp;quot; se abre una imagen con la tabla de equivalencias de secuencia Morse a caracter, y con el botón &amp;quot;Salir&amp;quot; se cierra completamente el programa.&lt;br /&gt;
&lt;br /&gt;
===Módulo Teclado===&lt;br /&gt;
&lt;br /&gt;
[[Archivo:TecladoGui.png | 750px]]&lt;br /&gt;
&lt;br /&gt;
En el módulo teclado, las letras se ingresan mediante código Morse. Un soplido equivale a un guión y una aspirada a un punto. Si el usuario no conoce las equivalencias de secuencia Morse a caracteres, puede pulsar el botón &amp;quot;Guía Morse&amp;quot; dentro de la interfaz en el módulo Mouse o ingresar la secuencia (---.-) para abrir una imagen con estos datos.&lt;br /&gt;
&lt;br /&gt;
Hay un tiempo mínimo que pasa entre señales antes de recibir otra, para dar estabilidad al programa y no contar dos o más veces una misma señal; este tiempo varía según el tipo de indicación. En el caso del soplido, equivalente a un guión, debe pasar medio segundo antes de que se interprete otro envío. Es decir, si el usuario sopla constantemente por un segundo, se registrarán dos guiones. Si este tiempo de espera no estuviera, se registraría una cantidad inmensa de guiones, tantas como señales el equipo sea capaz de recibir en ese tiempo. En el caso del aspirado, equivalente a un punto, el tiempo es de 0.95 segundos. Por lo tanto, en el peor caso hay aproximadamente un segundo entre cada indicación, y a efectos prácticos se toma un promedio de 1 segundo por señal por este peor caso, y porque es prácticamente imposible comenzar a ingresar otra indicación exactamente en el momento en que se comienza a contar el tiempo.&lt;br /&gt;
&lt;br /&gt;
Cada vez que se ingresa una señal se reproduce el sonido correspondiente; es decir, al ingresar un guión se escucha un guión Morse (ver [https://gitlab.fing.edu.uy/santiago.freire/SipAndPuff4Butia/-/blob/master/dash.wav dash.wav]), y al ingresar un punto un punto Morse (ver [https://gitlab.fing.edu.uy/santiago.freire/SipAndPuff4Butia/-/blob/master/dot.wav dot.wav]). Asimismo, a medida que se van ingresando datos la secuencia se va mostrando en la interfaz, a la derecha del texto &amp;quot;''Secuencia Morse ingresada''&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Cada cierta cantidad de segundos definida en la sección ajustes, el programa interpreta esa secuencia como un caracter y simula una presionada de la tecla correspondiente, que tiene el mismo efecto que presionarla en el teclado físico. Cuando esto ocurre se escuchan tres puntos seguidos (ver [https://gitlab.fing.edu.uy/santiago.freire/SipAndPuff4Butia/-/blob/master/tripleDot.wav tripleDot.wav]), para notificar al usuario de que ya puede comenzar a formar su nueva secuencia Morse. A medida que este tiempo avanza, la barra indicadora de progreso &amp;quot;''Tiempo''&amp;quot; de la parte superior derecha del programa se va llenando. Que esté llena indica que se acabó el tiempo de ingresar señales y que el programa interpretará lo ya ingresado; de la misma forma, la barra vacía indica que es el principio del ingreso de datos.&lt;br /&gt;
&lt;br /&gt;
Una vez que se agota este tiempo, la secuencia se reinicia y el programa continúa recibiendo señales para luego interpretarlas, repitiendo esta secuencia hasta enviar el comando de cambio de módulo o salir.&lt;br /&gt;
&lt;br /&gt;
En esta interpretación, el caracter al que correspondió lo ingresado se muestra en la interfaz, a la derecha del texto &amp;quot;''y equivale a: ''&amp;quot;. De esta forma, ante cualquier duda sobre el caracter que el usuario indicó, puede observar la interfaz y ver a qué correspondía. Si la secuencia es vacía o no corresponde a ningún caracter, se muestra la palabra &amp;quot;Nada&amp;quot;. De esta forma el usuario es consciente de que se equivocó al formar la secuencia, y no se queda preguntando por qué no funciona la tecla que ingresó.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:ProgramaGui.png | 750px]]&lt;br /&gt;
&lt;br /&gt;
Sin embargo, el error es humano; entonces, no se espera que el usuario tenga una precisión del 100% a la hora de enviar las señales. Por lo tanto, al percatarse de un error se puede cancelar el caracter ingresando siete o más señales Morse. Siendo que no hay ningún caracter o comando especial que requiera más de este número de señales, no puede significar otra cosa que la cancelación. Cuando el programa se encuentra con esta situación, no simula ningún presionado de tecla y continúa su ciclo. &lt;br /&gt;
&lt;br /&gt;
Este número ayuda especialmente en las teclas con secuencias largas, donde es fácil equivocarse y un error significa ingresar algo completamente diferente a lo deseado. Por ejemplo, si el usuario está ingresando un punto y coma (-.-.-.) pero en vez de eso ingresa un guión en vez de punto al final (-.-.--), accidentalmente habrá tipeado un signo de exclamación que puede cambiar significativamente la intención de lo que estaba escribiendo, a modo de ejemplo. Al percatarse del error, puede enviar un punto, convirtiendo la secuencia a (-.-.--.), efectivamente cancelando su ingreso. Luego puede intentar enviarlo nuevamente con la tranquilidad de no haber ingresado un caracter que no era el deseado.&lt;br /&gt;
&lt;br /&gt;
Debido a la forma de simulación de presión de teclas, hay algunas cuyo ingreso se hace de una manera diferente; en este caso, son las definidas como caracteres especiales en ''dicts.py''. Más específicamente, son las vocales con tilde, la eñe y las comillas dobles. Para ingresarlas, se copian al portapapeles y luego se simula la combinación de teclas Ctrl-V, de esta forma pegándolas. En situaciones normales no habría problema con este método; sin embargo, a modo de ejemplo en programas como la mayoría de las terminales Linux se pega con Ctrl-Shift-V y no Ctrl-V. En estos casos este método no funcionaría, y este programa no es capaz de ingresarlos directamente. Una alternativa más larga pero válida es hacer la combinación de puntos y guiones correspondiente a uno de estos caracteres especiales, y luego con el módulo Mouse presionar sobre el botón ''&amp;quot;Pegar&amp;quot;'' del programa donde se quiere ingresar, siempre y cuando cuente con esta opción.&lt;br /&gt;
&lt;br /&gt;
Una consecuencia de esto es la pérdida del contenido del portapapeles a menos que se respalde en otra ubicación. Aún así, si el equipo se usa exclusivamente con SipAndPuff4Butiá, siendo que actualmente no hay forma de copiar y pegar, no debería hacer ninguna diferencia. De todas formas es un hecho a tener en cuenta en el caso de que se use en conjunto con otras herramientas, que haya otra persona ayudando al control de la computadora, o cualquier otro caso similar.&lt;br /&gt;
&lt;br /&gt;
Además de las letras, números y símbolos convencionales, existen teclas especiales como la barra espaciadora, la tecla de borrar, Escape, Enter, Tab y Caps Lock. De estas cabe destacar que todas simulan una presión de la tecla correspondiente menos Caps Lock, siendo esta una configuración interna del programa; igualmente, su comportamiento es exactamente el mismo, y a efectos prácticos no debería haber diferencia alguna con tocar la tecla del teclado físico. Al entrar a el módulo teclado, el programa enciende el bloqueo de mayúsculas de forma predeterminada; actualmente esto no es configurable sin editar el código fuente.&lt;br /&gt;
&lt;br /&gt;
Para cambiar al módulo Mouse se puede ingresar la secuencia EOM (end of message), y para cerrar el programa en su totalidad se debe enviar la secuencia de salida, correspondiente a seis guiones.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:CambiarMouse.png]]&lt;br /&gt;
&lt;br /&gt;
Los botones interactivos de la interfaz están desactivados hasta cambiar nuevamente al Mouse. Esto es porque en teoría no se podría utilizar el teclado y el mouse a la vez con la implementación actual, además de que las acciones que pueden resultar útiles para el módulo teclado ya están implementadas como secuencias especiales. Esto es el caso del cambio a módulo mouse mediante EOM, la apertura de la guía Morse y el cerrado del programa principal.&lt;br /&gt;
&lt;br /&gt;
Notar que el código Morse utilizado sigue mayormente los estándares internacionales; sin embargo, se le hicieron modificaciones y agregados que no están normalmente en él. Por lo tanto, se sugiere consultar la Guía Morse incluida antes de utilizar este módulo.&lt;br /&gt;
&lt;br /&gt;
===Sección Ajustes===&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Ajustes.png]]&lt;br /&gt;
&lt;br /&gt;
Uno de los aspectos más importantes en este tipo de programas es la personalización; no todos los usuarios tienen las mismas necesidades, y lo que para algunos hace el programa inutilizable para otros hace posible su uso. Para lograr eso, se incorporó una sección de ajustes en el programa principal, donde se pueden personalizar diversos aspectos de los módulos.&lt;br /&gt;
&lt;br /&gt;
Todos los ajustes actuales son numéricos, y cada uno tiene un rango de valores válidos. Si se ingresa un número fuera de ellos o ni siquiera se ingresa un número en una primera instancia, al guardarlos el programa ignorará ese cambio y solo almacenará los ajustes que cumplan las condiciones.&lt;br /&gt;
&lt;br /&gt;
En su primera ejecución en el equipo el programa carga valores predeterminados que generalmente hacen posible y accesible su uso; si el usuario desea cambiarlos es completamente libre de hacerlo. &lt;br /&gt;
&lt;br /&gt;
Para guardar los ajustes personalizados, se debe presionar el botón &amp;quot;Guardar&amp;quot;, luego de lo cual el programa informa que los cambios han sido realizados con éxito. Sin embargo, se debe tener en cuenta que estos cambios solamente surtirán efecto al reiniciar el programa.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:AjustesGuardados.png]]&lt;br /&gt;
&lt;br /&gt;
Si en algún momento se ingresa una combinación específica de ajustes que hacen imposible su uso normal, siempre se pueden reiniciar a los valores predeterminados, pulsando el botón &amp;quot;Restaurar valores por defecto&amp;quot;. Luego de ello, los valores se reinician y el programa informa que sólo tendrán efecto luego de reiniciar el programa. Los valores predeterminados están detallados más abajo, en la explicación de cada uno de ellos.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Restaurados.png]]&lt;br /&gt;
&lt;br /&gt;
====Ajustes de Teclado====&lt;br /&gt;
&lt;br /&gt;
En el caso del teclado, la configuración disponible es el tiempo que da el programa para ingresar una secuencia Morse. Un usuario más experimentado podría ingresar secuencias en menos de 10 segundos, pero alguien que está dando sus primeros pasos con el uso quizás demore más, por ejemplo mientras se fija en la guía a qué secuencia corresponde el caracter que desea ingresar.&lt;br /&gt;
&lt;br /&gt;
Por lo tanto, el rango de este ajuste va de los 5 segundos hasta los 60, siendo el predeterminado 10. La elección del mínimo de 5 segundos no es aleatoria ni insignificante, siendo que corresponde a una posible situación problemática: en el evento de que el tiempo entre letras sea accidentalmente ingresado demasiado bajo, cinco segundos es el mínimo de tiempo que se necesita para volver a cambiarlo a la normalidad.&lt;br /&gt;
&lt;br /&gt;
Frente a esta situación, se puede enviar EOM para cambiar al módulo mouse (siendo que son 4 señales, el tiempo promedio para ingresarlo es de 4 segundos), luego mover el mouse hacia el cuadro de ajustes y seleccionar el campo de teclado, volver al módulo teclado, ingresar un número más alto y guardar los ajustes. Siendo que todos los números están formados por cinco señales Morse, el tiempo promedio de ingreso es de cinco segundos. Si el mínimo del rango fuera cuatro segundos, no se podría ingresar ningún número y sin ayuda externa el programa quedaría inutilizable.&lt;br /&gt;
&lt;br /&gt;
Si se recuerda de otra sección anterior, el tiempo que pasa entre que se recibe un punto y se vuelve a recibir otro es de exactamente 0.95 segundos. No es 1 exacto para dar estabilidad, pues si se ingresa la señal exactamente cuando se cumplen los cinco segundos puede tanto que se interprete como tanto que no, ya que la diferencia sería en términos de milisegundos y demasiado precisa. Por lo tanto, se le restan 50 milisegundos para intentar evitar esta situación.&lt;br /&gt;
&lt;br /&gt;
====Ajustes de Mouse====&lt;br /&gt;
&lt;br /&gt;
En cuanto a los ajustes del mouse respectan, se incluyeron dos diferentes: la velocidad de movimiento y el tiempo que se debe aspirar de forma continua para cambiar al teclado.&lt;br /&gt;
&lt;br /&gt;
En el caso del primero, determina la velocidad en píxeles por décima de segundo de movimiento del mouse, con un mínimo de 1 y un máximo de 150, siendo el predeterminado 10. Esta unidad de medida se debe a que el cursor se mueve efectivamente cada 1/10 segundo.&lt;br /&gt;
&lt;br /&gt;
Esto responde nuevamente al hecho que distintos usuarios pueden tener distintas necesidades, además de hardware y resoluciones de pantalla distintas. Un usuario con una resolución de 640x480 deberá elegir una velocidad menor que otro con 3840x2160, pues tiene 6 veces menos píxeles horizontalmente. Al usuario del segundo monitor la velocidad elegida por el primero podría resultarle abrumadoramente lenta.&lt;br /&gt;
&lt;br /&gt;
Por otro lado, el segundo ajuste es el tiempo necesario de aspirado constante para enviar la señal de cambio de módulo al programa. Tiene un mínimo de 1 segundo y un máximo de 10, siendo el predeterminado 3.&lt;br /&gt;
&lt;br /&gt;
===Programa en funcionamiento===&lt;br /&gt;
&lt;br /&gt;
El siguiente video muestra el programa en acción, incluyendo los dos módulos con sus características y los cambios entre ellos. El objetivo en este video fue entrar al EVA del Taller de Robótica Educativa con el Robot Butiá (TRERB) y leer el programa de la materia.&lt;br /&gt;
&lt;br /&gt;
Es importante destacar que está al triple de la velocidad normal, para reducir considerablemente la duración del mismo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://www.youtube.com/watch?v=mPy0ezSGQ9o&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Desarrollo y código==&lt;br /&gt;
&lt;br /&gt;
===Consideraciones previas===&lt;br /&gt;
&lt;br /&gt;
Este proyecto fue programado íntegramente en Python 2.7. Las librerías utilizadas fueron ''sys, time, json, subprocess, pyperclip, playsound'' y ''PySimpleGUI27''. Las explicaciones siguientes asumen que el lector ya tiene cierto conocimiento técnico básico sobre el lenguaje, por lo que algunas cosas simples pueden darse por sentadas.&lt;br /&gt;
&lt;br /&gt;
El programa está dividido en siete archivos diferentes, de los cuales son todos necesarios para su correcto funcionamiento. Ellos son los tres archivos de audio del teclado, la imagen de guía Morse, los ajustes predeterminados, el programa principal que se ejecuta y el archivo de Python que contiene los diccionarios de Morse, caracteres especiales y texto de instrucciones utilizados en él.&lt;br /&gt;
&lt;br /&gt;
En el programa principal están implementados todos los módulos y, a menos que se especifique lo contrario, en las secciones siguientes todo lo hablado se refiere a él.&lt;br /&gt;
&lt;br /&gt;
===Programa principal===&lt;br /&gt;
&lt;br /&gt;
En el programa principal se inicializa la interfaz grafica mediante la función &amp;lt;code&amp;gt;Window&amp;lt;/code&amp;gt; de ''PySimpleGUI27'', y se ejecutan en bucle infinito, uno tras otro, los subprogramas de mouse y teclado, comenzando por el de mouse. Por lo tanto cuando uno de ellos termina se pasa al siguiente, y esto continúa hasta que se elija la opción de ''Salir'' en cualquiera de ellos, mediante lo cual se cerrará definitivamente el programa mediante la función &amp;lt;code&amp;gt;quit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Interfaz gráfica===&lt;br /&gt;
&lt;br /&gt;
====Layouts====&lt;br /&gt;
&lt;br /&gt;
La interfaz gráfica de este programa fue creada utilizando la librería PySimpleGUI27, que es la versión específica de PySimpleGUI para Python 2.7. En esta librería los elementos están dispuestos en ''layouts'', que se pueden ubicar y combinar entre sí para formar los elementos gráficos.&lt;br /&gt;
&lt;br /&gt;
Dentro de ellos se ubican los elementos, dentro de los cuales hay varios tipos, como pueden ser cuadros de texto, botones, barras de progreso, entre otros.&lt;br /&gt;
&lt;br /&gt;
En este caso, la interfaz consiste en dos ''layouts'' principales, uno para la parte izquierda y otro para la derecha. En la parte izquierda el único elemento es el cuadro de texto de instrucciones, de tipo ''Multiline'' para que sea de múltiples líneas; en la derecha, están las disposiciones de la parte de feedback del módulo teclado y la de los ajustes, que se combinan en una sola mediante ''frames'', lo que permite su disposición en bloques, y la barra de botones inferiores. &lt;br /&gt;
&lt;br /&gt;
Las dos disposiciones de izquierda y derecha son dispuestas en forma de columnas, y se colocan los dos textos, uno estático y otro variante, encima de ellas.&lt;br /&gt;
&lt;br /&gt;
Es importante destacar que cada elemento que se desee que cambie durante la ejecución del programa debe tener asignada una clave única. Con ella, se puede acceder a sus elementos y modificarlos en la medida que se desee. Por lo tanto, todos los elementos excepto el texto estático tienen asignada una.&lt;br /&gt;
&lt;br /&gt;
Para facilitar este cambio creé una función auxiliar llamada ''cambiarTextoGUI'', que recibe como parámetros la clave del elemento, la ventana creada al inicializar la interfaz y el texto a cambiar; una vez llamada cambia el texto y refresca la ventana, de forma que el cambio se ve reflejado inmediatamente en la interfaz.&lt;br /&gt;
&lt;br /&gt;
Para ilustrar, un ejemplo de estas disposiciones es la siguiente, correspondiente a la sección de ajustes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
feedbackText = [&lt;br /&gt;
&lt;br /&gt;
	[sg.Text('Tiempo:', font=('Helvetica',10,'italic'))],&lt;br /&gt;
	[sg.ProgressBar(keyTimeout,size=(200,15),key='__PROGRESS__')],&lt;br /&gt;
	[sg.Text('Secuencia Morse ingresada:', font=('Helvetica',10)), sg.Text('', key='_FEEDBACK_', font=('Helvetica',20), enable_events=True)],&lt;br /&gt;
	[sg.Text('y equivale a: ',font=('Helvetica',10)), sg.Text('',key='_TRANSLATION_',font=('Helvetica',20), size=(200,None), enable_events=True)],&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
En este caso, ''sg'' corresponde a la librería PySimpleGUI27, que es importada &amp;quot;''as sg''&amp;quot; para resumir su nombre. Aquí se muestra que esta disposición tiene texto estático, indicado por aquellos ''sg.Text'' sin una clave asociada, texto variante con claves asociadas, y una barra de progreso cambiante también.&lt;br /&gt;
&lt;br /&gt;
Por defecto los elementos se disponen horizontalmente, y para hacerlo verticalmente se deben poner en forma de columnas, mediante el elemento ''sg.Column''. Un ejemplo de esto son las columnas de la ventana principal del programa, que poseen la siguiente ''layout'':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
combinedLayout = [&lt;br /&gt;
&lt;br /&gt;
	[sg.Text('Sip&amp;amp;Puff4Butia', size=(wSizeX, 1), font=(&amp;quot;Helvetica&amp;quot;, 25))],	&lt;br /&gt;
	[sg.Text('', size=(wSizeX, 1), justification='center', font=(&amp;quot;Helvetica&amp;quot;, 15), key='__ACTUAL__')],	&lt;br /&gt;
	[sg.Column(textHelp), sg.Column(doubleLayout)],&lt;br /&gt;
&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se pone el título en la parte superior, un subtítulo cambiante debajo para indicar el módulo en ejecución y dos ''layouts'' dispuestas verticalmente, cada una ocupando un 50% del ancho de la ventana. &lt;br /&gt;
Para ello, nuevamente, se utiliza la instrucción ''sg.Column(layout)'', que en este caso corresponde al cuadro de texto de instrucciones y a la disposición combinada de feedback de teclado y sección de ajustes.&lt;br /&gt;
&lt;br /&gt;
====Interacción con botones====&lt;br /&gt;
&lt;br /&gt;
Cada vez que un botón, tanto de la sección de ajustes como de la barra inferior, es presionado en el módulo mouse, se genera un evento, obtenido mediante la instrucción &amp;lt;code&amp;gt;event, values = window.Read()&amp;lt;/code&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
En este caso, los ''values'' son los valores de los cuadros de texto, y ''events'' el evento actual ocurrido en el programa. Normalmente ''events'' es vacío, pero al presionar uno de los botones esta variable se cambiará por el texto del botón propiamente dicho. Por lo tanto, en el módulo mouse se obtienen constantemente estos valores, y cuando el evento cambia, y por tanto cambia esta variable, se realiza la acción correspondiente. Siendo que es una ''string'', basta con compararlo con el operador '=='.&lt;br /&gt;
&lt;br /&gt;
Sin embargo, apenas se entra a las instrucciones de cada caso lo primero que se hace es dejar la variable ''events'' como una secuencia vacía. Esto es porque, en caso contrario, se ejecutarían las órdenes del botón indefinidamente, pues el condicional &amp;lt;code&amp;gt;if event == ''(evento)''&amp;lt;/code&amp;gt; siempre sería cierto.&lt;br /&gt;
&lt;br /&gt;
====''Popups''====&lt;br /&gt;
&lt;br /&gt;
Para abrir un ''popup'' con un mensaje informativo, se utiliza la función &amp;lt;code&amp;gt;sg.PopupAutoClose&amp;lt;/code&amp;gt;. Es importante que sea de cerrado automático, para que el usuario no tenga que presionar ningún botón para cerrarlo, pues ello podría ocasionar complicaciones innecesarias.&lt;br /&gt;
&lt;br /&gt;
Un ejemplo de ''popup'' es el de guardado de ajustes. Al presionar el botón ''Guardar'', aparecerá el siguiente mensaje:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:AjustesGuardados.png]]&lt;br /&gt;
&lt;br /&gt;
El código correspondiente a él es:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;sg.PopupAutoClose('Ajustes guardados. Reinicie el programa para que tengan efecto.', keep_on_top=True, title='Aviso')&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se define el texto (primer parámetro), que aparezca encima de todas las ventanas (''keep_on_top'') y el título (''title''). Lo mismo ocurre con las demás ventanas emergentes del programa, cada una con sus características correspondientes.&lt;br /&gt;
&lt;br /&gt;
===Ajustes===&lt;br /&gt;
&lt;br /&gt;
====Persistencia====&lt;br /&gt;
&lt;br /&gt;
Una de las incógnitas a la hora del desarrollo era cómo hacer para que los ajustes persistieran entre ejecuciones y no volvieran siempre a los predeterminados. La solución a ello fue guardarlos en un archivo externo con formato JSON, en el mismo directorio del programa, llamado ''settings.json''. De esta forma, los ajustes son persistentes y no se pierden al cerrar el programa, y si llega a ser necesario se pueden editar directamente en el archivo mismo.&lt;br /&gt;
&lt;br /&gt;
Al principio del programa, la primera instrucción que no es importar librerías es cargar los ajustes.  &lt;br /&gt;
Para ello, se cargan del archivo JSON y se pasan a un diccionario global, de forma que todas las funciones puedan llamarlo. Esto se hace mediante&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt;Abro el diccionario de ajustes en settings.json&lt;br /&gt;
&lt;br /&gt;
with open('settings.json') as setDict:&lt;br /&gt;
&lt;br /&gt;
	settings = json.load(setDict)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Utilizando la librería ''json'', se interpreta el formato y se convierte a un diccionario, donde los elementos son fácilmente accesibles mediante &amp;lt;code&amp;gt;settings.get('clave')&amp;lt;/code&amp;gt;, siendo 'clave' el nombre del ajuste.&lt;br /&gt;
&lt;br /&gt;
====Guardado====&lt;br /&gt;
&lt;br /&gt;
Si se lee nuevamente la sección de interacción con botones, se notará que explico cómo se obtienen los valores de los cuadros de texto con la instrucción &amp;lt;code&amp;gt;event, values = window.Read()&amp;lt;/code&amp;gt;. En ste caso, están almacenados en la variable ''values''. Cabe destacar que los valores contenidos, por defecto tienen formato JSON.&lt;br /&gt;
&lt;br /&gt;
Para guardar los ajustes mediante el botón ''Guardar'', se transforman los valores de esta variable a un diccionario con la instrucción &amp;lt;code&amp;gt;setString = json.dumps('valores')&amp;lt;/code&amp;gt;. Notar que es ''dumps'' y no ''dump'', esto es porque es porque la variable de valores es una '''s'''tring, y de ahí viene la 's' del final. Luego este diccionario se carga con la instrucción &amp;lt;code&amp;gt;settings = json.loads(setString)&amp;lt;/code&amp;gt;, donde los valores se pueden acceder mediante &amp;lt;code&amp;gt; ''ajuste'' = settings[''clave'']&amp;lt;/code&amp;gt;, siendo ''ajuste'' el nombre de la variable donde se almacenará temporalmente el ajuste al que le corresponde la clave &amp;quot;''clave''&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
En este caso, hay tres variables para los tres ajustes: ''keyTimeout, sipTimeout'' y ''mouseSpeed''. La primera corresponde al tiempo entre letra y letra del módulo teclado, la segunda al tiempo de aspirado para cambiar al módulo teclado en el módulo mouse, y la tercera la velocidad del cursor en el módulo mouse también.&lt;br /&gt;
&lt;br /&gt;
Para guardar los ajustes se define un procedimiento llamado ''guardarAjustes(newSettings)'', que recibe como parámetro los ''values'' obtenidos mediante ''window.Read()''.&lt;br /&gt;
&lt;br /&gt;
Ellos son obtenidos mediante la conversión de JSON a diccionario mencionada anteriormente, y luego mediante las líneas &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Obtengo los ajustes ya existentes&lt;br /&gt;
keyTimeout = settings['__KTIMEOUT__']&lt;br /&gt;
sipTimeout = settings['__STIMEOUT__']&lt;br /&gt;
mouseSpeed = settings['__MSPEED__']&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se puede ver como se guarda cada uno en su variable correspondiente, obtenido a través de su clave definida cuando se crearon las ''layouts''.&lt;br /&gt;
&lt;br /&gt;
====Validación de tipo y rango====&lt;br /&gt;
&lt;br /&gt;
Los ajustes son de tipo entero y están en un rango específico. Por lo tanto, si el usuario ingresa, por ejemplo, caracteres en vez de números, o enteros fuera del rango, ese ajuste no debería guardarse.&lt;br /&gt;
&lt;br /&gt;
Esto se hace mediante una validación de tipo y de rango. Cada ajuste tiene una variable booleana que indica si ese ajuste cumple con sus requisitos o no, y a la hora del guardado al archivo ''settings.json'' ella determinará si ese ajuste será modificado o no. Para ilustrar, el fragmento de código correspondiente al chequeo de la variable ''keyTimeout'' es el siguiente:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Chequeo si puedo pasar la string a un entero&lt;br /&gt;
try:&lt;br /&gt;
	int(keyTimeout)&lt;br /&gt;
&lt;br /&gt;
#Si se ingresa algo que no es un entero, dejo el valor original.&lt;br /&gt;
except ValueError:&lt;br /&gt;
	saveKT = False&lt;br /&gt;
&lt;br /&gt;
#Si no, entonces paso la string a un int&lt;br /&gt;
else:&lt;br /&gt;
	keyTimeout = int(keyTimeout)&lt;br /&gt;
&lt;br /&gt;
	#Chequeo de rango&lt;br /&gt;
	if keyTimeout &amp;gt;= 5 and keyTimeout &amp;lt;= 60:&lt;br /&gt;
		saveKT = True&lt;br /&gt;
	else:&lt;br /&gt;
		saveKT = False&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para validar el tipo, se prueba si se puede convertir lo ingresado al tipo entero mediante la orden &amp;lt;code&amp;gt;int(keyTimeout)&amp;lt;/code&amp;gt;. Si esto no es posible, se generará un error de tipo ''ValueError''. Esto se chequea con la orden ''except'', que al no cumplirse cambiará la variable de guardado del ajuste a ''false''.&lt;br /&gt;
&lt;br /&gt;
En cambio, si esta variable es efectivamente un entero, se procede a convertir la variable a un entero y a realizar la verificación de rango. Esta consiste en evaluar si este número está comprendido en su rango válido de valores, que es el que aparece en la GUI. Por ejemplo, en el caso del tiempo entre letra y letra va de 5 segundos hasta 60, como fue explicado en su sección. Entonces, si lo ingresado está entre o es uno de estos valores, la variable de guardado de ese ajuste se vuelve verdadera. En caso contrario, se vuelve falsa.&lt;br /&gt;
&lt;br /&gt;
Esto se repite para los otros tres ajustes, cada uno con sus características particulares.&lt;br /&gt;
&lt;br /&gt;
====Guardado final y modificación de ''settings.json''====&lt;br /&gt;
&lt;br /&gt;
Una vez que los ajustes son verificados y sus valideces marcadas, se procede al guardado persistente en el archivo ''settings.json''.&lt;br /&gt;
&lt;br /&gt;
Esto se hace mediante el siguiente código:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Diccionario vacío para los valores nuevos&lt;br /&gt;
resSettings = {}&lt;br /&gt;
&lt;br /&gt;
#Si todos los valores cumplen con los requisitos, entonces los guardo&lt;br /&gt;
if saveKT:&lt;br /&gt;
	resSettings['keyTimeout'] = keyTimeout&lt;br /&gt;
if saveMS:&lt;br /&gt;
	resSettings['mouseSpeed'] = mouseSpeed&lt;br /&gt;
if saveST:&lt;br /&gt;
	resSettings['sipTimeout'] = sipTimeout&lt;br /&gt;
&lt;br /&gt;
#Almaceno los cambios en settings.json&lt;br /&gt;
with open('settings.json','w') as setDict:&lt;br /&gt;
	json.dump(resSettings,setDict)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Se crea un diccionario vacío para guardar los ajustes a modificar; luego se verifica la variable de guardado correspondiente a cada uno, y si es verdadera se agrega su clave y valor nuevo correspondiente a él.&lt;br /&gt;
&lt;br /&gt;
Una vez que este diccionario fue creado, se abre el archivo ''settings.json'' mediante la instrucción ''open'' con la opción 'w' (de ''write'', es decir, &amp;quot;escribir&amp;quot;), y se reemplazan mediante ''json.dump'', con los parámetros del diccionario resultante y el archivo abierto anteriormente.&lt;br /&gt;
&lt;br /&gt;
Algo a destacar de esto es que la instrucción ''json.dump'' no sobreescribe completamente el archivo JSON de ajustes, sino que lo actualiza con los valores del diccionario nuevo. Entonces, si no hay ningún ajuste válido o solo algunos lo son, los que no se modifican quedarán con sus valores originales.&lt;br /&gt;
&lt;br /&gt;
Además, si alguna clave no se encuentra presente en el archivo, ya sea por una eliminación accidental de ''settings.json'' en el transcurso de la ejecución del programa u otra razón, al escribirlos ''json.dump'' creará las claves y les asignará el valor. Es decir, que no funciona solamente para actualizar sino también para crear en caso de eliminación.&lt;br /&gt;
&lt;br /&gt;
====Restauración a valores predeterminados====&lt;br /&gt;
&lt;br /&gt;
La restauración de los valores predeterminados se realiza cuando se presiona el botón correspondiente en la interfaz durante el módulo Mouse. Allí, se cambian los valores de los cuadros de texto de ingreso de datos mediante la función ''cambiarTextoGUI'', explicada en secciones anteriores:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Cambio el texto de los cuadros de texto&lt;br /&gt;
cambiarTextoGUI('__MSPEED__',window,'10')&lt;br /&gt;
cambiarTextoGUI('__KTIMEOUT__',window,'10')&lt;br /&gt;
cambiarTextoGUI('__STIMEOUT__',window,'3')&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Luego se leen los valores nuevos mediante window.Read(), y se llama a la función de guardar ajustes con estos valores:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#Leo los nuevos valores&lt;br /&gt;
event, values = window.Read(timeout=10)&lt;br /&gt;
&lt;br /&gt;
#Guardo los ajustes con los valores por defecto&lt;br /&gt;
guardarAjustes(values)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A efectos prácticos, lo que se hace es simular que el usuario ingresara estos valores y después los guardara normalmente. De esta forma, no se precisa hacer otra función adicional para modificar ''settings.json'', sino que basta con cambiar los números correspondientes en los cuadros de texto y luego usar la función de guardado ya implementada. De esta forma se necesita menos código, y se aprovecha más eficientemente el que ya está.&lt;br /&gt;
&lt;br /&gt;
Los valores por defecto son 10 segundos entre letra y letra, 10 píxeles por décima de segundo de velocidad del mouse y 3 segundos de aspirado para cambiar de módulo en el módulo Mouse. Ellos pueden ser ajustados según cada caso particular, pero actualmente esto solo es posible hacerlo editando el código fuente.&lt;br /&gt;
&lt;br /&gt;
===Módulo mouse===&lt;br /&gt;
&lt;br /&gt;
====Algunas consideraciones previas a la ejecución====&lt;br /&gt;
Lo primero que se hace al cargar el módulo mouse es cambiar el texto de instrucciones y programa actual, además de vaciar la barra de progreso y secuencias Morse de la interfaz, para que no queden residualmente de la ejecución del módulo teclado. Esto se hace en todos los casos mediante la función ''cambiarTextoGUI''.&lt;br /&gt;
&lt;br /&gt;
Para el movimiento automático del mouse se utiliza la librería ''pyautogui'', de funcionamiento similar a la librería ''xevents'' de la FING. Mediante ella antes que nada se obtiene el tamaño total de la pantalla para detectar cuáles son los bordes, y la posición actual del cursor. &lt;br /&gt;
&lt;br /&gt;
En la primera ejecución del programa se mueve el cursor a la mitad de la pantalla; es decir, cada uno de los tamaños horizontales y verticales divididos entre 2. Sin embargo, sería poco práctico que se mueva a la mitad en cada cambio de módulo, por lo que luego de este movimiento inicial, pensado como una suerte de inicialización, no se vuelve a modificar la posición el cursor sin indicación previa del usuario.&lt;br /&gt;
&lt;br /&gt;
Las primeras dos acciones se realizan mediante las funciones &amp;lt;code&amp;gt;size()&amp;lt;/code&amp;gt; y &amp;lt;code&amp;gt;position()&amp;lt;/code&amp;gt; de la librería ''pyautogui'', y para mover el cursor se usa la función &amp;lt;code&amp;gt;moveTo(X,Y)&amp;lt;/code&amp;gt;, siendo X e Y las coordenadas en píxeles horizontales y verticales de la pantalla respectivamente.&lt;br /&gt;
&lt;br /&gt;
La ejecución de este módulo continúa mientras no se reciba una orden de cambio o salir. Mientras la salida se maneja mediante la función &amp;lt;code&amp;gt;quit()&amp;lt;/code&amp;gt; de Python, la de salida del módulo se controla mediante la variable booleana &amp;lt;code&amp;gt;salgo&amp;lt;/code&amp;gt;. Se inicializa en ''false'', y en cada bucle dentro del módulo se controla que lo siga siendo. Una vez que se vuelve verdadera, nunca se entra a ningún bucle y el subprograma finalizará su ejecución.&lt;br /&gt;
&lt;br /&gt;
====Etapas====&lt;br /&gt;
&lt;br /&gt;
Cada etapa está marcada por la variable &amp;lt;code&amp;gt;etapa&amp;lt;/code&amp;gt;, que se modifica al recibir orden de cambio. Entonces, en los bucles de cada etapa además de verificar que no se haya decidido cambiar de módulo se chequea que la etapa no haya cambiado también.&lt;br /&gt;
&lt;br /&gt;
=====Etapa 0 (inicial) y conteo de tiempo de aspirado=====&lt;br /&gt;
&lt;br /&gt;
Durante la etapa 0, el cursor se mantiene quieto. Entonces, se monitorean constantemente los valores de soplido, aspirado y eventos de la interfaz en caso que se presione un botón. Una vez que ocurre uno de estos eventos, se sale de este bucle de obtención de datos y se ejecuta la acción correspondiente.&lt;br /&gt;
&lt;br /&gt;
En el caso del cambio de etapa, se cambia el valor de la variable &amp;lt;code&amp;gt;etapa&amp;lt;/code&amp;gt; por 1, y entonces se pasa a la siguiente. &lt;br /&gt;
&lt;br /&gt;
En el caso de los botones, pasa algo diferente según cuál sea el presionado:&lt;br /&gt;
&lt;br /&gt;
Al presionar ''Guardar'', se llama a la función auxiliar &amp;lt;code&amp;gt;guardarAjustes&amp;lt;/code&amp;gt;, que guarda los ajustes según se describió en la sección correspondiente. Lo mismo pasa con el botón ''Restaurar valores por defecto''. En el caso de ''Cambiar a teclado'', se cambia la variable de cambio de módulo, por lo que finaliza el subprograma y se cambia al módulo teclado. Con ''Guía Morse'' se abre la imagen de guía con el visor determinado del sistema mediante la instrucción &amp;lt;code&amp;gt;subprocess.call(['xdg-open', 'guide.jpg'])&amp;lt;/code&amp;gt;, y con ''Salir'' se sale completamente del programa mediante la orden de Python &amp;lt;code&amp;gt;quit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Al recibir un aspirado se hace click mediante &amp;lt;code&amp;gt;pyautogui.click()&amp;lt;/code&amp;gt;, y se cuenta el tiempo por el que se mantiene el aspirado.&lt;br /&gt;
&lt;br /&gt;
Si se recibe un soplido, se cambia la variable de etapa y se cambia a la siguiente.&lt;br /&gt;
&lt;br /&gt;
'''Conteo de tiempo'''&lt;br /&gt;
&lt;br /&gt;
Al recibir un aspirado, lo primero que se hace es obtener el tiempo actual de ese momento mediante la instrucción &amp;lt;code&amp;gt;time.time()&amp;lt;/code&amp;gt;. Se repiten las instrucciones de hacer click y refrescar los valores de los sensores hasta que se deje de aspirar o pase el tiempo indicado en los ajustes. Una vez que una de estas dos condiciones se rompe, se guarda el tiempo en que ello pasó para poder calcular el tiempo transcurrido. Si es mayor al máximo definido, entonces se cambia la variable de cambio de módulo y se notifica al usuario para que deje de aspirar.&lt;br /&gt;
&lt;br /&gt;
En caso de que este umbral no se superara, no pasaría nada aparte de el o los clicks.&lt;br /&gt;
&lt;br /&gt;
=====Etapa 1 y debouncing=====&lt;br /&gt;
&lt;br /&gt;
La posición del cursor está guardada en dos variables, una para la posición horizontal y otra para la vertical. En esta etapa, el cursor se mueve constantemente a la derecha aumentando la variable de posición horizontal por el valor de velocidad definido en los ajustes. Mientras no se reciba ninguna señal, se realiza este movimiento a la vez que se chequea que la posición en X no haya superado el largo en píxeles menos 1. Si esto ocurre, se cambia la posición horizontal a 0 pero se mantiene la vertical, así volviendo al extremo contrario del monitor.&lt;br /&gt;
&lt;br /&gt;
El ''menos 1'' como límite está porque utilizando esta librería este es el mayor valor que alcanza la variable de posición; si se pusiera el tamaño sin modificar, nunca llegaría a ese valor y quedaría estancado en el borde por siempre. Este mismo problema tuvieron los implementadores del programa anterior de Sip&amp;amp;Puff con Butiá, y también fue encontrado a la hora de desarrollar este programa.&lt;br /&gt;
&lt;br /&gt;
Igualmente que en la etapa anterior, al recibir un aspirado se simula un click y con un soplido se cambia de etapa a través del cambio de la variable &amp;lt;code&amp;gt;etapa&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=====Etapa 2=====&lt;br /&gt;
&lt;br /&gt;
La etapa 2 tiene mayormente el mismo funcionamiento y comportamiento que la etapa 1, siendo la única diferencia que la variable que se cambia es la posición vertical y no horizontal. Ella, al ser aumentada, moverá el cursor hacia abajo, volviendo al borde superior cuando se detecte que se llegó al borde inferior, indicado por el alto en píxeles de la pantalla menos 1.&lt;br /&gt;
&lt;br /&gt;
===Módulo teclado===&lt;br /&gt;
&lt;br /&gt;
====Previo a la ejecución====&lt;br /&gt;
&lt;br /&gt;
En el módulo teclado, como ya fue explicado en su sección correspondiente, los caracteres se ingresan mediante código Morse. Un soplido equivale a un guión y un aspirado a un punto. A medida que se envían estas señales se va construyendo la secuencia Morse, que al terminar el tiempo definido en los ajustes se convertirá a un caracter o instrucción especial mediante el uso del diccionario ''morse'' contenido en ''dicts.py''. Esta secuencia se guarda en una cadena de texto llamada &amp;lt;code&amp;gt;resSecuencia&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Igual que en el módulo mouse, lo primero que se hace al cambiar de módulo es actualizar el texto estático, para que los contenidos sean justamente los de este módulo. Además, se obtiene el ajuste de ''timeout'' entre letra y letra y se lo almacena en una variable llamada &amp;lt;code&amp;gt;tiempoChar&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
De la misma manera, la orden de cambio de módulo es dada por la variable booleana &amp;lt;code&amp;gt;salgo&amp;lt;/code&amp;gt;, verificada en todos los bucles para no entrar a ellos si es verdadera. El bucle principal del módulo se ejecuta de forma constante, siempre y cuando ella sea falsa.&lt;br /&gt;
&lt;br /&gt;
====Ingreso de caracteres y medición de tiempo====&lt;br /&gt;
&lt;br /&gt;
Como fue mencionado antes, el tiempo almacenado en los ajustes se guarda en la variable &amp;lt;code&amp;gt;tiempoChar&amp;lt;/code&amp;gt;. Entonces, en el bucle principal, mediante el uso de la librería &amp;lt;code&amp;gt;time&amp;lt;/code&amp;gt; se obtiene el tiempo inicial y se calcula el final con la variable antes mencionada.&lt;br /&gt;
&lt;br /&gt;
Mientras no se haya alcanzado el tiempo final se monitorean los sensores de botón de soplido y aspirado hasta que uno de ellos obtenga el valor 1.&lt;br /&gt;
&lt;br /&gt;
Al recibir un aspirado, se agrega un punto a la secuencia, se reproduce el sonido de punto Morse, se cambia la secuencia visual mostrada en la interfaz y se esperan 0.95 segundos para volver a recibir otra señal. Esto es implementado con el siguiente código:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if aspiro == 1:&lt;br /&gt;
&lt;br /&gt;
	#Agrego a la secuencia Morse		&lt;br /&gt;
	resSecuencia = (resSecuencia + '.')&lt;br /&gt;
&lt;br /&gt;
	#Feedback sonoro&lt;br /&gt;
	playsound('dot.wav')&lt;br /&gt;
&lt;br /&gt;
	#Actualizo el feedback&lt;br /&gt;
	cambiarTextoGUI('_FEEDBACK_',window,resSecuencia)&lt;br /&gt;
&lt;br /&gt;
	#Delay de estabilidad (evita que se registre la aspirada más de una vez)&lt;br /&gt;
	time.sleep(0.95)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para reproducir el sonido se utiliza la librería ''playsound'', que mediante la instrucción playsound(''archivo'') lo abre y reproduce, luego de lo cual el programa continúa su ejecución. Siendo que dura décimas de segundo, esta demora no afecta en lo más mínimo.&lt;br /&gt;
&lt;br /&gt;
En el caso del punto Morse, equivalente al aspirado, el comportamiento es el mismo, salvo que se agrega un guión a la secuencia, se reproduce el archivo ''dash.wav'' y se esperan 0.5 segundos.&lt;br /&gt;
&lt;br /&gt;
====Barra de progreso====&lt;br /&gt;
&lt;br /&gt;
La barra de progreso es un elemento de tipo ''ProgressBar'' de ''PySimpleGUI27''. Es definida con un valor máximo, que en este caso es el tiempo entre letra y letra definido entre los ajustes. Se actualiza mediante la instrucción &amp;lt;code&amp;gt;window.Element(''clave'').UpdateBar(''valor'')&amp;lt;/code&amp;gt;; a medida que aumenta el valor, más llena estará la barra.&lt;br /&gt;
&lt;br /&gt;
Entonces, mientras no se haya acabado el tiempo se va llenando la barra de progreso mediante las siguientes líneas:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
window.Element('__PROGRESS__').UpdateBar(contador)&lt;br /&gt;
contador = contador + 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Al final del tiempo quedará llena. La variable &amp;lt;code&amp;gt;contador&amp;lt;/code&amp;gt; se inicializa en &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; al principio del bucle de conteo de tiempo, por lo que la barra se vaciará automáticamente al comenzar a contarlo nuevamente.&lt;br /&gt;
&lt;br /&gt;
====Simulación de caracteres y comandos especiales====&lt;br /&gt;
&lt;br /&gt;
Una vez que se termina el tiempo, se evalúa si la longitud de la secuencia es menor a 7, mediante la orden &amp;lt;code&amp;gt;len(resSecuencia)&amp;lt;/code&amp;gt;, quien devuelve el número de caracteres en ella. Si es mayor, simplemente se cambia el texto de equivalencia en la interfaz por la palabra ''Cancelado'' y se vuelve al bucle de ingreso de señales Morse. &lt;br /&gt;
&lt;br /&gt;
Si no fue cancelado, entonces se traduce la secuencia a caracteres con el diccionario Morse contenido en ''dicts.py''. Los diccionarios en Python son equivalencias &amp;quot;clave-&amp;gt;valor&amp;quot;, siendo en este caso la clave la secuencia Morse y el valor cada caracter o acción correspondiente. Entonces, se puede obtener el valor a partir de la clave con la función &amp;lt;code&amp;gt;get(''clave'')&amp;lt;/code&amp;gt;. En este caso, se guarda en la variable &amp;lt;code&amp;gt;resCaracter&amp;lt;/code&amp;gt; el valor con la instrucción &amp;lt;code&amp;gt;resCaracter = dicts.morse.get(resSecuencia)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Si la secuencia no equivale a nada, esa variable tomará el valor especial ''None''. &lt;br /&gt;
&lt;br /&gt;
Luego se vacía la secuencia ingresada en la interfaz y se muestra el caracter o acción correspondiente al que equivale.&lt;br /&gt;
&lt;br /&gt;
=====Mayúsculas=====&lt;br /&gt;
&lt;br /&gt;
El bloqueo de mayúsculas está almacenado en la variable &amp;lt;code&amp;gt;mayus&amp;lt;/code&amp;gt;, que se inicializa en 1 al entrar al módulo y se puede cambiar a 0 ingresando la secuencia de cambio (---.). Un 1 equivale a activado y un 0 a desactivado.&lt;br /&gt;
&lt;br /&gt;
En el diccionario todas las letras están en mayúsculas. Por lo tanto, luego de verificar que la secuencia ingresada corresponde a un caracter o acción válido, si el bloqueo de mayúsculas está desactivado este caracter se pasará a minúsculas mediante la función &amp;lt;code&amp;gt;lower()&amp;lt;/code&amp;gt;. Cabe destacar que aunque los símbolos no tienen esta propiedad, si se llama la función sobre ellos no pasará nada, por lo que es completamente válido hacer esto en su caso.&lt;br /&gt;
&lt;br /&gt;
=====Ingreso de caracteres normales=====&lt;br /&gt;
&lt;br /&gt;
Los caracteres normales son todos aquellos que no son comandos especiales del programa (como EOM, MAYUS, GUÍA o SALIR) y tampoco pertenecen al conjunto de los caracteres especiales (Ñ, &amp;quot;, Á, É, Í, Ó, Ú). El programa verifica si &amp;lt;code&amp;gt;resCaracter&amp;lt;/code&amp;gt; pertenece a alguno de ellos. Si no lo está, entonces simula su presión en el teclado físico mediante &amp;lt;code&amp;gt;press(resCaracter)&amp;lt;/code&amp;gt;, acción perteneciente a la librería ''pyautogui''.&lt;br /&gt;
&lt;br /&gt;
Es importante remarcar que esta acción recibe ciertos comandos especiales pertenecientes a teclas de función, como pueden ser Enter, Esc, Borrar, etc. Ellos también pueden pasarse como parámetro a la función ''press'', quien simulará la presión de estas teclas y no ingresará la secuencia de sus caracteres; por ejemplo, &amp;lt;code&amp;gt;press('return')&amp;lt;/code&amp;gt; presiona la tecla Enter y no escribe literalmente la palabra &amp;quot;''return''&amp;quot;. La lista de posibles teclas que se pueden ingresar mediante esta función se pueden ver en [https://pyautogui.readthedocs.io/en/latest/keyboard.html#keyboard-keys la siguiente página]. Se podrían agregar teclas adicionales al módulo teclado asignando una secuencia Morse no utilizada a otra de las teclas listadas en ella.&lt;br /&gt;
&lt;br /&gt;
=====Ingreso de caracteres especiales=====&lt;br /&gt;
&lt;br /&gt;
Los caracteres especiales no disponibles para ingresar mediante la función &amp;lt;code&amp;gt;press&amp;lt;/code&amp;gt; son, como fue mencionado anteriormente, &amp;lt;code&amp;gt;Ñ, &amp;quot;, Á, É, Í, Ó y Ú&amp;lt;/code&amp;gt;. Ellos están incluidos en el diccionario &amp;lt;code&amp;gt;cEsp&amp;lt;/code&amp;gt; (de caracteres Especiales) incluido en el archivo ''dicts.py''. Cuando el programa identifica que &amp;lt;code&amp;gt;resCaracter&amp;lt;/code&amp;gt; pertenece a él, los ingresa de una forma alternativa: copia el caracter al portapapeles con &amp;lt;code&amp;gt;pyperclip.copy&amp;lt;/code&amp;gt; y lo pega simulando Ctrl-V mediante &amp;lt;code&amp;gt;pyautogui.hotkey(&amp;quot;ctrl&amp;quot;,&amp;quot;v&amp;quot;)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Esto se hace mediante:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pyperclip.copy(resCaracter)&lt;br /&gt;
pyautogui.hotkey(&amp;quot;ctrl&amp;quot;,&amp;quot;v&amp;quot;)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sin embargo, no es una solución perfecta, pues se borra el contenido del portapapeles y solo sirve para aquellos programas donde se puede pegar con esta combinación. Aún así, para la mayoría de los casos funciona y no debería haber problema.&lt;br /&gt;
&lt;br /&gt;
=====Acciones especiales del programa=====&lt;br /&gt;
&lt;br /&gt;
Hay valores correspondientes a secuencias Morse que equivalen a ciertas acciones internas del programa. Ellas son, y como fue mencionado anteriormente, EOM, MAYUS, GUIA y SALIR. El programa revisa también si &amp;lt;code&amp;gt;resCaracter&amp;lt;/code&amp;gt; pertenece a alguna de esas opciones, y si esto se cumple se ejecutará la acción correspondiente a cada una.&lt;br /&gt;
&lt;br /&gt;
Además, según si el bloqueo de mayúsculas está activado o no, estas órdenes se recibirán escritas en mayúsculas o minúsculas. Esto no hace diferencia en ninguno de los casos menos en el comando de bloqueo de mayúsculas. Si se recibe 'mayus', entonces él está desactivado y se activa. De la misma manera, haber recibido 'MAYUS' significa que está encendido y se debe desactivar. Según el caso, al recibir la orden se asigna el valor '0' o '1' a la variable &amp;lt;code&amp;gt;mayus&amp;lt;/code&amp;gt; según si se desactiva o activa respectivamente.&lt;br /&gt;
&lt;br /&gt;
En el caso de la apertura de la guía Morse, se abre la imagen que la contiene con la instrucción &amp;lt;code&amp;gt;subprocess.call(['xdg-open', 'guide.jpg'])&amp;lt;/code&amp;gt;, igual que en el módulo mouse. Lo mismo ocurre con la orden de salir, donde se cierra el programa con la función de Python &amp;lt;code&amp;gt;quit()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
En el caso de EOM, se cambia la variable de cambio de módulo &amp;lt;code&amp;gt;salgo&amp;lt;/code&amp;gt; a ''True'', lo que hará que no se ingrese a ningún bucle y se cambie de subprograma.&lt;br /&gt;
&lt;br /&gt;
==Trabajo a futuro==&lt;br /&gt;
&lt;br /&gt;
Este programa, aunque cumple su cometido y es completamente funcional, tiene aspectos aún pendientes de agregar que de así hacerlo, lo volverían mucho más completo y mejoraría su uso para los usuarios.&lt;br /&gt;
&lt;br /&gt;
Algunos de estos aspectos son:&lt;br /&gt;
&lt;br /&gt;
* Cerrar o minimizar ventanas con secuencias Morse&lt;br /&gt;
* Añadir combinaciones de teclas (ej: Ctrl-C, Shift-1, etc.)&lt;br /&gt;
* Más ajustes, por ejemplo desactivar el bloqueo de mayúsculas por defecto o desactivar/cambiar el volumen del feedback sonoro&lt;br /&gt;
* Deshabilitar botones visualmente al entrar al modo teclado, para indicar que no tienen funcionalidad hasta cambiar de módulo&lt;br /&gt;
* Cambiar aspirado por soplido sostenido para pasar del módulo mouse a teclado, para evitar hacer clicks innecesarios&lt;br /&gt;
* Agregar click derecho&lt;br /&gt;
* Copiar y pegar según indicaciones del usuario&lt;br /&gt;
* Permitir ingresar caracteres especiales sin tener que recurrir al copiado y pegado&lt;br /&gt;
* Poner más símbolos y teclas especiales en el módulo teclado&lt;br /&gt;
* Permitir recargar ajustes al guardarlos sin tener que reiniciar el programa&lt;br /&gt;
* Añadir valores por defecto personalizados dentro del programa; por ejemplo, agregando un botón en la sección de ajustes llamado &amp;quot;Marcar como valores por defecto&amp;quot;, y que al restaurar los valores por defecto se carguen ellos en vez de los estáticos definidos en el programa actual. Una posibilidad es almacenarlos en ''settings.json'', así como los ajustes actuales.&lt;br /&gt;
* Combinar todo en un solo ejecutable, para así facilitar su uso. Por ejemplo, mediante el uso de &amp;lt;code&amp;gt;PyInstaller&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Cada uno de estos aspectos tiene su complejidad asociada, y hay algunos más simples de implementar que otros. Sin embargo, todos aportan su parte y harían el uso de este programa más enriquecedor y conveniente.&lt;br /&gt;
&lt;br /&gt;
==Reflexiones finales==&lt;br /&gt;
&lt;br /&gt;
Se ha creado un programa con el que se aspira a que usuarios incapaces de manejar un equipo informático de forma convencional por limitaciones físicas puedan comenzar a hacerlo. De esta forma, y como fue mencionado al principio de esta entrada, se busca universalizar el acceso a herramientas computacionales mediante la accesibilidad, para así abrir las puertas de ellas a cada vez más personas, dado su creciente uso en la vida cotidiana.&lt;br /&gt;
&lt;br /&gt;
Este programa no es perfecto, y siempre tendrá cosas a corregir o mejorar. Sin embargo, lo que ya está funciona; y él también busca ser una ''chispa iniciadora'' a más proyectos de este tipo, como lo fue el de Sip&amp;amp;Puff con Butiá original en su momento para este proyecto.&lt;br /&gt;
&lt;br /&gt;
Por lo tanto, cualquier persona que desee mejorarlo, agregarle módulos o modificarlo es más que bienvenido, y siendo de hardware y software abierto esto es completamente posible y realizable. El código disponible en [https://gitlab.fing.edu.uy/santiago.freire/SipAndPuff4Butia GitLab] tiene multitud de comentarios que, agregados con esta entrada, permiten una comprensión mucho mayor de lo que ocurre internamente en el programa y ayuda a hacer cualquier tipo de cambio.&lt;br /&gt;
&lt;br /&gt;
Cualquier consulta, duda, sugerencia o aporte se pueden comunicar con el autor original de este programa mediante el correo electrónico disponible en la sección ''Autor''.&lt;br /&gt;
&lt;br /&gt;
==Enlaces==&lt;br /&gt;
&lt;br /&gt;
*Código fuente: [https://gitlab.fing.edu.uy/santiago.freire/SipAndPuff4Butia https://gitlab.fing.edu.uy/santiago.freire/SipAndPuff4Butia]&lt;br /&gt;
*Proyecto anterior de Sip and Puff con Butiá: [https://www.fing.edu.uy/inco/proyectos/butia/mediawiki/index.php/Accesibilidad https://www.fing.edu.uy/inco/proyectos/butia/mediawiki/index.php/Accesibilidad]&lt;br /&gt;
&lt;br /&gt;
==Autor==&lt;br /&gt;
&lt;br /&gt;
*Santiago Freire López - [mailto://santiago.freire@fing.edu.uy santiago.freire@fing.edu.uy]&lt;br /&gt;
==Tutores==&lt;br /&gt;
&lt;br /&gt;
*Daniel Larrosa&lt;br /&gt;
*Guillermo Trinidad&lt;br /&gt;
*Gonzalo Tejera&lt;br /&gt;
&lt;br /&gt;
==Descargo de responsabilidad==&lt;br /&gt;
&lt;br /&gt;
''Este programa es de estricto uso educativo. Prohibido su uso en sistemas o situaciones donde esté en juego la salud o integridad física de una persona. Consulte con su médico.''&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
''Este contenido está distribuido bajo licencia GNU Free Documentation License. Para el programa y código fuente véase el archivo LICENSE disponible en el repositorio [https://gitlab.fing.edu.uy/santiago.freire/SipAndPuff4Butia GitLab].''&lt;/div&gt;</summary>
		<author><name>Sfreirelp</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Butia_gol</id>
		<title>Butia gol</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Butia_gol"/>
				<updated>2021-06-19T15:58:22Z</updated>
		
		<summary type="html">&lt;p&gt;Bbrandino: /* Descripción del Proyecto */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Archivo:robots_pelota.png|x150px ]]&lt;br /&gt;
&lt;br /&gt;
== Descripción del Proyecto ==&lt;br /&gt;
Este proyecto tiene como objetivo que cualquier persona, sin necesidad de saber robótica o programación, pueda aprender sobre robótica, utilizando el Robot Butiá (visitar [https://www.fing.edu.uy/inco/proyectos/butia/ Proyecto Butiá] para más información). El objetivo de este proyecto será diseñar un robot simple que juegue al fútbol, al cual le pasaremos la pelota y la devolverá ([https://youtu.be/TGaE0nHiIBI video butiá jugando al fútbol])&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;youtube&amp;gt; TGaE0nHiIBI &amp;lt;/youtube&amp;gt;&amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En este proyecto veremos:&lt;br /&gt;
* Un tutorial básico de robótica, donde veremos todos los elementos que componen a un robot, en particular al Robot Butiá y cómo funcionan. También veremos cómo armar el robot&lt;br /&gt;
* Un tutorial básico de programación, que será necesario para que nuestro robot funcione&lt;br /&gt;
* Tutoriales de ejercicios simples para aprender a usar el robot&lt;br /&gt;
* Un tutorial del ejercicio final, donde haremos que el robot juegue al fútbol (como en el video)&lt;br /&gt;
&lt;br /&gt;
== Materiales necesarios ==&lt;br /&gt;
* Kit del Robot Butiá&lt;br /&gt;
** Incluyendo un sensor de distancia, un botón y un sensor de grises&lt;br /&gt;
* Computadora o XO con [https://valijas.ceibal.edu.uy/recurso/111 TurtleBots] instalado (es posible consultar una guía de instalación de TurtleBots [https://www.fing.edu.uy/inco/proyectos/butia/mediawiki/index.php/TortuBots#Instalaci.C3.B3n aquí])&lt;br /&gt;
* Cartulina blanca y negra&lt;br /&gt;
* Una pelota&lt;br /&gt;
&lt;br /&gt;
== Tutoriales ==&lt;br /&gt;
* Tutorial de Robótica Básica: [[Archivo:Robotica_Basica_ButiaGol.pdf ]]&lt;br /&gt;
* Tutorial de Programación Básica: [[Archivo:Programacion_Basica_ButiaGol.pdf ]]&lt;br /&gt;
* Tutoriales de ejercicios simples, para aprender a usar los sensores:  [[Archivo:Ejercicios_Sensores_ButiaGol.pdf ]]&lt;br /&gt;
* Tutorial del ejercicio final, donde hacemos que el Butiá juegue al fútbol:  [[Archivo:Ejercicio_Final_ButiaGol.pdf ]]&lt;/div&gt;</summary>
		<author><name>Bbrandino</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Buti%C3%A1_en_el_huerto_escolar</id>
		<title>Butiá en el huerto escolar</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Buti%C3%A1_en_el_huerto_escolar"/>
				<updated>2021-06-16T19:12:12Z</updated>
		
		<summary type="html">&lt;p&gt;Nataliawpr: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Introducción''' &lt;br /&gt;
&lt;br /&gt;
Este proyecto se enmarca en la unidad curricular “Taller de robótica educativa con el robot Butiá”, cursado en el primer semestre del 2021.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Antecedentes y justificación&lt;br /&gt;
'''&lt;br /&gt;
&lt;br /&gt;
En varias de las escuelas urbanas y rurales de nuestro país (al menos 45 en Montevideo) se lleva a cabo el trabajo en huertas, consideradas por el CEIP como una herramienta para el cultivo de valores y conductas proactivas, al mismo tiempo que motivan al trabajo en equipo, promoviendo la cooperación, la solidaridad y la tolerancia.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
En estos proyectos o actividades de huertas escolares el vínculo con la programación es limitado. Desde mi formación y experiencias personales he observado que la relación entre robótica y agroecología no solo es posible sino con mucho potencial a desarrollar. &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Objetivos del trabajo &lt;br /&gt;
'''&lt;br /&gt;
&lt;br /&gt;
Teniendo en cuenta el contexto descrito, la intención del proyecto es poder generar una base de insumos que incentive el uso de la robótica como herramienta didáctica, para entender y buscar soluciones agroecológicas aplicadas a las realidades de los huertos escolares.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Más sobre el proyecto'''&lt;br /&gt;
&lt;br /&gt;
Presentación: [[Medio: Butia_huerto_escolar.pdf]]&lt;br /&gt;
&lt;br /&gt;
Informe: [[Medio: Proyecto_final.pdf]]&lt;/div&gt;</summary>
		<author><name>Nataliawpr</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Alimentador_autom%C3%A1tico_para_macotas</id>
		<title>Alimentador automático para macotas</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Alimentador_autom%C3%A1tico_para_macotas"/>
				<updated>2021-06-15T20:10:55Z</updated>
		
		<summary type="html">&lt;p&gt;Micarodriguez2001: /* Construcción de la estructura */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Archivo:Presentacion.jpg|200px]]&lt;br /&gt;
&lt;br /&gt;
== Introducción ==&lt;br /&gt;
&lt;br /&gt;
Este proyecto fue motivado pensando en las personas que tienen mascotas pero que por distintos motivos no están siempre en la casa para alimentar a sus macotas en el horario que corresponde. También sirve para adultos muy mayores o personas con problemas de movilidad.&lt;br /&gt;
Trae como beneficio que es de gran utilidad para cualquier persona que tenga mascotas, pues permite alimentarlas sin hacer un gran esfuerzo. Además ayuda a que tu mascota agarre el habito de comer siempre en un mismo horario.&lt;br /&gt;
&lt;br /&gt;
La idea es hacer un alimentador que alimente automáticamente siempre en los mismos horarios (definidos previamente).&lt;br /&gt;
Además se le podrían añadir más funcionalidades útiles, entre ellas esta dar un mensaje al dueño avisándole cuando quede poca comida y tenga que recargar, o dar la posibilidad de que el dueño le dé un pequeño “premio” a su mascota en cualquier horario, si es deseado, solo apretando un botón.&lt;br /&gt;
&lt;br /&gt;
== Materiales == &lt;br /&gt;
*Kit robótico butia que incluya un motor, un sensor de distancia, un sensor de grises y un botón&lt;br /&gt;
*Computadora portátil con Python o turtleBots instalado. &lt;br /&gt;
*Cables&lt;br /&gt;
*Pote de comida para mascotas&lt;br /&gt;
*Cinta aisladora blanca o negra&lt;br /&gt;
*Marcador&lt;br /&gt;
*Tijeras y trincheta&lt;br /&gt;
*Pegamento &lt;br /&gt;
*Bidon de 5 o 6 litros&lt;br /&gt;
*Bandejas o platos descartables de poliestireno&lt;br /&gt;
*Cartón&lt;br /&gt;
*Papel blanco o negro&lt;br /&gt;
*Bandas elásticas&lt;br /&gt;
*Rollo de papel higiénico&lt;br /&gt;
*Hilo grueso o cuerdas&lt;br /&gt;
*Taco fischer, lapicera o cilindro pequeño&lt;br /&gt;
*Regla&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
El pegamento que se utilizo fue silicona fría, pero pueden ser otros mientras no arruinen el material que estamos pegando. Como se puede ver todos los materiales (menos el kit butia) son reciclados así no implica un gasto extra y además les damos un buen uso a cosas que podemos encontrar en nuestra casa&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Planificación de la estructura ==&lt;br /&gt;
Diseñaremos un alimentador que permita pasar la comida tapando y destapando un orificio. La tapa debería girar con ayuda del motor sobre un eje que este a un borde para poder permitir el paso de la comida.&lt;br /&gt;
La imagen es una ilustración de como se movería.&lt;br /&gt;
El motor esta dibujado en rojo, la tapa en negro y el alimentador en gris.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:Plat.png]]&lt;br /&gt;
&lt;br /&gt;
Dado que la comida ejerce peso sobre la tapa y estamos usando materiales reciclados, controlaremos que no se deforme y cierre mal (debido a que cambia el ángulo) mediante un sensor de grises.&lt;br /&gt;
La tapa será blanca y  tendrá una parte negra a la que el sensor debe apuntar cuando este cerrado. De esta manera si termina de alimentar y el sensor no detecta esa parte negra significa que no cerro del todo y seguirá girando la tapa hasta encontrarla (también esta la alternativa de hacer la tapa negra con una marca blanca).&lt;br /&gt;
&lt;br /&gt;
==Construcción de la estructura==&lt;br /&gt;
&lt;br /&gt;
'''Paso 1:''' Desarmado del kit&lt;br /&gt;
&lt;br /&gt;
Tomar nuestro robot butia y sacarle la rueda a uno de los motores.&lt;br /&gt;
Luego terminar de quitar el motor sacando los tornillos que lo sujetaban&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c1.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 2:''' &lt;br /&gt;
&lt;br /&gt;
Sacar la plataforma que tenia la placa quitando los tornillos que la sujetaban con el resto del robot butia.&lt;br /&gt;
Si conectamos el motor con la placa se vería como en la foto:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c2.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 3:''' Contenedor del alimentador&lt;br /&gt;
&lt;br /&gt;
Tomar un bidón de 5 litros vacío y cortarle la parte de abajo con trincheta a unos 4 cm de la base del bidón aproximadamente, aquí depositaremos las comida.&lt;br /&gt;
&lt;br /&gt;
En la foto se muestra el bidón antes de ser cortado:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c3.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 4:''' (Opcional)&lt;br /&gt;
&lt;br /&gt;
Tomar un  pequeño cilindro que tenga un hueco de aproximadamente 5 milímetros de diámetro donde el motor entre y quede ajustado. Este cilindro es el que estará pegado luego a la tapa del alimentador.&lt;br /&gt;
&lt;br /&gt;
En este caso usamos un taco Fischer y le cortamos con trincheta una parte. &lt;br /&gt;
&lt;br /&gt;
[[Archivo:c4.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
'''Alternativas:'''&lt;br /&gt;
Se pueden desarmar lapiceras que ya no anden y usar la parte cilíndrica, cortándola un poco.&lt;br /&gt;
En general cualquier cilindro hueco que sea un poquito mas grande y quede flojo se puede pegar con pegamento al motor, lo importante que quede ajustado y así cuando se mueva el motor mueva el cilindro.&lt;br /&gt;
&lt;br /&gt;
Si no se consigue un cilindro adecuado podemos saltar este paso, y pegar el motor directamente a la tapa del alimentador.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 5:''' Tapa del alimentador&lt;br /&gt;
&lt;br /&gt;
Trazar en una bandeja descartable de poliestireno o cartón una circunferencia de 6 cm de diámetro aproximadamente y recortar con tijera.&lt;br /&gt;
&lt;br /&gt;
#Si el material no es muy rígido trazar otra y pegar ambas circunferencias con pegamento.&lt;br /&gt;
#Si el material de nuestra tapa es blanco o negro dejarlo así, sino cortar una circunferencia de papel blanco o negro y pegarla a la tapa. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c5.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
A un centímetro aproximadamente de un borde de nuestra tapa hacemos un pequeño tajo del tamaño del diámetro del cilindro que colocamos en el motor.&lt;br /&gt;
Luego colocamos el cilindro con el motor por el tajo y pegamos con pegamento.&lt;br /&gt;
&lt;br /&gt;
Colocar cinta aisladora (o papel) del color opuesto a nuestra tapa en un costado como se ve en la imagen. Esto es para que el sensor de grises detecte el cambio y pueda corroborar que quede bien cerrado una vez alimente.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 6:''' (Opcional)&lt;br /&gt;
&lt;br /&gt;
Tomar un cilindro del tamaño de la boca de nuestro bidón, puede ser el rollo del papel higiénico. Este será el conector entre el motor y el contenedor de comida.&lt;br /&gt;
Para darle más rigidez se puede cortar un un rectángulo de una bandeja de plástico de la altura del cilindro y   perímetro de la base para colocarlo dentro.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c6.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 7:''' Unir todo&lt;br /&gt;
&lt;br /&gt;
Unir el motor con banditas elásticas a nuestro cilindro o pegándolo con pegamento de modo que la tapa quede rozando el cilindro. Luego colocar el  otro lado del cilindro en la boca del bidón y pegarlo con pegamento para que no se mueva&lt;br /&gt;
&lt;br /&gt;
Alternativa: Si decidieron no usar el cilindro se puede pegar directamente el motor con el bidón pero no puede quedar torcido, por eso se recomienda seguir el paso anterior&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Así se vería todo unido:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c7.jpg|300px]] [[Archivo:c8.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
Observar que es importante que la cinta negra que pusimos en la tapa debe queda del lado opuesto al rollo papel higiénico. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 8:''' &lt;br /&gt;
&lt;br /&gt;
Encontrar una estructura donde podamos atar el alimentador (también puede pegarse) y que queda a una distancia de aproximadamente el ancho de la plataforma del kit butia (pues lo podremos en sentido vertical en los siguientes pasos) más 2 centímetros.&lt;br /&gt;
Se recomienda que sea en una esquina.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c9.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 9:''' &lt;br /&gt;
&lt;br /&gt;
Sacarle la otra rueda y motor a la estructura del butia y colocarle el sensor de grises como se ve en la imagen.&lt;br /&gt;
Colocarlo en sentido vertical contra la pared, junto a donde esta el alimentador.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c10.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Así se vería con el pote de comida abajo incluido.&lt;br /&gt;
Notar que el sensor de grises queda a aproximadamente dos centímetros de la tapa si tomamos bien las medidas.&lt;br /&gt;
Verificar que el led del sensor apunte a la parte negra de la tapa. &lt;br /&gt;
&lt;br /&gt;
[[Archivo:c11.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 10:''' &lt;br /&gt;
&lt;br /&gt;
Atar la estructura que tiene a la placa al costado del bidón y asegurarse que quede bien sujeta.&lt;br /&gt;
&lt;br /&gt;
Aclaración: Esta posición es considerando que los cables que tenemos no son muy largos y tiene que llegar a conectar todos los sensores que usemos, con cables mas largos podría estar en otro lado.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c12.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 11:''' Conectar todo&lt;br /&gt;
&lt;br /&gt;
Traer la computadora portátil y colocarla de modo que llegue a conectarse con la placa.&lt;br /&gt;
Traer la fuente, colocarla en el suelo y conectarla con la placa.&lt;br /&gt;
Terminar de conectar el motor y el sensor de grises con la placa.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Así quedaría todo conectado!&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c13.jpg|300px]]&lt;br /&gt;
[[Archivo:c14.jpg|300px]]&lt;br /&gt;
[[Archivo:c15.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
Verificar que el led del sensor de gris apunte a la parte oscura: &lt;br /&gt;
&lt;br /&gt;
[[Archivo:c16.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hasta aquí hemos armado la estructura de un alimentador básico que alimente cada cierto periodo de tiempo, pero para añadirle mas funcionalidades como que alimente cuando lo indico con un botón o que me avise cuando queda poca comida debemos añadirle mas sensores! &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 12:''' &lt;br /&gt;
&lt;br /&gt;
Tomar un cartón o plato descartable que usaremos como parte superior del alimentador.&lt;br /&gt;
Aquí atornillaremos el sensor de distancia.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c17.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
Y así quedaría puesto en la parte superior del alimentador y conectado a la placa.&lt;br /&gt;
Por ultimo conectamos un botón a la placa, con un cable suficientemente largo podemos colocar el botón en un lugar a específico nuestro alcance.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c18.jpg|300px]] [[Archivo:c19.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 13:''' (Opcional)&lt;br /&gt;
&lt;br /&gt;
Podemos hacer dos líneas con marcador en el bidón para señalizar determinadas cantidades de comida.&lt;br /&gt;
#La línea mas abajo es el limite, por lo que si el sensor de distancia detecta menos comida que esa línea debe notificar.&lt;br /&gt;
#La línea mas arriba es para cuando quiero que el alimentador vuelva a funcionar con normalidad porque ya recargue suficiente comida.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:c20.jpg|300px]]&lt;br /&gt;
&lt;br /&gt;
==Planificación del código ==&lt;br /&gt;
Haremos dos códigos distintos, uno más simplificado y otro más complejo.&lt;br /&gt;
&lt;br /&gt;
El código mas simple será en TurtleBots: en este el alimentador alimentara cada cierto periodo de tiempo (aproximadamente 3 horas) ya que no tenemos tanto manejo del tiempo. Este código es de prueba, y se detendrá cada vez que detecte poca comida.&lt;br /&gt;
&lt;br /&gt;
El código mas complejo y completo será en Python, en el cual el alimentador alimente en ciertas horas que elija. Este código se ajusta más a la realidad ya que el programa quedaría andando continuamente (si queda poca comida espera a recarguen y sigue ejecutando) y alimentando de manera adecuada.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Antes de empezar el código es importante tomar las siguientes medidas:&lt;br /&gt;
*En que valor del sensor distancia detecta que queda poca comida (poner comida en el alimentador hasta la línea de más abajo y anotar valor del sensor).&lt;br /&gt;
*En que valor del sensor distancia detecta que ya se recargo suficiente comida (poner comida en el alimentador hasta la línea de más arriba y anotar valor del sensor).&lt;br /&gt;
*En que valor del sensor gris detecta el negro de la tapa para verificar que este cerrado.&lt;br /&gt;
&lt;br /&gt;
==Código==&lt;br /&gt;
===En TurtleBots===&lt;br /&gt;
&lt;br /&gt;
¿Que debemos programar?&lt;br /&gt;
&lt;br /&gt;
*Un programa principal que verifique si hay suficiente comida, de no ser así que notifique con un mensaje y que  alimente cada cierto periodo de tiempo y cuando se lo indique presionando el botón.&lt;br /&gt;
*Una función alimentar que mueva el motor para dejar pasar la comida.&lt;br /&gt;
*Una función VerificarComida que avise al dueño cuando queda poca comida.&lt;br /&gt;
&lt;br /&gt;
'''Paso 1:'''&lt;br /&gt;
&lt;br /&gt;
El primer paso es agregar las extensiones señaladas en la siguiente imagen y reiniciar TurtleBots para que se actualice.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:t1.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 2:''' Crear función alimentar&lt;br /&gt;
&lt;br /&gt;
Tomamos una caja de acción y la llamamos alimentar.&lt;br /&gt;
Dentro de la caja movemos el motor para un lado y luego para asegurarnos de que quede cerrado lo movemos para el otro hasta que el sensor de gris detecte el negro (medida que tomamos previamente).&lt;br /&gt;
&lt;br /&gt;
[[Archivo:t2.png|300px]]&lt;br /&gt;
&lt;br /&gt;
ADVERTENCIA! Los valores de la velocidad en la que debe moverse el motor o cuanto debe esperar pueden variar dependiendo de la estructura del alimentador&lt;br /&gt;
Si estos valores no funcionan, hay que probar subiendo o bajando la velocidad, aumentando o disminuyendo el tiempo de espera, hasta que el alimentador deje pasar la cantidad de comida que deseamos.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 3:''' Crear función VerificarComida&lt;br /&gt;
&lt;br /&gt;
Una vez el valor tomado previamente cuando hay poca comida, tomamos una caja de acción y la llamamos VerificarComida.&lt;br /&gt;
Dentro de la caja colocamos un if que ejecute un determinado código si el valor del sensor de distancia es mayor a la muestra tomada (o sea que hay poca comida) .&lt;br /&gt;
&lt;br /&gt;
[[Archivo:t3.png|300px]] [[Archivo:t4.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Si queda poca comida debemos ser notificados, por lo que adentro del if debemos desplegar en pantalla una señal de que queda poca comida y hay que recargar&lt;br /&gt;
Además cambiamos el valor de una variable hayComida a 0 ya que no queda mucha.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 4:''' Crear programa principal&lt;br /&gt;
&lt;br /&gt;
Primero guardamos un 1 en la variable hayComida para indicarle al programa que mientras haya comida siga ejecutando.&lt;br /&gt;
Para ello usamos un while y una vez comience llamamos a la función alimentar.&lt;br /&gt;
Además cada vez que alimentemos debemos asegurarnos de llamar a la función VerificarComida.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Una vez que alimentamos repetimos el siguiente código:&lt;br /&gt;
Si el botón es apretado debe alimentador y luego verificar si queda poca comida.&lt;br /&gt;
Luego espera 1 segundo y sigue repitiendo.&lt;br /&gt;
&lt;br /&gt;
Si queremos que alimente cada aproximadamente 3 horas debemos repetirlo 10800 veces (1 hora = 3600 segundos, 3 horas = 10800 segundos).&lt;br /&gt;
&lt;br /&gt;
'''Programa completo:'''&lt;br /&gt;
&lt;br /&gt;
[[Archivo:t5.png|300px]]&lt;br /&gt;
&lt;br /&gt;
Observar que una vez termina vuelve a alimentar si es que hay comida.&lt;br /&gt;
Si apretamos el botón en medio de esas 3 horas la próxima alimentación va a tardar un poco más (ya que alimentar toma un par de segundos extras).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== En Python ===&lt;br /&gt;
&lt;br /&gt;
Diseñaremos el código del alimentador pensándolo como una maquina de estados, donde tendría 3 estados abierto (cuando la tapa deja pasar comida), cerrado (cuando la tapa impide el paso de comida)  y sin comida (un caso particular del cerrado sumado a que no puede “abrirse” para alimentar ya que no hay comida)&lt;br /&gt;
&lt;br /&gt;
'''Estado cerrado:'''&lt;br /&gt;
Lo primero que deberíamos hacer es verificar que haya comida y si no es así, pasar al estado sin  comida y notificar.&lt;br /&gt;
Si hay comida y se detecta que alguien apretó el botón o llego la hora de alimentar, deberíamos alimentar y pasar al estado abierto.&lt;br /&gt;
&lt;br /&gt;
'''Estado abierto:'''&lt;br /&gt;
Lo único que debemos hacer aquí es cerrar cuando termine de alimentar y pasar a estado cerrado.&lt;br /&gt;
&lt;br /&gt;
'''Estado sin comida:'''&lt;br /&gt;
Este estado debería revisar continuamente si ya se recargo suficiente comida y una vez esto pase volver al estado cerrado y avisar que hay comida.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:maquina.png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diagrama de los estados que especifica transiciones de un estado a otro.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 1:''' Importar librerías&lt;br /&gt;
&lt;br /&gt;
Librerias de manejo del tiempo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
import datetime&lt;br /&gt;
&lt;br /&gt;
from datetime import datetime&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Libreria sys y Pybot necesarias para el butia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
sys.path.insert(0,'/home/osboxes/Activities/TurtleBots.activity/plugins/butia/')&lt;br /&gt;
&lt;br /&gt;
from pybot import usb4butia&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
asegurarse que dentro del sys.path.insert coloquemos bien la ruta donde se encuentren los plugings del butia.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Generamos una instancia de la placa butia:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
robot = usb4butia.USB4Butia()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 2''': Declarar variables&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt;horas de alimentacion:&lt;br /&gt;
&lt;br /&gt;
hora1= 11&lt;br /&gt;
&lt;br /&gt;
hora2= 21&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Horas de alimentación: En este caso declaramos dos horarios de alimentación (se pueden añadir todos los deseados) y nos basamos en que se alimenta puntual en minuto 0 y segundo 0, pero se puede editar haciendo una nueva variable “minuto1” y asignándole un valor, análogo para minuto2, etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt;distancias &lt;br /&gt;
&lt;br /&gt;
maximadistancia= 50500 &lt;br /&gt;
&lt;br /&gt;
distanciaadecuada= 40000&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Distancias: En la variable distaciamaxima colocamos el valor que tomamos previamente del sensor cuando queda poca comida (línea más abajo), mientras que en la variable distanciaadecuada colocamos el valor medido de la línea más arriba (cuando consideramos que cargo suficiente comida).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;#&amp;lt;/nowiki&amp;gt;Posibles estados: abierto, cerrado y sin comida&lt;br /&gt;
&lt;br /&gt;
estado = &amp;quot;cerrado&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Posibles estados: Declaramos la variable estado y le asignamos cerrado que debería ser el estado inicial, suponiendo que el programa empieza a ejecutarse con comida en el alimentador.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
haycomida= True&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Variable haycomida: inicializada en true por la misma suposición anterior.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 3:''' Función alimentar()&lt;br /&gt;
&lt;br /&gt;
Análoga a TurtleBots.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     def Alimentar():&lt;br /&gt;
        robot.set2MotorSpeed(0, 90, 0, 90)&lt;br /&gt;
        time.sleep(1.2)&lt;br /&gt;
        robot.set2MotorSpeed(0,0, 0, 0)&lt;br /&gt;
        time.sleep(0.6)&lt;br /&gt;
        robot.set2MotorSpeed(1, 90, 1, 90)&lt;br /&gt;
        time.sleep(1.2)&lt;br /&gt;
        g = robot.getGray(6)&lt;br /&gt;
        while g&amp;lt;=18000:&lt;br /&gt;
            robot.set2MotorSpeed(1, 100, 1, 100)&lt;br /&gt;
            g= robot.getGray(6)&lt;br /&gt;
        robot.set2MotorSpeed(0,0, 0, 0)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 4:''' Función verificarComida()&lt;br /&gt;
&lt;br /&gt;
Análoga a TurtleBots.&lt;br /&gt;
&lt;br /&gt;
    def VerificarComida(maximadistancia):&lt;br /&gt;
       d = robot.getDistance(5) &lt;br /&gt;
       if d &amp;gt;= maximadistancia:&lt;br /&gt;
           global estado&lt;br /&gt;
           global haycomida&lt;br /&gt;
           estado= &amp;quot;sin comida&amp;quot;&lt;br /&gt;
           print &amp;quot;ALERTA: Queda poca comida!!&amp;quot;&lt;br /&gt;
           haycomida= False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Paso 4:''' programa principal&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        now = datetime.now()&lt;br /&gt;
        if estado==&amp;quot;cerrado&amp;quot;:&lt;br /&gt;
             VerificarComida(maximadistancia)&lt;br /&gt;
             if haycomida == True:&lt;br /&gt;
                 if(now.hour==hora1 or now.hour==hora2) and now.minute == 0 and now.second==0:&lt;br /&gt;
                     estado= &amp;quot;abierto&amp;quot;&lt;br /&gt;
                     Alimentar()&lt;br /&gt;
                 b = robot.getButton(4) &lt;br /&gt;
                 if (estado == &amp;quot;cerrado&amp;quot; and b==1):&lt;br /&gt;
                     estado== &amp;quot;abierto&amp;quot;&lt;br /&gt;
                     Alimentar()&lt;br /&gt;
         elif estado==&amp;quot;abierto&amp;quot;:&lt;br /&gt;
              estado= &amp;quot;cerrado&amp;quot;&lt;br /&gt;
         elif estado== &amp;quot;sin comida&amp;quot;:&lt;br /&gt;
              d = robot.getDistance(5) &lt;br /&gt;
              if d &amp;lt;= distanciaadecuada: &lt;br /&gt;
                  estado= &amp;quot;cerrado&amp;quot;&lt;br /&gt;
                  haycomida= True&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Como podemos ver nuestro programa sigue el diagrama de la maquina de estados, que nos ayudo a organizar mejor el comportamiento de nuestro alimentador.&lt;br /&gt;
&lt;br /&gt;
Una observación es que en el estado abierto no se hace nada más que cambiar al estado cerrado ya que la función alimentar(), invocada en el estado cerrado, se encarga de cerrar correctamente una vez termina de alimentar. Si no fuera así deberíamos revisar con el sensor de grises que quede bien cerrado antes de cambiar de estado.&lt;br /&gt;
&lt;br /&gt;
== Pruebas ==&lt;br /&gt;
&lt;br /&gt;
=== Alimentando en la hora correspondiente ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://youtu.be/eSAJmQF-Yqk &amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Alimentando aprentando el botón ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt; https://youtu.be/BEU6HuE0KH4 &amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===  ¿Qué pasa si hay poca comida? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt; https://youtu.be/Z4-NmrpfEsk &amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Apretando el botón tres veces ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt; https://youtu.be/-BgXIoUxWvg &amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Trabajo a futuro ==&lt;br /&gt;
Como se puede ver en los videos a veces las pastillas se trancan y por lo tanto dejan de caer un poco antes de que el alimentador cierre del todo. Esto no es un gran problema ya que como se puede apreciar en el ultimo video, donde se aprieta tres veces el botón, a pesar de trancarse cuando yo vuelvo a alimentar vuelven a salir más pastillas, por lo que sigue funcionando correctamente. &lt;br /&gt;
Sin embargo este problema ocasiona que caigan distintas cantidades de pastillas cada vez que alimente. Para mejorar el comportamiento del alimentador y solucionar el problema podemos hacer las siguientes mejoras: &lt;br /&gt;
&lt;br /&gt;
# Colocar otro motor dentro del alimentador para que mueva las pastillas continuamente cuando esta alimentando (y así no se trancan). De esta manera nos aseguramos que sale siempre la misma cantidad de pastillas, pues alimenta siempre en un mismo periodo de tiempo.&lt;br /&gt;
# Observando que el problema se origina porque las pastillas son un poco grandes para la boca del alimentador, otra posible solución es usar un alimentador con boca más grande. Lo complicado es encontrar un objeto más grande reciclado.&lt;br /&gt;
&lt;br /&gt;
Más allá de este punto, otras mejoras al alimentador podrían ser:&lt;br /&gt;
&lt;br /&gt;
#Uso de materiales más resistentes o rígidos para que la salida de pastillas cuando alimente sea más uniforme.&lt;br /&gt;
#Cables más largos para colocar el botón en un lugar más accesible y tener la libertad de tener la placa y la computadora portátil más lejos.&lt;br /&gt;
&lt;br /&gt;
== Autor ==&lt;br /&gt;
&lt;br /&gt;
Micaela Rodríguez - [mailto://micaela.rodriguez.dores@fing.edu.uy micaela.rodriguez.dores@fing.edu.uy]&lt;br /&gt;
&lt;br /&gt;
== Tutores ==&lt;br /&gt;
*Guillermo Trinidad&lt;br /&gt;
*Gonzalo Tejera&lt;/div&gt;</summary>
		<author><name>Micarodriguez2001</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Alimentador</id>
		<title>Alimentador</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Alimentador"/>
				<updated>2021-06-15T20:01:24Z</updated>
		
		<summary type="html">&lt;p&gt;Micarodriguez2001: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
== Introducion ==&lt;br /&gt;
aa&lt;/div&gt;</summary>
		<author><name>Micarodriguez2001</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Sip%26Puff4Buti%C3%A1</id>
		<title>Sip&amp;Puff4Butiá</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Sip%26Puff4Buti%C3%A1"/>
				<updated>2021-06-15T18:21:05Z</updated>
		
		<summary type="html">&lt;p&gt;Sfreirelp: Página reemplazada por «Esta página ha sido migrada a [http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Sip%26Puff4Buti%C3%A1_-_Haciendo_la_computaci%C3%B3n_m%C3%A1s_accesible h...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Esta página ha sido migrada a [http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Sip%26Puff4Buti%C3%A1_-_Haciendo_la_computaci%C3%B3n_m%C3%A1s_accesible http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Sip%26Puff4Buti%C3%A1_-_Haciendo_la_computaci%C3%B3n_m%C3%A1s_accesible]&lt;/div&gt;</summary>
		<author><name>Sfreirelp</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Horus</id>
		<title>Horus</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Horus"/>
				<updated>2021-06-15T17:30:11Z</updated>
		
		<summary type="html">&lt;p&gt;Federico.gil: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Resumen ==&lt;br /&gt;
&lt;br /&gt;
Motivados por la falta de herramientas que permitan la accesibilidad a personas con capacidades motoras reducidas, decidimos desarrollar una herramienta multipropósito que permita diversas aplicaciones, desde una silla de ruedas hasta controlar un mouse, todo esto mediante la detección de la dirección en el que se mira. Para esto diseñamos y entrenamos una red neuronal convolucional que clasifica las direcciones: derecha, izquierda, centro y los ojos cerrados. A partir de esto se le pueden dar infinidad de usos a esta herramienta, la cual alcanzó resultados muy satisfactorios, con una tasa de acierto de más del 98%. Para fines demostrativos haremos una analogía entre controlar una silla de ruedas y controlar el robot butiá. En el siguiente documento incluimos una breve introducción a los conceptos de redes neuronales, convolucionales y distintas métricas, también incluiremos los resultados obtenidos, así como una guía para su replicación e implementación. Adicionalmente, se creó un material audiovisual en el que explicamos brevemente las  bases teóricas y en detalle la utilización de esta herramienta para el control del robot Butiá.  &lt;br /&gt;
&lt;br /&gt;
== Motivación ==&lt;br /&gt;
&lt;br /&gt;
Motivados por la falta de accesibilidad que presentan las personas con reducciones motoras importantes y ante la falta de herramientas que lo permitan, surgió la idea de desarrollar un sistema que permita controlar al robot Butiá, utilizando movimientos oculares. Para este proyecto, saber a qué dirección está mirando una persona es una tarea complicada, hay muchas maneras de hacerlo, y en este caso, decidimos embarcarnos en una aventura en el mundo de la inteligencia artificial con el objetivo de poder desarrollar una herramienta multiuso de código abierto que resuelva el problema. Esta herramienta podrá dar lugar a muchos futuros proyectos, ya que podríamos pensar que este problema es análogo a controlar una silla de ruedas mediante los ojos, para personas con reducciones motores severas, o controlar cualquier otro sistema programable. Para fines demostrativos utilizaremos esta herramienta para mover al robot Butiá.&lt;br /&gt;
&lt;br /&gt;
== Introducción a la Inteligencia Artificial ==&lt;br /&gt;
&lt;br /&gt;
Seguro que muchas veces nos preguntamos ¿Las máquinas piensan?, esta idea de máquinas artificiales capaces de “pensar” surge de hace muchos años y da lugar al término Inteligencia Artificial o IA, y hace referencia a cualquier software que puede replicar capacidades humanas, para tareas específicas o más amplias, este comportamiento nos hace creer que las máquinas pueden pensar aunque no tengan neuronas físicas como los humanos. Este concepto, aunque muchas veces es difícil de detectar, aparece muchas veces en las aplicaciones que utilizamos día a día, como por ejemplo, cuando queremos ver una película, seguro que la aplicación nos recomienda películas similares a las que nos gusta, es decir, aprendió nuestros gustos, o cuando queremos hacernos una foto y aparece un recuadro en nuestra cara, ¿cómo el sistema conoció que ahí hay una cara?. Cada día, estos sistemas “inteligentes” tienen más impacto en nuestra vida y las máquinas superan al hombre al reconocer patrones en imágenes u comportamientos repetitivos&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img2.jpg]]&lt;br /&gt;
&lt;br /&gt;
Seguro que si vemos esta foto, fácilmente podríamos identificar que hay un rostro de una persona, esto es porque podemos detectar la presencia de algunos elementos que conforman un rostro: ojos, boca, nariz, etc.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img3.jpg]]&lt;br /&gt;
&lt;br /&gt;
Y repetimos este procedimiento para cada uno de los elementos ¿cómo sabemos qué es un ojo y qué no?. Seguramente nuestro cerebro detectó pupilas, pestañas, superficies blancas, porque somos capaces de detectar estos patrones y texturas. Pero reproducir el procedimiento que nuestro cerebro realiza sobre las imágenes en una máquina es mucho más difícil, primero tenemos que definir lo que queremos que la IA resuelva, es decir,  tener un problema, que puede ser tan complejo como queramos y luego de esto, tener una muestra muy grande de entradas del problema y su respuesta con lo que la máquina podrá aprender. Para distintos problemas, existen distintos tipos de redes neuronales que lo resuelven, en nuestro caso, cuando el problema es reconocer patrones en imágenes, las redes neuronales convolucionales es la mejor opción.&lt;br /&gt;
&lt;br /&gt;
=== Red Neuronal Convolucional ===&lt;br /&gt;
&lt;br /&gt;
Una red neuronal convolucional o CNN está diseñada para replicar todo el proceso que mencionamos anteriormente, es decir, hay un procesamiento por pasos, en las primeras capas se identifican los elementos básicos y generales, y en posteriores capas esto se combina (convolucionando) para detectar patrones más complejos.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img4.jpg]]&lt;br /&gt;
&lt;br /&gt;
En la imágen anterior, así como lo haría una CNN, podemos detectar patrones en los píxeles de una imágen, y saber que cada píxel tiene dependencia con sus píxeles vecinos.&lt;br /&gt;
Esta red se caracteriza por aplicar un tipo de capa donde se realizan operaciones matemáticas conocidas como convoluciones, una convolución aplicada sobre los píxeles de una imágen, se colocarán filtros sobre la imágen original para obtener un píxel nuevo en base a sus vecinos, ya que, como mencionamos, necesitamos establecer qué dependencia tienen los píxeles con los que tiene a su lado y detectar un patrón. &lt;br /&gt;
Para entenderlo un poco mejor, esto es similar a los filtros que aplicamos en nuestras fotos en aplicaciones de edición que utilizamos: desenfoque, colores más vivos, pasar a blanco y negro, etc. Le damos una imágen de entrada, y nos devuelve una imagen con filtros.&lt;br /&gt;
&lt;br /&gt;
Sigue el siguiente procedimiento:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img5.jpg]]&lt;br /&gt;
[[Archivo:horus_img6.jpg]]&lt;br /&gt;
[[Archivo:horus_img7.jpg]]&lt;br /&gt;
&lt;br /&gt;
Cambiando los valores del filtro, podemos realizar distintos efectos, como el desenfoque:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img8.jpg]]&lt;br /&gt;
&lt;br /&gt;
Escaneando con distintos filtros, podemos encontrar un filtro que, al hacer los cálculos, el píxel resultante se active (píxel blanco) cuando encuentre el patrón que queremos buscar. Puede detectar cosas diferentes según cuáles sean los valores del filtro que definamos, pero esto no es nuestra tarea, la red automáticamente irá aprendiendo poco a poco para ir haciendo mejor su tarea. Probar distintos filtros y aprenderlos es el trabajo principal de estas redes neuronales convolucionales. Esto es lo que hace una capa de convolución de una CNN, hay una imagen de entrada, aplica filtros, y sale otra imagen. Pero este proceso se puede repetir muchas veces, y que luego de esta capa, la salida de la anterior sea la entrada de la siguiente.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img9.jpg]]&lt;br /&gt;
&lt;br /&gt;
Secuencialmente podremos aplicarlo las veces que queramos, pero esto va a depender del problema que nos enfrentemos, en general, mientras más complejo sea, más capas necesitaremos. Las salidas de cada capa convolucional son lo que llamamos mapas de características o de activación (es lo que observamos en la Imágen 9 entre capa y capa), son todas las imágenes que resultaron de aplicar filtros a la imagen de entrada, la cantidad de filtros puede ser muy grande en cada capa, resultando de muchas imágenes por cada entrada.&lt;br /&gt;
&lt;br /&gt;
=== Max Pooling ===&lt;br /&gt;
&lt;br /&gt;
Cada vez la operación de convolución se va haciendo más potente, detectando patrones cada vez más avanzados según la información de la foto. Esto, además, es algo que además podemos incentivar reduciendo cada cierto tiempo la resolución de nuestro mapa de características, estas reducciones son conocidas como max pooling.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img10.jpg]]&lt;br /&gt;
&lt;br /&gt;
En el ejemplo, aplicando un max pooling de 2x2, observamos que se queda con el valor más alto de ese cuadrado, dando como resultado una imagen más chica. Entonces, en resumen, las capas convolucionales van haciendo detecciones o activaciones sobre las detecciones anteriores, componiendo cada vez patrones más complejos, teniendo en cuenta esto, podemos observar que si la red es muy compleja necesitará hacer muchos cálculos para entrenar por la cantidad de cuentas que tiene, y en el mayor de los casos se debe tener un buen poder de cómputo para que el entrenamiento sea rápido. Cuando la imagen pase por todas la capas de convoluciones, si el entrenamiento fue eficaz, va a reconocer los patrones necesarios y ahora sí es posible pasar a la siguiente etapa, meter los resultados como entrada en una red neuronal de capas densas que acabará por tomar la decisión de que es lo que hay en esa imágen.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img11.jpg]]&lt;br /&gt;
&lt;br /&gt;
La entrada de esta etapa será una imágen aplanada, y la capa de salida es lo que detectó. Si por ejemplo queremos probar un modelo previamente entrenado para que detecte perros y gatos, al mandarle de entrada la imágen de un perro, probablemente la salida de esa red sea “perro”, ya que fue la categoría en la que metió a la imagen.&lt;br /&gt;
&lt;br /&gt;
Durante el entrenamiento esta red de neuronas guarda valores internos, y tiene que ir probando muchas combinaciones para ver cuál de estas combinaciones detecta mejor. Para que la red conozca si está aprendiendo o no también debemos alimentarla con un banco de imágenes que llamamos imágenes de validación o test (que generalmente representa un 20% de las imágenes totales, el otro 80% son imágenes de entrenamiento), las cuales ya están categorizadas, la red toma cada una, predice lo que hay y luego compara con la categoría real, repite este procedimiento hasta tener el mayor porcentaje de aciertos que pueda o tantas epochs como se le pida, este parámetro define el número de veces que la red va a ver las imágenes de entrenamiento en su totalidad. Pero en un modelo ya entrenado, estos valores ya están calculados y nuestro único trabajo será darle una imágen de entrada, y su respuesta probablemente sea una buena detección si la entrada fue algo que la red conoce, pero puede fallar, y esto simplemente depende del buen o mal entrenamiento que tuvo la red. Si la red solo conoce caras, al colocarle una imágen de un perro, no sabrá que hacer y probablemente reconozca una cara donde no la hay.&lt;br /&gt;
&lt;br /&gt;
=== Matriz de Confusión ===&lt;br /&gt;
&lt;br /&gt;
Durante la fase de test también puede pasar que al darle una imágen con una cara, el modelo no la detecta, es decir, el modelo se confunde, para esto podemos construir una matriz de confusión, una herramienta que permite la visualización del desempeño de un modelo.&lt;br /&gt;
&lt;br /&gt;
Para entender la semántica de esta matriz, observemos la matriz de ejemplo que aparece a continuación: de 8 gatos reales, el sistema predijo que 5 eran gatos y 3 eran perros; y de 6 perros, el sistema predijo que uno era un conejo y dos eran gatos. A partir de la matriz se puede ver que el sistema tiene problemas distinguiendo entre perros y gatos, pero que puede distinguir razonablemente bien entre conejos y otros animales.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img12.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Arquitectura del sistema ==&lt;br /&gt;
&lt;br /&gt;
Como mencionamos, queremos detectar la orientación de los ojos y con eso tomar una decisión sobre el Robot, para esto, decidimos dividir el problema en partes:&lt;br /&gt;
#Cómo detectar la cara.&lt;br /&gt;
#Cómo detectar los ojos.&lt;br /&gt;
#Detectar la orientación de los ojos.&lt;br /&gt;
#Comandar el robot según la orientación.&lt;br /&gt;
&lt;br /&gt;
Para cumplir con la parte 1, 2 y 3, necesitaremos obtener una red que detecta rostros, luego otra para que detecte ojos y luego otra para detectar la posición a la que está mirando, cada una tiene una tarea distinta. Pero esto implica una tarea muy difícil y puede llevar mucho tiempo, por eso utilizaremos modelos ya entrenados. A continuación un diagrama que explica esto con mayor claridad:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img13.jpg]]&lt;br /&gt;
&lt;br /&gt;
Dónde face cascade es la primera red, la cual recibe una imagen y extrae el rostro de ella, luego se la envía a la segunda red (eye cascade), especialista en detectar ojos. A continuación, esta red le pasa los ojos con un tamaño estandarizado de 128x128 a nuestra red (ya que sólo fue entrenada con datos de este tamaño) con el fin de detectar en qué dirección se está mirando. Finalmente se toma la decisión de en qué dirección mover el robot Butiá.&lt;br /&gt;
Para utilizar la tercera red, que fue entrenada para este proyecto, no es necesario volver a pasar por el proceso de entrenamiento, como mencionamos en la parte teórica, un modelo ya entrenado guarda los valores, es por esto que dejamos nuestro modelo entrenado a disposición para todos, lo único que necesitaremos es cargarlos en nuestro programa y darle imágenes de entradas acordes a lo que fue entrenada.&lt;br /&gt;
&lt;br /&gt;
== Arquitectura de nuestra red ==&lt;br /&gt;
&lt;br /&gt;
A continuación un diagrama que explicita la arquitectura que utilizamos en nuestra red, entrenada para detectar posicionamientos de ojos, la cual consta de las siguientes capas:&lt;br /&gt;
Convolución de 32 filtros de un tamaño de 16x16.&lt;br /&gt;
Max Pooling de tamaño 4x4.&lt;br /&gt;
Convolución de 16 filtros de un tamaño de 8x8.&lt;br /&gt;
Max Pooling de tamaño 4x4.&lt;br /&gt;
Aplanado de imágen a un tamaño de 400.&lt;br /&gt;
Dropout de 256 neuronas.&lt;br /&gt;
Capa densa de 256 neuronas.&lt;br /&gt;
Capa final o capa de salida con las 4 categorías que queremos detectar.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img132.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Recolección de datos ==&lt;br /&gt;
&lt;br /&gt;
Para entrenar CNN´s hacen falta grandes volúmenes de datos, por lo cual decidimos pedir la ayuda de 20 voluntarios, los cuales se grabaron durante 10 segundos mirando en cada una de las siguientes direcciones:&lt;br /&gt;
&lt;br /&gt;
*Centro&lt;br /&gt;
*Derecha&lt;br /&gt;
*Izquierda&lt;br /&gt;
*Arriba&lt;br /&gt;
*Abajo&lt;br /&gt;
*Cerrados&lt;br /&gt;
&lt;br /&gt;
Cada uno de estos videos fue procesado en las dos primeras capas de nuestra arquitectura, es decir la capa de detección facial y la de detección de los ojos, estos ojos fueron guardados en carpetas, luego se procedió a la eliminación de imagenes mal formadas o que no fueran ojos, luego se los clasificó según la dirección en la que se miraba.&lt;br /&gt;
Fueron extraídas, procesadas y clasificadas: 14.610 imágenes en total, de las cuales 11.775 imágenes fueron para el set de entrenamiento (80% del total), y 2.835 imágenes para el set de validación. (20% del total). Cada una de estas imágenes tiene una dimensión de 128x128 pixeles y está en escala de grises.&lt;br /&gt;
Entrenamiento&lt;br /&gt;
Para la etapa de entrenamiento es posible modificar diversos valores que harán que el modelo final se comporte distinto los cuales son la cantidad de épocas o la cantidad de imágenes, entre otros. Dentro de los parámetros a considerar también están los parámetros de cada capa en sí: tamaño de los filtros, cantidad, entre otros que fueron nombrados anteriormente.&lt;br /&gt;
&lt;br /&gt;
Tras muchos modelos entrenados con muchos parámetros distintos y diferentes cantidades de imágenes y tamaños de las mismas, los parámetros que arrojaron el mejor resultado fueron los descritos en la sección de arquitectura de nuestra red, con 10 épocas.&lt;br /&gt;
&lt;br /&gt;
Para el entrenamiento de nuestro sistema, pues nuestras computadoras no son tan potentes, decidimos utilizar Google Colab pues acelera el proceso de entrenamiento exponencialmente, tomándole menos de un minuto por epoch.&lt;br /&gt;
Se deja a disposición todo el código utilizado para el entrenamiento en el repositorio del proyecto.&lt;br /&gt;
Los primeros modelos entrenados no parecían tener buenos resultados, por lo cual, empezamos un análisis para obtener los mejores resultados. Uno de los cambios que resultaron más importantes en este proceso fue la eliminación de las categorías arriba y abajo, ya que estas podían presentar confusiones para el modelo y bajar mucho la precisión del modelo resultante.&lt;br /&gt;
Como podemos observar en el ejemplo de abajo, a veces incluso para un humano es difícil distinguir estos casos.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img14.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Resultados de la mejor red ==&lt;br /&gt;
&lt;br /&gt;
Después de muchos entrenamientos, probando distintos parámetros y analizando resultados, obtuvimos una red con la que estamos satisfechos y que tiene muy buenas predicciones al pasarle una imágen de un ojo en alguna de las direcciones entrenadas.&lt;br /&gt;
Para observar qué tan bien se comporta nuestro modelo definitivo, decidimos visualizar su precisión y tasa de aciertos.&lt;br /&gt;
&lt;br /&gt;
=== Accuracy y loss ===&lt;br /&gt;
Como podemos apreciar en en el primer set de graficas, al paso de los epochs, la precisión aumenta a la vez que la pérdida (loss) disminuye, a pesar de los picos en el segundo y séptimo epoch. Si bien obtuvimos gráficos donde existe una mejor correlación entre la función de pérdida y la precisión, como en el segundo set de graficos, los resultados finales de precisión y pérdida son mejores en la primera, así como los recall por categoría que estudiaremos en la siguiente sección.&lt;br /&gt;
&lt;br /&gt;
En síntesis, obtuvimos una precisión de 99,64% sobre el set de entrenamiento y una precisión de 99,33% sobre el set de validación.&lt;br /&gt;
&lt;br /&gt;
Respecto a la velocidad de muestreo que podemos obtener, en sobre 10.000 muestras, el modelo predice en un tiempo de aproximadamente 32 ms por muestra. Pero si tomamos en cuenta las capas previas del sistema (las capas de las redes provistas por OpenCV), este tiempo asciende a 45 ms en promedio. Lo cual se traduce en una tasa de muestreo de unas 22 muestras por segundo,&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img15.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Matriz de confusión ==&lt;br /&gt;
&lt;br /&gt;
La matriz de confusión para nuestro modelo es la mostrada a continuación.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img16.jpg]]&lt;br /&gt;
&lt;br /&gt;
Como mencionamos anteriormente, la matriz de confusión nos ayuda a detectar errores en el modelo pues que podemos apreciar con que frecuencia se confunde dos categorías dadas. Y como podemos apreciar, en nuestro modelo la tasa de acierto no solo es alta sino que la confusión es muy baja, clasifica correctamente más del 98% de las veces.&lt;br /&gt;
&lt;br /&gt;
== Mapas de características ==&lt;br /&gt;
&lt;br /&gt;
Un aspecto interesante sobre las CNN´s es que podemos ver cuales son los filtros que la red está aplicando, dichos filtros aplicados una imagen de entrada se llaman feature maps, o mapas de características en español, en los que podemos visualizar que es lo que ve nuestra red neuronal, como un intento de interpretar cómo funciona nuestra red.&lt;br /&gt;
Consideremos la siguiente imagen de entrada:&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img17.jpg]]&lt;br /&gt;
&lt;br /&gt;
De la cual para cada capa podemos apreciar los feature maps.&lt;br /&gt;
&lt;br /&gt;
=== Primera convolución ===&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img18.jpg]]&lt;br /&gt;
&lt;br /&gt;
En la cual podemos observar lo que para nosotros es claro que es un ojo en uno de los filtros aplicados.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img19.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Primer Max Pooling ===&lt;br /&gt;
[[Archivo:horus_img20.jpg]]&lt;br /&gt;
&lt;br /&gt;
De la cual el modelo toma las características más importantes para pasar a la siguiente capa.&lt;br /&gt;
&lt;br /&gt;
=== Segunda convolución ===&lt;br /&gt;
&lt;br /&gt;
[[Archivo:horus_img21.jpg]]&lt;br /&gt;
&lt;br /&gt;
De la que ya no quedan rastros de lo que una vez fue un ojo.&lt;br /&gt;
&lt;br /&gt;
== Implementar Sistema Predictor ==&lt;br /&gt;
&lt;br /&gt;
Para implementar todo el sistema de detección, utilizamos Python 3 sobre una máquina con Windows, la máquina que tendrá la webcam y con ella enviar señales al robot Butiá. &lt;br /&gt;
&lt;br /&gt;
Como mencionamos anteriormente utilizaremos de ayuda algunas librerías para cargar modelos entrenados y procesado de imágenes. &lt;br /&gt;
&lt;br /&gt;
Algunas librerías  requieren ser instaladas previamente, estas son:&lt;br /&gt;
*numpy&lt;br /&gt;
*tensorflow&lt;br /&gt;
*openCV (que es cv2)&lt;br /&gt;
&lt;br /&gt;
Para realizar la instalación, debemos abrir una terminal en una máquina con Python instalado e introducir el comando: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
pip install &amp;lt;nombre de la librería&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los demás no necesitan ser instalados ya que son nativos en Python. Todos los recursos necesarios como los modelos pre-entrenados en formato .h5 y .xml pueden encontrarse en el archivo comprimible adjunto a este documento y deben estar en la misma carpeta del .py que se va a implementar a continuación. Recomendamos leer los comentarios marcados con el formato (#&amp;lt;comentario&amp;gt;) para poder entender paso a paso el procedimiento a seguir, además, en el material audiovisual adjunto construimos paso a paso el predictor.&lt;br /&gt;
&lt;br /&gt;
Lo primero que tenemos que hacer es incluir las librerías que utilizaremos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
import numpy as np&lt;br /&gt;
import cv2&lt;br /&gt;
from keras.models import load_model&lt;br /&gt;
from keras.preprocessing.image import load_img, img_to_array&lt;br /&gt;
import statistics as stat&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cargamos el modulo detector de Rostros.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
predictor_caras = cv2.CascadeClassifier('predictor_caras.xml')&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cargamos el modulo detector de Ojos.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
predictor_ojos = cv2.CascadeClassifier('predictor_ojos.xml')&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cargamos nuestro modelo.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
model = load_model('modelo/modelo_horus.h5')&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Declaramos las dimensiones que tendrán las imágenes con las que trataremos&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
dim = (128,128)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Declaramos la función que predice utilizando nuestro modelo&lt;br /&gt;
&lt;br /&gt;
    def predict(ojos):&lt;br /&gt;
        x = load_img(ojos, target_size=dim)&lt;br /&gt;
        x = img_to_array(x)&lt;br /&gt;
        x = np.expand_dims(x, axis=0)&lt;br /&gt;
        array = model.predict(x)&lt;br /&gt;
        result = array[0]&lt;br /&gt;
        answer = np.argmax(result)&lt;br /&gt;
        return answer&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
Creamos un arreglo de tres elementos para almacenar predicciones de 3 fotogramas continuos, esto servirá para minimizar la cantidad de errores producidos por las primeras dos redes, pues son las que introducen un mayor error (por poca luz, etc). Ya que el modelo tiene probabilidad de equivocarse, al tomar la moda en tres muestras ganaremos certeza y “smoothness”.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
predicciones = [0,0,0]&lt;br /&gt;
&lt;br /&gt;
i = 0&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cargamos la captura de video, “ret” es una variable que indica que se está recibiendo información de la cámara e img es el fotograma actual.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
cap = cv2.VideoCapture(0)&lt;br /&gt;
&lt;br /&gt;
ret, img = cap.read()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mientras se reciba información:&lt;br /&gt;
&lt;br /&gt;
    while ret:&lt;br /&gt;
        #pasamos a grises la imágen recibida por la cámara&lt;br /&gt;
        imagen_en_gris = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)&lt;br /&gt;
        #introducimos el detector de rostros (modelo pre entrenado) y guardamos las coordenadas en la variable &amp;quot;faces&amp;quot;&lt;br /&gt;
        faces = predictor_caras.detectMultiScale(imagen_en_gris, 1.3, 5)&lt;br /&gt;
&lt;br /&gt;
        #para cada una de las caras detectadas (x,y son coordenadas, w ancho y h altura:&lt;br /&gt;
        for (x,y,w,h) in faces:&lt;br /&gt;
    &lt;br /&gt;
            #recortamos la cara de la imágen en gris&lt;br /&gt;
            cara = imagen_en_gris[y:y+h, x:x+w]&lt;br /&gt;
            #introducimos el detector de ojos(modelo pre entrenado) y guardamos las coordenadas en la variable &amp;quot;eyes&amp;quot;&lt;br /&gt;
            eyes = predictor_ojos.detectMultiScale(cara)&lt;br /&gt;
            if len(eyes) == 0:&lt;br /&gt;
                print(&amp;quot;No se detectan Ojos&amp;quot;)&lt;br /&gt;
            else:&lt;br /&gt;
            #nos quedamos con un solo ojo&lt;br /&gt;
                ex,ey,ew,eh = eyes[0]&lt;br /&gt;
	    #recortamos los ojos de la cara&lt;br /&gt;
                ojos = cara[ey:ey+ew,ex:ex+eh]&lt;br /&gt;
	    #reescalamos , mostramos y guardamos la imágen del ojo&lt;br /&gt;
                ojos = cv2.resize(ojos, dim, interpolation = cv2.INTER_AREA)&lt;br /&gt;
                cv2.imshow('img',ojos)&lt;br /&gt;
                cv2.imwrite('ojo.jpg',ojos)&lt;br /&gt;
	    #guardamos en el banco de 3 ultimas predicciones&lt;br /&gt;
                predicciones[i] = predict('ojo.jpg')&lt;br /&gt;
                i+=1&lt;br /&gt;
                if i == 3:&lt;br /&gt;
                    i=0&lt;br /&gt;
	    #stat.mean toma la moda (valor que más se repite) en las predicciones de 3 fotogramas continuos.&lt;br /&gt;
                    print('Prediccion: ',stat.mean(predicciones))&lt;br /&gt;
    #almaceno siguiente fotograma&lt;br /&gt;
    ret, img = cap.read()&lt;br /&gt;
    #Liberamos la captura de video y destruimos las ventanas de visualización&lt;br /&gt;
    cap.release()&lt;br /&gt;
    cv2.destroyAllWindows()&lt;br /&gt;
&lt;br /&gt;
'''Todo el código anterior es posible encontrarlo en los archivos adjuntos. (predictorWebcam.ipynb)'''&lt;br /&gt;
&lt;br /&gt;
== Comunicación con el Butiá ==&lt;br /&gt;
&lt;br /&gt;
Para la comunicación con el robot, la librería de Pybot incluida en el plugin de Butiá, nos permite levantar un servidor desde el robot utilizando Python, servidor que nos conectaremos vía Wi-Fi a través de la máquina cliente, que es la que tiene la webcam y envía señales de dirección en función de lo que el módulo de predicción haya retornado. Para levantar el servidor desde una consola, debemos estar en la carpeta pybot (en la máquina robot) y ejecutar el comando&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
python pybot_server.py DEBUG&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La bandera DEBUG es para ver la salida de lado del servidor (o Butiá).&lt;br /&gt;
&lt;br /&gt;
Cuando se levanta el servidor, podemos conectarnos vía Telnet, una herramienta que nos permite conectarnos a otra máquina y controlarla. Para esto, Python incluye nativamente comandos que nos ayudarán a conectarnos al servidor desde la máquina con la webcam. Esto funciona tanto en Windows como Linux, utilizando Python 3. En el código hay que poner lo siguiente para poder utilizarlo:&lt;br /&gt;
&lt;br /&gt;
    from telnetLib import Telnet&lt;br /&gt;
&lt;br /&gt;
Luego de esto, es posible conectarse mediante la siguiente línea&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
tn =Telnet(“&amp;lt;ip&amp;gt;”,puerto)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
La IP se obtiene mediante el comando ifconfig en la terminal de Linux de la máquina Butiá donde levantamos el servidor y buscamos IPv4, el puerto siempre es 2009.&lt;br /&gt;
&lt;br /&gt;
Luego de esto, puedo mandar comandos de escritura con:&lt;br /&gt;
&amp;lt;code&amp;gt;	&lt;br /&gt;
tn = tn.write(b’&amp;lt;comando&amp;gt;’)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Los comandos posibles los podemos encontrar más detalladamente en la documentación oficial de PyBot &lt;br /&gt;
&lt;br /&gt;
Siguiendo lo mencionado anteriormente realizamos algunas modificaciones leves en el código predictorWebcam.ipynb implementado anteriormente para que en vez de imprimir señales, envíe controles de dirección al robot Butiá.&lt;br /&gt;
&lt;br /&gt;
Puedes enviar los controles que quieras al Butiá, es decir, podemos hacer que al cerrar los ojos me devuelva lo que está leyendo el sensor de distancia o podemos hacer que al cerrar los ojos, el robot frene, esto tiene un abanico grande de posibilidades, todo depende del objetivo del proyecto para lo que quieras utilizar el módulo.&lt;br /&gt;
&lt;br /&gt;
A modo de ejemplo, utilizaremos los 4 comandos que las predicciones nos brindan (centro, cerrado, izquierda y derecha) para mover muy básicamente al Butiá.&lt;br /&gt;
Para esto definimos una función de movimiento que envía señales al servidor en base a la dirección pasada por parámetro (0 = cerrado, 1 = centro, 2  = izquierda, 3 = derecha).&lt;br /&gt;
&lt;br /&gt;
    def mover(tn,direccion):&lt;br /&gt;
        if direccion == 2:&lt;br /&gt;
            tn.write(b'CALL motors setvel2mtr 1 100 0 100')&lt;br /&gt;
        elif direccion == 3:&lt;br /&gt;
            tn.write(b'CALL motors setvel2mtr 0 100 1 100')&lt;br /&gt;
        elif direccion == 0:&lt;br /&gt;
            tn.write(b'CALL motors setvel2mtr 0 0 0 0')&lt;br /&gt;
        elif direccion ==  1:&lt;br /&gt;
           tn.write(b'CALL motors setvel2mtr 0 100 0 100')&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
Y en la sección donde se guarda la predicción, llamamos a esa función:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
direccion = stat.mean(predicciones)&lt;br /&gt;
&lt;br /&gt;
mover(tn,direccion)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
*tn es la conexión via Telnet, inicializada anteriormente como tn = Telnet(“&amp;lt;ip&amp;gt;”,2009)&lt;br /&gt;
&lt;br /&gt;
Estas funcion (mover) se encuentra junto a una función connect en un módulo llamado interfazButiaTelnet.py, y está en los archivos del proyecto.&lt;br /&gt;
Para utilizar nuestro módulo simplemente hay que importarlo:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; import interfazButiaTelnet as Butia &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nuestro módulo interfazButiaTelnet incluye dos funciones &lt;br /&gt;
&lt;br /&gt;
*Butia.connect(HOST,PORT) : Conecta al servidor del Butiá en el host HOST y puerto PORT. (HOST es la ip)&lt;br /&gt;
&lt;br /&gt;
*Butia.mover(TN,DIRECCION) : Envía la señal de mover al robot Butiá según la dirección pasada por parámetro, siempre se mueve a una velocidad de 100.&lt;br /&gt;
&lt;br /&gt;
Los controles pueden ser tan avanzados como se quiera, en este caso es solo un ejemplo, es posible definir la función ‘mover’ de distintas maneras según se ajuste a los objetivos del proyecto que se quiera implementar esta herramienta. &lt;br /&gt;
&lt;br /&gt;
Para la demostración de la implementación de la conexión inalámbrica con Telnet en el predictor también dejamos material audiovisual, y además, el código que utilizamos (predictorWebcamButia.py).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Video tutorial de la implementacion del modulo predictor ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt; https://youtu.be/ZHC5dEjghmY &amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Video del sistema en funcionamiento (control inalambrico) ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;https://youtu.be/5KX_6RteZ-I&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Agradecimientos ==&lt;br /&gt;
&lt;br /&gt;
Agradecimientos especiales a las siguientes personas cuya ayuda fue invaluable para la realización de este proyecto.&lt;br /&gt;
&lt;br /&gt;
*Sara Demov&lt;br /&gt;
*Sofia Suarez&lt;br /&gt;
*Luciano Melonio&lt;br /&gt;
*Natalia Rossi&lt;br /&gt;
*Mariella Teran&lt;br /&gt;
*Paula Soria&lt;br /&gt;
*Matias Landin&lt;br /&gt;
*Micaela Rodriguez&lt;br /&gt;
*Camila Gil&lt;br /&gt;
*Micaela Gelos&lt;br /&gt;
*Judith Cruz&lt;br /&gt;
*Juan Manuel Tassino&lt;br /&gt;
*Agustin Rivero&lt;br /&gt;
*Jonathan Rodriguez&lt;br /&gt;
*Gabriel Gil&lt;br /&gt;
*Franco Montero&lt;br /&gt;
*Facundo Diaz&lt;br /&gt;
*Jose Luis Rodriguez&lt;br /&gt;
&lt;br /&gt;
== Recursos y bibliografía ==&lt;br /&gt;
&lt;br /&gt;
=== Documentación útil ===&lt;br /&gt;
&lt;br /&gt;
*https://pythonprogramming.net/haar-cascade-face-eye-detection-python-opencv-tutorial/&lt;br /&gt;
*https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_righteye_2splits.xml&lt;br /&gt;
*https://www.tensorflow.org/tutorials/images/cnn&lt;br /&gt;
*https://pillow.readthedocs.io/en/stable/reference/Image.html&lt;br /&gt;
*https://www.tutorialkart.com/opencv/python/opencv-python-resize-image/&lt;br /&gt;
*https://www.tensorflow.org/tutorials/keras/classification?hl=es-419&lt;br /&gt;
*https://www.tensorflow.org/tutorials/keras/save_and_load&lt;br /&gt;
 &lt;br /&gt;
=== Recursos audiovisuales útiles ===&lt;br /&gt;
&lt;br /&gt;
*https://www.youtube.com/watch?v=YEZMk1P0-yw&amp;amp;ab_channel=AntoineLam%C3%A9&lt;br /&gt;
*https://www.youtube.com/watch?v=kbdbZFT9NQI&amp;amp;ab_channel=Pysource&lt;br /&gt;
*https://www.youtube.com/watch?v=sYIYQW03BZ8&amp;amp;ab_channel=KrishNaik&lt;br /&gt;
*https://www.youtube.com/watch?v=88HdqNDQsEk&amp;amp;ab_channel=sentdex&lt;br /&gt;
*https://www.youtube.com/watch?v=pDXdlXlaCco&amp;amp;ab_channel=NicholasRenotte&lt;br /&gt;
*https://www.youtube.com/watch?v=yqkISICHH-U&amp;amp;ab_channel=NicholasRenotte&lt;br /&gt;
*https://www.youtube.com/watch?v=7HPwo4wnJeA&amp;amp;ab_channel=codebasics&lt;br /&gt;
*https://www.youtube.com/watch?v=j-3vuBynnOE&amp;amp;ab_channel=sentdex &lt;br /&gt;
*https://www.youtube.com/watch?v=p3CcfIjycBA&amp;amp;list=PLdyfTrNDH-jZo5d7lqaRf3HNrxQGr1v-o&amp;amp;ab_channel=DigitalSreeni&lt;br /&gt;
&lt;br /&gt;
=== Notebooks y repositorios auxiliares ===&lt;br /&gt;
&lt;br /&gt;
*https://colab.research.google.com/drive/1VIhuNYUhFEAFIQl3fKYBSfeZ78dd0neW?authuser=1#scrollTo=5K7yqCjX582S&lt;br /&gt;
*https://github.com/codebasics/deep-learning-keras-tf-tutorial/blob/master/16_cnn_cifar10_small_image_classification/cnn_cifar10_dataset.ipynb &lt;br /&gt;
&lt;br /&gt;
=== Sobre Pooling ===&lt;br /&gt;
&lt;br /&gt;
https://machinelearningmastery.com/pooling-layers-for-convolutional-neural-networks/&lt;br /&gt;
&lt;br /&gt;
=== Sobre el diagramado de CNN ===&lt;br /&gt;
&lt;br /&gt;
https://github.com/gwding/draw_convnet/blob/master/draw_convnet.py&lt;br /&gt;
&lt;br /&gt;
=== Para obtener los feature maps de la red ===&lt;br /&gt;
&lt;br /&gt;
https://towardsdatascience.com/convolutional-neural-network-feature-map-and-filter-visualization-f75012a5a49c&lt;br /&gt;
&lt;br /&gt;
=== Documentación oficial de PyBot ===&lt;br /&gt;
&lt;br /&gt;
https://www.fing.edu.uy/inco/proyectos/butia/mediawiki/index.php/PyBot &lt;br /&gt;
&lt;br /&gt;
=== Repositorio oficial del proyecto ===&lt;br /&gt;
&lt;br /&gt;
https://github.com/Federico-Gil/Horus &lt;br /&gt;
https://gitlab.fing.edu.uy/federico.gil/Horus&lt;br /&gt;
&lt;br /&gt;
== Autores ==&lt;br /&gt;
*Federico Gil, federico.gil@fing.edu.uy, Ingeniería en Computación.&lt;br /&gt;
&lt;br /&gt;
*Facundo Fleitas, facundo.fleitas@fing.edu.uy, Ingeniería en Computación.&lt;br /&gt;
&lt;br /&gt;
== Tutores ==&lt;br /&gt;
*Guillermo Trinidad&lt;br /&gt;
*Gonzalo Tejera&lt;/div&gt;</summary>
		<author><name>Federico.gil</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/WALL-E</id>
		<title>WALL-E</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/WALL-E"/>
				<updated>2021-06-15T14:33:31Z</updated>
		
		<summary type="html">&lt;p&gt;Agustin.rieppi: /* Implementación */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introducción==&lt;br /&gt;
Día a día, el cuidado del medio ambiente resulta cada vez más importante.&lt;br /&gt;
Son muchas las maneras de ayudar con este problema, una de ellas es el reciclado de materiales. Esta es de vital importancia ya que es una forma directa en la que toda la población puede colaborar.&lt;br /&gt;
El reciclaje tiene como objetivo, no solamente reducir los desechos en una sociedad, sino también intenta amainar el uso excesivo de los recursos naturales. Por ejemplo, si se recicla el papel, ayuda a reducir la deforestación.&lt;br /&gt;
&lt;br /&gt;
En la educación, sobre todo en la etapa escolar, es cada vez más utilizada la temática del reciclaje. Esta sirve como primer paso para continuar con otras prácticas de cuidado del medioambiente. &lt;br /&gt;
En Uruguay tambien existen proyectos con el objetivo de generar, desde la primera infancia, concientización sobre el tema; dos ejemplos interesantes son: Repapel [https://repapel.org/] y Proyecto de Vermicompostaje en Primaria [https://montevideo.gub.uy/noticias/medio-ambiente-y-sostenibilidad/ninas-y-ninos-aprenden-a-reciclar-sus-residuos-organicos].&lt;br /&gt;
&lt;br /&gt;
A partir de estas dos puntas surge la motivación de este proyecto: utilizar la robótica para transmitir el mensaje a niños y adolescentes, principalmente a escolares de 5º y 6º o liceales de ciclo básico.&lt;br /&gt;
&lt;br /&gt;
La idea del proyecto es crear un robot clasificador de residuos secos. Para poder realizarlo, se definen 3 tipos de residuos y cada uno es representado por estos 3 colores: negro, gris, y blanco. El robot Butiá, a través de un sensor de grises y un sensor de distancia, detecta e identifica el tipo de residuo. Una vez identificado lleva a él mismo por el carril correspondiente (utilizando un seguidor de linea), habiendo 3 carriles, uno para cada residuo. Una vez que lleva el residuo al final del carril, retorna y vuelve a la posición inicial.&lt;br /&gt;
Para que el robot pueda arrastrar los objetos se le agrega en cada lado de la parte frontal, plaquetas del kit Butiá para ser utilizadas como brazos.&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Archivo:WALLE-Portada.jpg|1000px|center]]&lt;br /&gt;
&lt;br /&gt;
==Materiales==&lt;br /&gt;
*Kit Robótico Butiá [https://www.fing.edu.uy/inco/proyectos/butia/].&lt;br /&gt;
*3 sensores de grises.&lt;br /&gt;
*1 sensor de distancia.&lt;br /&gt;
*Papel blanco, negro y gris.&lt;br /&gt;
*Cartón Duro.&lt;br /&gt;
*Cinta Aisladora Negra.&lt;br /&gt;
*XO/PC con TurtleBots [http://activities.sugarlabs.org/es-ES/sugar/addon/4434].&lt;br /&gt;
&lt;br /&gt;
==Construcción de la Pista==&lt;br /&gt;
En este tutorial la pista será creada usando cinta aisladora negra sobre un piso claro (si se quiere utilizar cinta aisladora blanca sobre un piso oscuro, al final del tutorial se indican las consideraciones a tener).&amp;lt;br /&amp;gt;&lt;br /&gt;
En este caso, la pista que se presenta es con forma de tridente, lo que no implica que no pueda tener otra forma. Lo importante es que se mantengan las barreras perpendiculares en las puntas de cada carril.&amp;lt;br /&amp;gt;&lt;br /&gt;
A continuación se muestra una foto de un ejemplo de pista y sus medidas correspondientes, esto es a modo de guía por lo que las dimensiones pueden variar.&lt;br /&gt;
&lt;br /&gt;
[[Archivo:WALLE-Pista.jpg||450px]]&lt;br /&gt;
&lt;br /&gt;
En caso de que se quiera modificar la pista hay que tener en consideración que todas las intersecciones tienen que ser perpendiculares, esto aplica para la intersección central y para las 4 puntas de la pista. También hay que tener en consideración que el largo de cada tramo sea lo suficientemente grande para que el robot pueda hacer un giro de 180 grados y no irse de él mismo.&lt;br /&gt;
&lt;br /&gt;
==Construcción del Robot==&lt;br /&gt;
'''Armado de módulos:'''&lt;br /&gt;
* Paso 1: Armar el Robot siguiendo la guiá oficial [https://www.fing.edu.uy/inco/proyectos/butia/files/docs_butia2/armando_paso_a_paso_motores_CC_rev1.pdf]&lt;br /&gt;
* Paso 2: Tomar dos barras de encastre y unirlas en forma de T&lt;br /&gt;
[[Archivo:WALLE-FotoPaso2.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
* Paso 3: Agregar 3 tornillos desde la barra blanca y ajustarlos con 3 tuercas&lt;br /&gt;
[[Archivo:WALLE-FotoPaso3.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
* Paso 4: Colocar el sensor de distancia utilizando el lado en el que hay solo un tornillo, luego apretarlo con un tuerca&lt;br /&gt;
[[Archivo:WALLE-FotoPaso4.jpg|400px]]&lt;br /&gt;
|500px&lt;br /&gt;
* Paso 5: Colocar el sensor de grises utilizando el lado que tiene 2 tornillos, luego apretarlo con tuercas&lt;br /&gt;
[[Archivo:WALLE-FotoPaso5.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
* Paso 6: Armar 2 brazos, para cada uno alinear 3 barras de encastre y ajustar cada una con 2 tornillos y tuercas&lt;br /&gt;
[[Archivo:WALLE-FotoPaso6.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
'''Uniendo todo:'''&lt;br /&gt;
* Paso 1: Colocar las 2 barras en forma de T en el centro de la parte delantera, de forma que pueda sensar cualquier objeto que se le presente delante de él. Para este tutorial se usaron los mismos 2 tornillos que fueron utilizados para ajustar la rueda loca.&lt;br /&gt;
[[Archivo:WALLE-FotoPaso2-1.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
* Paso 2: Colocar cada brazo a cada lado de la pieza que se colocó anteriormente, de modo que el objeto que se detecte quede &amp;quot;atrapado&amp;quot; entre ambos brazos. Para este tutorial se utilizan los mismos tornillos usados para ajustar los brazos que para colocar los sensores de grises que se detallan en el siguiente paso.&lt;br /&gt;
* Paso 3: Colocar en la parte delantera los 2 sensores de grises &amp;quot;apuntando&amp;quot; hacia el piso, uno de cada lado del robot (izquierda y derecha). Es importante que la distancia entre ambos sensores sea mayor al ancho de la línea.&lt;br /&gt;
[[Archivo:WALLE-FotoPaso2-2y3.jpg|500px]]&lt;br /&gt;
* Paso 4: Conectar los sensores a los respectivos puertos de la placa Butiá. En este ejemplo:&lt;br /&gt;
   Puerto 1 - Sensor de grises frontal&lt;br /&gt;
   Puerto 2 - Sensor de distancia frontal&lt;br /&gt;
   Puerto 4 - Sensor de grises derecho&lt;br /&gt;
   Puerto 5 - Sensor de grises izquierdo&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A continuación se muestra un video uniendo todas los módulos del robot.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;youtube&amp;gt;LrK_J1g4a9I&amp;lt;/youtube&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Armado del residuo:'''&amp;lt;br /&amp;gt;&lt;br /&gt;
Crear el objeto que represente al residuo, se recomienda crear un cubo con carton, y pegar en cada cara un papel de los siguientes colores; grises, blanco, y negro.&amp;lt;br /&amp;gt;&lt;br /&gt;
El ancho y alto de cada una de las caras debe ser mayor a la altura del robot, para evitar que el robot se tranque con el objeto.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE-FotoResiduo.JPG|500px]]&lt;br /&gt;
&lt;br /&gt;
==Implementación==&lt;br /&gt;
Se deja disponible el código para TurtleBots [[Archivo:WALLE-LineaNegra.tb]].&lt;br /&gt;
&lt;br /&gt;
A continuación se muestra el código, por el orden de ejecución. En muchas partes de esta sección se menciona la etapa de calibración, toda la información relacionada a esa etapa se encuentra en la sección que viene despues de esta.&amp;lt;br /&amp;gt;&lt;br /&gt;
Los bloques del Plugin Butiá donde figuran los sensores tienen el siguiente mapeo:&lt;br /&gt;
   distance Butia: El sensor de grises que está ubicado en la parte frontal, el cual se usa para detectar el objeto.&lt;br /&gt;
   gray Butia:     El sensor de grises que está ubicado en la parte frontal, el cual se usa para identificar el objeto.&lt;br /&gt;
   gray Butia1:    El sensor de grises ubicado en la parte izquierda, el cual se usa para seguir el carril&lt;br /&gt;
   gray Butia2:    El sensor de grises ubicado en la parte derecha, el cual se usa para seguir el carril&lt;br /&gt;
&lt;br /&gt;
*'''Método Principal:'''&lt;br /&gt;
Aquí se configuran las distintas constantes que deben ser calibradas previo a la ejecución.&amp;lt;br /&amp;gt;&lt;br /&gt;
Luego se ejecuta de forma infinita el método encargado del control del robot (Clasificar)&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_Principal.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Clasificar:'''&lt;br /&gt;
En este método se encuentra todo el código necesario para el control del robot:&lt;br /&gt;
    1: Primero el robot detecta e identifica el objeto, definiendo el carril que corresponde seguir.&lt;br /&gt;
    2: Luego avanza hasta la primera intersección que detecta (separación entre carriles).&lt;br /&gt;
    3: Rota hacia el carril correcto&lt;br /&gt;
    4: Luego avanza hasta la primera intersección que detecta (final de la pista).&lt;br /&gt;
    5: Retrocede un poco (para no arrastrar el objeto) y rota 180 grados.&lt;br /&gt;
    6: Luego avanza hasta la primera intersección que detecta (separación entre carriles).&lt;br /&gt;
    7: Rota hacia el carril correcto (el carril inicial).&lt;br /&gt;
    8: Luego avanza hasta la primera intersección que detecta (final de la pista).&lt;br /&gt;
    9: Rota 180 grados y se vuelve al paso 1.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE-Clasificar.png|350]]&lt;br /&gt;
&lt;br /&gt;
*'''Metodo Seleccion Carril:'''&lt;br /&gt;
Aquí se queda en espera hasta que el sensor de distancia detecte un objeto a una distancia menor y a una mayor a las predefinidas (etapa de calibración).&amp;lt;br /&amp;gt;&lt;br /&gt;
Luego de que se detecta el objeto y se identifica el color, se define el carril a seguir.&amp;lt;br /&amp;gt;&lt;br /&gt;
Objeto Blanco: Carril central   (valor = 0)&amp;lt;br /&amp;gt;&lt;br /&gt;
Objeto Gris  : Carril izquierdo (valor = 1)&amp;lt;br /&amp;gt;&lt;br /&gt;
Objeto Negro : Carril derecho   (valor = 2)&amp;lt;br /&amp;gt;&lt;br /&gt;
La muestras del sensor de grises y de distancia son obtenidas luego de aplicado un filtro, donde se hace un promedio de N muestras tomadas.&amp;lt;br /&amp;gt;&lt;br /&gt;
Se realiza el filtro para eliminar posibles ruidos de los sensores.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE SeleccionCarril.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Tomar Muestra Distancia Objeto:'''&lt;br /&gt;
Como se mencionó anteriormente, se aplica un filtro al sensado de distancia del objeto.&amp;lt;br /&amp;gt;&lt;br /&gt;
Por lo que aquí se toman N muestras y se guarda el resultado del promedio de estos valores.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_Muestra_Distancia.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Tomar Muestra Color Objeto:'''&lt;br /&gt;
Se aplica un filtro al sensado de grises del objeto.&amp;lt;br /&amp;gt;&lt;br /&gt;
Por lo que aquí se toman N muestras y se guarda el resultado del promedio de estos valores.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_Muestra_Color.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Avanzar Hasta Intersección:'''&lt;br /&gt;
Este método es básicamente un seguidor de líneas, con el detalle de que el robot frena cuando detecta una intersección.&amp;lt;br /&amp;gt;&lt;br /&gt;
El robot infiere que está sobre una intersección cuando ambos sensores de grises detectan que se está sobre la línea al mismo tiempo.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_AvanzarHastaIntereseccion.png|400px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Rotar Carril Elegido:'''&lt;br /&gt;
Este método se encarga de rotar al carril elegido previamente (0=Saltar intersección, 1=Rotar hacia la izquierda, 2=Rotar hacia la derecha).&amp;lt;br /&amp;gt;&lt;br /&gt;
Dependiendo del carril se llama al método encargado de realizar la maniobra requerida.&amp;lt;br /&amp;gt;&lt;br /&gt;
Es importante destacar que cuando hay que rotar hacia la izquierda o derecha, se cambia el valor de carril elegido para que cuando retorne doble hacia el lado inverso.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_RotarCarrilElegido.png|300px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Rotar Al Carril Izq:'''&lt;br /&gt;
Aquí el robot rota hacia el carril izquierdo, esto lo hace girando el robot por un tiempo predefinido en calibración.&amp;lt;br /&amp;gt;&lt;br /&gt;
Esto con el objetivo de que el sensor de grises derecho saltee el carril central. Una vez salteado el carril central se sigue doblando hasta que el sensor derecho detecte la línea, que deberá corresponderse con el carril izquierdo.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_RotarAlCarrilIzq.png|350px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Rotar Al Carril Der:'''&lt;br /&gt;
Este método es análogo al anterior pero para el carril contrario.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_RotarCarrilElegido.png|300px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Saltear Intersección:'''&lt;br /&gt;
Cuando se quiere saltear la intersección se avanza un poquito para asegurar que se está sobre la misma. Y se sigue avanzando recto hasta que ambos sensores de grises detecten que están fuera de la línea.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_RotarCarrilElegido.png|300px]]&lt;br /&gt;
&lt;br /&gt;
*'''Método Giro 180:'''&lt;br /&gt;
Este último método realiza un giro 180 sobre la línea. Aquí se gira hacia la derecha sobre el lugar un tiempo predefinido en calibración, para que ambos sensores queden fuera de la línea.&amp;lt;br /&amp;gt;&lt;br /&gt;
Luego se sigue girando hasta que el sensor de izquierda detecte que está sobre la línea.&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Archivo:WALLE_RotarCarrilElegido.png|300px]]&lt;br /&gt;
&lt;br /&gt;
==Calibración==&lt;br /&gt;
Para el correcto funcionamiento es necesario calibrar las constantes. Esto se debe hacer en un ambiente similar al de ejecución.&amp;lt;br /&amp;gt;&lt;br /&gt;
Hay 11 valores a calibrar, todos son definidos en el método Principal. A continuación se detallan cuales son y cómo se deberían calibrar.&lt;br /&gt;
&lt;br /&gt;
Para obtener los valores del sensado se recomienda conectar el robot y hacer click sobre el bloque del sensor que se está calibrando en TurtleBot, con esto se obtiene el valor de sensado.&lt;br /&gt;
&lt;br /&gt;
* '''umbral_objeto_maximo''':&lt;br /&gt;
Aquí se define la distancia máxima a la cual el robot detecta el objeto, es importante que esta distancia sea lo suficientemente chica para que el sensor de grises detecte correctamente el color. Para el kit Butiá esta distancia oscila entre 2 a 7 cm.&amp;lt;br /&amp;gt;&lt;br /&gt;
Para encontrar ese valor se conecta el robot y haciendo click sobre el bloque del sensor en TurtleBot se obtiene el valor de sensado, se debe ir moviendo el objeto delante del sensor buscando encontrar el valor de sensado que asegure que la distancia máxima sea válida.&lt;br /&gt;
&lt;br /&gt;
* '''umbral_objeto_minimo''':&lt;br /&gt;
Aquí se define la distancia mínima a partir de la cual el robot comienza a detectar el objeto, es importante que esta distancia sea lo suficientemente cercana a la máxima para que el sensor de grises no tenga muchas variaciones a la hora del sensado.&amp;lt;br /&amp;gt;&lt;br /&gt;
El valor aquí es aquel que deja al robot detectar el objeto de forma razonable teniendo como tope el máximo definido preventivamente, tratando de minimizar la diferencia entre el máximo y el mínimo.&lt;br /&gt;
&lt;br /&gt;
* '''umbral_blanco''':&lt;br /&gt;
Aquí se define el umbral que separa entre el gris y blanco del objeto a clasificar.&amp;lt;br /&amp;gt;&lt;br /&gt;
Para encontrar este valor, colocar el objeto dentro del rango definido anteriormente. Luego alternar entre las caras blancas y grises para encontrar un valor medio entre las medidas sensadas para ambos colores.&lt;br /&gt;
&lt;br /&gt;
* '''umbral_gris''':&lt;br /&gt;
Aquí se define el umbral que separa entre el gris y negro del objeto a clasificar.&amp;lt;br /&amp;gt;&lt;br /&gt;
El procedimiento es análogo al usado para umbral_blanco, pero con las caras negras y grises.&lt;br /&gt;
&lt;br /&gt;
* '''umbral_linea_der'''&lt;br /&gt;
Aquí se define el umbral que permite al robot identificar que el sensor derecho está sobre la línea o fuera.&amp;lt;br /&amp;gt;&lt;br /&gt;
Para encontrar este valor, colocar el sensor sobre el borde de la línea y el valor sensado es el utilizado para este umbral.&lt;br /&gt;
&lt;br /&gt;
* '''umbral_linea_izq'''&lt;br /&gt;
Aquí se define el umbral que permite al robot identificar que el sensor derecho está sobre la línea o fuera.&amp;lt;br /&amp;gt;&lt;br /&gt;
Para encontrar este valor, colocar el sensor sobre el borde de la línea y el valor sensado es el utilizado para este umbral.&lt;br /&gt;
&lt;br /&gt;
* '''vel_rueda_izq_adelante''':&lt;br /&gt;
Aquí se define la velocidad de la rueda izquierda para avanzar.&amp;lt;br /&amp;gt;&lt;br /&gt;
Un valor razonable es 600, si se quiere que se vaya más rápido o más lento se puede variar a criterio este valor.&lt;br /&gt;
&lt;br /&gt;
* '''vel_rueda_der_adelante''':&lt;br /&gt;
Aquí se define la velocidad de la rueda derecha para avanzar.&amp;lt;br /&amp;gt;&lt;br /&gt;
Un valor razonable es 600, si se quiere que se vaya más rápido o más lento se puede variar a criterio este valor.&lt;br /&gt;
&lt;br /&gt;
* '''vel_rueda_izq_atras'''&lt;br /&gt;
Aquí se define la velocidad de la rueda izquierda para atrás.&amp;lt;br /&amp;gt;&lt;br /&gt;
Un valor razonable es -600, si se quiere que se vaya más rápido o más lento se puede variar a criterio este valor.&lt;br /&gt;
&lt;br /&gt;
* '''vel_rueda_der_atras'''&lt;br /&gt;
Aquí se define la velocidad de la rueda derecha para atrás.&amp;lt;br /&amp;gt;&lt;br /&gt;
Un valor razonable es -600, si se quiere que se vaya más rápido o más lento se puede variar a criterio este valor.&lt;br /&gt;
&lt;br /&gt;
* '''tiempo_rotar_carril''':&lt;br /&gt;
Aquí se define el tiempo que el robot va a girar en la intersección central antes de empezar a detectar si el sensor está sobre la línea.&amp;lt;br /&amp;gt;&lt;br /&gt;
Este valor se encuentra experimentando, ejecutando el programa y mirando si el robot no frena cuando el sensor pasa sobre la línea del carril central.&amp;lt;br /&amp;gt;&lt;br /&gt;
El valor depende de la velocidad definida previamente para la ruedas, pero para una velocidad de 600 un valor de 1.5 es posible que funcione correctamente.&lt;br /&gt;
&lt;br /&gt;
* '''tiempo_dejar_objeto'''&lt;br /&gt;
Aquí se define el tiempo que el robot va hacia atrás antes de realizar un giro de 180 grados.&amp;lt;br /&amp;gt;&lt;br /&gt;
Este valor se encuentra experimentando, ejecutando el programa y mirando si el robot no arrastra el objeto cuando gira 180 grados.&amp;lt;br /&amp;gt;&lt;br /&gt;
El valor depende de la velocidad hacia atrás definida previamente para la ruedas, pero para una velocidad de 600 un valor de 0.5 es posible que funcione correctamente.&lt;br /&gt;
&lt;br /&gt;
* '''tiempo_giro_180'''&lt;br /&gt;
Aquí se define el tiempo que el robot va a girar antes de empezar a detectar si el sensor está sobre la línea.&amp;lt;br /&amp;gt;&lt;br /&gt;
Este valor se encuentra experimentando, ejecutando el programa y mirando si el robot logra hacer un giro 180 sobre la línea.&amp;lt;br /&amp;gt;&lt;br /&gt;
El valor depende de la velocidad de las ruedas definida previamente, pero para una velocidad de 600 un valor de 1.5 es posible que funcione correctamente.&lt;br /&gt;
 &lt;br /&gt;
* '''cantidad_de_muestras'''&lt;br /&gt;
Este valor define la cantidad de muestras utilizadas para hacer el promedio de los valores sensados. Se utiliza para el sensor de grises y de distancia aplicados sobre el objeto a clasificar.&amp;lt;br /&amp;gt;&lt;br /&gt;
Un valor de 10 muestras es razonable, cuanto más alto este valor menor posibilidad de ruido pero con un mayor tiempo de respuesta del robot, y cuanto menor el valor mayor posibilidad de ruido en el sensado pero con un menor tiempo de respuesta.&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
'''Tip:''' Un tip para probar que todo haya quedado calibrado correctamente, es setear todas las velocidades en 0 y ejecutar el programa usando el modo debug (Caracol). Una vez iniciado el programa ir moviendo el robot con la mano simulando el recorrido, con esto podemos ver en el programa TurtleBots como el programa avanza. Esto nos permite ver que todo haya quedado calibrado correctamente y que no haya problemas en el código generado.&lt;br /&gt;
&lt;br /&gt;
==En acción==&lt;br /&gt;
En el siguiente video se puede ver como el robot clasifica el objeto dependiendo la cara que se le muestre. Cuando detecta la cara de color gris va hacia el carril izquierdo, cuando detecta el blanco utiliza el carril central, y si detecta el color negro va hacia el carril derecho.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;center&amp;gt;&amp;lt;youtube&amp;gt;https://youtu.be/rYKVi8eSSMI&amp;lt;/youtube&amp;gt; &amp;lt;/center&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Para iniciar el clasificador, hay que ejecutar el programa haciendo click en el modo liebre del programa TurtleBot. Es necesario previo a la ejecución tener todos los sensores conectados y el robot conectado a la laptop.&lt;br /&gt;
&lt;br /&gt;
==Usar línea blanca sobre un piso oscuro==&lt;br /&gt;
Si se quiere usar una cinta blanca en lugar de una negra, es necesario realizar modificaciones en el código brindado anteriormente, los cambios son pequeños pero importantes.&amp;lt;br /&amp;gt;&lt;br /&gt;
Lo que hay que realizar para soportar este cambio es invertir cada comparación entre los valores de los sensores de grises usados para seguir la línea y los umbrales asociados.&amp;lt;br /&amp;gt;&lt;br /&gt;
Por lo que en cada una de esas comparaciones, hay que cambiar las que son de menor estricto a unas de mayor estricto, y las que son de mayor estricto a una de menor estricto.&lt;br /&gt;
&lt;br /&gt;
==Trabajos a futuro==&lt;br /&gt;
Existen 2 áreas en la que hay espacio a mejoras, la primera es el agarre/empuje del residuo y la otra es la identificación del mismo.&lt;br /&gt;
&lt;br /&gt;
Sobre la primero, existen muchas posibles modificaciones en la forma de que el robot lleva el residuo al destino. &amp;lt;br /&amp;gt;&lt;br /&gt;
Por ejemplo se pueden utilizar dos abrazaderas para presionar al objeto luego de detectado. También se puede utilizar una pinza para que levante el objeto en vez de arrastrarlo.&lt;br /&gt;
&lt;br /&gt;
Para la identificación, hay 2 cambios que resultan interesantes:&lt;br /&gt;
* El primer cambio no aumenta demasiado la dificultad, la idea es cambiar el sensor de grises por uno de colores. Con esto se pueden identificar mayor variedad de objetos, utilizando más cantidad de colores y no solo 3 colores.&lt;br /&gt;
* El segundo cambio conlleva un aumento en la dificultad, la idea es reemplazar el sensor de grises por una cámara. Utilizando la cámara se puede reconocer distintos objetos por su forma, por ejemplo identificar botellas, latas, etc.&lt;br /&gt;
&lt;br /&gt;
==Posibles Fallas==&lt;br /&gt;
'''Luego de ejecutar toda una vuelta, el robot queda un poco torcido'''&lt;br /&gt;
&lt;br /&gt;
Al hacer el giro 180 al final del recorrido puede pasar que el robot gire un poco más de lo esperado, esto hace que quede un poco desviado, y si bien no debería afectar al funcionamiento es algo que se puede solucionar de forma sencilla.&amp;lt;br /&amp;gt;&lt;br /&gt;
Para arreglar esto, se puede agregar al final del método ‘Clasificar’ tres bloques. El primero es el bloque para mover la rueda izquierda hacia atrás, luego se debe colocar el bloque de esperar por un tiempo definido y por último la instrucción de frenar el robot Butiá. La velocidad seteada para la rueda y el tiempo de espera se deben seleccionar experimentando con el robot hasta que se logre que quede correctamente alineado luego de una vuelta entera.&lt;br /&gt;
&lt;br /&gt;
'''No detecta correctamente el tipo de residuo (negro, gris, blanco)'''&lt;br /&gt;
&lt;br /&gt;
Este problema, como la mayoría de las potenciales fallas, recaen sobre la correcta calibración de las constantes.&amp;lt;br /&amp;gt;&lt;br /&gt;
Dado que el sensor de grises es muy sensible a la distancia del objeto, es necesario definir un límite estrecho entre la mínima y máxima distancia a la cual el objeto es detectado.&amp;lt;br /&amp;gt;&lt;br /&gt;
Otra posible causa pueden ser variaciones de luminosidad en el ambiente, es recomendable que las condiciones lumínicas sean constantes a lo largo de la operación del robot.&amp;lt;br /&amp;gt;&lt;br /&gt;
También la luminosidad del ambiente debe ser similar tanto en la calibración como en la ejecución.&lt;br /&gt;
&lt;br /&gt;
'''No avanza en línea recta'''&lt;br /&gt;
&lt;br /&gt;
En muchos casos la velocidad real de cada rueda es diferente entre ellas para una velocidad definida.&amp;lt;br /&amp;gt;&lt;br /&gt;
Una forma de solucionar esto es ajustar la constantes de la velocidad izquierda y derecha de forma que la velocidad real sea igual para ambas ruedas.&lt;br /&gt;
&lt;br /&gt;
'''Problemas siguiendo las líneas y detectando intersecciones'''&lt;br /&gt;
&lt;br /&gt;
La mayoría de los problemas de este tipo son generados por una mala calibración, es importante re-calibrar si el robot no realiza el circuito correctamente.&lt;/div&gt;</summary>
		<author><name>Agustin.rieppi</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Link_ejemplo</id>
		<title>Link ejemplo</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Link_ejemplo"/>
				<updated>2021-06-15T14:31:32Z</updated>
		
		<summary type="html">&lt;p&gt;Agustin.rieppi: Página creada con «Test»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Test&lt;/div&gt;</summary>
		<author><name>Agustin.rieppi</name></author>	</entry>

	<entry>
		<id>http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Espacio_para_grupos_2021</id>
		<title>Espacio para grupos 2021</title>
		<link rel="alternate" type="text/html" href="http://164.73.124.35/inco/proyectos/butia/mediawiki/index.php/Espacio_para_grupos_2021"/>
				<updated>2021-06-15T12:27:10Z</updated>
		
		<summary type="html">&lt;p&gt;Leandromesaprofesional: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [[WALL-E|WALL-E]]&lt;br /&gt;
* [[Horus|Proyecto Horus]]&lt;br /&gt;
* [[Sip&amp;amp;Puff4Butiá - Haciendo la computación más accesible|Sip&amp;amp;Puff4Butiá - Haciendo la computación más accesible]]&lt;br /&gt;
* [[Alimentador automático para macotas| Alimentador automático para macotas]]&lt;br /&gt;
* [[Butiá en el huerto escolar | Butiá en el huerto escolar]]&lt;br /&gt;
* [[butia_gol | Butiá Gol]]&lt;br /&gt;
* [[Mindstorms | Mindstorms]]&lt;br /&gt;
* [[Incuba-Dora]]&lt;br /&gt;
* [[Programando el Butia desde el celular]]&lt;br /&gt;
* [[tbpy: Creación de paletas y bloques en TurtleBlocks utilizando Python a alto nivel]]&lt;br /&gt;
* [[Robot para el cuidado de plantas]]&lt;br /&gt;
* [[Introduciendo la robótica a jóvenes y adolescentes | Introduciendo la robótica a jóvenes y adolescentes]]&lt;br /&gt;
* [[Taller de Robótica educativa | Taller de Robótica educativa]]&lt;/div&gt;</summary>
		<author><name>Agustin.rieppi</name></author>	</entry>

	</feed>