Skip to content

Commit ab1a209

Browse files
committed
Merge pull request #71 from logivations/backport_velocity_polygon
Backport velocity polygons
1 parent d8b26e1 commit ab1a209

18 files changed

+1301
-11
lines changed

nav2_collision_monitor/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ set(detector_library_name ${detector_executable_name}_core)
4949
add_library(${monitor_library_name} SHARED
5050
src/collision_monitor_node.cpp
5151
src/polygon.cpp
52+
src/velocity_polygon.cpp
5253
src/circle.cpp
5354
src/source.cpp
5455
src/scan.cpp
@@ -60,6 +61,7 @@ add_library(${monitor_library_name} SHARED
6061
add_library(${detector_library_name} SHARED
6162
src/collision_detector_node.cpp
6263
src/polygon.cpp
64+
src/velocity_polygon.cpp
6365
src/circle.cpp
6466
src/source.cpp
6567
src/scan.cpp

nav2_collision_monitor/README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ The zones around the robot can take the following shapes:
3636
* Arbitrary user-defined polygon relative to the robot base frame, which can be static in a configuration file or dynamically changing via a topic interface.
3737
* Robot footprint polygon, which is used in the approach behavior model only. Will use the static user-defined polygon or the footprint topic to allow it to be dynamically adjusted over time.
3838
* Circle: is made for the best performance and could be used in the cases where the zone or robot footprint could be approximated by round shape.
39+
* VelocityPolygon: allow switching of polygons based on the command velocity. When the velocity is covered by multiple sub polygons, the first sub polygon in the `velocity_polygons` list will be used. This is useful for robots to set different safety zones based on their velocity (e.g. a robot that has a larger safety zone when moving at 1.0 m/s than when moving at 0.5 m/s).
40+
3941

4042
The data may be obtained from different data sources:
4143

@@ -48,8 +50,12 @@ The data may be obtained from different data sources:
4850
The Collision Monitor is designed to operate below Nav2 as an independent safety node.
4951
This acts as a filter on the `cmd_vel` topic coming out of the Controller Server. If no such zone is triggered, then the Controller's `cmd_vel` is used. Else, it is scaled or set to stop as appropriate.
5052

51-
The following diagram is showing the high-level design of Collision Monitor module. All shapes (Polygons and Circles) are derived from base `Polygon` class, so without loss of generality we can call them as polygons. Subscribed footprint is also having the same properties as other polygons, but it is being obtained a footprint topic for the Approach Model.
53+
The following diagram is showing the high-level design of Collision Monitor module. All shapes (`Polygon`, `Circle` and `VelocityPolygon`) are derived from base `Polygon` class, so without loss of generality we can call them as polygons. Subscribed footprint is also having the same properties as other polygons, but it is being obtained a footprint topic for the Approach Model.
5254
![HLD.png](doc/HLD.png)
55+
56+
`VelocityPolygon` can be configured with multiple sub polygons and can switch between them based on the velocity.
57+
58+
5359
### Configuration
5460

5561
Detailed configuration parameters, their description and how to setup a Collision Monitor could be found at its [Configuration Guide](https://navigation.ros.org/configuration/packages/configuring-collision-monitor.html) and [Using Collision Monitor tutorial](https://navigation.ros.org/tutorials/docs/using_collision_monitor.html) pages.

nav2_collision_monitor/include/nav2_collision_monitor/collision_detector_node.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "nav2_collision_monitor/types.hpp"
3434
#include "nav2_collision_monitor/polygon.hpp"
3535
#include "nav2_collision_monitor/circle.hpp"
36+
#include "nav2_collision_monitor/velocity_polygon.hpp"
3637
#include "nav2_collision_monitor/source.hpp"
3738
#include "nav2_collision_monitor/scan.hpp"
3839
#include "nav2_collision_monitor/pointcloud.hpp"

nav2_collision_monitor/include/nav2_collision_monitor/collision_monitor_node.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "nav2_collision_monitor/types.hpp"
3434
#include "nav2_collision_monitor/polygon.hpp"
3535
#include "nav2_collision_monitor/circle.hpp"
36+
#include "nav2_collision_monitor/velocity_polygon.hpp"
3637
#include "nav2_collision_monitor/source.hpp"
3738
#include "nav2_collision_monitor/scan.hpp"
3839
#include "nav2_collision_monitor/pointcloud.hpp"

nav2_collision_monitor/include/nav2_collision_monitor/polygon.hpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class Polygon
142142
/**
143143
* @brief Updates polygon from footprint subscriber (if any)
144144
*/
145-
void updatePolygon();
145+
virtual void updatePolygon(const Velocity & /*cmd_vel_in*/);
146146

147147
/**
148148
* @brief Gets number of points inside given polygon
@@ -217,6 +217,15 @@ class Polygon
217217
*/
218218
bool isPointInside(const Point & point) const;
219219

220+
/**
221+
* @brief Extracts Polygon points from a string with of the form [[x1,y1],[x2,y2],[x3,y3]...]
222+
* @param poly_string Input String containing the verteceis of the polygon
223+
* @param polygon Output Point vector with all the vertecies of the polygon
224+
* @return True if all parameters were obtained or false in failure case
225+
*/
226+
bool getPolygonFromString(std::string & poly_string, std::vector<Point> & polygon);
227+
228+
220229
// ----- Variables -----
221230

222231
/// @brief Collision Monitor node
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright (c) 2023 Dexory
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef NAV2_COLLISION_MONITOR__VELOCITY_POLYGON_HPP_
16+
#define NAV2_COLLISION_MONITOR__VELOCITY_POLYGON_HPP_
17+
18+
#include <memory>
19+
#include <string>
20+
#include <vector>
21+
22+
#include "geometry_msgs/msg/polygon_stamped.hpp"
23+
#include "nav2_collision_monitor/polygon.hpp"
24+
#include "nav2_collision_monitor/types.hpp"
25+
#include "nav2_util/lifecycle_node.hpp"
26+
#include "rclcpp/rclcpp.hpp"
27+
#include "tf2_ros/buffer.h"
28+
29+
namespace nav2_collision_monitor
30+
{
31+
32+
/**
33+
* @brief Velocity polygon class.
34+
* This class contains all the points of the polygon and
35+
* the expected condition of the velocity based polygon.
36+
*/
37+
class VelocityPolygon : public Polygon
38+
{
39+
public:
40+
/**
41+
* @brief VelocityPolygon constructor
42+
* @param node Collision Monitor node pointer
43+
* @param polygon_name Name of main polygon
44+
*/
45+
VelocityPolygon(
46+
const nav2_util::LifecycleNode::WeakPtr & node, const std::string & polygon_name,
47+
const std::shared_ptr<tf2_ros::Buffer> tf_buffer, const std::string & base_frame_id,
48+
const tf2::Duration & transform_tolerance);
49+
/**
50+
* @brief VelocityPolygon destructor
51+
*/
52+
virtual ~VelocityPolygon();
53+
54+
/**
55+
* @brief Overriden getParameters function for VelocityPolygon parameters
56+
* @param polygon_sub_topic Not used in VelocityPolygon
57+
* @param polygon_pub_topic Output name of polygon publishing topic
58+
* @param footprint_topic Not used in VelocityPolygon
59+
* @return True if all parameters were obtained or false in failure case
60+
*/
61+
bool getParameters(
62+
std::string & /*polygon_sub_topic*/, std::string & polygon_pub_topic,
63+
std::string & /*footprint_topic*/) override;
64+
65+
/**
66+
* @brief Overriden updatePolygon function for VelocityPolygon
67+
* @param cmd_vel_in Robot twist command input
68+
*/
69+
void updatePolygon(const Velocity & cmd_vel_in) override;
70+
71+
protected:
72+
/**
73+
* @brief Custom struc to store the parameters of the sub-polygon
74+
* @param poly_ The points of the sub-polygon
75+
* @param velocity_polygon_name_ The name of the sub-polygon
76+
* @param linear_min_ The minimum linear velocity
77+
* @param linear_max_ The maximum linear velocity
78+
* @param theta_min_ The minimum angular velocity
79+
* @param theta_max_ The maximum angular velocity
80+
* @param direction_end_angle_ The end angle of the direction(For holonomic robot only)
81+
* @param direction_start_angle_ The start angle of the direction(For holonomic robot only)
82+
*/
83+
struct SubPolygonParameter
84+
{
85+
std::vector<Point> poly_;
86+
std::string velocity_polygon_name_;
87+
double linear_min_;
88+
double linear_max_;
89+
double theta_min_;
90+
double theta_max_;
91+
double direction_end_angle_;
92+
double direction_start_angle_;
93+
};
94+
95+
/**
96+
* @brief Check if the velocities and direction is in expected range.
97+
* @param cmd_vel_in Robot twist command input
98+
* @param sub_polygon_param Sub polygon parameters
99+
* @return True if speed and direction is within the condition
100+
*/
101+
bool isInRange(const Velocity & cmd_vel_in, const SubPolygonParameter & sub_polygon_param);
102+
103+
// Clock
104+
rclcpp::Clock::SharedPtr clock_;
105+
106+
// Variables
107+
/// @brief Flag to indicate if the robot is holonomic
108+
bool holonomic_;
109+
/// @brief Vector to store the parameters of the sub-polygon
110+
std::vector<SubPolygonParameter> sub_polygons_;
111+
}; // class VelocityPolygon
112+
113+
} // namespace nav2_collision_monitor
114+
115+
#endif // NAV2_COLLISION_MONITOR__VELOCITY_POLYGON_HPP_

nav2_collision_monitor/params/collision_monitor_params.yaml

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ collision_monitor:
1111
stop_pub_timeout: 2.0
1212
# Polygons represent zone around the robot for "stop", "slowdown" and "limit" action types,
1313
# and robot footprint for "approach" action type.
14-
# Footprint could be "polygon" type with dynamically set footprint from footprint_topic
15-
# or "circle" type with static footprint set by radius. "footprint_topic" parameter
14+
# (1) Footprint could be "polygon" type with dynamically set footprint from footprint_topic
15+
# (2) "circle" type with static footprint set by radius. "footprint_topic" parameter
1616
# to be ignored in circular case.
17+
# (3) "velocity_polygon" type with dynamically set polygon from velocity_polygons
1718
polygons: ["PolygonStop"]
1819
PolygonStop:
1920
type: "polygon"
@@ -51,6 +52,42 @@ collision_monitor:
5152
min_points: 6
5253
visualize: False
5354
enabled: True
55+
VelocityPolygonStop:
56+
type: "velocity_polygon"
57+
action_type: "stop"
58+
min_points: 6
59+
visualize: True
60+
enabled: True
61+
polygon_pub_topic: "velocity_polygon_stop"
62+
velocity_polygons: ["rotation", "translation_forward", "translation_backward", "stopped"]
63+
holonomic: false
64+
rotation:
65+
points: "[[0.3, 0.3], [0.3, -0.3], [-0.3, -0.3], [-0.3, 0.3]]"
66+
linear_min: 0.0
67+
linear_max: 0.05
68+
theta_min: -1.0
69+
theta_max: 1.0
70+
translation_forward:
71+
points: "[[0.35, 0.3], [0.35, -0.3], [-0.2, -0.3], [-0.2, 0.3]]"
72+
linear_min: 0.0
73+
linear_max: 1.0
74+
theta_min: -1.0
75+
theta_max: 1.0
76+
translation_backward:
77+
points: "[[0.2, 0.3], [0.2, -0.3], [-0.35, -0.3], [-0.35, 0.3]]"
78+
linear_min: -1.0
79+
linear_max: 0.0
80+
theta_min: -1.0
81+
theta_max: 1.0
82+
# This is the last polygon to be checked, it should cover the entire range of robot's velocities
83+
# It is used as the stopped polygon when the robot is not moving and as a fallback if the velocity
84+
# is not covered by any of the other sub-polygons
85+
stopped:
86+
points: "[[0.25, 0.25], [0.25, -0.25], [-0.25, -0.25], [-0.25, 0.25]]"
87+
linear_min: -1.0
88+
linear_max: 1.0
89+
theta_min: -1.0
90+
theta_max: 1.0
5491
observation_sources: ["scan"]
5592
scan:
5693
type: "scan"

nav2_collision_monitor/src/collision_detector_node.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ bool CollisionDetector::configurePolygons(
207207
polygons_.push_back(
208208
std::make_shared<Circle>(
209209
node, polygon_name, tf_buffer_, base_frame_id, transform_tolerance));
210+
} else if (polygon_type == "velocity_polygon") {
211+
polygons_.push_back(
212+
std::make_shared<VelocityPolygon>(
213+
node, polygon_name, tf_buffer_, base_frame_id, transform_tolerance));
210214
} else { // Error if something else
211215
RCLCPP_ERROR(
212216
get_logger(),

nav2_collision_monitor/src/collision_monitor_node.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@ bool CollisionMonitor::configurePolygons(
298298
polygons_.push_back(
299299
std::make_shared<Circle>(
300300
node, polygon_name, tf_buffer_, base_frame_id, transform_tolerance));
301+
} else if (polygon_type == "velocity_polygon") {
302+
polygons_.push_back(
303+
std::make_shared<VelocityPolygon>(
304+
node, polygon_name, tf_buffer_, base_frame_id, transform_tolerance));
301305
} else { // Error if something else
302306
RCLCPP_ERROR(
303307
get_logger(),
@@ -458,7 +462,7 @@ void CollisionMonitor::process(const Velocity & cmd_vel_in)
458462
}
459463

460464
// Update polygon coordinates
461-
polygon->updatePolygon();
465+
polygon->updatePolygon(cmd_vel_in);
462466

463467
const ActionType at = polygon->getActionType();
464468
if (at == STOP || at == SLOWDOWN || at == LIMIT) {

nav2_collision_monitor/src/polygon.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include "nav2_util/node_utils.hpp"
2525
#include "nav2_util/robot_utils.hpp"
26+
#include "nav2_util/array_parser.hpp"
2627

2728
#include "nav2_collision_monitor/kinematics.hpp"
2829
using rcl_interfaces::msg::ParameterType;
@@ -191,7 +192,7 @@ bool Polygon::isShapeSet()
191192
return true;
192193
}
193194

194-
void Polygon::updatePolygon()
195+
void Polygon::updatePolygon(const Velocity & /*cmd_vel_in*/)
195196
{
196197
if (footprint_sub_ != nullptr) {
197198
// Get latest robot footprint from footprint subscriber
@@ -580,4 +581,45 @@ inline bool Polygon::isPointInside(const Point & point) const
580581
return res;
581582
}
582583

584+
bool Polygon::getPolygonFromString(
585+
std::string & poly_string,
586+
std::vector<Point> & polygon)
587+
{
588+
std::string error;
589+
std::vector<std::vector<float>> vvf = nav2_util::parseVVF(poly_string, error);
590+
591+
if (error != "") {
592+
RCLCPP_ERROR(
593+
logger_, "Error parsing polygon parameter %s: '%s'",
594+
poly_string.c_str(), error.c_str());
595+
return false;
596+
}
597+
598+
// Check for minimum 4 points
599+
if (vvf.size() <= 3) {
600+
RCLCPP_ERROR(
601+
logger_,
602+
"Polygon must have at least three points.");
603+
return false;
604+
}
605+
for (unsigned int i = 0; i < vvf.size(); i++) {
606+
if (vvf[i].size() == 2) {
607+
Point point;
608+
point.x = vvf[i][0];
609+
point.y = vvf[i][1];
610+
polygon.push_back(point);
611+
} else {
612+
RCLCPP_ERROR(
613+
logger_,
614+
"Points in the polygon specification must be pairs of numbers"
615+
"Found a point with %d numbers.",
616+
static_cast<int>(vvf[i].size()));
617+
polygon.clear();
618+
return false;
619+
}
620+
}
621+
622+
return true;
623+
}
624+
583625
} // namespace nav2_collision_monitor

0 commit comments

Comments
 (0)