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 }