created
This commit is contained in:
parent
f60cbc2ed3
commit
45d965671e
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -412,3 +412,4 @@ FodyWeavers.xsd
|
||||||
# Built Visual Studio Code Extensions
|
# Built Visual Studio Code Extensions
|
||||||
*.vsix
|
*.vsix
|
||||||
|
|
||||||
|
build
|
||||||
24
.gitmodules
vendored
Normal file
24
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
[submodule "src/Libraries/common_msgs"]
|
||||||
|
path = src/Libraries/common_msgs
|
||||||
|
url = https://git.pnkr.asia/DuongTD/common_msgs.git
|
||||||
|
[submodule "src/Libraries/costmap_2d"]
|
||||||
|
path = src/Libraries/costmap_2d
|
||||||
|
url = https://git.pnkr.asia/DuongTD/costmap_2d.git
|
||||||
|
[submodule "src/Libraries/geometry2"]
|
||||||
|
path = src/Libraries/geometry2
|
||||||
|
url = https://git.pnkr.asia/DuongTD/geometry2.git
|
||||||
|
[submodule "src/Libraries/xmlrpcpp"]
|
||||||
|
path = src/Libraries/xmlrpcpp
|
||||||
|
url = https://git.pnkr.asia/DuongTD/xmlrpcpp.git
|
||||||
|
[submodule "src/Libraries/laser_geometry"]
|
||||||
|
path = src/Libraries/laser_geometry
|
||||||
|
url = https://git.pnkr.asia/DuongTD/laser_geometry.git
|
||||||
|
[submodule "src/Libraries/robot_time"]
|
||||||
|
path = src/Libraries/robot_time
|
||||||
|
url = https://git.pnkr.asia/DuongTD/robot_time.git
|
||||||
|
[submodule "src/Libraries/voxel_grid"]
|
||||||
|
path = src/Libraries/voxel_grid
|
||||||
|
url = https://git.pnkr.asia/DuongTD/voxel_grid.git
|
||||||
|
[submodule "src/Libraries/data_convert"]
|
||||||
|
path = src/Libraries/data_convert
|
||||||
|
url = https://git.pnkr.asia/DuongTD/data_convert.git
|
||||||
71
.vscode/settings.json
vendored
Normal file
71
.vscode/settings.json
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"stdexcept": "cpp",
|
||||||
|
"cctype": "cpp",
|
||||||
|
"clocale": "cpp",
|
||||||
|
"cmath": "cpp",
|
||||||
|
"csignal": "cpp",
|
||||||
|
"cstdarg": "cpp",
|
||||||
|
"cstddef": "cpp",
|
||||||
|
"cstdio": "cpp",
|
||||||
|
"cstdlib": "cpp",
|
||||||
|
"cstring": "cpp",
|
||||||
|
"ctime": "cpp",
|
||||||
|
"cwchar": "cpp",
|
||||||
|
"cwctype": "cpp",
|
||||||
|
"array": "cpp",
|
||||||
|
"atomic": "cpp",
|
||||||
|
"strstream": "cpp",
|
||||||
|
"bit": "cpp",
|
||||||
|
"bitset": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"compare": "cpp",
|
||||||
|
"complex": "cpp",
|
||||||
|
"concepts": "cpp",
|
||||||
|
"condition_variable": "cpp",
|
||||||
|
"cstdint": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"map": "cpp",
|
||||||
|
"set": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"exception": "cpp",
|
||||||
|
"algorithm": "cpp",
|
||||||
|
"functional": "cpp",
|
||||||
|
"iterator": "cpp",
|
||||||
|
"memory": "cpp",
|
||||||
|
"memory_resource": "cpp",
|
||||||
|
"numeric": "cpp",
|
||||||
|
"optional": "cpp",
|
||||||
|
"random": "cpp",
|
||||||
|
"ratio": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"system_error": "cpp",
|
||||||
|
"tuple": "cpp",
|
||||||
|
"type_traits": "cpp",
|
||||||
|
"utility": "cpp",
|
||||||
|
"fstream": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"iomanip": "cpp",
|
||||||
|
"iosfwd": "cpp",
|
||||||
|
"iostream": "cpp",
|
||||||
|
"istream": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"mutex": "cpp",
|
||||||
|
"new": "cpp",
|
||||||
|
"ostream": "cpp",
|
||||||
|
"ranges": "cpp",
|
||||||
|
"sstream": "cpp",
|
||||||
|
"stop_token": "cpp",
|
||||||
|
"streambuf": "cpp",
|
||||||
|
"thread": "cpp",
|
||||||
|
"cfenv": "cpp",
|
||||||
|
"cinttypes": "cpp",
|
||||||
|
"typeindex": "cpp",
|
||||||
|
"typeinfo": "cpp",
|
||||||
|
"variant": "cpp",
|
||||||
|
"codecvt": "cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
58
CATKIN_BUILD_README.md
Normal file
58
CATKIN_BUILD_README.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Catkin Build Instructions
|
||||||
|
|
||||||
|
## Vấn đề
|
||||||
|
|
||||||
|
Thư mục này có `CMakeLists.txt` ở root để hỗ trợ **standalone CMake build**.
|
||||||
|
Tuy nhiên, **catkin workspace không được phép có CMakeLists.txt ở root**.
|
||||||
|
|
||||||
|
Khi chạy `catkin_make` trong thư mục này, bạn sẽ gặp lỗi:
|
||||||
|
```
|
||||||
|
The specified base path contains a CMakeLists.txt but "catkin_make" must be invoked in the root of workspace
|
||||||
|
```
|
||||||
|
|
||||||
|
## Giải pháp
|
||||||
|
|
||||||
|
### Option 1: Sử dụng script tự động (Khuyến nghị)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Chạy script setup
|
||||||
|
./setup_catkin_workspace.sh
|
||||||
|
|
||||||
|
# Build trong workspace mới
|
||||||
|
cd ../pnkx_nav_catkin_ws
|
||||||
|
catkin_make
|
||||||
|
source devel/setup.bash
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option 2: Tạo workspace thủ công
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Tạo workspace
|
||||||
|
mkdir -p ~/pnkx_nav_catkin_ws/src
|
||||||
|
cd ~/pnkx_nav_catkin_ws/src
|
||||||
|
|
||||||
|
# Link các packages có package.xml
|
||||||
|
ln -s /path/to/pnkx_nav_core/src/Navigations/Packages/move_base move_base
|
||||||
|
# ... link các packages khác nếu cần
|
||||||
|
|
||||||
|
# Build
|
||||||
|
cd ~/pnkx_nav_catkin_ws
|
||||||
|
catkin_make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build Systems
|
||||||
|
|
||||||
|
Project này hỗ trợ **2 build systems**:
|
||||||
|
|
||||||
|
1. **Standalone CMake** (mặc định)
|
||||||
|
- Build trực tiếp trong thư mục này: `mkdir build && cd build && cmake .. && make`
|
||||||
|
- Không cần catkin workspace
|
||||||
|
|
||||||
|
2. **Catkin** (cho ROS integration)
|
||||||
|
- Cần tạo workspace riêng (xem hướng dẫn trên)
|
||||||
|
- Packages tự động detect catkin mode khi build trong workspace
|
||||||
|
|
||||||
|
## Chi tiết
|
||||||
|
|
||||||
|
Xem `src/Navigations/Packages/move_base/BUILD_INSTRUCTIONS.md` để biết chi tiết về cách build package `move_base` với cả hai hệ thống.
|
||||||
|
|
||||||
140
CMakeLists.txt
Normal file
140
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
# ========================================================
|
||||||
|
# ROOT CMakeLists.txt
|
||||||
|
# Đặt ở: Navigations/CMakeLists.txt
|
||||||
|
# ========================================================
|
||||||
|
cmake_minimum_required(VERSION 3.0.2)
|
||||||
|
project(navigations VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Chuẩn C++
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Build type
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Flags chung
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
|
||||||
|
|
||||||
|
message(STATUS "========================================")
|
||||||
|
message(STATUS "Building Navigations Project")
|
||||||
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||||
|
message(STATUS "========================================")
|
||||||
|
|
||||||
|
# Build các packages theo thứ tự phụ thuộc
|
||||||
|
# 1. Core libraries (header-only hoặc base libraries)
|
||||||
|
|
||||||
|
if (NOT TARGET tf3)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/tf3)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET robot_time)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/robot_time)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET xmlrpcpp)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/xmlrpcpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET robot_cpp)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/robot_cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET data_convert)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/data_convert)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET geometry2)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/geometry2)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET common_msgs)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/common_msgs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET laser_geometry)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/laser_geometry)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET voxel_grid)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/voxel_grid)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET nav_grid)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Navigations/Libraries/nav_grid)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET nav_2d_msgs)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/nav_2d_msgs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET costmap_2d)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/costmap_2d)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET nav_2d_utils)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Libraries/nav_2d_utils)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET nav_core)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Navigations/Cores/nav_core)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET nav_core2)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Navigations/Cores/nav_core2)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
if (NOT TARGET nav_core_adapter)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Navigations/Cores/nav_core_adapter)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET move_base_core)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Navigations/Cores/move_base_core)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET mkt_msgs)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Algorithms/Libraries/mkt_msgs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET angles)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Algorithms/Libraries/angles)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET kalman)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Algorithms/Libraries/kalman)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET score_algorithm)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Algorithms/Cores/score_algorithm)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#if (NOT TARGET mkt_algorithm)
|
||||||
|
# add_subdirectory(${CMAKE_SOURCE_DIR}/src/Algorithms/Libraries/mkt_algorithm)
|
||||||
|
#endif()
|
||||||
|
|
||||||
|
if (NOT TARGET two_points_planner)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Algorithms/Packages/global_planners/two_points_planner)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
# 2. Main packages (phụ thuộc vào cores)
|
||||||
|
message(STATUS "[move_base] Shared library configured")
|
||||||
|
if (NOT TARGET move_base)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/Navigations/Packages/move_base)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# C API for .NET/C# integration
|
||||||
|
if (NOT TARGET navigation_c_api)
|
||||||
|
add_subdirectory(${CMAKE_SOURCE_DIR}/src/APIs/c_api)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "========================================")
|
||||||
|
message(STATUS "All packages configured successfully")
|
||||||
|
message(STATUS "========================================")
|
||||||
|
|
||||||
|
|
||||||
48
config/base_local_planner_params.yaml
Normal file
48
config/base_local_planner_params.yaml
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#For full documentation of the parameters in this file, and a list of all the
|
||||||
|
#parameters available for TrajectoryPlannerROS, please see
|
||||||
|
#http://www.ros.org/wiki/base_local_planner
|
||||||
|
TrajectoryPlannerROS:
|
||||||
|
#Set the acceleration limits of the robot
|
||||||
|
acc_lim_th: 3.2
|
||||||
|
acc_lim_x: 0.5
|
||||||
|
acc_lim_y: 0.5
|
||||||
|
|
||||||
|
#Set the velocity limits of the robot
|
||||||
|
max_vel_x: 0.4
|
||||||
|
min_vel_x: 0.1
|
||||||
|
max_rotational_vel: 1.0
|
||||||
|
min_in_place_rotational_vel: 0.4
|
||||||
|
|
||||||
|
#The velocity the robot will command when trying to escape from a stuck situation
|
||||||
|
escape_vel: -0.2
|
||||||
|
|
||||||
|
#For this example, we'll use a holonomic robot
|
||||||
|
holonomic_robot: false
|
||||||
|
|
||||||
|
#Since we're using a holonomic robot, we'll set the set of y velocities it will sample
|
||||||
|
y_vels: [-0.3, -0.1, 0.1, 0.3]
|
||||||
|
|
||||||
|
#Set the tolerance on achieving a goal
|
||||||
|
xy_goal_tolerance: 0.1
|
||||||
|
yaw_goal_tolerance: 0.05
|
||||||
|
|
||||||
|
#We'll configure how long and with what granularity we'll forward simulate trajectories
|
||||||
|
sim_time: 3.0
|
||||||
|
sim_granularity: 0.025
|
||||||
|
vx_samples: 5
|
||||||
|
vtheta_samples: 20
|
||||||
|
|
||||||
|
#Parameters for scoring trajectories
|
||||||
|
goal_distance_bias: 0.4
|
||||||
|
path_distance_bias: 0.7
|
||||||
|
occdist_scale: 0.3
|
||||||
|
heading_lookahead: 0.325
|
||||||
|
|
||||||
|
#We'll use the Dynamic Window Approach to control instead of Trajectory Rollout for this example
|
||||||
|
dwa: false
|
||||||
|
|
||||||
|
#How far the robot must travel before oscillation flags are reset
|
||||||
|
oscillation_reset_dist: 0.01
|
||||||
|
|
||||||
|
#Eat up the plan as the robot moves along it
|
||||||
|
prune_plan: false
|
||||||
54
config/costmap_common_params.yaml
Executable file
54
config/costmap_common_params.yaml
Executable file
|
|
@ -0,0 +1,54 @@
|
||||||
|
robot_base_frame: base_footprint
|
||||||
|
transform_tolerance: 1.0
|
||||||
|
obstacle_range: 3.0
|
||||||
|
#mark_threshold: 1
|
||||||
|
publish_voxel_map: true
|
||||||
|
footprint_padding: 0.0
|
||||||
|
|
||||||
|
navigation_map:
|
||||||
|
map_topic: /map
|
||||||
|
map_pkg: managerments
|
||||||
|
map_file: maze
|
||||||
|
|
||||||
|
virtual_walls_map:
|
||||||
|
map_topic: /virtual_walls/map
|
||||||
|
namespace: /virtual_walls
|
||||||
|
map_pkg: managerments
|
||||||
|
map_file: maze
|
||||||
|
use_maximum: true
|
||||||
|
lethal_cost_threshold: 100
|
||||||
|
|
||||||
|
obstacles:
|
||||||
|
observation_sources: f_scan_marking f_scan_clearing b_scan_marking b_scan_clearing
|
||||||
|
f_scan_marking:
|
||||||
|
topic: /f_scan
|
||||||
|
data_type: LaserScan
|
||||||
|
clearing: false
|
||||||
|
marking: true
|
||||||
|
inf_is_valid: false
|
||||||
|
min_obstacle_height: 0.0
|
||||||
|
max_obstacle_height: 0.25
|
||||||
|
f_scan_clearing:
|
||||||
|
topic: /f_scan
|
||||||
|
data_type: LaserScan
|
||||||
|
clearing: true
|
||||||
|
marking: false
|
||||||
|
inf_is_valid: false
|
||||||
|
min_obstacle_height: 0.0
|
||||||
|
max_obstacle_height: 0.25
|
||||||
|
b_scan_marking:
|
||||||
|
topic: /b_scan
|
||||||
|
data_type: LaserScan
|
||||||
|
clearing: false
|
||||||
|
marking: true
|
||||||
|
inf_is_valid: false
|
||||||
|
min_obstacle_height: 0.0
|
||||||
|
max_obstacle_height: 0.25
|
||||||
|
b_scan_clearing:
|
||||||
|
topic: /b_scan
|
||||||
|
data_type: LaserScan
|
||||||
|
clearing: true
|
||||||
|
marking: false
|
||||||
|
inf_is_valid: false
|
||||||
|
min_obstacle_height: 0.0
|
||||||
|
max_obstacle_height: 0.25
|
||||||
13
config/costmap_global_params.yaml
Executable file
13
config/costmap_global_params.yaml
Executable file
|
|
@ -0,0 +1,13 @@
|
||||||
|
global_costmap:
|
||||||
|
global_frame: map
|
||||||
|
update_frequency: 1.0
|
||||||
|
publish_frequency: 1.0
|
||||||
|
raytrace_range: 2.0
|
||||||
|
resolution: 0.05
|
||||||
|
z_resolution: 0.2
|
||||||
|
rolling_window: false
|
||||||
|
z_voxels: 10
|
||||||
|
inflation:
|
||||||
|
cost_scaling_factor: 10.0 # Exponential rate at which the obstacle cost drops off (default: 10). Must be chosen so that the cost value is > 0 at robot's circumscribed radius.
|
||||||
|
inflation_radius: 0.6 # Max. distance from an obstacle at which costs are incurred for planning paths. Must be > robot's circumscribed radius.
|
||||||
|
|
||||||
10
config/costmap_global_params_plugins_no_virtual_walls.yaml
Executable file
10
config/costmap_global_params_plugins_no_virtual_walls.yaml
Executable file
|
|
@ -0,0 +1,10 @@
|
||||||
|
global_costmap:
|
||||||
|
frame_id: map
|
||||||
|
plugins:
|
||||||
|
- {name: navigation_map, type: "costmap_2d::StaticLayer" }
|
||||||
|
- {name: virtual_walls_map, type: "costmap_2d::StaticLayer" }
|
||||||
|
- {name: obstacles, type: "costmap_2d::VoxelLayer" }
|
||||||
|
- {name: inflation, type: "costmap_2d::InflationLayer" }
|
||||||
|
obstacles:
|
||||||
|
enabled: false
|
||||||
|
footprint_clearing_enabled: false
|
||||||
16
config/costmap_local_params.yaml
Executable file
16
config/costmap_local_params.yaml
Executable file
|
|
@ -0,0 +1,16 @@
|
||||||
|
local_costmap:
|
||||||
|
global_frame: odom
|
||||||
|
update_frequency: 6.0
|
||||||
|
publish_frequency: 6.0
|
||||||
|
rolling_window: true
|
||||||
|
raytrace_range: 2.0
|
||||||
|
resolution: 0.05
|
||||||
|
z_resolution: 0.15
|
||||||
|
z_voxels: 8
|
||||||
|
inflation:
|
||||||
|
cost_scaling_factor: 10.0 # Exponential rate at which the obstacle cost drops off (default: 10). Must be chosen so that the cost value is > 0 at robot's circumscribed radius.
|
||||||
|
inflation_radius: 0.3 # Max. distance from an obstacle at which costs are incurred for planning paths. Must be > robot's circumscribed radius.
|
||||||
|
width: 8.0
|
||||||
|
height: 8.0
|
||||||
|
origin_x: 0.0
|
||||||
|
origin_y: 0.0
|
||||||
8
config/costmap_local_params_plugins_no_virtual_walls.yaml
Executable file
8
config/costmap_local_params_plugins_no_virtual_walls.yaml
Executable file
|
|
@ -0,0 +1,8 @@
|
||||||
|
local_costmap:
|
||||||
|
frame_id: odom
|
||||||
|
plugins:
|
||||||
|
- {name: obstacles, type: "costmap_2d::VoxelLayer" }
|
||||||
|
- {name: inflation, type: "costmap_2d::InflationLayer" }
|
||||||
|
obstacles:
|
||||||
|
enabled: true
|
||||||
|
footprint_clearing_enabled: true
|
||||||
17
config/custom_global_params.yaml
Normal file
17
config/custom_global_params.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
base_global_planner: CustomPlanner
|
||||||
|
CustomPlanner:
|
||||||
|
environment_type: XYThetaLattice
|
||||||
|
planner_type: ARAPlanner
|
||||||
|
allocated_time: 10.0
|
||||||
|
initial_epsilon: 1.0
|
||||||
|
force_scratch_limit: 10000
|
||||||
|
forward_search: false
|
||||||
|
nominalvel_mpersecs: 0.8
|
||||||
|
timetoturn45degsinplace_secs: 1.31 # = 0.6 rad/s
|
||||||
|
allow_unknown: true
|
||||||
|
directory_to_save_paths: "/init/paths"
|
||||||
|
pathway_filename: "pathway.txt"
|
||||||
|
current_pose_topic_name: "/amcl_pose"
|
||||||
|
map_frame_id: "map"
|
||||||
|
base_frame_id: "base_link"
|
||||||
|
|
||||||
55
config/dwa_local_planner_params.yaml
Executable file
55
config/dwa_local_planner_params.yaml
Executable file
|
|
@ -0,0 +1,55 @@
|
||||||
|
base_local_planner: dwa_local_planner/DWAPlannerROS
|
||||||
|
DWAPlannerROS:
|
||||||
|
# Robot configuration
|
||||||
|
max_vel_x: 0.8
|
||||||
|
min_vel_x: -0.2
|
||||||
|
|
||||||
|
max_vel_y: 0.0 # diff drive robot
|
||||||
|
min_vel_y: 0.0 # diff drive robot
|
||||||
|
|
||||||
|
max_trans_vel: 0.8 # choose slightly less than the base's capability
|
||||||
|
min_trans_vel: 0.1 # this is the min trans velocity when there is negligible rotational velocity
|
||||||
|
trans_stopped_vel: 0.03
|
||||||
|
|
||||||
|
# Warning!
|
||||||
|
# do not set min_trans_vel to 0.0 otherwise dwa will always think translational velocities
|
||||||
|
# are non-negligible and small in place rotational velocities will be created.
|
||||||
|
|
||||||
|
max_rot_vel: 1.0 # choose slightly less than the base's capability
|
||||||
|
min_rot_vel: 0.1 # this is the min angular velocity when there is negligible translational velocity
|
||||||
|
rot_stopped_vel: 0.1
|
||||||
|
|
||||||
|
acc_lim_x: 1.5
|
||||||
|
acc_lim_y: 0.0 # diff drive robot
|
||||||
|
acc_limit_trans: 1.5
|
||||||
|
acc_lim_theta: 2.0
|
||||||
|
|
||||||
|
# Goal tolerance
|
||||||
|
yaw_goal_tolerance: 0.03 # yaw_goal_tolerance > (sim_time * min_rot_vel) / 2 (from Navigation Tuning Guide)
|
||||||
|
xy_goal_tolerance: 0.08 # xy_goal_tolerance > (sim_time * min_vel_x) / 2
|
||||||
|
latch_xy_goal_tolerance: true
|
||||||
|
|
||||||
|
# Forward simulation
|
||||||
|
sim_time: 1.2
|
||||||
|
vx_samples: 15
|
||||||
|
vy_samples: 1 # diff drive robot, there is only one sample
|
||||||
|
vtheta_samples: 20
|
||||||
|
|
||||||
|
# Trajectory scoring
|
||||||
|
path_distance_bias: 64.0 # default: 32.0 mir: 32.0 - weighting for how much it should stick to the global path plan
|
||||||
|
goal_distance_bias: 12.0 # default: 24.0 mir: 48.0 - weighting for how much it should attempt to reach its goal
|
||||||
|
occdist_scale: 0.5 # default: 0.01 mir: 0.01 - weighting for how much the controller should avoid obstacles
|
||||||
|
forward_point_distance: 0.325 # default: 0.325 mir: 0.325 - how far along to place an additional scoring point
|
||||||
|
stop_time_buffer: 0.2 # default: 0.2 mir: 0.2 - amount of time a robot must stop before colliding for a valid traj.
|
||||||
|
scaling_speed: 0.25 # default: 0.25 mir: 0.25 - absolute velocity at which to start scaling the robot's footprint
|
||||||
|
max_scaling_factor: 0.2 # default: 0.2 mir: 0.2 - how much to scale the robot's footprint when at speed.
|
||||||
|
prune_plan: true
|
||||||
|
|
||||||
|
# Oscillation prevention
|
||||||
|
oscillation_reset_dist: 0.05 # 0.05 - how far to travel before resetting oscillation flags, in m
|
||||||
|
oscillation_reset_angle: 0.2 # 0.2 - the angle the robot must turn before resetting Oscillation flags, in rad
|
||||||
|
|
||||||
|
# Debugging
|
||||||
|
publish_traj_pc : true
|
||||||
|
publish_cost_grid_pc: true
|
||||||
|
global_frame_id: /odom # or <robot namespace>/odom
|
||||||
217
config/ekf.yaml
Executable file
217
config/ekf.yaml
Executable file
|
|
@ -0,0 +1,217 @@
|
||||||
|
# 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: 50
|
||||||
|
|
||||||
|
# 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: 0.1
|
||||||
|
|
||||||
|
# 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 specify how long the tf listener should wait for a transform to become available.
|
||||||
|
# Defaults to 0.0 if unspecified.
|
||||||
|
transform_timeout: 0.0
|
||||||
|
|
||||||
|
# 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: true
|
||||||
|
|
||||||
|
# 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: $(arg tf_prefix)odom # Defaults to "odom" if unspecified
|
||||||
|
base_link_frame: $(arg tf_prefix)base_footprint # Defaults to "base_link" if unspecified
|
||||||
|
world_frame: $(arg tf_prefix)odom # 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.
|
||||||
|
# see http://docs.ros.org/melodic/api/robot_localization/html/configuring_robot_localization.html
|
||||||
|
odom0_config: [false, false, false, # x y z
|
||||||
|
false, false, false, # roll pitch yaw
|
||||||
|
true, true, false, # vx vy vz
|
||||||
|
false, false, true, # vroll vpitch vyaw
|
||||||
|
false, false, false] # ax ay az
|
||||||
|
|
||||||
|
# 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: false
|
||||||
|
|
||||||
|
# [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<double>::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
|
||||||
|
#odom0_twist_rejection_threshold: 1
|
||||||
|
|
||||||
|
# Further input parameter examples
|
||||||
|
# see http://docs.ros.org/melodic/api/robot_localization/html/configuring_robot_localization.html
|
||||||
|
imu0: imu_data
|
||||||
|
imu0_config: [false, false, false, # x y z
|
||||||
|
false, false, true, # roll pitch yaw
|
||||||
|
false, false, false, # vx vy vz
|
||||||
|
false, false, true, # vroll vpitch vyaw
|
||||||
|
true, false, false] # ax ay az
|
||||||
|
imu0_nodelay: false
|
||||||
|
imu0_differential: false
|
||||||
|
imu0_relative: true
|
||||||
|
imu0_queue_size: 10
|
||||||
|
#imu0_pose_rejection_threshold: 0.8 # Note the difference in parameter names
|
||||||
|
#imu0_twist_rejection_threshold: 0.8 #
|
||||||
|
#imu0_linear_acceleration_rejection_threshold: 0.8 #
|
||||||
|
|
||||||
|
# [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: false
|
||||||
|
|
||||||
|
# [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.05, 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.03, 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.06, 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.025, 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.01, 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.02, 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.01, 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: [100.0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 100.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, 1e-9, 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, 1.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, 1e-9, 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, 1e-9, 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, 1.0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10.0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10.0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1e-9]
|
||||||
36
config/localization.yaml
Normal file
36
config/localization.yaml
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
Amcl:
|
||||||
|
use_map_topic: true
|
||||||
|
odom_model_type: "diff-corrected"
|
||||||
|
gui_publish_rate: 5.0
|
||||||
|
save_pose_rate: 0.5
|
||||||
|
laser_max_beams: 300
|
||||||
|
laser_min_range: -1.0
|
||||||
|
laser_max_range: -1.0
|
||||||
|
min_particles: 1000
|
||||||
|
max_particles: 3000
|
||||||
|
kld_err: 0.05
|
||||||
|
kld_z: 0.99
|
||||||
|
odom_alpha1: 0.02
|
||||||
|
odom_alpha2: 0.01
|
||||||
|
odom_alpha3: 0.01
|
||||||
|
odom_alpha4: 0.02
|
||||||
|
laser_z_hit: 0.5
|
||||||
|
laser_z_short: 0.05
|
||||||
|
laser_z_max: 0.05
|
||||||
|
laser_z_rand: 0.5
|
||||||
|
laser_sigma_hit: 0.2
|
||||||
|
laser_lambda_short: 0.1
|
||||||
|
laser_model_type: "likelihood_field"
|
||||||
|
laser_likelihood_max_dist: 1.0
|
||||||
|
update_min_d: 0.05
|
||||||
|
update_min_a: 0.05
|
||||||
|
odom_frame_id: odom
|
||||||
|
base_frame_id: base_footprint
|
||||||
|
global_frame_id: map
|
||||||
|
resample_interval: 1
|
||||||
|
transform_tolerance: 0.2
|
||||||
|
recovery_alpha_slow: 0.001
|
||||||
|
recovery_alpha_fast: 0.001
|
||||||
|
initial_pose_x: 0.0
|
||||||
|
initial_pose_y: 0.0
|
||||||
|
initial_pose_a: 0.0
|
||||||
152
config/maker_sources.yaml
Normal file
152
config/maker_sources.yaml
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
maker_sources: trolley charger dock_station undock_station dock_station_2 undock_station_2
|
||||||
|
trolley:
|
||||||
|
plugins:
|
||||||
|
- {name: 4legs, docking_planner: "DockPlanner", docking_nav: ""}
|
||||||
|
# - {name: qrcode, docking_planner: "TwoPointsPlanner", docking_nav: "" }
|
||||||
|
|
||||||
|
4legs:
|
||||||
|
maker_goal_frame: trolley_goal
|
||||||
|
footprint: [[0.583,-0.48],[0.583,0.48],[-0.583,0.48],[-0.583,-0.48]]
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60.0
|
||||||
|
vel_x: 0.25
|
||||||
|
vel_theta: 0.3
|
||||||
|
yaw_goal_tolerance: 0.015
|
||||||
|
xy_goal_tolerance: 0.015
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.16
|
||||||
|
|
||||||
|
qrcode:
|
||||||
|
maker_goal_frame: qr_trolley
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60.0
|
||||||
|
vel_x: 0.05
|
||||||
|
vel_theta: 0.5
|
||||||
|
allow_rotate: true
|
||||||
|
yaw_goal_tolerance: 0.015
|
||||||
|
xy_goal_tolerance: 0.02
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.16
|
||||||
|
|
||||||
|
charger:
|
||||||
|
plugins:
|
||||||
|
- {name: charger, docking_planner: "DockPlanner", docking_nav: ""}
|
||||||
|
|
||||||
|
charger:
|
||||||
|
maker_goal_frame: charger_goal
|
||||||
|
footprint: [[0.583,-0.48],[0.583,0.48],[-0.583,0.48],[-0.583,-0.48]]
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60
|
||||||
|
vel_x: 0.1
|
||||||
|
yaw_goal_tolerance: 0.015
|
||||||
|
xy_goal_tolerance: 0.015
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.16
|
||||||
|
|
||||||
|
dock_station:
|
||||||
|
plugins:
|
||||||
|
- {name: station, docking_planner: "DockPlanner", docking_nav: ""}
|
||||||
|
|
||||||
|
station:
|
||||||
|
maker_goal_frame: dock_station_goal
|
||||||
|
footprint: [[1.15,-0.55],[1.15,0.55],[-1.15,0.55],[-1.15,-0.55]]
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60
|
||||||
|
vel_x: 0.15
|
||||||
|
vel_theta: 0.3
|
||||||
|
yaw_goal_tolerance: 0.015
|
||||||
|
xy_goal_tolerance: 0.015
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.4
|
||||||
|
|
||||||
|
dock_station_2:
|
||||||
|
plugins:
|
||||||
|
- {name: station, docking_planner: "DockPlanner", docking_nav: ""}
|
||||||
|
|
||||||
|
station:
|
||||||
|
maker_goal_frame: dock_station_goal_2
|
||||||
|
footprint: [[1.15,-0.55],[1.15,0.55],[-1.15,0.55],[-1.15,-0.55]]
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60
|
||||||
|
vel_x: 0.15
|
||||||
|
vel_theta: 0.3
|
||||||
|
yaw_goal_tolerance: 0.015
|
||||||
|
xy_goal_tolerance: 0.015
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.4
|
||||||
|
|
||||||
|
undock_station:
|
||||||
|
plugins:
|
||||||
|
- {name: station, docking_planner: "DockPlanner", docking_nav: ""}
|
||||||
|
- {name: qrcode, docking_planner: "TwoPointsPlanner", docking_nav: "" }
|
||||||
|
|
||||||
|
station:
|
||||||
|
maker_goal_frame: undock_station_goal
|
||||||
|
footprint: [[0.583,-0.48],[0.583,0.48],[-0.583,0.48],[-0.583,-0.48]]
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60.0
|
||||||
|
vel_x: 0.25
|
||||||
|
vel_theta: 0.3
|
||||||
|
yaw_goal_tolerance: 0.015
|
||||||
|
xy_goal_tolerance: 0.015
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.16
|
||||||
|
|
||||||
|
qrcode:
|
||||||
|
maker_goal_frame: qr_trolley
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60.0
|
||||||
|
vel_x: 0.05
|
||||||
|
vel_theta: 0.5
|
||||||
|
allow_rotate: true
|
||||||
|
yaw_goal_tolerance: 0.015
|
||||||
|
xy_goal_tolerance: 0.03
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.16
|
||||||
|
|
||||||
|
undock_station_2:
|
||||||
|
plugins:
|
||||||
|
- {name: station, docking_planner: "DockPlanner", docking_nav: ""}
|
||||||
|
- {name: qrcode, docking_planner: "TwoPointsPlanner", docking_nav: "" }
|
||||||
|
|
||||||
|
station:
|
||||||
|
maker_goal_frame: undock_station_goal_2
|
||||||
|
footprint: [[0.583,-0.48],[0.583,0.48],[-0.583,0.48],[-0.583,-0.48]]
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60.0
|
||||||
|
vel_x: 0.25
|
||||||
|
vel_theta: 0.5
|
||||||
|
yaw_goal_tolerance: 0.015
|
||||||
|
xy_goal_tolerance: 0.03
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.16
|
||||||
|
|
||||||
|
qrcode:
|
||||||
|
maker_goal_frame: qr_trolley
|
||||||
|
delay: 1.5 # Cấm sửa không là không chạy được
|
||||||
|
timeout: 60.0
|
||||||
|
vel_x: 0.05
|
||||||
|
vel_theta: 0.5
|
||||||
|
allow_rotate: true
|
||||||
|
yaw_goal_tolerance: 0.02
|
||||||
|
xy_goal_tolerance: 0.02
|
||||||
|
min_lookahead_dist: 0.4
|
||||||
|
max_lookahead_dist: 1.0
|
||||||
|
lookahead_time: 1.5
|
||||||
|
angle_threshold: 0.16
|
||||||
63
config/mapping.yaml
Normal file
63
config/mapping.yaml
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
SlamToolBox:
|
||||||
|
# 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
|
||||||
|
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
|
||||||
|
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
|
||||||
|
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
|
||||||
24
config/move_base_common_params.yaml
Executable file
24
config/move_base_common_params.yaml
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
|
||||||
|
### replanning
|
||||||
|
controller_frequency: 20.0 # run controller at 15.0 Hz
|
||||||
|
controller_patience: 0.0 # if the controller failed, clear obstacles and retry; after 15.0 s, abort and replan
|
||||||
|
planner_frequency: 0.0 # don't continually replan (only when controller failed)
|
||||||
|
planner_patience: 5.0 # if the first planning attempt failed, abort planning retries after 5.0 s...
|
||||||
|
max_planning_retries: 5 # ... or after 10 attempts (whichever happens first)
|
||||||
|
oscillation_timeout: -1 # abort controller and trigger recovery behaviors after 30.0 s
|
||||||
|
oscillation_distance: 0.4
|
||||||
|
### recovery behaviors
|
||||||
|
recovery_behavior_enabled: true
|
||||||
|
recovery_behaviors: [
|
||||||
|
{name: aggressive_reset, type: clear_costmap_recovery/ClearCostmapRecovery},
|
||||||
|
{name: conservative_reset, type: clear_costmap_recovery/ClearCostmapRecovery},
|
||||||
|
]
|
||||||
|
|
||||||
|
conservative_reset:
|
||||||
|
reset_distance: 3.0 # clear obstacles farther away than 3.0 m
|
||||||
|
invert_area_to_clear: true
|
||||||
|
|
||||||
|
aggressive_reset:
|
||||||
|
reset_distance: 3.0
|
||||||
|
|
||||||
|
|
||||||
106
config/mpc_local_planner_params.yaml
Executable file
106
config/mpc_local_planner_params.yaml
Executable file
|
|
@ -0,0 +1,106 @@
|
||||||
|
base_local_planner: mpc_local_planner/MpcLocalPlannerROS
|
||||||
|
MpcLocalPlannerROS:
|
||||||
|
|
||||||
|
odom_topic: odom
|
||||||
|
|
||||||
|
## Robot settings
|
||||||
|
robot:
|
||||||
|
type: "unicycle"
|
||||||
|
unicycle:
|
||||||
|
max_vel_x: 0.5
|
||||||
|
max_vel_x_backwards: 0.3
|
||||||
|
max_vel_theta: 0.3
|
||||||
|
acc_lim_x: 0.4 # deactive bounds with zero
|
||||||
|
dec_lim_x: 0.4 # deactive bounds with zero
|
||||||
|
acc_lim_theta: 0.6 # deactivate bounds with zero
|
||||||
|
|
||||||
|
## Footprint model for collision avoidance
|
||||||
|
footprint_model:
|
||||||
|
type: "point"
|
||||||
|
is_footprint_dynamic: False
|
||||||
|
|
||||||
|
## Collision avoidance
|
||||||
|
collision_avoidance:
|
||||||
|
min_obstacle_dist: 0.5 # Note, this parameter must be chosen w.r.t. the footprint_model
|
||||||
|
enable_dynamic_obstacles: False
|
||||||
|
force_inclusion_dist: 0.5
|
||||||
|
cutoff_dist: 2.0
|
||||||
|
include_costmap_obstacles: True
|
||||||
|
costmap_obstacles_behind_robot_dist: 1.5
|
||||||
|
collision_check_no_poses: 5
|
||||||
|
|
||||||
|
## Planning grid
|
||||||
|
grid:
|
||||||
|
type: "fd_grid"
|
||||||
|
grid_size_ref: 20 # Set horizon length here (T = (grid_size_ref-1) * dt_ref); Note, also check max_global_plan_lookahead_dist
|
||||||
|
dt_ref: 0.3 # and here the corresponding temporal resolution
|
||||||
|
xf_fixed: [False, False, False] # Unfix final state -> we use terminal cost below
|
||||||
|
warm_start: True
|
||||||
|
collocation_method: "forward_differences"
|
||||||
|
cost_integration_method: "left_sum"
|
||||||
|
variable_grid:
|
||||||
|
enable: False # We want a fixed grid
|
||||||
|
min_dt: 0.0;
|
||||||
|
max_dt: 10.0;
|
||||||
|
grid_adaptation:
|
||||||
|
enable: True
|
||||||
|
dt_hyst_ratio: 0.1
|
||||||
|
min_grid_size: 2
|
||||||
|
max_grid_size: 50
|
||||||
|
|
||||||
|
## Planning options
|
||||||
|
planning:
|
||||||
|
objective:
|
||||||
|
type: "quadratic_form" # minimum_time requires grid/variable_grid/enable=True and grid/xf_fixed set properly
|
||||||
|
quadratic_form:
|
||||||
|
state_weights: [2.0, 2.0, 0.25]
|
||||||
|
control_weights: [0.1, 0.05]
|
||||||
|
integral_form: False
|
||||||
|
terminal_cost:
|
||||||
|
type: "quadratic" # can be "none"
|
||||||
|
quadratic:
|
||||||
|
final_state_weights: [10.0, 10.0, 0.5]
|
||||||
|
terminal_constraint:
|
||||||
|
type: "none" # can be "none"
|
||||||
|
l2_ball:
|
||||||
|
weight_matrix: [1.0, 1.0, 1.0]
|
||||||
|
radius: 5
|
||||||
|
|
||||||
|
## Controller options
|
||||||
|
controller:
|
||||||
|
outer_ocp_iterations: 1
|
||||||
|
xy_goal_tolerance: 0.05
|
||||||
|
yaw_goal_tolerance: 0.04
|
||||||
|
global_plan_overwrite_orientation: False
|
||||||
|
global_plan_prune_distance: 1.5
|
||||||
|
allow_init_with_backward_motion: True
|
||||||
|
max_global_plan_lookahead_dist: 1.0 # Check horizon length
|
||||||
|
force_reinit_new_goal_dist: 1.0
|
||||||
|
force_reinit_new_goal_angular: 1.57
|
||||||
|
force_reinit_num_steps: 0
|
||||||
|
prefer_x_feedback: False
|
||||||
|
publish_ocp_results: True
|
||||||
|
|
||||||
|
## Solver settings
|
||||||
|
solver:
|
||||||
|
type: "ipopt"
|
||||||
|
ipopt:
|
||||||
|
iterations: 100
|
||||||
|
max_cpu_time: -1.0
|
||||||
|
ipopt_numeric_options:
|
||||||
|
tol: 1e-3
|
||||||
|
ipopt_string_options:
|
||||||
|
linear_solver: "mumps"
|
||||||
|
hessian_approximation: "exact" # exact or limited-memory
|
||||||
|
lsq_lm:
|
||||||
|
iterations: 10
|
||||||
|
weight_init_eq: 2
|
||||||
|
weight_init_ineq: 2
|
||||||
|
weight_init_bounds: 2
|
||||||
|
weight_adapt_factor_eq: 1.5
|
||||||
|
weight_adapt_factor_ineq: 1.5
|
||||||
|
weight_adapt_factor_bounds: 1.5
|
||||||
|
weight_adapt_max_eq: 500
|
||||||
|
weight_adapt_max_ineq: 500
|
||||||
|
weight_adapt_max_bounds: 500
|
||||||
|
|
||||||
280
config/mprim/genmprim_unicycle_highcost_5cm.m
Executable file
280
config/mprim/genmprim_unicycle_highcost_5cm.m
Executable file
|
|
@ -0,0 +1,280 @@
|
||||||
|
% /*
|
||||||
|
% * Copyright (c) 2008, Maxim Likhachev
|
||||||
|
% * All rights reserved.
|
||||||
|
% *
|
||||||
|
% * Redistribution and use in source and binary forms, with or without
|
||||||
|
% * modification, are permitted provided that the following conditions are met:
|
||||||
|
% *
|
||||||
|
% * * Redistributions of source code must retain the above copyright
|
||||||
|
% * notice, this list of conditions and the following disclaimer.
|
||||||
|
% * * Redistributions in binary form must reproduce the above copyright
|
||||||
|
% * notice, this list of conditions and the following disclaimer in the
|
||||||
|
% * documentation and/or other materials provided with the distribution.
|
||||||
|
% * * Neither the name of the Carnegie Mellon University nor the names of its
|
||||||
|
% * contributors may be used to endorse or promote products derived from
|
||||||
|
% * this software without specific prior written permission.
|
||||||
|
% *
|
||||||
|
% * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
% * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
% * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
% * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
% * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
% * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
% * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
% * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
% * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
% * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
% * POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
% */
|
||||||
|
|
||||||
|
function[] = genmprim_unicycle_highcost_5cm(outfilename)
|
||||||
|
|
||||||
|
%
|
||||||
|
%generates motion primitives and saves them into file
|
||||||
|
%
|
||||||
|
%written by Maxim Likhachev
|
||||||
|
%---------------------------------------------------
|
||||||
|
%
|
||||||
|
|
||||||
|
%defines
|
||||||
|
|
||||||
|
UNICYCLE_MPRIM_16DEGS = 1;
|
||||||
|
|
||||||
|
|
||||||
|
if UNICYCLE_MPRIM_16DEGS == 1
|
||||||
|
resolution = 0.05;
|
||||||
|
numberofangles = 16; %preferably a power of 2, definitely multiple of 8
|
||||||
|
numberofprimsperangle = 7;
|
||||||
|
|
||||||
|
%multipliers (multiplier is used as costmult*cost)
|
||||||
|
forwardcostmult = 1;
|
||||||
|
backwardcostmult = 40;
|
||||||
|
forwardandturncostmult = 2;
|
||||||
|
sidestepcostmult = 10;
|
||||||
|
turninplacecostmult = 20;
|
||||||
|
|
||||||
|
%note, what is shown x,y,theta changes (not absolute numbers)
|
||||||
|
|
||||||
|
%0 degreees
|
||||||
|
basemprimendpts0_c = zeros(numberofprimsperangle, 4); %x,y,theta,costmult
|
||||||
|
%x aligned with the heading of the robot, angles are positive
|
||||||
|
%counterclockwise
|
||||||
|
%0 theta change
|
||||||
|
basemprimendpts0_c(1,:) = [1 0 0 forwardcostmult];
|
||||||
|
basemprimendpts0_c(2,:) = [8 0 0 forwardcostmult];
|
||||||
|
basemprimendpts0_c(3,:) = [-1 0 0 backwardcostmult];
|
||||||
|
%1/16 theta change
|
||||||
|
basemprimendpts0_c(4,:) = [8 1 1 forwardandturncostmult];
|
||||||
|
basemprimendpts0_c(5,:) = [8 -1 -1 forwardandturncostmult];
|
||||||
|
%turn in place
|
||||||
|
basemprimendpts0_c(6,:) = [0 0 1 turninplacecostmult];
|
||||||
|
basemprimendpts0_c(7,:) = [0 0 -1 turninplacecostmult];
|
||||||
|
|
||||||
|
%45 degrees
|
||||||
|
basemprimendpts45_c = zeros(numberofprimsperangle, 4); %x,y,theta,costmult (multiplier is used as costmult*cost)
|
||||||
|
%x aligned with the heading of the robot, angles are positive
|
||||||
|
%counterclockwise
|
||||||
|
%0 theta change
|
||||||
|
basemprimendpts45_c(1,:) = [1 1 0 forwardcostmult];
|
||||||
|
basemprimendpts45_c(2,:) = [6 6 0 forwardcostmult];
|
||||||
|
basemprimendpts45_c(3,:) = [-1 -1 0 backwardcostmult];
|
||||||
|
%1/16 theta change
|
||||||
|
basemprimendpts45_c(4,:) = [5 7 1 forwardandturncostmult];
|
||||||
|
basemprimendpts45_c(5,:) = [7 5 -1 forwardandturncostmult];
|
||||||
|
%turn in place
|
||||||
|
basemprimendpts45_c(6,:) = [0 0 1 turninplacecostmult];
|
||||||
|
basemprimendpts45_c(7,:) = [0 0 -1 turninplacecostmult];
|
||||||
|
|
||||||
|
%22.5 degrees
|
||||||
|
basemprimendpts22p5_c = zeros(numberofprimsperangle, 4); %x,y,theta,costmult (multiplier is used as costmult*cost)
|
||||||
|
%x aligned with the heading of the robot, angles are positive
|
||||||
|
%counterclockwise
|
||||||
|
%0 theta change
|
||||||
|
basemprimendpts22p5_c(1,:) = [2 1 0 forwardcostmult];
|
||||||
|
basemprimendpts22p5_c(2,:) = [6 3 0 forwardcostmult];
|
||||||
|
basemprimendpts22p5_c(3,:) = [-2 -1 0 backwardcostmult];
|
||||||
|
%1/16 theta change
|
||||||
|
basemprimendpts22p5_c(4,:) = [5 4 1 forwardandturncostmult];
|
||||||
|
basemprimendpts22p5_c(5,:) = [7 2 -1 forwardandturncostmult];
|
||||||
|
%turn in place
|
||||||
|
basemprimendpts22p5_c(6,:) = [0 0 1 turninplacecostmult];
|
||||||
|
basemprimendpts22p5_c(7,:) = [0 0 -1 turninplacecostmult];
|
||||||
|
|
||||||
|
else
|
||||||
|
fprintf(1, 'ERROR: undefined mprims type\n');
|
||||||
|
return;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
fout = fopen(outfilename, 'w');
|
||||||
|
|
||||||
|
|
||||||
|
%write the header
|
||||||
|
fprintf(fout, 'resolution_m: %f\n', resolution);
|
||||||
|
fprintf(fout, 'numberofangles: %d\n', numberofangles);
|
||||||
|
fprintf(fout, 'totalnumberofprimitives: %d\n', numberofprimsperangle*numberofangles);
|
||||||
|
|
||||||
|
%iterate over angles
|
||||||
|
for angleind = 1:numberofangles
|
||||||
|
|
||||||
|
figure(1);
|
||||||
|
hold off;
|
||||||
|
|
||||||
|
text(0, 0, int2str(angleind));
|
||||||
|
|
||||||
|
%iterate over primitives
|
||||||
|
for primind = 1:numberofprimsperangle
|
||||||
|
fprintf(fout, 'primID: %d\n', primind-1);
|
||||||
|
fprintf(fout, 'startangle_c: %d\n', angleind-1);
|
||||||
|
|
||||||
|
%current angle
|
||||||
|
currentangle = (angleind-1)*2*pi/numberofangles;
|
||||||
|
currentangle_36000int = round((angleind-1)*36000/numberofangles);
|
||||||
|
|
||||||
|
%compute which template to use
|
||||||
|
if (rem(currentangle_36000int, 9000) == 0)
|
||||||
|
basemprimendpts_c = basemprimendpts0_c(primind,:);
|
||||||
|
angle = currentangle;
|
||||||
|
elseif (rem(currentangle_36000int, 4500) == 0)
|
||||||
|
basemprimendpts_c = basemprimendpts45_c(primind,:);
|
||||||
|
angle = currentangle - 45*pi/180;
|
||||||
|
elseif (rem(currentangle_36000int-7875, 9000) == 0)
|
||||||
|
basemprimendpts_c = basemprimendpts33p75_c(primind,:);
|
||||||
|
basemprimendpts_c(1) = basemprimendpts33p75_c(primind, 2); %reverse x and y
|
||||||
|
basemprimendpts_c(2) = basemprimendpts33p75_c(primind, 1);
|
||||||
|
basemprimendpts_c(3) = -basemprimendpts33p75_c(primind, 3); %reverse the angle as well
|
||||||
|
angle = currentangle - 78.75*pi/180;
|
||||||
|
fprintf(1, '78p75\n');
|
||||||
|
elseif (rem(currentangle_36000int-6750, 9000) == 0)
|
||||||
|
basemprimendpts_c = basemprimendpts22p5_c(primind,:);
|
||||||
|
basemprimendpts_c(1) = basemprimendpts22p5_c(primind, 2); %reverse x and y
|
||||||
|
basemprimendpts_c(2) = basemprimendpts22p5_c(primind, 1);
|
||||||
|
basemprimendpts_c(3) = -basemprimendpts22p5_c(primind, 3); %reverse the angle as well
|
||||||
|
%fprintf(1, '%d %d %d onto %d %d %d\n', basemprimendpts22p5_c(1), basemprimendpts22p5_c(2), basemprimendpts22p5_c(3), ...
|
||||||
|
% basemprimendpts_c(1), basemprimendpts_c(2), basemprimendpts_c(3));
|
||||||
|
angle = currentangle - 67.5*pi/180;
|
||||||
|
fprintf(1, '67p5\n');
|
||||||
|
elseif (rem(currentangle_36000int-5625, 9000) == 0)
|
||||||
|
basemprimendpts_c = basemprimendpts11p25_c(primind,:);
|
||||||
|
basemprimendpts_c(1) = basemprimendpts11p25_c(primind, 2); %reverse x and y
|
||||||
|
basemprimendpts_c(2) = basemprimendpts11p25_c(primind, 1);
|
||||||
|
basemprimendpts_c(3) = -basemprimendpts11p25_c(primind, 3); %reverse the angle as well
|
||||||
|
angle = currentangle - 56.25*pi/180;
|
||||||
|
fprintf(1, '56p25\n');
|
||||||
|
elseif (rem(currentangle_36000int-3375, 9000) == 0)
|
||||||
|
basemprimendpts_c = basemprimendpts33p75_c(primind,:);
|
||||||
|
angle = currentangle - 33.75*pi/180;
|
||||||
|
fprintf(1, '33p75\n');
|
||||||
|
elseif (rem(currentangle_36000int-2250, 9000) == 0)
|
||||||
|
basemprimendpts_c = basemprimendpts22p5_c(primind,:);
|
||||||
|
angle = currentangle - 22.5*pi/180;
|
||||||
|
fprintf(1, '22p5\n');
|
||||||
|
elseif (rem(currentangle_36000int-1125, 9000) == 0)
|
||||||
|
basemprimendpts_c = basemprimendpts11p25_c(primind,:);
|
||||||
|
angle = currentangle - 11.25*pi/180;
|
||||||
|
fprintf(1, '11p25\n');
|
||||||
|
else
|
||||||
|
fprintf(1, 'ERROR: invalid angular resolution. angle = %d\n', currentangle_36000int);
|
||||||
|
return;
|
||||||
|
end;
|
||||||
|
|
||||||
|
%now figure out what action will be
|
||||||
|
baseendpose_c = basemprimendpts_c(1:3);
|
||||||
|
additionalactioncostmult = basemprimendpts_c(4);
|
||||||
|
endx_c = round(baseendpose_c(1)*cos(angle) - baseendpose_c(2)*sin(angle));
|
||||||
|
endy_c = round(baseendpose_c(1)*sin(angle) + baseendpose_c(2)*cos(angle));
|
||||||
|
endtheta_c = rem(angleind - 1 + baseendpose_c(3), numberofangles);
|
||||||
|
endpose_c = [endx_c endy_c endtheta_c];
|
||||||
|
|
||||||
|
fprintf(1, 'rotation angle=%f\n', angle*180/pi);
|
||||||
|
|
||||||
|
if baseendpose_c(2) == 0 & baseendpose_c(3) == 0
|
||||||
|
%fprintf(1, 'endpose=%d %d %d\n', endpose_c(1), endpose_c(2), endpose_c(3));
|
||||||
|
end;
|
||||||
|
|
||||||
|
%generate intermediate poses (remember they are w.r.t 0,0 (and not
|
||||||
|
%centers of the cells)
|
||||||
|
numofsamples = 10;
|
||||||
|
intermcells_m = zeros(numofsamples,3);
|
||||||
|
if UNICYCLE_MPRIM_16DEGS == 1
|
||||||
|
startpt = [0 0 currentangle];
|
||||||
|
endpt = [endpose_c(1)*resolution endpose_c(2)*resolution ...
|
||||||
|
rem(angleind - 1 + baseendpose_c(3), numberofangles)*2*pi/numberofangles];
|
||||||
|
intermcells_m = zeros(numofsamples,3);
|
||||||
|
if ((endx_c == 0 & endy_c == 0) | baseendpose_c(3) == 0) %turn in place or move forward
|
||||||
|
for iind = 1:numofsamples
|
||||||
|
intermcells_m(iind,:) = [startpt(1) + (endpt(1) - startpt(1))*(iind-1)/(numofsamples-1) ...
|
||||||
|
startpt(2) + (endpt(2) - startpt(2))*(iind-1)/(numofsamples-1) ...
|
||||||
|
0];
|
||||||
|
rotation_angle = (baseendpose_c(3) ) * (2*pi/numberofangles);
|
||||||
|
intermcells_m(iind,3) = rem(startpt(3) + (rotation_angle)*(iind-1)/(numofsamples-1), 2*pi);
|
||||||
|
|
||||||
|
end;
|
||||||
|
else %unicycle-based move forward or backward
|
||||||
|
R = [cos(startpt(3)) sin(endpt(3)) - sin(startpt(3));
|
||||||
|
sin(startpt(3)) -(cos(endpt(3)) - cos(startpt(3)))];
|
||||||
|
S = pinv(R)*[endpt(1) - startpt(1); endpt(2) - startpt(2)];
|
||||||
|
l = S(1);
|
||||||
|
tvoverrv = S(2);
|
||||||
|
rv = (baseendpose_c(3)*2*pi/numberofangles + l/tvoverrv);
|
||||||
|
tv = tvoverrv*rv;
|
||||||
|
|
||||||
|
if l < 0
|
||||||
|
fprintf(1, 'WARNING: l = %d < 0 -> bad action start/end points\n', l);
|
||||||
|
l = 0;
|
||||||
|
end;
|
||||||
|
%compute rv
|
||||||
|
%rv = baseendpose_c(3)*2*pi/numberofangles;
|
||||||
|
%compute tv
|
||||||
|
%tvx = (endpt(1) - startpt(1))*rv/(sin(endpt(3)) - sin(startpt(3)))
|
||||||
|
%tvy = -(endpt(2) - startpt(2))*rv/(cos(endpt(3)) - cos(startpt(3)))
|
||||||
|
%tv = (tvx + tvy)/2.0;
|
||||||
|
%generate samples
|
||||||
|
for iind = 1:numofsamples
|
||||||
|
dt = (iind-1)/(numofsamples-1);
|
||||||
|
|
||||||
|
%dtheta = rv*dt + startpt(3);
|
||||||
|
%intermcells_m(iind,:) = [startpt(1) + tv/rv*(sin(dtheta) - sin(startpt(3))) ...
|
||||||
|
% startpt(2) - tv/rv*(cos(dtheta) - cos(startpt(3))) ...
|
||||||
|
% dtheta];
|
||||||
|
|
||||||
|
if(dt*tv < l)
|
||||||
|
intermcells_m(iind,:) = [startpt(1) + dt*tv*cos(startpt(3)) ...
|
||||||
|
startpt(2) + dt*tv*sin(startpt(3)) ...
|
||||||
|
startpt(3)];
|
||||||
|
else
|
||||||
|
dtheta = rv*(dt - l/tv) + startpt(3);
|
||||||
|
intermcells_m(iind,:) = [startpt(1) + l*cos(startpt(3)) + tvoverrv*(sin(dtheta) - sin(startpt(3))) ...
|
||||||
|
startpt(2) + l*sin(startpt(3)) - tvoverrv*(cos(dtheta) - cos(startpt(3))) ...
|
||||||
|
dtheta];
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
%correct
|
||||||
|
errorxy = [endpt(1) - intermcells_m(numofsamples,1) ...
|
||||||
|
endpt(2) - intermcells_m(numofsamples,2)];
|
||||||
|
fprintf(1, 'l=%f errx=%f erry=%f\n', l, errorxy(1), errorxy(2));
|
||||||
|
interpfactor = [0:1/(numofsamples-1):1];
|
||||||
|
intermcells_m(:,1) = intermcells_m(:,1) + errorxy(1)*interpfactor';
|
||||||
|
intermcells_m(:,2) = intermcells_m(:,2) + errorxy(2)*interpfactor';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
%write out
|
||||||
|
fprintf(fout, 'endpose_c: %d %d %d\n', endpose_c(1), endpose_c(2), endpose_c(3));
|
||||||
|
fprintf(fout, 'additionalactioncostmult: %d\n', additionalactioncostmult);
|
||||||
|
fprintf(fout, 'intermediateposes: %d\n', size(intermcells_m,1));
|
||||||
|
for interind = 1:size(intermcells_m, 1)
|
||||||
|
fprintf(fout, '%.4f %.4f %.4f\n', intermcells_m(interind,1), intermcells_m(interind,2), intermcells_m(interind,3));
|
||||||
|
end;
|
||||||
|
|
||||||
|
plot(intermcells_m(:,1), intermcells_m(:,2));
|
||||||
|
axis([-0.3 0.3 -0.3 0.3]);
|
||||||
|
text(intermcells_m(numofsamples,1), intermcells_m(numofsamples,2), int2str(endpose_c(3)));
|
||||||
|
hold on;
|
||||||
|
|
||||||
|
end;
|
||||||
|
grid;
|
||||||
|
pause;
|
||||||
|
end;
|
||||||
|
|
||||||
|
fclose('all');
|
||||||
416
config/mprim/genmprim_unicycle_highcost_5cm.py
Executable file
416
config/mprim/genmprim_unicycle_highcost_5cm.py
Executable file
|
|
@ -0,0 +1,416 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016, David Conner (Christopher Newport University)
|
||||||
|
# Based on genmprim_unicycle.m
|
||||||
|
# Copyright (c) 2008, Maxim Likhachev
|
||||||
|
# All rights reserved.
|
||||||
|
# converted by libermate utility (https://github.com/awesomebytes/libermate)
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of the Carnegie Mellon University nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import rospkg
|
||||||
|
|
||||||
|
# if available import pylab (from matlibplot)
|
||||||
|
matplotlib_found = False
|
||||||
|
try:
|
||||||
|
import matplotlib.pylab as plt
|
||||||
|
|
||||||
|
matplotlib_found = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def matrix_size(mat, elem=None):
|
||||||
|
if not elem:
|
||||||
|
return mat.shape
|
||||||
|
else:
|
||||||
|
return mat.shape[int(elem) - 1]
|
||||||
|
|
||||||
|
|
||||||
|
def genmprim_unicycle(outfilename, visualize=False, separate_plots=False):
|
||||||
|
visualize = matplotlib_found and visualize # Plot the primitives
|
||||||
|
|
||||||
|
# Local Variables: basemprimendpts22p5_c, endtheta_c, endx_c,
|
||||||
|
# baseendpose_c, additionalactioncostmult, fout, numofsamples,
|
||||||
|
# basemprimendpts45_c, primind, basemprimendpts0_c, rv, angle, outfilename,
|
||||||
|
# numberofangles, startpt, UNICYCLE_MPRIM_16DEGS, sidestepcostmult,
|
||||||
|
# rotation_angle, basemprimendpts_c, forwardandturncostmult,
|
||||||
|
# forwardcostmult, turninplacecostmult, endpose_c, backwardcostmult,
|
||||||
|
# interpfactor, S, R, tvoverrv, dtheta, intermcells_m, tv, dt,
|
||||||
|
# currentangle, numberofprimsperangle, resolution, currentangle_36000int,
|
||||||
|
# l, iind, errorxy, interind, endy_c, angleind, endpt
|
||||||
|
# Function calls: plot, cos, pi, grid, figure, genmprim_unicycle, text,
|
||||||
|
# int2str, pause, axis, sin, pinv, fprintf, fclose, rem, zeros, fopen,
|
||||||
|
# round, size
|
||||||
|
# %
|
||||||
|
# %generates motion primitives and saves them into file
|
||||||
|
# %
|
||||||
|
# %written by Maxim Likhachev
|
||||||
|
# %---------------------------------------------------
|
||||||
|
# %
|
||||||
|
# %defines
|
||||||
|
UNICYCLE_MPRIM_16DEGS = 1.0
|
||||||
|
if UNICYCLE_MPRIM_16DEGS == 1.0:
|
||||||
|
resolution = 0.05
|
||||||
|
numberofangles = 16
|
||||||
|
# %preferably a power of 2, definitely multiple of 8
|
||||||
|
numberofprimsperangle = 7
|
||||||
|
# %multipliers (multiplier is used as costmult*cost)
|
||||||
|
forwardcostmult = 1.0
|
||||||
|
backwardcostmult = 40.0
|
||||||
|
forwardandturncostmult = 2.0
|
||||||
|
# sidestepcostmult = 10.0
|
||||||
|
turninplacecostmult = 20.0
|
||||||
|
# %note, what is shown x,y,theta changes (not absolute numbers)
|
||||||
|
# %0 degreees
|
||||||
|
basemprimendpts0_c = np.zeros((numberofprimsperangle, 4))
|
||||||
|
# %x,y,theta,costmult
|
||||||
|
# %x aligned with the heading of the robot, angles are positive
|
||||||
|
# %counterclockwise
|
||||||
|
# %0 theta change
|
||||||
|
basemprimendpts0_c[0, :] = np.array(np.hstack((1.0, 0.0, 0.0, forwardcostmult)))
|
||||||
|
basemprimendpts0_c[1, :] = np.array(np.hstack((8.0, 0.0, 0.0, forwardcostmult)))
|
||||||
|
basemprimendpts0_c[2, :] = np.array(np.hstack((-1.0, 0.0, 0.0, backwardcostmult)))
|
||||||
|
# %1/16 theta change
|
||||||
|
basemprimendpts0_c[3, :] = np.array(np.hstack((8.0, 1.0, 1.0, forwardandturncostmult)))
|
||||||
|
basemprimendpts0_c[4, :] = np.array(np.hstack((8.0, -1.0, -1.0, forwardandturncostmult)))
|
||||||
|
# %turn in place
|
||||||
|
basemprimendpts0_c[5, :] = np.array(np.hstack((0.0, 0.0, 1.0, turninplacecostmult)))
|
||||||
|
basemprimendpts0_c[6, :] = np.array(np.hstack((0.0, 0.0, -1.0, turninplacecostmult)))
|
||||||
|
# %45 degrees
|
||||||
|
basemprimendpts45_c = np.zeros((numberofprimsperangle, 4))
|
||||||
|
# %x,y,theta,costmult (multiplier is used as costmult*cost)
|
||||||
|
# %x aligned with the heading of the robot, angles are positive
|
||||||
|
# %counterclockwise
|
||||||
|
# %0 theta change
|
||||||
|
basemprimendpts45_c[0, :] = np.array(np.hstack((1.0, 1.0, 0.0, forwardcostmult)))
|
||||||
|
basemprimendpts45_c[1, :] = np.array(np.hstack((6.0, 6.0, 0.0, forwardcostmult)))
|
||||||
|
basemprimendpts45_c[2, :] = np.array(np.hstack((-1.0, -1.0, 0.0, backwardcostmult)))
|
||||||
|
# %1/16 theta change
|
||||||
|
basemprimendpts45_c[3, :] = np.array(np.hstack((5.0, 7.0, 1.0, forwardandturncostmult)))
|
||||||
|
basemprimendpts45_c[4, :] = np.array(np.hstack((7.0, 5.0, -1.0, forwardandturncostmult)))
|
||||||
|
# %turn in place
|
||||||
|
basemprimendpts45_c[5, :] = np.array(np.hstack((0.0, 0.0, 1.0, turninplacecostmult)))
|
||||||
|
basemprimendpts45_c[6, :] = np.array(np.hstack((0.0, 0.0, -1.0, turninplacecostmult)))
|
||||||
|
# %22.5 degrees
|
||||||
|
basemprimendpts22p5_c = np.zeros((numberofprimsperangle, 4))
|
||||||
|
# %x,y,theta,costmult (multiplier is used as costmult*cost)
|
||||||
|
# %x aligned with the heading of the robot, angles are positive
|
||||||
|
# %counterclockwise
|
||||||
|
# %0 theta change
|
||||||
|
basemprimendpts22p5_c[0, :] = np.array(np.hstack((2.0, 1.0, 0.0, forwardcostmult)))
|
||||||
|
basemprimendpts22p5_c[1, :] = np.array(np.hstack((6.0, 3.0, 0.0, forwardcostmult)))
|
||||||
|
basemprimendpts22p5_c[2, :] = np.array(np.hstack((-2.0, -1.0, 0.0, backwardcostmult)))
|
||||||
|
# %1/16 theta change
|
||||||
|
basemprimendpts22p5_c[3, :] = np.array(np.hstack((5.0, 4.0, 1.0, forwardandturncostmult)))
|
||||||
|
basemprimendpts22p5_c[4, :] = np.array(np.hstack((7.0, 2.0, -1.0, forwardandturncostmult)))
|
||||||
|
# %turn in place
|
||||||
|
basemprimendpts22p5_c[5, :] = np.array(np.hstack((0.0, 0.0, 1.0, turninplacecostmult)))
|
||||||
|
basemprimendpts22p5_c[6, :] = np.array(np.hstack((0.0, 0.0, -1.0, turninplacecostmult)))
|
||||||
|
else:
|
||||||
|
print('ERROR: undefined mprims type\n')
|
||||||
|
return []
|
||||||
|
|
||||||
|
fout = open(outfilename, 'w')
|
||||||
|
# %write the header
|
||||||
|
fout.write('resolution_m: %f\n' % (resolution))
|
||||||
|
fout.write('numberofangles: %d\n' % (numberofangles))
|
||||||
|
fout.write('totalnumberofprimitives: %d\n' % (numberofprimsperangle * numberofangles))
|
||||||
|
# %iterate over angles
|
||||||
|
for angleind in np.arange(1.0, (numberofangles) + 1):
|
||||||
|
currentangle = ((angleind - 1) * 2.0 * np.pi) / numberofangles
|
||||||
|
currentangle_36000int = np.round((angleind - 1) * 36000.0 / numberofangles)
|
||||||
|
if visualize:
|
||||||
|
if separate_plots:
|
||||||
|
fig = plt.figure(angleind)
|
||||||
|
plt.title('angle {:2.0f} (= {:3.1f} degrees)'.format(angleind - 1, currentangle_36000int / 100.0))
|
||||||
|
else:
|
||||||
|
fig = plt.figure(1)
|
||||||
|
|
||||||
|
plt.axis('equal')
|
||||||
|
plt.axis([-10 * resolution, 10 * resolution, -10 * resolution, 10 * resolution])
|
||||||
|
ax = fig.add_subplot(1, 1, 1)
|
||||||
|
major_ticks = np.arange(-8 * resolution, 9 * resolution, 4 * resolution)
|
||||||
|
minor_ticks = np.arange(-8 * resolution, 9 * resolution, resolution)
|
||||||
|
ax.set_xticks(major_ticks)
|
||||||
|
ax.set_xticks(minor_ticks, minor=True)
|
||||||
|
ax.set_yticks(major_ticks)
|
||||||
|
ax.set_yticks(minor_ticks, minor=True)
|
||||||
|
ax.grid(which='minor', alpha=0.5)
|
||||||
|
ax.grid(which='major', alpha=0.9)
|
||||||
|
|
||||||
|
# %iterate over primitives
|
||||||
|
for primind in np.arange(1.0, (numberofprimsperangle) + 1):
|
||||||
|
fout.write('primID: %d\n' % (primind - 1))
|
||||||
|
fout.write('startangle_c: %d\n' % (angleind - 1))
|
||||||
|
# %current angle
|
||||||
|
# %compute which template to use
|
||||||
|
if (currentangle_36000int % 9000) == 0:
|
||||||
|
basemprimendpts_c = basemprimendpts0_c[int(primind) - 1, :]
|
||||||
|
angle = currentangle
|
||||||
|
elif (currentangle_36000int % 4500) == 0:
|
||||||
|
basemprimendpts_c = basemprimendpts45_c[int(primind) - 1, :]
|
||||||
|
angle = currentangle - 45.0 * np.pi / 180.0
|
||||||
|
|
||||||
|
# commented out because basemprimendpts33p75_c is undefined
|
||||||
|
# elif ((currentangle_36000int - 7875) % 9000) == 0:
|
||||||
|
# basemprimendpts_c = (
|
||||||
|
# 1 * basemprimendpts33p75_c[primind, :]
|
||||||
|
# ) # 1* to force deep copy to avoid reference update below
|
||||||
|
# basemprimendpts_c[0] = basemprimendpts33p75_c[primind, 1]
|
||||||
|
# # %reverse x and y
|
||||||
|
# basemprimendpts_c[1] = basemprimendpts33p75_c[primind, 0]
|
||||||
|
# basemprimendpts_c[2] = -basemprimendpts33p75_c[primind, 2]
|
||||||
|
# # %reverse the angle as well
|
||||||
|
# angle = currentangle - (78.75 * np.pi) / 180.0
|
||||||
|
# print('78p75\n')
|
||||||
|
|
||||||
|
elif ((currentangle_36000int - 6750) % 9000) == 0:
|
||||||
|
basemprimendpts_c = (
|
||||||
|
1 * basemprimendpts22p5_c[int(primind) - 1, :]
|
||||||
|
) # 1* to force deep copy to avoid reference update below
|
||||||
|
basemprimendpts_c[0] = basemprimendpts22p5_c[int(primind) - 1, 1]
|
||||||
|
# %reverse x and y
|
||||||
|
basemprimendpts_c[1] = basemprimendpts22p5_c[int(primind) - 1, 0]
|
||||||
|
basemprimendpts_c[2] = -basemprimendpts22p5_c[int(primind) - 1, 2]
|
||||||
|
# %reverse the angle as well
|
||||||
|
# print(
|
||||||
|
# '%d : %d %d %d onto %d %d %d\n'
|
||||||
|
# % (
|
||||||
|
# primind - 1,
|
||||||
|
# basemprimendpts22p5_c[int(primind) - 1, 0],
|
||||||
|
# basemprimendpts22p5_c[int(primind) - 1, 1],
|
||||||
|
# basemprimendpts22p5_c[int(primind) - 1, 2],
|
||||||
|
# basemprimendpts_c[0],
|
||||||
|
# basemprimendpts_c[1],
|
||||||
|
# basemprimendpts_c[2],
|
||||||
|
# )
|
||||||
|
# )
|
||||||
|
angle = currentangle - (67.5 * np.pi) / 180.0
|
||||||
|
print('67p5\n')
|
||||||
|
|
||||||
|
# commented out because basemprimendpts11p25_c is undefined
|
||||||
|
# elif ((currentangle_36000int - 5625) % 9000) == 0:
|
||||||
|
# basemprimendpts_c = (
|
||||||
|
# 1 * basemprimendpts11p25_c[primind, :]
|
||||||
|
# ) # 1* to force deep copy to avoid reference update below
|
||||||
|
# basemprimendpts_c[0] = basemprimendpts11p25_c[primind, 1]
|
||||||
|
# # %reverse x and y
|
||||||
|
# basemprimendpts_c[1] = basemprimendpts11p25_c[primind, 0]
|
||||||
|
# basemprimendpts_c[2] = -basemprimendpts11p25_c[primind, 2]
|
||||||
|
# # %reverse the angle as well
|
||||||
|
# angle = currentangle - (56.25 * np.pi) / 180.0
|
||||||
|
# print('56p25\n')
|
||||||
|
|
||||||
|
# commented out because basemprimendpts33p75_c is undefined
|
||||||
|
# elif ((currentangle_36000int - 3375) % 9000) == 0:
|
||||||
|
# basemprimendpts_c = basemprimendpts33p75_c[int(primind), :]
|
||||||
|
# angle = currentangle - (33.75 * np.pi) / 180.0
|
||||||
|
# print('33p75\n')
|
||||||
|
|
||||||
|
elif ((currentangle_36000int - 2250) % 9000) == 0:
|
||||||
|
basemprimendpts_c = basemprimendpts22p5_c[int(primind) - 1, :]
|
||||||
|
angle = currentangle - (22.5 * np.pi) / 180.0
|
||||||
|
print('22p5\n')
|
||||||
|
|
||||||
|
# commented out because basemprimendpts11p25_c is undefined
|
||||||
|
# elif ((currentangle_36000int - 1125) % 9000) == 0:
|
||||||
|
# basemprimendpts_c = basemprimendpts11p25_c[int(primind), :]
|
||||||
|
# angle = currentangle - (11.25 * np.pi) / 180.0
|
||||||
|
# print('11p25\n')
|
||||||
|
|
||||||
|
else:
|
||||||
|
print('ERROR: invalid angular resolution. angle = %d\n' % currentangle_36000int)
|
||||||
|
return []
|
||||||
|
|
||||||
|
# %now figure out what action will be
|
||||||
|
baseendpose_c = basemprimendpts_c[0:3]
|
||||||
|
additionalactioncostmult = basemprimendpts_c[3]
|
||||||
|
endx_c = np.round((baseendpose_c[0] * np.cos(angle)) - (baseendpose_c[1] * np.sin(angle)))
|
||||||
|
endy_c = np.round((baseendpose_c[0] * np.sin(angle)) + (baseendpose_c[1] * np.cos(angle)))
|
||||||
|
endtheta_c = np.fmod(angleind - 1 + baseendpose_c[2], numberofangles)
|
||||||
|
endpose_c = np.array(np.hstack((endx_c, endy_c, endtheta_c)))
|
||||||
|
print("endpose_c=", endpose_c)
|
||||||
|
print(('rotation angle=%f\n' % (angle * 180.0 / np.pi)))
|
||||||
|
# if np.logical_and(baseendpose_c[1] == 0., baseendpose_c[2] == 0.):
|
||||||
|
# %fprintf(1, 'endpose=%d %d %d\n', endpose_c(1), endpose_c(2), endpose_c(3));
|
||||||
|
|
||||||
|
# %generate intermediate poses (remember they are w.r.t 0,0 (and not
|
||||||
|
# %centers of the cells)
|
||||||
|
numofsamples = 10
|
||||||
|
intermcells_m = np.zeros((numofsamples, 3))
|
||||||
|
if UNICYCLE_MPRIM_16DEGS == 1.0:
|
||||||
|
startpt = np.array(np.hstack((0.0, 0.0, currentangle)))
|
||||||
|
endpt = np.array(
|
||||||
|
np.hstack(
|
||||||
|
(
|
||||||
|
(endpose_c[0] * resolution),
|
||||||
|
(endpose_c[1] * resolution),
|
||||||
|
(
|
||||||
|
((np.fmod(angleind - 1 + baseendpose_c[2], numberofangles)) * 2.0 * np.pi)
|
||||||
|
/ numberofangles
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
print("startpt =", startpt)
|
||||||
|
print("endpt =", endpt)
|
||||||
|
intermcells_m = np.zeros((numofsamples, 3))
|
||||||
|
if np.logical_or(np.logical_and(endx_c == 0.0, endy_c == 0.0), baseendpose_c[2] == 0.0):
|
||||||
|
# %turn in place or move forward
|
||||||
|
for iind in np.arange(1.0, (numofsamples) + 1):
|
||||||
|
fraction = float(iind - 1) / (numofsamples - 1)
|
||||||
|
intermcells_m[int(iind) - 1, :] = np.array(
|
||||||
|
(
|
||||||
|
startpt[0] + (endpt[0] - startpt[0]) * fraction,
|
||||||
|
startpt[1] + (endpt[1] - startpt[1]) * fraction,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
rotation_angle = baseendpose_c[2] * (2.0 * np.pi / numberofangles)
|
||||||
|
intermcells_m[int(iind) - 1, 2] = np.fmod(startpt[2] + rotation_angle * fraction, (2.0 * np.pi))
|
||||||
|
# print " ",iind," of ",numofsamples," fraction=",fraction," rotation=",rotation_angle
|
||||||
|
|
||||||
|
else:
|
||||||
|
# %unicycle-based move forward or backward (http://sbpl.net/node/53)
|
||||||
|
R = np.array(
|
||||||
|
np.vstack(
|
||||||
|
(
|
||||||
|
np.hstack((np.cos(startpt[2]), np.sin(endpt[2]) - np.sin(startpt[2]))),
|
||||||
|
np.hstack((np.sin(startpt[2]), -np.cos(endpt[2]) + np.cos(startpt[2]))),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
S = np.dot(np.linalg.pinv(R), np.array(np.vstack((endpt[0] - startpt[0], endpt[1] - startpt[1]))))
|
||||||
|
l = S[0]
|
||||||
|
tvoverrv = S[1]
|
||||||
|
rv = (baseendpose_c[2] * 2.0 * np.pi / numberofangles) + l / tvoverrv
|
||||||
|
tv = tvoverrv * rv
|
||||||
|
|
||||||
|
# print "R=\n",R
|
||||||
|
# print "Rpi=\n",np.linalg.pinv(R)
|
||||||
|
# print "S=\n",S
|
||||||
|
# print "l=",l
|
||||||
|
# print "tvoverrv=",tvoverrv
|
||||||
|
# print "rv=",rv
|
||||||
|
# print "tv=",tv
|
||||||
|
|
||||||
|
if l < 0.0:
|
||||||
|
print(('WARNING: l = %f < 0 -> bad action start/end points\n' % (l)))
|
||||||
|
l = 0.0
|
||||||
|
|
||||||
|
# %compute rv
|
||||||
|
# %rv = baseendpose_c(3)*2*pi/numberofangles;
|
||||||
|
# %compute tv
|
||||||
|
# %tvx = (endpt(1) - startpt(1))*rv/(sin(endpt(3)) - sin(startpt(3)))
|
||||||
|
# %tvy = -(endpt(2) - startpt(2))*rv/(cos(endpt(3)) - cos(startpt(3)))
|
||||||
|
# %tv = (tvx + tvy)/2.0;
|
||||||
|
# %generate samples
|
||||||
|
for iind in np.arange(1, numofsamples + 1):
|
||||||
|
dt = (iind - 1) / (numofsamples - 1)
|
||||||
|
# %dtheta = rv*dt + startpt(3);
|
||||||
|
# %intermcells_m(iind,:) = [startpt(1) + tv/rv*(sin(dtheta) - sin(startpt(3))) ...
|
||||||
|
# % startpt(2) - tv/rv*(cos(dtheta) - cos(startpt(3))) ...
|
||||||
|
# % dtheta];
|
||||||
|
if (dt * tv) < l:
|
||||||
|
intermcells_m[int(iind) - 1, :] = np.array(
|
||||||
|
np.hstack(
|
||||||
|
(
|
||||||
|
startpt[0] + dt * tv * np.cos(startpt[2]),
|
||||||
|
startpt[1] + dt * tv * np.sin(startpt[2]),
|
||||||
|
startpt[2],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
dtheta = rv * (dt - l / tv) + startpt[2]
|
||||||
|
intermcells_m[int(iind) - 1, :] = np.array(
|
||||||
|
np.hstack(
|
||||||
|
(
|
||||||
|
startpt[0]
|
||||||
|
+ l * np.cos(startpt[2])
|
||||||
|
+ tvoverrv * (np.sin(dtheta) - np.sin(startpt[2])),
|
||||||
|
startpt[1]
|
||||||
|
+ l * np.sin(startpt[2])
|
||||||
|
- tvoverrv * (np.cos(dtheta) - np.cos(startpt[2])),
|
||||||
|
dtheta,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# %correct
|
||||||
|
errorxy = np.array(
|
||||||
|
np.hstack(
|
||||||
|
(
|
||||||
|
endpt[0] - intermcells_m[int(numofsamples) - 1, 0],
|
||||||
|
endpt[1] - intermcells_m[int(numofsamples) - 1, 1],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# print('l=%f errx=%f erry=%f\n'%(l, errorxy[0], errorxy[1]))
|
||||||
|
interpfactor = np.array(
|
||||||
|
np.hstack((np.arange(0.0, 1.0 + (1.0 / (numofsamples)), 1.0 / (numofsamples - 1))))
|
||||||
|
)
|
||||||
|
|
||||||
|
# print "intermcells_m=",intermcells_m
|
||||||
|
# print "interp'=",interpfactor.conj().T
|
||||||
|
|
||||||
|
intermcells_m[:, 0] = intermcells_m[:, 0] + errorxy[0] * interpfactor.conj().T
|
||||||
|
intermcells_m[:, 1] = intermcells_m[:, 1] + errorxy[1] * interpfactor.conj().T
|
||||||
|
|
||||||
|
# %write out
|
||||||
|
fout.write('endpose_c: %d %d %d\n' % (endpose_c[0], endpose_c[1], endpose_c[2]))
|
||||||
|
fout.write('additionalactioncostmult: %d\n' % (additionalactioncostmult))
|
||||||
|
fout.write('intermediateposes: %d\n' % (matrix_size(intermcells_m, 1.0)))
|
||||||
|
for interind in np.arange(1.0, (matrix_size(intermcells_m, 1.0)) + 1):
|
||||||
|
fout.write(
|
||||||
|
'%.4f %.4f %.4f\n'
|
||||||
|
% (
|
||||||
|
intermcells_m[int(interind) - 1, 0],
|
||||||
|
intermcells_m[int(interind) - 1, 1],
|
||||||
|
intermcells_m[int(interind) - 1, 2],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if visualize:
|
||||||
|
plt.plot(intermcells_m[:, 0], intermcells_m[:, 1], linestyle="-", marker="o")
|
||||||
|
plt.text(endpt[0], endpt[1], '{:2.0f}'.format(endpose_c[2]))
|
||||||
|
# if (visualize):
|
||||||
|
# plt.waitforbuttonpress() # uncomment to plot each primitive set one at a time
|
||||||
|
|
||||||
|
fout.close()
|
||||||
|
if visualize:
|
||||||
|
# plt.waitforbuttonpress() # hold until buttom pressed
|
||||||
|
plt.show() # Keep windows open until the program is terminated
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
rospack = rospkg.RosPack()
|
||||||
|
outfilename = rospack.get_path('mir_navigation') + '/mprim/unicycle_highcost_5cm.mprim'
|
||||||
|
genmprim_unicycle(outfilename, visualize=True)
|
||||||
1203
config/mprim/unicycle_5cm.mprim
Executable file
1203
config/mprim/unicycle_5cm.mprim
Executable file
File diff suppressed because it is too large
Load Diff
1683
config/mprim/unicycle_5cm_expensive_turn_in_place.mprim
Executable file
1683
config/mprim/unicycle_5cm_expensive_turn_in_place.mprim
Executable file
File diff suppressed because it is too large
Load Diff
1683
config/mprim/unicycle_5cm_expensive_turn_in_place_highcost.mprim
Executable file
1683
config/mprim/unicycle_5cm_expensive_turn_in_place_highcost.mprim
Executable file
File diff suppressed because it is too large
Load Diff
2403
config/mprim/unicycle_5cm_noreverse_trolley.mprim
Executable file
2403
config/mprim/unicycle_5cm_noreverse_trolley.mprim
Executable file
File diff suppressed because it is too large
Load Diff
1683
config/mprim/unicycle_highcost_10cm.mprim
Executable file
1683
config/mprim/unicycle_highcost_10cm.mprim
Executable file
File diff suppressed because it is too large
Load Diff
1683
config/mprim/unicycle_highcost_1cm.mprim
Executable file
1683
config/mprim/unicycle_highcost_1cm.mprim
Executable file
File diff suppressed because it is too large
Load Diff
1683
config/mprim/unicycle_highcost_2_5cm.mprim
Executable file
1683
config/mprim/unicycle_highcost_2_5cm.mprim
Executable file
File diff suppressed because it is too large
Load Diff
1683
config/mprim/unicycle_highcost_2cm.mprim
Executable file
1683
config/mprim/unicycle_highcost_2cm.mprim
Executable file
File diff suppressed because it is too large
Load Diff
1683
config/mprim/unicycle_highcost_5cm.mprim
Executable file
1683
config/mprim/unicycle_highcost_5cm.mprim
Executable file
File diff suppressed because it is too large
Load Diff
8
config/mqtt_general.yaml
Normal file
8
config/mqtt_general.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
MQTT:
|
||||||
|
Name: T800
|
||||||
|
Host: 172.20.235.170
|
||||||
|
Port: 1885
|
||||||
|
Client_ID: T800
|
||||||
|
Username: robotics
|
||||||
|
Password: robotics
|
||||||
|
Keep_Alive: 60
|
||||||
186
config/pnkx_local_planner_params.yaml
Normal file
186
config/pnkx_local_planner_params.yaml
Normal file
|
|
@ -0,0 +1,186 @@
|
||||||
|
|
||||||
|
position_planner_name: PNKXLocalPlanner
|
||||||
|
docking_planner_name: PNKXDockingLocalPlanner
|
||||||
|
go_straight_planner_name: PNKXGoStraightLocalPlanner
|
||||||
|
rotate_planner_name: PNKXRotateLocalPlanner
|
||||||
|
|
||||||
|
base_local_planner: nav_core_adapter::LocalPlannerAdapter
|
||||||
|
yaw_goal_tolerance: 0.017
|
||||||
|
xy_goal_tolerance: 0.03
|
||||||
|
min_approach_linear_velocity: 0.06 # The minimum velocity (m/s) threshold to apply when approaching the goal to ensure progress. Must be > 0.01. (default: 0.05)
|
||||||
|
stateful: true
|
||||||
|
publish_topic: true
|
||||||
|
|
||||||
|
LocalPlannerAdapter:
|
||||||
|
PNKXLocalPlanner:
|
||||||
|
# Algorithm
|
||||||
|
trajectory_generator_name: mkt_plugins::LimitedAccelGenerator
|
||||||
|
algorithm_nav_name: mkt_algorithm::diff::PredictiveTrajectory
|
||||||
|
algorithm_rotate_name: mkt_algorithm::diff::RotateToGoal
|
||||||
|
# Goal checking
|
||||||
|
goal_checker_name: mkt_plugins::GoalChecker
|
||||||
|
|
||||||
|
PNKXDockingLocalPlanner:
|
||||||
|
# Algorithm
|
||||||
|
trajectory_generator_name: mkt_plugins::LimitedAccelGenerator
|
||||||
|
algorithm_nav_name: mkt_algorithm::diff::PredictiveTrajectory
|
||||||
|
algorithm_rotate_name: mkt_algorithm::diff::RotateToGoal
|
||||||
|
# Goal checking
|
||||||
|
goal_checker_name: mkt_plugins::GoalChecker
|
||||||
|
|
||||||
|
PNKXGoStraightLocalPlanner:
|
||||||
|
# Algorithm
|
||||||
|
trajectory_generator_name: mkt_plugins::LimitedAccelGenerator
|
||||||
|
algorithm_nav_name: mkt_algorithm::diff::GoStraight
|
||||||
|
# Goal checking
|
||||||
|
goal_checker_name: mkt_plugins::GoalChecker
|
||||||
|
|
||||||
|
PNKXRotateLocalPlanner:
|
||||||
|
# Algorithm
|
||||||
|
algorithm_rotate_name: mkt_algorithm::diff::RotateToGoal
|
||||||
|
trajectory_generator_name: mkt_plugins::LimitedAccelGenerator
|
||||||
|
# Goal checking
|
||||||
|
goal_checker_name: mkt_plugins::SimpleGoalChecker
|
||||||
|
stateful: true
|
||||||
|
|
||||||
|
LimitedAccelGenerator:
|
||||||
|
max_vel_x: 1.2
|
||||||
|
min_vel_x: -1.2
|
||||||
|
|
||||||
|
max_vel_y: 0.0 # diff drive robot
|
||||||
|
min_vel_y: 0.0 # diff drive robot
|
||||||
|
|
||||||
|
max_speed_xy: 2.0 # max_trans_vel: 0.8 # choose slightly less than the base's capability
|
||||||
|
min_speed_xy: 0.1 # min_trans_vel: 0.1 # this is the min trans velocity when there is negligible rotational velocity
|
||||||
|
|
||||||
|
max_vel_theta: 0.9 # max_rot_vel: 1.0 # choose slightly less than the base's capability
|
||||||
|
min_vel_theta: 0.04 # min_rot_vel: 0.1 default: 0.4 # this is the min angular velocity when there is negligible translational velocity
|
||||||
|
|
||||||
|
acc_lim_x: 1.0
|
||||||
|
acc_lim_y: 0.0 # diff drive robot
|
||||||
|
acc_lim_theta: 0.9
|
||||||
|
decel_lim_x: -1.0
|
||||||
|
decel_lim_y: -0.0
|
||||||
|
decel_lim_theta: -1.5
|
||||||
|
|
||||||
|
# Whether to split the path into segments or not
|
||||||
|
split_path: true
|
||||||
|
sim_time: 1.5
|
||||||
|
vx_samples: 15
|
||||||
|
vy_samples: 1
|
||||||
|
vtheta_samples: 10
|
||||||
|
discretize_by_time: true
|
||||||
|
angular_granularity: 0.05
|
||||||
|
linear_granularity: 0.1
|
||||||
|
# sim_period
|
||||||
|
include_last_point: true
|
||||||
|
|
||||||
|
PredictiveTrajectory:
|
||||||
|
avoid_obstacles: false
|
||||||
|
xy_local_goal_tolerance: 0.01
|
||||||
|
angle_threshold: 0.6
|
||||||
|
index_samples: 60
|
||||||
|
follow_step_path: true
|
||||||
|
|
||||||
|
# Lookahead
|
||||||
|
use_velocity_scaled_lookahead_dist: true # Whether to use the velocity scaled lookahead distances or constant lookahead_distance. (default: false)
|
||||||
|
# only when false:
|
||||||
|
lookahead_dist: 0.5 # The lookahead distance (m) to use to find the lookahead point. (default: 0.6)
|
||||||
|
# only when true:
|
||||||
|
min_lookahead_dist: 1.0 # The minimum lookahead distance (m) threshold. (default: 0.3)
|
||||||
|
max_lookahead_dist: 2.0 # The maximum lookahead distance (m) threshold. (default: 0.9)
|
||||||
|
lookahead_time: 1.6 # The time (s) to project the velocity by, a.k.a. lookahead gain. (default: 1.5)
|
||||||
|
min_journey_squared: 0.3 # Minimum squared journey to consider for goal (default: 0.2)
|
||||||
|
max_journey_squared: 0.8 # Maximum squared journey to consider for goal (default: 0.2)
|
||||||
|
|
||||||
|
# Rotate to heading param - onle one of use_rotate_to_heading and allow_reversing can be set to true
|
||||||
|
use_rotate_to_heading: true # Whether to enable rotating to rough heading and goal orientation when using holonomic planners. Recommended on for all robot types that can rotate in place. (default: true)
|
||||||
|
# only when true:
|
||||||
|
rotate_to_heading_min_angle: 0.03 # The difference in the path orientation and the starting robot orientation (radians) to trigger a rotate in place. (default: 0.785)
|
||||||
|
angular_decel_zone: 0.1
|
||||||
|
|
||||||
|
# stoped
|
||||||
|
rot_stopped_velocity: 0.1
|
||||||
|
trans_stopped_velocity: 0.1
|
||||||
|
|
||||||
|
# Regulated linear velocity scaling
|
||||||
|
use_regulated_linear_velocity_scaling: false # Whether to use the regulated features for path curvature (e.g. slow on high curvature paths). (default: true)
|
||||||
|
# only when true:
|
||||||
|
regulated_linear_scaling_min_radius: 0.6 # The turning radius (m) for which the regulation features are triggered. Remember, sharper turns have smaller radii. (default: 0.9)
|
||||||
|
regulated_linear_scaling_min_speed: 0.15 # The minimum speed (m/s) for which any of the regulated heuristics can send, to ensure process is still achievable even in high cost spaces with high curvature. Must be > 0.1. (default: 0.25)
|
||||||
|
|
||||||
|
# Inflation cost scaling (Limit velocity by proximity to obstacles)
|
||||||
|
use_cost_regulated_linear_velocity_scaling: false # Whether to use the regulated features for proximity to obstacles (e.g. slow in close proximity to obstacles). (default: true)
|
||||||
|
inflation_cost_scaling_factor: 2.0 # (default: 3.0) # must be > 0
|
||||||
|
cost_scaling_dist: 0.2 # (default: 0.6)
|
||||||
|
cost_scaling_gain: 2.0 # (default: 1.0)
|
||||||
|
|
||||||
|
GoStraight:
|
||||||
|
avoid_obstacles: false
|
||||||
|
xy_local_goal_tolerance: 0.01
|
||||||
|
angle_threshold: 0.6
|
||||||
|
index_samples: 60
|
||||||
|
follow_step_path: true
|
||||||
|
|
||||||
|
# Lookahead
|
||||||
|
use_velocity_scaled_lookahead_dist: true # Whether to use the velocity scaled lookahead distances or constant lookahead_distance. (default: false)
|
||||||
|
# only when false:
|
||||||
|
lookahead_dist: 0.5 # The lookahead distance (m) to use to find the lookahead point. (default: 0.6)
|
||||||
|
# only when true:
|
||||||
|
min_lookahead_dist: 0.8 # The minimum lookahead distance (m) threshold. (default: 0.3)
|
||||||
|
max_lookahead_dist: 1.5 # The maximum lookahead distance (m) threshold. (default: 0.9)
|
||||||
|
lookahead_time: 2.5 # The time (s) to project the velocity by, a.k.a. lookahead gain. (default: 1.5)
|
||||||
|
min_journey_squared: 0.3 # Minimum squared journey to consider for goal (default: 0.2)
|
||||||
|
max_journey_squared: 0.6 # Minimum squared journey to consider for goal (default: 0.2)
|
||||||
|
|
||||||
|
# Rotate to heading param - onle one of use_rotate_to_heading and allow_reversing can be set to true
|
||||||
|
use_rotate_to_heading: true # Whether to enable rotating to rough heading and goal orientation when using holonomic planners. Recommended on for all robot types that can rotate in place. (default: true)
|
||||||
|
# only when true:
|
||||||
|
rotate_to_heading_min_angle: 0.35 # The difference in the path orientation and the starting robot orientation (radians) to trigger a rotate in place. (default: 0.785)
|
||||||
|
|
||||||
|
# stoped
|
||||||
|
rot_stopped_velocity: 0.03
|
||||||
|
trans_stopped_velocity: 0.06
|
||||||
|
|
||||||
|
use_regulated_linear_velocity_scaling: false
|
||||||
|
use_cost_regulated_linear_velocity_scaling: false
|
||||||
|
|
||||||
|
RotateToGoal:
|
||||||
|
avoid_obstacles: false
|
||||||
|
xy_local_goal_tolerance: 0.01
|
||||||
|
angle_threshold: 0.6
|
||||||
|
index_samples: 60
|
||||||
|
follow_step_path: true
|
||||||
|
|
||||||
|
# Lookahead
|
||||||
|
use_velocity_scaled_lookahead_dist: true # Whether to use the velocity scaled lookahead distances or constant lookahead_distance. (default: false)
|
||||||
|
# only when false:
|
||||||
|
lookahead_dist: 0.325 # The lookahead distance (m) to use to find the lookahead point. (default: 0.6)
|
||||||
|
# only when true:
|
||||||
|
min_lookahead_dist: 0.8 # The minimum lookahead distance (m) threshold. (default: 0.3)
|
||||||
|
max_lookahead_dist: 1.5 # The maximum lookahead distance (m) threshold. (default: 0.9)
|
||||||
|
lookahead_time: 1.8 # The time (s) to project the velocity by, a.k.a. lookahead gain. (default: 1.5)
|
||||||
|
min_journey_squared: 0.3 # Minimum squared journey to consider for goal (default: 0.2)
|
||||||
|
max_journey_squared: 0.6 # Maximum squared journey to consider for goal (default: 0.2)
|
||||||
|
|
||||||
|
# Rotate to heading param - onle one of use_rotate_to_heading and allow_reversing can be set to true
|
||||||
|
use_rotate_to_heading: true # Whether to enable rotating to rough heading and goal orientation when using holonomic planners. Recommended on for all robot types that can rotate in place. (default: true)
|
||||||
|
# only when true:
|
||||||
|
rotate_to_heading_min_angle: 0.03 # The difference in the path orientation and the starting robot orientation (radians) to trigger a rotate in place. (default: 0.785)
|
||||||
|
angular_decel_zone: 0.1
|
||||||
|
|
||||||
|
# stoped
|
||||||
|
rot_stopped_velocity: 0.03
|
||||||
|
trans_stopped_velocity: 0.06
|
||||||
|
|
||||||
|
# Regulated linear velocity scaling
|
||||||
|
use_regulated_linear_velocity_scaling: false # Whether to use the regulated features for path curvature (e.g. slow on high curvature paths). (default: true)
|
||||||
|
# only when true:
|
||||||
|
regulated_linear_scaling_min_radius: 0.6 # The turning radius (m) for which the regulation features are triggered. Remember, sharper turns have smaller radii. (default: 0.9)
|
||||||
|
regulated_linear_scaling_min_speed: 0.05 # The minimum speed (m/s) for which any of the regulated heuristics can send, to ensure process is still achievable even in high cost spaces with high curvature. Must be > 0.1. (default: 0.25)
|
||||||
|
|
||||||
|
# Inflation cost scaling (Limit velocity by proximity to obstacles)
|
||||||
|
use_cost_regulated_linear_velocity_scaling: false # Whether to use the regulated features for proximity to obstacles (e.g. slow in close proximity to obstacles). (default: true)
|
||||||
|
inflation_cost_scaling_factor: 2.0 # (default: 3.0) # must be > 0
|
||||||
|
cost_scaling_dist: 0.2 # (default: 0.6)
|
||||||
|
cost_scaling_gain: 2.0 # (default: 1.0)
|
||||||
71
config/ros_diff_drive_controller.yaml
Executable file
71
config/ros_diff_drive_controller.yaml
Executable file
|
|
@ -0,0 +1,71 @@
|
||||||
|
# -----------------------------------
|
||||||
|
left_wheel : 'left_wheel_joint'
|
||||||
|
right_wheel : 'right_wheel_joint'
|
||||||
|
publish_rate: 50 # this is what the real MiR platform publishes (default: 50)
|
||||||
|
# These covariances are exactly what the real MiR platform publishes
|
||||||
|
pose_covariance_diagonal : [0.00001, 0.00001, 1000000.0, 1000000.0, 1000000.0, 1000.0]
|
||||||
|
twist_covariance_diagonal: [0.1, 0.1, 1000000.0, 1000000.0, 1000000.0, 1000.0]
|
||||||
|
enable_odom_tf: true
|
||||||
|
enable_wheel_tf: true
|
||||||
|
allow_multiple_cmd_vel_publishers: true
|
||||||
|
# open_loop: false
|
||||||
|
# Wheel separation and diameter. These are both optional.
|
||||||
|
# diff_drive_controller will attempt to read either one or both from the
|
||||||
|
# URDF if not specified as a parameter.
|
||||||
|
# We don't set the value here because it's different for each MiR type (100, 250, ...), and
|
||||||
|
# the plugin figures out the correct values.
|
||||||
|
wheel_separation : 0.5106
|
||||||
|
wheel_radius : 0.1
|
||||||
|
|
||||||
|
# Wheel separation and radius multipliers
|
||||||
|
wheel_separation_multiplier: 1.0 # default: 1.0
|
||||||
|
wheel_radius_multiplier : 1.0 # default: 1.0
|
||||||
|
|
||||||
|
# Velocity commands timeout [s], default 0.5
|
||||||
|
cmd_vel_timeout: 1.0
|
||||||
|
|
||||||
|
# frame_ids (same as real MiR platform)
|
||||||
|
base_frame_id: base_footprint # default: base_link base_footprint
|
||||||
|
odom_frame_id: odom # default: odom
|
||||||
|
|
||||||
|
# Velocity and acceleration limits
|
||||||
|
# Whenever a min_* is unspecified, default to -max_*
|
||||||
|
linear:
|
||||||
|
x:
|
||||||
|
has_velocity_limits : true
|
||||||
|
max_velocity : 1.5 # m/s; move_base max_vel_x: 0.8
|
||||||
|
min_velocity : -1.5 # m/s
|
||||||
|
has_acceleration_limits: true
|
||||||
|
max_acceleration : 0.5 # m/s^2; move_base acc_lim_x: 1.5
|
||||||
|
min_acceleration : -0.5 # m/s^2
|
||||||
|
has_jerk_limits : true
|
||||||
|
max_jerk : 3.0 # m/s^3
|
||||||
|
angular:
|
||||||
|
z:
|
||||||
|
has_velocity_limits : true
|
||||||
|
max_velocity : 1.0 # rad/s; move_base max_rot_vel: 1.0
|
||||||
|
min_velocity : -1.0
|
||||||
|
has_acceleration_limits: true
|
||||||
|
max_acceleration : 3.0 # rad/s^2; move_base acc_lim_th: 2.0
|
||||||
|
has_jerk_limits : true
|
||||||
|
max_jerk : 2.5 # rad/s^3
|
||||||
|
|
||||||
|
left_wheel_joint:
|
||||||
|
lookup_name: WheelPlugin
|
||||||
|
max_publish_rate: 50
|
||||||
|
mesurement_topic: left_encoder
|
||||||
|
frame_id: left_wheel_link
|
||||||
|
wheel_topic: /left_wheel
|
||||||
|
subscribe_queue_size: 1
|
||||||
|
command_timeout: 5.0
|
||||||
|
origin : [0.0, 0.255, 0.075, 0.0, 0.0, 0.0] # origin from base_frame_id
|
||||||
|
|
||||||
|
right_wheel_joint:
|
||||||
|
lookup_name: WheelPlugin
|
||||||
|
max_publish_rate: 50
|
||||||
|
mesurement_topic: right_encoder
|
||||||
|
frame_id: right_wheel_link
|
||||||
|
wheel_topic: /right_wheel
|
||||||
|
subscribe_queue_size: 1
|
||||||
|
command_timeout: 5.0
|
||||||
|
origin : [0.0, -0.255, 0.075, 0.0, 0.0, 0.0] # origin from base_frame_id
|
||||||
10
config/sbpl_global_params.yaml
Executable file
10
config/sbpl_global_params.yaml
Executable file
|
|
@ -0,0 +1,10 @@
|
||||||
|
base_global_planner: SBPLLatticePlanner
|
||||||
|
SBPLLatticePlanner:
|
||||||
|
environment_type: XYThetaLattice
|
||||||
|
planner_type: ARAPlanner
|
||||||
|
allocated_time: 10.0
|
||||||
|
initial_epsilon: 1.0
|
||||||
|
force_scratch_limit: 10000
|
||||||
|
forward_search: true
|
||||||
|
nominalvel_mpersecs: 0.2
|
||||||
|
timetoturn45degsinplace_secs: 0.6 # = 0.6 rad/s
|
||||||
61
config/sick_line_guidance_mls.yaml
Normal file
61
config/sick_line_guidance_mls.yaml
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
bus:
|
||||||
|
device: can0
|
||||||
|
driver_plugin: can::SocketCANInterface
|
||||||
|
master_allocator: canopen::SimpleMaster::Allocator
|
||||||
|
sync:
|
||||||
|
interval_ms: 10
|
||||||
|
overflow: 0
|
||||||
|
#
|
||||||
|
# heartbeat: # simple heartbeat producer (optional, not supported by OLS or MLS, do not enable heartbeats)
|
||||||
|
# rate: 100 # heartbeat rate (1/rate in seconds)
|
||||||
|
# msg: "77f#05" # message to send, cansend format: heartbeat of node 127 with status 5=Started
|
||||||
|
nodes:
|
||||||
|
f_mlse:
|
||||||
|
id: 0x01 # CAN-Node-ID of can device, default: Node-ID 10=0x0A for OLS and MLS
|
||||||
|
eds_pkg: sick_line_guidance # package name for relative path
|
||||||
|
eds_file: mls/SICK-MLS.eds # path to EDS/DCF file
|
||||||
|
publish: ["1001","1018sub1","1018sub4","2021sub1!","2021sub2!","2021sub3!","2021sub4!","2022!"]
|
||||||
|
# MLS: 1001 = error register, 1018sub1 = VendorID, 1018sub4 = SerialNumber, TPDO1 = 0x2021sub1 to 0x2021sub4 and 0x2022
|
||||||
|
|
||||||
|
# sick_line_guidance configuration of this node:
|
||||||
|
sick_device_family: "MLS" # can devices of OLS10, OLS20 or MLS family currently supported
|
||||||
|
sick_topic: "f_mlse" # MLS_Measurement messages are published in topic "/mls"
|
||||||
|
subscribe_queue_size: 1
|
||||||
|
sick_frame_id: "f_mlse" # MLS_Measurement messages are published frame_id "mls_measurement_frame"
|
||||||
|
|
||||||
|
# device configuration of writable parameter by dcf_overlay: "objectindex": "parametervalue"
|
||||||
|
# example: "2027": "0x01" # Object 2027 (sensorFlipped, defaultvalue 0x00) will be configured with value 0x01
|
||||||
|
# dcf_overlay:
|
||||||
|
# "2028sub1": "0x01" # UseMarkers (0 = disable marker detection, 1 = enable marker detection), UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
# "2028sub2": "0x02" # MarkerStyle (0 = disable marker detection, 1 = standard mode, 2 = extended mode), UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
# "2028sub3": "0x01" # FailSafeMode (0 = disabled, 1 = enabled), UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
# "2025": "1000" # Min.Level, UINT16, DataType=0x0006, defaultvalue=600
|
||||||
|
# "2026": "1" # Offset [mm] Nullpunkt, INT16, DataType=0x0003, defaultvalue=0
|
||||||
|
# "2027": "0x01" # sensorFlipped, UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
# "2029": "0x01" # LockTeach, UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
#
|
||||||
|
|
||||||
|
b_mlse:
|
||||||
|
id: 0x02 # CAN-Node-ID of can device, default: Node-ID 10=0x0A for OLS and MLS
|
||||||
|
eds_pkg: sick_line_guidance # package name for relative path
|
||||||
|
eds_file: mls/SICK-MLS.eds # path to EDS/DCF file
|
||||||
|
publish: ["1001","1018sub1","1018sub4","2021sub1!","2021sub2!","2021sub3!","2021sub4!","2022!"]
|
||||||
|
# MLS: 1001 = error register, 1018sub1 = VendorID, 1018sub4 = SerialNumber, TPDO1 = 0x2021sub1 to 0x2021sub4 and 0x2022
|
||||||
|
|
||||||
|
# sick_line_guidance configuration of this node:
|
||||||
|
sick_device_family: "MLS" # can devices of OLS10, OLS20 or MLS family currently supported
|
||||||
|
sick_topic: "b_mlse" # MLS_Measurement messages are published in topic "/mls"
|
||||||
|
subscribe_queue_size: 1
|
||||||
|
sick_frame_id: "b_mlse" # MLS_Measurement messages are published frame_id "mls_measurement_frame"
|
||||||
|
|
||||||
|
# device configuration of writable parameter by dcf_overlay: "objectindex": "parametervalue"
|
||||||
|
# example: "2027": "0x01" # Object 2027 (sensorFlipped, defaultvalue 0x00) will be configured with value 0x01
|
||||||
|
# dcf_overlay:
|
||||||
|
# "2028sub1": "0x01" # UseMarkers (0 = disable marker detection, 1 = enable marker detection), UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
# "2028sub2": "0x02" # MarkerStyle (0 = disable marker detection, 1 = standard mode, 2 = extended mode), UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
# "2028sub3": "0x01" # FailSafeMode (0 = disabled, 1 = enabled), UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
# "2025": "1000" # Min.Level, UINT16, DataType=0x0006, defaultvalue=600
|
||||||
|
# "2026": "1" # Offset [mm] Nullpunkt, INT16, DataType=0x0003, defaultvalue=0
|
||||||
|
# "2027": "0x01" # sensorFlipped, UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
# "2029": "0x01" # LockTeach, UINT8, DataType=0x0005, defaultvalue=0
|
||||||
|
#
|
||||||
3
config/two_points_global_params.yaml
Normal file
3
config/two_points_global_params.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
base_global_planner: TwoPointsPlanner
|
||||||
|
TwoPointsPlanner:
|
||||||
|
lethal_obstacle: 20
|
||||||
446
doc/architecture_discussion.md
Normal file
446
doc/architecture_discussion.md
Normal file
|
|
@ -0,0 +1,446 @@
|
||||||
|
# Thảo luận về Kiến trúc Navigation cho AMR
|
||||||
|
|
||||||
|
## Mục tiêu dự án
|
||||||
|
|
||||||
|
Nghiên cứu và phát triển hệ thống navigation (di chuyển bám quỹ đạo) cho robot AMR dạng hai bánh vi sai, **không sử dụng ROS**, viết thuần C++ với CMake trên Linux.
|
||||||
|
|
||||||
|
## Yêu cầu chức năng
|
||||||
|
|
||||||
|
Từ `readme.md`:
|
||||||
|
|
||||||
|
- Có khả năng thay đổi mô hình kinematics (dạng hai bánh vi sai, dạng steering bicycle, ...)
|
||||||
|
- Có chức năng di chuyển từ điểm khởi đầu đến điểm đích
|
||||||
|
- Có chức năng xoay tròn
|
||||||
|
- Có chức năng đi thẳng
|
||||||
|
- Có chức năng thay đổi vận tốc
|
||||||
|
|
||||||
|
## Sơ đồ kiến trúc hệ thống
|
||||||
|
|
||||||
|
Kiến trúc được thiết kế theo mô hình layered, tách biệt các concerns và cho phép mở rộng dễ dàng:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TB
|
||||||
|
%% ========== API LAYER ==========
|
||||||
|
subgraph API["🌐 API Layer"]
|
||||||
|
direction TB
|
||||||
|
CAPI["<b>📦 C API</b><br/>━━━━━━━━━━━━━━━━<br/>🔌 nav_c_api<br/>💻 P/Invoke cho .NET/C#<br/>📝 Wrapper Functions<br/>🔗 Interop Layer"]
|
||||||
|
style API fill:#E3F2FD,stroke:#1976D2,stroke-width:4px,color:#000
|
||||||
|
style CAPI fill:#BBDEFB,stroke:#1976D2,stroke-width:3px,font-size:14px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== USER CONTROLLER LAYER ==========
|
||||||
|
subgraph UserController["🎮 User Controller Layer"]
|
||||||
|
direction TB
|
||||||
|
UserCtrl["<b>🔌 User Controller Plugin</b><br/>━━━━━━━━━━━━━━━━<br/>📚 Dynamic Loader<br/>⚙️ boost::dll<br/>🎯 Custom Behavior<br/>🔄 Runtime Loading"]
|
||||||
|
style UserController fill:#F3E5F5,stroke:#7B1FA2,stroke-width:4px,color:#000
|
||||||
|
style UserCtrl fill:#E1BEE7,stroke:#7B1FA2,stroke-width:3px,font-size:14px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== INTERFACE LAYER ==========
|
||||||
|
subgraph Interface["🔌 Interface Layer"]
|
||||||
|
direction TB
|
||||||
|
BaseNav["<b>📋 BaseNavigation</b><br/>━━━━━━━━━━━━━━━━<br/>🏗️ move_base_core::BaseNavigation<br/>🎯 Abstract Interface<br/>━━━━━━━━━━━━━━━━<br/>📍 moveTo, dockTo<br/>🔄 rotateTo, moveStraightTo<br/>⏸️ pause, resume, cancel<br/>📊 getRobotPose"]
|
||||||
|
style Interface fill:#FFF3E0,stroke:#E65100,stroke-width:4px,color:#000
|
||||||
|
style BaseNav fill:#FFE0B2,stroke:#E65100,stroke-width:3px,font-size:14px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== MOVE BASE CORE ==========
|
||||||
|
subgraph MoveBaseCore["⚙️ Move Base Core"]
|
||||||
|
direction TB
|
||||||
|
MoveBase["<b>🚀 MoveBase</b><br/>━━━━━━━━━━━━━━━━<br/>📦 move_base::MoveBase<br/>🔄 State Machine<br/>━━━━━━━━━━━━━━━━<br/>📊 PLANNING<br/>🎮 CONTROLLING<br/>🧹 CLEARING<br/>━━━━━━━━━━━━━━━━<br/>🎛️ Control Loop<br/>🔄 executeCycle"]
|
||||||
|
style MoveBaseCore fill:#E8F5E9,stroke:#2E7D32,stroke-width:4px,color:#000
|
||||||
|
style MoveBase fill:#C8E6C9,stroke:#2E7D32,stroke-width:3px,font-size:14px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== PLANNING LAYER ==========
|
||||||
|
subgraph Planning["🗺️ Planning Layer - Plugin System"]
|
||||||
|
direction LR
|
||||||
|
GP["<b>🌍 Global Planner</b><br/>━━━━━━━━━━━━━━━━<br/>📋 nav_core::BaseGlobalPlanner<br/>🔌 Dynamic Plugin<br/>━━━━━━━━━━━━━━━━<br/>🎯 A*, D*, Hybrid A*<br/>📐 Long-range Planning<br/>🗺️ Global Path"]
|
||||||
|
LP["<b>📍 Local Planner</b><br/>━━━━━━━━━━━━━━━━<br/>📋 nav_core::BaseLocalPlanner<br/>🔌 Dynamic Plugin<br/>━━━━━━━━━━━━━━━━<br/>🎯 DWA, TEB, MKT<br/>🚗 Velocity Commands<br/>🛡️ Obstacle Avoidance"]
|
||||||
|
RB["<b>🔄 Recovery Behaviors</b><br/>━━━━━━━━━━━━━━━━<br/>📋 nav_core::RecoveryBehavior<br/>🔌 Dynamic Plugin<br/>━━━━━━━━━━━━━━━━<br/>🧹 Clear Costmap<br/>🔄 Rotate Recovery<br/>🚨 Emergency Stop"]
|
||||||
|
style Planning fill:#E1F5FE,stroke:#0277BD,stroke-width:4px,color:#000
|
||||||
|
style GP fill:#B3E5FC,stroke:#0277BD,stroke-width:3px,font-size:13px
|
||||||
|
style LP fill:#B3E5FC,stroke:#0277BD,stroke-width:3px,font-size:13px
|
||||||
|
style RB fill:#B3E5FC,stroke:#0277BD,stroke-width:3px,font-size:13px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== COSTMAP LAYER ==========
|
||||||
|
subgraph Costmap["🗺️ Costmap Layer"]
|
||||||
|
direction LR
|
||||||
|
GC["<b>🌍 Global Costmap</b><br/>━━━━━━━━━━━━━━━━<br/>📦 costmap_2d::Costmap2DROBOT<br/>🌍 frame: map<br/>━━━━━━━━━━━━━━━━<br/>🗺️ Static Map<br/>🚫 Obstacles<br/>💰 Inflation Layer"]
|
||||||
|
LC["<b>📍 Local Costmap</b><br/>━━━━━━━━━━━━━━━━<br/>📦 costmap_2d::Costmap2DROBOT<br/>📍 frame: odom<br/>━━━━━━━━━━━━━━━━<br/>🔍 Dynamic Obstacles<br/>📡 Sensor Fusion<br/>⚡ Real-time Updates"]
|
||||||
|
style Costmap fill:#F1F8E9,stroke:#558B2F,stroke-width:4px,color:#000
|
||||||
|
style GC fill:#DCEDC8,stroke:#558B2F,stroke-width:3px,font-size:13px
|
||||||
|
style LC fill:#DCEDC8,stroke:#558B2F,stroke-width:3px,font-size:13px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== ALGORITHMS LAYER ==========
|
||||||
|
subgraph Algorithms["🧮 Algorithms Layer"]
|
||||||
|
direction LR
|
||||||
|
MKTAlgo["<b>🚗 MKT Algorithm</b><br/>━━━━━━━━━━━━━━━━<br/>⚙️ Diff Drive Kinematics<br/>🚲 Bicycle Kinematics<br/>📐 Trajectory Generation"]
|
||||||
|
ScoreAlgo["<b>📊 Score Algorithm</b><br/>━━━━━━━━━━━━━━━━<br/>📈 Trajectory Scoring<br/>✅ Goal Checking<br/>🎯 Path Evaluation"]
|
||||||
|
KalmanAlgo["<b>🔍 Kalman Filter</b><br/>━━━━━━━━━━━━━━━━<br/>📊 State Estimation<br/>🔮 Sensor Fusion<br/>📉 Noise Filtering"]
|
||||||
|
style Algorithms fill:#FCE4EC,stroke:#C2185B,stroke-width:4px,color:#000
|
||||||
|
style MKTAlgo fill:#F8BBD0,stroke:#C2185B,stroke-width:3px,font-size:13px
|
||||||
|
style ScoreAlgo fill:#F8BBD0,stroke:#C2185B,stroke-width:3px,font-size:13px
|
||||||
|
style KalmanAlgo fill:#F8BBD0,stroke:#C2185B,stroke-width:3px,font-size:13px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== DATA SOURCES ==========
|
||||||
|
subgraph DataSources["📡 Data Sources"]
|
||||||
|
direction TB
|
||||||
|
Goal["<b>🎯 Goal Input</b><br/>━━━━━━━━━━━━━━━━<br/>📍 geometry_msgs::PoseStamped<br/>📨 move_base_simple/goal"]
|
||||||
|
Loc["<b>🌍 Localization</b><br/>━━━━━━━━━━━━━━━━<br/>📍 Pnkx Loc<br/>🗺️ Global Pose<br/>🔄 Pose Updates"]
|
||||||
|
TF["<b>🔄 Transform System</b><br/>━━━━━━━━━━━━━━━━<br/>📐 tf3::BufferCore<br/>🌐 Coordinate Frames<br/>⏱️ Time Synchronization"]
|
||||||
|
Odom["<b>🚗 Odometry</b><br/>━━━━━━━━━━━━━━━━<br/>📍 geometry_msgs::Odometry<br/>⚡ Robot Velocity<br/>📊 Position Tracking"]
|
||||||
|
Laser["<b>📡 Laser Sensors</b><br/>━━━━━━━━━━━━━━━━<br/>🔍 sensor_msgs::LaserScan<br/>🚫 Obstacle Detection<br/>📏 Distance Measurement"]
|
||||||
|
Map["<b>🗺️ Map Server</b><br/>━━━━━━━━━━━━━━━━<br/>📋 nav_msgs::OccupancyGrid<br/>🏗️ Static Map<br/>📐 Map Metadata"]
|
||||||
|
style DataSources fill:#FFF9C4,stroke:#F57F17,stroke-width:4px,color:#000
|
||||||
|
style Goal fill:#FFF59D,stroke:#F57F17,stroke-width:3px,font-size:12px
|
||||||
|
style Loc fill:#FFF59D,stroke:#F57F17,stroke-width:3px,font-size:12px
|
||||||
|
style TF fill:#FFF59D,stroke:#F57F17,stroke-width:3px,font-size:12px
|
||||||
|
style Odom fill:#FFF59D,stroke:#F57F17,stroke-width:3px,font-size:12px
|
||||||
|
style Laser fill:#FFF59D,stroke:#F57F17,stroke-width:3px,font-size:12px
|
||||||
|
style Map fill:#FFF59D,stroke:#F57F17,stroke-width:3px,font-size:12px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== CONTROL LOOP ==========
|
||||||
|
subgraph ControlLoop["🔄 Control Loop"]
|
||||||
|
direction LR
|
||||||
|
CmdVel["<b>⚡ Velocity Command</b><br/>━━━━━━━━━━━━━━━━<br/>📤 geometry_msgs::Twist<br/>📨 cmd_vel<br/>━━━━━━━━━━━━━━━━<br/>➡️ Linear Velocity<br/>🔄 Angular Velocity"]
|
||||||
|
BaseCtrl["<b>🎮 Base Controller</b><br/>━━━━━━━━━━━━━━━━<br/>🚗 diff_driver_controller<br/>🚲 steer_drive_controller<br/>━━━━━━━━━━━━━━━━<br/>⚙️ Kinematics<br/>🔧 Hardware Interface"]
|
||||||
|
style ControlLoop fill:#FFEBEE,stroke:#C62828,stroke-width:4px,color:#000
|
||||||
|
style CmdVel fill:#FFCDD2,stroke:#C62828,stroke-width:3px,font-size:13px
|
||||||
|
style BaseCtrl fill:#FFCDD2,stroke:#C62828,stroke-width:3px,font-size:13px
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ========== CONNECTIONS ==========
|
||||||
|
%% API to User Controller
|
||||||
|
CAPI -->|"🔗 P/Invoke"| UserCtrl
|
||||||
|
|
||||||
|
%% User Controller to Interface
|
||||||
|
UserCtrl -->|"🎯 Uses"| BaseNav
|
||||||
|
|
||||||
|
%% Interface to MoveBase
|
||||||
|
BaseNav -->|"⚙️ Implements"| MoveBase
|
||||||
|
|
||||||
|
%% MoveBase to Planning
|
||||||
|
MoveBase -->|"🎛️ Manages"| GP
|
||||||
|
MoveBase -->|"🎛️ Manages"| LP
|
||||||
|
MoveBase -->|"🎛️ Manages"| RB
|
||||||
|
|
||||||
|
%% MoveBase to Costmap
|
||||||
|
MoveBase -->|"🎛️ Manages"| GC
|
||||||
|
MoveBase -->|"🎛️ Manages"| LC
|
||||||
|
|
||||||
|
%% Data Sources to Components
|
||||||
|
Goal -->|"📥 Input"| UserCtrl
|
||||||
|
Goal -->|"📥 Input"| BaseNav
|
||||||
|
Loc -->|"📍 Pose"| MoveBase
|
||||||
|
TF -->|"🔄 Transforms"| MoveBase
|
||||||
|
Laser -->|"📡 Scan Data"| LC
|
||||||
|
Map -->|"🗺️ Static Map"| GC
|
||||||
|
Odom -->|"⚡ Velocity"| LP
|
||||||
|
Odom -->|"📍 Pose"| MoveBase
|
||||||
|
|
||||||
|
%% Planning Flow
|
||||||
|
GC -->|"🗺️ Costmap"| GP
|
||||||
|
GP -->|"🛤️ Global Path"| LP
|
||||||
|
LC -->|"🗺️ Costmap"| LP
|
||||||
|
LC -->|"🗺️ Costmap"| RB
|
||||||
|
GC -->|"🗺️ Costmap"| RB
|
||||||
|
|
||||||
|
%% Algorithm Integration
|
||||||
|
MKTAlgo -->|"🚗 Kinematics"| LP
|
||||||
|
ScoreAlgo -->|"📊 Scoring"| LP
|
||||||
|
KalmanAlgo -.->|"🔍 Filtering"| Loc
|
||||||
|
|
||||||
|
%% Control Flow
|
||||||
|
LP -->|"⚡ Velocity Cmd"| CmdVel
|
||||||
|
CmdVel -->|"▶️ Execute"| BaseCtrl
|
||||||
|
BaseCtrl -->|"📊 Feedback"| Odom
|
||||||
|
|
||||||
|
%% Styling Classes
|
||||||
|
classDef implemented fill:#C8E6C9,stroke:#2E7D32,stroke-width:4px,color:#000
|
||||||
|
classDef partial fill:#FFF9C4,stroke:#F57F17,stroke-width:3px,color:#000
|
||||||
|
classDef todo fill:#FFCDD2,stroke:#C62828,stroke-width:3px,color:#000
|
||||||
|
|
||||||
|
class BaseNav,MoveBase,GP,LP,RB,GC,LC,CAPI,MKTAlgo,ScoreAlgo,KalmanAlgo,UserCtrl implemented
|
||||||
|
class BaseCtrl,Loc,Odom,Map,Laser,TF partial
|
||||||
|
```
|
||||||
|
|
||||||
|
## Đề xuất giải pháp kiến trúc
|
||||||
|
|
||||||
|
### 1. Xác định phạm vi & yêu cầu vận hành
|
||||||
|
|
||||||
|
Cần làm rõ:
|
||||||
|
- **Kịch bản sử dụng chính**: go-to-goal trong môi trường indoor/outdoor? Tốc độ di chuyển? Độ chính xác yêu cầu?
|
||||||
|
- **Cảm biến có sẵn**: encoder, IMU, lidar, camera? Dữ liệu nào đã có?
|
||||||
|
- **Yêu cầu real-time**: chu kỳ điều khiển (control loop frequency), độ trễ tối đa cho phép?
|
||||||
|
|
||||||
|
### 2. Kiến trúc tổng thể
|
||||||
|
|
||||||
|
**Các layer chính:**
|
||||||
|
|
||||||
|
1. **API Layer** ✅
|
||||||
|
- C API (`nav_c_api`) cho P/Invoke với .NET/C#
|
||||||
|
- Wrapper functions cho tất cả BaseNavigation methods
|
||||||
|
|
||||||
|
2. **User Controller Layer** ✅
|
||||||
|
- **User Controller Plugin**: Dynamically allocated từ loader controller plugin
|
||||||
|
- Sử dụng `boost::dll` để load plugins động
|
||||||
|
- Cho phép user định nghĩa controller riêng để điều khiển navigation behavior
|
||||||
|
- Kết nối với `BaseNavigation` interface
|
||||||
|
|
||||||
|
3. **Interface Layer** ✅
|
||||||
|
- `move_base_core::BaseNavigation`: Abstract interface cho navigation
|
||||||
|
- Định nghĩa các operations: moveTo, dockTo, rotateTo, moveStraightTo, pause, resume, cancel
|
||||||
|
- Là lớp trung gian định nghĩa các phương thức và thuộc tính liên quan đến navigation
|
||||||
|
|
||||||
|
4. **Move Base Core** ✅
|
||||||
|
- `move_base::MoveBase`: Core implementation của BaseNavigation
|
||||||
|
- Quản lý state machine (PLANNING, CONTROLLING, CLEARING)
|
||||||
|
- Điều phối global/local planner và recovery behaviors
|
||||||
|
- Quản lý costmaps (global và local)
|
||||||
|
- Thực thi control loop (executeCycle)
|
||||||
|
|
||||||
|
4. **Planning Layer** ✅
|
||||||
|
- `nav_core::BaseGlobalPlanner`: Interface cho global planners (A*, D*, etc.)
|
||||||
|
- `nav_core::BaseLocalPlanner`: Interface cho local planners (DWA, TEB, MKT, etc.)
|
||||||
|
- `nav_core::RecoveryBehavior`: Interface cho recovery behaviors
|
||||||
|
- Plugin system sử dụng `boost::dll` để dynamic loading
|
||||||
|
|
||||||
|
5. **Costmap Layer** ✅
|
||||||
|
- `costmap_2d::Costmap2DROBOT`: Global và local costmap
|
||||||
|
- Costmap layers: static map, obstacles, inflation
|
||||||
|
- Frame management: map (global), odom (local)
|
||||||
|
|
||||||
|
6. **Algorithms Layer** ✅
|
||||||
|
- `mkt_algorithm`: Diff drive và bicycle kinematics algorithms
|
||||||
|
- `score_algorithm`: Trajectory scoring và goal checking
|
||||||
|
- `kalman`: Filtering algorithms
|
||||||
|
|
||||||
|
7. **Data Sources** ⚠️ (Interface cần định nghĩa)
|
||||||
|
- Localization source (Pnkx Loc)
|
||||||
|
- Odometry source
|
||||||
|
- Sensor transforms (tf3)
|
||||||
|
- Map server
|
||||||
|
- Laser sensors
|
||||||
|
|
||||||
|
8. **Control Layer** ⚠️ (Cần implementation)
|
||||||
|
- Base Controller interface (Diff/Steer drive)
|
||||||
|
- Velocity command execution
|
||||||
|
|
||||||
|
**Định dạng dữ liệu:**
|
||||||
|
- `geometry_msgs::Pose2D` / `geometry_msgs::PoseStamped` (vị trí + hướng)
|
||||||
|
- `geometry_msgs::Twist` (vận tốc linear/angular)
|
||||||
|
- `std::vector<geometry_msgs::PoseStamped>` (đường đi)
|
||||||
|
- `costmap_2d::Costmap2D` (bản đồ chi phí)
|
||||||
|
|
||||||
|
### 3. Thiết kế từng module (interface level)
|
||||||
|
|
||||||
|
**Các interface đã có:** ✅
|
||||||
|
|
||||||
|
- `move_base_core::BaseNavigation` ✅
|
||||||
|
- `initialize(TFListenerPtr)` - Khởi tạo với TF listener
|
||||||
|
- `moveTo(goal, xy_tol, yaw_tol)` - Di chuyển đến goal
|
||||||
|
- `dockTo(marker, goal, ...)` - Docking đến marker
|
||||||
|
- `rotateTo(goal, yaw_tol)` - Xoay tại chỗ
|
||||||
|
- `moveStraightTo(goal, xy_tol)` - Đi thẳng
|
||||||
|
- `pause()`, `resume()`, `cancel()` - Điều khiển trạng thái
|
||||||
|
- `getRobotPose(...)` - Lấy vị trí robot
|
||||||
|
|
||||||
|
- `nav_core::BaseGlobalPlanner` ✅
|
||||||
|
- `makePlan(start, goal, plan)` - Tạo global path
|
||||||
|
- `initialize(name, costmap_robot)` - Khởi tạo với costmap
|
||||||
|
|
||||||
|
- `nav_core::BaseLocalPlanner` ✅
|
||||||
|
- `computeVelocityCommands(cmd_vel)` - Tính toán velocity command
|
||||||
|
- `setPlan(plan)` - Set global path để follow
|
||||||
|
- `isGoalReached()` - Kiểm tra đã đến goal chưa
|
||||||
|
- `swapPlanner(name)` - Thay đổi planner động
|
||||||
|
- `setTwistLinear/Angular(...)` - Set velocity limits
|
||||||
|
|
||||||
|
- `nav_core::RecoveryBehavior` ✅
|
||||||
|
- `runBehavior()` - Thực thi recovery behavior
|
||||||
|
|
||||||
|
- `costmap_2d::Costmap2DROBOT` ✅
|
||||||
|
- Wrapper cho costmap với robot footprint
|
||||||
|
- Thread-safe access với mutex
|
||||||
|
|
||||||
|
**Các interface cần bổ sung:** ⚠️
|
||||||
|
|
||||||
|
- `ILocalizationSource` ⚠️
|
||||||
|
- `getCurrentPose()` - Lấy vị trí hiện tại từ localization
|
||||||
|
- `isAvailable()` - Kiểm tra localization có sẵn không
|
||||||
|
|
||||||
|
- `IOdometrySource` ⚠️
|
||||||
|
- `getCurrentPose()` - Lấy vị trí từ odometry
|
||||||
|
- `getCurrentVelocity()` - Lấy vận tốc hiện tại
|
||||||
|
- `isAvailable()` - Kiểm tra odometry có sẵn không
|
||||||
|
|
||||||
|
- `IBaseController` ⚠️
|
||||||
|
- `executeVelocity(cmd_vel)` - Thực thi velocity command
|
||||||
|
- `stop()` - Dừng robot ngay lập tức
|
||||||
|
- `getCurrentVelocity()` - Lấy vận tốc thực tế
|
||||||
|
|
||||||
|
- `IMapProvider` ⚠️
|
||||||
|
- `getMap()` - Lấy static map
|
||||||
|
- `isMapAvailable()` - Kiểm tra map có sẵn không
|
||||||
|
|
||||||
|
**Plugin mechanism:** ✅
|
||||||
|
- Sử dụng `boost::dll` để dynamic loading plugins
|
||||||
|
- Factory pattern với `boost::function` và `boost::dll::import`
|
||||||
|
- Config file YAML để specify plugin names
|
||||||
|
- Plugin interfaces: `BaseGlobalPlanner`, `BaseLocalPlanner`, `RecoveryBehavior`
|
||||||
|
|
||||||
|
### 4. Cơ chế giao tiếp & đồng bộ
|
||||||
|
|
||||||
|
**Lựa chọn transport:**
|
||||||
|
- Shared memory + mutex (cho real-time nhẹ)
|
||||||
|
- Message queue (ZeroMQ, nanomsg)
|
||||||
|
- Event loop với callback thread-safe
|
||||||
|
|
||||||
|
**Time synchronization:**
|
||||||
|
- Sử dụng `std::chrono` cho timestamp
|
||||||
|
- Buffer dữ liệu để xử lý dữ liệu không đồng bộ
|
||||||
|
|
||||||
|
**Threading strategy:**
|
||||||
|
- Mỗi module một thread riêng, hoặc
|
||||||
|
- Scheduler chung quản lý tất cả
|
||||||
|
|
||||||
|
### 5. Chiến lược an toàn & recovery
|
||||||
|
|
||||||
|
**Monitoring:**
|
||||||
|
- Heartbeat mechanism
|
||||||
|
- Watchdog timer
|
||||||
|
|
||||||
|
**Recovery behaviors:**
|
||||||
|
- Không tìm được đường đi
|
||||||
|
- Mất localization
|
||||||
|
- Obstacle chặn đường
|
||||||
|
- Emergency stop mechanism
|
||||||
|
- Giới hạn vận tốc theo trạng thái
|
||||||
|
|
||||||
|
### 6. Config & Logging/Diagnostics
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
- File YAML/JSON cho:
|
||||||
|
- Kinematics parameters
|
||||||
|
- Velocity limits
|
||||||
|
- Planner parameters
|
||||||
|
- Sensor configurations
|
||||||
|
|
||||||
|
**Logging & Debugging:**
|
||||||
|
- Logging framework (spdlog?)
|
||||||
|
- Telemetry interface
|
||||||
|
- Visualizer tool (SDL/ImGui) để debug map/path
|
||||||
|
|
||||||
|
### 7. Trạng thái triển khai & lộ trình
|
||||||
|
|
||||||
|
**Đã hoàn thành:** ✅
|
||||||
|
|
||||||
|
1. ✅ **Interface Layer**: `BaseNavigation` interface
|
||||||
|
2. ✅ **Implementation Layer**: `MoveBase` core logic
|
||||||
|
3. ✅ **Planning Layer**: Plugin system cho global/local planners và recovery
|
||||||
|
4. ✅ **Costmap Layer**: Global và local costmap với layers
|
||||||
|
5. ✅ **Algorithms Layer**: MKT algorithms, score algorithm, kalman
|
||||||
|
6. ✅ **API Layer**: C API wrapper cho .NET integration
|
||||||
|
7. ✅ **Supporting Libraries**: tf3, robot_time, geometry_msgs, nav_2d_utils
|
||||||
|
|
||||||
|
**Đang triển khai / Cần bổ sung:** ⚠️
|
||||||
|
|
||||||
|
1. ⚠️ **Data Sources Interfaces**:
|
||||||
|
- `ILocalizationSource` interface
|
||||||
|
- `IOdometrySource` interface
|
||||||
|
- `IMapProvider` interface
|
||||||
|
- Integration với Pnkx Loc, odometry sources
|
||||||
|
|
||||||
|
2. ⚠️ **Base Controller**:
|
||||||
|
- `IBaseController` interface
|
||||||
|
- Diff drive controller implementation
|
||||||
|
- Steer drive controller implementation
|
||||||
|
- Velocity command execution
|
||||||
|
|
||||||
|
3. ⚠️ **Control Loop**:
|
||||||
|
- Control loop trong MoveBase (executeCycle)
|
||||||
|
- State machine management hoàn chỉnh
|
||||||
|
- Threading và synchronization
|
||||||
|
|
||||||
|
4. ⚠️ **User Controller Plugin System**:
|
||||||
|
- Factory để load user controller plugins
|
||||||
|
- Integration với BaseNavigation
|
||||||
|
|
||||||
|
**Lộ trình tiếp theo:**
|
||||||
|
|
||||||
|
**Phase 1: Data Sources & Base Controller** (Ưu tiên cao)
|
||||||
|
- Định nghĩa interfaces cho data sources
|
||||||
|
- Implement Base Controller interface và diff drive controller
|
||||||
|
- Integration với MoveBase
|
||||||
|
|
||||||
|
**Phase 2: Control Loop & State Management** (Ưu tiên cao)
|
||||||
|
- Hoàn thiện executeCycle trong MoveBase
|
||||||
|
- State machine management
|
||||||
|
- Threading strategy
|
||||||
|
|
||||||
|
**Phase 3: User Controller Plugin System** (Ưu tiên trung bình)
|
||||||
|
- Factory pattern cho user controllers
|
||||||
|
- Plugin loading mechanism
|
||||||
|
- Integration testing
|
||||||
|
|
||||||
|
**Phase 4: Testing & Optimization** (Ưu tiên trung bình)
|
||||||
|
- Unit tests cho các module
|
||||||
|
- Integration tests
|
||||||
|
- Performance optimization
|
||||||
|
|
||||||
|
**Testing strategy:**
|
||||||
|
- Unit tests cho các module độc lập (gtest?)
|
||||||
|
- Integration tests cho full navigation stack
|
||||||
|
- Simulation environment (2D simulator) - TODO
|
||||||
|
- Hardware-in-the-loop testing - TODO
|
||||||
|
|
||||||
|
## Cấu trúc thư mục
|
||||||
|
|
||||||
|
```
|
||||||
|
pnkx_nav_core/
|
||||||
|
├── src/
|
||||||
|
│ ├── Navigations/
|
||||||
|
│ │ ├── Cores/
|
||||||
|
│ │ │ ├── move_base_core/ # BaseNavigation interface
|
||||||
|
│ │ │ ├── nav_core/ # Planner interfaces
|
||||||
|
│ │ │ ├── nav_core_adapter/ # Adapter utilities
|
||||||
|
│ │ │ └── nav_core2/ # Additional nav utilities
|
||||||
|
│ │ ├── Libraries/
|
||||||
|
│ │ │ ├── costmap_2d/ # Costmap system
|
||||||
|
│ │ │ ├── tf3/ # Transform system
|
||||||
|
│ │ │ ├── robot_time/ # Time management
|
||||||
|
│ │ │ ├── geometry2/ # Geometry utilities
|
||||||
|
│ │ │ └── ... # Other supporting libraries
|
||||||
|
│ │ └── Packages/
|
||||||
|
│ │ └── move_base/ # MoveBase implementation
|
||||||
|
│ ├── Algorithms/
|
||||||
|
│ │ ├── Cores/
|
||||||
|
│ │ │ └── score_algorithm/ # Trajectory scoring
|
||||||
|
│ │ └── Libraries/
|
||||||
|
│ │ ├── mkt_algorithm/ # MKT kinematics algorithms
|
||||||
|
│ │ ├── kalman/ # Kalman filtering
|
||||||
|
│ │ └── angles/ # Angle utilities
|
||||||
|
│ └── APIs/
|
||||||
|
│ └── c_api/ # C API wrapper
|
||||||
|
├── build/ # Build artifacts
|
||||||
|
└── doc/ # Documentation
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ghi chú
|
||||||
|
|
||||||
|
- ✅ Kiến trúc cốt lõi đã được triển khai với plugin system linh hoạt
|
||||||
|
- ⚠️ Cần bổ sung data sources interfaces và base controller
|
||||||
|
- 🔄 Kiến trúc được thiết kế để dễ dàng thay đổi thuật toán và mô hình kinematics thông qua plugin system
|
||||||
|
- 📦 Tất cả components được build bằng CMake, không phụ thuộc ROS
|
||||||
|
- 🔌 Plugin system sử dụng `boost::dll` cho dynamic loading
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1282
doc/diff_drive_c.drawio
Executable file
1282
doc/diff_drive_c.drawio
Executable file
File diff suppressed because one or more lines are too long
53
doc/folders.md
Normal file
53
doc/folders.md
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
Mô tả cấu trúc:
|
||||||
|
|
||||||
|
├── common_msgs/
|
||||||
|
│ ├── build/
|
||||||
|
│ ├── geometry_msgs/
|
||||||
|
│ │ ├── include/
|
||||||
|
│ │ └── test/
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ ├── nav_msgs/
|
||||||
|
│ │ ├── include/
|
||||||
|
│ │ └── test/
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ ├── sensor_msgs/
|
||||||
|
│ │ ├── cfg/
|
||||||
|
│ │ ├── include/
|
||||||
|
│ │ └── test/
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ ├── std_msgs/
|
||||||
|
│ │ ├── include/
|
||||||
|
│ │ └── CMakeLists.txt
|
||||||
|
│ └── CMakeLists.txt (root)
|
||||||
|
|
|
||||||
|
├── Navigations/
|
||||||
|
│ ├── Cores/
|
||||||
|
│ │ └── move_base_core/
|
||||||
|
│ │ ├── build/
|
||||||
|
│ │ ├── example/
|
||||||
|
│ │ ├── include/
|
||||||
|
│ │ ├── .gitignore
|
||||||
|
│ │ ├── CMakeLists.txt
|
||||||
|
│ │ └── README.md
|
||||||
|
│ ├── Libraries/
|
||||||
|
│ │ ├── geometry_msgs/
|
||||||
|
│ │ │ ├── build/
|
||||||
|
│ │ │ ├── include/
|
||||||
|
│ │ │ └── CMakeLists.txt
|
||||||
|
│ │ └── libtf2/
|
||||||
|
│ │ ├── .vscode/
|
||||||
|
│ │ ├── include/
|
||||||
|
│ │ ├── samples/
|
||||||
|
│ │ ├── src/
|
||||||
|
│ │ ├── .gitignore
|
||||||
|
│ │ ├── DEBIAN_PACKAGING.md
|
||||||
|
│ │ ├── libtf2_2.0.0_amd64.deb
|
||||||
|
│ │ ├── Makefile
|
||||||
|
│ │ └── README.md
|
||||||
|
│ ├── Packages/
|
||||||
|
│ │ └── move_base/
|
||||||
|
│ │ ├── build/
|
||||||
|
│ │ ├── include/
|
||||||
|
│ │ ├── src/
|
||||||
|
│ │ └── CMakeLists.txt
|
||||||
|
│ └── CMakeLists.txt (root)
|
||||||
230
doc/implementation_plan.md
Normal file
230
doc/implementation_plan.md
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
# Kế hoạch Implementation Navigation System
|
||||||
|
|
||||||
|
## Phân tích Kiến trúc Hiện tại
|
||||||
|
|
||||||
|
### ✅ Đã có sẵn:
|
||||||
|
|
||||||
|
1. **Interface Layer:**
|
||||||
|
- `move_base_core::BaseNavigation` - Interface chính
|
||||||
|
- `move_base::MoveBase` - Implementation
|
||||||
|
|
||||||
|
2. **Core Components:**
|
||||||
|
- `nav_core::BaseGlobalPlanner` - Interface cho global planner
|
||||||
|
- `nav_core::BaseLocalPlanner` - Interface cho local planner
|
||||||
|
- `nav_core::RecoveryBehavior` - Interface cho recovery behaviors
|
||||||
|
- Plugin system với `boost::dll` để load dynamic plugins
|
||||||
|
|
||||||
|
3. **Costmap System:**
|
||||||
|
- `costmap_2d::Costmap2DROBOT` - Global và local costmap
|
||||||
|
- Costmap layers (static, obstacle, inflation, etc.)
|
||||||
|
|
||||||
|
4. **Supporting Libraries:**
|
||||||
|
- `tf3` - Transform system
|
||||||
|
- `robot_time` - Time management
|
||||||
|
- `geometry_msgs` - Message types
|
||||||
|
- `nav_2d_msgs`, `nav_2d_utils` - 2D navigation utilities
|
||||||
|
|
||||||
|
### ❌ Cần bổ sung/hoàn thiện:
|
||||||
|
|
||||||
|
1. **User Controller Plugin System:**
|
||||||
|
- Factory để tạo User Controller từ plugin
|
||||||
|
- Interface cho User Controller
|
||||||
|
- Integration với BaseNavigation
|
||||||
|
|
||||||
|
2. **Data Sources Integration:**
|
||||||
|
- Pnkx Loc interface
|
||||||
|
- Odometry Source interface
|
||||||
|
- Sensor Transform management
|
||||||
|
- Map Server interface
|
||||||
|
- Laser Sensor Sources interface
|
||||||
|
|
||||||
|
3. **Base Controller:**
|
||||||
|
- Diff drive controller
|
||||||
|
- Steer drive controller
|
||||||
|
- Velocity command execution
|
||||||
|
|
||||||
|
4. **Hoàn thiện MoveBase:**
|
||||||
|
- Control loop implementation
|
||||||
|
- State machine management
|
||||||
|
- Recovery behavior execution
|
||||||
|
|
||||||
|
## Kế hoạch Implementation
|
||||||
|
|
||||||
|
### Phase 1: Data Sources & Interfaces (Ưu tiên cao)
|
||||||
|
|
||||||
|
#### 1.1 Odometry Source Interface
|
||||||
|
**File:** `src/Navigations/Cores/move_base_core/include/move_base_core/odometry_source.h`
|
||||||
|
```cpp
|
||||||
|
class IOdometrySource {
|
||||||
|
virtual geometry_msgs::PoseStamped getCurrentPose() = 0;
|
||||||
|
virtual geometry_msgs::Twist getCurrentVelocity() = 0;
|
||||||
|
virtual bool isAvailable() = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 Localization Source Interface (Pnkx Loc)
|
||||||
|
**File:** `src/Navigations/Cores/move_base_core/include/move_base_core/localization_source.h`
|
||||||
|
```cpp
|
||||||
|
class ILocalizationSource {
|
||||||
|
virtual geometry_msgs::PoseStamped getRobotPose() = 0;
|
||||||
|
virtual std::string getGlobalFrame() = 0;
|
||||||
|
virtual bool isLocalized() = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.3 Map Provider Interface
|
||||||
|
**File:** `src/Navigations/Cores/move_base_core/include/move_base_core/map_provider.h`
|
||||||
|
```cpp
|
||||||
|
class IMapProvider {
|
||||||
|
virtual nav_msgs::OccupancyGrid getMap() = 0;
|
||||||
|
virtual bool isMapAvailable() = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.4 Sensor Data Interface
|
||||||
|
**File:** `src/Navigations/Cores/move_base_core/include/move_base_core/sensor_source.h`
|
||||||
|
```cpp
|
||||||
|
class ISensorSource {
|
||||||
|
virtual sensor_msgs::LaserScan getLatestScan() = 0;
|
||||||
|
virtual bool hasNewData() = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Phase 2: Base Controller (Ưu tiên cao)
|
||||||
|
|
||||||
|
#### 2.1 Base Controller Interface
|
||||||
|
**File:** `src/Navigations/Cores/move_base_core/include/move_base_core/base_controller.h`
|
||||||
|
```cpp
|
||||||
|
class IBaseController {
|
||||||
|
virtual bool setVelocity(const geometry_msgs::Twist& cmd_vel) = 0;
|
||||||
|
virtual bool stop() = 0;
|
||||||
|
virtual geometry_msgs::Twist getCurrentVelocity() = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2 Diff Drive Controller
|
||||||
|
**File:** `src/Navigations/Packages/base_controllers/include/base_controllers/diff_drive_controller.h`
|
||||||
|
- Implement IBaseController
|
||||||
|
- Convert Twist to wheel velocities
|
||||||
|
- Handle kinematics cho differential drive
|
||||||
|
|
||||||
|
#### 2.3 Steer Drive Controller
|
||||||
|
**File:** `src/Navigations/Packages/base_controllers/include/base_controllers/steer_drive_controller.h`
|
||||||
|
- Implement IBaseController
|
||||||
|
- Convert Twist to steering angles và wheel velocities
|
||||||
|
- Handle kinematics cho bicycle/steering model
|
||||||
|
|
||||||
|
### Phase 3: User Controller Plugin System (Ưu tiên trung bình)
|
||||||
|
|
||||||
|
#### 3.1 User Controller Interface
|
||||||
|
**File:** `src/Navigations/Cores/move_base_core/include/move_base_core/user_controller.h`
|
||||||
|
```cpp
|
||||||
|
class IUserController {
|
||||||
|
virtual void onGoalReceived(const geometry_msgs::PoseStamped& goal) = 0;
|
||||||
|
virtual void onNavigationStateChanged(move_base_core::State state) = 0;
|
||||||
|
virtual void onFeedback(const NavFeedback& feedback) = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2 User Controller Factory
|
||||||
|
**File:** `src/Navigations/Cores/move_base_core/src/user_controller_factory.cpp`
|
||||||
|
- Load plugin từ config
|
||||||
|
- Create instance với boost::dll
|
||||||
|
- Manage lifecycle
|
||||||
|
|
||||||
|
### Phase 4: Control Loop & State Machine (Ưu tiên cao)
|
||||||
|
|
||||||
|
#### 4.1 Control Loop Implementation
|
||||||
|
**File:** `src/Navigations/Packages/move_base/src/move_base_control_loop.cpp`
|
||||||
|
- Main control loop thread
|
||||||
|
- Planner thread management
|
||||||
|
- Controller execution
|
||||||
|
- Frequency control
|
||||||
|
|
||||||
|
#### 4.2 State Machine
|
||||||
|
**File:** `src/Navigations/Packages/move_base/src/move_base_state_machine.cpp`
|
||||||
|
- State transitions
|
||||||
|
- Recovery behavior triggers
|
||||||
|
- Goal management
|
||||||
|
|
||||||
|
### Phase 5: Integration & Testing (Ưu tiên trung bình)
|
||||||
|
|
||||||
|
#### 5.1 Integration Layer
|
||||||
|
- Connect tất cả components
|
||||||
|
- Data flow management
|
||||||
|
- Error handling
|
||||||
|
|
||||||
|
#### 5.2 Testing
|
||||||
|
- Unit tests
|
||||||
|
- Integration tests
|
||||||
|
- Simulation tests
|
||||||
|
|
||||||
|
## Cấu trúc Thư mục Đề xuất
|
||||||
|
|
||||||
|
```
|
||||||
|
src/Navigations/
|
||||||
|
├── Cores/
|
||||||
|
│ ├── move_base_core/ ✅ Đã có
|
||||||
|
│ │ ├── interfaces/
|
||||||
|
│ │ │ ├── odometry_source.h ⚠️ Cần tạo
|
||||||
|
│ │ │ ├── localization_source.h ⚠️ Cần tạo
|
||||||
|
│ │ │ ├── map_provider.h ⚠️ Cần tạo
|
||||||
|
│ │ │ ├── sensor_source.h ⚠️ Cần tạo
|
||||||
|
│ │ │ ├── base_controller.h ⚠️ Cần tạo
|
||||||
|
│ │ │ └── user_controller.h ⚠️ Cần tạo
|
||||||
|
│ │ └── src/
|
||||||
|
│ │ └── user_controller_factory.cpp ⚠️ Cần tạo
|
||||||
|
│ ├── nav_core/ ✅ Đã có
|
||||||
|
│ └── nav_core2/ ✅ Đã có
|
||||||
|
│
|
||||||
|
├── Packages/
|
||||||
|
│ ├── move_base/ ✅ Đã có (cần hoàn thiện)
|
||||||
|
│ │ └── src/
|
||||||
|
│ │ ├── move_base_control_loop.cpp ⚠️ Cần tạo
|
||||||
|
│ │ └── move_base_state_machine.cpp ⚠️ Cần tạo
|
||||||
|
│ │
|
||||||
|
│ └── base_controllers/ ⚠️ Cần tạo
|
||||||
|
│ ├── include/
|
||||||
|
│ │ └── base_controllers/
|
||||||
|
│ │ ├── diff_drive_controller.h
|
||||||
|
│ │ └── steer_drive_controller.h
|
||||||
|
│ └── src/
|
||||||
|
│ ├── diff_drive_controller.cpp
|
||||||
|
│ └── steer_drive_controller.cpp
|
||||||
|
│
|
||||||
|
└── Libraries/
|
||||||
|
└── (các libraries hiện có) ✅
|
||||||
|
```
|
||||||
|
|
||||||
|
## Thứ tự Implementation
|
||||||
|
|
||||||
|
### Sprint 1: Foundation (1-2 tuần)
|
||||||
|
1. ✅ Tạo interfaces cho data sources
|
||||||
|
2. ✅ Tạo base controller interface
|
||||||
|
3. ✅ Implement diff drive controller cơ bản
|
||||||
|
|
||||||
|
### Sprint 2: Integration (1-2 tuần)
|
||||||
|
1. ✅ Integrate data sources vào MoveBase
|
||||||
|
2. ✅ Implement control loop
|
||||||
|
3. ✅ Connect base controller
|
||||||
|
|
||||||
|
### Sprint 3: Plugin System (1 tuần)
|
||||||
|
1. ✅ User controller plugin system
|
||||||
|
2. ✅ Factory pattern implementation
|
||||||
|
|
||||||
|
### Sprint 4: State Machine & Recovery (1 tuần)
|
||||||
|
1. ✅ State machine implementation
|
||||||
|
2. ✅ Recovery behavior integration
|
||||||
|
|
||||||
|
### Sprint 5: Testing & Polish (1 tuần)
|
||||||
|
1. ✅ Unit tests
|
||||||
|
2. ✅ Integration tests
|
||||||
|
3. ✅ Documentation
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Tất cả interfaces nên follow pattern của `BaseNavigation`
|
||||||
|
- Sử dụng `boost::dll` cho plugin system (đã có sẵn)
|
||||||
|
- Thread safety: sử dụng `boost::mutex` và `boost::recursive_mutex`
|
||||||
|
- Error handling: throw exceptions, return bool cho simple operations
|
||||||
|
|
||||||
15
doc/readme.md
Normal file
15
doc/readme.md
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
Mô tả dựng án :
|
||||||
|
Tôi đang nghiên cứu viết chương di chuyển bám quỹ đạo (navigation) cho robot amr dạng hai bánh vi sai. Tôi muốn bỏ ROS chuyển sang viết
|
||||||
|
thuần trên Cmake.
|
||||||
|
|
||||||
|
Các chức năng cần có:
|
||||||
|
- Có khả năng thay đổi mô hình kinematics như dạng hai bánh vi sai, dạng steering bicycle, ...
|
||||||
|
- Có chức năng di chuyển từ điểủ khởi đầu đến điểm đích
|
||||||
|
- Có chức năng xoay tròn
|
||||||
|
- Có chức năng đi thẳng
|
||||||
|
- Có chức năng thay đổi vận tốc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
322
examples/CSharpExample.cs
Normal file
322
examples/CSharpExample.cs
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace NavigationExample
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// C# P/Invoke wrapper for Navigation C API
|
||||||
|
/// </summary>
|
||||||
|
public class NavigationAPI
|
||||||
|
{
|
||||||
|
private const string DllName = "libnav_c_api.so"; // Linux
|
||||||
|
// For Windows: "nav_c_api.dll"
|
||||||
|
// For macOS: "libnav_c_api.dylib"
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Enums
|
||||||
|
// ============================================================================
|
||||||
|
public enum NavigationState
|
||||||
|
{
|
||||||
|
Pending = 0,
|
||||||
|
Active = 1,
|
||||||
|
Preempted = 2,
|
||||||
|
Succeeded = 3,
|
||||||
|
Aborted = 4,
|
||||||
|
Rejected = 5,
|
||||||
|
Preempting = 6,
|
||||||
|
Recalling = 7,
|
||||||
|
Recalled = 8,
|
||||||
|
Lost = 9,
|
||||||
|
Planning = 10,
|
||||||
|
Controlling = 11,
|
||||||
|
Clearing = 12,
|
||||||
|
Paused = 13
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Structures
|
||||||
|
// ============================================================================
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Point
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Pose2D
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Quaternion
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
public double w;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Position
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Pose
|
||||||
|
{
|
||||||
|
public Position position;
|
||||||
|
public Quaternion orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Header
|
||||||
|
{
|
||||||
|
public uint seq;
|
||||||
|
public long sec;
|
||||||
|
public uint nsec;
|
||||||
|
public IntPtr frame_id; // char*
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct PoseStamped
|
||||||
|
{
|
||||||
|
public Header header;
|
||||||
|
public Pose pose;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Vector3
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct NavFeedback
|
||||||
|
{
|
||||||
|
public NavigationState navigation_state;
|
||||||
|
public IntPtr feed_back_str; // char*
|
||||||
|
public Pose2D current_pose;
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool goal_checked;
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool is_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// String Management
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void nav_c_api_free_string(IntPtr str);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// State Conversion
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||||
|
public static extern IntPtr navigation_state_to_string(NavigationState state);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper Functions
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_offset_goal_2d(
|
||||||
|
double pose_x, double pose_y, double pose_theta,
|
||||||
|
string frame_id, double offset_distance,
|
||||||
|
ref PoseStamped out_goal);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_offset_goal_stamped(
|
||||||
|
ref PoseStamped in_pose, double offset_distance,
|
||||||
|
ref PoseStamped out_goal);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Navigation Handle Management
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr navigation_create();
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_destroy(IntPtr handle);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TF Listener Management
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr tf_listener_create();
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void tf_listener_destroy(IntPtr handle);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Navigation Interface Methods
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_initialize(IntPtr handle, IntPtr tf_handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_set_robot_footprint(
|
||||||
|
IntPtr handle, Point[] points, UIntPtr point_count);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_move_to(
|
||||||
|
IntPtr handle, ref PoseStamped goal,
|
||||||
|
double xy_goal_tolerance, double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_dock_to(
|
||||||
|
IntPtr handle, string marker, ref PoseStamped goal,
|
||||||
|
double xy_goal_tolerance, double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_move_straight_to(
|
||||||
|
IntPtr handle, ref PoseStamped goal, double xy_goal_tolerance);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_rotate_to(
|
||||||
|
IntPtr handle, ref PoseStamped goal, double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_pause(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_resume(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_cancel(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_set_twist_linear(
|
||||||
|
IntPtr handle, double linear_x, double linear_y, double linear_z);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_set_twist_angular(
|
||||||
|
IntPtr handle, double angular_x, double angular_y, double angular_z);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_get_robot_pose_stamped(
|
||||||
|
IntPtr handle, ref PoseStamped out_pose);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_get_robot_pose_2d(
|
||||||
|
IntPtr handle, ref Pose2D out_pose);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_get_feedback(
|
||||||
|
IntPtr handle, ref NavFeedback out_feedback);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_free_feedback(ref NavFeedback feedback);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper Methods for String Conversion
|
||||||
|
// ============================================================================
|
||||||
|
public static string MarshalString(IntPtr ptr)
|
||||||
|
{
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
|
return string.Empty;
|
||||||
|
return Marshal.PtrToStringAnsi(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Example Usage
|
||||||
|
// ============================================================================
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
// Helper method để hiển thị file và line number tự động
|
||||||
|
static void LogError(string message,
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerMemberName] string memberName = "")
|
||||||
|
{
|
||||||
|
// Lấy tên file từ đường dẫn đầy đủ
|
||||||
|
string fileName = System.IO.Path.GetFileName(filePath);
|
||||||
|
Console.WriteLine($"[{fileName}:{lineNumber}] {memberName}: {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
// Create TF listener
|
||||||
|
IntPtr tfHandle = NavigationAPI.tf_listener_create();
|
||||||
|
if (tfHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
LogError("Failed to create TF listener");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create navigation instance
|
||||||
|
IntPtr navHandle = NavigationAPI.navigation_create();
|
||||||
|
if (navHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
LogError("Failed to create navigation instance");
|
||||||
|
NavigationAPI.tf_listener_destroy(tfHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize navigation
|
||||||
|
if (!NavigationAPI.navigation_initialize(navHandle, tfHandle))
|
||||||
|
{
|
||||||
|
LogError("Failed to initialize navigation");
|
||||||
|
NavigationAPI.navigation_destroy(navHandle);
|
||||||
|
NavigationAPI.tf_listener_destroy(tfHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set robot footprint
|
||||||
|
NavigationAPI.Point[] footprint = new NavigationAPI.Point[]
|
||||||
|
{
|
||||||
|
new NavigationAPI.Point { x = 0.3, y = -0.2, z = 0.0 },
|
||||||
|
new NavigationAPI.Point { x = 0.3, y = 0.2, z = 0.0 },
|
||||||
|
new NavigationAPI.Point { x = -0.3, y = 0.2, z = 0.0 },
|
||||||
|
new NavigationAPI.Point { x = -0.3, y = -0.2, z = 0.0 }
|
||||||
|
};
|
||||||
|
NavigationAPI.navigation_set_robot_footprint(navHandle, footprint, new UIntPtr((uint)footprint.Length));
|
||||||
|
|
||||||
|
// Get robot pose
|
||||||
|
NavigationAPI.Pose2D robotPose = new NavigationAPI.Pose2D();
|
||||||
|
if (NavigationAPI.navigation_get_robot_pose_2d(navHandle, ref robotPose))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Robot pose: x={robotPose.x}, y={robotPose.y}, theta={robotPose.theta}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get navigation feedback
|
||||||
|
NavigationAPI.NavFeedback feedback = new NavigationAPI.NavFeedback();
|
||||||
|
if (NavigationAPI.navigation_get_feedback(navHandle, ref feedback))
|
||||||
|
{
|
||||||
|
string stateStr = NavigationAPI.MarshalString(
|
||||||
|
NavigationAPI.navigation_state_to_string(feedback.navigation_state));
|
||||||
|
string feedbackStr = NavigationAPI.MarshalString(feedback.feed_back_str);
|
||||||
|
Console.WriteLine($"State: {stateStr}, Feedback: {feedbackStr}");
|
||||||
|
NavigationAPI.navigation_free_feedback(ref feedback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
NavigationAPI.navigation_destroy(navHandle);
|
||||||
|
NavigationAPI.tf_listener_destroy(tfHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
13
examples/NavigationExample/NavigationExample.csproj
Normal file
13
examples/NavigationExample/NavigationExample.csproj
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="libnav_c_api.so">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
322
examples/NavigationExample/Program.cs
Normal file
322
examples/NavigationExample/Program.cs
Normal file
|
|
@ -0,0 +1,322 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace NavigationExample
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// C# P/Invoke wrapper for Navigation C API
|
||||||
|
/// </summary>
|
||||||
|
public class NavigationAPI
|
||||||
|
{
|
||||||
|
private const string DllName = "libnav_c_api.so"; // Linux
|
||||||
|
// For Windows: "nav_c_api.dll"
|
||||||
|
// For macOS: "libnav_c_api.dylib"
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Enums
|
||||||
|
// ============================================================================
|
||||||
|
public enum NavigationState
|
||||||
|
{
|
||||||
|
Pending = 0,
|
||||||
|
Active = 1,
|
||||||
|
Preempted = 2,
|
||||||
|
Succeeded = 3,
|
||||||
|
Aborted = 4,
|
||||||
|
Rejected = 5,
|
||||||
|
Preempting = 6,
|
||||||
|
Recalling = 7,
|
||||||
|
Recalled = 8,
|
||||||
|
Lost = 9,
|
||||||
|
Planning = 10,
|
||||||
|
Controlling = 11,
|
||||||
|
Clearing = 12,
|
||||||
|
Paused = 13
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Structures
|
||||||
|
// ============================================================================
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Point
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Pose2D
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Quaternion
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
public double w;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Position
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Pose
|
||||||
|
{
|
||||||
|
public Position position;
|
||||||
|
public Quaternion orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Header
|
||||||
|
{
|
||||||
|
public uint seq;
|
||||||
|
public long sec;
|
||||||
|
public uint nsec;
|
||||||
|
public IntPtr frame_id; // char*
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct PoseStamped
|
||||||
|
{
|
||||||
|
public Header header;
|
||||||
|
public Pose pose;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct Vector3
|
||||||
|
{
|
||||||
|
public double x;
|
||||||
|
public double y;
|
||||||
|
public double z;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct NavFeedback
|
||||||
|
{
|
||||||
|
public NavigationState navigation_state;
|
||||||
|
public IntPtr feed_back_str; // char*
|
||||||
|
public Pose2D current_pose;
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool goal_checked;
|
||||||
|
[MarshalAs(UnmanagedType.I1)]
|
||||||
|
public bool is_ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// String Management
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void nav_c_api_free_string(IntPtr str);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// State Conversion
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||||
|
public static extern IntPtr navigation_state_to_string(NavigationState state);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper Functions
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_offset_goal_2d(
|
||||||
|
double pose_x, double pose_y, double pose_theta,
|
||||||
|
string frame_id, double offset_distance,
|
||||||
|
ref PoseStamped out_goal);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_offset_goal_stamped(
|
||||||
|
ref PoseStamped in_pose, double offset_distance,
|
||||||
|
ref PoseStamped out_goal);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Navigation Handle Management
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr navigation_create();
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_destroy(IntPtr handle);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TF Listener Management
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern IntPtr tf_listener_create();
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void tf_listener_destroy(IntPtr handle);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Navigation Interface Methods
|
||||||
|
// ============================================================================
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_initialize(IntPtr handle, IntPtr tf_handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_set_robot_footprint(
|
||||||
|
IntPtr handle, Point[] points, UIntPtr point_count);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_move_to(
|
||||||
|
IntPtr handle, ref PoseStamped goal,
|
||||||
|
double xy_goal_tolerance, double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_dock_to(
|
||||||
|
IntPtr handle, string marker, ref PoseStamped goal,
|
||||||
|
double xy_goal_tolerance, double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_move_straight_to(
|
||||||
|
IntPtr handle, ref PoseStamped goal, double xy_goal_tolerance);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_rotate_to(
|
||||||
|
IntPtr handle, ref PoseStamped goal, double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_pause(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_resume(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_cancel(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_set_twist_linear(
|
||||||
|
IntPtr handle, double linear_x, double linear_y, double linear_z);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_set_twist_angular(
|
||||||
|
IntPtr handle, double angular_x, double angular_y, double angular_z);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_get_robot_pose_stamped(
|
||||||
|
IntPtr handle, ref PoseStamped out_pose);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_get_robot_pose_2d(
|
||||||
|
IntPtr handle, ref Pose2D out_pose);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
[return: MarshalAs(UnmanagedType.I1)]
|
||||||
|
public static extern bool navigation_get_feedback(
|
||||||
|
IntPtr handle, ref NavFeedback out_feedback);
|
||||||
|
|
||||||
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void navigation_free_feedback(ref NavFeedback feedback);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper Methods for String Conversion
|
||||||
|
// ============================================================================
|
||||||
|
public static string MarshalString(IntPtr ptr)
|
||||||
|
{
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
|
return string.Empty;
|
||||||
|
return Marshal.PtrToStringAnsi(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Example Usage
|
||||||
|
// ============================================================================
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
// Helper method để hiển thị file và line number tự động
|
||||||
|
static void LogError(string message,
|
||||||
|
[CallerFilePath] string filePath = "",
|
||||||
|
[CallerLineNumber] int lineNumber = 0,
|
||||||
|
[CallerMemberName] string memberName = "")
|
||||||
|
{
|
||||||
|
// Lấy tên file từ đường dẫn đầy đủ
|
||||||
|
string fileName = System.IO.Path.GetFileName(filePath);
|
||||||
|
Console.WriteLine($"[{fileName}:{lineNumber}] {memberName}: {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
// Create TF listener
|
||||||
|
IntPtr tfHandle = NavigationAPI.tf_listener_create();
|
||||||
|
if (tfHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
LogError("Failed to create TF listener");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create navigation instance
|
||||||
|
IntPtr navHandle = NavigationAPI.navigation_create();
|
||||||
|
if (navHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
LogError("Failed to create navigation instance");
|
||||||
|
NavigationAPI.tf_listener_destroy(tfHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize navigation
|
||||||
|
if (!NavigationAPI.navigation_initialize(navHandle, tfHandle))
|
||||||
|
{
|
||||||
|
LogError("Failed to initialize navigation");
|
||||||
|
NavigationAPI.navigation_destroy(navHandle);
|
||||||
|
NavigationAPI.tf_listener_destroy(tfHandle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set robot footprint
|
||||||
|
NavigationAPI.Point[] footprint = new NavigationAPI.Point[]
|
||||||
|
{
|
||||||
|
new NavigationAPI.Point { x = 0.3, y = -0.2, z = 0.0 },
|
||||||
|
new NavigationAPI.Point { x = 0.3, y = 0.2, z = 0.0 },
|
||||||
|
new NavigationAPI.Point { x = -0.3, y = 0.2, z = 0.0 },
|
||||||
|
new NavigationAPI.Point { x = -0.3, y = -0.2, z = 0.0 }
|
||||||
|
};
|
||||||
|
NavigationAPI.navigation_set_robot_footprint(navHandle, footprint, new UIntPtr((uint)footprint.Length));
|
||||||
|
|
||||||
|
// Get robot pose
|
||||||
|
NavigationAPI.Pose2D robotPose = new NavigationAPI.Pose2D();
|
||||||
|
if (NavigationAPI.navigation_get_robot_pose_2d(navHandle, ref robotPose))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Robot pose: x={robotPose.x}, y={robotPose.y}, theta={robotPose.theta}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get navigation feedback
|
||||||
|
NavigationAPI.NavFeedback feedback = new NavigationAPI.NavFeedback();
|
||||||
|
if (NavigationAPI.navigation_get_feedback(navHandle, ref feedback))
|
||||||
|
{
|
||||||
|
string stateStr = NavigationAPI.MarshalString(
|
||||||
|
NavigationAPI.navigation_state_to_string(feedback.navigation_state));
|
||||||
|
string feedbackStr = NavigationAPI.MarshalString(feedback.feed_back_str);
|
||||||
|
Console.WriteLine($"State: {stateStr}, Feedback: {feedbackStr}");
|
||||||
|
NavigationAPI.navigation_free_feedback(ref feedback);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
NavigationAPI.navigation_destroy(navHandle);
|
||||||
|
NavigationAPI.tf_listener_destroy(tfHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
BIN
examples/NavigationExample/libnav_c_api.so
Executable file
BIN
examples/NavigationExample/libnav_c_api.so
Executable file
Binary file not shown.
148
examples/QUICK_START.md
Normal file
148
examples/QUICK_START.md
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
# Quick Start - Chạy C# Example
|
||||||
|
|
||||||
|
## Bước 1: Cài đặt .NET SDK (nếu chưa có)
|
||||||
|
|
||||||
|
### Ubuntu/Debian:
|
||||||
|
```bash
|
||||||
|
# Cài đặt .NET 6.0 hoặc mới hơn
|
||||||
|
wget https://dot.net/v1/dotnet-install.sh
|
||||||
|
chmod +x dotnet-install.sh
|
||||||
|
./dotnet-install.sh --channel 6.0
|
||||||
|
|
||||||
|
# Thêm vào PATH
|
||||||
|
export PATH=$PATH:$HOME/.dotnet
|
||||||
|
export DOTNET_ROOT=$HOME/.dotnet
|
||||||
|
|
||||||
|
# Hoặc cài qua apt (nếu có)
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y dotnet-sdk-6.0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Kiểm tra:
|
||||||
|
```bash
|
||||||
|
dotnet --version
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bước 2: Build C API Library
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make nav_c_api
|
||||||
|
```
|
||||||
|
|
||||||
|
Library sẽ ở: `build/src/APIs/c_api/libnav_c_api.so`
|
||||||
|
|
||||||
|
## Bước 3: Chạy C# Example
|
||||||
|
|
||||||
|
### Cách 1: Dùng script tự động (Khuyến nghị)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/examples
|
||||||
|
chmod +x run_example.sh
|
||||||
|
./run_example.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Script sẽ tự động:
|
||||||
|
- ✅ Build library nếu chưa có
|
||||||
|
- ✅ Tạo C# project
|
||||||
|
- ✅ Copy library và source code
|
||||||
|
- ✅ Set LD_LIBRARY_PATH cho tất cả dependencies
|
||||||
|
- ✅ Build và chạy example
|
||||||
|
|
||||||
|
### Cách 2: Chạy thủ công
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Tạo project
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/examples
|
||||||
|
dotnet new console -n NavigationExample
|
||||||
|
cd NavigationExample
|
||||||
|
|
||||||
|
# 2. Copy source code
|
||||||
|
cp ../CSharpExample.cs Program.cs
|
||||||
|
|
||||||
|
# 3. Tạo .csproj
|
||||||
|
cat > NavigationExample.csproj << 'EOF'
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="libnav_c_api.so">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 4. Copy library
|
||||||
|
cp ../../build/src/APIs/c_api/libnav_c_api.so .
|
||||||
|
|
||||||
|
# 5. Set library path (quan trọng!)
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/APIs/c_api:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/costmap_2d:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/geometry2/tf3_geometry_msgs:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/geometry2/tf3_sensor_msgs:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Packages/move_base:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Cores/move_base_core:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/tf3:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/robot_time:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
# 6. Build và chạy
|
||||||
|
dotnet build
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bước 4: Kiểm tra kết quả
|
||||||
|
|
||||||
|
Nếu chạy thành công, bạn sẽ thấy output như:
|
||||||
|
```
|
||||||
|
Robot pose: x=0.0, y=0.0, theta=0.0
|
||||||
|
State: PENDING, Feedback: ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Lỗi: "dotnet: command not found"
|
||||||
|
→ Cài đặt .NET SDK (xem Bước 1)
|
||||||
|
|
||||||
|
### Lỗi: "Unable to load DLL 'libnav_c_api.so'"
|
||||||
|
```bash
|
||||||
|
# Kiểm tra library có tồn tại không
|
||||||
|
ls -la ../../build/src/APIs/c_api/libnav_c_api.so
|
||||||
|
|
||||||
|
# Set LD_LIBRARY_PATH (bao gồm tất cả dependencies)
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/APIs/c_api:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/costmap_2d:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/geometry2/tf3_geometry_msgs:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/geometry2/tf3_sensor_msgs:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Packages/move_base:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Cores/move_base_core:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/tf3:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/robot_time:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
# Hoặc copy vào system lib
|
||||||
|
sudo cp libnav_c_api.so /usr/local/lib/
|
||||||
|
sudo ldconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lỗi: "Missing dependencies"
|
||||||
|
```bash
|
||||||
|
# Kiểm tra dependencies
|
||||||
|
ldd libnav_c_api.so
|
||||||
|
|
||||||
|
# Đảm bảo tất cả dependencies đều có sẵn
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lỗi: "Failed to create navigation instance"
|
||||||
|
→ Đã được sửa! `navigation_create()` bây giờ tạo instance của `move_base::MoveBase`.
|
||||||
|
Nếu vẫn gặp lỗi, kiểm tra:
|
||||||
|
- Library đã được build đầy đủ: `make nav_c_api` trong build directory
|
||||||
|
- Dependencies đã được build: `make move_base costmap_2d`
|
||||||
|
- LD_LIBRARY_PATH đã được set đúng
|
||||||
|
|
||||||
142
examples/README.md
Normal file
142
examples/README.md
Normal file
|
|
@ -0,0 +1,142 @@
|
||||||
|
# Hướng dẫn chạy C# Example
|
||||||
|
|
||||||
|
## Yêu cầu
|
||||||
|
|
||||||
|
1. **.NET SDK** (version 6.0 trở lên hoặc .NET 10)
|
||||||
|
2. **C API Library** đã được build (`libnav_c_api.so`)
|
||||||
|
3. **Linux environment** (hoặc WSL nếu dùng Windows)
|
||||||
|
|
||||||
|
## Bước 1: Build C API Library
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make nav_c_api
|
||||||
|
```
|
||||||
|
|
||||||
|
Library sẽ được tạo tại: `build/src/APIs/c_api/libnav_c_api.so`
|
||||||
|
|
||||||
|
## Bước 2: Chạy script tự động (Khuyến nghị)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/examples
|
||||||
|
chmod +x run_example.sh
|
||||||
|
./run_example.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Script sẽ tự động:
|
||||||
|
- Build library nếu chưa có
|
||||||
|
- Tạo C# project
|
||||||
|
- Copy library và source code
|
||||||
|
- Set LD_LIBRARY_PATH cho tất cả dependencies
|
||||||
|
- Build và chạy example
|
||||||
|
|
||||||
|
## Bước 3: Hoặc chạy thủ công
|
||||||
|
|
||||||
|
### Tạo C# Project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/examples
|
||||||
|
dotnet new console -n NavigationExample
|
||||||
|
cd NavigationExample
|
||||||
|
```
|
||||||
|
|
||||||
|
### Copy file và library
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy C# source code
|
||||||
|
cp ../CSharpExample.cs Program.cs
|
||||||
|
|
||||||
|
# Copy library vào thư mục project
|
||||||
|
cp ../../build/src/APIs/c_api/libnav_c_api.so .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bước 4: Cập nhật .csproj (nếu cần)
|
||||||
|
|
||||||
|
Tạo file `NavigationExample.csproj`:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="libnav_c_api.so">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bước 4: Build và chạy
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set LD_LIBRARY_PATH để tìm được tất cả dependencies
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/APIs/c_api:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/costmap_2d:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/geometry2/tf3_geometry_msgs:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/geometry2/tf3_sensor_msgs:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Packages/move_base:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Cores/move_base_core:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/tf3:$LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=../../build/src/Navigations/Libraries/robot_time:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
# Build
|
||||||
|
dotnet build
|
||||||
|
|
||||||
|
# Chạy
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lưu ý
|
||||||
|
|
||||||
|
1. **Library path**: Đảm bảo `libnav_c_api.so` có thể được tìm thấy:
|
||||||
|
- Copy vào cùng thư mục với executable
|
||||||
|
- Hoặc set `LD_LIBRARY_PATH` environment variable
|
||||||
|
- Hoặc copy vào `/usr/local/lib` và chạy `ldconfig`
|
||||||
|
|
||||||
|
2. **Dependencies**: Library cần các dependencies khác:
|
||||||
|
```bash
|
||||||
|
# Kiểm tra dependencies
|
||||||
|
ldd libnav_c_api.so
|
||||||
|
|
||||||
|
# Đảm bảo tất cả dependencies đều có sẵn
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Permissions**: Đảm bảo file có quyền execute:
|
||||||
|
```bash
|
||||||
|
chmod +x libnav_c_api.so
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Lỗi: "Unable to load DLL 'libnav_c_api.so'"
|
||||||
|
|
||||||
|
**Giải pháp:**
|
||||||
|
```bash
|
||||||
|
# Set LD_LIBRARY_PATH
|
||||||
|
export LD_LIBRARY_PATH=/home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/build/src/APIs/c_api:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
# Hoặc copy library vào system path
|
||||||
|
sudo cp libnav_c_api.so /usr/local/lib/
|
||||||
|
sudo ldconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lỗi: "DllNotFoundException"
|
||||||
|
|
||||||
|
**Giải pháp:**
|
||||||
|
- Kiểm tra tên file library có đúng không
|
||||||
|
- Kiểm tra architecture (x64 vs x86)
|
||||||
|
- Kiểm tra dependencies: `ldd libnav_c_api.so`
|
||||||
|
|
||||||
|
### Lỗi: "Symbol not found"
|
||||||
|
|
||||||
|
**Giải pháp:**
|
||||||
|
- Đảm bảo library đã được build đầy đủ
|
||||||
|
- Kiểm tra tên hàm trong C# có khớp với C API không
|
||||||
|
|
||||||
83
examples/START_HERE.md
Normal file
83
examples/START_HERE.md
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
# 🚀 Hướng dẫn chạy thử C API Navigation
|
||||||
|
|
||||||
|
## Cách nhanh nhất (1 lệnh)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/examples
|
||||||
|
chmod +x run_example.sh
|
||||||
|
./run_example.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Chi tiết các bước
|
||||||
|
|
||||||
|
### Bước 1: Build C API Library
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/build
|
||||||
|
cmake ..
|
||||||
|
make nav_c_api
|
||||||
|
```
|
||||||
|
|
||||||
|
Library sẽ được tạo tại: `build/src/APIs/c_api/libnav_c_api.so`
|
||||||
|
|
||||||
|
### Bước 2: Chạy C# Example
|
||||||
|
|
||||||
|
Script `run_example.sh` sẽ tự động:
|
||||||
|
- ✅ Kiểm tra và build library nếu cần
|
||||||
|
- ✅ Tạo C# project
|
||||||
|
- ✅ Copy library và source code
|
||||||
|
- ✅ Set LD_LIBRARY_PATH cho tất cả dependencies
|
||||||
|
- ✅ Build và chạy example
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/examples
|
||||||
|
./run_example.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kết quả mong đợi
|
||||||
|
|
||||||
|
Nếu chạy thành công, bạn sẽ thấy:
|
||||||
|
|
||||||
|
```
|
||||||
|
==========================================
|
||||||
|
Building and Running C# Navigation Example
|
||||||
|
==========================================
|
||||||
|
Library already exists: .../build/src/APIs/c_api/libnav_c_api.so
|
||||||
|
C# project already exists
|
||||||
|
Copying library...
|
||||||
|
Building C# project...
|
||||||
|
|
||||||
|
Running example...
|
||||||
|
==========================================
|
||||||
|
Robot pose: x=0, y=0, theta=0
|
||||||
|
State: PENDING, Feedback:
|
||||||
|
==========================================
|
||||||
|
Done!
|
||||||
|
```
|
||||||
|
|
||||||
|
## Yêu cầu
|
||||||
|
|
||||||
|
1. **.NET SDK 6.0+** (script sẽ kiểm tra và hướng dẫn nếu thiếu)
|
||||||
|
2. **Library đã được build** (script sẽ tự động build nếu thiếu)
|
||||||
|
3. **Linux environment**
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Lỗi: "dotnet: command not found"
|
||||||
|
→ Script sẽ hiển thị hướng dẫn cài đặt .NET SDK
|
||||||
|
|
||||||
|
### Lỗi: "Failed to create navigation instance"
|
||||||
|
→ Đảm bảo `move_base` đã được build:
|
||||||
|
```bash
|
||||||
|
cd build && make move_base
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lỗi: "Cannot load library"
|
||||||
|
→ Kiểm tra LD_LIBRARY_PATH đã được set đúng (script tự động set)
|
||||||
|
|
||||||
|
## Xem thêm
|
||||||
|
|
||||||
|
- `README.md` - Hướng dẫn chi tiết
|
||||||
|
- `QUICK_START.md` - Quick start guide
|
||||||
|
- `run_example.sh` - Script tự động
|
||||||
|
|
||||||
1888
examples/dotnet-install.sh
vendored
Executable file
1888
examples/dotnet-install.sh
vendored
Executable file
File diff suppressed because it is too large
Load Diff
117
examples/run_example.sh
Executable file
117
examples/run_example.sh
Executable file
|
|
@ -0,0 +1,117 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Script để build và chạy C# example
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
BUILD_DIR="$PROJECT_ROOT/build"
|
||||||
|
LIB_DIR="$BUILD_DIR/src/APIs/c_api"
|
||||||
|
EXAMPLE_DIR="$SCRIPT_DIR"
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Building and Running C# Navigation Example"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
echo "📁 Paths:"
|
||||||
|
echo " SCRIPT_DIR: $SCRIPT_DIR"
|
||||||
|
echo " PROJECT_ROOT: $PROJECT_ROOT"
|
||||||
|
echo " BUILD_DIR: $BUILD_DIR"
|
||||||
|
echo " LIB_DIR: $LIB_DIR"
|
||||||
|
echo " EXAMPLE_DIR: $EXAMPLE_DIR"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
|
||||||
|
echo "Building C API library..."
|
||||||
|
cd "$BUILD_DIR"
|
||||||
|
cmake ..
|
||||||
|
make
|
||||||
|
echo "Library built successfully!"
|
||||||
|
|
||||||
|
|
||||||
|
# Kiểm tra dotnet có được cài đặt không
|
||||||
|
if ! command -v dotnet &> /dev/null; then
|
||||||
|
echo "=========================================="
|
||||||
|
echo "WARNING: .NET SDK not found!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo "To run the C# example, please install .NET SDK:"
|
||||||
|
echo ""
|
||||||
|
echo " Ubuntu/Debian:"
|
||||||
|
echo " wget https://dot.net/v1/dotnet-install.sh -O dotnet-install.sh"
|
||||||
|
echo " chmod +x dotnet-install.sh"
|
||||||
|
echo " ./dotnet-install.sh --channel 6.0"
|
||||||
|
echo " export PATH=\$PATH:\$HOME/.dotnet"
|
||||||
|
echo ""
|
||||||
|
echo " Or visit: https://dotnet.microsoft.com/download"
|
||||||
|
echo ""
|
||||||
|
echo "Skipping C# example. Library is available at:"
|
||||||
|
echo " $LIB_DIR/libnav_c_api.so"
|
||||||
|
echo "=========================================="
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Bước 2: Tạo C# project nếu chưa có
|
||||||
|
if [ ! -d "$EXAMPLE_DIR/NavigationExample" ]; then
|
||||||
|
echo "Creating C# project..."
|
||||||
|
cd "$EXAMPLE_DIR"
|
||||||
|
dotnet new console -n NavigationExample
|
||||||
|
cd NavigationExample
|
||||||
|
|
||||||
|
# Tạo .csproj file
|
||||||
|
cat > NavigationExample.csproj << 'EOF'
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>linux-x64</RuntimeIdentifier>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="libnav_c_api.so">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "C# project created!"
|
||||||
|
else
|
||||||
|
echo "C# project already exists"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Luôn copy source code mới nhất (cập nhật file nếu đã có)
|
||||||
|
cd "$EXAMPLE_DIR/NavigationExample"
|
||||||
|
echo "Updating Program.cs from CSharpExample.cs..."
|
||||||
|
cp ../CSharpExample.cs Program.cs
|
||||||
|
|
||||||
|
# Bước 3: Copy library
|
||||||
|
echo "Copying library..."
|
||||||
|
cp "$LIB_DIR/libnav_c_api.so" .
|
||||||
|
|
||||||
|
# Bước 4: Set LD_LIBRARY_PATH để tìm được tất cả dependencies
|
||||||
|
export LD_LIBRARY_PATH="$LIB_DIR:$LD_LIBRARY_PATH"
|
||||||
|
export LD_LIBRARY_PATH="$BUILD_DIR/src/Navigations/Libraries/costmap_2d:$LD_LIBRARY_PATH"
|
||||||
|
export LD_LIBRARY_PATH="$BUILD_DIR/src/Navigations/Libraries/geometry2/tf3_geometry_msgs:$LD_LIBRARY_PATH"
|
||||||
|
export LD_LIBRARY_PATH="$BUILD_DIR/src/Navigations/Libraries/geometry2/tf3_sensor_msgs:$LD_LIBRARY_PATH"
|
||||||
|
export LD_LIBRARY_PATH="$BUILD_DIR/src/Navigations/Packages/move_base:$LD_LIBRARY_PATH"
|
||||||
|
export LD_LIBRARY_PATH="$BUILD_DIR/src/Navigations/Cores/move_base_core:$LD_LIBRARY_PATH"
|
||||||
|
export LD_LIBRARY_PATH="$BUILD_DIR/src/Navigations/Libraries/tf3:$LD_LIBRARY_PATH"
|
||||||
|
export LD_LIBRARY_PATH="$BUILD_DIR/src/Navigations/Libraries/robot_time:$LD_LIBRARY_PATH"
|
||||||
|
|
||||||
|
# Bước 5: Build và chạy
|
||||||
|
echo "Building C# project..."
|
||||||
|
dotnet build
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Running example..."
|
||||||
|
echo "=========================================="
|
||||||
|
echo "LD_LIBRARY_PATH includes:"
|
||||||
|
echo "$LD_LIBRARY_PATH" | tr ':' '\n' | head -5
|
||||||
|
echo "..."
|
||||||
|
echo "=========================================="
|
||||||
|
dotnet run
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Done!"
|
||||||
|
|
||||||
116
setup_catkin_workspace.sh
Executable file
116
setup_catkin_workspace.sh
Executable file
|
|
@ -0,0 +1,116 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# ========================================================
|
||||||
|
# Script to setup Catkin workspace for pnkx_nav_core
|
||||||
|
# ========================================================
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
WORKSPACE_NAME="pnkx_nav_catkin_ws"
|
||||||
|
WORKSPACE_DIR="${SCRIPT_DIR}/../${WORKSPACE_NAME}"
|
||||||
|
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Setting up Catkin workspace for pnkx_nav_core"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Create workspace directory
|
||||||
|
echo "Creating workspace directory: ${WORKSPACE_DIR}"
|
||||||
|
mkdir -p "${WORKSPACE_DIR}/src"
|
||||||
|
|
||||||
|
# Check if src directory already has packages
|
||||||
|
if [ -d "${WORKSPACE_DIR}/src" ] && [ "$(ls -A ${WORKSPACE_DIR}/src 2>/dev/null)" ]; then
|
||||||
|
echo "Warning: ${WORKSPACE_DIR}/src already contains packages"
|
||||||
|
read -p "Do you want to continue? (y/n) " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Aborted."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create symlinks to packages that have package.xml
|
||||||
|
echo ""
|
||||||
|
echo "Creating symlinks to packages with package.xml..."
|
||||||
|
|
||||||
|
# Find all packages with package.xml in the source tree
|
||||||
|
PACKAGES=(
|
||||||
|
"src/Libraries/tf3"
|
||||||
|
"src/Libraries/nav_2d_utils"
|
||||||
|
"src/Navigations/Libraries/nav_grid"
|
||||||
|
"src/Navigations/Cores/nav_core"
|
||||||
|
"src/Navigations/Cores/nav_core2"
|
||||||
|
"src/Navigations/Cores/nav_core_adapter"
|
||||||
|
"src/Navigations/Cores/move_base_core"
|
||||||
|
"src/Navigations/Cores/nav_core_adapter"
|
||||||
|
"src/Packages/move_base"
|
||||||
|
"src/Navigations/Packages/move_base"
|
||||||
|
)
|
||||||
|
|
||||||
|
for PKG_PATH in "${PACKAGES[@]}"; do
|
||||||
|
FULL_PATH="${SCRIPT_DIR}/${PKG_PATH}"
|
||||||
|
if [ -f "${FULL_PATH}/package.xml" ]; then
|
||||||
|
PKG_NAME=$(basename "${PKG_PATH}")
|
||||||
|
TARGET="${WORKSPACE_DIR}/src/${PKG_NAME}"
|
||||||
|
|
||||||
|
if [ -e "${TARGET}" ]; then
|
||||||
|
echo " Warning: ${TARGET} already exists, skipping..."
|
||||||
|
else
|
||||||
|
echo " Linking: ${PKG_NAME} -> ${PKG_PATH}"
|
||||||
|
ln -s "${FULL_PATH}" "${TARGET}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " Warning: ${PKG_PATH}/package.xml not found, skipping..."
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Create a README in the workspace
|
||||||
|
cat > "${WORKSPACE_DIR}/README.md" << EOF
|
||||||
|
# Catkin Workspace for pnkx_nav_core
|
||||||
|
|
||||||
|
This is a Catkin workspace containing ROS-compatible packages from pnkx_nav_core.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
${WORKSPACE_NAME}/
|
||||||
|
├── src/ # Source packages (symlinked from pnkx_nav_core)
|
||||||
|
└── build/ # Build directory (created by catkin_make)
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
cd ${WORKSPACE_DIR}
|
||||||
|
catkin_make
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Source the workspace
|
||||||
|
|
||||||
|
After building, source the setup file:
|
||||||
|
|
||||||
|
\`\`\`bash
|
||||||
|
source devel/setup.bash
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## Note
|
||||||
|
|
||||||
|
Packages in \`src/\` are symlinked from the main pnkx_nav_core project.
|
||||||
|
To add more packages, create symlinks in \`src/\` pointing to packages
|
||||||
|
that have both \`CMakeLists.txt\` and \`package.xml\`.
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo "Workspace setup complete!"
|
||||||
|
echo "=========================================="
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " 1. cd ${WORKSPACE_DIR}"
|
||||||
|
echo " 2. catkin_make"
|
||||||
|
echo " 3. source devel/setup.bash"
|
||||||
|
echo ""
|
||||||
|
echo "Note: Make sure all dependencies are built in the main project first"
|
||||||
|
echo " using standalone CMake before building with catkin."
|
||||||
|
echo ""
|
||||||
|
|
||||||
82
src/APIs/c_api/CMakeLists.txt
Normal file
82
src/APIs/c_api/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(nav_c_api VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Chuẩn C++
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
set(PACKAGES_DIR
|
||||||
|
move_base_core
|
||||||
|
move_base
|
||||||
|
tf3
|
||||||
|
robot_time
|
||||||
|
geometry_msgs
|
||||||
|
)
|
||||||
|
|
||||||
|
# Thư mục include
|
||||||
|
include_directories(
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tìm tất cả file source
|
||||||
|
file(GLOB SOURCES "src/*.cpp")
|
||||||
|
file(GLOB HEADERS "include/*.h")
|
||||||
|
|
||||||
|
# Tạo thư viện shared (.so)
|
||||||
|
add_library(nav_c_api SHARED ${SOURCES} ${HEADERS})
|
||||||
|
|
||||||
|
# Link libraries
|
||||||
|
target_link_libraries(nav_c_api
|
||||||
|
PUBLIC
|
||||||
|
${PACKAGES_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set include directories
|
||||||
|
target_include_directories(nav_c_api
|
||||||
|
PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt header files
|
||||||
|
install(DIRECTORY include/
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING PATTERN "*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt library
|
||||||
|
install(TARGETS nav_c_api
|
||||||
|
EXPORT nav_c_api-targets
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|
||||||
|
# Export targets
|
||||||
|
install(EXPORT nav_c_api-targets
|
||||||
|
FILE nav_c_api-targets.cmake
|
||||||
|
DESTINATION lib/cmake/nav_c_api
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tùy chọn build
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
|
option(BUILD_TESTS "Build test programs" OFF)
|
||||||
|
|
||||||
|
# Flags biên dịch
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
|
||||||
|
|
||||||
|
# In thông tin cấu hình
|
||||||
|
message(STATUS "=================================")
|
||||||
|
message(STATUS "Project: ${PROJECT_NAME}")
|
||||||
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
|
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||||
|
message(STATUS "=================================")
|
||||||
|
|
||||||
349
src/APIs/c_api/include/nav_c_api.h
Normal file
349
src/APIs/c_api/include/nav_c_api.h
Normal file
|
|
@ -0,0 +1,349 @@
|
||||||
|
#ifndef NAVIGATION_C_API_H
|
||||||
|
#define NAVIGATION_C_API_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
typedef void* NavigationHandle;
|
||||||
|
typedef void* TFListenerHandle;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Enums
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Navigation states, including planning and controller status
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
NAV_STATE_PENDING = 0,
|
||||||
|
NAV_STATE_ACTIVE = 1,
|
||||||
|
NAV_STATE_PREEMPTED = 2,
|
||||||
|
NAV_STATE_SUCCEEDED = 3,
|
||||||
|
NAV_STATE_ABORTED = 4,
|
||||||
|
NAV_STATE_REJECTED = 5,
|
||||||
|
NAV_STATE_PREEMPTING = 6,
|
||||||
|
NAV_STATE_RECALLING = 7,
|
||||||
|
NAV_STATE_RECALLED = 8,
|
||||||
|
NAV_STATE_LOST = 9,
|
||||||
|
NAV_STATE_PLANNING = 10,
|
||||||
|
NAV_STATE_CONTROLLING = 11,
|
||||||
|
NAV_STATE_CLEARING = 12,
|
||||||
|
NAV_STATE_PAUSED = 13
|
||||||
|
} NavigationState;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Structures
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Point structure (x, y, z)
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
} Point;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pose2D structure (x, y, theta)
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double theta;
|
||||||
|
} Pose2D;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Quaternion structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
double w;
|
||||||
|
} Quaternion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Position structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
} Position;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pose structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
Position position;
|
||||||
|
Quaternion orientation;
|
||||||
|
} Pose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Header structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seq;
|
||||||
|
int64_t sec;
|
||||||
|
uint32_t nsec;
|
||||||
|
char* frame_id;
|
||||||
|
} Header;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief PoseStamped structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
Header header;
|
||||||
|
Pose pose;
|
||||||
|
} PoseStamped;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vector3 structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
} Vector3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Navigation feedback structure
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
NavigationState navigation_state;
|
||||||
|
char* feed_back_str;
|
||||||
|
Pose2D current_pose;
|
||||||
|
bool goal_checked;
|
||||||
|
bool is_ready;
|
||||||
|
} NavFeedback;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// String Management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free a string allocated by the library
|
||||||
|
* @param str String to free
|
||||||
|
*/
|
||||||
|
void nav_c_api_free_string(char* str);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// State Conversion
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a State enum to its string representation
|
||||||
|
* @param state Enum value of NavigationState
|
||||||
|
* @return String representation (caller must free with nav_c_api_free_string)
|
||||||
|
*/
|
||||||
|
char* navigation_state_to_string(NavigationState state);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper Functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a target pose by offsetting a given 2D pose along its heading direction
|
||||||
|
* @param pose_x X coordinate of the original pose
|
||||||
|
* @param pose_y Y coordinate of the original pose
|
||||||
|
* @param pose_theta Heading angle in radians
|
||||||
|
* @param frame_id The coordinate frame ID (null-terminated string)
|
||||||
|
* @param offset_distance Distance to offset along heading (positive = forward, negative = backward)
|
||||||
|
* @param out_goal Output parameter for the offset pose
|
||||||
|
* @return true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool navigation_offset_goal_2d(double pose_x, double pose_y, double pose_theta,
|
||||||
|
const char* frame_id, double offset_distance,
|
||||||
|
PoseStamped* out_goal);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates an offset target pose from a given PoseStamped
|
||||||
|
* @param in_pose Input pose
|
||||||
|
* @param offset_distance Distance to offset along heading direction
|
||||||
|
* @param out_goal Output parameter for the offset pose
|
||||||
|
* @return true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool navigation_offset_goal_stamped(const PoseStamped* in_pose, double offset_distance,
|
||||||
|
PoseStamped* out_goal);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Navigation Handle Management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a new navigation instance
|
||||||
|
* @return Navigation handle, or NULL on failure
|
||||||
|
*/
|
||||||
|
NavigationHandle navigation_create(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy a navigation instance
|
||||||
|
* @param handle Navigation handle to destroy
|
||||||
|
*/
|
||||||
|
void navigation_destroy(NavigationHandle handle);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TF Listener Management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create a TF listener instance
|
||||||
|
* @return TF listener handle, or NULL on failure
|
||||||
|
*/
|
||||||
|
TFListenerHandle tf_listener_create(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destroy a TF listener instance
|
||||||
|
* @param handle TF listener handle to destroy
|
||||||
|
*/
|
||||||
|
void tf_listener_destroy(TFListenerHandle handle);
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Navigation Interface Methods
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the navigation system
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param tf_handle TF listener handle
|
||||||
|
* @return true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool navigation_initialize(NavigationHandle handle, TFListenerHandle tf_handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set the robot's footprint (outline shape)
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param points Array of points representing the footprint polygon
|
||||||
|
* @param point_count Number of points in the array
|
||||||
|
* @return true on success, false on failure
|
||||||
|
*/
|
||||||
|
bool navigation_set_robot_footprint(NavigationHandle handle, const Point* points, size_t point_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a goal for the robot to navigate to
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param goal Target pose in the global frame
|
||||||
|
* @param xy_goal_tolerance Acceptable error in X/Y (meters)
|
||||||
|
* @param yaw_goal_tolerance Acceptable angular error (radians)
|
||||||
|
* @return true if goal was accepted and sent successfully
|
||||||
|
*/
|
||||||
|
bool navigation_move_to(NavigationHandle handle, const PoseStamped* goal,
|
||||||
|
double xy_goal_tolerance, double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send a docking goal to a predefined marker
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param marker Marker name or ID (null-terminated string)
|
||||||
|
* @param goal Target pose for docking
|
||||||
|
* @param xy_goal_tolerance Acceptable XY error (meters)
|
||||||
|
* @param yaw_goal_tolerance Acceptable heading error (radians)
|
||||||
|
* @return true if docking command succeeded
|
||||||
|
*/
|
||||||
|
bool navigation_dock_to(NavigationHandle handle, const char* marker,
|
||||||
|
const PoseStamped* goal,
|
||||||
|
double xy_goal_tolerance, double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Move straight toward the target position
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param goal Target pose
|
||||||
|
* @param xy_goal_tolerance Acceptable positional error (meters)
|
||||||
|
* @return true if command issued successfully
|
||||||
|
*/
|
||||||
|
bool navigation_move_straight_to(NavigationHandle handle, const PoseStamped* goal,
|
||||||
|
double xy_goal_tolerance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Rotate in place to align with target orientation
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param goal Pose containing desired heading (only Z-axis used)
|
||||||
|
* @param yaw_goal_tolerance Acceptable angular error (radians)
|
||||||
|
* @return true if rotation command was sent successfully
|
||||||
|
*/
|
||||||
|
bool navigation_rotate_to(NavigationHandle handle, const PoseStamped* goal,
|
||||||
|
double yaw_goal_tolerance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pause the robot's movement
|
||||||
|
* @param handle Navigation handle
|
||||||
|
*/
|
||||||
|
void navigation_pause(NavigationHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resume motion after a pause
|
||||||
|
* @param handle Navigation handle
|
||||||
|
*/
|
||||||
|
void navigation_resume(NavigationHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cancel the current goal and stop the robot
|
||||||
|
* @param handle Navigation handle
|
||||||
|
*/
|
||||||
|
void navigation_cancel(NavigationHandle handle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send limited linear velocity command
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param linear_x Linear velocity in X direction
|
||||||
|
* @param linear_y Linear velocity in Y direction
|
||||||
|
* @param linear_z Linear velocity in Z direction
|
||||||
|
* @return true if the command was accepted
|
||||||
|
*/
|
||||||
|
bool navigation_set_twist_linear(NavigationHandle handle,
|
||||||
|
double linear_x, double linear_y, double linear_z);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send limited angular velocity command
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param angular_x Angular velocity around X axis
|
||||||
|
* @param angular_y Angular velocity around Y axis
|
||||||
|
* @param angular_z Angular velocity around Z axis
|
||||||
|
* @return true if the command was accepted
|
||||||
|
*/
|
||||||
|
bool navigation_set_twist_angular(NavigationHandle handle,
|
||||||
|
double angular_x, double angular_y, double angular_z);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the robot's pose as a PoseStamped
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param out_pose Output parameter with the robot's current pose
|
||||||
|
* @return true if pose was successfully retrieved
|
||||||
|
*/
|
||||||
|
bool navigation_get_robot_pose_stamped(NavigationHandle handle, PoseStamped* out_pose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the robot's pose as a 2D pose
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param out_pose Output parameter with the robot's current 2D pose
|
||||||
|
* @return true if pose was successfully retrieved
|
||||||
|
*/
|
||||||
|
bool navigation_get_robot_pose_2d(NavigationHandle handle, Pose2D* out_pose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get navigation feedback
|
||||||
|
* @param handle Navigation handle
|
||||||
|
* @param out_feedback Output parameter with navigation feedback
|
||||||
|
* @return true if feedback was successfully retrieved
|
||||||
|
* @note The feed_back_str field must be freed using nav_c_api_free_string
|
||||||
|
*/
|
||||||
|
bool navigation_get_feedback(NavigationHandle handle, NavFeedback* out_feedback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free navigation feedback structure
|
||||||
|
* @param feedback Feedback structure to free
|
||||||
|
*/
|
||||||
|
void navigation_free_feedback(NavFeedback* feedback);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // NAVIGATION_C_API_H
|
||||||
|
|
||||||
432
src/APIs/c_api/src/nav_c_api.cpp
Normal file
432
src/APIs/c_api/src/nav_c_api.cpp
Normal file
|
|
@ -0,0 +1,432 @@
|
||||||
|
#include "nav_c_api.h"
|
||||||
|
#include <move_base_core/navigation.h>
|
||||||
|
#include <move_base_core/common.h>
|
||||||
|
#include <move_base/move_base.h>
|
||||||
|
#include <geometry_msgs/PoseStamped.h>
|
||||||
|
#include <geometry_msgs/Pose2D.h>
|
||||||
|
#include <geometry_msgs/Point.h>
|
||||||
|
#include <geometry_msgs/Vector3.h>
|
||||||
|
#include <tf3/buffer_core.h>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <boost/dll/import.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Internal Helper Functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Convert C PoseStamped to C++ PoseStamped
|
||||||
|
geometry_msgs::PoseStamped c_to_cpp_pose_stamped(const PoseStamped* c_pose) {
|
||||||
|
geometry_msgs::PoseStamped cpp_pose;
|
||||||
|
cpp_pose.header.seq = c_pose->header.seq;
|
||||||
|
cpp_pose.header.stamp.sec = c_pose->header.sec;
|
||||||
|
cpp_pose.header.stamp.nsec = c_pose->header.nsec;
|
||||||
|
if (c_pose->header.frame_id) {
|
||||||
|
cpp_pose.header.frame_id = c_pose->header.frame_id;
|
||||||
|
}
|
||||||
|
cpp_pose.pose.position.x = c_pose->pose.position.x;
|
||||||
|
cpp_pose.pose.position.y = c_pose->pose.position.y;
|
||||||
|
cpp_pose.pose.position.z = c_pose->pose.position.z;
|
||||||
|
cpp_pose.pose.orientation.x = c_pose->pose.orientation.x;
|
||||||
|
cpp_pose.pose.orientation.y = c_pose->pose.orientation.y;
|
||||||
|
cpp_pose.pose.orientation.z = c_pose->pose.orientation.z;
|
||||||
|
cpp_pose.pose.orientation.w = c_pose->pose.orientation.w;
|
||||||
|
return cpp_pose;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert C++ PoseStamped to C PoseStamped
|
||||||
|
void cpp_to_c_pose_stamped(const geometry_msgs::PoseStamped& cpp_pose, PoseStamped* c_pose) {
|
||||||
|
c_pose->header.seq = cpp_pose.header.seq;
|
||||||
|
c_pose->header.sec = cpp_pose.header.stamp.sec;
|
||||||
|
c_pose->header.nsec = cpp_pose.header.stamp.nsec;
|
||||||
|
if (!cpp_pose.header.frame_id.empty()) {
|
||||||
|
c_pose->header.frame_id = strdup(cpp_pose.header.frame_id.c_str());
|
||||||
|
} else {
|
||||||
|
c_pose->header.frame_id = nullptr;
|
||||||
|
}
|
||||||
|
c_pose->pose.position.x = cpp_pose.pose.position.x;
|
||||||
|
c_pose->pose.position.y = cpp_pose.pose.position.y;
|
||||||
|
c_pose->pose.position.z = cpp_pose.pose.position.z;
|
||||||
|
c_pose->pose.orientation.x = cpp_pose.pose.orientation.x;
|
||||||
|
c_pose->pose.orientation.y = cpp_pose.pose.orientation.y;
|
||||||
|
c_pose->pose.orientation.z = cpp_pose.pose.orientation.z;
|
||||||
|
c_pose->pose.orientation.w = cpp_pose.pose.orientation.w;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert C++ Pose2D to C Pose2D
|
||||||
|
void cpp_to_c_pose_2d(const geometry_msgs::Pose2D& cpp_pose, Pose2D* c_pose) {
|
||||||
|
c_pose->x = cpp_pose.x;
|
||||||
|
c_pose->y = cpp_pose.y;
|
||||||
|
c_pose->theta = cpp_pose.theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert C++ NavFeedback to C NavFeedback
|
||||||
|
void cpp_to_c_nav_feedback(const move_base_core::NavFeedback& cpp_feedback, NavFeedback* c_feedback) {
|
||||||
|
c_feedback->navigation_state = static_cast<NavigationState>(static_cast<int>(cpp_feedback.navigation_state));
|
||||||
|
if (!cpp_feedback.feed_back_str.empty()) {
|
||||||
|
c_feedback->feed_back_str = strdup(cpp_feedback.feed_back_str.c_str());
|
||||||
|
} else {
|
||||||
|
c_feedback->feed_back_str = nullptr;
|
||||||
|
}
|
||||||
|
c_feedback->current_pose.x = cpp_feedback.current_pose.x;
|
||||||
|
c_feedback->current_pose.y = cpp_feedback.current_pose.y;
|
||||||
|
c_feedback->current_pose.theta = cpp_feedback.current_pose.theta;
|
||||||
|
c_feedback->goal_checked = cpp_feedback.goal_checked;
|
||||||
|
c_feedback->is_ready = cpp_feedback.is_ready;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// String Management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
extern "C" void nav_c_api_free_string(char* str) {
|
||||||
|
if (str) {
|
||||||
|
free(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// State Conversion
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
extern "C" char* navigation_state_to_string(NavigationState state) {
|
||||||
|
move_base_core::State cpp_state = static_cast<move_base_core::State>(static_cast<int>(state));
|
||||||
|
std::string str = move_base_core::toString(cpp_state);
|
||||||
|
return strdup(str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Helper Functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
extern "C" bool navigation_offset_goal_2d(double pose_x, double pose_y, double pose_theta,
|
||||||
|
const char* frame_id, double offset_distance,
|
||||||
|
PoseStamped* out_goal) {
|
||||||
|
if (!out_goal || !frame_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry_msgs::Pose2D pose;
|
||||||
|
pose.x = pose_x;
|
||||||
|
pose.y = pose_y;
|
||||||
|
pose.theta = pose_theta;
|
||||||
|
|
||||||
|
geometry_msgs::PoseStamped result = move_base_core::offset_goal(pose, std::string(frame_id), offset_distance);
|
||||||
|
cpp_to_c_pose_stamped(result, out_goal);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_offset_goal_stamped(const PoseStamped* in_pose, double offset_distance,
|
||||||
|
PoseStamped* out_goal) {
|
||||||
|
if (!in_pose || !out_goal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry_msgs::PoseStamped cpp_pose = c_to_cpp_pose_stamped(in_pose);
|
||||||
|
geometry_msgs::PoseStamped result = move_base_core::offset_goal(cpp_pose, offset_distance);
|
||||||
|
cpp_to_c_pose_stamped(result, out_goal);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Navigation Handle Management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
extern "C" NavigationHandle navigation_create(void) {
|
||||||
|
try {
|
||||||
|
// Create a concrete MoveBase instance
|
||||||
|
// Using default constructor - initialization will be done via navigation_initialize()
|
||||||
|
move_base::MoveBase* move_base = new move_base::MoveBase();
|
||||||
|
return static_cast<NavigationHandle>(move_base);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
// Log error if possible (in production, use proper logging)
|
||||||
|
return nullptr;
|
||||||
|
} catch (...) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void navigation_destroy(NavigationHandle handle) {
|
||||||
|
if (handle) {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
delete nav;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// TF Listener Management
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
extern "C" TFListenerHandle tf_listener_create(void) {
|
||||||
|
try {
|
||||||
|
auto tf = std::make_shared<tf3::BufferCore>();
|
||||||
|
return new std::shared_ptr<tf3::BufferCore>(tf);
|
||||||
|
} catch (...) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void tf_listener_destroy(TFListenerHandle handle) {
|
||||||
|
if (handle) {
|
||||||
|
auto* tf_ptr = static_cast<std::shared_ptr<tf3::BufferCore>*>(handle);
|
||||||
|
delete tf_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Navigation Interface Methods
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
extern "C" bool navigation_initialize(NavigationHandle handle, TFListenerHandle tf_handle)
|
||||||
|
{
|
||||||
|
printf("[%s:%d] Begin: navigation_initialize\n", __FILE__, __LINE__);
|
||||||
|
if (!handle || !tf_handle) {
|
||||||
|
printf("[%s:%d] Error: Invalid parameters\n", __FILE__, __LINE__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
printf("[%s:%d] Initialize navigation\n", __FILE__, __LINE__);
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
auto* tf_ptr = static_cast<std::shared_ptr<tf3::BufferCore>*>(tf_handle);
|
||||||
|
|
||||||
|
auto create_plugin = boost::dll::import_alias<move_base_core::BaseNavigation::Ptr()>(
|
||||||
|
"/home/robotics/AGV/Diff_Wheel_Prj/pnkx_nav_core/build/src/Navigations/Packages/move_base/libmove_base.so",
|
||||||
|
"MoveBase",
|
||||||
|
boost::dll::load_mode::append_decorations);
|
||||||
|
|
||||||
|
move_base_core::BaseNavigation::Ptr nav_ptr = create_plugin();
|
||||||
|
printf("[%s:%d] Navigation created\n", __FILE__, __LINE__);
|
||||||
|
if (nav_ptr == nullptr) {
|
||||||
|
printf("[%s:%d] Error: Failed to create navigation\n", __FILE__, __LINE__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nav_ptr->initialize(*tf_ptr);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
printf("[%s:%d] Error: Failed to initialize navigation: %s\n", __FILE__, __LINE__, e.what());
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
printf("[%s:%d] Error: Failed to initialize navigation\n", __FILE__, __LINE__);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_set_robot_footprint(NavigationHandle handle, const Point* points, size_t point_count) {
|
||||||
|
if (!handle || !points || point_count == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
std::vector<geometry_msgs::Point> footprint;
|
||||||
|
footprint.reserve(point_count);
|
||||||
|
for (size_t i = 0; i < point_count; ++i) {
|
||||||
|
geometry_msgs::Point pt;
|
||||||
|
pt.x = points[i].x;
|
||||||
|
pt.y = points[i].y;
|
||||||
|
pt.z = points[i].z;
|
||||||
|
footprint.push_back(pt);
|
||||||
|
}
|
||||||
|
nav->setRobotFootprint(footprint);
|
||||||
|
return true;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_move_to(NavigationHandle handle, const PoseStamped* goal,
|
||||||
|
double xy_goal_tolerance, double yaw_goal_tolerance) {
|
||||||
|
if (!handle || !goal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
geometry_msgs::PoseStamped cpp_goal = c_to_cpp_pose_stamped(goal);
|
||||||
|
return nav->moveTo(cpp_goal, xy_goal_tolerance, yaw_goal_tolerance);
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_dock_to(NavigationHandle handle, const char* marker,
|
||||||
|
const PoseStamped* goal,
|
||||||
|
double xy_goal_tolerance, double yaw_goal_tolerance) {
|
||||||
|
if (!handle || !marker || !goal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
geometry_msgs::PoseStamped cpp_goal = c_to_cpp_pose_stamped(goal);
|
||||||
|
return nav->dockTo(std::string(marker), cpp_goal, xy_goal_tolerance, yaw_goal_tolerance);
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_move_straight_to(NavigationHandle handle, const PoseStamped* goal,
|
||||||
|
double xy_goal_tolerance) {
|
||||||
|
if (!handle || !goal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
geometry_msgs::PoseStamped cpp_goal = c_to_cpp_pose_stamped(goal);
|
||||||
|
return nav->moveStraightTo(cpp_goal, xy_goal_tolerance);
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_rotate_to(NavigationHandle handle, const PoseStamped* goal,
|
||||||
|
double yaw_goal_tolerance) {
|
||||||
|
if (!handle || !goal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
geometry_msgs::PoseStamped cpp_goal = c_to_cpp_pose_stamped(goal);
|
||||||
|
return nav->rotateTo(cpp_goal, yaw_goal_tolerance);
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void navigation_pause(NavigationHandle handle) {
|
||||||
|
if (handle) {
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
nav->pause();
|
||||||
|
} catch (...) {
|
||||||
|
// Ignore exceptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void navigation_resume(NavigationHandle handle) {
|
||||||
|
if (handle) {
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
nav->resume();
|
||||||
|
} catch (...) {
|
||||||
|
// Ignore exceptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void navigation_cancel(NavigationHandle handle) {
|
||||||
|
if (handle) {
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
nav->cancel();
|
||||||
|
} catch (...) {
|
||||||
|
// Ignore exceptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_set_twist_linear(NavigationHandle handle,
|
||||||
|
double linear_x, double linear_y, double linear_z) {
|
||||||
|
if (!handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
geometry_msgs::Vector3 linear;
|
||||||
|
linear.x = linear_x;
|
||||||
|
linear.y = linear_y;
|
||||||
|
linear.z = linear_z;
|
||||||
|
return nav->setTwistLinear(linear);
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_set_twist_angular(NavigationHandle handle,
|
||||||
|
double angular_x, double angular_y, double angular_z) {
|
||||||
|
if (!handle) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
geometry_msgs::Vector3 angular;
|
||||||
|
angular.x = angular_x;
|
||||||
|
angular.y = angular_y;
|
||||||
|
angular.z = angular_z;
|
||||||
|
return nav->setTwistAngular(angular);
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_get_robot_pose_stamped(NavigationHandle handle, PoseStamped* out_pose) {
|
||||||
|
if (!handle || !out_pose) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
geometry_msgs::PoseStamped cpp_pose;
|
||||||
|
if (nav->getRobotPose(cpp_pose)) {
|
||||||
|
cpp_to_c_pose_stamped(cpp_pose, out_pose);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_get_robot_pose_2d(NavigationHandle handle, Pose2D* out_pose) {
|
||||||
|
if (!handle || !out_pose) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
geometry_msgs::Pose2D cpp_pose;
|
||||||
|
if (nav->getRobotPose(cpp_pose)) {
|
||||||
|
cpp_to_c_pose_2d(cpp_pose, out_pose);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool navigation_get_feedback(NavigationHandle handle, NavFeedback* out_feedback) {
|
||||||
|
if (!handle || !out_feedback) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
move_base_core::BaseNavigation* nav = static_cast<move_base_core::BaseNavigation*>(handle);
|
||||||
|
if (nav->nav_feedback_) {
|
||||||
|
cpp_to_c_nav_feedback(*nav->nav_feedback_, out_feedback);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void navigation_free_feedback(NavFeedback* feedback) {
|
||||||
|
if (feedback) {
|
||||||
|
nav_c_api_free_string(feedback->feed_back_str);
|
||||||
|
feedback->feed_back_str = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
71
src/Algorithms/Cores/score_algorithm/CMakeLists.txt
Normal file
71
src/Algorithms/Cores/score_algorithm/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
# Tên dự án
|
||||||
|
project(score_algorithm VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Chuẩn C++
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(PACKAGES_DIR nav_2d_msgs nav_2d_utils nav_core nav_core2 geometry_msgs mkt_msgs angles)
|
||||||
|
|
||||||
|
find_package(Boost REQUIRED COMPONENTS filesystem system)
|
||||||
|
|
||||||
|
# Thư mục include
|
||||||
|
include_directories(
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
# Tạo thư viện shared (.so)
|
||||||
|
|
||||||
|
add_library(score_algorithm src/score_algorithm.cpp)
|
||||||
|
target_link_libraries(score_algorithm
|
||||||
|
PUBLIC
|
||||||
|
${PACKAGES_DIR}
|
||||||
|
PRIVATE
|
||||||
|
Boost::filesystem
|
||||||
|
Boost::system
|
||||||
|
)
|
||||||
|
target_include_directories(score_algorithm PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>)
|
||||||
|
|
||||||
|
# Cài đặt header files
|
||||||
|
install(DIRECTORY include/score_algorithm
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING PATTERN "*.h")
|
||||||
|
|
||||||
|
# Cài đặt library
|
||||||
|
install(TARGETS score_algorithm
|
||||||
|
EXPORT score_algorithm-targets
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
|
# Export targets
|
||||||
|
install(EXPORT score_algorithm-targets
|
||||||
|
FILE score_algorithm-targets.cmake
|
||||||
|
DESTINATION lib/cmake/score_algorithm)
|
||||||
|
|
||||||
|
# Tùy chọn build
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
|
option(BUILD_TESTS "Build test programs" OFF)
|
||||||
|
|
||||||
|
# Flags biên dịch
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
|
||||||
|
|
||||||
|
# In thông tin cấu hình
|
||||||
|
message(STATUS "=================================")
|
||||||
|
message(STATUS "Project: ${PROJECT_NAME}")
|
||||||
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
|
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||||
|
message(STATUS "Headers found:")
|
||||||
|
foreach(hdr ${HEADERS})
|
||||||
|
message(STATUS " - ${hdr}")
|
||||||
|
endforeach()
|
||||||
|
message(STATUS "=================================")
|
||||||
26
src/Algorithms/Cores/score_algorithm/include/angles/angles.h
Normal file
26
src/Algorithms/Cores/score_algorithm/include/angles/angles.h
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef ANGLES_ANGLES_H
|
||||||
|
#define ANGLES_ANGLES_H
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace angles
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Normalize an angle to the range [-π, π]
|
||||||
|
* @param angle The angle in radians to normalize
|
||||||
|
* @return The normalized angle in the range [-π, π]
|
||||||
|
*/
|
||||||
|
inline double normalize_angle(double angle)
|
||||||
|
{
|
||||||
|
while (angle > M_PI)
|
||||||
|
angle -= 2.0 * M_PI;
|
||||||
|
while (angle < -M_PI)
|
||||||
|
angle += 2.0 * M_PI;
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace angles
|
||||||
|
|
||||||
|
#endif // ANGLES_ANGLES_H
|
||||||
|
|
||||||
56
src/Algorithms/Cores/score_algorithm/include/score_algorithm/goal_checker.h
Executable file
56
src/Algorithms/Cores/score_algorithm/include/score_algorithm/goal_checker.h
Executable file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef _SCORE_GOAL_CHECKER_H_INCLUDED__
|
||||||
|
#define _SCORE_GOAL_CHECKER_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <ros/ros.h>
|
||||||
|
#include <geometry_msgs/Pose2D.h>
|
||||||
|
#include <geometry_msgs/PoseStamped.h>
|
||||||
|
#include <nav_2d_msgs/Twist2D.h>
|
||||||
|
#include <nav_2d_msgs/Pose2DStamped.h>
|
||||||
|
#include <nav_2d_msgs/Path2D.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace score_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class GoalChecker
|
||||||
|
* @brief Function-object for checking whether a goal has been reached
|
||||||
|
*
|
||||||
|
* This class defines the plugin interface for determining whether you have reached
|
||||||
|
* the goal state. This primarily consists of checking the relative positions of two poses
|
||||||
|
* (which are presumed to be in the same frame). It can also check the velocity, as some
|
||||||
|
* applications require that robot be stopped to be considered as having reached the goal.
|
||||||
|
*/
|
||||||
|
class GoalChecker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<score_algorithm::GoalChecker>;
|
||||||
|
|
||||||
|
virtual ~GoalChecker() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize any parameters from the NodeHandle
|
||||||
|
* @param nh NodeHandle for grabbing parameters
|
||||||
|
*/
|
||||||
|
virtual void initialize(const ros::NodeHandle& nh) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the state of the goal checker (if any)
|
||||||
|
*/
|
||||||
|
virtual void reset() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether the goal should be considered reached
|
||||||
|
* @param query_pose The pose to check
|
||||||
|
* @param goal_pose The pose to check against
|
||||||
|
*
|
||||||
|
* @param velocity The robot's current velocity
|
||||||
|
* @return True if goal is reached
|
||||||
|
*/
|
||||||
|
virtual bool isGoalReached(const nav_2d_msgs::Pose2DStamped& query_pose, const nav_2d_msgs::Pose2DStamped& goal_pose,
|
||||||
|
const nav_2d_msgs::Path2D &path, const nav_2d_msgs::Twist2D& velocity) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace score_algorithm
|
||||||
|
|
||||||
|
#endif // _SCORE_GOAL_CHECKER_H_INCLUDED__
|
||||||
169
src/Algorithms/Cores/score_algorithm/include/score_algorithm/score_algorithm.h
Executable file
169
src/Algorithms/Cores/score_algorithm/include/score_algorithm/score_algorithm.h
Executable file
|
|
@ -0,0 +1,169 @@
|
||||||
|
#ifndef _SCORE_ALGORITHM_H_INCLUDED__
|
||||||
|
#define _SCORE_ALGORITHM_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <yaml-cpp/yaml.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <nav_2d_msgs/Twist2DStamped.h>
|
||||||
|
#include <nav_2d_msgs/Path2D.h>
|
||||||
|
#include <nav_2d_msgs/Pose2DStamped.h>
|
||||||
|
|
||||||
|
#include <nav_core2/common.h>
|
||||||
|
#include <nav_core2/exceptions.h>
|
||||||
|
#include <nav_core2/costmap.h>
|
||||||
|
|
||||||
|
#include <costmap_2d/costmap_2d_robot.h>
|
||||||
|
#include <geometry_msgs/PoseArray.h>
|
||||||
|
#include <mkt_msgs/Trajectory2D.h>
|
||||||
|
#include <score_algorithm/trajectory_generator.h>
|
||||||
|
|
||||||
|
#define FORWARD 1
|
||||||
|
#define BACKWARD -1
|
||||||
|
|
||||||
|
namespace score_algorithm
|
||||||
|
{
|
||||||
|
class ScoreAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = boost::shared_ptr<score_algorithm::ScoreAlgorithm>;
|
||||||
|
|
||||||
|
inline double smoothstep(double x)
|
||||||
|
{
|
||||||
|
x = std::clamp(x, 0.0, 1.0);
|
||||||
|
return x * x * (3 - 2 * x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param name Namespace for this planner
|
||||||
|
* @param tf TFListener pointer
|
||||||
|
* @param costmap_ros Costmap pointer
|
||||||
|
*/
|
||||||
|
virtual void initialize(YAML::Node &nh, std::string name, TFListenerPtr tf, costmap_2d::Costmap2DROBOT *costmap_ros,
|
||||||
|
const score_algorithm::TrajectoryGenerator::Ptr &traj) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prior to evaluating any trajectories, look at contextual information constant across all trajectories
|
||||||
|
*
|
||||||
|
* Subclasses may overwrite. Return false in case there is any error.
|
||||||
|
*
|
||||||
|
* @param pose Current pose (costmap frame)
|
||||||
|
* @param velocity Current velocity
|
||||||
|
* @param goal The final goal (costmap frame)
|
||||||
|
* @param global_plan Transformed global plan in costmap frame, possibly cropped to nearby points
|
||||||
|
*/
|
||||||
|
virtual bool prepare(const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity,
|
||||||
|
const nav_2d_msgs::Pose2DStamped &goal, const nav_2d_msgs::Path2D &global_plan,
|
||||||
|
double &x_direction, double &y_direction, double &theta_direction) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating algorithm
|
||||||
|
* @param pose
|
||||||
|
* @param velocity
|
||||||
|
* @param traj
|
||||||
|
*/
|
||||||
|
virtual mkt_msgs::Trajectory2D calculator(
|
||||||
|
const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset all data
|
||||||
|
*/
|
||||||
|
virtual void reset() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stoping move navigation
|
||||||
|
*/
|
||||||
|
virtual void stop() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief resume move navigation after stopped
|
||||||
|
*/
|
||||||
|
virtual void resume() {};
|
||||||
|
|
||||||
|
std::string getName()
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
double sign(double x)
|
||||||
|
{
|
||||||
|
return x < 0.0 ? -1.0 : 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get goal index
|
||||||
|
* @param robot_pose
|
||||||
|
* @param plan
|
||||||
|
* @param distance
|
||||||
|
* @param start_index
|
||||||
|
* @param last_valid_index
|
||||||
|
* @return goal index
|
||||||
|
*/
|
||||||
|
virtual unsigned int getGoalIndex(const geometry_msgs::Pose2D &robot_pose, const std::vector<nav_2d_msgs::Pose2DStamped> &plan,
|
||||||
|
const double distance, unsigned int start_index, unsigned int last_valid_index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get goal pose
|
||||||
|
* @param robot_pose
|
||||||
|
* @param velocity
|
||||||
|
* @param global_plan
|
||||||
|
* @param sub_goal
|
||||||
|
* @param S
|
||||||
|
* @return true if goal pose is found, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool computePlanCommand(const nav_2d_msgs::Pose2DStamped &robot_pose, const nav_2d_msgs::Twist2D &velocity, const double &S,
|
||||||
|
const nav_2d_msgs::Path2D &global_plan, unsigned int &start_index_global_plan, unsigned int &goal_index_global_plan, nav_2d_msgs::Path2D &result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find sub goal index
|
||||||
|
* @param plan
|
||||||
|
* @param index_s
|
||||||
|
* @return true if sub goal index is found, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool findSubGoalIndex(const std::vector<nav_2d_msgs::Pose2DStamped> &plan, std::vector<unsigned int> &seq_s, std::vector<nav_2d_msgs::Pose2DStamped> &mutes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculate journey
|
||||||
|
* @param plan
|
||||||
|
* @param start_index
|
||||||
|
* @param last_valid_index
|
||||||
|
* @return journey
|
||||||
|
*/
|
||||||
|
double journey(const std::vector<nav_2d_msgs::Pose2DStamped> &plan, const unsigned int start_index, const unsigned int last_valid_index) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether the robot is stopped or not
|
||||||
|
* @param velocity The current odometry information for the robot
|
||||||
|
* @param rot_stopped_velocity The rotational velocity below which the robot is considered stopped
|
||||||
|
* @param trans_stopped_velocity The translational velocity below which the robot is considered stopped
|
||||||
|
* @return True if the robot is stopped, false otherwise
|
||||||
|
*/
|
||||||
|
bool stopped(const nav_2d_msgs::Twist2D &velocity, const double &rot_stopped_velocity, const double &trans_stopped_velocity);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
std::string name_;
|
||||||
|
TFListenerPtr tf_;
|
||||||
|
costmap_2d::Costmap2DROBOT *costmap_robot_;
|
||||||
|
TrajectoryGenerator::Ptr traj_;
|
||||||
|
|
||||||
|
int index_samples_;
|
||||||
|
bool follow_step_path_;
|
||||||
|
double xy_local_goal_tolerance_;
|
||||||
|
double old_xy_goal_tolerance_;
|
||||||
|
double angle_threshold_;
|
||||||
|
|
||||||
|
bool enable_publish_;
|
||||||
|
// ros::Publisher reached_intermediate_goals_pub_;
|
||||||
|
// ros::Publisher current_goal_pub_;
|
||||||
|
// ros::Publisher closet_robot_goal_pub_;
|
||||||
|
// ros::Publisher transformed_plan_pub_, compute_plan_pub_;
|
||||||
|
|
||||||
|
std::vector<nav_2d_msgs::Pose2DStamped> reached_intermediate_goals_;
|
||||||
|
std::vector<unsigned int> start_index_saved_vt_;
|
||||||
|
unsigned int sub_goal_index_saved_, sub_goal_seq_saved_;
|
||||||
|
unsigned int sub_start_index_saved_, sub_start_seq_saved_;
|
||||||
|
};
|
||||||
|
} // namespace score_algorithm
|
||||||
|
|
||||||
|
#endif // SCORE_ALGORITHM_H_INCLUDED__
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
#ifndef _SCORE_ALGORITHM_TRAJECTORY_GENERATOR_H
|
||||||
|
#define _SCORE_ALGORITHM_TRAJECTORY_GENERATOR_H
|
||||||
|
|
||||||
|
#include <yaml-cpp/yaml.h>
|
||||||
|
#include <mkt_msgs/Trajectory2D.h>
|
||||||
|
#include <nav_2d_msgs/Path2D.h>
|
||||||
|
#include <nav_2d_msgs/Twist2D.h>
|
||||||
|
#include <nav_2d_msgs/Pose2DStamped.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <geometry_msgs/Vector3.h>
|
||||||
|
|
||||||
|
namespace score_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class TrajectoryGenerator
|
||||||
|
* @brief Interface for iterating through possible velocities and creating trajectories
|
||||||
|
*
|
||||||
|
* This class defines the plugin interface for two separate but related components.
|
||||||
|
*
|
||||||
|
* First, this class provides an iterator interface for exploring all of the velocities
|
||||||
|
* to search, given the current velocity.
|
||||||
|
*
|
||||||
|
* Second, the class gives an independent interface for creating a trajectory from a twist,
|
||||||
|
* i.e. projecting it out in time and space.
|
||||||
|
*
|
||||||
|
* Both components rely heavily on the robot's kinematic model, and can share many parameters,
|
||||||
|
* which is why they are grouped into a singular class.
|
||||||
|
*/
|
||||||
|
class TrajectoryGenerator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = boost::shared_ptr<score_algorithm::TrajectoryGenerator>;
|
||||||
|
|
||||||
|
virtual ~TrajectoryGenerator() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initialize(const YAML::Node &nh) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the state (if any) when the planner gets a new goal
|
||||||
|
*/
|
||||||
|
virtual void reset() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start a new iteration based on the current velocity
|
||||||
|
* @param current_velocity
|
||||||
|
*/
|
||||||
|
virtual void startNewIteration(const nav_2d_msgs::Twist2D ¤t_velocity) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set direct of robot based on the current velocity
|
||||||
|
* @param direct
|
||||||
|
*/
|
||||||
|
virtual void setDirect(int *xytheta_direct) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief set velocity for x, y asix of the robot
|
||||||
|
* @param linear the velocity command
|
||||||
|
* @return True if set is done, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool setTwistLinear(geometry_msgs::Vector3 linear) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief get velocity for x, y asix of the robot
|
||||||
|
* @param linear The velocity command
|
||||||
|
* @return True if set is done, false otherwise
|
||||||
|
*/
|
||||||
|
virtual geometry_msgs::Vector3 getTwistLinear(bool direct) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set velocity theta for z asix of the robot
|
||||||
|
* @param angular the command velocity
|
||||||
|
* @return True if set is done, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool setTwistAngular(geometry_msgs::Vector3 angular) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get velocity theta for z asix of the robot
|
||||||
|
* @param direct The velocity command
|
||||||
|
* @return True if set is done, false otherwise
|
||||||
|
*/
|
||||||
|
virtual geometry_msgs::Vector3 getTwistAngular(bool direct) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Test to see whether there are more twists to test
|
||||||
|
* @return True if more twists, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool hasMoreTwists() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the next twist and advance the iteration
|
||||||
|
* @return The Twist!
|
||||||
|
*/
|
||||||
|
virtual nav_2d_msgs::Twist2D nextTwist() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get all the twists for an iteration.
|
||||||
|
*
|
||||||
|
* Note: Resets the iterator if one is in process
|
||||||
|
*
|
||||||
|
* @param current_velocity
|
||||||
|
* @return all the twists
|
||||||
|
*/
|
||||||
|
virtual std::vector<nav_2d_msgs::Twist2D> getTwists(const nav_2d_msgs::Twist2D ¤t_velocity)
|
||||||
|
{
|
||||||
|
std::vector<nav_2d_msgs::Twist2D> twists;
|
||||||
|
startNewIteration(current_velocity);
|
||||||
|
while (hasMoreTwists())
|
||||||
|
{
|
||||||
|
twists.push_back(nextTwist());
|
||||||
|
}
|
||||||
|
return twists;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Given a cmd_vel in the robot's frame and initial conditions, generate a Trajectory2D
|
||||||
|
* @param start_pose Current robot location
|
||||||
|
* @param start_vel Current robot velocity
|
||||||
|
* @param cmd_vel The desired command velocity
|
||||||
|
*/
|
||||||
|
virtual mkt_msgs::Trajectory2D generateTrajectory(const nav_2d_msgs::Pose2DStamped &start_pose,
|
||||||
|
const nav_2d_msgs::Path2D &transformed_plan,
|
||||||
|
const nav_2d_msgs::Twist2D &start_vel,
|
||||||
|
const nav_2d_msgs::Twist2D &cmd_vel) = 0;
|
||||||
|
|
||||||
|
virtual YAML::Node getNodeHandle() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace score_algorithm
|
||||||
|
|
||||||
|
#endif // _SCORE_ALGORITHM_TRAJECTORY_GENERATOR_H
|
||||||
470
src/Algorithms/Cores/score_algorithm/src/score_algorithm.cpp
Normal file
470
src/Algorithms/Cores/score_algorithm/src/score_algorithm.cpp
Normal file
|
|
@ -0,0 +1,470 @@
|
||||||
|
#include <score_algorithm/score_algorithm.h>
|
||||||
|
#include <nav_2d_utils/path_ops.h>
|
||||||
|
#include <nav_2d_utils/conversions.h>
|
||||||
|
#include <angles/angles.h>
|
||||||
|
|
||||||
|
unsigned int score_algorithm::ScoreAlgorithm::getGoalIndex(const geometry_msgs::Pose2D &robot_pose, const std::vector<nav_2d_msgs::Pose2DStamped> &plan,
|
||||||
|
const double distance, unsigned int start_index, unsigned int last_valid_index) const
|
||||||
|
{
|
||||||
|
if (start_index >= last_valid_index)
|
||||||
|
return last_valid_index;
|
||||||
|
|
||||||
|
unsigned int goal_index = start_index + 1;
|
||||||
|
const double start_direction_x = plan[goal_index].pose.x - plan[start_index].pose.x;
|
||||||
|
const double start_direction_y = plan[goal_index].pose.y - plan[start_index].pose.y;
|
||||||
|
if (fabs(start_direction_x) > 1e-9 || fabs(start_direction_y) > 1e-9)
|
||||||
|
{ // make sure that atan2 is defined
|
||||||
|
double start_angle = atan2(start_direction_y, start_direction_x);
|
||||||
|
double S = sqrt(pow(start_direction_x, 2) + pow(start_direction_y, 2));
|
||||||
|
// double angle_threshold = 0.0;
|
||||||
|
for (unsigned int i = start_index + 1; i <= last_valid_index; i++)
|
||||||
|
{
|
||||||
|
const double current_direction_x = plan[i].pose.x - plan[i - 1].pose.x;
|
||||||
|
const double current_direction_y = plan[i].pose.y - plan[i - 1].pose.y;
|
||||||
|
const double dd = sqrt(pow(current_direction_x, 2) + pow(current_direction_y, 2));
|
||||||
|
S += dd;
|
||||||
|
if (fabs(current_direction_x) > 1e-9 || fabs(current_direction_y) > 1e-9)
|
||||||
|
{
|
||||||
|
double current_angle = atan2(current_direction_y, current_direction_x);
|
||||||
|
goal_index = i;
|
||||||
|
if (fabs(remainder(start_angle - current_angle, 2 * M_PI)) >= angle_threshold_ || S >= distance)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (last_valid_index - goal_index == 1)
|
||||||
|
goal_index = last_valid_index;
|
||||||
|
return goal_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool score_algorithm::ScoreAlgorithm::findSubGoalIndex(const std::vector<nav_2d_msgs::Pose2DStamped> &plan, std::vector<unsigned int> &seq_s, std::vector<nav_2d_msgs::Pose2DStamped> &mutes)
|
||||||
|
{
|
||||||
|
if (plan.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double x_direction_saved = 0.0;
|
||||||
|
geometry_msgs::PoseArray poseArrayMsg;
|
||||||
|
poseArrayMsg.header.stamp = robot::Time::now();
|
||||||
|
poseArrayMsg.header.frame_id = costmap_robot_->getGlobalFrameID();
|
||||||
|
|
||||||
|
nav_2d_msgs::Pose2DStamped p1, p2, p3;
|
||||||
|
|
||||||
|
if (plan.size() < 3)
|
||||||
|
{
|
||||||
|
seq_s.push_back(plan.back().header.seq);
|
||||||
|
mutes.push_back(plan.back());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
p1 = plan[i];
|
||||||
|
for (i = 0; i < (unsigned int)plan.size() - 2; i++)
|
||||||
|
{
|
||||||
|
double egde1_angle, egde2_angle;
|
||||||
|
p2 = plan[i + 1];
|
||||||
|
if ((fabs(p2.pose.y - p1.pose.y) > 1e-9 || fabs(p2.pose.x - p1.pose.x) > 1e-9))
|
||||||
|
{
|
||||||
|
egde1_angle = atan2(p2.pose.y - p1.pose.y, p2.pose.x - p1.pose.x);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const double target_direction = cos(fabs(egde1_angle - p2.pose.theta));
|
||||||
|
|
||||||
|
if (target_direction * x_direction_saved < 0.0)
|
||||||
|
{
|
||||||
|
if (std::find(seq_s.begin(), seq_s.end(), plan[i].header.seq) == seq_s.end())
|
||||||
|
{
|
||||||
|
seq_s.push_back(plan[i].header.seq);
|
||||||
|
mutes.push_back(plan[i]);
|
||||||
|
geometry_msgs::Pose pose = nav_2d_utils::pose2DToPoseStamped(plan[i]).pose;
|
||||||
|
poseArrayMsg.poses.push_back(pose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x_direction_saved = target_direction;
|
||||||
|
|
||||||
|
p3 = plan[i + 2];
|
||||||
|
if ((fabs(p3.pose.y - p2.pose.y) > 1e-9 || fabs(p3.pose.x - p2.pose.x) > 1e-9))
|
||||||
|
{
|
||||||
|
egde2_angle = atan2(p3.pose.y - p2.pose.y, p3.pose.x - p2.pose.x);
|
||||||
|
p1 = p2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
double thresh_angle = 0.3;
|
||||||
|
double angle = fabs(remainder(egde1_angle - egde2_angle, 2 * M_PI));
|
||||||
|
if (angle >= thresh_angle || angle >= M_PI - thresh_angle)
|
||||||
|
{
|
||||||
|
if (std::find(seq_s.begin(), seq_s.end(), plan[i].header.seq) == seq_s.end())
|
||||||
|
{
|
||||||
|
seq_s.push_back(plan[i + 1].header.seq);
|
||||||
|
mutes.push_back(plan[i + 1]);
|
||||||
|
geometry_msgs::Pose pose = nav_2d_utils::pose2DToPoseStamped(plan[i + 1]).pose;
|
||||||
|
poseArrayMsg.poses.push_back(pose);
|
||||||
|
}
|
||||||
|
p2 = p3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seq_s.empty())
|
||||||
|
{
|
||||||
|
seq_s.push_back(plan.back().header.seq);
|
||||||
|
mutes.push_back(plan.back());
|
||||||
|
geometry_msgs::Pose pose = nav_2d_utils::pose2DToPoseStamped(plan.back()).pose;
|
||||||
|
poseArrayMsg.poses.push_back(pose);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (seq_s.back() < plan.back().header.seq)
|
||||||
|
{
|
||||||
|
seq_s.push_back(plan.back().header.seq);
|
||||||
|
mutes.push_back(plan.back());
|
||||||
|
geometry_msgs::Pose pose = nav_2d_utils::pose2DToPoseStamped(plan.back()).pose;
|
||||||
|
poseArrayMsg.poses.push_back(pose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool score_algorithm::ScoreAlgorithm::computePlanCommand(const nav_2d_msgs::Pose2DStamped &robot_pose, const nav_2d_msgs::Twist2D &velocity, const double &S,
|
||||||
|
const nav_2d_msgs::Path2D &global_plan, unsigned int &start_index_global_plan, unsigned int &goal_index_global_plan, nav_2d_msgs::Path2D &result)
|
||||||
|
{
|
||||||
|
result.poses.clear();
|
||||||
|
if (global_plan.poses.empty())
|
||||||
|
{
|
||||||
|
std::cerr << "ScoreAlgorithm: The global plan was empty." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> seq_s;
|
||||||
|
std::vector<nav_2d_msgs::Pose2DStamped> mutes;
|
||||||
|
if (!this->findSubGoalIndex(global_plan.poses, seq_s, mutes))
|
||||||
|
{
|
||||||
|
std::cerr << "ScoreAlgorithm: Cannot find SubGoal Index" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int sub_goal_index;
|
||||||
|
unsigned int sub_start_index;
|
||||||
|
|
||||||
|
bool found_sub_goal_index_saved = false, found_sub_start_index_saved = false;
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)global_plan.poses.size(); ++i)
|
||||||
|
{
|
||||||
|
if (global_plan.poses[i].header.seq == sub_goal_seq_saved_)
|
||||||
|
{
|
||||||
|
sub_goal_index_saved_ = i;
|
||||||
|
found_sub_goal_index_saved = true;
|
||||||
|
}
|
||||||
|
if (global_plan.poses[i].header.seq == sub_start_seq_saved_)
|
||||||
|
{
|
||||||
|
sub_start_index_saved_ = i;
|
||||||
|
found_sub_start_index_saved = true;
|
||||||
|
}
|
||||||
|
if (found_sub_goal_index_saved && found_sub_start_index_saved)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub_goal_index = !found_sub_goal_index_saved ? (unsigned int)global_plan.poses.size() : sub_goal_index_saved_;
|
||||||
|
sub_start_index = !found_sub_start_index_saved ? 0 : sub_start_index_saved_;
|
||||||
|
|
||||||
|
std::vector<unsigned int> index_s;
|
||||||
|
for (auto seq : seq_s)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)global_plan.poses.size(); ++i)
|
||||||
|
{
|
||||||
|
if (global_plan.poses[i].header.seq == seq)
|
||||||
|
{
|
||||||
|
index_s.push_back(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle empty seq_s
|
||||||
|
if (index_s.empty())
|
||||||
|
{
|
||||||
|
sub_goal_index = (unsigned int)global_plan.poses.size();
|
||||||
|
sub_goal_seq_saved_ = global_plan.poses.back().header.seq;
|
||||||
|
std::cout << "ScoreAlgorithm: seq_s is empty, setting sub_goal_index to " << sub_goal_index << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Update sub_goal_index if index_s.front() is greater and valid
|
||||||
|
if (index_s.front() > sub_goal_index_saved_ && index_s.front() < (unsigned int)global_plan.poses.size())
|
||||||
|
{
|
||||||
|
sub_goal_index = (unsigned int)index_s.front() > 0 ? (unsigned int)index_s.front() - 1 : (unsigned int)index_s.front();
|
||||||
|
sub_goal_seq_saved_ = global_plan.poses[sub_goal_index].header.seq;
|
||||||
|
std::cout << "ScoreAlgorithm: Updated sub_goal_index to " << sub_goal_index << " based on index_s.front()" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process index_s with multiple elements
|
||||||
|
if (index_s.size() > 1)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < index_s.size(); ++i)
|
||||||
|
{
|
||||||
|
if (index_s[i - 1] >= (unsigned int)global_plan.poses.size() || index_s[i] >= (unsigned int)global_plan.poses.size())
|
||||||
|
{
|
||||||
|
std::cout << "ScoreAlgorithm: Invalid index index_s[" << i - 1 << "]=" << index_s[i - 1] << " or index_s[" << i << "]=" << index_s[i] << ", plan size=" << (unsigned int)global_plan.poses.size() << std::endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double dx = robot_pose.pose.x - global_plan.poses[index_s[i - 1]].pose.x;
|
||||||
|
double dy = robot_pose.pose.y - global_plan.poses[index_s[i - 1]].pose.y;
|
||||||
|
double theta = angles::normalize_angle(robot_pose.pose.theta - global_plan.poses[index_s[i - 1]].pose.theta);
|
||||||
|
double x = cos(global_plan.poses[index_s[i - 1]].pose.theta) * dx + sin(global_plan.poses[index_s[i - 1]].pose.theta) * dy;
|
||||||
|
double y = -sin(global_plan.poses[index_s[i - 1]].pose.theta) * dx + cos(global_plan.poses[index_s[i - 1]].pose.theta) * dy;
|
||||||
|
|
||||||
|
if (std::abs(std::sqrt(dx * dx + dy * dy)) <= xy_local_goal_tolerance_ + 0.1)
|
||||||
|
{
|
||||||
|
double tolerance = fabs(cos(theta)) >= fabs(sin(theta)) ? x : y;
|
||||||
|
if (fabs(tolerance) <= xy_local_goal_tolerance_)
|
||||||
|
{
|
||||||
|
// ROS_INFO_THROTTLE(0.1, "%f %f %f %f", fabs(cos(theta)), fabs(sin(theta)), robot_pose.pose.theta, global_plan.poses[index_s[i - 1]].pose.theta);
|
||||||
|
// ROS_INFO_THROTTLE(0.1, "tolerance 1 %f %f %f %f %f ", tolerance, old_xy_goal_tolerance_, x, y, theta);
|
||||||
|
if (index_s[i] > sub_goal_index_saved_)
|
||||||
|
{
|
||||||
|
// ROS_INFO("%d %d %d %d %d", index_s[i], sub_goal_index, sub_goal_index_saved_, sub_goal_seq_saved_, (unsigned int)global_plan.poses.size());
|
||||||
|
// ROS_INFO_NAMED("ScoreAlgorithm", "Following from %u to %d", sub_goal_index, i < (unsigned int)(index_s.size() - 1) ? index_s[i] + 1 : (unsigned int)global_plan.poses.size());
|
||||||
|
sub_goal_index = (i < index_s.size() - 1) ? index_s[i] : (unsigned int)global_plan.poses.size() - 1;
|
||||||
|
sub_goal_seq_saved_ = global_plan.poses[sub_goal_index].header.seq;
|
||||||
|
old_xy_goal_tolerance_ = 0.0;
|
||||||
|
if (follow_step_path_)
|
||||||
|
{
|
||||||
|
sub_start_index = index_s[i - 1];
|
||||||
|
sub_start_seq_saved_ = global_plan.poses[sub_start_index].header.seq;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
old_xy_goal_tolerance_ = fabs(cos(theta)) >= fabs(sin(theta)) ? x : y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Validate sub_goal_index
|
||||||
|
if (sub_goal_index >= (unsigned int)global_plan.poses.size() - 1)
|
||||||
|
{
|
||||||
|
sub_goal_index = (unsigned int)global_plan.poses.size() - 1;
|
||||||
|
sub_goal_seq_saved_ = global_plan.poses[sub_goal_index].header.seq;
|
||||||
|
std::cout << "ScoreAlgorithm: Invalid sub_goal_index, setting to " << sub_goal_index << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double dx = robot_pose.pose.x - global_plan.poses[sub_goal_index].pose.x;
|
||||||
|
double dy = robot_pose.pose.y - global_plan.poses[sub_goal_index].pose.y;
|
||||||
|
double theta = angles::normalize_angle(robot_pose.pose.theta - global_plan.poses[sub_goal_index].pose.theta);
|
||||||
|
double x = cos(global_plan.poses[sub_goal_index].pose.theta) * dx + sin(global_plan.poses[sub_goal_index].pose.theta) * dy;
|
||||||
|
double y = -sin(global_plan.poses[sub_goal_index].pose.theta) * dx + cos(global_plan.poses[sub_goal_index].pose.theta) * dy;
|
||||||
|
if (std::abs(std::sqrt(dx * dx + dy * dy)) <= xy_local_goal_tolerance_ + 0.1)
|
||||||
|
{
|
||||||
|
double tolerance = fabs(cos(theta)) >= fabs(sin(theta)) ? x : y;
|
||||||
|
if (fabs(tolerance) <= xy_local_goal_tolerance_)
|
||||||
|
{
|
||||||
|
// ROS_INFO_THROTTLE(0.1, "%f %f %f %f ", fabs(cos(theta)), fabs(sin(theta)), robot_pose.pose.theta, global_plan.poses[sub_goal_index].pose.theta);
|
||||||
|
// ROS_INFO_THROTTLE(0.1, "tolerance 2 %f %f %f %f %f ", tolerance, old_xy_goal_tolerance_, x, y, theta);
|
||||||
|
sub_goal_index = (unsigned int)global_plan.poses.size() - 1;
|
||||||
|
sub_goal_seq_saved_ = global_plan.poses[sub_goal_index].header.seq;
|
||||||
|
old_xy_goal_tolerance_ = 0.0;
|
||||||
|
std::cout << "ScoreAlgorithm: Single sub-goal reached, setting sub_goal_index to " << sub_goal_index << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
old_xy_goal_tolerance_ = fabs(cos(theta)) >= fabs(sin(theta)) ? x : y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sub_start_index >= sub_goal_index)
|
||||||
|
{
|
||||||
|
std::cerr << "ScoreAlgorithm: Sub path is empty" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the "start pose", i.e. the pose on the plan closest to the robot that is also on the local map
|
||||||
|
// Tìm điểm pose bắt đầu trên kế hoạch đường đi gần nhất với robot đồng thời có tồn tại trong local map
|
||||||
|
unsigned int start_index = 0; // số vị trí pose trong kế hoạch đường đi
|
||||||
|
unsigned int closet_index = 0;
|
||||||
|
double distance_to_start = std::numeric_limits<double>::infinity(); // Xét giá trị là vô cùng oo
|
||||||
|
bool started_path = false;
|
||||||
|
for (unsigned int i = sub_start_index; i < sub_goal_index; ++i)
|
||||||
|
{
|
||||||
|
// Still on the costmap. Continue.
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(global_plan.poses[i].pose, robot_pose.pose)); // Tính khoảng cách từ vị trí của robot đến pose đang xét
|
||||||
|
if (distance_to_start > distance)
|
||||||
|
{
|
||||||
|
start_index = i;
|
||||||
|
closet_index = start_index;
|
||||||
|
distance_to_start = distance;
|
||||||
|
started_path = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nếu khồng tìm được điểm gần với robot nhất thì trả về false
|
||||||
|
if (!started_path)
|
||||||
|
{
|
||||||
|
std::cerr << "ScoreAlgorithm: None of the points of the global plan were in the local costmap." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::stringstream ss;
|
||||||
|
start_index_saved_vt_.push_back(global_plan.poses[start_index].header.seq);
|
||||||
|
if (start_index_saved_vt_.size() > index_samples_)
|
||||||
|
start_index_saved_vt_.erase(start_index_saved_vt_.begin());
|
||||||
|
|
||||||
|
unsigned num = 0;
|
||||||
|
if (!start_index_saved_vt_.empty())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < (int)start_index_saved_vt_.size() - 1; i++)
|
||||||
|
{
|
||||||
|
if (start_index_saved_vt_[i] == start_index_saved_vt_[i + 1])
|
||||||
|
num++;
|
||||||
|
ss << start_index_saved_vt_[i] << " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num < index_samples_ - 1 && !start_index_saved_vt_.empty())
|
||||||
|
{
|
||||||
|
auto max_iter = *(std::max_element(start_index_saved_vt_.begin(), start_index_saved_vt_.end()));
|
||||||
|
unsigned int max_start_index = start_index;
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)global_plan.poses.size(); i++)
|
||||||
|
{
|
||||||
|
if (global_plan.poses[i].header.seq == max_iter)
|
||||||
|
{
|
||||||
|
max_start_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double S1 = journey(global_plan.poses, start_index, (unsigned int)global_plan.poses.size() - 1);
|
||||||
|
double S2 = journey(global_plan.poses, max_start_index, (unsigned int)global_plan.poses.size() - 1);
|
||||||
|
|
||||||
|
if (S2 - S1)
|
||||||
|
{
|
||||||
|
start_index = max_start_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ROS_INFO_STREAM_THROTTLE(0.1, ss.str() << "\n");
|
||||||
|
|
||||||
|
// find the "last valid pose", i.e. the last pose on the plan after the start pose that is still on the local map
|
||||||
|
// Tìm điểm pose cuôi cùng sau điểm pose bắt đầu và có tồn tại trong local map
|
||||||
|
if (start_index < 1)
|
||||||
|
start_index = 1;
|
||||||
|
// unsigned int last_valid_index = (unsigned int)global_plan.poses.size() - 1;
|
||||||
|
unsigned int last_valid_index = sub_goal_index;
|
||||||
|
|
||||||
|
// find the "goal pose" by walking along the plan as long as each step leads far enough away from the starting point,
|
||||||
|
// i.e. is within angle_threshold_ of the starting direction.
|
||||||
|
// Tìm điểm mục tiêu chạy từ điểm start pose đến last valid pose dọc thep plan
|
||||||
|
unsigned int goal_index = start_index;
|
||||||
|
while (goal_index < last_valid_index)
|
||||||
|
{
|
||||||
|
// Tìm kiếm vị trí điểm mục tiêu phù hợp
|
||||||
|
goal_index = getGoalIndex(robot_pose.pose, global_plan.poses, S, start_index, last_valid_index);
|
||||||
|
|
||||||
|
// check if goal already reached
|
||||||
|
bool goal_already_reached = false;
|
||||||
|
|
||||||
|
// geometry_msgs::PoseArray poseArrayMsg;
|
||||||
|
// poseArrayMsg.header.stamp = ros::Time::now();
|
||||||
|
// poseArrayMsg.header.frame_id = costmap_robot_->getGlobalFrameID();
|
||||||
|
// int c = 0;
|
||||||
|
for (auto &reached_intermediate_goal : reached_intermediate_goals_)
|
||||||
|
{
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(reached_intermediate_goal.pose, global_plan.poses[goal_index].pose));
|
||||||
|
|
||||||
|
// geometry_msgs::Pose pose = nav_2d_utils::pose2DToPose(reached_intermediate_goal.pose);
|
||||||
|
// poseArrayMsg.poses.push_back(pose);
|
||||||
|
|
||||||
|
if (distance < xy_local_goal_tolerance_)
|
||||||
|
{
|
||||||
|
goal_already_reached = true;
|
||||||
|
// choose a new start_index by walking along the plan until we're outside xy_local_goal_tolerance_ and try again
|
||||||
|
// (start_index is now > goal_index)
|
||||||
|
for (start_index = goal_index; start_index < last_valid_index; ++start_index)
|
||||||
|
{
|
||||||
|
distance = nav_2d_utils::poseDistance(reached_intermediate_goal.pose, global_plan.poses[start_index].pose);
|
||||||
|
if (distance >= xy_local_goal_tolerance_)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!goal_already_reached)
|
||||||
|
{
|
||||||
|
// new goal not in reached_intermediate_goals_
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(global_plan.poses[start_index].pose, global_plan.poses[goal_index].pose));
|
||||||
|
if (distance < xy_local_goal_tolerance_)
|
||||||
|
{
|
||||||
|
// the robot has currently reached the goal
|
||||||
|
reached_intermediate_goals_.push_back(global_plan.poses[goal_index]);
|
||||||
|
std::cout << "ScoreAlgorithm: Number of reached_intermediate goals: " << reached_intermediate_goals_.size() << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we've found a new goal!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_index > goal_index)
|
||||||
|
start_index = goal_index;
|
||||||
|
if (goal_index > last_valid_index)
|
||||||
|
goal_index = last_valid_index;
|
||||||
|
if ((unsigned int)global_plan.poses.size() == 2 && !global_plan.poses.empty())
|
||||||
|
{
|
||||||
|
start_index = 0;
|
||||||
|
goal_index = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (goal_index == (unsigned int)global_plan.poses.size() - 1)
|
||||||
|
start_index = (unsigned int)global_plan.poses.size() - 2;
|
||||||
|
|
||||||
|
start_index_global_plan = start_index;
|
||||||
|
goal_index_global_plan = goal_index;
|
||||||
|
|
||||||
|
nav_2d_msgs::Pose2DStamped sub_pose;
|
||||||
|
sub_pose = global_plan.poses[closet_index];
|
||||||
|
|
||||||
|
nav_2d_msgs::Pose2DStamped sub_goal;
|
||||||
|
sub_goal = global_plan.poses[goal_index];
|
||||||
|
|
||||||
|
result.header = global_plan.header;
|
||||||
|
for (int i = closet_index; i <= goal_index; i++)
|
||||||
|
{
|
||||||
|
result.poses.push_back(global_plan.poses[i]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double score_algorithm::ScoreAlgorithm::journey(const std::vector<nav_2d_msgs::Pose2DStamped> &plan, const unsigned int start_index, const unsigned int last_valid_index) const
|
||||||
|
{
|
||||||
|
double S = 0;
|
||||||
|
if (last_valid_index - start_index > 1)
|
||||||
|
{
|
||||||
|
for (int i = start_index; i < last_valid_index; i++)
|
||||||
|
{
|
||||||
|
S += nav_2d_utils::poseDistance(plan[i].pose, plan[i + 1].pose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool score_algorithm::ScoreAlgorithm::stopped(const nav_2d_msgs::Twist2D &velocity, const double &rot_stopped_velocity, const double &trans_stopped_velocity)
|
||||||
|
{
|
||||||
|
return fabs(velocity.theta) <= rot_stopped_velocity && fabs(velocity.x) <= trans_stopped_velocity && fabs(velocity.y) <= trans_stopped_velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void score_algorithm::ScoreAlgorithm::clear()
|
||||||
|
{
|
||||||
|
reached_intermediate_goals_.clear();
|
||||||
|
start_index_saved_vt_.clear();
|
||||||
|
sub_goal_index_saved_ = sub_goal_seq_saved_ = 0;
|
||||||
|
sub_start_index_saved_, sub_start_seq_saved_ = 0;
|
||||||
|
}
|
||||||
34
src/Algorithms/Libraries/angles/CMakeLists.txt
Normal file
34
src/Algorithms/Libraries/angles/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(angles VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
# Create interface library (header-only)
|
||||||
|
add_library(angles INTERFACE)
|
||||||
|
|
||||||
|
# Set include directories
|
||||||
|
target_include_directories(angles INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install headers
|
||||||
|
install(DIRECTORY include/angles
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING PATTERN "*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Install target
|
||||||
|
install(TARGETS angles
|
||||||
|
EXPORT angles-targets
|
||||||
|
INCLUDES DESTINATION include
|
||||||
|
)
|
||||||
|
|
||||||
|
# Export targets
|
||||||
|
install(EXPORT angles-targets
|
||||||
|
FILE angles-targets.cmake
|
||||||
|
DESTINATION lib/cmake/angles
|
||||||
|
)
|
||||||
|
|
||||||
26
src/Algorithms/Libraries/angles/include/angles/angles.h
Normal file
26
src/Algorithms/Libraries/angles/include/angles/angles.h
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#ifndef ANGLES_ANGLES_H
|
||||||
|
#define ANGLES_ANGLES_H
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace angles
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Normalize an angle to the range [-π, π]
|
||||||
|
* @param angle The angle in radians to normalize
|
||||||
|
* @return The normalized angle in the range [-π, π]
|
||||||
|
*/
|
||||||
|
inline double normalize_angle(double angle)
|
||||||
|
{
|
||||||
|
while (angle > M_PI)
|
||||||
|
angle -= 2.0 * M_PI;
|
||||||
|
while (angle < -M_PI)
|
||||||
|
angle += 2.0 * M_PI;
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace angles
|
||||||
|
|
||||||
|
#endif // ANGLES_ANGLES_H
|
||||||
|
|
||||||
92
src/Algorithms/Libraries/kalman/CMakeLists.txt
Executable file
92
src/Algorithms/Libraries/kalman/CMakeLists.txt
Executable file
|
|
@ -0,0 +1,92 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(kalman VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Chuẩn C++
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Find dependencies
|
||||||
|
find_package(Eigen3 REQUIRED)
|
||||||
|
|
||||||
|
# Thư mục include
|
||||||
|
include_directories(
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
${EIGEN3_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tìm tất cả file source
|
||||||
|
file(GLOB SOURCES "src/kalman.cpp")
|
||||||
|
file(GLOB HEADERS "include/kalman/kalman.h")
|
||||||
|
|
||||||
|
# Tạo thư viện shared (.so)
|
||||||
|
add_library(kalman SHARED ${SOURCES} ${HEADERS})
|
||||||
|
|
||||||
|
# Link libraries
|
||||||
|
target_link_libraries(kalman
|
||||||
|
PUBLIC
|
||||||
|
Eigen3::Eigen
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set include directories
|
||||||
|
target_include_directories(kalman
|
||||||
|
PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
${EIGEN3_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tạo executable cho test
|
||||||
|
add_executable(kalman_node src/kalman-test.cpp)
|
||||||
|
target_link_libraries(kalman_node
|
||||||
|
PRIVATE
|
||||||
|
kalman
|
||||||
|
Eigen3::Eigen
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt header files
|
||||||
|
install(DIRECTORY include/kalman
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING PATTERN "*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt library
|
||||||
|
install(TARGETS kalman
|
||||||
|
EXPORT kalman-targets
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt executable (optional)
|
||||||
|
install(TARGETS kalman_node
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|
||||||
|
# Export targets
|
||||||
|
install(EXPORT kalman-targets
|
||||||
|
FILE kalman-targets.cmake
|
||||||
|
DESTINATION lib/cmake/kalman
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tùy chọn build
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
|
option(BUILD_TESTS "Build test programs" OFF)
|
||||||
|
|
||||||
|
# Flags biên dịch
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
|
||||||
|
|
||||||
|
# In thông tin cấu hình
|
||||||
|
message(STATUS "=================================")
|
||||||
|
message(STATUS "Project: ${PROJECT_NAME}")
|
||||||
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
|
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||||
|
message(STATUS "Eigen3 found: ${EIGEN3_FOUND}")
|
||||||
|
message(STATUS "Eigen3 include dir: ${EIGEN3_INCLUDE_DIRS}")
|
||||||
|
message(STATUS "=================================")
|
||||||
18
src/Algorithms/Libraries/kalman/README.md
Executable file
18
src/Algorithms/Libraries/kalman/README.md
Executable file
|
|
@ -0,0 +1,18 @@
|
||||||
|
Kalman Filter
|
||||||
|
=============
|
||||||
|
This is a basic Kalman filter implementation in C++ using the
|
||||||
|
[Eigen](http://eigen.tuxfamily.org/) library. It implements the algorithm
|
||||||
|
directly as found in [An Introduction to the Kalman Filter](http://www.cs.unc.edu/~welch/media/pdf/kalman_intro.pdf).
|
||||||
|
|
||||||
|
There is a test program that estimates the motion of a projectile based on
|
||||||
|
noisy observations. To run it, use CMake:
|
||||||
|
|
||||||
|
cd kalman-cpp
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make
|
||||||
|
./kalman-test
|
||||||
|
|
||||||
|
Note: You may have to specify the path to your Eigen library in
|
||||||
|
`CMakeLists.txt`.
|
||||||
91
src/Algorithms/Libraries/kalman/include/kalman/kalman.h
Executable file
91
src/Algorithms/Libraries/kalman/include/kalman/kalman.h
Executable file
|
|
@ -0,0 +1,91 @@
|
||||||
|
/**
|
||||||
|
* Kalman filter implementation using Eigen. Based on the following
|
||||||
|
* introductory paper:
|
||||||
|
*
|
||||||
|
* http://www.cs.unc.edu/~welch/media/pdf/kalman_intro.pdf
|
||||||
|
*
|
||||||
|
* @author: Hayk Martirosyan
|
||||||
|
* @date: 2014.11.15
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class KalmanFilter {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Kalman filter with the specified matrices.
|
||||||
|
* A - System dynamics matrix
|
||||||
|
* C - Output matrix
|
||||||
|
* Q - Process noise covariance
|
||||||
|
* R - Measurement noise covariance
|
||||||
|
* P - Estimate error covariance
|
||||||
|
*/
|
||||||
|
KalmanFilter(
|
||||||
|
double dt,
|
||||||
|
const Eigen::MatrixXd& A,
|
||||||
|
const Eigen::MatrixXd& C,
|
||||||
|
const Eigen::MatrixXd& Q,
|
||||||
|
const Eigen::MatrixXd& R,
|
||||||
|
const Eigen::MatrixXd& P
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a blank estimator.
|
||||||
|
*/
|
||||||
|
KalmanFilter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the filter with initial states as zero.
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the filter with a guess for initial states.
|
||||||
|
*/
|
||||||
|
void init(double t0, const Eigen::VectorXd& x0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the estimated state based on measured values. The
|
||||||
|
* time step is assumed to remain constant.
|
||||||
|
*/
|
||||||
|
void update(const Eigen::VectorXd& y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the estimated state based on measured values,
|
||||||
|
* using the given time step and dynamics matrix.
|
||||||
|
*/
|
||||||
|
void update(const Eigen::VectorXd& y, double dt, const Eigen::MatrixXd A);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current state and time.
|
||||||
|
*/
|
||||||
|
Eigen::VectorXd state() { return x_hat; };
|
||||||
|
double time() { return t; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Matrices for computation
|
||||||
|
Eigen::MatrixXd A, C, Q, R, P, K, P0;
|
||||||
|
|
||||||
|
// System dimensions
|
||||||
|
int m, n;
|
||||||
|
|
||||||
|
// Initial and current time
|
||||||
|
double t0, t;
|
||||||
|
|
||||||
|
// Discrete time step
|
||||||
|
double dt;
|
||||||
|
|
||||||
|
// Is the filter initialized?
|
||||||
|
bool initialized;
|
||||||
|
|
||||||
|
// n-size identity
|
||||||
|
Eigen::MatrixXd I;
|
||||||
|
|
||||||
|
// Estimated states
|
||||||
|
Eigen::VectorXd x_hat, x_hat_new;
|
||||||
|
};
|
||||||
77
src/Algorithms/Libraries/kalman/src/kalman-test.cpp
Executable file
77
src/Algorithms/Libraries/kalman/src/kalman-test.cpp
Executable file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
* Test for the KalmanFilter class with 1D projectile motion.
|
||||||
|
*
|
||||||
|
* @author: Hayk Martirosyan
|
||||||
|
* @date: 2014.11.15
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
|
#include <kalman/kalman.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
|
int n = 3; // Number of states
|
||||||
|
int m = 1; // Number of measurements
|
||||||
|
|
||||||
|
double dt = 1.0/30; // Time step
|
||||||
|
|
||||||
|
Eigen::MatrixXd A(n, n); // System dynamics matrix
|
||||||
|
Eigen::MatrixXd C(m, n); // Output matrix
|
||||||
|
Eigen::MatrixXd Q(n, n); // Process noise covariance
|
||||||
|
Eigen::MatrixXd R(m, m); // Measurement noise covariance
|
||||||
|
Eigen::MatrixXd P(n, n); // Estimate error covariance
|
||||||
|
|
||||||
|
// Discrete LTI projectile motion, measuring position only
|
||||||
|
A << 1, dt, 0, 0, 1, dt, 0, 0, 1;
|
||||||
|
C << 1, 0, 0;
|
||||||
|
|
||||||
|
// Reasonable covariance matrices
|
||||||
|
Q << .05, .05, .0, .05, .05, .0, .0, .0, .0;
|
||||||
|
R << 5;
|
||||||
|
P << .1, .1, .1, .1, 10000, 10, .1, 10, 100;
|
||||||
|
|
||||||
|
std::cout << "A: \n" << A << std::endl;
|
||||||
|
std::cout << "C: \n" << C << std::endl;
|
||||||
|
std::cout << "Q: \n" << Q << std::endl;
|
||||||
|
std::cout << "R: \n" << R << std::endl;
|
||||||
|
std::cout << "P: \n" << P << std::endl;
|
||||||
|
|
||||||
|
// Construct the filter
|
||||||
|
KalmanFilter kf(dt,A, C, Q, R, P);
|
||||||
|
|
||||||
|
// List of noisy position measurements (y)
|
||||||
|
std::vector<double> measurements = {
|
||||||
|
1.04202710058, 1.10726790452, 1.2913511148, 1.48485250951, 1.72825901034,
|
||||||
|
1.74216489744, 2.11672039768, 2.14529225112, 2.16029641405, 2.21269371128,
|
||||||
|
2.57709350237, 2.6682215744, 2.51641839428, 2.76034056782, 2.88131780617,
|
||||||
|
2.88373786518, 2.9448468727, 2.82866600131, 3.0006601946, 3.12920591669,
|
||||||
|
2.858361783, 2.83808170354, 2.68975330958, 2.66533185589, 2.81613499531,
|
||||||
|
2.81003612051, 2.88321849354, 2.69789264832, 2.4342229249, 2.23464791825,
|
||||||
|
2.30278776224, 2.02069770395, 1.94393985809, 1.82498398739, 1.52526230354,
|
||||||
|
1.86967808173, 1.18073207847, 1.10729605087, 0.916168349913, 0.678547664519,
|
||||||
|
0.562381751596, 0.355468474885, -0.155607486619, -0.287198661013, -0.602973173813
|
||||||
|
};
|
||||||
|
|
||||||
|
// Best guess of initial states
|
||||||
|
Eigen::VectorXd x0(n);
|
||||||
|
double t = 0;
|
||||||
|
x0 << measurements[0], 0, -9.81;
|
||||||
|
kf.init(t, x0);
|
||||||
|
|
||||||
|
// Feed measurements into filter, output estimated states
|
||||||
|
|
||||||
|
Eigen::VectorXd y(m);
|
||||||
|
std::cout << "t = " << t << ", " << "x_hat[0]: " << kf.state().transpose() << std::endl;
|
||||||
|
for(int i = 0; i < measurements.size(); i++) {
|
||||||
|
t += dt;
|
||||||
|
y << measurements[i];
|
||||||
|
kf.update(y);
|
||||||
|
std::cout << "t = " << t << ", " << "y[" << i << "] = " << y.transpose()
|
||||||
|
<< ", x_hat[" << i << "] = " << kf.state().transpose() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
65
src/Algorithms/Libraries/kalman/src/kalman.cpp
Executable file
65
src/Algorithms/Libraries/kalman/src/kalman.cpp
Executable file
|
|
@ -0,0 +1,65 @@
|
||||||
|
/**
|
||||||
|
* Implementation of KalmanFilter class.
|
||||||
|
*
|
||||||
|
* @author: Hayk Martirosyan
|
||||||
|
* @date: 2014.11.15
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <kalman/kalman.h>
|
||||||
|
|
||||||
|
KalmanFilter::KalmanFilter(
|
||||||
|
double dt,
|
||||||
|
const Eigen::MatrixXd& A,
|
||||||
|
const Eigen::MatrixXd& C,
|
||||||
|
const Eigen::MatrixXd& Q,
|
||||||
|
const Eigen::MatrixXd& R,
|
||||||
|
const Eigen::MatrixXd& P)
|
||||||
|
: A(A), C(C), Q(Q), R(R), P0(P),
|
||||||
|
m(C.rows()), n(A.rows()), dt(dt), initialized(false),
|
||||||
|
I(n, n), x_hat(n), x_hat_new(n)
|
||||||
|
{
|
||||||
|
I.setIdentity();
|
||||||
|
}
|
||||||
|
|
||||||
|
KalmanFilter::KalmanFilter() {}
|
||||||
|
|
||||||
|
void KalmanFilter::init(double t0, const Eigen::VectorXd& x0) {
|
||||||
|
x_hat = x0;
|
||||||
|
P = P0;
|
||||||
|
this->t0 = t0;
|
||||||
|
t = t0;
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KalmanFilter::init() {
|
||||||
|
x_hat.setZero();
|
||||||
|
P = P0;
|
||||||
|
t0 = 0;
|
||||||
|
t = t0;
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KalmanFilter::update(const Eigen::VectorXd& y) {
|
||||||
|
|
||||||
|
if(!initialized)
|
||||||
|
throw std::runtime_error("Filter is not initialized!");
|
||||||
|
|
||||||
|
x_hat_new = A * x_hat;
|
||||||
|
P = A*P*A.transpose() + Q;
|
||||||
|
K = P*C.transpose()*(C*P*C.transpose() + R).inverse();
|
||||||
|
x_hat_new += K * (y - C*x_hat_new);
|
||||||
|
P = (I - K*C)*P;
|
||||||
|
x_hat = x_hat_new;
|
||||||
|
|
||||||
|
t += dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KalmanFilter::update(const Eigen::VectorXd& y, double dt, const Eigen::MatrixXd A) {
|
||||||
|
|
||||||
|
this->A = A;
|
||||||
|
this->dt = dt;
|
||||||
|
update(y);
|
||||||
|
}
|
||||||
110
src/Algorithms/Libraries/mkt_algorithm/CMakeLists.txt
Normal file
110
src/Algorithms/Libraries/mkt_algorithm/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(mkt_algorithm VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Chuẩn C++
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Find dependencies
|
||||||
|
find_package(Boost REQUIRED COMPONENTS system)
|
||||||
|
find_package(Eigen3 REQUIRED)
|
||||||
|
|
||||||
|
# Thư mục include
|
||||||
|
include_directories(
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
${EIGEN3_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Dependencies packages
|
||||||
|
set(PACKAGES_DIR
|
||||||
|
geometry_msgs
|
||||||
|
score_algorithm
|
||||||
|
nav_2d_msgs
|
||||||
|
nav_2d_utils
|
||||||
|
kalman
|
||||||
|
angles
|
||||||
|
nav_grid
|
||||||
|
costmap_2d
|
||||||
|
sensor_msgs
|
||||||
|
visualization_msgs
|
||||||
|
std_msgs
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tìm tất cả file source cho diff library
|
||||||
|
file(GLOB DIFF_SOURCES
|
||||||
|
"src/diff/diff_predictive_trajectory.cpp"
|
||||||
|
"src/diff/diff_rotate_to_goal.cpp"
|
||||||
|
"src/diff/diff_go_straight.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
file(GLOB DIFF_HEADERS
|
||||||
|
"include/mkt_algorithm/diff/*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tạo thư viện shared cho diff
|
||||||
|
add_library(mkt_algorithm_diff SHARED ${DIFF_SOURCES} ${DIFF_HEADERS})
|
||||||
|
|
||||||
|
# Link libraries
|
||||||
|
target_link_libraries(mkt_algorithm_diff
|
||||||
|
PUBLIC
|
||||||
|
${PACKAGES_DIR}
|
||||||
|
Boost::system
|
||||||
|
Eigen3::Eigen
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set include directories
|
||||||
|
target_include_directories(mkt_algorithm_diff
|
||||||
|
PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
${EIGEN3_INCLUDE_DIRS}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt header files
|
||||||
|
install(DIRECTORY include/mkt_algorithm
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING PATTERN "*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt library
|
||||||
|
install(TARGETS mkt_algorithm_diff
|
||||||
|
EXPORT mkt_algorithm-targets
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt plugins.xml (nếu cần cho pluginlib)
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/plugins.xml)
|
||||||
|
install(FILES plugins.xml
|
||||||
|
DESTINATION share/${PROJECT_NAME}
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Export targets
|
||||||
|
install(EXPORT mkt_algorithm-targets
|
||||||
|
FILE mkt_algorithm-targets.cmake
|
||||||
|
DESTINATION lib/cmake/mkt_algorithm
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tùy chọn build
|
||||||
|
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
|
option(BUILD_TESTS "Build test programs" OFF)
|
||||||
|
|
||||||
|
# Flags biên dịch
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
|
||||||
|
|
||||||
|
# In thông tin cấu hình
|
||||||
|
message(STATUS "=================================")
|
||||||
|
message(STATUS "Project: ${PROJECT_NAME}")
|
||||||
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
|
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||||
|
message(STATUS "Eigen3 found: ${EIGEN3_FOUND}")
|
||||||
|
message(STATUS "=================================")
|
||||||
0
src/Algorithms/Libraries/mkt_algorithm/README.md
Normal file
0
src/Algorithms/Libraries/mkt_algorithm/README.md
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
#ifndef _NAV_ALGORITHM_BICYCLE_H_INCLUDED__
|
||||||
|
#define _NAV_ALGORITHM_BICYCLE_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <score_algorithm/score_algorithm.h>
|
||||||
|
#include <mkt_algorithm/equation_line.h>
|
||||||
|
#include <pluginlib/class_loader.h>
|
||||||
|
#include <geometry_msgs/PoseArray.h>
|
||||||
|
#include <geometry_msgs/PoseStamped.h>
|
||||||
|
#include <kalman/kalman.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Bicycle
|
||||||
|
* @brief Standard Bicycle-like ScoreAlgorithm
|
||||||
|
*/
|
||||||
|
class Bicycle : public score_algorithm::ScoreAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Bicycle() {}; //: line_generator_(nullptr) {};
|
||||||
|
|
||||||
|
virtual ~Bicycle() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initialize(const ros::NodeHandle & nh, std::string name, TFListenerPtr tf, nav_core2::Costmap::Ptr costmap) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prior to evaluating any trajectories, look at contextual information constant across all trajectories
|
||||||
|
*
|
||||||
|
* Subclasses may overwrite. Return false in case there is any error.
|
||||||
|
*
|
||||||
|
* @param pose Current pose (costmap frame)
|
||||||
|
* @param velocity Current velocity
|
||||||
|
* @param goal The final goal (costmap frame)
|
||||||
|
* @param global_plan Transformed global plan in costmap frame, possibly cropped to nearby points
|
||||||
|
*/
|
||||||
|
virtual bool prepare(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const geometry_msgs::Pose2D& goal, const nav_2d_msgs::Path2D& global_plan,
|
||||||
|
double& x_direction, double& y_direction, double& theta_direction) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset all data
|
||||||
|
*/
|
||||||
|
virtual void reset() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating algorithm
|
||||||
|
* @param pose
|
||||||
|
* @param velocity
|
||||||
|
*/
|
||||||
|
virtual nav_2d_msgs::Twist2DStamped calculator(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D velocity) override;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
unsigned int getGoalIndex(const geometry_msgs::Pose2D &robot_pose, const std::vector<geometry_msgs::Pose2D> &plan,
|
||||||
|
const double distance, unsigned int start_index, unsigned int last_valid_index) const;
|
||||||
|
|
||||||
|
double journey(const std::vector<geometry_msgs::Pose2D> &plan, const unsigned int start_index, const unsigned int last_valid_index) const;
|
||||||
|
|
||||||
|
|
||||||
|
bool getGoalPose(const geometry_msgs::Pose2D &robot_pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const nav_2d_msgs::Path2D &global_plan, geometry_msgs::Pose2D &sub_goal,
|
||||||
|
double &target_direction);
|
||||||
|
|
||||||
|
bool findSubGoalIndex(const std::vector<geometry_msgs::Pose2D> &plan, std::vector<unsigned int> &index_s);
|
||||||
|
|
||||||
|
ros::NodeHandle nh_priv_, nh_;
|
||||||
|
std::string frame_id_path_;
|
||||||
|
ros::Publisher reached_intermediate_goals_pub_, current_goal_pub_, closet_robot_goal_pub_;
|
||||||
|
|
||||||
|
std::vector<geometry_msgs::Pose2D> reached_intermediate_goals_;
|
||||||
|
geometry_msgs::Pose2D rev_sub_goal_, sub_goal_;
|
||||||
|
geometry_msgs::Pose2D goal_;
|
||||||
|
nav_2d_msgs::Path2D global_plan_;
|
||||||
|
|
||||||
|
unsigned int start_index_saved_;
|
||||||
|
unsigned int sub_goal_index_saved_, sub_start_index_saved_;
|
||||||
|
std::vector<unsigned int> start_index_saved_vt_;
|
||||||
|
int index_samples_;
|
||||||
|
|
||||||
|
double steering_fix_wheel_distance_x_;
|
||||||
|
double steering_fix_wheel_distance_y_;
|
||||||
|
double xy_local_goal_tolerance_;
|
||||||
|
double xy_goal_tolerance_;
|
||||||
|
double angle_threshold_;
|
||||||
|
double acc_lim_theta_;
|
||||||
|
double decel_lim_theta_;
|
||||||
|
double x_direction_, y_direction_, theta_direction_;
|
||||||
|
double k_d_reduce_, distance_rg_, k_ld_, ld_min_, ld_max_;
|
||||||
|
double controller_frequency_param_name_;
|
||||||
|
|
||||||
|
bool follow_step_path_;
|
||||||
|
bool is_filter_;
|
||||||
|
boost::shared_ptr<KalmanFilter> kf_;
|
||||||
|
ros::Publisher cmd_raw_pub_;
|
||||||
|
ros::Time last_actuator_update_;
|
||||||
|
}; // class Bicycle
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
|
||||||
|
#endif //_NAV_ALGORITHM_BICYCLE_H_INCLUDED__
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef __NAV_ALGORITHM_EQUATION_LINE_H_INCLUDED__
|
||||||
|
#define __NAV_ALGORITHM_EQUATION_LINE_H_INCLUDED__
|
||||||
|
#include <ros/ros.h>
|
||||||
|
#include <geometry_msgs/Pose2D.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class NoSolution
|
||||||
|
*/
|
||||||
|
class NoSolution : public std::exception {
|
||||||
|
public:
|
||||||
|
const char * what () const throw () {
|
||||||
|
return "Robot cannot calculate error line!";
|
||||||
|
}
|
||||||
|
}; // class NoSolution
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class LineGenerator
|
||||||
|
*/
|
||||||
|
class LineGenerator
|
||||||
|
{
|
||||||
|
/* data */
|
||||||
|
struct LineEquation {
|
||||||
|
geometry_msgs::Pose2D Gi; /* 𝑮𝒊(𝒙𝒊,𝒚𝒊) */
|
||||||
|
geometry_msgs::Pose2D Gj; /* 𝑮𝒋(𝒙𝒋,𝒚𝒋) */
|
||||||
|
float a, b, c ; /* 𝒂𝒙+𝒃𝒚+𝒄=𝟎 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Save data present position */
|
||||||
|
struct PresentPosition {
|
||||||
|
float Gxh, Gyh; /* 𝑮𝒋(𝒙h,𝒚h) The head position in Robot */
|
||||||
|
float Yaw_degree; /* Angle of Robot (degree) */
|
||||||
|
float Yaw_rad; /* Angle of Robot (degree) */
|
||||||
|
float error_line; /* 𝒆(𝑮,𝒍𝒊𝒏𝒆)=|𝒂𝒙+𝒃𝒚+𝒄|/sqrt(𝒂^2+𝒃^2) */
|
||||||
|
double distance_to_goal; /* The distance from query pose to goal */
|
||||||
|
double distance_to_start; /* The distance from query pose to start*/
|
||||||
|
double distace_start_goal;
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief To caculated the equation of the line
|
||||||
|
* @param start_point start point of the line
|
||||||
|
* @param end_point end point of the line
|
||||||
|
*/
|
||||||
|
virtual bool calculatorEquationLine(geometry_msgs::Pose2D start_point, geometry_msgs::Pose2D end_point);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating error
|
||||||
|
* @param[in] Lm The distance from the center of the wheel axis to the center line
|
||||||
|
* @param[in] pose
|
||||||
|
* @param[in] rev
|
||||||
|
*/
|
||||||
|
virtual void calculateErrorLine(float Lm, geometry_msgs::Pose2D pose, bool rev = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating tolerance
|
||||||
|
* @param query_pose The pose to check
|
||||||
|
* @param goal_pose The pose to check against
|
||||||
|
*/
|
||||||
|
virtual double calculateTolerance(const geometry_msgs::Pose2D& query_pose, const geometry_msgs::Pose2D& goal_pose);
|
||||||
|
|
||||||
|
/* Properties */
|
||||||
|
LineEquation Leq_;
|
||||||
|
PresentPosition present_pose_;
|
||||||
|
|
||||||
|
}; // class LineGenerator
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
#endif // __NAV_ALGORITHM_EQUATION_LINE_H_INCLUDED__
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
#ifndef _NAV_ALGORITHM_ROTATE_TO_GOAL_H_INCLUDED__
|
||||||
|
#define _NAV_ALGORITHM_ROTATE_TO_GOAL_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <score_algorithm/score_algorithm.h>
|
||||||
|
#include <pluginlib/class_loader.h>
|
||||||
|
#include <geometry_msgs/PoseArray.h>
|
||||||
|
#include <geometry_msgs/PoseStamped.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class GoStraight
|
||||||
|
* @brief Standard Bicycle-like ScoreAlgorithm
|
||||||
|
*/
|
||||||
|
class GoStraight : public score_algorithm::ScoreAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
GoStraight() {};
|
||||||
|
|
||||||
|
virtual ~GoStraight() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initialize(const ros::NodeHandle & nh, std::string name, TFListenerPtr tf, nav_core2::Costmap::Ptr costmap) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prior to evaluating any trajectories, look at contextual information constant across all trajectories
|
||||||
|
*
|
||||||
|
* Subclasses may overwrite. Return false in case there is any error.
|
||||||
|
*
|
||||||
|
* @param pose Current pose (costmap frame)
|
||||||
|
* @param velocity Current velocity
|
||||||
|
* @param goal The final goal (costmap frame)
|
||||||
|
* @param global_plan Transformed global plan in costmap frame, possibly cropped to nearby points
|
||||||
|
*/
|
||||||
|
virtual bool prepare(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const geometry_msgs::Pose2D& goal, const nav_2d_msgs::Path2D& global_plan,
|
||||||
|
double& x_direction, double& y_direction, double& theta_direction) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset all data
|
||||||
|
*/
|
||||||
|
virtual void reset() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating algorithm
|
||||||
|
* @param pose
|
||||||
|
* @param velocity
|
||||||
|
*/
|
||||||
|
virtual nav_2d_msgs::Twist2DStamped calculator(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D velocity) override;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ros::NodeHandle nh_;
|
||||||
|
ros::NodeHandle nh_kinematics_;
|
||||||
|
|
||||||
|
double steering_fix_wheel_distance_x_;
|
||||||
|
double steering_fix_wheel_distance_y_;
|
||||||
|
geometry_msgs::Pose2D goal_;
|
||||||
|
ros::Time time_last_cmd_;
|
||||||
|
|
||||||
|
}; // class GoStraight
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef _NAV_ALGORITHM_CHECKER_GOAL_H_INCLUDED__
|
||||||
|
#define _NAV_ALGORITHM_CHECKER_GOAL_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <score_algorithm/goal_checker.h>
|
||||||
|
#include <mkt_algorithm/equation_line.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
class GoalChecker : public score_algorithm::GoalChecker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize any parameters from the NodeHandle
|
||||||
|
* @param nh NodeHandle for grabbing parameters
|
||||||
|
*/
|
||||||
|
virtual void initialize(const ros::NodeHandle& nh) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the state of the goal checker (if any)
|
||||||
|
*/
|
||||||
|
virtual void reset() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether the goal should be considered reached
|
||||||
|
* @param query_pose The pose to check
|
||||||
|
* @param goal_pose The pose to check against
|
||||||
|
* @param velocity The robot's current velocity
|
||||||
|
* @return True if goal is reached
|
||||||
|
*/
|
||||||
|
bool isGoalReached(const geometry_msgs::Pose2D& query_pose, const geometry_msgs::Pose2D& goal_pose,
|
||||||
|
const std::vector<geometry_msgs::PoseStamped>& path, const nav_2d_msgs::Twist2D& velocity) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
boost::shared_ptr<mkt_algorithm::LineGenerator> line_generator_;
|
||||||
|
double yaw_goal_tolerance_;
|
||||||
|
double xy_goal_tolerance_;
|
||||||
|
double old_xy_goal_tolerance_;
|
||||||
|
bool setup_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
#endif // _NAV_ALGORITHM_CHECKER_GOAL_H_INCLUDED__
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef _NAV_ALGORITHM_PTA_H_INCLUDED__
|
||||||
|
#define _NAV_ALGORITHM_PTA_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <score_algorithm/score_algorithm.h>
|
||||||
|
#include <mkt_algorithm/equation_line.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class PTA
|
||||||
|
* @brief Standard PTA-like ScoreAlgorithm
|
||||||
|
*/
|
||||||
|
class PTA : public score_algorithm::ScoreAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
PTA() : line_generator_(nullptr) {};
|
||||||
|
|
||||||
|
virtual ~PTA() {};
|
||||||
|
|
||||||
|
// Standard ScoreAlgorithm Interface
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initialize(const ros::NodeHandle & nh, std::string name, TFListenerPtr tf, nav_core2::Costmap::Ptr costmap) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prior to evaluating any trajectories, look at contextual information constant across all trajectories
|
||||||
|
*
|
||||||
|
* Subclasses may overwrite. Return false in case there is any error.
|
||||||
|
*
|
||||||
|
* @param pose Current pose (costmap frame)
|
||||||
|
* @param velocity Current velocity
|
||||||
|
* @param goal The final goal (costmap frame)
|
||||||
|
* @param global_plan Transformed global plan in costmap frame, possibly cropped to nearby points
|
||||||
|
*/
|
||||||
|
virtual bool prepare(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const geometry_msgs::Pose2D& goal, const nav_2d_msgs::Path2D& global_plan,
|
||||||
|
double& x_direction, double& y_direction, double& theta_direction) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating algorithm
|
||||||
|
* @param pose
|
||||||
|
* @param velocity
|
||||||
|
*/
|
||||||
|
virtual nav_2d_msgs::Twist2DStamped calculator(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D velocity) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
boost::shared_ptr<mkt_algorithm::LineGenerator> line_generator_;
|
||||||
|
double pta_amplitude_max_; // (Default: 0.5 - Range: 0.1 -> 1.0) Cai dat bien do (mot phia - m) cho phep robot di chuyen trong do
|
||||||
|
|
||||||
|
}; // class PTA
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
|
||||||
|
#endif //_NAV_ALGORITHM_PTA_H_INCLUDED__
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
#ifndef _NAV_ALGORITHM_ROTATE_TO_GOAL_H_INCLUDED__
|
||||||
|
#define _NAV_ALGORITHM_ROTATE_TO_GOAL_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <score_algorithm/score_algorithm.h>
|
||||||
|
#include <pluginlib/class_loader.h>
|
||||||
|
#include <geometry_msgs/PoseArray.h>
|
||||||
|
#include <geometry_msgs/PoseStamped.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class GoStraight
|
||||||
|
* @brief Standard Bicycle-like ScoreAlgorithm
|
||||||
|
*/
|
||||||
|
class RotateToGoal : public score_algorithm::ScoreAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
RotateToGoal() {};
|
||||||
|
|
||||||
|
virtual ~RotateToGoal() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initialize(const ros::NodeHandle & nh, std::string name, TFListenerPtr tf, nav_core2::Costmap::Ptr costmap) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prior to evaluating any trajectories, look at contextual information constant across all trajectories
|
||||||
|
*
|
||||||
|
* Subclasses may overwrite. Return false in case there is any error.
|
||||||
|
*
|
||||||
|
* @param pose Current pose (costmap frame)
|
||||||
|
* @param velocity Current velocity
|
||||||
|
* @param goal The final goal (costmap frame)
|
||||||
|
* @param global_plan Transformed global plan in costmap frame, possibly cropped to nearby points
|
||||||
|
*/
|
||||||
|
virtual bool prepare(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const geometry_msgs::Pose2D& goal, const nav_2d_msgs::Path2D& global_plan,
|
||||||
|
double& x_direction, double& y_direction, double& theta_direction) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset all data
|
||||||
|
*/
|
||||||
|
virtual void reset() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating algorithm
|
||||||
|
* @param pose
|
||||||
|
* @param velocity
|
||||||
|
*/
|
||||||
|
virtual nav_2d_msgs::Twist2DStamped calculator(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D velocity) override;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ros::NodeHandle nh_;
|
||||||
|
ros::NodeHandle nh_kinematics_;
|
||||||
|
geometry_msgs::Pose2D sub_goal_;
|
||||||
|
|
||||||
|
double steering_fix_wheel_distance_x_;
|
||||||
|
double steering_fix_wheel_distance_y_;
|
||||||
|
double angle_threshold_;
|
||||||
|
double current_direction_;
|
||||||
|
double velocity_rotate_min_, velocity_rotate_max_;
|
||||||
|
geometry_msgs::Pose2D goal_;
|
||||||
|
ros::Time time_last_cmd_;
|
||||||
|
|
||||||
|
}; // class RotateToGoal
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef _NAV_ALGORITHM_DIFF_ROTATE_TO_GOAL_H_INCLUDED__
|
||||||
|
#define _NAV_ALGORITHM_DIFF_ROTATE_TO_GOAL_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <mkt_algorithm/diff/diff_predictive_trajectory.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
namespace diff
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @class GoStraight
|
||||||
|
* @brief Standard Bicycle-like ScoreAlgorithm
|
||||||
|
*/
|
||||||
|
class GoStraight : public mkt_algorithm::diff::PredictiveTrajectory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GoStraight() {};
|
||||||
|
|
||||||
|
virtual ~GoStraight() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initialize(
|
||||||
|
ros::NodeHandle &nh, std::string name, TFListenerPtr tf, costmap_2d::Costmap2DROS *costmap_ros, const score_algorithm::TrajectoryGenerator::Ptr &traj) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating algorithm
|
||||||
|
* @param pose
|
||||||
|
* @param velocity
|
||||||
|
* @param traj
|
||||||
|
*/
|
||||||
|
virtual mkt_msgs::Trajectory2D calculator(
|
||||||
|
const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity) override;
|
||||||
|
|
||||||
|
}; // class GoStraight
|
||||||
|
} // namespace diff
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
#endif // _NAV_ALGORITHM_DIFF_ROTATE_TO_GOAL_H_INCLUDED__
|
||||||
|
|
@ -0,0 +1,325 @@
|
||||||
|
#ifndef _NAV_ALGORITHM_DIFF_PREDICTIVE_TRAJECTORY_H_INCLUDED__
|
||||||
|
#define _NAV_ALGORITHM_DIFF_PREDICTIVE_TRAJECTORY_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <score_algorithm/score_algorithm.h>
|
||||||
|
|
||||||
|
#include <boost/dll/import.hpp>
|
||||||
|
#include <geometry_msgs/PoseStamped.h>
|
||||||
|
#include <geometry_msgs/PointStamped.h>
|
||||||
|
#include <nav_2d_msgs/Pose2DStamped.h>
|
||||||
|
// #include <visualization_msgs/Marker.h>
|
||||||
|
// #include <ddynamic_reconfigure/ddynamic_reconfigure.h>
|
||||||
|
|
||||||
|
// #include <base_local_planner/costmap_model.h>
|
||||||
|
// #include <base_local_planner/world_model.h>
|
||||||
|
// #include <base_local_planner/trajectory_planner.h>
|
||||||
|
// #include <base_local_planner/map_grid_visualizer.h>
|
||||||
|
// #include <base_local_planner/BaseLocalPlannerConfig.h>
|
||||||
|
// #include <teb_local_planner/pose_se2.h>
|
||||||
|
|
||||||
|
#include <nav_core2/exceptions.h>
|
||||||
|
#include <nav_core2/costmap.h>
|
||||||
|
#include <nav_grid/coordinate_conversion.h>
|
||||||
|
#include <angles/angles.h>
|
||||||
|
#include <tf3/utils.h>
|
||||||
|
#include <nav_msgs/Path.h>
|
||||||
|
#include <kalman/kalman.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <nav_2d_utils/parameters.h>
|
||||||
|
#include <nav_2d_utils/tf_help.h>
|
||||||
|
#include <nav_2d_utils/path_ops.h>
|
||||||
|
#include <nav_2d_utils/conversions.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
namespace diff
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @class PredictiveTrajectory
|
||||||
|
* @brief Standard PredictiveTrajectory-like ScoreAlgorithm
|
||||||
|
*/
|
||||||
|
class PredictiveTrajectory : public score_algorithm::ScoreAlgorithm
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PredictiveTrajectory() : initialized_(false), nav_stop_(false) {};
|
||||||
|
|
||||||
|
virtual ~PredictiveTrajectory();
|
||||||
|
|
||||||
|
// Standard ScoreAlgorithm Interface
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initialize(
|
||||||
|
ros::NodeHandle &nh, std::string name, TFListenerPtr tf, costmap_2d::Costmap2DROS *costmap_ros, const score_algorithm::TrajectoryGenerator::Ptr &traj) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prior to evaluating any trajectories, look at contextual information constant across all trajectories
|
||||||
|
*
|
||||||
|
* Subclasses may overwrite. Return false in case there is any error.
|
||||||
|
*
|
||||||
|
* @param pose Current pose (costmap frame)
|
||||||
|
* @param velocity Current velocity
|
||||||
|
* @param goal The final goal (costmap frame)
|
||||||
|
* @param global_plan Transformed global plan in costmap frame, possibly cropped to nearby points
|
||||||
|
*/
|
||||||
|
virtual bool prepare(const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity,
|
||||||
|
const nav_2d_msgs::Pose2DStamped &goal, const nav_2d_msgs::Path2D &global_plan,
|
||||||
|
double &x_direction, double &y_direction, double &theta_direction) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating algorithm
|
||||||
|
* @param pose
|
||||||
|
* @param velocity
|
||||||
|
* @param traj
|
||||||
|
*/
|
||||||
|
virtual mkt_msgs::Trajectory2D calculator(
|
||||||
|
const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset all data
|
||||||
|
*/
|
||||||
|
virtual void reset() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stoping move navigation
|
||||||
|
*/
|
||||||
|
virtual void stop() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief resume move navigation after stopped
|
||||||
|
*/
|
||||||
|
virtual void resume() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
inline double sign(double x)
|
||||||
|
{
|
||||||
|
return x < 0.0 ? -1.0 : 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters
|
||||||
|
*/
|
||||||
|
virtual void getParams();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize dynamic reconfigure
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initDynamicReconfigure(const ros::NodeHandle &nh);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dynamically adjust look ahead distance based on the speed
|
||||||
|
* @param velocity
|
||||||
|
* @return look ahead distance
|
||||||
|
*/
|
||||||
|
double getLookAheadDistance(const nav_2d_msgs::Twist2D &velocity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get lookahead point on the global plan
|
||||||
|
* @param lookahead_dist
|
||||||
|
* @param global_plan
|
||||||
|
* @return lookahead point
|
||||||
|
*/
|
||||||
|
std::vector<nav_2d_msgs::Pose2DStamped>::iterator
|
||||||
|
getLookAheadPoint(const nav_2d_msgs::Twist2D &velocity, const double &lookahead_dist, nav_2d_msgs::Path2D global_plan);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create carrot message
|
||||||
|
* @param carrot_pose
|
||||||
|
* @return carrot message
|
||||||
|
*/
|
||||||
|
geometry_msgs::PointStamped createCarrotMsg(const nav_2d_msgs::Pose2DStamped &carrot_pose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prune global plan
|
||||||
|
* @param tf
|
||||||
|
* @param pose
|
||||||
|
* @param global_plan
|
||||||
|
* @param dist_behind_robot
|
||||||
|
* @return true if plan is pruned, false otherwise
|
||||||
|
*/
|
||||||
|
bool pruneGlobalPlan(TFListenerPtr tf, const nav_2d_msgs::Pose2DStamped &pose,
|
||||||
|
nav_2d_msgs::Path2D &global_plan, double dist_behind_robot);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transforms the global plan of the robot from the planner frame to the local frame (modified).
|
||||||
|
*
|
||||||
|
* The method replaces transformGlobalPlan as defined in base_local_planner/goal_functions.h
|
||||||
|
* such that the index of the current goal pose is returned as well as
|
||||||
|
* the transformation between the global plan and the planning frame.
|
||||||
|
* @param tf A reference to a tf buffer
|
||||||
|
* @param global_plan The plan to be transformed
|
||||||
|
* @param pose The pose of the robot
|
||||||
|
* @param costmap A reference to the costmap being used so the window size for transforming can be computed
|
||||||
|
* @param global_frame The frame to transform the plan to
|
||||||
|
* @param max_plan_length Specify maximum length (cumulative Euclidean distances) of the transformed plan [if <=0: disabled; the length is also bounded by the local costmap size!]
|
||||||
|
* @param[out] transformed_plan Populated with the transformed plan
|
||||||
|
* @return \c true if the global plan is transformed, \c false otherwise
|
||||||
|
*/
|
||||||
|
bool transformGlobalPlan(
|
||||||
|
TFListenerPtr tf, const nav_2d_msgs::Path2D &global_plan, const nav_2d_msgs::Pose2DStamped &pose,
|
||||||
|
const costmap_2d::Costmap2DROS *costmap, const std::string &robot_base_frame, double max_plan_length,
|
||||||
|
nav_2d_msgs::Path2D &transformed_plan);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Should rotate to path
|
||||||
|
* @param carrot_pose
|
||||||
|
* @param angle_to_path
|
||||||
|
* @return true if should rotate, false otherwise
|
||||||
|
*/
|
||||||
|
bool shouldRotateToPath(
|
||||||
|
const nav_2d_msgs::Path2D &global_plan, const nav_2d_msgs::Pose2DStamped &carrot_pose, const nav_2d_msgs::Twist2D &velocity, double &angle_to_path, const double &sign_x);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Rotate to heading
|
||||||
|
* @param angle_to_path
|
||||||
|
* @param velocity The velocity of the robot
|
||||||
|
* @param cmd_vel The velocity commands to be filled
|
||||||
|
*/
|
||||||
|
void rotateToHeading(const double &angle_to_path, const nav_2d_msgs::Twist2D &velocity, nav_2d_msgs::Twist2D &cmd_vel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief the robot is moving acceleration limits
|
||||||
|
* @param velocity The velocity of the robot
|
||||||
|
* @param cmd_vel The velocity commands
|
||||||
|
* @param cmd_vel_result The velocity commands result
|
||||||
|
*/
|
||||||
|
void moveWithAccLimits(
|
||||||
|
const nav_2d_msgs::Twist2D &velocity, const nav_2d_msgs::Twist2D &cmd_vel, nav_2d_msgs::Twist2D &cmd_vel_result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stop the robot taking into account acceleration limits
|
||||||
|
* @param pose The pose of the robot in the global frame
|
||||||
|
* @param velocity The velocity of the robot
|
||||||
|
* @param cmd_vel The velocity commands to be filled
|
||||||
|
* @return True if a valid trajectory was found, false otherwise
|
||||||
|
*/
|
||||||
|
bool stopWithAccLimits(const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity, nav_2d_msgs::Twist2D &cmd_vel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Apply constraints
|
||||||
|
* @param dist_error
|
||||||
|
* @param lookahead_dist
|
||||||
|
* @param curvature
|
||||||
|
* @param curr_speed
|
||||||
|
* @param pose_cost
|
||||||
|
* @param linear_vel
|
||||||
|
* @param sign
|
||||||
|
*/
|
||||||
|
void applyConstraints(
|
||||||
|
const double &dist_error, const double &lookahead_dist,
|
||||||
|
const double &curvature, const nav_2d_msgs::Twist2D &curr_speed,
|
||||||
|
const double &pose_cost, double &linear_vel, double &sign_x);
|
||||||
|
|
||||||
|
std::vector<geometry_msgs::Point> interpolateFootprint(geometry_msgs::Pose2D pose, std::vector<geometry_msgs::Point> footprint, double resolution);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Cost at pose
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @return cost
|
||||||
|
*/
|
||||||
|
double costAtPose(const double &x, const double &y);
|
||||||
|
|
||||||
|
void updateCostAtOffset(
|
||||||
|
TFListenerPtr tf, const std::string &robot_base_frame, const nav_2d_msgs::Pose2DStamped &base_pose,
|
||||||
|
double x_offset, double y_offset, double &cost_left, double &cost_right);
|
||||||
|
|
||||||
|
double computeDecelerationFactor(double remaining_distance, double decel_distance);
|
||||||
|
|
||||||
|
double getEffectiveDistance(const nav_2d_msgs::Pose2DStamped &carrot_pose, double journey_plan);
|
||||||
|
|
||||||
|
bool detectWobbleByCarrotAngle(std::vector<double>& angle_history, double current_angle,
|
||||||
|
double amplitude_threshold = 0.3, size_t window_size = 20);
|
||||||
|
|
||||||
|
void publishMarkers(nav_2d_msgs::Pose2DStamped pose);
|
||||||
|
|
||||||
|
std::vector<double> angle_history_;
|
||||||
|
size_t window_size_;
|
||||||
|
|
||||||
|
bool initialized_;
|
||||||
|
bool nav_stop_, avoid_obstacles_;
|
||||||
|
ros::NodeHandle nh_, nh_priv_;
|
||||||
|
std::string frame_id_path_;
|
||||||
|
std::string robot_base_frame_;
|
||||||
|
ros::Publisher carrot_pub_;
|
||||||
|
|
||||||
|
nav_2d_msgs::Pose2DStamped goal_;
|
||||||
|
nav_2d_msgs::Path2D global_plan_;
|
||||||
|
nav_2d_msgs::Path2D compute_plan_;
|
||||||
|
nav_2d_msgs::Path2D transform_plan_;
|
||||||
|
nav_2d_msgs::Twist2D prevous_drive_cmd_;
|
||||||
|
ros::Publisher drive_pub_;
|
||||||
|
|
||||||
|
double x_direction_, y_direction_, theta_direction_;
|
||||||
|
double max_robot_pose_search_dist_;
|
||||||
|
double global_plan_prune_distance_{1.0};
|
||||||
|
|
||||||
|
// Lookahead
|
||||||
|
bool use_velocity_scaled_lookahead_dist_;
|
||||||
|
double lookahead_time_;
|
||||||
|
double lookahead_dist_;
|
||||||
|
double min_lookahead_dist_;
|
||||||
|
double max_lookahead_dist_;
|
||||||
|
|
||||||
|
// journey
|
||||||
|
double min_journey_squared_{1e9};
|
||||||
|
double max_journey_squared_{1e9};
|
||||||
|
|
||||||
|
// Rotate to heading
|
||||||
|
bool use_rotate_to_heading_;
|
||||||
|
double rotate_to_heading_min_angle_;
|
||||||
|
|
||||||
|
double max_vel_theta_, min_vel_theta_, acc_lim_theta_, decel_lim_theta_;
|
||||||
|
double min_path_distance_, max_path_distance_;
|
||||||
|
|
||||||
|
// Regulated linear velocity scaling
|
||||||
|
bool use_regulated_linear_velocity_scaling_;
|
||||||
|
double max_vel_x_, min_vel_x_, acc_lim_x_, decel_lim_x_;
|
||||||
|
double max_vel_y_, min_vel_y_, acc_lim_y_, decel_lim_y_;
|
||||||
|
|
||||||
|
double rot_stopped_velocity_, trans_stopped_velocity_;
|
||||||
|
|
||||||
|
double min_approach_linear_velocity_;
|
||||||
|
double regulated_linear_scaling_min_radius_;
|
||||||
|
double regulated_linear_scaling_min_speed_;
|
||||||
|
|
||||||
|
bool use_cost_regulated_linear_velocity_scaling_;
|
||||||
|
double inflation_cost_scaling_factor_;
|
||||||
|
double cost_scaling_dist_, cost_scaling_gain_;
|
||||||
|
|
||||||
|
double cost_left_goal_, cost_right_goal_;
|
||||||
|
double cost_left_side_ , cost_right_side_;
|
||||||
|
double center_cost_;
|
||||||
|
|
||||||
|
// Control frequency
|
||||||
|
double control_duration_;
|
||||||
|
|
||||||
|
std::shared_ptr<ddynamic_reconfigure::DDynamicReconfigure> ddr_;
|
||||||
|
base_local_planner::BaseLocalPlannerConfig config_;
|
||||||
|
|
||||||
|
base_local_planner::WorldModel *world_model_; ///< @brief The world model that the controller will use
|
||||||
|
base_local_planner::TrajectoryPlanner *tc_; ///< @brief The trajectory controller
|
||||||
|
base_local_planner::MapGridVisualizer map_viz_;
|
||||||
|
std::vector<geometry_msgs::Point> footprint_spec_;
|
||||||
|
|
||||||
|
ros::Time last_actuator_update_;
|
||||||
|
boost::shared_ptr<KalmanFilter> kf_;
|
||||||
|
int m_, n_;
|
||||||
|
Eigen::MatrixXd A;
|
||||||
|
Eigen::MatrixXd C;
|
||||||
|
Eigen::MatrixXd Q;
|
||||||
|
Eigen::MatrixXd R;
|
||||||
|
Eigen::MatrixXd P;
|
||||||
|
|
||||||
|
ros::Publisher cost_right_goals_pub_, cost_left_goals_pub_;
|
||||||
|
// visualization_msgs::Marker L_, R_;
|
||||||
|
}; // class PredictiveTrajectory
|
||||||
|
|
||||||
|
} // namespace diff
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
#endif //_NAV_ALGORITHM_DIFF_PREDICTIVE_TRAJECTORY_H_INCLUDED__
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
#ifndef _NAV_ALGORITHM_ROTATE_TO_GOAL_DIFF_H_INCLUDED__
|
||||||
|
#define _NAV_ALGORITHM_ROTATE_TO_GOAL_DIFF_H_INCLUDED__
|
||||||
|
|
||||||
|
#include <mkt_algorithm/diff/diff_predictive_trajectory.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
namespace diff
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @class GoStraight
|
||||||
|
* @brief Standard Bicycle-like ScoreAlgorithm
|
||||||
|
*/
|
||||||
|
class RotateToGoal : public mkt_algorithm::diff::PredictiveTrajectory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RotateToGoal() {};
|
||||||
|
|
||||||
|
virtual ~RotateToGoal() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters as needed
|
||||||
|
* @param nh NodeHandle to read parameters from
|
||||||
|
*/
|
||||||
|
virtual void initialize(
|
||||||
|
ros::NodeHandle &nh, std::string name, TFListenerPtr tf, costmap_2d::Costmap2DROS *costmap_ros, const score_algorithm::TrajectoryGenerator::Ptr &traj) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prior to evaluating any trajectories, look at contextual information constant across all trajectories
|
||||||
|
*
|
||||||
|
* Subclasses may overwrite. Return false in case there is any error.
|
||||||
|
*
|
||||||
|
* @param pose Current pose (costmap frame)
|
||||||
|
* @param velocity Current velocity
|
||||||
|
* @param goal The final goal (costmap frame)
|
||||||
|
* @param global_plan Transformed global plan in costmap frame, possibly cropped to nearby points
|
||||||
|
*/
|
||||||
|
virtual bool prepare(const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity,
|
||||||
|
const nav_2d_msgs::Pose2DStamped &goal, const nav_2d_msgs::Path2D &global_plan,
|
||||||
|
double &x_direction, double &y_direction, double &theta_direction) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset all data
|
||||||
|
*/
|
||||||
|
virtual void reset() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculating algorithm
|
||||||
|
* @param pose
|
||||||
|
* @param velocity
|
||||||
|
* @param traj
|
||||||
|
*/
|
||||||
|
virtual mkt_msgs::Trajectory2D calculator(
|
||||||
|
const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Initialize parameters
|
||||||
|
*/
|
||||||
|
virtual void getParams() override;
|
||||||
|
|
||||||
|
}; // class RotateToGoalDiff
|
||||||
|
|
||||||
|
} // namespace diff
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
#endif // _NAV_ALGORITHM_ROTATE_TO_GOAL_DIFF_H_INCLUDED__
|
||||||
94
src/Algorithms/Libraries/mkt_algorithm/package.xml
Normal file
94
src/Algorithms/Libraries/mkt_algorithm/package.xml
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<package format="2">
|
||||||
|
<name>mkt_algorithm</name>
|
||||||
|
<version>0.0.0</version>
|
||||||
|
<description>The mkt_algorithm package</description>
|
||||||
|
|
||||||
|
<!-- One maintainer tag required, multiple allowed, one person per tag -->
|
||||||
|
<!-- Example: -->
|
||||||
|
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
|
||||||
|
<maintainer email="robotics@todo.todo">robotics</maintainer>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- One license tag required, multiple allowed, one license per tag -->
|
||||||
|
<!-- Commonly used license strings: -->
|
||||||
|
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
|
||||||
|
<license>TODO</license>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Url tags are optional, but multiple are allowed, one per tag -->
|
||||||
|
<!-- Optional attribute type can be: website, bugtracker, or repository -->
|
||||||
|
<!-- Example: -->
|
||||||
|
<!-- <url type="website">http://wiki.ros.org/mkt_algorithm</url> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Author tags are optional, multiple are allowed, one per tag -->
|
||||||
|
<!-- Authors do not have to be maintainers, but could be -->
|
||||||
|
<!-- Example: -->
|
||||||
|
<!-- <author email="jane.doe@example.com">Jane Doe</author> -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- The *depend tags are used to specify dependencies -->
|
||||||
|
<!-- Dependencies can be catkin packages or system dependencies -->
|
||||||
|
<!-- Examples: -->
|
||||||
|
<!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
|
||||||
|
<!-- <depend>roscpp</depend> -->
|
||||||
|
<!-- Note that this is equivalent to the following: -->
|
||||||
|
<!-- <build_depend>roscpp</build_depend> -->
|
||||||
|
<!-- <exec_depend>roscpp</exec_depend> -->
|
||||||
|
<!-- Use build_depend for packages you need at compile time: -->
|
||||||
|
<!-- <build_depend>message_generation</build_depend> -->
|
||||||
|
<!-- Use build_export_depend for packages you need in order to build against this package: -->
|
||||||
|
<!-- <build_export_depend>message_generation</build_export_depend> -->
|
||||||
|
<!-- Use buildtool_depend for build tool packages: -->
|
||||||
|
<!-- <buildtool_depend>catkin</buildtool_depend> -->
|
||||||
|
<!-- Use exec_depend for packages you need at runtime: -->
|
||||||
|
<!-- <exec_depend>message_runtime</exec_depend> -->
|
||||||
|
<!-- Use test_depend for packages you need only for testing: -->
|
||||||
|
<!-- <test_depend>gtest</test_depend> -->
|
||||||
|
<!-- Use doc_depend for packages you need only for building documentation: -->
|
||||||
|
<!-- <doc_depend>doxygen</doc_depend> -->
|
||||||
|
<buildtool_depend>catkin</buildtool_depend>
|
||||||
|
<build_depend>geometry_msgs</build_depend>
|
||||||
|
<build_depend>score_algorithm</build_depend>
|
||||||
|
<build_depend>nav_2d_msgs</build_depend>
|
||||||
|
<build_depend>roscpp</build_depend>
|
||||||
|
<build_depend>sensor_msgs</build_depend>
|
||||||
|
<build_depend>nav_2d_utils</build_depend>
|
||||||
|
<build_depend>kalman</build_depend>
|
||||||
|
<build_depend>ddynamic_reconfigure</build_depend>
|
||||||
|
<build_depend>costmap_2d</build_depend>
|
||||||
|
<build_depend>base_local_planner</build_depend>
|
||||||
|
<build_depend>visualization_msgs</build_depend>
|
||||||
|
|
||||||
|
<build_export_depend>geometry_msgs</build_export_depend>
|
||||||
|
<build_export_depend>score_algorithm</build_export_depend>
|
||||||
|
<build_export_depend>nav_2d_msgs</build_export_depend>
|
||||||
|
<build_export_depend>roscpp</build_export_depend>
|
||||||
|
<build_export_depend>sensor_msgs</build_export_depend>
|
||||||
|
<build_export_depend>nav_2d_utils</build_export_depend>
|
||||||
|
<build_export_depend>kalman</build_export_depend>
|
||||||
|
<build_export_depend>ddynamic_reconfigure</build_export_depend>
|
||||||
|
<build_export_depend>costmap_2d</build_export_depend>
|
||||||
|
<build_export_depend>base_local_planner</build_export_depend>
|
||||||
|
<build_export_depend>visualization_msgs</build_export_depend>
|
||||||
|
|
||||||
|
<exec_depend>geometry_msgs</exec_depend>
|
||||||
|
<exec_depend>score_algorithm</exec_depend>
|
||||||
|
<exec_depend>nav_2d_msgs</exec_depend>
|
||||||
|
<exec_depend>roscpp</exec_depend>
|
||||||
|
<exec_depend>sensor_msgs</exec_depend>
|
||||||
|
<exec_depend>nav_2d_utils</exec_depend>
|
||||||
|
<exec_depend>kalman</exec_depend>
|
||||||
|
<exec_depend>ddynamic_reconfigure</exec_depend>
|
||||||
|
<exec_depend>costmap_2d</exec_depend>
|
||||||
|
<exec_depend>base_local_planner</exec_depend>
|
||||||
|
<exec_depend>visualization_msgs</exec_depend>
|
||||||
|
|
||||||
|
<depend>pluginlib</depend>
|
||||||
|
|
||||||
|
<!-- The export tag contains other, unspecified, tags -->
|
||||||
|
<export>
|
||||||
|
<score_algorithm plugin="${prefix}/plugins.xml"/>
|
||||||
|
</export>
|
||||||
|
</package>
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include <mkt_algorithm/go_straight.h>
|
||||||
|
#include <nav_2d_utils/parameters.h>
|
||||||
|
#include <pluginlib/class_list_macros.h>
|
||||||
|
#include <angles/angles.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
void GoStraight::initialize(const ros::NodeHandle & nh, std::string name, TFListenerPtr tf, nav_core2::Costmap::Ptr costmap)
|
||||||
|
{
|
||||||
|
nh_ = ros::NodeHandle(nh, name);
|
||||||
|
name_ = name;
|
||||||
|
tf_ = tf;
|
||||||
|
costmap_ros_ = costmap_ros;
|
||||||
|
|
||||||
|
steering_fix_wheel_distance_x_ = nav_2d_utils::searchAndGetParam(nh_, "steering_fix_wheel_distance_x", 1.1);
|
||||||
|
steering_fix_wheel_distance_y_ = nav_2d_utils::searchAndGetParam(nh_, "steering_fix_wheel_distance_y", 0.);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GoStraight::reset()
|
||||||
|
{
|
||||||
|
time_last_cmd_ = ros::Time::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GoStraight::prepare( const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const geometry_msgs::Pose2D& goal, const nav_2d_msgs::Path2D& global_plan,
|
||||||
|
double& x_direction, double& y_direction, double& theta_direction)
|
||||||
|
{
|
||||||
|
goal_ = goal;
|
||||||
|
|
||||||
|
const double rb_direction_x = goal_.x - pose.x;
|
||||||
|
const double rb_direction_y = goal_.y - pose.y;
|
||||||
|
const double rb_angle = atan2(rb_direction_y, rb_direction_x);
|
||||||
|
double rb_dir = cos(rb_angle- pose.theta);
|
||||||
|
x_direction = y_direction = theta_direction = rb_dir;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav_2d_msgs::Twist2DStamped GoStraight::calculator(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D velocity)
|
||||||
|
{
|
||||||
|
nav_2d_msgs::Twist2DStamped result;
|
||||||
|
result.header.stamp = ros::Time::now();
|
||||||
|
|
||||||
|
geometry_msgs::Pose2D steer_to_baselink_pose;
|
||||||
|
|
||||||
|
if(!getPose("steer_link", "base_link", steer_to_baselink_pose))
|
||||||
|
return result;
|
||||||
|
double odom_alpha = steer_to_baselink_pose.theta;
|
||||||
|
if(fabs(odom_alpha) > 0.03) return result;
|
||||||
|
|
||||||
|
double delta_x = goal_.x - pose.x;
|
||||||
|
double delta_y = goal_.y - pose.y;
|
||||||
|
|
||||||
|
double d_rg = sqrt(pow(delta_x, 2) + pow(delta_y, 2));
|
||||||
|
double d_reduce = std::min(std::max(fabs(velocity.x), 0.6), 0.9);
|
||||||
|
double v_min = 0.03 * velocity.x / (fabs(velocity.x) + 1e-9);
|
||||||
|
|
||||||
|
// Van toc robot
|
||||||
|
double vr = d_rg > d_reduce? velocity.x : (velocity.x - v_min)*sin((d_rg / d_reduce) * (M_PI/2)) + v_min;
|
||||||
|
result.velocity.x = fabs(cos(fabs(0.0 - odom_alpha))) * vr / cos(std::min(M_PI/3, fabs(odom_alpha)));
|
||||||
|
// ROS_INFO("d_rg %f d_reduce %f V = %f %f", d_rg, d_reduce,velocity.x, vr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace mkt_algorithm
|
||||||
|
|
||||||
|
PLUGINLIB_EXPORT_CLASS(mkt_algorithm::GoStraight, score_algorithm::ScoreAlgorithm)
|
||||||
|
|
@ -0,0 +1,641 @@
|
||||||
|
#include <mkt_algorithm/bicycle.h>
|
||||||
|
#include <pluginlib/class_list_macros.h>
|
||||||
|
#include <nav_grid/coordinate_conversion.h>
|
||||||
|
#include <nav_2d_utils/parameters.h>
|
||||||
|
#include <nav_2d_utils/conversions.h>
|
||||||
|
#include <nav_2d_utils/tf_help.h>
|
||||||
|
#include <nav_2d_utils/path_ops.h>
|
||||||
|
#include <angles/angles.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
void Bicycle::initialize(const ros::NodeHandle& nh, std::string name, TFListenerPtr tf, nav_core2::Costmap::Ptr costmap)
|
||||||
|
{
|
||||||
|
nh_priv_ = ros::NodeHandle(nh, name);
|
||||||
|
nh_ = ros::NodeHandle("~");
|
||||||
|
name_ = name;
|
||||||
|
tf_ = tf;
|
||||||
|
costmap_ros_ = costmap_ros;
|
||||||
|
last_actuator_update_ = ros::Time(0);
|
||||||
|
|
||||||
|
nh_priv_.param("xy_local_goal_tolerance", xy_local_goal_tolerance_, 0.5);
|
||||||
|
nh_priv_.param("xy_local_goal_tolerance_offset", xy_local_goal_tolerance_offset_, 0.5);
|
||||||
|
nh_priv_.param("angle_threshold", angle_threshold_, M_PI/8);
|
||||||
|
nh_priv_.param("index_samples", index_samples_, 0);
|
||||||
|
nh_priv_.param("filter", is_filter_, false);
|
||||||
|
|
||||||
|
steering_fix_wheel_distance_x_ = nav_2d_utils::searchAndGetParam(nh_priv_, "steering_fix_wheel_distance_x", 1.1);
|
||||||
|
steering_fix_wheel_distance_y_ = nav_2d_utils::searchAndGetParam(nh_priv_, "steering_fix_wheel_distance_y", 0.);
|
||||||
|
xy_goal_tolerance_ = nav_2d_utils::searchAndGetParam(nh_priv_, "xy_goal_tolerance", 0.1);
|
||||||
|
acc_lim_theta_ = nav_2d_utils::searchAndGetParam(nh_priv_, "acc_lim_theta", 0.1);
|
||||||
|
decel_lim_theta_ = nav_2d_utils::searchAndGetParam(nh_priv_, "decel_lim_theta", 0.1);
|
||||||
|
controller_frequency_param_name_ = nav_2d_utils::searchAndGetParam(nh_priv_, "controller_frequency", 10);
|
||||||
|
if(controller_frequency_param_name_ <= 0.0)
|
||||||
|
{
|
||||||
|
ROS_WARN("controller_frequency is not setting lower 0.0 so will set to 1.0");
|
||||||
|
controller_frequency_param_name_ = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
reached_intermediate_goals_pub_ = nh_.advertise<geometry_msgs::PoseArray>("reached_intermediate_goals", 1);
|
||||||
|
current_goal_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("current_goal", 1);
|
||||||
|
closet_robot_goal_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("closet_robot_goal", 1);
|
||||||
|
cmd_raw_pub_ = nh_.advertise<geometry_msgs::Twist>("cmd_raw", 1);
|
||||||
|
x_direction_ = y_direction_= theta_direction_ = 0;
|
||||||
|
|
||||||
|
// kalman
|
||||||
|
int n = 3; // Number of states
|
||||||
|
int m = 1; // Number of measurements
|
||||||
|
double dt = 1.0/controller_frequency_param_name_; // Time step
|
||||||
|
// ROS_INFO("controller_frequency_param_name %f", controller_frequency_param_name);
|
||||||
|
Eigen::MatrixXd A(n, n); // System dynamics matrix
|
||||||
|
Eigen::MatrixXd C(m, n); // Output matrix
|
||||||
|
Eigen::MatrixXd Q(n, n); // Process noise covariance
|
||||||
|
Eigen::MatrixXd R(m, m); // Measurement noise covariance
|
||||||
|
Eigen::MatrixXd P(n, n); // Estimate error covariance
|
||||||
|
|
||||||
|
// Discrete LTI projectile motion, measuring position only
|
||||||
|
A << 1, dt, 0, 0, 1, dt, 0, 0, 1;
|
||||||
|
C << 1, 0, 0;
|
||||||
|
|
||||||
|
// Reasonable covariance matrices
|
||||||
|
double q = 0.1;
|
||||||
|
double r = 0.6;
|
||||||
|
double p = 0.2;
|
||||||
|
Q << q, q, 0.0, q, q, 0.0, 0.0, 0.0, 0.0;
|
||||||
|
R << r;
|
||||||
|
P << p, p, p, p, 10.0, 1, p, 1, 10.0;
|
||||||
|
|
||||||
|
// Construct the filter
|
||||||
|
kf_ = boost::make_shared<KalmanFilter>(dt,A, C, Q, R, P);
|
||||||
|
// Best guess of initial states
|
||||||
|
Eigen::VectorXd x0(n);
|
||||||
|
x0 << 0.0, 0.0, 0.0;
|
||||||
|
kf_->init(ros::Time::now().toSec(), x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bicycle::reset()
|
||||||
|
{
|
||||||
|
reached_intermediate_goals_.clear();
|
||||||
|
start_index_saved_vt_.clear();
|
||||||
|
start_index_saved_ = 0;
|
||||||
|
sub_goal_index_saved_ = 0;
|
||||||
|
sub_start_index_saved_ = 0;
|
||||||
|
x_direction_ = y_direction_= theta_direction_ = 0;
|
||||||
|
follow_step_path_ = false;
|
||||||
|
last_actuator_update_ = ros::Time(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bicycle::prepare( const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const geometry_msgs::Pose2D& goal, const nav_2d_msgs::Path2D& global_plan,
|
||||||
|
double& x_direction, double& y_direction, double& theta_direction)
|
||||||
|
{
|
||||||
|
nh_priv_.param("xy_local_goal_tolerance", xy_local_goal_tolerance_, 0.5);
|
||||||
|
nh_priv_.param("xy_local_goal_tolerance_offset", xy_local_goal_tolerance_offset_, 0.5);
|
||||||
|
nh_priv_.param("angle_threshold", angle_threshold_, M_PI/8);
|
||||||
|
nh_priv_.param("index_samples", index_samples_, 0);
|
||||||
|
nh_priv_.param("distance_rg", distance_rg_, 0.1);
|
||||||
|
nh_priv_.param("k_ld", k_ld_, 1.0);
|
||||||
|
nh_priv_.param("k_d_reduce", k_d_reduce_, 1.0);
|
||||||
|
nh_priv_.param("ld_min", ld_min_, 0.2);
|
||||||
|
nh_priv_.param("ld_max", ld_max_, 1.1);
|
||||||
|
nh_priv_.param("follow_step_path", follow_step_path_, false);
|
||||||
|
|
||||||
|
// ROS_INFO("%f %f %f %d", xy_local_goal_tolerance_, xy_local_goal_tolerance_offset_, angle_threshold_, index_samples_);
|
||||||
|
frame_id_path_ = global_plan.header.frame_id;
|
||||||
|
goal_ = goal;
|
||||||
|
global_plan_ = global_plan;
|
||||||
|
double rb_direction;
|
||||||
|
if(!getGoalPose(pose, velocity,global_plan, sub_goal_, rb_direction))
|
||||||
|
{
|
||||||
|
ROS_ERROR("getGoalPose Failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
x_direction_= fabs(rb_direction)/rb_direction;
|
||||||
|
x_direction = x_direction_;
|
||||||
|
y_direction = y_direction_ = 0;
|
||||||
|
theta_direction = theta_direction_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav_2d_msgs::Twist2DStamped Bicycle::calculator(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D velocity)
|
||||||
|
{
|
||||||
|
nav_2d_msgs::Twist2DStamped result;
|
||||||
|
result.header.stamp = ros::Time::now();
|
||||||
|
|
||||||
|
geometry_msgs::Pose2D steer_to_baselink_pose;
|
||||||
|
|
||||||
|
if(!getPose("steer_link", "base_link", steer_to_baselink_pose))
|
||||||
|
return result;
|
||||||
|
double actual_phi_steer = steer_to_baselink_pose.theta;
|
||||||
|
|
||||||
|
const double L = sqrt(pow(steering_fix_wheel_distance_x_, 2) + pow(steering_fix_wheel_distance_y_, 2));
|
||||||
|
const double delta_x = sub_goal_.x - pose.x;
|
||||||
|
const double delta_y = sub_goal_.y - pose.y;
|
||||||
|
const double d_rg = sqrt(pow(delta_x, 2) + pow(delta_y, 2));
|
||||||
|
|
||||||
|
// Van toc robot
|
||||||
|
double d_reduce = std::min(std::max(fabs(velocity.x) * k_d_reduce_, 0.6), 3.0);
|
||||||
|
double v_min = 0.05 * velocity.x / (fabs(velocity.x) + 1e-9);
|
||||||
|
double vr = d_rg > d_reduce? velocity.x : (velocity.x - v_min)*sin((d_rg / d_reduce) * (M_PI/2)) + v_min;
|
||||||
|
|
||||||
|
// Góc lái của bánh lái là: α(t)
|
||||||
|
double alpha = atan2(delta_y,delta_x) - pose.theta;
|
||||||
|
double ld = std::min(std::max(fabs(velocity.x)*k_ld_, ld_min_), ld_max_);
|
||||||
|
// double ld = std::min(std::max(d_rg*k_ld_, ld_min_), ld_max_);
|
||||||
|
|
||||||
|
double phi_steer = atan2(2 * L * sin(alpha), ld);
|
||||||
|
if(d_rg <= distance_rg_ && global_plan_.poses.size() > 1)
|
||||||
|
{
|
||||||
|
const double d_x = goal_.x - sub_goal_.x;
|
||||||
|
const double d_y = goal_.y - sub_goal_.y;
|
||||||
|
const double dd = sqrt(d_x * d_x + d_y * d_y);
|
||||||
|
const double d_theta = goal_.theta - sub_goal_.theta;
|
||||||
|
if(dd < 1e-5)
|
||||||
|
{
|
||||||
|
geometry_msgs::Pose2D p = global_plan_.poses[global_plan_.poses.size() - 2];
|
||||||
|
alpha = velocity.x / (fabs(velocity.x) + 1e-9)*(p.theta - pose.theta);
|
||||||
|
phi_steer = atan2(2 * L * sin(alpha), 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double alpha_reduce = std::min(std::max(fabs(vr), 0.6), 1.0);
|
||||||
|
double cos_actual_phi_steer = cos( std::min(M_PI/2.3, fabs(actual_phi_steer)));
|
||||||
|
|
||||||
|
// limit W
|
||||||
|
double result_W_max = 0.25;
|
||||||
|
// double result_W_min = 0.13;
|
||||||
|
double result_W = vr * fabs(cos(alpha)) * tan(actual_phi_steer) / L;
|
||||||
|
double V_s = std::max(alpha_reduce, fabs(cos(alpha))) * vr / cos_actual_phi_steer;
|
||||||
|
std::stringstream ss;
|
||||||
|
if(fabs(result_W) > 0.02)
|
||||||
|
{
|
||||||
|
double d_w = fabs(result_W) - fabs(velocity.theta);
|
||||||
|
double a = fabs(velocity.theta) > fabs(result_W) ? fabs(acc_lim_theta_/controller_frequency_param_name_) : fabs(decel_lim_theta_/controller_frequency_param_name_);
|
||||||
|
// ss << d_w << " " << a << " ";
|
||||||
|
double result;
|
||||||
|
if(fabs(d_w) >= a)
|
||||||
|
result = fabs(velocity.theta) + d_w / fabs(d_w + 1e-9) * a;
|
||||||
|
else if (fabs(d_w) < fabs(a))
|
||||||
|
result = fabs(velocity.theta);
|
||||||
|
// ss << result_W << " " << velocity.theta << " ";
|
||||||
|
result_W = result_W / (fabs(result_W) + 1e-9) * result;
|
||||||
|
// ss << result_W << " ";
|
||||||
|
// ROS_INFO_STREAM(ss.str());
|
||||||
|
|
||||||
|
double d_v = fabs(result_W * L / tan(actual_phi_steer)) - fabs(vr);
|
||||||
|
if(fabs(d_v) >= a)
|
||||||
|
result = velocity.x / (fabs(velocity.x) + 1e-9)* (fabs(vr) + d_v / fabs(d_v + 1e-9) * a);
|
||||||
|
else if (fabs(d_v) < fabs(a))
|
||||||
|
result = velocity.x / (fabs(velocity.x) + 1e-9) * fabs(vr);
|
||||||
|
|
||||||
|
V_s = std::max(alpha_reduce, fabs(cos(alpha)))*result/ cos_actual_phi_steer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fabs(result_W) > result_W_max)
|
||||||
|
V_s = ( result_W / (fabs(result_W) + 1e-9) * result_W_max * L / tan(actual_phi_steer)) / cos_actual_phi_steer;
|
||||||
|
|
||||||
|
if(is_filter_)
|
||||||
|
{
|
||||||
|
geometry_msgs::Twist msg;
|
||||||
|
msg.linear.x = result.velocity.x;
|
||||||
|
msg.angular.z = phi_steer;
|
||||||
|
cmd_raw_pub_.publish(msg);
|
||||||
|
|
||||||
|
Eigen::VectorXd y(1);
|
||||||
|
y << phi_steer;
|
||||||
|
ros::Time current_time = ros::Time::now();
|
||||||
|
double dt = ros::Duration(current_time - last_actuator_update_).toSec();
|
||||||
|
last_actuator_update_ = current_time;
|
||||||
|
Eigen::MatrixXd A(3, 3); // System dynamics matrix
|
||||||
|
A << 1, dt, 0, 0, 1, dt, 0, 0, 1;
|
||||||
|
kf_->update(y, dt, A);
|
||||||
|
phi_steer = kf_->state().transpose()[0];
|
||||||
|
}
|
||||||
|
theta_direction_ = phi_steer !=0 ? phi_steer/(fabs(phi_steer) + 1e-9) * velocity.x/((fabs(velocity.x) + 1e-9)) : 0;
|
||||||
|
|
||||||
|
result.velocity.theta = phi_steer;
|
||||||
|
result.velocity.x = fabs(cos(phi_steer - actual_phi_steer)) * V_s;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Bicycle::getGoalIndex(const geometry_msgs::Pose2D &robot_pose, const std::vector<geometry_msgs::Pose2D> &plan,
|
||||||
|
const double distance, unsigned int start_index, unsigned int last_valid_index) const
|
||||||
|
{
|
||||||
|
if (start_index >= last_valid_index)
|
||||||
|
return last_valid_index;
|
||||||
|
|
||||||
|
unsigned int goal_index = start_index;
|
||||||
|
const double start_direction_x = plan[start_index + 1].x - plan[start_index].x;
|
||||||
|
const double start_direction_y = plan[start_index + 1].y - plan[start_index].y;
|
||||||
|
if (fabs(start_direction_x) > 1e-9 || fabs(start_direction_y) > 1e-9) { // make sure that atan2 is defined
|
||||||
|
double start_angle = atan2(start_direction_y, start_direction_x);
|
||||||
|
double S = sqrt(pow(start_direction_x, 2) + pow(start_direction_y, 2));
|
||||||
|
// double angle_threshold = 0.0;
|
||||||
|
for (unsigned int i = start_index + 1; i <= last_valid_index; ++i)
|
||||||
|
{
|
||||||
|
const double current_direction_x = plan[i].x - plan[i - 1].x;
|
||||||
|
const double current_direction_y = plan[i].y - plan[i - 1].y;
|
||||||
|
const double dd = sqrt(pow(current_direction_x, 2) + pow(current_direction_y, 2));
|
||||||
|
S += dd;
|
||||||
|
if (fabs(current_direction_x) > 1e-9 || fabs(current_direction_y) > 1e-9)
|
||||||
|
{
|
||||||
|
double current_angle = atan2(current_direction_y, current_direction_x);
|
||||||
|
if(fabs(remainder(start_angle - current_angle, 2 * M_PI)) >= angle_threshold_ || S >= distance)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
goal_index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return goal_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bicycle::getGoalPose(const geometry_msgs::Pose2D &robot_pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const nav_2d_msgs::Path2D &global_plan, geometry_msgs::Pose2D &sub_goal,
|
||||||
|
double &target_direction)
|
||||||
|
{
|
||||||
|
const nav_core2::Costmap &costmap = *costmap_;
|
||||||
|
const nav_grid::NavGridInfo &info = costmap.getInfo();
|
||||||
|
|
||||||
|
if (global_plan.poses.empty())
|
||||||
|
{
|
||||||
|
ROS_ERROR_NAMED("PathProgressCritic", "The global plan was empty.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Chuyển đổi dữ liệu kế hoạch đường đi 'nav_2d_msgs::Path2D' sang 'std::vector<geometry_msgs::Pose2D>'
|
||||||
|
std::vector<geometry_msgs::Pose2D> plan = global_plan.poses;
|
||||||
|
|
||||||
|
std::vector<unsigned int> index_s;
|
||||||
|
if(!findSubGoalIndex(plan, index_s))
|
||||||
|
{
|
||||||
|
ROS_ERROR_NAMED("PathProgressCritic", "Can not find SubGoal Index");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// std::stringstream ss;
|
||||||
|
// for(auto i : index_s) ss << i << " ";
|
||||||
|
// ROS_INFO_STREAM(ss.str());
|
||||||
|
// }
|
||||||
|
|
||||||
|
unsigned int sub_goal_index = sub_goal_index_saved_;
|
||||||
|
unsigned int sub_start_index = sub_start_index_saved_;
|
||||||
|
if(index_s.empty() || index_s.size() < 1)
|
||||||
|
{
|
||||||
|
sub_goal_index = (unsigned int)plan.size();
|
||||||
|
sub_goal_index_saved_ = sub_goal_index;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(index_s.front() > sub_goal_index_saved_)
|
||||||
|
{
|
||||||
|
sub_goal_index = (unsigned int)(index_s.front()) + 1;
|
||||||
|
sub_goal_index_saved_ = sub_goal_index;
|
||||||
|
}
|
||||||
|
if(index_s.size() > 1)
|
||||||
|
{
|
||||||
|
for(int i = 1; i < index_s.size(); ++i)
|
||||||
|
{
|
||||||
|
// double tolerance = line_generator->calculateTolerance(robot_pose, plan[index_s[i-1]]);
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(robot_pose, plan[index_s[i-1]]));
|
||||||
|
// double dx = plan[index_s[i-1]].x - robot_pose.x;
|
||||||
|
// double dy = plan[index_s[i-1]].y - robot_pose.y;
|
||||||
|
// if(std::abs(std::sqrt(dx * dx + dy * dy)) <= xy_goal_tolerance_ + 0.15)
|
||||||
|
if (distance < xy_local_goal_tolerance_offset_)
|
||||||
|
{
|
||||||
|
if(index_s[i] > sub_goal_index_saved_)
|
||||||
|
{
|
||||||
|
if(i < index_s.size()-1)
|
||||||
|
{
|
||||||
|
sub_goal_index = index_s[i] + 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sub_goal_index = (unsigned int)plan.size();
|
||||||
|
}
|
||||||
|
if(follow_step_path_)
|
||||||
|
{
|
||||||
|
sub_start_index = index_s[i-1];
|
||||||
|
sub_start_index_saved_ = sub_start_index;
|
||||||
|
}
|
||||||
|
ROS_INFO("Tang nac path tu %d den %d boi khoang cach", sub_goal_index_saved_, sub_goal_index);
|
||||||
|
// ROS_WARN("i %d follow_step_path_ = %x start = %d sub_goal = %d size = %d", i, follow_step_path_, sub_start_index, sub_goal_index, (unsigned int)plan.size());
|
||||||
|
sub_goal_index_saved_ = sub_goal_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(plan[sub_goal_index], robot_pose));
|
||||||
|
if(distance <= xy_local_goal_tolerance_ )
|
||||||
|
{
|
||||||
|
sub_goal_index = (unsigned int)plan.size();
|
||||||
|
sub_goal_index_saved_ = sub_goal_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the "start pose", i.e. the pose on the plan closest to the robot that is also on the local map
|
||||||
|
// Tìm điểm pose bắt đầu trên kế hoạch đường đi gần nhất với robot đồng thời có tồn tại trong local map
|
||||||
|
unsigned int start_index = 0; // số vị trí pose trong kế hoạch đường đi
|
||||||
|
double distance_to_start = std::numeric_limits<double>::infinity(); // Xét giá trị là vô cùng oo
|
||||||
|
bool started_path = false;
|
||||||
|
// for (unsigned int i = 0; i < plan.size(); i++)
|
||||||
|
// ROS_INFO_THROTTLE(1.0, "follow_step_path_ = %x start = %d sub_goal = %d size = %d", follow_step_path_, sub_start_index, sub_goal_index, (unsigned int)plan.size());
|
||||||
|
for (unsigned int i = sub_start_index; i < sub_goal_index; i++)
|
||||||
|
{
|
||||||
|
|
||||||
|
// double g_x = plan[i].x;
|
||||||
|
// double g_y = plan[i].y;
|
||||||
|
// unsigned int map_x, map_y;
|
||||||
|
// if (worldToGridBounded(info, g_x, g_y, map_x, map_y) // chuyển tọa độ từ đơn vị mét sang pixel
|
||||||
|
// && costmap(map_x, map_y) != nav_core2::Costmap::NO_INFORMATION)
|
||||||
|
// {
|
||||||
|
// Still on the costmap. Continue.
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(plan[i], robot_pose)); // Tính khoảng cách từ vị trí của robot đến pose đang xét
|
||||||
|
if (distance_to_start > distance)
|
||||||
|
{
|
||||||
|
start_index = i;
|
||||||
|
distance_to_start = distance;
|
||||||
|
started_path = true;
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// else if (started_path)
|
||||||
|
// {
|
||||||
|
// // Plan is going away from the robot again. It's possible that it comes back and we would find a pose that's
|
||||||
|
// // even closer to the robot, but then we would skip over parts of the plan.
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// else, we have not yet found a point on the costmap, so we just continue
|
||||||
|
}
|
||||||
|
// Nếu khồng tìm được điểm gần với robot nhất thì trả về false
|
||||||
|
if (!started_path)
|
||||||
|
{
|
||||||
|
ROS_ERROR_NAMED("PathProgressCritic", "None of the points of the global plan were in the local costmap.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the "last valid pose", i.e. the last pose on the plan after the start pose that is still on the local map
|
||||||
|
// Tìm điểm pose cuôi cùng sau điểm pose bắt đầu và có tồn tại trong local map
|
||||||
|
if(start_index < 1) start_index == 1;
|
||||||
|
// unsigned int last_valid_index = plan.size() - 1;
|
||||||
|
unsigned int last_valid_index = sub_goal_index - 1;
|
||||||
|
// for (unsigned int i = start_index + 1; i < sub_goal_index; i++)
|
||||||
|
// {
|
||||||
|
// double g_x = plan[i].x;
|
||||||
|
// double g_y = plan[i].y;
|
||||||
|
// unsigned int map_x, map_y;
|
||||||
|
// if (worldToGridBounded(info, g_x, g_y, map_x, map_y) && costmap(map_x, map_y) != nav_core2::Costmap::NO_INFORMATION)
|
||||||
|
// {
|
||||||
|
// // Still on the costmap. Continue.
|
||||||
|
// last_valid_index = i;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// // Off the costmap after being on the costmap.
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// find the "goal pose" by walking along the plan as long as each step leads far enough away from the starting point,
|
||||||
|
// i.e. is within angle_threshold_ of the starting direction.
|
||||||
|
// Tìm điểm mục tiêu chạy từ điểm start pose đến last valid pose dọc thep plan
|
||||||
|
|
||||||
|
unsigned int goal_index = start_index;
|
||||||
|
ros::Rate r(30);
|
||||||
|
while (goal_index < last_valid_index && ros::ok())
|
||||||
|
{
|
||||||
|
// Tìm kiếm vị trí điểm mục tiêu phù hợp
|
||||||
|
double S;
|
||||||
|
if(velocity.x > 0) S = std::min(4.0, std::max(0.9, fabs(velocity.x)*k_d_reduce_));
|
||||||
|
// else if(velocity.x < 0) S = 0.5;
|
||||||
|
else if(velocity.x < 0) S = std::min(0.7, std::max(0.5, fabs(velocity.x)*k_d_reduce_));
|
||||||
|
else S = 0.5;
|
||||||
|
goal_index = getGoalIndex(robot_pose, plan, S, start_index, last_valid_index);
|
||||||
|
|
||||||
|
// check if goal already reached
|
||||||
|
bool goal_already_reached = false;
|
||||||
|
|
||||||
|
geometry_msgs::PoseArray poseArrayMsg;
|
||||||
|
poseArrayMsg.header.stamp = ros::Time::now();
|
||||||
|
poseArrayMsg.header.frame_id = frame_id_path_;
|
||||||
|
// std::stringstream ss;
|
||||||
|
for (auto &reached_intermediate_goal : reached_intermediate_goals_)
|
||||||
|
{
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(reached_intermediate_goal, plan[goal_index]));
|
||||||
|
// ss << distance << " ";
|
||||||
|
geometry_msgs::Pose pose = nav_2d_utils::pose2DToPose(reached_intermediate_goal);
|
||||||
|
poseArrayMsg.poses.push_back(pose);
|
||||||
|
}
|
||||||
|
reached_intermediate_goals_pub_.publish(poseArrayMsg);
|
||||||
|
// if(!reached_intermediate_goals_.empty())
|
||||||
|
// {
|
||||||
|
// ROS_INFO_STREAM(ss.str());
|
||||||
|
// }
|
||||||
|
|
||||||
|
for (auto &reached_intermediate_goal : reached_intermediate_goals_)
|
||||||
|
{
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(reached_intermediate_goal, plan[goal_index]));
|
||||||
|
if (distance < xy_local_goal_tolerance_)
|
||||||
|
{
|
||||||
|
goal_already_reached = true;
|
||||||
|
// choose a new start_index by walking along the plan until we're outside xy_local_goal_tolerance_ and try again
|
||||||
|
// (start_index is now > goal_index)
|
||||||
|
for (start_index = goal_index; start_index <= last_valid_index; ++start_index)
|
||||||
|
{
|
||||||
|
distance = nav_2d_utils::poseDistance(reached_intermediate_goal, plan[start_index]);
|
||||||
|
if ( distance >= xy_local_goal_tolerance_offset_)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// start_index_saved_ = start_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//try hiep
|
||||||
|
unsigned num = 0;
|
||||||
|
start_index_saved_vt_.insert(start_index_saved_vt_.begin(),start_index);
|
||||||
|
if(start_index_saved_vt_.size() > index_samples_) start_index_saved_vt_.pop_back();
|
||||||
|
std::stringstream ss;
|
||||||
|
for(int i = 0; i < start_index_saved_vt_.size() - 1; i++)
|
||||||
|
{
|
||||||
|
double edge = 0;
|
||||||
|
if(start_index_saved_vt_[i] != start_index_saved_vt_[i+1])
|
||||||
|
edge = journey(plan, start_index_saved_vt_[i], start_index_saved_vt_[i+1]);
|
||||||
|
if(edge < xy_local_goal_tolerance_) num++;
|
||||||
|
ss << start_index_saved_vt_[i] << " ";
|
||||||
|
}
|
||||||
|
// ss << start_index << " ";
|
||||||
|
|
||||||
|
if(num < index_samples_ - 1 && !start_index_saved_vt_.empty())
|
||||||
|
{
|
||||||
|
auto max_iter = *(std::max_element(start_index_saved_vt_.begin(), start_index_saved_vt_.end()));
|
||||||
|
start_index_saved_ = start_index_saved_ >= max_iter? start_index_saved_ : max_iter;
|
||||||
|
double S1 = journey(plan, start_index, plan.size()-1 );
|
||||||
|
double S2 = journey(plan, start_index_saved_, plan.size()-1 );
|
||||||
|
|
||||||
|
// ROS_INFO_STREAM(ss.str());
|
||||||
|
if(S2 - S1 < -fabs(xy_local_goal_tolerance_))
|
||||||
|
{
|
||||||
|
start_index = start_index_saved_;
|
||||||
|
}
|
||||||
|
else start_index_saved_ = start_index;
|
||||||
|
// ROS_INFO(" %d %d %f %d %f %f", max_iter, start_index, S1, start_index_saved_, S2, S2 - S1);
|
||||||
|
}
|
||||||
|
else start_index_saved_ = start_index;
|
||||||
|
|
||||||
|
if(start_index >= goal_index) goal_index = getGoalIndex(robot_pose, plan, S,start_index, last_valid_index);
|
||||||
|
|
||||||
|
if (!goal_already_reached)
|
||||||
|
{
|
||||||
|
// new goal not in reached_intermediate_goals_
|
||||||
|
double distance = fabs(nav_2d_utils::poseDistance(plan[goal_index], plan[start_index]));
|
||||||
|
if (distance < xy_local_goal_tolerance_)
|
||||||
|
{
|
||||||
|
// ROS_INFO("goal_index %d distance %f", goal_index, distance);
|
||||||
|
// the robot has currently reached the goal
|
||||||
|
reached_intermediate_goals_.push_back(plan[goal_index]);
|
||||||
|
ROS_DEBUG_NAMED("PathProgressCritic", "Number of reached_intermediate goals: %zu", reached_intermediate_goals_.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we've found a new goal!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r.sleep();
|
||||||
|
ros::spinOnce();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_index > goal_index)
|
||||||
|
start_index = goal_index;
|
||||||
|
ROS_ASSERT(goal_index <= last_valid_index);
|
||||||
|
if((unsigned int)plan.size() == 2 && !plan.empty())
|
||||||
|
{
|
||||||
|
start_index = 0;
|
||||||
|
goal_index = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tham chiếu lại đối số đầu vao
|
||||||
|
sub_goal = plan[goal_index];
|
||||||
|
if(goal_index > 0) rev_sub_goal_ = plan[goal_index - 1];
|
||||||
|
else rev_sub_goal_ = plan[start_index];
|
||||||
|
|
||||||
|
target_direction = x_direction_;
|
||||||
|
if(goal_index > 0 && (unsigned int)plan.size() > 1)
|
||||||
|
{
|
||||||
|
if(goal_index < (unsigned int)(plan.size() -1))
|
||||||
|
{
|
||||||
|
const geometry_msgs::Pose2D p1 = plan[start_index];
|
||||||
|
int index;
|
||||||
|
for(index = start_index+1; index < goal_index; index++)
|
||||||
|
{
|
||||||
|
geometry_msgs::Pose2D pose = plan[index];
|
||||||
|
if(nav_2d_utils::poseDistance(p1, pose) > xy_goal_tolerance_) break;
|
||||||
|
}
|
||||||
|
const geometry_msgs::Pose2D p2 = plan[index];
|
||||||
|
if(fabs(p2.y - p1.y) > 1e-9 || fabs(p2.x - p1.x) > 1e-9)
|
||||||
|
{
|
||||||
|
const double path_angle = atan2(p2.y - p1.y, p2.x - p1.x);
|
||||||
|
const double dir_path = cos(fabs(path_angle - p2.theta));
|
||||||
|
if(fabs(dir_path) > 1e-9)
|
||||||
|
target_direction = dir_path;
|
||||||
|
// ROS_INFO("%f %f %f %f", p1.x ,p1.y, p2.x ,p2.y);
|
||||||
|
// ROS_INFO("%d %0.2f %0.2f %0.2f", goal_index, path_angle, p2.theta, target_direction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const double rb_direction_x = sub_goal.x - robot_pose.x;
|
||||||
|
const double rb_direction_y = sub_goal.y - robot_pose.y;
|
||||||
|
const double rb_angle = atan2(rb_direction_y, rb_direction_x);
|
||||||
|
double dir_rg = cos(rb_angle - robot_pose.theta);
|
||||||
|
const double angle_threshold = 0.6;
|
||||||
|
if(fabs(dir_rg) > angle_threshold)
|
||||||
|
target_direction = dir_rg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish start_index
|
||||||
|
geometry_msgs::PoseStamped pose_st = nav_2d_utils::pose2DToPoseStamped(plan[start_index], global_plan.header.frame_id, ros::Time::now());
|
||||||
|
closet_robot_goal_pub_.publish(pose_st);
|
||||||
|
|
||||||
|
// Publish goal_index
|
||||||
|
geometry_msgs::PoseStamped pose_g = nav_2d_utils::pose2DToPoseStamped(plan[goal_index], global_plan.header.frame_id, ros::Time::now());
|
||||||
|
current_goal_pub_.publish(pose_g);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bicycle::findSubGoalIndex(const std::vector<geometry_msgs::Pose2D> &plan, std::vector<unsigned int> &index_s)
|
||||||
|
{
|
||||||
|
if (plan.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
double x_direction_saved = 0.0;
|
||||||
|
geometry_msgs::PoseArray poseArrayMsg;
|
||||||
|
poseArrayMsg.header.stamp = ros::Time::now();
|
||||||
|
poseArrayMsg.header.frame_id = frame_id_path_;
|
||||||
|
|
||||||
|
for (unsigned int i = 1; i < (unsigned int)plan.size(); i++)
|
||||||
|
{
|
||||||
|
geometry_msgs::Pose2D p1 = plan[i];
|
||||||
|
geometry_msgs::Pose2D p2 = plan[i+1];
|
||||||
|
// geometry_msgs::Pose2D p3 = plan[i+2];
|
||||||
|
double angle1;
|
||||||
|
if(fabs(p2.y - p1.y) > 1e-9 || fabs(p2.x - p1.x) > 1e-9)
|
||||||
|
angle1 = atan2(p2.y - p1.y, p2.x - p1.x);
|
||||||
|
else continue;
|
||||||
|
// const double angle2 = atan2(p3.y - p2.y, p3.x - p2.x);
|
||||||
|
const double target_direction = cos(fabs(angle1 - p2.theta));
|
||||||
|
|
||||||
|
if(target_direction * x_direction_saved < 0.0)
|
||||||
|
{
|
||||||
|
index_s.push_back(i);
|
||||||
|
geometry_msgs::Pose pose = nav_2d_utils::pose2DToPose(plan[i]);
|
||||||
|
poseArrayMsg.poses.push_back(pose);
|
||||||
|
}
|
||||||
|
x_direction_saved = target_direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index_s.empty())
|
||||||
|
index_s.push_back((unsigned int)plan.size() - 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(index_s.back() < (unsigned int)plan.size() - 1)
|
||||||
|
index_s.push_back((unsigned int)plan.size() - 1);
|
||||||
|
}
|
||||||
|
reached_intermediate_goals_pub_.publish(poseArrayMsg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Bicycle::journey(const std::vector<geometry_msgs::Pose2D> &plan, const unsigned int start_index, const unsigned int last_valid_index) const
|
||||||
|
{
|
||||||
|
double S = 0;
|
||||||
|
if(last_valid_index - start_index > 1)
|
||||||
|
{
|
||||||
|
for(int i= start_index; i < last_valid_index; i++)
|
||||||
|
{
|
||||||
|
S += nav_2d_utils::poseDistance(plan[i], plan[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace mkt_algorithm
|
||||||
|
|
||||||
|
PLUGINLIB_EXPORT_CLASS(mkt_algorithm::Bicycle, score_algorithm::ScoreAlgorithm)
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
#include <mkt_algorithm/rotate_to_goal.h>
|
||||||
|
#include <nav_2d_utils/parameters.h>
|
||||||
|
#include <pluginlib/class_list_macros.h>
|
||||||
|
#include <angles/angles.h>
|
||||||
|
|
||||||
|
namespace mkt_algorithm
|
||||||
|
{
|
||||||
|
|
||||||
|
void RotateToGoal::initialize(const ros::NodeHandle & nh, std::string name, TFListenerPtr tf, nav_core2::Costmap::Ptr costmap)
|
||||||
|
{
|
||||||
|
nh_ = ros::NodeHandle(nh, name);
|
||||||
|
name_ = name;
|
||||||
|
tf_ = tf;
|
||||||
|
costmap_ros_ = costmap_ros;
|
||||||
|
|
||||||
|
steering_fix_wheel_distance_x_ = nav_2d_utils::searchAndGetParam(nh_, "steering_fix_wheel_distance_x", 1.1);
|
||||||
|
steering_fix_wheel_distance_y_ = nav_2d_utils::searchAndGetParam(nh_, "steering_fix_wheel_distance_y", 0.);
|
||||||
|
nh_.param("velocity_rotate_min", velocity_rotate_min_, 0.1);
|
||||||
|
nh_.param("velocity_rotate_max", velocity_rotate_max_, 0.6);
|
||||||
|
nh_.param("angle_pass_rotate", angle_threshold_, 0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotateToGoal::reset()
|
||||||
|
{
|
||||||
|
time_last_cmd_ = ros::Time::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RotateToGoal::prepare( const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D& velocity,
|
||||||
|
const geometry_msgs::Pose2D& goal, const nav_2d_msgs::Path2D& global_plan,
|
||||||
|
double& x_direction, double& y_direction, double& theta_direction)
|
||||||
|
{
|
||||||
|
goal_ = goal;
|
||||||
|
double angle = angles::shortest_angular_distance(pose.theta, goal_.theta);
|
||||||
|
|
||||||
|
if(angle > 0) current_direction_ = 1;
|
||||||
|
else if(angle < 0) current_direction_ = -1;
|
||||||
|
x_direction = y_direction = theta_direction = current_direction_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav_2d_msgs::Twist2DStamped RotateToGoal::calculator(const geometry_msgs::Pose2D& pose, const nav_2d_msgs::Twist2D velocity)
|
||||||
|
{
|
||||||
|
nav_2d_msgs::Twist2DStamped result;
|
||||||
|
result.header.stamp = ros::Time::now();
|
||||||
|
|
||||||
|
geometry_msgs::Pose2D steer_to_baselink_pose;
|
||||||
|
|
||||||
|
if(!getPose("steer_link", "base_link", steer_to_baselink_pose))
|
||||||
|
return result;
|
||||||
|
double actual_phi_steer = steer_to_baselink_pose.theta;
|
||||||
|
|
||||||
|
double L = sqrt(pow(steering_fix_wheel_distance_x_, 2) + pow(steering_fix_wheel_distance_y_, 2));
|
||||||
|
|
||||||
|
// ros::Time t = ros::Time::now();
|
||||||
|
// double dt = time_last_cmd_.isZero() ? 0.0 : (t - time_last_cmd_).toSec();
|
||||||
|
// time_last_cmd_ = ros::Time::now();
|
||||||
|
|
||||||
|
double angle_rg = angles::shortest_angular_distance(pose.theta, goal_.theta);
|
||||||
|
double angle_reduce = std::min(std::max(fabs(velocity.theta), 0.15), velocity_rotate_max_);
|
||||||
|
double w_min = velocity.theta / (fabs(velocity.theta) + 1e-9) * velocity_rotate_min_;
|
||||||
|
double w_r = fabs(angle_rg) > angle_reduce? velocity.theta : (velocity.theta - w_min)*sin((fabs(angle_rg) / angle_reduce) * (M_PI/2)) + w_min;
|
||||||
|
|
||||||
|
int direct_rotate = (angle_rg/fabs(angle_rg));
|
||||||
|
double target_phi_steer = direct_rotate * M_PI/2;
|
||||||
|
if( fabs(target_phi_steer - actual_phi_steer) <= angle_threshold_)
|
||||||
|
{
|
||||||
|
double target_v = fabs(w_r * L);
|
||||||
|
result.velocity.x = std::min(velocity_rotate_max_ * L, fabs(target_v));
|
||||||
|
}
|
||||||
|
else result.velocity.x = 0.0;
|
||||||
|
|
||||||
|
result.velocity.theta = target_phi_steer;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace mkt_algorithm
|
||||||
|
|
||||||
|
PLUGINLIB_EXPORT_CLASS(mkt_algorithm::RotateToGoal, score_algorithm::ScoreAlgorithm)
|
||||||
|
|
@ -0,0 +1,243 @@
|
||||||
|
#include <mkt_algorithm/diff/diff_go_straight.h>
|
||||||
|
|
||||||
|
// other
|
||||||
|
// #include <pluginlib/class_list_macros.h>
|
||||||
|
#include <boost/dll/alias.hpp>
|
||||||
|
|
||||||
|
void mkt_algorithm::diff::GoStraight::initialize(
|
||||||
|
ros::NodeHandle &nh, std::string name, TFListenerPtr tf, costmap_2d::Costmap2DROS *costmap_ros, const score_algorithm::TrajectoryGenerator::Ptr &traj)
|
||||||
|
{
|
||||||
|
if (!initialized_)
|
||||||
|
{
|
||||||
|
nh_ = ros::NodeHandle("~/");
|
||||||
|
nh_priv_ = ros::NodeHandle("~/" + name);
|
||||||
|
name_ = name;
|
||||||
|
tf_ = tf;
|
||||||
|
traj_ = traj;
|
||||||
|
costmap_ros_ = costmap_ros;
|
||||||
|
|
||||||
|
this->getParams();
|
||||||
|
// this->initDynamicReconfigure(nh_priv_);
|
||||||
|
nh_.param("publish_topic", enable_publish_, false);
|
||||||
|
nh_.param<double>("min_approach_linear_velocity", min_approach_linear_velocity_, 0.1);
|
||||||
|
|
||||||
|
|
||||||
|
carrot_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("lookahead_point", 1);
|
||||||
|
reached_intermediate_goals_pub_ = nh_.advertise<geometry_msgs::PoseArray>("reached_intermediate_goals", 1);
|
||||||
|
current_goal_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("sub_goal", 1);
|
||||||
|
closet_robot_goal_pub_ = nh_.advertise<geometry_msgs::PoseStamped>("closet_robot_goal", 1);
|
||||||
|
transformed_plan_pub_ = nh_.advertise<nav_msgs::Path>("transformed_plan", 1);
|
||||||
|
compute_plan_pub_ = nh_.advertise<nav_msgs::Path>("compute_plan", 1);
|
||||||
|
|
||||||
|
std::vector<geometry_msgs::Point> footprint = costmap_ros_? costmap_ros_->getRobotFootprint() : std::vector<geometry_msgs::Point>();
|
||||||
|
if (footprint.size() > 1)
|
||||||
|
{
|
||||||
|
double min_length = 1e10;
|
||||||
|
double max_length = 0.0;
|
||||||
|
for (size_t i = 0; i < footprint.size(); ++i)
|
||||||
|
{
|
||||||
|
const geometry_msgs::Point &p1 = footprint[i];
|
||||||
|
const geometry_msgs::Point &p2 = footprint[(i + 1) % footprint.size()]; // wrap around to first point
|
||||||
|
double len = std::hypot(p2.x - p1.x, p2.y - p1.y) / 2.0;
|
||||||
|
if (len > max_length)
|
||||||
|
{
|
||||||
|
max_length = len;
|
||||||
|
}
|
||||||
|
if (len < min_length)
|
||||||
|
{
|
||||||
|
min_length = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this->min_path_distance_ = min_length > 0.1 ? min_length : 0.1;
|
||||||
|
this->max_path_distance_ = max_length > 0.1 ? max_length : 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// kalman
|
||||||
|
last_actuator_update_ = ros::Time::now();
|
||||||
|
n_ = 6; // [x, vx, ax, y, vy, ay, theta, vtheta, atheta]
|
||||||
|
m_ = 2; // measurements: x, y, theta
|
||||||
|
double dt = control_duration_;
|
||||||
|
|
||||||
|
// Khởi tạo ma trận
|
||||||
|
A = Eigen::MatrixXd::Identity(n_, n_);
|
||||||
|
C = Eigen::MatrixXd::Zero(m_, n_);
|
||||||
|
Q = Eigen::MatrixXd::Zero(n_, n_);
|
||||||
|
R = Eigen::MatrixXd::Identity(m_, m_);
|
||||||
|
P = Eigen::MatrixXd::Identity(n_, n_);
|
||||||
|
|
||||||
|
for (int i = 0; i < n_; i += 3)
|
||||||
|
{
|
||||||
|
A(i, i + 1) = dt;
|
||||||
|
A(i, i + 2) = 0.5 * dt * dt;
|
||||||
|
A(i + 1, i + 2) = dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
C(0, 0) = 1;
|
||||||
|
C(1, 3) = 1;
|
||||||
|
Q(2, 2) = 0.1;
|
||||||
|
Q(5, 5) = 0.6;
|
||||||
|
|
||||||
|
R(0, 0) = 0.1;
|
||||||
|
R(1, 1) = 0.2;
|
||||||
|
|
||||||
|
P(3, 3) = 0.4;
|
||||||
|
P(4, 4) = 0.4;
|
||||||
|
P(5, 5) = 0.4;
|
||||||
|
|
||||||
|
kf_ = boost::make_shared<KalmanFilter>(dt, A, C, Q, R, P);
|
||||||
|
Eigen::VectorXd x0(n_);
|
||||||
|
x0 << 0, 0, 0, 0, 0, 0;
|
||||||
|
kf_->init(ros::Time::now().toSec(), x0);
|
||||||
|
|
||||||
|
x_direction_ = y_direction_ = theta_direction_ = 0;
|
||||||
|
initialized_ = true;
|
||||||
|
ROS_INFO("GoStraight Initialized successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mkt_msgs::Trajectory2D mkt_algorithm::diff::GoStraight::calculator(
|
||||||
|
const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity)
|
||||||
|
{
|
||||||
|
mkt_msgs::Trajectory2D result;
|
||||||
|
result.velocity.x = result.velocity.y = result.velocity.theta = 0.0;
|
||||||
|
if (!traj_)
|
||||||
|
return result;
|
||||||
|
if (compute_plan_.poses.size() < 2)
|
||||||
|
{
|
||||||
|
ROS_WARN_THROTTLE(2.0, "Local compute plan is available");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ros::Time current_time = ros::Time::now();
|
||||||
|
double dt = (current_time - last_actuator_update_).toSec();
|
||||||
|
last_actuator_update_ = current_time;
|
||||||
|
|
||||||
|
nav_2d_msgs::Twist2D drive_cmd;
|
||||||
|
double sign_x = x_direction_;
|
||||||
|
|
||||||
|
nav_2d_msgs::Twist2D twist;
|
||||||
|
traj_->startNewIteration(velocity); // Nhận tốc độ hiện tại từ odom
|
||||||
|
ros::Rate r(50);
|
||||||
|
while (ros::ok() && traj_->hasMoreTwists())
|
||||||
|
{
|
||||||
|
twist = traj_->nextTwist();
|
||||||
|
// ROS_INFO("Twist: x: %.2f, y: %.2f, theta: %.2f", twist.x, twist.y, twist.theta);
|
||||||
|
r.sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
drive_cmd.x = sqrt(twist.x * twist.x);
|
||||||
|
nav_2d_msgs::Path2D transformed_plan = transform_plan_;
|
||||||
|
if (transformed_plan.poses.empty())
|
||||||
|
{
|
||||||
|
ROS_WARN("Transformed plan is empty. Cannot determine a local plan.");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enable_publish_)
|
||||||
|
transformed_plan_pub_.publish(nav_2d_utils::pathToPath(transformed_plan));
|
||||||
|
|
||||||
|
// Dynamically adjust look ahead distance based on the speed
|
||||||
|
double lookahead_dist = this->getLookAheadDistance(twist);
|
||||||
|
// Return false if the transformed global plan is empty
|
||||||
|
geometry_msgs::Pose2D front = transform_plan_.poses.size() > 3 ? (*(transform_plan_.poses.begin() + 1)).pose : transform_plan_.poses.front().pose;
|
||||||
|
lookahead_dist += fabs(front.y);
|
||||||
|
|
||||||
|
// Get lookahead point and publish for visualization
|
||||||
|
auto carrot_pose = *getLookAheadPoint(velocity, lookahead_dist, transformed_plan);
|
||||||
|
|
||||||
|
if (enable_publish_)
|
||||||
|
carrot_pub_.publish(this->createCarrotMsg(carrot_pose));
|
||||||
|
|
||||||
|
// Carrot distance squared
|
||||||
|
const double carrot_dist2 =
|
||||||
|
(carrot_pose.pose.x * carrot_pose.pose.x) +
|
||||||
|
(carrot_pose.pose.y * carrot_pose.pose.y);
|
||||||
|
|
||||||
|
// Find curvature of circle (k = 1 / R)
|
||||||
|
double curvature = 0.0;
|
||||||
|
if (carrot_dist2 > 2e-2)
|
||||||
|
{
|
||||||
|
curvature = 2.0 * carrot_pose.pose.y / carrot_dist2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constrain linear velocity
|
||||||
|
this->applyConstraints(
|
||||||
|
0.0, lookahead_dist, curvature, twist,
|
||||||
|
this->costAtPose(pose.pose.x, pose.pose.y),
|
||||||
|
drive_cmd.x, sign_x);
|
||||||
|
|
||||||
|
|
||||||
|
if (std::hypot(carrot_pose.pose.x, carrot_pose.pose.y) > min_journey_squared_)
|
||||||
|
{
|
||||||
|
nav_2d_msgs::Pose2DStamped end = transform_plan_.poses.back();
|
||||||
|
nav_2d_msgs::Pose2DStamped start = transform_plan_.poses[transform_plan_.poses.size() - 2];
|
||||||
|
double dx = end.pose.x - start.pose.x;
|
||||||
|
double dy = end.pose.y - start.pose.y;
|
||||||
|
drive_cmd.theta = atan2(dy, dx);
|
||||||
|
|
||||||
|
//[-π/2, π/2]
|
||||||
|
if (drive_cmd.theta > M_PI / 2)
|
||||||
|
drive_cmd.theta -= M_PI;
|
||||||
|
else if (drive_cmd.theta < -M_PI / 2)
|
||||||
|
drive_cmd.theta += M_PI;
|
||||||
|
|
||||||
|
drive_cmd.theta = std::clamp(drive_cmd.theta, -min_vel_theta_, min_vel_theta_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
drive_cmd.theta = 0.0;
|
||||||
|
|
||||||
|
// populate and return message
|
||||||
|
if (fabs(carrot_pose.pose.x) > 1e-9 || carrot_pose.pose.y > 1e-9)
|
||||||
|
drive_cmd.x *= fabs(cos(std::atan2(carrot_pose.pose.y, carrot_pose.pose.x)));
|
||||||
|
|
||||||
|
double v_max = sign_x > 0 ? traj_->getTwistLinear(true).x : traj_->getTwistLinear(false).x;
|
||||||
|
const double vel_x_reduce = std::min(fabs(v_max), 0.3);
|
||||||
|
double journey_plan = compute_plan_.poses.empty() ? 0 : journey(compute_plan_.poses, 0, compute_plan_.poses.size() - 1);
|
||||||
|
const double scale = fabs(velocity.x) * lookahead_time_ * 0.9;
|
||||||
|
const double min_S = min_lookahead_dist_ + max_path_distance_ + scale, max_S = max_lookahead_dist_ + max_path_distance_ + scale;
|
||||||
|
double d_reduce = std::clamp(journey_plan, min_S, max_S);
|
||||||
|
double d_begin_reduce = std::clamp(d_reduce * 0.2, 0.4, 1.0);
|
||||||
|
double cosine_factor_begin_reduce = 0.5 * (1.0 + cos(M_PI * (1.0 - fabs(journey_plan) / d_begin_reduce)));
|
||||||
|
double v_min =
|
||||||
|
journey_plan > d_begin_reduce ? vel_x_reduce : (vel_x_reduce - min_approach_linear_velocity_) * cosine_factor_begin_reduce + min_approach_linear_velocity_;
|
||||||
|
v_min *= sign_x;
|
||||||
|
double effective_journey = getEffectiveDistance(carrot_pose, journey_plan);
|
||||||
|
double decel_factor = computeDecelerationFactor(effective_journey, d_reduce);
|
||||||
|
journey_plan += max_path_distance_;
|
||||||
|
drive_cmd.x = journey_plan >= d_reduce ? drive_cmd.x : (drive_cmd.x - v_min) * decel_factor + v_min;
|
||||||
|
|
||||||
|
// drive_cmd.x = journey_plan > d_reduce ? drive_cmd.x : (drive_cmd.x - v_min) * sin((journey_plan / d_reduce) * (M_PI / 2)) + v_min;
|
||||||
|
|
||||||
|
Eigen::VectorXd y(2);
|
||||||
|
y << drive_cmd.x, drive_cmd.theta;
|
||||||
|
|
||||||
|
// Cập nhật lại A nếu dt thay đổi
|
||||||
|
for (int i = 0; i < n_; ++i)
|
||||||
|
for (int j = 0; j < n_; ++j)
|
||||||
|
A(i, j) = (i == j ? 1.0 : 0.0);
|
||||||
|
for (int i = 0; i < n_; i += 3)
|
||||||
|
{
|
||||||
|
A(i, i + 1) = dt;
|
||||||
|
A(i, i + 2) = 0.5 * dt * dt;
|
||||||
|
A(i + 1, i + 2) = dt;
|
||||||
|
}
|
||||||
|
kf_->update(y, dt, A);
|
||||||
|
|
||||||
|
if (drive_cmd.x != v_max)
|
||||||
|
{
|
||||||
|
double min = drive_cmd.x < v_max ? drive_cmd.x : v_max;
|
||||||
|
double max = drive_cmd.x > v_max ? drive_cmd.x : v_max;
|
||||||
|
drive_cmd.x = std::clamp(kf_->state()[0], min, max);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drive_cmd.x = std::clamp(kf_->state()[0], v_max, v_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
drive_cmd.x = fabs(drive_cmd.x) >= min_approach_linear_velocity_ ? drive_cmd.x : std::copysign(min_approach_linear_velocity_, sign_x);
|
||||||
|
drive_cmd.theta = kf_->state()[3];
|
||||||
|
result.velocity = drive_cmd;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGINLIB_EXPORT_CLASS(mkt_algorithm::diff::GoStraight, score_algorithm::ScoreAlgorithm)
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,131 @@
|
||||||
|
#include <mkt_algorithm/diff/diff_rotate_to_goal.h>
|
||||||
|
|
||||||
|
// other
|
||||||
|
#include <nav_2d_utils/parameters.h>
|
||||||
|
#include <pluginlib/class_list_macros.h>
|
||||||
|
#include <angles/angles.h>
|
||||||
|
|
||||||
|
void mkt_algorithm::diff::RotateToGoal::initialize(
|
||||||
|
ros::NodeHandle &nh, std::string name, TFListenerPtr tf, costmap_2d::Costmap2DROS *costmap_ros, const score_algorithm::TrajectoryGenerator::Ptr &traj)
|
||||||
|
{
|
||||||
|
if (!initialized_)
|
||||||
|
{
|
||||||
|
nh_ = ros::NodeHandle(nh, name);
|
||||||
|
name_ = name;
|
||||||
|
tf_ = tf;
|
||||||
|
traj_ = traj;
|
||||||
|
costmap_ros_ = costmap_ros;
|
||||||
|
this->getParams();
|
||||||
|
|
||||||
|
x_direction_ = y_direction_ = theta_direction_ = 0;
|
||||||
|
this->initialized_ = true;
|
||||||
|
ROS_INFO("RotateToGoal Initialized successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mkt_algorithm::diff::RotateToGoal::getParams()
|
||||||
|
{
|
||||||
|
robot_base_frame_ = nav_2d_utils::searchAndGetParam(nh_priv_, "robot_base_frame", std::string("base_link"));
|
||||||
|
nh_priv_.param<bool>("avoid_obstacles", avoid_obstacles_, false);
|
||||||
|
nh_priv_.param<double>("xy_local_goal_tolerance", xy_local_goal_tolerance_, 0.5);
|
||||||
|
nh_priv_.param<double>("angle_threshold", angle_threshold_, M_PI / 8);
|
||||||
|
nh_priv_.param<int>("index_samples", index_samples_, 0);
|
||||||
|
nh_priv_.param<bool>("follow_step_path", follow_step_path_, false);
|
||||||
|
|
||||||
|
nh_priv_.param<bool>("use_velocity_scaled_lookahead_dist", use_velocity_scaled_lookahead_dist_, false);
|
||||||
|
nh_priv_.param<double>("lookahead_dist", lookahead_dist_, 0.25);
|
||||||
|
nh_priv_.param<double>("min_lookahead_dist", min_lookahead_dist_, 0.3);
|
||||||
|
nh_priv_.param<double>("max_lookahead_dist", max_lookahead_dist_, 0.9);
|
||||||
|
nh_priv_.param<double>("lookahead_time", lookahead_time_, 1.5);
|
||||||
|
nh_priv_.param<double>("min_journey_squared", min_journey_squared_, std::numeric_limits<double>::infinity());
|
||||||
|
nh_priv_.param<double>("max_journey_squared", max_journey_squared_, std::numeric_limits<double>::infinity());
|
||||||
|
|
||||||
|
nh_priv_.param<bool>("use_rotate_to_heading", use_rotate_to_heading_, false);
|
||||||
|
nh_priv_.param<double>("rotate_to_heading_min_angle", rotate_to_heading_min_angle_, 0.785);
|
||||||
|
|
||||||
|
nh_priv_.param<double>("rot_stopped_velocity", rot_stopped_velocity_, 0.0);
|
||||||
|
nh_priv_.param<double>("trans_stopped_velocity", trans_stopped_velocity_, 0.0);
|
||||||
|
nh_priv_.param<double>("min_approach_linear_velocity", min_approach_linear_velocity_, 0.0);
|
||||||
|
|
||||||
|
// Regulated linear velocity scaling
|
||||||
|
nh_priv_.param<bool>("use_regulated_linear_velocity_scaling", use_regulated_linear_velocity_scaling_, false);
|
||||||
|
nh_priv_.param<double>("regulated_linear_scaling_min_radius", regulated_linear_scaling_min_radius_, 0.9);
|
||||||
|
nh_priv_.param<double>("regulated_linear_scaling_min_speed", regulated_linear_scaling_min_speed_, 0.25);
|
||||||
|
|
||||||
|
// Inflation cost scaling (Limit velocity by proximity to obstacles)
|
||||||
|
nh_priv_.param<bool>("use_cost_regulated_linear_velocity_scaling", use_cost_regulated_linear_velocity_scaling_, true);
|
||||||
|
nh_priv_.param<double>("inflation_cost_scaling_factor", inflation_cost_scaling_factor_, 3.0);
|
||||||
|
nh_priv_.param<double>("cost_scaling_dist", cost_scaling_dist_, 0.6);
|
||||||
|
nh_priv_.param<double>("cost_scaling_gain", cost_scaling_gain_, 1.0);
|
||||||
|
if (inflation_cost_scaling_factor_ <= 0.0)
|
||||||
|
{
|
||||||
|
ROS_WARN("The value inflation_cost_scaling_factor is incorrectly set, "
|
||||||
|
"it should be >0. Disabling cost regulated linear velocity scaling.");
|
||||||
|
use_cost_regulated_linear_velocity_scaling_ = false;
|
||||||
|
}
|
||||||
|
double control_frequency = nav_2d_utils::searchAndGetParam(nh_priv_, "controller_frequency", 10);
|
||||||
|
control_duration_ = 1.0 / control_frequency;
|
||||||
|
if (traj_)
|
||||||
|
{
|
||||||
|
traj_.get()->getNodeHandle().param<double>("max_vel_x", max_vel_x_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("min_vel_x", min_vel_x_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("acc_lim_x", acc_lim_x_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("decel_lim_x", decel_lim_x_, 0.0);
|
||||||
|
|
||||||
|
traj_.get()->getNodeHandle().param<double>("max_vel_y", max_vel_y_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("min_vel_y", min_vel_y_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("acc_lim_y", acc_lim_y_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("decel_lim_y", decel_lim_y_, 0.0);
|
||||||
|
|
||||||
|
traj_.get()->getNodeHandle().param<double>("max_vel_theta", max_vel_theta_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("min_vel_theta", min_vel_theta_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("acc_lim_theta", acc_lim_theta_, 0.0);
|
||||||
|
traj_.get()->getNodeHandle().param<double>("decel_lim_theta", decel_lim_theta_, 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mkt_algorithm::diff::RotateToGoal::reset()
|
||||||
|
{
|
||||||
|
this->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mkt_algorithm::diff::RotateToGoal::prepare(const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity,
|
||||||
|
const nav_2d_msgs::Pose2DStamped &goal, const nav_2d_msgs::Path2D &global_plan,
|
||||||
|
double &x_direction, double &y_direction, double &theta_direction)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!initialized_)
|
||||||
|
{
|
||||||
|
ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this->getParams();
|
||||||
|
global_plan_ = global_plan;
|
||||||
|
|
||||||
|
goal_ = goal;
|
||||||
|
double angle = angles::shortest_angular_distance(pose.pose.theta, goal_.pose.theta);
|
||||||
|
x_direction = y_direction = theta_direction = sign(angle);
|
||||||
|
;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mkt_msgs::Trajectory2D mkt_algorithm::diff::RotateToGoal::calculator(
|
||||||
|
const nav_2d_msgs::Pose2DStamped &pose, const nav_2d_msgs::Twist2D &velocity)
|
||||||
|
{
|
||||||
|
mkt_msgs::Trajectory2D result;
|
||||||
|
nav_2d_msgs::Twist2D drive_cmd;
|
||||||
|
result.velocity.x = result.velocity.y = result.velocity.theta = 0.0;
|
||||||
|
if (!traj_)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
const double dt = control_duration_;
|
||||||
|
double vel_yaw = velocity.theta;
|
||||||
|
double ang_diff = angles::shortest_angular_distance(pose.pose.theta, goal_.pose.theta);
|
||||||
|
rotateToHeading(ang_diff, velocity, drive_cmd);
|
||||||
|
drive_cmd.x = 0.0;
|
||||||
|
drive_cmd.y = 0.0;
|
||||||
|
result.velocity = drive_cmd;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PLUGINLIB_EXPORT_CLASS(mkt_algorithm::diff::RotateToGoal, score_algorithm::ScoreAlgorithm)
|
||||||
56
src/Algorithms/Libraries/mkt_msgs/CMakeLists.txt
Normal file
56
src/Algorithms/Libraries/mkt_msgs/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
# Tên dự án
|
||||||
|
project(mkt_msgs VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Chuẩn C++
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
# Cho phép các project khác include được header của mkt_msgs
|
||||||
|
set(mkt_msgs_INCLUDE_DIRS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(
|
||||||
|
${PROJECT_SOURCE_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tạo INTERFACE library (header-only)
|
||||||
|
add_library(mkt_msgs INTERFACE)
|
||||||
|
target_link_libraries(mkt_msgs INTERFACE nav_2d_msgs geometry_msgs)
|
||||||
|
|
||||||
|
# Set include directories
|
||||||
|
target_include_directories(mkt_msgs
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt header files
|
||||||
|
install(DIRECTORY include/mkt_msgs
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING PATTERN "*.h")
|
||||||
|
|
||||||
|
install(TARGETS mkt_msgs
|
||||||
|
EXPORT mkt_msgs-targets
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
|
# Export targets
|
||||||
|
install(EXPORT mkt_msgs-targets
|
||||||
|
FILE mkt_msgs-targets.cmake
|
||||||
|
DESTINATION lib/cmake/mkt_msgs)
|
||||||
|
|
||||||
|
# In thông tin cấu hình
|
||||||
|
message(STATUS "=================================")
|
||||||
|
message(STATUS "Project: ${PROJECT_NAME} (Header-Only)")
|
||||||
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
|
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||||
|
message(STATUS "Headers found:")
|
||||||
|
foreach(hdr ${HEADERS})
|
||||||
|
message(STATUS " - ${hdr}")
|
||||||
|
endforeach()
|
||||||
|
message(STATUS "=================================")
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
// Generated by gencpp from file mkt_msgs/Trajectory2D.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
#ifndef MKT_MSGS_MESSAGE_TRAJECTORY2D_H
|
||||||
|
#define MKT_MSGS_MESSAGE_TRAJECTORY2D_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <nav_2d_msgs/Twist2D.h>
|
||||||
|
#include <geometry_msgs/Pose2D.h>
|
||||||
|
|
||||||
|
namespace mkt_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct Trajectory2D_
|
||||||
|
{
|
||||||
|
typedef Trajectory2D_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
Trajectory2D_()
|
||||||
|
: velocity(), poses(), time_offsets()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
Trajectory2D_(const ContainerAllocator &_alloc)
|
||||||
|
: velocity(_alloc), poses(_alloc), time_offsets(_alloc)
|
||||||
|
{
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Twist2D_<ContainerAllocator> _velocity_type;
|
||||||
|
_velocity_type velocity;
|
||||||
|
|
||||||
|
typedef std::vector<geometry_msgs::Pose2D, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<geometry_msgs::Pose2D>> _poses_type;
|
||||||
|
_poses_type poses;
|
||||||
|
|
||||||
|
typedef std::vector<robot::Duration, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<robot::Duration>> _time_offsets_type;
|
||||||
|
_time_offsets_type time_offsets;
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<::mkt_msgs::Trajectory2D_<ContainerAllocator>> Ptr;
|
||||||
|
typedef boost::shared_ptr<::mkt_msgs::Trajectory2D_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct Trajectory2D_
|
||||||
|
|
||||||
|
typedef ::mkt_msgs::Trajectory2D_<std::allocator<void>> Trajectory2D;
|
||||||
|
|
||||||
|
typedef boost::shared_ptr<::mkt_msgs::Trajectory2D> Trajectory2DPtr;
|
||||||
|
typedef boost::shared_ptr<::mkt_msgs::Trajectory2D const> Trajectory2DConstPtr;
|
||||||
|
|
||||||
|
template <typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::mkt_msgs::Trajectory2D_<ContainerAllocator1> &lhs, const ::mkt_msgs::Trajectory2D_<ContainerAllocator2> &rhs)
|
||||||
|
{
|
||||||
|
return lhs.velocity == rhs.velocity &&
|
||||||
|
lhs.poses == rhs.poses &&
|
||||||
|
lhs.time_offsets == rhs.time_offsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::mkt_msgs::Trajectory2D_<ContainerAllocator1> &lhs, const ::mkt_msgs::Trajectory2D_<ContainerAllocator2> &rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mkt_msgs
|
||||||
|
|
||||||
|
#endif // MKT_MSGS_MESSAGE_TRAJECTORY2D_H
|
||||||
61
src/Libraries/nav_2d_msgs/CMakeLists.txt
Executable file
61
src/Libraries/nav_2d_msgs/CMakeLists.txt
Executable file
|
|
@ -0,0 +1,61 @@
|
||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(nav_2d_msgs VERSION 1.0.0 LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Chuẩn C++
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
# Tìm tất cả header files
|
||||||
|
file(GLOB_RECURSE HEADERS "include/nav_2d_msgs/*.h")
|
||||||
|
|
||||||
|
# Tạo INTERFACE library (header-only)
|
||||||
|
add_library(nav_2d_msgs INTERFACE)
|
||||||
|
|
||||||
|
# Set include directories
|
||||||
|
target_include_directories(nav_2d_msgs
|
||||||
|
INTERFACE
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
|
# Link dependencies (header-only, chỉ cần include paths)
|
||||||
|
# Các dependencies này cũng là header-only từ common_msgs
|
||||||
|
target_link_libraries(nav_2d_msgs
|
||||||
|
INTERFACE
|
||||||
|
std_msgs
|
||||||
|
geometry_msgs
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cài đặt header files
|
||||||
|
install(DIRECTORY include/nav_2d_msgs
|
||||||
|
DESTINATION include
|
||||||
|
FILES_MATCHING PATTERN "*.h")
|
||||||
|
|
||||||
|
# Cài đặt target
|
||||||
|
install(TARGETS nav_2d_msgs
|
||||||
|
EXPORT nav_2d_msgs-targets
|
||||||
|
ARCHIVE DESTINATION lib
|
||||||
|
LIBRARY DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
|
# Export targets
|
||||||
|
# Bây giờ có thể export dependencies vì std_msgs và geometry_msgs đã được export
|
||||||
|
install(EXPORT nav_2d_msgs-targets
|
||||||
|
FILE nav_2d_msgs-targets.cmake
|
||||||
|
NAMESPACE nav_2d_msgs::
|
||||||
|
DESTINATION lib/cmake/nav_2d_msgs)
|
||||||
|
|
||||||
|
# In thông tin cấu hình
|
||||||
|
message(STATUS "=================================")
|
||||||
|
message(STATUS "Project: ${PROJECT_NAME} (Header-Only)")
|
||||||
|
message(STATUS "Version: ${PROJECT_VERSION}")
|
||||||
|
message(STATUS "C++ Standard: ${CMAKE_CXX_STANDARD}")
|
||||||
|
message(STATUS "Headers found:")
|
||||||
|
foreach(hdr ${HEADERS})
|
||||||
|
message(STATUS " - ${hdr}")
|
||||||
|
endforeach()
|
||||||
|
message(STATUS "Dependencies: std_msgs, geometry_msgs")
|
||||||
|
message(STATUS "=================================")
|
||||||
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/ComplexPolygon2D.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_COMPLEXPOLYGON2D_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_COMPLEXPOLYGON2D_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <nav_2d_msgs/Polygon2D.h>
|
||||||
|
#include <nav_2d_msgs/Polygon2D.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct ComplexPolygon2D_
|
||||||
|
{
|
||||||
|
typedef ComplexPolygon2D_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
ComplexPolygon2D_()
|
||||||
|
: outer()
|
||||||
|
, inner() {
|
||||||
|
}
|
||||||
|
ComplexPolygon2D_(const ContainerAllocator& _alloc)
|
||||||
|
: outer(_alloc)
|
||||||
|
, inner(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Polygon2D_<ContainerAllocator> _outer_type;
|
||||||
|
_outer_type outer;
|
||||||
|
|
||||||
|
typedef std::vector< ::nav_2d_msgs::Polygon2D_<ContainerAllocator> , typename std::allocator_traits<ContainerAllocator>::template rebind_alloc< ::nav_2d_msgs::Polygon2D_<ContainerAllocator> >> _inner_type;
|
||||||
|
_inner_type inner;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::ComplexPolygon2D_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::ComplexPolygon2D_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct ComplexPolygon2D_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::ComplexPolygon2D_<std::allocator<void> > ComplexPolygon2D;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::ComplexPolygon2D > ComplexPolygon2DPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::ComplexPolygon2D const> ComplexPolygon2DConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::ComplexPolygon2D_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::ComplexPolygon2D_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.outer == rhs.outer &&
|
||||||
|
lhs.inner == rhs.inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::ComplexPolygon2D_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::ComplexPolygon2D_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_COMPLEXPOLYGON2D_H
|
||||||
94
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/NavGridInfo.h
Normal file
94
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/NavGridInfo.h
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/NavGridInfo.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_NAVGRIDINFO_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_NAVGRIDINFO_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct NavGridInfo_
|
||||||
|
{
|
||||||
|
typedef NavGridInfo_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
NavGridInfo_()
|
||||||
|
: width(0)
|
||||||
|
, height(0)
|
||||||
|
, resolution(0.0)
|
||||||
|
, frame_id()
|
||||||
|
, origin_x(0.0)
|
||||||
|
, origin_y(0.0) {
|
||||||
|
}
|
||||||
|
NavGridInfo_(const ContainerAllocator& _alloc)
|
||||||
|
: width(0)
|
||||||
|
, height(0)
|
||||||
|
, resolution(0.0)
|
||||||
|
, frame_id(_alloc)
|
||||||
|
, origin_x(0.0)
|
||||||
|
, origin_y(0.0) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef uint32_t _width_type;
|
||||||
|
_width_type width;
|
||||||
|
|
||||||
|
typedef uint32_t _height_type;
|
||||||
|
_height_type height;
|
||||||
|
|
||||||
|
typedef double _resolution_type;
|
||||||
|
_resolution_type resolution;
|
||||||
|
|
||||||
|
typedef std::basic_string<char, std::char_traits<char>, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<char>> _frame_id_type;
|
||||||
|
_frame_id_type frame_id;
|
||||||
|
|
||||||
|
typedef double _origin_x_type;
|
||||||
|
_origin_x_type origin_x;
|
||||||
|
|
||||||
|
typedef double _origin_y_type;
|
||||||
|
_origin_y_type origin_y;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridInfo_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridInfo_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct NavGridInfo_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::NavGridInfo_<std::allocator<void> > NavGridInfo;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridInfo > NavGridInfoPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridInfo const> NavGridInfoConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::NavGridInfo_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridInfo_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.width == rhs.width &&
|
||||||
|
lhs.height == rhs.height &&
|
||||||
|
lhs.resolution == rhs.resolution &&
|
||||||
|
lhs.frame_id == rhs.frame_id &&
|
||||||
|
lhs.origin_x == rhs.origin_x &&
|
||||||
|
lhs.origin_y == rhs.origin_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::NavGridInfo_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridInfo_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_NAVGRIDINFO_H
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/NavGridOfChars.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_NAVGRIDOFCHARS_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_NAVGRIDOFCHARS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <robot/time.h>
|
||||||
|
#include <nav_2d_msgs/NavGridInfo.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct NavGridOfChars_
|
||||||
|
{
|
||||||
|
typedef NavGridOfChars_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
NavGridOfChars_()
|
||||||
|
: stamp()
|
||||||
|
, info()
|
||||||
|
, data() {
|
||||||
|
}
|
||||||
|
NavGridOfChars_(const ContainerAllocator& _alloc)
|
||||||
|
: stamp()
|
||||||
|
, info(_alloc)
|
||||||
|
, data(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef robot::Time _stamp_type;
|
||||||
|
_stamp_type stamp;
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::NavGridInfo_<ContainerAllocator> _info_type;
|
||||||
|
_info_type info;
|
||||||
|
|
||||||
|
typedef std::vector<uint8_t, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<uint8_t>> _data_type;
|
||||||
|
_data_type data;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfChars_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfChars_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct NavGridOfChars_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::NavGridOfChars_<std::allocator<void> > NavGridOfChars;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfChars > NavGridOfCharsPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfChars const> NavGridOfCharsConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::NavGridOfChars_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridOfChars_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.stamp == rhs.stamp &&
|
||||||
|
lhs.info == rhs.info &&
|
||||||
|
lhs.data == rhs.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::NavGridOfChars_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridOfChars_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_NAVGRIDOFCHARS_H
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/NavGridOfCharsUpdate.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_NAVGRIDOFCHARSUPDATE_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_NAVGRIDOFCHARSUPDATE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <robot/time.h>
|
||||||
|
#include <nav_2d_msgs/UIntBounds.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct NavGridOfCharsUpdate_
|
||||||
|
{
|
||||||
|
typedef NavGridOfCharsUpdate_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
NavGridOfCharsUpdate_()
|
||||||
|
: stamp()
|
||||||
|
, bounds()
|
||||||
|
, data() {
|
||||||
|
}
|
||||||
|
NavGridOfCharsUpdate_(const ContainerAllocator& _alloc)
|
||||||
|
: stamp()
|
||||||
|
, bounds(_alloc)
|
||||||
|
, data(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef robot::Time _stamp_type;
|
||||||
|
_stamp_type stamp;
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::UIntBounds_<ContainerAllocator> _bounds_type;
|
||||||
|
_bounds_type bounds;
|
||||||
|
|
||||||
|
typedef std::vector<uint8_t, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<uint8_t>> _data_type;
|
||||||
|
_data_type data;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfCharsUpdate_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfCharsUpdate_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct NavGridOfCharsUpdate_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::NavGridOfCharsUpdate_<std::allocator<void> > NavGridOfCharsUpdate;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfCharsUpdate > NavGridOfCharsUpdatePtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfCharsUpdate const> NavGridOfCharsUpdateConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::NavGridOfCharsUpdate_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridOfCharsUpdate_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.stamp == rhs.stamp &&
|
||||||
|
lhs.bounds == rhs.bounds &&
|
||||||
|
lhs.data == rhs.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::NavGridOfCharsUpdate_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridOfCharsUpdate_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_NAVGRIDOFCHARSUPDATE_H
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/NavGridOfDoubles.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_NAVGRIDOFDOUBLES_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_NAVGRIDOFDOUBLES_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <robot/time.h>
|
||||||
|
#include <nav_2d_msgs/NavGridInfo.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct NavGridOfDoubles_
|
||||||
|
{
|
||||||
|
typedef NavGridOfDoubles_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
NavGridOfDoubles_()
|
||||||
|
: stamp()
|
||||||
|
, info()
|
||||||
|
, data() {
|
||||||
|
}
|
||||||
|
NavGridOfDoubles_(const ContainerAllocator& _alloc)
|
||||||
|
: stamp()
|
||||||
|
, info(_alloc)
|
||||||
|
, data(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef robot::Time _stamp_type;
|
||||||
|
_stamp_type stamp;
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::NavGridInfo_<ContainerAllocator> _info_type;
|
||||||
|
_info_type info;
|
||||||
|
|
||||||
|
typedef std::vector<double, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<double>> _data_type;
|
||||||
|
_data_type data;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfDoubles_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfDoubles_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct NavGridOfDoubles_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::NavGridOfDoubles_<std::allocator<void> > NavGridOfDoubles;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfDoubles > NavGridOfDoublesPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfDoubles const> NavGridOfDoublesConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::NavGridOfDoubles_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridOfDoubles_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.stamp == rhs.stamp &&
|
||||||
|
lhs.info == rhs.info &&
|
||||||
|
lhs.data == rhs.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::NavGridOfDoubles_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridOfDoubles_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_NAVGRIDOFDOUBLES_H
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/NavGridOfDoublesUpdate.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_NAVGRIDOFDOUBLESUPDATE_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_NAVGRIDOFDOUBLESUPDATE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <robot/time.h>
|
||||||
|
#include <nav_2d_msgs/UIntBounds.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct NavGridOfDoublesUpdate_
|
||||||
|
{
|
||||||
|
typedef NavGridOfDoublesUpdate_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
NavGridOfDoublesUpdate_()
|
||||||
|
: stamp()
|
||||||
|
, bounds()
|
||||||
|
, data() {
|
||||||
|
}
|
||||||
|
NavGridOfDoublesUpdate_(const ContainerAllocator& _alloc)
|
||||||
|
: stamp()
|
||||||
|
, bounds(_alloc)
|
||||||
|
, data(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef robot::Time _stamp_type;
|
||||||
|
_stamp_type stamp;
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::UIntBounds_<ContainerAllocator> _bounds_type;
|
||||||
|
_bounds_type bounds;
|
||||||
|
|
||||||
|
typedef std::vector<double, typename std::allocator_traits<ContainerAllocator>::template rebind_alloc<double>> _data_type;
|
||||||
|
_data_type data;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfDoublesUpdate_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfDoublesUpdate_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct NavGridOfDoublesUpdate_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::NavGridOfDoublesUpdate_<std::allocator<void> > NavGridOfDoublesUpdate;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfDoublesUpdate > NavGridOfDoublesUpdatePtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::NavGridOfDoublesUpdate const> NavGridOfDoublesUpdateConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::NavGridOfDoublesUpdate_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridOfDoublesUpdate_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.stamp == rhs.stamp &&
|
||||||
|
lhs.bounds == rhs.bounds &&
|
||||||
|
lhs.data == rhs.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::NavGridOfDoublesUpdate_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::NavGridOfDoublesUpdate_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_NAVGRIDOFDOUBLESUPDATE_H
|
||||||
74
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/Path2D.h
Normal file
74
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/Path2D.h
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/Path2D.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_PATH2D_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_PATH2D_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <std_msgs/Header.h>
|
||||||
|
#include <nav_2d_msgs/Pose2DStamped.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct Path2D_
|
||||||
|
{
|
||||||
|
typedef Path2D_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
Path2D_()
|
||||||
|
: header()
|
||||||
|
, poses() {
|
||||||
|
}
|
||||||
|
Path2D_(const ContainerAllocator& _alloc)
|
||||||
|
: header()
|
||||||
|
, poses(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef ::std_msgs::Header _header_type;
|
||||||
|
_header_type header;
|
||||||
|
|
||||||
|
typedef std::vector< ::nav_2d_msgs::Pose2DStamped_<ContainerAllocator> , typename std::allocator_traits<ContainerAllocator>::template rebind_alloc< ::nav_2d_msgs::Pose2DStamped_<ContainerAllocator> >> _poses_type;
|
||||||
|
_poses_type poses;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Path2D_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Path2D_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct Path2D_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Path2D_<std::allocator<void> > Path2D;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Path2D > Path2DPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Path2D const> Path2DConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::Path2D_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Path2D_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.header == rhs.header &&
|
||||||
|
lhs.poses == rhs.poses;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::Path2D_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Path2D_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_PATH2D_H
|
||||||
72
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/Point2D.h
Normal file
72
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/Point2D.h
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/Point2D.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_POINT2D_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_POINT2D_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct Point2D_
|
||||||
|
{
|
||||||
|
typedef Point2D_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
Point2D_()
|
||||||
|
: x(0.0)
|
||||||
|
, y(0.0) {
|
||||||
|
}
|
||||||
|
Point2D_(const ContainerAllocator& _alloc)
|
||||||
|
: x(0.0)
|
||||||
|
, y(0.0) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef double _x_type;
|
||||||
|
_x_type x;
|
||||||
|
|
||||||
|
typedef double _y_type;
|
||||||
|
_y_type y;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Point2D_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Point2D_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct Point2D_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Point2D_<std::allocator<void> > Point2D;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Point2D > Point2DPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Point2D const> Point2DConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::Point2D_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Point2D_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.x == rhs.x &&
|
||||||
|
lhs.y == rhs.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::Point2D_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Point2D_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_POINT2D_H
|
||||||
67
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/Polygon2D.h
Normal file
67
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/Polygon2D.h
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/Polygon2D.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_POLYGON2D_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_POLYGON2D_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <nav_2d_msgs/Point2D.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct Polygon2D_
|
||||||
|
{
|
||||||
|
typedef Polygon2D_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
Polygon2D_()
|
||||||
|
: points() {
|
||||||
|
}
|
||||||
|
Polygon2D_(const ContainerAllocator& _alloc)
|
||||||
|
: points(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::vector< ::nav_2d_msgs::Point2D_<ContainerAllocator> , typename std::allocator_traits<ContainerAllocator>::template rebind_alloc< ::nav_2d_msgs::Point2D_<ContainerAllocator> >> _points_type;
|
||||||
|
_points_type points;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2D_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2D_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct Polygon2D_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Polygon2D_<std::allocator<void> > Polygon2D;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2D > Polygon2DPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2D const> Polygon2DConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::Polygon2D_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Polygon2D_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.points == rhs.points;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::Polygon2D_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Polygon2D_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_POLYGON2D_H
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/Polygon2DCollection.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_POLYGON2DCOLLECTION_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_POLYGON2DCOLLECTION_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <std_msgs/Header.h>
|
||||||
|
#include <nav_2d_msgs/ComplexPolygon2D.h>
|
||||||
|
#include <std_msgs/ColorRGBA.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct Polygon2DCollection_
|
||||||
|
{
|
||||||
|
typedef Polygon2DCollection_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
Polygon2DCollection_()
|
||||||
|
: header()
|
||||||
|
, polygons()
|
||||||
|
, colors() {
|
||||||
|
}
|
||||||
|
Polygon2DCollection_(const ContainerAllocator& _alloc)
|
||||||
|
: header()
|
||||||
|
, polygons(_alloc)
|
||||||
|
, colors(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef ::std_msgs::Header _header_type;
|
||||||
|
_header_type header;
|
||||||
|
|
||||||
|
typedef std::vector< ::nav_2d_msgs::ComplexPolygon2D_<ContainerAllocator> , typename std::allocator_traits<ContainerAllocator>::template rebind_alloc< ::nav_2d_msgs::ComplexPolygon2D_<ContainerAllocator> >> _polygons_type;
|
||||||
|
_polygons_type polygons;
|
||||||
|
|
||||||
|
typedef std::vector< ::std_msgs::ColorRGBA , typename std::allocator_traits<ContainerAllocator>::template rebind_alloc< ::std_msgs::ColorRGBA >> _colors_type;
|
||||||
|
_colors_type colors;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2DCollection_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2DCollection_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct Polygon2DCollection_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Polygon2DCollection_<std::allocator<void> > Polygon2DCollection;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2DCollection > Polygon2DCollectionPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2DCollection const> Polygon2DCollectionConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::Polygon2DCollection_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Polygon2DCollection_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.header == rhs.header &&
|
||||||
|
lhs.polygons == rhs.polygons &&
|
||||||
|
lhs.colors == rhs.colors;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::Polygon2DCollection_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Polygon2DCollection_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_POLYGON2DCOLLECTION_H
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/Polygon2DStamped.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_POLYGON2DSTAMPED_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_POLYGON2DSTAMPED_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <std_msgs/Header.h>
|
||||||
|
#include <nav_2d_msgs/Polygon2D.h>
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct Polygon2DStamped_
|
||||||
|
{
|
||||||
|
typedef Polygon2DStamped_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
Polygon2DStamped_()
|
||||||
|
: header()
|
||||||
|
, polygon() {
|
||||||
|
}
|
||||||
|
Polygon2DStamped_(const ContainerAllocator& _alloc)
|
||||||
|
: header()
|
||||||
|
, polygon(_alloc) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef ::std_msgs::Header _header_type;
|
||||||
|
_header_type header;
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Polygon2D_<ContainerAllocator> _polygon_type;
|
||||||
|
_polygon_type polygon;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2DStamped_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2DStamped_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct Polygon2DStamped_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Polygon2DStamped_<std::allocator<void> > Polygon2DStamped;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2DStamped > Polygon2DStampedPtr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Polygon2DStamped const> Polygon2DStampedConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::Polygon2DStamped_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Polygon2DStamped_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.header == rhs.header &&
|
||||||
|
lhs.polygon == rhs.polygon;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::Polygon2DStamped_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Polygon2DStamped_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_POLYGON2DSTAMPED_H
|
||||||
78
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/Pose2D32.h
Normal file
78
src/Libraries/nav_2d_msgs/include/nav_2d_msgs/Pose2D32.h
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Generated by gencpp from file nav_2d_msgs/Pose2D32.msg
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NAV_2D_MSGS_MESSAGE_POSE2D32_H
|
||||||
|
#define NAV_2D_MSGS_MESSAGE_POSE2D32_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace nav_2d_msgs
|
||||||
|
{
|
||||||
|
template <class ContainerAllocator>
|
||||||
|
struct Pose2D32_
|
||||||
|
{
|
||||||
|
typedef Pose2D32_<ContainerAllocator> Type;
|
||||||
|
|
||||||
|
Pose2D32_()
|
||||||
|
: x(0.0)
|
||||||
|
, y(0.0)
|
||||||
|
, theta(0.0) {
|
||||||
|
}
|
||||||
|
Pose2D32_(const ContainerAllocator& _alloc)
|
||||||
|
: x(0.0)
|
||||||
|
, y(0.0)
|
||||||
|
, theta(0.0) {
|
||||||
|
(void)_alloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef float _x_type;
|
||||||
|
_x_type x;
|
||||||
|
|
||||||
|
typedef float _y_type;
|
||||||
|
_y_type y;
|
||||||
|
|
||||||
|
typedef float _theta_type;
|
||||||
|
_theta_type theta;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Pose2D32_<ContainerAllocator> > Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Pose2D32_<ContainerAllocator> const> ConstPtr;
|
||||||
|
|
||||||
|
}; // struct Pose2D32_
|
||||||
|
|
||||||
|
typedef ::nav_2d_msgs::Pose2D32_<std::allocator<void> > Pose2D32;
|
||||||
|
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Pose2D32 > Pose2D32Ptr;
|
||||||
|
typedef std::shared_ptr< ::nav_2d_msgs::Pose2D32 const> Pose2D32ConstPtr;
|
||||||
|
|
||||||
|
// constants requiring out of line definition
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator==(const ::nav_2d_msgs::Pose2D32_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Pose2D32_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return lhs.x == rhs.x &&
|
||||||
|
lhs.y == rhs.y &&
|
||||||
|
lhs.theta == rhs.theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerAllocator1, typename ContainerAllocator2>
|
||||||
|
bool operator!=(const ::nav_2d_msgs::Pose2D32_<ContainerAllocator1> & lhs, const ::nav_2d_msgs::Pose2D32_<ContainerAllocator2> & rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace nav_2d_msgs
|
||||||
|
|
||||||
|
#endif // NAV_2D_MSGS_MESSAGE_POSE2D32_H
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user