1. 程式人生 > 實用技巧 >CV學習日誌:自動提取ROS2及Webots標頭檔案

CV學習日誌:自動提取ROS2及Webots標頭檔案

ROS2包含許多的開發包,這些開發包覆蓋了機器人開發過程所有可能涉及到的訊息、服務及動作。我們可以直接使用這些訊息/服務/動作進行開發而無需再自定義,從而提高開發效率。然而,也正因為ROS2開發包較多且不同版本的開發包可能還不完全一致,所以要一覽其提供的訊息/服務/動作、或要自動提取相應的標頭檔案、或要比較不同版本ROS2間的區別還比較麻煩,尤其是要經常這麼做時。於是,我基於ROS2檔案結構的特點寫了一個指令碼來自動提取每個開發包的標頭檔案,函式createROSHPP已經包含了所有提供了訊息/服務/動作的開發包及其它常用的開發包(如rclcpp/rcl_action/ament_index_cpp),若有新增開發包或自編譯包,只需要按相應的格式在函式createROSHPP中追加相應的包即可。

另外,由於Webots脫離ROS2的易用性、多平臺的良好相容性及開發自定義Webots與ROS2通訊外掛的需要,我也寫了一個自動提取Webots所有CPP標頭檔案(因為更偏好C++開發)的指令碼,但函式createWebotsHPP中也實現了自動提取Webots所有C標頭檔案的功能,只是註釋掉了,若有需求也可開啟。

以上功能都封裝在類ROS2WebotsHeaders中,依賴OpenCV和Spdlog,類主體結構如下:

ROS2WebotsHeaders

TestMe:主函式(輸入引數為{whichLib(只能為ros2或webots) homePath(如/usr/local/webots或/opt/ros/foxy)})

createWebotsHPP:提取Webots的所有HPP標頭檔案(去掉註釋也可提取所有H標頭檔案)

createROSHPP:提取ROS2相關包的所有HPP標頭檔案(按相應格式追加包即可提取對應包的所有HPP標頭檔案)

globPaths:獲取所有檔案或目錄或檔案目錄

getNewPath:獲取指定基名和副檔名的尚不存在的路徑

以下自動提取的webots-2020b-rev1和ros-foxy-rev1-windows的標頭檔案

#define stdmsg std_msgs::msg
#define stdsrv std_srvs::srv
#define geomsg geometry_msgs::msg
#define
ssrmsg sensor_msgs::msg #if 1 //Webots headers #include <webots/GPS.hpp> #include <webots/LED.hpp> #include <webots/Pen.hpp> #include <webots/Gyro.hpp> #include <webots/Node.hpp> #include <webots/Skin.hpp> #include <webots/Brake.hpp> #include <webots/Field.hpp> #include <webots/Lidar.hpp> #include <webots/Motor.hpp> #include <webots/Mouse.hpp> #include <webots/Radar.hpp> #include <webots/Robot.hpp> #include <webots/Camera.hpp> #include <webots/Device.hpp> #include <webots/Compass.hpp> #include <webots/Display.hpp> #include <webots/Emitter.hpp> #include <webots/Speaker.hpp> #include <webots/ImageRef.hpp> #include <webots/Joystick.hpp> #include <webots/Keyboard.hpp> #include <webots/Receiver.hpp> #include <webots/Connector.hpp> #include <webots/Supervisor.hpp> #include <webots/LightSensor.hpp> #include <webots/RangeFinder.hpp> #include <webots/TouchSensor.hpp> #include <webots/vehicle/Car.hpp> #include <webots/InertialUnit.hpp> #include <webots/utils/Motion.hpp> #include <webots/Accelerometer.hpp> #include <webots/DistanceSensor.hpp> #include <webots/PositionSensor.hpp> #include <webots/vehicle/Driver.hpp> #include <webots/utils/AnsiCodes.hpp> #include <webots/DifferentialWheels.hpp> #endif #if 1 //ROS2 headers //ament_index_cpp #include <ament_index_cpp/get_resource.hpp> #include <ament_index_cpp/has_resource.hpp> #include <ament_index_cpp/get_resources.hpp> #include <ament_index_cpp/get_search_paths.hpp> #include <ament_index_cpp/get_package_prefix.hpp> #include <ament_index_cpp/get_packages_with_prefixes.hpp> #include <ament_index_cpp/get_package_share_directory.hpp> //rclcpp #include <rclcpp/qos.hpp> #include <rclcpp/node.hpp> #include <rclcpp/rate.hpp> #include <rclcpp/time.hpp> #include <rclcpp/clock.hpp> #include <rclcpp/event.hpp> #include <rclcpp/timer.hpp> #include <rclcpp/client.hpp> #include <rclcpp/logger.hpp> #include <rclcpp/macros.hpp> #include <rclcpp/rclcpp.hpp> #include <rclcpp/context.hpp> #include <rclcpp/logging.hpp> #include <rclcpp/service.hpp> #include <rclcpp/duration.hpp> #include <rclcpp/executor.hpp> #include <rclcpp/wait_set.hpp> #include <rclcpp/waitable.hpp> #include <rclcpp/executors.hpp> #include <rclcpp/parameter.hpp> #include <rclcpp/publisher.hpp> #include <rclcpp/qos_event.hpp> #include <rclcpp/utilities.hpp> #include <rclcpp/exceptions.hpp> #include <rclcpp/scope_exit.hpp> #include <rclcpp/time_source.hpp> #include <rclcpp/wait_result.hpp> #include <rclcpp/create_timer.hpp> #include <rclcpp/init_options.hpp> #include <rclcpp/message_info.hpp> #include <rclcpp/node_options.hpp> #include <rclcpp/subscription.hpp> #include <rclcpp/create_client.hpp> #include <rclcpp/parameter_map.hpp> #include <rclcpp/serialization.hpp> #include <rclcpp/any_executable.hpp> #include <rclcpp/callback_group.hpp> #include <rclcpp/create_service.hpp> #include <rclcpp/graph_listener.hpp> #include <rclcpp/loaned_message.hpp> #include <rclcpp/publisher_base.hpp> #include <rclcpp/function_traits.hpp> #include <rclcpp/guard_condition.hpp> #include <rclcpp/memory_strategy.hpp> #include <rclcpp/parameter_value.hpp> #include <rclcpp/create_publisher.hpp> #include <rclcpp/executor_options.hpp> #include <rclcpp/parameter_client.hpp> #include <rclcpp/wait_result_kind.hpp> #include <rclcpp/memory_strategies.hpp> #include <rclcpp/parameter_service.hpp> #include <rclcpp/publisher_factory.hpp> #include <rclcpp/publisher_options.hpp> #include <rclcpp/subscription_base.hpp> #include <rclcpp/type_support_decl.hpp> #include <rclcpp/wait_set_template.hpp> #include <rclcpp/future_return_code.hpp> #include <rclcpp/serialized_message.hpp> #include <rclcpp/visibility_control.hpp> #include <rclcpp/create_subscription.hpp> #include <rclcpp/subscription_traits.hpp> #include <rclcpp/any_service_callback.hpp> #include <rclcpp/subscription_factory.hpp> #include <rclcpp/subscription_options.hpp> #include <rclcpp/intra_process_setting.hpp> #include <rclcpp/topic_statistics_state.hpp> #include <rclcpp/message_memory_strategy.hpp> #include <rclcpp/parameter_events_filter.hpp> #include <rclcpp/any_subscription_callback.hpp> #include <rclcpp/intra_process_buffer_type.hpp> #include <rclcpp/subscription_wait_set_mask.hpp> #include <rclcpp/expand_topic_or_service_name.hpp> //rclcpp_action #include <rclcpp_action/qos.hpp> #include <rclcpp_action/types.hpp> #include <rclcpp_action/client.hpp> #include <rclcpp_action/server.hpp> #include <rclcpp_action/exceptions.hpp> #include <rclcpp_action/create_client.hpp> #include <rclcpp_action/create_server.hpp> #include <rclcpp_action/rclcpp_action.hpp> #include <rclcpp_action/client_goal_handle.hpp> #include <rclcpp_action/server_goal_handle.hpp> #include <rclcpp_action/visibility_control.hpp> //std_msgs #include <std_msgs/msg/bool.hpp> #include <std_msgs/msg/byte.hpp> #include <std_msgs/msg/char.hpp> #include <std_msgs/msg/int8.hpp> #include <std_msgs/msg/empty.hpp> #include <std_msgs/msg/int16.hpp> #include <std_msgs/msg/int32.hpp> #include <std_msgs/msg/int64.hpp> #include <std_msgs/msg/header.hpp> #include <std_msgs/msg/string.hpp> #include <std_msgs/msg/u_int8.hpp> #include <std_msgs/msg/float32.hpp> #include <std_msgs/msg/float64.hpp> #include <std_msgs/msg/u_int16.hpp> #include <std_msgs/msg/u_int32.hpp> #include <std_msgs/msg/u_int64.hpp> #include <std_msgs/msg/color_rgba.hpp> #include <std_msgs/msg/byte_multi_array.hpp> #include <std_msgs/msg/int8_multi_array.hpp> #include <std_msgs/msg/int16_multi_array.hpp> #include <std_msgs/msg/int32_multi_array.hpp> #include <std_msgs/msg/int64_multi_array.hpp> #include <std_msgs/msg/multi_array_layout.hpp> #include <std_msgs/msg/u_int8_multi_array.hpp> #include <std_msgs/msg/float32_multi_array.hpp> #include <std_msgs/msg/float64_multi_array.hpp> #include <std_msgs/msg/u_int16_multi_array.hpp> #include <std_msgs/msg/u_int32_multi_array.hpp> #include <std_msgs/msg/u_int64_multi_array.hpp> #include <std_msgs/msg/multi_array_dimension.hpp> //std_srvs #include <std_srvs/srv/empty.hpp> #include <std_srvs/srv/trigger.hpp> #include <std_srvs/srv/set_bool.hpp> //builtin_interfaces #include <builtin_interfaces/msg/time.hpp> #include <builtin_interfaces/msg/duration.hpp> //sensor_msgs #include <sensor_msgs/fill_image.hpp> #include <sensor_msgs/image_encodings.hpp> #include <sensor_msgs/distortion_models.hpp> #include <sensor_msgs/point_cloud2_iterator.hpp> #include <sensor_msgs/point_cloud_conversion.hpp> #include <sensor_msgs/point_field_conversion.hpp> #include <sensor_msgs/msg/imu.hpp> #include <sensor_msgs/msg/joy.hpp> #include <sensor_msgs/msg/image.hpp> #include <sensor_msgs/msg/range.hpp> #include <sensor_msgs/msg/laser_echo.hpp> #include <sensor_msgs/msg/laser_scan.hpp> #include <sensor_msgs/msg/camera_info.hpp> #include <sensor_msgs/msg/illuminance.hpp> #include <sensor_msgs/msg/joint_state.hpp> #include <sensor_msgs/msg/nav_sat_fix.hpp> #include <sensor_msgs/msg/point_cloud.hpp> #include <sensor_msgs/msg/point_field.hpp> #include <sensor_msgs/msg/temperature.hpp> #include <sensor_msgs/msg/joy_feedback.hpp> #include <sensor_msgs/msg/point_cloud2.hpp> #include <sensor_msgs/msg/battery_state.hpp> #include <sensor_msgs/msg/fluid_pressure.hpp> #include <sensor_msgs/msg/magnetic_field.hpp> #include <sensor_msgs/msg/nav_sat_status.hpp> #include <sensor_msgs/msg/time_reference.hpp> #include <sensor_msgs/msg/channel_float32.hpp> #include <sensor_msgs/msg/compressed_image.hpp> #include <sensor_msgs/msg/relative_humidity.hpp> #include <sensor_msgs/msg/joy_feedback_array.hpp> #include <sensor_msgs/msg/region_of_interest.hpp> #include <sensor_msgs/msg/multi_dof_joint_state.hpp> #include <sensor_msgs/msg/multi_echo_laser_scan.hpp> #include <sensor_msgs/srv/set_camera_info.hpp> //geometry_msgs #include <geometry_msgs/msg/pose.hpp> #include <geometry_msgs/msg/accel.hpp> #include <geometry_msgs/msg/point.hpp> #include <geometry_msgs/msg/twist.hpp> #include <geometry_msgs/msg/wrench.hpp> #include <geometry_msgs/msg/inertia.hpp> #include <geometry_msgs/msg/point32.hpp> #include <geometry_msgs/msg/polygon.hpp> #include <geometry_msgs/msg/pose2_d.hpp> #include <geometry_msgs/msg/vector3.hpp> #include <geometry_msgs/msg/transform.hpp> #include <geometry_msgs/msg/pose_array.hpp> #include <geometry_msgs/msg/quaternion.hpp> #include <geometry_msgs/msg/pose_stamped.hpp> #include <geometry_msgs/msg/accel_stamped.hpp> #include <geometry_msgs/msg/point_stamped.hpp> #include <geometry_msgs/msg/twist_stamped.hpp> #include <geometry_msgs/msg/wrench_stamped.hpp> #include <geometry_msgs/msg/inertia_stamped.hpp> #include <geometry_msgs/msg/polygon_stamped.hpp> #include <geometry_msgs/msg/vector3_stamped.hpp> #include <geometry_msgs/msg/transform_stamped.hpp> #include <geometry_msgs/msg/quaternion_stamped.hpp> #include <geometry_msgs/msg/pose_with_covariance.hpp> #include <geometry_msgs/msg/accel_with_covariance.hpp> #include <geometry_msgs/msg/twist_with_covariance.hpp> #include <geometry_msgs/msg/pose_with_covariance_stamped.hpp> #include <geometry_msgs/msg/accel_with_covariance_stamped.hpp> #include <geometry_msgs/msg/twist_with_covariance_stamped.hpp> //trajectory_msgs #include <trajectory_msgs/msg/joint_trajectory.hpp> #include <trajectory_msgs/msg/joint_trajectory_point.hpp> #include <trajectory_msgs/msg/multi_dof_joint_trajectory.hpp> #include <trajectory_msgs/msg/multi_dof_joint_trajectory_point.hpp> //move_base_msgs #include <move_base_msgs/action/move_base.hpp> //stereo_msgs #include <stereo_msgs/msg/disparity_image.hpp> //shape_msgs #include <shape_msgs/msg/mesh.hpp> #include <shape_msgs/msg/plane.hpp> #include <shape_msgs/msg/mesh_triangle.hpp> #include <shape_msgs/msg/solid_primitive.hpp> //map_msgs #include <map_msgs/msg/projected_map.hpp> #include <map_msgs/msg/projected_map_info.hpp> #include <map_msgs/msg/point_cloud2_update.hpp> #include <map_msgs/msg/occupancy_grid_update.hpp> #include <map_msgs/srv/save_map.hpp> #include <map_msgs/srv/get_map_roi.hpp> #include <map_msgs/srv/get_point_map.hpp> #include <map_msgs/srv/get_point_map_roi.hpp> #include <map_msgs/srv/projected_maps_info.hpp> #include <map_msgs/srv/set_map_projections.hpp> //nav_msgs #include <nav_msgs/msg/path.hpp> #include <nav_msgs/msg/odometry.hpp> #include <nav_msgs/msg/grid_cells.hpp> #include <nav_msgs/msg/map_meta_data.hpp> #include <nav_msgs/msg/occupancy_grid.hpp> #include <nav_msgs/srv/get_map.hpp> #include <nav_msgs/srv/set_map.hpp> #include <nav_msgs/srv/get_plan.hpp> //visualization_msgs #include <visualization_msgs/msg/marker.hpp> #include <visualization_msgs/msg/menu_entry.hpp> #include <visualization_msgs/msg/image_marker.hpp> #include <visualization_msgs/msg/marker_array.hpp> #include <visualization_msgs/msg/interactive_marker.hpp> #include <visualization_msgs/msg/interactive_marker_init.hpp> #include <visualization_msgs/msg/interactive_marker_pose.hpp> #include <visualization_msgs/msg/interactive_marker_update.hpp> #include <visualization_msgs/msg/interactive_marker_control.hpp> #include <visualization_msgs/msg/interactive_marker_feedback.hpp> #include <visualization_msgs/srv/get_interactive_markers.hpp> //diagnostic_msgs #include <diagnostic_msgs/msg/key_value.hpp> #include <diagnostic_msgs/msg/diagnostic_array.hpp> #include <diagnostic_msgs/msg/diagnostic_status.hpp> #include <diagnostic_msgs/srv/self_test.hpp> #include <diagnostic_msgs/srv/add_diagnostics.hpp> //test_msgs #include <test_msgs/msg/empty.hpp> #include <test_msgs/msg/arrays.hpp> #include <test_msgs/msg/nested.hpp> #include <test_msgs/msg/strings.hpp> #include <test_msgs/msg/builtins.hpp> #include <test_msgs/msg/defaults.hpp> #include <test_msgs/msg/constants.hpp> #include <test_msgs/msg/w_strings.hpp> #include <test_msgs/msg/basic_types.hpp> #include <test_msgs/msg/multi_nested.hpp> #include <test_msgs/msg/bounded_sequences.hpp> #include <test_msgs/msg/unbounded_sequences.hpp> #include <test_msgs/srv/empty.hpp> #include <test_msgs/srv/arrays.hpp> #include <test_msgs/srv/basic_types.hpp> #include <test_msgs/action/fibonacci.hpp> #include <test_msgs/action/nested_message.hpp> //action_msgs #include <action_msgs/msg/goal_info.hpp> #include <action_msgs/msg/goal_status.hpp> #include <action_msgs/msg/goal_status_array.hpp> #include <action_msgs/srv/cancel_goal.hpp> //actionlib_msgs #include <actionlib_msgs/msg/goal_id.hpp> #include <actionlib_msgs/msg/goal_status.hpp> #include <actionlib_msgs/msg/goal_status_array.hpp> //lifecycle_msgs #include <lifecycle_msgs/msg/state.hpp> #include <lifecycle_msgs/msg/transition.hpp> #include <lifecycle_msgs/msg/transition_event.hpp> #include <lifecycle_msgs/msg/transition_description.hpp> #include <lifecycle_msgs/srv/get_state.hpp> #include <lifecycle_msgs/srv/change_state.hpp> #include <lifecycle_msgs/srv/get_available_states.hpp> #include <lifecycle_msgs/srv/get_available_transitions.hpp> //rosgraph_msgs #include <rosgraph_msgs/msg/clock.hpp> //pendulum_msgs #include <pendulum_msgs/msg/joint_state.hpp> #include <pendulum_msgs/msg/joint_command.hpp> #include <pendulum_msgs/msg/rttest_results.hpp> //composition_interfaces #include <composition_interfaces/srv/load_node.hpp> #include <composition_interfaces/srv/list_nodes.hpp> #include <composition_interfaces/srv/unload_node.hpp> //unique_identifier_msgs #include <unique_identifier_msgs/msg/uuid.hpp> //tf2_msgs #include <tf2_msgs/msg/tf2_error.hpp> #include <tf2_msgs/msg/tf_message.hpp> #include <tf2_msgs/srv/frame_graph.hpp> #include <tf2_msgs/action/lookup_transform.hpp> //tf2_sensor_msgs //tf2_geometry_msgs #endif

詳細指令碼內容如下

  1 #include <string>
  2 #include <opencv2/opencv.hpp>
  3 #include <opencv2/core/utils/filesystem.hpp>
  4 #include <spdlog/spdlog.h>
  5 using namespace std;
  6 using namespace cv;
  7 
  8 class ROS2WebotsHeaders
  9 {
 10 public:
 11     static void TestMe(int argc, char** argv)
 12     {
 13         if (argc < 3) spdlog::critical("Usage: appName whichLib(ros or webots) homePath(/usr/local/webots or /opt/ros/foxy)");
 14         else spdlog::info("Save the result to {}/abcx.xxx", argv[2]);
 15         if (argc >= 3 && strcmp(argv[1], "ros") == 0) createROSHPP(argv[2]);
 16         if (argc >= 3 && strcmp(argv[1], "webots") == 0) createWebotHPP(argv[2]);
 17     }
 18 
 19 public:
 20     static void createWebotHPP(string webotsHomePath = "/user/local/webots")
 21     {
 22         string hDir = webotsHomePath + "/include/controller/c/webots";
 23         string hppDir = webotsHomePath + "/include/controller/cpp/webots";
 24         vector<string> webotsHs = globPaths(hDir, "*.h", 0, true);
 25         vector<string> webotsHpps = globPaths(hppDir, "*.hpp", 0, true);
 26         FILE* file = fopen(getNewPath(webotsHomePath, "abc", "hpp", -1).c_str(), "w");
 27         //for (size_t k = 0; k < webotsHs.size(); ++k) fprintf(file, "#include <webots%s>\n", webotsHs[k].substr(hDir.size()).c_str()); //C
 28         for (size_t k = 0; k < webotsHpps.size(); ++k) fprintf(file, "#include <webots%s>\n", webotsHpps[k].substr(hppDir.size()).c_str());//CPP
 29         fclose(file);
 30     }
 31     static void createROSHPP(string rosHomePath = "/opt/ros/foxy/inclue")
 32     {
 33         //0.
 34         auto writeROSHPP = [](string modDir, int choice/*1=cur 2=msg 4=srv 8=action*/, FILE* file)->void
 35         {
 36             string modName = modDir.substr(modDir.find_last_of('/') + 1);
 37             string msgDir = modDir + "/msg";
 38             string srvDir = modDir + "/srv";
 39             string actionDir = modDir + "/action";
 40             vector<string> selfHeaders = cv::utils::fs::exists(modDir) && choice & 1 ? globPaths(modDir, "*.hpp", 0, false) : vector<string>();
 41             vector<string> msgHeaders = cv::utils::fs::exists(msgDir) && choice & 2 ? globPaths(msgDir, "*.hpp", 0, false) : vector<string>();
 42             vector<string> srvHeaders = cv::utils::fs::exists(srvDir) && choice & 4 ? globPaths(srvDir, "*.hpp", 0, false) : vector<string>();
 43             vector<string> actionHeaders = cv::utils::fs::exists(actionDir) && choice & 8 ? globPaths(actionDir, "*.hpp", 0, false) : vector<string>();
 44             vector<string> allHeaders = { "\n//" + modName + "\n" };
 45             for (size_t k = 0; k < selfHeaders.size(); ++k)
 46                 if (selfHeaders[k].find("__") == string::npos && selfHeaders[k].find("impl") == string::npos)
 47                     allHeaders.push_back("#include <" + modName + selfHeaders[k].substr(selfHeaders[k].find_last_of('/')) + ">\n");
 48             for (size_t k = 0; k < msgHeaders.size(); ++k)
 49                 if (msgHeaders[k].find("__") == string::npos && msgHeaders[k].find("impl") == string::npos)
 50                     allHeaders.push_back("#include <" + modName + "/msg" + msgHeaders[k].substr(msgHeaders[k].find_last_of('/')) + ">\n");
 51             for (size_t k = 0; k < srvHeaders.size(); ++k)
 52                 if (srvHeaders[k].find("__") == string::npos && srvHeaders[k].find("impl") == string::npos)
 53                     allHeaders.push_back("#include <" + modName + "/srv" + srvHeaders[k].substr(srvHeaders[k].find_last_of('/')) + ">\n");
 54             for (size_t k = 0; k < actionHeaders.size(); ++k)
 55                 if (actionHeaders[k].find("__") == string::npos && actionHeaders[k].find("impl") == string::npos)
 56                     allHeaders.push_back("#include <" + modName + "/action" + actionHeaders[k].substr(actionHeaders[k].find_last_of('/')) + ">\n");
 57             if (file != nullptr) for (size_t k = 0; k < allHeaders.size(); ++k) fprintf(file, allHeaders[k].c_str());
 58             //return allHeaders;
 59         };
 60         FILE* file = fopen(getNewPath(rosHomePath, "abc", "hpp", -1).c_str(), "w");
 61         rosHomePath += "/include";
 62 
 63         //1:Cores
 64         writeROSHPP(rosHomePath + "/ament_index_cpp", 1, file); //depend on env AMENT_PREFIX_PATH
 65         writeROSHPP(rosHomePath + "/rclcpp", 1, file);
 66         writeROSHPP(rosHomePath + "/rclcpp_action", 1, file);
 67 
 68         //2:Standards
 69         writeROSHPP(rosHomePath + "/std_msgs", 14, file);
 70         writeROSHPP(rosHomePath + "/std_srvs", 14, file);
 71         writeROSHPP(rosHomePath + "/builtin_interfaces", 14, file);
 72         writeROSHPP(rosHomePath + "/sensor_msgs", 15, file);
 73         writeROSHPP(rosHomePath + "/geometry_msgs", 14, file);
 74         writeROSHPP(rosHomePath + "/trajectory_msgs", 14, file);
 75         writeROSHPP(rosHomePath + "/move_base_msgs", 14, file);
 76         writeROSHPP(rosHomePath + "/stereo_msgs", 14, file);
 77         writeROSHPP(rosHomePath + "/shape_msgs", 14, file);
 78         writeROSHPP(rosHomePath + "/map_msgs", 14, file);
 79         writeROSHPP(rosHomePath + "/nav_msgs", 14, file);
 80         writeROSHPP(rosHomePath + "/visualization_msgs", 14, file);
 81 
 82         //3.Introspections
 83         writeROSHPP(rosHomePath + "/diagnostic_msgs", 14, file);
 84         writeROSHPP(rosHomePath + "/test_msgs", 14, file);
 85         writeROSHPP(rosHomePath + "/action_msgs", 14, file);
 86         writeROSHPP(rosHomePath + "/actionlib_msgs", 14, file);
 87         writeROSHPP(rosHomePath + "/lifecycle_msgs", 14, file);
 88         writeROSHPP(rosHomePath + "/rosgraph_msgs", 14, file);
 89         writeROSHPP(rosHomePath + "/pendulum_msgs", 14, file);
 90         writeROSHPP(rosHomePath + "/composition_interfaces", 14, file);
 91         writeROSHPP(rosHomePath + "/unique_identifier_msgs", 14, file);
 92 
 93         //4:SalientFields: TF2+URDF
 94         writeROSHPP(rosHomePath + "/tf2_msgs", 14, file);
 95         writeROSHPP(rosHomePath + "/tf2_sensor_msgs", 14, file);
 96         writeROSHPP(rosHomePath + "/tf2_geometry_msgs", 14, file);
 97 
 98         //
 99         fclose(file);
100     }
101 
102 public:
103     static vector<string> globPaths(string dir, string pattern = "*", int type = 0/*0=files 1=dirs 2=all*/, bool recursive = false)
104     {
105         if (cv::utils::fs::exists(dir) == false) return vector<string>();
106 
107         //1.Glob all paths including directories and files 
108         vector<string> srcPaths;
109         cv::utils::fs::glob(dir, pattern, srcPaths, recursive, true);
110         for (uint64 k = 0, pos = 0; k < srcPaths.size(); ++k)
111             for (uint64 ind = 0; ; ++ind)
112             {
113                 ind = srcPaths[k].find('\\', ind);
114                 if (ind != string::npos) srcPaths[k].replace(ind, 1, "/");
115                 else break;
116             }
117 
118         //2.Separate all paths into directories and files
119         vector<string> dirPaths, filePaths;
120         for (uint64 k = 0; k < srcPaths.size(); ++k) cv::utils::fs::isDirectory(srcPaths[k]) ? dirPaths.push_back(srcPaths[k]) : filePaths.push_back(srcPaths[k]);
121 
122         //3.Sort dirPaths and filePaths separately
123         if (dirPaths.size() > 1) stable_sort(dirPaths.begin(), dirPaths.end(), less<string>());
124         if (dirPaths.size() > 1) stable_sort(dirPaths.begin(), dirPaths.end(), [](string str1, string str2)->bool {return str1.length() < str2.length(); });
125         if (filePaths.size() > 1) stable_sort(filePaths.begin(), filePaths.end(), less<string>());
126         if (filePaths.size() > 1) stable_sort(filePaths.begin(), filePaths.end(), [](string str1, string str2)->bool {return str1.length() < str2.length(); });
127 
128         //4.Return specified paths
129         if (type == 0) return filePaths;
130         if (type == 1) return dirPaths;
131         if (type == 2) for (uint k = 0; k < dirPaths.size(); ++k) filePaths.push_back(dirPaths[k]);
132         return filePaths;
133     }
134     static string getNewPath(string dir, string basename, string extname = ""/*empty for dirPath*/, int64 initialId = -1/*refer to comments*/)
135     {
136         if (initialId >= 0)//e.g: if file0 file3 file5 file7 file9 exist, return file1 for initialId=0, file4 for initialId=3, file10 for initialId < = 0
137         {
138             string fullPath;
139             do
140             {
141                 fullPath = fmt::format("{}/{}{}{}", dir, basename, initialId, (extname.empty() ? extname : "." + extname));
142                 if (utils::fs::exists(fullPath) == false) break;
143             } while (++initialId);
144             return fullPath;
145         }
146         else
147         {
148             vector<string> paths = globPaths(dir, basename + "*", extname.empty() ? 1 : 0, false);
149             if (paths.empty()) return fmt::format("{}/{}{}{}", dir, basename, 0, (extname.empty() ? extname : "." + extname));
150             if (extname.empty())
151             {
152                 int64 ind = paths[paths.size() - 1].find(basename) + basename.length();
153                 int64 id = atoll(paths[paths.size() - 1].substr(ind).c_str()) + 1;
154                 return fmt::format("{}/{}{}", dir, basename, id);
155             }
156             else
157             {
158                 int64 ind1 = paths[paths.size() - 1].find(basename) + basename.length();
159                 int64 ind2 = paths[paths.size() - 1].find_last_of(".");
160                 int64 id = atoll(paths[paths.size() - 1].substr(ind1, ind2 - ind1).c_str()) + 1;
161                 return fmt::format("{}/{}{}.{}", dir, basename, id, extname);
162             }
163         }
164     }
165 };
166 
167 int main(int argc, char** argv)
168 {
169     ROS2WebotsHeaders::TestMe(argc, argv);
170     return 0;
171 }
View Code