<add>1.Add dev_status.csv for device & data tx rx rate monitor;

2. Add high frequency odom data ;
 3. Add image undistort functionality;
 4. optimized data publish pipeline
 5. other optimizations
This commit is contained in:
mt-lifan
2025-09-28 19:19:07 +08:00
parent 97686cc034
commit 7d738e12f8
18 changed files with 1246 additions and 291 deletions
+3 -1
View File
@@ -1 +1,3 @@
recorddata/
recorddata/
/config/calib.yaml
/log
+3
View File
@@ -96,6 +96,9 @@ endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Set optimization flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
# Find common dependencies
find_package(PkgConfig REQUIRED)
find_package(OpenCV REQUIRED)
+106 -17
View File
@@ -16,7 +16,7 @@ This driver package provides core functionality for point cloud SLAM application
## 1. Version
Current Version: v0.4.1
Current Version: v0.5.0
## 2. Preparation
@@ -30,7 +30,7 @@ Current Version: v0.4.1
### 2.2 Dependencies
● Opencv >= 4.5.0(recommand 4.5.5/4.8.0)
● Opencv >= 4.5.0(recommand 4.5.5/4.8.0. Make sure only one version of opencv is installed)
● yaml-cpp
@@ -122,7 +122,7 @@ source /opt/ros/foxy/setup.bash
#### 3.4.1 ROS1 (Noetic for example):
```shell
source [ros_workspace]/install/setup.bash
source [ros_workspace]/devel/setup.bash
roslaunch odin_ros_driver [launch file]
```
● odin_ros_driver: package name;
@@ -186,6 +186,8 @@ Odin_ROS_Driver/ // ROS1/ROS2 driver package
script/
build_ros1.sh // Installation script for ROS1
build_ros2.sh // Installation script for ROS2
recorddata/ // holds recorded data that can import into MindCloud
log/ // holds log files
README.md // Usage instructions
CMakeLists.txt // CMake build file
License // License file
@@ -200,17 +202,67 @@ Odin_ROS_Driver/ // ROS1/ROS2 driver package
### 4.3 ROS topics
Internal parameters of the Odin ROS driver are defined in config/control_command.yaml. Below are descriptions of the commonly used parameters:
| Topic | Detailed Description |
|---------------------|----------------------|
| odin1/imu | Imu Topic |
| odin1/image | RGB Camera Topic |
| odin1/image/compressed | RGB Camera compressed Topic |
| odin1/cloud_raw | Raw_Cloud Topic |
| odin1/cloud_render | Render_Cloud Topic |
| odin1/cloud_slam | Slam_PointCloud Topic |
| odin1/odometry | Odom Topic |
| odin1/depth_img_competetion | Dense depth image Topic |
| odin1/depth_img_competetion_cloud | Dense Depth_Cloud Topic |
| Topic |control_command.yaml | Detailed Description |
|---------------------|----------------------|----------------------|
| odin1/imu | sendimu | Imu Topic |
| odin1/image | sendrgb | RGB Camera Topic, decoded from jpeg data from device |
| odin1/image_undistort | sendrgbundistort | undistorted RGB Camera Topic, processed with calib.yaml from device |
| odin1/image/compressed | sendrgbcompressed | RGB Camera compressed Topic, original jpeg data from device |
| odin1/cloud_raw | senddtof | Raw_Cloud Topic |
| odin1/cloud_render | sendcloudrender | Render_Cloud Topic, processed with raw point cloud, rgb image, and calib.yaml from device |
| odin1/cloud_slam | sendcloudslam | Slam_PointCloud Topic |
| odin1/odometry | sendodom | Odom Topic |
| odin1/odometry_high | sendodom | high frequency Odom Topic |
| odin1/depth_img_competetion | senddepth | Dense depth image Topic, demo, high computing power required |
| odin1/depth_img_competetion_cloud | senddepth | Dense Depth_Cloud Topic, demo, high computing power required |
### 4.4 Data format
1. The raw point cloud (cloud_raw) has the following fields:
```
float32 x // X axis, in meters
float32 y // Y axis, in meters
float32 z // Z axis, in meters
uint8 intensity // Reflectivity, range 0–255
uint16 confidence // Point confidence, range 0–65535
float32 offset_time // Time offset relative to the base timestamp
```
To work with this custom format in PCL, first define the point type:
```cpp
/*** LS ***/
namespace ls_ros {
struct EIGEN_ALIGN16 Point {
float x;
float y;
float z;
uint8_t intensity;
uint16_t confidence;
float offset_time;
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
} // namespace ls_ros
POINT_CLOUD_REGISTER_POINT_STRUCT(ls_ros::Point,
(float, x, x)
(float, y, y)
(float, z, z)
(uint8_t, intensity, intensity)
(uint16_t, confidence, confidence)
(float offset_time , offset_time)
)
```
Then, you can easily convert a ROS sensor_msgs::PointCloud2 message into a PCL point cloud:
```
pcl::PointCloud<ls_ros::Point> ls_cloud;
pcl::fromROSMsg(*msg, ls_cloud);
```
### 4.5 Other functionalities
|control_command.yaml | Detailed Description |
|-----------------------|----------------------|
| recorddata | Record data in specific format that can be imported into MindCloud(TM) for post-processing. Please be aware that this will consume a lot of storage space. Testing shows 9.5G for 10mins of data. |
| devstatuslog | Device status logging, currently save device status (soc temperature, cpu usage, ram usage, dtof sensor temp .etc) and data tx & rx rate to devstatus.csv under log folder. A new file will be created every time the driver is started. |
## 5. FAQ
### 5.1 Segmentation fault upon re-launching host SDK
@@ -252,7 +304,20 @@ Unable to open X display or No protocol specified
xhost + #This command enables graphical passthrough to Docker containers
```
### 5.4 RVIZ has not responded for a long time
### 5.4 ROS driver exit with get version failed error
**Error Message**
```shell
<ERROR><api.cpp:lidar_get_version:672>: get device version fail.
get version failed.
```
**Resolution**
Device firmware version is too low, please update to latest version.
### 5.5 RVIZ has not responded for a long time
**Error Message**
Rviz does not respond, and after a while the terminal prints Device disconnected, waiting for reconnection...
@@ -261,7 +326,7 @@ Rviz does not respond, and after a while the terminal prints Device disconnected
Please power on Odin module again
### 5.5 Device not responding
### 5.6 Device not responding
**Error Message**
Missed ok response from device,probably wrong interaction procedure.
@@ -270,7 +335,7 @@ Missed ok response from device,probably wrong interaction procedure.
Please adopt the solution mentioned in 5.1
### 5.6 Device has no external calibration file
### 5.7 Device has no external calibration file
**Error Message**
ERROR:Missing camera node 'cam_0'
@@ -279,6 +344,30 @@ ERROR:Missing camera node 'cam_0'
Please plug and unplug the USB again
### 5.8 ROS Driver report device disconnected immediately after stream started
**Error Message**
```shell
Device ready and streams activated
Device detaching...
Wating for device reconnection...
Device disconnected, waiting for reconnection...
```
**Reason**
Mostly common on ros2 environment and connected to complex network environment, such as office wifi & ethernet. ROS2 default to broadcast, and complex network environment will cause ros2 publish to block, leading to device disconnection.
**Resolution**
If cross-device communication is not required, please restrict ros2 to localhost only with:
```shell
export ROS_LOCALHOST_ONLY=1
```
If cross-device communication is required, please simplify the network environment as much as possible. Mini local network with only required devices is recommended.
## 6. Contact Information​​
To help diagnose the issue, please provide the following details to our FAE engineer:
+12 -10
View File
@@ -1,12 +1,14 @@
register_keys:
streamctrl: 1
sendrgb: 1
sendimu: 1
sendodom: 1
senddtof: 1
sendcloudslam: 1
sendcloudrender: 1
sendrgbcompressed: 1
senddepth: 0
recorddata: 0
streamctrl: 1 # 0: off; 1: on
sendrgb: 1 # 0: off; 1: on
sendimu: 1 # 0: off; 1: on
sendodom: 1 # 0: off; 1: on
senddtof: 1 # 0: off; 1: on
sendcloudslam: 1 # 0: off; 1: on
sendcloudrender: 1 # 0: off; 1: on
sendrgbcompressed: 1 # 0: off; 1: on
senddepth: 0 # 0: off; 1: on
sendrgbundistort: 0 # 0: off; 1: on
recorddata: 0 # 0: off; 1: on
devstatuslog: 1 # 0: off; 1: on
+159 -69
View File
@@ -3,9 +3,12 @@ Panels:
Help Height: 138
Name: Displays
Property Tree Widget:
Expanded: ~
Splitter Ratio: 0.5
Tree Height: 767
Expanded:
- /Odometry_high1/Shape1
- /slam1
- /dense_depth_demo1
Splitter Ratio: 0.4993045926094055
Tree Height: 1052
- Class: rviz/Selection
Name: Selection
- Class: rviz/Tool Properties
@@ -23,7 +26,7 @@ Panels:
- Class: rviz/Time
Name: Time
SyncMode: 0
SyncSource: Image
SyncSource: raw
Preferences:
PromptSaveOnExit: true
Toolbars:
@@ -63,11 +66,11 @@ Visualization Manager:
Value: true
- Class: rviz/Image
Enabled: false
Image Topic: /odin1/depth_img_competetion
Image Topic: /odin1/image/undistorted
Max Value: 1
Median window: 5
Min Value: 0
Name: dense_depth_image
Name: Image_undistort
Normalize Range: true
Queue Size: 2
Transport Hint: raw
@@ -108,6 +111,41 @@ Visualization Manager:
Topic: /odin1/odometry
Unreliable: false
Value: true
- 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: true
Enabled: false
Keep: 100
Name: Odometry_high
Position Tolerance: 0.10000000149011612
Queue Size: 10
Shape:
Alpha: 1
Axes Length: 1
Axes Radius: 0.10000000149011612
Color: 52; 101; 164
Head Length: 0.30000001192092896
Head Radius: 0.10000000149011612
Shaft Length: 1
Shaft Radius: 0.05000000074505806
Value: Arrow
Topic: /odin1/odometry_highfreq
Unreliable: false
Value: false
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
@@ -123,14 +161,16 @@ Visualization Manager:
Enabled: false
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 255
Min Color: 0; 0; 0
Min Intensity: 0
Name: raw
Position Transformer: XYZ
Queue Size: 10
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Style: Points
Topic: /odin1/cloud_raw
Unreliable: false
Use Fixed Frame: true
@@ -164,62 +204,110 @@ Visualization Manager:
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: rgb
Class: rviz/PointCloud2
Color: 255; 255; 255
Color Transformer: RGB8
Decay Time: 0
- Class: rviz/Group
Displays:
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
Max Value: 10
Min Value: -10
Value: true
Axis: Z
Channel Name: rgb
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: slam_current
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: true
Value: true
- Alpha: 0.10000000149011612
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: 5
Enabled: true
Invert Rainbow: false
Max Color: 255; 255; 255
Min Color: 0; 0; 0
Name: slam_decay
Position Transformer: XYZ
Queue Size: 10
Selectable: true
Size (Pixels): 1
Size (m): 0.009999999776482582
Style: Points
Topic: /odin1/cloud_slam
Unreliable: false
Use Fixed Frame: true
Use rainbow: true
Value: true
Enabled: false
Invert Rainbow: false
Max Color: 255; 255; 255
Min Color: 0; 0; 0
Name: slam
Position Transformer: XYZ
Queue Size: 10
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic: /odin1/cloud_slam
Unreliable: false
Use Fixed Frame: true
Use rainbow: true
Value: false
- 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
- Class: rviz/Group
Displays:
- Class: rviz/Image
Enabled: false
Image Topic: /odin1/depth_img_competetion
Max Value: 1
Median window: 5
Min Value: 0
Name: dense_depth_image
Normalize Range: true
Queue Size: 2
Transport Hint: raw
Unreliable: false
Value: false
- 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: false
Invert Rainbow: false
Max Color: 255; 255; 255
Min Color: 0; 0; 0
Name: dense_depth_cloud
Position Transformer: XYZ
Queue Size: 10
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Points
Topic: /odin1/depth_img_competetion_cloud
Unreliable: false
Use Fixed Frame: true
Use rainbow: true
Value: false
Enabled: false
Invert Rainbow: false
Max Color: 255; 255; 255
Min Color: 0; 0; 0
Name: dense_depth_cloud
Position Transformer: XYZ
Queue Size: 10
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic: /odin1/depth_img_competetion_cloud
Unreliable: false
Use Fixed Frame: true
Use rainbow: true
Value: false
Name: dense_depth_demo
Enabled: true
Global Options:
Background Color: 48; 48; 48
@@ -248,7 +336,7 @@ Visualization Manager:
Views:
Current:
Class: rviz/Orbit
Distance: 4.46931266784668
Distance: 7.223263740539551
Enable Stereo Rendering:
Stereo Eye Separation: 0.05999999865889549
Stereo Focal Distance: 1
@@ -264,19 +352,21 @@ Visualization Manager:
Invert Z Axis: false
Name: Current View
Near Clip Distance: 0.009999999776482582
Pitch: 0.3703991174697876
Pitch: 0.6153989434242249
Target Frame: <Fixed Frame>
Yaw: 3.3054051399230957
Yaw: 3.0504050254821777
Saved: ~
Window Geometry:
Displays:
collapsed: false
Height: 1672
Height: 1736
Hide Left Dock: false
Hide Right Dock: false
Image:
collapsed: false
QMainWindow State: 000000ff00000000fd0000000400000000000002d100000582fc020000000afb0000001200530065006c0065006300740069006f006e00000001e10000009b000000b000fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000b0fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000006e000003f70000018200fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006501000004710000017f0000002600fffffffb0000002200640065006e00730065005f00640065007000740068005f0069006d006100670065000000047d000001730000002600ffffff000000010000015f00000582fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000006e000005820000013200fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e1000001970000000300000ab00000005efc0100000002fb0000000800540069006d0065010000000000000ab0000006dc00fffffffb0000000800540069006d00650100000000000004500000000000000000000006680000058200000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Image_undistort:
collapsed: false
QMainWindow State: 000000ff00000000fd0000000400000000000001bf0000060afc020000000bfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000b0fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000004e3000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d0061006700650100000526000001210000001600fffffffb0000002200640065006e00730065005f00640065007000740068005f0069006d006100670065000000047d000001730000001600fffffffb0000001e0049006d006100670065005f0075006e0064006900730074006f007200740000000568000000df0000001600ffffff000000010000015f0000060afc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d0000060a000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e1000001970000000300000af80000005efc0100000002fb0000000800540069006d0065010000000000000af8000003bc00fffffffb0000000800540069006d00650100000000000004500000000000000000000007ce0000060a00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Selection:
collapsed: false
Time:
@@ -285,8 +375,8 @@ Window Geometry:
collapsed: false
Views:
collapsed: false
Width: 2736
X: 144
Y: 54
Width: 2808
X: 72
Y: 27
dense_depth_image:
collapsed: false
collapsed: false
+178 -78
View File
@@ -7,6 +7,9 @@ Panels:
- /Global Options1
- /Status1
- /Image1/Topic1
- /Odometry_high1/Shape1
- /slam1
- /dense_depth_demo1
Splitter Ratio: 0.5
Tree Height: 548
- Class: rviz_common/Selection
@@ -62,14 +65,14 @@ Visualization Manager:
Max Value: 1
Median window: 5
Min Value: 0
Name: dense_depth_image
Name: Image_undistort
Normalize Range: true
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /odin1/depth_img_competetion
Value: /odin1/image/undistorted
Value: false
- Angle Tolerance: 0.10000000149011612
Class: rviz_default_plugins/Odometry
@@ -110,6 +113,45 @@ Visualization Manager:
Reliability Policy: Reliable
Value: /odin1/odometry
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: false
Keep: 10
Name: Odometry_high
Position Tolerance: 0.10000000149011612
Shape:
Alpha: 1
Axes Length: 1
Axes Radius: 0.10000000149011612
Color: 98; 160; 234
Head Length: 0.30000001192092896
Head Radius: 0.10000000149011612
Shaft Length: 1
Shaft Radius: 0.05000000074505806
Value: Arrow
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /odin1/odometry_highfreq
Value: false
- Alpha: 1
Autocompute Intensity Bounds: true
Autocompute Value Bounds:
@@ -167,7 +209,7 @@ Visualization Manager:
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Style: Points
Topic:
Depth: 5
Durability Policy: Volatile
@@ -178,74 +220,130 @@ Visualization Manager:
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: RGB8
Decay Time: 0
- Class: rviz_common/Group
Displays:
- 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: slam_current
Position Transformer: XYZ
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Points
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /odin1/cloud_slam
Use Fixed Frame: true
Use rainbow: true
Value: true
- Alpha: 0.10000000149011612
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: 10
Enabled: true
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 4096
Min Color: 0; 0; 0
Min Intensity: 0
Name: slam_deacy
Position Transformer: XYZ
Selectable: true
Size (Pixels): 1
Size (m): 0.009999999776482582
Style: Points
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /odin1/cloud_slam
Use Fixed Frame: true
Use rainbow: true
Value: true
Enabled: false
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 4096
Min Color: 0; 0; 0
Min Intensity: 0
Name: slam
Position Transformer: XYZ
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /odin1/cloud_slam
Use Fixed Frame: true
Use rainbow: true
Value: false
- 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
- Class: rviz_common/Group
Displays:
- Class: rviz_default_plugins/Image
Enabled: false
Max Value: 1
Median window: 5
Min Value: 0
Name: dense_depth_image
Normalize Range: true
Topic:
Depth: 5
Durability Policy: Volatile
History Policy: Keep Last
Reliability Policy: Reliable
Value: /odin1/depth_img_competetion
Value: false
- 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: false
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 4096
Min Color: 0; 0; 0
Min Intensity: 0
Name: dense_depth_cloud
Position Transformer: XYZ
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /odin1/depth_img_competetion_cloud
Use Fixed Frame: true
Use rainbow: true
Value: false
Enabled: false
Invert Rainbow: false
Max Color: 255; 255; 255
Max Intensity: 4096
Min Color: 0; 0; 0
Min Intensity: 0
Name: dense_depth_cloud
Position Transformer: XYZ
Selectable: true
Size (Pixels): 3
Size (m): 0.009999999776482582
Style: Flat Squares
Topic:
Depth: 5
Durability Policy: Volatile
Filter size: 10
History Policy: Keep Last
Reliability Policy: Reliable
Value: /odin1/depth_img_competetion_cloud
Use Fixed Frame: true
Use rainbow: true
Value: false
Name: dense_depth_demo
Enabled: true
Global Options:
Background Color: 48; 48; 48
@@ -292,25 +390,25 @@ Visualization Manager:
Views:
Current:
Class: rviz_default_plugins/Orbit
Distance: 7.086822509765625
Distance: 6.814720153808594
Enable Stereo Rendering:
Stereo Eye Separation: 0.05999999865889549
Stereo Focal Distance: 1
Swap Stereo Eyes: false
Value: false
Focal Point:
X: 0.40898558497428894
Y: -0.07609735429286957
Z: 0.5482669472694397
X: 0.38628554344177246
Y: -1.1808340549468994
Z: 1.2151938676834106
Focal Shape Fixed Size: false
Focal Shape Size: 0.05000000074505806
Invert Z Axis: false
Name: Current View
Near Clip Distance: 0.009999999776482582
Pitch: 0.3503986895084381
Pitch: 0.5653982758522034
Target Frame: <Fixed Frame>
Value: Orbit (rviz)
Yaw: 3.4554057121276855
Yaw: 3.0103981494903564
Saved: ~
Window Geometry:
Displays:
@@ -320,7 +418,9 @@ Window Geometry:
Hide Right Dock: false
Image:
collapsed: false
QMainWindow State: 000000ff00000000fd000000040000000000000242000003abfc020000000afb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002af000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006501000002f2000000f60000002800fffffffb0000002200640065006e00730065005f00640065007000740068005f0069006d00610067006500000002cd0000011b0000002800ffffff000000010000010f000003abfc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000003ab000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d0065010000000000000450000000000000000000000423000003ab00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Image_undistort:
collapsed: false
QMainWindow State: 000000ff00000000fd000000040000000000000242000003abfc020000000bfb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002af000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb0000000a0049006d00610067006501000002f2000000f60000002800fffffffb0000002200640065006e00730065005f00640065007000740068005f0069006d00610067006500000002cd0000011b0000002800fffffffb0000001e0049006d006100670065005f0075006e0064006900730074006f00720074000000031d000000cb0000002800ffffff000000010000010f000003abfc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000003ab000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d0065010000000000000450000000000000000000000423000003ab00000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
Selection:
collapsed: false
Tool Properties:
@@ -328,7 +428,7 @@ Window Geometry:
Views:
collapsed: false
Width: 1920
X: 70
Y: 27
X: 498
Y: 112
dense_depth_image:
collapsed: false
collapsed: false
+12
View File
@@ -1,3 +1,15 @@
/*
Copyright 2025 Manifold Tech Ltd.(www.manifoldtech.com.co)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <cstdint>
+6 -2
View File
@@ -47,15 +47,18 @@ public:
private:
std::string cloud_raw_topic_;
std::string color_compressed_topic_;
std::string color_raw_topic_;
std::string depth_image_topic_;
std::string depth_cloud_topic_;
message_filters::Subscriber<sensor_msgs::msg::PointCloud2> cloud_sub_;
message_filters::Subscriber<sensor_msgs::msg::CompressedImage> color_compressed_sub_;
message_filters::Subscriber<sensor_msgs::msg::Image> color_sub_;
typedef message_filters::sync_policies::ApproximateTime<
sensor_msgs::msg::PointCloud2,
sensor_msgs::msg::CompressedImage> MySyncPolicy;
// sensor_msgs::msg::CompressedImage,
sensor_msgs::msg::Image> MySyncPolicy;
typedef message_filters::Synchronizer<MySyncPolicy> Sync;
std::shared_ptr<Sync> sync_;
@@ -69,7 +72,8 @@ private:
PointCloudToDepthConverter::CameraParams loadCameraParams();
void syncCallback(const sensor_msgs::msg::PointCloud2::ConstSharedPtr cloud_msg,
const sensor_msgs::msg::CompressedImage::ConstSharedPtr image_msg);
// const sensor_msgs::msg::CompressedImage::ConstSharedPtr image_msg,
const sensor_msgs::msg::Image::ConstSharedPtr color_msg);
void publishDepthImage(const cv::Mat &img,
+4 -2
View File
@@ -48,14 +48,16 @@ private:
std::string cloud_raw_topic_;
std::string color_raw_topic_;
std::string color_compressed_topic_;
std::string depth_image_topic_;
std::string depth_cloud_topic_;
message_filters::Subscriber<sensor_msgs::PointCloud2> cloud_sub_;
message_filters::Subscriber<sensor_msgs::Image> color_sub_;
message_filters::Subscriber<sensor_msgs::CompressedImage> color_compressed_sub_;
typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::PointCloud2, sensor_msgs::CompressedImage> MySyncPolicy;
typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::PointCloud2, sensor_msgs::Image> MySyncPolicy;
typedef message_filters::Synchronizer<MySyncPolicy> Sync;
std::shared_ptr<Sync> sync_;
@@ -68,7 +70,7 @@ private:
void syncCallback(const sensor_msgs::PointCloud2ConstPtr &cloud_msg,
const sensor_msgs::CompressedImageConstPtr &image_msg);
const sensor_msgs::ImageConstPtr &image_msg);
void publishDepthImage(const cv::Mat &img,
+165 -55
View File
@@ -43,6 +43,15 @@ limitations under the License.
#include <sys/types.h>
#include <sys/wait.h>
#include <yaml-cpp/yaml.h>
#include "polynomial_camera.hpp"
struct CameraParams {
int width, height;
double fx, fy, cx, cy, skew;
double k2, k3, k4, k5, k6, k7;
double p1, p2;
};
#define LOG_LEVEL_NONE 0
#define LOG_LEVEL_ERROR 1
@@ -128,21 +137,9 @@ extern int g_sendcloudrender;
#endif
// Common definitions
#define GD_ACCL_G 9.7833f
#define ACC_1G_ms2 9.8
#define ACC_SEN_SCALE 4096
#define PAI 3.14159265358979323846
#define GYRO_SEN_SCALE 16.4f
#define DTOF_NUM_ROW_PER_GROUP 6
// Common functions
inline float accel_convert(int16_t raw, int sen_scale) {
return (raw * GD_ACCL_G / sen_scale);
}
inline float gyro_convert(int16_t raw, float sen_scale) {
return (raw * PAI) / (sen_scale * 180);
}
inline ros::Time ns_to_ros_time(uint64_t timestamp_ns) {
ros::Time t;
#ifdef ROS2
@@ -211,7 +208,7 @@ public:
}
rawCloudRender render_;
void publishImu(icm_6aixs_data_t *stream) {
void publishImu(imu_convert_data_t *stream) {
#ifdef ROS2
sensor_msgs::msg::Imu imu_msg;
#else
@@ -220,15 +217,15 @@ public:
imu_msg.header.stamp = ns_to_ros_time(stream->stamp);
imu_msg.header.frame_id = "imu_link";
imu_msg.linear_acceleration.y = -1 * static_cast<double>(accel_convert(stream->aacx, ACC_SEN_SCALE));
imu_msg.linear_acceleration.x = static_cast<double>(accel_convert(stream->aacy, ACC_SEN_SCALE));
imu_msg.linear_acceleration.z = static_cast<double>(accel_convert(stream->aacz, ACC_SEN_SCALE));
imu_msg.angular_velocity.y = -1 * static_cast<double>(gyro_convert(stream->gyrox, GYRO_SEN_SCALE));
imu_msg.angular_velocity.x = static_cast<double>(gyro_convert(stream->gyroy, GYRO_SEN_SCALE));
imu_msg.angular_velocity.z = static_cast<double>(gyro_convert(stream->gyroz, GYRO_SEN_SCALE));
imu_msg.linear_acceleration.y = -1 * stream->accel_x;
imu_msg.linear_acceleration.x = stream->accel_y;
imu_msg.linear_acceleration.z = stream->accel_z;
imu_msg.angular_velocity.y = -1 * stream->gyro_x;
imu_msg.angular_velocity.x = stream->gyro_y;
imu_msg.angular_velocity.z = stream->gyro_z;
imu_msg.orientation.x = 0.0;
imu_msg.orientation.y = 0.0;
imu_msg.orientation.z = 0.0;
@@ -552,8 +549,7 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
//std::cout << stream->imageCount << std::endl;
float dtof_subframe_odr = getRosNodeControl()->getDtofSubframeODR() / 1000.0f;
// printf("dtof_subframe_odr: %f\n", dtof_subframe_odr);
int valid_points = 0;
if (stream->imageCount == 4) {
uint8_t* intensity_data = static_cast<uint8_t*>(stream->imageList[2].pAddr);
@@ -561,25 +557,29 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
for (int i = 0; i < total_points; ++i) {
if (confidence_data[i] < 35) {
continue;
}
// XYZ point
*iter_x = xyz_data_f[i * 3 + 2] / 1000.0f; ++iter_x;
*iter_y = -xyz_data_f[i * 3 + 0] / 1000.0f; ++iter_y;
*iter_z = xyz_data_f[i * 3 + 1] / 1000.0f; ++iter_z;
*iter_intensity = intensity_data[i]; ++iter_intensity;
*iter_confidence = confidence_data[i]; ++iter_confidence;
if (dtof_subframe_odr > 0.0) {
int group = i / DTOF_NUM_ROW_PER_GROUP;
float timestamp_offset = group * 1.0 / dtof_subframe_odr;
*iter_x = 0.0f; ++iter_x;
*iter_y = 0.0f; ++iter_y;
*iter_z = 0.0f; ++iter_z;
*iter_intensity = 0; ++iter_intensity;
*iter_confidence = 0; ++iter_confidence;
*iter_offsettime = 0.0f; ++iter_offsettime;
} else {
// XYZ point
*iter_x = xyz_data_f[i * 3 + 2] / 1000.0f; ++iter_x;
*iter_y = -xyz_data_f[i * 3 + 0] / 1000.0f; ++iter_y;
*iter_z = xyz_data_f[i * 3 + 1] / 1000.0f; ++iter_z;
*iter_intensity = intensity_data[i]; ++iter_intensity;
*iter_confidence = confidence_data[i]; ++iter_confidence;
if (dtof_subframe_odr > 0.0) {
int group = i / DTOF_NUM_ROW_PER_GROUP;
float timestamp_offset = group * 1.0 / dtof_subframe_odr;
*iter_offsettime = timestamp_offset;
++iter_offsettime;
*iter_offsettime = timestamp_offset;
++iter_offsettime;
}
}
valid_points++;
}
} else {
uint16_t* intensity_data = static_cast<uint16_t*>(stream->imageList[2].pAddr);
@@ -601,8 +601,6 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
*iter_confidence = 0;
++iter_confidence;
valid_points++;
}
}
@@ -657,9 +655,9 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
//Create ROS image message
#ifdef ROS2
auto header = std::make_shared<std_msgs::msg::Header>();
header->stamp = ns_to_ros_time(image.timestamp + 719060); // Offset compensation
header->stamp = ns_to_ros_time(image.timestamp); // Offset compensation
//RCLCPP_INFO(rclcpp::get_logger("device_cb"), "image rgb %ld",image.timestamp + 719060);
//RCLCPP_INFO(rclcpp::get_logger("device_cb"), "image rgb %ld",image.timestamp);
header->frame_id = "camera_rgb_frame";
auto cv_image = std::make_shared<cv_bridge::CvImage>(*header, "bgr8", bgr);
@@ -693,7 +691,7 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
// Enqueue binary logging for image
if (data_logger_) {
const uint32_t idx_now = image_index_.fetch_add(1, std::memory_order_relaxed);
const double ts_sec = static_cast<double>(image.timestamp + 719060) / 1e9;
const double ts_sec = static_cast<double>(image.timestamp) / 1e9;
const uint32_t jpeg_size = static_cast<uint32_t>(compressed_msg->data.size());
std::vector<uint8_t> blob;
blob.reserve(sizeof(uint32_t) + sizeof(double) + sizeof(uint32_t) + jpeg_size);
@@ -713,7 +711,7 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
#else
// ROS1 version
std_msgs::Header header;
header.stamp = ns_to_ros_time(image.timestamp + 719060); // Offset compensation
header.stamp = ns_to_ros_time(image.timestamp); // Offset compensation
header.frame_id = "camera_rgb_frame";
auto cv_image = boost::make_shared<cv_bridge::CvImage>(header, "bgr8", bgr);
@@ -785,7 +783,7 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
cv::Mat decoded_image = cv::imdecode(jpeg_data, cv::IMREAD_COLOR);
cv_bridge::CvImage cv_image;
cv_image.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp + 719060);
cv_image.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp);
cv_image.encoding = "bgr8";
cv_image.image = decoded_image;
@@ -800,7 +798,7 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
// Enqueue binary logging for image
if (data_logger_) {
const uint32_t idx_now = image_index_.fetch_add(1, std::memory_order_relaxed);
const double ts_sec = static_cast<double>(stream->imageList[0].timestamp + 719060) / 1e9;
const double ts_sec = static_cast<double>(stream->imageList[0].timestamp) / 1e9;
const uint32_t jpeg_size = static_cast<uint32_t>(jpeg_data.size());
std::vector<uint8_t> blob;
blob.reserve(sizeof(uint32_t) + sizeof(double) + sizeof(uint32_t) + jpeg_size);
@@ -815,13 +813,26 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
data_logger_->enqueueImageFrame(std::move(blob));
}
// undistort image
cv::Mat undistorted_image = cv::Mat::zeros(decoded_image.size(), decoded_image.type());
cv_bridge::CvImage cv_undistorted_image;
if (m_undistort_map_init_success) {
cv::remap(decoded_image, undistorted_image, m_undistort_map_x, m_undistort_map_y, cv::INTER_LINEAR);
cv_undistorted_image.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp);
cv_undistorted_image.encoding = "bgr8";
cv_undistorted_image.image = undistorted_image;
}
#ifdef ROS2
{
rgb_pub_->publish(*cv_image.toImageMsg());
if (m_undistort_map_init_success) {
undistort_rgb_pub_->publish(*cv_undistorted_image.toImageMsg());
}
// original jpeg
sensor_msgs::msg::CompressedImage jpeg_msg;
jpeg_msg.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp + 719060);
jpeg_msg.header.stamp = ns_to_ros_time(stream->imageList[0].timestamp);
jpeg_msg.format = "jpeg";
jpeg_msg.data = jpeg_data;
@@ -830,12 +841,15 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
#else
{
rgb_pub_.publish(cv_image.toImageMsg());
if (m_undistort_map_init_success) {
undistort_rgb_pub_.publish(cv_undistorted_image.toImageMsg());
}
// original jpeg
sensor_msgs::CompressedImagePtr jpeg_msg(new sensor_msgs::CompressedImage());
// compressed_msg->header = header;
// compressed_msg->format = "jpeg";
jpeg_msg->header.stamp = ns_to_ros_time(stream->imageList[0].timestamp + 719060);
jpeg_msg->header.stamp = ns_to_ros_time(stream->imageList[0].timestamp);
jpeg_msg->format = "jpeg";
jpeg_msg->data = jpeg_data;
@@ -977,7 +991,7 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
#endif
}
void publishOdometry(capture_Image_List_t* stream) {
void publishOdometry(capture_Image_List_t* stream, bool is_highfreq) {
#ifdef ROS2
auto msg = nav_msgs::msg::Odometry();
@@ -1062,9 +1076,17 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
}
#ifdef ROS2
odom_publisher_->publish(std::move(msg));
if (is_highfreq) {
odom_highfreq_publisher_->publish(std::move(msg));
} else {
odom_publisher_->publish(std::move(msg));
}
#else
odom_publisher_.publish(msg);
if (is_highfreq) {
odom_highfreq_publisher_.publish(msg);
} else {
odom_publisher_.publish(msg);
}
#endif
}
@@ -1088,6 +1110,81 @@ void process_pair(const ImageConstPtr &rgb_msg, const PointCloud2ConstPtr &pcd_m
}
}
int loadCameraParams(const std::string& yaml_file) {
try {
YAML::Node config = YAML::LoadFile(yaml_file);
YAML::Node cam_node = config["cam_0"];
m_camera_params.width = cam_node["image_width"].as<int>();
m_camera_params.height = cam_node["image_height"].as<int>();
double A11 = cam_node["A11"].as<double>();
double A12 = cam_node["A12"].as<double>();
double A22 = cam_node["A22"].as<double>();
double u0 = cam_node["u0"].as<double>();
double v0 = cam_node["v0"].as<double>();
m_camera_params.fx = A11;
m_camera_params.fy = A22;
m_camera_params.cx = u0;
m_camera_params.cy = v0;
m_camera_params.skew = A12;
m_camera_params.k2 = cam_node["k2"].as<double>();
m_camera_params.k3 = cam_node["k3"].as<double>();
m_camera_params.k4 = cam_node["k4"].as<double>();
m_camera_params.k5 = cam_node["k5"].as<double>();
m_camera_params.k6 = cam_node["k6"].as<double>();
m_camera_params.k7 = cam_node["k7"].as<double>();
m_camera_params.p1 = cam_node["p1"].as<double>();
m_camera_params.p2 = cam_node["p2"].as<double>();
#if 0
std::cout << "成功读取相机参数:" << std::endl;
std::cout << "图像尺寸: " << m_camera_params.width << "x" << m_camera_params.height << std::endl;
std::cout << "焦距: fx=" << m_camera_params.fx << ", fy=" << m_camera_params.fy << std::endl;
std::cout << "主点: cx=" << m_camera_params.cx << ", cy=" << m_camera_params.cy << std::endl;
std::cout << "倾斜: " << m_camera_params.skew << std::endl;
std::cout << "畸变系数: k2=" << m_camera_params.k2 << ", k3=" << m_camera_params.k3
<< ", k4=" << m_camera_params.k4 << ", k5=" << m_camera_params.k5
<< ", k6=" << m_camera_params.k6 << ", k7=" << m_camera_params.k7 << std::endl;
#endif
m_cam = std::make_unique<mini_vikit::PolynomialCamera>(m_camera_params.width, m_camera_params.height,
m_camera_params.fx, m_camera_params.fy, m_camera_params.cx, m_camera_params.cy, m_camera_params.skew,
m_camera_params.k2, m_camera_params.k3, m_camera_params.k4, m_camera_params.k5, m_camera_params.k6, m_camera_params.k7);
m_cam_init_success = true;
return 0;
} catch (const std::exception& e) {
std::cerr << "读取YAML文件失败: " << e.what() << std::endl;
m_cam_init_success = false;
return -1;
}
}
void buildUndistortMap()
{
m_undistort_map_x.create(m_camera_params.height, m_camera_params.width, CV_32F);
m_undistort_map_y.create(m_camera_params.height, m_camera_params.width, CV_32F);
for (int v_out = 0; v_out < m_camera_params.height; ++v_out) {
for (int u_out = 0; u_out < m_camera_params.width; ++u_out) {
double x_norm = (u_out - m_cam->cx()) / m_cam->fx();
double y_norm = (v_out - m_cam->cy()) / m_cam->fy();
// remove skew
x_norm = x_norm - y_norm * m_cam->skew() / m_cam->fx();
Eigen::Vector2d uv(x_norm, y_norm);
Eigen::Vector2d distorted_pixel = m_cam->world2cam(uv);
m_undistort_map_x.at<float>(v_out, u_out) = static_cast<float>(distorted_pixel[0]);
m_undistort_map_y.at<float>(v_out, u_out) = static_cast<float>(distorted_pixel[1]);
}
}
m_undistort_map_init_success = true;
}
private:
// Add the following member variables
std::mutex rgb_queue_mutex_;
@@ -1132,7 +1229,12 @@ private:
return images;
}
CameraParams m_camera_params;
std::unique_ptr<mini_vikit::PolynomialCamera> m_cam;
bool m_cam_init_success;
bool m_undistort_map_init_success = false;
cv::Mat m_undistort_map_x;
cv::Mat m_undistort_map_y;
#ifdef ROS2
std::vector<sensor_msgs::msg::PointCloud2> getIntensityCloudQueueSnapshot() {
std::lock_guard<std::mutex> lock(pcd_queue_mutex_);
@@ -1164,8 +1266,10 @@ private:
cloud_pub_ = node_->create_publisher<ros::PointCloud2>("odin1/cloud_raw", 10);
xyzrgbacloud_pub_ = node_->create_publisher<ros::PointCloud2>("odin1/cloud_slam", 10);
odom_publisher_ = node_->create_publisher<ros::Odometry>("odin1/odometry", 10);
odom_highfreq_publisher_ = node_->create_publisher<ros::Odometry>("odin1/odometry_highfreq", 10);
rgbcloud_pub_ = node_->create_publisher<sensor_msgs::msg::PointCloud2>("odin1/cloud_render", 10);
compressed_rgb_pub_ = node_->create_publisher<sensor_msgs::msg::CompressedImage>("odin1/image/compressed", 10);
undistort_rgb_pub_ = node_->create_publisher<sensor_msgs::msg::Image>("odin1/image/undistorted", 10);
#endif
}
#ifdef ROS1
@@ -1175,8 +1279,10 @@ private:
cloud_pub_ = nh.advertise<ros::PointCloud2>("odin1/cloud_raw", 10);
xyzrgbacloud_pub_ = nh.advertise<ros::PointCloud2>("odin1/cloud_slam", 10);
odom_publisher_ = nh.advertise<ros::Odometry>("odin1/odometry", 10);
odom_highfreq_publisher_ = nh.advertise<ros::Odometry>("odin1/odometry_highfreq", 10);
rgbcloud_pub_ = nh.advertise<sensor_msgs::PointCloud2>("odin1/cloud_render", 10);
compressed_rgb_pub_ = nh.advertise<sensor_msgs::CompressedImage>("odin1/image/compressed", 10);
undistort_rgb_pub_ = nh.advertise<sensor_msgs::Image>("odin1/image/undistorted", 10);
}
#endif
@@ -1187,20 +1293,24 @@ private:
rclcpp::Publisher<ros::PointCloud2>::SharedPtr cloud_pub_;
rclcpp::Publisher<ros::PointCloud2>::SharedPtr xyzrgbacloud_pub_;
rclcpp::Publisher<ros::Odometry>::SharedPtr odom_publisher_;
rclcpp::Publisher<ros::Odometry>::SharedPtr odom_highfreq_publisher_;
rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr rendered_cloud_pub_;
rclcpp::Publisher<PointCloud2Msg>::SharedPtr rgbcloud_pub_;
rclcpp::Publisher<ImageMsg>::SharedPtr rgbFromnv12_pub_;
rclcpp::Publisher<sensor_msgs::msg::CompressedImage>::SharedPtr compressed_rgb_pub_; // New compressed image publisher
rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr undistort_rgb_pub_;
#else
ros::Publisher imu_pub_;
ros::Publisher rgb_pub_;
ros::Publisher cloud_pub_;
ros::Publisher xyzrgbacloud_pub_;
ros::Publisher odom_publisher_;
ros::Publisher odom_highfreq_publisher_;
ros::Publisher rendered_cloud_pub_;
ros::Publisher rgbcloud_pub_;
ros::Publisher rgbFromnv12_pub_;
ros::Publisher compressed_rgb_pub_; // New compressed image publisher
ros::Publisher undistort_rgb_pub_;
#endif
};
+74 -13
View File
@@ -53,6 +53,8 @@ typedef enum {
LIDAR_DT_RAW_DTOF = 1 << 3,
LIDAR_DT_SLAM_CLOUD = 1 << 4,
LIDAR_DT_SLAM_ODOMETRY = 1 << 5,
LIDAR_DT_DEV_STATUS = 1 << 6,
LIDAR_DT_SLAM_ODOMETRY_HIGHFREQ = 1 << 7,
} lidar_data_type_e;
typedef struct {
@@ -90,19 +92,16 @@ typedef struct {
int64_t cov[3 * 3 * 2];
} ros_odom_convert_complete_t;
typedef struct icm_6aixs_data_t {
int16_t aacx;
int16_t aacy;
int16_t aacz;
int16_t gyrox;
int16_t gyroy;
int16_t gyroz;
uint8_t valid;
uint32_t nums;
uint8_t fsync_pack;
uint16_t interval;
uint64_t stamp;
} icm_6aixs_data_t;
typedef struct {
float accel_x;
float accel_y;
float accel_z;
float gyro_x;
float gyro_y;
float gyro_z;
uint64_t stamp;
uint64_t sequence;
} imu_convert_data_t;
typedef struct {
uint32_t length;
@@ -140,6 +139,68 @@ typedef struct {
char host_app_version[64];
} lidar_version_t;
/**
* @brief RGB image sensor frame rate
*
*/
typedef struct{
int configured_odr; /* rgb image sensor configured output data rate */
int tx_odr; /* rgb image sensor tx output data rate */
} lidar_rgb_sensor_status_t;
/**
* @brief DTOF Lidar frame rate
*
*/
typedef struct{
int configured_odr; /* dtof lidar sensor configured output data rate */
int tx_odr; /* dtof lidar sensor tx output data rate */
int subframe_odr; /* dtof lidar sensor subframe output data rate */
short tx_temp; /* dtof lidar tx module temp */
short rx_temp; /* dtof lidar rx module temp */
} lidar_dtof_sensor_status_t;
/**
* @brief IMU Sensor
*
*/
typedef struct{
int configured_odr; /* imu sensor configured output data rate */
int tx_odr; /* imu sensor tx output data rate */
} lidar_imu_sensor_status_t;
typedef struct{
int package_temp; /* soc package temp */
int cpu_temp; /* cpu temp */
int center_temp; /* center temp */
int gpu_temp; /* gpu temp */
int npu_temp; /* npu temp */
} lidar_soc_thermal_t;
typedef struct
{
lidar_soc_thermal_t soc_thermal;
int cpu_use_rate[8]; /* cpu usage rate */
int ram_use_rate; /* ram usage rate */
lidar_rgb_sensor_status_t rgb_sensor;
lidar_dtof_sensor_status_t dtof_sensor;
lidar_imu_sensor_status_t imu_sensor;
int slam_cloud_tx_odr; /* slam cloud tx output data rate */
int slam_odom_tx_odr; /* slam odom tx output data rate */
int slam_odom_highfreq_tx_odr; /* slam odom high freq tx output data rate */
} lidar_device_status_t;
#ifdef __cplusplus
}
#endif
+144
View File
@@ -0,0 +1,144 @@
/*
Copyright 2025 Manifold Tech Ltd.(www.manifoldtech.com.co)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <Eigen/Dense>
#include <cmath>
namespace mini_vikit {
using namespace Eigen;
class PolynomialCamera {
private:
const double fx_, fy_;
const double cx_, cy_;
const double skew_;
bool distortion_;
double k2_, k3_, k4_, k5_, k6_, k7_;
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
PolynomialCamera(double width, double height,
double fx, double fy, double cx, double cy, double skew,
double k2=0.0, double k3=0.0, double k4=0.0,
double k5=0.0, double k6=0.0, double k7=0.0)
: fx_(fx), fy_(fy), cx_(cx), cy_(cy), skew_(skew),
distortion_(std::abs(k2) > 1e-7) {
k2_ = k2; k3_ = k3; k4_ = k4; k5_ = k5; k6_ = k6; k7_ = k7;
}
Vector3d cam2world(const double& u, const double& v) const {
Vector3d xyz;
if (!distortion_) {
double y = (v - cy_) / fy_;
double x = (u - cx_ - y * skew_) / fx_;
xyz << x, y, 1.0;
} else {
double y = (v - cy_) / fy_;
double x = (u - cx_ - y * skew_) / fx_;
const double thetad = std::sqrt(x * x + y * y);
double theta = thetad;
for (int i = 0; i < 7; ++i) {
const double theta2 = theta * theta;
const double theta3 = theta2 * theta;
const double theta4 = theta3 * theta;
const double theta5 = theta4 * theta;
const double theta6 = theta5 * theta;
theta = thetad / (1.0 + k2_ * theta + k3_ * theta2 + k4_ * theta3 +
k5_ * theta4 + k6_ * theta5 + k7_ * theta6);
}
const double scaling = std::tan(theta) / thetad;
x *= scaling;
y *= scaling;
xyz << x, y, 1.0;
}
return xyz.normalized();
}
Vector3d cam2world(const Vector2d& px) const {
return cam2world(px[0], px[1]);
}
Vector2d world2cam(const Vector3d& xyz) const {
Vector2d px;
if (!distortion_) {
px[0] = fx_ * xyz[0] + cx_;
px[1] = fy_ * xyz[1] + cy_;
} else {
double xd, yd;
const double r = std::sqrt(xyz(1) * xyz(1) + xyz(0) * xyz(0));
const double theta = std::acos(xyz(2) / xyz.norm());
const double thetad = thetad_from_theta(theta);
const double scaling = thetad / r;
xd = xyz[0] * scaling;
yd = xyz[1] * scaling;
px[0] = xd * fx_ + yd * skew_ + cx_;
px[1] = yd * fy_ + cy_;
}
return px;
}
Vector2d world2cam(const Vector2d& uv) const {
Vector2d px;
if (!distortion_) {
px[0] = fx_ * uv[0] + cx_;
px[1] = fy_ * uv[1] + cy_;
} else {
double xd, yd;
const double r = uv.norm();
if (r < 1e-8) {
return uv;
}
const double theta = std::atan(r);
const double thetad = thetad_from_theta(theta);
const double scaling = thetad / r;
xd = uv[0] * scaling;
yd = uv[1] * scaling;
px[0] = xd * fx_ + yd * skew_ + cx_;
px[1] = yd * fy_ + cy_;
}
return px;
}
inline double thetad_from_theta(const double theta) const {
const double theta2 = theta * theta;
const double theta3 = theta2 * theta;
const double theta4 = theta3 * theta;
const double theta5 = theta4 * theta;
const double theta6 = theta5 * theta;
const double theta7 = theta6 * theta;
const double thetad = theta + k2_ * theta2 + k3_ * theta3 +
k4_ * theta4 + k5_ * theta5 + k6_ * theta6 + k7_ * theta7;
return thetad;
}
double fx() const { return fx_; }
double fy() const { return fy_; }
double cx() const { return cx_; }
double cy() const { return cy_; }
double skew() const { return skew_; }
bool has_distortion() const { return distortion_; }
double k2() const { return k2_; }
double k3() const { return k3_; }
double k4() const { return k4_; }
double k5() const { return k5_; }
double k6() const { return k6_; }
double k7() const { return k7_; }
};
} // namespace mini_vikit
Binary file not shown.
Binary file not shown.
Executable
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<package format="3">
<name>odin_ros_driver</name>
<version>0.0.1</version>
<description>ROS driver for Odin sensor</description>
<maintainer email="[email protected]">rlk</maintainer>
<license>Apache 2.0</license>
<!-- ROS1 uses catkin as the build tool -->
<buildtool_depend>catkin</buildtool_depend>
<!-- ROS1 dependencies -->
<depend>roscpp</depend>
<depend>std_msgs</depend>
<depend>sensor_msgs</depend>
<depend>nav_msgs</depend>
<depend>cv_bridge</depend>
<depend>image_transport</depend>
<!-- System dependencies -->
<depend>eigen</depend>
<depend>opencv</depend>
<depend>yaml-cpp</depend>
<!-- Specify build type as catkin -->
<export>
<build_type>catkin</build_type>
</export>
</package>
+9 -3
View File
@@ -10,12 +10,14 @@ DepthImageRos2Node::DepthImageRos2Node(const rclcpp::NodeOptions & options)
cloud_raw_topic_ = this->declare_parameter<std::string>("cloud_raw_topic", "/odin1/cloud_raw");
color_compressed_topic_ = this->declare_parameter<std::string>("color_compressed_topic", "/odin1/image/compressed");
color_raw_topic_ = this->declare_parameter<std::string>("color_raw_topic", "/odin1/image");
depth_image_topic_ = this->declare_parameter<std::string>("depth_image_topic", "/odin1/depth_img_competetion");
depth_cloud_topic_ = this->declare_parameter<std::string>("depth_cloud_topic", "/odin1/depth_img_competetion_cloud");
RCLCPP_INFO_STREAM(this->get_logger(),
"\n cloud_raw_topic: " << cloud_raw_topic_
<< "\n color_compressed_topic: " << color_compressed_topic_
<< "\n color_raw_topic: " << color_raw_topic_
<< "\n depth_image_topic: " << depth_image_topic_
<< "\n depth_cloud_topic: " << depth_cloud_topic_);
}
@@ -24,8 +26,9 @@ void DepthImageRos2Node::initialize()
{
cloud_sub_.subscribe(this, cloud_raw_topic_);
color_compressed_sub_.subscribe(this, color_compressed_topic_);
color_sub_.subscribe(this, color_raw_topic_);
sync_ = std::make_shared<Sync>(MySyncPolicy(10), cloud_sub_, color_compressed_sub_);
sync_ = std::make_shared<Sync>(MySyncPolicy(10), cloud_sub_, color_sub_);
sync_->registerCallback(std::bind(&DepthImageRos2Node::syncCallback, this,
std::placeholders::_1, std::placeholders::_2));
@@ -94,7 +97,8 @@ PointCloudToDepthConverter::CameraParams DepthImageRos2Node::loadCameraParams()
}
void DepthImageRos2Node::syncCallback(const sensor_msgs::msg::PointCloud2::ConstSharedPtr cloud_msg,
const sensor_msgs::msg::CompressedImage::ConstSharedPtr image_msg)
// const sensor_msgs::msg::CompressedImage::ConstSharedPtr image_msg,
const sensor_msgs::msg::Image::ConstSharedPtr color_msg)
{
pcl::PointCloud<pcl::PointXYZ> cloud;
pcl::fromROSMsg(*cloud_msg, cloud);
@@ -107,7 +111,9 @@ void DepthImageRos2Node::syncCallback(const sensor_msgs::msg::PointCloud2::Const
cv::Mat img_raw;
try
{
img_raw = cv::imdecode(cv::Mat(image_msg->data), cv::IMREAD_COLOR);
// img_raw = cv::imdecode(cv::Mat(image_msg->data), cv::IMREAD_COLOR);
cv_bridge::CvImageConstPtr cv_ptr = cv_bridge::toCvShare(color_msg, "bgr8");
img_raw = cv_ptr->image;
if (img_raw.empty())
{
RCLCPP_WARN(this->get_logger(), "Failed to decode compressed image");
+11 -6
View File
@@ -8,19 +8,22 @@ DepthImageRosNode::DepthImageRosNode(ros::NodeHandle &nh, ros::NodeHandle &pnh)
depth_converter_ = std::make_unique<PointCloudToDepthConverter>(camera_params);
pnh_.param<std::string>("cloud_raw_topic", cloud_raw_topic_, std::string("/odin1/cloud_raw"));
pnh_.param<std::string>("color_raw_topic", color_raw_topic_, std::string("/odin1/image"));
pnh_.param<std::string>("color_compressed_topic_", color_compressed_topic_, std::string("/odin1/image/compressed"));
pnh_.param<std::string>("depth_image_topic", depth_image_topic_, std::string("/odin1/depth_img_competetion"));
pnh_.param<std::string>("depth_cloud_topic", depth_cloud_topic_, std::string("/odin1/depth_img_competetion_cloud"));
ROS_INFO_STREAM("\n cloud_raw_topic: " << cloud_raw_topic_
<< "\n color_compressed_topic: " << color_compressed_topic_
<< "\n depth_image_topic: " << depth_image_topic_
<< "\n depth_cloud_topic: " << depth_cloud_topic_);
<< "\n color_raw_topic: " << color_raw_topic_
<< "\n color_compressed_topic: " << color_compressed_topic_
<< "\n depth_image_topic: " << depth_image_topic_
<< "\n depth_cloud_topic: " << depth_cloud_topic_);
cloud_sub_.subscribe(nh_, cloud_raw_topic_, 1);
color_sub_.subscribe(nh_, color_raw_topic_, 1);
color_compressed_sub_.subscribe(nh_, color_compressed_topic_, 1);
sync_ = std::make_shared<Sync>(MySyncPolicy(10), cloud_sub_, color_compressed_sub_);
sync_ = std::make_shared<Sync>(MySyncPolicy(10), cloud_sub_, color_sub_);
sync_->registerCallback(boost::bind(&DepthImageRosNode::syncCallback, this, _1, _2));
depth_image_pub_ = it_.advertise(depth_image_topic_, 1);
@@ -88,7 +91,7 @@ PointCloudToDepthConverter::CameraParams DepthImageRosNode::loadCameraParams()
}
void DepthImageRosNode::syncCallback(const sensor_msgs::PointCloud2ConstPtr &cloud_msg,
const sensor_msgs::CompressedImageConstPtr &image_msg)
const sensor_msgs::ImageConstPtr &image_msg)
{
pcl::PointCloud<pcl::PointXYZ> cloud;
pcl::fromROSMsg(*cloud_msg, cloud);
@@ -101,7 +104,9 @@ void DepthImageRosNode::syncCallback(const sensor_msgs::PointCloud2ConstPtr &clo
cv::Mat img_raw;
try
{
img_raw = cv::imdecode(cv::Mat(image_msg->data), cv::IMREAD_COLOR);
// img_raw = cv::imdecode(cv::Mat(image_msg->data), cv::IMREAD_COLOR);
cv_bridge::CvImageConstPtr cv_ptr = cv_bridge::toCvShare(image_msg, "bgr8");
img_raw = cv_ptr->image;
if (img_raw.empty())
{
ROS_WARN("Failed to decode compressed image");
+331 -35
View File
@@ -17,11 +17,12 @@
#include <sys/wait.h>
#include <signal.h>
#include <chrono>
#include <filesystem>
#include <fstream>
#include <vector>
#include <cstdio>
#include <array>
#include <yaml-cpp/yaml.h>
// #include <yaml-cpp/yaml.h>
#include <iomanip>
#ifdef ROS2
#include <ament_index_cpp/get_package_share_directory.hpp>
@@ -30,7 +31,7 @@
#include <ros/package.h>
#include <ros/ros.h>
#endif
#define ros_driver_version "0.4.1"
#define ros_driver_version "0.5.0"
// Global variable declarations
static device_handle odinDevice = nullptr;
static std::atomic<bool> deviceConnected(false);
@@ -67,7 +68,53 @@ int g_sendodom = 1;
int g_sendcloudslam = 0;
int g_sendcloudrender = 0;
int g_sendrgb_compressed = 0;
int g_sendrgb_undistort = 0;
int g_record_data = 0;
int g_devstatus_log = 0;
const char* DEV_STATUS_CSV_FILE = "dev_status.csv";
FILE* dev_status_csv_file = nullptr;
typedef struct {
struct timespec start = {0, 0};
double frame_count = 0.0;
std::atomic<double> fps;
} fpsHandle;
static void sensor_fps(fpsHandle* handle, const char* name, bool print = false)
{
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if (handle->start.tv_sec == 0 && handle->start.tv_nsec == 0) {
handle->start = now;
}
handle->frame_count += 1.0;
double elapsed = (now.tv_sec - handle->start.tv_sec)
+ (now.tv_nsec - handle->start.tv_nsec) / 1e9;
if (elapsed >= 1.0) {
handle->fps.store(handle->frame_count / elapsed);
if (print) {
#ifdef ROS2
RCLCPP_INFO(rclcpp::get_logger("device_cb"), "%s FPS: %f", name, handle->fps.load());
#else
ROS_INFO("%s FPS: %f", name, handle->fps.load());
#endif
}
handle->frame_count = 0;
handle->start = now;
}
}
static fpsHandle rgb_rx_fps;
static fpsHandle dtof_rx_fps;
static fpsHandle imu_rx_fps;
static fpsHandle slam_cloud_rx_fps;
static fpsHandle slam_odom_rx_fps;
static fpsHandle slam_odom_highfreq_rx_fps;
class RosNodeControlImpl : public RosNodeControlInterface {
public:
@@ -353,6 +400,8 @@ static void lidar_data_callback(const lidar_data_t *data, void *user_data)
printf("Invalid device handle or data.\n");
return;
}
imu_convert_data_t *imudata = nullptr;
lidar_device_status_t *dev_info_data;
switch(data->type) {
case LIDAR_DT_NONE:
@@ -362,25 +411,166 @@ static void lidar_data_callback(const lidar_data_t *data, void *user_data)
if (g_sendrgb) {
g_ros_object->publishRgb((capture_Image_List_t *)&data->stream);
}
sensor_fps(&rgb_rx_fps, "rgb_rx");
break;
case LIDAR_DT_RAW_IMU:
if (g_sendimu) {
g_ros_object->publishImu((icm_6aixs_data_t *)data->stream.imageList[0].pAddr);
imudata = (imu_convert_data_t *)data->stream.imageList[0].pAddr;
g_ros_object->publishImu(imudata);
}
sensor_fps(&imu_rx_fps, "imu_rx");
break;
case LIDAR_DT_RAW_DTOF:
if (g_senddtof ) {
g_ros_object->publishIntensityCloud((capture_Image_List_t *)&data->stream, 1);
if (g_senddtof ) {
g_ros_object->publishIntensityCloud((capture_Image_List_t *)&data->stream, 1);
}
break;
sensor_fps(&dtof_rx_fps, "dtof_rx");
break;
case LIDAR_DT_SLAM_CLOUD:
if (g_sendcloudslam) {
g_ros_object->publishPC2XYZRGBA((capture_Image_List_t *)&data->stream, 0);
}
sensor_fps(&slam_cloud_rx_fps, "slam_cloud_rx");
break;
case LIDAR_DT_SLAM_ODOMETRY:
if (g_sendodom) {
g_ros_object->publishOdometry((capture_Image_List_t *)&data->stream);
g_ros_object->publishOdometry((capture_Image_List_t *)&data->stream, false);
}
sensor_fps(&slam_odom_rx_fps, "slam_odom_rx");
break;
case LIDAR_DT_DEV_STATUS:
dev_info_data = (lidar_device_status_t *)data->stream.imageList[0].pAddr;
if (g_devstatus_log) {
if (dev_status_csv_file) {
// append the data row
int rc = 0;
rc = std::fprintf(dev_status_csv_file, "%d,%d,%d,%d,%d,%d,", // %.0f
// get_uptime_seconds(),
0,
dev_info_data->soc_thermal.package_temp,
dev_info_data->soc_thermal.cpu_temp,
dev_info_data->soc_thermal.center_temp,
dev_info_data->soc_thermal.gpu_temp,
dev_info_data->soc_thermal.npu_temp);
if (rc < 0) {
printf("Failed to write to dev_status_csv_file\n");
}
rc = std::fprintf(dev_status_csv_file, "%d,%d,",
dev_info_data->dtof_sensor.tx_temp,
dev_info_data->dtof_sensor.rx_temp);
if (rc < 0) {
printf("Failed to write to dev_status_csv_file\n");
}
for (int i = 0; i < 8; i++) {
rc = std::fprintf(dev_status_csv_file, "%d,", dev_info_data->cpu_use_rate[i]);
}
rc = std::fprintf(dev_status_csv_file, "%d,", dev_info_data->ram_use_rate);
rc = std::fprintf(dev_status_csv_file, "%.2f,%.2f,%.2f,",
((float)dev_info_data->rgb_sensor.configured_odr)/1000,
((float)dev_info_data->rgb_sensor.tx_odr)/1000,
(rgb_rx_fps.fps.load()));
if (rc < 0) {
printf("Failed to write to dev_status_csv_file\n");
}
rc = std::fprintf(dev_status_csv_file, "%.2f,%.2f,%.2f,",
((float)dev_info_data->dtof_sensor.configured_odr)/1000,
((float)dev_info_data->dtof_sensor.tx_odr)/1000,
(dtof_rx_fps.fps.load()));
if (rc < 0) {
printf("Failed to write to dev_status_csv_file\n");
}
rc = std::fprintf(dev_status_csv_file, "%.2f,%.2f,%.2f,",
((float)dev_info_data->imu_sensor.configured_odr)/1000,
((float)dev_info_data->imu_sensor.tx_odr)/1000,
(imu_rx_fps.fps.load()));
if (rc < 0) {
printf("Failed to write to dev_status_csv_file\n");
}
rc = std::fprintf(dev_status_csv_file, "%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n",
((float)dev_info_data->slam_cloud_tx_odr)/1000,
(slam_cloud_rx_fps.fps.load()),
((float)dev_info_data->slam_odom_tx_odr)/1000,
(slam_odom_rx_fps.fps.load()),
((float)dev_info_data->slam_odom_highfreq_tx_odr)/1000,
(slam_odom_highfreq_rx_fps.fps.load()));
if (rc < 0) {
printf("Failed to write to dev_status_csv_file\n");
}
std::fflush(dev_status_csv_file);
}
}
if (g_show_fps) {
printf("\n [dev_info] [soc_thermal]: package_temp:%dC \n",
dev_info_data->soc_thermal.package_temp);
printf("\n [dev_info] [soc_thermal]: cpu:%dC \n",
dev_info_data->soc_thermal.cpu_temp);
printf("\n [dev_info] [soc_thermal]: center_temp:%dC \n",
dev_info_data->soc_thermal.center_temp);
printf("\n [dev_info] [soc_thermal]: gpu_temp:%dC \n",
dev_info_data->soc_thermal.gpu_temp);
printf("\n [dev_info] [soc_thermal]: npu_temp:%dC \n",
dev_info_data->soc_thermal.npu_temp);
for ( int i=0;i<8;i++)
{
printf("\n [dev_info] [cpu]: cpu_use_rate-core[%d]:%d%% \n",
i,
dev_info_data->cpu_use_rate[i]);
}
printf("\n [dev_info] [cpu]: ram_use_rate:%d%% \n",
dev_info_data->ram_use_rate);
printf("\n [dev_info] [rgb]: configured_odr: %.2f HZ, tx_odr: %.2f HZ, rx_odr: %.2f HZ \n",
((float)dev_info_data->rgb_sensor.configured_odr)/1000,
((float)dev_info_data->rgb_sensor.tx_odr)/1000,
(rgb_rx_fps.fps.load()));
printf("\n [dev_info] [dtof]: configured_odr: %.2f HZ, tx_odr: %.2f HZ, rx_odr: %.2f HZ \n",
((float)dev_info_data->dtof_sensor.configured_odr)/1000,
((float)dev_info_data->dtof_sensor.tx_odr)/1000,
(dtof_rx_fps.fps.load()));
printf("\n [dev_info] [dtof]: subframe_odr: %.2f \n",
((float)dev_info_data->dtof_sensor.subframe_odr)/1000);
printf("\n [dev_info] [dtof]: txtemp:%dC, rxtemp:%dC \n", dev_info_data->dtof_sensor.tx_temp, dev_info_data->dtof_sensor.rx_temp);
printf("\n [dev_info] [imu]: configured_odr: %.2f HZ, tx_odr: %.2f HZ, rx_odr: %.2f HZ\n",
((float) dev_info_data->imu_sensor.configured_odr)/1000,
((float) dev_info_data->imu_sensor.tx_odr)/1000,
(imu_rx_fps.fps.load())
);
printf("\n [dev_info] [slam]: slam_cloud_tx_odr: %.2f HZ, rx_odr: %.2f HZ \n",
((float)dev_info_data->slam_cloud_tx_odr)/1000,
(slam_cloud_rx_fps.fps.load())
);
printf("\n [dev_info] [slam]: slam_odom_tx_odr: %.2f HZ, rx_odr: %.2f HZ \n",
((float)dev_info_data->slam_odom_tx_odr)/1000,
(slam_odom_rx_fps.fps.load())
);
printf("\n [dev_info] [slam]: slam_odom_highfreq_tx_odr: %.2f HZ, rx_odr: %.2f HZ \n",
((float)dev_info_data->slam_odom_highfreq_tx_odr)/1000,
(slam_odom_highfreq_rx_fps.fps.load())
);
printf("\n------------------------------------------\n");
}
break;
case LIDAR_DT_SLAM_ODOMETRY_HIGHFREQ:
{
if (g_sendodom) {
g_ros_object->publishOdometry((capture_Image_List_t *)&data->stream, true);
}
sensor_fps(&slam_odom_highfreq_rx_fps, "slam_odom_highfreq_rx");
}
break;
default:
@@ -392,6 +582,7 @@ static void lidar_data_callback(const lidar_data_t *data, void *user_data)
static void lidar_device_callback(const lidar_device_info_t* device, bool attach)
{
int type = LIDAR_MODE_SLAM;
// int type = LIDAR_MODE_RAW;
static std::chrono::steady_clock::time_point software_connect_start;
static bool software_connect_timing = false;
@@ -488,7 +679,13 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach
}
if(lidar_get_version(odinDevice)) {
printf("get version failed.\n");
#ifdef ROS2
RCLCPP_ERROR(rclcpp::get_logger("device_cb"), "Failed to get device firmware version, potential incompatible, please upgrade device firmware and retry.");
#else
ROS_ERROR("Failed to get device firmware version, potential incompatible, please upgrade device firmware and retry.");
#endif
system("pkill -f rviz");
exit(1);
}
else {
printf("ros_driver_version:%s\n", ros_driver_version);
@@ -565,7 +762,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach
odinDevice = nullptr;
return;
}
uint32_t dtof_subframe_odr = 0;
if (lidar_start_stream(odinDevice, type, dtof_subframe_odr)) {
#ifdef ROS2
@@ -603,6 +800,10 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach
deviceConnected = true;
deviceDisconnected = false;
if (g_sendrgb_undistort && g_ros_object->loadCameraParams(calib_config) == 0) {
g_ros_object->buildUndistortMap();
}
#ifdef ROS2
RCLCPP_INFO(rclcpp::get_logger("device_cb"), "Software connection successful in %ld seconds",
std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - software_connect_start).count());
@@ -631,6 +832,7 @@ static void lidar_device_callback(const lidar_device_info_t* device, bool attach
#endif
}
}
int main(int argc, char *argv[])
{
#ifdef ROS2
@@ -677,33 +879,76 @@ int main(int argc, char *argv[])
g_sendcloudslam = get_key_value("sendcloudslam", 0);
g_sendcloudrender = get_key_value("sendcloudrender", 1);
g_sendrgb_compressed = get_key_value("sendrgbcompressed", 1);
g_sendrgb_undistort = get_key_value("sendrgbundistort", 0);
g_record_data = get_key_value("recorddata", 0);
g_show_fps = get_key_value("showfps", 0);
g_devstatus_log = get_key_value("devstatuslog", 0);
g_log_level = get_key_value("log_devel", LOG_LEVEL_INFO);
lidar_log_set_level(LIDAR_LOG_INFO);
if (g_record_data) {
const std::string package_name = "odin_ros_driver";
std::string data_dir = "";
#ifdef ROS2
char* ros_workspace = std::getenv("COLCON_PREFIX_PATH");
if (ros_workspace) {
std::string workspace_path(ros_workspace);
size_t pos = workspace_path.find("/install");
if (pos != std::string::npos) {
data_dir = workspace_path.substr(0, pos) + "/src/odin_ros_driver/recorddata";
} else {
data_dir = ament_index_cpp::get_package_share_directory(package_name) + "/recorddata";
}
} else {
const std::string package_name = "odin_ros_driver";
std::string data_dir = "";
std::string log_dir = "";
#ifdef ROS2
char* ros_workspace = std::getenv("COLCON_PREFIX_PATH");
if (ros_workspace) {
std::string workspace_path(ros_workspace);
size_t pos = workspace_path.find("/install");
if (pos != std::string::npos) {
data_dir = workspace_path.substr(0, pos) + "/src/odin_ros_driver/recorddata";
log_dir = workspace_path.substr(0, pos) + "/src/odin_ros_driver/log";
} else {
data_dir = ament_index_cpp::get_package_share_directory(package_name) + "/recorddata";
}
#else
data_dir = ros::package::getPath(package_name) + "/recorddata";
#endif
log_dir = ament_index_cpp::get_package_share_directory(package_name) + "/log";
}
} else {
data_dir = ament_index_cpp::get_package_share_directory(package_name) + "/recorddata";
log_dir = ament_index_cpp::get_package_share_directory(package_name) + "/log";
}
#else
data_dir = ros::package::getPath(package_name) + "/recorddata";
log_dir = ros::package::getPath(package_name) + "/log";
#endif
if (g_record_data) {
g_ros_object->initialize_data_logger(data_dir);
}
if (g_devstatus_log) {
auto now = std::chrono::system_clock::now();
std::time_t t = std::chrono::system_clock::to_time_t(now);
std::tm tm{};
#ifdef _WIN32
localtime_s(&tm, &t);
#else
localtime_r(&t, &tm);
#endif
char buf[32];
std::strftime(buf, sizeof(buf), "%Y%m%d_%H%M%S", &tm);
std::filesystem::path log_root_dir_ = std::filesystem::path(log_dir) / buf;
std::filesystem::create_directories(log_root_dir_);
std::string dev_status_csv_file_path_ = log_root_dir_ / "dev_status.csv";
// Open the file in append mode
dev_status_csv_file = fopen(dev_status_csv_file_path_.c_str(), "a");
if (!dev_status_csv_file) {
#ifdef ROS2
RCLCPP_ERROR(rclcpp::get_logger("init"), "Failed to open dev_status CSV file");
#else
ROS_ERROR("Failed to open dev_status CSV file");
#endif
} else {
const char* header =
"uptime_seconds,package_temp,cpu_temp,center_temp,gpu_temp,npu_temp,dtof_tx_temp,dtof_rx_temp,"
"cpu0,cpu1,cpu2,cpu3,cpu4,cpu5,cpu6,cpu7,ram_use,"
"rgb_configured_odr,rgb_tx_odr,rgb_rx_odr,dtof_configured_odr,dtof_tx_odr,dtof_rx_odr,imu_configured_odr,imu_tx_odr,imu_rx_odr,"
"slam_cloud_tx_odr,slam_cloud_rx_odr,slam_odom_tx_odr,slam_odom_rx_odr,slam_odom_highfreq_tx_odr,slam_odom_highfreq_rx_odr\n";
fprintf(dev_status_csv_file, "%s", header);
std::fflush(dev_status_csv_file);
}
}
if (lidar_system_init(lidar_device_callback)) {
#ifdef ROS2
RCLCPP_ERROR(node->get_logger(), "Lidar system init failed");
@@ -717,6 +962,17 @@ int main(int argc, char *argv[])
bool usbPresent = false;
bool usbVersionChecked = false;
while (!deviceConnected) {
#ifdef ROS2
if (!rclcpp::ok()) {
break;
}
#else
if (!ros::ok()) // ROS1 shutdown check
{
break;
}
#endif
usbPresent = isUsbDevicePresent(TARGET_VENDOR, TARGET_PRODUCT);
if (usbPresent) {
if (!usbVersionChecked) {
@@ -752,19 +1008,36 @@ int main(int argc, char *argv[])
return -1;
}
if (!deviceConnected) {
#ifdef ROS2
if (g_ros_object) {
g_ros_object.reset(); // destroys all publishers/subscribers
}
node.reset(); // destroy the node first
rclcpp::shutdown();
#else
if (g_ros_object) {
delete g_ros_object;
g_ros_object = nullptr;
}
ros::shutdown();
#endif
return 1;
}
bool disconnect_msg_printed = false;
#ifdef ROS2
// Create 10Hz Rate object
rclcpp::Rate rate(10);
while (rclcpp::ok()) {
rclcpp::spin_some(node);
// Check device disconnection status
if (deviceDisconnected.load()) {
#ifdef ROS2
if (!disconnect_msg_printed) {
RCLCPP_INFO(node->get_logger(), "Device disconnected, waiting for reconnection...");
#else
ROS_INFO("Device disconnected, waiting for reconnection...");
#endif
disconnect_msg_printed = true;
}
// Wait 0.1 seconds
rate.sleep();
@@ -775,6 +1048,7 @@ int main(int argc, char *argv[])
if (g_sendcloudrender) {
g_ros_object->try_process_pair();
}
disconnect_msg_printed = false;
// Wait 0.1 seconds
rate.sleep();
@@ -788,7 +1062,10 @@ int main(int argc, char *argv[])
// Check device disconnection status
if (deviceDisconnected.load()) {
ROS_INFO("Device disconnected, waiting for reconnection...");
if (!disconnect_msg_printed) {
ROS_INFO("Device disconnected, waiting for reconnection...");
disconnect_msg_printed = true;
}
// Wait 0.1 seconds
rate.sleep();
@@ -799,6 +1076,7 @@ int main(int argc, char *argv[])
if (g_sendcloudrender) {
g_ros_object->try_process_pair();
}
disconnect_msg_printed = false;
// Wait 0.1 seconds
rate.sleep();
@@ -823,10 +1101,28 @@ int main(int argc, char *argv[])
ROS_INFO("image_index: %d", g_ros_object->get_image_index());
#endif
// Perform cleanup on normal exit
// lidar_stop_stream(odinDevice, LIDAR_MODE_SLAM);
// lidar_unregister_stream_callback(odinDevice);
// if(lidar_stop_stream(odinDevice, LIDAR_MODE_SLAM))
// {
// #ifdef ROS2
// RCLCPP_INFO(rclcpp::get_logger("device_cb"), "lidar_stop_stream failed");
// #else
// ROS_INFO("lidar_stop_stream failed");
// #endif
// }
if(lidar_unregister_stream_callback(odinDevice))
{
#ifdef ROS2
RCLCPP_INFO(rclcpp::get_logger("device_cb"), "lidar_unregister_stream_callback failed");
#else
ROS_INFO("lidar_unregister_stream_callback failed");
#endif
}
// lidar_close_device(odinDevice);
// lidar_destory_device(odinDevice);
std::fflush(dev_status_csv_file);
fclose(dev_status_csv_file);
}
// lidar_system_deinit();