{"id":3749,"date":"2025-08-14T14:23:31","date_gmt":"2025-08-14T14:23:31","guid":{"rendered":"https:\/\/learnbydoing.dev\/?p=3749"},"modified":"2026-01-10T21:59:46","modified_gmt":"2026-01-10T21:59:46","slug":"how-to-build-and-test-a-ros-2-action-server-in-python","status":"publish","type":"post","link":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/","title":{"rendered":"How to Build and Test a ROS 2 Action Server in Python"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"3749\" class=\"elementor elementor-3749\" data-elementor-post-type=\"post\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e28ab35 e-flex e-con-boxed e-con e-parent\" data-id=\"e28ab35\" data-element_type=\"container\" data-e-type=\"container\" id=\"content\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t<div class=\"elementor-element elementor-element-62ab6e3 e-con-full e-flex e-con e-child\" data-id=\"62ab6e3\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-62ab203 elementor-align-center elementor-widget elementor-widget-post-info\" data-id=\"62ab203\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"post-info.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul class=\"elementor-inline-items elementor-icon-list-items elementor-post-info\">\n\t\t\t\t\t\t\t\t<li class=\"elementor-icon-list-item elementor-repeater-item-2c98363 elementor-inline-item\" itemprop=\"about\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-icon-list-text elementor-post-info__item elementor-post-info__item--type-terms\">\n\t\t\t\t\t\t\t\t\t\t<span class=\"elementor-post-info__terms-list\">\n\t\t\t\t<span class=\"elementor-post-info__terms-list-item\">ROS 2<\/span>, <span class=\"elementor-post-info__terms-list-item\">Tutorials<\/span>\t\t\t\t<\/span>\n\t\t\t\t\t<\/span>\n\t\t\t\t\t\t\t\t<\/li>\n\t\t\t\t<\/ul>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-0650e10 e-con-full e-flex e-con e-child\" data-id=\"0650e10\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-ac19582 elementor-view-default elementor-widget elementor-widget-icon\" data-id=\"ac19582\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"icon.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-icon-wrapper\">\n\t\t\t<div class=\"elementor-icon\">\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"75\" height=\"75\" viewBox=\"0 0 75 75\" fill=\"none\"><path d=\"M74.9999 75H13.1889V73.0002H71.5859L0.460938 1.87521L1.87515 0.460999L73.0001 71.586V13.1889H74.9999V75Z\" fill=\"white\"><\/path><\/svg>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-47aa245d e-flex e-con-boxed e-con e-parent\" data-id=\"47aa245d\" data-element_type=\"container\" data-e-type=\"container\" data-settings=\"{&quot;background_background&quot;:&quot;classic&quot;}\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-206a001 elementor-widget elementor-widget-image\" data-id=\"206a001\" data-element_type=\"widget\" data-e-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\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"1920\" height=\"1080\" src=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp\" class=\"attachment-full size-full wp-image-3763\" alt=\"\" srcset=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp 1920w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-300x169.webp 300w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1024x576.webp 1024w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-768x432.webp 768w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1536x864.webp 1536w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-18x10.webp 18w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/>\t\t\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-4bc31ca3 elementor-widget elementor-widget-text-editor\" data-id=\"4bc31ca3\" data-element_type=\"widget\" data-e-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\t\t<p data-start=\"406\" data-end=\"768\">When working with robots, not every task is instantaneous. Some operations take time: navigating across a room, picking up an object, scanning an area, or performing a long computation.<br \/><br data-start=\"591\" data-end=\"594\" \/>In ROS 2, these \u201clong-running\u201d tasks need a special way for nodes to talk to each other \u2014 one that allows <strong data-start=\"700\" data-end=\"720\">progress updates<\/strong> and <strong data-start=\"725\" data-end=\"767\">the ability to stop the task if needed<\/strong>.<br \/><br \/><\/p><p data-start=\"770\" data-end=\"812\">This is where <strong data-start=\"784\" data-end=\"801\">ROS 2 Actions<\/strong> come in.<br \/><br \/><\/p><p data-start=\"814\" data-end=\"1159\">In this article, we\u2019ll explore what Actions are, why they\u2019re different from Topics and Services, and then we\u2019ll create a fully functional <strong data-start=\"952\" data-end=\"979\">Action Server in Python<\/strong> that calculates the <strong data-start=\"1000\" data-end=\"1022\">Fibonacci sequence<\/strong>. This example will serve as a starting point for more advanced action-based tasks you might want to implement in your robotics projects.<\/p>\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-12a4ca0 elementor-widget elementor-widget-text-editor\" data-id=\"12a4ca0\" data-element_type=\"widget\" data-e-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\t\t<h2 data-start=\"3173\" data-end=\"3210\"><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f50d.svg\" alt=\"\ud83d\udd0d\" \/><strong>\u00a0What\u2019s a ROS 2 Action?<\/strong><\/h2>\n<p data-start=\"1198\" data-end=\"1295\">In ROS 2, nodes communicate using three main patterns: <strong data-start=\"1253\" data-end=\"1263\">Topics<\/strong>, <strong data-start=\"1265\" data-end=\"1277\">Services<\/strong>, and <strong data-start=\"1283\" data-end=\"1294\">Actions<\/strong>.<\/p>\n<div class=\"_tableContainer_1rjym_1\">\n<div class=\"_tableWrapper_1rjym_13 group flex w-fit flex-col-reverse\" tabindex=\"-1\">\n<table class=\"w-fit min-w-(--thread-content-width)\" data-start=\"1297\" data-end=\"1693\">\n<thead data-start=\"1297\" data-end=\"1340\">\n<tr data-start=\"1297\" data-end=\"1340\">\n<th data-start=\"1297\" data-end=\"1318\" data-col-size=\"sm\">Communication Type<\/th>\n<th data-start=\"1318\" data-end=\"1329\" data-col-size=\"md\">Best For<\/th>\n<th data-start=\"1329\" data-end=\"1340\" data-col-size=\"md\">Pattern<\/th>\n<\/tr>\n<\/thead>\n<tbody data-start=\"1385\" data-end=\"1693\">\n<tr data-start=\"1385\" data-end=\"1484\">\n<td data-start=\"1385\" data-end=\"1397\" data-col-size=\"sm\"><strong data-start=\"1387\" data-end=\"1396\">Topic<\/strong><\/td>\n<td data-col-size=\"md\" data-start=\"1397\" data-end=\"1461\">Continuous data streams (e.g., sensor readings, camera feeds)<\/td>\n<td data-col-size=\"md\" data-start=\"1461\" data-end=\"1484\">Publish \/ Subscribe<\/td>\n<\/tr>\n<tr data-start=\"1485\" data-end=\"1576\">\n<td data-start=\"1485\" data-end=\"1499\" data-col-size=\"sm\"><strong data-start=\"1487\" data-end=\"1498\">Service<\/strong><\/td>\n<td data-col-size=\"md\" data-start=\"1499\" data-end=\"1557\">Instant request\u2013response (e.g., converting coordinates)<\/td>\n<td data-col-size=\"md\" data-start=\"1557\" data-end=\"1576\">Request \/ Reply<\/td>\n<\/tr>\n<tr data-start=\"1577\" data-end=\"1693\">\n<td data-start=\"1577\" data-end=\"1590\" data-col-size=\"sm\"><strong data-start=\"1579\" data-end=\"1589\">Action<\/strong><\/td>\n<td data-col-size=\"md\" data-start=\"1590\" data-end=\"1644\">Long-running tasks (e.g., navigation, manipulation)<\/td>\n<td data-col-size=\"md\" data-start=\"1644\" data-end=\"1693\">Goal \u2192 Feedback \u2192 Result (with Cancel option)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<div class=\"sticky end-(--thread-content-margin) h-0 self-end select-none\">\n<div class=\"absolute end-0 flex items-end\">\u00a0<\/div>\n<\/div>\n<\/div>\n<\/div>\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-cbe45eb elementor-widget elementor-widget-text-editor\" data-id=\"cbe45eb\" data-element_type=\"widget\" data-e-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\t\t<h2 data-start=\"3173\" data-end=\"3210\"><strong><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f914.svg\" alt=\"\ud83e\udd14\" \/> <\/strong><strong>Why Not Just Use Services?<\/strong><\/h2>\n<p data-start=\"1731\" data-end=\"1965\">Services are perfect for quick tasks. You send a request, wait for the reply, and you\u2019re done. But if the task takes 5, 10, or 30 seconds, the client is left waiting with no idea what\u2019s happening \u2014 and no way to stop it mid-execution.<\/p>\n<p data-start=\"1967\" data-end=\"2009\">Actions solve this problem by introducing:<\/p>\n<ul data-start=\"2010\" data-end=\"2156\">\n<li data-start=\"2010\" data-end=\"2084\">\n<p data-start=\"2012\" data-end=\"2084\"><strong data-start=\"2012\" data-end=\"2033\">Feedback messages<\/strong> \u2014 progress updates sent while the task is running.<\/p>\n<\/li>\n<li data-start=\"2085\" data-end=\"2156\">\n<p data-start=\"2087\" data-end=\"2156\"><strong data-start=\"2087\" data-end=\"2106\">Cancel messages<\/strong> \u2014 the ability to stop a task before it completes.<\/p>\n<\/li>\n<\/ul>\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-03e5f29 elementor-widget elementor-widget-text-editor\" data-id=\"03e5f29\" data-element_type=\"widget\" data-e-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\t\t<h2 data-start=\"6710\" data-end=\"6739\"><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f680.svg\" alt=\"\ud83d\ude80\" \/> <strong>The Goal \u2192 Feedback \u2192 Result Workflow<\/strong><\/h2>\n<p data-start=\"2206\" data-end=\"2239\">Here\u2019s how Actions work in ROS 2:<\/p>\n<ol data-start=\"2241\" data-end=\"2868\">\n<li data-start=\"2241\" data-end=\"2395\">\n<p data-start=\"2244\" data-end=\"2395\"><strong data-start=\"2244\" data-end=\"2252\">Goal<\/strong> \u2014 The client sends the task parameters.<br data-start=\"2292\" data-end=\"2295\" \/>Example: \u201cMove to coordinates (x: 1.2, y: 0.5)\u201d or \u201cCalculate Fibonacci sequence up to order 10.\u201d<\/p>\n<\/li>\n<li data-start=\"2400\" data-end=\"2566\">\n<p data-start=\"2403\" data-end=\"2566\"><strong data-start=\"2403\" data-end=\"2415\">Feedback<\/strong> \u2014 While the server works, it sends updates to the client.<br data-start=\"2473\" data-end=\"2476\" \/>Example: \u201cI\u2019ve reached 50% of the path\u201d or \u201cCurrent Fibonacci sequence: 0, 1, 1, 2, 3\u2026\u201d<\/p>\n<\/li>\n<li data-start=\"2571\" data-end=\"2737\">\n<p data-start=\"2574\" data-end=\"2737\"><strong data-start=\"2574\" data-end=\"2584\">Result<\/strong> \u2014 When the task finishes, the server sends the final outcome.<br data-start=\"2646\" data-end=\"2649\" \/>Example: \u201cArrived at destination\u201d or \u201cFinal Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8\u2026\u201d<\/p>\n<\/li>\n<li data-start=\"2739\" data-end=\"2868\">\n<p data-start=\"2742\" data-end=\"2868\"><strong data-start=\"2742\" data-end=\"2763\">Cancel (optional)<\/strong> \u2014 At any time, the client can stop the task.<br data-start=\"2808\" data-end=\"2811\" \/>Example: \u201cStop moving, the target object disappeared.\u201d<\/p>\n<\/li>\n<\/ol>\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-797aeee elementor-widget elementor-widget-image\" data-id=\"797aeee\" data-element_type=\"widget\" data-e-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\t\t<img decoding=\"async\" width=\"800\" height=\"450\" src=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-4-1024x576.gif\" class=\"attachment-large size-large wp-image-3758\" alt=\"\" srcset=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-4-1024x576.gif 1024w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-4-300x169.gif 300w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-4-768x432.gif 768w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-4-1536x864.gif 1536w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-4-18x10.gif 18w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/>\t\t\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-a3f438c elementor-widget elementor-widget-text-editor\" data-id=\"a3f438c\" data-element_type=\"widget\" data-e-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\t\t<h2 data-start=\"1792\" data-end=\"1824\"><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f4e6.svg\" alt=\"\ud83d\udce6\" \/> <strong>A Practical Robotics Example<\/strong><\/h2><p data-start=\"2909\" data-end=\"2926\">Imagine you have:<\/p><ul data-start=\"2927\" data-end=\"3055\"><li data-start=\"2927\" data-end=\"2982\"><p data-start=\"2929\" data-end=\"2982\">A <strong data-start=\"2931\" data-end=\"2946\">vision node<\/strong> that detects the position of a pen.<\/p><\/li><li data-start=\"2983\" data-end=\"3055\"><p data-start=\"2985\" data-end=\"3055\">A <strong data-start=\"2987\" data-end=\"3008\">manipulation node<\/strong> that can move the robot\u2019s arm to grab objects.<br \/><br \/><\/p><\/li><\/ul><p data-start=\"3057\" data-end=\"3120\">You could design the manipulation node as an <strong data-start=\"3102\" data-end=\"3119\">Action Server<\/strong>:<br \/><br \/><\/p><ol data-start=\"3121\" data-end=\"3576\"><li data-start=\"3121\" data-end=\"3246\"><p data-start=\"3124\" data-end=\"3246\">When the pen is detected, the vision node sends a <strong data-start=\"3174\" data-end=\"3182\">goal<\/strong> to the manipulation node: \u201cGrab the pen at position (x, y, z).\u201d<\/p><\/li><li data-start=\"3247\" data-end=\"3369\"><p data-start=\"3250\" data-end=\"3369\">The manipulation node starts moving the arm and sends <strong data-start=\"3304\" data-end=\"3316\">feedback<\/strong> like \u201cArm halfway to position\u201d or \u201cGripper opening.\u201d<\/p><\/li><li data-start=\"3370\" data-end=\"3486\"><p data-start=\"3373\" data-end=\"3486\">If the pen falls off the table, the vision node can send a <strong data-start=\"3432\" data-end=\"3442\">cancel<\/strong> request, and the server stops the movement.<\/p><\/li><li data-start=\"3487\" data-end=\"3576\"><p data-start=\"3490\" data-end=\"3576\">Regardless of whether it completes or is canceled, the server sends a <strong data-start=\"3560\" data-end=\"3570\">result<\/strong> back.<br \/><br \/><\/p><\/li><\/ol><p data-start=\"3578\" data-end=\"3640\">This flexibility is what makes Actions essential for robotics.<\/p>\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-95c0b6c elementor-widget elementor-widget-image\" data-id=\"95c0b6c\" data-element_type=\"widget\" data-e-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\t\t<img decoding=\"async\" width=\"800\" height=\"450\" src=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-5-1024x576.gif\" class=\"attachment-large size-large wp-image-3759\" alt=\"\" srcset=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-5-1024x576.gif 1024w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-5-300x169.gif 300w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-5-768x432.gif 768w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-5-1536x864.gif 1536w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Progetto-senza-titolo-5-18x10.gif 18w\" sizes=\"(max-width: 800px) 100vw, 800px\" \/>\t\t\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-3f8b944 elementor-widget elementor-widget-text-editor\" data-id=\"3f8b944\" data-element_type=\"widget\" data-e-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\t\t<h2 data-start=\"6581\" data-end=\"6611\"><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f6e0.svg\" alt=\"\ud83d\udee0\ufe0f\" \/> <strong>Our Project: Fibonacci Action Server in Python<\/strong><\/h2>\n<p data-start=\"3698\" data-end=\"3849\">For our first practical Action example, we\u2019ll implement a Python Action Server that calculates the <strong data-start=\"3797\" data-end=\"3819\">Fibonacci sequence<\/strong> up to a user-defined order.<br \/><br \/><\/p>\n<p data-start=\"3698\" data-end=\"3849\">The Fibonacci sequence is a series where each number is the sum of the two preceding ones, starting from 0 and 1.<br \/><br \/><\/p>\n<h5 data-start=\"3851\" data-end=\"3867\"><strong>Why Fibonacci?<\/strong><br \/><br \/><\/h5>\n<ul data-start=\"3868\" data-end=\"4071\">\n<li data-start=\"3868\" data-end=\"3896\">\n<p data-start=\"3870\" data-end=\"3896\">It\u2019s simple to understand.<\/p>\n<\/li>\n<li data-start=\"3897\" data-end=\"3974\">\n<p data-start=\"3899\" data-end=\"3974\">It allows us to focus on the Action Server logic instead of robot hardware.<\/p>\n<\/li>\n<li data-start=\"3975\" data-end=\"4071\">\n<p data-start=\"3977\" data-end=\"4071\">It gives us a natural way to send progress updates (feedback) after each number is calculated.<\/p>\n<\/li>\n<\/ul>\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-accb672 elementor-widget elementor-widget-text-editor\" data-id=\"accb672\" data-element_type=\"widget\" data-e-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\t\t<h3><strong>Step-by-Step Implementation<\/strong><\/h3><p>We\u2019ll create our Action Server in the <code data-start=\"4150\" data-end=\"4174\">arduinobot_py_examples<\/code> package.<\/p>\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-11c975d elementor-widget elementor-widget-text-editor\" data-id=\"11c975d\" data-element_type=\"widget\" data-e-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\t\t<h2 data-start=\"1792\" data-end=\"1824\"><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f4e6.svg\" alt=\"\ud83d\udce6\" \/> <strong>Create the Action Definition<\/strong><\/h2>\n<p data-start=\"4223\" data-end=\"4366\">In ROS 2, an action is defined in an <code data-start=\"4260\" data-end=\"4269\">.action<\/code> file inside an <code data-start=\"4285\" data-end=\"4293\">action<\/code> folder of a package. Let\u2019s define ours in the <code data-start=\"4340\" data-end=\"4357\">arduinobot_msgs<\/code> package.<\/p>\n<p data-start=\"4368\" data-end=\"4419\">File:\u00a0 <code data-start=\"4378\" data-end=\"4419\">arduinobot_msgs\/action\/Fibonacci.action<\/code><\/p>\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-66d9afa elementor-widget elementor-widget-code-highlight\" data-id=\"66d9afa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language- \">\n\t\t\t\t<code readonly=\"true\" class=\"language-\">\n\t\t\t\t\t<xmp># Goal\r\nint32 order\r\n---\r\n# Result\r\nint32[] sequence\r\n---\r\n# Feedback\r\nint32[] partial_sequence\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d5889a3 elementor-widget elementor-widget-text-editor\" data-id=\"d5889a3\" data-element_type=\"widget\" data-e-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\t\t<ul><li data-start=\"4526\" data-end=\"4600\"><p data-start=\"4528\" data-end=\"4600\"><strong data-start=\"4528\" data-end=\"4537\">Goal:<\/strong> One integer (<code data-start=\"4551\" data-end=\"4558\">order<\/code>) \u2014 the length of the sequence to compute.<\/p><\/li><li data-start=\"4601\" data-end=\"4643\"><p data-start=\"4603\" data-end=\"4643\"><strong data-start=\"4603\" data-end=\"4614\">Result:<\/strong> The full Fibonacci sequence.<\/p><\/li><li data-start=\"4644\" data-end=\"4680\"><p data-start=\"4646\" data-end=\"4680\"><strong data-start=\"4646\" data-end=\"4659\">Feedback:<\/strong> The sequence so far.<\/p><\/li><\/ul>\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-68ecbdd elementor-widget elementor-widget-text-editor\" data-id=\"68ecbdd\" data-element_type=\"widget\" data-e-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\t\t<h2 data-start=\"2302\" data-end=\"2336\"><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f3d7.svg\" alt=\"\ud83c\udfd7\ufe0f\" \/> <strong>Update <code data-start=\"4702\" data-end=\"4718\">CMakeLists.txt<\/code> and <code data-start=\"4723\" data-end=\"4736\">package.xml<\/code><\/strong><\/h2>\n<p data-start=\"4737\" data-end=\"4813\">Add the new action file to <code data-start=\"4764\" data-end=\"4792\">rosidl_generate_interfaces<\/code> in <code data-start=\"4796\" data-end=\"4812\">CMakeLists.txt<\/code>:<\/p>\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-8f210fa elementor-widget elementor-widget-code-highlight\" data-id=\"8f210fa\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language- \">\n\t\t\t\t<code readonly=\"true\" class=\"language-\">\n\t\t\t\t\t<xmp>rosidl_generate_interfaces(${PROJECT_NAME}\r\n  \"srv\/AddTwoInts.srv\"\r\n  \"action\/Fibonacci.action\"\r\n)\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c853e65 elementor-widget elementor-widget-text-editor\" data-id=\"c853e65\" data-element_type=\"widget\" data-e-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\t\t<p>And in <code data-start=\"4930\" data-end=\"4943\">package.xml<\/code> add:<\/p>\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-db894ad elementor-widget elementor-widget-code-highlight\" data-id=\"db894ad\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language- \">\n\t\t\t\t<code readonly=\"true\" class=\"language-\">\n\t\t\t\t\t<xmp><depend>action_msgs<\/depend>\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-96b4646 elementor-widget elementor-widget-text-editor\" data-id=\"96b4646\" data-element_type=\"widget\" data-e-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\t\t<p data-start=\"4990\" data-end=\"5012\">Then rebuild the workspace:<\/p>\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-6bb41b4 elementor-widget elementor-widget-code-highlight\" data-id=\"6bb41b4\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-bash \">\n\t\t\t\t<code readonly=\"true\" class=\"language-bash\">\n\t\t\t\t\t<xmp>cd ~\/arduinobot_ws\r\ncolcon build\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ec87dd1 elementor-widget elementor-widget-text-editor\" data-id=\"ec87dd1\" data-element_type=\"widget\" data-e-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\t\t<h3 data-start=\"94\" data-end=\"133\"><strong>\ud83e\udde0 <\/strong><strong>Create the Action Server Node<\/strong><\/h3>\n<p data-start=\"5102\" data-end=\"5160\">File:\u00a0 <code data-start=\"5112\" data-end=\"5160\">arduinobot_py_examples\/simple_action_server.py<\/code><\/p>\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-0ef06fe elementor-widget elementor-widget-code-highlight\" data-id=\"0ef06fe\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>import rclpy\r\nfrom rclpy.node import Node\r\nfrom rclpy.action import ActionServer\r\nfrom arduinobot_msgs.action import Fibonacci\r\nimport time\r\n\r\nclass SimpleActionServer(Node):\r\n    def __init__(self):\r\n        super().__init__(\"simple_action_server\")\r\n        self.action_server = ActionServer(\r\n            self,\r\n            Fibonacci,\r\n            \"fibonacci\",\r\n            self.goal_callback\r\n        )\r\n        self.get_logger().info(\"Fibonacci Action Server started!\")\r\n\r\n    def goal_callback(self, goal_handle):\r\n        self.get_logger().info(\r\n            f\"Received goal request: order = {goal_handle.request.order}\"\r\n        )\r\n\r\n        feedback_msg = Fibonacci.Feedback()\r\n        feedback_msg.partial_sequence = [0, 1]\r\n\r\n        for i in range(1, goal_handle.request.order):\r\n            feedback_msg.partial_sequence.append(\r\n                feedback_msg.partial_sequence[i] + feedback_msg.partial_sequence[i - 1]\r\n            )\r\n            self.get_logger().info(f\"Feedback: {feedback_msg.partial_sequence}\")\r\n            goal_handle.publish_feedback(feedback_msg)\r\n            time.sleep(1)\r\n\r\n        goal_handle.succeed()\r\n\r\n        result = Fibonacci.Result()\r\n        result.sequence = feedback_msg.partial_sequence\r\n        return result\r\n\r\ndef main():\r\n    rclpy.init()\r\n    action_server = SimpleActionServer()\r\n    rclpy.spin(action_server)\r\n    rclpy.shutdown()\r\n\r\nif __name__ == \"__main__\":\r\n    main()\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a812dfa elementor-widget elementor-widget-text-editor\" data-id=\"a812dfa\" data-element_type=\"widget\" data-e-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\t\t<h3 data-start=\"3475\" data-end=\"3506\"><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f9e9.svg\" alt=\"\ud83e\udde9\" \/>\u00a0<strong> Let\u2019s break down the code (Python)<\/strong><\/h3>\n<p data-start=\"135\" data-end=\"230\">We\u2019ll dissect <code data-start=\"149\" data-end=\"174\">simple_action_server.py<\/code> top to bottom so you know exactly what every line does.<\/p>\n<h5 data-start=\"5063\" data-end=\"5100\"><code data-start=\"5112\" data-end=\"5160\"><\/code><\/h5>\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-f8dfe75 elementor-widget elementor-widget-text-editor\" data-id=\"f8dfe75\" data-element_type=\"widget\" data-e-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\t\t<h5><strong>Imports &amp; types<\/strong><\/h5>\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-805c9c3 elementor-widget elementor-widget-code-highlight\" data-id=\"805c9c3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>import rclpy\r\nfrom rclpy.node import Node\r\nfrom rclpy.action import ActionServer\r\nfrom arduinobot_msgs.action import Fibonacci\r\nimport time<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0970675 elementor-widget elementor-widget-text-editor\" data-id=\"0970675\" data-element_type=\"widget\" data-e-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\t\t<ul><li data-start=\"411\" data-end=\"472\"><p data-start=\"413\" data-end=\"472\"><code data-start=\"413\" data-end=\"420\">rclpy<\/code>, <code data-start=\"422\" data-end=\"428\">Node<\/code>: ROS 2 Python client and base node class.<\/p><\/li><li data-start=\"473\" data-end=\"557\"><p data-start=\"475\" data-end=\"557\"><code data-start=\"475\" data-end=\"489\">ActionServer<\/code>: helper that wires up the Action\u2019s Goal\/Feedback\/Result plumbing.<\/p><\/li><li data-start=\"558\" data-end=\"644\"><p data-start=\"560\" data-end=\"644\"><code data-start=\"560\" data-end=\"571\">Fibonacci<\/code>: the custom <code data-start=\"584\" data-end=\"593\">.action<\/code> type you defined (<code data-start=\"612\" data-end=\"618\">Goal<\/code>, <code data-start=\"620\" data-end=\"630\">Feedback<\/code>, <code data-start=\"632\" data-end=\"640\">Result<\/code>).<\/p><\/li><li data-start=\"645\" data-end=\"731\"><p data-start=\"647\" data-end=\"731\"><code data-start=\"647\" data-end=\"653\">time<\/code>: we\u2019ll <code data-start=\"661\" data-end=\"671\">sleep(1)<\/code> to simulate a long-running job and emit multiple feedbacks.<\/p><\/li><\/ul>\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-8d0b5a7 elementor-widget elementor-widget-text-editor\" data-id=\"8d0b5a7\" data-element_type=\"widget\" data-e-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\t\t<h5><strong>A minimal ROS 2 node<\/strong><\/h5>\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-2182692 elementor-widget elementor-widget-code-highlight\" data-id=\"2182692\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>class SimpleActionServer(Node):\r\n    def __init__(self):\r\n        super().__init__(\"simple_action_server\")\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-187728b elementor-widget elementor-widget-text-editor\" data-id=\"187728b\" data-element_type=\"widget\" data-e-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\t\t<p>We create a ROS 2 node named <code data-start=\"915\" data-end=\"937\">simple_action_server<\/code>. You\u2019ll see this name in <code data-start=\"963\" data-end=\"979\">ros2 node list<\/code> and in logs.<\/p>\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-5c23edc elementor-widget elementor-widget-text-editor\" data-id=\"5c23edc\" data-element_type=\"widget\" data-e-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\t\t<h5><strong>Spinning up the Action Server<\/strong><\/h5>\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-b1fed19 elementor-widget elementor-widget-code-highlight\" data-id=\"b1fed19\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>self.action_server = ActionServer(\r\n    self,            # the hosting node\r\n    Fibonacci,       # the Action interface (Goal\/Feedback\/Result schemas)\r\n    \"fibonacci\",     # the action name (ROS graph resource)\r\n    self.goal_callback  # function that executes each accepted goal\r\n)\r\nself.get_logger().info(\"Fibonacci Action Server started!\")\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9327e33 elementor-widget elementor-widget-text-editor\" data-id=\"9327e33\" data-element_type=\"widget\" data-e-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\t\t<ul data-start=\"1390\" data-end=\"1637\"><li data-start=\"1390\" data-end=\"1457\"><p data-start=\"1392\" data-end=\"1457\">The <strong data-start=\"1396\" data-end=\"1404\">type<\/strong> (<code data-start=\"1406\" data-end=\"1417\">Fibonacci<\/code>) tells ROS how to serialize messages.<\/p><\/li><li data-start=\"1458\" data-end=\"1535\"><p data-start=\"1460\" data-end=\"1535\">The <strong data-start=\"1464\" data-end=\"1472\">name<\/strong> (<code data-start=\"1474\" data-end=\"1486\">\/fibonacci<\/code>) is how clients discover and call your server.<\/p><\/li><li data-start=\"1536\" data-end=\"1637\"><p data-start=\"1538\" data-end=\"1637\">The <strong data-start=\"1542\" data-end=\"1554\">callback<\/strong> is invoked per-goal; it performs the work, streams feedback, and returns a result.<\/p><\/li><\/ul><blockquote data-start=\"1639\" data-end=\"1824\"><p data-start=\"1641\" data-end=\"1824\">Tip: In rclpy docs this parameter is often called <code data-start=\"1691\" data-end=\"1709\">execute_callback<\/code>. We\u2019re calling it <code data-start=\"1728\" data-end=\"1743\">goal_callback<\/code> to stick with the lesson\u2019s naming, but it\u2019s the function that <strong data-start=\"1806\" data-end=\"1823\">runs the goal<\/strong>.<\/p><\/blockquote>\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-8722d8e elementor-widget elementor-widget-text-editor\" data-id=\"8722d8e\" data-element_type=\"widget\" data-e-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\t\t<h5><strong>Executing a goal<\/strong><\/h5>\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-c037748 elementor-widget elementor-widget-code-highlight\" data-id=\"c037748\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>def goal_callback(self, goal_handle):\r\n    self.get_logger().info(\r\n        f\"Received goal request: order = {goal_handle.request.order}\"\r\n    )\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-aef75f3 elementor-widget elementor-widget-text-editor\" data-id=\"aef75f3\" data-element_type=\"widget\" data-e-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\t\t<ul><li><code data-start=\"2014\" data-end=\"2027\">goal_handle<\/code> gives you access to the <strong data-start=\"2052\" data-end=\"2077\">incoming goal request<\/strong> (here, <code data-start=\"2085\" data-end=\"2092\">order<\/code>) and tools to <strong data-start=\"2107\" data-end=\"2127\">publish feedback<\/strong>, <strong data-start=\"2129\" data-end=\"2143\">set status<\/strong>, etc.<\/li><\/ul>\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-b9df00f elementor-widget elementor-widget-text-editor\" data-id=\"b9df00f\" data-element_type=\"widget\" data-e-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\t\t<h5><strong>Preparing the feedback message<\/strong><\/h5>\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-15af1ac elementor-widget elementor-widget-code-highlight\" data-id=\"15af1ac\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>feedback_msg = Fibonacci.Feedback()\r\nfeedback_msg.partial_sequence = [0, 1]\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f16bfdc elementor-widget elementor-widget-text-editor\" data-id=\"f16bfdc\" data-element_type=\"widget\" data-e-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\t\t<ul data-start=\"2284\" data-end=\"2445\"><li data-start=\"2284\" data-end=\"2348\"><p data-start=\"2286\" data-end=\"2348\">The Action\u2019s <strong data-start=\"2299\" data-end=\"2311\">Feedback<\/strong> type carries <strong data-start=\"2325\" data-end=\"2345\">partial progress<\/strong>.<\/p><\/li><li data-start=\"2349\" data-end=\"2445\"><p data-start=\"2351\" data-end=\"2445\">We seed the Fibonacci sequence with <code data-start=\"2387\" data-end=\"2395\">[0, 1]<\/code>, so each loop iteration can append the next term.<\/p><\/li><\/ul><blockquote data-start=\"2447\" data-end=\"2635\"><p data-start=\"2449\" data-end=\"2635\">Note: If you want mathematically strict behavior for tiny orders (e.g., <code data-start=\"2521\" data-end=\"2530\">order=0<\/code> or <code data-start=\"2534\" data-end=\"2543\">order=1<\/code>), you can clamp or slice the list before returning the result. This sample keeps it simple.<\/p><\/blockquote>\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-8e9680e elementor-widget elementor-widget-text-editor\" data-id=\"8e9680e\" data-element_type=\"widget\" data-e-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\t\t<h5><strong>The computation loop (and feedback streaming)<\/strong><\/h5>\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-a55ec4a elementor-widget elementor-widget-code-highlight\" data-id=\"a55ec4a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>for i in range(1, goal_handle.request.order):\r\n    feedback_msg.partial_sequence.append(\r\n        feedback_msg.partial_sequence[i] +\r\n        feedback_msg.partial_sequence[i - 1]\r\n    )\r\n    self.get_logger().info(f\"Feedback: {feedback_msg.partial_sequence}\")\r\n    goal_handle.publish_feedback(feedback_msg)\r\n    time.sleep(1)  # simulate processing time\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ce7094b elementor-widget elementor-widget-text-editor\" data-id=\"ce7094b\" data-element_type=\"widget\" data-e-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\t\t<ul data-start=\"3058\" data-end=\"3306\"><li data-start=\"3058\" data-end=\"3131\"><p data-start=\"3060\" data-end=\"3131\">Each iteration computes the <strong data-start=\"3088\" data-end=\"3113\">next Fibonacci number<\/strong> and appends it.<\/p><\/li><li data-start=\"3132\" data-end=\"3222\"><p data-start=\"3134\" data-end=\"3222\">We <strong data-start=\"3137\" data-end=\"3144\">log<\/strong> and <strong data-start=\"3149\" data-end=\"3160\">publish<\/strong> the current partial sequence as <strong data-start=\"3193\" data-end=\"3205\">feedback<\/strong> to the client.<\/p><\/li><li data-start=\"3223\" data-end=\"3306\"><p data-start=\"3225\" data-end=\"3306\"><code data-start=\"3225\" data-end=\"3235\">sleep(1)<\/code> just simulates work so you can actually see multiple feedback updates.<\/p><\/li><\/ul><blockquote data-start=\"3308\" data-end=\"3418\"><p data-start=\"3310\" data-end=\"3418\">In real robots, this \u201cwork\u201d would be path planning, motion, or perception\u2014no <code data-start=\"3387\" data-end=\"3394\">sleep<\/code>, just real computation.<\/p><\/blockquote>\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-2405353 elementor-widget elementor-widget-text-editor\" data-id=\"2405353\" data-element_type=\"widget\" data-e-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\t\t<h5><strong>Marking success &amp; returning the result<\/strong><\/h5>\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-5352b1c elementor-widget elementor-widget-code-highlight\" data-id=\"5352b1c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>goal_handle.succeed()\r\nresult = Fibonacci.Result()\r\nresult.sequence = feedback_msg.partial_sequence\r\nreturn result<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b51b47f elementor-widget elementor-widget-text-editor\" data-id=\"b51b47f\" data-element_type=\"widget\" data-e-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\t\t<div><ul data-start=\"3598\" data-end=\"3749\"><li data-start=\"3598\" data-end=\"3652\"><p data-start=\"3600\" data-end=\"3652\"><code data-start=\"3600\" data-end=\"3611\">succeed()<\/code> sets the goal status to <strong data-start=\"3636\" data-end=\"3649\">SUCCEEDED<\/strong>.<\/p><\/li><li data-start=\"3653\" data-end=\"3749\"><p data-start=\"3655\" data-end=\"3749\">We fill the <strong data-start=\"3667\" data-end=\"3677\">Result<\/strong> with the full sequence and return it\u2014ROS 2 sends it back to the client.<\/p><\/li><\/ul><blockquote data-start=\"3751\" data-end=\"4059\"><p data-start=\"3753\" data-end=\"3820\">Optional enhancement: handle cancellations. Inside the loop, check:<\/p><\/blockquote><\/div>\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-61de0b2 elementor-widget elementor-widget-code-highlight\" data-id=\"61de0b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>if goal_handle.is_cancel_requested:\r\n    goal_handle.canceled()\r\n    result = Fibonacci.Result()\r\n    result.sequence = feedback_msg.partial_sequence\r\n    return result\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-dfb3be0 elementor-widget elementor-widget-text-editor\" data-id=\"dfb3be0\" data-element_type=\"widget\" data-e-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\t\t<p>That lets clients abort long tasks cleanly.<\/p>\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-c629634 elementor-widget elementor-widget-text-editor\" data-id=\"c629634\" data-element_type=\"widget\" data-e-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\t\t<h5><strong>Bootstrapping the node<\/strong><\/h5>\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-4fbf175 elementor-widget elementor-widget-code-highlight\" data-id=\"4fbf175\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>def main():\r\n    rclpy.init()\r\n    action_server = SimpleActionServer()\r\n    rclpy.spin(action_server)\r\n    rclpy.shutdown()\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ed2ac8d elementor-widget elementor-widget-text-editor\" data-id=\"ed2ac8d\" data-element_type=\"widget\" data-e-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\t\t<ul><li data-start=\"4232\" data-end=\"4288\"><p data-start=\"4234\" data-end=\"4288\"><code data-start=\"4234\" data-end=\"4248\">rclpy.init()<\/code> brings ROS 2 online for this process.<\/p><\/li><li data-start=\"4289\" data-end=\"4374\"><p data-start=\"4291\" data-end=\"4374\"><code data-start=\"4291\" data-end=\"4305\">rclpy.spin()<\/code> keeps the node alive to <strong data-start=\"4330\" data-end=\"4346\">accept goals<\/strong> and <strong data-start=\"4351\" data-end=\"4371\">publish feedback<\/strong>.<\/p><\/li><li data-start=\"4375\" data-end=\"4412\"><p data-start=\"4377\" data-end=\"4412\">On Ctrl-C, we cleanly <code data-start=\"4399\" data-end=\"4411\">shutdown()<\/code>.<\/p><\/li><\/ul>\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-ff987a9 elementor-widget elementor-widget-text-editor\" data-id=\"ff987a9\" data-element_type=\"widget\" data-e-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\t\t<h3 data-start=\"5448\" data-end=\"5479\"><strong><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/2699.svg\" alt=\"\u2699\ufe0f\" \/> <\/strong><strong>Make It Executable<\/strong><\/h3>\n<p>In <code data-start=\"6598\" data-end=\"6631\">arduinobot_py_examples\/setup.py<\/code>:<\/p>\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-3f26e10 elementor-widget elementor-widget-code-highlight\" data-id=\"3f26e10\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-python \">\n\t\t\t\t<code readonly=\"true\" class=\"language-python\">\n\t\t\t\t\t<xmp>'console_scripts': [\r\n    'simple_action_server = arduinobot_py_examples.simple_action_server:main',\r\n]\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4f16037 elementor-widget elementor-widget-text-editor\" data-id=\"4f16037\" data-element_type=\"widget\" data-e-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\t\t<p>Rebuild:<\/p>\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-2339ced elementor-widget elementor-widget-code-highlight\" data-id=\"2339ced\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-bash \">\n\t\t\t\t<code readonly=\"true\" class=\"language-bash\">\n\t\t\t\t\t<xmp>colcon build\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e401c61 elementor-widget elementor-widget-text-editor\" data-id=\"e401c61\" data-element_type=\"widget\" data-e-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\t\t<h3 data-start=\"5814\" data-end=\"5852\"><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f680.svg\" alt=\"\ud83d\ude80\" \/> \u00a0<strong>Test the Action Server<\/strong><\/h3>\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-948da42 elementor-widget elementor-widget-text-editor\" data-id=\"948da42\" data-element_type=\"widget\" data-e-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\t\t<h5><strong><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f5a5.svg\" alt=\"\ud83d\udda5\ufe0f\" \/>\u00a0Terminal 1: Start the Server<\/strong><\/h5>\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-55781f7 elementor-widget elementor-widget-code-highlight\" data-id=\"55781f7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-bash \">\n\t\t\t\t<code readonly=\"true\" class=\"language-bash\">\n\t\t\t\t\t<xmp>. install\/setup.bash\r\nros2 run arduinobot_py_examples simple_action_server\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-567dd68 elementor-widget elementor-widget-text-editor\" data-id=\"567dd68\" data-element_type=\"widget\" data-e-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\t\t<h5><strong><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f5a5.svg\" alt=\"\ud83d\udda5\ufe0f\" \/> Terminal 2: Check available actions:<\/strong><\/h5>\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-c0b6b30 elementor-widget elementor-widget-code-highlight\" data-id=\"c0b6b30\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-bash \">\n\t\t\t\t<code readonly=\"true\" class=\"language-bash\">\n\t\t\t\t\t<xmp>ros2 action list\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-03fa186 elementor-widget elementor-widget-text-editor\" data-id=\"03fa186\" data-element_type=\"widget\" data-e-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\t\t<h5><strong><img decoding=\"async\" class=\"emoji\" role=\"img\" draggable=\"false\" src=\"https:\/\/s.w.org\/images\/core\/emoji\/16.0.1\/svg\/1f5a5.svg\" alt=\"\ud83d\udda5\ufe0f\" \/> Terminal 3: Send a goal and view feedback:<\/strong><\/h5>\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-62b8618 elementor-widget elementor-widget-code-highlight\" data-id=\"62b8618\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"prismjs-tomorrow copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-bash \">\n\t\t\t\t<code readonly=\"true\" class=\"language-bash\">\n\t\t\t\t\t<xmp>ros2 action send_goal \/fibonacci arduinobot_msgs\/action\/Fibonacci \"order: 10\" -f\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9b426fb elementor-widget elementor-widget-text-editor\" data-id=\"9b426fb\" data-element_type=\"widget\" data-e-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\t\t<p>You\u2019ll see feedback messages in real-time and, at the end, the full sequence.<\/p>\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\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-c5d20e7 e-con-full e-flex e-con e-parent\" data-id=\"c5d20e7\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-0741169 elementor-bg-transform elementor-bg-transform-move-left elementor-cta--layout-image-left elementor-cta--mobile-layout-image-above elementor-cta--skin-classic elementor-animated-content elementor-widget elementor-widget-call-to-action\" data-id=\"0741169\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"call-to-action.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-cta\">\n\t\t\t\t\t<div class=\"elementor-cta__bg-wrapper\">\n\t\t\t\t<div class=\"elementor-cta__bg elementor-bg\" style=\"background-image: url(https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/06\/manipulation-ros2.webp);\" role=\"img\" aria-label=\"manipulation ros2\"><\/div>\n\t\t\t\t<div class=\"elementor-cta__bg-overlay\"><\/div>\n\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-cta__content\">\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<h2 class=\"elementor-cta__title elementor-cta__content-item elementor-content-item\">\n\t\t\t\t\t\tWant to learn more?\t\t\t\t\t<\/h2>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-cta__description elementor-cta__content-item elementor-content-item\">\n\t\t\t\t\t\tExplore all the ROS 2 actions in the \"Robotics and ROS 2 - Learn by Doing! Manipulators\" course\t\t\t\t\t<\/div>\n\t\t\t\t\n\t\t\t\t\t\t\t\t\t<div class=\"elementor-cta__button-wrapper elementor-cta__content-item elementor-content-item \">\n\t\t\t\t\t<a class=\"elementor-cta__button elementor-button elementor-size-\" href=\"\" target=\"_blank\">\n\t\t\t\t\t\tEnroll Now\t\t\t\t\t<\/a>\n\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t\t\t<div class=\"elementor-ribbon elementor-ribbon-right\">\n\t\t\t\t<div class=\"elementor-ribbon-inner\">\n\t\t\t\t\tDISCOUNT\t\t\t\t<\/div>\n\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-180426a elementor-widget elementor-widget-spacer\" data-id=\"180426a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"spacer.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-spacer\">\n\t\t\t<div class=\"elementor-spacer-inner\"><\/div>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>When working with robots, not every task is instantaneous. Some operations take time: navigating across a room, picking up an object, scanning an area, or performing a long computation.In ROS 2, these \u201clong-running\u201d tasks need a special way for nodes to talk to each other \u2014 one that allows progress updates and the ability to [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":3763,"comment_status":"closed","ping_status":"open","sticky":false,"template":"elementor_header_footer","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[45,43],"tags":[286,289,287,87,179,66,120,141,98,107,72,246,76,288,64],"class_list":["post-3749","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ros-2","category-tutorials","tag-action","tag-action-server","tag-client-ros","tag-guide","tag-lbd","tag-learn-by-doing","tag-manipulators","tag-py","tag-python","tag-ros-2","tag-ros2","tag-server","tag-step-by-step","tag-test","tag-tutorial"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>How to Build and Test a ROS 2 Action Server in Python - Learn by Doing!<\/title>\n<meta name=\"description\" content=\"Explore what Actions are, why they\u2019re different from Topics and Services, and how to build and test a ROS 2 Action Server in Python\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/learnbydoing.dev\/es\/how-to-build-and-test-a-ros-2-action-server-in-python\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Build and Test a ROS 2 Action Server in Python\" \/>\n<meta property=\"og:description\" content=\"Learn by Doing!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/learnbydoing.dev\/es\/how-to-build-and-test-a-ros-2-action-server-in-python\/\" \/>\n<meta property=\"og:site_name\" content=\"Learn by Doing!\" \/>\n<meta property=\"article:published_time\" content=\"2025-08-14T14:23:31+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-01-10T21:59:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"How to Build and Test a ROS 2 Action Server in Python\",\"datePublished\":\"2025-08-14T14:23:31+00:00\",\"dateModified\":\"2026-01-10T21:59:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/\"},\"wordCount\":1053,\"publisher\":{\"@id\":\"https:\/\/learnbydoing.dev\/es\/#organization\"},\"image\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp\",\"keywords\":[\"Action\",\"action server\",\"client. ROS\",\"Guide\",\"lbd\",\"learn by doing\",\"manipulators\",\"py\",\"python\",\"ROS 2\",\"ROS2\",\"server\",\"step by step\",\"Test\",\"tutorial\"],\"articleSection\":[\"ROS 2\",\"Tutorials\"],\"inLanguage\":\"es\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/\",\"url\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/\",\"name\":\"How to Build and Test a ROS 2 Action Server in Python - Learn by Doing!\",\"isPartOf\":{\"@id\":\"https:\/\/learnbydoing.dev\/es\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp\",\"datePublished\":\"2025-08-14T14:23:31+00:00\",\"dateModified\":\"2026-01-10T21:59:46+00:00\",\"description\":\"Explore what Actions are, why they\u2019re different from Topics and Services, and how to build and test a ROS 2 Action Server in Python\",\"breadcrumb\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#primaryimage\",\"url\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp\",\"contentUrl\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp\",\"width\":1920,\"height\":1080},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/learnbydoing.dev\/es\/learn-by-doing-es\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Build and Test a ROS 2 Action Server in Python\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/learnbydoing.dev\/es\/#website\",\"url\":\"https:\/\/learnbydoing.dev\/es\/\",\"name\":\"Learn by Doing!\",\"description\":\"Learn Robotics the fun way\",\"publisher\":{\"@id\":\"https:\/\/learnbydoing.dev\/es\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/learnbydoing.dev\/es\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/learnbydoing.dev\/es\/#organization\",\"name\":\"Learn by Doing!\",\"url\":\"https:\/\/learnbydoing.dev\/es\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/learnbydoing.dev\/es\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/06\/cropped-cropped-cropped-Progetto-senza-titolo-6-1.png\",\"contentUrl\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/06\/cropped-cropped-cropped-Progetto-senza-titolo-6-1.png\",\"width\":512,\"height\":512,\"caption\":\"Learn by Doing!\"},\"image\":{\"@id\":\"https:\/\/learnbydoing.dev\/es\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/antonio-brandi-512166bb\/\"]},{\"@type\":\"Person\",\"@id\":\"\",\"url\":\"https:\/\/learnbydoing.dev\/es\/author\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Build and Test a ROS 2 Action Server in Python - Learn by Doing!","description":"Explore what Actions are, why they\u2019re different from Topics and Services, and how to build and test a ROS 2 Action Server in Python","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/learnbydoing.dev\/es\/how-to-build-and-test-a-ros-2-action-server-in-python\/","og_locale":"es_ES","og_type":"article","og_title":"How to Build and Test a ROS 2 Action Server in Python","og_description":"Learn by Doing!","og_url":"https:\/\/learnbydoing.dev\/es\/how-to-build-and-test-a-ros-2-action-server-in-python\/","og_site_name":"Learn by Doing!","article_published_time":"2025-08-14T14:23:31+00:00","article_modified_time":"2026-01-10T21:59:46+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp","type":"image\/webp"}],"twitter_card":"summary_large_image","twitter_misc":{"Escrito por":"","Tiempo de lectura":"8 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#article","isPartOf":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/"},"author":{"name":"","@id":""},"headline":"How to Build and Test a ROS 2 Action Server in Python","datePublished":"2025-08-14T14:23:31+00:00","dateModified":"2026-01-10T21:59:46+00:00","mainEntityOfPage":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/"},"wordCount":1053,"publisher":{"@id":"https:\/\/learnbydoing.dev\/es\/#organization"},"image":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#primaryimage"},"thumbnailUrl":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp","keywords":["Action","action server","client. ROS","Guide","lbd","learn by doing","manipulators","py","python","ROS 2","ROS2","server","step by step","Test","tutorial"],"articleSection":["ROS 2","Tutorials"],"inLanguage":"es"},{"@type":"WebPage","@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/","url":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/","name":"How to Build and Test a ROS 2 Action Server in Python - Learn by Doing!","isPartOf":{"@id":"https:\/\/learnbydoing.dev\/es\/#website"},"primaryImageOfPage":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#primaryimage"},"image":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#primaryimage"},"thumbnailUrl":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp","datePublished":"2025-08-14T14:23:31+00:00","dateModified":"2026-01-10T21:59:46+00:00","description":"Explore what Actions are, why they\u2019re different from Topics and Services, and how to build and test a ROS 2 Action Server in Python","breadcrumb":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#primaryimage","url":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp","contentUrl":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server.webp","width":1920,"height":1080},{"@type":"BreadcrumbList","@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-python\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/learnbydoing.dev\/es\/learn-by-doing-es\/"},{"@type":"ListItem","position":2,"name":"How to Build and Test a ROS 2 Action Server in Python"}]},{"@type":"WebSite","@id":"https:\/\/learnbydoing.dev\/es\/#website","url":"https:\/\/learnbydoing.dev\/es\/","name":"Learn by Doing!","description":"Learn Robotics the fun way","publisher":{"@id":"https:\/\/learnbydoing.dev\/es\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/learnbydoing.dev\/es\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/learnbydoing.dev\/es\/#organization","name":"Learn by Doing!","url":"https:\/\/learnbydoing.dev\/es\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/learnbydoing.dev\/es\/#\/schema\/logo\/image\/","url":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/06\/cropped-cropped-cropped-Progetto-senza-titolo-6-1.png","contentUrl":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/06\/cropped-cropped-cropped-Progetto-senza-titolo-6-1.png","width":512,"height":512,"caption":"Learn by Doing!"},"image":{"@id":"https:\/\/learnbydoing.dev\/es\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/in\/antonio-brandi-512166bb\/"]},{"@type":"Person","@id":"","url":"https:\/\/learnbydoing.dev\/es\/author\/"}]}},"_links":{"self":[{"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/posts\/3749","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/comments?post=3749"}],"version-history":[{"count":27,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/posts\/3749\/revisions"}],"predecessor-version":[{"id":5502,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/posts\/3749\/revisions\/5502"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/media\/3763"}],"wp:attachment":[{"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/media?parent=3749"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/categories?post=3749"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/tags?post=3749"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}