Skip to content

Commit efcc9b0

Browse files
authored
Merge pull request #17 from dfki-ric/example_case
Example case
2 parents dc43700 + dacc121 commit efcc9b0

10 files changed

+485
-334
lines changed

README.md

Lines changed: 110 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,16 +126,21 @@ This provides instructions for setting up a test environment using **Gazebo Fort
126126
## Prerequisites
127127

128128
### 1. Install ROS2 Humble
129-
Ensure you have **ROS2 Humble** installed on your system.
130-
131-
```
132-
sudo apt install ros-humble-desktop-full
133-
```
129+
Ensure you have **ROS2 Humble** installed on your system. Follow the official page at [ROS2 Humble Debian Installation](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debs.html)
134130

135131
### 2. Install Gazebo Fortress
136132
If you need to install **Gazebo Fortress**, follow the instructions provided on the official page at [Gazebo Installation](https://gazebosim.org/docs/latest/ros_installation/).
137133

138-
### 3. Get the repos
134+
### 3. Install SLAM
135+
If you have a SLAM package which provides a pointcloud map on a topic then you can skip this step. If not then you can use [lidarslam_ros2](https://github.com/rsasaki0109/lidarslam_ros2). Please follow the build and install instructions from the original repository. Set the parameter `robot_frame_id: "husky/base_link"` for the `scanmatcher` node in [lidarslam.yaml](https://github.com/rsasaki0109/lidarslam_ros2/blob/a63b8fa2485e05251505b2bb209598285106bff2/lidarslam/param/lidarslam.yaml#L4)
136+
137+
Install libg2o:
138+
139+
```
140+
sudo apt-get install -y ros-humble-libg2o
141+
```
142+
143+
### 3. Get ugv_nav4d_ros2 and a test environment for robot husky in gazebo
139144

140145
```
141146
mkdir -p your_ros2_workspace/src
@@ -146,6 +151,8 @@ You can clone the repo `ros2_humble_gazebo_sim` anywhere in your system. Here we
146151
```
147152
cd ~/your_ros2_workspace
148153
git clone https://github.com/dfki-ric/ros2_humble_gazebo_sim.git
154+
cd ros2_humble_gazebo_sim
155+
bash install_dependencies.bash
149156
```
150157
### 4. Husky Configuration
151158
To ensure that Gazebo can find the robot model, you need to export the following environment variable. Replace /path/to/ with the actual **complete** path where you clone the repository `ros2_humble_gazebo_sim`. Add this command to your terminal:
@@ -154,10 +161,11 @@ export IGN_GAZEBO_RESOURCE_PATH=/path/to/your_ros2_workspace/ros2_humble_gazebo_
154161
```
155162

156163
### 5. Building the ROS 2 Workspace
157-
Before launching the simulation, build your ROS 2 workspace with the release flag:
164+
Before launching the simulation, source your env.sh from ugv_nav4d and build your ROS 2 workspace:
158165

159166
```
160167
cd ~/your_ros2_workspace
168+
source path/to/ugv_nav4d/build/install/env.sh
161169
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release
162170
```
163171

@@ -168,16 +176,107 @@ source ~/your_ros2_workspace/install/setup.bash
168176
cd ~/your_ros2_workspace/ros2_humble_gazebo_sim/simulation
169177
ros2 launch start.launch.py
170178
```
179+
You can use the `Teleop` plugin of Gazebo for sending velocity commands to the robot. Click on the three dots in top-right corner of Gazebo window and search for `Teleop`. Select the plugin and adjust the values as shown in figure.
180+
181+
![GazeboTeleop](doc/figures/gazebo_teleop.png)
182+
183+
Alternative to the `Teleop` plugin, you can use a joystick for moving the robot. For this, set the argument `use_joystick:=True`. Adjust the config files in the folder `/config` of the `ros2_humble_gazebo_sim` package from Step 3. Provide the full paths to the arguments `joy_config_file` and `teleop_twist_config_file` as shown below:
184+
185+
```
186+
ros2 launch start.launch.py use_joystick:=True joy_config_file:=/your_ros2_workspace/ros2_humble_gazebo_sim/simulation/config/joy_config.yaml teleop_twist_config_file:=/your_ros2_workspace/ros2_humble_gazebo_sim/simulation/config/teleop_twist_config.yaml
187+
```
188+
189+
Available arguments:
190+
```
191+
'robot_name':
192+
Options: husky
193+
(default: 'husky')
194+
195+
'world_file_name':
196+
Options: cave_circuit, urban_circuit_practice_03
197+
(default: 'cave_circuit')
198+
199+
'use_joystick':
200+
Use a real joystick.
201+
(default: 'False')
202+
203+
'joy_config_file':
204+
Full path to the joy config
205+
(default: 'joy_config_file')
206+
207+
'teleop_twist_config_file':
208+
Full path to the teleop twist joy config
209+
(default: 'teleop_twist_config_file')
210+
```
211+
212+
In a new terminal, source your workspace and start SLAM. Remap the node scanmatcher's topic `/input_cloud` to `/husky/scan/points` in the `lidarslam.launch.py`
213+
214+
```
215+
ros2 launch lidarslam lidarslam.launch.py main_param_dir:=/path/to/your/lidarslam.yaml
216+
```
217+
171218

172-
In a new terminal, source your workspace, ugv_nav4d library, and launch the ugv_nav4d_ros2. Replace the /path/to/ugv_nav4d with the location of the ugv_nav4d library. Add this command to your terminal:
219+
In a new terminal, source your workspace, ugv_nav4d library, and launch the ugv_nav4d_ros2. Replace the /path/to/your/ugv_nav4d with the location of the ugv_nav4d library. Add this command to your terminal:
173220

174221
```
175222
source ~/your_ros2_workspace/install/setup.bash
176-
source /path/to/ugv_nav4d/build/install/env.sh
223+
source /path/to/your/ugv_nav4d/build/install/env.sh
224+
225+
ros2 launch ugv_nav4d_ros2 ugv_nav4d.launch.py pointcloud_topic:=/map goal_topic:=/goal_pose
226+
```
227+
228+
### 7. Plan
177229

178-
ros2 launch ugv_nav4d_ros2 ugv_nav4d_ros2.launch.py
230+
In a new terminal, start Rviz2.
179231
```
180-
232+
cd ~/your_ros2_workspace
233+
source ~/your_ros2_workspace/install/setup.bash
234+
source /path/to/your/ugv_nav4d/build/install/env.sh
235+
rviz2 -d src/ugv_nav4d_ros2/config/ugv_nav4d.rviz
236+
```
237+
238+
After you start to move the robot, the planner will show the following status:
239+
240+
```
241+
[ugv_nav4d_ros2]: Planner state: Got Map
242+
[ugv_nav4d_ros2]: Initial patch added.
243+
[ugv_nav4d_ros2]: Planner state: Ready
244+
```
245+
246+
Visualize the MLS in Rviz2 using
247+
248+
```
249+
ros2 service call /ugv_nav4d_ros2/map_publish std_srvs/srv/Trigger
250+
```
251+
![MLSVizRviz2](doc/figures/mls_visualization_rviz2.png)
252+
253+
The gaps in the MLS map are due to the gaps in the scanned points. Move the robot around in the environment. After some time, you will see the MLS start to fill out the gaps.
254+
255+
![MLSVizRviz2](doc/figures/mls_visualization_rviz2_2.png)
256+
257+
Set a goal using the `2D Goal Pose` option in Rviz2 or by publishing to the topic `/ugv_nav4d_ros2/goal_pose`.
258+
259+
![GoalPose2D](doc/figures/set_goal_pose_rviz2.png)
260+
261+
```
262+
ros2 topic pub /goal_pose geometry_msgs/PoseStamped "{header: {stamp: {sec: 0, nanosec: 0}, frame_id: 'map'}, pose: {position: {x: 4.0, y: 4.0, z: 0.0}, orientation: {x: 0.0, y: 0.0, z: 0.0, w: 1.0}}}"
263+
```
264+
265+
#### cave_circuit
266+
267+
![MLSVizRviz2](doc/figures/mls_visualization_rviz2_3.png)
268+
269+
If planning is successful you should see the following status in the terminal:
270+
271+
```
272+
[ugv_nav4d_ros2]: FOUND_SOLUTION
273+
```
274+
275+
#### urban_circuit_practice_03
276+
You could repeat the same steps and in Step 6 set `world_file_name:=urban_circuit_practice_03`.
277+
278+
![MLSVizRviz2](doc/figures/mls_visualization_rviz2_4.png)
279+
181280
---
182281
## Implementation Details
183282
### Planning

doc/figures/gazebo_teleop.png

630 KB
Loading
165 KB
Loading
349 KB
Loading
374 KB
Loading
348 KB
Loading
301 KB
Loading

src/test/CMakeLists.txt

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
1-
find_package(GTest REQUIRED)
21
add_executable(test_ugv_nav4d test_ugv_nav4d.cpp)
2+
add_executable(test_EnvironmentXYZTheta test_EnvironmentXYZTheta.cpp)
3+
4+
target_include_directories(test_ugv_nav4d PUBLIC ${Boost_INCLUDE_DIR})
5+
target_include_directories(test_EnvironmentXYZTheta PUBLIC ${Boost_INCLUDE_DIR})
6+
37

48
if (ROCK_QT_VERSION_4)
5-
target_link_libraries(test_ugv_nav4d GTest::GTest ugv_nav4d)
9+
target_link_libraries(test_ugv_nav4d PRIVATE
10+
ugv_nav4d)
11+
target_link_libraries(test_EnvironmentXYZTheta PRIVATE
12+
ugv_nav4d)
613
endif()
714

815
if (ROCK_QT_VERSION_5)
9-
target_link_libraries(test_ugv_nav4d GTest::GTest ugv_nav4d-qt5)
16+
target_link_libraries(test_ugv_nav4d PRIVATE
17+
ugv_nav4d-qt5)
18+
target_link_libraries(test_EnvironmentXYZTheta PRIVATE
19+
ugv_nav4d-qt5)
1020
endif()
1121

1222
# Install the binaries
@@ -15,3 +25,9 @@ install(TARGETS test_ugv_nav4d EXPORT test_ugv_nav4d-targets
1525
LIBRARY DESTINATION lib
1626
RUNTIME DESTINATION bin
1727
)
28+
29+
install(TARGETS test_EnvironmentXYZTheta EXPORT test_EnvironmentXYZTheta-targets
30+
ARCHIVE DESTINATION lib
31+
LIBRARY DESTINATION lib
32+
RUNTIME DESTINATION bin
33+
)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
#define BOOST_TEST_MODULE EnvironmentXYZThetaTestModule
2+
3+
#include <fstream>
4+
#include <cstdlib>
5+
6+
#include "ugv_nav4d/EnvironmentXYZTheta.hpp"
7+
#include "ugv_nav4d/Mobility.hpp"
8+
#include <sbpl_spline_primitives/SplinePrimitivesConfig.hpp>
9+
#include <traversability_generator3d/TraversabilityConfig.hpp>
10+
11+
#include <maps/grid/MLSMap.hpp>
12+
13+
#include <pcl/io/ply_io.h>
14+
#include <pcl/common/common.h>
15+
#include <pcl/common/transforms.h>
16+
17+
#include <boost/test/included/unit_test.hpp>
18+
#include <boost/archive/binary_oarchive.hpp>
19+
#include <boost/archive/binary_iarchive.hpp>
20+
21+
using namespace ugv_nav4d;
22+
23+
std::string mlsBinFile;
24+
25+
// Define EnvironmentXYZThetaTest fixture for Boost Test
26+
struct EnvironmentXYZThetaTest {
27+
EnvironmentXYZThetaTest();
28+
~EnvironmentXYZThetaTest();
29+
30+
void loadMlsMap();
31+
32+
typedef EnvironmentXYZTheta::MLGrid MLSBase;
33+
34+
EnvironmentXYZTheta* environment;
35+
maps::grid::MLSMapSloped mlsMap;
36+
Mobility mobility;
37+
sbpl_spline_primitives::SplinePrimitivesConfig splinePrimitiveConfig;
38+
traversability_generator3d::TraversabilityConfig traversabilityConfig;
39+
bool map_loaded = false;
40+
};
41+
42+
EnvironmentXYZThetaTest::EnvironmentXYZThetaTest() {
43+
std::cout << "Called SetUp()" << std::endl;
44+
45+
splinePrimitiveConfig.gridSize = 0.3;
46+
splinePrimitiveConfig.numAngles = 16;
47+
splinePrimitiveConfig.numEndAngles = 8;
48+
splinePrimitiveConfig.destinationCircleRadius = 6;
49+
splinePrimitiveConfig.cellSkipFactor = 0.1;
50+
splinePrimitiveConfig.splineOrder = 4.0;
51+
52+
mobility.translationSpeed = 0.5;
53+
mobility.rotationSpeed = 0.5;
54+
mobility.minTurningRadius = 1;
55+
mobility.spline_sampling_resolution = 0.05;
56+
mobility.remove_goal_offset = true;
57+
mobility.multiplierForward = 1;
58+
mobility.multiplierBackward = 3;
59+
mobility.multiplierPointTurn = 3;
60+
mobility.multiplierLateral = 4;
61+
mobility.multiplierForwardTurn = 2;
62+
mobility.multiplierBackwardTurn = 4;
63+
mobility.multiplierLateralCurve = 4;
64+
mobility.searchRadius = 1.0;
65+
mobility.searchProgressSteps = 0.1;
66+
mobility.maxMotionCurveLength = 100;
67+
68+
traversabilityConfig.maxStepHeight = 0.25;
69+
traversabilityConfig.maxSlope = 0.45;
70+
traversabilityConfig.inclineLimittingMinSlope = 0.2;
71+
traversabilityConfig.inclineLimittingLimit = 0.1;
72+
traversabilityConfig.costFunctionDist = 0.0;
73+
traversabilityConfig.minTraversablePercentage = 0.4;
74+
traversabilityConfig.robotHeight = 1.2;
75+
traversabilityConfig.robotSizeX = 1.35;
76+
traversabilityConfig.robotSizeY = 0.85;
77+
traversabilityConfig.distToGround = 0.0;
78+
traversabilityConfig.slopeMetricScale = 1.0;
79+
traversabilityConfig.slopeMetric = traversability_generator3d::NONE;
80+
traversabilityConfig.gridResolution = 0.3;
81+
traversabilityConfig.initialPatchVariance = 0.0001;
82+
traversabilityConfig.allowForwardDownhill = true;
83+
traversabilityConfig.enableInclineLimitting = false;
84+
85+
loadMlsMap();
86+
}
87+
88+
EnvironmentXYZThetaTest::~EnvironmentXYZThetaTest(){
89+
std::cout << "Called TearDown()" << std::endl;
90+
delete environment;
91+
}
92+
93+
void EnvironmentXYZThetaTest::loadMlsMap() {
94+
std::string filename;
95+
96+
if (mlsBinFile.empty()) {
97+
filename = "cave_circuit_mls.bin";
98+
} else {
99+
filename = mlsBinFile;
100+
}
101+
102+
std::ifstream file(filename, std::ios::binary);
103+
if (!file.is_open()) {
104+
map_loaded = false;
105+
return;
106+
}
107+
108+
try {
109+
boost::archive::binary_iarchive ia(file);
110+
ia >> mlsMap; // Deserialize into mlsMap
111+
} catch (const std::exception& e) {
112+
map_loaded = false;
113+
}
114+
map_loaded = true;
115+
}
116+
117+
// Define the test suite and test cases
118+
BOOST_FIXTURE_TEST_SUITE(EnvironmentXYZThetaTestSuite, EnvironmentXYZThetaTest)
119+
120+
BOOST_AUTO_TEST_CASE(check_planner_init_failure_wrong_grid_resolutions) {
121+
std::shared_ptr<MLSBase> mlsPtr = std::make_shared<MLSBase>(mlsMap);
122+
try {
123+
environment = new EnvironmentXYZTheta(mlsPtr, traversabilityConfig, splinePrimitiveConfig, mobility);
124+
} catch (const std::exception& ex) {
125+
std::cout << "Exception: \n" << ex.what() << "\n";
126+
BOOST_CHECK_NE(splinePrimitiveConfig.gridSize, traversabilityConfig.gridResolution);
127+
}
128+
}
129+
130+
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)