{"id":6251,"date":"2022-09-15T15:32:54","date_gmt":"2022-09-15T15:32:54","guid":{"rendered":"https:\/\/robotica-facil-con-ros2.es\/?p=6251"},"modified":"2024-12-01T18:57:26","modified_gmt":"2024-12-01T18:57:26","slug":"ros2-servicios","status":"publish","type":"post","link":"https:\/\/robotica-facil-con-ros2.es\/?p=6251","title":{"rendered":"ROS2. Aprende c\u00f3mo usar servicios con Python"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"6251\" class=\"elementor elementor-6251\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-3c6b921 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"3c6b921\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-a1e7b85\" data-id=\"a1e7b85\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-3e2ad92 elementor-widget elementor-widget-text-editor\" data-id=\"3e2ad92\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h3>1 Introducci\u00f3n<\/h3><p>Adem\u00e1s de mediante topics, otra forma de hacer que los nodos se comuniquen entre s\u00ed es mediante el uso de servicios. Los servicios est\u00e1n basados en el modelo <em><strong>cliente-servidor<\/strong><\/em> seg\u00fan el cual un nodo (<em>cliente<\/em>) env\u00eda una petici\u00f3n a otro nodo (<em>servidor<\/em>) que responde proporcionado el resultado de la solicitud.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b0e0481 elementor-widget elementor-widget-text-editor\" data-id=\"b0e0481\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>La comunicaci\u00f3n entre el cliente y el servidor puede realizarse de formas:<\/p><p>\u00a0<\/p><ul><li style=\"list-style-type: none;\"><ul><li style=\"list-style-type: none;\"><ul><li><strong>S\u00edncrona.<\/strong> El cliente, tras enviar la petici\u00f3n, detiene su ejecuci\u00f3n hasta recibir la respuesta.<\/li><li><strong>As\u00edncrona.<\/strong> El cliente no detiene su ejecuci\u00f3n cuando env\u00eda la petici\u00f3n al servidor.<\/li><\/ul><\/li><\/ul><\/li><\/ul>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a9c4b59 elementor-widget elementor-widget-text-editor\" data-id=\"a9c4b59\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\tTanto la solicitud como la respuesta est\u00e1n definidas en un archivo con extensi\u00f3n <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">.srv<\/span><\/code> que tiene una estructura como la siguiente:\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-04f829c elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"04f829c\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-04f829c\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-tomorrow\"\n            data-dark-theme=\"mdp-theme-tomorrow\"\n        >\n            \n                <pre class=\"language-shell-session copy-to-clipboard\"data-previewers=\"\"><code>int64 a\nint64 b\n---\nint64 sum<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_04f829c = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_04f829c();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_04f829c );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3e60d82 elementor-widget elementor-widget-text-editor\" data-id=\"3e60d82\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Donde cada l\u00ednea indica un dato que se deben pasar o que devuelve el servicio. Siendo los que se encuentran antes de\u00a0 &#8220;<strong>&#8211;\u00a0 &#8211;\u00a0 &#8211;<\/strong>&#8221;\u00a0 los correspondientes a la petici\u00f3n y los que se encuentran despu\u00e9s los asociados a la respuesta. Para cada uno de los datos se indica su tipo y el nombre.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-cedbd18 elementor-widget elementor-widget-text-editor\" data-id=\"cedbd18\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>La estructura mostrada forma parte de un servicio definido en el paquete <em>example_interfaces<\/em> con el nombre <em>AddTwoInts<\/em>, el cual recibe dos valores enteros (<em>a<\/em> y <em>b<\/em>) y devuelve el resultado de su suma (<em>sum<\/em>).<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8263239 elementor-widget elementor-widget-text-editor\" data-id=\"8263239\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>En este art\u00edculo vamos a generar un nuevo paquete python que llamaremos <strong><i>py_srvcli<\/i><\/strong> en el cual crearemos un nodo servidor que va a implementar este servicio y un nodo cliente que realizar\u00e1 las peticiones.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4b8a46c elementor-widget elementor-widget-text-editor\" data-id=\"4b8a46c\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h3>2 Generando el paquete python<\/h3><p>Para crear el paquete vamos a la carpeta <i>src<\/i> de nuestro espacio de trabajo y ejecutamos el siguiente comando:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dd149a2 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"dd149a2\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-dd149a2\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-tomorrow\"\n            data-dark-theme=\"mdp-theme-tomorrow\"\n        >\n            \n                <pre class=\"language-shell-session copy-to-clipboard\"data-previewers=\"\"><code>ros2 pkg create --build-type ament_python py_srvcli --dependencies rclpy example_interfaces<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_dd149a2 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_dd149a2();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_dd149a2 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c184944 elementor-widget elementor-widget-text-editor\" data-id=\"c184944\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>C\u00f3mo en el comando anterior ya hemos indicado las dependencias estas ya se incluyen autom\u00e1ticamente en el archivo <em>package.xml<\/em> del paquete por lo que no es necesario editarlo para a\u00f1adirlas manualmente.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5655040 elementor-widget elementor-widget-text-editor\" data-id=\"5655040\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Si quieres conocer los argumentos que se pueden usar a la hora de generar un paquete puedes consultar el art\u00edculo <a href=\"https:\/\/robotica-facil-con-ros2.es\/?p=3078\">&#8220;ROS2. C\u00f3mo crear un paquete Python&#8221;<\/a>.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d540b2a elementor-widget elementor-widget-text-editor\" data-id=\"d540b2a\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h3>3 Creando el nodo servidor que proporciona el servicio<\/h3><p>Para ello, en nuestro paquete dentro de la carpeta que tiene su mismo nombre, creamos un archivo al que vamos a llamar <strong><em>server_node.py<\/em><\/strong>:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c47445c elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"c47445c\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-c47445c\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-tomorrow\"\n            data-dark-theme=\"mdp-theme-tomorrow\"\n        >\n            \n                <pre class=\"language-shell-session copy-to-clipboard\"data-previewers=\"\"><code>cd py_srvcli\/py_srvcli\ntouch server_node.py<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_c47445c = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_c47445c();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_c47445c );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ee827b6 elementor-widget elementor-widget-text-editor\" data-id=\"ee827b6\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Abrimos el archivo y pegamos una de las dos versiones de c\u00f3digo que se muestran a continuaci\u00f3n. La diferencia entre ellas es que en una se ha utilizado programaci\u00f3n orientada a objetos y en la otra no.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ffce0a5 elementor-widget elementor-widget-text-editor\" data-id=\"ffce0a5\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>El c\u00f3digo se encuentra explicado en los comentarios.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c4ea73c elementor-widget elementor-widget-text-editor\" data-id=\"c4ea73c\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h4>3.1 Usando una funci\u00f3n local<\/h4>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c271768 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"c271768\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-c271768\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-xonokai\"\n            data-dark-theme=\"mdp-theme-xonokai\"\n        >\n            \n                <pre class=\"language-python copy-to-clipboard\"data-previewers=\"\"><code># Importa el tipo de servicio AddTwoInts del paquete example_interface. \nfrom example_interfaces.srv import AddTwoInts\n\n# Importa la biblioteca cliente Python de ROS 2.\nimport rclpy\n\n# Crea una variable global que se usar&aacute; m&aacute;s adelante para almacenar la \n# instancia del nodo.\nnode = None\n\n# Define la funci&oacute;n que se ejecuta al recibir una petici&oacute;n y que devuelve\n# la respuesta del servicio.\ndef add_two_ints_callback(request, response):\n    global node\n\n    # Asigna el resultado a la respuesta del servicio.\n    response.sum = request.a + request.b\n\n    # Muestra en la consola la informaci&oacute;n de la petici&oacute;n recibida.\n    node.get_logger().info(\n        &#039;Incoming request\\na: %d b: %d&#039; % (request.a, request.b))\n\n    # Devuelve la respuesta del servicio.\n    return response\n\n\ndef main(args=None):\n    global node\n\n    # Inicializa la librer&iacute;a Python de ROS2.\n    rclpy.init(args=args)\n\n    # Crea el nodo que va a proporcionar el servicio.\n    node = rclpy.create_node(&#039;minimal_service&#039;)\n\n    # Crea el servicio y define el tipo, su nombre y el de la funci&oacute;n que se\n    # ejecutara al recibir una petici&oacute;n.\n    srv = node.create_service(AddTwoInts, &#039;add_two_ints&#039;, add_two_ints_callback)\n\n    # Mantiene corriendo el bucle interno del nodo para poder gestionar las\n    # peticiones del cliente.\n    rclpy.spin(node)\n\n    # Destruye expl&iacute;citamente el servicio. Es opcional ya que el recolector de\n    # basura realiza esta acci&oacute;n cuandop destruye el objeto nodo.\n    node.destroy_service(srv)\n\n    # Destruye el nodo.\n    node.destroy_node()\n\n    rclpy.shutdown()\n\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_c271768 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_c271768();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_c271768 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-88b9d73 elementor-widget elementor-widget-text-editor\" data-id=\"88b9d73\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h4>3.2 Usando una clase<\/h4>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-51b9921 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"51b9921\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-51b9921\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-xonokai\"\n            data-dark-theme=\"mdp-theme-xonokai\"\n        >\n            \n                <pre class=\"language-python copy-to-clipboard\"data-previewers=\"\"><code># Importa el tipo de servicio AddTwoInts del paquete example_interface. \nfrom example_interfaces.srv import AddTwoInts\n\n# Importa la biblioteca cliente Python de ROS 2 y, espec&iacute;ficamente, la clase Node.\nimport rclpy\nfrom rclpy.node import Node\n\n\nclass MinimalService(Node):\n\n    # El constructor de la clase inicializa el nodo con el nombre service_node.\n    # Luego, crea un servicio y define el tipo, su nombre y el de la funci&oacute;n que\n    # se ejecutar&aacute; al recibir una petici&oacute;n.\n    def __init__(self):\n        super().__init__(&#039;service_node&#039;)\n        self.srv = self.create_service(AddTwoInts, &#039;add_two_ints&#039;, self.add_two_ints_callback)\n\n    # Define la funci&oacute;n que se ejecuta al recibir una petici&oacute;n y que devuelve\n    # la respuesta del servicio.\n    def add_two_ints_callback(self, request, response):\n        response.sum = request.a + request.b\n        self.get_logger().info(&#039;Incoming request\\na: %d b: %d&#039; % (request.a, request.b))\n\n        return response\n\n\ndef main(args=None):\n\n    # Inicializa la librer&iacute;a Python de ROS2.\n    rclpy.init(args=args)\n\n    # Crea una instancia de la clase.\n    node = MinimalService()\n\n    # Mantiene corriendo el bucle interno del nodo para poder gestionar las\n    # peticiones del cliente.\n    rclpy.spin(node)\n\n    rclpy.shutdown()\n\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_51b9921 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_51b9921();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_51b9921 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-951eae4 elementor-widget elementor-widget-text-editor\" data-id=\"951eae4\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h3>4 Creando el nodo cliente<\/h3><p>Creamos mediante el siguiente comando, en la misma ubicaci\u00f3n,\u00a0 el archivo <em><strong>client_node.py<\/strong><\/em> que va a contener el c\u00f3digo de nuestro nodo cliente.\u00a0<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bd9cb33 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"bd9cb33\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-bd9cb33\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-tomorrow\"\n            data-dark-theme=\"mdp-theme-tomorrow\"\n        >\n            \n                <pre class=\"language-shell-session copy-to-clipboard\"data-previewers=\"\"><code>touch client_node.py<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_bd9cb33 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_bd9cb33();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_bd9cb33 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-296d050 elementor-widget elementor-widget-text-editor\" data-id=\"296d050\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Abrimos el archivo y al igual que hemos hecho con el nodo servidor pegamos una de las versiones de c\u00f3digo que se muestran a continuaci\u00f3n, en funci\u00f3n de que queramos realizar la petici\u00f3n al servicio de forma <strong>s\u00edncrona<\/strong> o <strong>as\u00edncrona<\/strong> y de que queramos usar una clase o no.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-144dc3e elementor-widget elementor-widget-text-editor\" data-id=\"144dc3e\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>El c\u00f3digo se encuentra explicado en los comentarios.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-370fa96 elementor-widget elementor-widget-text-editor\" data-id=\"370fa96\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h4>4.1 Cliente con comunicaci\u00f3n s\u00edncrona<\/h4><p>En este caso el cliente realiza la petici\u00f3n al servicio y <u>su ejecuci\u00f3n se detiene<\/u> hasta recibir la respuesta.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e7188e1 elementor-widget elementor-widget-text-editor\" data-id=\"e7188e1\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Hay que destacar que, aunque el objetivo de este apartado es ver un ejemplo de cliente con comunicaci\u00f3n s\u00edncrona con el servidor, las dos versiones de c\u00f3digo que se muestran a continuaci\u00f3n realmente realizan una llamada as\u00edncrona al servicio mediante <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">.call_async()<\/span><\/code> y luego esperan a recibir la respuesta mediante <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">.spin_until_future_complete()<\/span><\/code>.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c61410e elementor-widget elementor-widget-text-editor\" data-id=\"c61410e\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Aunque rclpy tiene la funci\u00f3n <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">.call()<\/span><\/code> para realizar una verdadera llamada s\u00edncrona al servicio su uso puede causar interbloqueos, por ejemplo con <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">rclpy.spin()<\/span><\/code> si este \u00faltimo no se lanza en un hilo diferente. Es por ello que se recomienda el uso de <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">.call_async()<\/span><\/code>, que es totalmente seguro.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ff8db4e elementor-widget elementor-widget-text-editor\" data-id=\"ff8db4e\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Si de todas formas estas interesado en ver c\u00f3mo usar <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">.call()<\/span><\/code> sin provocar interbloqueos puedes echarle un ojo a <a href=\"https:\/\/docs.ros.org\/en\/humble\/How-To-Guides\/Sync-Vs-Async.html\">Synchronous vs. asynchronous service clients<\/a> en la documentaci\u00f3n de ROS2 Humble Hawksbill.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-529dbfa elementor-widget elementor-widget-text-editor\" data-id=\"529dbfa\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h5>4.1.1 Sin usar clases<\/h5>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dcc22e8 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"dcc22e8\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-dcc22e8\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-xonokai\"\n            data-dark-theme=\"mdp-theme-xonokai\"\n        >\n            \n                <pre class=\"language-python copy-to-clipboard\"data-previewers=\"\"><code># Importa el tipo de servicio AddTwoInts del paquete example_interface. \nfrom example_interfaces.srv import AddTwoInts\n\n# Importa la libreria Python de ROS 2.\nimport rclpy\n\n\ndef main(args=None):\n\n    # Inicializa la librer&iacute;a Python de ROS2.\n    rclpy.init(args=args)\n\n    # Crea el nodo.\n    node = rclpy.create_node(&#039;minimal_client&#039;)\n\n    # Crea un cliente y define el tipo, su nombre.\n    cli = node.create_client(AddTwoInts, &#039;add_two_ints&#039;)\n\n    # Crea una variable de tipo petici&oacute;n y almacena en ella la informaci&oacute;n\n    # que se proporcionar&aacute; al servicio.\n    req = AddTwoInts.Request()\n    req.a = 41\n    req.b = 1\n\n    # Espera a que el servicio est&eacute; disponible.\n    while not cli.wait_for_service(timeout_sec=1.0):\n        node.get_logger().info(&#039;service not available, waiting again...&#039;)\n\n    # Env&iacute;a la petici&oacute;n al servicio.\n    future = cli.call_async(req)\n\n    # Espera hasta que el servicio haya proporcionado la respuesta.\n    rclpy.spin_until_future_complete(node, future)\n\n    # Obtiene la informaci&oacute;n de la respuesta.\n    result = future.result()\n\n    # Muestra en la consola los valores suministrados al servicio\n    # y el resultado recibido como respuesta.\n    node.get_logger().info(\n        &#039;Result of add_two_ints: for %d + %d = %d&#039; %\n        (req.a, req.b, result.sum))\n\n    # Destruye expl&iacute;citamente el servicio. Es opcional ya que el recolector de\n    # basura realiza esta acci&oacute;n cuandop destruye el objeto nodo.\n    node.destroy_service(srv)\n\n    # Destruye el nodo.\n    node.destroy_node()\n\n    rclpy.shutdown()\n\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_dcc22e8 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_dcc22e8();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_dcc22e8 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-33cd4ce elementor-widget elementor-widget-text-editor\" data-id=\"33cd4ce\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h5>4.1.1 Usando una clase<\/h5>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7527e79 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"7527e79\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-7527e79\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-xonokai\"\n            data-dark-theme=\"mdp-theme-xonokai\"\n        >\n            \n                <pre class=\"language-python copy-to-clipboard\"data-previewers=\"\"><code># Importa el tipo de servicio AddTwoInts del paquete example_interface. \nfrom example_interfaces.srv import AddTwoInts\n\n# Importa la libreria Python de ROS 2 y, espec&iacute;ficamente, la clase node.\nimport rclpy\nfrom rclpy.node import Node\n\n# Definimos la clase que va a crear el nodo y contiene la funci&oacute;n que realizar&aacute;\n# la petici&oacute;n al servicio.\nclass MinimalClient(Node):\n\n    # El constructor de la clase inicializa el nodo con el nombre minimal_client_async.\n    # Luego, crea un servicio y define el tipo, su nombre y el de la funci&oacute;n que\n    # se ejecutar&aacute; al recibir una petici&oacute;n. Y finalmente espera a que el servicio\n    # est&eacute; disponible.\n    def __init__(self):\n        # El constructor de la clase inicializa el nodo y le asigna el nombre \n        # minimal_client_async.\n        super().__init__(&#039;minimal_client_async&#039;)\n\n        # Crea un servicio y define el tipo, su nombre y el de la funci&oacute;n que\n        # se ejecutar&aacute; al recibir una petici&oacute;n.\n        self.cli = self.create_client(AddTwoInts, &#039;add_two_ints&#039;)\n\n        # Espera a que el servicio est&eacute; disponible.\n        while not self.cli.wait_for_service(timeout_sec=1.0):\n            self.get_logger().info(&#039;service not available, waiting again...&#039;)\n\n        # Crea la variable que almacenar&aacute; los datos que se enviar&aacute;n en la petici&oacute;n\n        # al servicio.\n        self.req = AddTwoInts.Request()\n\n    # Define la funci&oacute;n que realiza la petici&oacute;n al servicio.\n    def send_request(self):\n        self.req.a = 41\n        self.req.b = 1\n        self.future = self.cli.call_async(self.req)\n\n\ndef main(args=None):\n\n    # Inicializa la librer&iacute;a Python de ROS2.\n    rclpy.init(args=args)\n\n    # Crea el nodo.\n    node = MinimalClient()\n\n    # Realiza la petici&oacute;n al servicio.\n    node.send_request()\n\n    # Espera hasta que el servicio haya proporcionado la respuesta.\n    rclpy.spin_until_future_complete(node, node.future)\n\n    # Lee la informaci&oacute;n de la respuesta.\n    result = node.future.result()\n\n    # Muestra la informaci&oacute;n en la consola.\n    node.get_logger().info(\n        &#039;Result of add_two_ints: for %d + %d = %d&#039; %\n        (node.req.a, node.req.b, result.sum))\n\n\n    # Destruye el nodo.\n    node.destroy_node()\n    \n    rclpy.shutdown()\n\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_7527e79 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_7527e79();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_7527e79 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8ad4db2 elementor-widget elementor-widget-text-editor\" data-id=\"8ad4db2\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h4>4.2 Cliente con comunicaci\u00f3n as\u00edncrona<\/h4>\nEn este caso el cliente realiza la petici\u00f3n al servicio pero <span style=\"text-decoration: underline;\">no detiene su ejecuci\u00f3n<\/span>, por lo que es necesario en el c\u00f3digo crear un bucle y comprobar que se ha recibido la respuesta usando <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">.done()<\/span><\/code> antes de acceder al resultado con <code class=\"docutils literal notranslate\"><span class=\"pre\" style=\"padding-left: 5px; padding-right: 5px; background-color: #f5f5f5; color: blue; border: 1px solid blue;\">.result()<\/span><\/code>.\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-489da88 elementor-widget elementor-widget-text-editor\" data-id=\"489da88\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h5>4.2.1 Sin usar clases<\/h5>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-79875af elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"79875af\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-79875af\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-xonokai\"\n            data-dark-theme=\"mdp-theme-xonokai\"\n        >\n            \n                <pre class=\"language-python copy-to-clipboard\"data-previewers=\"\"><code># Importa el tipo de servicio AddTwoInts del paquete example_interface. \nfrom example_interfaces.srv import AddTwoInts\n\n# Importa la libreria Python de ROS 2.\nimport rclpy\n\n\ndef main(args=None):\n\n    # Inicializa la librer&iacute;a Python de ROS2.\n    rclpy.init(args=args)\n\n    # Crea el nodo.\n    node = rclpy.create_node(&#039;minimal_client_async&#039;)\n\n    # Crea un cliente y define el tipo, su nombre.\n    cli = node.create_client(AddTwoInts, &#039;add_two_ints&#039;)\n\n    # Crea una variable de tipo petici&oacute;n y almacena en ella la informaci&oacute;n\n    # que se proporcionar&aacute; al servicio.\n    req = AddTwoInts.Request()\n    req.a = 41\n    req.b = 1\n\n    # Espera a que el servicio est&eacute; disponible.\n    while not cli.wait_for_service(timeout_sec=1.0):\n        node.get_logger().info(&#039;service not available, waiting again...&#039;)\n\n    # Env&iacute;a la petici&oacute;n al servicio.\n    future = cli.call_async(req)\n\n    # Bucle infinito hasta que se reciba la respuesta del servicio.\n    while rclpy.ok():\n\n        # Ejecuta una sola vez el bucle interno del nodo, actualizando los \n        # buffers de entrada (llegada de topics, respuestas de servicios...).  \n        rclpy.spin_once(node)\n\n        # Comprueba si el servicio ha proporcionado la respuesta.\n        if future.done():\n\n            # Lee la informaci&oacute;n de la respuesta.\n            result = future.result()\n\n            # Muestra la informaci&oacute;n en la consola.\n            node.get_logger().info(\n                &#039;Result of add_two_ints: for %d + %d = %d&#039; %\n                (req.a, req.b, result.sum))\n\n            # Interrumpe el bucle.\n            break\n\n\n    # Destruye expl&iacute;citamente el servicio. Es opcional ya que el recolector de\n    # basura realiza esta acci&oacute;n cuandop destruye el objeto nodo.\n    node.destroy_service(srv)\n\n    # Destruye el nodo.\n    node.destroy_node()\n\n    rclpy.shutdown()\n\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_79875af = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_79875af();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_79875af );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8c8db81 elementor-widget elementor-widget-text-editor\" data-id=\"8c8db81\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h5>4.2.2 Usando una clase<\/h5>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f0d1ecb elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"f0d1ecb\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-f0d1ecb\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-xonokai\"\n            data-dark-theme=\"mdp-theme-xonokai\"\n        >\n            \n                <pre class=\"language-python copy-to-clipboard\"data-previewers=\"\"><code># Importa el tipo de servicio AddTwoInts del paquete example_interface. \nfrom example_interfaces.srv import AddTwoInts\n\n# Importa la libreria Python de ROS 2 y, espec&iacute;ficamente, la clase node.\nimport rclpy\nfrom rclpy.node import Node\n\n# Definimos la clase que va a crear el nodo y contiene la funci&oacute;n que realizar&aacute;\n# la petici&oacute;n al servicio.\nclass MinimalClientAsync(Node):\n\n    # El constructor de la clase inicializa el nodo con el nombre minimal_client_async.\n    # Luego, crea un servicio y define el tipo, su nombre y el de la funci&oacute;n que\n    # se ejecutar&aacute; al recibir una petici&oacute;n. Y finalmente espera a que el servicio\n    # est&eacute; disponible.\n    def __init__(self):\n        # El constructor de la clase inicializa el nodo y le asigna el nombre \n        # minimal_client_async.\n        super().__init__(&#039;minimal_client_async&#039;)\n\n        # Crea un servicio y define el tipo, su nombre y el de la funci&oacute;n que\n        # se ejecutar&aacute; al recibir una petici&oacute;n.\n        self.cli = self.create_client(AddTwoInts, &#039;add_two_ints&#039;)\n\n        # Espera a que el servicio est&eacute; disponible.\n        while not self.cli.wait_for_service(timeout_sec=1.0):\n            self.get_logger().info(&#039;service not available, waiting again...&#039;)\n\n        # Crea la variable que almacenar&aacute; los datos que se enviar&aacute;n en la petici&oacute;n\n        # al servicio.\n        self.req = AddTwoInts.Request()\n\n    # Define la funci&oacute;n que realiza la petici&oacute;n al servicio.\n    def send_request(self):\n        self.req.a = 41\n        self.req.b = 1\n        self.future = self.cli.call_async(self.req)\n\n\ndef main(args=None):\n\n    # Inicializa la librer&iacute;a Python de ROS2.\n    rclpy.init(args=args)\n\n    # Crea el nodo.\n    node = MinimalClientAsync()\n\n    # Realiza la petici&oacute;n al servicio.\n    node.send_request()\n\n    # Bucle infinito hasta que se reciba la respuesta del servicio.\n    while rclpy.ok():\n\n        # Ejecuta una sola vez el bucle interno del nodo, actualizando los \n        # buffers de entrada (llegada de topics, respuestas de servicios...). \n        rclpy.spin_once(node)\n\n        # Comprueba si el servicio ha proporcionado la respuesta.\n        if node.future.done():\n\n            # Lee la informaci&oacute;n de la respuesta.\n            result = node.future.result()\n\n            # Muestra la informaci&oacute;n en la consola.\n            node.get_logger().info(\n                &#039;Result of add_two_ints: for %d + %d = %d&#039; %\n                (node.req.a, node.req.b, result.sum))\n\n            # Interrumpe el bucle.\n            break\n\n    # Destruye el nodo.\n    node.destroy_node()\n    \n    rclpy.shutdown()\n\n\nif __name__ == &#039;__main__&#039;:\n    main()<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_f0d1ecb = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_f0d1ecb();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_f0d1ecb );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9b4542f elementor-widget elementor-widget-text-editor\" data-id=\"9b4542f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h3>5 Incorporando los puntos de entrada en setup.py<\/h3><p>El \u00faltimo paso es editar el archivo setup.py para a\u00f1adir al array <strong><em>entry_points<\/em><\/strong> los puntos de entrada para de los scripts de los nodos servidor y cliente, de modo que puedan ejecutarse mediante <em>ros2 run<\/em>.\u00a0<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fa5a6f2 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"fa5a6f2\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-fa5a6f2\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-xonokai\"\n            data-dark-theme=\"mdp-theme-xonokai\"\n        >\n            \n                <pre class=\"language-python copy-to-clipboard\"data-previewers=\"\"><code>from setuptools import setup\n\npackage_name = &#039;py_srvcli&#039;\n\nsetup(\n    name=package_name,\n    version=&#039;0.0.0&#039;,\n    packages=[package_name],\n    data_files=[\n        (&#039;share\/ament_index\/resource_index\/packages&#039;,\n            [&#039;resource\/&#039; + package_name]),\n        (&#039;share\/&#039; + package_name, [&#039;package.xml&#039;]),\n    ],\n    install_requires=[&#039;setuptools&#039;],\n    zip_safe=True,\n    maintainer=&#039;ros&#039;,\n    maintainer_email=&#039;TODO@gmail.com&#039;,\n    description=&#039;TODO: Package description&#039;,\n    license=&#039;TODO: License declaration&#039;,\n    tests_require=[&#039;pytest&#039;],\n    entry_points={\n        &#039;console_scripts&#039;: [\n              &#039;server = py_srvcli.server_node:main&#039;,\n              &#039;client = py_srvcli.client_node:main&#039;,\n        ],\n    },\n)<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_fa5a6f2 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_fa5a6f2();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_fa5a6f2 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e2d4cc7 elementor-widget elementor-widget-text-editor\" data-id=\"e2d4cc7\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<h3>6 Ejecutando los nodos<\/h3><p>Una vez que ya tenemos preparado nuestro paquete lo compilamos desde el directorio ra\u00edz de nuestro espacio de trabajo:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f684480 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"f684480\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-f684480\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-tomorrow\"\n            data-dark-theme=\"mdp-theme-tomorrow\"\n        >\n            \n                <pre class=\"language-shell-session copy-to-clipboard\"data-previewers=\"\"><code>colcon build --packages-select py_srvcli\n. install\/setup.bash<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_f684480 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_f684480();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_f684480 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-da4a1d4 elementor-widget elementor-widget-text-editor\" data-id=\"da4a1d4\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Seguidamente ejecutamos el nodo servidor mediante el siguiente comando:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5b23df4 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"5b23df4\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-5b23df4\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-tomorrow\"\n            data-dark-theme=\"mdp-theme-tomorrow\"\n        >\n            \n                <pre class=\"language-shell-session copy-to-clipboard\"data-previewers=\"\"><code>ros2 run py_srvcli server<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_5b23df4 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_5b23df4();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_5b23df4 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-96a2407 elementor-widget elementor-widget-text-editor\" data-id=\"96a2407\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Y finalmente abrimos otro terminal y ejecutamos el nodo cliente:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b7ff3f7 elementor-widget elementor-widget-mdp-coder-elementor\" data-id=\"b7ff3f7\" data-element_type=\"widget\" data-widget_type=\"mdp-coder-elementor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t        <!-- Start Coder for Elementor WordPress Plugin -->\n        <div\n            id=\"mdp-coder-b7ff3f7\"\n            class=\"mdp-coder-elementor-box\"\n            data-theme=\"mdp-theme-tomorrow\"\n            data-dark-theme=\"mdp-theme-tomorrow\"\n        >\n            \n                <pre class=\"language-shell-session copy-to-clipboard\"data-previewers=\"\"><code>ros2 run py_srvcli client<\/code><\/pre>\n                    <\/div>\n                <script>\n            \"use strict\";\n\n            \/** Handler when the DOM is fully loaded. *\/\n            let callback_b7ff3f7 = function() {\n\n                \/** Set theme for coder widget. *\/\n                function setTheme() {\n\n                    \/** Foreach Code Widget. *\/\n                    let coderBoxes = document.querySelectorAll( '.mdp-coder-elementor-box' );\n\n                    for ( let coderBox of coderBoxes ) {\n\n                        let lightTheme = coderBox.dataset.theme;\n                        let darkTheme = coderBox.dataset.darkTheme;\n\n                        coderBox.className = '';\n                        if ( window.matchMedia && window.matchMedia( '(prefers-color-scheme: dark)' ).matches ) {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + darkTheme;\n\n                        } else {\n\n                            coderBox.className = 'mdp-coder-elementor-box ' + lightTheme;\n\n                        }\n\n                    }\n\n                }\n                setTheme();\n\n\n                \/** Watch for changes color-scheme. *\/\n                window.matchMedia(\"(prefers-color-scheme: dark)\").addListener( function() {\n                    setTheme();\n                } );\n\n                \n                if ( typeof Prism !== 'undefined' ) {\n\n                    Prism.plugins.autoloader.languages_path = 'https:\/\/robotica-facil-con-ros2.es\/wp-content\/plugins\/coder-elementor\/js\/prism\/components\/';\n                    Prism.highlightAll();\n                    Prism.fileHighlight();\n\n                }\n\n                \n            };\n\n            if (\n                document.readyState === \"complete\" ||\n                ( document.readyState !== \"loading\" && !document.documentElement.doScroll )\n            ) {\n                callback_b7ff3f7();\n            } else {\n                document.addEventListener( \"DOMContentLoaded\", callback_b7ff3f7 );\n            }\n\n        <\/script>\n                <!-- End Coder for Elementor WordPress Plugin -->\n\n        \t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-182ad44 elementor-widget elementor-widget-text-editor\" data-id=\"182ad44\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Si hemos seguido los pasos correctamente deber\u00edamos ver en un terminal los datos enviados por el cliente y en el otro la respuesta del servidor.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-76378a0 elementor-widget elementor-widget-image\" data-id=\"76378a0\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"786\" height=\"533\" src=\"https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/service-server-output.png\" class=\"attachment-large size-large wp-image-6554\" alt=\"Servicios - Salida por consola del nodo servidor\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8722d4d elementor-widget elementor-widget-image\" data-id=\"8722d4d\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<img decoding=\"async\" width=\"759\" height=\"533\" src=\"https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/service-client-output.png\" class=\"attachment-large size-large wp-image-6553\" alt=\"Servicios - Salida por consola del nodo cliente\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>En este art\u00edculo aprender\u00e1s a comunicar dos nodos mediante un servicio usando Python.<\/p>\n","protected":false},"author":1,"featured_media":6611,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[5],"tags":[30],"class_list":["post-6251","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ros2","tag-servicios"],"aioseo_notices":[],"rttpg_featured_image_url":{"full":["https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/Services-1.png",840,426,false],"landscape":["https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/Services-1.png",840,426,false],"portraits":["https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/Services-1.png",840,426,false],"thumbnail":["https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/Services-1-150x150.png",150,150,true],"medium":["https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/Services-1-300x152.png",300,152,true],"large":["https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/Services-1.png",840,426,false],"1536x1536":["https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/Services-1.png",840,426,false],"2048x2048":["https:\/\/robotica-facil-con-ros2.es\/wp-content\/uploads\/2022\/09\/Services-1.png",840,426,false]},"rttpg_author":{"display_name":"Jose Enrique Cabrera","author_link":"https:\/\/robotica-facil-con-ros2.es\/?author=1"},"rttpg_comment":0,"rttpg_category":"<a href=\"https:\/\/robotica-facil-con-ros2.es\/?cat=5\" rel=\"category\">ROS2<\/a>","rttpg_excerpt":"En este art\u00edculo aprender\u00e1s a comunicar dos nodos mediante un servicio usando Python.","_links":{"self":[{"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=\/wp\/v2\/posts\/6251","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6251"}],"version-history":[{"count":378,"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=\/wp\/v2\/posts\/6251\/revisions"}],"predecessor-version":[{"id":8127,"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=\/wp\/v2\/posts\/6251\/revisions\/8127"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=\/wp\/v2\/media\/6611"}],"wp:attachment":[{"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6251"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6251"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/robotica-facil-con-ros2.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6251"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}