diff --git a/CMakeLists.txt b/CMakeLists.txt index e9485e7..6e59982 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(odin_ros_driver) if(DEFINED BUILD_SYSTEM) set(ROS_VERSION ${BUILD_SYSTEM}) - message(STATUS "使用命令行指定的构建系统: ${ROS_VERSION}") + message(STATUS "ROS_VERSION: ${ROS_VERSION}") elseif(DEFINED ENV{ROS_DISTRO}) if("$ENV{ROS_DISTRO}" MATCHES "foxy|galactic|humble|iron|rolling") set(ROS_VERSION "ROS2") @@ -18,30 +18,30 @@ elseif(DEFINED ENV{ROS_VERSION}) set(ROS_VERSION "ROS1") endif() else() - # 尝试自动检测 + # Attempt automatic detection if(COMMAND catkin_package) set(ROS_VERSION "ROS1") elseif(COMMAND ament_package) set(ROS_VERSION "ROS2") else() - # 默认使用ROS2 + # Default to ROS2 set(ROS_VERSION "ROS2") - message(WARNING "无法确定ROS版本,默认使用ROS2") + message(WARNING "Unable to determine ROS version, defaulting to ROS2") endif() endif() -# 检测 ROS 版本后添加编译宏 +# Add compile definitions after detecting ROS version if(ROS_VERSION STREQUAL "ROS2") add_definitions(-DROS2) - message(STATUS "定义 ROS2 宏") + message(STATUS "Defining ROS2") else() add_definitions(-DROS1) - message(STATUS "定义 ROS1 宏") + message(STATUS "Defining ROS1") endif() -message(STATUS "构建系统: ${ROS_VERSION}") +message(STATUS "Build system: ${ROS_VERSION}") -# 平台检测 +# Platform detection execute_process( COMMAND uname -m OUTPUT_VARIABLE ARCH @@ -50,27 +50,27 @@ execute_process( if(ARCH STREQUAL "x86_64") set(TARGET_PLATFORM "x86") - message(STATUS "检测到 x86_64 架构") + message(STATUS "Detected x86_64 architecture") elseif(ARCH MATCHES "arm|aarch64") set(TARGET_PLATFORM "arm") - message(STATUS "检测到 ARM 架构: ${ARCH}") + message(STATUS "Detected ARM architecture: ${ARCH}") else() - message(WARNING "不支持的架构: ${ARCH}. 使用默认设置") + message(WARNING "Unsupported architecture: ${ARCH}. Using default settings") set(TARGET_PLATFORM "unknown") endif() -# 设置库路径 +# Set library path set(LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lib") -message(STATUS "库目录: ${LIB_DIR}") +message(STATUS "Library directory: ${LIB_DIR}") -# 根据平台设置库名称 +# Set library name based on platform if(TARGET_PLATFORM STREQUAL "arm") set(LYD_HOST_API_LIB_NAME "lydHostApi_arm") else() set(LYD_HOST_API_LIB_NAME "lydHostApi_amd") endif() -# 查找预编译的 lydHostApi 库 +# Find precompiled lydHostApi library find_library(LYD_HOST_API_LIB NAMES ${LYD_HOST_API_LIB_NAME} @@ -81,22 +81,22 @@ find_library(LYD_HOST_API_LIB ) if(LYD_HOST_API_LIB) - message(STATUS "找到 lydHostApi 库: ${LYD_HOST_API_LIB}") + message(STATUS "Found lydHostApi library: ${LYD_HOST_API_LIB}") else() file(GLOB LIB_FILES "${LIB_DIR}/lib${LYD_HOST_API_LIB_NAME}.*") if(LIB_FILES) - message(STATUS "找到库文件: ${LIB_FILES}") + message(STATUS "Found library files: ${LIB_FILES}") set(LYD_HOST_API_LIB ${LIB_FILES}) else() - message(FATAL_ERROR "在 ${LIB_DIR} 中找不到预编译的 lydHostApi 库") + message(FATAL_ERROR "Could not find precompiled lydHostApi library in ${LIB_DIR}") endif() endif() -# 设置公共编译选项 +# Set common compile options set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) -# 公共依赖查找 +# Find common dependencies find_package(PkgConfig REQUIRED) find_package(OpenCV REQUIRED COMPONENTS core imgproc highgui) find_package(Eigen3 REQUIRED) @@ -104,7 +104,7 @@ find_package(yaml-cpp REQUIRED) find_package(OpenSSL REQUIRED) pkg_check_modules(LIBUSB REQUIRED libusb-1.0) -# 共享包含目录 +# Shared include directories include_directories( include ${EIGEN3_INCLUDE_DIRS} @@ -114,7 +114,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/include ) -# 共享链接库列表 +# Shared library list set(COMMON_LIBS ${OpenCV_LIBS} ${yaml-cpp_LIBRARIES} @@ -126,9 +126,9 @@ set(COMMON_LIBS ${LYD_HOST_API_LIB} ) -# ===== ROS1 专属配置 ===== +# ===== ROS1 Configuration ===== if(ROS_VERSION STREQUAL "ROS1") - message(STATUS "配置为 ROS1 构建") + message(STATUS "Configuring for ROS1 build") find_package(catkin REQUIRED COMPONENTS roscpp @@ -146,7 +146,7 @@ if(ROS_VERSION STREQUAL "ROS1") INCLUDE_DIRS include ) - # 设置输出目录 + # Set output directories set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/lib/${PROJECT_NAME}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CATKIN_DEVEL_PREFIX}/lib) @@ -166,7 +166,7 @@ if(ROS_VERSION STREQUAL "ROS1") usb-1.0 ) - # 安装规则 + # Installation rules install(TARGETS host_sdk_sample RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} ) @@ -181,11 +181,11 @@ if(ROS_VERSION STREQUAL "ROS1") ) endif() -# ===== ROS2 配置 ===== +# ===== ROS2 Configuration ===== elseif(ROS_VERSION STREQUAL "ROS2") - message(STATUS "配置为 ROS2 构建") + message(STATUS "Configuring for ROS2 build") - # 查找所有必要的ROS2包 + # Find all necessary ROS2 packages find_package(ament_cmake REQUIRED) find_package(rclcpp REQUIRED) find_package(std_msgs REQUIRED) @@ -194,13 +194,13 @@ elseif(ROS_VERSION STREQUAL "ROS2") find_package(cv_bridge REQUIRED) find_package(image_transport REQUIRED) - # 创建可执行文件 + # Create executable add_executable(host_sdk_sample src/host_sdk_sample.cpp src/yaml_parser.cpp ) - # 链接库 + # Link libraries target_link_libraries(host_sdk_sample ${catkin_LIBRARIES} ${COMMON_LIBS} @@ -208,7 +208,7 @@ elseif(ROS_VERSION STREQUAL "ROS2") usb-1.0 ) - # 添加ROS2依赖 + # Add ROS2 dependencies ament_target_dependencies(host_sdk_sample rclcpp std_msgs @@ -218,8 +218,8 @@ elseif(ROS_VERSION STREQUAL "ROS2") image_transport ) - # 安装规则 - 确保所有安装目标在 ament_package() 之前定义 - # 安装可执行文件 + # Installation rules - ensure all install targets are defined before ament_package() + # Install executable install(TARGETS host_sdk_sample EXPORT export_${PROJECT_NAME} ARCHIVE DESTINATION lib @@ -227,39 +227,39 @@ elseif(ROS_VERSION STREQUAL "ROS2") RUNTIME DESTINATION lib/${PROJECT_NAME} ) - # 安装 package.xml + # Install package.xml install(FILES package.xml DESTINATION share/${PROJECT_NAME} ) - # 安装头文件 + # Install headers install(DIRECTORY include/ DESTINATION include ) - # 安装 launch_ROS2 目录 + # Install launch_ROS2 directory if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/launch_ROS2") install(DIRECTORY launch_ROS2/ DESTINATION share/${PROJECT_NAME}/launch ) - message(STATUS "安装 launch_ROS2 目录到 share/${PROJECT_NAME}/launch") + message(STATUS "Installing launch_ROS2 directory to share/${PROJECT_NAME}/launch") else() - message(WARNING "未找到 launch_ROS2 目录") + message(WARNING "launch_ROS2 directory not found") endif() - # 安装配置文件 (如果存在) + # Install config files if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/config") install(DIRECTORY config/ DESTINATION share/${PROJECT_NAME}/config ) endif() - # 安装启动文件 (如果存在) + # Install launch files if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/launch") install(DIRECTORY launch/ DESTINATION share/${PROJECT_NAME}/launch ) endif() ament_export_targets(export_${PROJECT_NAME}) - # 声明依赖 + # Declare dependencies ament_export_dependencies( rclcpp std_msgs @@ -269,28 +269,25 @@ elseif(ROS_VERSION STREQUAL "ROS2") image_transport ) - # 可选的lint检查 - - # 完成包配置 - 必须在所有安装规则之后调用 ament_package() - message(STATUS "安装目标已添加") + message(STATUS "Install targets added") else() - message(FATAL_ERROR "无效的 ROS_VERSION: ${ROS_VERSION}") + message(FATAL_ERROR "Invalid ROS_VERSION: ${ROS_VERSION}") endif() -# ARM平台特定的链接选项 +# ARM platform specific link options if(TARGET_PLATFORM STREQUAL "arm") set_target_properties(host_sdk_sample PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -Wl,--rpath=${LIB_DIR}" ) - message(STATUS "添加 ARM 特定的链接选项和 RPATH") + message(STATUS "Adding ARM-specific link options and RPATH") endif() -# 添加调试信息 +# Add debug information message(STATUS "=======================================") message(STATUS "Project: ${PROJECT_NAME}") -message(STATUS "ROS 版本: ${ROS_VERSION}") +message(STATUS "ROS_VERSION: ${ROS_VERSION}") message(STATUS "Target platform: ${TARGET_PLATFORM}") message(STATUS "lydHostApi library: ${LYD_HOST_API_LIB}") message(STATUS "libusb library: ${LIBUSB_LIBRARIES}") diff --git a/README.md b/README.md index 7d328f5..03b1b7c 100644 --- a/README.md +++ b/README.md @@ -67,13 +67,17 @@ sudo apt-get install libopencv-dev ``` #### 2.3.4 ROS install -```shell -#Installation method -For ROS Melodic installation, please refer to: ROS Melodic installation instructions -For ROS Noetic installation, please refer to: ROS Noetic installation instructions -For ROS2 Foxy installation, please refer to: ROS Foxy installation instructions -For ROS2 Humble installation, please refer to: ROS Humble installation instructions -``` +For ROS Melodic installation, please refer to: +[ROS Melodic installation instructions](https://wiki.ros.org/melodic/Installation) + +For ROS Noetic installation, please refer to: +[ROS Noetic installation instructions](https://wiki.ros.org/noetic/Installation) + +For ROS2 Foxy installation, please refer to: +[ROS Foxy installation instructions](https://docs.ros.org/en/foxy/Installation/Ubuntu-Install-Debians.html) + +For ROS2 Humble installation, please refer to: +[ROS Humble installation instructions](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html) ## 3. Preparation @@ -83,7 +87,7 @@ sudo vim /etc/udev/rules.d/99-odin-usb.rules ``` Add the following content to the 99-odin-usb.rules file ```shell -SUBSYSTEM=="usb", ATTR{idVendor}=="2207", ATTR{idProduct}=="0019", MODE="0666", GROUP="plugdev +SUBSYSTEM=="usb", ATTR{idVendor}=="2207", ATTR{idProduct}=="0019", MODE="0666", GROUP="plugdev" ``` Reload rules and reinsert devices ```shell diff --git a/config/odin_ros.rviz b/config/odin_ros.rviz new file mode 100644 index 0000000..26017f0 --- /dev/null +++ b/config/odin_ros.rviz @@ -0,0 +1,222 @@ +Panels: + - Class: rviz/Displays + Help Height: 78 + Name: Displays + Property Tree Widget: + Expanded: ~ + Splitter Ratio: 0.5 + Tree Height: 489 + - Class: rviz/Selection + Name: Selection + - Class: rviz/Tool Properties + Expanded: + - /2D Pose Estimate1 + - /2D Nav Goal1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz/Time + Name: Time + SyncMode: 0 + SyncSource: Image +Preferences: + PromptSaveOnExit: true +Toolbars: + toolButtonStyle: 2 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: + Value: true + - Class: rviz/Image + Enabled: true + Image Topic: /odin1/image + Max Value: 1 + Median window: 5 + Min Value: 0 + Name: Image + Normalize Range: true + Queue Size: 2 + Transport Hint: raw + Unreliable: false + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: PointCloud2 + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Flat Squares + Topic: /odin1/cloud_raw + Unreliable: false + Use Fixed Frame: true + Use rainbow: true + Value: false + - Angle Tolerance: 0.10000000149011612 + Class: rviz/Odometry + Covariance: + Orientation: + Alpha: 0.5 + Color: 255; 255; 127 + Color Style: Unique + Frame: Local + Offset: 1 + Scale: 1 + Value: true + Position: + Alpha: 0.30000001192092896 + Color: 204; 51; 204 + Scale: 1 + Value: true + Value: false + Enabled: true + Keep: 1 + Name: Odometry + Position Tolerance: 0.10000000149011612 + Queue Size: 100 + Shape: + Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Color: 255; 25; 0 + Head Length: 0.30000001192092896 + Head Radius: 0.10000000149011612 + Shaft Length: 1 + Shaft Radius: 0.05000000074505806 + Value: Axes + Topic: /odin1/odometry_map + Unreliable: false + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz/PointCloud2 + Color: 255; 255; 255 + Color Transformer: RGB8 + Decay Time: 0 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Min Color: 0; 0; 0 + Name: PointCloud2 + Position Transformer: XYZ + Queue Size: 10 + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Points + Topic: /odin1/cloud_slam + Unreliable: false + Use Fixed Frame: true + Use rainbow: false + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Default Light: true + Fixed Frame: map + Frame Rate: 30 + Name: root + Tools: + - Class: rviz/Interact + Hide Inactive Objects: true + - Class: rviz/MoveCamera + - Class: rviz/Select + - Class: rviz/FocusCamera + - Class: rviz/Measure + - Class: rviz/SetInitialPose + Theta std deviation: 0.2617993950843811 + Topic: /initialpose + X std deviation: 0.5 + Y std deviation: 0.5 + - Class: rviz/SetGoal + Topic: /move_base_simple/goal + - Class: rviz/PublishPoint + Single click: true + Topic: /clicked_point + Value: true + Views: + Current: + Class: rviz/Orbit + Distance: 10.812461853027344 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Field of View: 0.7853981852531433 + Focal Point: + X: -0.4511165916919708 + Y: -0.1217871829867363 + Z: 0.8345625996589661 + Focal Shape Fixed Size: true + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.830398678779602 + Target Frame: + Yaw: 3.0054032802581787 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 1029 + Hide Left Dock: false + Hide Right Dock: false + Image: + collapsed: false + QMainWindow State: 000000ff00000000fd00000004000000000000015600000367fc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d00000274000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006501000002b7000000ed0000001600ffffff000000010000010f00000367fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d00000367000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000007800000003efc0100000002fb0000000800540069006d00650100000000000007800000033700fffffffb0000000800540069006d006501000000000000045000000000000000000000050f0000036700000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 1920 + X: 0 + Y: 27 diff --git a/config/odin_ros2.rviz b/config/odin_ros2.rviz new file mode 100644 index 0000000..466414f --- /dev/null +++ b/config/odin_ros2.rviz @@ -0,0 +1,248 @@ +Panels: + - Class: rviz_common/Displays + Help Height: 78 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Status1 + - /PointCloud21 + - /PointCloud22 + - /Image1 + - /Image1/Topic1 + - /Odometry1 + Splitter Ratio: 0.5 + Tree Height: 472 + - Class: rviz_common/Selection + Name: Selection + - Class: rviz_common/Tool Properties + Expanded: + - /2D Goal Pose1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz_common/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz_default_plugins/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz_default_plugins/PointCloud2 + Color: 255; 255; 255 + Color Transformer: RGB8 + Decay Time: 0 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Max Intensity: 4096 + Min Color: 0; 0; 0 + Min Intensity: 0 + Name: PointCloud2 + Position Transformer: XYZ + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Flat Squares + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /odin1/cloud_slam + Use Fixed Frame: true + Use rainbow: true + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz_default_plugins/PointCloud2 + Color: 255; 255; 255 + Color Transformer: "" + Decay Time: 0 + Enabled: false + Invert Rainbow: false + Max Color: 255; 255; 255 + Max Intensity: 4096 + Min Color: 0; 0; 0 + Min Intensity: 0 + Name: PointCloud2 + Position Transformer: "" + Selectable: true + Size (Pixels): 3 + Size (m): 0.009999999776482582 + Style: Flat Squares + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /odin1/cloud_raw + Use Fixed Frame: true + Use rainbow: true + Value: false + - Class: rviz_default_plugins/Image + Enabled: true + Max Value: 1 + Median window: 5 + Min Value: 0 + Name: Image + Normalize Range: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /odin1/image + Value: true + - Angle Tolerance: 0.10000000149011612 + Class: rviz_default_plugins/Odometry + Covariance: + Orientation: + Alpha: 0.5 + Color: 255; 255; 127 + Color Style: Unique + Frame: Local + Offset: 1 + Scale: 1 + Value: true + Position: + Alpha: 0.30000001192092896 + Color: 204; 51; 204 + Scale: 1 + Value: true + Value: true + Enabled: true + Keep: 100 + Name: Odometry + Position Tolerance: 0.10000000149011612 + Shape: + Alpha: 1 + Axes Length: 1 + Axes Radius: 0.10000000149011612 + Color: 255; 25; 0 + Head Length: 0.30000001192092896 + Head Radius: 0.10000000149011612 + Shaft Length: 1 + Shaft Radius: 0.05000000074505806 + Value: Axes + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /odin1/odometry_map + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Fixed Frame: map + Frame Rate: 30 + Name: root + Tools: + - Class: rviz_default_plugins/Interact + Hide Inactive Objects: true + - Class: rviz_default_plugins/MoveCamera + - Class: rviz_default_plugins/Select + - Class: rviz_default_plugins/FocusCamera + - Class: rviz_default_plugins/Measure + Line color: 128; 128; 0 + - Class: rviz_default_plugins/SetInitialPose + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /initialpose + - Class: rviz_default_plugins/SetGoal + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /goal_pose + - Class: rviz_default_plugins/PublishPoint + Single click: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /clicked_point + Transformation: + Current: + Class: rviz_default_plugins/TF + Value: true + Views: + Current: + Class: rviz_default_plugins/Orbit + Distance: 10.72309398651123 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Focal Point: + X: 0 + Y: 0 + Z: 0 + Focal Shape Fixed Size: false + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.7503987550735474 + Target Frame: + Value: Orbit (rviz) + Yaw: 2.205399513244629 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 1029 + Hide Left Dock: false + Hide Right Dock: false + Image: + collapsed: false + QMainWindow State: 000000ff00000000fd000000040000000000000242000003abfc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d00000263000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006501000002a6000001420000002800ffffff000000010000010f000003abfc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000003ab000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d0065010000000000000450000000000000000000000423000003ab00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 1920 + X: 0 + Y: 27 \ No newline at end of file diff --git a/include/host_sdk_sample.h b/include/host_sdk_sample.h index 7faedbe..34a5d21 100644 --- a/include/host_sdk_sample.h +++ b/include/host_sdk_sample.h @@ -67,14 +67,14 @@ limitations under the License. } #endif -// 公共定义 +// Common definitions #define GD_ACCL_G 9.7833f #define ACC_1G_ms2 9.8 #define ACC_SEN_SCALE 16348 #define PAI 3.14159265358979323846 #define GYRO_SEN_SCALE 32.8f -// 公共函数 +// Common functions inline float accel_convert(int16_t raw, int sen_scale) { return (raw * GD_ACCL_G / sen_scale); } @@ -103,7 +103,7 @@ inline uint64_t ros_time_to_ns(const ros::Time &t) { #endif } -// 多传感器发布器类 +// Multi-sensor publisher class class MultiSensorPublisher { public: #ifdef ROS2 @@ -147,9 +147,9 @@ public: #endif } -void publishIntensityCloud(capture_Image_List_t* stream, int idx) -{ - #ifdef ROS2 + void publishIntensityCloud(capture_Image_List_t* stream, int idx) + { + #ifdef ROS2 sensor_msgs::msg::PointCloud2 msg; msg.header.frame_id = "map"; msg.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp); @@ -172,63 +172,63 @@ void publishIntensityCloud(capture_Image_List_t* stream, int idx) sensor_msgs::PointCloud2Iterator iter_y(msg, "y"); sensor_msgs::PointCloud2Iterator iter_z(msg, "z"); sensor_msgs::PointCloud2Iterator iter_intensity(msg, "intensity"); - #else - sensor_msgs::PointCloud2 msg; - msg.header.frame_id = "map"; - msg.header.stamp = ros::Time::now(); // ROS1使用全局时间 - msg.height = stream->imageList[idx].height; - msg.width = stream->imageList[idx].width; - msg.is_dense = false; - msg.is_bigendian = false; - - sensor_msgs::PointCloud2Modifier modifier(msg); - modifier.setPointCloud2Fields( - 4, - "x", 1, sensor_msgs::PointField::FLOAT32, - "y", 1, sensor_msgs::PointField::FLOAT32, - "z", 1, sensor_msgs::PointField::FLOAT32, - "intensity", 1, sensor_msgs::PointField::UINT8 - ); - modifier.resize(msg.height * msg.width); - - sensor_msgs::PointCloud2Iterator iter_x(msg, "x"); - sensor_msgs::PointCloud2Iterator iter_y(msg, "y"); - sensor_msgs::PointCloud2Iterator iter_z(msg, "z"); - sensor_msgs::PointCloud2Iterator iter_intensity(msg, "intensity"); - #endif - - float* xyz_data = static_cast(stream->imageList[idx].pAddr); - uint16_t* intensity_data = static_cast(stream->imageList[2].pAddr); - - int total_points = stream->imageList[idx].height * stream->imageList[idx].width; - for (int i = 0; i < total_points; ++i) { - float* pf = xyz_data + i * 4; - - #ifdef ROS2 - *iter_x = pf[2] / 1000.0f; ++iter_x; - *iter_y = pf[0] / 1000.0f; ++iter_y; - *iter_z = -pf[1] / 1000.0f; ++iter_z; - *iter_intensity = static_cast(intensity_data[i] >> 8); ++iter_intensity; #else - *iter_x = pf[2] / 1000.0f; ++iter_x; - *iter_y = pf[0] / 1000.0f; ++iter_y; - *iter_z = -pf[1] / 1000.0f; ++iter_z; - *iter_intensity = static_cast(intensity_data[i] >> 8); ++iter_intensity; + sensor_msgs::PointCloud2 msg; + msg.header.frame_id = "map"; + msg.header.stamp = ros::Time::now(); + msg.height = stream->imageList[idx].height; + msg.width = stream->imageList[idx].width; + msg.is_dense = false; + msg.is_bigendian = false; + + sensor_msgs::PointCloud2Modifier modifier(msg); + modifier.setPointCloud2Fields( + 4, + "x", 1, sensor_msgs::PointField::FLOAT32, + "y", 1, sensor_msgs::PointField::FLOAT32, + "z", 1, sensor_msgs::PointField::FLOAT32, + "intensity", 1, sensor_msgs::PointField::UINT8 + ); + modifier.resize(msg.height * msg.width); + + sensor_msgs::PointCloud2Iterator iter_x(msg, "x"); + sensor_msgs::PointCloud2Iterator iter_y(msg, "y"); + sensor_msgs::PointCloud2Iterator iter_z(msg, "z"); + sensor_msgs::PointCloud2Iterator iter_intensity(msg, "intensity"); + #endif + + float* xyz_data = static_cast(stream->imageList[idx].pAddr); + uint16_t* intensity_data = static_cast(stream->imageList[2].pAddr); + + int total_points = stream->imageList[idx].height * stream->imageList[idx].width; + for (int i = 0; i < total_points; ++i) { + float* pf = xyz_data + i * 4; + + #ifdef ROS2 + *iter_x = pf[2] / 1000.0f; ++iter_x; + *iter_y = -pf[0] / 1000.0f; ++iter_y; + *iter_z = pf[1] / 1000.0f; ++iter_z; + *iter_intensity = static_cast(intensity_data[i] >> 8); ++iter_intensity; + #else + *iter_x = pf[2] / 1000.0f; ++iter_x; + *iter_y = -pf[0] / 1000.0f; ++iter_y; + *iter_z = pf[1] / 1000.0f; ++iter_z; + *iter_intensity = static_cast(intensity_data[i] >> 8); ++iter_intensity; + #endif + } + + // Publish Intensity point cloud + #ifdef ROS2 + cloud_pub_->publish(std::move(msg)); + #else + cloud_pub_.publish(msg); #endif } - // 发布点云 - #ifdef ROS2 - cloud_pub_->publish(std::move(msg)); - #else - cloud_pub_.publish(msg); - #endif -} - void publishRgb(capture_Image_List_t *stream) { buffer_List_t &image = stream->imageList[0]; - // 验证图像参数 + // Validate image parameters if (!image.pAddr) { #ifdef ROS2 RCLCPP_ERROR(node_->get_logger(), "Invalid RGB image: null data pointer"); @@ -247,10 +247,10 @@ void publishIntensityCloud(capture_Image_List_t* stream, int idx) return; } - // 计算 NV12 图像高度 + // Calculate NV12 image height const int height_nv12 = image.height * 3 / 2; - // 验证 NV12 图像尺寸 + // Validate NV12 image size const size_t expected_size = static_cast(image.width) * height_nv12; if (image.length < expected_size) { #ifdef ROS2 @@ -312,103 +312,103 @@ void publishIntensityCloud(capture_Image_List_t* stream, int idx) } } -void publishPC2XYZRGBA(capture_Image_List_t* stream, int idx) -{ - static int flag = 1; - #ifdef ROS2 - sensor_msgs::msg::PointCloud2 msg; - // msg.header.frame_id = "base_link"; + void publishPC2XYZRGBA(capture_Image_List_t* stream, int idx) + { + static int flag = 1; + #ifdef ROS2 + sensor_msgs::msg::PointCloud2 msg; + // msg.header.frame_id = "base_link"; + msg.header.frame_id = "map"; + msg.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp); + // msg.header.stamp = this->now(); + size_t pt_size = sizeof(int32_t) * 3 + sizeof(int32_t) * 4; + uint32_t points = stream->imageList[idx].length / pt_size; + + msg.height = 1; + msg.width = points; + msg.is_dense = false; + // LOG_INFO("msg.height=%ld, msg.width=%ld.\n", msg.height, msg.width); + + sensor_msgs::PointCloud2Modifier modifier(msg); + modifier.setPointCloud2Fields( + 4, + "x", 1, sensor_msgs::msg::PointField::FLOAT32, + "y", 1, sensor_msgs::msg::PointField::FLOAT32, + "z", 1, sensor_msgs::msg::PointField::FLOAT32, + "rgb", 1, sensor_msgs::msg::PointField::FLOAT32 + ); + modifier.resize(msg.width * msg.height); + + sensor_msgs::PointCloud2Iterator iter_x(msg, "x"); + sensor_msgs::PointCloud2Iterator iter_y(msg, "y"); + sensor_msgs::PointCloud2Iterator iter_z(msg, "z"); + sensor_msgs::PointCloud2Iterator iter_rgb(msg, "rgb"); + #else + sensor_msgs::PointCloud2 msg; msg.header.frame_id = "map"; msg.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp); - // msg.header.stamp = this->now(); + size_t pt_size = sizeof(int32_t) * 3 + sizeof(int32_t) * 4; uint32_t points = stream->imageList[idx].length / pt_size; - + msg.height = 1; msg.width = points; msg.is_dense = false; - // LOG_INFO("msg.height=%ld, msg.width=%ld.\n", msg.height, msg.width); - + sensor_msgs::PointCloud2Modifier modifier(msg); modifier.setPointCloud2Fields( 4, - "x", 1, sensor_msgs::msg::PointField::FLOAT32, - "y", 1, sensor_msgs::msg::PointField::FLOAT32, - "z", 1, sensor_msgs::msg::PointField::FLOAT32, - "rgb", 1, sensor_msgs::msg::PointField::FLOAT32 + "x", 1, sensor_msgs::PointField::FLOAT32, + "y", 1, sensor_msgs::PointField::FLOAT32, + "z", 1, sensor_msgs::PointField::FLOAT32, + "rgb", 1, sensor_msgs::PointField::FLOAT32 ); modifier.resize(msg.width * msg.height); - + sensor_msgs::PointCloud2Iterator iter_x(msg, "x"); sensor_msgs::PointCloud2Iterator iter_y(msg, "y"); sensor_msgs::PointCloud2Iterator iter_z(msg, "z"); sensor_msgs::PointCloud2Iterator iter_rgb(msg, "rgb"); - #else - sensor_msgs::PointCloud2 msg; - msg.header.frame_id = "map"; - msg.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp); - - size_t pt_size = sizeof(int32_t) * 3 + sizeof(int32_t) * 4; - uint32_t points = stream->imageList[idx].length / pt_size; - - msg.height = 1; - msg.width = points; - msg.is_dense = false; - - sensor_msgs::PointCloud2Modifier modifier(msg); - modifier.setPointCloud2Fields( - 4, - "x", 1, sensor_msgs::PointField::FLOAT32, - "y", 1, sensor_msgs::PointField::FLOAT32, - "z", 1, sensor_msgs::PointField::FLOAT32, - "rgb", 1, sensor_msgs::PointField::FLOAT32 - ); - modifier.resize(msg.width * msg.height); - - sensor_msgs::PointCloud2Iterator iter_x(msg, "x"); - sensor_msgs::PointCloud2Iterator iter_y(msg, "y"); - sensor_msgs::PointCloud2Iterator iter_z(msg, "z"); - sensor_msgs::PointCloud2Iterator iter_rgb(msg, "rgb"); - #endif - - // 共享的数据处理逻辑 - int32_t* xyz_data = static_cast(stream->imageList[idx].pAddr); - - for(uint32_t i = 0; i < points; i++) { - int32_t* ptr = xyz_data + 7*i; - - #ifdef ROS2 - *iter_x = static_cast(ptr[0]) / 10000.0f; ++iter_x; - *iter_y = static_cast(ptr[1]) / 10000.0f; ++iter_y; - *iter_z = static_cast(ptr[2]) / 10000.0f; ++iter_z; - #else - *iter_x = (1.0 * ptr[0]) / 1e4; ++iter_x; - *iter_y = (1.0 * ptr[1]) / 1e4; ++iter_y; - *iter_z = (1.0 * ptr[2]) / 1e4; ++iter_z; #endif - uint8_t r = ptr[3] & 0xff; - uint8_t g = ptr[4] & 0xff; - uint8_t b = ptr[5] & 0xff; + // Shared data processing logic + int32_t* xyz_data = static_cast(stream->imageList[idx].pAddr); - uint32_t packed_rgb = (static_cast(r) << 16) | - (static_cast(g) << 8) | - static_cast(b); + for(uint32_t i = 0; i < points; i++) { + int32_t* ptr = xyz_data + 7*i; + + #ifdef ROS2 + *iter_x = static_cast(ptr[0]) / 10000.0f; ++iter_x; + *iter_y = static_cast(ptr[1]) / 10000.0f; ++iter_y; + *iter_z = static_cast(ptr[2]) / 10000.0f; ++iter_z; + #else + *iter_x = (1.0 * ptr[0]) / 1e4; ++iter_x; + *iter_y = (1.0 * ptr[1]) / 1e4; ++iter_y; + *iter_z = (1.0 * ptr[2]) / 1e4; ++iter_z; + #endif + + uint8_t r = ptr[3] & 0xff; + uint8_t g = ptr[4] & 0xff; + uint8_t b = ptr[5] & 0xff; + + uint32_t packed_rgb = (static_cast(r) << 16) | + (static_cast(g) << 8) | + static_cast(b); + + float rgb_float; + std::memcpy(&rgb_float, &packed_rgb, sizeof(float)); + + *iter_rgb = rgb_float; ++iter_rgb; + } - float rgb_float; - std::memcpy(&rgb_float, &packed_rgb, sizeof(float)); - - *iter_rgb = rgb_float; ++iter_rgb; + #ifdef ROS2 + flag = 0; // Preserve assignment if flag is used elsewhere + xyzrgbacloud_pub_->publish(std::move(msg)); + #else + flag = 0; + xyzrgbacloud_pub_.publish(msg); + #endif } - - #ifdef ROS2 - flag = 0; // 如果flag在其他地方使用,保留赋值 - xyzrgbacloud_pub_->publish(std::move(msg)); - #else - flag = 0; - xyzrgbacloud_pub_.publish(msg); - #endif -} void publishOdometry(capture_Image_List_t* stream) { ros2_odom_convert_t* odom_data = (ros2_odom_convert_t*)stream->imageList[0].pAddr; @@ -476,7 +476,6 @@ private: #endif }; -// 命令行控制类 class CommandLineControl { public: using Callback = std::function; @@ -539,7 +538,6 @@ private: }; -// 控制命令定义 #define STREAMCTRL "streamctrl" /* start/stop all streams */ #define SENDRGB "sendrgb" /* send RGB data */ #define SENDIMU "sendimu" /* send IMU data */ diff --git a/include/yaml_parser.h b/include/yaml_parser.h index 887c980..4cf055f 100644 --- a/include/yaml_parser.h +++ b/include/yaml_parser.h @@ -21,7 +21,6 @@ namespace odin_ros_driver { class YamlParser { public: - // 使用一致的成员变量名 YamlParser(const std::string& config_file); bool loadConfig(); @@ -33,6 +32,6 @@ private: std::map register_keys_; }; -} // namespace odin_ros_driver +} -#endif // YAML_PARSER_H \ No newline at end of file +#endif \ No newline at end of file diff --git a/launch_ROS1/odin1_ros1.launch b/launch_ROS1/odin1_ros1.launch index d978903..3567825 100644 --- a/launch_ROS1/odin1_ros1.launch +++ b/launch_ROS1/odin1_ros1.launch @@ -1,12 +1,22 @@ - + - + + + + + + + + - + + + + \ No newline at end of file diff --git a/launch_ROS2/odin1_ros2.launch.py b/launch_ROS2/odin1_ros2.launch.py index a7e1301..c210624 100644 --- a/launch_ROS2/odin1_ros2.launch.py +++ b/launch_ROS2/odin1_ros2.launch.py @@ -1,5 +1,5 @@ -#用法: ros2 launch odin_ros_driver odin1_ros2.launch.py +# USAGE: ros2 launch odin_ros_driver odin1_ros2.launch.py import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription @@ -8,17 +8,24 @@ from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node def generate_launch_description(): - # 获取包目录 + # Get package directory package_dir = get_package_share_directory('odin_ros_driver') - # 声明配置参数 + # Declare configuration parameter config_file_arg = DeclareLaunchArgument( 'config_file', default_value=os.path.join(package_dir, 'config', 'control_command.yaml'), description='Path to the control config YAML file' ) - # 创建节点 + # Add RViz2 configuration file parameter + rviz_config_arg = DeclareLaunchArgument( + 'rviz_config', + default_value=os.path.join(package_dir, 'config', 'odin_ros2.rviz'), + description='Path to RViz2 config file' + ) + + # Create main node host_sdk_node = Node( package='odin_ros_driver', executable='host_sdk_sample', @@ -30,9 +37,20 @@ def generate_launch_description(): }] ) - # 创建启动描述 + # Create RViz2 node - loads specified configuration file + rviz_node = Node( + package='rviz2', + executable='rviz2', + name='rviz2', + output='screen', + arguments=['-d', LaunchConfiguration('rviz_config')] + ) + + # Create launch description ld = LaunchDescription() ld.add_action(config_file_arg) + ld.add_action(rviz_config_arg) # Add RViz configuration argument ld.add_action(host_sdk_node) + ld.add_action(rviz_node) # Add RViz node - return ld + return ld \ No newline at end of file diff --git a/package_ros1.xml b/package_ros1.xml index 92c28a1..17f851d 100644 --- a/package_ros1.xml +++ b/package_ros1.xml @@ -6,10 +6,10 @@ rlk Apache 2.0 - + catkin - + roscpp std_msgs sensor_msgs @@ -17,12 +17,12 @@ cv_bridge image_transport - + eigen opencv yaml-cpp - + catkin diff --git a/package_ros2.xml b/package_ros2.xml index 5d5f028..a4a45ab 100644 --- a/package_ros2.xml +++ b/package_ros2.xml @@ -5,17 +5,17 @@ ROS2 driver for Odin sensor rlk Apache 2.0 - + ament_cmake - + rclcpp - + std_msgs sensor_msgs nav_msgs cv_bridge image_transport - + ament_cmake diff --git a/script/build_ros.sh b/script/build_ros.sh index 56479ab..28218ad 100644 --- a/script/build_ros.sh +++ b/script/build_ros.sh @@ -1,117 +1,117 @@ #!/bin/bash -# 获取脚本所在目录(Odin_ROS_Driver 目录) +# Get the directory where the script is located (Odin_ROS_Driver directory) PKG_DIR="$(cd "$(dirname "$0")/.."; pwd)" -# 计算工作空间根目录(包含 devel、build、src 的目录) +# Calculate the workspace root directory (contains devel, build, src) WORKSPACE_ROOT="$(dirname "$(dirname "$PKG_DIR")")" -# 工作空间源码目录(包含所有包的 src) +# Workspace source directory (contains all packages) WORKSPACE_SRC="${WORKSPACE_ROOT}/src" PROJECT_NAME="odin_ros_driver" -# 定义颜色代码 +# Define color codes RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' -NC='\033[0m' # 无颜色 +NC='\033[0m' -# 清理函数 +# Clean workspace function clean_workspace() { - echo -e "${YELLOW}🧹 清理构建目录${NC}" + echo -e "${YELLOW}Cleaning build directories${NC}" - # 清理工作空间根目录下的构建产物 + # Clean build artifacts in workspace rm -rf "${WORKSPACE_ROOT}/build" rm -rf "${WORKSPACE_ROOT}/install" rm -rf "${WORKSPACE_ROOT}/log" rm -rf "${WORKSPACE_ROOT}/devel" - echo -e "${GREEN}✅ 清理完成${NC}" + echo -e "${GREEN}Cleanup complete${NC}" } -# 运行函数 +# Run node function run_node() { - echo -e "${YELLOW}🏃‍♂️‍➡️ 运行 ROS1 节点${NC}" + echo -e "${YELLOW}Running ROS1 node${NC}" - # 检查环境文件是否存在 + # Check if environment file exists if [ ! -f "${WORKSPACE_ROOT}/devel/setup.bash" ]; then - echo -e "${RED}❌ 找不到 devel/setup.bash,请先执行 ./build_ros1.sh 构建项目${NC}" + echo -e "${RED}Could not find devel/setup.bash, please build the project with ./build_ros1.sh first${NC}" return 1 fi - # Source 环境并运行节点 + # Source environment and run node source "${WORKSPACE_ROOT}/devel/setup.bash" } -# 构建函数 +# Build workspace function build_workspace() { - echo -e "${YELLOW}🔍 工作空间结构:${NC}" - echo " 工作空间根目录: ${WORKSPACE_ROOT}" - echo " 源码目录: ${WORKSPACE_SRC}" - echo " 包目录: ${PKG_DIR}" - echo " ROS版本: ROS1" + echo -e "${YELLOW}Workspace structure:${NC}" + echo " Workspace root: ${WORKSPACE_ROOT}" + echo " Source directory: ${WORKSPACE_SRC}" + echo " Package directory: ${PKG_DIR}" + echo " ROS version: ROS1" - echo -e "${YELLOW}🔧 开始构建 ROS1 工程...${NC}" + echo -e "${YELLOW}Starting ROS1 project build...${NC}" - # 清理 + # Clean cd $WS_DIR rm -rf build devel install - # 确保 ROS1 环境已加载 + # Ensure ROS1 environment is loaded if [ -f "/opt/ros/noetic/setup.bash" ]; then source "/opt/ros/noetic/setup.bash" elif [ -f "/opt/ros/melodic/setup.bash" ]; then source "/opt/ros/melodic/setup.bash" else - echo -e "${RED}❌ 找不到 ROS1 的 setup.bash 文件。请确保 ROS1 已安装。${NC}" + echo -e "${RED}Could not find ROS1 setup.bash file. Please ensure ROS1 is installed.${NC}" return 1 fi - # 创建临时 package.xml + # Create temporary package.xml if [ -f "${PKG_DIR}/package_ros1.xml" ]; then - echo "🔄 创建临时 package.xml(使用 package_ros1.xml)" + echo "Creating temporary package.xml (using package_ros1.xml)" cp "${PKG_DIR}/package_ros1.xml" "${PKG_DIR}/package.xml" TEMP_PACKAGE=true elif [ -f "${PKG_DIR}/package.xml" ]; then - echo "ℹ️ 使用现有的 package.xml" + echo "Using existing package.xml" else - echo -e "${RED}❌ 在包目录中找不到 package.xml${NC}" + echo -e "${RED}Could not find package.xml in package directory${NC}" return 1 fi - # 设置构建系统变量 + # Set build system variable export BUILD_SYSTEM=ROS1 - # 切换到工作空间根目录并构建 + # Switch to workspace root and build cd "${WORKSPACE_ROOT}" || return 1 catkin_make -DBUILD_SYSTEM=ROS1 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -j$(nproc) BUILD_RESULT=$? - # 构建成功,source 环境 + # If build successful, source environment if [[ $BUILD_RESULT -eq 0 ]]; then - echo -e "${GREEN}✅ ROS1 构建成功,载入环境变量:source devel/setup.bash${NC}" + echo -e "${GREEN}ROS1 build successful, loading environment: source devel/setup.bash${NC}" source "${WORKSPACE_ROOT}/devel/setup.bash" else - echo -e "${RED}❌ ROS1 构建失败,请检查错误日志${NC}" + echo -e "${RED}ROS1 build failed, please check error logs${NC}" fi } -# 帮助函数 +# Help function show_help() { - echo -e "${YELLOW}使用说明:${NC}" - echo " ./build_ros.sh # 构建项目" - echo " ./build_ros.sh -c # 清理构建产物" - echo " ./build_ros.sh -h # 显示帮助信息" + echo -e "${YELLOW}Usage:${NC}" + echo " ./build_ros.sh # Build project" + echo " ./build_ros.sh -c # Clean build artifacts" + echo " ./build_ros.sh -h # Show help information" echo "" - echo -e "${YELLOW}当前配置:${NC}" - echo " 项目名称: ${PROJECT_NAME}" - echo " 包目录: ${PKG_DIR}" - echo " 工作空间根目录: ${WORKSPACE_ROOT}" - echo " 源码目录: ${WORKSPACE_SRC}" + echo -e "${YELLOW}Current configuration:${NC}" + echo " Project name: ${PROJECT_NAME}" + echo " Package directory: ${PKG_DIR}" + echo " Workspace root: ${WORKSPACE_ROOT}" + echo " Source directory: ${WORKSPACE_SRC}" } -# 主程序 +# Main case "$1" in -c|--clean) clean_workspace diff --git a/script/build_ros2.sh b/script/build_ros2.sh index 2253102..0a418e4 100644 --- a/script/build_ros2.sh +++ b/script/build_ros2.sh @@ -1,73 +1,73 @@ #!/bin/bash -# 获取脚本所在目录(Odin_ROS_Driver 目录) +# Get the directory where the script is located (Odin_ROS_Driver directory) PKG_DIR="$(cd "$(dirname "$0")/.."; pwd)" -# 计算工作空间根目录(包含 devel、build、src 的目录) +# Calculate the workspace root directory (contains devel, build, src) WORKSPACE_ROOT="$(dirname "$(dirname "$PKG_DIR")")" -# 工作空间源码目录(包含所有包的 src) +# Workspace source directory (contains all packages) WORKSPACE_SRC="${WORKSPACE_ROOT}/src" PROJECT_NAME="odin_ros_driver" PACKAGE_DIR_NAME=$(basename "$PKG_DIR") -# 定义颜色代码 +# Define color codes RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' -NC='\033[0m' # 无颜色 +NC='\033[0m' -# 从 package.xml 中提取包名 +# Extract package name from package.xml get_package_name() { local package_xml="$1" if [ -f "$package_xml" ]; then - # 提取 标签内容 + # Extract content of tag grep -oP '\K[^<]+' "$package_xml" | head -1 else echo "" fi } -# 清理函数 +# Clean workspace function clean_workspace() { - echo -e "${YELLOW}🧹 清理构建目录${NC}" + echo -e "${YELLOW}Cleaning build directories${NC}" - # 清理工作空间根目录下的构建产物 + # Clean build artifacts in workspace rm -rf "${WORKSPACE_ROOT}/build" rm -rf "${WORKSPACE_ROOT}/install" rm -rf "${WORKSPACE_ROOT}/log" rm -rf "${WORKSPACE_ROOT}/devel" - echo -e "${GREEN}✅ 清理完成${NC}" + echo -e "${GREEN}Cleanup complete${NC}" } -# 运行函数 +# Run node function run_node() { - echo -e "${YELLOW}🏃‍♂️‍➡️ 运行 ROS2 节点${NC}" + echo -e "${YELLOW}Running ROS2 node${NC}" - # 检查环境文件是否存在 + # Check if environment file exists if [ ! -f "${WORKSPACE_ROOT}/install/setup.bash" ]; then - echo -e "${RED}❌ 找不到 install/setup.bash,请先执行 ./build_ros2.sh 构建项目${NC}" + echo -e "${RED}Could not find install/setup.bash, please build the project with ./build_ros2.sh first${NC}" return 1 fi - # Source 环境并运行节点 + # Source environment and run node source "${WORKSPACE_ROOT}/install/setup.bash" } -# 构建函数 +# Build workspace function build_workspace() { - echo -e "${YELLOW}🔍 工作空间结构:${NC}" - echo " 工作空间根目录: ${WORKSPACE_ROOT}" - echo " 源码目录: ${WORKSPACE_SRC}" - echo " 包目录: ${PKG_DIR}" - echo " 目录名: ${PACKAGE_DIR_NAME}" - echo " ROS版本: ROS2" + echo -e "${YELLOW}Workspace structure:${NC}" + echo " Workspace root: ${WORKSPACE_ROOT}" + echo " Source directory: ${WORKSPACE_SRC}" + echo " Package directory: ${PKG_DIR}" + echo " Directory name: ${PACKAGE_DIR_NAME}" + echo " ROS version: ROS2" - echo -e "${YELLOW}🔧 开始构建 ROS2 工程...${NC}" - # 清理 + echo -e "${YELLOW}Starting ROS2 project build...${NC}" + cd $WS_DIR rm -rf build install log - # 确保 ROS2 环境已加载 + # Ensure ROS2 environment is loaded if [ -f "/opt/ros/foxy/setup.bash" ]; then source "/opt/ros/foxy/setup.bash" elif [ -f "/opt/ros/galactic/setup.bash" ]; then @@ -75,38 +75,38 @@ build_workspace() { elif [ -f "/opt/ros/humble/setup.bash" ]; then source "/opt/ros/humble/setup.bash" else - echo -e "${RED}❌ 找不到 ROS2 的 setup.bash 文件。请确保 ROS2 已安装。${NC}" + echo -e "${RED}Could not find ROS2 setup.bash file. Please ensure ROS2 is installed.${NC}" return 1 fi - # 创建临时 package.xml + # Create temporary package.xml if [ -f "${PKG_DIR}/package_ros2.xml" ]; then - echo "🔄 创建临时 package.xml(使用 package_ros2.xml)" + echo "Creating temporary package.xml (using package_ros2.xml)" cp "${PKG_DIR}/package_ros2.xml" "${PKG_DIR}/package.xml" TEMP_PACKAGE=true elif [ -f "${PKG_DIR}/package.xml" ]; then - echo "ℹ️ 使用现有的 package.xml" + echo "Using existing package.xml" TEMP_PACKAGE=false else - echo -e "${RED}❌ 在包目录中找不到 package.xml${NC}" + echo -e "${RED}Could not find package.xml in package directory${NC}" return 1 fi - # 从 package.xml 中提取包名 + # Extract package name from package.xml PACKAGE_NAME=$(get_package_name "${PKG_DIR}/package.xml") if [ -z "$PACKAGE_NAME" ]; then - echo -e "${RED}❌ 无法从 package.xml 中提取包名${NC}" + echo -e "${RED}Failed to extract package name from package.xml${NC}" return 1 fi - echo " 包名: ${PACKAGE_NAME}" + echo " Package name: ${PACKAGE_NAME}" - # 设置构建系统变量 + # Set build system variable export BUILD_SYSTEM=ROS2 - # 切换到工作空间根目录并构建 + # Switch to workspace root and build cd "${WORKSPACE_ROOT}" || return 1 - # 使用正确的包名构建 + # Build with correct package name colcon build \ --packages-select "${PACKAGE_NAME}" \ --parallel-workers $(nproc) \ @@ -116,32 +116,32 @@ build_workspace() { BUILD_RESULT=$? - # 构建成功,source 环境 + # If build successful, source environment if [[ $BUILD_RESULT -eq 0 ]]; then - echo -e "${GREEN}✅ ROS2 构建成功,载入环境变量:source install/setup.bash${NC}" + echo -e "${GREEN}ROS2 build successful, loading environment: source install/setup.bash${NC}" source "${WORKSPACE_ROOT}/install/setup.bash" else - echo -e "${RED}❌ ROS2 构建失败,请检查错误日志${NC}" + echo -e "${RED}ROS2 build failed, please check error logs${NC}" fi } -# 帮助函数 +# Help function show_help() { - echo -e "${YELLOW}使用说明:${NC}" - echo " ./build_ros2.sh # 构建项目" - echo " ./build_ros2.sh -c # 清理构建产物" - echo " ./build_ros2.sh -h # 显示帮助信息" + echo -e "${YELLOW}Usage:${NC}" + echo " ./build_ros2.sh # Build project" + echo " ./build_ros2.sh -c # Clean build artifacts" + echo " ./build_ros2.sh -h # Show help information" echo "" - echo -e "${YELLOW}当前配置:${NC}" - echo " 项目名称: ${PROJECT_NAME}" - echo " 包目录: ${PKG_DIR}" - echo " 工作空间根目录: ${WORKSPACE_ROOT}" - echo " 源码目录: ${WORKSPACE_SRC}" + echo -e "${YELLOW}Current configuration:${NC}" + echo " Project name: ${PROJECT_NAME}" + echo " Package directory: ${PKG_DIR}" + echo " Workspace root: ${WORKSPACE_ROOT}" + echo " Source directory: ${WORKSPACE_SRC}" } -# 主程序 +# Main program case "$1" in -c|--clean) clean_workspace diff --git a/src/host_sdk_sample.cpp b/src/host_sdk_sample.cpp index cdf93fd..7af06b6 100644 --- a/src/host_sdk_sample.cpp +++ b/src/host_sdk_sample.cpp @@ -16,7 +16,7 @@ static device_handle odinDevice = nullptr; static std::shared_ptr g_ros_object; static std::atomic deviceConnected(false); -// 定义获取包路径的函数 +// Function to get package share path std::string get_package_share_path(const std::string& package_name) { #ifdef ROS2 try { @@ -33,7 +33,7 @@ std::string get_package_share_path(const std::string& package_name) { #endif } -// 全局配置变量 +// Global configuration variables static int g_sendrgb = 1; static int g_sendimu = 1; static int g_senddtof = 1; @@ -93,7 +93,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach ROS_INFO("Device attaching..."); #endif - // 清理任何已存在的设备 + // Clean up any existing device if (odinDevice) { lidar_stop_stream(odinDevice, type); lidar_unregister_stream_callback(odinDevice); @@ -102,7 +102,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach odinDevice = nullptr; } - // 修复:使用const_cast移除const限定符 + // Use const_cast to remove const qualifier if (lidar_create_device(const_cast(device), &odinDevice)) { #ifdef ROS2 RCLCPP_ERROR(rclcpp::get_logger("device_cb"), "Create device failed"); @@ -112,7 +112,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach return; } - // 打开设备 + // Open device if (lidar_open_device(odinDevice)) { #ifdef ROS2 RCLCPP_ERROR(rclcpp::get_logger("device_cb"), "Open device failed"); @@ -124,7 +124,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach return; } - // 设置模式 + // Set mode if (lidar_set_mode(odinDevice, type)) { #ifdef ROS2 RCLCPP_ERROR(rclcpp::get_logger("device_cb"), "Set mode failed"); @@ -137,7 +137,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach return; } - // 注册回调 + // Register callback lidar_data_callback_info_t data_callback_info; data_callback_info.data_callback = lidar_data_callback; data_callback_info.user_data = &odinDevice; @@ -154,7 +154,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach return; } - // 启动数据流 + // Start data stream if (lidar_start_stream(odinDevice, type)) { #ifdef ROS2 RCLCPP_ERROR(rclcpp::get_logger("device_cb"), "Start stream failed"); @@ -167,7 +167,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach return; } - // 根据配置激活数据流类型 + // Activate stream types based on configuration if (g_sendrgb) { lidar_activate_stream_type(odinDevice, LIDAR_DT_RAW_RGB); } @@ -211,7 +211,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach int main(int argc, char *argv[]) { - // ROS初始化 + // ROS initialization #ifdef ROS2 rclcpp::init(argc, argv); auto node = std::make_shared("lydros_node"); @@ -226,10 +226,10 @@ int main(int argc, char *argv[]) std::string package_path = get_package_share_path("odin_ros_driver"); std::string config_file = package_path + "/config/control_command.yaml"; - // 创建 YAML 解析器 + // Create YAML parser odin_ros_driver::YamlParser parser(config_file); - // 加载配置 + // Load configuration if (!parser.loadConfig()) { #ifdef ROS2 RCLCPP_ERROR(node->get_logger(), "Failed to load config file: %s", config_file.c_str()); @@ -239,13 +239,12 @@ int main(int argc, char *argv[]) return -1; } - // 获取键值映射 + // Get key-value auto keys = parser.getRegisterKeys(); - // 打印配置 + // Print configuration parser.printConfig(); - // 获取键值函数 auto get_key_value = [&](const std::string& key_name, int default_value) -> int { auto it = keys.find(key_name); if (it != keys.end()) { @@ -254,17 +253,17 @@ int main(int argc, char *argv[]) return default_value; }; - // 读取配置值到全局变量 + // Read configuration values into global variables g_sendrgb = get_key_value("sendrgb", 1); g_sendimu = get_key_value("sendimu", 1); g_senddtof = get_key_value("senddtof", 1); g_sendodom = get_key_value("sendodom", 1); g_sendcloudslam = get_key_value("sendcloudslam", 0); - // 设置日志级别 + // Set log level lidar_log_set_level(LIDAR_LOG_INFO); - // 初始化系统,启动USB监控 + // Initialize system and start USB monitoring if(lidar_system_init(lidar_device_callback)) { #ifdef ROS2 RCLCPP_ERROR(node->get_logger(), "Lidar system init failed"); @@ -274,7 +273,7 @@ int main(int argc, char *argv[]) return -1; } - // 等待设备连接(最长30秒) + // wait device connect #ifdef ROS2 RCLCPP_INFO(node->get_logger(), "Waiting for device connection..."); #else @@ -308,7 +307,7 @@ int main(int argc, char *argv[]) return -1; } - // ROS主循环 + // ROS loop #ifdef ROS2 rclcpp::spin(node); rclcpp::shutdown(); @@ -317,7 +316,7 @@ int main(int argc, char *argv[]) ros::shutdown(); #endif - // 清理 + // Cleanup if (odinDevice) { lidar_stop_stream(odinDevice, LIDAR_MODE_SLAM); lidar_unregister_stream_callback(odinDevice); diff --git a/src/yaml_parser.cpp b/src/yaml_parser.cpp index ca6e9e1..bdbfe4f 100644 --- a/src/yaml_parser.cpp +++ b/src/yaml_parser.cpp @@ -2,35 +2,34 @@ #include #include #include -#include // 用于 std::transform +#include namespace odin_ros_driver { -// 使用一致的成员变量名 YamlParser::YamlParser(const std::string& config_file) - : config_file_(config_file) {} // 这里使用 config_file_ + : config_file_(config_file) {} // // Using config_file_ member variable bool YamlParser::loadConfig() { try { - // 使用成员变量 config_file_ + // Using member variable config_file_ std::cerr << "Loading config file: " << config_file_ << std::endl; - // 检查文件是否存在 + // Check if file exists if (!std::filesystem::exists(config_file_)) { std::cerr << "Config file not found: " << config_file_ << std::endl; return false; } - // 打印文件内容 + // Print file contents std::ifstream file(config_file_); std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator()); std::cerr << "Config file content:\n" << content << "\n--- End of file ---" << std::endl; - // 加载 YAML - 使用成员变量 config_file_ + // Load YAML YAML::Node config = YAML::LoadFile(config_file_); - // 检查是否存在 register_keys 节点 + // Check if 'register_keys' node exists if (!config["register_keys"]) { std::cerr << "Missing 'register_keys' section in config file" << std::endl; return false; @@ -39,14 +38,14 @@ bool YamlParser::loadConfig() { YAML::Node register_keys = config["register_keys"]; register_keys_.clear(); - // 打印键值对数量 + // Print number of key-value pairs found std::cerr << "Found " << register_keys.size() << " keys in config" << std::endl; for (YAML::const_iterator it = register_keys.begin(); it != register_keys.end(); ++it) { std::string key = it->first.as(); int value = it->second.as(); - // 转换为小写 + // Convert key to lowercase std::transform(key.begin(), key.end(), key.begin(), [](unsigned char c){ return std::tolower(c); }); @@ -80,4 +79,4 @@ void YamlParser::printConfig() const { } } -} // namespace odin_ros_driver \ No newline at end of file +} \ No newline at end of file