28 #define POT_HIGH 1.0e10 32 #include <tuw_multi_robot_msgs/Route.h> 34 #include <boost/functional/hash.hpp> 35 #include <boost/regex.hpp> 40 int main (
int argc,
char **argv ) {
42 ros::init ( argc, argv,
"tuw_multi_robot_router" );
65 monitor_enabled_ ( false ),
67 attempts_successful_(0),
68 sum_processing_time_total_(.0),
69 sum_processing_time_successful_(.0){
81 if ( single_robot_mode_) {
101 std::map<std::string, double>::iterator it =
finished_robots_.find ( robot->robot_name );
102 if ( robot->status == tuw_multi_robot_msgs::RobotInfo::STATUS_DRIVING ) {
106 ROS_INFO (
"%10s started!", robot->robot_name.c_str() );
115 ROS_INFO (
"%10s stopped @ %6.2lf sec, %3i robots left", robot->robot_name.c_str(), duration, nr_of_driving_robots );
123 ROS_INFO (
"Execution finished after %lf sec!", duration.
toSec() );
124 std::stringstream ss;
126 ss << it->second <<
", ";
128 ROS_INFO (
"Duration by robot: \n [%s]", ss.str().c_str() );
140 ROS_WARN (
"No robot subsribed, ou have to publish a tuw_multi_robot_msgs::RobotInfo to let the planer know where your robot is located!");
141 ROS_WARN (
"Use a local behavior controller to publish regual a RobotInfo msg!");
144 tuw_multi_robot_msgs::RobotGoalsArray goalsArray;
145 goalsArray.header = msg.header;
146 goalsArray.robots.resize(1);
147 tuw_multi_robot_msgs::RobotGoals &goals = goalsArray.robots[0];
149 goals.destinations.resize(1);
150 goals.destinations[0] = msg.pose;
157 ( *it )->updateOnlineStatus ( _secs );
162 uint32_t threads = config.nr_threads;
163 if ( config.router_type == 1 )
168 if ( config.collision_resolver == 0 ){
171 }
else if ( config.collision_resolver == 1 ) {
179 if ( config.voronoi_graph )
184 if ( config.goal_mode == 0 )
186 else if ( config.goal_mode == 1 )
201 std::vector<signed char> map = _map.data;
203 Eigen::Vector2d origin;
204 origin[0] = _map.info.origin.position.x;
205 origin[1] = _map.info.origin.position.y;
207 size_t new_hash =
getHash ( map, origin, _map.info.resolution );
209 ROS_INFO (
"map %f %f %f", origin[0], origin[1], _map.info.resolution );
216 cv::Mat m ( _map.info.height, _map.info.width, CV_8SC1, map.data() );
218 m.convertTo ( m, CV_8UC1 );
219 cv::bitwise_not ( m, m );
221 cv::threshold ( m, m, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU );
222 cv::distanceTransform ( m,
distMap_, CV_DIST_L1, 3 );
233 tuw_multi_robot_msgs::RobotInfo ri;
234 if ( shape == ri.SHAPE_CIRCLE ) {
235 return shape_variables[0];
246 RobotInfoPtr robot_new = std::make_shared<RobotInfo> ( _robotInfo );
250 ( *robot )->updateInfo ( _robotInfo );
259 ROS_WARN(
"More than one robot subsribed, but the MRRP is in single robot mode");
266 ROS_INFO(
"No map received. Waiting...");
270 std::vector<Segment> graph;
272 for (
const tuw_multi_robot_msgs::Vertex &segment : msg.vertices ) {
273 std::vector<Eigen::Vector2d> points;
275 for (
const geometry_msgs::Point &point : segment.path ) {
279 std::vector<uint32_t> successors;
281 for (
const auto &succ : segment.successors ) {
282 successors.emplace_back ( succ );
285 std::vector<uint32_t> predecessors;
287 for (
const auto &pred : segment.predecessors ) {
288 predecessors.emplace_back ( pred );
291 if ( segment.valid ) {
294 graph.emplace_back ( segment.id, points, successors, predecessors, 0 );
300 size_t hash =
getHash ( graph );
310 bool Router_Node::preparePlanning ( std::vector<float> &_radius, std::vector<Eigen::Vector3d> &_starts, std::vector<Eigen::Vector3d> &_goals,
const tuw_multi_robot_msgs::RobotGoalsArray &goal_msg, std::vector<std::string> &robot_names ) {
317 for (
int k = 0; k < goal_msg.robots.size(); k++ ) {
318 const tuw_multi_robot_msgs::RobotGoals &route_request = goal_msg.robots[k];
321 ROS_INFO (
"No robot subsribed with the name: %s", route_request.robot_name.c_str() );
323 if ( route_request.destinations.empty() ) {
324 ROS_INFO (
"No robot: %s has not goal defined", route_request.robot_name.c_str() );
330 _radius.push_back ( ( *active_robot )->radius() );
331 if ( route_request.destinations.size() > 1 ) {
332 geometry_msgs::Pose p = route_request.destinations[0];
333 _starts.push_back ( Eigen::Vector3d ( p.position.x, p.position.y,
getYaw ( p.orientation ) ) );
335 _starts.push_back ( ( *active_robot )->getPose() );
338 geometry_msgs::Pose p = route_request.destinations.back();
339 _goals.push_back ( Eigen::Vector3d ( p.position.x, p.position.y,
getYaw ( p.orientation ) ) );
353 std::vector<Eigen::Vector3d> starts;
354 std::vector<Eigen::Vector3d> goals;
355 std::vector<float> radius;
356 std::vector<std::string> robot_names;
360 bool preparationSuccessful =
preparePlanning ( radius, starts, goals, _goals, robot_names );
365 auto t1 = std::chrono::high_resolution_clock::now();
367 auto t2 = std::chrono::high_resolution_clock::now();
368 int duration = std::chrono::duration_cast<std::chrono::milliseconds> ( t2 - t1 ).count();
370 if ( preparationSuccessful ) {
388 ROS_INFO (
"\nSuccess %i, %i = %4.3f, avr %4.0f ms, success: %4.0f ms, %s, %s, %s \n [%4.3f, %4.0f, %4.0f]",
391 rate_success, avr_duration_total, avr_duration_successful);
404 double roll, pitch, yaw;
416 nav_msgs::Path msg_path;
417 tuw_multi_robot_msgs::Route msg_route;
418 msg_path.header.seq = 0;
420 msg_path.header.frame_id =
"map";
421 msg_route.header = msg_path.header;
424 robot->pubPaths_.publish ( msg_path );
425 robot->pubRoute_.publish ( msg_route );
439 nav_msgs::Path msg_path;
440 tuw_multi_robot_msgs::Route msg_route;
441 msg_path.header.seq = 0;
443 msg_path.header.frame_id =
"map";
444 msg_route.header = msg_path.header;
448 const std::vector<Checkpoint> &route =
getRoute ( i );
449 msg_path.poses.clear();
452 geometry_msgs::PoseStamped pose_1;
453 pose_1.header.seq = 0;
455 pose_1.header.frame_id =
"map";
458 pose_1.pose.position.x = pos[0] +
mapOrigin_[0];
459 pose_1.pose.position.y = pos[1] + mapOrigin_[1];
461 pose_1.pose.orientation.w = 1;
462 msg_path.poses.push_back ( pose_1 );
466 geometry_msgs::PoseStamped pose;
469 pose.header.frame_id =
"map";
471 Eigen::Vector2d pos ( c.end[0] * mapResolution_, c.end[1] * mapResolution_ );
472 pose.pose.position.x = pos[0] + mapOrigin_[0];
473 pose.pose.position.y = pos[1] + mapOrigin_[1];
478 pose.pose.orientation.w = q.w();
479 pose.pose.orientation.x = q.x();
480 pose.pose.orientation.y = q.y();
481 pose.pose.orientation.z = q.z();
482 msg_path.poses.push_back ( pose );
485 robot->pubPaths_.publish ( msg_path );
488 msg_route.segments.clear();
491 tuw_multi_robot_msgs::RouteSegment seg;
493 Eigen::Vector2d posStart ( cp.start[0] * mapResolution_, cp.start[1] * mapResolution_ );
495 qStart.
setEuler ( 0, 0, cp.start[2] );
497 seg.start.position.x = posStart[0] + mapOrigin_[0];
498 seg.start.position.y = posStart[1] + mapOrigin_[1];
499 seg.start.orientation.w = qStart.w();
500 seg.start.orientation.x = qStart.x();
501 seg.start.orientation.y = qStart.y();
502 seg.start.orientation.z = qStart.z();
504 Eigen::Vector2d posEnd ( cp.end[0] * mapResolution_, cp.end[1] * mapResolution_ );
508 seg.end.position.x = posEnd[0] + mapOrigin_[0];
509 seg.end.position.y = posEnd[1] + mapOrigin_[1];
510 seg.end.orientation.w = qEnd.w();
511 seg.end.orientation.x = qEnd.x();
512 seg.end.orientation.y = qEnd.y();
513 seg.end.orientation.z = qEnd.z();
515 seg.segment_id = cp.segId;
518 for (
int j = 0; j < cp.preconditions.size(); j++ ) {
519 tuw_multi_robot_msgs::RoutePrecondition pc;
520 pc.robot_id =
active_robots_[cp.preconditions[j].robotId]->robot_name;
521 pc.current_route_segment = cp.preconditions[j].stepCondition;
522 seg.preconditions.push_back ( pc );
525 msg_route.segments.push_back ( seg );
528 robot->pubRoute_.publish ( msg_route );
531 tuw_multi_robot_msgs::RouterStatus ps;
543 size_t Router_Node::getHash (
const std::vector<signed char> &_map,
const Eigen::Vector2d &_origin,
const float &_resolution ) {
544 std::size_t seed = 0;
546 boost::hash_combine ( seed, _origin[0] );
547 boost::hash_combine ( seed, _origin[1] );
548 boost::hash_combine ( seed, _resolution );
550 for (
const signed char &val : _map ) {
551 boost::hash_combine ( seed, val );
558 std::size_t seed = 0;
560 for (
const Segment &seg : _graph ) {
561 boost::hash_combine ( seed, seg.width() );
562 boost::hash_combine ( seed, seg.length() );
563 boost::hash_combine ( seed, seg.getSegmentId() );
565 for (
const int &p : seg.getPredecessors() ) {
566 boost::hash_combine ( seed, p );
569 for (
const int &
s : seg.getSuccessors() ) {
570 boost::hash_combine ( seed,
s );
573 for (
const Eigen::Vector2d &vec : seg.getPoints() ) {
574 boost::hash_combine ( seed, vec[0] );
575 boost::hash_combine ( seed, vec[1] );
void goalsCallback(const tuw_multi_robot_msgs::RobotGoalsArray &_goals)
static std::vector< std::shared_ptr< RobotInfo > >::iterator findObj(std::vector< std::shared_ptr< RobotInfo > > &data, const std::string &name)
float getYaw(const geometry_msgs::Quaternion &_rot)
Eigen::Vector2d mapOrigin_
dynamic_reconfigure::Server< tuw_multi_robot_router::routerConfig > param_server
void parametersCallback(tuw_multi_robot_router::routerConfig &config, uint32_t level)
size_t current_graph_hash_
int main(int argc, char **argv)
float calcRadius(const int shape, const std::vector< float > &shape_variables) const
std::vector< RobotInfoPtr > subscribed_robots_
void monitorExecution()
monitors the execution
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ros::Publisher pubPlannerStatus_
void setPlannerType(routerType _type, uint32_t _nr_threads)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
Router_Node(ros::NodeHandle &n)
Construct a new Router_Node object.
std::vector< std::shared_ptr< RobotInfo > >::iterator RobotInfoPtrIterator
uint32_t getPriorityScheduleAttemps() const
getter
ros::Subscriber subVoronoiGraph_
bool publish_routing_table_
double sum_processing_time_total_
size_t getHash(const std::vector< signed char > &_map, const Eigen::Vector2d &_origin, const float &_resolution)
void mapCallback(const nav_msgs::OccupancyGrid &_map)
void publish()
publishes a RoutingTable
tuw_multi_robot_msgs::RouterStatus mrrp_status_
ros::Subscriber subSingleRobotGoal_
ros::NodeHandle n_
Node handler to the root node.
ros::NodeHandle n_param_
Node handler to the current node.
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
const std::vector< Checkpoint > & getRoute(const uint32_t _robot) const
returns the found Routing Table
void publish(const boost::shared_ptr< M > &message) const
void robotInfoCallback(const tuw_multi_robot_msgs::RobotInfo &_robotInfo)
void graphCallback(const tuw_multi_robot_msgs::Graph &msg)
void publishEmpty()
publishes an empty RoutingTable
std::map< std::string, double > finished_robots_
robots currently used by the planner
bool makePlan(const std::vector< Eigen::Vector3d > &_starts, const std::vector< Eigen::Vector3d > &_goals, const std::vector< float > &_radius, const cv::Mat &_map, const float &_resolution, const Eigen::Vector2d &_origin, const std::vector< Segment > &_graph, const std::vector< std::string > &_robot_names)
generates the plan from (Vertex[odom robotPose] to Vertex[_goals]
static bool sortSegments(const Segment &i, const Segment &j)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void setEuler(const tfScalar &yaw, const tfScalar &pitch, const tfScalar &roll)
const std::string & getNamespace() const
void setCollisionResolutionType(const SegmentExpander::CollisionResolverType _cr)
sets the CollisionResolverType used
ros::Time time_first_robot_started_
dynamic_reconfigure::Server< tuw_multi_robot_router::routerConfig >::CallbackType call_type
bool preparePlanning(std::vector< float > &_radius, std::vector< Eigen::Vector3d > &_starts, std::vector< Eigen::Vector3d > &_goals, const tuw_multi_robot_msgs::RobotGoalsArray &_ros_goals, std::vector< std::string > &robot_names)
void getRPY(tfScalar &roll, tfScalar &pitch, tfScalar &yaw, unsigned int solution_number=1) const
bool priorityRescheduling_
std::vector< Segment > graph_
std::shared_ptr< RobotInfo > RobotInfoPtr
ros::Subscriber subRobotInfo_
void goalCallback(const geometry_msgs::PoseStamped &_goal)
float getLongestPathLength() const
getter
float getOverallPathLength() const
getter
uint32_t getSpeedScheduleAttemps() const
getter
ROSCPP_DECL void spinOnce()
ros::Subscriber subGoalSet_
double sum_processing_time_successful_
bool segmentOptimizations_
Duration expectedCycleTime() const
std::vector< RobotInfoPtr > active_robots_
robots avaliable
void updateTimeout(const float _secs)
used to update the nodes timeout to latch topics
uint32_t getDuration_ms() const
getter