00001
00010 #include <iostream>
00011 #include <ros/ros.h>
00012 #include <sensor_msgs/LaserScan.h>
00013 #include <memory>
00014
00015 #include <nav_msgs/OccupancyGrid.h>
00016
00017
00018
00019 #include "../core/sensor_data.h"
00020 #include "../ros/topic_with_transform.h"
00021 #include "../ros/rviz_grid_viewer.h"
00022 #include "../ros/utils.h"
00023 #include "../core/maps/area_occupancy_estimator.h"
00024 #include "../core/maps/const_occupancy_estimator.h"
00025 #include "../core/maps/grid_cell_strategy.h"
00026 #include "tiny_fascade.h"
00027 #include "tiny_world.h"
00028 #include "tiny_grid_cells.h"
00029
00035 class PoseScanMatcherObserver : public GridScanMatcherObserver {
00036 public:
00037
00042 virtual void on_scan_test(const RobotState &pose,
00043 const TransformedLaserScan &scan,
00044 double score) override {
00045 publish_transform("sm_curr_pose", _frame_odom, pose);
00046 }
00051 virtual void on_pose_update(const RobotState &pose,
00052 const TransformedLaserScan &scan,
00053 double score) override {
00054 publish_transform("sm_best_pose", _frame_odom, pose);
00055 }
00056 private:
00057 void publish_transform(const std::string& frame_id, std::string frame_odom, const RobotState& p) {
00058 publish_2D_transform(frame_id, frame_odom, p.x, p.y, p.theta);
00059 }
00060
00061 std::string _frame_odom;
00062 };
00063
00069 std::shared_ptr<GridCellFactory> init_cell_factory(TinyWorldParams ¶ms) {
00070 std::string cell_type;
00071 ros::param::param<std::string>("~cell_type", cell_type, "avg");
00072
00073 if (cell_type == "base") {
00074 params.localized_scan_quality = 0.2;
00075 params.raw_scan_quality = 0.1;
00076 return std::shared_ptr<GridCellFactory>{new TinyBaseCellFactory()};
00077 } else if (cell_type == "avg") {
00078 params.localized_scan_quality = 0.9;
00079 params.raw_scan_quality = 0.6;
00080 return std::shared_ptr<GridCellFactory>{new TinyAvgCellFactory()};
00081 } else {
00082 std::cerr << "Unknown cell type: " << cell_type << std::endl;
00083 std::exit(-1);
00084 }
00085 }
00086
00092 std::shared_ptr<CellOccupancyEstimator> init_occ_estimator() {
00093 double occ_prob, empty_prob;
00094 ros::param::param<double>("~base_occupied_prob", occ_prob, 0.95);
00095 ros::param::param<double>("~base_empty_prob", empty_prob, 0.01);
00096
00097 using OccEstPtr = std::shared_ptr<CellOccupancyEstimator>;
00098 std::string est_type;
00099 ros::param::param<std::string>("~occupancy_estimator", est_type, "const");
00100
00101 if (est_type == "const") {
00102 return OccEstPtr{new ConstOccupancyEstimator(occ_prob, empty_prob)};
00103 } else if (est_type == "area") {
00104 return OccEstPtr{new AreaOccupancyEstimator(occ_prob, empty_prob)};
00105 } else {
00106 std::cerr << "Unknown estimator type: " << est_type << std::endl;
00107 std::exit(-1);
00108 }
00109 }
00110
00115 bool init_skip_exceeding_lsr() {
00116 bool param_value;
00117 ros::param::param<bool>("~skip_exceeding_lsr_vals", param_value, false);
00118 return param_value;
00119 }
00120
00125 TinyWorldParams init_common_world_params() {
00126 double sig_XY, sig_T, width;
00127 int lim_bad, lim_totl;
00128 ros::param::param<double>("~scmtch_sigma_XY_MonteCarlo", sig_XY, 0.2);
00129 ros::param::param<double>("~scmtch_sigma_theta_MonteCarlo", sig_T, 0.1);
00130 ros::param::param<int>("~scmtch_limit_of_bad_attempts", lim_bad, 20);
00131 ros::param::param<int>("~scmtch_limit_of_total_attempts", lim_totl, 100);
00132 ros::param::param<double>("~hole_width", width,1.5);
00133
00134 return TinyWorldParams(sig_XY, sig_T, lim_bad, lim_totl, width);
00135 }
00136
00141 GridMapParams init_grid_map_params() {
00142 GridMapParams params;
00143 ros::param::param<double>("~map_height_in_meters", params.height, 20);
00144 ros::param::param<double>("~map_width_in_meters", params.width, 20);
00145 ros::param::param<double>("~map_meters_per_cell", params.meters_per_cell,
00146 0.1);
00147 return params;
00148 }
00149
00154 void init_constants_for_ros(double &ros_tf_buffer_size,
00155 double &ros_map_rate,
00156 int &ros_filter_queue,
00157 int &ros_subscr_queue) {
00158 ros::param::param<double>("~ros_tf_buffer_duration",ros_tf_buffer_size,5.0);
00159 ros::param::param<double>("~ros_rviz_map_publishing_rate", ros_map_rate, 5.0);
00160 ros::param::param<int>("~ros_filter_queue_size",ros_filter_queue,1000);
00161 ros::param::param<int>("~ros_subscribers_queue_size",ros_subscr_queue,1000);
00162 }
00163
00164 void init_frame_names(std::string &frame_odom, std::string &frame_robot_pose) {
00165 ros::param::param<std::string>("~odom", frame_odom, "odom_combined");
00166 ros::param::param<std::string>("~robot_pose", frame_robot_pose, "robot_pose");
00167 }
00168
00172 int main(int argc, char** argv) {
00173 ros::init(argc, argv, "tinySLAM");
00174
00175 ros::NodeHandle nh;
00176 TinyWorldParams params = init_common_world_params();
00177 GridMapParams grid_map_params = init_grid_map_params();
00178 std::shared_ptr<ScanCostEstimator> cost_est{new TinyScanCostEstimator()};
00179 std::shared_ptr<GridCellStrategy> gcs{new GridCellStrategy{
00180 init_cell_factory(params), cost_est, init_occ_estimator()}};
00181 std::shared_ptr<TinySlamFascade> slam{new TinySlamFascade(gcs,
00182 params, grid_map_params, init_skip_exceeding_lsr())};
00183
00184 double ros_map_publishing_rate, ros_tf_buffer_size;
00185 int ros_filter_queue, ros_subscr_queue;
00186 std::string frame_odom, frame_robot_pose;
00187 init_constants_for_ros(ros_tf_buffer_size, ros_map_publishing_rate,
00188 ros_filter_queue, ros_subscr_queue);
00189 init_frame_names(frame_odom, frame_robot_pose);
00190 TopicWithTransform<sensor_msgs::LaserScan> scan_observer(nh,
00191 "laser_scan", frame_odom, ros_tf_buffer_size,
00192 ros_filter_queue, ros_subscr_queue);
00193 scan_observer.subscribe(slam);
00194
00195 std::shared_ptr<RvizGridViewer> viewer(
00196 new RvizGridViewer(nh.advertise<nav_msgs::OccupancyGrid>("/map", 5),
00197 ros_map_publishing_rate, frame_odom, frame_robot_pose));
00198 slam->set_viewer(viewer);
00199
00200 #ifdef RVIZ_DEBUG
00201 std::shared_ptr<PoseScanMatcherObserver> obs(new PoseScanMatcherObserver(frame_odom));
00202 slam->add_scan_matcher_observer(obs);
00203 #endif
00204 ros::spin();
00205 }