15 #include "nav2_map_server/vector_object_server.hpp"
24 #include "rclcpp/create_timer.hpp"
26 #include "nav2_util/occ_grid_values.hpp"
28 using namespace std::placeholders;
30 namespace nav2_map_server
33 VectorObjectServer::VectorObjectServer(
const rclcpp::NodeOptions & options)
34 : nav2::LifecycleNode(
"vector_object_server",
"", options), process_map_(false)
40 RCLCPP_INFO(get_logger(),
"Configuring");
43 return nav2::CallbackReturn::FAILURE;
48 tf_buffer_ = nav2::create_transform_buffer(
this);
53 "Parameter enforce_global_frame_id is true. TF listener is disabled. "
54 "All incoming shapes must have frame_id empty or equal to global_frame_id '%s'.",
58 map_pub_ = create_publisher<nav_msgs::msg::OccupancyGrid>(
74 return nav2::CallbackReturn::SUCCESS;
80 RCLCPP_INFO(get_logger(),
"Activating");
91 return nav2::CallbackReturn::SUCCESS;
97 RCLCPP_INFO(get_logger(),
"Deactivating");
110 return nav2::CallbackReturn::SUCCESS;
116 RCLCPP_INFO(get_logger(),
"Cleaning up");
130 return nav2::CallbackReturn::SUCCESS;
136 RCLCPP_INFO(get_logger(),
"Shutting down");
137 return nav2::CallbackReturn::SUCCESS;
145 map_topic_ = nav2::declare_or_get_parameter(node,
"map_topic", std::string{
"vo_map"});
146 global_frame_id_ = nav2::declare_or_get_parameter(node,
"global_frame_id", std::string{
"map"});
148 resolution_ = nav2::declare_or_get_parameter(node,
"resolution", 0.05);
150 node,
"default_value",
151 static_cast<int>(nav2_util::OCC_GRID_UNKNOWN));
152 overlay_type_ =
static_cast<OverlayType
>(nav2::declare_or_get_parameter(
153 node,
"overlay_type",
154 static_cast<int>(OverlayType::OVERLAY_SEQ)));
155 update_frequency_ = nav2::declare_or_get_parameter(node,
"update_frequency", 1.0);
159 auto shape_names = nav2::declare_or_get_parameter(node,
"shapes", std::vector<std::string>());
160 for (std::string shape_name : shape_names) {
161 std::string shape_type;
163 shape_type = nav2::declare_or_get_parameter<std::string>(node, shape_name +
".type");
164 }
catch (
const std::exception & ex) {
166 get_logger(),
"Error while getting shape %s type: %s", shape_name.c_str(), ex.what());
170 if (shape_type ==
"polygon") {
171 auto polygon = std::make_shared<Polygon>(node);
172 if (!polygon->obtainParams(shape_name)) {
176 }
else if (shape_type ==
"circle") {
177 auto circle = std::make_shared<Circle>(node);
178 if (!circle->obtainParams(shape_name)) {
185 "Please specify the correct type for shape %s. Supported types are 'polygon' and 'circle'",
193 for (
const auto & shape :
shapes_) {
194 const std::string & frame_id = shape->getFrameID();
198 "Shape '%s' has frame_id '%s' which differs from global_frame_id '%s'. "
199 "All shapes must have frame_id empty or equal to global_frame_id "
200 "when enforce_global_frame_id is true.",
211 std::vector<std::shared_ptr<Shape>>::iterator
215 if ((*it)->isUUID(uuid)) {
225 if (shape->getFrameID() !=
global_frame_id_ && !shape->getFrameID().empty()) {
229 get_logger(),
"Can not transform vector object from %s to %s frame",
240 double & min_x,
double & min_y,
double & max_x,
double & max_y)
const
242 min_x = std::numeric_limits<double>::max();
243 min_y = std::numeric_limits<double>::max();
244 max_x = std::numeric_limits<double>::lowest();
245 max_y = std::numeric_limits<double>::lowest();
247 double min_p_x, min_p_y, max_p_x, max_p_y;
249 shape->getBoundaries(min_p_x, min_p_y, max_p_x, max_p_y);
250 min_x = std::min(min_x, min_p_x);
251 min_y = std::min(min_y, min_p_y);
252 max_x = std::max(max_x, max_p_x);
253 max_y = std::max(max_y, max_p_y);
257 min_x == std::numeric_limits<double>::max() ||
258 min_y == std::numeric_limits<double>::max() ||
259 max_x == std::numeric_limits<double>::lowest() ||
260 max_y == std::numeric_limits<double>::lowest())
262 throw std::runtime_error(
"Can not obtain map boundaries");
267 const double & min_x,
const double & min_y,
const double & max_x,
const double & max_y)
270 int size_x =
static_cast<int>((max_x - min_x) /
resolution_) + 1;
271 int size_y =
static_cast<int>((max_y - min_y) /
resolution_) + 1;
274 throw std::runtime_error(
"Incorrect map x-size");
278 throw std::runtime_error(
"Incorrect map y-size");
282 map_ = std::make_shared<nav_msgs::msg::OccupancyGrid>();
286 map_->info.width !=
static_cast<unsigned int>(size_x) ||
287 map_->info.height !=
static_cast<unsigned int>(size_y))
291 map_->info.width = size_x;
292 map_->info.height = size_y;
293 }
else if (size_x > 0 && size_y > 0) {
300 map_->info.origin.position.x = min_x;
301 map_->info.origin.position.y = min_y;
308 if (shape->isFill()) {
312 "Error to get shape boundaries on map (UUID: %s)", shape->getUUID().c_str());
325 auto map = std::make_unique<nav_msgs::msg::OccupancyGrid>(*
map_);
341 double min_x, min_y, max_x, max_y;
349 }
catch (
const std::exception & ex) {
350 RCLCPP_ERROR(get_logger(),
"Can not update map: %s", ex.what());
360 if (shape->getFrameID() !=
global_frame_id_ && !shape->getFrameID().empty()) {
366 RCLCPP_INFO(get_logger(),
"Publishing map dynamically at %f Hz rate",
update_frequency_);
375 RCLCPP_INFO(get_logger(),
"Publishing map once");
380 const std::shared_ptr<rmw_request_id_t>,
381 const std::shared_ptr<nav2_msgs::srv::AddShapes::Request> request,
382 std::shared_ptr<nav2_msgs::srv::AddShapes::Response> response)
386 response->success =
true;
390 auto check_frame_id = [
this](
391 const auto & shapes,
const std::string & shape_type_name)
393 for (
const auto & shape : shapes) {
394 if (!shape.header.frame_id.empty() && shape.header.frame_id !=
global_frame_id_) {
397 "%s frame_id '%s' must be empty or equal to global_frame_id '%s' "
398 "when enforce_global_frame_id is true. Rejecting request.",
399 shape_type_name.c_str(), shape.header.frame_id.c_str(),
global_frame_id_.c_str());
406 if (!check_frame_id(request->polygons,
"Polygon") ||
407 !check_frame_id(request->circles,
"Circle"))
409 response->success =
false;
417 for (
auto req_poly : request->polygons) {
418 nav2_msgs::msg::PolygonObject::SharedPtr new_params =
419 std::make_shared<nav2_msgs::msg::PolygonObject>(req_poly);
421 auto it =
findShape(new_params->uuid.uuid.data());
425 if ((*it)->getType() != POLYGON) {
428 "Shape (UUID: %s) is not a polygon type for a polygon update. Not adding shape.",
429 (*it)->getUUID().c_str());
430 response->success =
false;
435 std::shared_ptr<Polygon> polygon = std::static_pointer_cast<Polygon>(*it);
438 nav2_msgs::msg::PolygonObject::SharedPtr old_params = polygon->getParams();
439 if (!polygon->setParams(new_params)) {
442 "Failed to update existing polygon object (UUID: %s) with new params. "
443 "Reverting to old polygon params.",
444 (*it)->getUUID().c_str());
446 polygon->setParams(old_params);
448 response->success =
false;
452 std::shared_ptr<Polygon> polygon = std::make_shared<Polygon>(node);
453 if (polygon->setParams(new_params)) {
457 get_logger(),
"Failed to create a new polygon object using the provided params.");
458 response->success =
false;
464 for (
auto req_crcl : request->circles) {
465 nav2_msgs::msg::CircleObject::SharedPtr new_params =
466 std::make_shared<nav2_msgs::msg::CircleObject>(req_crcl);
468 auto it =
findShape(new_params->uuid.uuid.data());
472 if ((*it)->getType() != CIRCLE) {
475 "Shape (UUID: %s) is not a circle type for a circle update. Not adding shape.",
476 (*it)->getUUID().c_str());
477 response->success =
false;
482 std::shared_ptr<Circle> circle = std::static_pointer_cast<Circle>(*it);
485 nav2_msgs::msg::CircleObject::SharedPtr old_params = circle->getParams();
486 if (!circle->setParams(new_params)) {
489 "Failed to update existing circle object (UUID: %s) with new params. "
490 "Reverting to old circle params.",
491 (*it)->getUUID().c_str());
493 circle->setParams(old_params);
495 response->success =
false;
499 std::shared_ptr<Circle> circle = std::make_shared<Circle>(node);
500 if (circle->setParams(new_params)) {
504 get_logger(),
"Failed to create a new circle object using the provided params.");
505 response->success =
false;
514 const std::shared_ptr<rmw_request_id_t>,
515 const std::shared_ptr<nav2_msgs::srv::GetShapes::Request>,
516 std::shared_ptr<nav2_msgs::srv::GetShapes::Response> response)
518 std::shared_ptr<Polygon> polygon;
519 std::shared_ptr<Circle> circle;
522 switch (shape->getType()) {
524 polygon = std::static_pointer_cast<Polygon>(shape);
525 response->polygons.push_back(*(polygon->getParams()));
528 circle = std::static_pointer_cast<Circle>(shape);
529 response->circles.push_back(*(circle->getParams()));
532 RCLCPP_WARN(get_logger(),
"Unknown shape type (UUID: %s)", shape->getUUID().c_str());
538 const std::shared_ptr<rmw_request_id_t>,
539 const std::shared_ptr<nav2_msgs::srv::RemoveShapes::Request> request,
540 std::shared_ptr<nav2_msgs::srv::RemoveShapes::Response> response)
544 response->success =
true;
546 if (request->all_objects) {
551 for (
auto req_uuid : request->uuids) {
552 auto it =
findShape(req_uuid.uuid.data());
561 "Can not find shape to remove with UUID: %s",
562 unparseUUID(req_uuid.uuid.data()).c_str());
563 response->success =
false;
573 #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.