diff --git a/src/subjugator/mission_planner/CMakeLists.txt b/src/subjugator/mission_planner/CMakeLists.txt index 4e1527cbe..0a592d81f 100644 --- a/src/subjugator/mission_planner/CMakeLists.txt +++ b/src/subjugator/mission_planner/CMakeLists.txt @@ -32,7 +32,8 @@ add_library( subjugator_operations/src/poles_big_enough.cpp subjugator_operations/src/determine_channel_side.cpp subjugator_operations/src/any_poles_detected.cpp - subjugator_operations/src/has_found_pair.cpp) + subjugator_operations/src/has_found_pair.cpp + subjugator_operations/src/waypoint_recorder.cpp) ament_target_dependencies( operations diff --git a/src/subjugator/mission_planner/include/context.hpp b/src/subjugator/mission_planner/include/context.hpp index a7e4884e9..3469d2425 100644 --- a/src/subjugator/mission_planner/include/context.hpp +++ b/src/subjugator/mission_planner/include/context.hpp @@ -1,10 +1,12 @@ #pragma once #include #include +#include #include #include +#include #include #include #include @@ -33,6 +35,11 @@ struct Context uint32_t img_width{ 0 }; uint32_t img_height{ 0 }; + // Waypoints + std::mutex waypoints_mx; + std::vector waypoints; + std::optional last_waypoint; + inline rclcpp::Logger logger() const { return node->get_logger(); diff --git a/src/subjugator/mission_planner/src/mission_planner_node.cpp b/src/subjugator/mission_planner/src/mission_planner_node.cpp index 686bd19bc..e11e753fb 100644 --- a/src/subjugator/mission_planner/src/mission_planner_node.cpp +++ b/src/subjugator/mission_planner/src/mission_planner_node.cpp @@ -18,6 +18,7 @@ #include "poles_big_enough.hpp" #include "publish_goal.hpp" #include "track_largest_poles.hpp" +#include "waypoint_recorder.hpp" #include #include @@ -91,6 +92,7 @@ int main(int argc, char** argv) factory.registerNodeType("DetermineChannelSide"); factory.registerNodeType("AnyPolesDetected"); factory.registerNodeType("HasFoundPair"); + factory.registerNodeType("WaypointRecorder"); factory.registerNodeType>("TopicTicker"); factory.registerNodeType("CountWhenTicked"); diff --git a/src/subjugator/mission_planner/subjugator_missions/xml/relative_move.xml b/src/subjugator/mission_planner/subjugator_missions/xml/relative_move.xml index 43eb78468..1740f70f0 100644 --- a/src/subjugator/mission_planner/subjugator_missions/xml/relative_move.xml +++ b/src/subjugator/mission_planner/subjugator_missions/xml/relative_move.xml @@ -13,6 +13,13 @@ + + + + +#include + +#include "context.hpp" + +struct Context; +class OperationBase; + +class WaypointRecorder final : public BT::SyncActionNode, public OperationBase +{ + public: + WaypointRecorder(std::string const& name, const BT::NodeConfiguration& config) + : BT::SyncActionNode(name, config), OperationBase(config) + { + } + + static BT::PortsList providedPorts(); + + BT::NodeStatus tick() override; +}; diff --git a/src/subjugator/mission_planner/subjugator_operations/src/waypoint_recorder.cpp b/src/subjugator/mission_planner/subjugator_operations/src/waypoint_recorder.cpp new file mode 100644 index 000000000..62eee46b0 --- /dev/null +++ b/src/subjugator/mission_planner/subjugator_operations/src/waypoint_recorder.cpp @@ -0,0 +1,90 @@ +#include "waypoint_recorder.hpp" + +#include +#include + +#include +#include +#include +#include + +#include "rclcpp/rclcpp.hpp" + +#include "context.hpp" +#include "geometry_msgs/msg/pose_stamped.hpp" +#include "nav_msgs/msg/odometry.hpp" +#include "nav_msgs/msg/path.hpp" +#include "operations.hpp" + +BT::NodeStatus WaypointRecorder::tick() +{ + double gx, gy, gz, gqx, gqy, gqz, gqw, spacing_m; + std::shared_ptr ctx_; + + if (!getInput("x", gx) || !getInput("y", gy) || !getInput("z", gz) || !getInput("qx", gqx) || + !getInput("qy", gqy) || !getInput("qz", gqz) || !getInput("qw", gqw) || !getInput("spacing_m", spacing_m) || + !getInput("ctx_", ctx_)) + { + RCLCPP_ERROR(ctx_->logger(), "WaypointRecorder: missing required inputs."); + } + + std::optional odom; + { + std::scoped_lock lk(ctx_->odom_mx); + odom = ctx_->latest_odom; + } + + if (!odom) + { + RCLCPP_WARN_THROTTLE(ctx_->logger(), *ctx_->node->get_clock(), 1000, "WaypointRecorder: no odometry yet."); + } + else + { + geometry_msgs::msg::PoseStamped wp; + wp.header = odom->header; + wp.pose = odom->pose.pose; + + std::scoped_lock lkwp(ctx_->waypoints_mx); + + if (!ctx_->last_waypoint) + { + ctx_->waypoints.push_back(wp); + ctx_->last_waypoint = wp; + + if (ctx_) + { + RCLCPP_INFO(ctx_->logger(), "WaypointRecorder: first waypoint recorded."); + } + } + else + { + auto const& last = ctx_->last_waypoint->pose.position; + double const dx = wp.pose.position.x - last.x; + double const dy = wp.pose.position.y - last.y; + double const d = std::sqrt(dx * dx + dy * dy); + + if (d >= spacing_m) + { + ctx_->waypoints.push_back(wp); + ctx_->last_waypoint = wp; + RCLCPP_INFO(ctx_->logger(), "WaypointRecorder: recorded waypoint #%zu", ctx_->waypoints.size()); + } + } + } + return BT::NodeStatus::SUCCESS; +} + +BT::PortsList WaypointRecorder::providedPorts() +{ + BT::PortsList ports; + ports.insert(BT::InputPort("x")); + ports.insert(BT::InputPort("y")); + ports.insert(BT::InputPort("z")); + ports.insert(BT::InputPort("qx")); + ports.insert(BT::InputPort("qy")); + ports.insert(BT::InputPort("qz")); + ports.insert(BT::InputPort("qw")); + ports.insert(BT::InputPort("spacing_m", 0.5, "Waypoint spacing in meters")); + ports.insert(BT::InputPort>("ctx_")); + return ports; +}