<fix>​ Fix format errors in README, Add rviz configuration loading.​​

This commit is contained in:
manifoldsdk
2025-07-12 21:28:38 +08:00
parent 31bff6868b
commit 876cc931b4
14 changed files with 838 additions and 344 deletions
+49 -52
View File
@@ -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}")
+12 -8
View File
@@ -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
+222
View File
@@ -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: <Fixed 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: <Fixed 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
+248
View File
@@ -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: <Fixed 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: <Fixed 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
+130 -132
View File
@@ -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<float> iter_y(msg, "y");
sensor_msgs::PointCloud2Iterator<float> iter_z(msg, "z");
sensor_msgs::PointCloud2Iterator<uint8_t> 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<float> iter_x(msg, "x");
sensor_msgs::PointCloud2Iterator<float> iter_y(msg, "y");
sensor_msgs::PointCloud2Iterator<float> iter_z(msg, "z");
sensor_msgs::PointCloud2Iterator<uint8_t> iter_intensity(msg, "intensity");
#endif
float* xyz_data = static_cast<float*>(stream->imageList[idx].pAddr);
uint16_t* intensity_data = static_cast<uint16_t*>(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<uint8_t>(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<uint8_t>(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<float> iter_x(msg, "x");
sensor_msgs::PointCloud2Iterator<float> iter_y(msg, "y");
sensor_msgs::PointCloud2Iterator<float> iter_z(msg, "z");
sensor_msgs::PointCloud2Iterator<uint8_t> iter_intensity(msg, "intensity");
#endif
float* xyz_data = static_cast<float*>(stream->imageList[idx].pAddr);
uint16_t* intensity_data = static_cast<uint16_t*>(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<uint8_t>(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<uint8_t>(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<size_t>(image.width) * height_nv12;
if (image.length < expected_size) {
#ifdef ROS2
@@ -312,30 +312,56 @@ 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<float> iter_x(msg, "x");
sensor_msgs::PointCloud2Iterator<float> iter_y(msg, "y");
sensor_msgs::PointCloud2Iterator<float> iter_z(msg, "z");
sensor_msgs::PointCloud2Iterator<float> 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);
@@ -343,73 +369,47 @@ void publishPC2XYZRGBA(capture_Image_List_t* stream, int idx)
sensor_msgs::PointCloud2Iterator<float> iter_y(msg, "y");
sensor_msgs::PointCloud2Iterator<float> iter_z(msg, "z");
sensor_msgs::PointCloud2Iterator<float> 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<float> iter_x(msg, "x");
sensor_msgs::PointCloud2Iterator<float> iter_y(msg, "y");
sensor_msgs::PointCloud2Iterator<float> iter_z(msg, "z");
sensor_msgs::PointCloud2Iterator<float> iter_rgb(msg, "rgb");
#endif
// 共享的数据处理逻辑
int32_t* xyz_data = static_cast<int32_t*>(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<float>(ptr[0]) / 10000.0f; ++iter_x;
*iter_y = static_cast<float>(ptr[1]) / 10000.0f; ++iter_y;
*iter_z = static_cast<float>(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<int32_t*>(stream->imageList[idx].pAddr);
uint32_t packed_rgb = (static_cast<uint32_t>(r) << 16) |
(static_cast<uint32_t>(g) << 8) |
static_cast<uint32_t>(b);
for(uint32_t i = 0; i < points; i++) {
int32_t* ptr = xyz_data + 7*i;
float rgb_float;
std::memcpy(&rgb_float, &packed_rgb, sizeof(float));
#ifdef ROS2
*iter_x = static_cast<float>(ptr[0]) / 10000.0f; ++iter_x;
*iter_y = static_cast<float>(ptr[1]) / 10000.0f; ++iter_y;
*iter_z = static_cast<float>(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
*iter_rgb = rgb_float; ++iter_rgb;
uint8_t r = ptr[3] & 0xff;
uint8_t g = ptr[4] & 0xff;
uint8_t b = ptr[5] & 0xff;
uint32_t packed_rgb = (static_cast<uint32_t>(r) << 16) |
(static_cast<uint32_t>(g) << 8) |
static_cast<uint32_t>(b);
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<void(const std::string&, int)>;
@@ -539,7 +538,6 @@ private:
};
// 控制命令定义
#define STREAMCTRL "streamctrl" /* start/stop all streams */
#define SENDRGB "sendrgb" /* send RGB data */
#define SENDIMU "sendimu" /* send IMU data */
+2 -3
View File
@@ -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<std::string, int> register_keys_;
};
} // namespace odin_ros_driver
}
#endif // YAML_PARSER_H
#endif
+13 -3
View File
@@ -1,12 +1,22 @@
<launch>
<!--
用法: roslaunch odin_ros_driver odin1_ros1.launch
Usage: roslaunch odin_ros_driver odin1_ros1.launch
-->
<!-- 设置节点名称 -->
<!-- Set node name -->
<arg name="node_name" default="host_sdk_sample"/>
<!-- 启动节点 -->
<!-- Set parameter file path -->
<arg name="config_file" default="$(find odin_ros_driver)/config/control_command.yaml"/>
<!-- Set RViz configuration file path -->
<arg name="rviz_config" default="$(find odin_ros_driver)/config/odin_ros.rviz"/>
<!-- Launch main node -->
<node name="$(arg node_name)" pkg="odin_ros_driver" type="host_sdk_sample" output="screen">
<param name="config_file" value="$(arg config_file)"/>
</node>
<!-- Launch RViz with configuration -->
<node name="rviz" pkg="rviz" type="rviz" args="-d $(arg rviz_config)" output="screen"/>
</launch>
+23 -5
View File
@@ -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
+4 -4
View File
@@ -6,10 +6,10 @@
<maintainer email="[email protected]">rlk</maintainer>
<license>Apache 2.0</license>
<!-- ROS1 使用 catkin 作为构建工具 -->
<!-- ROS1 uses catkin as the build tool -->
<buildtool_depend>catkin</buildtool_depend>
<!-- ROS1 依赖项 -->
<!-- ROS1 dependencies -->
<depend>roscpp</depend>
<depend>std_msgs</depend>
<depend>sensor_msgs</depend>
@@ -17,12 +17,12 @@
<depend>cv_bridge</depend>
<depend>image_transport</depend>
<!-- 系统依赖项 -->
<!-- System dependencies -->
<depend>eigen</depend>
<depend>opencv</depend>
<depend>yaml-cpp</depend>
<!-- 指定构建类型为 catkin -->
<!-- Specify build type as catkin -->
<export>
<build_type>catkin</build_type>
</export>
+4 -4
View File
@@ -5,17 +5,17 @@
<description>ROS2 driver for Odin sensor</description>
<maintainer email="[email protected]">rlk</maintainer>
<license>Apache 2.0</license>
<!-- ROS2 使用 colcon 作为构建工具 -->
<!-- ROS2 uses colcon as the build tool -->
<buildtool_depend>ament_cmake</buildtool_depend>
<!-- ROS2 依赖项 -->
<!-- ROS2 dependencies -->
<depend>rclcpp</depend>
<!-- 系统依赖项 -->
<!-- System dependencies -->
<depend>std_msgs</depend>
<depend>sensor_msgs</depend>
<depend>nav_msgs</depend>
<depend>cv_bridge</depend>
<depend>image_transport</depend>
<!-- 指定构建类型为 ament -->
<!-- Specify build type as ament -->
<export>
<build_type>ament_cmake</build_type>
</export>
+44 -44
View File
@@ -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
+51 -51
View File
@@ -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
# 提取 <name> 标签内容
# Extract content of <name> tag
grep -oP '<name>\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}Starting ROS2 project build...${NC}"
echo -e "${YELLOW}🔧 开始构建 ROS2 工程...${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
+20 -21
View File
@@ -16,7 +16,7 @@ static device_handle odinDevice = nullptr;
static std::shared_ptr<MultiSensorPublisher> g_ros_object;
static std::atomic<bool> 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<lidar_device_info_t*>(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<rclcpp::Node>("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);
+10 -11
View File
@@ -2,35 +2,34 @@
#include <fstream>
#include <filesystem>
#include <iostream>
#include <algorithm> // 用于 std::transform
#include <algorithm>
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<char>(file)),
std::istreambuf_iterator<char>());
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<std::string>();
int value = it->second.as<int>();
// 转换为小写
// 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
}