将src目录作为普通文件而非子模块添加
This commit is contained in:
1
src
1
src
Submodule src deleted from ec1c1e29cd
1
src/CMakeLists.txt
Symbolic link
1
src/CMakeLists.txt
Symbolic link
@@ -0,0 +1 @@
|
||||
/opt/ros/noetic/share/catkin/cmake/toplevel.cmake
|
||||
146
src/README.md
Normal file
146
src/README.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# TR360 ROS 包
|
||||
|
||||
基于ROS Noetic的TR360雷达点云处理包,支持TR360-3-60避障雷达和TR360-4-60地形雷达。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ UDP数据接收和解析
|
||||
- ✅ 点云数据转换(极坐标→直角坐标)
|
||||
- ✅ PointCloud2话题发布
|
||||
- ✅ RViz可视化支持
|
||||
- ✅ 动态参数配置
|
||||
- ✅ 多雷达类型支持
|
||||
- ✅ 网络参数可配置
|
||||
- ✅ 测试数据模拟
|
||||
|
||||
## 系统要求
|
||||
|
||||
- Ubuntu 20.04
|
||||
- ROS Noetic
|
||||
- PCL 1.10
|
||||
|
||||
## 安装和编译
|
||||
|
||||
### 自动编译
|
||||
```bash
|
||||
cd tr360_ros
|
||||
./build.sh
|
||||
```
|
||||
|
||||
### 手动编译
|
||||
```bash
|
||||
# 设置ROS环境
|
||||
source /opt/ros/noetic/setup.bash
|
||||
|
||||
# 创建工作空间(如果不存在)
|
||||
mkdir -p ~/catkin_ws/src
|
||||
cd ~/catkin_ws
|
||||
catkin_make
|
||||
|
||||
# 复制包到工作空间
|
||||
cp -r /path/to/tr360_ros ~/catkin_ws/src/
|
||||
|
||||
# 编译
|
||||
cd ~/catkin_ws
|
||||
catkin_make
|
||||
|
||||
# 设置环境
|
||||
source devel/setup.bash
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 启动主节点(需要真实雷达)
|
||||
```bash
|
||||
roslaunch tr360_ros tr360.launch
|
||||
```
|
||||
|
||||
### 2. 启动测试节点(无雷达时使用)
|
||||
```bash
|
||||
rosrun tr360_ros test_publisher
|
||||
```
|
||||
|
||||
### 3. 可视化
|
||||
```bash
|
||||
rviz -d $(rospack find tr360_ros)/config/tr360.rviz
|
||||
```
|
||||
|
||||
## 参数配置
|
||||
|
||||
### 启动参数
|
||||
在`launch/tr360.launch`中配置:
|
||||
- `radar_type`: 雷达类型 (`TR360-3-60`/`TR360-4-60`)
|
||||
- `radar_ip`: 雷达设备IP
|
||||
- `radar_port`: 雷达端口 (默认: 10123)
|
||||
- `local_ip`: 本地接收IP
|
||||
- `local_port`: 本地端口 (默认: 10193/20193)
|
||||
|
||||
### 动态参数
|
||||
运行时可通过`rqt_reconfigure`调整:
|
||||
- 距离范围限制
|
||||
- 角度范围限制
|
||||
- 强度范围限制
|
||||
- 坐标显示范围
|
||||
- 发布频率
|
||||
|
||||
## 网络配置
|
||||
|
||||
### TR360-3-60 (避障雷达)
|
||||
- 雷达IP: `192.168.1.80`
|
||||
- 雷达端口: `10123`
|
||||
- 本地IP: `192.168.1.193`
|
||||
- 本地端口: `10193`
|
||||
|
||||
### TR360-4-60 (地形雷达)
|
||||
- 雷达IP: `192.168.0.80`
|
||||
- 雷达端口: `10123`
|
||||
- 本地IP: `192.168.0.193`
|
||||
- 本地端口: `20193`
|
||||
|
||||
## 数据结构
|
||||
|
||||
### 点云格式
|
||||
每个点包含:
|
||||
- 方位角 (9 bits)
|
||||
- 距离 (12 bits)
|
||||
- 俯仰角 (11 bits)
|
||||
- RCS值 (8 bits)
|
||||
|
||||
### 坐标转换
|
||||
极坐标 → 直角坐标:
|
||||
```
|
||||
{x, y, z, v} = {r*cos(e)*cos(a), r*cos(e)*sin(a), r*sin(e), v}
|
||||
```
|
||||
|
||||
## 话题
|
||||
|
||||
### 多雷达支持
|
||||
支持同时处理多个TR360雷达数据,根据雷达类型和数量自动生成话题名称:
|
||||
|
||||
#### TR360-3-60 双雷达配置 (max_radars=2)
|
||||
- `/TR360-3-30-up` (`sensor_msgs/PointCloud2`) - 上方雷达点云数据
|
||||
- `/TR360-3-60-front` (`sensor_msgs/PointCloud2`) - 前方雷达点云数据
|
||||
|
||||
#### TR360-3-60 单雷达配置 (max_radars=1)
|
||||
- `/TR360-4-60-terrain` (`sensor_msgs/PointCloud2`) - 地形雷达点云数据
|
||||
|
||||
#### 默认配置
|
||||
- `/tr360_points_1` (`sensor_msgs/PointCloud2`) - 雷达1的点云数据
|
||||
- `/tr360_points_2` (`sensor_msgs/PointCloud2`) - 雷达2的点云数据
|
||||
- `/tr360_points_3` (`sensor_msgs/PointCloud2`) - 雷达3的点云数据
|
||||
- `/tr360_points_4` (`sensor_msgs/PointCloud2`) - 雷达4的点云数据
|
||||
|
||||
### 坐标系
|
||||
每个雷达使用独立的坐标系:
|
||||
- `tr360_radar_1` - 雷达1坐标系
|
||||
- `tr360_radar_2` - 雷达2坐标系
|
||||
- `tr360_radar_3` - 雷达3坐标系
|
||||
- `tr360_radar_4` - 雷达4坐标系
|
||||
|
||||
## 版本控制
|
||||
|
||||
使用Git进行版本管理,采用分步测试开发模式。
|
||||
|
||||
## 许可证
|
||||
|
||||
BSD 3-Clause License
|
||||
41
src/build.sh
Executable file
41
src/build.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# TR360 ROS包编译脚本
|
||||
echo "正在编译TR360 ROS包..."
|
||||
|
||||
# 设置ROS环境
|
||||
source /opt/ros/noetic/setup.bash
|
||||
|
||||
# 创建编译目录
|
||||
BUILD_DIR="$HOME/catkin_ws"
|
||||
if [ ! -d "$BUILD_DIR" ]; then
|
||||
echo "创建catkin工作空间..."
|
||||
mkdir -p "$BUILD_DIR/src"
|
||||
cd "$BUILD_DIR"
|
||||
catkin_make
|
||||
fi
|
||||
|
||||
# 复制包到工作空间
|
||||
PACKAGE_DIR="$BUILD_DIR/src/tr360_ros"
|
||||
if [ -d "$PACKAGE_DIR" ]; then
|
||||
echo "删除旧版包..."
|
||||
rm -rf "$PACKAGE_DIR"
|
||||
fi
|
||||
|
||||
echo "复制包到工作空间..."
|
||||
cp -r "$(dirname "$0")" "$BUILD_DIR/src/"
|
||||
|
||||
# 编译包
|
||||
cd "$BUILD_DIR"
|
||||
echo "开始编译..."
|
||||
catkin_make
|
||||
|
||||
# 设置环境变量
|
||||
echo "source $BUILD_DIR/devel/setup.bash" >> ~/.bashrc
|
||||
source "$BUILD_DIR/devel/setup.bash"
|
||||
|
||||
echo "编译完成!"
|
||||
echo "使用方法:"
|
||||
echo "1. 启动主节点: roslaunch tr360_ros tr360.launch"
|
||||
echo "2. 启动测试节点: rosrun tr360_ros test_publisher"
|
||||
echo "3. 可视化: rviz -d $(rospack find tr360_ros)/config/tr360.rviz"
|
||||
64
src/tr360_ros/CMakeLists.txt
Normal file
64
src/tr360_ros/CMakeLists.txt
Normal file
@@ -0,0 +1,64 @@
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
project(tr360_ros)
|
||||
|
||||
find_package(catkin REQUIRED COMPONENTS
|
||||
roscpp
|
||||
sensor_msgs
|
||||
pcl_ros
|
||||
pcl_conversions
|
||||
dynamic_reconfigure
|
||||
)
|
||||
|
||||
# 添加动态参数配置生成
|
||||
find_package(catkin REQUIRED)
|
||||
generate_dynamic_reconfigure_options(
|
||||
cfg/TR360Config.cfg
|
||||
)
|
||||
|
||||
catkin_package(
|
||||
INCLUDE_DIRS include
|
||||
LIBRARIES tr360_ros
|
||||
CATKIN_DEPENDS roscpp sensor_msgs pcl_ros pcl_conversions
|
||||
)
|
||||
|
||||
include_directories(
|
||||
include
|
||||
${catkin_INCLUDE_DIRS}
|
||||
${PCL_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_executable(tr360_node src/tr360_node.cpp)
|
||||
target_link_libraries(tr360_node
|
||||
${catkin_LIBRARIES}
|
||||
${PCL_LIBRARIES}
|
||||
)
|
||||
|
||||
# 添加网络库链接
|
||||
target_link_libraries(tr360_node ${Boost_LIBRARIES})
|
||||
|
||||
# 测试发布器
|
||||
add_executable(test_publisher src/test_publisher.cpp)
|
||||
target_link_libraries(test_publisher
|
||||
${catkin_LIBRARIES}
|
||||
${PCL_LIBRARIES}
|
||||
)
|
||||
|
||||
install(TARGETS test_publisher
|
||||
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||
)
|
||||
|
||||
install(TARGETS tr360_node
|
||||
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
|
||||
)
|
||||
|
||||
install(DIRECTORY include/${PROJECT_NAME}/
|
||||
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
|
||||
)
|
||||
|
||||
install(DIRECTORY launch/
|
||||
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
|
||||
)
|
||||
|
||||
install(DIRECTORY config/
|
||||
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/config
|
||||
)
|
||||
146
src/tr360_ros/README.md
Normal file
146
src/tr360_ros/README.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# TR360 ROS 包
|
||||
|
||||
基于ROS Noetic的TR360雷达点云处理包,支持TR360-3-60避障雷达和TR360-4-60地形雷达。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- ✅ UDP数据接收和解析
|
||||
- ✅ 点云数据转换(极坐标→直角坐标)
|
||||
- ✅ PointCloud2话题发布
|
||||
- ✅ RViz可视化支持
|
||||
- ✅ 动态参数配置
|
||||
- ✅ 多雷达类型支持
|
||||
- ✅ 网络参数可配置
|
||||
- ✅ 测试数据模拟
|
||||
|
||||
## 系统要求
|
||||
|
||||
- Ubuntu 20.04
|
||||
- ROS Noetic
|
||||
- PCL 1.10
|
||||
|
||||
## 安装和编译
|
||||
|
||||
### 自动编译
|
||||
```bash
|
||||
cd tr360_ros
|
||||
./build.sh
|
||||
```
|
||||
|
||||
### 手动编译
|
||||
```bash
|
||||
# 设置ROS环境
|
||||
source /opt/ros/noetic/setup.bash
|
||||
|
||||
# 创建工作空间(如果不存在)
|
||||
mkdir -p ~/catkin_ws/src
|
||||
cd ~/catkin_ws
|
||||
catkin_make
|
||||
|
||||
# 复制包到工作空间
|
||||
cp -r /path/to/tr360_ros ~/catkin_ws/src/
|
||||
|
||||
# 编译
|
||||
cd ~/catkin_ws
|
||||
catkin_make
|
||||
|
||||
# 设置环境
|
||||
source devel/setup.bash
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 启动主节点(需要真实雷达)
|
||||
```bash
|
||||
roslaunch tr360_ros tr360.launch
|
||||
```
|
||||
|
||||
### 2. 启动测试节点(无雷达时使用)
|
||||
```bash
|
||||
rosrun tr360_ros test_publisher
|
||||
```
|
||||
|
||||
### 3. 可视化
|
||||
```bash
|
||||
rviz -d $(rospack find tr360_ros)/config/tr360.rviz
|
||||
```
|
||||
|
||||
## 参数配置
|
||||
|
||||
### 启动参数
|
||||
在`launch/tr360.launch`中配置:
|
||||
- `radar_type`: 雷达类型 (`TR360-3-60`/`TR360-4-60`)
|
||||
- `radar_ip`: 雷达设备IP
|
||||
- `radar_port`: 雷达端口 (默认: 10123)
|
||||
- `local_ip`: 本地接收IP
|
||||
- `local_port`: 本地端口 (默认: 10193/20193)
|
||||
|
||||
### 动态参数
|
||||
运行时可通过`rqt_reconfigure`调整:
|
||||
- 距离范围限制
|
||||
- 角度范围限制
|
||||
- 强度范围限制
|
||||
- 坐标显示范围
|
||||
- 发布频率
|
||||
|
||||
## 网络配置
|
||||
|
||||
### TR360-3-60 (避障雷达)
|
||||
- 雷达IP: `192.168.1.80`
|
||||
- 雷达端口: `10123`
|
||||
- 本地IP: `192.168.1.193`
|
||||
- 本地端口: `10193`
|
||||
|
||||
### TR360-4-60 (地形雷达)
|
||||
- 雷达IP: `192.168.0.80`
|
||||
- 雷达端口: `10123`
|
||||
- 本地IP: `192.168.0.193`
|
||||
- 本地端口: `20193`
|
||||
|
||||
## 数据结构
|
||||
|
||||
### 点云格式
|
||||
每个点包含:
|
||||
- 方位角 (9 bits)
|
||||
- 距离 (12 bits)
|
||||
- 俯仰角 (11 bits)
|
||||
- RCS值 (8 bits)
|
||||
|
||||
### 坐标转换
|
||||
极坐标 → 直角坐标:
|
||||
```
|
||||
{x, y, z, v} = {r*cos(e)*cos(a), r*cos(e)*sin(a), r*sin(e), v}
|
||||
```
|
||||
|
||||
## 话题
|
||||
|
||||
### 多雷达支持
|
||||
支持同时处理多个TR360雷达数据,根据雷达类型和数量自动生成话题名称:
|
||||
|
||||
#### TR360-3-60 双雷达配置 (max_radars=2)
|
||||
- `/TR360-3-30-up` (`sensor_msgs/PointCloud2`) - 上方雷达点云数据
|
||||
- `/TR360-3-60-front` (`sensor_msgs/PointCloud2`) - 前方雷达点云数据
|
||||
|
||||
#### TR360-3-60 单雷达配置 (max_radars=1)
|
||||
- `/TR360-4-60-terrain` (`sensor_msgs/PointCloud2`) - 地形雷达点云数据
|
||||
|
||||
#### 默认配置
|
||||
- `/tr360_points_1` (`sensor_msgs/PointCloud2`) - 雷达1的点云数据
|
||||
- `/tr360_points_2` (`sensor_msgs/PointCloud2`) - 雷达2的点云数据
|
||||
- `/tr360_points_3` (`sensor_msgs/PointCloud2`) - 雷达3的点云数据
|
||||
- `/tr360_points_4` (`sensor_msgs/PointCloud2`) - 雷达4的点云数据
|
||||
|
||||
### 坐标系
|
||||
每个雷达使用独立的坐标系:
|
||||
- `tr360_radar_1` - 雷达1坐标系
|
||||
- `tr360_radar_2` - 雷达2坐标系
|
||||
- `tr360_radar_3` - 雷达3坐标系
|
||||
- `tr360_radar_4` - 雷达4坐标系
|
||||
|
||||
## 版本控制
|
||||
|
||||
使用Git进行版本管理,采用分步测试开发模式。
|
||||
|
||||
## 许可证
|
||||
|
||||
BSD 3-Clause License
|
||||
41
src/tr360_ros/build.sh
Executable file
41
src/tr360_ros/build.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# TR360 ROS包编译脚本
|
||||
echo "正在编译TR360 ROS包..."
|
||||
|
||||
# 设置ROS环境
|
||||
source /opt/ros/noetic/setup.bash
|
||||
|
||||
# 创建编译目录
|
||||
BUILD_DIR="$HOME/catkin_ws"
|
||||
if [ ! -d "$BUILD_DIR" ]; then
|
||||
echo "创建catkin工作空间..."
|
||||
mkdir -p "$BUILD_DIR/src"
|
||||
cd "$BUILD_DIR"
|
||||
catkin_make
|
||||
fi
|
||||
|
||||
# 复制包到工作空间
|
||||
PACKAGE_DIR="$BUILD_DIR/src/tr360_ros"
|
||||
if [ -d "$PACKAGE_DIR" ]; then
|
||||
echo "删除旧版包..."
|
||||
rm -rf "$PACKAGE_DIR"
|
||||
fi
|
||||
|
||||
echo "复制包到工作空间..."
|
||||
cp -r "$(dirname "$0")" "$BUILD_DIR/src/"
|
||||
|
||||
# 编译包
|
||||
cd "$BUILD_DIR"
|
||||
echo "开始编译..."
|
||||
catkin_make
|
||||
|
||||
# 设置环境变量
|
||||
echo "source $BUILD_DIR/devel/setup.bash" >> ~/.bashrc
|
||||
source "$BUILD_DIR/devel/setup.bash"
|
||||
|
||||
echo "编译完成!"
|
||||
echo "使用方法:"
|
||||
echo "1. 启动主节点: roslaunch tr360_ros tr360.launch"
|
||||
echo "2. 启动测试节点: rosrun tr360_ros test_publisher"
|
||||
echo "3. 可视化: rviz -d $(rospack find tr360_ros)/config/tr360.rviz"
|
||||
47
src/tr360_ros/cfg/TR360Config.cfg
Normal file
47
src/tr360_ros/cfg/TR360Config.cfg
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
PACKAGE = "tr360_ros"
|
||||
|
||||
from dynamic_reconfigure.parameter_generator_catkin import *
|
||||
|
||||
# 距离参数
|
||||
gen = ParameterGenerator()
|
||||
|
||||
# 距离限制参数
|
||||
gen.add("r_lo", double_t, 0, "距离下限(m)", 0.0, 0.0, 100.0)
|
||||
gen.add("r_hi", double_t, 0, "距离上限(m)", 100.0, 0.0, 100.0)
|
||||
|
||||
# 方位角参数
|
||||
gen.add("az_lo", double_t, 0, "方位角下限(度)", -180.0, -180.0, 180.0)
|
||||
gen.add("az_hi", double_t, 0, "方位角上限(度)", 180.0, -180.0, 180.0)
|
||||
|
||||
# 俯仰角参数
|
||||
gen.add("el_lo", double_t, 0, "俯仰角下限(度)", -90.0, -90.0, 90.0)
|
||||
gen.add("el_hi", double_t, 0, "俯仰角上限(度)", 90.0, -90.0, 90.0)
|
||||
|
||||
# 强度参数
|
||||
gen.add("intensity_lo", double_t, 0, "强度下限", 0.0, 0.0, 100.0)
|
||||
gen.add("intensity_hi", double_t, 0, "强度上限", 100.0, 0.0, 100.0)
|
||||
|
||||
# 坐标显示范围
|
||||
gen.add("x_lo", double_t, 0, "X轴显示下限(m)", -50.0, -100.0, 100.0)
|
||||
gen.add("x_hi", double_t, 0, "X轴显示上限(m)", 50.0, -100.0, 100.0)
|
||||
gen.add("y_lo", double_t, 0, "Y轴显示下限(m)", -50.0, -100.0, 100.0)
|
||||
gen.add("y_hi", double_t, 0, "Y轴显示上限(m)", 50.0, -100.0, 100.0)
|
||||
gen.add("z_lo", double_t, 0, "Z轴显示下限(m)", -50.0, -100.0, 100.0)
|
||||
gen.add("z_hi", double_t, 0, "Z轴显示上限(m)", 50.0, -100.0, 100.0)
|
||||
|
||||
# 雷达类型选择
|
||||
gen.add("radar_type", str_t, 0, "雷达类型", "TR360-3-60", edit_method={"enum_description": ["TR360-3-60: 避障雷达", "TR360-4-60: 地形雷达"]})
|
||||
|
||||
# 网络配置
|
||||
gen.add("radar_ip", str_t, 0, "雷达IP地址", "192.168.1.80")
|
||||
gen.add("radar_port", int_t, 0, "雷达端口", 10123, 1024, 65535)
|
||||
gen.add("local_ip", str_t, 0, "本地IP地址", "192.168.1.193")
|
||||
gen.add("local_port", int_t, 0, "本地端口", 10193, 1024, 65535)
|
||||
|
||||
# 点云处理参数
|
||||
gen.add("max_points", int_t, 0, "最大点数", 20000, 1000, 100000)
|
||||
gen.add("publish_rate", double_t, 0, "发布频率(Hz)", 10.0, 1.0, 100.0)
|
||||
|
||||
exit(gen.generate(PACKAGE, "tr360_ros", "TR360Config"))
|
||||
177
src/tr360_ros/config/tr360.rviz
Normal file
177
src/tr360_ros/config/tr360.rviz
Normal file
@@ -0,0 +1,177 @@
|
||||
Panels:
|
||||
- Class: rviz/Displays
|
||||
Help Height: 78
|
||||
Name: Displays
|
||||
Property Tree Widget:
|
||||
Expanded:
|
||||
- /Global Options1
|
||||
- /Status1
|
||||
Splitter Ratio: 0.5
|
||||
Tree Height: 323
|
||||
- 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
|
||||
Name: Views
|
||||
Splitter Ratio: 0.5
|
||||
- Class: rviz/Time
|
||||
Name: Time
|
||||
Splitter Ratio: 0.5
|
||||
Visualization Manager:
|
||||
Class: ""
|
||||
Displays:
|
||||
# 雷达1点云显示
|
||||
- Alpha: 0.5
|
||||
Class: rviz/PointCloud2
|
||||
Color: 1 0 0
|
||||
Color Transformer: Intensity
|
||||
Decay Time: 0
|
||||
Enabled: true
|
||||
Invert Rainbow: false
|
||||
Max Color: 255
|
||||
Min Color: 0
|
||||
Name: TR360 Radar 1
|
||||
Position Transformer: XYZ
|
||||
Selectable: true
|
||||
Size (Pixels): 3
|
||||
Style: Points
|
||||
Topic: /tr360_points_1
|
||||
Unreliable: false
|
||||
Use Fixed Frame: true
|
||||
Use rainbow: true
|
||||
Value: true
|
||||
# 雷达2点云显示
|
||||
- Alpha: 0.5
|
||||
Class极: rviz/PointCloud2
|
||||
Color: 0 1 0
|
||||
Color Transformer: Intensity
|
||||
Decay Time: 0
|
||||
Enabled: true
|
||||
Invert Rainbow: false
|
||||
Max Color: 255
|
||||
Min Color: 0
|
||||
Name: TR360 Radar 2
|
||||
Position Transformer: XYZ
|
||||
Selectable: true
|
||||
Size (Pixels): 3
|
||||
Style: Points
|
||||
Topic: /tr360_points_2
|
||||
Unreliable: false
|
||||
Use Fixed Frame: true
|
||||
Use rainbow: true
|
||||
Value: true
|
||||
# 雷达3点云显示
|
||||
- Alpha: 0.5
|
||||
Class: rviz/PointCloud2
|
||||
Color: 0 0 1
|
||||
Color Transformer: Intensity
|
||||
Decay Time: 0
|
||||
Enabled: true
|
||||
Invert Rainbow: false
|
||||
Max Color: 255
|
||||
Min Color: 0
|
||||
Name: TR360 Radar 3
|
||||
Position Transformer: XYZ
|
||||
Selectable: true
|
||||
Size (Pixels): 3
|
||||
Style: Points
|
||||
Topic: /tr360_points_3
|
||||
Unreliable: false
|
||||
Use Fixed Frame: true
|
||||
Use rainbow: true
|
||||
Value: true
|
||||
# 雷达4点云显示
|
||||
- Alpha: 0.5
|
||||
Class: rviz/PointCloud2
|
||||
Color: 1 1 0
|
||||
Color Transformer: Intensity
|
||||
Decay Time: 0
|
||||
Enabled: true
|
||||
Invert Rainbow: false
|
||||
Max Color: 255
|
||||
Min Color: 0
|
||||
Name: TR360 Radar 4
|
||||
Position Transformer: XYZ
|
||||
Selectable: true
|
||||
Size (Pixels): 3
|
||||
Style: Points
|
||||
Topic: /tr360_points_4
|
||||
Unreliable: false
|
||||
Use Fixed Frame: true
|
||||
Use rainbow: true
|
||||
Value: true
|
||||
- Class: rviz/Grid
|
||||
Cell Size: 1
|
||||
Color: 0.9411764740943909 0.9411764740943909 0.9411764740943909
|
||||
Enabled: true
|
||||
Line Style: Lines
|
||||
Line Width: 0.03
|
||||
Name: Grid
|
||||
Normal Cell Count: 0
|
||||
Offset:
|
||||
X: 0
|
||||
Y: 0
|
||||
Z: 0
|
||||
Plane: XY
|
||||
Plane Cell Count: 10
|
||||
Reference Frame: ""
|
||||
Value: true
|
||||
Enabled: true
|
||||
Global Options:
|
||||
Background Color: 48 48 48
|
||||
Fixed Frame: tr360_radar_1
|
||||
Frame Rate: 30
|
||||
Name: root
|
||||
Tools:
|
||||
- Class: rviz/Interact
|
||||
Hide Inactive Objects: false
|
||||
- Class: rviz/MoveCamera
|
||||
- Class: rviz/Select
|
||||
- Class: rviz/FocusCamera
|
||||
- Class: rviz/Measure
|
||||
- Class: rviz/2D Pose Estimate
|
||||
- Class: rviz/2D Nav Goal
|
||||
- Class: rviz/Publish Point
|
||||
Value: rviz/Interact
|
||||
Views:
|
||||
Current:
|
||||
Class: rviz/Orbit
|
||||
Distance: 10
|
||||
Enable Stereo Rendering: true
|
||||
Focal Point:
|
||||
X: 0
|
||||
Y: 0
|
||||
Z: 0
|
||||
Focal Shape Fixed Size: true
|
||||
Focal Shape Size: 0.05
|
||||
Name: Current View
|
||||
Near Clip Distance: 0.01
|
||||
Pitch: 0.7853981852531433
|
||||
Target Frame: ""
|
||||
Value: Orbit (rviz)
|
||||
Yaw: 0.7853981852531433
|
||||
Saved: ~
|
||||
Window Geometry:
|
||||
Displays:
|
||||
collapsed: false
|
||||
Height: 768
|
||||
Hide Left Dock: false
|
||||
Hide Right Dock: false
|
||||
QMainWindow State: 000000ff00000000fd0000000000000000000001d6000003c4fcfd0000000bf000000000000000000000432000001590000000643ffffff0000001000000032000001d6fcfd00000002df0000020f00000001000000000000000000000000fc0200000002fb000000100064006900730070006c00610079007300000001df0000020f00000001000000000000000000000000fc0100000001fb0000000a00760069006500770073000000014300000159fcfd0000000a000000000000000000000432000001590000000000000000000000000000000000000200000001000000005f0000012dfc0200000003fb0000001e0074006f006f006c005f00700072006f007000650072007400690065007300000001df0000020f00000001000000000000000000000000fc0100000001fb0000000c00740069006d00650072007300000000000000000000000000000000020000010000000000000000000000000000000000000000000200000001000000005f0000012dfc0200000003fb0000001e0074006f006f006c005f00700072006f007000650072007400690065007300000001df0000020f00000001000000000000000000000000fc0100000001fb0000000c00740069006d00650072007300000000000000000000000000000000020000010000000000000000000000000000000000000000000200000001000000005f0000012dfc0200000003fb极0000001e0074006f006f006c005f00700072006f007000650072007400极690065007300000001df0000020f00000001000000000000000000000000fc0100000001fb0000000c00740069006d0065007200730000000000000000000000000000000002000001000000000000000000000000000000000000000000
|
||||
Selection:
|
||||
collapsed: false
|
||||
Time:
|
||||
collapsed: false
|
||||
Tool Properties:
|
||||
collapsed: false
|
||||
Views:
|
||||
collapsed: false
|
||||
Width: 1024
|
||||
X: 0
|
||||
Y: 0
|
||||
83
src/tr360_ros/include/tr360_ros/tr360_types.h
Normal file
83
src/tr360_ros/include/tr360_ros/tr360_types.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef TR360_ROS_TR360_TYPES_H
|
||||
#define TR360_ROS_TR360_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// 雷达帧头结构
|
||||
#pragma pack(push, 1)
|
||||
typedef struct
|
||||
{
|
||||
uint32_t a:9; // 方位角
|
||||
uint32_t r:12; // 距离
|
||||
int32_t e:11; // 俯仰角
|
||||
uint8_t v; // rcs
|
||||
} points_5b;
|
||||
|
||||
// 帧头对象新结构
|
||||
typedef struct
|
||||
{
|
||||
unsigned char Outtype; //0 raev 1 xyz
|
||||
unsigned char Version; //默认4
|
||||
unsigned char RadarType; //
|
||||
unsigned char NFrame;
|
||||
unsigned int Rev[3];
|
||||
unsigned int FrameCounter; // 帧计数
|
||||
float Res[4]; // 分辨率
|
||||
float Offset[4]; // 偏移量
|
||||
float Time; //雷达输出时间和开始0度采集时间差值
|
||||
int ObjNum; // 目标个数
|
||||
unsigned int CheckSum; // 和校验
|
||||
} FrameHeadObjNewS;
|
||||
|
||||
// 雷达头信息结构
|
||||
typedef struct
|
||||
{
|
||||
char header[12]; //帧头 避障"TR360-3-60",地形"TR360-4-60"
|
||||
uint32_t FrameCounter; // 帧计数
|
||||
uint32_t nRadar; // 传感器个数,避障默认2,地形默认1
|
||||
uint32_t ObjNum; // 总目标个数
|
||||
uint8_t Rev[36]; //保留
|
||||
unsigned int CheckSum; //总和校验
|
||||
} RadarHeaderInfoS;
|
||||
|
||||
// 参数限制结构
|
||||
typedef struct
|
||||
{
|
||||
int RLo100; // 距离下限cm
|
||||
int RHi100; // 距离上限cm
|
||||
int azLo100; // 方位角下限
|
||||
int azHi100; // 方位角上限
|
||||
int elLo100; // 俯仰角下限
|
||||
int elHi100; // 俯仰角上限
|
||||
int vLo; // 幅值下限
|
||||
int vHi; // 幅值上限
|
||||
int xLo100;
|
||||
int xHi100;
|
||||
int yLo100;
|
||||
int yHi100;
|
||||
int zLo100;
|
||||
int zHi100;
|
||||
int azComp100; // 方位角补偿
|
||||
int elComp100; // 俯仰角补偿
|
||||
int Roll100; // 安装滚转角补偿
|
||||
int Pitch100; // 安装俯仰角补偿
|
||||
int Yaw100; // 安装方位角补偿
|
||||
int type;
|
||||
int xGLo100; // x显示下限
|
||||
int xGHi100; // x显示上限
|
||||
int yGLo100; // y显示下限
|
||||
int yGHi100; // y显示上限
|
||||
int zGLo100; // z显示下限
|
||||
int zGHi100; // z显示上限
|
||||
int vGLo; // 幅度显示下限
|
||||
int vGHi; // 幅度显示上限
|
||||
int nStep; // vGLo与vGHi之间显示nStep个色阶
|
||||
int MaxPoint; //最多显示多少个点
|
||||
int EleQ;
|
||||
int ARQ;
|
||||
int NegQ;
|
||||
} ParaLim;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // TR360_ROS_TR360_TYPES_H
|
||||
53
src/tr360_ros/launch/tr360.launch
Normal file
53
src/tr360_ros/launch/tr360.launch
Normal file
@@ -0,0 +1,53 @@
|
||||
<launch>
|
||||
<!-- TR360-3-60 雷达节点 -->
|
||||
<node name="tr360_3_60_node" pkg="tr360_ros" type="tr360_node" output="screen">
|
||||
<!-- 雷达类型配置 -->
|
||||
<param name="radar_type" type="string" value="TR360-3-60" />
|
||||
|
||||
<!-- 雷达设备IP和端口 -->
|
||||
<param name="radar_ip" type="string" value="192.168.1.80" />
|
||||
<param name="radar_port" type="int" value="10123" />
|
||||
|
||||
<!-- 本地接收IP和端口 -->
|
||||
<param name="local_ip" type="string" value="192.168.1.193" />
|
||||
<param name="local_port" type="int" value="10195" />
|
||||
|
||||
<!-- 雷达数量配置 -->
|
||||
<param name="max_radars" type="int" value="2" />
|
||||
|
||||
<!-- 命令服务器配置 -->
|
||||
<param name="enable_command_server" type="bool" value="true" />
|
||||
<param name="max_history_size" type="int" value="100" />
|
||||
</node>
|
||||
|
||||
<!-- TR360-4-60 雷达节点 -->
|
||||
<node name="tr360_4_60_node" pkg="tr360_ros" type="tr360_node" output="screen">
|
||||
<!-- 雷达类型配置 -->
|
||||
<param name="radar_type" type="string" value="TR360-4-60" />
|
||||
|
||||
<!-- 雷达设备IP和端口 -->
|
||||
<param name="radar_ip" type="string" value="192.168.1.81" />
|
||||
<param name="radar_port" type="int" value="20223" />
|
||||
|
||||
<!-- 本地接收IP和端口 -->
|
||||
<param name="local_ip" type="string" value="192.168.1.193" />
|
||||
<param name="local_port" type="int" value="20295" />
|
||||
|
||||
<!-- 雷达数量配置 -->
|
||||
<param name="max_radars" type="int" value="1" />
|
||||
|
||||
<!-- 命令服务器配置 -->
|
||||
<param name="enable_command_server" type="bool" value="true" />
|
||||
<param name="max_history_size" type="int" value="100" />
|
||||
</node>
|
||||
|
||||
<!-- 点云过滤参数(全局参数) -->
|
||||
<param name="min_range" type="double" value="0.0" />
|
||||
<param name="max_range" type="double" value="100.0" />
|
||||
<param name="min_intensity" type="double" value="0.0" />
|
||||
<param name="max_intensity" type="double" value="100.0" />
|
||||
|
||||
<!-- 启动RViz进行点云可视化 -->
|
||||
<node name="rviz" pkg="rviz" type="rviz" args="-d $(find tr360_ros)/config/tr360.rviz" />
|
||||
|
||||
</launch>
|
||||
25
src/tr360_ros/package.xml
Normal file
25
src/tr360_ros/package.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0"?>
|
||||
<package format="2">
|
||||
<name>tr360_ros</name>
|
||||
<version>0.1.0</version>
|
||||
<description>ROS package for TR360 radar point cloud processing</description>
|
||||
<maintainer email="yemai@example.com">yemai</maintainer>
|
||||
<license>BSD</license>
|
||||
|
||||
<buildtool_depend>catkin</buildtool_depend>
|
||||
|
||||
<build_depend>roscpp</build_depend>
|
||||
<build_depend>sensor_msgs</build_depend>
|
||||
<build_depend>pcl_ros</build_depend>
|
||||
<build_depend>pcl_conversions</build_depend>
|
||||
<build_depend>dynamic_reconfigure</build_depend>
|
||||
|
||||
<exec_depend>roscpp</exec_depend>
|
||||
<exec_depend>sensor_msgs</exec_depend>
|
||||
<exec_depend>pcl_ros</exec_depend>
|
||||
<exec_depend>pcl_conversions</exec_depend>
|
||||
<exec_depend>dynamic_reconfigure</exec_depend>
|
||||
|
||||
<export>
|
||||
</export>
|
||||
</package>
|
||||
66
src/tr360_ros/src/test_publisher.cpp
Normal file
66
src/tr360_ros/src/test_publisher.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include <ros/ros.h>
|
||||
#include <sensor_msgs/PointCloud2.h>
|
||||
#include <pcl/point_types.h>
|
||||
#include <pcl/point_cloud.h>
|
||||
#include <pcl_conversions/pcl_conversions.h>
|
||||
#include <cmath>
|
||||
|
||||
class TestPublisher
|
||||
{
|
||||
private:
|
||||
ros::NodeHandle nh_;
|
||||
ros::Publisher cloud_pub_;
|
||||
ros::Timer timer_;
|
||||
|
||||
public:
|
||||
TestPublisher()
|
||||
{
|
||||
cloud_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("tr360_points", 10);
|
||||
timer_ = nh_.createTimer(ros::Duration(0.1), &TestPublisher::publishTestData, this);
|
||||
ROS_INFO("Test publisher initialized");
|
||||
}
|
||||
|
||||
void publishTestData(const ros::TimerEvent& event)
|
||||
{
|
||||
// 创建测试点云数据
|
||||
pcl::PointCloud<pcl::PointXYZI> cloud;
|
||||
cloud.header.frame_id = "tr360_radar";
|
||||
cloud.is_dense = false;
|
||||
|
||||
// 生成模拟雷达数据(圆锥形点云)
|
||||
int num_points = 1000;
|
||||
for (int i = 0; i < num_points; ++i) {
|
||||
float angle = 2.0 * M_PI * i / num_points;
|
||||
float distance = 5.0 + 2.0 * sin(angle * 5.0);
|
||||
float height = 2.0 * cos(angle * 3.0);
|
||||
|
||||
pcl::PointXYZI point;
|
||||
point.x = distance * cos(angle);
|
||||
point.y = distance * sin(angle);
|
||||
point.z = height;
|
||||
point.intensity = 50.0 + 30.0 * sin(angle * 2.0);
|
||||
|
||||
cloud.points.push_back(point);
|
||||
}
|
||||
|
||||
// 发布点云
|
||||
sensor_msgs::PointCloud2 cloud_msg;
|
||||
pcl::toROSMsg(cloud, cloud_msg);
|
||||
cloud_msg.header.stamp = ros::Time::now();
|
||||
cloud_msg.header.frame_id = "tr360_radar";
|
||||
|
||||
cloud_pub_.publish(cloud_msg);
|
||||
|
||||
ROS_INFO("Published %d test points", num_points);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
ros::init(argc, argv, "test_publisher");
|
||||
|
||||
TestPublisher publisher;
|
||||
ros::spin();
|
||||
|
||||
return 0;
|
||||
}
|
||||
459
src/tr360_ros/src/tr360_node.cpp
Normal file
459
src/tr360_ros/src/tr360_node.cpp
Normal file
@@ -0,0 +1,459 @@
|
||||
#include <ros/ros.h>
|
||||
#include <sensor_msgs/PointCloud2.h>
|
||||
#include <pcl/point_types.h>
|
||||
#include <pcl/point_cloud.h>
|
||||
#include <pcl_conversions/pcl_conversions.h>
|
||||
#include <dynamic_reconfigure/server.h>
|
||||
#include "tr360_ros/tr360_types.h"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
class TR360RadarNode
|
||||
{
|
||||
private:
|
||||
ros::NodeHandle nh_;
|
||||
std::vector<ros::Publisher> cloud_pubs_;
|
||||
|
||||
int udp_socket_;
|
||||
struct sockaddr_in server_addr_, client_addr_;
|
||||
|
||||
// 配置参数
|
||||
std::string radar_type_;
|
||||
std::string radar_ip_;
|
||||
int radar_port_;
|
||||
std::string local_ip_;
|
||||
int local_port_;
|
||||
int max_radars_;
|
||||
|
||||
// 命令历史记录
|
||||
std::vector<std::string> command_history_;
|
||||
int max_history_size_;
|
||||
|
||||
// TCP命令服务器
|
||||
int tcp_socket_;
|
||||
bool enable_command_server_;
|
||||
|
||||
// 点云处理状态
|
||||
uint32_t state_;
|
||||
uint32_t total_len_;
|
||||
uint32_t len1_;
|
||||
int counter_;
|
||||
uint8_t header_buf_[128];
|
||||
uint8_t out_data_[327680];
|
||||
|
||||
ParaLim para_obj_;
|
||||
|
||||
public:
|
||||
TR360RadarNode() : state_(0), total_len_(0), len1_(0), counter_(0)
|
||||
{
|
||||
// 初始化参数
|
||||
ros::NodeHandle private_nh("~");
|
||||
private_nh.param<std::string>("radar_type", radar_type_, "TR360-3-60");
|
||||
private_nh.param<std::string>("radar_ip", radar_ip_, "192.168.1.80");
|
||||
private_nh.param("radar_port", radar_port_, 10123);
|
||||
private_nh.param<std::string>("local_ip", local_ip_, "192.168.1.193");
|
||||
private_nh.param("local_port", local_port_, 10193);
|
||||
private_nh.param("max_radars", max_radars_, 4); // 最大雷达数量
|
||||
private_nh.param("enable_command_server", enable_command_server_, true);
|
||||
private_nh.param("max_history_size", max_history_size_, 100);
|
||||
|
||||
// 创建点云发布者(支持多个雷达)
|
||||
for (int i = 0; i < max_radars_; ++i) {
|
||||
std::string topic_name;
|
||||
if (radar_type_ == "TR360-3-60" && max_radars_ == 2) {
|
||||
// TR360-3-60 双雷达配置
|
||||
if (i == 0) topic_name = "tr360_3_30_up";
|
||||
else if (i == 1) topic_name = "tr360_3_60_front";
|
||||
else topic_name = "tr360_points_" + std::to_string(i+1);
|
||||
} else if (radar_type_ == "TR360-3-60" && max_radars_ == 1) {
|
||||
// TR360-3-60 单雷达配置
|
||||
topic_name = "tr360_4_60_terrain";
|
||||
} else {
|
||||
// 默认配置
|
||||
topic_name = "tr360_points_" + std::to_string(i+1);
|
||||
}
|
||||
cloud_pubs_.push_back(nh_.advertise<sensor_msgs::PointCloud2>(topic_name, 10));
|
||||
}
|
||||
|
||||
// 初始化UDP socket
|
||||
initUDP();
|
||||
|
||||
// 初始化TCP命令服务器
|
||||
if (enable_command_server_) {
|
||||
initCommandServer();
|
||||
}
|
||||
|
||||
// 初始化参数对象
|
||||
initParameters();
|
||||
}
|
||||
|
||||
void initUDP()
|
||||
{
|
||||
udp_socket_ = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (udp_socket_ < 0) {
|
||||
ROS_ERROR("Failed to create socket");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置本地地址
|
||||
memset(&server_addr_, 0, sizeof(server_addr_));
|
||||
server_addr_.sin_family = AF_INET;
|
||||
server_addr_.sin_addr.s_addr = inet_addr(local_ip_.c_str());
|
||||
server_addr_.sin_port = htons(local_port_);
|
||||
|
||||
// 绑定socket
|
||||
if (bind(udp_socket_, (struct sockaddr*)&server_addr_, sizeof(server_addr_)) < 0) {
|
||||
ROS_ERROR("Bind failed");
|
||||
close(udp_socket_);
|
||||
return;
|
||||
}
|
||||
|
||||
ROS_INFO("UDP socket initialized on %s:%d", local_ip_.c_str(), local_port_);
|
||||
|
||||
// 根据雷达类型设置默认端口
|
||||
if (radar_type_ == "TR360-3-60") {
|
||||
local_port_ = 10195;
|
||||
} else if (radar_type_ == "TR360-4-60") {
|
||||
local_port_ = 20295;
|
||||
}
|
||||
}
|
||||
|
||||
void initParameters()
|
||||
{
|
||||
// 初始化参数默认值
|
||||
para_obj_.RLo100 = 0;
|
||||
para_obj_.RHi100 = 4000;
|
||||
para_obj_.azLo100 = 0;
|
||||
para_obj_.azHi100 = 36000;
|
||||
para_obj_.elLo100 = -12000;
|
||||
para_obj_.elHi100 = 12000;
|
||||
para_obj_.vLo = 0;
|
||||
para_obj_.vHi = 100;
|
||||
para_obj_.xLo100 = -4000;
|
||||
para_obj_.xHi100 = 4000;
|
||||
para_obj_.yLo100 = -4000;
|
||||
para_obj_.yHi100 = 4000;
|
||||
para_obj_.zLo100 = -4000;
|
||||
para_obj_.zHi100 = 4000;
|
||||
para_obj_.azComp100 = 0;
|
||||
para_obj_.elComp100 = 0;
|
||||
para_obj_.Roll100 = 0;
|
||||
para_obj_.Pitch100 = 0;
|
||||
para_obj_.Yaw100 = 0;
|
||||
para_obj_.xGLo100 = -4000;
|
||||
para_obj_.xGHi100 = 4000;
|
||||
para_obj_.yGLo100 = -4000;
|
||||
para_obj_.yGHi100 = 4000;
|
||||
para_obj_.zGLo100 = -4000;
|
||||
para_obj_.zGHi100 = 4000;
|
||||
para_obj_.vGLo = 20;
|
||||
para_obj_.vGHi = 60;
|
||||
para_obj_.nStep = 33;
|
||||
para_obj_.MaxPoint = 20000;
|
||||
para_obj_.EleQ = 0;
|
||||
para_obj_.ARQ = 0;
|
||||
para_obj_.NegQ = 0;
|
||||
}
|
||||
|
||||
int parseFrame(unsigned char *data, unsigned int len)
|
||||
{
|
||||
RadarHeaderInfoS *ptr = (RadarHeaderInfoS *)data;
|
||||
FrameHeadObjNewS *frame_ptr;
|
||||
|
||||
const char *header = radar_type_.c_str();
|
||||
|
||||
if (strncmp(header, (char*)ptr->header, strlen(header)) == 0) {
|
||||
frame_ptr = (FrameHeadObjNewS *)(data + 64);
|
||||
|
||||
if (state_ != 3) {
|
||||
ROS_DEBUG("Counter:%d, len1:%d, total_len:%d, ObjNum:%d, nRadar:%d, RadarObj:%d",
|
||||
counter_, len1_, total_len_, ptr->ObjNum, ptr->nRadar, frame_ptr->ObjNum);
|
||||
}
|
||||
|
||||
if (len >= 128) {
|
||||
memcpy(header_buf_, data, 128);
|
||||
} else {
|
||||
memset(header_buf_, 0, 128);
|
||||
}
|
||||
|
||||
total_len_ = ptr->ObjNum * 5 + ptr->nRadar * 64 + 64;
|
||||
len1_ = len;
|
||||
state_ = 1;
|
||||
} else if (state_ == 1) {
|
||||
len1_ += len;
|
||||
state_ = 2;
|
||||
} else if (state_ == 2) {
|
||||
len1_ += len;
|
||||
state_ = 2;
|
||||
}
|
||||
|
||||
if (state_ == 1) {
|
||||
counter_++;
|
||||
if ((total_len_ < 0) || (total_len_ > 60000)) {
|
||||
ROS_WARN("Invalid total length: %d", total_len_);
|
||||
total_len_ = 0;
|
||||
state_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (state_) {
|
||||
if (len1_ > total_len_) {
|
||||
ptr = (RadarHeaderInfoS *)header_buf_;
|
||||
frame_ptr = (FrameHeadObjNewS *)(header_buf_ + 64);
|
||||
ROS_WARN("Data length exceeded: Counter:%d, len1:%d, total_len:%d",
|
||||
counter_, len1_, total_len_);
|
||||
total_len_ = 0;
|
||||
state_ = 0;
|
||||
} else if (len1_ == total_len_) {
|
||||
total_len_ = 0;
|
||||
state_ = 3;
|
||||
return state_;
|
||||
}
|
||||
}
|
||||
|
||||
return state_;
|
||||
}
|
||||
|
||||
void callback_arev5b(float *arve, void *ptr, float *factor4, float *offset4)
|
||||
{
|
||||
points_5b *point_ptr = (points_5b *)ptr;
|
||||
arve[0] = point_ptr->a * factor4[0] + offset4[0];
|
||||
arve[1] = point_ptr->r * factor4[1] + offset4[1];
|
||||
arve[2] = point_ptr->e * factor4[2];
|
||||
arve[3] = point_ptr->v * factor4[3] + offset4[3];
|
||||
}
|
||||
|
||||
void processPointCloud(unsigned char *data, unsigned int len)
|
||||
{
|
||||
RadarHeaderInfoS *radar_info_ptr = (RadarHeaderInfoS *)data;
|
||||
if (radar_info_ptr->nRadar == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理所有雷达数据
|
||||
for (int radar_idx = 0; radar_idx < radar_info_ptr->nRadar; ++radar_idx) {
|
||||
if (radar_idx >= cloud_pubs_.size()) {
|
||||
ROS_WARN("Radar index %d exceeds configured publisher count", radar_idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
FrameHeadObjNewS frame_obj = *(FrameHeadObjNewS *)(data + 64 * radar_idx + 64);
|
||||
|
||||
// 创建PCL点云
|
||||
pcl::PointCloud<pcl::PointXYZI> cloud;
|
||||
cloud.header.frame_id = "tr360_radar";
|
||||
cloud.is_dense = false;
|
||||
|
||||
// 解析点云数据
|
||||
points_5b *points = (points_5b *)(data + len - 5 * frame_obj.ObjNum);
|
||||
|
||||
for (int i = 0; i < frame_obj.ObjNum; ++i) {
|
||||
points_5b point = points[i];
|
||||
|
||||
// 转换为直角坐标系
|
||||
float a_rad = point.a * frame_obj.Res[0] + frame_obj.Offset[0];
|
||||
float r = point.r * frame_obj.Res[1] + frame_obj.Offset[1];
|
||||
float e_rad = point.e * frame_obj.Res[2];
|
||||
float intensity = point.v * frame_obj.Res[3] + frame_obj.Offset[3];
|
||||
|
||||
// 坐标转换: {x,y,z,v} = {r*cos(e)*cos(a), r*cos(e)*sin(a), r*sin(e), v}
|
||||
pcl::PointXYZI pcl_point;
|
||||
pcl_point.x = r * cos(e_rad) * cos(a_rad);
|
||||
pcl_point.y = r * cos(e_rad) * sin(a_rad);
|
||||
pcl_point.z = r * sin(e_rad);
|
||||
pcl_point.intensity = intensity;
|
||||
|
||||
cloud.points.push_back(pcl_point);
|
||||
}
|
||||
|
||||
// 发布点云
|
||||
sensor_msgs::PointCloud2 cloud_msg;
|
||||
pcl::toROSMsg(cloud, cloud_msg);
|
||||
cloud_msg.header.stamp = ros::Time::now();
|
||||
cloud_msg.header.frame_id = "tr360_radar_" + std::to_string(radar_idx + 1);
|
||||
|
||||
cloud_pubs_[radar_idx].publish(cloud_msg);
|
||||
|
||||
ROS_INFO("Published %lu points from radar %d", cloud.points.size(), radar_idx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void initCommandServer()
|
||||
{
|
||||
tcp_socket_ = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (tcp_socket_ < 0) {
|
||||
ROS_ERROR("Failed to create TCP socket");
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置TCP服务器地址
|
||||
struct sockaddr_in tcp_addr;
|
||||
memset(&tcp_addr, 0, sizeof(tcp_addr));
|
||||
tcp_addr.sin_family = AF_INET;
|
||||
tcp_addr.sin_addr.s_addr = inet_addr(local_ip_.c_str());
|
||||
tcp_addr.sin_port = htons(local_port_ + 1000); // 命令端口为数据端口+1000
|
||||
|
||||
// 绑定并监听
|
||||
if (bind(tcp_socket_, (struct sockaddr*)&tcp_addr, sizeof(tcp_addr)) < 0) {
|
||||
ROS_ERROR("TCP bind failed");
|
||||
close(tcp_socket_);
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(tcp_socket_, 5) < 0) {
|
||||
ROS_ERROR("TCP listen failed");
|
||||
close(tcp_socket_);
|
||||
return;
|
||||
}
|
||||
|
||||
ROS_INFO("TCP command server started on %s:%d", local_ip_.c_str(), local_port_ + 1000);
|
||||
}
|
||||
|
||||
void handleCommand(int client_sock)
|
||||
{
|
||||
char buffer[1024];
|
||||
int recv_len = recv(client_sock, buffer, sizeof(buffer) - 1, 0);
|
||||
|
||||
if (recv_len > 0) {
|
||||
buffer[recv_len] = '\0';
|
||||
std::string command(buffer);
|
||||
|
||||
// 去除回车换行
|
||||
size_t pos;
|
||||
while ((pos = command.find("\r\n")) != std::string::npos) {
|
||||
command.erase(pos, 2);
|
||||
}
|
||||
while ((pos = command.find('\n')) != std::string::npos) {
|
||||
command.erase(pos, 1);
|
||||
}
|
||||
while ((pos = command.find('\r')) != std::string::npos) {
|
||||
command.erase(pos, 1);
|
||||
}
|
||||
|
||||
// 添加到历史记录
|
||||
addToHistory(command);
|
||||
|
||||
// 处理命令
|
||||
std::string response = processRadarCommand(command);
|
||||
|
||||
// 发送响应(添加回车换行)
|
||||
response += "\r\n";
|
||||
send(client_sock, response.c_str(), response.length(), 0);
|
||||
|
||||
ROS_INFO("Command: %s -> Response: %s", command.c_str(), response.c_str());
|
||||
}
|
||||
|
||||
close(client_sock);
|
||||
}
|
||||
|
||||
void addToHistory(const std::string& command)
|
||||
{
|
||||
command_history_.push_back(command);
|
||||
if (command_history_.size() > max_history_size_) {
|
||||
command_history_.erase(command_history_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
std::string processRadarCommand(const std::string& command)
|
||||
{
|
||||
if (command == "history") {
|
||||
std::string history;
|
||||
for (size_t i = 0; i < command_history_.size(); ++i) {
|
||||
history += std::to_string(i + 1) + ": " + command_history_[i] + "\n";
|
||||
}
|
||||
return history.empty() ? "No command history" : history;
|
||||
}
|
||||
else if (command == "status") {
|
||||
return "Radar type: " + radar_type_ + ", Port: " + std::to_string(local_port_);
|
||||
}
|
||||
else if (command.find("set_port") == 0) {
|
||||
// 设置端口命令格式: set_port 10195
|
||||
size_t space_pos = command.find(' ');
|
||||
if (space_pos != std::string::npos) {
|
||||
try {
|
||||
int new_port = std::stoi(command.substr(space_pos + 1));
|
||||
local_port_ = new_port;
|
||||
return "Port set to: " + std::to_string(new_port);
|
||||
} catch (...) {
|
||||
return "Invalid port number";
|
||||
}
|
||||
}
|
||||
return "Usage: set_port <port_number>";
|
||||
}
|
||||
|
||||
// 默认响应 - 模拟雷达命令响应
|
||||
return "ACK: " + command;
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
unsigned char buffer[1500];
|
||||
socklen_t client_len = sizeof(client_addr_);
|
||||
fd_set read_fds;
|
||||
int max_fd;
|
||||
|
||||
while (ros::ok()) {
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(udp_socket_, &read_fds);
|
||||
max_fd = udp_socket_;
|
||||
|
||||
if (enable_command_server_) {
|
||||
FD_SET(tcp_socket_, &read_fds);
|
||||
if (tcp_socket_ > max_fd) max_fd = tcp_socket_;
|
||||
}
|
||||
|
||||
struct timeval timeout = {0, 100000}; // 100ms timeout
|
||||
|
||||
int activity = select(max_fd + 1, &read_fds, NULL, NULL, &timeout);
|
||||
|
||||
if (activity > 0) {
|
||||
// 处理UDP数据
|
||||
if (FD_ISSET(udp_socket_, &read_fds)) {
|
||||
int recv_len = recvfrom(udp_socket_, buffer, sizeof(buffer), 0,
|
||||
(struct sockaddr*)&client_addr_, &client_len);
|
||||
|
||||
if (recv_len > 0) {
|
||||
int result = parseFrame(buffer, recv_len);
|
||||
if (result == 3) {
|
||||
processPointCloud(buffer, recv_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理TCP命令连接
|
||||
if (enable_command_server_ && FD_ISSET(tcp_socket_, &read_fds)) {
|
||||
struct sockaddr_in client_addr;
|
||||
socklen_t client_len = sizeof(client_addr);
|
||||
int client_sock = accept(tcp_socket_, (struct sockaddr*)&client_addr, &client_len);
|
||||
|
||||
if (client_sock >= 0) {
|
||||
// 在新线程中处理命令
|
||||
std::thread(&TR360RadarNode::handleCommand, this, client_sock).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ros::spinOnce();
|
||||
}
|
||||
|
||||
close(udp_socket_);
|
||||
if (enable_command_server_) {
|
||||
close(tcp_socket_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
ros::init(argc, argv, "tr360_radar_node");
|
||||
|
||||
TR360RadarNode node;
|
||||
node.run();
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user