24 #include <core/exception.h> 25 #include <core/utils/lockptr.h> 26 #include <core/threading/mutex_locker.h> 27 #include <utils/system/fam.h> 28 #include <navgraph/navgraph.h> 29 #include <navgraph/yaml_navgraph.h> 31 #include <fawkes_msgs/NavGraph.h> 32 #include <fawkes_msgs/NavGraphGetPairwiseCosts.h> 33 #include <fawkes_msgs/NavGraphSearchPath.h> 35 #include <boost/filesystem.hpp> 39 #define GET_CONFIG(privn, n, path, var) \ 40 if (! privn.getParam(path, var)) { \ 41 n.getParam(path, var); \ 51 const std::string& target_frame,
70 GET_CONFIG(privn, n,
"navgraph_file", cfg_navgraph_file_);
71 GET_CONFIG(privn, n,
"base_frame_id", cfg_base_frame_);
72 GET_CONFIG(privn, n,
"global_frame_id", cfg_global_frame_);
74 boost::filesystem::path p(cfg_navgraph_file_);
75 p = boost::filesystem::absolute(p);
76 cfg_navgraph_file_ = p.string();
77 if (boost::filesystem::exists(p)) {
78 navgraph = fawkes::LockPtr<fawkes::NavGraph>(fawkes::load_yaml_navgraph(cfg_navgraph_file_),
80 ROS_INFO(
"[F-NavGraph] Loaded navgraph from '%s': %zu nodes, %zu edges",
81 cfg_navgraph_file_.c_str(), navgraph->nodes().size(), navgraph->edges().size());
83 navgraph = fawkes::LockPtr<fawkes::NavGraph>(
new fawkes::NavGraph(
"empty"),
true);
86 boost::filesystem::create_directories(p.parent_path());
87 fam_ =
new fawkes::FileAlterationMonitor();
88 fam_->add_filter((std::string(
"^") + p.filename().string() +
"$").c_str());
89 printf(
"Watching dir %s\n", p.parent_path().string().c_str());
90 fam_->watch_dir(p.parent_path().string().c_str());
93 fam_->add_listener(
this);
97 pub_navgraph_ = n.
advertise<fawkes_msgs::NavGraph>(
"navgraph", 10,
true);
124 if (mask & FAM_DELETE) {
125 ROS_INFO(
"[F-NavGraph] Navgraph file deleted, clearing");
131 if (mask & (FAM_MODIFY | FAM_IGNORED)) {
132 ROS_INFO(
"[F-NavGraph] NavGraph changed on disk, reloading");
135 fawkes::LockPtr<fawkes::NavGraph> new_graph =
136 fawkes::LockPtr<fawkes::NavGraph>(fawkes::load_yaml_navgraph(cfg_navgraph_file_),
138 ROS_INFO(
"[F-NavGraph] Re-loaded navgraph from '%s': %zu nodes, %zu edges",
139 cfg_navgraph_file_.c_str(), new_graph->nodes().size(), new_graph->edges().size());
140 **navgraph = **new_graph;
142 }
catch (fawkes::Exception &e) {
143 ROS_WARN(
"[F-NavGraph] Loading new graph failed: %s", e.what());
145 }
catch (std::runtime_error &e) {
146 ROS_WARN(
"[F-NavGraph] Loading new graph failed: %s", e.what());
155 fam_->process_events();
160 std::vector<fawkes_msgs::NavGraphNode> &out)
162 for (
const fawkes::NavGraphNode &node : nodes) {
163 fawkes_msgs::NavGraphNode ngn;
164 ngn.name = node.name();
165 ngn.has_orientation = node.has_property(fawkes::navgraph::PROP_ORIENTATION);
166 ngn.pose.x = node.x();
167 ngn.pose.y = node.y();
168 if (ngn.has_orientation) {
169 ngn.pose.theta = node.property_as_float(fawkes::navgraph::PROP_ORIENTATION);
171 ngn.unconnected = node.unconnected();
172 const std::map<std::string, std::string> &props = node.properties();
173 for (
const auto p : props) {
174 fawkes_msgs::NavGraphProperty ngp;
176 ngp.value = p.second;
177 ngn.properties.push_back(ngp);
186 fawkes::MutexLocker lock(navgraph.objmutex_ptr());
188 fawkes_msgs::NavGraph ngm;
190 const std::vector<fawkes::NavGraphNode> &nodes = navgraph->nodes();
191 convert_nodes(nodes, ngm.nodes);
193 const std::vector<fawkes::NavGraphEdge> &edges = navgraph->edges();
194 for (
const fawkes::NavGraphEdge &edge : edges) {
195 fawkes_msgs::NavGraphEdge nge;
196 nge.from_node = edge.from();
197 nge.to_node = edge.to();
198 nge.directed = edge.is_directed();
199 const std::map<std::string, std::string> &props = edge.properties();
200 for (
const auto p : props) {
201 fawkes_msgs::NavGraphProperty ngp;
203 ngp.value = p.second;
204 nge.properties.push_back(ngp);
206 ngm.edges.push_back(nge);
209 pub_navgraph_.publish(ngm);
215 fawkes_msgs::NavGraphSearchPath::Response &res)
217 fawkes::NavGraphNode from, to;
220 if (req.from_node.empty()) {
222 if (! tf_listener->transform_origin(cfg_base_frame_, cfg_global_frame_, pose)) {
223 ROS_WARN(
"[F-NavGraph] Failed to compute pose, cannot generate plan");
226 res.errmsg =
"Failed to compute pose, cannot generate plan";
231 navgraph->closest_node(pose.getOrigin().x(), pose.getOrigin().y());
232 if (! from.is_valid()) {
234 res.errmsg =
"Failed to get closest node to pose";
238 fawkes_msgs::NavGraphNode free_start;
239 free_start.name =
"free-start";
240 free_start.pose.x = pose.getOrigin().x();
241 free_start.pose.y = pose.getOrigin().y();
242 free_start.has_orientation =
true;
243 free_start.pose.theta =
tf::getYaw(pose.getRotation());
244 res.path.push_back(free_start);
246 from = navgraph->node(req.from_node);
247 if (! from.is_valid()) {
249 res.errmsg =
"Failed to find start node " + req.from_node;
254 fawkes::NavGraphPath path;
256 if (! req.to_node.empty()) {
257 path = navgraph->search_path(from.name(), req.to_node);
259 fawkes::NavGraphNode close_to_goal = navgraph->closest_node(req.to_pose.x, req.to_pose.y);
260 path = navgraph->search_path(from, close_to_goal);
261 if (! path.empty()) {
262 fawkes::NavGraphNode free_target(
"free-target", req.to_pose.x, req.to_pose.y);
263 if (std::isfinite(req.to_pose.theta)) {
264 free_target.set_property(
"orientation", (
float)req.to_pose.theta);
266 path.add_node(free_target, navgraph->cost(path.nodes().back(), free_target));
271 convert_nodes(path.nodes(), res.path);
272 res.cost = path.cost();
280 fawkes_msgs::NavGraphGetPairwiseCosts::Response &res)
282 for (
unsigned int i = 0; i < req.nodes.size(); ++i) {
283 for (
unsigned int j = 0; j < req.nodes.size(); ++j) {
284 if (i == j)
continue;
286 fawkes::NavGraphNode from_node, to_node;
288 from_node = navgraph->node(req.nodes[i]);
289 to_node = navgraph->node(req.nodes[j]);
290 }
catch (fawkes::Exception &e) {
292 res.errmsg =
"Failed to get path from '" + req.nodes[i] +
"' to '" +
293 req.nodes[j] +
"': " + e.what_no_backtrace();
294 res.path_costs.clear();
298 fawkes::NavGraphNode start_node, goal_node;
300 if (from_node.unconnected()) {
301 start_node = navgraph->closest_node_to(from_node.name());
305 start_node = from_node;
307 if (to_node.unconnected()) {
308 goal_node = navgraph->closest_node_to(to_node.name());
314 fawkes::NavGraphPath p = navgraph->search_path(start_node, goal_node);
317 res.errmsg =
"Failed to get path from '" + start_node.name() +
"' to '" + goal_node.name() +
"'";
318 res.path_costs.clear();
321 fawkes_msgs::NavGraphPathCost pc;
322 pc.from_node = req.nodes[i];
323 pc.to_node = req.nodes[j];
325 if (from_node.unconnected()) {
326 pc.cost += navgraph->cost(from_node, start_node);
328 if (to_node.unconnected()) {
329 pc.cost += navgraph->cost(goal_node, to_node);
331 res.path_costs.push_back(pc);
348 fawkes::FileAlterationMonitor *
fam_;
std::string cfg_global_frame_
#define GET_CONFIG(privn, n, path, var)
ros::ServiceServer svs_search_path_
std::string cfg_base_frame_
static double getYaw(const Quaternion &bt_q)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
virtual void fam_event(const char *filename, unsigned int mask)
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
void cb_fam_timer(const ros::WallTimerEvent &event)
bool svs_get_pwcosts_cb(fawkes_msgs::NavGraphGetPairwiseCosts::Request &req, fawkes_msgs::NavGraphGetPairwiseCosts::Response &res)
std::string cfg_navgraph_file_
ROSCPP_DECL void spin(Spinner &spinner)
ros::ServiceServer svs_get_pwcosts_
ros::WallTimer fam_timer_
fawkes::FileAlterationMonitor * fam_
WallTimer createWallTimer(WallDuration period, void(T::*callback)(const WallTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
fawkes::LockPtr< fawkes::NavGraph > navgraph
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::Publisher pub_navgraph_
TransformListenerExtended * tf_listener
virtual ~NavGraphRosNode()
NavGraphRosNode(ros::NodeHandle &n)
int main(int argc, char **argv)
void convert_nodes(const std::vector< fawkes::NavGraphNode > &nodes, std::vector< fawkes_msgs::NavGraphNode > &out)
bool svs_search_path_cb(fawkes_msgs::NavGraphSearchPath::Request &req, fawkes_msgs::NavGraphSearchPath::Response &res)