diff --git a/src/lite6_controller/CMakeLists.txt b/src/lite6_controller/CMakeLists.txt
index 420b6b9..1395c06 100644
--- a/src/lite6_controller/CMakeLists.txt
+++ b/src/lite6_controller/CMakeLists.txt
@@ -22,4 +22,16 @@ if(BUILD_TESTING)
ament_lint_auto_find_test_dependencies()
endif()
+find_package(robot_controller REQUIRED)
+find_package(rclcpp REQUIRED)
+
+find_package(geometry_msgs REQUIRED)
+find_package(rosidl_default_generators REQUIRED)
+
+rosidl_generate_interfaces(${PROJECT_NAME}
+ "msg/Motion.msg"
+ "srv/ExecuteMotion.srv"
+ DEPENDENCIES geometry_msgs # Add packages that above messages depend on
+)
+
ament_package()
diff --git a/src/robot_controller/CMakeLists.txt b/src/robot_controller/CMakeLists.txt
index cb80731..1a9d932 100644
--- a/src/robot_controller/CMakeLists.txt
+++ b/src/robot_controller/CMakeLists.txt
@@ -1,29 +1,31 @@
cmake_minimum_required(VERSION 3.8)
project(robot_controller)
+# Default to C++14
+if(NOT CMAKE_CXX_STANDARD)
+ set(CMAKE_CXX_STANDARD 14)
+endif()
+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
-# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
+find_package(rclcpp_action REQUIRED)
find_package(robot_interfaces REQUIRED)
+add_executable(robot_controller src/cpp/robot_controller.cpp)
+ament_target_dependencies(robot_controller
+ "rclcpp"
+ "rclcpp_action"
+ "robot_interfaces")
+
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
- # the following line skips the linter which checks for copyrights
- # uncomment the line when a copyright and license is not present in all source files
- #set(ament_cmake_copyright_FOUND TRUE)
- # the following line skips cpplint (only works in a git repo)
- # uncomment the line when this package is not in a git repo
- #set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()
-add_executable(robot_controller src/cpp/robot_controller.cpp)
-ament_target_dependencies(robot_controller rclcpp robot_interfaces)
-
install(TARGETS
robot_controller
DESTINATION lib/${PROJECT_NAME})
diff --git a/src/robot_controller/package.xml b/src/robot_controller/package.xml
index 75a78da..fd177da 100644
--- a/src/robot_controller/package.xml
+++ b/src/robot_controller/package.xml
@@ -10,6 +10,8 @@
ament_cmake
rclcpp
+ rclcpp_action
+ rclcpp_components
robot_interfaces
ament_lint_auto
diff --git a/src/robot_controller/src/cpp/robot_controller.cpp b/src/robot_controller/src/cpp/robot_controller.cpp
index f48571f..25f89af 100644
--- a/src/robot_controller/src/cpp/robot_controller.cpp
+++ b/src/robot_controller/src/cpp/robot_controller.cpp
@@ -1,58 +1,125 @@
#include
-#include "rclcpp/rclcpp.hpp"
-#include "robot_interfaces/srv/execute_motion.hpp"
+#include
+#include
+#include
+#include "robot_interfaces/action/execute_motion.hpp"
+#include "rclcpp/rclcpp.hpp"
+#include "rclcpp_action/rclcpp_action.hpp"
+#include "rclcpp_components/register_node_macro.hpp"
+
+//#include "robot_interfaces/visibility_control.h"
+
+//
+// https://docs.ros.org/en/foxy/Tutorials/Intermediate/Writing-an-Action-Server-Client/Cpp.html
class RobotController : public rclcpp::Node
{
public:
- RobotController(std::string name) : Node(name)
- {
- this->service = this->create_service("execute_path", std::bind(&RobotController::executePath, this, std::placeholders::_1, std::placeholders::_2));
- }
+ using ExecuteMotion = robot_interfaces::action::ExecuteMotion;
+ using GoalHandleExecuteMotion = rclcpp_action::ServerGoalHandle;
- /// Callback that executes path on robot
- virtual void executePath(const std::shared_ptr request, std::shared_ptr response)
+ explicit RobotController(const rclcpp::NodeOptions & options = rclcpp::NodeOptions())
+ : Node("robot_controller",options)
{
- //request->motion->path PoseStamped[]
- //request->motion->acceleration float64
- //request->motion->velocity float64
- RCLCPP_INFO(this->get_logger(), "NEW MOTION: Acceleration: ");
- //RCLCPP_INFO(this->get_logger(), "Acceleration: " + std::to_string(request.motion.acceleration));
- response->status = "executePath not implemented";
- RCLCPP_WARN(this->get_logger(), "executePath not implemented");
+ using namespace std::placeholders;
+
+ this->action_server_ = rclcpp_action::create_server(
+ this,
+ "execute_motion",
+ std::bind(&RobotController::motion_handle_goal, this, _1, _2),
+ std::bind(&RobotController::motion_handle_cancel, this, _1),
+ std::bind(&RobotController::motion_handle_accepted, this, _1));
}
private:
- rclcpp::Service::SharedPtr service;
+ rclcpp_action::Server::SharedPtr action_server_;
+
+ virtual rclcpp_action::GoalResponse motion_handle_goal(
+ const rclcpp_action::GoalUUID & uuid,
+ std::shared_ptr goal)
+ {
+ RCLCPP_INFO(this->get_logger(), "Received goal request with acceleration %f", goal->motion.acceleration);
+ (void)uuid;
+ return rclcpp_action::GoalResponse::ACCEPT_AND_EXECUTE;
+ }
+
+ virtual rclcpp_action::CancelResponse motion_handle_cancel(
+ const std::shared_ptr goal_handle)
+ {
+ RCLCPP_INFO(this->get_logger(), "Received request to cancel goal");
+ (void)goal_handle;
+ return rclcpp_action::CancelResponse::ACCEPT;
+ }
+
+ virtual void motion_handle_accepted(const std::shared_ptr goal_handle)
+ {
+ using namespace std::placeholders;
+ // this needs to return quickly to avoid blocking the executor, so spin up a new thread
+ std::thread{std::bind(&RobotController::executePath, this, _1), goal_handle}.detach();
+ }
+
+ /// Callback that executes path on robot
+ virtual void executePath(const std::shared_ptr goal_handle)
+ {
+ const auto goal = goal_handle->get_goal();
+ auto feedback = std::make_shared();
+ auto result = std::make_shared();
+ std::string msg = "executePath not implemented";
+ result->result = msg;
+ feedback->status = msg;
+ RCLCPP_WARN(this->get_logger(), msg.c_str());
+ }
};
// A controller for a Dummy robot. Only logs messages and serves as an example for real implementation.
class DummyController : public RobotController
{
public:
+ DummyController(const rclcpp::NodeOptions & options = rclcpp::NodeOptions()) : RobotController(options) {}
- DummyController(std::string name) : RobotController(name) {}
+ /// Callback that executes path on robot
+ virtual void executePath(const std::shared_ptr> goal_handle)
+ {
+ RCLCPP_INFO(this->get_logger(), "Executing goal");
+ rclcpp::Rate loop_rate(1);
+ const auto goal = goal_handle->get_goal();
+ auto feedback = std::make_shared();
+ auto status = feedback->status;
+ auto result = std::make_shared();
- virtual void executePath(const std::shared_ptr request, std::shared_ptr response)
- {
- //request->motion->path PoseStamped[]
- //request->motion->acceleration float64
- //request->motion->velocity float64
- RCLCPP_INFO(this->get_logger(), "NEW MOTION: Acceleration: ");
- //RCLCPP_INFO(this->get_logger(), "Acceleration: " + std::to_string(request.motion.acceleration));
- response->status = "executePath not implemented";
- RCLCPP_WARN(this->get_logger(), "AAAAAA executePath not implemented");
+
+ for (int i = 1; (i < 100) && rclcpp::ok(); ++i) {
+ // Check if there is a cancel request
+ if (goal_handle->is_canceling()) {
+ result->result = status;
+ goal_handle->canceled(result);
+ RCLCPP_INFO(this->get_logger(), "Goal canceled");
+ return;
+ }
+ // Update status
+ status = i + "/100 complete";
+ // Publish feedback
+ goal_handle->publish_feedback(feedback);
+ RCLCPP_INFO(this->get_logger(), "Publish feedback");
+
+ loop_rate.sleep();
}
+ // Check if goal is done
+ if (rclcpp::ok()) {
+ result->result = status;
+ goal_handle->succeed(result);
+ RCLCPP_INFO(this->get_logger(), "Goal succeeded");
+ }
+ }
};
-
int main(int argc, char ** argv)
{
rclcpp::init(argc, argv);
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Starting dummy_controller");
- auto robot = std::make_shared("dummy");
+ auto robot = std::make_shared();
rclcpp::executors::SingleThreadedExecutor executor;
executor.add_node(robot);
diff --git a/src/robot_interfaces/CMakeLists.txt b/src/robot_interfaces/CMakeLists.txt
index 69f4e66..da0d9e9 100644
--- a/src/robot_interfaces/CMakeLists.txt
+++ b/src/robot_interfaces/CMakeLists.txt
@@ -29,6 +29,7 @@ find_package(rclcpp REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME}
"msg/Motion.msg"
"srv/ExecuteMotion.srv"
+ "action/ExecuteMotion.action"
DEPENDENCIES geometry_msgs # Add packages that above messages depend on
)
diff --git a/src/robot_interfaces/action/ExecuteMotion.action b/src/robot_interfaces/action/ExecuteMotion.action
new file mode 100644
index 0000000..220bb16
--- /dev/null
+++ b/src/robot_interfaces/action/ExecuteMotion.action
@@ -0,0 +1,7 @@
+# Motion action
+
+Motion motion
+---
+string result
+---
+string status
diff --git a/src/robot_interfaces/package.xml b/src/robot_interfaces/package.xml
index 8332bba..2c830dd 100644
--- a/src/robot_interfaces/package.xml
+++ b/src/robot_interfaces/package.xml
@@ -13,6 +13,7 @@
ament_lint_common
geometry_msgs
+ action_msgs
rosidl_default_generators