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){
92 if ( !singleRobotName_.size() == 0 ) {
106 std::map<std::string, double>::iterator it =
finished_robots_.find ( robot->robot_name );
107 if ( robot->status == tuw_multi_robot_msgs::RobotInfo::STATUS_DRIVING ) {
111 ROS_INFO (
"%10s started!", robot->robot_name.c_str() );
120 ROS_INFO (
"%10s stopped @ %6.2lf sec, %3i robots left", robot->robot_name.c_str(), duration, nr_of_driving_robots );
128 ROS_INFO (
"Execution finished after %lf sec!", duration.
toSec() );
129 std::stringstream ss;
131 ss << it->second <<
", ";
133 ROS_INFO (
"Duration by robot: \n [%s]", ss.str().c_str() );
143 tuw_multi_robot_msgs::RobotGoals goal;
145 goal.destinations.push_back ( _goal.pose );
147 tuw_multi_robot_msgs::RobotGoalsArray goals;
148 goals.robots.push_back ( goal );
156 ( *it )->updateOnlineStatus ( _secs );
161 uint32_t threads = config.nr_threads;
162 if ( config.router_type == 1 )
167 if ( config.collision_resolver == 0 ){
170 }
else if ( config.collision_resolver == 1 ) {
178 if ( config.voronoi_graph )
183 if ( config.goal_mode == 0 )
185 else if ( config.goal_mode == 1 )
200 std::vector<signed char> map = _map.data;
202 Eigen::Vector2d origin;
203 origin[0] = _map.info.origin.position.x;
204 origin[1] = _map.info.origin.position.y;
206 size_t new_hash =
getHash ( map, origin, _map.info.resolution );
208 ROS_INFO (
"map %f %f %f", origin[0], origin[1], _map.info.resolution );
215 cv::Mat m ( _map.info.height, _map.info.width, CV_8SC1, map.data() );
217 m.convertTo ( m, CV_8UC1 );
218 cv::bitwise_not ( m, m );
220 cv::threshold ( m, m, 40, 255, CV_THRESH_BINARY | CV_THRESH_OTSU );
221 cv::distanceTransform ( m,
distMap_, CV_DIST_L1, 3 );
232 tuw_multi_robot_msgs::RobotInfo ri;
233 if ( shape == ri.SHAPE_CIRCLE ) {
234 return shape_variables[0];
245 RobotInfoPtr robot_new = std::make_shared<RobotInfo> ( _robotInfo );
246 robot_new->initTopics (
n_ );
249 ( *robot )->updateInfo ( _robotInfo );
260 std::vector<Segment> graph;
262 for (
const tuw_multi_robot_msgs::Vertex &segment : msg.vertices ) {
263 std::vector<Eigen::Vector2d> points;
265 for (
const geometry_msgs::Point &point : segment.path ) {
266 points.emplace_back ( point.x, point.y );
269 std::vector<uint32_t> successors;
271 for (
const auto &succ : segment.successors ) {
272 successors.emplace_back ( succ );
275 std::vector<uint32_t> predecessors;
277 for (
const auto &pred : segment.predecessors ) {
278 predecessors.emplace_back ( pred );
281 if ( segment.valid ) {
284 graph.emplace_back ( segment.id, points, successors, predecessors, 0 );
290 size_t hash =
getHash ( graph );
300 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 ) {
307 for (
int k = 0; k < goal_msg.robots.size(); k++ ) {
308 const tuw_multi_robot_msgs::RobotGoals &route_request = goal_msg.robots[k];
311 ROS_INFO (
"No robot subsribed with the name: %s", route_request.robot_name.c_str() );
313 if ( route_request.destinations.empty() ) {
314 ROS_INFO (
"No robot: %s has not goal defined", route_request.robot_name.c_str() );
320 _radius.push_back ( ( *active_robot )->radius() );
321 if ( route_request.destinations.size() > 1 ) {
322 geometry_msgs::Pose p = route_request.destinations[0];
323 _starts.push_back ( Eigen::Vector3d ( p.position.x, p.position.y,
getYaw ( p.orientation ) ) );
325 _starts.push_back ( ( *active_robot )->getPose() );
328 geometry_msgs::Pose p = route_request.destinations.back();
329 _goals.push_back ( Eigen::Vector3d ( p.position.x, p.position.y,
getYaw ( p.orientation ) ) );
343 std::vector<Eigen::Vector3d> starts;
344 std::vector<Eigen::Vector3d> goals;
345 std::vector<float> radius;
346 std::vector<std::string> robot_names;
350 bool preparationSuccessful =
preparePlanning ( radius, starts, goals, _goals, robot_names );
355 auto t1 = std::chrono::high_resolution_clock::now();
357 auto t2 = std::chrono::high_resolution_clock::now();
358 int duration = std::chrono::duration_cast<std::chrono::milliseconds> ( t2 - t1 ).count();
360 if ( preparationSuccessful ) {
378 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]",
381 rate_success, avr_duration_total, avr_duration_successful);
394 double roll, pitch, yaw;
406 nav_msgs::Path msg_path;
407 tuw_multi_robot_msgs::Route msg_route;
408 msg_path.header.seq = 0;
410 msg_path.header.frame_id =
"map";
411 msg_route.header = msg_path.header;
414 robot->pubPaths_.publish ( msg_path );
415 robot->pubRoute_.publish ( msg_route );
429 nav_msgs::Path msg_path;
430 tuw_multi_robot_msgs::Route msg_route;
431 msg_path.header.seq = 0;
433 msg_path.header.frame_id =
"map";
434 msg_route.header = msg_path.header;
438 const std::vector<Checkpoint> &route =
getRoute ( i );
439 msg_path.poses.clear();
442 geometry_msgs::PoseStamped pose_1;
443 pose_1.header.seq = 0;
445 pose_1.header.frame_id =
"map";
447 Eigen::Vector2d pos ( route[0].start[0] *
mapResolution_, route[0].start[1] * mapResolution_ );
448 pose_1.pose.position.x = pos[0] +
mapOrigin_[0];
449 pose_1.pose.position.y = pos[1] + mapOrigin_[1];
451 pose_1.pose.orientation.w = 1;
452 msg_path.poses.push_back ( pose_1 );
456 geometry_msgs::PoseStamped pose;
459 pose.header.frame_id =
"map";
461 Eigen::Vector2d pos ( c.end[0] * mapResolution_, c.end[1] * mapResolution_ );
462 pose.pose.position.x = pos[0] + mapOrigin_[0];
463 pose.pose.position.y = pos[1] + mapOrigin_[1];
468 pose.pose.orientation.w = q.w();
469 pose.pose.orientation.x = q.x();
470 pose.pose.orientation.y = q.y();
471 pose.pose.orientation.z = q.z();
472 msg_path.poses.push_back ( pose );
475 robot->pubPaths_.publish ( msg_path );
478 msg_route.segments.clear();
481 tuw_multi_robot_msgs::RouteSegment seg;
483 Eigen::Vector2d posStart ( cp.start[0] * mapResolution_, cp.start[1] * mapResolution_ );
485 qStart.
setEuler ( 0, 0, cp.start[2] );
487 seg.start.position.x = posStart[0] + mapOrigin_[0];
488 seg.start.position.y = posStart[1] + mapOrigin_[1];
489 seg.start.orientation.w = qStart.w();
490 seg.start.orientation.x = qStart.x();
491 seg.start.orientation.y = qStart.y();
492 seg.start.orientation.z = qStart.z();
494 Eigen::Vector2d posEnd ( cp.end[0] * mapResolution_, cp.end[1] * mapResolution_ );
498 seg.end.position.x = posEnd[0] + mapOrigin_[0];
499 seg.end.position.y = posEnd[1] + mapOrigin_[1];
500 seg.end.orientation.w = qEnd.w();
501 seg.end.orientation.x = qEnd.x();
502 seg.end.orientation.y = qEnd.y();
503 seg.end.orientation.z = qEnd.z();
505 seg.segment_id = cp.segId;
508 for (
int j = 0; j < cp.preconditions.size(); j++ ) {
509 tuw_multi_robot_msgs::RoutePrecondition pc;
510 pc.robot_id =
active_robots_[cp.preconditions[j].robotId]->robot_name;
511 pc.current_route_segment = cp.preconditions[j].stepCondition;
512 seg.preconditions.push_back ( pc );
515 msg_route.segments.push_back ( seg );
518 robot->pubRoute_.publish ( msg_route );
521 tuw_multi_robot_msgs::RouterStatus ps;
533 size_t Router_Node::getHash (
const std::vector<signed char> &_map,
const Eigen::Vector2d &_origin,
const float &_resolution ) {
534 std::size_t seed = 0;
536 boost::hash_combine ( seed, _origin[0] );
537 boost::hash_combine ( seed, _origin[1] );
538 boost::hash_combine ( seed, _resolution );
540 for (
const signed char &val : _map ) {
541 boost::hash_combine ( seed, val );
548 std::size_t seed = 0;
550 for (
const Segment &seg : _graph ) {
551 boost::hash_combine ( seed, seg.width() );
552 boost::hash_combine ( seed, seg.length() );
553 boost::hash_combine ( seed, seg.getSegmentId() );
555 for (
const int &p : seg.getPredecessors() ) {
556 boost::hash_combine ( seed, p );
559 for (
const int &
s : seg.getSuccessors() ) {
560 boost::hash_combine ( seed,
s );
563 for (
const Eigen::Vector2d &vec : seg.getPoints() ) {
564 boost::hash_combine ( seed, vec[0] );
565 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
float getOverallPathLength() const
getter
void parametersCallback(tuw_multi_robot_router::routerConfig &config, uint32_t level)
size_t current_graph_hash_
int main(int argc, char **argv)
void publish(const boost::shared_ptr< M > &message) 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())
std::string singleRobotName_
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::string singleRobotGoalTopic_
std::vector< std::shared_ptr< RobotInfo > >::iterator RobotInfoPtrIterator
ros::Subscriber subVoronoiGraph_
bool publish_routing_table_
double sum_processing_time_total_
std::string planner_status_topic_
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.
const std::vector< Checkpoint > & getRoute(const uint32_t _robot) const
returns the found Routing Table
float getLongestPathLength() const
getter
void robotInfoCallback(const tuw_multi_robot_msgs::RobotInfo &_robotInfo)
void getRPY(tfScalar &roll, tfScalar &pitch, tfScalar &yaw, unsigned int solution_number=1) const
Duration expectedCycleTime() const
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void graphCallback(const tuw_multi_robot_msgs::Graph &msg)
float calcRadius(const int shape, const std::vector< float > &shape_variables) const
void publishEmpty()
publishes an empty RoutingTable
const std::string & getNamespace() const
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)
uint32_t getPriorityScheduleAttemps() const
getter
std::string robot_info_topic_
void setEuler(const tfScalar &yaw, const tfScalar &pitch, const tfScalar &roll)
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)
std::string voronoi_topic_
bool priorityRescheduling_
std::vector< Segment > graph_
std::shared_ptr< RobotInfo > RobotInfoPtr
ros::Subscriber subRobotInfo_
uint32_t getSpeedScheduleAttemps() const
getter
void goalCallback(const geometry_msgs::PoseStamped &_goal)
ROSCPP_DECL void spinOnce()
ros::Subscriber subGoalSet_
double sum_processing_time_successful_
uint32_t getDuration_ms() const
getter
bool segmentOptimizations_
std::vector< RobotInfoPtr > active_robots_
robots avaliable
void updateTimeout(const float _secs)
used to update the nodes timeout to latch topics