00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "parameter_server.h"
00017
00018
00019
00020 ParameterServer* ParameterServer::_instance = NULL;
00021
00022 void ParameterServer::defaultConfig() {
00023 double dInf = std::numeric_limits<double>::infinity();
00024
00025 addOption("topic_image_mono", std::string("/camera/rgb/image_color"), "Color or grayscale image ros topic");
00026 addOption("camera_info_topic", std::string("/camera/rgb/camera_info"), "Required for backprojection if no pointcloud topic is given");
00027 addOption("topic_image_depth", std::string("/camera/depth_registered/sw_registered/image_rect_raw"), "Depth image ros topic");
00028 addOption("topic_points", std::string(""), "If omitted, xyz will be computed from depth image. ");
00029 addOption("wide_topic", std::string(""), "Topics for stereo cam, e.g. /wide_stereo/left/image_mono");
00030 addOption("wide_cloud_topic", std::string(""), "Topics for stereo cam e.g. /wide_stereo/points2");
00031 addOption("bagfile_name", std::string(""), "Read data from a bagfile, make sure to enter the right topics above");
00032 addOption("subscriber_queue_size", static_cast<int> (3), "Cache incoming data (carefully, RGB-D Clouds are 10MB each)");
00033 addOption("drop_async_frames", static_cast<bool> (false), "Check timestamps of depth and visual image, reject if not in sync ");
00034 addOption("depth_scaling_factor", static_cast<double> (1.0), "Some kinects have a wrongly scaled depth");
00035 addOption("data_skip_step", static_cast<int> (1), "Skip every n-th frame completely ");
00036 addOption("cloud_creation_skip_step", static_cast<int> (2), "Downsampling factor (rows and colums, so size reduction is quadratic) for the point cloud. Only active if cloud is computed (i.e. \"topic_points\" is empty. This value multiplies to emm__skip_step and visualization_skip_step.");
00037 addOption("create_cloud_every_nth_node", static_cast<int> (1), "Create a point cloud only for every nth frame");
00038 addOption("maximum_depth", static_cast<double> (dInf), "Clip far points when reconstructing the cloud. In meter.");
00039 addOption("minimum_depth", static_cast<double> (0.1), "Clip near points when reconstructing the cloud. In meter.");
00040 addOption("encoding_bgr", static_cast<bool> (true), "Whether the color image encoding is bgr (fuerte openni_launch) as opposed to rgb (electric openni_camera)");
00041
00042 addOption("depth_camera_fx", static_cast<double> (0.0), "Focal length w.r.t. horizontal pixel size. Use zero to use values from CameraInfo");
00043 addOption("depth_camera_fy", static_cast<double> (0.0), "Focal length w.r.t. vertical pixel size. Use zero to use values from CameraInfo");
00044 addOption("depth_camera_cx", static_cast<double> (0.0), "Horizontal image center. Use zero to use values from CameraInfo");
00045 addOption("depth_camera_cy", static_cast<double> (0.0), "Vertical image center. Use zero to use values from CameraInfo");
00046 addOption("sigma_depth", static_cast<double> (0.01), "Factor c for the standard deviation of depth measurements: sigma_Z = c * depth * depth. Khoshelham 2012 (0.001425) seems to be a bit overconfident.");
00047
00048
00049 addOption("store_pointclouds", static_cast<bool> (true), "If the point clouds are not needed online, setting this to false saves lots of memory ");
00050 addOption("individual_cloud_out_topic", std::string("/rgbdslam/batch_clouds"), "Use this topic when sending the individual clouds with the computed transforms, e.g. for octomap_server");
00051 addOption("aggregate_cloud_out_topic", std::string("/rgbdslam/aggregate_clouds"), "Use this topic when sending the all points in one big registered cloud");
00052 addOption("online_cloud_out_topic", std::string("/rgbdslam/online_clouds"), "Use this topic to get the latest cloud.");
00053 addOption("send_clouds_rate", static_cast<double> (5), "When sending the point clouds (e.g. to RVIZ or Octomap Server) limit sending to this many clouds per second");
00054 addOption("publisher_queue_size", static_cast<int> (5), "ROS standard parameter for all publishers");
00055
00056 addOption("octomap_resolution", static_cast<double> (0.05), "Minimal voxel size of the OctoMap, when saved directly (not when used in conjunction with octomap_server)");
00057 addOption("octomap_autosave_step", static_cast<int> (50), "Automatically save the octomap repeatedly after insertion of this many clouds");
00058 addOption("octomap_clear_after_save", static_cast<bool> (false), "Clear out octomap after (final) saving.");
00059 addOption("octomap_clear_raycasted_clouds",static_cast<bool> (false), "Clear out point clouds after raycasting.");
00060 addOption("octomap_occupancy_threshold", static_cast<double> (0.5), "Occupancy threshold for binary OctoMap");
00061 addOption("octomap_clamping_max", static_cast<double> (0.999), "Maximum value for clamping of occupancy threshold in voxels");
00062 addOption("octomap_clamping_min", static_cast<double> (0.001), "Minimum value for clamping of occupancy threshold in voxels");
00063 addOption("octomap_prob_hit", static_cast<double> (0.9), "Octomap sensor model: Probability value for hit.");
00064 addOption("octomap_prob_miss", static_cast<double> (0.4), "Octomap sensor model: Probability value for miss.");
00065 addOption("octomap_online_creation", static_cast<bool> (false), "Create the octomap during mapping. If using this, every node will be rendered to the octomap directly after they have been added to the graph (and graph optimization, if not skipped b/c of optimizer_skip_step).");
00066 addOption("screencast_path_prefix", std::string(""), "If set: capture frames for a screencast with this path as filename-prefix.");
00067 addOption("transform_individual_clouds", static_cast<bool> (false), "If set: Transform individually saved pcds into common coordinate frame.");
00068 addOption("compress_output_bagfile", static_cast<bool> (true), "Whether to enable bz2 compression when saving bagfiles");
00069 addOption("occupancy_filter_threshold", static_cast<double> (0.9), "Remove points located at voxels with occupancy probability below this.");
00070
00071
00072 addOption("fixed_frame_name", std::string("/map"), "The computed camera transforms are with respect to this frame. It is set to the identity for the first frame processed or, if ground truth is available, to the ground truth of the first frame");
00073 addOption("odom_frame_name", std::string(""), "A fixed frame estimation from somewhere else (e.g. odometry, laser-based mapping). Doesn't need to correspond to the pose of the fixed_frame_name");
00074 addOption("odom_target_frame_name", std::string(""), "If given, try to get the odometry transformation from odom_frame_name to this frame instead of the frame of the points. Meant to compute the offset between robot base and sensor online.");
00075 addOption("ground_truth_frame_name", std::string(""), "Use empty string if no ground truth tf frame available");
00076 addOption("base_frame_name", std::string("/openni_rgb_optical_frame"), "If the camera is articulated use robot base");
00077 addOption("fixed_camera", static_cast<bool> (true), "Is camera fixed relative to base?");
00078
00079
00080 addOption("feature_detector_type", std::string("ORB"), "SIFTGPU, SURF, SIFT or ORB, or variants like GridDynamicORB or DynamicSURF (however, not GridXXX only, and not in combination with SIFTGPU)");
00081 addOption("feature_extractor_type", std::string("ORB"), "SIFTGPU, SURF, SIFT or ORB");
00082 addOption("matcher_type", std::string("FLANN"), "SIFTGPU (matching on the gpu) or FLANN or BRUTEFORCE. FLANN is fast for SURF. For ORB FLANN is slower than Bruteforce for few keypoints (less than ~3000).");
00083 addOption("max_keypoints", static_cast<int> (600), "Extract no more than this many keypoints ");
00084 addOption("min_keypoints", static_cast<int> (000), "Deprecated: Extract no less than this many keypoints ");
00085 addOption("min_matches", static_cast<int> (20), "Don't try RANSAC if less than this many matches (if using SiftGPU and GLSL you should use max. 60 matches)");
00086 addOption("max_matches", static_cast<int> (300), "Reduce the feature matches to the best n, speeding up ransac (but not feature matching itself)");
00087 addOption("detector_grid_resolution", static_cast<int> (3), "If >1, split image into x by x subimages (overlapping b/c of keypoint size) and detect keypoints in parallel. Good to spread ORB keypoints over the image and speed up the slow SURF detection.");
00088 addOption("sufficient_matches", static_cast<int> (1e9), "Extract no less than this many only honored by the adjustable SURF and FAST features");
00089 addOption("adjuster_max_iterations", static_cast<int> (5), "If outside of bounds for max_kp and min_kp, retry this many times with adapted threshold");
00090 addOption("use_feature_min_depth", static_cast<bool>(false), "Consider the nearest point in the neighborhood of the feature as its depth, as it will dominate the motion");
00091 addOption("use_feature_mask", static_cast<bool>(false), "Whether to extract features without depth");
00092 addOption("use_root_sift", static_cast<bool>(true), "Whether to use euclidean distance or Hellman kernel for feature comparison");
00093 addOption("siftgpu_with_cuda", static_cast<bool>(false), "Use CUDA instead of GLSL for the computation of SIFTGPU features. Requires CUDA drivers to be installed.");
00094
00095
00096 addOption("max_translation_meter", static_cast<double> (1e10), "Sanity check for smooth motion.");
00097 addOption("max_rotation_degree", static_cast<double> (360), "Sanity check for smooth motion.");
00098 addOption("min_translation_meter", static_cast<double> (0.0), "Frames with motion less than this, will be omitted ");
00099 addOption("min_rotation_degree", static_cast<double> (0.0), "Frames with motion less than this, will be omitted ");
00100 addOption("max_dist_for_inliers", static_cast<double> (3), "Mahalanobis distance for matches to be considered inliers by ransac");
00101 addOption("ransac_iterations", static_cast<int> (200), "Number of iterations for registration");
00102 addOption("ransac_termination_inlier_pct", static_cast<double> (60.0), "Percentage of matches that need to be inliers to succesfully terminate ransac before the 'ransac_iterations' have been reached");
00103 addOption("g2o_transformation_refinement", static_cast<int> (0), "Use g2o to refine the ransac result for that many iterations, i.e. optimize the Mahalanobis distance in a final step. Use zero to disable.");
00104 addOption("max_connections", static_cast<int> (-1), "Stop frame comparisons after this many succesfully found spation relations. Negative value: No limit.");
00105 addOption("geodesic_depth", static_cast<int> (3), "For comparisons with neighbors, consider those with a graph distance (hop count) equal or below this value as neighbors of the direct predecessor");
00106 addOption("predecessor_candidates", static_cast<int> (4), "Compare Features to this many direct sequential predecessors");
00107 addOption("neighbor_candidates", static_cast<int> (4), "Compare Features to this many graph neighbours. Sample from the candidates");
00108 addOption("min_sampled_candidates", static_cast<int> (4), "Compare Features to this many uniformly sampled nodes for corrspondences ");
00109 addOption("use_icp", static_cast<bool> (false), "Activate ICP Fallback. Ignored if ICP is not compiled in (see top of CMakeLists.txt) ");
00110 addOption("icp_method", std::string("icp"), "gicp, icp or icp_nl");
00111 addOption("gicp_max_cloud_size", static_cast<int> (10000), "Subsample for increased speed");
00112 addOption("emm__skip_step", static_cast<int> (8), "When evaluating the transformation, subsample rows and cols with this stepping");
00113 addOption("emm__mark_outliers", static_cast<bool> (false), "Mark outliers in the observation likelihood evaluation with colors. Red: point would have blocked the view of an earlier observation. Cyan: An earlier observation should have blocked the view to this point");
00114 addOption("observability_threshold", static_cast<double> (-0.6), "What fraction of the aligned points are required to be in observable position (i.e. don't contradict the sensor physics)");
00115 addOption("allow_features_without_depth", static_cast<bool> (false), "Keep matches without depth (currently has no benefit)");
00116
00117
00118 addOption("pose_relative_to", std::string("first"), "This option allows to choose which frame(s) should be set fixed during optimization: first, previous, inaffected, largest_loop. The latter sets all frames as fixed to which no transformation has been found.");
00119 addOption("optimizer_iterations", static_cast<double> (0.01), "Maximum of iterations. If between 0 and 1, optimizer stops after improvement is less than the given fraction (default: 1%).");
00120 addOption("optimizer_skip_step", static_cast<int> (1), "Optimize every n-th frame. Set negative for offline operation ");
00121 addOption("optimize_landmarks", static_cast<bool> (false), "Consider the features as landmarks in optimization. Otherwise optimize camera pose graph only");
00122 addOption("concurrent_optimization", static_cast<bool> (true), "Do graph optimization in a seperate thread");
00123 addOption("backend_solver", std::string("pcg"), "Which solver to use in g2o for matrix inversion: 'csparse' , 'cholmod' or 'pcg'");
00124
00125
00126 addOption("use_robot_odom", static_cast<bool> (false), "In addition to frame-to-frame transformation use odometry information in the graph");
00127 addOption("use_robot_odom_only", static_cast<bool> (false), "In addition to frame-to-frame transformation use odometry information in the graph");
00128 addOption("constrain_2d", static_cast<bool> (false), "Constrain camera motion to 2d plus heading");
00129 addOption("use_odom_for_prediction", static_cast<bool> (false), "Use odometry information to predict feature locations. Do not use Kd-Tree anymore.");
00130 addOption("odometry_tpc", std::string("/odom"), "Robot odometry topic. Not required if odometry comes via /tf. Only the pose of the odometry is used.");
00131 addOption("odometry_information_factor", static_cast<double> (1e4), "Diagonal coefficients of the information matrix of the odometry edges. Default: Std Dev of 0.01m and 0.01rad");
00132
00133
00134 addOption("use_glwidget", static_cast<bool> (true), "3D view");
00135 addOption("use_gui", static_cast<bool> (true), "GUI vs Headless Mode");
00136 addOption("show_2d_display", static_cast<bool> (true), "show or hide 2D view initially");
00137 addOption("glwidget_without_clouds", static_cast<bool> (false), "3D view should only display the graph");
00138 addOption("visualize_mono_depth_overlay", static_cast<bool> (false), "Show Depth and Monochrome image as overlay in featureflow");
00139 addOption("visualization_skip_step", static_cast<int> (1), "Draw only every nth pointcloud row and line, high values require higher squared_meshing_threshold ");
00140 addOption("visualize_keyframes_only", static_cast<bool> (false), "Do not render point cloud of non-keyframes.");
00141 addOption("fast_rendering_step", static_cast<int> (1), "Draw only every nth pointcloud during user interaction");
00142 addOption("octomap_display_level", static_cast<int> (16), "Show this level of OctoMap octree");
00143 addOption("gl_point_size", static_cast<double> (1.0), "Point size, when not triangulating. See documentation of GL_POINT_SIZE.");
00144 addOption("gl_grid_size_xy", static_cast<int> (0), "Grid size in the xy plane (sidelength in number of cell). Zero disables. Note that this is in the coordinate system of the point cloud");
00145 addOption("gl_grid_size_xz", static_cast<int> (20), "Grid size in the xz plane (sidelength in number of cell). Zero disables. Note that this is in the coordinate system of the point cloud");
00146 addOption("gl_grid_size_yz", static_cast<int> (0), "Grid size in the yz plane (sidelength in number of cell). Zero disables. Note that this is in the coordinate system of the point cloud");
00147 addOption("gl_cell_size", static_cast<double> (1.0), "Grid cell size in meter.");
00148 addOption("squared_meshing_threshold", static_cast<double> (0.0009), "Don't triangulate over depth jumps. Should be increased with increasing visualization_skip_step");
00149 addOption("show_axis", static_cast<bool> (true), "Do/don't visualize the pose graph in glwidget");
00150 addOption("scalable_2d_display", static_cast<bool> (false), "Whether the input images are expanded. Consumes CPU time");
00151 addOption("cloud_display_type", static_cast<std::string>("POINTS"), "Drastically affects rendering time. GL_xxx type of compiled list GL_TRIANGLE_STRIP (fastest processing of new clouds), GL_POINTS (fastest display) GL_TRIANGLES (no good), or ELLIPSOIDS (very slow, but visualizes standard deviation)");
00152
00153
00154 addOption("start_paused", static_cast<bool> (false), "Whether to directly start mapping with the first input image, or to wait for the user to start manually");
00155 addOption("batch_processing", static_cast<bool> (false), "Store results and close after bagfile has been processed");
00156 addOption("concurrent_node_construction", static_cast<bool> (true), "Detect+extract features for new frame, while current frame is inserted into graph ");
00157 addOption("concurrent_edge_construction", static_cast<bool> (true), "Compare current frame to many predecessors in parallel. Note that SIFTGPU matcher and GICP are mutex'ed for thread-safety");
00158 addOption("concurrent_io", static_cast<bool> (true), "Whether saving/sending should be done in background threads.");
00159 addOption("voxelfilter_size", static_cast<double> (-1.0), "In meter voxefilter displayed and stored pointclouds, useful to reduce the time for, e.g., octomap generation. Set negative to disable");
00160 addOption("nn_distance_ratio", static_cast<double> (0.95), "Feature correspondence is valid if distance to nearest neighbour is smaller than this parameter times the distance to the 2nd neighbour. This needs to be 0.9-1.0 for ORB and SIFTGPU w/ FLANN, since SIFTGPU Features are normalized and ORB become ambiguous for blurry images. For SURF and SIFT (CPU) use 0.5-0.8");
00161 addOption("keep_all_nodes", static_cast<bool> (false), "Keep all nodes with 'no motion' assumption");
00162 addOption("keep_good_nodes", static_cast<bool> (false), "Keep nodes without transformation estimation but enough features (according to min_matches) with 'no motion' assumption. These are not rendered in visualization.");
00163 addOption("clear_non_keyframes", static_cast<bool> (false), "Remove the net data of nodes when it becomes clear that they will not be used as keyframe. However, this makes matching against them impossible.");
00164 addOption("min_time_reported", static_cast<double> (-1.0), "For easy profiling. Negative: nothing should be reported");
00165 addOption("preserve_raster_on_save", static_cast<bool> (false), "Filter NaNs when saving clouds, destroying the image raster");
00166 addOption("skip_first_n_frames", static_cast<int> (0), "Useful to skip start of a bagfile");
00167 addOption("segment_to_optimize", static_cast<int> (-1), "If segment information is available, optimize with higher weights on this segment (set negative to disable)");
00168 addOption("send_clouds_delay", static_cast<double> (-10.0), "If set, wait with sending clouds until they are x seconds old (uses the clouds timestamp).");
00169 addOption("save_octomap_delay", static_cast<double> (10.0), "If set, wait with sending clouds until they are x seconds old (uses the clouds timestamp).");
00170
00171 addOption("show_cloud_with_id", static_cast<int> (-1), "Show only one cloud (namely that perceived at the respective node id");
00172 addOption("use_error_shortcut", static_cast<bool> (true), "Compute isotropic bounds first in inlier determination");
00173 }
00174
00175
00176 ParameterServer::ParameterServer() {
00177 pre = ros::this_node::getName();
00178 pre += "/config/";
00179
00180 defaultConfig();
00181 getValues();
00182 }
00183
00184 ParameterServer* ParameterServer::instance() {
00185 if (_instance == NULL) {
00186 _instance = new ParameterServer();
00187 }
00188 return _instance;
00189 }
00190
00191 void ParameterServer::addOption(std::string name, boost::any value, std::string description){
00192 config[name] = value;
00193 descriptions[name] = description;
00194 }
00195
00196
00197 std::string ParameterServer::getDescription(std::string param_name) {
00198 return descriptions[param_name];
00199 }
00200
00201 void ParameterServer::getValues() {
00202 std::map<std::string, boost::any>::const_iterator itr;
00203 for (itr = config.begin(); itr != config.end(); ++itr) {
00204 std::string name = itr->first;
00205 if (itr->second.type() == typeid(std::string)) {
00206 config[name] = getFromParameterServer<std::string> (pre + name,
00207 boost::any_cast<std::string>(itr->second));
00208 ROS_DEBUG_STREAM("Value for " << name << ": " << boost::any_cast<std::string>(itr->second));
00209 } else if (itr->second.type() == typeid(int)) {
00210 config[name] = getFromParameterServer<int> (pre + name,
00211 boost::any_cast<int>(itr->second));
00212 ROS_DEBUG_STREAM("Value for " << name << ": " << boost::any_cast<int>(itr->second));
00213 } else if (itr->second.type() == typeid(double)) {
00214 config[name] = getFromParameterServer<double> (pre + name,
00215 boost::any_cast<double>(itr->second));
00216 ROS_DEBUG_STREAM("Value for " << name << ": " << boost::any_cast<double>(itr->second));
00217 } else if (itr->second.type() == typeid(bool)) {
00218 config[name] = getFromParameterServer<bool> (pre + name,
00219 boost::any_cast<bool>(itr->second));
00220 ROS_DEBUG_STREAM("Value for " << name << ": " << boost::any_cast<bool>(itr->second));
00221 }
00222 }
00223 checkValues();
00224 }
00225
00226 void ParameterServer::checkValues() {
00227 if (get<std::string>("matcher_type").compare("SIFTGPU") == 0
00228 && get<bool>("concurrent_node_construction") == true) {
00229 config["concurrent_node_construction"] = static_cast<bool>(false);
00230 ROS_WARN("Cannot use concurrent node construction with SiftGPU matcher! 'concurrent_node_construction' was set to false. Everything should work fine, but the CPU-threading won't happen (because you are using the GPU instead).");
00231 }
00232
00233 if (get<double>("voxelfilter_size") > 0 && get<double>("observability_threshold") > 0) {
00234 ROS_ERROR("You cannot use the voxelfilter (param: voxelfilter_size) in combination with the environment measurement model (param: observability_threshold)");
00235 }
00236 if (get<std::string>("matcher_type").compare("SIFTGPU") == 0
00237 && get<bool>("concurrent_edge_construction") == true) {
00238 config["concurrent_edge_construction"] = static_cast<bool>(false);
00239 ROS_WARN("Cannot use concurrent edge construction with SiftGPU matcher! 'concurrent_edge_construction' was set to false. Everything should work fine, but the CPU-threading won't happen (because you are using the GPU instead).");
00240 }
00241 if (get<double>("max_translation_meter") <= 0){
00242 double dInf = std::numeric_limits<double>::infinity();
00243 set("max_translation_meter", dInf);
00244 }
00245 if (get<double>("max_rotation_degree") <= 0){
00246 double dInf = std::numeric_limits<double>::infinity();
00247 set("max_rotation_degree", dInf);
00248 }
00249 }