{"id":2463,"date":"2020-06-29T23:02:53","date_gmt":"2020-06-29T23:02:53","guid":{"rendered":"http:\/\/blog.rastersoft.com\/?p=2463"},"modified":"2020-10-21T12:15:21","modified_gmt":"2020-10-21T12:15:21","slug":"a-ritmo-de-conga-y-5","status":"publish","type":"post","link":"https:\/\/blog.rastersoft.com\/?p=2463","title":{"rendered":"A ritmo de conga (5)"},"content":{"rendered":"\n<p><strong>DISCLAIMER:<\/strong> no ser\u00e9 responsable si alguien decide seguir mis pasos y se carga su aspiradora. En principio todo lo que cuento deber\u00eda ser seguro, pero por motivos obvios no me puedo responsabilizar de lo que hagan otras personas, s\u00f3lo de lo que haga yo.<\/p>\n\n\n\n<p>\u00a1Victoria, victoria! \u00a1Mi conga ya me hace caso!<\/p>\n\n\n\n<figure class=\"wp-block-video aligncenter\"><video controls src=\"https:\/\/www.rastersoft.com\/donita3.mp4\"><\/video><\/figure>\n\n\n\n<p>Lo que hice fue escribir un nuevo servidor, esta vez desde cero, que combina HTTP y el protocolo espec\u00edfico de la conga. El c\u00f3digo he decidido no hacerlo p\u00fablico hasta que termine el an\u00e1lisis completo, no vaya a ser que meta la pata en algo&#8230;<\/p>\n\n\n\n<p>El motivo de no utilizar el c\u00f3digo de <a href=\"https:\/\/docs.python.org\/3\/library\/http.server.html\">http.server<\/a> que ya ten\u00eda ha sido, fundamentalmente, porque debido a todos los trucos que tuve que utilizar para que funcionase, al final no usaba casi nada, con lo que me compensaba escribir mi propio servidor. Adem\u00e1s, al hacerlo yo todo con <a href=\"https:\/\/docs.python.org\/3\/library\/select.html\">select<\/a> y <a href=\"https:\/\/docs.python.org\/3\/library\/socket.html\">sockets<\/a> pod\u00eda integrar mucho mejor en un \u00fanico hilo la gesti\u00f3n del puerto 80 y la del 20008.<\/p>\n\n\n\n<p>B\u00e1sicamente cre\u00e9 una primera clase, <em>BaseServer<\/em>, que tiene un <em>socket<\/em> y que gestiona las funcionalidades b\u00e1sicas de \u00e9ste, incluyendo un m\u00e9todo vac\u00edo para cada vez que se reciben datos nuevos, y otros m\u00e9todos para gestionar cuando se cierra. Sobre esta clase he construido absolutamente todo.<\/p>\n\n\n\n<p>Luego cre\u00e9 la clase <em>HTTPConnection<\/em>, la cual es la que gestiona una conexi\u00f3n <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hypertext_Transfer_Protocol\">HTTP<\/a> concreta. Cada vez que se hace una petici\u00f3n <em>HTTP<\/em>, se crea un objeto de este tipo, y es \u00e9l quien analiza lo que llega. Su funci\u00f3n es la misma que el c\u00f3digo que hice antes con <em>http.server<\/em>. Para gestionar esto est\u00e1 la clase <em>HTTPServer<\/em>, que es la que abre el puerto 80 y crea los objetos anteriores tras cada conexi\u00f3n.<\/p>\n\n\n\n<p>De la misma manera est\u00e1n las clases <em>RobotConnection<\/em> y <em>RobotServer<\/em>, pero esta vez para gestionar las conexiones al puerto 20008. El tenerlo dividido as\u00ed permite controlar varios robots a la vez (aunque no creo que lo implemente de momento, no est\u00e1 de m\u00e1s que la arquitectura subyacente lo est\u00e9 preparada).<\/p>\n\n\n\n<p>La clase <em>RobotConnection<\/em> tiene un m\u00e9todo llamado <em>send_command<\/em>, que lo que hace es, b\u00e1sicamente, emitir exactamente las mismas secuencias que registr\u00e9 anteriormente, copiadas byte a byte. Esto, al final, es bastante sencillo porque todos los comandos se emiten con el mismo tipo de paquete, y s\u00f3lo cambia el n\u00famero de comando y, en un par de casos, un par\u00e1metro extra.<\/p>\n\n\n\n<p>Por otro lado, en base al contenido del segundo, tercero y quinto enteros de los paquetes enviados por la aspiradora puedo saber si es un paquete que espera una respuesta por mi parte, o un ACK de un comando enviado por m\u00ed, por lo que en el m\u00e9todo de recepci\u00f3n de datos me limito a hacer una lista de comparaciones para ver qu\u00e9 tengo que responder; y si recibo una combinaci\u00f3n desconocida, la imprimo.<\/p>\n\n\n\n<p>Todas estas clases est\u00e1n gestionadas por una clase maestra llamada <em>Multiplexer<\/em>, que lanza primero una instancia de <em>HTTPServer<\/em> y otra de <em>RobotServer<\/em>, y va gestionando las nuevas instancias creadas por estos dos objetos mediante <em>select<\/em>.<\/p>\n\n\n\n<p>Por \u00faltimo, hay una clase llamada <em>Robot<\/em> que est\u00e1 asociada permanentemente con un robot concreto, aunque \u00e9ste no est\u00e9 conectado. De momento se crea bajo demanda, pero en el futuro podr\u00eda incluir alg\u00fan tipo de <a href=\"https:\/\/en.wikipedia.org\/wiki\/Persistence_(computer_science)\">persistencia<\/a>, por ejemplo para que recuerde la configuraci\u00f3n deseada por el usuario o los mapas, aunque se apague la aspiradora. Cada vez que un robot se conecta, se utiliza su identificador \u00fanico para encontrar el objeto correspondiente y enlazarlo, y cada vez que se pierde la conexi\u00f3n, se informa de ello al objeto <em>Robot<\/em> para que borre la referencia al objeto <em>RobotConnection<\/em>.<\/p>\n\n\n\n<p>Para la primera prueba decid\u00ed aprovechar el mismo servidor web que ya tengo para los robots e implementar un control sencillo por <a href=\"https:\/\/en.wikipedia.org\/wiki\/Representational_state_transfer\">REST<\/a>, mediante una sencilla p\u00e1gina web. Es justo lo que se ve en el v\u00eddeo.<\/p>\n\n\n\n<p>El siguiente paso es analizar y a\u00f1adir los comandos para configurar el m\u00e9todo de trabajo, la potencia del ventilador y el uso de la fregona, y por supuesto el control manual (aunque ya adelanto que <em>parece<\/em> que es en este caso donde entra en juego el puerto 8888 y la conexi\u00f3n directa con la tablet&#8230; a ver si hay suerte y me la puedo saltar).<\/p>\n\n\n\n<p>Tambi\u00e9n quiero analizar c\u00f3mo se transmite la informaci\u00f3n de los mapas, pero eso ser\u00e1 al final.<\/p>\n\n\n\n<p><a href=\"https:\/\/blog.rastersoft.com\/?p=2494\">Parte 6<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>DISCLAIMER: no ser\u00e9 responsable si alguien decide seguir mis pasos y se carga su aspiradora. En principio todo lo que cuento deber\u00eda ser seguro, pero por motivos obvios no me puedo responsabilizar de lo que hagan otras personas, s\u00f3lo de lo que haga yo. \u00a1Victoria, victoria! \u00a1Mi conga ya me hace caso! Lo que hice &hellip; <a href=\"https:\/\/blog.rastersoft.com\/?p=2463\" class=\"more-link\">Seguir leyendo <span class=\"screen-reader-text\">A ritmo de conga (5)<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,16,5,7],"tags":[],"class_list":["post-2463","post","type-post","status-publish","format-standard","hentry","category-cacharreo","category-opendonita","category-programacion","category-tutoriales"],"_links":{"self":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2463","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2463"}],"version-history":[{"count":14,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2463\/revisions"}],"predecessor-version":[{"id":2597,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2463\/revisions\/2597"}],"wp:attachment":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2463"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2463"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}