{"id":3899,"date":"2025-08-21T13:34:39","date_gmt":"2025-08-21T13:34:39","guid":{"rendered":"https:\/\/learnbydoing.dev\/?p=3899"},"modified":"2026-01-10T21:35:34","modified_gmt":"2026-01-10T21:35:34","slug":"how-to-build-and-test-a-ros-2-action-server-in-cpp","status":"publish","type":"post","link":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/","title":{"rendered":"How to Build and Test a ROS 2 Action Server in C++"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"3899\" class=\"elementor elementor-3899\" 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-1.webp\" class=\"attachment-full size-full wp-image-3901\" alt=\"\" srcset=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp 1920w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1-300x169.webp 300w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1-1024x576.webp 1024w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1-768x432.webp 768w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1-1536x864.webp 1536w, https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1-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><p data-start=\"3698\" data-end=\"3849\">For our first practical Action example, we\u2019ll implement a C++ Action Server that calculates the <strong data-start=\"3797\" data-end=\"3819\">Fibonacci sequence<\/strong> up to a user-defined order.<\/p><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.<\/p><h5 data-start=\"3851\" data-end=\"3867\"><strong>Why Fibonacci?<\/strong><\/h5><ul data-start=\"3868\" data-end=\"4071\"><li data-start=\"3868\" data-end=\"3896\"><p data-start=\"3870\" data-end=\"3896\">It\u2019s simple to understand.<\/p><\/li><li data-start=\"3897\" data-end=\"3974\"><p data-start=\"3899\" data-end=\"3974\">It allows us to focus on the Action Server logic instead of robot hardware.<\/p><\/li><li data-start=\"3975\" data-end=\"4071\"><p data-start=\"3977\" data-end=\"4071\">It gives us a natural way to send progress updates (feedback) after each number is calculated.<\/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-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<h3 data-start=\"2586\" data-end=\"2639\"><strong>\ud83d\udee0 Hands-On: Building a ROS 2 Action Server in C++<\/strong><\/h3><p data-start=\"2641\" data-end=\"2897\">In this hands-on section, we\u2019ll create a C++ Action Server that calculates the Fibonacci sequence. The <strong data-start=\"2744\" data-end=\"2753\">order<\/strong> of the sequence will be sent as the Goal, and the server will return the full sequence as the Result, sending intermediate numbers as Feedback.<\/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-c85344d elementor-widget elementor-widget-text-editor\" data-id=\"c85344d\" 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>\ud83d\udcc4 Full C++ Code for the Fibonacci 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-9dfe0a8 elementor-widget elementor-widget-code-highlight\" data-id=\"9dfe0a8\" 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-cpp line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>#include <memory>\r\n#include <thread>\r\n#include <vector>\r\n#include <rclcpp\/rclcpp.hpp>\r\n#include <rclcpp_action\/rclcpp_action.hpp>\r\n#include \"arduinobot_msgs\/action\/fibonacci.hpp\"\r\n\r\nnamespace arduinobot_cpp_examples\r\n{\r\nclass SimpleActionServer : public rclcpp::Node\r\n{\r\npublic:\r\n  using Fibonacci = arduinobot_msgs::action::Fibonacci;\r\n  using GoalHandleFibonacci = rclcpp_action::ServerGoalHandle<Fibonacci>;\r\n\r\n  explicit SimpleActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())\r\n  : Node(\"simple_action_server\", options)\r\n  {\r\n    using namespace std::placeholders;\r\n\r\n    action_server_ = rclcpp_action::create_server<Fibonacci>(\r\n      this,\r\n      \"fibonacci\",\r\n      std::bind(&SimpleActionServer::goalCallback, this, _1, _2),\r\n      std::bind(&SimpleActionServer::cancelCallback, this, _1),\r\n      std::bind(&SimpleActionServer::acceptedCallback, this, _1)\r\n    );\r\n\r\n    RCLCPP_INFO(get_logger(), \"Starting the Action Server\");\r\n  }\r\n\r\nprivate:\r\n  rclcpp_action::Server<Fibonacci>::SharedPtr action_server_;\r\n\r\n  rclcpp_action::GoalResponse goalCallback(\r\n    const rclcpp_action::GoalUUID & uuid,\r\n    std::shared_ptr<const Fibonacci::Goal> goal)\r\n  {\r\n    RCLCPP_INFO(get_logger(), \"Received goal request with order %d\", goal->order);\r\n    return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;\r\n  }\r\n\r\n  rclcpp_action::CancelResponse cancelCallback(\r\n    const std::shared_ptr<GoalHandleFibonacci> goal_handle)\r\n  {\r\n    RCLCPP_INFO(get_logger(), \"Received request to cancel goal\");\r\n    return rclcpp_action::CancelResponse::ACCEPT;\r\n  }\r\n\r\n  void acceptedCallback(const std::shared_ptr<GoalHandleFibonacci> goal_handle)\r\n  {\r\n    std::thread{std::bind(&SimpleActionServer::execute, this, goal_handle)}.detach();\r\n  }\r\n\r\n  void execute(const std::shared_ptr<GoalHandleFibonacci> goal_handle)\r\n  {\r\n    RCLCPP_INFO(get_logger(), \"Executing goal\");\r\n\r\n    rclcpp::Rate loop_rate(1);\r\n    const auto goal = goal_handle->get_goal();\r\n    auto feedback = std::make_shared<Fibonacci::Feedback>();\r\n    auto & sequence = feedback->partial_sequence;\r\n    sequence.push_back(0);\r\n    sequence.push_back(1);\r\n\r\n    auto result = std::make_shared<Fibonacci::Result>();\r\n\r\n    for (int i = 1; (i < goal->order) && rclcpp::ok(); ++i)\r\n    {\r\n      if (goal_handle->is_canceling())\r\n      {\r\n        result->sequence = sequence;\r\n        goal_handle->canceled(result);\r\n        RCLCPP_INFO(get_logger(), \"Goal canceled\");\r\n        return;\r\n      }\r\n\r\n      sequence.push_back(sequence[i] + sequence[i - 1]);\r\n      goal_handle->publish_feedback(feedback);\r\n      RCLCPP_INFO(get_logger(), \"Publish feedback\");\r\n      loop_rate.sleep();\r\n    }\r\n\r\n    if (rclcpp::ok())\r\n    {\r\n      result->sequence = sequence;\r\n      goal_handle->succeed(result);\r\n      RCLCPP_INFO(get_logger(), \"Goal succeeded\");\r\n    }\r\n  }\r\n};\r\n}  \/\/ namespace arduinobot_cpp_examples\r\n\r\n#include <rclcpp_components\/register_node_macro.hpp>\r\nRCLCPP_COMPONENTS_REGISTER_NODE(arduinobot_cpp_examples::SimpleActionServer)\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-f9b3b54 elementor-widget elementor-widget-text-editor\" data-id=\"f9b3b54\" 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=\"125\" data-end=\"161\"><strong>\ud83e\udde0 Let\u2019s break down the code (C++)<\/strong><\/h3><p data-start=\"163\" data-end=\"324\">We\u2019ll dissect <code data-start=\"177\" data-end=\"203\">simple_action_server.cpp<\/code> from top to bottom. Each snippet is the <em data-start=\"244\" data-end=\"251\">exact<\/em> line(s) you need, followed by why they matter and how they fit together.<\/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-912b47f elementor-widget elementor-widget-text-editor\" data-id=\"912b47f\" 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>Includes &amp; basic 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-a4aede0 elementor-widget elementor-widget-code-highlight\" data-id=\"a4aede0\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>#include <memory>\r\n#include <thread>\r\n#include <vector>\r\n#include <rclcpp\/rclcpp.hpp>\r\n#include <rclcpp_action\/rclcpp_action.hpp>\r\n#include \"arduinobot_msgs\/action\/fibonacci.hpp\"\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-48c1c08 elementor-widget elementor-widget-text-editor\" data-id=\"48c1c08\" 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=\"547\" data-end=\"690\"><p data-start=\"549\" data-end=\"568\">Standard headers:<\/p><ul data-start=\"571\" data-end=\"690\"><li data-start=\"571\" data-end=\"605\"><p data-start=\"573\" data-end=\"605\"><code data-start=\"573\" data-end=\"583\">&lt;memory&gt;<\/code> for smart pointers,<\/p><\/li><li data-start=\"608\" data-end=\"655\"><p data-start=\"610\" data-end=\"655\"><code data-start=\"610\" data-end=\"620\">&lt;thread&gt;<\/code> to run execution asynchronously,<\/p><\/li><li data-start=\"658\" data-end=\"690\"><p data-start=\"660\" data-end=\"690\"><code data-start=\"660\" data-end=\"670\">&lt;vector&gt;<\/code> for the sequence.<\/p><\/li><\/ul><\/li><li data-start=\"691\" data-end=\"778\"><p data-start=\"693\" data-end=\"701\">ROS 2:<\/p><ul data-start=\"704\" data-end=\"778\"><li data-start=\"704\" data-end=\"731\"><p data-start=\"706\" data-end=\"731\"><code data-start=\"706\" data-end=\"714\">rclcpp<\/code> core node API,<\/p><\/li><li data-start=\"734\" data-end=\"778\"><p data-start=\"736\" data-end=\"778\"><code data-start=\"736\" data-end=\"751\">rclcpp_action<\/code> Action server utilities.<\/p><\/li><\/ul><\/li><li data-start=\"779\" data-end=\"861\"><p data-start=\"781\" data-end=\"861\">Your custom interface: <code data-start=\"804\" data-end=\"815\">Fibonacci<\/code> (defines <strong data-start=\"825\" data-end=\"833\">Goal<\/strong>, <strong data-start=\"835\" data-end=\"847\">Feedback<\/strong>, <strong data-start=\"849\" data-end=\"859\">Result<\/strong>).<\/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-b295898 elementor-widget elementor-widget-text-editor\" data-id=\"b295898\" 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>Node skeleton + handy aliases<\/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-dd26523 elementor-widget elementor-widget-code-highlight\" data-id=\"dd26523\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>namespace arduinobot_cpp_examples\r\n{\r\nclass SimpleActionServer : public rclcpp::Node\r\n{\r\npublic:\r\n  using Fibonacci = arduinobot_msgs::action::Fibonacci;\r\n  using GoalHandleFibonacci = rclcpp_action::ServerGoalHandle<Fibonacci>;\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-75b58e4 elementor-widget elementor-widget-text-editor\" data-id=\"75b58e4\" 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=\"1140\" data-end=\"1176\"><p data-start=\"1142\" data-end=\"1176\">Namespacing keeps symbols clean.<\/p><\/li><li data-start=\"1177\" data-end=\"1335\"><p data-start=\"1179\" data-end=\"1192\">Type aliases:<\/p><ul data-start=\"1195\" data-end=\"1335\"><li data-start=\"1195\" data-end=\"1247\"><p data-start=\"1197\" data-end=\"1247\"><code data-start=\"1197\" data-end=\"1208\">Fibonacci<\/code> \u2192 shorter access to the action type.<\/p><\/li><li data-start=\"1250\" data-end=\"1335\"><p data-start=\"1252\" data-end=\"1335\"><code data-start=\"1252\" data-end=\"1273\">GoalHandleFibonacci<\/code> \u2192 the goal handle used everywhere (status, feedback, result).<\/p><\/li><\/ul><\/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-fe6ee56 elementor-widget elementor-widget-text-editor\" data-id=\"fe6ee56\" 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>Constructor: name the node, create 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-628397c elementor-widget elementor-widget-code-highlight\" data-id=\"628397c\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>explicit SimpleActionServer(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())\r\n: Node(\"simple_action_server\", options)\r\n{\r\n  using namespace std::placeholders;\r\n\r\n  action_server_ = rclcpp_action::create_server<Fibonacci>(\r\n    this,                         \/\/ hosting node\r\n    \"fibonacci\",                  \/\/ action name in the graph\r\n    std::bind(&SimpleActionServer::goalCallback,    this, _1, _2),\r\n    std::bind(&SimpleActionServer::cancelCallback,  this, _1),\r\n    std::bind(&SimpleActionServer::acceptedCallback,this, _1)\r\n  );\r\n\r\n  RCLCPP_INFO(get_logger(), \"Starting the Action Server\");\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-93b48b2 elementor-widget elementor-widget-text-editor\" data-id=\"93b48b2\" 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=\"2007\" data-end=\"2063\"><p data-start=\"2009\" data-end=\"2063\"><strong data-start=\"2009\" data-end=\"2022\">Node name<\/strong>: visible in <code data-start=\"2035\" data-end=\"2051\">ros2 node list<\/code> and logs.<\/p><\/li><li data-start=\"2064\" data-end=\"2205\"><p data-start=\"2066\" data-end=\"2205\"><code data-start=\"2066\" data-end=\"2081\">create_server<\/code> signature (for reference):<br data-start=\"2108\" data-end=\"2111\" \/><code data-start=\"2113\" data-end=\"2203\">node, action_name, goal_cb(uuid, goal), cancel_cb(goal_handle), accepted_cb(goal_handle)<\/code><\/p><\/li><li data-start=\"2206\" data-end=\"2296\"><p data-start=\"2208\" data-end=\"2296\"><code data-start=\"2208\" data-end=\"2219\">std::bind<\/code> + placeholders connect member functions to the server\u2019s callback signatures.<\/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-1e13dec elementor-widget elementor-widget-text-editor\" data-id=\"1e13dec\" 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>Member that owns 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-5fec98e elementor-widget elementor-widget-code-highlight\" data-id=\"5fec98e\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>private:\r\n  rclcpp_action::Server<Fibonacci>::SharedPtr 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-9d99ff9 elementor-widget elementor-widget-text-editor\" data-id=\"9d99ff9\" 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=\"2421\" data-end=\"2475\"><p data-start=\"2423\" data-end=\"2475\">Keeps the server alive as long as the node exists.<\/p><\/li><li data-start=\"2476\" data-end=\"2524\"><p data-start=\"2478\" data-end=\"2524\">Shared pointer (lifecycle owned by your node).<\/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-aca7319 elementor-widget elementor-widget-text-editor\" data-id=\"aca7319\" 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>Goal evaluation (accept\/reject)<\/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-d767750 elementor-widget elementor-widget-code-highlight\" data-id=\"d767750\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>rclcpp_action::GoalResponse goalCallback(\r\n  const rclcpp_action::GoalUUID & uuid,\r\n  std::shared_ptr<const Fibonacci::Goal> goal)\r\n{\r\n  (void)uuid;  \/\/ not used here, but available if you need per-goal logic\r\n  RCLCPP_INFO(get_logger(), \"Received goal request with order %d\", goal->order);\r\n  return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;\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-f1d4fc7 elementor-widget elementor-widget-text-editor\" data-id=\"f1d4fc7\" 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=\"2928\" data-end=\"2974\"><p data-start=\"2930\" data-end=\"2974\">Called whenever a client sends a <strong data-start=\"2963\" data-end=\"2971\">Goal<\/strong>.<\/p><\/li><li data-start=\"2975\" data-end=\"3130\"><p data-start=\"2977\" data-end=\"3048\">You could <strong data-start=\"2987\" data-end=\"2999\">validate<\/strong> the request here (e.g., reject negative orders):<\/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-c00d8ee elementor-widget elementor-widget-code-highlight\" data-id=\"c00d8ee\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>if (goal->order < 1) return rclcpp_action::GoalResponse::REJECT;\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-8b51e25 elementor-widget elementor-widget-text-editor\" data-id=\"8b51e25\" 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=\"2975\" data-end=\"3130\">We keep it simple and <strong data-start=\"3155\" data-end=\"3165\">accept<\/strong> immediately.<\/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-be4dabe elementor-widget elementor-widget-text-editor\" data-id=\"be4dabe\" 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>Handling cancel requests<\/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-22cf0ea elementor-widget elementor-widget-code-highlight\" data-id=\"22cf0ea\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>rclcpp_action::CancelResponse cancelCallback(\r\n  const std::shared_ptr<GoalHandleFibonacci> \/*goal_handle*\/)\r\n{\r\n  RCLCPP_INFO(get_logger(), \"Received request to cancel goal\");\r\n  return rclcpp_action::CancelResponse::ACCEPT;\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-87b0967 elementor-widget elementor-widget-text-editor\" data-id=\"87b0967\" 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=\"3453\" data-end=\"3502\"><p data-start=\"3455\" data-end=\"3502\">Allows clients to stop long tasks gracefully.<\/p><\/li><li data-start=\"3503\" data-end=\"3610\"><p data-start=\"3505\" data-end=\"3610\">Returning <code data-start=\"3515\" data-end=\"3523\">ACCEPT<\/code> doesn\u2019t cancel instantly \u2014 the <strong data-start=\"3555\" data-end=\"3566\">execute<\/strong> loop must <strong data-start=\"3577\" data-end=\"3596\">check and honor<\/strong> cancellation.<\/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-ea0f59e elementor-widget elementor-widget-text-editor\" data-id=\"ea0f59e\" 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>Don\u2019t block the executor: spawn the work<\/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-1404264 elementor-widget elementor-widget-code-highlight\" data-id=\"1404264\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>void acceptedCallback(const std::shared_ptr<GoalHandleFibonacci> goal_handle)\r\n{\r\n  std::thread{std::bind(&SimpleActionServer::execute, this, goal_handle)}.detach();\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-fb7ce2d elementor-widget elementor-widget-text-editor\" data-id=\"fb7ce2d\" 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=\"3843\" data-end=\"4081\"><li data-start=\"3843\" data-end=\"3904\"><p data-start=\"3845\" data-end=\"3904\">The <strong data-start=\"3849\" data-end=\"3861\">accepted<\/strong> callback fires after a goal is accepted.<\/p><\/li><li data-start=\"3905\" data-end=\"4019\"><p data-start=\"3907\" data-end=\"4019\">We launch <code data-start=\"3917\" data-end=\"3928\">execute()<\/code> on a <strong data-start=\"3934\" data-end=\"3953\">separate thread<\/strong> so the node remains responsive (spinning, handling more goals).<\/p><\/li><li data-start=\"4020\" data-end=\"4081\"><p data-start=\"4022\" data-end=\"4081\"><code data-start=\"4022\" data-end=\"4032\">detach()<\/code> \u2192 fire-and-forget; ROS 2 executor isn\u2019t blocked.<\/p><\/li><\/ul><blockquote data-start=\"4083\" data-end=\"4228\"><p data-start=\"4085\" data-end=\"4228\">Alternative: use a dedicated executor, a thread pool, or <code data-start=\"4142\" data-end=\"4154\">std::async<\/code> if you want structured joining. For this tutorial, <code data-start=\"4206\" data-end=\"4216\">detach()<\/code> is perfect.<\/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-0a461ab elementor-widget elementor-widget-text-editor\" data-id=\"0a461ab\" 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 execution loop (compute \u2192 feedback \u2192 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-476d173 elementor-widget elementor-widget-code-highlight\" data-id=\"476d173\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>void execute(const std::shared_ptr<GoalHandleFibonacci> goal_handle)\r\n{\r\n  RCLCPP_INFO(get_logger(), \"Executing goal\");\r\n\r\n  rclcpp::Rate loop_rate(1); \/\/ 1 Hz\r\n  const auto goal = goal_handle->get_goal();\r\n\r\n  auto feedback = std::make_shared<Fibonacci::Feedback>();\r\n  auto & sequence = feedback->partial_sequence;\r\n  sequence.push_back(0);\r\n  sequence.push_back(1);\r\n\r\n  auto result = std::make_shared<Fibonacci::Result>();\r\n\r\n  for (int i = 1; (i < goal->order) && rclcpp::ok(); ++i)\r\n  {\r\n    \/\/ 8.1 honor cancellations\r\n    if (goal_handle->is_canceling())\r\n    {\r\n      result->sequence = sequence;        \/\/ partial result\r\n      goal_handle->canceled(result);      \/\/ set final state + send result\r\n      RCLCPP_INFO(get_logger(), \"Goal canceled\");\r\n      return;\r\n    }\r\n\r\n    \/\/ 8.2 compute next Fibonacci term\r\n    sequence.push_back(sequence[i] + sequence[i - 1]);\r\n\r\n    \/\/ 8.3 send feedback\r\n    goal_handle->publish_feedback(feedback);\r\n    RCLCPP_INFO(get_logger(), \"Publish feedback\");\r\n\r\n    \/\/ 8.4 throttle loop so feedback is visible\r\n    loop_rate.sleep();\r\n  }\r\n\r\n  \/\/ 8.5 success path\r\n  if (rclcpp::ok())\r\n  {\r\n    result->sequence = sequence;\r\n    goal_handle->succeed(result);     \/\/ set final state + send result\r\n    RCLCPP_INFO(get_logger(), \"Goal succeeded\");\r\n  }\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-04dda64 elementor-widget elementor-widget-text-editor\" data-id=\"04dda64\" 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=\"5559\" data-end=\"5576\">What\u2019s happening:<\/p><ul data-start=\"5577\" data-end=\"5926\"><li data-start=\"5577\" data-end=\"5647\"><p data-start=\"5579\" data-end=\"5647\"><code data-start=\"5579\" data-end=\"5593\">loop_rate(1)<\/code> \u2192 one iteration per second (so you <em data-start=\"5629\" data-end=\"5634\">see<\/em> feedback).<\/p><\/li><li data-start=\"5648\" data-end=\"5751\"><p data-start=\"5650\" data-end=\"5751\">We keep a <strong data-start=\"5660\" data-end=\"5670\">single<\/strong> feedback message and mutate its vector; this is efficient and normal in ROS 2.<\/p><\/li><li data-start=\"5752\" data-end=\"5856\"><p data-start=\"5754\" data-end=\"5856\"><strong data-start=\"5754\" data-end=\"5770\">Cancellation<\/strong> is checked every iteration \u2014 if requested, we send the <strong data-start=\"5826\" data-end=\"5837\">partial<\/strong> result and exit.<\/p><\/li><li data-start=\"5857\" data-end=\"5926\"><p data-start=\"5859\" data-end=\"5926\">On success, we fill the <strong data-start=\"5883\" data-end=\"5893\">Result<\/strong> and mark the goal <strong data-start=\"5912\" data-end=\"5925\">SUCCEEDED<\/strong>.<\/p><\/li><\/ul><blockquote data-start=\"5928\" data-end=\"6148\"><p data-start=\"5930\" data-end=\"5964\">Edge cases (optional hardening):<\/p><ul data-start=\"5967\" data-end=\"6148\"><li data-start=\"5967\" data-end=\"6064\"><p data-start=\"5969\" data-end=\"6064\"><code data-start=\"5969\" data-end=\"5981\">order &lt;= 1<\/code>: you might want to <strong data-start=\"6001\" data-end=\"6018\">short-circuit<\/strong> and return <code data-start=\"6030\" data-end=\"6035\">[0]<\/code> or <code data-start=\"6039\" data-end=\"6046\">[0,1]<\/code> as appropriate.<\/p><\/li><li data-start=\"6067\" data-end=\"6148\"><p data-start=\"6069\" data-end=\"6148\"><strong data-start=\"6069\" data-end=\"6085\">Large orders<\/strong>: Fibonacci grows fast; consider <code data-start=\"6118\" data-end=\"6127\">int64_t<\/code> and bounds checking.<\/p><\/li><\/ul><\/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-299bf9e elementor-widget elementor-widget-text-editor\" data-id=\"299bf9e\" 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>Component registration (so you can <code data-start=\"6196\" data-end=\"6206\">ros2 run<\/code> it)<\/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-fab3bdd elementor-widget elementor-widget-code-highlight\" data-id=\"fab3bdd\" 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-cpp \">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>#include <rclcpp_components\/register_node_macro.hpp>\r\nRCLCPP_COMPONENTS_REGISTER_NODE(arduinobot_cpp_examples::SimpleActionServer)\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-7a365ec elementor-widget elementor-widget-text-editor\" data-id=\"7a365ec\" 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=\"6354\" data-end=\"6480\"><p data-start=\"6356\" data-end=\"6480\">Registers this class as a <strong data-start=\"6382\" data-end=\"6395\">component<\/strong>; your CMake uses <code data-start=\"6413\" data-end=\"6446\">rclcpp_components_register_node<\/code> to build an executable for you.<\/p><\/li><li data-start=\"6481\" data-end=\"6585\"><p data-start=\"6483\" data-end=\"6513\">This is why you can simply do:<\/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-1fe1b1c elementor-widget elementor-widget-code-highlight\" data-id=\"1fe1b1c\" 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 run arduinobot_cpp_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-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_cpp_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":3901,"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,248,83,87,179,66,120,290,107,72,246,76,288,64],"class_list":["post-3899","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ros-2","category-tutorials","tag-action","tag-action-server","tag-client","tag-cpp","tag-guide","tag-lbd","tag-learn-by-doing","tag-manipulators","tag-plus","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 C++ - 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 C++\" \/>\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-cpp\/\" \/>\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 C++\" \/>\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-cpp\/\" \/>\n<meta property=\"og:site_name\" content=\"Learn by Doing!\" \/>\n<meta property=\"article:published_time\" content=\"2025-08-21T13:34:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-01-10T21:35:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.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-cpp\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"How to Build and Test a ROS 2 Action Server in C++\",\"datePublished\":\"2025-08-21T13:34:39+00:00\",\"dateModified\":\"2026-01-10T21:35:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/\"},\"wordCount\":1037,\"publisher\":{\"@id\":\"https:\/\/learnbydoing.dev\/es\/#organization\"},\"image\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp\",\"keywords\":[\"Action\",\"action server\",\"client\",\"cpp\",\"Guide\",\"lbd\",\"learn by doing\",\"manipulators\",\"plus\",\"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-cpp\/\",\"url\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/\",\"name\":\"How to Build and Test a ROS 2 Action Server in C++ - 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-cpp\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp\",\"datePublished\":\"2025-08-21T13:34:39+00:00\",\"dateModified\":\"2026-01-10T21:35:34+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 C++\",\"breadcrumb\":{\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#primaryimage\",\"url\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp\",\"contentUrl\":\"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp\",\"width\":1920,\"height\":1080},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#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 C++\"}]},{\"@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 C++ - 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 C++","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-cpp\/","og_locale":"es_ES","og_type":"article","og_title":"How to Build and Test a ROS 2 Action Server in C++","og_description":"Learn by Doing!","og_url":"https:\/\/learnbydoing.dev\/es\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/","og_site_name":"Learn by Doing!","article_published_time":"2025-08-21T13:34:39+00:00","article_modified_time":"2026-01-10T21:35:34+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.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-cpp\/#article","isPartOf":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/"},"author":{"name":"","@id":""},"headline":"How to Build and Test a ROS 2 Action Server in C++","datePublished":"2025-08-21T13:34:39+00:00","dateModified":"2026-01-10T21:35:34+00:00","mainEntityOfPage":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/"},"wordCount":1037,"publisher":{"@id":"https:\/\/learnbydoing.dev\/es\/#organization"},"image":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#primaryimage"},"thumbnailUrl":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp","keywords":["Action","action server","client","cpp","Guide","lbd","learn by doing","manipulators","plus","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-cpp\/","url":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/","name":"How to Build and Test a ROS 2 Action Server in C++ - 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-cpp\/#primaryimage"},"image":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#primaryimage"},"thumbnailUrl":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp","datePublished":"2025-08-21T13:34:39+00:00","dateModified":"2026-01-10T21:35:34+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 C++","breadcrumb":{"@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#primaryimage","url":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp","contentUrl":"https:\/\/learnbydoing.dev\/wp-content\/uploads\/2025\/08\/Action-Server-1.webp","width":1920,"height":1080},{"@type":"BreadcrumbList","@id":"https:\/\/learnbydoing.dev\/how-to-build-and-test-a-ros-2-action-server-in-cpp\/#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 C++"}]},{"@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\/3899","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=3899"}],"version-history":[{"count":7,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/posts\/3899\/revisions"}],"predecessor-version":[{"id":5450,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/posts\/3899\/revisions\/5450"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/media\/3901"}],"wp:attachment":[{"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/media?parent=3899"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/categories?post=3899"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/learnbydoing.dev\/es\/wp-json\/wp\/v2\/tags?post=3899"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}