commit 7fbddb15c211a2fda64f067b4a1c2324da229f95 Author: Orange <2314753575@qq.com> Date: Thu Mar 5 10:27:00 2026 +0800 Please enter the commit message for your changes. Lines starting with '#' will be ignored, and an empty message aborts the commit. On branch master Initial commit Changes to be committed: new file: bashes/README.md new file: bashes/radar-driver-switch.sh new file: dependencies/dependencies.txt new file: src/LSLIDAR_X_ROS2-20240228/src/README.md new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/CMakeLists.txt new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/input.h new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/lsiosr.h new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/lslidar_driver.h new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lslidar_double_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10_net_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10_uart_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10p_net_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10p_uart_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10_net_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10p_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10p_net_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/viewer_scan_launch.py new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/package.xml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsm10_net.yaml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsm10p_net.yaml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsn10_net.yaml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsn10p_net.yaml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsm10.yaml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsm10_p.yaml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsn10.yaml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsn10p.yaml new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/rviz/lslidar.rviz new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/input.cc new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lsiosr.cpp new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lslidar_driver.cc new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lslidar_driver_node.cc new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/CMakeLists.txt new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarDifop.msg new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarPacket.msg new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarPoint.msg new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarScan.msg new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarSweep.msg new file: src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/package.xml new file: src/LSLIDAR_X_ROS2-20240228/src/version.txt new file: src/LSLIDAR_X_ROS2-20240228/src/wheeltec_udev.sh new file: "src/LSLIDAR_X_ROS2-20240228/src/\351\225\255\347\245\236Lsx\351\233\267\350\276\276\346\227\213\350\275\254\350\247\222\345\272\246.png" new file: src/LSLIDAR_X_ROS2-20240228/wheeltec_lidar.launch.py new file: "src/LSLIDAR_X_ROS2-20240228/wheeltec_lidar.launch.py\344\273\205\345\234\250WHEELTEC\351\225\234\345\203\217\344\270\255\344\275\277\347\224\250" new file: src/cyy_navigation2/CMakeLists.txt new file: src/cyy_navigation2/bt/follow_point.xml new file: src/cyy_navigation2/bt/nav_to_pose_with_consistent_replanning_and_if_path_becomes_invalid.xml new file: src/cyy_navigation2/bt/navigate_through_poses_w_replanning_and_recovery.xml new file: src/cyy_navigation2/bt/navigate_to_pose_w_replanning_and_recovery.xml new file: src/cyy_navigation2/bt/navigate_to_pose_w_replanning_goal_patience_and_recovery.xml new file: src/cyy_navigation2/bt/navigate_w_recovery_and_replanning_only_if_path_becomes_invalid.xml new file: src/cyy_navigation2/bt/navigate_w_replanning_distance.xml new file: src/cyy_navigation2/bt/navigate_w_replanning_only_if_goal_is_updated.xml new file: src/cyy_navigation2/bt/navigate_w_replanning_only_if_path_becomes_invalid.xml new file: src/cyy_navigation2/bt/navigate_w_replanning_speed.xml new file: src/cyy_navigation2/bt/navigate_w_replanning_time.xml new file: src/cyy_navigation2/bt/odometry_calibration.xml new file: src/cyy_navigation2/config/nav2_params.yaml new file: src/cyy_navigation2/launch/car_bringup.launch.py new file: src/cyy_navigation2/launch/cyy_nav.launch.py new file: src/cyy_navigation2/launch/cyy_nav_box.launch.py new file: src/cyy_navigation2/maps/cyy_map.data new file: src/cyy_navigation2/maps/cyy_map.pgm new file: src/cyy_navigation2/maps/cyy_map.yaml new file: src/cyy_navigation2/maps/cyy_map1.pgm new file: src/cyy_navigation2/maps/cyy_map1.yaml new file: src/cyy_navigation2/package.xml new file: src/cyy_navigation2/param/nav2_params.yaml new file: src/cyy_navigation2/param/slam_toolbox_localization.yaml new file: src/cyy_slamtoolbox/CMakeLists.txt new file: src/cyy_slamtoolbox/config/angular_filter_example.yaml new file: src/cyy_slamtoolbox/config/box_filter_example.yaml new file: src/cyy_slamtoolbox/config/footprint_filter_example.yaml new file: src/cyy_slamtoolbox/config/intensity_filter_example.yaml new file: src/cyy_slamtoolbox/config/laser_filter_config.yaml new file: src/cyy_slamtoolbox/config/mapper_params_lifelong.yaml new file: src/cyy_slamtoolbox/config/mapper_params_localization.yaml new file: src/cyy_slamtoolbox/config/mapper_params_offline.yaml new file: src/cyy_slamtoolbox/config/mapper_params_online_async.yaml new file: src/cyy_slamtoolbox/config/mapper_params_online_sync.yaml new file: src/cyy_slamtoolbox/config/mask_filter_example.yaml new file: src/cyy_slamtoolbox/config/median_filter_example.yaml new file: src/cyy_slamtoolbox/config/median_spatial_filter_example.yaml new file: src/cyy_slamtoolbox/config/multiple_filters_example.yaml new file: src/cyy_slamtoolbox/config/pass_through_example.yaml new file: src/cyy_slamtoolbox/config/polygon_filter_example.yaml new file: src/cyy_slamtoolbox/config/range_filter_example.yaml new file: src/cyy_slamtoolbox/config/scan_blob_filter_example.yaml new file: src/cyy_slamtoolbox/config/sector_filter_example.yaml new file: src/cyy_slamtoolbox/config/shadow_filter_example.yaml new file: src/cyy_slamtoolbox/config/slam_toolbox_default.rviz new file: src/cyy_slamtoolbox/config/speckle_filter_example.yaml new file: src/cyy_slamtoolbox/launch/cyy_slam_toolbox_launch.launch.py new file: src/cyy_slamtoolbox/launch/cyy_slam_toolbox_location.launch.py new file: src/cyy_slamtoolbox/launch/filter.launch.py new file: src/cyy_slamtoolbox/package.xml new file: src/gc_navigation_fish/CMakeLists.txt new file: src/gc_navigation_fish/launch/gc_navigation.launch.py new file: src/gc_navigation_fish/maps/test_map.pgm new file: src/gc_navigation_fish/maps/test_map.yaml new file: src/gc_navigation_fish/package.xml new file: src/gc_navigation_fish/param/gc_navigation.yaml new file: src/gc_navigation_fish/param/navigation_test.yaml new file: src/gc_slam_toolbox_fish/CMakeLists.txt new file: src/gc_slam_toolbox_fish/config/gc_2d.lua new file: src/gc_slam_toolbox_fish/launch/catograph.launch.py new file: src/gc_slam_toolbox_fish/package.xml new file: src/origincar_base/CMakeLists.txt new file: src/origincar_base/config/ekf.yaml new file: src/origincar_base/config/imu.yaml new file: src/origincar_base/include/origincar_base/Quaternion_Solution.h new file: src/origincar_base/include/origincar_base/origincar_base.h new file: src/origincar_base/launch/__pycache__/testtwo.launch.cpython-38.pyc new file: src/origincar_base/launch/base_serial.launch.py new file: src/origincar_base/launch/ekf.launch.py new file: src/origincar_base/launch/origincar_bringup.launch.py new file: src/origincar_base/launch/robot_mode_description.launch.py new file: src/origincar_base/msg/Position.msg new file: src/origincar_base/package.xml new file: src/origincar_base/scripts/cmd_vel_to_ackermann_drive.py new file: src/origincar_base/src/Quaternion_Solution.cpp new file: src/origincar_base/src/origincar_base.cpp new file: src/origincar_description/CMakeLists.txt new file: src/origincar_description/CMakeLists.txt.save new file: src/origincar_description/config/joint_names_origincar_description.yaml new file: "src/origincar_description/config/joint_names_origincar_description.yaml\357\200\272Zone.Identifier" new file: src/origincar_description/launch/display.launch new file: src/origincar_description/launch/display.launch.py new file: src/origincar_description/launch/gazebo.launch new file: src/origincar_description/launch/gazebo.launch.py new file: src/origincar_description/meshes/base_link.STL new file: "src/origincar_description/meshes/base_link.STL\357\200\272Zone.Identifier" new file: src/origincar_description/meshes/down_left_Link.STL new file: "src/origincar_description/meshes/down_left_Link.STL\357\200\272Zone.Identifier" new file: src/origincar_description/meshes/down_right_Link.STL new file: "src/origincar_description/meshes/down_right_Link.STL\357\200\272Zone.Identifier" new file: src/origincar_description/meshes/up_left_Link.STL new file: "src/origincar_description/meshes/up_left_Link.STL\357\200\272Zone.Identifier" new file: src/origincar_description/meshes/up_right_Link.STL new file: "src/origincar_description/meshes/up_right_Link.STL\357\200\272Zone.Identifier" new file: src/origincar_description/package.xml new file: src/origincar_description/rviz/README new file: src/origincar_description/rviz/display.rviz new file: src/origincar_description/urdf/origincar.urdf new file: src/origincar_description/urdf/origincar.xacro new file: src/origincar_description/world/fishbot.world new file: src/origincar_description/world/gc_world.world new file: src/origincar_description/world/test.world new file: src/origincar_msg/CMakeLists.txt new file: src/origincar_msg/msg/Data.msg new file: src/origincar_msg/msg/Sign.msg new file: src/origincar_msg/package.xml new file: src/zbw_slamtoolbox/CMakeLists.txt new file: src/zbw_slamtoolbox/config/mapper_params_online_async.yaml new file: src/zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml new file: src/zbw_slamtoolbox/config/navigation.yaml new file: src/zbw_slamtoolbox/launch/navigation.launch.py new file: src/zbw_slamtoolbox/launch/slamtoolbox.launch.py new file: src/zbw_slamtoolbox/package.xml new file: zbw_slamtoolbox/CMakeLists.txt new file: zbw_slamtoolbox/config/mapper_params_online_async.yaml new file: zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml new file: zbw_slamtoolbox/config/navigation.yaml new file: zbw_slamtoolbox/launch/navigation.launch.py new file: zbw_slamtoolbox/launch/slamtoolbox.launch.py new file: zbw_slamtoolbox/package.xml Changes not staged for commit: deleted: zbw_slamtoolbox/CMakeLists.txt deleted: zbw_slamtoolbox/config/mapper_params_online_async.yaml deleted: zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml deleted: zbw_slamtoolbox/config/navigation.yaml deleted: zbw_slamtoolbox/launch/navigation.launch.py deleted: zbw_slamtoolbox/launch/slamtoolbox.launch.py deleted: zbw_slamtoolbox/package.xml Untracked files: .gitignore diff --git a/bashes/README.md b/bashes/README.md new file mode 100644 index 0000000..42b9182 --- /dev/null +++ b/bashes/README.md @@ -0,0 +1,52 @@ +## 关于雷达驱动自动配置脚本的说明 +### 在设备上配置开机自启动 +1. 放到固定位置并授权 + ```bash + sudo cp 你的脚本路径 /usr/local/bin/radar-driver-switch.sh + sudo chmod +x /usr/local/bin/radar-driver-switch.sh + sudo chown root:root /usr/local/bin/radar-driver-switch.sh + ``` +2. 创建 systemd 服务文件 + ```bash + sudo vim /etc/systemd/system/radar-driver-switch.service + ``` + 编辑内容: + ```ini + [Unit] + Description=雷达驱动自动切换程序 + After=sysfs.target udev.target systemd-udevd.service + Before=multi-user.target + + [Service] + Type=oneshot + ExecStart=/usr/local/bin/radar-driver-switch.sh + User=root + Group=root + StandardOutput=journal+console + StandardError=journal+console + + [Install] + WantedBy=multi-user.target + ``` +3. 应用开机自启 + ```bash + sudo systemctl daemon-reload + sudo systemctl enable radar-driver-switch.service + ``` +4. 测试与debug + - 测试一次 + ```bash + sudo systemctl start radar-driver-switch.service + ``` + - 查看状态 / 日志(排查必用) + ```bash + sudo systemctl status radar-driver-switch.service + ``` + - 看 dmesg 日志 + ```bash + dmesg | grep 雷达驱动自动切换程序 + ``` +--- +### 特别说明 +1. 关于退出码对应的情况,详见sh文件开头 +2. 日志输出在`/dev/kmsg`文件中,使用`dmesg | grep 雷达驱动自动切换程序`命令即可查看 \ No newline at end of file diff --git a/bashes/radar-driver-switch.sh b/bashes/radar-driver-switch.sh new file mode 100644 index 0000000..4faab12 --- /dev/null +++ b/bashes/radar-driver-switch.sh @@ -0,0 +1,125 @@ +#!/bin/bash + +# 退出码说明 +# 0 - 成功 +# 1 - 错误:等待TTY设备就绪超时 +# 2 - 错误:未找到CH343驱动 +# 3 - 错误:未找到含Qingheng的USB设备 +# 4 - 错误:未找到对应USB地址 +# 5 - 错误:未找到cdc_acm绑定的对应USB设备 +# 6 - 错误:解绑cdc_acm驱动失败 +# 7 - 错误:绑定usb_ch343驱动失败 + +# 变量设置 +TTY_DEVICE="/dev/ttyACM1" # 替换为你要等待的tty设备路径 +CDC_ACM_PATH="/sys/bus/usb/drivers/cdc_acm" +USB_CH343_PATH="/sys/bus/usb/drivers/usb_ch343" +CHECK_INTERVAL=1 # 检查设备就绪的时间间隔(秒) +MAX_WAIT_SECONDS=30 # 最大等待时间(秒),0表示无限等待 + +# 初始化变量 +start_time=$(date +%s) +current_time=0 +qinheng_id="" +usb_address="" +vendor_id="" +product_id="" +cdc_acm_sub_addr="" + + +# ----------------- 1. 等待TTY设备就绪 ----------------- +# 循环等待tty设备就绪(检查设备节点是否存在+是否可读写) +while true; do + if [ -c "${TTY_DEVICE}" ] && [ -r "${TTY_DEVICE}" ] && [ -w "${TTY_DEVICE}" ]; then + echo "[雷达驱动自动切换程序] 设备 ${TTY_DEVICE} 已就绪!" > /dev/kmsg + break + fi + + if [ ${MAX_WAIT_SECONDS} -gt 0 ]; then + current_time=$(date +%s) + elapsed_seconds=$((current_time - start_time)) + if [ ${elapsed_seconds} -ge ${MAX_WAIT_SECONDS} ]; then + echo "[雷达驱动自动切换程序] 错误:等待 ${TTY_DEVICE} 超时(${MAX_WAIT_SECONDS}秒)!" > /dev/kmsg + exit 1 + fi + echo "[雷达驱动自动切换程序] 仍在等待${TTY_DEVICE}(已等待${elapsed_seconds}秒)..." > /dev/kmsg + fi + + sleep ${CHECK_INTERVAL} +done + +# ------ 2. 查看CH343是否存在 ------ +if ls /sys/bus/usb/drivers/usb_ch343 > /dev/null 2>&1; then + echo "[雷达驱动自动切换程序] 检测到CH343驱动存在,继续执行..." > /dev/kmsg +else + echo "[雷达驱动自动切换程序] 错误:未找到CH343驱动!" > /dev/kmsg + exit 2 +fi + + +# ------------- 3. 查找Qingheng对应的usb接口 ------------- +echo "[雷达驱动自动切换程序] 开始提取QinHeng设备ID..." > /dev/kmsg + +# 执行lsusb并过滤含QinHeng的行,提取ID(核心逻辑) +qinheng_id=$(lsusb | grep "QinHeng" | awk '{print $6}' | head -n 1) + +# 检查是否提取到ID +if [ -z "${qinheng_id}" ]; then + echo "[雷达驱动自动切换程序] 错误:未找到含QinHeng的USB设备!" > /dev/kmsg + exit 3 +else + echo "[雷达驱动自动切换程序] 成功提取QinHeng设备ID:${qinheng_id}" > /dev/kmsg + # 将ID拆分为vendor_id和product_id + vendor_id=$(echo "${qinheng_id}" | cut -d ':' -f 1) + product_id=$(echo "${qinheng_id}" | cut -d ':' -f 2) +fi + +# -------------------- 4. 提取USB地址 -------------------- +echo "[雷达驱动自动切换程序] 开始查找idVendor=${vendor_id},idProduct=${product_id}的USB地址..." > /dev/kmsg +# 核心命令:过滤dmesg日志,提取USB地址 +usb_address=$(dmesg | grep -E "idVendor=${vendor_id}, idProduct=${product_id}" | grep -oE "usb [0-9]+-[0-9.]+:" | awk '{print $2}' | sed 's/://' | tail -n 1) + +# 检查是否提取到USB地址 +if [ -z "${usb_address}" ]; then + echo "[雷达驱动自动切换程序] 错误:未找到对应USB地址" > /dev/kmsg + exit 4 +else + echo "[雷达驱动自动切换程序] 成功找到USB地址:${usb_address}" > /dev/kmsg +fi + +# ---- 5. 找到cdc_acm驱动对应的usb设备 ---- +echo "[雷达驱动自动切换程序] 开始从${CDC_ACM_PATH}提取${usb_address}对应的子地址..." > /dev/kmsg + +cdc_acm_sub_addr=$(ls "${CDC_ACM_PATH}" 2>/dev/null | grep "^${usb_address}:" | head -n 1) + +if [ -z "${cdc_acm_sub_addr}" ]; then + echo "[雷达驱动自动切换程序] 错误:${CDC_ACM_PATH}中未找到${usb_address}绑定的对应USB设备" > /dev/kmsg + exit 5 +else + echo "[雷达驱动自动切换程序] 成功提取cdc_acm子地址:${cdc_acm_sub_addr}" > /dev/kmsg +fi + +# 6. 切换驱动 +echo "[雷达驱动自动切换程序] 开始切换cdc_acm驱动到USB地址${usb_address}..." > /dev/kmsg + +echo "${cdc_acm_sub_addr}" | sudo tee "${CDC_ACM_PATH}/unbind" 2>/dev/null +if [ $? -eq 0 ]; then + echo "[雷达驱动自动切换程序] 成功解绑cdc_acm驱动:${cdc_acm_sub_addr}" > /dev/kmsg +else + echo "[雷达驱动自动切换程序] 错误:解绑cdc_acm驱动失败" > /dev/kmsg + exit 6 +fi + +echo "${cdc_acm_sub_addr}" | sudo tee "${USB_CH343_PATH}/bind" 2>/dev/null +if [ $? -eq 0 ]; then + echo "[雷达驱动自动切换程序] 成功绑定usb_ch343驱动:${cdc_acm_sub_addr}" > /dev/kmsg +else + echo "[雷达驱动自动切换程序] 错误:绑定usb_ch343驱动失败(检查驱动是否加载)" > /dev/kmsg + exit 7 +fi + + +# 执行完成 +echo "[雷达驱动自动切换程序] 雷达驱动自动切换完毕!" > /dev/kmsg + +exit 0 \ No newline at end of file diff --git a/dependencies/dependencies.txt b/dependencies/dependencies.txt new file mode 100644 index 0000000..489f65e --- /dev/null +++ b/dependencies/dependencies.txt @@ -0,0 +1,5 @@ +ros-humble-serial-driver +ros-humble-ackermann-msgs +# 从源码编译serial库 +ros-humble-navigation2 +ros-humble-slam-toolbox \ No newline at end of file diff --git a/src/LSLIDAR_X_ROS2-20240228/src/README.md b/src/LSLIDAR_X_ROS2-20240228/src/README.md new file mode 100644 index 0000000..9871ecc --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/README.md @@ -0,0 +1,44 @@ +# lslidar + +## Description +The `lslidar package is a linux ROS2 driver for lslidar M10 ,M10_GPS,M10_P,M10_PLUS and N10. +The package is tested on Ubuntu 20.04 with ROS2 indigo. + +## Compling +This is a Catkin package. Make sure the package is on `ROS_PACKAGE_PATH` after cloning the package to your workspace. And the normal procedure for compling a catkin package will work. + +``` +cd your_work_space +colcon build +source install/setup.bash +ros2 launch lslidar_driver lslidar_launch.py +``` +open new terminal +ros2 topic pub -1 /lslidar_order std_msgs/msg/Int8 data:\ 1\ (open radar) +ros2 topic pub -1 /lslidar_order std_msgs/msg/Int8 data:\ 0\ (close radar) + + + + + +ros2 launch lslidar_driver lslidar_launch.py + +``` + +Note that this launch file launches both the driver, which is the only launch file needed to be used. + + +## FAQ + + +## Bug Report + +Prefer to open an issue. You can also send an E-mail to honghangli@lslidar.com + + + + +RERTION + + + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/CMakeLists.txt b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/CMakeLists.txt new file mode 100644 index 0000000..85e13f6 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/CMakeLists.txt @@ -0,0 +1,56 @@ +cmake_minimum_required(VERSION 3.5) +project(lslidar_driver) + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +set(libpcap_LIBRARIES -lpcap) + +#set(FastRTPS_INCLUDE_DIR /opt/ros/foxy/include) +#set(FastRTPS_LIBRARY_RELEASE /opt/ros/foxy/lib/libfastrtps.so) + +#find_package(Boost REQUIRED COMPONENTS ) +find_package(Boost REQUIRED thread) +find_package(rclcpp REQUIRED) +find_package(PCL REQUIRED) +find_package(diagnostic_updater REQUIRED) +find_package(lslidar_msgs REQUIRED) +find_package(std_msgs REQUIRED) +find_package(ament_cmake REQUIRED) +find_package(pluginlib REQUIRED) +find_package(rclpy REQUIRED) +find_package(pcl_conversions REQUIRED) +find_package(sensor_msgs REQUIRED) +#find_package(PCL REQUIRED COMPONENTS common io) + +include_directories( + include + ${PCL_INCLUDE_DIRS} + ${PCL_COMMON_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} +) + +# Node +add_executable(lslidar_driver_node src/lslidar_driver_node.cc src/lslidar_driver.cc src/input.cc src/lsiosr.cpp) +target_link_libraries(lslidar_driver_node ${rclcpp_LIBRARIES} ${libpcap_LIBRARIES} ${Boost_LIBRARIES} Boost::thread) +ament_target_dependencies(lslidar_driver_node rclcpp std_msgs lslidar_msgs sensor_msgs diagnostic_updater pcl_conversions) + + +install(DIRECTORY launch params rviz + DESTINATION share/${PROJECT_NAME}) + +install(TARGETS + lslidar_driver_node + DESTINATION lib/${PROJECT_NAME} +) + +ament_export_dependencies(rclcpp pluginlib lslidar_msgs sensor_msgs pcl_conversions) +ament_export_include_directories(include ${PCL_COMMON_INCLUDE_DIRS}) + +ament_package() diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/input.h b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/input.h new file mode 100644 index 0000000..2715da4 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/input.h @@ -0,0 +1,134 @@ +/* + * This file is part of lslidar_ch driver. + * + * The driver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the driver. If not, see . + * + * Input -- base class used to access the data independently of + * its source + * + * InputSocket -- derived class reads live data from the device + * via a UDP socket + * + * InputPCAP -- derived class provides a similar interface from a + * PCAP dump + */ + +#ifndef __LSLIDAR_INPUT_H_ +#define __LSLIDAR_INPUT_H_ + +#include +#include +#include +#include +#include "rclcpp/rclcpp.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace lslidar_driver +{ +static uint16_t MSOP_DATA_PORT_NUMBER = 2368; // lslidar default data port on PC +/** + * 从在线的网络数据或离线的网络抓包数据(pcap文件)中提取出lidar的原始数据,即packet数据包 + * @brief The Input class, + * + * @param private_nh 一个NodeHandled,用于通过节点传递参数 + * @param port + * @returns 0 if successful, + * -1 if end of file + * >0 if incomplete packet (is this possible?) + */ +class Input +{ +public: + Input(rclcpp::Node* private_nh, uint16_t port); + + virtual ~Input() + { + } + + virtual int getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &packet) = 0; + + int getRpm(void); + int getReturnMode(void); + bool getUpdateFlag(void); + void clearUpdateFlag(void); + void UDP_order(const std_msgs::msg::Int8 msg); + void UDP_difop(); +protected: + rclcpp::Node* private_nh_; + uint16_t port_; + std::string devip_str_; + std::string lidar_name; + int cur_rpm_; + int return_mode_; + bool npkt_update_flag_; + bool add_multicast; + std::string group_ip; + int UDP_PORT_NUMBER_DIFOP; + int socket_id_difop; + int sockfd_; + std::string devip_str_difop; +}; + +/** @brief Live lslidar input from socket. */ +class InputSocket : public Input +{ +public: + InputSocket(rclcpp::Node* private_nh, uint16_t port = MSOP_DATA_PORT_NUMBER); + + virtual ~InputSocket(); + + virtual int getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &packet); + +private: +private: + + in_addr devip_; + in_addr devip_difop; + //struct ip_mreq group; + +}; +class InputPCAP : public Input +{ +public: + InputPCAP(rclcpp::Node* private_nh,uint16_t port = MSOP_DATA_PORT_NUMBER, double packet_rate = 0.0, + std::string filename=""); + virtual ~InputPCAP(); + virtual int getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &pkt); +private: + + rclcpp::Rate packet_rate_; + std::string filename_; + pcap_t *pcap_; + bpf_program pcap_packet_filter_; + char errbuf_[PCAP_ERRBUF_SIZE]; + bool empty_; + bool read_once_; + bool read_fast_; + double repeat_delay_; + }; +} + +#endif // __LSLIDAR_INPUT_H diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/lsiosr.h b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/lsiosr.h new file mode 100644 index 0000000..6109497 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/lsiosr.h @@ -0,0 +1,88 @@ +/******************************************************* +@company: Copyright (C) 2021, Leishen Intelligent System +@product: LSM10_N10 +@filename: lsiosr.cpp +@brief: +@version: date: author: comments: +@v1.0 22-10-24 li new +*******************************************************/ +#ifndef LSIOSR_H +#define LSIOSR_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//波特率 +#define BAUD_230400 230400 +#define BAUD_460800 460800 +#define BAUD_500000 500000 +#define BAUD_921600 921600 + +//奇偶校验位 +#define PARITY_ODD 'O' //奇数 +#define PARITY_EVEN 'E' //偶数 +#define PARITY_NONE 'N' //无奇偶校验位 + +//停止位 +#define STOP_BIT_1 1 +#define STOP_BIT_2 2 + +//数据位 +#define DATA_BIT_7 7 +#define DATA_BIT_8 8 + +namespace lslidar_driver +{ +class LSIOSR{ +public: + static LSIOSR* instance(std::string name, int speed, int fd = 0); + + ~LSIOSR(); + + /* 从串口中读取数据 */ + int read(unsigned char *buffer, int length, int timeout = 30); + + /* 向串口传数据 */ + int send(const char* buffer, int length, int timeout = 30); + + /* Empty serial port input buffer */ + void flushinput(); + + /* 串口初始化 */ + int init(); + + int close(); + + /* 获取串口号 */ + std::string getPort(); + + /* 设置串口号 */ + int setPortName(std::string name); + +private: + LSIOSR(std::string name, int speed, int fd); + + int waitWritable(int millis); + int waitReadable(int millis); + + /* 串口配置的函数 */ + int setOpt(int nBits, uint8_t nEvent, int nStop); + + std::string port_; + int baud_rate_; + + int fd_; +}; +} +#endif + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/lslidar_driver.h b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/lslidar_driver.h new file mode 100644 index 0000000..34bb6d1 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/include/lslidar_driver/lslidar_driver.h @@ -0,0 +1,159 @@ +/* + * This file is part of lslidar driver. + * + * The driver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the driver. If not, see . + */ + +#ifndef LSLIDAR_DRIVER_H +#define LSLIDAR_DRIVER_H + +#include +#include +#include +#include + +#include +#include +#include +#include "rclcpp/rclcpp.hpp" +#include +#include "diagnostic_updater/diagnostic_updater.hpp" +#include "diagnostic_updater/publisher.hpp" +#include "lslidar_msgs/msg/lslidar_packet.hpp" +#include "std_msgs/msg/byte.hpp" + +#include "sensor_msgs/msg/point_cloud2.hpp" +#include "pcl_conversions/pcl_conversions.h" +#include "pcl/point_types.h" + +#include "time.h" +#include "input.h" +#include "lsiosr.h" +#include "sensor_msgs/msg/laser_scan.hpp" +namespace lslidar_driver { + +struct PointXYZIT { + PCL_ADD_POINT4D; + uint8_t intensity; + double timestamp; + EIGEN_MAKE_ALIGNED_OPERATOR_NEW // make sure our new allocators are aligned +} EIGEN_ALIGN16; + +typedef struct { + double degree; + double range; + double intensity; +} ScanPoint; + +class LslidarDriver: public rclcpp::Node { +public: + LslidarDriver(); + LslidarDriver(const rclcpp::NodeOptions& options); + ~LslidarDriver(); + + bool initialize(); + bool polling(); + + typedef std::shared_ptr LslidarDriverPtr; + typedef std::shared_ptr LslidarDriverConstPtr; + +private: + uint64_t get_gps_stamp(struct tm t); + uint8_t N10_CalCRC8(unsigned char * p, int len); + bool loadParameters(); + bool createRosIO(); + void open_serial(); + void lidar_difop(); + void lidar_order(const std_msgs::msg::Int8::SharedPtr msg); + void data_processing(unsigned char *packet_bytes,int len); + void data_processing_2(unsigned char *packet_bytes,int len); + void difop_processing(unsigned char *packet_bytes); + void pubScanThread(); + void recvThread_crc(int &count,int &link_time); + int receive_data(unsigned char *packet_bytes); + int getScan(std::vector &points, rclcpp::Time &scan_time, float &scan_duration); + + boost::thread *pubscan_thread_ ; + boost::shared_ptr msop_input_; + boost::mutex mutex_; + boost::mutex pubscan_mutex_; + boost::condition_variable pubscan_cond_; + int UDP_PORT_NUMBER; + int count_num; + int package_points; + int data_bits_start; + int degree_bits_start; + int end_degree_bits_start; + int rpm_bits_start; + int baud_rate_; + int points_size_; + int idx = 0; + int link_time = 0; + int fixed_array_length;//cyy_add + + bool use_gps_ts; + bool is_start; + bool high_reflection; + bool compensation; + bool first_compensation = true; + bool pubScan; + bool pubPointCloud2; + + double min_range; + double max_range; + double angle_disable_min; + double angle_disable_max; + double angle_able_min; + double angle_able_max; + double last_degree = 0.0; + double degree_compensation = 0.0; + + uint16_t PACKET_SIZE ; + uint64_t sweep_end_time_gps; + uint64_t sweep_end_time_hardware; + uint64_t sub_second; + + std::string frame_id; + std::string interface_selection; + std::string scan_topic; + std::string lidar_name; + std::string serial_port_; + std::string dump_file; + std::string pointcloud_topic; + std::string in_file_name; + + tm pTime; + rclcpp::Time pre_time_; + rclcpp::Time time_; + std::vector scan_points_; + std::vector scan_points_bak_; + // Diagnostics updater + diagnostic_updater::Updater diagnostics; + std::shared_ptr diag_topic; + double diag_min_freq; + double diag_max_freq; + rclcpp::Publisher::SharedPtr scan_pub; + rclcpp::Publisher::SharedPtr point_cloud_pub; + rclcpp::Subscription::SharedPtr difop_switch; + LSIOSR * serial_; +}; +typedef PointXYZIT VPoint; +typedef pcl::PointCloud VPointCloud; + +} // namespace lslidar_driver +POINT_CLOUD_REGISTER_POINT_STRUCT(lslidar_driver::PointXYZIT, + (float, x, x)(float, y, y)(float, z, z)( + std::uint8_t, intensity, + intensity)(double, timestamp, timestamp)) +#endif // _LSLIDAR_DRIVER_H_ diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lslidar_double_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lslidar_double_launch.py new file mode 100644 index 0000000..40ad793 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lslidar_double_launch.py @@ -0,0 +1,50 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir_1 = os.path.join(get_package_share_directory('lslidar_driver_n10p'), 'params', 'lsx10_1.yaml') + driver_dir_2 = os.path.join(get_package_share_directory('lslidar_driver_n10p'), 'params', 'lsx10_2.yaml') + + driver_node_1 = LifecycleNode(package='lslidar_driver_n10p', + executable='lslidar_driver_node', + name='lslidar_driver_node', #设置激光数据topic名称 + output='screen', + emulate_tty=True, + namespace='lidar_1', + parameters=[driver_dir_1], + ) + + driver_node_2 = LifecycleNode(package='lslidar_driver_n10p', + executable='lslidar_driver_node', + name='lslidar_driver_node', #设置激光数据topic名称 + output='screen', + emulate_tty=True, + namespace='lidar_2', + parameters=[driver_dir_2], + ) + + rviz_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'rviz', 'lslidar.rviz') + + rviz_node = Node( + package='rviz2', + namespace='', + executable='rviz2', + name='rviz2', + arguments=['-d', rviz_dir], + output='screen') + + return LaunchDescription([ + driver_node_1, + driver_node_2, + rviz_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10_net_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10_net_launch.py new file mode 100644 index 0000000..7659d3f --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10_net_launch.py @@ -0,0 +1,27 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params', 'lidar_net_ros2','lsm10_net.yaml') + + driver_node = LifecycleNode(package='lslidar_driver', + executable='lslidar_driver_node', + name='lslidar_driver_node', + output='screen', + emulate_tty=True, + namespace='', + parameters=[driver_dir], + ) + return LaunchDescription([ + driver_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10_uart_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10_uart_launch.py new file mode 100644 index 0000000..cd2fa16 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10_uart_launch.py @@ -0,0 +1,27 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params', 'lidar_uart_ros2','lsm10.yaml') + + driver_node = LifecycleNode(package='lslidar_driver', + executable='lslidar_driver_node', + name='lslidar_driver_node', + output='screen', + emulate_tty=True, + namespace='', + parameters=[driver_dir], + ) + return LaunchDescription([ + driver_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10p_net_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10p_net_launch.py new file mode 100644 index 0000000..e2468c8 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10p_net_launch.py @@ -0,0 +1,27 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params', 'lidar_net_ros2','lsm10p_net.yaml') + + driver_node = LifecycleNode(package='lslidar_driver', + executable='lslidar_driver_node', + name='lslidar_driver_node', + output='screen', + emulate_tty=True, + namespace='', + parameters=[driver_dir], + ) + return LaunchDescription([ + driver_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10p_uart_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10p_uart_launch.py new file mode 100644 index 0000000..10d1763 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsm10p_uart_launch.py @@ -0,0 +1,27 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params', 'lidar_uart_ros2','lsm10_p.yaml') + + driver_node = LifecycleNode(package='lslidar_driver', + executable='lslidar_driver_node', + name='lslidar_driver_node', + output='screen', + emulate_tty=True, + namespace='', + parameters=[driver_dir], + ) + return LaunchDescription([ + driver_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10_launch.py new file mode 100644 index 0000000..ae9366e --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10_launch.py @@ -0,0 +1,28 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params','lidar_uart_ros2', 'lsn10.yaml') + + driver_node = LifecycleNode(package='lslidar_driver', + executable='lslidar_driver_node', + name='lslidar_driver_node', #设置激光数据topic名称 + output='screen', + emulate_tty=True, + namespace='', + parameters=[driver_dir], + ) + + return LaunchDescription([ + driver_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10_net_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10_net_launch.py new file mode 100644 index 0000000..9a6a4d8 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10_net_launch.py @@ -0,0 +1,28 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params','lidar_net_ros2', 'lsn10_net.yaml') + + driver_node = LifecycleNode(package='lslidar_driver', + executable='lslidar_driver_node', + name='lslidar_driver_node', #设置激光数据topic名称 + output='screen', + emulate_tty=True, + namespace='', + parameters=[driver_dir], + ) + + return LaunchDescription([ + driver_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10p_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10p_launch.py new file mode 100644 index 0000000..758b03b --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10p_launch.py @@ -0,0 +1,28 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params','lidar_uart_ros2', 'lsn10p.yaml') + + driver_node = LifecycleNode(package='lslidar_driver', + executable='lslidar_driver_node', + name='lslidar_driver_node', #设置激光数据topic名称 + output='screen', + emulate_tty=True, + namespace='', + parameters=[driver_dir], + ) + + return LaunchDescription([ + driver_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10p_net_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10p_net_launch.py new file mode 100644 index 0000000..966bda9 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/lsn10p_net_launch.py @@ -0,0 +1,28 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + driver_dir = os.path.join(get_package_share_directory('lslidar_driver'), 'params','lidar_net_ros2', 'lsn10p_net.yaml') + + driver_node = LifecycleNode(package='lslidar_driver', + executable='lslidar_driver_node', + name='lslidar_driver_node', #设置激光数据topic名称 + output='screen', + emulate_tty=True, + namespace='', + parameters=[driver_dir], + ) + + return LaunchDescription([ + driver_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/viewer_scan_launch.py b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/viewer_scan_launch.py new file mode 100644 index 0000000..c82e76d --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/launch/viewer_scan_launch.py @@ -0,0 +1,26 @@ +#!/usr/bin/python3 +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch_ros.actions import LifecycleNode +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch.actions import DeclareLaunchArgument + +import lifecycle_msgs.msg +import os + +def generate_launch_description(): + + rviz2_config = os.path.join(get_package_share_directory('lslidar_driver'),'rviz','lslidar.rviz') + + rviz2_node = Node( + package='rviz2', + executable='rviz2', + name='rviz2', + arguments=['-d',rviz2_config], + output='screen') + + return LaunchDescription([ + rviz2_node, + ]) + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/package.xml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/package.xml new file mode 100644 index 0000000..2d88422 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/package.xml @@ -0,0 +1,36 @@ + + + lslidar_driver + 1.2.0 + ROS device driver for Leishen lidar. + Nick Shu + Nick Shu + GNU General Public License V3.0 + + ament_cmake + + rclcpp + std_msgs + lslidar_msgs + pcl_conversions + rclpy + libpcap + libpcl-all-dev + pluginlib + sensor_msgs + + rclcpp + std_msgs + lslidar_msgs + pcl_conversions + rclpy + libpcap + libpcl-all + pluginlib + sensor_msgs + + diagnostic_updater + + ament_cmake + + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsm10_net.yaml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsm10_net.yaml new file mode 100644 index 0000000..6e91feb --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsm10_net.yaml @@ -0,0 +1,22 @@ +/lslidar_driver_node: + ros__parameters: + frame_id: laser #激光坐标 + group_ip: 224.1.1.2 + add_multicast: false + device_ip: 192.168.1.200 #雷达目的ip + device_ip_difop: 192.168.1.102 #雷达源IP + msop_port: 2368 #雷达目的端口号 + difop_port: 2369 #雷达源端口号 + lidar_name: M10 #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 + ceil_increase: -1 #Lsm10*时改值应设置为-1 + angle_disable_min: 0.0 #单角度裁剪开始值 + angle_disable_max: 0.0 #单角度裁剪结束值 + truncated_mode_: 0 #多角度裁剪开关:值为0时表示不使用多角度裁剪,默认为0 + #值为1表示使用多角度裁剪,同时angle_disable_min与angle_disable_max设为 0,角度值在/lslidar_driver.cc中修改 + min_range: 0.0 #雷达接收距离最小值 + max_range: 200.0 #雷达接收距离最大值 + use_gps_ts: false #雷达是否使用GPS授时 + scan_topic: /scan #设置激光数据topic名称 + interface_selection: net #接口选择:net 为网口,serial 为串口。 + serial_port_: /dev/wheeltec_laser #串口连接时的串口号 +# pcap: /home/ls/work/2211/M10_P_gps.pcap #雷达是否使用pcap包读取功能 diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsm10p_net.yaml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsm10p_net.yaml new file mode 100644 index 0000000..a8e30ce --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsm10p_net.yaml @@ -0,0 +1,22 @@ +/lslidar_driver_node: + ros__parameters: + frame_id: laser #激光坐标 + group_ip: 224.1.1.2 + add_multicast: false + device_ip: 192.168.1.200 #雷达目的ip + device_ip_difop: 192.168.1.102 #雷达源IP + msop_port: 2368 #雷达目的端口号 + difop_port: 2369 #雷达源端口号 + lidar_name: M10_P #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 + ceil_increase: -1 #Lsm10*时改值应设置为-1 + angle_disable_min: 0.0 #单角度裁剪开始值 + angle_disable_max: 0.0 #单角度裁剪结束值 + truncated_mode_: 0 #多角度裁剪开关:值为0时表示不使用多角度裁剪,默认为0 + #值为1表示使用多角度裁剪,同时angle_disable_min与angle_disable_max设为 0,角度值在/lslidar_driver.cc中修改 + min_range: 0.0 #雷达接收距离最小值 + max_range: 200.0 #雷达接收距离最大值 + use_gps_ts: false #雷达是否使用GPS授时 + scan_topic: /scan #设置激光数据topic名称 + interface_selection: net #接口选择:net 为网口,serial 为串口。 + serial_port_: /dev/wheeltec_laser #串口连接时的串口号 +# pcap: /home/ls/work/2211/M10_P_gps.pcap #雷达是否使用pcap包读取功能 diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsn10_net.yaml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsn10_net.yaml new file mode 100644 index 0000000..f211d48 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsn10_net.yaml @@ -0,0 +1,25 @@ +/lslidar_driver_node: + ros__parameters: + frame_id: laser #激光坐标 + group_ip: 224.1.1.2 + add_multicast: false + device_ip: 192.168.1.200 #雷达源IP + device_ip_difop: 192.168.1.102 #雷达目的ip + msop_port: 2368 #雷达目的端口号 + difop_port: 2369 #雷达源端口号 + lidar_name: N10 #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 L10 N10_P + angle_disable_min: 0.0 #角度裁剪开始值 + angle_disable_max: 0.0 #角度裁剪结束值 + min_range: 0.2 #雷达接收距离最小值 + max_range: 200.0 #雷达接收距离最大值 + use_gps_ts: false #雷达是否使用GPS授时 + scan_topic: /scan #设置激光数据topic名称 + interface_selection: net #接口选择:net 为网口,serial 为串口。 + serial_port_: /dev/wheeltec_laser #串口连接时的串口号 + high_reflection: false #M10_P雷达需填写该值,若不确定,请联系技术支持。 + compensation: false #M10系列是否使用角度补偿功能 + pubScan: true #是否发布scan话题 + pubPointCloud2: false #是否发布pointcloud2话题 + pointcloud_topic: /lslidar_point_cloud #设置激光数据topic名称 +# pcap: /home/ls/1.pcap #雷达是否使用pcap包读取功能 +# in_file_name: /home/ls/1.txt #雷达是否使用txt文件读取功能 \ No newline at end of file diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsn10p_net.yaml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsn10p_net.yaml new file mode 100644 index 0000000..ffd83bb --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_net_ros2/lsn10p_net.yaml @@ -0,0 +1,25 @@ +/lslidar_driver_node: + ros__parameters: + frame_id: laser #激光坐标 + group_ip: 224.1.1.2 + add_multicast: false + device_ip: 192.168.1.200 #雷达源IP + device_ip_difop: 192.168.1.102 #雷达目的ip + msop_port: 2368 #雷达目的端口号 + difop_port: 2369 #雷达源端口号 + lidar_name: N10_P #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 L10 N10_P + angle_disable_min: 120.0 #角度裁剪开始值 + angle_disable_max: 230.0 #角度裁剪结束值 + min_range: 0.2 #雷达接收距离最小值 + max_range: 200.0 #雷达接收距离最大值 + use_gps_ts: false #雷达是否使用GPS授时 + scan_topic: /scan #设置激光数据topic名称 + interface_selection: net #接口选择:net 为网口,serial 为串口。 + serial_port_: /dev/wheeltec_laser #串口连接时的串口号 + high_reflection: false #M10_P雷达需填写该值,若不确定,请联系技术支持。 + compensation: false #M10系列是否使用角度补偿功能 + pubScan: true #是否发布scan话题 + pubPointCloud2: false #是否发布pointcloud2话题 + pointcloud_topic: /lslidar_point_cloud #设置激光数据topic名称 +# pcap: /home/ls/1.pcap #雷达是否使用pcap包读取功能 +# in_file_name: /home/ls/1.txt #雷达是否使用txt文件读取功能 \ No newline at end of file diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsm10.yaml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsm10.yaml new file mode 100644 index 0000000..203f6b5 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsm10.yaml @@ -0,0 +1,28 @@ +/lslidar_driver_node: + ros__parameters: + frame_id: laser #激光坐标 + group_ip: 224.1.1.2 + add_multicast: false + device_ip: 192.168.1.200 #雷达目的ip + device_ip_difop: 192.168.1.102 #雷达源IP + msop_port: 2368 #雷达目的端口号 + difop_port: 2369 #雷达源端口号 + lidar_name: M10 #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 + ceil_increase: -1 #Lsm10*时改值应设置为-1 + angle_disable_min: 0.0 #单角度裁剪开始值 + angle_disable_max: 0.0 #单角度裁剪结束值 + truncated_mode_: 0 #多角度裁剪开关:值为0时表示不使用多角度裁剪,默认为0 + #值为1表示使用多角度裁剪,同时angle_disable_min与angle_disable_max设为 0,角度值在/lslidar_driver.cc中修改 + min_range: 0.0 #雷达接收距离最小值 + max_range: 200.0 #雷达接收距离最大值 + use_gps_ts: false #雷达是否使用GPS授时 + scan_topic: /scan #设置激光数据topic名称 + interface_selection: serial #接口选择:net 为网口,serial 为串口。 + serial_port_: /dev/wheeltec_laser #串口连接时的串口号 + high_reflection: false #M10_P雷达需填写该值,若不确定,请联系技术支持。 + compensation: false #M10系列是否使用角度补偿功能 + pubScan: true #是否发布scan话题 + pubPointCloud2: false #是否发布pointcloud2话题 + pointcloud_topic: /lslidar_point_cloud #设置激光数据topic名称 +# pcap: /home/ls/1.pcap #雷达是否使用pcap包读取功能 +# in_file_name: /home/ls/1.txt #雷达是否使用txt文件读取功能 \ No newline at end of file diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsm10_p.yaml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsm10_p.yaml new file mode 100644 index 0000000..009e5fb --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsm10_p.yaml @@ -0,0 +1,28 @@ +/lslidar_driver_node: + ros__parameters: + frame_id: laser #激光坐标 + group_ip: 224.1.1.2 + add_multicast: false + device_ip: 192.168.1.200 #雷达目的ip + device_ip_difop: 192.168.1.102 #雷达源IP + msop_port: 2368 #雷达目的端口号 + difop_port: 2369 #雷达源端口号 + lidar_name: M10_P #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 + ceil_increase: -1 #Lsm10*时改值应设置为-1 + angle_disable_min: 0.0 #单角度裁剪开始值 + angle_disable_max: 0.0 #单角度裁剪结束值 + truncated_mode_: 0 #多角度裁剪开关:值为0时表示不使用多角度裁剪,默认为0 + #值为1表示使用多角度裁剪,同时angle_disable_min与angle_disable_max设为 0,角度值在/lslidar_driver.cc中修改 + min_range: 0.0 #雷达接收距离最小值 + max_range: 200.0 #雷达接收距离最大值 + use_gps_ts: false #雷达是否使用GPS授时 + scan_topic: /scan #设置激光数据topic名称 + interface_selection: serial #接口选择:net 为网口,serial 为串口。 + serial_port_: /dev/wheeltec_laser #串口连接时的串口号 + high_reflection: false #M10_P雷达需填写该值,若不确定,请联系技术支持。 + compensation: false #M10系列是否使用角度补偿功能 + pubScan: true #是否发布scan话题 + pubPointCloud2: false #是否发布pointcloud2话题 + pointcloud_topic: /lslidar_point_cloud #设置激光数据topic名称 +# pcap: /home/ls/1.pcap #雷达是否使用pcap包读取功能 +# in_file_name: /home/ls/1.txt #雷达是否使用txt文件读取功能 \ No newline at end of file diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsn10.yaml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsn10.yaml new file mode 100644 index 0000000..ea0e78f --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsn10.yaml @@ -0,0 +1,26 @@ +/lslidar_driver_node: + ros__parameters: + frame_id: laser_link #激光坐标 + group_ip: 224.1.1.2 + add_multicast: false + device_ip: 192.168.1.200 #雷达源IP + device_ip_difop: 192.168.1.102 #雷达目的ip + msop_port: 2368 #雷达目的端口号 + difop_port: 2369 #雷达源端口号 + lidar_name: N10 #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 L10 N10_P + angle_disable_min: 0.0 #角度裁剪开始值 + angle_disable_max: 0.0 #角度裁剪结束值 + min_range: 0.15 #雷达接收距离最小值 + max_range: 200.0 #雷达接收距离最大值 + use_gps_ts: false #雷达是否使用GPS授时 + scan_topic: /scan #设置激光数据topic名称 + interface_selection: serial #接口选择:net 为网口,serial 为串口。 + serial_port_: /dev/ttyCH343USB0 #串口连接时的串口号 + high_reflection: false #M10_P雷达需填写该值,若不确定,请联系技术支持。 + compensation: false #M10系列是否使用角度补偿功能 + pubScan: true #是否发布scan话题 + pubPointCloud2: false #是否发布pointcloud2话题 + pointcloud_topic: /lslidar_point_cloud #设置激光数据topic名称 + fixed_array_length: 450 +# pcap: /home/ls/1.pcap #雷达是否使用pcap包读取功能 +# in_file_name: /home/ls/1.txt #雷达是否使用txt文件读取功能 \ No newline at end of file diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsn10p.yaml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsn10p.yaml new file mode 100644 index 0000000..8f1c6c9 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/params/lidar_uart_ros2/lsn10p.yaml @@ -0,0 +1,25 @@ +/lslidar_driver_node: + ros__parameters: + frame_id: laser #激光坐标 + group_ip: 224.1.1.2 + add_multicast: false + device_ip: 192.168.1.200 #雷达源IP + device_ip_difop: 192.168.1.102 #雷达目的ip + msop_port: 2368 #雷达目的端口号 + difop_port: 2369 #雷达源端口号 + lidar_name: N10_P #雷达选择:M10 M10_P M10_PLUS M10_GPS N10 L10 N10_P + angle_disable_min: 120.0 #角度裁剪开始值 + angle_disable_max: 230.0 #角度裁剪结束值 + min_range: 0.2 #雷达接收距离最小值 + max_range: 200.0 #雷达接收距离最大值 + use_gps_ts: false #雷达是否使用GPS授时 + scan_topic: /scan #设置激光数据topic名称 + interface_selection: serial #接口选择:net 为网口,serial 为串口。 + serial_port_: /dev/wheeltec_laser #串口连接时的串口号 + high_reflection: false #M10_P雷达需填写该值,若不确定,请联系技术支持。 + compensation: false #M10系列是否使用角度补偿功能 + pubScan: true #是否发布scan话题 + pubPointCloud2: false #是否发布pointcloud2话题 + pointcloud_topic: /lslidar_point_cloud #设置激光数据topic名称 +# pcap: /home/ls/1.pcap #雷达是否使用pcap包读取功能 +# in_file_name: /home/ls/1.txt #雷达是否使用txt文件读取功能 \ No newline at end of file diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/rviz/lslidar.rviz b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/rviz/lslidar.rviz new file mode 100644 index 0000000..4b104c7 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/rviz/lslidar.rviz @@ -0,0 +1,161 @@ +Panels: + - Class: rviz_common/Displays + Help Height: 78 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Status1 + - /LaserScan1 + Splitter Ratio: 0.3441176414489746 + Tree Height: 617 + - Class: rviz_common/Selection + Name: Selection + - Class: rviz_common/Tool Properties + Expanded: + - /2D Goal Pose1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz_common/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz_default_plugins/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: + Value: true + - Alpha: 1 + Autocompute Intensity Bounds: true + Autocompute Value Bounds: + Max Value: 10 + Min Value: -10 + Value: true + Axis: Z + Channel Name: intensity + Class: rviz_default_plugins/LaserScan + Color: 255; 255; 255 + Color Transformer: Intensity + Decay Time: 0 + Enabled: true + Invert Rainbow: false + Max Color: 255; 255; 255 + Max Intensity: 0 + Min Color: 0; 0; 0 + Min Intensity: 0 + Name: LaserScan + 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: scan + Use Fixed Frame: true + Use rainbow: true + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Fixed Frame: laser + Frame Rate: 30 + Name: root + Tools: + - Class: rviz_default_plugins/Interact + Hide Inactive Objects: true + - Class: rviz_default_plugins/MoveCamera + - Class: rviz_default_plugins/Select + - Class: rviz_default_plugins/FocusCamera + - Class: rviz_default_plugins/Measure + Line color: 128; 128; 0 + - Class: rviz_default_plugins/SetInitialPose + Covariance x: 0.25 + Covariance y: 0.25 + Covariance yaw: 0.06853891909122467 + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /initialpose + - Class: rviz_default_plugins/SetGoal + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /goal_pose + - Class: rviz_default_plugins/PublishPoint + Single click: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /clicked_point + Transformation: + Current: + Class: rviz_default_plugins/TF + Value: true + Views: + Current: + Class: rviz_default_plugins/Orbit + Distance: 3.635173797607422 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Focal Point: + X: 0 + Y: 0 + Z: 0 + Focal Shape Fixed Size: true + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.8653978705406189 + Target Frame: + Value: Orbit (rviz) + Yaw: 3.095397710800171 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 846 + Hide Left Dock: false + Hide Right Dock: false + QMainWindow State: 000000ff00000000fd000000040000000000000156000002f4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002f4000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002f4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000002f4000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d0065010000000000000450000000000000000000000292000002f400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 1283 + X: 406 + Y: 152 diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/input.cc b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/input.cc new file mode 100644 index 0000000..cfa40a8 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/input.cc @@ -0,0 +1,398 @@ +#include "lslidar_driver/input.h" + +extern volatile sig_atomic_t flag; +namespace lslidar_driver +{ + static const size_t packet_size_input = 400; + //////////////////////////////////////////////////////////////////////// + // Input base class implementation + //////////////////////////////////////////////////////////////////////// + + /** @brief constructor + * + * @param private_nh ROS private handle for calling node. + * @param port UDP port number. + */ + Input::Input(rclcpp::Node *private_nh, uint16_t port) : private_nh_(private_nh), port_(port) { + npkt_update_flag_ = false; + cur_rpm_ = 0; + return_mode_ = 1; + devip_str_difop = std::string("192.168.1.200"); + devip_str_ = std::string("192.168.1.102"); + lidar_name = std::string("M10"); + add_multicast = false; + group_ip = std::string("224.1.1.2"); + UDP_PORT_NUMBER_DIFOP = 2369; + + + private_nh->declare_parameter("device_ip","192.168.1.102"); + private_nh->declare_parameter("device_ip_difop","192.168.1.200"); + private_nh->declare_parameter("add_multicast",false); + private_nh->declare_parameter("group_ip","224.1.1.2"); + private_nh->declare_parameter("difop_port",2369); + + + private_nh->get_parameter("lidar_name", lidar_name); + private_nh->get_parameter("device_ip", devip_str_); + private_nh->get_parameter("add_multicast", add_multicast); + private_nh->get_parameter("group_ip", group_ip); + private_nh->get_parameter("difop_port", UDP_PORT_NUMBER_DIFOP); + private_nh->get_parameter("device_ip_difop", devip_str_difop); + + if (!devip_str_.empty()) + RCLCPP_INFO(private_nh->get_logger(), "[driver][input] accepting packets from IP address: %s port: %d", + devip_str_.c_str(),port); + } + + /** @brief constructor + * + * @param private_nh ROS private handle for calling node. + * @param port UDP port number + */ + InputSocket::InputSocket(rclcpp::Node *private_nh, uint16_t port) : Input(private_nh, port) { + sockfd_ = -1; + + if (!devip_str_.empty()) { + inet_aton(devip_str_.c_str(), &devip_); + inet_aton(devip_str_difop.c_str(), &devip_difop); + } + + RCLCPP_INFO(private_nh_->get_logger(), "[driver][socket] Opening UDP socket: port %d", port); + sockfd_ = socket(PF_INET, SOCK_DGRAM, 0); + if (sockfd_ == -1) { + perror("socket"); // TODO: ROS_ERROR errno + return; + } + + int opt = 1; + if (setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, (const void *) &opt, sizeof(opt))) { + perror("setsockopt error!\n"); + return; + } + + sockaddr_in my_addr; // my address information + memset(&my_addr, 0, sizeof(my_addr)); // initialize to zeros + my_addr.sin_family = AF_INET; // host byte order + my_addr.sin_port = htons(port); // port in network byte order + my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill in my IP + + if (bind(sockfd_, (sockaddr * ) & my_addr, sizeof(sockaddr)) == -1) { + perror("bind"); // TODO: ROS_ERROR errno + return; + } + + if (add_multicast) { + struct ip_mreq group; + group.imr_multiaddr.s_addr = inet_addr(group_ip.c_str()); + group.imr_interface.s_addr = htonl(INADDR_ANY); + + if (setsockopt(sockfd_, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &group, sizeof(group)) < 0) { + perror("Adding multicast group error "); + close(sockfd_); + exit(1); + } else + printf("Adding multicast group...OK.\n"); + } + if (fcntl(sockfd_, F_SETFL, O_NONBLOCK | FASYNC) < 0) { + perror("non-block"); + return; + } + } + + /** @brief destructor */ + InputSocket::~InputSocket(void) { + (void) close(sockfd_); + } + + void Input::UDP_difop() + { + sockaddr_in server_sai; + server_sai.sin_family = AF_INET; // IPV4 协议族 + server_sai.sin_port = htons(UDP_PORT_NUMBER_DIFOP); + server_sai.sin_addr.s_addr = inet_addr(devip_str_.c_str()); + for (int k = 0; k < 10; k++) + { + unsigned char data[188]= {0x00}; + data[0] = 0xA5; + data[1] = 0x5A; + data[2] = 0x55; + data[184] = 0x08; + data[185] = 0x01; + data[186] = 0xFA; + data[187] = 0xFB; + int rtn = sendto(sockfd_, data, 188, 0, (struct sockaddr *)&server_sai, sizeof(struct sockaddr)); + if (rtn < 0) printf("start scan error !\n"); + else return; + } + return; + } + + void Input::UDP_order(const std_msgs::msg::Int8 msg) + { + int i = msg.data; + sockaddr_in server_sai; + server_sai.sin_family = AF_INET; // IPV4 协议族 + server_sai.sin_port = htons(UDP_PORT_NUMBER_DIFOP); + server_sai.sin_addr.s_addr = inet_addr(devip_str_.c_str()); + int rtn = 0; + for (int k = 0; k < 10; k++) + { + unsigned char data[188]= {0x00}; + data[0] = 0xA5; + data[1] = 0x5A; + data[2] = 0x55; + data[186] = 0xFA; + data[187] = 0xFB; + if(lidar_name == "M10" || lidar_name == "M10_GPS" || lidar_name == "M10_P"){ + if (i <= 1){ //雷达启停 + data[184] = 0x01; + data[185] = char(i); + } + else if (i == 2){ //雷达点云不滤波 + data[181] = 0x0A; + data[184] = 0x06; + data[185] = 0x01; + } + else if (i == 3){ //雷达点云正常滤波 + data[181] = 0x0B; + data[184] = 0x06; + data[185] = 0x01; + } + else if (i == 4){ //雷达近距离滤波 + data[181] = 0x0C; + data[184] = 0x06; + data[185] = 0x01; + } + else if (i == 100){ //接收设备包 + data[184] = 0x08; + data[185] = 0x01; + } + else return; + } + else if (lidar_name == "M10_PLUS"){ + data[184] = 0x0A; + data[185] = 0x01; + if(i == 5) { + data[141] = 0x01; + data[142] = 0x2c; + } + else if(i == 6) { + data[141] = 0x01; + data[142] = 0x68; + } + else if(i == 8) { + data[141] = 0x01; + data[142] = 0xe0; + } + else if(i == 10) { + data[141] = 0x02; + data[142] = 0x58; + } + else if(i == 12) { + data[141] = 0x02; + data[142] = 0xd0; + } + else if(i == 15) { + data[141] = 0x03; + data[142] = 0x84; + } + else if(i == 20) { + data[141] = 0x04; + data[142] = 0xb0; + } + else if(i <= 1) { + data[184] = 0x01; + data[185] = char(i); + } + else if(i == 100) { //接收设备包 + data[184] = 0x08; + data[185] = 0x01; + } + else return; + } + else if(lidar_name == "N10"){ + if(i <= 1){ + data[185] = char(i); + data[184] = 0x01; + } + else if(i>=6 && i<=12){ + data[172] = char(i); + data[184] = 0x0a; + data[185] = 0X01; + } + else return; + } + rtn = sendto(sockfd_, data, 188, 0, (struct sockaddr *)&server_sai, sizeof(struct sockaddr)); + if (rtn < 0) + { + printf("start scan error !\n"); + } + else + { + if (i == 1) + usleep(3000000); + return; + } + } + return; + } + + + + int InputSocket::getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &packet) + { + int q = 0; + struct pollfd fds[1]; + fds[0].fd = sockfd_; + fds[0].events = POLLIN; + static const int POLL_TIMEOUT = 2000; // one second (in msec) + + sockaddr_in sender_address{}; + socklen_t sender_address_len = sizeof(sender_address); + while (flag == 1) + { + // poll() until input available + do { + int retval = poll(fds, 1, POLL_TIMEOUT); + if (retval < 0) // poll() error? + { + if (errno != EINTR) + RCLCPP_ERROR(private_nh_->get_logger(), "[driver][socket] poll() error: %s", strerror(errno)); + return 0; + } + if (retval == 0) // poll() timeout? + { + RCLCPP_WARN(private_nh_->get_logger(), "lslidar poll() timeout, port: %d",port_); + return 0; + } + if ((fds[0].revents & POLLERR) || (fds[0].revents & POLLHUP) || (fds[0].revents & POLLNVAL)) // device error? + { + RCLCPP_ERROR(private_nh_->get_logger(),"poll() reports lslidar error"); + return 0; + } + } while ((fds[0].revents & POLLIN) == 0); + + // Receive packets that should now be available from the + // socket using a blocking read. + ssize_t nbytes = recvfrom(sockfd_, &packet->data[0], packet_size_input, 0, + (sockaddr *)&sender_address, &sender_address_len); + // ROS_DEBUG_STREAM("incomplete lslidar packet read: " + // << nbytes << " bytes"); + q = (int)nbytes; + if (nbytes < 0) + { + if (errno != EWOULDBLOCK) + { + perror("recvfail"); + RCLCPP_ERROR(private_nh_->get_logger(),"recvfail"); + return 1; + } + } + else if ((size_t)nbytes <= packet_size_input || (size_t)nbytes >= 50) + { + + // read successful, + // if packet is not from the lidar scanner we selected by IP, + // continue otherwise we are done + if (devip_str_ != "" && sender_address.sin_addr.s_addr != devip_.s_addr) + continue; + else + break; // done + } + + } + if (flag == 0) + { + abort(); + } + + return q; + } + InputPCAP::InputPCAP(rclcpp::Node *private_nh, uint16_t port, double packet_rate, std::string filename) : Input(private_nh, port), + packet_rate_(packet_rate), + filename_(filename) + { + pcap_ = NULL; + empty_ = true; + read_once_ = false; + read_fast_ = false; + repeat_delay_ = 0.0; + private_nh->get_parameter("read_once", read_once_); + private_nh->get_parameter("read_fast", read_fast_); + private_nh->get_parameter("repeat_delay", repeat_delay_); + + if (read_once_) + RCLCPP_WARN(private_nh_->get_logger(),"Read input file only once."); + if (read_fast_) + RCLCPP_WARN(private_nh_->get_logger(),"Read input file as quickly as possible."); + if (repeat_delay_ > 0.0) + RCLCPP_WARN(private_nh_->get_logger(),"Delay %.3f seconds before repeating input file.", repeat_delay_); + + RCLCPP_INFO(private_nh_->get_logger(),"Opening PCAP file %s",filename_.c_str()); + if ((pcap_ = pcap_open_offline(filename_.c_str(), errbuf_)) == NULL) + { + RCLCPP_WARN(private_nh_->get_logger(),"Error opening lslidar socket dump file."); + return; + } + std::stringstream filter; + if (devip_str_ != "") + { + filter << "src host " << devip_str_ << "&&"; + } + filter << "udp dst port " << port; + pcap_compile(pcap_, &pcap_packet_filter_, filter.str().c_str(), 1, PCAP_NETMASK_UNKNOWN); + } + + InputPCAP::~InputPCAP(void) + { + pcap_close(pcap_); + } + + int InputPCAP::getPacket(lslidar_msgs::msg::LslidarPacket::UniquePtr &pkt) + { + struct pcap_pkthdr *header; + const u_char *pkt_data; + while (flag == 1) + { + int res; + if ((res = pcap_next_ex(pcap_, &header, &pkt_data)) >= 0) + { + // skip packets not for the correct port and from the selected IP address + if (!devip_str_.empty() && (0 == pcap_offline_filter(&pcap_packet_filter_, header, pkt_data))) + continue; + + if (read_fast_ == false) + packet_rate_.sleep(); + mempcpy(&pkt->data[0], pkt_data + 42, packet_size_input); + empty_ = false; + return 0; + } + if (empty_) + { + RCLCPP_WARN(private_nh_->get_logger(),"Error %d reading lslidar packet: %s", res, pcap_geterr(pcap_)); + return -1; + } + if (read_once_) + { + RCLCPP_WARN(private_nh_->get_logger(),"end of file reached -- done reading."); + return -1; + } + if (repeat_delay_ > 0.0) + { + RCLCPP_WARN(private_nh_->get_logger(),"end of file reached -- delaying %.3f seconds.", repeat_delay_); + usleep(rint(repeat_delay_ * 1000000.0)); + } + RCLCPP_WARN(private_nh_->get_logger(),"replayding lsliar dump file"); + + pcap_close(pcap_); + pcap_ = pcap_open_offline(filename_.c_str(), errbuf_); + empty_ = true; + } + if (flag == 0) + { + abort(); + } + return 0; + } + +} // namespace diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lsiosr.cpp b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lsiosr.cpp new file mode 100644 index 0000000..d560b12 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lsiosr.cpp @@ -0,0 +1,400 @@ +/******************************************************* +@company: Copyright (C) 2022, Leishen Intelligent System +@product: LSM10 and N10 +@filename: lsiosr.cpp +@brief: +@version: date: author: comments: +@v1.0 21-2-4 yao new +*******************************************************/ +#include "lslidar_driver/lsiosr.h" + +namespace lslidar_driver { + +LSIOSR * LSIOSR::instance(std::string name, int speed, int fd) +{ + static LSIOSR obj(name, speed, fd); + return &obj; +} + +LSIOSR::LSIOSR(std::string port, int baud_rate, int fd):port_(port), baud_rate_(baud_rate), fd_(fd) +{ + printf("port = %s, baud_rate = %d\n", port.c_str(), baud_rate); +} + +LSIOSR::~LSIOSR() +{ + close(); +} +/* 串口配置的函数 */ +int LSIOSR::setOpt(int nBits, uint8_t nEvent, int nStop) +{ + struct termios newtio, oldtio; + /*保存测试现有串口参数设置,在这里如果串口号等出错,会有相关的出错信息*/ + if (tcgetattr(fd_, &oldtio) != 0) + { + perror("SetupSerial 1"); + return -1; + } + bzero(&newtio, sizeof(newtio)); + /*步骤一,设置字符大小*/ + newtio.c_cflag |= CLOCAL; //如果设置,modem 的控制线将会被忽略。如果没有设置,则 open()函数会阻塞直到载波检测线宣告 modem 处于摘机状态为止。 + newtio.c_cflag |= CREAD; //使端口能读取输入的数据 + /*设置每个数据的位数*/ + switch (nBits) + { + case 7: + newtio.c_cflag |= CS7; + break; + case 8: + newtio.c_cflag |= CS8; + break; + } + /*设置奇偶校验位*/ + switch (nEvent) + { + case 'O': //奇数 + newtio.c_iflag |= (INPCK | ISTRIP); + newtio.c_cflag |= PARENB; //使能校验,如果不设PARODD则是偶校验 + newtio.c_cflag |= PARODD; //奇校验 + break; + case 'E': //偶数 + newtio.c_iflag |= (INPCK | ISTRIP); + newtio.c_cflag |= PARENB; + newtio.c_cflag &= ~PARODD; + break; + case 'N': //无奇偶校验位 + newtio.c_cflag &= ~PARENB; + break; + } + /*设置波特率*/ + switch (baud_rate_) + { + case 230400: + cfsetispeed(&newtio, B230400); + cfsetospeed(&newtio, B230400); + break; + case 460800: + cfsetispeed(&newtio, B460800); + cfsetospeed(&newtio, B460800); + break; + case 500000: + cfsetispeed(&newtio, B500000); + cfsetospeed(&newtio, B500000); + break; + case 921600: + cfsetispeed(&newtio, B921600); + cfsetospeed(&newtio, B921600); + break; + default: + cfsetispeed(&newtio, B460800); + cfsetospeed(&newtio, B460800); + break; + } + + /* + * 设置停止位 + * 设置停止位的位数, 如果设置,则会在每帧后产生两个停止位, 如果没有设置,则产生一个 + * 停止位。一般都是使用一位停止位。需要两位停止位的设备已过时了。 + * */ + if (nStop == 1) + newtio.c_cflag &= ~CSTOPB; + else if (nStop == 2) + newtio.c_cflag |= CSTOPB; + /*设置等待时间和最小接收字符*/ + newtio.c_cc[VTIME] = 0; + newtio.c_cc[VMIN] = 0; + /*处理未接收字符*/ + tcflush(fd_, TCIFLUSH); + /*激活新配置*/ + if ((tcsetattr(fd_, TCSANOW, &newtio)) != 0) + { + perror("serial set error"); + return -1; + } + + return 0; +} + +void LSIOSR::flushinput() { + tcflush(fd_, TCIFLUSH); +} + +/* 从串口中读取数据 */ +int LSIOSR::read(unsigned char *buffer, int length, int timeout) +{ + memset(buffer, 0, length); + + int totalBytesRead = 0; + int rc; + int unlink = 0; + unsigned char* pb = buffer; + + if (timeout > 0) + { + rc = waitReadable(timeout); + if (rc <= 0) + { + return (rc == 0) ? 0 : -1; + } + + int retry = 3; + while (length > 0) + { + rc = ::read(fd_, pb, (size_t)length); + + if (rc > 0) + { + length -= rc; + pb += rc; + totalBytesRead += rc; + + if (length == 0) + { + break; + } + } + else if (rc < 0) + { + printf("error \n"); + retry--; + if (retry <= 0) + { + break; + } + } + unlink++; + rc = waitReadable(20); + if(unlink > 10) + return -1; + + if (rc <= 0) + { + break; + } + } + } + else + { + rc = ::read(fd_, pb, (size_t)length); + + if (rc > 0) + { + totalBytesRead += rc; + } + else if ((rc < 0) && (errno != EINTR) && (errno != EAGAIN)) + { + printf("read error\n"); + return -1; + } + } + + return totalBytesRead; +} + +int LSIOSR::waitReadable(int millis) +{ + if (fd_ < 0) + { + return -1; + } + int serial = fd_; + + fd_set fdset; + struct timeval tv; + int rc = 0; + + while (millis > 0) + { + if (millis < 5000) + { + tv.tv_usec = millis % 1000 * 1000; + tv.tv_sec = millis / 1000; + + millis = 0; + } + else + { + tv.tv_usec = 0; + tv.tv_sec = 5; + + millis -= 5000; + } + + FD_ZERO(&fdset); + FD_SET(serial, &fdset); + + rc = select(serial + 1, &fdset, NULL, NULL, &tv); + if (rc > 0) + { + rc = (FD_ISSET(serial, &fdset)) ? 1 : -1; + break; + } + else if (rc < 0) + { + rc = -1; + break; + } + } + + return rc; +} + + +int LSIOSR::waitWritable(int millis) +{ + if (fd_ < 0) + { + return -1; + } + int serial = fd_; + + fd_set fdset; + struct timeval tv; + int rc = 0; + + while (millis > 0) + { + if (millis < 5000) + { + tv.tv_usec = millis % 1000 * 1000; + tv.tv_sec = millis / 1000; + + millis = 0; + } + else + { + tv.tv_usec = 0; + tv.tv_sec = 5; + + millis -= 5000; + } + + FD_ZERO(&fdset); + FD_SET(serial, &fdset); + + rc = select(serial + 1, NULL, &fdset, NULL, &tv); + if (rc > 0) + { + rc = (FD_ISSET(serial, &fdset)) ? 1 : -1; + break; + } + else if (rc < 0) + { + rc = -1; + break; + } + } + + return rc; +} + +/* 向串口中发送数据 */ +int LSIOSR::send(const char* buffer, int length, int timeout) +{ + if (fd_ < 0) + { + return -1; + } + + if ((buffer == 0) || (length <= 0)) + { + return -1; + } + + int totalBytesWrite = 0; + int rc; + char* pb = (char*)buffer; + + + if (timeout > 0) + { + rc = waitWritable(timeout); + if (rc <= 0) + { + return (rc == 0) ? 0 : -1; + } + + int retry = 3; + while (length > 0) + { + rc = write(fd_, pb, (size_t)length); + if (rc > 0) + { + length -= rc; + pb += rc; + totalBytesWrite += rc; + + if (length == 0) + { + break; + } + } + else + { + retry--; + if (retry <= 0) + { + break; + } + } + + rc = waitWritable(50); + if (rc <= 0) + { + break; + } + } + } + else + { + rc = write(fd_, pb, (size_t)length); + if (rc > 0) + { + totalBytesWrite += rc; + } + else if ((rc < 0) && (errno != EINTR) && (errno != EAGAIN)) + { + return -1; + } + } + + return totalBytesWrite; +} + +int LSIOSR::init() +{ + int error_code = 0; + + fd_ = open(port_.c_str(), O_RDWR|O_NOCTTY|O_NDELAY); + if (0 < fd_) + { + error_code = 0; + setOpt(DATA_BIT_8, PARITY_NONE, STOP_BIT_1);//设置串口参数 + //printf("open_port %s OK !\n", port_.c_str()); + } + else + { + error_code = -1; + } + + return error_code; +} + +int LSIOSR::close() +{ + ::close(fd_); + return 0; +} + +std::string LSIOSR::getPort() +{ + return port_; +} + +int LSIOSR::setPortName(std::string name) +{ + port_ = name; + return 0; +} + +} diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lslidar_driver.cc b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lslidar_driver.cc new file mode 100644 index 0000000..c22c0f7 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lslidar_driver.cc @@ -0,0 +1,1423 @@ +/* + * This file is part of lslidar driver. + * + * The driver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the driver. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "lslidar_driver/lslidar_driver.h" +#include + +int truncated_mode_=0; //多角度屏蔽开关:默认为0,如果需要屏蔽多个角度,则truncated_mode_赋值为1。 + +int scan_crop_min[]={0,180}; //雷达屏蔽角度,这里屏蔽角度为135°到225°, + //如果要多角度屏蔽,如10~30,50~60,改为: + //scan_angle_min[]={10,50};scan_angle_max[]={30,60}; +int scan_crop_max[]={90,270}; //修改后编译即可 + + +namespace lslidar_driver +{ + + static void my_hander(int sig) + { + printf("sig: %d", sig); + abort(); + } + LslidarDriver::LslidarDriver() : LslidarDriver(rclcpp::NodeOptions()) {} + LslidarDriver::LslidarDriver(const rclcpp::NodeOptions &options) : Node("lslidar_driver_node", options), diagnostics(this) + { + signal(SIGINT, my_hander); + + if (!this->initialize()) + RCLCPP_ERROR(this->get_logger(), "Could not initialize the driver..."); + else + RCLCPP_INFO(this->get_logger(), "Successfully initialize driver..."); + } + + LslidarDriver::~LslidarDriver() + { + return; + } + + bool LslidarDriver::loadParameters() + { + pubscan_thread_ = new boost::thread(boost::bind(&LslidarDriver::pubScanThread, this)); + interface_selection = std::string("net"); + frame_id = std::string("laser_link"); + scan_topic = std::string("/scan"); + lidar_name = std::string("M10"); + pointcloud_topic = std::string("/lslidar_point_cloud"); + is_start = true; + min_range = 0.3; + max_range = 100.0; + use_gps_ts = true; + compensation = true; + pubScan = true; + pubPointCloud2 = true; + angle_disable_min = 0.0; + angle_disable_max = 0.0; + // 添加恒定输出长度参数 + fixed_array_length = 450; //cyy_addcyy_add + this->declare_parameter("fixed_array_length", 450);//cyy_addcyy_add + + + this->declare_parameter("lidar_name", "M10"); + this->declare_parameter("frame_id", "laser_link"); + this->declare_parameter("scan_topic", "/scan"); + this->declare_parameter("pointcloud_topic", "/lslidar_point_cloud"); + this->declare_parameter("min_range", 0.3); + this->declare_parameter("max_range", 100.0); + this->declare_parameter("use_gps_ts", false); + this->declare_parameter("high_reflection", false); + this->declare_parameter("compensation", false); + this->declare_parameter("pubScan", true); + this->declare_parameter("pubPointCloud2", false); + this->declare_parameter("angle_disable_min", 0.0); + this->declare_parameter("angle_disable_max", 0.0); + this->declare_parameter("interface_selection", "net"); + + this->get_parameter("fixed_array_length", fixed_array_length);//cyy_addcyy_add + this->get_parameter("lidar_name", lidar_name); + this->get_parameter("frame_id", frame_id); + this->get_parameter("high_reflection", high_reflection); + this->get_parameter("scan_topic", scan_topic); + this->get_parameter("min_range", min_range); + this->get_parameter("max_range", max_range); + this->get_parameter("use_gps_ts", use_gps_ts); + this->get_parameter("compensation", compensation); + this->get_parameter("pointcloud_topic", pointcloud_topic); + this->get_parameter("pubScan", pubScan); + this->get_parameter("pubPointCloud2", pubPointCloud2); + this->get_parameter("angle_disable_min", angle_disable_min); + this->get_parameter("angle_disable_max", angle_disable_max); + this->get_parameter("interface_selection", interface_selection); + while (angle_disable_min < 0) + angle_disable_min += 360; + while (angle_disable_max < 0) + angle_disable_max += 360; + while (angle_disable_min > 360) + angle_disable_min -= 360; + while (angle_disable_max > 360) + angle_disable_max -= 360; + if (angle_disable_max == angle_disable_min) + { + angle_able_min = 0; + angle_able_max = 360; + } + else + { + if (angle_disable_min < angle_disable_max && angle_disable_min != 0.0) + { + angle_able_min = angle_disable_max; + angle_able_max = angle_disable_min + 360; + } + if (angle_disable_min < angle_disable_max && angle_disable_min == 0.0) + { + angle_able_min = angle_disable_max; + angle_able_max = 360; + } + if (angle_disable_min > angle_disable_max) + { + angle_able_min = angle_disable_max; + angle_able_max = angle_disable_min; + } + } + count_num = 0; + + scan_points_.resize(6000); + + if (lidar_name == "M10") + { + use_gps_ts = false; + PACKET_SIZE = 92; + package_points = 42; + data_bits_start = 6; + degree_bits_start = 2; + rpm_bits_start = 4; + baud_rate_ = 460800; + points_size_ = 1008; + } + else if (lidar_name == "M10_P") + { + PACKET_SIZE = 160; + package_points = 70; + data_bits_start = 8; + degree_bits_start = 4; + rpm_bits_start = 6; + baud_rate_ = 500000; + points_size_ = 2000; + } + else if (lidar_name == "M10_PLUS") + { + PACKET_SIZE = 104; + package_points = 41; + data_bits_start = 8; + degree_bits_start = 4; + rpm_bits_start = 6; + points_size_ = 5000; + baud_rate_ = 921600; + } + else if (lidar_name == "M10_GPS") + { + PACKET_SIZE = 102; + package_points = 42; + data_bits_start = 6; + degree_bits_start = 2; + rpm_bits_start = 4; + baud_rate_ = 460800; + points_size_ = 1008; + } + else if (lidar_name == "N10") + { + PACKET_SIZE = 58; + package_points = 16; + data_bits_start = 7; + degree_bits_start = 5; + end_degree_bits_start = 55; + baud_rate_ = 230400; + points_size_ = 2000; + use_gps_ts = false; + compensation = false; + } + else if (lidar_name == "M10_DOUBLE") + { + PACKET_SIZE = 300; + package_points = 70; + data_bits_start = 8; + degree_bits_start = 4; + rpm_bits_start = 6; + points_size_ = 3000; + baud_rate_ = 921600; + } + else if (lidar_name == "N10_P") + { + PACKET_SIZE = 108; + package_points = 16; + data_bits_start = 7; + degree_bits_start = 5; + end_degree_bits_start = 105; + baud_rate_ = 460800; + points_size_ = 2000; + use_gps_ts = false; + compensation = false; + } + else if (lidar_name == "L10") + { + PACKET_SIZE = 58; + package_points = 16; + data_bits_start = 7; + degree_bits_start = 5; + end_degree_bits_start = 55; + baud_rate_ = 230400; + points_size_ = 2000; + use_gps_ts = false; + compensation = false; + } + RCLCPP_INFO_STREAM(this->get_logger(), "Lidar is " << lidar_name.c_str()); + + if (pubScan) + scan_pub = this->create_publisher(scan_topic, 10); + if (pubPointCloud2) + point_cloud_pub = this->create_publisher(pointcloud_topic, 10); + difop_switch = this->create_subscription("lslidar_order", 1, std::bind(&LslidarDriver::lidar_order, this, std::placeholders::_1)); // 转速输入 + return true; + } + + void LslidarDriver::lidar_difop() + { + if (lidar_name == "L10" || lidar_name == "N10" || lidar_name == "N10_P") + return; + if (interface_selection == "net") + msop_input_->UDP_difop(); + else + { + for (int k = 0; k < 10; k++) + { + unsigned char data[188] = {0x00}; + data[0] = 0xA5; + data[1] = 0x5A; + data[2] = 0x55; + data[184] = 0x08; + data[185] = 0x01; + data[186] = 0xFA; + data[187] = 0xFB; + int rtn = serial_->send((const char *)data, 188); + if (rtn < 0) + printf("start scan error !\n"); + else + return; + } + } + return; + } + + void LslidarDriver::lidar_order(const std_msgs::msg::Int8::SharedPtr msg) + { + if (lidar_name == "L10") + return; + int i = msg->data; + if (i == 0) + is_start = false; + else + is_start = true; + if (interface_selection == "net") + msop_input_->UDP_order(*msg); + else + { + int i = msg->data; + for (int k = 0; k < 10; k++) + { + int rtn; + unsigned char data[188] = {0x00}; + data[0] = 0xA5; + data[1] = 0x5A; + data[2] = 0x55; + data[186] = 0xFA; + data[187] = 0xFB; + + if (lidar_name == "M10" || lidar_name == "M10_GPS" || lidar_name == "M10_P" || lidar_name == "M10_DOUBLE") + { + if (i <= 1) + { // 雷达启停 + data[184] = 0x01; + data[185] = char(i); + } + else if (i == 2) + { // 雷达点云不滤波 + data[181] = 0x0A; + data[184] = 0x06; + if (is_start) + data[185] = 0x01; + } + else if (i == 3) + { // 雷达点云正常滤波 + data[181] = 0x0B; + data[184] = 0x06; + if (is_start) + data[185] = 0x01; + } + else if (i == 4) + { // 雷达近距离滤波 + data[181] = 0x0C; + data[184] = 0x06; + if (is_start) + data[185] = 0x01; + } + else if (i == 100) + { // 接收设备包 + data[184] = 0x08; + data[185] = 0x01; + } + else + return; + } + else if (lidar_name == "M10_PLUS") + { + data[184] = 0x0A; + data[185] = 0x01; + if (i == 5) + { + data[141] = 0x01; + data[142] = 0x2c; + } + else if (i == 6) + { + data[141] = 0x01; + data[142] = 0x68; + } + else if (i == 8) + { + data[141] = 0x01; + data[142] = 0xe0; + } + else if (i == 10) + { + data[141] = 0x02; + data[142] = 0x58; + } + else if (i == 12) + { + data[141] = 0x02; + data[142] = 0xd0; + } + else if (i == 15) + { + data[141] = 0x03; + data[142] = 0x84; + } + else if (i == 20) + { + data[141] = 0x04; + data[142] = 0xb0; + } + else if (i <= 1) + { + data[184] = 0x01; + data[185] = char(i); + } + else if (i == 100) // 接收设备包 + { + data[184] = 0x08; + data[185] = 0x01; + } + else + return; + } + else if (lidar_name == "N10" || lidar_name == "N10_P") + { + if (i <= 1) + { + data[185] = char(i); + data[184] = 0x01; + } + else if (i >= 6 && i <= 12) + { + data[172] = char(i); + data[184] = 0x0a; + data[185] = 0X01; + } + else + return; + } + rtn = serial_->send((const char *)data, 188); + if (rtn < 0) + printf("start scan error !\n"); + else + { + if (i == 1) + usleep(1000000); // 1.0s + if (i == 0) + is_start = false; + if (i == 1) + is_start = true; + return; + } + } + return; + } + } + + void LslidarDriver::open_serial() + { + diagnostics.setHardwareID("Lslidar"); + int code = 0; + serial_port_ = std::string("/dev/ttyUSB0"); + this->declare_parameter("serial_port_", "/dev/ttyUSB0"); + this->get_parameter("serial_port_", serial_port_); + serial_ = LSIOSR::instance(serial_port_, baud_rate_); + code = serial_->init(); + if (code != 0) + { + printf("open_port %s ERROR !\n", serial_port_.c_str()); + rclcpp::shutdown(); + exit(0); + } + printf("open_port %s OK !\n", serial_port_.c_str()); + } + + bool LslidarDriver::createRosIO() + { + UDP_PORT_NUMBER = 2368; + this->declare_parameter("msop_port", 2368); + this->get_parameter("msop_port", UDP_PORT_NUMBER); + RCLCPP_INFO_STREAM(this->get_logger(), "Opening UDP socket: port " << UDP_PORT_NUMBER); + dump_file = std::string(""); + this->declare_parameter("pcap", ""); + this->get_parameter("pcap", dump_file); + // ROS diagnostics + diagnostics.setHardwareID("Lslidar"); + + const double diag_freq = 12 * 24; + diag_max_freq = diag_freq; + diag_min_freq = diag_freq; + RCLCPP_INFO(this->get_logger(), "expected frequency: %.3f (Hz)", diag_freq); + + using namespace diagnostic_updater; + diag_topic.reset(new TopicDiagnostic( + "lslidar_packets", diagnostics, + FrequencyStatusParam(&diag_min_freq, &diag_max_freq, 0.1, 10), + TimeStampStatusParam())); + + int hz = 10; + if (lidar_name == "M10_P") + hz = 12; + else if (lidar_name == "M10_PLUS") + hz = 20; + + double packet_rate = hz * 24; + if (dump_file != "") + { + msop_input_.reset(new lslidar_driver::InputPCAP(this, UDP_PORT_NUMBER, packet_rate, dump_file)); + } + else + { + msop_input_.reset(new lslidar_driver::InputSocket(this, UDP_PORT_NUMBER)); + } + + // Output + return true; + } + + int LslidarDriver::getScan(std::vector &points, rclcpp::Time &scan_time, float &scan_duration) + { + boost::unique_lock lock(mutex_); + points.assign(scan_points_bak_.begin(), scan_points_bak_.end()); + scan_time = pre_time_; + scan_duration = time_.seconds() - pre_time_.seconds(); + return 1; + } + + uint64_t LslidarDriver::get_gps_stamp(struct tm t) + { + + uint64_t ptime = static_cast(timegm(&t)); + return ptime; + } + + bool LslidarDriver::initialize() + { + if (!loadParameters()) + { + RCLCPP_ERROR(this->get_logger(), "Cannot load all required ROS parameters..."); + return false; + } + if (interface_selection == "net") + { + if (!createRosIO()) + { + RCLCPP_ERROR(this->get_logger(), "Cannot create all ROS IO..."); + return false; + } + } + else + { + in_file_name = std::string(""); + this->declare_parameter("in_file_name", ""); + this->get_parameter("in_file_name", in_file_name); + if (in_file_name == "") + open_serial(); + else + { + RCLCPP_INFO_STREAM(this->get_logger(), "Opening txt file " << in_file_name.c_str()); + std::ifstream file_reader(in_file_name); + if (!file_reader.is_open()) + { + RCLCPP_ERROR(this->get_logger(), "Cannot open the file"); + return false; + } + } + } + RCLCPP_INFO(this->get_logger(), "Initialised lslidar without error"); + return true; + } + + void LslidarDriver::recvThread_crc(int &count, int &link_time) + { + if (count <= 0) + link_time++; + else + link_time = 0; + + if (link_time > 150) + { + serial_->close(); + int ret = serial_->init(); + if (ret < 0) + { + RCLCPP_ERROR(this->get_logger(), "serial open fail"); + usleep(200000); + } + link_time = 0; + } + } + + int LslidarDriver::receive_data(unsigned char *packet_bytes) + { + int link_time = 0; + int len_H = 0; + int len_L = 0; + int len = 0; + int count_2 = 0; + int count = 0; + while (count <= 0) + { + count = serial_->read(packet_bytes, 1); + LslidarDriver::recvThread_crc(count, link_time); + } + if (packet_bytes[0] != 0xA5) + return 0; + + while (count_2 <= 0) + { + count_2 = serial_->read(packet_bytes + count, 1); + if (count_2 >= 0) + count += count_2; + LslidarDriver::recvThread_crc(count_2, link_time); + } + + count_2 = 0; + if (packet_bytes[1] != 0x5A) + return 0; + while (count_2 <= 0) + { + count_2 = serial_->read(packet_bytes + count, 2); + if (count_2 >= 0) + count += count_2; + LslidarDriver::recvThread_crc(count_2, link_time); + } + + count_2 = 0; + + if (lidar_name == "M10") + len = 92; + else if (lidar_name == "M10_GPS") + len = 102; + else if (lidar_name == "N10_P") + len = 108; + else if (lidar_name == "N10" || lidar_name == "L10") + len = packet_bytes[2]; + else + { + len_H = packet_bytes[2]; + len_L = packet_bytes[3]; + len = len_H * 256 + len_L; + } + if (lidar_name == "M10" || lidar_name == "M10_DOUBLE" || lidar_name == "M10_GPS" || lidar_name == "M10_P" || lidar_name == "M10_PLUS") + { + if (packet_bytes[2] == 0x55 && packet_bytes[3] == 0x00) + len = 188; + } + while (count < len) + { + count_2 = serial_->read(packet_bytes + count, len - count); + if (count_2 >= 0) + count += count_2; + LslidarDriver::recvThread_crc(count_2, link_time); + } + if (lidar_name == "N10" || lidar_name == "L10" || lidar_name == "N10_P") + { + if (packet_bytes[PACKET_SIZE - 1] != N10_CalCRC8(packet_bytes, PACKET_SIZE - 1)) + return 0; + } + return len; + } + + uint8_t LslidarDriver::N10_CalCRC8(unsigned char *p, int len) + { + uint8_t crc = 0; + int sum = 0; + + for (int i = 0; i < len; i++) + { + sum += uint8_t(p[i]); + } + crc = sum & 0xff; + return crc; + } + + void LslidarDriver::difop_processing(unsigned char *packet_bytes) // 处理设备包的数据 + { + int s = packet_bytes[173]; + int z = packet_bytes[174]; + int degree_temp = s & 0x7F; + int sign_temp = s & 0x80; + degree_compensation = double(degree_temp * 256 + z) / 100.f; + if (sign_temp) + degree_compensation = -degree_compensation; + first_compensation = false; + printf("degree_compensation = %f\n", degree_compensation); + return; + } + + void LslidarDriver::data_processing(unsigned char *packet_bytes, int len) // 处理每一包的数据 + { + double degree; + double end_degree; + double degree_interval = 15.0; + boost::posix_time::ptime t1, t2; + t1 = boost::posix_time::microsec_clock::universal_time(); + + int s = packet_bytes[degree_bits_start]; + int z = packet_bytes[degree_bits_start + 1]; + + degree = (s * 256 + z) / 100.f + degree_compensation; + degree = (degree < 0) ? degree + 360 : degree; + degree = (degree > 360) ? degree - 360 : degree; + if (lidar_name == "N10" || lidar_name == "L10") + { + int s_e = packet_bytes[end_degree_bits_start]; + int z_e = packet_bytes[end_degree_bits_start + 1]; + + end_degree = (s_e * 256 + z_e) / 100.f; + end_degree = (end_degree > 360) ? end_degree - 360 : end_degree; + + if (degree > end_degree) + degree_interval = end_degree + 360 - degree; + else + degree_interval = end_degree - degree; + } + + // boost::unique_lock lock(mutex_); + if (lidar_name == "M10_PLUS" || lidar_name == "M10_P") + { + PACKET_SIZE = len; + package_points = (PACKET_SIZE - 20) / 2; + } + int invalidValue = 0; + int point_len = 2; + if (lidar_name == "N10" || lidar_name == "L10") + point_len = 3; + + if (lidar_name == "M10_GPS" || lidar_name == "M10") + { + int err_data_84 = packet_bytes[84]; + int err_data_85 = packet_bytes[85]; + if ((err_data_84 * 256 + err_data_85) == 0xFFFF || packet_bytes[86] >= 0xF5) + { + packet_bytes[86] = 0xFF; + packet_bytes[87] = 0xFF; + } + } + + for (int num = 0; num < point_len * package_points; num += point_len) + { + int s = packet_bytes[num + data_bits_start]; + int z = packet_bytes[num + data_bits_start + 1]; + if ((s * 256 + z) == 0xFFFF) + invalidValue++; + } + + if (use_gps_ts && lidar_name != "N10") + { + pTime.tm_year = packet_bytes[PACKET_SIZE - 12] + 2000 - 1900; // x+2000 + pTime.tm_mon = packet_bytes[PACKET_SIZE - 11] - 1; // 1-12 + pTime.tm_mday = packet_bytes[PACKET_SIZE - 10]; // 1-31 + pTime.tm_hour = packet_bytes[PACKET_SIZE - 9]; // 0-23 + pTime.tm_min = packet_bytes[PACKET_SIZE - 8]; // 0-59 + pTime.tm_sec = packet_bytes[PACKET_SIZE - 7]; // 0-59 + sub_second = (packet_bytes[PACKET_SIZE - 6] * 256 + packet_bytes[PACKET_SIZE - 5]) * 1000000 + (packet_bytes[PACKET_SIZE - 4] * 256 + packet_bytes[PACKET_SIZE - 3]) * 1000; + sweep_end_time_gps = get_gps_stamp(pTime); + sweep_end_time_hardware = sub_second % 1000000000; + } + invalidValue = package_points - invalidValue; + if (lidar_name == "N10" || lidar_name == "L10") + invalidValue--; + if (invalidValue <= 1) + { + delete packet_bytes; + return; + } + + for (int num = 0; num < package_points; num++) + { + int s = packet_bytes[num * point_len + data_bits_start]; + int z = packet_bytes[num * point_len + data_bits_start + 1]; + int y = 0; + if (lidar_name == "N10" || lidar_name == "L10") + y = packet_bytes[num * point_len + data_bits_start + 2]; + int dist_temp = s & 0x7F; + int inten_temp = s & 0x80; + + if ((s * 256 + z) != 0xFFFF) + { + if (lidar_name == "N10" || lidar_name == "L10") + { + scan_points_[idx].range = double(s * 256 + (z)) / 1000.f; + scan_points_[idx].intensity = int(y); + } + else if ((lidar_name == "M10_P" || lidar_name == "M10_PLUS") && !high_reflection) + { + scan_points_[idx].range = double(s * 256 + (z)) / 1000.f; + scan_points_[idx].intensity = 0; + } + else + { + scan_points_[idx].range = double(dist_temp * 256 + (z)) / 1000.f; + if (inten_temp) + scan_points_[idx].intensity = 255; + else + scan_points_[idx].intensity = 0; + } + if ((degree + (degree_interval / invalidValue * num)) > 360) + scan_points_[idx].degree = degree + (degree_interval / invalidValue * num) - 360; + else + scan_points_[idx].degree = degree + (degree_interval / invalidValue * num); + } + else + continue; + + if ((scan_points_[idx].degree < last_degree && scan_points_[idx].degree < 5 && last_degree > 355) || idx >= points_size_) + { + last_degree = scan_points_[idx].degree; + count_num = idx; + idx = 0; + for (long unsigned int k = 0; k < scan_points_.size(); k++) + { + if (scan_points_[k].range < min_range || scan_points_[k].range > max_range) + scan_points_[k].range = 0; + } + boost::unique_lock lock(mutex_); + scan_points_bak_.resize(scan_points_.size()); + scan_points_bak_.assign(scan_points_.begin(), scan_points_.end()); + for (long unsigned int k = 0; k < scan_points_.size(); k++) + { + scan_points_[k].range = 0; + scan_points_[k].degree = 0; + scan_points_[k].intensity = 0; + } + pre_time_ = time_; + lock.unlock(); + pubscan_cond_.notify_one(); + time_ = get_clock()->now(); + } + else + { + last_degree = scan_points_[idx].degree; + idx++; + } + } + packet_bytes = {0x00}; + if (packet_bytes) + { + packet_bytes = NULL; + delete packet_bytes; + } + } + + void LslidarDriver::data_processing_2(unsigned char *packet_bytes, int len) // 处理每一包的数据 + { + double degree; + double end_degree; + double degree_interval = 15.0; + boost::posix_time::ptime t1, t2; + t1 = boost::posix_time::microsec_clock::universal_time(); + + int s = packet_bytes[degree_bits_start]; + int z = packet_bytes[degree_bits_start + 1]; + + degree = (s * 256 + z) / 100.f + degree_compensation; + degree = (degree < 0) ? degree + 360 : degree; + degree = (degree > 360) ? degree - 360 : degree; + if (lidar_name == "N10_P") + { + int s_e = packet_bytes[end_degree_bits_start]; + int z_e = packet_bytes[end_degree_bits_start + 1]; + + end_degree = (s_e * 256 + z_e) / 100.f; + end_degree = (end_degree > 360) ? end_degree - 360 : end_degree; + + if (degree > end_degree) + degree_interval = end_degree + 360 - degree; + else + degree_interval = end_degree - degree; + } + + // boost::unique_lock lock(mutex_); + if (lidar_name == "M10_DOUBLE") + { + PACKET_SIZE = len; + package_points = (PACKET_SIZE - 20) / 4; + } + int invalidValue = 0; + int point_len = 4; + if (lidar_name == "N10_P") + point_len = 6; + + for (int num = 0; num < point_len * package_points; num += point_len) + { + int s = packet_bytes[num + data_bits_start]; + int z = packet_bytes[num + data_bits_start + 1]; + if ((s * 256 + z) == 0xFFFF) + invalidValue++; + } + + if (use_gps_ts) + { + pTime.tm_year = packet_bytes[PACKET_SIZE - 12] + 2000 - 1900; // x+2000 + pTime.tm_mon = packet_bytes[PACKET_SIZE - 11] - 1; // 1-12 + pTime.tm_mday = packet_bytes[PACKET_SIZE - 10]; // 1-31 + pTime.tm_hour = packet_bytes[PACKET_SIZE - 9]; // 0-23 + pTime.tm_min = packet_bytes[PACKET_SIZE - 8]; // 0-59 + pTime.tm_sec = packet_bytes[PACKET_SIZE - 7]; // 0-59 + sub_second = (packet_bytes[PACKET_SIZE - 6] * 256 + packet_bytes[PACKET_SIZE - 5]) * 1000000 + (packet_bytes[PACKET_SIZE - 4] * 256 + packet_bytes[PACKET_SIZE - 3]) * 1000; + sweep_end_time_gps = get_gps_stamp(pTime); + sweep_end_time_hardware = sub_second % 1000000000; + } + invalidValue = package_points - invalidValue; + if (lidar_name == "N10_P") + invalidValue--; + if (invalidValue <= 1) + { + delete packet_bytes; + return; + } + + for (int num = 0; num < package_points; num++) + { + int s = packet_bytes[num * point_len + data_bits_start]; + int z = packet_bytes[num * point_len + data_bits_start + 1]; + int y = 0; + if (lidar_name == "N10_P") + y = packet_bytes[num * point_len + data_bits_start + 2]; + + if ((s * 256 + z) != 0xFFFF) + { + scan_points_[idx].range = double(s * 256 + (z)) / 1000.f; + if (lidar_name == "N10_P") + scan_points_[idx].intensity = int(y); + else + scan_points_[idx].intensity = 0; + s = packet_bytes[num * point_len + data_bits_start + point_len / 2]; + z = packet_bytes[num * point_len + data_bits_start + point_len / 2 + 1]; + if (lidar_name == "N10_P") + y = packet_bytes[num * point_len + data_bits_start + point_len / 2 + 2]; + + scan_points_[idx + 3000].range = double(s * 256 + (z)) / 1000.f; + if (lidar_name == "N10_P") + scan_points_[idx + 3000].intensity = int(y); + else + scan_points_[idx + 3000].intensity = 0; + + if ((degree + (degree_interval / invalidValue * num)) > 360) + scan_points_[idx].degree = degree + (degree_interval / invalidValue * num) - 360; + else + scan_points_[idx].degree = degree + (degree_interval / invalidValue * num); + } + else + continue; + if (((scan_points_[idx].degree < last_degree && scan_points_[idx].degree < 5 && last_degree > 355) || idx >= points_size_) && idx > 10) + { + last_degree = scan_points_[idx].degree; + count_num = idx; + idx = 0; + for (int k = 0; k < count_num; k++) + { + if (angle_able_max > 360) + { + if ((360 - scan_points_[k].degree) > (angle_able_max - 360) && (360 - scan_points_[k].degree) < angle_able_min) + { + scan_points_[k].range = 0; + scan_points_[k + 3000].range = 0; + } + } + else + { + if ((360 - scan_points_[k].degree) > angle_able_max || (360 - scan_points_[k].degree) < angle_able_min) + { + scan_points_[k].range = 0; + scan_points_[k + 3000].range = 0; + } + } + if (scan_points_[k].range < min_range || scan_points_[k].range > max_range) + scan_points_[k].range = 0; + if (scan_points_[k + 3000].range < min_range || scan_points_[k + 3000].range > max_range) + scan_points_[k + 3000].range = 0; + } + boost::unique_lock lock(mutex_); + scan_points_bak_.resize(scan_points_.size()); + scan_points_bak_.assign(scan_points_.begin(), scan_points_.end()); + for (long unsigned int k = 0; k < scan_points_.size(); k++) + { + scan_points_[k].range = 0; + scan_points_[k].degree = 0; + scan_points_[k].intensity = 0; + } + pre_time_ = time_; + lock.unlock(); + pubscan_cond_.notify_one(); + time_ = get_clock()->now(); + } + else + { + last_degree = scan_points_[idx].degree; + idx++; + } + } + packet_bytes = {0x00}; + if (packet_bytes) + { + packet_bytes = NULL; + delete packet_bytes; + } + } + + void LslidarDriver::pubScanThread() + { + bool wait_for_wake = true; + boost::unique_lock lock(pubscan_mutex_); + + while (rclcpp::ok()) + { + + while (wait_for_wake) + { + pubscan_cond_.wait(lock); + wait_for_wake = false; + } + if (lidar_name == "N10_P" || lidar_name == "M10_DOUBLE") + { + if (pubScan) + { + auto scan = sensor_msgs::msg::LaserScan::UniquePtr(new sensor_msgs::msg::LaserScan()); + ////int scan_num = count_num * 2; + int scan_num = count_num ; + + std::vector points; + rclcpp::Time start_time; + float scan_time; + this->getScan(points, start_time, scan_time); + scan->header.frame_id = frame_id; + if (use_gps_ts) + { + scan->header.stamp = rclcpp::Time(sweep_end_time_gps, sweep_end_time_hardware); + } + else + { + scan->header.stamp = this->now(); // timestamp will obtained from sweep data stamp + } + + scan->angle_min = 0; + scan->angle_max = 2 * M_PI; + scan->angle_increment = 2 * M_PI / (double)(count_num); + scan->range_min = min_range; + scan->range_max = max_range; + scan->ranges.reserve(scan_num); + scan->ranges.assign(scan_num, std::numeric_limits::infinity()); + scan->intensities.reserve(scan_num); + scan->intensities.assign(scan_num, std::numeric_limits::infinity()); + // scan->scan_time = scan_time; + // scan->time_increment = scan_time / (double)(count_num); + + for (int k = 0; k < scan_num; k++) + { + scan->ranges[k] = std::numeric_limits::infinity(); + scan->intensities[k] = 0; + } + + for (int i = 0; i < count_num; i++) + { + int point_idx = round((360 - points[i].degree) * count_num / 360); + if (points[i].range == 0.0) + { + scan->ranges[point_idx] = std::numeric_limits::infinity(); + scan->intensities[point_idx] = 0; + } + else + { + double dist = points[i].range; + scan->ranges[point_idx] = (float)dist; + scan->intensities[point_idx] = points[i].intensity; + } + + if(truncated_mode_){ + int len=sizeof(scan_crop_max) / sizeof(scan_crop_max[0]) ; + for(int j=0;j=(scan_crop_min[j]*count_num / 360)) && (point_idx<=(scan_crop_max[j]*count_num / 360))){ + scan->ranges[point_idx] = std::numeric_limits::infinity(); + scan->intensities[point_idx] = 0; + } + } + } + /* + if (points[i + 3000].range == 0.0) + { + scan->ranges[point_idx + count_num] = std::numeric_limits::infinity(); + scan->intensities[point_idx + count_num] = 0; + } + else + { + double dist = points[i+3000].range; + scan->ranges[point_idx + count_num] = (float)dist; + scan->intensities[point_idx + count_num] = points[i + 3000].intensity; + }*/ + } + scan_pub->publish(std::move(scan)); + } + if (pubPointCloud2) + { + std::vector points; + rclcpp::Time start_time; + float scan_time; + this->getScan(points, start_time, scan_time); + VPointCloud::Ptr point_cloud(new VPointCloud()); + if (use_gps_ts) + { + start_time = rclcpp::Time(sweep_end_time_gps, sweep_end_time_hardware); + } + double timestamp = start_time.seconds(); + point_cloud->header.stamp = static_cast(timestamp * 1e6); + point_cloud->header.frame_id = frame_id; + point_cloud->height = 1; + // printf("now = %f\n",timestamp); + for (uint16_t i = 0; i < count_num; i++) + { + // printf("degree = %f\n",points[i].degree); + double degree = 360.0 - points[i].degree; + bool pass_point = false; + if (angle_able_max < 360) + { + if (degree < angle_able_min || degree > angle_able_max) + pass_point = true; + } + else + { + if (degree < angle_able_min && degree > (angle_able_max - 360)) + pass_point = true; + } + if (points[i].range < 0.001) + pass_point = true; + if (!pass_point) + { + // printf("degree = %f\n",degree); + // printf("angle_able_min = %f\nangle_able_max=%f\n",angle_able_min,angle_able_max); + VPoint point; + int point_idx = round(degree * count_num / 360); + point.timestamp = timestamp - point_idx * (scan_time / count_num); + // printf("timestamp = %f\n",point.timestamp); + point.x = points[i].range * cos(M_PI / 180 * points[i].degree); + point.y = -points[i].range * sin(M_PI / 180 * points[i].degree); + point.z = 0; + point.intensity = points[i].intensity; + point_cloud->points.push_back(point); + ++point_cloud->width; + } + if (points[i + 3000].range < 0.001) + pass_point = true; + if (!pass_point) + { + // printf("degree = %f\n",degree); + // printf("angle_able_min = %f\nangle_able_max=%f\n",angle_able_min,angle_able_max); + VPoint point; + int point_idx = round(degree * count_num / 360); + point.timestamp = timestamp - point_idx * (scan_time / count_num); + // printf("timestamp = %f\n",point.timestamp); + point.x = points[i + 3000].range * cos(M_PI / 180 * points[i].degree); + point.y = -points[i + 3000].range * sin(M_PI / 180 * points[i].degree); + point.z = 0; + point.intensity = points[i + 3000].intensity; + point_cloud->points.push_back(point); + ++point_cloud->width; + } + } + sensor_msgs::msg::PointCloud2 pc_msg; + pcl::toROSMsg(*point_cloud, pc_msg); + point_cloud_pub->publish(pc_msg); + } + } + else + { + if (pubScan) + { + auto scan = sensor_msgs::msg::LaserScan::UniquePtr(new sensor_msgs::msg::LaserScan()); + //int scan_num = ceil((angle_able_max - angle_able_min) / 360 * count_num) + 1; + int scan_num = fixed_array_length;//cyy_addcyy_add + + std::vector points; + rclcpp::Time start_time; + float scan_time; + this->getScan(points, start_time, scan_time); + scan->header.frame_id = frame_id; + if (use_gps_ts) + { + scan->header.stamp = rclcpp::Time(sweep_end_time_gps, sweep_end_time_hardware); + } + else + { + scan->header.stamp = this->now(); // timestamp will obtained from sweep data stamp + } + + if (angle_able_max > 360) + { + scan->angle_min = 2 * M_PI * (angle_able_min - 360) / 360; + scan->angle_max = 2 * M_PI * (angle_able_max - 360) / 360; + } + else + { + scan->angle_min = 2 * M_PI * angle_able_min / 360; + scan->angle_max = 2 * M_PI * angle_able_max / 360; + } + scan->angle_increment = 2 * M_PI / (double)(fixed_array_length - 1); + + scan->range_min = min_range; + scan->range_max = max_range; + scan->ranges.reserve(scan_num); + scan->ranges.assign(scan_num, std::numeric_limits::infinity()); + scan->intensities.reserve(scan_num); + scan->intensities.assign(scan_num, std::numeric_limits::infinity()); + scan->scan_time = 0.1; + scan->time_increment = 0.1 / (double)(fixed_array_length - 1); + + int start_num = floor(angle_able_min * count_num / 360); + int end_num = floor(angle_able_max * count_num / 360); + + for (int i = 0; i < count_num; i++) + { + int point_idx = round((360 - points[i].degree) * count_num / 360); + if (point_idx < (end_num - count_num)) + point_idx += count_num; + point_idx = point_idx - start_num; + if (point_idx < 0 || point_idx >= scan_num) + continue; + if (points[i].range == 0.0) + { + scan->ranges[point_idx] = std::numeric_limits::infinity(); + } + else + { + double dist = points[i].range; + scan->ranges[point_idx] = (float)dist; + } + scan->intensities[point_idx] = points[i].intensity; + + if(truncated_mode_){ + int len=sizeof(scan_crop_max) / sizeof(scan_crop_max[0]) ; + for(int j=0;j=(scan_crop_min[j]*count_num / 360)) && (point_idx<=(scan_crop_max[j]*count_num / 360))){ + scan->ranges[point_idx] = std::numeric_limits::infinity(); + scan->intensities[point_idx] = 0; + } + } + } + } + + + scan_pub->publish(std::move(scan)); + } + if (pubPointCloud2) + { + std::vector points; + rclcpp::Time start_time; + float scan_time; + this->getScan(points, start_time, scan_time); + VPointCloud::Ptr point_cloud(new VPointCloud()); + if (use_gps_ts) + { + start_time = rclcpp::Time(sweep_end_time_gps, sweep_end_time_hardware); + } + double timestamp = start_time.seconds(); + point_cloud->header.stamp = static_cast(timestamp * 1e6); + point_cloud->header.frame_id = frame_id; + point_cloud->height = 1; + for (uint16_t i = 0; i < count_num; i++) + { + double degree = 360.0 - points[i].degree; + bool pass_point = false; + if (angle_able_max < 360) + { + if (degree < angle_able_min || degree > angle_able_max) + pass_point = true; + } + else + { + if (degree < angle_able_min && degree > (angle_able_max - 360)) + pass_point = true; + } + if (points[i].range < 0.001) + pass_point = true; + if (!pass_point) + { + // printf("degree = %f\n",degree); + // printf("angle_able_min = %f\nangle_able_max=%f\n",angle_able_min,angle_able_max); + VPoint point; + int point_idx = round(degree * count_num / 360); + point.timestamp = timestamp - point_idx * (scan_time / count_num); + // printf("timestamp = %f\n",point.timestamp); + point.x = points[i].range * cos(M_PI / 180 * points[i].degree); + point.y = -points[i].range * sin(M_PI / 180 * points[i].degree); + point.z = 0; + point.intensity = points[i].intensity; + point_cloud->points.push_back(point); + ++point_cloud->width; + } + } + sensor_msgs::msg::PointCloud2 pc_msg; + pcl::toROSMsg(*point_cloud, pc_msg); + point_cloud_pub->publish(pc_msg); + } + } + count_num = 0; + wait_for_wake = true; + if (first_compensation && compensation) + { + lidar_difop(); + } + } + } + + bool LslidarDriver::polling() + { + if (!is_start) + return true; + // Allocate a new shared pointer for zero-copy sharing with other nodelets. + unsigned char *packet_bytes = new unsigned char[500]; + int len = 0; + bool difop = false; + if (interface_selection == "net") + { + auto packet = lslidar_msgs::msg::LslidarPacket::UniquePtr( + new lslidar_msgs::msg::LslidarPacket()); + + std_msgs::msg::Byte msg; + while (true) + { + difop = false; + len = 0; + // keep reading until full packet received + len = msop_input_->getPacket(packet); + if (packet->data[0] == 0x5a) + { + if (lidar_name == "N10" || lidar_name == "L10") + len = 58; + else if (lidar_name == "M10") + len = 92; + else if (lidar_name == "N10_P") + len = 108; + else if (lidar_name == "M10_GPS") + len = 102; + else + { + int len_H = packet->data[1]; + int len_L = packet->data[2]; + len = len_H * 256 + len_L; + } + for (int i = len - 1; i > 0; i--) + packet->data[i] = packet->data[i - 1]; + packet->data[0] = 0xa5; + } + + if (lidar_name == "N10" || lidar_name == "L10") + len = 58; + else if (lidar_name == "M10") + len = 92; + else if (lidar_name == "N10_P") + len = 108; + else if (lidar_name == "M10_GPS") + len = 102; + else + { + int len_H = packet->data[2]; + int len_L = packet->data[3]; + len = len_H * 256 + len_L; + } + if ((lidar_name == "M10" || lidar_name == "M10_DOUBLE" || lidar_name == "M10_GPS" || lidar_name == "M10_P" || lidar_name == "M10_PLUS") && compensation) + { + if (packet->data[2] == 0x55 && packet->data[3] == 0x00 && packet->data[186] == 0xFA && packet->data[187] == 0xFB) + { + len = 188; + difop = true; + } + } + + if (len <= 0 || len >= 1000 || packet->data[0] != 0xa5 || packet->data[1] != 0x5a) + continue; + for (int i = 0; i < len; i++) + { + packet_bytes[i] = packet->data[i]; + } + if ((lidar_name == "N10" || lidar_name == "L10" || lidar_name == "N10_P") && packet_bytes[len - 1] != N10_CalCRC8(packet_bytes, len - 1)) + continue; + break; + } + } + else + { + if (in_file_name != "") // 读txt文件功能 + { + int usleep_time = round(1000000 / 10 / 24) - 135; + while (true) + { + std::ifstream file_reader(in_file_name); + while (file_reader.peek() != EOF) + { + std::string line; + std::getline(file_reader, line, '\n'); + for (long unsigned int i = 0; i < line.size() - 1; i++) + { + line[i] = line[i] - 48; + if (line[i] > 9) + line[i] = line[i] - 39; + } + + for (long unsigned int i = 0; i < (line.size() - 1) / 2; i++) + { + packet_bytes[i] = line[i * 2] * 16 + line[i * 2 + 1]; + } + if (lidar_name == "N10" || lidar_name == "L10") + len = 58; + else if (lidar_name == "M10") + len = 92; + else if (lidar_name == "N10_P") + len = 108; + else if (lidar_name == "M10_GPS") + len = 102; + else + { + int len_H = packet_bytes[2]; + int len_L = packet_bytes[3]; + len = len_H * 256 + len_L; + } + if (lidar_name == "N10_P" || lidar_name == "M10_DOUBLE") + LslidarDriver::data_processing_2(packet_bytes, len); + else + LslidarDriver::data_processing(packet_bytes, len); + usleep(usleep_time); + } + } + return false; + } + else + { + while (true) + { + difop = false; + len = 0; + len = LslidarDriver::receive_data(packet_bytes); + if ((lidar_name == "M10" || lidar_name == "M10_DOUBLE" || lidar_name == "M10_GPS" || lidar_name == "M10_P" || lidar_name == "M10_PLUS") && compensation) + { + if (packet_bytes[2] == 0x55 && packet_bytes[3] == 0x00 && packet_bytes[186] == 0xFA && packet_bytes[187] == 0xFB) + difop = true; + } + if (len == 0) + continue; + break; + } + } + } + if (difop) + LslidarDriver::difop_processing(packet_bytes); + else + { + if (lidar_name == "N10_P" || lidar_name == "M10_DOUBLE") + LslidarDriver::data_processing_2(packet_bytes, len); + else + LslidarDriver::data_processing(packet_bytes, len); + } + delete packet_bytes; + return true; + } + +} // namespace lslidar_driver diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lslidar_driver_node.cc b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lslidar_driver_node.cc new file mode 100644 index 0000000..6a89f99 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_driver/src/lslidar_driver_node.cc @@ -0,0 +1,35 @@ +/* + * This file is part of lslidar driver. + * + * The driver is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the driver. If not, see . + */ + +#include "rclcpp/rclcpp.hpp" +#include "lslidar_driver/lslidar_driver.h" + +using namespace lslidar_driver; +volatile sig_atomic_t flag = 1; + +int main(int argc, char* argv[]) +{ + rclcpp::init(argc, argv); + auto node = std::make_shared(); + + while (rclcpp::ok() && node->polling()) { + rclcpp::spin_some(node); + } + //rclcpp::spin(node); + rclcpp::shutdown(); + return 0; +} diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/CMakeLists.txt b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/CMakeLists.txt new file mode 100644 index 0000000..e6a603e --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.5) +project(lslidar_msgs) + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(std_msgs REQUIRED) +find_package(sensor_msgs REQUIRED) +find_package(builtin_interfaces REQUIRED) +find_package(rosidl_default_generators REQUIRED) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + ament_lint_auto_find_test_dependencies() +endif() + +rosidl_generate_interfaces(lslidar_msgs + "msg/LslidarDifop.msg" + "msg/LslidarPacket.msg" + "msg/LslidarPoint.msg" + "msg/LslidarScan.msg" + "msg/LslidarSweep.msg" + DEPENDENCIES builtin_interfaces std_msgs + ) + +ament_package() diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarDifop.msg b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarDifop.msg new file mode 100644 index 0000000..f377c75 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarDifop.msg @@ -0,0 +1,2 @@ +int64 temperature +int64 rpm diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarPacket.msg b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarPacket.msg new file mode 100644 index 0000000..d77ee45 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarPacket.msg @@ -0,0 +1,5 @@ +# Raw Leishen LIDAR packet. + +builtin_interfaces/Time stamp # packet timestamp +uint8[2000] data # packet contents + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarPoint.msg b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarPoint.msg new file mode 100644 index 0000000..3132167 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarPoint.msg @@ -0,0 +1,12 @@ +# Time when the point is captured +float32 time + +# Converted distance in the sensor frame +float64 x +float64 y +float64 z + +# Raw measurement from Leishen M10 +float64 azimuth +float64 distance +float64 intensity diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarScan.msg b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarScan.msg new file mode 100644 index 0000000..0a3891c --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarScan.msg @@ -0,0 +1,6 @@ +# Altitude of all the points within this scan +float64 altitude + +# The valid points in this scan sorted by azimuth +# from 0 to 359.99 +LslidarPoint[] points diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarSweep.msg b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarSweep.msg new file mode 100644 index 0000000..9cfe4b7 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/msg/LslidarSweep.msg @@ -0,0 +1,4 @@ +std_msgs/Header header + +# The 0th scan is at the bottom +LslidarScan[16] scans diff --git a/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/package.xml b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/package.xml new file mode 100644 index 0000000..8001ad5 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/lslidar_msgs/package.xml @@ -0,0 +1,25 @@ + + + lslidar_msgs + 1.2.0 + ROS message definitions for Leishen LIDARs. + Nick Shu + Nick Shu + GNU General Public License V3.0 + + ament_cmake + rosidl_default_generators + + rosidl_default_runtime + builtin_interfaces + + std_msgs + ament_lint_auto + ament_lint_common + + rosidl_interface_packages + + + ament_cmake + + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/version.txt b/src/LSLIDAR_X_ROS2-20240228/src/version.txt new file mode 100644 index 0000000..7a2b9d4 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/version.txt @@ -0,0 +1,20 @@ +版本变更 +/*************************************************************** +初始版本: LSLIDAR_M10_N10_V2.5.0_221104_ROS2 +变更内容: + 1.实现M10/M10_P/M10_PLUS/N10/M10_GPS网口和串口传输数据生成点云功能 + 2.实现点云角度裁剪和距离过滤功能 + 3.可以通过lslidar_order话题控制雷达启停 + 4.支持读取pcap包 + +更改日期: 2022-11-04 +***************************************************************/ + +/*************************************************************** +初始版本: LSLIDAR_M10_N10_V2.5.0_221111_ROS2 +变更内容: + 1.针对M10和M10_GPS雷达出货后发现的点云问题进行驱动补救 + +更改日期: 2022-11-11 +***************************************************************/ + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/wheeltec_udev.sh b/src/LSLIDAR_X_ROS2-20240228/src/wheeltec_udev.sh new file mode 100644 index 0000000..17aaa46 --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/src/wheeltec_udev.sh @@ -0,0 +1,33 @@ +#CP2102 串口号0002 设置别名为wheeltec_controller +echo 'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60",ATTRS{serial}=="0002", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_controller"' >/etc/udev/rules.d/wheeltec_controller.rules +#CH9102,同时系统安装了对应驱动 串口号0002 设置别名为wheeltec_controller +echo 'KERNEL=="ttyCH343USB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4",ATTRS{serial}=="0002", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_controller"' >/etc/udev/rules.d/wheeltec_controller2.rules +#CH9102,同时系统没有安装对应驱动 串口号0002 设置别名为wheeltec_controller +echo 'KERNEL=="ttyACM*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4",ATTRS{serial}=="0002", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_controller"' >/etc/udev/rules.d/wheeltec_controller3.rules + +#CP2102 串口号0001 设置别名为wheeltec_lidar +echo 'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60",ATTRS{serial}=="0001", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_lidar"' >/etc/udev/rules.d/wheeltec_lidar.rules +#CH9102,同时系统安装了对应驱动 串口号0001 设置别名为wheeltec_lidar +echo 'KERNEL=="ttyCH343USB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4",ATTRS{serial}=="54B8001974", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_lidar"' >/etc/udev/rules.d/wheeltec_lidar2.rules +#CH9102,同时系统没有安装对应驱动 串口号0001 设置别名为wheeltec_lidar +echo 'KERNEL=="ttyACM*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4",ATTRS{serial}=="0001", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_lidar"' >/etc/udev/rules.d/wheeltec_lidar3.rules + +#CP2102 串口号0003 设置别名为wheeltec_FDI_IMU_GNSS +echo 'KERNEL=="ttyUSB*", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60",ATTRS{serial}=="0003", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_FDI_IMU_GNSS"' >/etc/udev/rules.d/wheeltec_fdi_imu_gnss.rules +#CH9102,同时系统安装了对应驱动 串口号0003 设置别名为wheeltec_FDI_IMU_GNSS +echo 'KERNEL=="ttyCH343USB*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4",ATTRS{serial}=="0003", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_FDI_IMU_GNSS"' >/etc/udev/rules.d/wheeltec_fdi_imu_gnss2.rules +#CH9102,同时系统没有安装对应驱动 串口号0003 设置别名为wheeltec_FDI_IMU_GNSS +echo 'KERNEL=="ttyACM*", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4",ATTRS{serial}=="0003", MODE:="0777", GROUP:="dialout", SYMLINK+="wheeltec_FDI_IMU_GNSS"' >/etc/udev/rules.d/wheeltec_fdi_imu_gnss3.rules + +echo 'SUBSYSTEM=="video4linux",ATTR{name}=="GENERAL WEBCAM",ATTR{index}=="0",MODE:="0777",SYMLINK+="RgbCam"' >>/etc/udev/rules.d/camera.rules +echo 'SUBSYSTEM=="video4linux",ATTR{name}=="GENERAL WEBCAM: GENERAL WEBCAM",ATTR{index}=="0",MODE:="0777",SYMLINK+="RgbCam"' >>/etc/udev/rules.d/camera.rules +echo 'SUBSYSTEM=="video4linux",ATTR{name}=="Astra Pro HD Camera: Astra Pro ",ATTR{index}=="0",MODE:="0777",SYMLINK+="Astra_Pro"' >>/etc/udev/rules.d/camera.rules +echo 'SUBSYSTEM=="video4linux",ATTR{name}=="USB 2.0 Camera: USB Camera",ATTR{index}=="0",MODE:="0777",SYMLINK+="Astra_Dabai"' >>/etc/udev/rules.d/camera.rules +echo 'SUBSYSTEM=="video4linux",ATTR{name}=="USB 2.0 Camera",ATTR{index}=="0",MODE:="0777",SYMLINK+="Astra_Gemini"' >>/etc/udev/rules.d/camera.rules +echo 'SUBSYSTEM=="video4linux",ATTR{name}=="Intel(R) RealSense(TM) Depth Ca",ATTR{index}=="0",MODE:="0777",SYMLINK+="realsense"' >>/etc/udev/rules.d/camera.rules + +service udev reload +sleep 2 +service udev restart + + diff --git a/src/LSLIDAR_X_ROS2-20240228/src/镭神Lsx雷达旋转角度.png b/src/LSLIDAR_X_ROS2-20240228/src/镭神Lsx雷达旋转角度.png new file mode 100644 index 0000000..aa24785 Binary files /dev/null and b/src/LSLIDAR_X_ROS2-20240228/src/镭神Lsx雷达旋转角度.png differ diff --git a/src/LSLIDAR_X_ROS2-20240228/wheeltec_lidar.launch.py b/src/LSLIDAR_X_ROS2-20240228/wheeltec_lidar.launch.py new file mode 100644 index 0000000..f38b80a --- /dev/null +++ b/src/LSLIDAR_X_ROS2-20240228/wheeltec_lidar.launch.py @@ -0,0 +1,62 @@ +import os +from pathlib import Path +import launch_ros.actions +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import (DeclareLaunchArgument, GroupAction, + IncludeLaunchDescription, SetEnvironmentVariable) +from launch.launch_description_sources import PythonLaunchDescriptionSource + +def generate_launch_description(): + Lslidar_dir = get_package_share_directory('lslidar_driver') + Lslidar_launch_dir = os.path.join(Lslidar_dir, 'launch') + + + Ld14_dir = get_package_share_directory('ldlidar_sl_ros2') + Ld14_launch_dir = os.path.join(Ld14_dir, 'launch') + + Ld06_dir = get_package_share_directory('ldlidar_stl_ros2') + Ld06_launch_dir = os.path.join(Ld14_dir, 'launch') + + + Lsm10_m10_uart = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Lslidar_launch_dir, 'lsm10_uart_launch.py')),) + + Lsm10_m10_net = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Lslidar_launch_dir, 'lsm10_net_launch.py')),) + + Lsm10_m10p_uart = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Lslidar_launch_dir, 'lsm10p_uart_launch.py')),) + + Lsm10_m10p_net = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Lslidar_launch_dir, 'lsm10p_net_launch.py')),) + + Lsn10 = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Lslidar_launch_dir, 'lsn10_launch.py')),) + Lsn10p = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Lslidar_launch_dir, 'lsn10p_launch.py')),) + + Lsn10_net = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Lslidar_launch_dir, 'lsn10_net_launch.py')),) + Lsn10p_net = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Lslidar_launch_dir, 'lsn10p_net_launch.py')),) + + Ld14 = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Ld14_launch_dir, 'ld14.launch.py')),) + Ld06 = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(Ld06_launch_dir, 'ld06.launch.py')),) + + # Create the launch description and populate + ld = LaunchDescription() + ''' + Please select your lidar here, options include: + Lsm10_m10p_uart、Lsm10_m10p_net、Lsm10_m10_uart、Lsm10_m10_net、Lsn10、Lsn10p,Lsn10_net、Lsn10p_net,ld14、Ld06. + 1.If you are using LS* lidar (including lsn10, lsm10*), please don't forget to + modify the tf conversion parameters of robot_mode_description.launch.py + according to the user guide file. + 2.If you are using m10 lidar, please pay attention to distinguish whether it is m10p or not. + ''' + ld.add_action(Lsn10) + + return ld + diff --git a/src/LSLIDAR_X_ROS2-20240228/wheeltec_lidar.launch.py仅在WHEELTEC镜像中使用 b/src/LSLIDAR_X_ROS2-20240228/wheeltec_lidar.launch.py仅在WHEELTEC镜像中使用 new file mode 100644 index 0000000..e69de29 diff --git a/src/cyy_navigation2/CMakeLists.txt b/src/cyy_navigation2/CMakeLists.txt new file mode 100644 index 0000000..884ac6a --- /dev/null +++ b/src/cyy_navigation2/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.8) +project(cyy_navigation2) + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +find_package(nav2_bringup REQUIRED) +install( + DIRECTORY launch param maps + DESTINATION share/${PROJECT_NAME} +) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # comment the line when a copyright and license is added to all source files + set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # comment the line when this package is in a git repo and when + # a copyright and license is added to all source files + set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() + diff --git a/src/cyy_navigation2/bt/follow_point.xml b/src/cyy_navigation2/bt/follow_point.xml new file mode 100644 index 0000000..ffae8d9 --- /dev/null +++ b/src/cyy_navigation2/bt/follow_point.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/nav_to_pose_with_consistent_replanning_and_if_path_becomes_invalid.xml b/src/cyy_navigation2/bt/nav_to_pose_with_consistent_replanning_and_if_path_becomes_invalid.xml new file mode 100644 index 0000000..f4ed518 --- /dev/null +++ b/src/cyy_navigation2/bt/nav_to_pose_with_consistent_replanning_and_if_path_becomes_invalid.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/navigate_through_poses_w_replanning_and_recovery.xml b/src/cyy_navigation2/bt/navigate_through_poses_w_replanning_and_recovery.xml new file mode 100644 index 0000000..1378863 --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_through_poses_w_replanning_and_recovery.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/navigate_to_pose_w_replanning_and_recovery.xml b/src/cyy_navigation2/bt/navigate_to_pose_w_replanning_and_recovery.xml new file mode 100644 index 0000000..2396b84 --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_to_pose_w_replanning_and_recovery.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/navigate_to_pose_w_replanning_goal_patience_and_recovery.xml b/src/cyy_navigation2/bt/navigate_to_pose_w_replanning_goal_patience_and_recovery.xml new file mode 100644 index 0000000..6b5883b --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_to_pose_w_replanning_goal_patience_and_recovery.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/navigate_w_recovery_and_replanning_only_if_path_becomes_invalid.xml b/src/cyy_navigation2/bt/navigate_w_recovery_and_replanning_only_if_path_becomes_invalid.xml new file mode 100644 index 0000000..d21efa3 --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_w_recovery_and_replanning_only_if_path_becomes_invalid.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/navigate_w_replanning_distance.xml b/src/cyy_navigation2/bt/navigate_w_replanning_distance.xml new file mode 100644 index 0000000..8ca5dbb --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_w_replanning_distance.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/navigate_w_replanning_only_if_goal_is_updated.xml b/src/cyy_navigation2/bt/navigate_w_replanning_only_if_goal_is_updated.xml new file mode 100644 index 0000000..3e88944 --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_w_replanning_only_if_goal_is_updated.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/navigate_w_replanning_only_if_path_becomes_invalid.xml b/src/cyy_navigation2/bt/navigate_w_replanning_only_if_path_becomes_invalid.xml new file mode 100644 index 0000000..e921db5 --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_w_replanning_only_if_path_becomes_invalid.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/cyy_navigation2/bt/navigate_w_replanning_speed.xml b/src/cyy_navigation2/bt/navigate_w_replanning_speed.xml new file mode 100644 index 0000000..f0f47c4 --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_w_replanning_speed.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/navigate_w_replanning_time.xml b/src/cyy_navigation2/bt/navigate_w_replanning_time.xml new file mode 100644 index 0000000..33c2c41 --- /dev/null +++ b/src/cyy_navigation2/bt/navigate_w_replanning_time.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/cyy_navigation2/bt/odometry_calibration.xml b/src/cyy_navigation2/bt/odometry_calibration.xml new file mode 100644 index 0000000..49000e1 --- /dev/null +++ b/src/cyy_navigation2/bt/odometry_calibration.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/cyy_navigation2/config/nav2_params.yaml b/src/cyy_navigation2/config/nav2_params.yaml new file mode 100644 index 0000000..295058a --- /dev/null +++ b/src/cyy_navigation2/config/nav2_params.yaml @@ -0,0 +1,348 @@ +amcl: + ros__parameters: + use_sim_time: True + alpha1: 0.5 + alpha2: 0.5 + alpha3: 0.5 + alpha4: 0.5 + alpha5: 0.5 + base_frame_id: "base_link" + beam_skip_distance: 0.5 + beam_skip_error_threshold: 0.9 + beam_skip_threshold: 0.3 + do_beamskip: true + global_frame_id: "map" + lambda_short: 0.1 + laser_likelihood_max_dist: 4.0 + laser_max_range: 100.0 + laser_min_range: -1.0 + laser_model_type: "likelihood_field" + max_beams: 120 + max_particles: 4000 + min_particles: 1000 + odom_frame_id: "odom" + pf_err: 0.01 + pf_z: 0.99 + recovery_alpha_fast: 0.0 + recovery_alpha_slow: 0.0 + resample_interval: 2 + robot_model_type: "nav2_amcl::DifferentialMotionModel" + save_pose_rate: 0.5 + sigma_hit: 0.2 + tf_broadcast: true + transform_tolerance: 1.0 + update_min_a: 0.2 + update_min_d: 0.25 + z_hit: 0.9 + z_max: 0.05 + z_rand: 0.1 + z_short: 0.05 + scan_topic: scan + +bt_navigator: + ros__parameters: + use_sim_time: True + global_frame: map + robot_base_frame: base_link + odom_topic: /odom + bt_loop_duration: 10 + default_server_timeout: 20 + wait_for_service_timeout: 1000 + # 'default_nav_through_poses_bt_xml' and 'default_nav_to_pose_bt_xml' are use defaults: + # nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml + # nav2_bt_navigator/navigate_through_poses_w_replanning_and_recovery.xml + # They can be set here or via a RewrittenYaml remap from a parent launch file to Nav2. + plugin_lib_names: + - nav2_compute_path_to_pose_action_bt_node + - nav2_compute_path_through_poses_action_bt_node + - nav2_smooth_path_action_bt_node + - nav2_follow_path_action_bt_node + - nav2_spin_action_bt_node + - nav2_wait_action_bt_node + - nav2_assisted_teleop_action_bt_node + - nav2_back_up_action_bt_node + - nav2_drive_on_heading_bt_node + - nav2_clear_costmap_service_bt_node + - nav2_is_stuck_condition_bt_node + - nav2_goal_reached_condition_bt_node + - nav2_goal_updated_condition_bt_node + - nav2_globally_updated_goal_condition_bt_node + - nav2_is_path_valid_condition_bt_node + - nav2_initial_pose_received_condition_bt_node + - nav2_reinitialize_global_localization_service_bt_node + - nav2_rate_controller_bt_node + - nav2_distance_controller_bt_node + - nav2_speed_controller_bt_node + - nav2_truncate_path_action_bt_node + - nav2_truncate_path_local_action_bt_node + - nav2_goal_updater_node_bt_node + - nav2_recovery_node_bt_node + - nav2_pipeline_sequence_bt_node + - nav2_round_robin_node_bt_node + - nav2_transform_available_condition_bt_node + - nav2_time_expired_condition_bt_node + - nav2_path_expiring_timer_condition + - nav2_distance_traveled_condition_bt_node + - nav2_single_trigger_bt_node + - nav2_goal_updated_controller_bt_node + - nav2_is_battery_low_condition_bt_node + - nav2_navigate_through_poses_action_bt_node + - nav2_navigate_to_pose_action_bt_node + - nav2_remove_passed_goals_action_bt_node + - nav2_planner_selector_bt_node + - nav2_controller_selector_bt_node + - nav2_goal_checker_selector_bt_node + - nav2_controller_cancel_bt_node + - nav2_path_longer_on_approach_bt_node + - nav2_wait_cancel_bt_node + - nav2_spin_cancel_bt_node + - nav2_back_up_cancel_bt_node + - nav2_assisted_teleop_cancel_bt_node + - nav2_drive_on_heading_cancel_bt_node + - nav2_is_battery_charging_condition_bt_node + +bt_navigator_navigate_through_poses_rclcpp_node: + ros__parameters: + use_sim_time: True + +bt_navigator_navigate_to_pose_rclcpp_node: + ros__parameters: + use_sim_time: True + +controller_server: + ros__parameters: + use_sim_time: True + controller_frequency: 20.0 + min_x_velocity_threshold: 0.001 + min_y_velocity_threshold: 0.5 + min_theta_velocity_threshold: 0.001 + failure_tolerance: 0.3 + progress_checker_plugin: "progress_checker" + goal_checker_plugins: ["general_goal_checker"] # "precise_goal_checker" + controller_plugins: ["FollowPath"] + + # Progress checker parameters + progress_checker: + plugin: "nav2_controller::SimpleProgressChecker" + required_movement_radius: 0.5 + movement_time_allowance: 10.0 + # Goal checker parameters + #precise_goal_checker: + # plugin: "nav2_controller::SimpleGoalChecker" + # xy_goal_tolerance: 0.25 + # yaw_goal_tolerance: 0.25 + # stateful: True + general_goal_checker: + stateful: True + plugin: "nav2_controller::SimpleGoalChecker" + xy_goal_tolerance: 0.25 + yaw_goal_tolerance: 0.25 + # DWB parameters + FollowPath: + plugin: "dwb_core::DWBLocalPlanner" + debug_trajectory_details: True + min_vel_x: 0.0 + min_vel_y: 0.0 + max_vel_x: 0.50 + max_vel_y: 0.0 + max_vel_theta: 3.0 + min_speed_xy: 0.0 + max_speed_xy: 0.50 + min_speed_theta: 0.0 + # Add high threshold velocity for turtlebot 3 issue. + # https://github.com/ROBOTIS-GIT/turtlebot3_simulations/issues/75 + acc_lim_x: 2.5 + acc_lim_y: 0.0 + acc_lim_theta: 3.2 + decel_lim_x: -2.5 + decel_lim_y: 0.0 + decel_lim_theta: -3.2 + vx_samples: 20 + vy_samples: 5 + vtheta_samples: 20 + sim_time: 1.7 + linear_granularity: 0.05 + angular_granularity: 0.025 + transform_tolerance: 0.2 + xy_goal_tolerance: 0.25 + trans_stopped_velocity: 0.25 + short_circuit_trajectory_evaluation: True + stateful: True + critics: ["RotateToGoal", "Oscillation", "BaseObstacle", "GoalAlign", "PathAlign", "PathDist", "GoalDist"] + BaseObstacle.scale: 0.02 + PathAlign.scale: 32.0 + PathAlign.forward_point_distance: 0.1 + GoalAlign.scale: 24.0 + GoalAlign.forward_point_distance: 0.1 + PathDist.scale: 32.0 + GoalDist.scale: 24.0 + RotateToGoal.scale: 32.0 + RotateToGoal.slowing_factor: 5.0 + RotateToGoal.lookahead_time: -1.0 + +local_costmap: + local_costmap: + ros__parameters: + update_frequency: 5.0 + publish_frequency: 2.0 + global_frame: odom + robot_base_frame: base_link + use_sim_time: True + rolling_window: true + width: 3 + height: 3 + resolution: 0.05 + robot_radius: 0.20 + plugins: ["voxel_layer", "inflation_layer"] + inflation_layer: + plugin: "nav2_costmap_2d::InflationLayer" + cost_scaling_factor: 3.0 + inflation_radius: 0.30 + voxel_layer: + plugin: "nav2_costmap_2d::VoxelLayer" + enabled: True + publish_voxel_map: True + origin_z: 0.0 + z_resolution: 0.05 + z_voxels: 16 + max_obstacle_height: 2.0 + mark_threshold: 0 + observation_sources: scan + scan: + topic: /scan + max_obstacle_height: 2.0 + clearing: True + marking: True + data_type: "LaserScan" + raytrace_max_range: 3.0 + raytrace_min_range: 0.0 + obstacle_max_range: 2.5 + obstacle_min_range: 0.0 + static_layer: + plugin: "nav2_costmap_2d::StaticLayer" + map_subscribe_transient_local: True + always_send_full_costmap: True + +global_costmap: + global_costmap: + ros__parameters: + update_frequency: 1.0 + publish_frequency: 1.0 + global_frame: map + robot_base_frame: base_link + use_sim_time: True + robot_radius: 0.20 + resolution: 0.05 + track_unknown_space: true + plugins: ["static_layer", "obstacle_layer", "inflation_layer"] + obstacle_layer: + plugin: "nav2_costmap_2d::ObstacleLayer" + enabled: True + observation_sources: scan + scan: + topic: /scan + max_obstacle_height: 2.0 + clearing: True + marking: True + data_type: "LaserScan" + raytrace_max_range: 3.0 + raytrace_min_range: 0.0 + obstacle_max_range: 2.5 + obstacle_min_range: 0.0 + static_layer: + plugin: "nav2_costmap_2d::StaticLayer" + map_subscribe_transient_local: True + inflation_layer: + plugin: "nav2_costmap_2d::InflationLayer" + cost_scaling_factor: 3.0 + inflation_radius: 0.30 + always_send_full_costmap: True + +map_server: + ros__parameters: + use_sim_time: True + # Overridden in launch by the "map" launch configuration or provided default value. + # To use in yaml, remove the default "map" value in the tb3_simulation_launch.py file & provide full path to map below. + yaml_filename: "" + +map_saver: + ros__parameters: + use_sim_time: True + save_map_timeout: 5.0 + free_thresh_default: 0.25 + occupied_thresh_default: 0.65 + map_subscribe_transient_local: True + +planner_server: + ros__parameters: + expected_planner_frequency: 20.0 + use_sim_time: True + planner_plugins: ["GridBased"] + GridBased: + plugin: "nav2_navfn_planner/NavfnPlanner" + tolerance: 0.5 + use_astar: false + allow_unknown: true + +smoother_server: + ros__parameters: + use_sim_time: True + smoother_plugins: ["simple_smoother"] + simple_smoother: + plugin: "nav2_smoother::SimpleSmoother" + tolerance: 1.0e-10 + max_its: 1000 + do_refinement: True + +behavior_server: + ros__parameters: + costmap_topic: local_costmap/costmap_raw + footprint_topic: local_costmap/published_footprint + cycle_frequency: 10.0 + behavior_plugins: ["backup", "drive_on_heading", "assisted_teleop", "wait"] + backup: + plugin: "nav2_behaviors/BackUp" + drive_on_heading: + plugin: "nav2_behaviors/DriveOnHeading" + wait: + plugin: "nav2_behaviors/Wait" + assisted_teleop: + plugin: "nav2_behaviors/AssistedTeleop" + global_frame: odom + robot_base_frame: base_link + transform_tolerance: 0.3 + use_sim_time: true + simulate_ahead_time: 2.0 + max_rotational_vel: 1.0 + min_rotational_vel: 0.4 + rotational_acc_lim: 3.2 + +robot_state_publisher: + ros__parameters: + use_sim_time: True + +waypoint_follower: + ros__parameters: + use_sim_time: True + loop_rate: 20 + stop_on_failure: false + waypoint_task_executor_plugin: "wait_at_waypoint" + wait_at_waypoint: + plugin: "nav2_waypoint_follower::WaitAtWaypoint" + enabled: True + waypoint_pause_duration: 200 + +velocity_smoother: + ros__parameters: + use_sim_time: True + smoothing_frequency: 20.0 + scale_velocities: False + feedback: "OPEN_LOOP" + max_velocity: [0.26, 0.0, 1.0] + min_velocity: [-0.26, 0.0, -1.0] + max_accel: [2.5, 0.0, 3.2] + max_decel: [-2.5, 0.0, -3.2] + odom_topic: "odom" + odom_duration: 0.1 + deadband_velocity: [0.0, 0.0, 0.0] + velocity_timeout: 1.0 diff --git a/src/cyy_navigation2/launch/car_bringup.launch.py b/src/cyy_navigation2/launch/car_bringup.launch.py new file mode 100644 index 0000000..ebed688 --- /dev/null +++ b/src/cyy_navigation2/launch/car_bringup.launch.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +""" +小车导航系统启动文件 +启动所有必要的硬件和导航节点 +""" + +import os +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument, TimerAction, LogInfo +from launch.launch_description_sources import PythonLaunchDescriptionSource, FrontendLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration, PathJoinSubstitution, PythonExpression +from launch_ros.actions import Node +from launch_ros.substitutions import FindPackageShare +from launch.conditions import IfCondition, UnlessCondition + +def generate_launch_description(): + # 获取包路径 + cyy_navigation2_dir = get_package_share_directory('cyy_navigation2') + + # 声明启动参数 + use_base = LaunchConfiguration('use_base', default='true') + use_lidar = LaunchConfiguration('use_lidar', default='true') + use_description = LaunchConfiguration('use_description', default='true') + use_bridge = LaunchConfiguration('use_bridge', default='true') + + # 启动参数列表 + launch_arguments = [ + DeclareLaunchArgument( + 'use_base', + default_value='true', + description='启动底盘控制' + ), + DeclareLaunchArgument( + 'use_lidar', + default_value='true', + description='启动激光雷达' + ), + DeclareLaunchArgument( + 'use_description', + default_value='true', + description='启动URDF显示' + ), + DeclareLaunchArgument( + 'use_bridge', + default_value='true', + description='启动ROS Bridge' + ), + ] + + # 创建启动描述 + ld = LaunchDescription(launch_arguments) + + # 1. 启动底盘控制 + base_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource([ + FindPackageShare('origincar_base'), '/launch/base_serial.launch.py' + ]), + condition=IfCondition(use_base) + ) + + # 添加延迟,确保底盘先启动 + ld.add_action(TimerAction( + period=1.0, + actions=[LogInfo(msg='启动底盘控制...'), base_launch] + )) + + # 2. 启动激光雷达 + lidar_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource([ + FindPackageShare('lslidar_driver'), '/launch/lsn10_launch.py' + ]), + condition=IfCondition(use_lidar) + ) + + ld.add_action(TimerAction( + period=2.0, + actions=[LogInfo(msg='启动激光雷达...'), lidar_launch] + )) + + # 3. 启动URDF显示 + description_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource([ + FindPackageShare('origincar_description'), '/launch/display.launch.py' + ]), + condition=IfCondition(use_description) + ) + + ld.add_action(TimerAction( + period=3.0, + actions=[LogInfo(msg='启动URDF显示...'), description_launch] + )) + + # 4. 启动ROS Bridge + bridge_launch = IncludeLaunchDescription( + FrontendLaunchDescriptionSource([ + FindPackageShare('rosbridge_server'), '/launch/rosbridge_websocket_launch.xml' + ]), + condition=IfCondition(use_bridge) + ) + + ld.add_action(TimerAction( + period=4.0, + actions=[LogInfo(msg='启动ROS Bridge...'), bridge_launch] + )) + + + return ld diff --git a/src/cyy_navigation2/launch/cyy_nav.launch.py b/src/cyy_navigation2/launch/cyy_nav.launch.py new file mode 100644 index 0000000..26f4de1 --- /dev/null +++ b/src/cyy_navigation2/launch/cyy_nav.launch.py @@ -0,0 +1,41 @@ +import os +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + + +def generate_launch_description(): + # =============================1.λĵַ============================================================= + cyy_navigation2_dir = get_package_share_directory('cyy_navigation2') + nav2_bringup_dir = get_package_share_directory('nav2_bringup') + slam = LaunchConfiguration('slam', default='True') + # =============================2.ȡļ·=================================================== + # use_sim_time Ҫótrue,ΪgazeboǷ滷ʱͨ/clockȡϵͳʱ + use_sim_time = LaunchConfiguration('use_sim_time', default='false') + map_yaml_path = LaunchConfiguration('map', + default=os.path.join(cyy_navigation2_dir, 'maps', 'cyy_map1.yaml')) + nav2_param_path = LaunchConfiguration('params_file', + default=os.path.join(cyy_navigation2_dir, 'param', 'nav2_params.yaml')) + rviz_config_dir = os.path.join(nav2_bringup_dir, 'rviz', 'nav2_default_view.rviz') + + # =============================3.launchļ룺ͼ·Ƿʹ÷ʱԼnav2ļ============== + nav2_bringup_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource([nav2_bringup_dir, '/launch', '/bringup_launch.py']), + launch_arguments={ + 'map': map_yaml_path, + 'use_sim_time': use_sim_time, + 'params_file': nav2_param_path, + 'slam': slam}.items(), + ) + rviz_node = Node( + package='rviz2', + executable='rviz2', + name='rviz2', + arguments=['-d', rviz_config_dir], + parameters=[{'use_sim_time': use_sim_time}], + output='screen') + + return LaunchDescription([nav2_bringup_launch]) \ No newline at end of file diff --git a/src/cyy_navigation2/launch/cyy_nav_box.launch.py b/src/cyy_navigation2/launch/cyy_nav_box.launch.py new file mode 100644 index 0000000..c6fd3f2 --- /dev/null +++ b/src/cyy_navigation2/launch/cyy_nav_box.launch.py @@ -0,0 +1,86 @@ +import os +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +def generate_launch_description(): + # 获取包路径 + cyy_navigation2_dir = get_package_share_directory('cyy_navigation2') + nav2_bringup_dir = get_package_share_directory('nav2_bringup') + + # 声明参数 + use_sim_time = LaunchConfiguration('use_sim_time', default='False') + slam = LaunchConfiguration('slam', default='False') + localization = LaunchConfiguration('localization', default='False') + + # 定义文件路径 + map_yaml_path = os.path.join(cyy_navigation2_dir, 'maps', 'cyy_map.yaml') + nav2_param_path = os.path.join(cyy_navigation2_dir, 'param', 'nav2_params.yaml') + slam_params_file = os.path.join(cyy_navigation2_dir, 'param', 'slam_toolbox_localization.yaml') + + # 定义地图基础路径(用于 .posegraph 文件) + map_base_path = os.path.join(cyy_navigation2_dir, 'maps', 'cyy_map') + + # 检查 .posegraph 文件是否存在 + posegraph_path = map_base_path + '.posegraph' + if not os.path.exists(posegraph_path): + print(f"警告: .posegraph 文件不存在: {posegraph_path}") + print("将使用 AMCL 替代") + use_slam_toolbox = False + else: + use_slam_toolbox = True + print(f"找到 .posegraph 文件: {posegraph_path}") + + # 创建启动描述 + ld = LaunchDescription([ + DeclareLaunchArgument('use_sim_time', default_value='False'), + DeclareLaunchArgument('slam', default_value='False'), + DeclareLaunchArgument('localization', default_value='False'), + ]) + + # 如果使用 slam_toolbox + if use_slam_toolbox: + slam_toolbox_node = Node( + package='slam_toolbox', + executable='localization_slam_toolbox_node', + name='slam_toolbox', + output='screen', + parameters=[ + slam_params_file, + {'use_sim_time': use_sim_time}, + {'map_file_name': map_base_path}, + {'map_start_pose': [0.0, 0.0, 0.0]} + ], + remappings=[('/scan', '/scan')] + ) + ld.add_action(slam_toolbox_node) + # 使用 slam_toolbox 时,Nav2 不启用定位 + localization_arg = 'False' + else: + # 使用 AMCL + localization_arg = 'True' + + # Nav2 启动 - 使用正确的路径 + nav2_launch_path = os.path.join(nav2_bringup_dir, 'launch', 'bringup_launch.py') + if not os.path.exists(nav2_launch_path): + print(f"错误: 找不到 Nav2 启动文件: {nav2_launch_path}") + return ld + + nav2_bringup_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource(nav2_launch_path), + launch_arguments={ + 'map': map_yaml_path, + 'use_sim_time': use_sim_time, + 'params_file': nav2_param_path, + 'slam': slam, + 'localization': localization_arg, + 'autostart': 'True', + }.items(), + ) + + ld.add_action(nav2_bringup_launch) + + return ld \ No newline at end of file diff --git a/src/cyy_navigation2/maps/cyy_map.data b/src/cyy_navigation2/maps/cyy_map.data new file mode 100644 index 0000000..f1ee3aa Binary files /dev/null and b/src/cyy_navigation2/maps/cyy_map.data differ diff --git a/src/cyy_navigation2/maps/cyy_map.pgm b/src/cyy_navigation2/maps/cyy_map.pgm new file mode 100644 index 0000000..294e35a Binary files /dev/null and b/src/cyy_navigation2/maps/cyy_map.pgm differ diff --git a/src/cyy_navigation2/maps/cyy_map.yaml b/src/cyy_navigation2/maps/cyy_map.yaml new file mode 100644 index 0000000..8d57c8b --- /dev/null +++ b/src/cyy_navigation2/maps/cyy_map.yaml @@ -0,0 +1,7 @@ +image: cyy_map.pgm +mode: trinary +resolution: 0.01 +origin: [-2.27, -1.63, 0] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.25 \ No newline at end of file diff --git a/src/cyy_navigation2/maps/cyy_map1.pgm b/src/cyy_navigation2/maps/cyy_map1.pgm new file mode 100644 index 0000000..c1da83d Binary files /dev/null and b/src/cyy_navigation2/maps/cyy_map1.pgm differ diff --git a/src/cyy_navigation2/maps/cyy_map1.yaml b/src/cyy_navigation2/maps/cyy_map1.yaml new file mode 100644 index 0000000..097f099 --- /dev/null +++ b/src/cyy_navigation2/maps/cyy_map1.yaml @@ -0,0 +1,7 @@ +image: cyy_map1.pgm +mode: trinary +resolution: 0.01 +origin: [-3.49, -3.24, 0] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.25 \ No newline at end of file diff --git a/src/cyy_navigation2/package.xml b/src/cyy_navigation2/package.xml new file mode 100644 index 0000000..8d7370f --- /dev/null +++ b/src/cyy_navigation2/package.xml @@ -0,0 +1,20 @@ + + + + cyy_navigation2 + 0.0.0 + TODO: Package description + root + TODO: License declaration + + ament_cmake + + nav2_bringup + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/src/cyy_navigation2/param/nav2_params.yaml b/src/cyy_navigation2/param/nav2_params.yaml new file mode 100644 index 0000000..02c388c --- /dev/null +++ b/src/cyy_navigation2/param/nav2_params.yaml @@ -0,0 +1,353 @@ +amcl: + ros__parameters: + enabled: False + use_sim_time: True + alpha1: 0.2 + alpha2: 0.2 + alpha3: 0.2 + alpha4: 0.2 + alpha5: 0.2 + base_frame_id: "base_link" + beam_skip_distance: 0.5 + beam_skip_error_threshold: 0.9 + beam_skip_threshold: 0.3 + do_beamskip: false + global_frame_id: "map" + lambda_short: 0.1 + laser_likelihood_max_dist: 2.0 + laser_max_range: 100.0 + laser_min_range: -1.0 + laser_model_type: "likelihood_field" + max_beams: 60 + max_particles: 2000 + min_particles: 500 + odom_frame_id: "odom" + pf_err: 0.05 + pf_z: 0.99 + recovery_alpha_fast: 0.0 + recovery_alpha_slow: 0.0 + resample_interval: 1 + robot_model_type: "nav2_amcl::DifferentialMotionModel" + save_pose_rate: 0.5 + sigma_hit: 0.2 + tf_broadcast: true + transform_tolerance: 1.0 + update_min_a: 0.2 + update_min_d: 0.25 + z_hit: 0.5 + z_max: 0.05 + z_rand: 0.5 + z_short: 0.05 + scan_topic: scan + +bt_navigator: + ros__parameters: + use_sim_time: True + global_frame: map + robot_base_frame: base_link + odom_topic: /odom + bt_loop_duration: 10 + default_server_timeout: 20 + wait_for_service_timeout: 1000 + # 'default_nav_through_poses_bt_xml' and 'default_nav_to_pose_bt_xml' are use defaults: + # nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml + # nav2_bt_navigator/navigate_through_poses_w_replanning_and_recovery.xml + # They can be set here or via a RewrittenYaml remap from a parent launch file to Nav2. + plugin_lib_names: + - nav2_compute_path_to_pose_action_bt_node + - nav2_compute_path_through_poses_action_bt_node + - nav2_smooth_path_action_bt_node + - nav2_follow_path_action_bt_node + - nav2_spin_action_bt_node + - nav2_wait_action_bt_node + - nav2_assisted_teleop_action_bt_node + - nav2_back_up_action_bt_node + - nav2_drive_on_heading_bt_node + - nav2_clear_costmap_service_bt_node + - nav2_is_stuck_condition_bt_node + - nav2_goal_reached_condition_bt_node + - nav2_goal_updated_condition_bt_node + - nav2_globally_updated_goal_condition_bt_node + - nav2_is_path_valid_condition_bt_node + - nav2_initial_pose_received_condition_bt_node + - nav2_reinitialize_global_localization_service_bt_node + - nav2_rate_controller_bt_node + - nav2_distance_controller_bt_node + - nav2_speed_controller_bt_node + - nav2_truncate_path_action_bt_node + - nav2_truncate_path_local_action_bt_node + - nav2_goal_updater_node_bt_node + - nav2_recovery_node_bt_node + - nav2_pipeline_sequence_bt_node + - nav2_round_robin_node_bt_node + - nav2_transform_available_condition_bt_node + - nav2_time_expired_condition_bt_node + - nav2_path_expiring_timer_condition + - nav2_distance_traveled_condition_bt_node + - nav2_single_trigger_bt_node + - nav2_goal_updated_controller_bt_node + - nav2_is_battery_low_condition_bt_node + - nav2_navigate_through_poses_action_bt_node + - nav2_navigate_to_pose_action_bt_node + - nav2_remove_passed_goals_action_bt_node + - nav2_planner_selector_bt_node + - nav2_controller_selector_bt_node + - nav2_goal_checker_selector_bt_node + - nav2_controller_cancel_bt_node + - nav2_path_longer_on_approach_bt_node + - nav2_wait_cancel_bt_node + - nav2_spin_cancel_bt_node + - nav2_back_up_cancel_bt_node + - nav2_assisted_teleop_cancel_bt_node + - nav2_drive_on_heading_cancel_bt_node + - nav2_is_battery_charging_condition_bt_node + +bt_navigator_navigate_through_poses_rclcpp_node: + ros__parameters: + use_sim_time: True + +bt_navigator_navigate_to_pose_rclcpp_node: + ros__parameters: + use_sim_time: True + +controller_server: + ros__parameters: + use_sim_time: True + controller_frequency: 20.0 + min_x_velocity_threshold: 0.001 + min_y_velocity_threshold: 0.5 + min_theta_velocity_threshold: 0.001 + failure_tolerance: 0.3 + progress_checker_plugin: "progress_checker" + goal_checker_plugins: ["general_goal_checker"] # "precise_goal_checker" + controller_plugins: ["FollowPath"] + + # Progress checker parameters + progress_checker: + plugin: "nav2_controller::SimpleProgressChecker" + required_movement_radius: 0.5 + movement_time_allowance: 10.0 + # Goal checker parameters + #precise_goal_checker: + # plugin: "nav2_controller::SimpleGoalChecker" + # xy_goal_tolerance: 0.25 + # yaw_goal_tolerance: 0.25 + # stateful: True + general_goal_checker: + stateful: True + plugin: "nav2_controller::SimpleGoalChecker" + xy_goal_tolerance: 0.25 + yaw_goal_tolerance: 6.28 + # DWB parameters + FollowPath: + plugin: "dwb_core::DWBLocalPlanner" + debug_trajectory_details: True + min_vel_x: -0.50 + min_vel_y: 0.0 + max_vel_x: 0.50 + max_vel_y: 0.0 + max_vel_theta: 1.0 + min_speed_xy: 0.0 + max_speed_xy: 0.50 + min_speed_theta: 0.0 + # Add high threshold velocity for turtlebot 3 issue. + # https://github.com/ROBOTIS-GIT/turtlebot3_simulations/issues/75 + acc_lim_x: 2.5 + acc_lim_y: 0.0 + acc_lim_theta: 3.2 + decel_lim_x: -2.5 + decel_lim_y: 0.0 + decel_lim_theta: -3.2 + vx_samples: 20 + vy_samples: 0 + vtheta_samples: 20 + sim_time: 1.7 + linear_granularity: 0.05 + angular_granularity: 0.025 + transform_tolerance: 0.2 + xy_goal_tolerance: 0.25 + trans_stopped_velocity: 0.25 + short_circuit_trajectory_evaluation: True + stateful: True + critics: ["RotateToGoal", "Oscillation", "BaseObstacle", "GoalAlign", "PathAlign", "PathDist", "GoalDist"] + BaseObstacle.scale: 0.01 + PathAlign.scale: 32.0 + PathAlign.forward_point_distance: 0.1 + GoalAlign.scale: 24.0 + GoalAlign.forward_point_distance: 0.1 + PathDist.scale: 32.0 + GoalDist.scale: 24.0 + RotateToGoal.scale: 32.0 + RotateToGoal.slowing_factor: 5.0 + RotateToGoal.lookahead_time: -1.0 + +local_costmap: + local_costmap: + ros__parameters: + update_frequency: 5.0 + publish_frequency: 2.0 + global_frame: odom + robot_base_frame: base_link + use_sim_time: True + rolling_window: true + width: 3 + height: 3 + resolution: 0.05 + footprint: "[[0.2, 0.15], [0.2, -0.15], [-0.2, -0.15], [-0.2, 0.15]]" + robot_radius: 0.00 + plugins: ["voxel_layer", "inflation_layer"] + inflation_layer: + plugin: "nav2_costmap_2d::InflationLayer" + cost_scaling_factor: 3.0 + inflation_radius: 0.10 + voxel_layer: + plugin: "nav2_costmap_2d::VoxelLayer" + enabled: True + publish_voxel_map: True + origin_z: 0.0 + z_resolution: 0.05 + z_voxels: 16 + max_obstacle_height: 2.0 + mark_threshold: 0 + observation_sources: scan + scan: + topic: /scan + max_obstacle_height: 2.0 + clearing: True + marking: True + data_type: "LaserScan" + raytrace_max_range: 3.0 + raytrace_min_range: 0.0 + obstacle_max_range: 2.5 + obstacle_min_range: 0.0 + static_layer: + plugin: "nav2_costmap_2d::StaticLayer" + map_subscribe_transient_local: True + always_send_full_costmap: True + +global_costmap: + global_costmap: + ros__parameters: + update_frequency: 1.0 + publish_frequency: 1.0 + global_frame: map + robot_base_frame: base_link + use_sim_time: True + footprint: "[[0.2, 0.15], [0.2, -0.15], [-0.2, -0.15], [-0.2, 0.15]]" + robot_radius: 0.0 + resolution: 0.05 + track_unknown_space: true + plugins: ["static_layer", "obstacle_layer", "inflation_layer"] + obstacle_layer: + plugin: "nav2_costmap_2d::ObstacleLayer" + enabled: True + observation_sources: scan + scan: + topic: /scan + max_obstacle_height: 2.0 + clearing: True + marking: True + data_type: "LaserScan" + raytrace_max_range: 3.0 + raytrace_min_range: 0.0 + obstacle_max_range: 2.5 + obstacle_min_range: 0.0 + static_layer: + plugin: "nav2_costmap_2d::StaticLayer" + map_subscribe_transient_local: True + inflation_layer: + plugin: "nav2_costmap_2d::InflationLayer" + cost_scaling_factor: 3.0 + inflation_radius: 0.30 + always_send_full_costmap: True + +map_server: + ros__parameters: + use_sim_time: True + # Overridden in launch by the "map" launch configuration or provided default value. + # To use in yaml, remove the default "map" value in the tb3_simulation_launch.py file & provide full path to map below. + yaml_filename: "" + +map_saver: + ros__parameters: + use_sim_time: True + save_map_timeout: 5.0 + free_thresh_default: 0.25 + occupied_thresh_default: 0.65 + map_subscribe_transient_local: True + +planner_server: + ros__parameters: + expected_planner_frequency: 20.0 + use_sim_time: True + planner_plugins: ["GridBased"] + GridBased: + plugin: "nav2_navfn_planner/NavfnPlanner" + tolerance: 0.5 + use_astar: false + allow_unknown: true + +smoother_server: + ros__parameters: + use_sim_time: True + smoother_plugins: ["simple_smoother"] + simple_smoother: + plugin: "nav2_smoother::SimpleSmoother" + tolerance: 1.0e-10 + max_its: 1000 + do_refinement: True + +behavior_server: + ros__parameters: + costmap_topic: local_costmap/costmap_raw + footprint_topic: local_costmap/published_footprint + cycle_frequency: 10.0 + behavior_plugins: ["spin", "backup", "drive_on_heading", "assisted_teleop", "wait"] + spin: + plugin: "nav2_behaviors/Spin" + backup: + plugin: "nav2_behaviors/BackUp" + drive_on_heading: + plugin: "nav2_behaviors/DriveOnHeading" + wait: + plugin: "nav2_behaviors/Wait" + assisted_teleop: + plugin: "nav2_behaviors/AssistedTeleop" + global_frame: odom + robot_base_frame: base_link + transform_tolerance: 0.3 + use_sim_time: true + simulate_ahead_time: 2.0 + max_rotational_vel: 1.0 + min_rotational_vel: 0.4 + rotational_acc_lim: 3.2 + +robot_state_publisher: + ros__parameters: + use_sim_time: True + +waypoint_follower: + ros__parameters: + use_sim_time: True + loop_rate: 20 + stop_on_failure: false + waypoint_task_executor_plugin: "wait_at_waypoint" + wait_at_waypoint: + plugin: "nav2_waypoint_follower::WaitAtWaypoint" + enabled: True + waypoint_pause_duration: 200 + +velocity_smoother: + ros__parameters: + use_sim_time: True + smoothing_frequency: 20.0 + scale_velocities: False + feedback: "OPEN_LOOP" + max_velocity: [0.26, 0.0, 1.0] + min_velocity: [-0.26, 0.0, -1.0] + max_accel: [2.5, 0.0, 3.2] + max_decel: [-2.5, 0.0, -3.2] + odom_topic: "odom" + odom_duration: 0.1 + deadband_velocity: [0.0, 0.0, 0.0] + velocity_timeout: 1.0 diff --git a/src/cyy_navigation2/param/slam_toolbox_localization.yaml b/src/cyy_navigation2/param/slam_toolbox_localization.yaml new file mode 100644 index 0000000..cd751e1 --- /dev/null +++ b/src/cyy_navigation2/param/slam_toolbox_localization.yaml @@ -0,0 +1,54 @@ +slam_toolbox: + ros__parameters: + # 核心模式设置 + mode: "localization" # 重要:设置为定位模式 + map_file_name: "" # 由启动参数传入 + map_start_pose: [0.0, 0.0, 0.0] + # ROS框架设置 + odom_frame: "odom" + map_frame: "map" + base_frame: "base_link" + scan_topic: "/scan" + + # 求解器设置 + solver_plugin: "solver_plugins::CeresSolver" + ceres_linear_solver: "SPARSE_NORMAL_CHOLESKY" + ceres_preconditioner: "SCHUR_JACOBI" + ceres_trust_strategy: "LEVENBERG_MARQUARDT" + ceres_dogleg_type: "TRADITIONAL_DOGLEG" + ceres_loss_function: "None" + + # 定位优化参数 + use_scan_matching: true + use_scan_barycenter: true + minimum_travel_distance: 0.05 + minimum_travel_heading: 0.087 + + # 扫描处理 + scan_buffer_size: 20 + throttle_scans: 1 + + # 回环检测(定位模式可关闭) + do_loop_closing: false + + # 搜索参数 + link_match_minimum_response_fine: 0.2 + link_scan_maximum_distance: 2.0 + loop_search_maximum_distance: 5.0 + + # 性能参数 + minimum_time_interval: 0.1 + transform_publish_period: 0.02 + map_update_interval: 0.5 + + # 地图参数 + resolution: 0.05 + max_laser_range: 15.0 + min_laser_range: 0.2 + + # 初始位姿(可选,可以通过RViz设置) + # map_start_pose: [0.0, 0.0, 0.0] + + # 调试 + debug_logging: false + enable_interactive_mode: true \ No newline at end of file diff --git a/src/cyy_slamtoolbox/CMakeLists.txt b/src/cyy_slamtoolbox/CMakeLists.txt new file mode 100644 index 0000000..305da3e --- /dev/null +++ b/src/cyy_slamtoolbox/CMakeLists.txt @@ -0,0 +1,61 @@ +# 设置CMake最低版本要求 +cmake_minimum_required(VERSION 3.8) +# 定义项目名称(应与package.xml中的一致) +project(cyy_slamtoolbox) + +# 如果未设置,默认使用C++17标准 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 17) +endif() + +# 查找编译依赖 +find_package(ament_cmake REQUIRED) +# 查找slam_toolbox包 +find_package(slam_toolbox REQUIRED) +# 查找其他可能的依赖,如传感器消息、几何库等 +find_package(rclcpp REQUIRED) +find_package(std_msgs REQUIRED) +find_package(sensor_msgs REQUIRED) +find_package(nav_msgs REQUIRED) +find_package(tf2 REQUIRED) +find_package(tf2_ros REQUIRED) +find_package(geometry_msgs REQUIRED) + +# 消息输出,用于调试 +message(STATUS "开始配置项目: ${PROJECT_NAME}") + +# 包含头文件目录 +include_directories( + include + ${ament_INCLUDE_DIRS} +) + +# 如果有自定义的C++节点源文件,在此添加可执行文件 +# 例如,如果您有自定义的SLAM处理节点: +# add_executable(origincar_slam_node src/origincar_slam_node.cpp) +# ament_target_dependencies(origincar_slam_node +# rclcpp std_msgs sensor_msgs nav_msgs tf2 tf2_ros geometry_msgs slam_toolbox) +# +# 安装目标(将可执行文件安装到lib/) +# install(TARGETS origincar_slam_node +# DESTINATION lib/${PROJECT_NAME}) + +# 安装launch文件到share//launch目录 +install(DIRECTORY launch + DESTINATION share/${PROJECT_NAME} + PATTERN "*.py" +) + +# 安装配置文件(如YAML参数文件)到share//config目录 +install(DIRECTORY config + DESTINATION share/${PROJECT_NAME} + PATTERN "*.yaml" + PATTERN "*.yml" +) + + +# 声明ament包依赖关系(确保在package.xml中已声明这些依赖) +ament_export_dependencies(slam_toolbox rclcpp std_msgs sensor_msgs nav_msgs tf2 tf2_ros geometry_msgs) + +# 必须调用此函数来生成必要的CMake配置 +ament_package() \ No newline at end of file diff --git a/src/cyy_slamtoolbox/config/angular_filter_example.yaml b/src/cyy_slamtoolbox/config/angular_filter_example.yaml new file mode 100644 index 0000000..26ef078 --- /dev/null +++ b/src/cyy_slamtoolbox/config/angular_filter_example.yaml @@ -0,0 +1,9 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: angle + type: laser_filters/LaserScanAngularBoundsFilter + params: + lower_angle: -1.52 + upper_angle: 1.52 + \ No newline at end of file diff --git a/src/cyy_slamtoolbox/config/box_filter_example.yaml b/src/cyy_slamtoolbox/config/box_filter_example.yaml new file mode 100644 index 0000000..ae63991 --- /dev/null +++ b/src/cyy_slamtoolbox/config/box_filter_example.yaml @@ -0,0 +1,15 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: box_filter + type: laser_filters/LaserScanBoxFilter + params: + box_frame: base_link + max_x: 0.5 + max_y: 0.5 + max_z: 0.5 + min_x: -0.5 + min_y: -0.5 + min_z: -0.5 + + invert: false # activate to remove all points outside of the box diff --git a/src/cyy_slamtoolbox/config/footprint_filter_example.yaml b/src/cyy_slamtoolbox/config/footprint_filter_example.yaml new file mode 100644 index 0000000..aa3ae16 --- /dev/null +++ b/src/cyy_slamtoolbox/config/footprint_filter_example.yaml @@ -0,0 +1,7 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: footprint_filter + type: laser_filters/LaserScanFootprintFilter + params: + inscribed_radius: 0.325 diff --git a/src/cyy_slamtoolbox/config/intensity_filter_example.yaml b/src/cyy_slamtoolbox/config/intensity_filter_example.yaml new file mode 100644 index 0000000..05d0827 --- /dev/null +++ b/src/cyy_slamtoolbox/config/intensity_filter_example.yaml @@ -0,0 +1,9 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: intensity + type: laser_filters/LaserScanIntensityFilter + params: + lower_threshold: 8000. + upper_threshold: 100000. + disp_histogram: 0 diff --git a/src/cyy_slamtoolbox/config/laser_filter_config.yaml b/src/cyy_slamtoolbox/config/laser_filter_config.yaml new file mode 100644 index 0000000..05730e4 --- /dev/null +++ b/src/cyy_slamtoolbox/config/laser_filter_config.yaml @@ -0,0 +1,19 @@ +scan_filter_chain: + - name: angle_bounds + type: laser_filters/LaserScanAngularBoundsFilter + params: + # 示例:如果您只想处理前方180度的数据,可以设置为: + lower_angle: -1.57 # 约-90度 + upper_angle: 1.57 # 约90度 + + - name: range_filter + type: laser_filters/LaserScanRangeFilter + params: + # 过滤掉无效的距离值,这对于SLAM非常重要 + lower_threshold: 0.2 # 忽略小于0.2米的测量(如雷达自身的噪声) + upper_threshold: 20.0 # 忽略大于20.0米的测量(通常是不稳定的数据) + use_message_range_limits: false + + - name: interpolation + type: laser_filters/InterpolationFilter + # 此滤波器没有参数,它会自动对因过滤产生的无效值(如NaN)进行插值修复[1](@ref) \ No newline at end of file diff --git a/src/cyy_slamtoolbox/config/mapper_params_lifelong.yaml b/src/cyy_slamtoolbox/config/mapper_params_lifelong.yaml new file mode 100644 index 0000000..fe39dc2 --- /dev/null +++ b/src/cyy_slamtoolbox/config/mapper_params_lifelong.yaml @@ -0,0 +1,87 @@ + +slam_toolbox: + ros__parameters: + + # Plugin params + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_footprint + scan_topic: /scan + use_map_saver: true + mode: mapping + + # lifelong params + lifelong_search_use_tree: false + lifelong_minimum_score: 0.1 + lifelong_iou_match: 0.85 + lifelong_node_removal_score: 0.04 + lifelong_overlap_score_scale: 0.06 + lifelong_constraint_multiplier: 0.08 + lifelong_nearby_penalty: 0.001 + lifelong_candidates_scale: 0.03 + + # if you'd like to immediately start continuing a map at a given pose + # or at the dock, but they are mutually exclusive, if pose is given + # will use pose + #map_file_name: test_steve + #map_start_pose: [0.0, 0.0, 0.0] + #map_start_at_dock: true + + debug_logging: false + throttle_scans: 1 + transform_publish_period: 0.02 #if 0 never publishes odometry + map_update_interval: 5.0 + resolution: 0.05 + min_laser_range: 0.0 #for rastering images + max_laser_range: 20.0 #for rastering images + minimum_time_interval: 0.5 + transform_timeout: 0.2 + tf_buffer_duration: 10. + stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps + + # General Parameters + use_scan_matching: true + use_scan_barycenter: true + minimum_travel_distance: 0.5 + minimum_travel_heading: 0.5 + scan_buffer_size: 10 + scan_buffer_maximum_scan_distance: 10.0 + link_match_minimum_response_fine: 0.1 + link_scan_maximum_distance: 1.5 + loop_search_maximum_distance: 3.0 + do_loop_closing: true + loop_match_minimum_chain_size: 10 + loop_match_maximum_variance_coarse: 3.0 + loop_match_minimum_response_coarse: 0.35 + loop_match_minimum_response_fine: 0.45 + + # Correlation Parameters - Correlation Parameters + correlation_search_space_dimension: 0.5 + correlation_search_space_resolution: 0.01 + correlation_search_space_smear_deviation: 0.1 + + # Correlation Parameters - Loop Closure Parameters + loop_search_space_dimension: 8.0 + loop_search_space_resolution: 0.05 + loop_search_space_smear_deviation: 0.03 + + # Scan Matcher Parameters + distance_variance_penalty: 0.5 + angle_variance_penalty: 1.0 + + fine_search_angle_offset: 0.00349 + coarse_search_angle_offset: 0.349 + coarse_angle_resolution: 0.0349 + minimum_angle_penalty: 0.9 + minimum_distance_penalty: 0.5 + use_response_expansion: true + min_pass_through: 2 + occupancy_threshold: 0.1 diff --git a/src/cyy_slamtoolbox/config/mapper_params_localization.yaml b/src/cyy_slamtoolbox/config/mapper_params_localization.yaml new file mode 100644 index 0000000..176f2e2 --- /dev/null +++ b/src/cyy_slamtoolbox/config/mapper_params_localization.yaml @@ -0,0 +1,70 @@ +slam_toolbox: + ros__parameters: + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_link + scan_topic: /scan + mode: localization #localization + + # if you'd like to start localizing on bringup in a map and pose + #map_file_name: test_steve + #map_start_pose: [5.0, 1.0, 0.0] + + debug_logging: false + throttle_scans: 1 + transform_publish_period: 0.02 #if 0 never publishes odometry + map_update_interval: 5.0 + resolution: 0.05 + min_laser_range: 0.0 #for rastering images + max_laser_range: 20.0 #for rastering images + minimum_time_interval: 0.5 + transform_timeout: 0.2 + tf_buffer_duration: 30. + stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps + + # General Parameters + use_scan_matching: true + use_scan_barycenter: true + minimum_travel_distance: 0.5 + minimum_travel_heading: 0.5 + scan_buffer_size: 3 + scan_buffer_maximum_scan_distance: 10.0 + link_match_minimum_response_fine: 0.1 + link_scan_maximum_distance: 1.5 + do_loop_closing: true + loop_match_minimum_chain_size: 3 + loop_match_maximum_variance_coarse: 3.0 + loop_match_minimum_response_coarse: 0.35 + loop_match_minimum_response_fine: 0.45 + + # Correlation Parameters - Correlation Parameters + correlation_search_space_dimension: 0.5 + correlation_search_space_resolution: 0.01 + correlation_search_space_smear_deviation: 0.1 + + # Correlation Parameters - Loop Closure Parameters + loop_search_space_dimension: 8.0 + loop_search_space_resolution: 0.05 + loop_search_space_smear_deviation: 0.03 + loop_search_maximum_distance: 3.0 + + # Scan Matcher Parameters + distance_variance_penalty: 0.5 + angle_variance_penalty: 1.0 + + fine_search_angle_offset: 0.00349 + coarse_search_angle_offset: 0.349 + coarse_angle_resolution: 0.0349 + minimum_angle_penalty: 0.9 + minimum_distance_penalty: 0.5 + use_response_expansion: true + min_pass_through: 2 + occupancy_threshold: 0.1 diff --git a/src/cyy_slamtoolbox/config/mapper_params_offline.yaml b/src/cyy_slamtoolbox/config/mapper_params_offline.yaml new file mode 100644 index 0000000..d7d8587 --- /dev/null +++ b/src/cyy_slamtoolbox/config/mapper_params_offline.yaml @@ -0,0 +1,69 @@ +slam_toolbox: + ros__parameters: + + # Plugin params + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_footprint + scan_topic: /scan + use_map_saver: true + mode: mapping #localization + debug_logging: false + throttle_scans: 1 + transform_publish_period: 0.02 #if 0 never publishes odometry + map_update_interval: 10.0 + resolution: 0.05 + min_laser_range: 0.0 #for rastering images + max_laser_range: 20.0 #for rastering images + minimum_time_interval: 0.5 + transform_timeout: 0.2 + tf_buffer_duration: 14400. + stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps + enable_interactive_mode: true + + # General Parameters + use_scan_matching: true + use_scan_barycenter: true + minimum_travel_distance: 0.5 + minimum_travel_heading: 0.5 + scan_buffer_size: 10 + scan_buffer_maximum_scan_distance: 10.0 + link_match_minimum_response_fine: 0.1 + link_scan_maximum_distance: 1.5 + loop_search_maximum_distance: 3.0 + do_loop_closing: true + loop_match_minimum_chain_size: 10 + loop_match_maximum_variance_coarse: 3.0 + loop_match_minimum_response_coarse: 0.35 + loop_match_minimum_response_fine: 0.45 + + # Correlation Parameters - Correlation Parameters + correlation_search_space_dimension: 0.5 + correlation_search_space_resolution: 0.01 + correlation_search_space_smear_deviation: 0.1 + + # Correlation Parameters - Loop Closure Parameters + loop_search_space_dimension: 8.0 + loop_search_space_resolution: 0.05 + loop_search_space_smear_deviation: 0.03 + + # Scan Matcher Parameters + distance_variance_penalty: 0.5 + angle_variance_penalty: 1.0 + + fine_search_angle_offset: 0.00349 + coarse_search_angle_offset: 0.349 + coarse_angle_resolution: 0.0349 + minimum_angle_penalty: 0.9 + minimum_distance_penalty: 0.5 + use_response_expansion: true + min_pass_through: 2 + occupancy_threshold: 0.1 diff --git a/src/cyy_slamtoolbox/config/mapper_params_online_async.yaml b/src/cyy_slamtoolbox/config/mapper_params_online_async.yaml new file mode 100644 index 0000000..8a392d5 --- /dev/null +++ b/src/cyy_slamtoolbox/config/mapper_params_online_async.yaml @@ -0,0 +1,78 @@ +slam_toolbox: + ros__parameters: + + # Plugin params + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_link + scan_topic: /scan + use_map_saver: true + mode: mapping #localization + samples: 440 + # if you'd like to immediately start continuing a map at a given pose + # or at the dock, but they are mutually exclusive, if pose is given + # will use pose + #map_file_name: test_steve + # map_start_pose: [0.0, 0.0, 0.0] + #map_start_at_dock: true + + debug_logging: false + throttle_scans: 5 + transform_publish_period: 0.02 #if 0 never publishes odometry + map_update_interval: 0.01 + resolution: 0.01 + min_laser_range: 0.21 #for rastering images + max_laser_range: 15.0 #for rastering images + minimum_time_interval: 0.1 + transform_timeout: 2.0 + tf_buffer_duration: 30. + stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps + enable_interactive_mode: true + + # General Parameters + use_scan_matching: true + use_scan_barycenter: true + minimum_travel_distance: 0.2 + minimum_travel_heading: 0.2 + scan_buffer_size: 10 + samples: 440 + scan_buffer_maximum_scan_distance: 10.0 + link_match_minimum_response_fine: 0.1 + link_scan_maximum_distance: 1.5 + loop_search_maximum_distance: 3.0 + do_loop_closing: true + loop_match_minimum_chain_size: 10 + loop_match_maximum_variance_coarse: 3.0 + loop_match_minimum_response_coarse: 0.35 + loop_match_minimum_response_fine: 0.45 + + # Correlation Parameters - Correlation Parameters + correlation_search_space_dimension: 0.5 + correlation_search_space_resolution: 0.05 + correlation_search_space_smear_deviation: 0.1 + + # Correlation Parameters - Loop Closure Parameters + loop_search_space_dimension: 8.0 + loop_search_space_resolution: 0.05 + loop_search_space_smear_deviation: 0.03 + + # Scan Matcher Parameters + distance_variance_penalty: 0.5 + angle_variance_penalty: 1.0 + + fine_search_angle_offset: 0.00349 + coarse_search_angle_offset: 0.349 + coarse_angle_resolution: 0.0349 + minimum_angle_penalty: 0.9 + minimum_distance_penalty: 0.5 + use_response_expansion: true + min_pass_through: 2 + occupancy_threshold: 0.1 diff --git a/src/cyy_slamtoolbox/config/mapper_params_online_sync.yaml b/src/cyy_slamtoolbox/config/mapper_params_online_sync.yaml new file mode 100644 index 0000000..4ccc68c --- /dev/null +++ b/src/cyy_slamtoolbox/config/mapper_params_online_sync.yaml @@ -0,0 +1,77 @@ +slam_toolbox: + ros__parameters: + + # Plugin params + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_footprint + scan_topic: /scan + use_map_saver: true + mode: mapping #localization + + # if you'd like to immediately start continuing a map at a given pose + # or at the dock, but they are mutually exclusive, if pose is given + # will use pose + #map_file_name: test_steve + #map_start_pose: [0.0, 0.0, 0.0] + #map_start_at_dock: true + + debug_logging: false + throttle_scans: 1 + transform_publish_period: 0.02 #if 0 never publishes odometry + map_update_interval: 5.0 + resolution: 0.05 + min_laser_range: 0.0 #for rastering images + max_laser_range: 20.0 #for rastering images + minimum_time_interval: 0.5 + transform_timeout: 0.2 + tf_buffer_duration: 30. + stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps + enable_interactive_mode: true + + # General Parameters + use_scan_matching: true + use_scan_barycenter: true + minimum_travel_distance: 0.5 + minimum_travel_heading: 0.5 + scan_buffer_size: 10 + scan_buffer_maximum_scan_distance: 10.0 + link_match_minimum_response_fine: 0.1 + link_scan_maximum_distance: 1.5 + loop_search_maximum_distance: 3.0 + do_loop_closing: true + loop_match_minimum_chain_size: 10 + loop_match_maximum_variance_coarse: 3.0 + loop_match_minimum_response_coarse: 0.35 + loop_match_minimum_response_fine: 0.45 + + # Correlation Parameters - Correlation Parameters + correlation_search_space_dimension: 0.5 + correlation_search_space_resolution: 0.01 + correlation_search_space_smear_deviation: 0.1 + + # Correlation Parameters - Loop Closure Parameters + loop_search_space_dimension: 8.0 + loop_search_space_resolution: 0.05 + loop_search_space_smear_deviation: 0.03 + + # Scan Matcher Parameters + distance_variance_penalty: 0.5 + angle_variance_penalty: 1.0 + + fine_search_angle_offset: 0.00349 + coarse_search_angle_offset: 0.349 + coarse_angle_resolution: 0.0349 + minimum_angle_penalty: 0.9 + minimum_distance_penalty: 0.5 + use_response_expansion: true + min_pass_through: 2 + occupancy_threshold: 0.1 diff --git a/src/cyy_slamtoolbox/config/mask_filter_example.yaml b/src/cyy_slamtoolbox/config/mask_filter_example.yaml new file mode 100644 index 0000000..17751d1 --- /dev/null +++ b/src/cyy_slamtoolbox/config/mask_filter_example.yaml @@ -0,0 +1,16 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: mask + type: laser_filters/LaserScanMaskFilter + params: + masks: + laser: + - 100. + - 101. + - 102. + - 103. + - 104. + - 1000. + - 1001. + - 1002. diff --git a/src/cyy_slamtoolbox/config/median_filter_example.yaml b/src/cyy_slamtoolbox/config/median_filter_example.yaml new file mode 100644 index 0000000..ea6c447 --- /dev/null +++ b/src/cyy_slamtoolbox/config/median_filter_example.yaml @@ -0,0 +1,20 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + type: laser_filters/LaserArrayFilter + name: median + params: + range_filter_chain: + filter1: + name: median + type: filters/MultiChannelMedianFilterFloat + params: + number_of_observations: 5 + unused: 10 + intensity_filter_chain: + filter1: + name: median + type: filters/MultiChannelMedianFilterFloat + params: + number_of_observations: 5 + unused: 10 diff --git a/src/cyy_slamtoolbox/config/median_spatial_filter_example.yaml b/src/cyy_slamtoolbox/config/median_spatial_filter_example.yaml new file mode 100644 index 0000000..bbe95e0 --- /dev/null +++ b/src/cyy_slamtoolbox/config/median_spatial_filter_example.yaml @@ -0,0 +1,17 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: median_spatial + type: laser_filters/LaserScanMedianSpatialFilter + params: + window_size: 31 + filter2: + name: median_filter + type: laser_filters/LaserArrayFilter + params: + range_filter_chain: + filter1: + name: median + type: filters/MultiChannelMedianFilterFloat + params: + number_of_observations: 3 \ No newline at end of file diff --git a/src/cyy_slamtoolbox/config/multiple_filters_example.yaml b/src/cyy_slamtoolbox/config/multiple_filters_example.yaml new file mode 100644 index 0000000..e992449 --- /dev/null +++ b/src/cyy_slamtoolbox/config/multiple_filters_example.yaml @@ -0,0 +1,42 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + type: laser_filters/LaserArrayFilter + name: laser_median_5 + params: + range_filter_chain: + filter1: + name: median_5 + type: filters/MultiChannelMedianFilterFloat + params: + number_of_observations: 5 + unused: 10 + intensity_filter_chain: + filter2: + name: median_5 + type: filters/MultiChannelMedianFilterFloat + params: + number_of_observations: 5 + unused: 10 + filter2: + name: intensity + type: laser_filters/LaserScanIntensityFilter + params: + lower_threshold: 8000. + upper_threshold: 100000. + disp_histogram: 0 + filter3: + name: shadows + type: laser_filters/ScanShadowsFilter + params: + min_angle: 10. + max_angle: 170. + neighbors: 20 + window: 0 + filter4: + name: dark_shadows + type: laser_filters/LaserScanIntensityFilter + params: + lower_threshold: 100. + upper_threshold: 10000. + disp_histogram: 0 diff --git a/src/cyy_slamtoolbox/config/pass_through_example.yaml b/src/cyy_slamtoolbox/config/pass_through_example.yaml new file mode 100644 index 0000000..e69de29 diff --git a/src/cyy_slamtoolbox/config/polygon_filter_example.yaml b/src/cyy_slamtoolbox/config/polygon_filter_example.yaml new file mode 100644 index 0000000..90bf7d9 --- /dev/null +++ b/src/cyy_slamtoolbox/config/polygon_filter_example.yaml @@ -0,0 +1,10 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: polygon_filter + type: laser_filters/LaserScanPolygonFilter + params: + polygon_frame: base_link + polygon: '[[0.0, 0.0], [0.1, 0.1], [0.1, 0.0], [0.0, -0.1]]' + invert: false + footprint_topic: base_footprint_exclude diff --git a/src/cyy_slamtoolbox/config/range_filter_example.yaml b/src/cyy_slamtoolbox/config/range_filter_example.yaml new file mode 100644 index 0000000..27869ed --- /dev/null +++ b/src/cyy_slamtoolbox/config/range_filter_example.yaml @@ -0,0 +1,11 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: box_filter + type: laser_filters/LaserScanRangeFilter + params: + use_message_range_limits: false # if not specified defaults to false + lower_threshold: 0.5 # if not specified defaults to 0.0 + upper_threshold: 1.0 # if not specified defaults to 100000.0 + lower_replacement_value: -.inf # if not specified defaults to NaN + upper_replacement_value: .inf # if not specified defaults to NaN diff --git a/src/cyy_slamtoolbox/config/scan_blob_filter_example.yaml b/src/cyy_slamtoolbox/config/scan_blob_filter_example.yaml new file mode 100644 index 0000000..eb9f4ab --- /dev/null +++ b/src/cyy_slamtoolbox/config/scan_blob_filter_example.yaml @@ -0,0 +1,8 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: scan_blob_filter + type: laser_filters/ScanBlobFilter + params: + max_radius: 0.25 # maximum radius to be considered as blob object + min_points: 6 # min scan points to be considered as blob object diff --git a/src/cyy_slamtoolbox/config/sector_filter_example.yaml b/src/cyy_slamtoolbox/config/sector_filter_example.yaml new file mode 100644 index 0000000..e278235 --- /dev/null +++ b/src/cyy_slamtoolbox/config/sector_filter_example.yaml @@ -0,0 +1,12 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: scan_filter + type: laser_filters/LaserScanSectorFilter + params: + angle_min: 2.54 # if not specified defaults to 0.0 + angle_max: -2.54 # if not specified defaults to 0.0 + range_min: 0.2 # if not specified defaults to 0.0 + range_max: 2.0 # if not specified defaults to 100000.0 + clear_inside: true # if not specified defaults to true + invert: false # (!clear_inside) if not specified defaults to false diff --git a/src/cyy_slamtoolbox/config/shadow_filter_example.yaml b/src/cyy_slamtoolbox/config/shadow_filter_example.yaml new file mode 100644 index 0000000..82504fe --- /dev/null +++ b/src/cyy_slamtoolbox/config/shadow_filter_example.yaml @@ -0,0 +1,18 @@ +scan_to_scan_filter_chain: + ros__parameters: + filter1: + name: shadows + type: laser_filters/ScanShadowsFilter + params: + min_angle: 10. + max_angle: 170. + neighbors: 20 + window: 1 + filter2: + name: dark_shadows + type: laser_filters/LaserScanIntensityFilter + params: + lower_threshold: 100. + upper_threshold: 10000. + disp_histogram: 0 + diff --git a/src/cyy_slamtoolbox/config/slam_toolbox_default.rviz b/src/cyy_slamtoolbox/config/slam_toolbox_default.rviz new file mode 100644 index 0000000..c079a07 --- /dev/null +++ b/src/cyy_slamtoolbox/config/slam_toolbox_default.rviz @@ -0,0 +1,137 @@ +Panels: + - Class: rviz_common/Displays + Help Height: 78 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Status1 + Splitter Ratio: 0.5 + Tree Height: 154 + - Class: rviz_common/Selection + Name: Selection + - Class: rviz_common/Tool Properties + Expanded: + - /2D Goal Pose1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz_common/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 + - Class: rviz_common/Time + Experimental: false + Name: Time + SyncMode: 0 + SyncSource: "" + - Class: slam_toolbox::SlamToolboxPlugin + Name: SlamToolboxPlugin +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz_default_plugins/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: + Value: true + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Fixed Frame: map + Frame Rate: 30 + Name: root + Tools: + - Class: rviz_default_plugins/Interact + Hide Inactive Objects: true + - Class: rviz_default_plugins/MoveCamera + - Class: rviz_default_plugins/Select + - Class: rviz_default_plugins/FocusCamera + - Class: rviz_default_plugins/Measure + Line color: 128; 128; 0 + - Class: rviz_default_plugins/SetInitialPose + Covariance x: 0.25 + Covariance y: 0.25 + Covariance yaw: 0.06853891909122467 + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /initialpose + - Class: rviz_default_plugins/SetGoal + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /goal_pose + - Class: rviz_default_plugins/PublishPoint + Single click: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /clicked_point + Transformation: + Current: + Class: rviz_default_plugins/TF + Value: true + Views: + Current: + Class: rviz_default_plugins/Orbit + Distance: 10 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Focal Point: + X: 0 + Y: 0 + Z: 0 + Focal Shape Fixed Size: true + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.785398006439209 + Target Frame: + Value: Orbit (rviz) + Yaw: 0.785398006439209 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 846 + Hide Left Dock: false + Hide Right Dock: false + QMainWindow State: 000000ff00000000fd000000040000000000000217000002b0fc0200000009fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d00000125000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261fb000000220053006c0061006d0054006f006f006c0062006f00780050006c007500670069006e0100000168000001850000018500ffffff000000010000010f000002b0fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000002b0000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004b00000003efc0100000002fb0000000800540069006d00650100000000000004b0000002eb00fffffffb0000000800540069006d006501000000000000045000000000000000000000017e000002b000000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + SlamToolboxPlugin: + collapsed: false + Time: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 1200 + X: 72 + Y: 60 diff --git a/src/cyy_slamtoolbox/config/speckle_filter_example.yaml b/src/cyy_slamtoolbox/config/speckle_filter_example.yaml new file mode 100644 index 0000000..6f8c6a7 --- /dev/null +++ b/src/cyy_slamtoolbox/config/speckle_filter_example.yaml @@ -0,0 +1,19 @@ +scan_filter_chain: +- name: speckle_filter + type: laser_filters/LaserScanSpeckleFilter + params: + # Select which filter type to use. + # 0: Range based filtering (distance between consecutive points) + # 1: Euclidean filtering based on radius outlier search + filter_type: 0 + + # Only ranges smaller than this range are taken into account + max_range: 2.0 + + # filter_type[0] (Distance): max distance between consecutive points + # filter_type[1] (RadiusOutlier): max distance between points + max_range_difference: 0.1 + + # filter_type[0] (Distance): Number of consecutive ranges that will be tested for max_distance + # filter_type[1] (RadiusOutlier): Minimum number of neighbors + filter_window: 2 diff --git a/src/cyy_slamtoolbox/launch/cyy_slam_toolbox_launch.launch.py b/src/cyy_slamtoolbox/launch/cyy_slam_toolbox_launch.launch.py new file mode 100644 index 0000000..aa4ff01 --- /dev/null +++ b/src/cyy_slamtoolbox/launch/cyy_slam_toolbox_launch.launch.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +from launch import LaunchDescription +from launch_ros.actions import Node +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + # 获取参数文件路径 + pkg_share = get_package_share_directory('cyy_slamtoolbox') + params_file = os.path.join(pkg_share, 'config', 'mapper_params_online_async.yaml') + + # 创建SLAM Toolbox节点 + slam_toolbox_node = Node( + package='slam_toolbox', + executable='async_slam_toolbox_node', # 或 sync_slam_toolbox_node + name='slam_toolbox', + output='screen', + parameters=[params_file] + ) + + + return LaunchDescription([ + slam_toolbox_node + ]) \ No newline at end of file diff --git a/src/cyy_slamtoolbox/launch/cyy_slam_toolbox_location.launch.py b/src/cyy_slamtoolbox/launch/cyy_slam_toolbox_location.launch.py new file mode 100644 index 0000000..c8c784a --- /dev/null +++ b/src/cyy_slamtoolbox/launch/cyy_slam_toolbox_location.launch.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +from launch import LaunchDescription +from launch_ros.actions import Node +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + # ȡļ· + pkg_share = get_package_share_directory('cyy_slamtoolbox') + params_file = os.path.join(pkg_share, 'config', 'mapper_params_localization.yaml') + + # SLAM Toolboxڵ + slam_toolbox_node = Node( + package='slam_toolbox', + executable='localization_slam_toolbox_node', # sync_slam_toolbox_node + name='slam_toolbox', + output='screen', + parameters=[params_file] + ) + + + return LaunchDescription([ + slam_toolbox_node + ]) \ No newline at end of file diff --git a/src/cyy_slamtoolbox/launch/filter.launch.py b/src/cyy_slamtoolbox/launch/filter.launch.py new file mode 100644 index 0000000..19f7450 --- /dev/null +++ b/src/cyy_slamtoolbox/launch/filter.launch.py @@ -0,0 +1,24 @@ +from launch import LaunchDescription +from launch_ros.actions import Node +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + # 假设配置文件路径,你需要根据实际情况修改 + config_path = os.path.join( + get_package_share_directory('cyy_slamtoolbox'), + 'config', + 'angular_filter_example.yaml' + ) + + laser_filter_node = Node( + package='laser_filters', + executable='scan_to_scan_filter_chain', + name='laser_filter', + output='screen', + parameters=[config_path], + # 重新映射话题:从/base_scan原始数据过滤后发布到/scan + remappings=[('scan', '/base_scan'), ('scan_filtered', '/scan')] + ) + + return LaunchDescription([laser_filter_node]) \ No newline at end of file diff --git a/src/cyy_slamtoolbox/package.xml b/src/cyy_slamtoolbox/package.xml new file mode 100644 index 0000000..18ae51b --- /dev/null +++ b/src/cyy_slamtoolbox/package.xml @@ -0,0 +1,18 @@ + + + + cyy_slamtoolbox + 0.0.0 + TODO: Package description + root + TODO: License declaration + + ament_cmake + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/src/gc_navigation_fish/CMakeLists.txt b/src/gc_navigation_fish/CMakeLists.txt new file mode 100644 index 0000000..21e4ee1 --- /dev/null +++ b/src/gc_navigation_fish/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.8) +project(gc_navigation_fish) + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) +install( + DIRECTORY launch param maps + DESTINATION share/${PROJECT_NAME} +) +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # comment the line when a copyright and license is added to all source files + set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # comment the line when this package is in a git repo and when + # a copyright and license is added to all source files + set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/src/gc_navigation_fish/launch/gc_navigation.launch.py b/src/gc_navigation_fish/launch/gc_navigation.launch.py new file mode 100644 index 0000000..2419737 --- /dev/null +++ b/src/gc_navigation_fish/launch/gc_navigation.launch.py @@ -0,0 +1,34 @@ +import os +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + + +def generate_launch_description(): + # =============================1.定位到包的地址============================================================= + gc_navigation_fish_dir = get_package_share_directory( + 'gc_navigation_fish') + nav2_bringup_dir = get_package_share_directory('nav2_bringup') + + # =============================2.声明参数,获取配置文件路径=================================================== + # use_sim_time 这里要设置成true,因为gazebo是仿真环境,其时间是通过/clock话题获取,而不是系统时间 + use_sim_time = LaunchConfiguration('use_sim_time', default='false') + map_yaml_path = LaunchConfiguration('map', default=os.path.join( + gc_navigation_fish_dir, 'maps', 'test_map.yaml')) + nav2_param_path = LaunchConfiguration('params_file', default=os.path.join( + gc_navigation_fish_dir, 'param', 'gc_navigation.yaml')) + # =============================3.声明启动launch文件,传入:地图路径、是否使用仿真时间以及nav2参数文件============== + nav2_bringup_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + [nav2_bringup_dir, '/launch', '/bringup_launch.py']), + launch_arguments={ + 'map': map_yaml_path, + 'use_sim_time': use_sim_time, + 'params_file': nav2_param_path}.items(), + ) + + + return LaunchDescription([nav2_bringup_launch]) diff --git a/src/gc_navigation_fish/maps/test_map.pgm b/src/gc_navigation_fish/maps/test_map.pgm new file mode 100644 index 0000000..079a090 Binary files /dev/null and b/src/gc_navigation_fish/maps/test_map.pgm differ diff --git a/src/gc_navigation_fish/maps/test_map.yaml b/src/gc_navigation_fish/maps/test_map.yaml new file mode 100644 index 0000000..2d524cd --- /dev/null +++ b/src/gc_navigation_fish/maps/test_map.yaml @@ -0,0 +1,7 @@ +image: test_map.pgm +mode: trinary +resolution: 0.05 +origin: [-2.03, -6.12, 0] +negate: 0 +occupied_thresh: 0.65 +free_thresh: 0.25 \ No newline at end of file diff --git a/src/gc_navigation_fish/package.xml b/src/gc_navigation_fish/package.xml new file mode 100644 index 0000000..f54f961 --- /dev/null +++ b/src/gc_navigation_fish/package.xml @@ -0,0 +1,18 @@ + + + + gc_navigation_fish + 0.0.0 + TODO: Package description + guoch + TODO: License declaration + + ament_cmake + + ament_lint_auto + ament_lint_common + nav2_bringup + + ament_cmake + + diff --git a/src/gc_navigation_fish/param/gc_navigation.yaml b/src/gc_navigation_fish/param/gc_navigation.yaml new file mode 100644 index 0000000..0b6f53a --- /dev/null +++ b/src/gc_navigation_fish/param/gc_navigation.yaml @@ -0,0 +1,408 @@ +amcl: + ros__parameters: + use_sim_time: False + alpha1: 0.2 + alpha2: 0.2 + alpha3: 0.2 + alpha4: 0.2 + alpha5: 0.2 + base_frame_id: "base_link" + beam_skip_distance: 0.5 + beam_skip_error_threshold: 0.9 + beam_skip_threshold: 0.3 + do_beamskip: false + global_frame_id: "map" + lambda_short: 0.1 + laser_likelihood_max_dist: 2.0 + laser_max_range: 100.0 + laser_min_range: -1.0 + laser_model_type: "likelihood_field" + max_beams: 60 + max_particles: 2000 + min_particles: 500 + odom_frame_id: "odom" + pf_err: 0.05 + pf_z: 0.99 + recovery_alpha_fast: 0.0 + recovery_alpha_slow: 0.0 + resample_interval: 1 + robot_model_type: "nav2_amcl::DifferentialMotionModel" + save_pose_rate: 0.5 + sigma_hit: 0.2 + tf_broadcast: true + transform_tolerance: 10.0 + update_min_a: 0.2 + update_min_d: 0.25 + z_hit: 0.5 + z_max: 0.05 + z_rand: 0.5 + z_short: 0.05 + scan_topic: scan + +amcl_map_client: + ros__parameters: + use_sim_time: False + +amcl_rclcpp_node: + ros__parameters: + use_sim_time: False + +bt_navigator: + ros__parameters: + use_sim_time: False + global_frame: map + robot_base_frame: base_link + odom_topic: /odom + bt_loop_duration: 10 + default_server_timeout: 20 + # 'default_nav_through_poses_bt_xml' and 'default_nav_to_pose_bt_xml' are use defaults: + # nav2_bt_navigator/navigate_to_pose_w_replanning_and_recovery.xml + # nav2_bt_navigator/navigate_through_poses_w_replanning_and_recovery.xml + # They can be set here or via a RewrittenYaml remap from a parent launch file to Nav2. + plugin_lib_names: + - nav2_compute_path_to_pose_action_bt_node + - nav2_compute_path_through_poses_action_bt_node + - nav2_smooth_path_action_bt_node + - nav2_follow_path_action_bt_node + - nav2_spin_action_bt_node + - nav2_wait_action_bt_node + - nav2_back_up_action_bt_node + - nav2_drive_on_heading_bt_node + - nav2_clear_costmap_service_bt_node + - nav2_is_stuck_condition_bt_node + - nav2_goal_reached_condition_bt_node + - nav2_goal_updated_condition_bt_node + - nav2_globally_updated_goal_condition_bt_node + - nav2_is_path_valid_condition_bt_node + - nav2_initial_pose_received_condition_bt_node + - nav2_reinitialize_global_localization_service_bt_node + - nav2_rate_controller_bt_node + - nav2_distance_controller_bt_node + - nav2_speed_controller_bt_node + - nav2_truncate_path_action_bt_node + - nav2_truncate_path_local_action_bt_node + - nav2_goal_updater_node_bt_node + - nav2_recovery_node_bt_node + - nav2_pipeline_sequence_bt_node + - nav2_round_robin_node_bt_node + - nav2_transform_available_condition_bt_node + - nav2_time_expired_condition_bt_node + - nav2_path_expiring_timer_condition + - nav2_distance_traveled_condition_bt_node + - nav2_single_trigger_bt_node + - nav2_is_battery_low_condition_bt_node + - nav2_navigate_through_poses_action_bt_node + - nav2_navigate_to_pose_action_bt_node + - nav2_remove_passed_goals_action_bt_node + - nav2_planner_selector_bt_node + - nav2_controller_selector_bt_node + - nav2_goal_checker_selector_bt_node + - nav2_controller_cancel_bt_node + - nav2_path_longer_on_approach_bt_node + - nav2_wait_cancel_bt_node + - nav2_spin_cancel_bt_node + - nav2_back_up_cancel_bt_node + - nav2_drive_on_heading_cancel_bt_node + +bt_navigator_rclcpp_node: + ros__parameters: + use_sim_time: False + +controller_server: + ros__parameters: + controller_frequency: 30.0 + FollowPath: + plugin: "nav2_mppi_controller::MPPIController" + time_steps: 56 + model_dt: 0.05 + batch_size: 2000 + vx_std: 0.2 + vy_std: 0.0 + wz_std: 0.4 + vx_max: 0.5 + vx_min: -0.35 + vy_max: 0.0 + wz_max: 1.9 + iteration_count: 1 + temperature: 0.3 + gamma: 0.015 + motion_model: "Ackermann" + visualize: false + TrajectoryVisualizer: + trajectory_step: 5 + time_step: 3 + AckermannConstraints: + min_turning_r: 0.4 + critics: ["ConstraintCritic", "CostCritic", "GoalCritic", "GoalAngleCritic", "PathAlignCritic", "PathFollowCritic", "PathAngleCritic", "PreferForwardCritic"] + ConstraintCritic: + enabled: true + cost_power: 1 + cost_weight: 4.0 + GoalCritic: + enabled: true + cost_power: 1 + cost_weight: 5.0 + threshold_to_consider: 1.4 + GoalAngleCritic: + enabled: true + cost_power: 1 + cost_weight: 3.0 + threshold_to_consider: 0.5 + PreferForwardCritic: + enabled: true + cost_power: 1 + cost_weight: 5.0 + threshold_to_consider: 0.5 + # Option to replace Cost and use Obstacles instead + # ObstaclesCritic: + # enabled: true + # cost_power: 1 + # repulsion_weight: 1.5 + # critical_weight: 20.0 + # consider_footprint: false + # collision_cost: 10000.0 + # collision_margin_distance: 0.1 + # near_goal_distance: 0.5 + CostCritic: + enabled: true + cost_power: 1 + cost_weight: 3.81 + critical_cost: 300.0 + consider_footprint: true + collision_cost: 1000000.0 + near_goal_distance: 1.0 + trajectory_point_step: 2 + PathAlignCritic: + enabled: true + cost_power: 1 + cost_weight: 14.0 + max_path_occupancy_ratio: 0.05 + trajectory_point_step: 4 + threshold_to_consider: 0.5 + offset_from_furthest: 20 + use_path_orientations: false + PathFollowCritic: + enabled: true + cost_power: 1 + cost_weight: 5.0 + offset_from_furthest: 5 + threshold_to_consider: 1.4 + PathAngleCritic: + enabled: true + cost_power: 1 + cost_weight: 2.0 + offset_from_furthest: 4 + threshold_to_consider: 0.5 + max_angle_to_furthest: 1.0 + forward_preference: true + # VelocityDeadbandCritic: + # enabled: true + # cost_power: 1 + # cost_weight: 35.0 + # deadband_velocities: [0.05, 0.05, 0.05] + # TwirlingCritic: + # enabled: true + # twirling_cost_power: 1 + # twirling_cost_weight: 10.0 + +controller_server_rclcpp_node: + ros__parameters: + use_sim_time: False + +local_costmap: + local_costmap: + ros__parameters: + update_frequency: 5.0 + publish_frequency: 2.0 + global_frame: odom + robot_base_frame: base_link + use_sim_time: False + rolling_window: true + width: 3 + height: 3 + resolution: 0.05 + footprint: "[[0.14, 0.085], + [0.14, -0.085], + [-0.14, -0.085], + [-0.14, 0.085]]" + footprint_padding: 0.02 + plugins: ["voxel_layer", "inflation_layer"] + inflation_layer: + plugin: "nav2_costmap_2d::InflationLayer" + cost_scaling_factor: 3.0 + inflation_radius: 0.55 + voxel_layer: + plugin: "nav2_costmap_2d::VoxelLayer" + enabled: True + publish_voxel_map: True + origin_z: 0.0 + z_resolution: 0.05 + z_voxels: 16 + max_obstacle_height: 2.0 + mark_threshold: 0 + observation_sources: scan + scan: + topic: /scan + max_obstacle_height: 2.0 + clearing: True + marking: True + data_type: "LaserScan" + raytrace_max_range: 3.0 + raytrace_min_range: 0.0 + obstacle_max_range: 2.5 + obstacle_min_range: 0.0 + static_layer: + map_subscribe_transient_local: True + always_send_full_costmap: True + local_costmap_client: + ros__parameters: + use_sim_time: False + local_costmap_rclcpp_node: + ros__parameters: + use_sim_time: False + +global_costmap: + global_costmap: + ros__parameters: + update_frequency: 1.0 + publish_frequency: 1.0 + global_frame: map + robot_base_frame: base_link + use_sim_time: False + footprint: "[[0.14, 0.085], + [0.14, -0.085], + [-0.14, -0.085], + [-0.14, 0.085]]" + footprint_padding: 0.02 + resolution: 0.05 + track_unknown_space: true + plugins: ["static_layer", "obstacle_layer", "inflation_layer"] + obstacle_layer: + plugin: "nav2_costmap_2d::ObstacleLayer" + enabled: True + observation_sources: scan + scan: + topic: /scan + max_obstacle_height: 2.0 + clearing: True + marking: True + data_type: "LaserScan" + raytrace_max_range: 3.0 + raytrace_min_range: 0.0 + obstacle_max_range: 2.5 + obstacle_min_range: 0.0 + static_layer: + plugin: "nav2_costmap_2d::StaticLayer" + map_subscribe_transient_local: True + inflation_layer: + plugin: "nav2_costmap_2d::InflationLayer" + cost_scaling_factor: 3.0 + inflation_radius: 0.55 + always_send_full_costmap: True + global_costmap_client: + ros__parameters: + use_sim_time: False + global_costmap_rclcpp_node: + ros__parameters: + use_sim_time: False + +map_server: + ros__parameters: + use_sim_time: False + yaml_filename: "turtlebot3_world.yaml" + +map_saver: + ros__parameters: + use_sim_time: False + save_map_timeout: 5.0 + free_thresh_default: 0.25 + occupied_thresh_default: 0.65 + map_subscribe_transient_local: True + +planner_server: + ros__parameters: + planner_plugins: ["GridBased"] + use_sim_time: False + + GridBased: + plugin: "nav2_smac_planner/SmacPlannerHybrid" + downsample_costmap: false # whether or not to downsample the map + downsampling_factor: 1 # multiplier for the resolution of the costmap layer (e.g. 2 on a 5cm costmap would be 10cm) + tolerance: 0.25 # dist-to-goal heuristic cost (distance) for valid tolerance endpoints if exact goal cannot be found. + allow_unknown: true # allow traveling in unknown space + max_iterations: 1000000 # maximum total iterations to search for before failing (in case unreachable), set to -1 to disable + max_on_approach_iterations: 1000 # Maximum number of iterations after within tolerances to continue to try to find exact solution + max_planning_time: 5.0 # max time in s for planner to plan, smooth + motion_model_for_search: "REEDS_SHEPP" # or REEDS_SHEPP 可以倒车 + angle_quantization_bins: 72 # Number of angle bins for search + analytic_expansion_ratio: 3.5 # The ratio to attempt analytic expansions during search for final approach. + analytic_expansion_max_length: 3.0 # For Hybrid/Lattice nodes: The maximum length of the analytic expansion to be considered valid to prevent unsafe shortcutting + minimum_turning_radius: 0.40 # minimum turning radius in m of path / vehicle + reverse_penalty: 2.0 # Penalty to apply if motion is reversing, must be => 1 + change_penalty: 0.0 # Penalty to apply if motion is changing directions (L to R), must be >= 0 + non_straight_penalty: 1.2 # Penalty to apply if motion is non-straight, must be => 1 + cost_penalty: 2.0 # Penalty to apply to higher cost areas when adding into the obstacle map dynamic programming distance expansion heuristic. This drives the robot more towards the center of passages. A value between 1.3 - 3.5 is reasonable. + retrospective_penalty: 0.015 + lookup_table_size: 20.0 # Size of the dubin/reeds-sheep distance window to cache, in meters. + cache_obstacle_heuristic: false # Cache the obstacle map dynamic programming distance expansion heuristic between subsiquent replannings of the same goal location. Dramatically speeds up replanning performance (40x) if costmap is largely static. + viz_expansions: false # For Hybrid nodes: Whether to publish expansions on the /expansions topic as an array of poses (the orientation has no meaning). WARNING: heavy to compute and to display, for debug only as it degrades the performance. + smooth_path: True # If true, does a simple and quick smoothing post-processing to the path + + smoother: + max_iterations: 1000 + w_smooth: 0.3 + w_data: 0.2 + tolerance: 1.0e-10 + do_refinement: true + refinement_num: 2 + +planner_server_rclcpp_node: + ros__parameters: + use_sim_time: False + +smoother_server: + ros__parameters: + use_sim_time: False + smoother_plugins: ["simple_smoother"] + simple_smoother: + plugin: "nav2_smoother::SimpleSmoother" + tolerance: 1.0e-10 + max_its: 1000 + do_refinement: True + +behavior_server: + ros__parameters: + costmap_topic: local_costmap/costmap_raw + footprint_topic: local_costmap/published_footprint + cycle_frequency: 10.0 + behavior_plugins: ["spin", "backup", "drive_on_heading", "wait"] + spin: + plugin: "nav2_behaviors/Spin" + backup: + plugin: "nav2_behaviors/BackUp" + drive_on_heading: + plugin: "nav2_behaviors/DriveOnHeading" + wait: + plugin: "nav2_behaviors/Wait" + global_frame: odom + robot_base_frame: base_link + transform_tolerance: 0.1 + use_sim_time: False + simulate_ahead_time: 2.0 + max_rotational_vel: 1.0 + min_rotational_vel: 0.4 + rotational_acc_lim: 3.2 + +robot_state_publisher: + ros__parameters: + use_sim_time: False + +waypoint_follower: + ros__parameters: + loop_rate: 20 + stop_on_failure: false + waypoint_task_executor_plugin: "wait_at_waypoint" + wait_at_waypoint: + plugin: "nav2_waypoint_follower::WaitAtWaypoint" + enabled: True + waypoint_pause_duration: 200 diff --git a/src/gc_navigation_fish/param/navigation_test.yaml b/src/gc_navigation_fish/param/navigation_test.yaml new file mode 100644 index 0000000..86160da --- /dev/null +++ b/src/gc_navigation_fish/param/navigation_test.yaml @@ -0,0 +1,173 @@ +# ========================= +# 🚫 删除 amcl(SLAM模式不需要) +# ========================= +# ❌ 已移除 amcl 整块 +# ❌ 已移除 amcl_map_client +# ❌ 已移除 amcl_rclcpp_node + + +# ========================= +# 🚫 删除 map_server(由 slam_toolbox 提供 map) +# ========================= +# ❌ 已移除 map_server +# ❌ 已移除 map_saver + + +# ========================= +# BT Navigator +# ========================= +bt_navigator: + ros__parameters: + use_sim_time: false # ✅ 改为 false(真车) + global_frame: map + robot_base_frame: base_link + odom_topic: /odom + bt_loop_duration: 10 + default_server_timeout: 20 + plugin_lib_names: + - nav2_compute_path_to_pose_action_bt_node + - nav2_follow_path_action_bt_node + - nav2_goal_reached_condition_bt_node + - nav2_initial_pose_received_condition_bt_node + - nav2_is_path_valid_condition_bt_node + - nav2_navigate_to_pose_action_bt_node + +bt_navigator_rclcpp_node: + ros__parameters: + use_sim_time: false # ✅ 改为 false + + +# ========================= +# Controller Server(保持你的MPPI) +# ========================= +controller_server: + ros__parameters: + use_sim_time: false # ✅ 改为 false + controller_frequency: 30.0 + controller_plugins: ["FollowPath"] # ✅ 确保声明插件 + + FollowPath: + plugin: "nav2_mppi_controller::MPPIController" + motion_model: "Ackermann" + time_steps: 56 + model_dt: 0.05 + batch_size: 2000 + vx_max: 0.5 + vx_min: -0.35 + wz_max: 1.9 + +controller_server_rclcpp_node: + ros__parameters: + use_sim_time: false # ✅ 改为 false + + +# ========================= +# Planner Server(Smac Hybrid A*) +# ========================= +planner_server: + ros__parameters: + use_sim_time: false # ✅ 改为 false + planner_plugins: ["GridBased"] + + GridBased: + plugin: "nav2_smac_planner/SmacPlannerHybrid" + motion_model_for_search: "REEDS_SHEPP" + minimum_turning_radius: 0.40 + allow_unknown: true + +planner_server_rclcpp_node: + ros__parameters: + use_sim_time: false # ✅ 改为 false + + +# ========================= +# Local Costmap +# ========================= +local_costmap: + local_costmap: + ros__parameters: + use_sim_time: false # ✅ 改为 false + global_frame: odom + robot_base_frame: base_link + rolling_window: true + width: 3 + height: 3 + resolution: 0.05 + plugins: ["voxel_layer", "inflation_layer"] + + voxel_layer: + plugin: "nav2_costmap_2d::VoxelLayer" + observation_sources: scan + scan: + topic: /scan + data_type: "LaserScan" + marking: true + clearing: true + + inflation_layer: + plugin: "nav2_costmap_2d::InflationLayer" + inflation_radius: 0.55 + + local_costmap_rclcpp_node: + ros__parameters: + use_sim_time: false # ✅ 改为 false + + +# ========================= +# Global Costmap +# ========================= +global_costmap: + global_costmap: + ros__parameters: + use_sim_time: false # ✅ 改为 false + global_frame: map + robot_base_frame: base_link + resolution: 0.05 + track_unknown_space: true + plugins: ["obstacle_layer", "inflation_layer"] # ✅ 删除 static_layer(SLAM模式不需要) + + obstacle_layer: + plugin: "nav2_costmap_2d::ObstacleLayer" + observation_sources: scan + scan: + topic: /scan + data_type: "LaserScan" + marking: true + clearing: true + + inflation_layer: + plugin: "nav2_costmap_2d::InflationLayer" + inflation_radius: 0.55 + + global_costmap_rclcpp_node: + ros__parameters: + use_sim_time: false # ✅ 改为 false + + +# ========================= +# Behavior Server +# ========================= +behavior_server: + ros__parameters: + use_sim_time: false # ✅ 改为 false + global_frame: odom + robot_base_frame: base_link + behavior_plugins: ["spin", "backup", "drive_on_heading", "wait"] + + spin: + plugin: "nav2_behaviors/Spin" + backup: + plugin: "nav2_behaviors/BackUp" + drive_on_heading: + plugin: "nav2_behaviors/DriveOnHeading" + wait: + plugin: "nav2_behaviors/Wait" + + +# ========================= +# Waypoint Follower +# ========================= +waypoint_follower: + ros__parameters: + use_sim_time: false # ✅ 改为 false + loop_rate: 20 \ No newline at end of file diff --git a/src/gc_slam_toolbox_fish/CMakeLists.txt b/src/gc_slam_toolbox_fish/CMakeLists.txt new file mode 100644 index 0000000..262d40e --- /dev/null +++ b/src/gc_slam_toolbox_fish/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.8) +project(gc_slam_toolbox_fish) + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) +install( + DIRECTORY config launch rviz + DESTINATION share/${PROJECT_NAME} +) +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # comment the line when a copyright and license is added to all source files + set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # comment the line when this package is in a git repo and when + # a copyright and license is added to all source files + set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/src/gc_slam_toolbox_fish/config/gc_2d.lua b/src/gc_slam_toolbox_fish/config/gc_2d.lua new file mode 100644 index 0000000..329a2ee --- /dev/null +++ b/src/gc_slam_toolbox_fish/config/gc_2d.lua @@ -0,0 +1,63 @@ +include "map_builder.lua" +include "trajectory_builder.lua" + +options = { + map_builder = MAP_BUILDER, + trajectory_builder = TRAJECTORY_BUILDER, + map_frame = "map", + tracking_frame = "base_link", + -- base_link改为odom,发布map到odom之间的位姿态 + published_frame = "odom", + odom_frame = "odom", + -- true改为false,不用提供里程计数据 + provide_odom_frame = false, + -- false改为true,仅发布2D位资 + publish_frame_projected_to_2d = true, + -- false改为true,使用里程计数据 + use_odometry = true, + use_nav_sat = false, + use_landmarks = false, + -- 0改为1,使用一个雷达 + num_laser_scans = 1, + -- 1改为0,不使用多波雷达 + num_multi_echo_laser_scans = 0, + -- 10改为1,1/1=1等于不分割 + num_subdivisions_per_laser_scan = 1, + num_point_clouds = 0, + lookup_transform_timeout_sec = 0.2, + submap_publish_period_sec = 0.3, + pose_publish_period_sec = 5e-3, + trajectory_publish_period_sec = 30e-3, + rangefinder_sampling_ratio = 1., + odometry_sampling_ratio = 1., + fixed_frame_pose_sampling_ratio = 1., + imu_sampling_ratio = 1., + landmarks_sampling_ratio = 1., +} + + +-- false改为true,启动2D SLAM +MAP_BUILDER.use_trajectory_builder_2d = true + +-- 0改成0.10,比机器人半径小的都忽略 +TRAJECTORY_BUILDER_2D.min_range = 0.10 +-- 30改成3.5,限制在雷达最大扫描范围内,越小一般越精确些 +TRAJECTORY_BUILDER_2D.max_range = 3.5 +-- 5改成3,传感器数据超出有效范围最大值 +TRAJECTORY_BUILDER_2D.missing_data_ray_length = 3. +-- true改成false,不使用IMU数据,大家可以开启,然后对比下效果 +TRAJECTORY_BUILDER_2D.use_imu_data = false +-- false改成true,使用实时回环检测来进行前端的扫描匹配 +TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true +-- 1.0改成0.1,提高对运动的敏感度 +TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians = math.rad(0.1) + +-- 0.55改成0.65,Fast csm的最低分数,高于此分数才进行优化。 +POSE_GRAPH.constraint_builder.min_score = 0.65 +--0.6改成0.7,全局定位最小分数,低于此分数则认为目前全局定位不准确 +POSE_GRAPH.constraint_builder.global_localization_min_score = 0.7 + +-- 设置0可关闭全局SLAM +-- POSE_GRAPH.optimize_every_n_nodes = 0 + +return options diff --git a/src/gc_slam_toolbox_fish/launch/catograph.launch.py b/src/gc_slam_toolbox_fish/launch/catograph.launch.py new file mode 100644 index 0000000..ff51eec --- /dev/null +++ b/src/gc_slam_toolbox_fish/launch/catograph.launch.py @@ -0,0 +1,63 @@ + +import os +from launch import LaunchDescription +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node +from launch_ros.substitutions import FindPackageShare + + +def generate_launch_description(): + # 定位到功能包的地址 + pkg_share = FindPackageShare( + package='gc_slam_toolbox_fish').find('gc_slam_toolbox_fish') + + # =====================运行节点需要的配置======================================================================= + # 是否使用仿真时间,我们用gazebo,这里设置成true + use_sim_time = LaunchConfiguration('use_sim_time', default='true') + # 地图的分辨率 + resolution = LaunchConfiguration('resolution', default='0.05') + # 地图的发布周期 + publish_period_sec = LaunchConfiguration( + 'publish_period_sec', default='1.0') + # 配置文件夹路径 + configuration_directory = LaunchConfiguration( + 'configuration_directory', default=os.path.join(pkg_share, 'config')) + # 配置文件 + configuration_basename = LaunchConfiguration( + 'configuration_basename', default='gc_2d.lua') + rviz_config_dir = os.path.join(pkg_share, 'config')+"/cartographer.rviz" + print(f"rviz config in {rviz_config_dir}") + + # =====================声明三个节点,cartographer/occupancy_grid_node/rviz_node================================= + cartographer_node = Node( + package='cartographer_ros', + executable='cartographer_node', + name='cartographer_node', + output='screen', + parameters=[{'use_sim_time': use_sim_time}], + arguments=['-configuration_directory', configuration_directory, + '-configuration_basename', configuration_basename]) + + cartographer_occupancy_grid_node = Node( + package='cartographer_ros', + executable='cartographer_occupancy_grid_node', + name='cartographer_occupancy_grid_node', + output='screen', + parameters=[{'use_sim_time': use_sim_time}], + arguments=['-resolution', resolution, '-publish_period_sec', publish_period_sec]) + + rviz_node = Node( + package='rviz2', + executable='rviz2', + name='rviz2', + arguments=['-d', rviz_config_dir], + parameters=[{'use_sim_time': use_sim_time}], + output='screen') + + # ===============================================定义启动文件======================================================== + ld = LaunchDescription() + ld.add_action(cartographer_node) + ld.add_action(cartographer_occupancy_grid_node) + # ld.add_action(rviz_node) + + return ld diff --git a/src/gc_slam_toolbox_fish/package.xml b/src/gc_slam_toolbox_fish/package.xml new file mode 100644 index 0000000..81a27f4 --- /dev/null +++ b/src/gc_slam_toolbox_fish/package.xml @@ -0,0 +1,18 @@ + + + + gc_slam_toolbox_fish + 0.0.0 + TODO: Package description + guoch + TODO: License declaration + + ament_cmake + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/src/origincar_base/CMakeLists.txt b/src/origincar_base/CMakeLists.txt new file mode 100644 index 0000000..e02128e --- /dev/null +++ b/src/origincar_base/CMakeLists.txt @@ -0,0 +1,89 @@ +cmake_minimum_required(VERSION 3.5) +project(origincar_base) + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +#find_package(actionlib REQUIRED) +#find_package(actionlib_msgs REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(tf2_geometry_msgs REQUIRED) + +find_package(nav2_msgs REQUIRED) +find_package(nav_msgs REQUIRED) +find_package(rclcpp REQUIRED) +find_package(rclpy REQUIRED) +find_package(sensor_msgs REQUIRED) +find_package(geometry_msgs REQUIRED) +find_package(std_msgs REQUIRED) +find_package(tf2 REQUIRED) +find_package(tf2_ros REQUIRED) +find_package(std_srvs REQUIRED) +find_package(std_msgs REQUIRED) +find_package(ackermann_msgs REQUIRED) # CHANGE +find_package(origincar_msg REQUIRED) # CHANGE +find_package(serial REQUIRED) +find_package(rosidl_default_generators REQUIRED) +find_package(origincar_description REQUIRED) +find_package(robot_localization REQUIRED) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) +rosidl_generate_interfaces(${PROJECT_NAME} + "msg/Position.msg" + ) +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +include_directories( + include + ${robot_localization_INCLUDE_DIRS} +) +set(origincar_base_node_SRCS + src/origincar_base.cpp + src/Quaternion_Solution.cpp +) + +add_executable(origincar_base_node src/origincar_base.cpp src/Quaternion_Solution.cpp) +ament_target_dependencies(origincar_base_node tf2_ros tf2 tf2_geometry_msgs rclcpp std_msgs geometry_msgs robot_localization nav_msgs std_srvs sensor_msgs ackermann_msgs serial origincar_msg origincar_description) + +#add_executable(testNode src/test.cpp src/Quaternion_Solution.cpp) +#ament_target_dependencies(testNode rclcpp std_msgs nav_msgs std_srvs sensor_msgs ackermann_msgs serial origincar_msg) + +install(PROGRAMS scripts/cmd_vel_to_ackermann_drive.py DESTINATION lib/${PROJECT_NAME}) + +install(TARGETS +origincar_base_node + +DESTINATION lib/${PROJECT_NAME} + ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} + RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + +install( + DIRECTORY launch config + DESTINATION share/${PROJECT_NAME} +) +ament_package() diff --git a/src/origincar_base/config/ekf.yaml b/src/origincar_base/config/ekf.yaml new file mode 100644 index 0000000..4c15af1 --- /dev/null +++ b/src/origincar_base/config/ekf.yaml @@ -0,0 +1,222 @@ +### ekf config file ### +ekf_filter_node: + ros__parameters: +# ͨóʼλ + use_pose_with_covariance_stamped: true # ͨ + pose0: /set_pose # ָ + pose0_config: [true, true, false, # ʹ x, y + false, false, true] # ʹ yaw + pose0_differential: false +# The frequency, in Hz, at which the filter will output a position estimate. Note that the filter will not begin +# computation until it receives at least one message from one of the inputs. It will then run continuously at the +# frequency specified here, regardless of whether it receives more measurements. Defaults to 30 if unspecified. + frequency: 30.0 + +# The period, in seconds, after which we consider a sensor to have timed out. In this event, we carry out a predict +# cycle on the EKF without correcting it. This parameter can be thought of as the minimum frequency with which the +# filter will generate new output. Defaults to 1 / frequency if not specified. + sensor_timeout: 2.0 + +# ekf_localization_node and ukf_localization_node both use a 3D omnidirectional motion model. If this parameter is +# set to true, no 3D information will be used in your state estimate. Use this if you are operating in a planar +# environment and want to ignore the effect of small variations in the ground plane that might otherwise be detected +# by, for example, an IMU. Defaults to false if unspecified. + two_d_mode: true + +# Use this parameter to provide an offset to the transform generated by ekf_localization_node. This can be used for +# future dating the transform, which is required for interaction with some other packages. Defaults to 0.0 if +# unspecified. + transform_time_offset: 0.0 + +# Use this parameter to provide specify how long the tf listener should wait for a transform to become available. +# Defaults to 0.0 if unspecified. + transform_timeout: 0.2 + +# If you're having trouble, try setting this to true, and then echo the /diagnostics_agg topic to see if the node is +# unhappy with any settings or data. + print_diagnostics: false + +# Debug settings. Not for the faint of heart. Outputs a ludicrous amount of information to the file specified by +# debug_out_file. I hope you like matrices! Please note that setting this to true will have strongly deleterious +# effects on the performance of the node. Defaults to false if unspecified. + debug: false + +# Defaults to "robot_localization_debug.txt" if unspecified. Please specify the full path. + debug_out_file: /path/to/debug/file.txt + +# Whether to broadcast the transformation over the /tf topic. Defaults to true if unspecified. + publish_tf: true + +# Whether to publish the acceleration state. Defaults to false if unspecified. + publish_acceleration: false + +# REP-105 (http://www.ros.org/reps/rep-0105.html) specifies four principal coordinate frames: base_link, odom, map, and +# earth. base_link is the coordinate frame that is affixed to the robot. Both odom and map are world-fixed frames. +# The robot's position in the odom frame will drift over time, but is accurate in the short term and should be +# continuous. The odom frame is therefore the best frame for executing local motion plans. The map frame, like the odom +# frame, is a world-fixed coordinate frame, and while it contains the most globally accurate position estimate for your +# robot, it is subject to discrete jumps, e.g., due to the fusion of GPS data or a correction from a map-based +# localization node. The earth frame is used to relate multiple map frames by giving them a common reference frame. +# ekf_localization_node and ukf_localization_node are not concerned with the earth frame. +# Here is how to use the following settings: +# 1. Set the map_frame, odom_frame, and base_link frames to the appropriate frame names for your system. +# 1a. If your system does not have a map_frame, just remove it, and make sure "world_frame" is set to the value of +# odom_frame. +# 2. If you are fusing continuous position data such as wheel encoder odometry, visual odometry, or IMU data, set +# "world_frame" to your odom_frame value. This is the default behavior for robot_localization's state estimation nodes. +# 3. If you are fusing global absolute position data that is subject to discrete jumps (e.g., GPS or position updates +# from landmark observations) then: +# 3a. Set your "world_frame" to your map_frame value +# 3b. MAKE SURE something else is generating the odom->base_link transform. Note that this can even be another state +# estimation node from robot_localization! However, that instance should *not* fuse the global data. + map_frame: map # Defaults to "map" if unspecified + odom_frame: odom_combined # Defaults to "odom" if unspecified + base_link_frame: base_footprint # Defaults to "base_link" if unspecified + world_frame: odom_combined # Defaults to the value of odom_frame if unspecified + +# The filter accepts an arbitrary number of inputs from each input message type (nav_msgs/Odometry, +# geometry_msgs/PoseWithCovarianceStamped, geometry_msgs/TwistWithCovarianceStamped, +# sensor_msgs/Imu). To add an input, simply append the next number in the sequence to its "base" name, e.g., odom0, +# odom1, twist0, twist1, imu0, imu1, imu2, etc. The value should be the topic name. These parameters obviously have no +# default values, and must be specified. + odom0: odom +# Each sensor reading updates some or all of the filter's state. These options give you greater control over which +# values from each measurement are fed to the filter. For example, if you have an odometry message as input, but only +# want to use its Z position value, then set the entire vector to false, except for the third entry. The order of the +# values is x, y, z, roll, pitch, yaw, vx, vy, vz, vroll, vpitch, vyaw, ax, ay, az. Note that not some message types +# do not provide some of the state variables estimated by the filter. For example, a TwistWithCovarianceStamped message +# has no pose information, so the first six values would be meaningless in that case. Each vector defaults to all false +# if unspecified, effectively making this parameter required for each sensor. + odom0_config: [true, false, false, + false, false, false, + true, true, false, + false, false, true, + false, false, false] + +# If you have high-frequency data or are running with a low frequency parameter value, then you may want to increase +# the size of the subscription queue so that more measurements are fused. + odom0_queue_size: 10 + +# [ADVANCED] Large messages in ROS can exhibit strange behavior when they arrive at a high frequency. This is a result +# of Nagle's algorithm. This option tells the ROS subscriber to use the tcpNoDelay option, which disables Nagle's +# algorithm. + odom0_nodelay: false + +# [ADVANCED] When measuring one pose variable with two sensors, a situation can arise in which both sensors under- +# report their covariances. This can lead to the filter rapidly jumping back and forth between each measurement as they +# arrive. In these cases, it often makes sense to (a) correct the measurement covariances, or (b) if velocity is also +# measured by one of the sensors, let one sensor measure pose, and the other velocity. However, doing (a) or (b) isn't +# always feasible, and so we expose the differential parameter. When differential mode is enabled, all absolute pose +# data is converted to velocity data by differentiating the absolute pose measurements. These velocities are then +# integrated as usual. NOTE: this only applies to sensors that provide pose measurements; setting differential to true +# for twist measurements has no effect. + odom0_differential: true + +# [ADVANCED] When the node starts, if this parameter is true, then the first measurement is treated as a "zero point" +# for all future measurements. While you can achieve the same effect with the differential paremeter, the key +# difference is that the relative parameter doesn't cause the measurement to be converted to a velocity before +# integrating it. If you simply want your measurements to start at 0 for a given sensor, set this to true. + odom0_relative: false + +# [ADVANCED] If your data is subject to outliers, use these threshold settings, expressed as Mahalanobis distances, to +# control how far away from the current vehicle state a sensor measurement is permitted to be. Each defaults to +# numeric_limits::max() if unspecified. It is strongly recommended that these parameters be removed if not +# required. Data is specified at the level of pose and twist variables, rather than for each variable in isolation. +# For messages that have both pose and twist data, the parameter specifies to which part of the message we are applying +# the thresholds. +# odom0_pose_rejection_threshold: 5.0 +# odom0_twist_rejection_threshold: 1.0 + + imu0: /imu/data_raw + imu0_config: [false, false, false, + false, false, true, + false, false, false, + false, false, true, + false, false, false] + + imu0_nodelay: false + imu0_differential: false + imu0_relative: true + imu0_queue_size: 10 + imu0_pose_rejection_threshold: 20.0 # Note the difference in parameter names + imu0_twist_rejection_threshold: 1.542 # + imu0_linear_acceleration_rejection_threshold: 10.0 # + +# [ADVANCED] Some IMUs automatically remove acceleration due to gravity, and others don't. If yours doesn't, please set +# this to true, and *make sure* your data conforms to REP-103, specifically, that the data is in ENU frame. + imu0_remove_gravitational_acceleration: true + +# [ADVANCED] The EKF and UKF models follow a standard predict/correct cycle. During prediction, if there is no +# acceleration reference, the velocity at time t+1 is simply predicted to be the same as the velocity at time t. During +# correction, this predicted value is fused with the measured value to produce the new velocity estimate. This can be +# problematic, as the final velocity will effectively be a weighted average of the old velocity and the new one. When +# this velocity is the integrated into a new pose, the result can be sluggish covergence. This effect is especially +# noticeable with LIDAR data during rotations. To get around it, users can try inflating the process_noise_covariance +# for the velocity variable in question, or decrease the variance of the variable in question in the measurement +# itself. In addition, users can also take advantage of the control command being issued to the robot at the time we +# make the prediction. If control is used, it will get converted into an acceleration term, which will be used during +# predicition. Note that if an acceleration measurement for the variable in question is available from one of the +# inputs, the control term will be ignored. +# Whether or not we use the control input during predicition. Defaults to false. + use_control: false +# Whether the input (assumed to be cmd_vel) is a geometry_msgs/Twist or geometry_msgs/TwistStamped message. Defaults to +# false. + stamped_control: false +# The last issued control command will be used in prediction for this period. Defaults to 0.2. + control_timeout: 0.2 +# Which velocities are being controlled. Order is vx, vy, vz, vroll, vpitch, vyaw. + control_config: [true, false, false, false, false, true] +# Places limits on how large the acceleration term will be. Should match your robot's kinematics. + acceleration_limits: [1.3, 0.0, 0.0, 0.0, 0.0, 3.4] +# Acceleration and deceleration limits are not always the same for robots. + deceleration_limits: [1.3, 0.0, 0.0, 0.0, 0.0, 4.5] +# If your robot cannot instantaneously reach its acceleration limit, the permitted change can be controlled with these +# gains + acceleration_gains: [0.8, 0.0, 0.0, 0.0, 0.0, 0.9] +# If your robot cannot instantaneously reach its deceleration limit, the permitted change can be controlled with these +# gains + deceleration_gains: [1.0, 0.0, 0.0, 0.0, 0.0, 1.0] +# [ADVANCED] The process noise covariance matrix can be difficult to tune, and can vary for each application, so it is +# exposed as a configuration parameter. This matrix represents the noise we add to the total error after each +# prediction step. The better the omnidirectional motion model matches your system, the smaller these values can be. +# However, if users find that a given variable is slow to converge, one approach is to increase the +# process_noise_covariance diagonal value for the variable in question, which will cause the filter's predicted error +# to be larger, which will cause the filter to trust the incoming measurement more during correction. The values are +# ordered as x, y, z, roll, pitch, yaw, vx, vy, vz, vroll, vpitch, vyaw, ax, ay, az. Defaults to the matrix below if +# unspecified. + process_noise_covariance: [0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.06, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.06, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.025, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.025, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.04, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.015] +# [ADVANCED] This represents the initial value for the state estimate error covariance matrix. Setting a diagonal +# value (variance) to a large value will result in rapid convergence for initial measurements of the variable in +# question. Users should take care not to use large values for variables that will not be measured directly. The values +# are ordered as x, y, z, roll, pitch, yaw, vx, vy, vz, vroll, vpitch, vyaw, ax, ay, az. Defaults to the matrix below +#if unspecified. + initial_estimate_covariance: [1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9] + diff --git a/src/origincar_base/config/imu.yaml b/src/origincar_base/config/imu.yaml new file mode 100644 index 0000000..edbf7de --- /dev/null +++ b/src/origincar_base/config/imu.yaml @@ -0,0 +1,7 @@ +imu_filter_madgwick: + ros__parameters: + fixed_frame: "base_footprint" + use_mag: false + publish_tf: false + world_frame: "enu" + orientation_stddev: 0.05 diff --git a/src/origincar_base/include/origincar_base/Quaternion_Solution.h b/src/origincar_base/include/origincar_base/Quaternion_Solution.h new file mode 100644 index 0000000..b839cec --- /dev/null +++ b/src/origincar_base/include/origincar_base/Quaternion_Solution.h @@ -0,0 +1,10 @@ + +#ifndef __QUATERNION_SOLUTION_H_ +#define __QUATERNION_SOLUTION_H_ +#include "origincar_base.h" +float InvSqrt(float number); +void Quaternion_Solution(float gx, float gy, float gz, float ax, float ay, float az); +extern volatile float q0, q1, q2, q3; +#endif + + diff --git a/src/origincar_base/include/origincar_base/origincar_base.h b/src/origincar_base/include/origincar_base/origincar_base.h new file mode 100644 index 0000000..456ce18 --- /dev/null +++ b/src/origincar_base/include/origincar_base/origincar_base.h @@ -0,0 +1,228 @@ + +#ifndef _ORIGINCAR_BASE_H_ +#define _ORIGINCAR_BASE_H_ + +#include +#include +#include "rclcpp/rclcpp.hpp" +#include "std_msgs/msg/string.hpp" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tf2_geometry_msgs/tf2_geometry_msgs.hpp" +#include "tf2/LinearMath/Transform.h" +#include "tf2/LinearMath/Quaternion.h" +#include +#include "ackermann_msgs/msg/ackermann_drive_stamped.hpp" +#include "origincar_msg/msg/data.hpp" +#include "origincar_msg/msg/sign.hpp" // 匹配信号发送 +#include +#include +using namespace std; + + +#define SEND_DATA_CHECK 1 //Send data check flag bits //发送数据校验标志位 +#define READ_DATA_CHECK 0 //Receive data to check flag bits //接收数据校验标志位 +#define FRAME_HEADER 0X7B //Frame head //帧头 +#define FRAME_TAIL 0X7D //Frame tail //帧尾 +#define RECEIVE_DATA_SIZE 24 //The length of the data sent by the lower computer //下位机发送过来的数据的长度 +#define SEND_DATA_SIZE 11 //The length of data sent by ROS to the lower machine //ROS向下位机发送的数据的长度 +#define PI 3.1415926f //PI //圆周率 + +#define GYROSCOPE_RATIO 0.00026644f + +#define ACCEl_RATIO 1671.84f + +extern sensor_msgs::msg::Imu Mpu6050; + +const double odom_pose_covariance[36] = {1e-3, 0, 0, 0, 0, 0, + 0, 1e-3, 0, 0, 0, 0, + 0, 0, 1e6, 0, 0, 0, + 0, 0, 0, 1e6, 0, 0, + 0, 0, 0, 0, 1e6, 0, + 0, 0, 0, 0, 0, 1e3 }; + +const double odom_pose_covariance2[36] = {1e-9, 0, 0, 0, 0, 0, + 0, 1e-3, 1e-9, 0, 0, 0, + 0, 0, 1e6, 0, 0, 0, + 0, 0, 0, 1e6, 0, 0, + 0, 0, 0, 0, 1e6, 0, + 0, 0, 0, 0, 0, 1e-9 }; + +const double odom_twist_covariance[36] = {1e-3, 0, 0, 0, 0, 0, + 0, 1e-3, 0, 0, 0, 0, + 0, 0, 1e6, 0, 0, 0, + 0, 0, 0, 1e6, 0, 0, + 0, 0, 0, 0, 1e6, 0, + 0, 0, 0, 0, 0, 1e3 }; + +const double odom_twist_covariance2[36] = {1e-9, 0, 0, 0, 0, 0, + 0, 1e-3, 1e-9, 0, 0, 0, + 0, 0, 1e6, 0, 0, 0, + 0, 0, 0, 1e6, 0, 0, + 0, 0, 0, 0, 1e6, 0, + 0, 0, 0, 0, 0, 1e-9} ; + +typedef struct __Vel_Pos_Data_ +{ + float X; + float Y; + float Z; + +} Vel_Pos_Data; + +typedef struct __MPU6050_DATA_ +{ + short accele_x_data; + short accele_y_data; + short accele_z_data; + short gyros_x_data; + short gyros_y_data; + short gyros_z_data; + +} MPU6050_DATA; + +typedef struct _SEND_DATA_ +{ + uint8_t tx[SEND_DATA_SIZE]; + float X_speed; + float Y_speed; + float Z_speed; + unsigned char Frame_Tail; +} SEND_DATA; + +typedef struct _RECEIVE_DATA_ +{ + uint8_t rx[RECEIVE_DATA_SIZE]; + uint8_t Flag_Stop; + unsigned char Frame_Header; + float X_speed; + float Y_speed; + float Z_speed; + float Power_Voltage; + unsigned char Frame_Tail; +} RECEIVE_DATA; + +class origincar_base : public rclcpp::Node + +{ +public: + origincar_base(); + ~origincar_base(); + void Control(); + void Publish_Odom(); + +public : + serial::Serial Stm32_Serial; + +private: + void declare_parameters(); + void get_parameters(); + + + void Cmd_Vel_Callback(const geometry_msgs::msg::Twist::SharedPtr twist_aux); + void Akm_Cmd_Vel_Callback(const ackermann_msgs::msg::AckermannDriveStamped::SharedPtr akm_ctl); + + void Publish_ImuSensor(); + void Publish_Voltage(); + auto createQuaternionMsgFromYaw(double yaw); + + bool Get_Sensor_Data(); + unsigned char Check_Sum(unsigned char Count_Number,unsigned char mode); + short IMU_Trans(uint8_t Data_High,uint8_t Data_Low); + float Odom_Trans(uint8_t Data_High,uint8_t Data_Low); + + void Sign_Switch_Callback(const std_msgs::msg::Int32::SharedPtr sign_switch); + +private: + void reset_filter() + { + auto msg = std::make_shared(); + + // 设置头信息 + msg->header.stamp = this->now(); + msg->header.frame_id = "odom_combined"; + + // 重置位姿 + msg->pose.pose.position.x = 0.54; + msg->pose.pose.position.y = 0.2; + msg->pose.pose.orientation.w = 1.0; + + // 设置关键协方差 + std::array cov = {0}; + cov[0] = 0.5; // x + cov[7] = 0.5; // y + cov[35] = 0.5; // yaw + msg->pose.covariance = cov; + + // 发布重置指令 + pose_pub_->publish(*msg); + RCLCPP_WARN(this->get_logger(), "FILTER RESET TRIGGERED!"); + } + + rclcpp::Publisher::SharedPtr pose_pub_; + rclcpp::Time _Now, _Last_Time; + float Sampling_Time; + rclcpp::Subscription::SharedPtr Cmd_Vel_Sub; + rclcpp::Subscription::SharedPtr Akm_Cmd_Vel_Sub; + + rclcpp::Publisher::SharedPtr odom_publisher; + rclcpp::Publisher::SharedPtr voltage_publisher; + rclcpp::Publisher::SharedPtr imu_publisher; + + rclcpp::Publisher::SharedPtr test_publisher; + + rclcpp::Publisher::SharedPtr robotpose_publisher; + rclcpp::Publisher::SharedPtr robotvel_publisher; + // rclcpp::Publisher::SharedPtr tf_pub_; + + std::shared_ptr tf_bro; + rclcpp::Publisher::SharedPtr tf_pub_; + rclcpp::TimerBase::SharedPtr test_timer; + + rclcpp::TimerBase::SharedPtr odom_timer; + rclcpp::TimerBase::SharedPtr imu_timer; + rclcpp::TimerBase::SharedPtr voltage_timer; + + rclcpp::TimerBase::SharedPtr robotpose_timer; + rclcpp::TimerBase::SharedPtr robotvel_timer; + + std::unique_ptr tf_broadcaster_; + + rclcpp::Subscription::SharedPtr Sign_Switch_Sub; + + string usart_port_name, robot_frame_id, gyro_frame_id, odom_frame_id, akm_cmd_vel, test; + std::string cmd_vel; + int serial_baud_rate; + RECEIVE_DATA Receive_Data; + SEND_DATA Send_Data; + + Vel_Pos_Data Robot_Pos; + Vel_Pos_Data Robot_Vel; + MPU6050_DATA Mpu6050_Data; + float Power_voltage; + size_t count_; +}; + + +#endif //_ORIGINCAR_BASE_H_ diff --git a/src/origincar_base/launch/__pycache__/testtwo.launch.cpython-38.pyc b/src/origincar_base/launch/__pycache__/testtwo.launch.cpython-38.pyc new file mode 100644 index 0000000..5150cce Binary files /dev/null and b/src/origincar_base/launch/__pycache__/testtwo.launch.cpython-38.pyc differ diff --git a/src/origincar_base/launch/base_serial.launch.py b/src/origincar_base/launch/base_serial.launch.py new file mode 100644 index 0000000..848e78d --- /dev/null +++ b/src/origincar_base/launch/base_serial.launch.py @@ -0,0 +1,47 @@ +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch.conditions import IfCondition, UnlessCondition +import launch_ros.actions + +def generate_launch_description(): + akmcar = LaunchConfiguration('akmcar', default='false') + + robot_parameters = [ + {'usart_port_name': '/dev/ttyACM0', + 'serial_baud_rate': 115200, + 'robot_frame_id': 'base_link', + 'odom_frame_id': 'odom', + 'cmd_vel': 'cmd_vel', + 'product_number': 0} + ] + + return LaunchDescription([ + DeclareLaunchArgument( + 'akmcar', + default_value='false', + description='Use simulation (Gazebo) clock if true' + ), + + launch_ros.actions.Node( + condition=IfCondition(akmcar), + package='origincar_base', + executable='origincar_base_node', + parameters=robot_parameters + [{'akm_cmd_vel': 'ackermann_cmd'}], + remappings=[('/cmd_vel', 'cmd_vel')], + ), + + launch_ros.actions.Node( + condition=IfCondition(akmcar), + package='origincar_base', + executable='cmd_vel_to_ackermann_drive.py', + name='cmd_vel_to_ackermann_drive', + ), + + launch_ros.actions.Node( + condition=UnlessCondition(akmcar), + package='origincar_base', + executable='origincar_base_node', + parameters=robot_parameters + [{'akm_cmd_vel': 'none'}], + ) + ]) diff --git a/src/origincar_base/launch/ekf.launch.py b/src/origincar_base/launch/ekf.launch.py new file mode 100644 index 0000000..51713ba --- /dev/null +++ b/src/origincar_base/launch/ekf.launch.py @@ -0,0 +1,33 @@ +#!/usr/bin/python3 + +import os +import launch +import launch_ros +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + + +def generate_launch_description(): + + package_name = 'origincar_base' + ld = launch.LaunchDescription() + pkg_share = launch_ros.substitutions.FindPackageShare(package=package_name).find(package_name) + robot_localization_file_path = os.path.join(pkg_share, 'config/ekf.yaml') + use_sim_time = LaunchConfiguration('use_sim_time') + + # Start robot localization using an Extended Kalman filter + robot_localization_node = Node( + package='robot_localization', + executable='ekf_node', + name='ekf_filter_node', + output='screen', + remappings=[("odometry/filtered", "odom_combined")], + parameters=[ + robot_localization_file_path, + {'use_sim_time': use_sim_time} + ]) + + ld.add_action(launch.actions.DeclareLaunchArgument(name='use_sim_time', default_value='false', + description='Flag to disable use_sim_time')) + ld.add_action(robot_localization_node) + return ld diff --git a/src/origincar_base/launch/origincar_bringup.launch.py b/src/origincar_base/launch/origincar_bringup.launch.py new file mode 100644 index 0000000..3d9fb0d --- /dev/null +++ b/src/origincar_base/launch/origincar_bringup.launch.py @@ -0,0 +1,90 @@ +import os +from pathlib import Path +import launch +from launch.actions import SetEnvironmentVariable +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import (DeclareLaunchArgument, GroupAction, + IncludeLaunchDescription, SetEnvironmentVariable) +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration, PythonExpression +from launch_ros.actions import PushRosNamespace +import launch_ros.actions +from launch.conditions import UnlessCondition + +def generate_launch_description(): + # Get the launch directory + bringup_dir = get_package_share_directory('origincar_base') + launch_dir = os.path.join(bringup_dir, 'launch') + ekf_config = Path(get_package_share_directory('origincar_base'), 'config', 'ekf.yaml') + imu_config = Path(get_package_share_directory('origincar_base'), 'config', 'imu.yaml') + + + carto_slam = LaunchConfiguration('carto_slam', default='false') + carto_slam_dec = DeclareLaunchArgument('carto_slam',default_value='false') + + origincar_base = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(launch_dir, 'base_serial.launch.py')), + launch_arguments={'akmcar': 'false'}.items(), + ) + + choose_car = IncludeLaunchDescription( + PythonLaunchDescriptionSource(os.path.join(launch_dir, 'robot_mode_description.launch.py')), + ) + + + base_to_link = launch_ros.actions.Node( + package='tf2_ros', + executable='static_transform_publisher', + name='base_to_link', + arguments=['0', '0', '0','0', '0','0','base_footprint','base_link'],#arguments=['0.41', '0.12', '0','0', '0','0','base_footprint','base_link'], + ) + + + base_to_gyro = launch_ros.actions.Node( + package='tf2_ros', + executable='static_transform_publisher', + name='base_to_gyro', + arguments=['0', '0', '0','0', '0','0','base_footprint','gyro_link'], + ) + + link_to_laser = launch_ros.actions.Node( + package='tf2_ros', + executable='static_transform_publisher', + name='link_to_laser', + arguments=['0', '0', '0','0', '0','0','base_link','laser'], + ) + + imu_filter_node = launch_ros.actions.Node( + package='imu_filter_madgwick', + executable='imu_filter_madgwick_node', + parameters=[imu_config] + ) + + robot_ekf = launch_ros.actions.Node( + condition=UnlessCondition(carto_slam), + package='robot_localization', + executable='ekf_node', + parameters=[ekf_config], + remappings=[("odometry/filtered", "odom_combined")] + ) + + joint_state_publisher_node = launch_ros.actions.Node( + package='joint_state_publisher', + executable='joint_state_publisher', + name='joint_state_publisher', + ) + + ld = LaunchDescription() + + ld.add_action(carto_slam_dec) + ld.add_action(origincar_base) + ld.add_action(base_to_link) + ld.add_action(base_to_gyro) + ld.add_action(joint_state_publisher_node) + ld.add_action(choose_car) + ld.add_action(imu_filter_node) + ld.add_action(robot_ekf) + + return ld + diff --git a/src/origincar_base/launch/robot_mode_description.launch.py b/src/origincar_base/launch/robot_mode_description.launch.py new file mode 100644 index 0000000..4bce9d9 --- /dev/null +++ b/src/origincar_base/launch/robot_mode_description.launch.py @@ -0,0 +1,24 @@ +import os +from pathlib import Path +import launch_ros.actions +import launch +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import (DeclareLaunchArgument, GroupAction,LogInfo, + IncludeLaunchDescription, SetEnvironmentVariable) +from launch.substitutions import LaunchConfiguration + +def generate_launch_description(): + origincar_description = GroupAction([ + launch_ros.actions.Node( + package='robot_state_publisher', + executable='robot_state_publisher', + name='robot_state_publisher', + arguments=[os.path.join(get_package_share_directory('origincar_description'),'urdf','origincar.urdf')] + ) + ]) + + ld = LaunchDescription() + + ld.add_action(origincar_description) + return ld \ No newline at end of file diff --git a/src/origincar_base/msg/Position.msg b/src/origincar_base/msg/Position.msg new file mode 100644 index 0000000..2fe2697 --- /dev/null +++ b/src/origincar_base/msg/Position.msg @@ -0,0 +1,3 @@ +float32 angle_x +float32 angle_y +float32 distance diff --git a/src/origincar_base/package.xml b/src/origincar_base/package.xml new file mode 100644 index 0000000..5e569f3 --- /dev/null +++ b/src/origincar_base/package.xml @@ -0,0 +1,44 @@ + + + + origincar_base + 0.0.0 + ROS2 origincar_base for origincar_base + ps-micro + TODO: License declaration + + ament_cmake + + ament_lint_auto + ament_lint_common + tf2_geometry_msgs + + + rosidl_default_generators + rosidl_interface_packages + tf2_geometry_msgs + + rosidl_default_runtime + ament_index_cpp + geometry_msgs + rclcpp + rclcpp_action + sensor_msgs + std_msgs + std_srvs + tf2 + tf2_ros + rclpy + serial + nav2_msgs + nav_msgs + ackermann_msgs + origincar_msg + origincar_description + robot_localization + + boost + + ament_cmake + + diff --git a/src/origincar_base/scripts/cmd_vel_to_ackermann_drive.py b/src/origincar_base/scripts/cmd_vel_to_ackermann_drive.py new file mode 100644 index 0000000..bae5266 --- /dev/null +++ b/src/origincar_base/scripts/cmd_vel_to_ackermann_drive.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +import math +import rclpy +from rclpy.node import Node +from geometry_msgs.msg import Twist +from ackermann_msgs.msg import AckermannDriveStamped +from rclpy.qos import QoSProfile + +class CmdVel2AckermannDriveNode(Node): + def __init__(self): + super().__init__('cmd_vel_to_ackermann_drive') + self.publisher = self.create_publisher(AckermannDriveStamped, '/ackermann_cmd', QoSProfile(depth=10)) + self.subscription = self.create_subscription(Twist, 'cmd_vel', self.cmd_callback, QoSProfile(depth=10)) + self.wheelbase = 0.143 #轮距 + self.frame_id = 'odom_combined' + self.cmd_angle_instead_rotvel = False + + def convert_trans_rot_vel_to_steering_angle(self, vel, omega): + if omega == 0 or vel == 0: + return 0 + radius = vel / omega + return math.atan(self.wheelbase / radius) + + def cmd_callback(self, data): + vel = data.linear.x + if self.cmd_angle_instead_rotvel: + steering = data.angular.z + else: + steering = 1.0 * self.convert_trans_rot_vel_to_steering_angle(vel, data.angular.z) + + msg = AckermannDriveStamped() + msg.header.stamp = self.get_clock().now().to_msg() + msg.header.frame_id = self.frame_id + msg.drive.steering_angle = steering + msg.drive.speed = vel + self.publisher.publish(msg) + +def main(): + rclpy.init() + node = CmdVel2AckermannDriveNode() + rclpy.spin(node) + node.destroy_node() + rclpy.shutdown() + +if __name__ == '__main__': + main() diff --git a/src/origincar_base/src/Quaternion_Solution.cpp b/src/origincar_base/src/Quaternion_Solution.cpp new file mode 100644 index 0000000..56cf830 --- /dev/null +++ b/src/origincar_base/src/Quaternion_Solution.cpp @@ -0,0 +1,91 @@ + +#include "origincar_base/Quaternion_Solution.h" +#define SAMPLING_FREQ 20.0f // 采样频率 +/************************************** +Date: May 31, 2020 +Function: 平方根倒数 求四元数用到 +***************************************/ +float InvSqrt(float number) +{ + volatile long i; + volatile float x, y; + volatile const float f = 1.5F; + x = number * 0.5F; + y = number; + i = * (( long * ) &y); + i = 0x5f375a86 - ( i >> 1 ); + y = * (( float * ) &i); + y = y * ( f - ( x * y * y ) ); + + return y; +} +/************************************** +Date: May 31, 2020 +Function: 四元数解算 +***************************************/ +volatile float twoKp = 1.0f; // 2 * proportional gain (Kp) +volatile float twoKi = 0.0f; // 2 * integral gain (Ki) +volatile float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; // quaternion of sensor frame relative to auxiliary frame +volatile float integralFBx = 0.0f, integralFBy = 0.0f, integralFBz = 0.0f; // integral error terms scaled by Ki +void Quaternion_Solution(float gx, float gy, float gz, float ax, float ay, float az) +{ + float recipNorm; + float halfvx, halfvy, halfvz; + float halfex, halfey, halfez; + float qa, qb, qc; + // Compute feedback only if accelerometer measurement valid (avoids NaN in accelerometer normalisation) + if(!((ax == 0.0f) && (ay == 0.0f) && (az == 0.0f))) { + // 首先把加速度计采集到的值(三维向量)转化为单位向量,即向量除以模 + recipNorm = InvSqrt(ax * ax + ay * ay + az * az); + ax *= recipNorm; + ay *= recipNorm; + az *= recipNorm; + // 把四元数换算成方向余弦中的第三行的三个元素 + halfvx = q1 * q3 - q0 * q2; + halfvy = q0 * q1 + q2 * q3; + halfvz = q0 * q0 - 0.5f + q3 * q3; + //误差是估计的重力方向和测量的重力方向的交叉乘积之和 + halfex = (ay * halfvz - az * halfvy); + halfey = (az * halfvx - ax * halfvz); + halfez = (ax * halfvy - ay * halfvx); + // 计算并应用积分反馈(如果启用) + if(twoKi > 0.0f) { + integralFBx += twoKi * halfex * (1.0f / SAMPLING_FREQ); // integral error scaled by Ki + integralFBy += twoKi * halfey * (1.0f / SAMPLING_FREQ); + integralFBz += twoKi * halfez * (1.0f / SAMPLING_FREQ); + gx += integralFBx; // apply integral feedback + gy += integralFBy; + gz += integralFBz; + } + else { + integralFBx = 0.0f; // prevent integral windup + integralFBy = 0.0f; + integralFBz = 0.0f; + } + // Apply proportional feedback + gx += twoKp * halfex; + gy += twoKp * halfey; + gz += twoKp * halfez; + } + // Integrate rate of change of quaternion + gx *= (0.5f * (1.0f / SAMPLING_FREQ)); // pre-multiply common factors + gy *= (0.5f * (1.0f / SAMPLING_FREQ)); + gz *= (0.5f * (1.0f / SAMPLING_FREQ)); + qa = q0; + qb = q1; + qc = q2; + q0 += (-qb * gx - qc * gy - q3 * gz); + q1 += (qa * gx + qc * gz - q3 * gy); + q2 += (qa * gy - qb * gz + q3 * gx); + q3 += (qa * gz + qb * gy - qc * gx); + // Normalise quaternion + recipNorm = InvSqrt(q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3); + q0 *= recipNorm; + q1 *= recipNorm; + q2 *= recipNorm; + q3 *= recipNorm; + Mpu6050.orientation.w = q0; + Mpu6050.orientation.x = q1; + Mpu6050.orientation.y = q2; + Mpu6050.orientation.z = q3; +} diff --git a/src/origincar_base/src/origincar_base.cpp b/src/origincar_base/src/origincar_base.cpp new file mode 100644 index 0000000..4a39723 --- /dev/null +++ b/src/origincar_base/src/origincar_base.cpp @@ -0,0 +1,469 @@ +#include "origincar_base/origincar_base.h" +#include "rclcpp/rclcpp.hpp" +#include "origincar_base/Quaternion_Solution.h" +#include "ackermann_msgs/msg/ackermann_drive_stamped.hpp" +#include "origincar_msg/msg/data.hpp" +#include "robot_localization/srv/set_pose.hpp" +#include + +using std::placeholders::_1; +using namespace std; +void sigintHandler(int sig); +sensor_msgs::msg::Imu Mpu6050; +rclcpp::Node::SharedPtr node_handle = nullptr; +int Init_imu_num = 0; +float gyro_z_sum=0; + +int main(int argc, char *argv[]) +{ + rclcpp::init(argc, argv); + signal(SIGINT, sigintHandler); + origincar_base Robot_Control; + Robot_Control.Control(); + rclcpp::shutdown(); + return 0; +} + + + + +short origincar_base::IMU_Trans(uint8_t Data_High,uint8_t Data_Low) +{ + short transition_16; + transition_16 = 0; + transition_16 |= Data_High<<8; + transition_16 |= Data_Low; + return transition_16; +} + +float origincar_base::Odom_Trans(uint8_t Data_High,uint8_t Data_Low) +{ + float data_return; + short transition_16; + transition_16 = 0; + transition_16 |= Data_High<<8; + transition_16 |= Data_Low; + data_return = (transition_16 / 1000)+(transition_16 % 1000)*0.001; + return data_return; + } + +void origincar_base::Akm_Cmd_Vel_Callback(const ackermann_msgs::msg::AckermannDriveStamped::SharedPtr akm_ctl) +{ + short transition; + std::cout<<"linerx"<drive.speed<drive.steering_angle<drive.speed*1000; + Send_Data.tx[4] = transition; + Send_Data.tx[3] = transition>>8; + + transition=0; + transition = akm_ctl->drive.steering_angle*1000/2; + Send_Data.tx[8] = transition; + Send_Data.tx[7] = transition>>8; + + Send_Data.tx[9]=Check_Sum(9,SEND_DATA_CHECK); + Send_Data.tx[10]=FRAME_TAIL; + + try { + Stm32_Serial.write(Send_Data.tx,sizeof (Send_Data.tx)); + } catch (serial::IOException& e) { + RCLCPP_ERROR(this->get_logger(),("Unable to send data through serial port")); + } +} + +void origincar_base::Cmd_Vel_Callback(const geometry_msgs::msg::Twist::SharedPtr twist_aux) +{ + RCLCPP_INFO(this->get_logger(),"linarx: %.2f, angularz: %.2f ", twist_aux->linear.x, twist_aux->angular.z); + std::cout<<"linerx"<linear.x<angular.z<linear.x*1000; + Send_Data.tx[4] = transition; + Send_Data.tx[3] = transition>>8; + + transition=0; + transition = twist_aux->linear.y*1000; + Send_Data.tx[6] = transition; + Send_Data.tx[5] = transition>>8; + + transition=0; + transition = (twist_aux->angular.z)*1000; + Send_Data.tx[8] = transition; + Send_Data.tx[7] = transition>>8; + + Send_Data.tx[9]=Check_Sum(9,SEND_DATA_CHECK); + Send_Data.tx[10]=FRAME_TAIL; + + try + { + Stm32_Serial.write(Send_Data.tx,sizeof (Send_Data.tx)); + } catch (serial::IOException& e) { + RCLCPP_ERROR(this->get_logger(),("Unable to send data through serial port")); + } +} + +void origincar_base::Sign_Switch_Callback(const std_msgs::msg::Int32::SharedPtr sign_switch) +{ + (void)sign_switch; + if (sign_switch->data == -1) { + memset(&Robot_Pos, 0, sizeof(Robot_Pos)); + memset(&Mpu6050, 0, sizeof(Mpu6050)); + q0 = 0; + q1 = 0; + q2 = 0; + q3 = 0; + Robot_Pos.X = 0.54; + Robot_Pos.Y = 0.2; + Robot_Pos.Z = 0; + Robot_Vel.X = 0; + Robot_Vel.Y = 0; + Robot_Vel.Z = 0; + memset(&Robot_Vel, 0, sizeof(Robot_Vel)); + reset_filter(); + } + else if(sign_switch->data == -2) { + memset(&Robot_Pos, 0, sizeof(Robot_Pos)); + Robot_Pos.X = 2.54; + Robot_Pos.Y = 2.5; + Robot_Pos.Z = -1.5708; + Robot_Vel.X = 0; + Robot_Vel.Y = 0; + Robot_Vel.Z = 0; + memset(&Robot_Vel, 0, sizeof(Robot_Vel)); + reset_filter(); + } + /* + else if (sign_switch->data == 6) { + memset(&Robot_Pos, 0, sizeof(Robot_Pos)); + Robot_Pos.X = 2; + Robot_Pos.Y = 2; + memset(&Robot_Vel, 0, sizeof(Robot_Vel)); + }*/ + +} + +void origincar_base::Publish_ImuSensor() +{ + sensor_msgs::msg::Imu Imu_Data_Pub; + Imu_Data_Pub.header.stamp = rclcpp::Node::now(); + Imu_Data_Pub.header.frame_id = gyro_frame_id; + + Imu_Data_Pub.orientation.x = Mpu6050.orientation.x; + Imu_Data_Pub.orientation.y = Mpu6050.orientation.y; + Imu_Data_Pub.orientation.z = Mpu6050.orientation.z; + Imu_Data_Pub.orientation.w = Mpu6050.orientation.w; + Imu_Data_Pub.orientation_covariance[0] = 1e6; + Imu_Data_Pub.orientation_covariance[4] = 1e6; + Imu_Data_Pub.orientation_covariance[8] = 1e-6; + Imu_Data_Pub.angular_velocity.x = Mpu6050.angular_velocity.x; + Imu_Data_Pub.angular_velocity.y = Mpu6050.angular_velocity.y; + Imu_Data_Pub.angular_velocity.z = Mpu6050.angular_velocity.z; + Imu_Data_Pub.angular_velocity_covariance[0] = 1e6; + Imu_Data_Pub.angular_velocity_covariance[4] = 1e6; + Imu_Data_Pub.angular_velocity_covariance[8] = 1e-6; + Imu_Data_Pub.linear_acceleration.x = Mpu6050.linear_acceleration.x; + Imu_Data_Pub.linear_acceleration.y = Mpu6050.linear_acceleration.y; + Imu_Data_Pub.linear_acceleration.z = Mpu6050.linear_acceleration.z; + + imu_publisher->publish(Imu_Data_Pub); + +} + +void origincar_base::Publish_Odom() +{ + tf2::Quaternion q; + q.setRPY(0,0,Robot_Pos.Z); + geometry_msgs::msg::Quaternion odom_quat=tf2::toMsg(q); + + origincar_msg::msg::Data robotpose; + origincar_msg::msg::Data robotvel; + nav_msgs::msg::Odometry odom; + + odom.header.stamp = rclcpp::Node::now(); + odom.header.frame_id = odom_frame_id; + odom.child_frame_id = robot_frame_id; + + odom.pose.pose.position.x = Robot_Pos.X; + odom.pose.pose.position.y = Robot_Pos.Y; + + odom.pose.pose.position.z = 0.0; + odom.pose.pose.orientation = odom_quat; + //odom_quat; + + + odom.twist.twist.linear.x = Robot_Vel.X; + odom.twist.twist.linear.y = Robot_Vel.Y; + odom.twist.twist.angular.z = Robot_Vel.Z; + + robotpose.x = Robot_Pos.X; + robotpose.y = Robot_Pos.Y; + robotpose.z = Robot_Pos.Z; + + robotvel.x = Robot_Vel.X; + robotvel.y = Robot_Vel.Y; + robotvel.z = Robot_Vel.Z; + + geometry_msgs::msg::TransformStamped t; + + t.header.stamp = rclcpp::Node::now(); + t.header.frame_id = odom_frame_id; + t.child_frame_id = robot_frame_id; + + t.transform.translation.x = Robot_Pos.X; + t.transform.translation.y = Robot_Pos.Y; + t.transform.translation.z = 0.0; + + t.transform.rotation = odom_quat; + tf_broadcaster_->sendTransform(t); + odom_publisher->publish(odom); + robotpose_publisher->publish(robotpose); + robotvel_publisher->publish(robotvel); +} + +void origincar_base::Publish_Voltage() +{ + std_msgs::msg::Float32 voltage_msgs; + static float Count_Voltage_Pub = 0; + + if (Count_Voltage_Pub++ > 10) { + Count_Voltage_Pub = 0; + voltage_msgs.data = Power_voltage; + voltage_publisher->publish(voltage_msgs); + } +} + +unsigned char origincar_base::Check_Sum(unsigned char Count_Number,unsigned char mode) +{ + unsigned char check_sum = 0, k; + + if (mode == 0) { + for(k=0; k < Count_Number; k++) { + check_sum = check_sum^Receive_Data.rx[k]; + } + } else if (mode == 1) { + for (k=0; k < Count_Number; k++) { + check_sum = check_sum^Send_Data.tx[k]; + } + } + + return check_sum; +} + +bool origincar_base::Get_Sensor_Data() +{ + short transition_16 = 0, j = 0, Header_Pos = 0, Tail_Pos = 0; + uint8_t Receive_Data_Pr[RECEIVE_DATA_SIZE] = {0}; + Stm32_Serial.read(Receive_Data_Pr,sizeof (Receive_Data_Pr)); + for (j = 0; j < 24; j++) { + if (Receive_Data_Pr[j] == FRAME_HEADER) + Header_Pos=j; + else if (Receive_Data_Pr[j] == FRAME_TAIL) + Tail_Pos = j; + } + + if (Tail_Pos == (Header_Pos + 23)) { + memcpy(Receive_Data.rx, Receive_Data_Pr, sizeof(Receive_Data_Pr)); + } else if (Header_Pos == (1 + Tail_Pos)) { + for (j = 0;j < 24; j++) + Receive_Data.rx[j] = Receive_Data_Pr[(j+Header_Pos) % 24]; + } else { + return false; + } + + Receive_Data.Frame_Header = Receive_Data.rx[0]; + Receive_Data.Frame_Tail = Receive_Data.rx[23]; + if (Receive_Data.Frame_Header == FRAME_HEADER) { + if (Receive_Data.Frame_Tail == FRAME_TAIL) { + if (Receive_Data.rx[22] == Check_Sum(22,READ_DATA_CHECK)||(Header_Pos == (1 + Tail_Pos))) { + Receive_Data.Flag_Stop=Receive_Data.rx[1]; + Robot_Vel.X = Odom_Trans(Receive_Data.rx[2],Receive_Data.rx[3]); + + Robot_Vel.Y = Odom_Trans(Receive_Data.rx[4],Receive_Data.rx[5]); + + //Robot_Vel.Z = Odom_Trans(Receive_Data.rx[6],Receive_Data.rx[7]); + + Mpu6050_Data.accele_x_data = IMU_Trans(Receive_Data.rx[8],Receive_Data.rx[9]); + Mpu6050_Data.accele_y_data = IMU_Trans(Receive_Data.rx[10],Receive_Data.rx[11]); + Mpu6050_Data.accele_z_data = IMU_Trans(Receive_Data.rx[12],Receive_Data.rx[13]); + Mpu6050_Data.gyros_x_data = IMU_Trans(Receive_Data.rx[14],Receive_Data.rx[15]); + Mpu6050_Data.gyros_y_data = IMU_Trans(Receive_Data.rx[16],Receive_Data.rx[17]); + Mpu6050_Data.gyros_z_data = IMU_Trans(Receive_Data.rx[18],Receive_Data.rx[19]); + + Mpu6050.linear_acceleration.x = Mpu6050_Data.accele_x_data / ACCEl_RATIO; + Mpu6050.linear_acceleration.y = Mpu6050_Data.accele_y_data / ACCEl_RATIO; + Mpu6050.linear_acceleration.z = Mpu6050_Data.accele_z_data / ACCEl_RATIO; + + Mpu6050.angular_velocity.x = Mpu6050_Data.gyros_x_data * GYROSCOPE_RATIO; + Mpu6050.angular_velocity.y = Mpu6050_Data.gyros_y_data * GYROSCOPE_RATIO; + + if(Init_imu_num<100) + { + Init_imu_num += 1; + gyro_z_sum += Mpu6050_Data.gyros_z_data ; + Mpu6050.angular_velocity.z = 0; + } + else + { + Mpu6050.angular_velocity.z = (Mpu6050_Data.gyros_z_data - (gyro_z_sum / (float)Init_imu_num))*GYROSCOPE_RATIO; + //RCLCPP_INFO(this->get_logger(),"gyro_z_sum: %.2f, err: %.2f, gyroz: %.2f ", gyro_z_sum ,(gyro_z_sum / (float)Init_imu_num), Mpu6050.angular_velocity.z); + } + Robot_Vel.Z = Mpu6050.angular_velocity.z; + transition_16 = 0; + transition_16 |= Receive_Data.rx[20]<<8; + transition_16 |= Receive_Data.rx[21]; + Power_voltage = transition_16/1000+(transition_16 % 1000)*0.001; + + return true; + } + } + } + + return false; +} + +void origincar_base::Control() +{ + rclcpp::Time current_time, last_time; + current_time = rclcpp::Node::now(); + last_time = rclcpp::Node::now(); + while(rclcpp::ok()) { + current_time = rclcpp::Node::now(); + Sampling_Time = (current_time - last_time).seconds(); + if (true == Get_Sensor_Data()) { + Robot_Pos.X+=1.03*(Robot_Vel.X * cos(Robot_Pos.Z) - Robot_Vel.Y * sin(Robot_Pos.Z)) * Sampling_Time; + Robot_Pos.Y+=1.01*(Robot_Vel.X * sin(Robot_Pos.Z) + Robot_Vel.Y * cos(Robot_Pos.Z)) * Sampling_Time;//1.125 + Robot_Pos.Z+= Mpu6050.angular_velocity.z * Sampling_Time; + + Quaternion_Solution(Mpu6050.angular_velocity.x, Mpu6050.angular_velocity.y, Mpu6050.angular_velocity.z,\ + Mpu6050.linear_acceleration.x, Mpu6050.linear_acceleration.y, Mpu6050.linear_acceleration.z); + Publish_ImuSensor(); + Publish_Voltage(); + Publish_Odom(); + rclcpp::spin_some(this->get_node_base_interface()); + } + last_time = current_time; + } +} + +origincar_base::origincar_base() +: rclcpp::Node ("origincar_base") +{ + memset(&Robot_Pos, 0, sizeof(Robot_Pos)); + memset(&Robot_Vel, 0, sizeof(Robot_Vel)); + memset(&Receive_Data, 0, sizeof(Receive_Data)); + memset(&Send_Data, 0, sizeof(Send_Data)); + memset(&Mpu6050_Data, 0, sizeof(Mpu6050_Data)); + Robot_Pos.X = 0.54; + Robot_Pos.Y = 0.2; + + int serial_baud_rate = 115200; + + this->declare_parameter("usart_port_name", "/dev/ttyCH343USB0"); + this->declare_parameter("cmd_vel", "cmd_vel"); + this->declare_parameter("akm_cmd_vel", "ackermann_cmd"); + this->declare_parameter("odom_frame_id", "odom"); + this->declare_parameter("robot_frame_id", "base_link"); + this->declare_parameter("gyro_frame_id", "gyro_link"); + + this->get_parameter("serial_baud_rate", serial_baud_rate); + this->get_parameter("usart_port_name", usart_port_name); + this->get_parameter("cmd_vel", cmd_vel); + this->get_parameter("akm_cmd_vel", akm_cmd_vel); + this->get_parameter("odom_frame_id", odom_frame_id); + this->get_parameter("robot_frame_id", robot_frame_id); + this->get_parameter("gyro_frame_id", gyro_frame_id); + + odom_publisher = create_publisher("odom", 10); + + imu_publisher = create_publisher("imu/data_raw", 10); + + voltage_publisher = create_publisher("PowerVoltage", 1); + + robotpose_publisher = create_publisher("robotpose", 10); + + robotvel_publisher = create_publisher("robotvel", 10); + + pose_pub_ = create_publisher( + "/set_pose", + rclcpp::SystemDefaultsQoS().reliable()); + + tf_bro = std::make_shared(this); + tf_broadcaster_ = std::make_unique(*this); + Cmd_Vel_Sub = create_subscription( + cmd_vel, 1, std::bind(&origincar_base::Cmd_Vel_Callback, this, _1)); + Akm_Cmd_Vel_Sub = create_subscription( + akm_cmd_vel, 1, std::bind(&origincar_base::Akm_Cmd_Vel_Callback, this, _1)); + + Sign_Switch_Sub = create_subscription( + "/sign4return", 1, std::bind(&origincar_base::Sign_Switch_Callback, this, _1)); + try { + Stm32_Serial.setPort("/dev/ttyACM0"); + Stm32_Serial.setBaudrate(serial_baud_rate); + serial::Timeout _time = serial::Timeout::simpleTimeout(2000); + Stm32_Serial.setTimeout(_time); + Stm32_Serial.open(); + } catch (serial::IOException& e) { + RCLCPP_ERROR(this->get_logger(),"origincar_base can not open serial port,Please check the serial port cable! "); + } + if(Stm32_Serial.isOpen()) { + RCLCPP_INFO(this->get_logger(),"origincar_base serial port opened"); + } +} + + +void sigintHandler(int sig) +{ + sig = sig; + printf("OriginBot shutdown...\n"); + serial::Serial Stm32_Serial; + Stm32_Serial.setPort("/dev/ttyACM0"); + Stm32_Serial.setBaudrate(115200); + serial::Timeout _time = serial::Timeout::simpleTimeout(2000); + Stm32_Serial.setTimeout(_time); + Stm32_Serial.open(); + SEND_DATA Send_Data; + if (Stm32_Serial.isOpen()) { + Send_Data.tx[0]=FRAME_HEADER; + Send_Data.tx[1] = 0; + Send_Data.tx[2] = 0; + + Send_Data.tx[4] = 0; + Send_Data.tx[3] = 0; + + Send_Data.tx[6] = 0; + Send_Data.tx[5] = 0; + + Send_Data.tx[7] = 0; + Send_Data.tx[8] = 0; + int check_sum = 0; + for (int k = 0; k < 9; k++) { + check_sum = check_sum^Send_Data.tx[k]; + } + Send_Data.tx[9]=check_sum; + Send_Data.tx[10]=FRAME_TAIL; + + try { + Stm32_Serial.write(Send_Data.tx,sizeof (Send_Data.tx)); + } catch (serial::IOException& e) { + } + + } + // 关闭ROS2接口,清除资源 + rclcpp::shutdown(); +} + +origincar_base::~origincar_base() +{ + RCLCPP_INFO(this->get_logger(),"Shutting down"); +} \ No newline at end of file diff --git a/src/origincar_description/CMakeLists.txt b/src/origincar_description/CMakeLists.txt new file mode 100644 index 0000000..21934a5 --- /dev/null +++ b/src/origincar_description/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.5) +project(origincar_description) + +# Default to C99 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) + +install( + DIRECTORY launch urdf rviz meshes world + DESTINATION share/${PROJECT_NAME} +) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # uncomment the line when a copyright and license is not present in all source files + #set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # uncomment the line when this package is not in a git repo + #set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/src/origincar_description/CMakeLists.txt.save b/src/origincar_description/CMakeLists.txt.save new file mode 100644 index 0000000..05033cf --- /dev/null +++ b/src/origincar_description/CMakeLists.txt.save @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.8.3) + +project(origincar_description) + +find_package(ament_cmake REQUIRED) + +find_package(roslaunch) + +foreach(dir config launch meshes urdf) + install(DIRECTORY ${dir}/ + DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/${dir}) +endforeach(dir) diff --git a/src/origincar_description/config/joint_names_origincar_description.yaml b/src/origincar_description/config/joint_names_origincar_description.yaml new file mode 100644 index 0000000..8d4a477 --- /dev/null +++ b/src/origincar_description/config/joint_names_origincar_description.yaml @@ -0,0 +1 @@ +controller_joint_names: ['', 'down_left_joint', 'down_right_joint', 'up_left_joint', ] diff --git a/src/origincar_description/config/joint_names_origincar_description.yamlZone.Identifier b/src/origincar_description/config/joint_names_origincar_description.yamlZone.Identifier new file mode 100644 index 0000000..d6c1ec6 Binary files /dev/null and b/src/origincar_description/config/joint_names_origincar_description.yamlZone.Identifier differ diff --git a/src/origincar_description/launch/display.launch b/src/origincar_description/launch/display.launch new file mode 100644 index 0000000..ef7821b --- /dev/null +++ b/src/origincar_description/launch/display.launch @@ -0,0 +1,20 @@ + + + + + + + \ No newline at end of file diff --git a/src/origincar_description/launch/display.launch.py b/src/origincar_description/launch/display.launch.py new file mode 100644 index 0000000..68eeeb8 --- /dev/null +++ b/src/origincar_description/launch/display.launch.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 + +from launch import LaunchDescription +from launch_ros.actions import Node +import os +from ament_index_python.packages import get_package_share_directory +from launch_ros.parameter_descriptions import ParameterValue +from launch.substitutions import Command, LaunchConfiguration +from launch.actions import DeclareLaunchArgument + + +def generate_launch_description(): + # * 这里是机器人模型路径之类的 + origincar_urdf_dir = get_package_share_directory('origincar_description') + default_model_path = os.path.join( + origincar_urdf_dir, "urdf", "origincar.urdf") + default_rviz_path = os.path.join( + origincar_urdf_dir, "rviz", "display.rviz") + model = DeclareLaunchArgument( + name="model", default_value=default_model_path) + use_sim_time = LaunchConfiguration('use_sim_time', default='true') + + # 加载机器人模型 + # 1.启动 robot_state_publisher 节点并以参数方式加载 urdf 文件 + robot_description = ParameterValue(Command(["xacro ", LaunchConfiguration("model")]), + value_type=str) + robot_state_publisher = Node( + package="robot_state_publisher", + executable="robot_state_publisher", + parameters=[{"robot_description": robot_description, + 'use_sim_time': True, 'publish_frequency': 30.0}] + ) + + joint_state_publisher_node = Node( + package='joint_state_publisher_gui', + executable='joint_state_publisher_gui', + name='joint_state_publisher_gui', + parameters=[{'use_sim_time': use_sim_time}], + arguments=[default_model_path] + ) + + # 2.启动 joint_state_publisher 节点发布非固定关节状态 + joint_state_publisher = Node( + package="joint_state_publisher", + executable="joint_state_publisher" + ) + + # rviz2 节点 + # *-d 为加载配置文件,这个不用看,因人而异 + rviz2 = Node( + package="rviz2", + executable="rviz2", + parameters=[{'use_sim_time': use_sim_time}], + arguments=["-d", default_rviz_path] + ) + + return LaunchDescription([ + model, + robot_state_publisher, + # joint_state_publisher_node, + joint_state_publisher, + rviz2 + ]) diff --git a/src/origincar_description/launch/gazebo.launch b/src/origincar_description/launch/gazebo.launch new file mode 100644 index 0000000..42b2bcd --- /dev/null +++ b/src/origincar_description/launch/gazebo.launch @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/src/origincar_description/launch/gazebo.launch.py b/src/origincar_description/launch/gazebo.launch.py new file mode 100644 index 0000000..384d4b8 --- /dev/null +++ b/src/origincar_description/launch/gazebo.launch.py @@ -0,0 +1,68 @@ +from launch import LaunchDescription +from launch_ros.actions import Node +import os +from ament_index_python.packages import get_package_share_directory +from launch_ros.parameter_descriptions import ParameterValue +from launch.substitutions import Command, LaunchConfiguration +from launch.actions import DeclareLaunchArgument +from launch.actions import ExecuteProcess + + +def generate_launch_description(): + ld = LaunchDescription() + robot_name_in_model = 'mycar' + origincar_urdf_dir = get_package_share_directory( + 'origincar_description') + default_model_path = os.path.join( + origincar_urdf_dir, "urdf", "origincar.urdf") + default_rviz_path = os.path.join( + origincar_urdf_dir, "rviz", "display.rviz") + model = DeclareLaunchArgument( + name="model", default_value=default_model_path) + use_sim_time = LaunchConfiguration('use_sim_time', default='true') + # * ###################gazebo + gazebo_world_path = os.path.join(origincar_urdf_dir, 'world/test.world') + start_gazebo_cmd = ExecuteProcess( + cmd=['gazebo', '--verbose', '-s', 'libgazebo_ros_init.so', + '-s', 'libgazebo_ros_factory.so', gazebo_world_path], + output='screen') + + spawn_entity_cmd = Node( + package='gazebo_ros', + executable='spawn_entity.py', + arguments=['-entity', robot_name_in_model, + '-file', default_model_path], + output='screen' + ) + + robot_description = ParameterValue(Command(["xacro ", LaunchConfiguration("model")]), + value_type=str) + + robot_state_publisher = Node( + package="robot_state_publisher", + executable="robot_state_publisher", + parameters=[{"robot_description": robot_description, + 'use_sim_time': True, 'publish_frequency': 30.0}] + ) + + # 2.启动 joint_state_publisher 节点发布非固定关节状态 + joint_state_publisher = Node( + package="joint_state_publisher", + executable="joint_state_publisher" + ) + # *###################rviz + # rviz2 节点 + # *-d 为加载配置文件,这个不用看,因人而异 + rviz2 = Node( + package="rviz2", + executable="rviz2", + arguments=["-d", default_rviz_path], + parameters=[{'use_sim_time': use_sim_time}] + ) + ld.add_action(model) + ld.add_action(start_gazebo_cmd) + ld.add_action(spawn_entity_cmd) + ld.add_action(robot_state_publisher) + # ld.add_action(joint_state_publisher) + # ld.add_action(rviz2) + return ld diff --git a/src/origincar_description/meshes/base_link.STL b/src/origincar_description/meshes/base_link.STL new file mode 100644 index 0000000..9588ff4 Binary files /dev/null and b/src/origincar_description/meshes/base_link.STL differ diff --git a/src/origincar_description/meshes/base_link.STLZone.Identifier b/src/origincar_description/meshes/base_link.STLZone.Identifier new file mode 100644 index 0000000..d6c1ec6 Binary files /dev/null and b/src/origincar_description/meshes/base_link.STLZone.Identifier differ diff --git a/src/origincar_description/meshes/down_left_Link.STL b/src/origincar_description/meshes/down_left_Link.STL new file mode 100644 index 0000000..746f229 Binary files /dev/null and b/src/origincar_description/meshes/down_left_Link.STL differ diff --git a/src/origincar_description/meshes/down_left_Link.STLZone.Identifier b/src/origincar_description/meshes/down_left_Link.STLZone.Identifier new file mode 100644 index 0000000..d6c1ec6 Binary files /dev/null and b/src/origincar_description/meshes/down_left_Link.STLZone.Identifier differ diff --git a/src/origincar_description/meshes/down_right_Link.STL b/src/origincar_description/meshes/down_right_Link.STL new file mode 100644 index 0000000..a2e315a Binary files /dev/null and b/src/origincar_description/meshes/down_right_Link.STL differ diff --git a/src/origincar_description/meshes/down_right_Link.STLZone.Identifier b/src/origincar_description/meshes/down_right_Link.STLZone.Identifier new file mode 100644 index 0000000..d6c1ec6 Binary files /dev/null and b/src/origincar_description/meshes/down_right_Link.STLZone.Identifier differ diff --git a/src/origincar_description/meshes/up_left_Link.STL b/src/origincar_description/meshes/up_left_Link.STL new file mode 100644 index 0000000..3367b35 Binary files /dev/null and b/src/origincar_description/meshes/up_left_Link.STL differ diff --git a/src/origincar_description/meshes/up_left_Link.STLZone.Identifier b/src/origincar_description/meshes/up_left_Link.STLZone.Identifier new file mode 100644 index 0000000..d6c1ec6 Binary files /dev/null and b/src/origincar_description/meshes/up_left_Link.STLZone.Identifier differ diff --git a/src/origincar_description/meshes/up_right_Link.STL b/src/origincar_description/meshes/up_right_Link.STL new file mode 100644 index 0000000..0174871 Binary files /dev/null and b/src/origincar_description/meshes/up_right_Link.STL differ diff --git a/src/origincar_description/meshes/up_right_Link.STLZone.Identifier b/src/origincar_description/meshes/up_right_Link.STLZone.Identifier new file mode 100644 index 0000000..d6c1ec6 Binary files /dev/null and b/src/origincar_description/meshes/up_right_Link.STLZone.Identifier differ diff --git a/src/origincar_description/package.xml b/src/origincar_description/package.xml new file mode 100644 index 0000000..493cafe --- /dev/null +++ b/src/origincar_description/package.xml @@ -0,0 +1,24 @@ + + + + origincar_description + 0.0.0 + TODO: Package description + ps-micro + TODO: License declaration + + ament_cmake + + rviz2 + xacro + robot_state_publisher + joint_state_publisher + ros2launch + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/src/origincar_description/rviz/README b/src/origincar_description/rviz/README new file mode 100644 index 0000000..1ba2ec8 --- /dev/null +++ b/src/origincar_description/rviz/README @@ -0,0 +1 @@ +## 此文件夹为配置RVIZ,暂时不使用 \ No newline at end of file diff --git a/src/origincar_description/rviz/display.rviz b/src/origincar_description/rviz/display.rviz new file mode 100644 index 0000000..57dd63a --- /dev/null +++ b/src/origincar_description/rviz/display.rviz @@ -0,0 +1,186 @@ +Panels: + - Class: rviz_common/Displays + Help Height: 78 + Name: Displays + Property Tree Widget: + Expanded: + - /Global Options1 + - /Status1 + - /RobotModel1 + - /RobotModel1/Description Topic1 + Splitter Ratio: 0.5 + Tree Height: 490 + - Class: rviz_common/Selection + Name: Selection + - Class: rviz_common/Tool Properties + Expanded: + - /2D Goal Pose1 + - /Publish Point1 + Name: Tool Properties + Splitter Ratio: 0.5886790156364441 + - Class: rviz_common/Views + Expanded: + - /Current View1 + Name: Views + Splitter Ratio: 0.5 +Visualization Manager: + Class: "" + Displays: + - Alpha: 0.5 + Cell Size: 1 + Class: rviz_default_plugins/Grid + Color: 160; 160; 164 + Enabled: true + Line Style: + Line Width: 0.029999999329447746 + Value: Lines + Name: Grid + Normal Cell Count: 0 + Offset: + X: 0 + Y: 0 + Z: 0 + Plane: XY + Plane Cell Count: 10 + Reference Frame: + Value: true + - Alpha: 1 + Class: rviz_default_plugins/RobotModel + Collision Enabled: false + Description File: "" + Description Source: Topic + Description Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /robot_description + Enabled: true + Links: + All Links Enabled: true + Expand Joint Details: false + Expand Link Details: false + Expand Tree: false + Link Tree Style: Links in Alphabetic Order + base_link: + Alpha: 1 + Show Axes: false + Show Trail: false + down_left_Link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + down_right_Link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + up_left_Link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + up_right_Link: + Alpha: 1 + Show Axes: false + Show Trail: false + Value: true + Name: RobotModel + TF Prefix: "" + Update Interval: 0 + Value: true + Visual Enabled: true + - Class: rviz_default_plugins/TF + Enabled: false + Frame Timeout: 15 + Frames: + All Enabled: true + Marker Scale: 1 + Name: TF + Show Arrows: true + Show Axes: true + Show Names: false + Tree: + {} + Update Interval: 0 + Value: false + Enabled: true + Global Options: + Background Color: 48; 48; 48 + Fixed Frame: base_link + Frame Rate: 30 + Name: root + Tools: + - Class: rviz_default_plugins/Interact + Hide Inactive Objects: true + - Class: rviz_default_plugins/MoveCamera + - Class: rviz_default_plugins/Select + - Class: rviz_default_plugins/FocusCamera + - Class: rviz_default_plugins/Measure + Line color: 128; 128; 0 + - Class: rviz_default_plugins/SetInitialPose + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /initialpose + - Class: rviz_default_plugins/SetGoal + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /goal_pose + - Class: rviz_default_plugins/PublishPoint + Single click: true + Topic: + Depth: 5 + Durability Policy: Volatile + History Policy: Keep Last + Reliability Policy: Reliable + Value: /clicked_point + Transformation: + Current: + Class: rviz_default_plugins/TF + Value: true + Views: + Current: + Class: rviz_default_plugins/Orbit + Distance: 0.4845520257949829 + Enable Stereo Rendering: + Stereo Eye Separation: 0.05999999865889549 + Stereo Focal Distance: 1 + Swap Stereo Eyes: false + Value: false + Focal Point: + X: 0 + Y: 0 + Z: 0 + Focal Shape Fixed Size: true + Focal Shape Size: 0.05000000074505806 + Invert Z Axis: false + Name: Current View + Near Clip Distance: 0.009999999776482582 + Pitch: 0.7803981304168701 + Target Frame: + Value: Orbit (rviz) + Yaw: 0.05039529129862785 + Saved: ~ +Window Geometry: + Displays: + collapsed: false + Height: 719 + Hide Left Dock: false + Hide Right Dock: false + QMainWindow State: 000000ff00000000fd00000004000000000000015600000275fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d00000275000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f00000275fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d00000275000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d006501000000000000045000000000000000000000035a0000027500000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000 + Selection: + collapsed: false + Tool Properties: + collapsed: false + Views: + collapsed: false + Width: 1483 + X: 72 + Y: 27 diff --git a/src/origincar_description/urdf/origincar.urdf b/src/origincar_description/urdf/origincar.urdf new file mode 100644 index 0000000..a51ecbd --- /dev/null +++ b/src/origincar_description/urdf/origincar.urdf @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + cmd_vel:=cmd_vel + odom:=odom + distance:=distance + + 30.0 + fr_left_wheel_joint + fr_right_wheel_joint + re_left_wheel_joint + re_right_wheel_joint + fr_left_steer_joint + fr_right_steer_joint + virtual_steering_wheel_joint + 0.583972 + 1.570796 + 4 + + + 600 0 6 + 0 0 + 600 0 6 + 0 0 + 800 0 0 + 0 0 + odom + base_footprint + true + true + + + + + + 100 + fr_right_steer_joint + fr_right_wheel_joint + fr_left_steer_joint + fr_left_wheel_joint + re_right_wheel_joint + re_left_wheel_joint + virtual_steering_wheel_joint + + + + + + + + + / + ~/out:=imu + + false + + true + 100 + true + + + + + 0.0 + 2e-4 + 0.0000075 + 0.0000008 + + + + + 0.0 + 2e-4 + 0.0000075 + 0.0000008 + + + + + 0.0 + 2e-4 + 0.0000075 + 0.0000008 + + + + + + + 0.0 + 1.7e-2 + 0.1 + 0.001 + + + + + 0.0 + 1.7e-2 + 0.1 + 0.001 + + + + + 0.0 + 1.7e-2 + 0.1 + 0.001 + + + + + + + + + + true + true + 5 + 0 0 0.075 0 0 0 + + + + 360 + 1.000000 + 0.000000 + 6.280000 + + + + 0.120000 + 3.5 + 0.015000 + + + gaussian + 0.0 + 0.01 + + + + + + + ~/out:=scan + + sensor_msgs/LaserScan + laser_link + + + + \ No newline at end of file diff --git a/src/origincar_description/urdf/origincar.xacro b/src/origincar_description/urdf/origincar.xacro new file mode 100644 index 0000000..0aca376 --- /dev/null +++ b/src/origincar_description/urdf/origincar.xacro @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/origincar_description/world/fishbot.world b/src/origincar_description/world/fishbot.world new file mode 100644 index 0000000..e6e1c0a --- /dev/null +++ b/src/origincar_description/world/fishbot.world @@ -0,0 +1,626 @@ + + + + 1 + 0 0 10 0 -0 0 + 0.8 0.8 0.8 1 + 0.2 0.2 0.2 1 + + 1000 + 0.9 + 0.01 + 0.001 + + -0.5 0.1 -0.9 + + 0 + 0 + 0 + + + + 1 + + + + + 0 0 1 + 100 100 + + + + + + 100 + 50 + + + + + + + + + + + 10 + + + 0 + + + 0 0 1 + 100 100 + + + + + + + 0 + 0 + 0 + + + 0 0 -9.8 + 6e-06 2.3e-05 -4.2e-05 + + + 0.001 + 1 + 1000 + + + 0.4 0.4 0.4 1 + 0.7 0.7 0.7 1 + 1 + + + + + EARTH_WGS84 + 0 + 0 + 0 + 0 + + + 51 251000000 + 51 570048324 + 1767706562 783975173 + 51251 + + 0.005469 0.07101 0 0 -0 0 + 1 1 1 + + 2.33047 -1.27133 0 0 0 -2.0944 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 0.005469 -2.61367 0 0 -0 3.14159 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -2.31953 -1.27133 0 0 -0 2.0944 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -2.31953 1.41335 0 0 -0 1.0472 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 0.005469 2.75569 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 2.33047 1.41335 0 0 0 -1.0472 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + + 0 0 0 0 -0 0 + 1 1 1 + + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + + -0.039643 1.36341 0.499995 0 1e-05 0 + 1 1 1 + + -0.039643 1.36341 0.499995 0 1e-05 0 + 0 0 0 0 -0 0 + 0.010615 -0.006191 -9.78231 0.012424 0.021225 1.8e-05 + 0.010615 -0.006191 -9.78231 0 -0 0 + + + + -1.0625 -0.503729 0.499993 -3e-06 -4e-06 -0 + 1 1 1 + + -1.0625 -0.503729 0.499993 -3e-06 -4e-06 -0 + 0 0 0 0 -0 0 + 0 0 -9.8 0 -0 0 + 0 0 -9.8 0 -0 0 + + + + 0.724857 -0.542454 0.499997 3e-06 4e-06 -0 + 1 1 1 + + 0.724857 -0.542454 0.499997 3e-06 4e-06 -0 + 0 0 0 0 -0 0 + 0 0 -9.8 0 -0 0 + 0 0 -9.8 0 -0 0 + + + + 0 0 10 0 -0 0 + + + + 0.005469 0.07101 0 0 -0 0 + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 0.996078 0.47451 0.0196078 1 + + + 0 + + + 2.325 -1.34234 0 0 -0 -2.0944 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 0.996078 0.47451 0.0196078 1 + + + 0 + + + -0 -2.68468 0 0 -0 3.14159 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 0.996078 0.47451 0.0196078 1 + + + 0 + + + -2.325 -1.34234 0 0 -0 2.0944 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 0.996078 0.47451 0.0196078 1 + + + 0 + + + -2.325 1.34234 0 0 -0 1.0472 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 0.996078 0.47451 0.0196078 1 + + + 0 + + + -0 2.68468 0 0 -0 0 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 0.996078 0.47451 0.0196078 1 + + + 0 + + + 2.325 1.34234 0 0 -0 -1.0472 + 0 + 0 + 0 + + 1 + + + -0.039648 1.36341 0.5 0 -0 0 + + + 1 + + 0.166667 + 0 + 0 + 0.166667 + 0 + 0.166667 + + 0 0 0 0 -0 0 + + + + + 1 1 1 + + + 10 + + + + + + + + + + + + + + + + + 1 1 1 + + + + + + + 0 + 0 + 0 + + + + -1.0625 -0.503731 0.5 0 -0 0 + + + 1 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + 0 0 0 0 -0 0 + + + + + 0.5 + 1 + + + 10 + + + + + + + + + + + + + + + + + 0.5 + 1 + + + + + + + 0 + 0 + 0 + + + + 0.724855 -0.542452 0.5 0 -0 0 + + + 1 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + 0 0 0 0 -0 0 + + + + + 0.5 + 1 + + + 10 + + + + + + + + + + + + + + + + + 0.5 + 1 + + + + + + + 0 + 0 + 0 + + + + + 11.8556 -5.21446 33.9466 0 1.2498 2.56501 + orbit + perspective + + + + diff --git a/src/origincar_description/world/gc_world.world b/src/origincar_description/world/gc_world.world new file mode 100644 index 0000000..cc15c7b --- /dev/null +++ b/src/origincar_description/world/gc_world.world @@ -0,0 +1,893 @@ + + + + 1 + 0 0 10 0 -0 0 + 0.8 0.8 0.8 1 + 0.2 0.2 0.2 1 + + 1000 + 0.9 + 0.01 + 0.001 + + -0.5 0.1 -0.9 + + 0 + 0 + 0 + + + + 1 + + + + + 0 0 1 + 100 100 + + + + + + 100 + 50 + + + + + + + + + + + 10 + + + 0 + + + 0 0 1 + 100 100 + + + + + + + 0 + 0 + 0 + + + 0 0 -9.8 + 6e-06 2.3e-05 -4.2e-05 + + + 0.001 + 1 + 1000 + + + 0.4 0.4 0.4 1 + 0.7 0.7 0.7 1 + 1 + + + + + EARTH_WGS84 + 0 + 0 + 0 + 0 + + + -4.71646 -0.134166 0 0 -0 0 + + + + + 6.5 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 6.5 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -10.5912 -3.10164 0 0 -0 0 + 0 + 0 + 0 + + + + + + 16 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 16 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -5.36881 -0.250968 0 0 -0 -1.5708 + 0 + 0 + 0 + + + + + + 19.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 19.25 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 4.18119 -8.17597 0 0 -0 0 + 0 + 0 + 0 + + + + + + 16.5 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 16.5 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 13.7312 -0.000968 0 0 -0 1.5708 + 0 + 0 + 0 + + + + + + 19.2565 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 19.2565 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 4.18119 7.92403 0 0 -0 -3.11542 + 0 + 0 + 0 + + + + + + 10.75 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 10.75 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -1.01381 3.08403 0 0 -0 0 + 0 + 0 + 0 + + + + + + 5.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 5.25 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 4.28619 0.534032 0 0 -0 -1.5708 + 0 + 0 + 0 + + + + + + 5 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 5 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -3.07881 -1.59597 0 0 -0 0 + 0 + 0 + 0 + + + + + + 5 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 5 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 9.25619 -5.56097 0 0 -0 1.5708 + 0 + 0 + 0 + + + + + + 4.75 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 4.75 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 11.4662 3.66903 0 0 -0 0 + 0 + 0 + 0 + + 1 + + + -6.35985 -5.47044 0.5 0 -0 0 + + + 1 + + 0.166667 + 0 + 0 + 0.166667 + 0 + 0.166667 + + 0 0 0 0 -0 0 + + + + + 1 1 1 + + + 10 + + + + + + + + + + + + + + + + + 1 1 1 + + + + + + + 0 + 0 + 0 + + + + -2.08128 -5.46626 0.5 0 -0 0 + + + 1 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + 0 0 0 0 -0 0 + + + + + 0.5 + 1 + + + 10 + + + + + + + + + + + + + + + + + 0.5 + 1 + + + + + + + 0 + 0 + 0 + + + + 3.24338 0.112284 0.5 0 -0 0 + + + 1 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + 0 0 0 0 -0 0 + + + + + 0.5 + 1 + + + 10 + + + + + + + + + + + + + + + + + 0.5 + 1 + + + + + + + 0 + 0 + 0 + + + + 1.72376 5.13 0.5 0 -0 0 + + + 1 + + 0.166667 + 0 + 0 + 0.166667 + 0 + 0.166667 + + 0 0 0 0 -0 0 + + + + + 1 1 1 + + + 10 + + + + + + + + + + + + + + + + + 1 1 1 + + + + + + + 0 + 0 + 0 + + + + 148 245000000 + 149 497524618 + 1770372561 596283813 + 148245 + + -4.71646 -0.134166 0 0 -0 0 + 1 1 1 + + -15.3077 -3.23581 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -10.0853 -0.385134 0 0 0 -1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -0.53527 -8.31014 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 9.01474 -0.135134 0 0 -0 1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -0.53527 7.78986 0 0 0 -3.11542 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -5.73027 2.94986 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -0.43027 0.399866 0 0 0 -1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -7.79527 -1.73014 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 4.53973 -5.69514 0 0 -0 1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 6.74974 3.53486 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + + 0 0 0 0 -0 0 + 1 1 1 + + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + + -6.35985 -5.47044 0.499995 -1e-05 -0 -0 + 1 1 1 + + -6.35985 -5.47044 0.499995 -1e-05 -0 -0 + 0 0 0 0 -0 0 + 0.004709 0.011055 -9.78158 -0.022108 0.009414 1e-06 + 0.004709 0.011055 -9.78158 0 -0 0 + + + + 1.72376 5.13 0.5 0 -0 0 + 1 1 1 + + 1.72376 5.13 0.5 0 -0 0 + 0 0 0 0 -0 0 + -0.004709 -9.78112 9.78158 0.712677 -0.009414 -4.3e-05 + -0.004709 -9.78112 9.78158 0 -0 0 + + + + -2.08128 -5.46626 0.499997 3e-06 4e-06 -0 + 1 1 1 + + -2.08128 -5.46626 0.499997 3e-06 4e-06 -0 + 0 0 0 0 -0 0 + 0 0 -9.8 0 -0 0 + 0 0 -9.8 0 -0 0 + + + + 3.24338 0.112286 0.499993 -3e-06 -4e-06 -0 + 1 1 1 + + 3.24338 0.112286 0.499993 -3e-06 -4e-06 -0 + 0 0 0 0 -0 0 + 0 0 -9.8 0 -0 0 + 0 0 -9.8 0 -0 0 + + + + 0 0 10 0 -0 0 + + + + + 7.40665 -3.57041 31.6489 0 1.4618 3.1242 + orbit + perspective + + + + diff --git a/src/origincar_description/world/test.world b/src/origincar_description/world/test.world new file mode 100644 index 0000000..8cbcf19 --- /dev/null +++ b/src/origincar_description/world/test.world @@ -0,0 +1,828 @@ + + + + 1 + 0 0 10 0 -0 0 + 0.8 0.8 0.8 1 + 0.2 0.2 0.2 1 + + 1000 + 0.9 + 0.01 + 0.001 + + -0.5 0.1 -0.9 + + 0 + 0 + 0 + + + + 1 + + + + + 0 0 1 + 100 100 + + + + + + 100 + 50 + + + + + + + + + + + 10 + + + 0 + + + 0 0 1 + 100 100 + + + + + + + 0 + 0 + 0 + + + 0 0 -9.8 + 6e-06 2.3e-05 -4.2e-05 + + + 0.001 + 1 + 1000 + + + 0.4 0.4 0.4 1 + 0.7 0.7 0.7 1 + 1 + + + + + EARTH_WGS84 + 0 + 0 + 0 + 0 + + + 2.92199 0.94347 0 0 -0 0 + + + + + 5.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 5.25 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -4.8877 -4.19109 0 0 -0 -1.5708 + 0 + 0 + 0 + + + + + + 10 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 10 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 0.0373 -6.74109 0 0 -0 0 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 1.06397 5.19109 0 0 -0 1.5708 + 0 + 0 + 0 + + + + + + 3.75 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.75 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 1.09029 -4.75661 0 0 -0 -1.5708 + 0 + 0 + 0 + + + + + + 13.5 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 13.5 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 4.9623 -0.066086 0 0 -0 1.5708 + 0 + 0 + 0 + + + + + + 10 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 10 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + 0.0373 6.60891 0 0 -0 3.14159 + 0 + 0 + 0 + + + + + + 9.75 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 9.75 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -4.8877 1.80891 0 0 -0 -1.5708 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -3.4123 3.54932 0 0 -0 0 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -1.8623 1.99932 0 0 -0 -1.5708 + 0 + 0 + 0 + + + + + + 3.25 0.15 2.5 + + + 0 0 1.25 0 -0 0 + 10 + + + + + + + + + + + + + + + 0 0 1.25 0 -0 0 + + + 3.25 0.15 2.5 + + + + + 1 1 1 1 + + + 0 + + + -0.312301 0.449317 0 0 -0 0 + 0 + 0 + 0 + + 1 + + + 0.15442 -3.50156 0.5 0 -0 0 + + + 1 + + 0.166667 + 0 + 0 + 0.166667 + 0 + 0.166667 + + 0 0 0 0 -0 0 + + + + + 1 1 1 + + + 10 + + + + + + + + + + + + + + + + + 1 1 1 + + + + + + + 0 + 0 + 0 + + + + 1.94616 -0.907636 0.5 0 -0 0 + + + 1 + + 0.145833 + 0 + 0 + 0.145833 + 0 + 0.125 + + 0 0 0 0 -0 0 + + + + + 0.5 + 1 + + + 10 + + + + + + + + + + + + + + + + + 0.5 + 1 + + + + + + + 0 + 0 + 0 + + + + 5.80896 0.105775 0.5 0 -0 0 + + + 1 + + 0.166667 + 0 + 0 + 0.166667 + 0 + 0.166667 + + 0 0 0 0 -0 0 + + + + + 1 1 1 + + + 10 + + + + + + + + + + + + + + + + + 1 1 1 + + + + + + + 0 + 0 + 0 + + + + 77 768000000 + 78 15142337 + 1770533307 91681029 + 77768 + + 2.92199 0.94347 0 0 -0 0 + 1 1 1 + + -1.96571 -3.24762 0 0 0 -1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 2.95929 -5.79762 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 3.98596 6.13456 0 0 -0 1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 4.01228 -3.81314 0 0 0 -1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 7.88429 0.877384 0 0 -0 1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 2.95929 7.55238 0 0 -0 3.14159 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -1.96571 2.75238 0 0 0 -1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + -0.49031 4.49279 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 1.05969 2.94279 0 0 0 -1.5708 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + 2.60969 1.39279 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + + 0 0 0 0 -0 0 + 1 1 1 + + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + 0 0 0 0 -0 0 + + + + 0.15442 -3.50156 0.5 0 -0 0.691942 + 1 1 1 + + 0.15442 -3.50156 0.5 0 -0 0.691942 + 0 0 0 0 -0 0 + -0 0 -0 0 -0 0 + -0 0 -0 0 -0 0 + + + + 5.80896 0.105775 0.5 0 -0 0.665093 + 1 1 1 + + 5.80896 0.105775 0.5 0 -0 0.665093 + 0 0 0 0 -0 0 + 7.28216 6.1355 9.84639 -2.8462 1.14378 -3.14153 + 7.28216 6.1355 9.84639 0 -0 0 + + + + 1.94616 -0.907634 0.499993 -3e-06 -3e-06 0 + 1 1 1 + + 1.94616 -0.907634 0.499993 -3e-06 -3e-06 0 + 0 0 0 0 -0 0 + 0 0 -9.8 0 -0 0 + 0 0 -9.8 0 -0 0 + + + + 0 0 10 0 -0 0 + + + + + 4.60766 -4.56851 22.292 -0 1.35564 1.44419 + orbit + perspective + + + + diff --git a/src/origincar_msg/CMakeLists.txt b/src/origincar_msg/CMakeLists.txt new file mode 100644 index 0000000..8697fbf --- /dev/null +++ b/src/origincar_msg/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.5) + +project(origincar_msg) + +# Default to C++14 +if(NOT CMAKE_C_STANDARD) + set(CMAKE_C_STANDARD 99) +endif() + +# Default to C++14 +if(NOT CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 14) +endif() + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + + +find_package(ament_cmake REQUIRED) +find_package(rosidl_default_generators REQUIRED) + +find_package(std_msgs REQUIRED) + +rosidl_generate_interfaces(${PROJECT_NAME} + "msg/Data.msg" + "msg/Sign.msg" + DEPENDENCIES std_msgs + ADD_LINTER_TESTS +) + +ament_export_dependencies(rosidl_default_runtime) + +ament_package() diff --git a/src/origincar_msg/msg/Data.msg b/src/origincar_msg/msg/Data.msg new file mode 100644 index 0000000..161f45e --- /dev/null +++ b/src/origincar_msg/msg/Data.msg @@ -0,0 +1,3 @@ +float32 x +float32 y +float32 z diff --git a/src/origincar_msg/msg/Sign.msg b/src/origincar_msg/msg/Sign.msg new file mode 100644 index 0000000..189d1f8 --- /dev/null +++ b/src/origincar_msg/msg/Sign.msg @@ -0,0 +1 @@ +int32 sign_data \ No newline at end of file diff --git a/src/origincar_msg/package.xml b/src/origincar_msg/package.xml new file mode 100644 index 0000000..bd08ee6 --- /dev/null +++ b/src/origincar_msg/package.xml @@ -0,0 +1,21 @@ + + + + origincar_msg + 0.0.0 + TODO: Package description + ps-micro + TODO: License declaration + + ament_cmake + + ament_lint_auto + ament_lint_common + rosidl_default_generators + rosidl_default_runtime + rosidl_interface_packages + + + ament_cmake + + diff --git a/src/zbw_slamtoolbox/CMakeLists.txt b/src/zbw_slamtoolbox/CMakeLists.txt new file mode 100644 index 0000000..6ec9f44 --- /dev/null +++ b/src/zbw_slamtoolbox/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.8) +project(zbw_slamtoolbox) + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) + +install( + DIRECTORY launch config + DESTINATION share/${PROJECT_NAME} +) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # comment the line when a copyright and license is added to all source files + set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # comment the line when this package is in a git repo and when + # a copyright and license is added to all source files + set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/src/zbw_slamtoolbox/config/mapper_params_online_async.yaml b/src/zbw_slamtoolbox/config/mapper_params_online_async.yaml new file mode 100644 index 0000000..b1853e6 --- /dev/null +++ b/src/zbw_slamtoolbox/config/mapper_params_online_async.yaml @@ -0,0 +1,22 @@ +slam_toolbox: + ros__parameters: + + # Plugin params + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_link + scan_topic: /scan + + transform_timeout: 5.0 + tf_buffer_duration: 30.0 + + minimum_range: 0.2 # 雷达硬件最小测距 + queue_size: 50 \ No newline at end of file diff --git a/src/zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml b/src/zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml new file mode 100644 index 0000000..2a956f8 --- /dev/null +++ b/src/zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml @@ -0,0 +1,77 @@ +slam_toolbox: + ros__parameters: + + # Plugin params + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_link + scan_topic: /scan + use_map_saver: true + mode: mapping #localization + + # if you'd like to immediately start continuing a map at a given pose + # or at the dock, but they are mutually exclusive, if pose is given + # will use pose + #map_file_name: test_steve + #map_start_pose: [0.0, 0.0, 0.0] + #map_start_at_dock: true + + debug_logging: false + throttle_scans: 2 + transform_publish_period: 0.02 #if 0 never publishes odometry + map_update_interval: 5.0 + resolution: 0.05 + min_laser_range: 0.0 #for rastering images + max_laser_range: 20.0 #for rastering images + minimum_time_interval: 0.5 + transform_timeout: 0.2 + tf_buffer_duration: 30. + stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps + enable_interactive_mode: true + + # General Parameters + use_scan_matching: true + use_scan_barycenter: true + minimum_travel_distance: 0.5 + minimum_travel_heading: 0.5 + scan_buffer_size: 10 + scan_buffer_maximum_scan_distance: 10.0 + link_match_minimum_response_fine: 0.1 + link_scan_maximum_distance: 1.5 + loop_search_maximum_distance: 3.0 + do_loop_closing: true + loop_match_minimum_chain_size: 10 + loop_match_maximum_variance_coarse: 3.0 + loop_match_minimum_response_coarse: 0.35 + loop_match_minimum_response_fine: 0.45 + + # Correlation Parameters - Correlation Parameters + correlation_search_space_dimension: 0.5 + correlation_search_space_resolution: 0.01 + correlation_search_space_smear_deviation: 0.1 + + # Correlation Parameters - Loop Closure Parameters + loop_search_space_dimension: 8.0 + loop_search_space_resolution: 0.05 + loop_search_space_smear_deviation: 0.03 + + # Scan Matcher Parameters + distance_variance_penalty: 0.5 + angle_variance_penalty: 1.0 + + fine_search_angle_offset: 0.00349 + coarse_search_angle_offset: 0.349 + coarse_angle_resolution: 0.0349 + minimum_angle_penalty: 0.9 + minimum_distance_penalty: 0.5 + use_response_expansion: true + min_pass_through: 2 + occupancy_threshold: 0.1 diff --git a/src/zbw_slamtoolbox/config/navigation.yaml b/src/zbw_slamtoolbox/config/navigation.yaml new file mode 100644 index 0000000..e69de29 diff --git a/src/zbw_slamtoolbox/launch/navigation.launch.py b/src/zbw_slamtoolbox/launch/navigation.launch.py new file mode 100644 index 0000000..8b28bf0 --- /dev/null +++ b/src/zbw_slamtoolbox/launch/navigation.launch.py @@ -0,0 +1,86 @@ +import os +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +def generate_launch_description(): + # 获取包路径 + cyy_navigation2_dir = get_package_share_directory('cyy_navigation2') + nav2_bringup_dir = get_package_share_directory('nav2_bringup') + + # 声明参数 + use_sim_time = LaunchConfiguration('use_sim_time', default='False') + slam = LaunchConfiguration('slam', default='False') + localization = LaunchConfiguration('localization', default='False') + + # 定义文件路径 + map_yaml_path = os.path.join(cyy_navigation2_dir, 'maps', 'cyy_map.yaml') + nav2_param_path = os.path.join(cyy_navigation2_dir, 'param', 'nav2_params.yaml') + slam_params_file = os.path.join(cyy_navigation2_dir, 'param', 'slam_toolbox_localization.yaml') + + # 定义地图基础路径(用于 .posegraph 文件) + map_base_path = os.path.join(cyy_navigation2_dir, 'maps', 'cyy_map') + + # 检查 .posegraph 文件是否存在 + posegraph_path = map_base_path + '.posegraph' + if not os.path.exists(posegraph_path): + print(f"警告: .posegraph 文件不存在: {posegraph_path}") + print("将使用 AMCL 替代") + use_slam_toolbox = False + else: + use_slam_toolbox = True + print(f"找到 .posegraph 文件: {posegraph_path}") + + # 创建启动描述 + ld = LaunchDescription([ + DeclareLaunchArgument('use_sim_time', default_value='False'), + DeclareLaunchArgument('slam', default_value='False'), + DeclareLaunchArgument('localization', default_value='False'), + ]) + + # 如果使用 slam_toolbox + if use_slam_toolbox: + slam_toolbox_node = Node( + package='slam_toolbox', + executable='localization_slam_toolbox_node', + name='slam_toolbox', + output='screen', + parameters=[ + slam_params_file, + {'use_sim_time': use_sim_time}, + {'map_file_name': map_base_path}, + {'map_start_pose': [0.0, 0.0, 0.0]} + ], + remappings=[('/scan', '/scan')] + ) + ld.add_action(slam_toolbox_node) + # 使用 slam_toolbox 时,Nav2 不启用定位 + localization_arg = 'False' + else: + # 使用 AMCL + localization_arg = 'True' + + # Nav2 启动 - 使用正确的路径 + nav2_launch_path = os.path.join(nav2_bringup_dir, 'launch', 'bringup_launch.py') + if not os.path.exists(nav2_launch_path): + print(f"错误: 找不到 Nav2 启动文件: {nav2_launch_path}") + return ld + + nav2_bringup_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource(nav2_launch_path), + launch_arguments={ + 'map': map_yaml_path, + 'use_sim_time': use_sim_time, + 'params_file': nav2_param_path, + 'slam': slam, + 'localization': localization_arg, + 'autostart': 'True', + }.items(), + ) + + ld.add_action(nav2_bringup_launch) + + return ld \ No newline at end of file diff --git a/src/zbw_slamtoolbox/launch/slamtoolbox.launch.py b/src/zbw_slamtoolbox/launch/slamtoolbox.launch.py new file mode 100644 index 0000000..be83830 --- /dev/null +++ b/src/zbw_slamtoolbox/launch/slamtoolbox.launch.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +from launch import LaunchDescription +from launch_ros.actions import Node, SetParameter +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + # 获取参数文件路径 + pkg_share = get_package_share_directory('zbw_slamtoolbox') + params_file = os.path.join(pkg_share, 'config', 'mapper_params_online_async.yaml') + + set_use_sim_time = SetParameter(name='use_sim_time', value=False) + + # 创建SLAM Toolbox节点 + slam_toolbox_node = Node( + package='slam_toolbox', + executable='async_slam_toolbox_node', # 或 sync_slam_toolbox_node + name='slam_toolbox', + output='screen', + parameters=[params_file] + ) + + + return LaunchDescription([ + set_use_sim_time, + slam_toolbox_node + ]) \ No newline at end of file diff --git a/src/zbw_slamtoolbox/package.xml b/src/zbw_slamtoolbox/package.xml new file mode 100644 index 0000000..0f1cc9c --- /dev/null +++ b/src/zbw_slamtoolbox/package.xml @@ -0,0 +1,18 @@ + + + + zbw_slamtoolbox + 0.0.0 + TODO: Package description + sunrise + TODO: License declaration + + ament_cmake + + ament_lint_auto + ament_lint_common + + + ament_cmake + + diff --git a/zbw_slamtoolbox/CMakeLists.txt b/zbw_slamtoolbox/CMakeLists.txt new file mode 100644 index 0000000..6ec9f44 --- /dev/null +++ b/zbw_slamtoolbox/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 3.8) +project(zbw_slamtoolbox) + +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + add_compile_options(-Wall -Wextra -Wpedantic) +endif() + +# find dependencies +find_package(ament_cmake REQUIRED) +# uncomment the following section in order to fill in +# further dependencies manually. +# find_package( REQUIRED) + +install( + DIRECTORY launch config + DESTINATION share/${PROJECT_NAME} +) + +if(BUILD_TESTING) + find_package(ament_lint_auto REQUIRED) + # the following line skips the linter which checks for copyrights + # comment the line when a copyright and license is added to all source files + set(ament_cmake_copyright_FOUND TRUE) + # the following line skips cpplint (only works in a git repo) + # comment the line when this package is in a git repo and when + # a copyright and license is added to all source files + set(ament_cmake_cpplint_FOUND TRUE) + ament_lint_auto_find_test_dependencies() +endif() + +ament_package() diff --git a/zbw_slamtoolbox/config/mapper_params_online_async.yaml b/zbw_slamtoolbox/config/mapper_params_online_async.yaml new file mode 100644 index 0000000..b1853e6 --- /dev/null +++ b/zbw_slamtoolbox/config/mapper_params_online_async.yaml @@ -0,0 +1,22 @@ +slam_toolbox: + ros__parameters: + + # Plugin params + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_link + scan_topic: /scan + + transform_timeout: 5.0 + tf_buffer_duration: 30.0 + + minimum_range: 0.2 # 雷达硬件最小测距 + queue_size: 50 \ No newline at end of file diff --git a/zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml b/zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml new file mode 100644 index 0000000..2a956f8 --- /dev/null +++ b/zbw_slamtoolbox/config/mapper_params_online_sync copy.yaml @@ -0,0 +1,77 @@ +slam_toolbox: + ros__parameters: + + # Plugin params + solver_plugin: solver_plugins::CeresSolver + ceres_linear_solver: SPARSE_NORMAL_CHOLESKY + ceres_preconditioner: SCHUR_JACOBI + ceres_trust_strategy: LEVENBERG_MARQUARDT + ceres_dogleg_type: TRADITIONAL_DOGLEG + ceres_loss_function: None + + # ROS Parameters + odom_frame: odom + map_frame: map + base_frame: base_link + scan_topic: /scan + use_map_saver: true + mode: mapping #localization + + # if you'd like to immediately start continuing a map at a given pose + # or at the dock, but they are mutually exclusive, if pose is given + # will use pose + #map_file_name: test_steve + #map_start_pose: [0.0, 0.0, 0.0] + #map_start_at_dock: true + + debug_logging: false + throttle_scans: 2 + transform_publish_period: 0.02 #if 0 never publishes odometry + map_update_interval: 5.0 + resolution: 0.05 + min_laser_range: 0.0 #for rastering images + max_laser_range: 20.0 #for rastering images + minimum_time_interval: 0.5 + transform_timeout: 0.2 + tf_buffer_duration: 30. + stack_size_to_use: 40000000 #// program needs a larger stack size to serialize large maps + enable_interactive_mode: true + + # General Parameters + use_scan_matching: true + use_scan_barycenter: true + minimum_travel_distance: 0.5 + minimum_travel_heading: 0.5 + scan_buffer_size: 10 + scan_buffer_maximum_scan_distance: 10.0 + link_match_minimum_response_fine: 0.1 + link_scan_maximum_distance: 1.5 + loop_search_maximum_distance: 3.0 + do_loop_closing: true + loop_match_minimum_chain_size: 10 + loop_match_maximum_variance_coarse: 3.0 + loop_match_minimum_response_coarse: 0.35 + loop_match_minimum_response_fine: 0.45 + + # Correlation Parameters - Correlation Parameters + correlation_search_space_dimension: 0.5 + correlation_search_space_resolution: 0.01 + correlation_search_space_smear_deviation: 0.1 + + # Correlation Parameters - Loop Closure Parameters + loop_search_space_dimension: 8.0 + loop_search_space_resolution: 0.05 + loop_search_space_smear_deviation: 0.03 + + # Scan Matcher Parameters + distance_variance_penalty: 0.5 + angle_variance_penalty: 1.0 + + fine_search_angle_offset: 0.00349 + coarse_search_angle_offset: 0.349 + coarse_angle_resolution: 0.0349 + minimum_angle_penalty: 0.9 + minimum_distance_penalty: 0.5 + use_response_expansion: true + min_pass_through: 2 + occupancy_threshold: 0.1 diff --git a/zbw_slamtoolbox/config/navigation.yaml b/zbw_slamtoolbox/config/navigation.yaml new file mode 100644 index 0000000..e69de29 diff --git a/zbw_slamtoolbox/launch/navigation.launch.py b/zbw_slamtoolbox/launch/navigation.launch.py new file mode 100644 index 0000000..8b28bf0 --- /dev/null +++ b/zbw_slamtoolbox/launch/navigation.launch.py @@ -0,0 +1,86 @@ +import os +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import IncludeLaunchDescription, DeclareLaunchArgument +from launch.launch_description_sources import PythonLaunchDescriptionSource +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import Node + +def generate_launch_description(): + # 获取包路径 + cyy_navigation2_dir = get_package_share_directory('cyy_navigation2') + nav2_bringup_dir = get_package_share_directory('nav2_bringup') + + # 声明参数 + use_sim_time = LaunchConfiguration('use_sim_time', default='False') + slam = LaunchConfiguration('slam', default='False') + localization = LaunchConfiguration('localization', default='False') + + # 定义文件路径 + map_yaml_path = os.path.join(cyy_navigation2_dir, 'maps', 'cyy_map.yaml') + nav2_param_path = os.path.join(cyy_navigation2_dir, 'param', 'nav2_params.yaml') + slam_params_file = os.path.join(cyy_navigation2_dir, 'param', 'slam_toolbox_localization.yaml') + + # 定义地图基础路径(用于 .posegraph 文件) + map_base_path = os.path.join(cyy_navigation2_dir, 'maps', 'cyy_map') + + # 检查 .posegraph 文件是否存在 + posegraph_path = map_base_path + '.posegraph' + if not os.path.exists(posegraph_path): + print(f"警告: .posegraph 文件不存在: {posegraph_path}") + print("将使用 AMCL 替代") + use_slam_toolbox = False + else: + use_slam_toolbox = True + print(f"找到 .posegraph 文件: {posegraph_path}") + + # 创建启动描述 + ld = LaunchDescription([ + DeclareLaunchArgument('use_sim_time', default_value='False'), + DeclareLaunchArgument('slam', default_value='False'), + DeclareLaunchArgument('localization', default_value='False'), + ]) + + # 如果使用 slam_toolbox + if use_slam_toolbox: + slam_toolbox_node = Node( + package='slam_toolbox', + executable='localization_slam_toolbox_node', + name='slam_toolbox', + output='screen', + parameters=[ + slam_params_file, + {'use_sim_time': use_sim_time}, + {'map_file_name': map_base_path}, + {'map_start_pose': [0.0, 0.0, 0.0]} + ], + remappings=[('/scan', '/scan')] + ) + ld.add_action(slam_toolbox_node) + # 使用 slam_toolbox 时,Nav2 不启用定位 + localization_arg = 'False' + else: + # 使用 AMCL + localization_arg = 'True' + + # Nav2 启动 - 使用正确的路径 + nav2_launch_path = os.path.join(nav2_bringup_dir, 'launch', 'bringup_launch.py') + if not os.path.exists(nav2_launch_path): + print(f"错误: 找不到 Nav2 启动文件: {nav2_launch_path}") + return ld + + nav2_bringup_launch = IncludeLaunchDescription( + PythonLaunchDescriptionSource(nav2_launch_path), + launch_arguments={ + 'map': map_yaml_path, + 'use_sim_time': use_sim_time, + 'params_file': nav2_param_path, + 'slam': slam, + 'localization': localization_arg, + 'autostart': 'True', + }.items(), + ) + + ld.add_action(nav2_bringup_launch) + + return ld \ No newline at end of file diff --git a/zbw_slamtoolbox/launch/slamtoolbox.launch.py b/zbw_slamtoolbox/launch/slamtoolbox.launch.py new file mode 100644 index 0000000..be83830 --- /dev/null +++ b/zbw_slamtoolbox/launch/slamtoolbox.launch.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +from launch import LaunchDescription +from launch_ros.actions import Node, SetParameter +from ament_index_python.packages import get_package_share_directory +import os + +def generate_launch_description(): + # 获取参数文件路径 + pkg_share = get_package_share_directory('zbw_slamtoolbox') + params_file = os.path.join(pkg_share, 'config', 'mapper_params_online_async.yaml') + + set_use_sim_time = SetParameter(name='use_sim_time', value=False) + + # 创建SLAM Toolbox节点 + slam_toolbox_node = Node( + package='slam_toolbox', + executable='async_slam_toolbox_node', # 或 sync_slam_toolbox_node + name='slam_toolbox', + output='screen', + parameters=[params_file] + ) + + + return LaunchDescription([ + set_use_sim_time, + slam_toolbox_node + ]) \ No newline at end of file diff --git a/zbw_slamtoolbox/package.xml b/zbw_slamtoolbox/package.xml new file mode 100644 index 0000000..0f1cc9c --- /dev/null +++ b/zbw_slamtoolbox/package.xml @@ -0,0 +1,18 @@ + + + + zbw_slamtoolbox + 0.0.0 + TODO: Package description + sunrise + TODO: License declaration + + ament_cmake + + ament_lint_auto + ament_lint_common + + + ament_cmake + +