15 #include "nav2_map_server/vector_object_server.hpp"
24 #include "rclcpp/create_timer.hpp"
26 #include "nav2_util/occ_grid_utils.hpp"
27 #include "nav2_util/occ_grid_values.hpp"
29 using namespace std::placeholders;
31 namespace nav2_map_server
34 VectorObjectServer::VectorObjectServer(
const rclcpp::NodeOptions & options)
35 : nav2::LifecycleNode(
"vector_object_server",
"", options), process_map_(false)
41 RCLCPP_INFO(get_logger(),
"Configuring");
44 return nav2::CallbackReturn::FAILURE;
49 tf_buffer_ = nav2::create_transform_buffer(
this);
54 "Parameter enforce_global_frame_id is true. TF listener is disabled. "
55 "All incoming shapes must have frame_id empty or equal to global_frame_id '%s'.",
59 map_pub_ = create_publisher<nav_msgs::msg::OccupancyGrid>(
75 return nav2::CallbackReturn::SUCCESS;
81 RCLCPP_INFO(get_logger(),
"Activating");
92 return nav2::CallbackReturn::SUCCESS;
98 RCLCPP_INFO(get_logger(),
"Deactivating");
111 return nav2::CallbackReturn::SUCCESS;
117 RCLCPP_INFO(get_logger(),
"Cleaning up");
131 return nav2::CallbackReturn::SUCCESS;
137 RCLCPP_INFO(get_logger(),
"Shutting down");
138 return nav2::CallbackReturn::SUCCESS;
146 map_topic_ = nav2::declare_or_get_parameter(node,
"map_topic", std::string{
"vo_map"});
147 global_frame_id_ = nav2::declare_or_get_parameter(node,
"global_frame_id", std::string{
"map"});
149 resolution_ = nav2::declare_or_get_parameter(node,
"resolution", 0.05);
151 node,
"default_value",
152 static_cast<int>(nav2_util::OCC_GRID_UNKNOWN));
153 overlay_type_ =
static_cast<OverlayType
>(nav2::declare_or_get_parameter(
154 node,
"overlay_type",
155 static_cast<int>(OverlayType::OVERLAY_SEQ)));
156 update_frequency_ = nav2::declare_or_get_parameter(node,
"update_frequency", 1.0);
160 auto shape_names = nav2::declare_or_get_parameter(node,
"shapes", std::vector<std::string>());
161 for (std::string shape_name : shape_names) {
162 std::string shape_type;
164 shape_type = nav2::declare_or_get_parameter<std::string>(node, shape_name +
".type");
165 }
catch (
const std::exception & ex) {
167 get_logger(),
"Error while getting shape %s type: %s", shape_name.c_str(), ex.what());
171 if (shape_type ==
"polygon") {
172 auto polygon = std::make_shared<Polygon>(node);
173 if (!polygon->obtainParams(shape_name)) {
177 }
else if (shape_type ==
"circle") {
178 auto circle = std::make_shared<Circle>(node);
179 if (!circle->obtainParams(shape_name)) {
186 "Please specify the correct type for shape %s. Supported types are 'polygon' and 'circle'",
194 for (
const auto & shape :
shapes_) {
195 const std::string & frame_id = shape->getFrameID();
199 "Shape '%s' has frame_id '%s' which differs from global_frame_id '%s'. "
200 "All shapes must have frame_id empty or equal to global_frame_id "
201 "when enforce_global_frame_id is true.",
212 std::vector<std::shared_ptr<Shape>>::iterator
216 if ((*it)->isUUID(uuid)) {
226 if (shape->getFrameID() !=
global_frame_id_ && !shape->getFrameID().empty()) {
230 get_logger(),
"Can not transform vector object from %s to %s frame",
241 double & min_x,
double & min_y,
double & max_x,
double & max_y)
const
243 min_x = std::numeric_limits<double>::max();
244 min_y = std::numeric_limits<double>::max();
245 max_x = std::numeric_limits<double>::lowest();
246 max_y = std::numeric_limits<double>::lowest();
248 double min_p_x, min_p_y, max_p_x, max_p_y;
250 shape->getBoundaries(min_p_x, min_p_y, max_p_x, max_p_y);
251 min_x = std::min(min_x, min_p_x);
252 min_y = std::min(min_y, min_p_y);
253 max_x = std::max(max_x, max_p_x);
254 max_y = std::max(max_y, max_p_y);
258 min_x == std::numeric_limits<double>::max() ||
259 min_y == std::numeric_limits<double>::max() ||
260 max_x == std::numeric_limits<double>::lowest() ||
261 max_y == std::numeric_limits<double>::lowest())
263 throw std::runtime_error(
"Can not obtain map boundaries");
268 const double & min_x,
const double & min_y,
const double & max_x,
const double & max_y)
271 int size_x =
static_cast<int>((max_x - min_x) /
resolution_) + 1;
272 int size_y =
static_cast<int>((max_y - min_y) /
resolution_) + 1;
275 throw std::runtime_error(
"Incorrect map x-size");
279 throw std::runtime_error(
"Incorrect map y-size");
283 map_ = std::make_shared<nav_msgs::msg::OccupancyGrid>();
287 map_->info.width !=
static_cast<unsigned int>(size_x) ||
288 map_->info.height !=
static_cast<unsigned int>(size_y))
292 map_->info.width = size_x;
293 map_->info.height = size_y;
294 }
else if (size_x > 0 && size_y > 0) {
301 map_->info.origin.position.x = min_x;
302 map_->info.origin.position.y = min_y;
309 if (shape->isFill()) {
311 double wx1 = std::numeric_limits<double>::max();
312 double wy1 = std::numeric_limits<double>::max();
313 double wx2 = std::numeric_limits<double>::lowest();
314 double wy2 = std::numeric_limits<double>::lowest();
315 unsigned int mx1 = 0;
316 unsigned int my1 = 0;
317 unsigned int mx2 = 0;
318 unsigned int my2 = 0;
320 shape->getBoundaries(wx1, wy1, wx2, wy2);
322 !nav2_util::worldToMap(
map_, wx1, wy1, mx1, my1) ||
323 !nav2_util::worldToMap(
map_, wx2, wy2, mx2, my2))
327 "Error to get shape boundaries on map (UUID: %s)", shape->getUUID().c_str());
332 for (
unsigned int my = my1; my <= my2; my++) {
333 for (
unsigned int mx = mx1; mx <= mx2; mx++) {
334 it = my *
map_->info.width + mx;
336 nav2_util::mapToWorld(
map_, mx, my, wx, wy);
337 if (shape->isPointInside(wx, wy)) {
352 auto map = std::make_unique<nav_msgs::msg::OccupancyGrid>(*
map_);
368 double min_x, min_y, max_x, max_y;
376 }
catch (
const std::exception & ex) {
377 RCLCPP_ERROR(get_logger(),
"Can not update map: %s", ex.what());
387 if (shape->getFrameID() !=
global_frame_id_ && !shape->getFrameID().empty()) {
393 RCLCPP_INFO(get_logger(),
"Publishing map dynamically at %f Hz rate",
update_frequency_);
402 RCLCPP_INFO(get_logger(),
"Publishing map once");
407 const std::shared_ptr<rmw_request_id_t>,
408 const std::shared_ptr<nav2_msgs::srv::AddShapes::Request> request,
409 std::shared_ptr<nav2_msgs::srv::AddShapes::Response> response)
413 response->success =
true;
417 auto check_frame_id = [
this](
418 const auto & shapes,
const std::string & shape_type_name)
420 for (
const auto & shape : shapes) {
421 if (!shape.header.frame_id.empty() && shape.header.frame_id !=
global_frame_id_) {
424 "%s frame_id '%s' must be empty or equal to global_frame_id '%s' "
425 "when enforce_global_frame_id is true. Rejecting request.",
426 shape_type_name.c_str(), shape.header.frame_id.c_str(),
global_frame_id_.c_str());
433 if (!check_frame_id(request->polygons,
"Polygon") ||
434 !check_frame_id(request->circles,
"Circle"))
436 response->success =
false;
444 for (
auto req_poly : request->polygons) {
445 nav2_msgs::msg::PolygonObject::SharedPtr new_params =
446 std::make_shared<nav2_msgs::msg::PolygonObject>(req_poly);
448 auto it =
findShape(new_params->uuid.uuid.data());
452 if ((*it)->getType() != POLYGON) {
455 "Shape (UUID: %s) is not a polygon type for a polygon update. Not adding shape.",
456 (*it)->getUUID().c_str());
457 response->success =
false;
462 std::shared_ptr<Polygon> polygon = std::static_pointer_cast<Polygon>(*it);
465 nav2_msgs::msg::PolygonObject::SharedPtr old_params = polygon->getParams();
466 if (!polygon->setParams(new_params)) {
469 "Failed to update existing polygon object (UUID: %s) with new params. "
470 "Reverting to old polygon params.",
471 (*it)->getUUID().c_str());
473 polygon->setParams(old_params);
475 response->success =
false;
479 std::shared_ptr<Polygon> polygon = std::make_shared<Polygon>(node);
480 if (polygon->setParams(new_params)) {
484 get_logger(),
"Failed to create a new polygon object using the provided params.");
485 response->success =
false;
491 for (
auto req_crcl : request->circles) {
492 nav2_msgs::msg::CircleObject::SharedPtr new_params =
493 std::make_shared<nav2_msgs::msg::CircleObject>(req_crcl);
495 auto it =
findShape(new_params->uuid.uuid.data());
499 if ((*it)->getType() != CIRCLE) {
502 "Shape (UUID: %s) is not a circle type for a circle update. Not adding shape.",
503 (*it)->getUUID().c_str());
504 response->success =
false;
509 std::shared_ptr<Circle> circle = std::static_pointer_cast<Circle>(*it);
512 nav2_msgs::msg::CircleObject::SharedPtr old_params = circle->getParams();
513 if (!circle->setParams(new_params)) {
516 "Failed to update existing circle object (UUID: %s) with new params. "
517 "Reverting to old circle params.",
518 (*it)->getUUID().c_str());
520 circle->setParams(old_params);
522 response->success =
false;
526 std::shared_ptr<Circle> circle = std::make_shared<Circle>(node);
527 if (circle->setParams(new_params)) {
531 get_logger(),
"Failed to create a new circle object using the provided params.");
532 response->success =
false;
541 const std::shared_ptr<rmw_request_id_t>,
542 const std::shared_ptr<nav2_msgs::srv::GetShapes::Request>,
543 std::shared_ptr<nav2_msgs::srv::GetShapes::Response> response)
545 std::shared_ptr<Polygon> polygon;
546 std::shared_ptr<Circle> circle;
549 switch (shape->getType()) {
551 polygon = std::static_pointer_cast<Polygon>(shape);
552 response->polygons.push_back(*(polygon->getParams()));
555 circle = std::static_pointer_cast<Circle>(shape);
556 response->circles.push_back(*(circle->getParams()));
559 RCLCPP_WARN(get_logger(),
"Unknown shape type (UUID: %s)", shape->getUUID().c_str());
565 const std::shared_ptr<rmw_request_id_t>,
566 const std::shared_ptr<nav2_msgs::srv::RemoveShapes::Request> request,
567 std::shared_ptr<nav2_msgs::srv::RemoveShapes::Response> response)
571 response->success =
true;
573 if (request->all_objects) {
578 for (
auto req_uuid : request->uuids) {
579 auto it =
findShape(req_uuid.uuid.data());
588 "Can not find shape to remove with UUID: %s",
589 unparseUUID(req_uuid.uuid.data()).c_str());
590 response->success =
false;
600 #include "rclcpp_components/register_node_macro.hpp"
void destroyBond()
Destroy bond connection to lifecycle manager.
nav2::LifecycleNode::SharedPtr shared_from_this()
Get a shared pointer of this.
rclcpp::GenericTimer< CallbackT >::SharedPtr create_timer(std::chrono::duration< DurationRepT, DurationT > period, CallbackT callback, rclcpp::CallbackGroup::SharedPtr group=nullptr)
Create a sim-time-aware timer for Nav2 lifecycle nodes.
void createBond()
Create bond connection to lifecycle manager.
A QoS profile for latched, reliable topics with a history of 1 messages.
Vector Object server node.
void addShapesCallback(const std::shared_ptr< rmw_request_id_t > request_header, const std::shared_ptr< nav2_msgs::srv::AddShapes::Request > request, std::shared_ptr< nav2_msgs::srv::AddShapes::Response > response)
Callback for AddShapes service call. Reads all input vector objects from service request,...
void switchMapUpdate()
If map to be update dynamically, creates map processing timer, otherwise process map once.
void publishMap()
Publishes output map.
nav2::CallbackReturn on_cleanup(const rclcpp_lifecycle::State &state) override
: Resets all services, publishers, map and TF-s
double process_map_
Whether to process and publish map.
nav2::ServiceServer< nav2_msgs::srv::GetShapes >::SharedPtr get_shapes_service_
GetShapes service.
bool transformVectorObjects()
Transform all vector shapes from their local frame to output map frame.
void processMap()
Calculates new map sizes, updates map, processes all vector objects on it and publishes output map on...
std::vector< std::shared_ptr< Shape > > shapes_
All shapes vector.
double update_frequency_
Frequency to dynamically update/publish the map (if necessary)
int8_t default_value_
Default value the output map to be filled with.
void removeShapesCallback(const std::shared_ptr< rmw_request_id_t > request_header, const std::shared_ptr< nav2_msgs::srv::RemoveShapes::Request > request, std::shared_ptr< nav2_msgs::srv::RemoveShapes::Response > response)
Callback for RemoveShapes service call. Try to remove requested vector objects and switches map proce...
std::vector< std::shared_ptr< Shape > >::iterator findShape(const unsigned char *uuid)
Finds the shape with given UUID.
double resolution_
Output map resolution.
nav2::CallbackReturn on_activate(const rclcpp_lifecycle::State &state) override
: Activates output map publisher and creates bond connection
bool enforce_global_frame_id_
If true, disables TF listener and requires all incoming shapes to have frame_id empty or equal to glo...
nav2::Publisher< nav_msgs::msg::OccupancyGrid >::SharedPtr map_pub_
Output map publisher.
nav_msgs::msg::OccupancyGrid::SharedPtr map_
Output map with vector objects on it.
void putVectorObjectsOnMap()
Processes all vector objects on raster output map.
double transform_tolerance_
Transform tolerance.
std::string global_frame_id_
Frame of output map.
std::string map_topic_
@beirf Topic name where the output map to be published to
nav2::CallbackReturn on_shutdown(const rclcpp_lifecycle::State &state) override
Called in shutdown state.
rclcpp::TimerBase::SharedPtr map_timer_
Map update timer.
void getMapBoundaries(double &min_x, double &min_y, double &max_x, double &max_y) const
Obtains map boundaries to place all vector objects inside.
void getShapesCallback(const std::shared_ptr< rmw_request_id_t > request_header, const std::shared_ptr< nav2_msgs::srv::GetShapes::Request > request, std::shared_ptr< nav2_msgs::srv::GetShapes::Response > response)
Callback for GetShapes service call. Gets all shapes and returns them to the service response.
nav2::CallbackReturn on_deactivate(const rclcpp_lifecycle::State &state) override
: Deactivates map publisher and timer (if any), destroys bond connection
nav2::ServiceServer< nav2_msgs::srv::AddShapes >::SharedPtr add_shapes_service_
AddShapes service.
nav2::TransformListener::SharedPtr tf_listener_
TF listener.
nav2::TransformBuffer::SharedPtr tf_buffer_
TF buffer.
void updateMap(const double &min_x, const double &min_y, const double &max_x, const double &max_y)
Creates or updates existing map with required sizes and fills it with default value.
nav2::CallbackReturn on_configure(const rclcpp_lifecycle::State &state) override
: Initializes TF buffer/listener, obtains ROS-parameters, creates incoming services,...
OverlayType overlay_type_
@Overlay Type of overlay of vector objects on the map
bool obtainParams()
Supporting routine obtaining all ROS-parameters.
nav2::ServiceServer< nav2_msgs::srv::RemoveShapes >::SharedPtr remove_shapes_service_
RemoveShapes service.