This repository integrates various open-source algorithms to achieve 2-D localization and navigation on a wheeled robot platform.
Code repository: https://github.com/66Lau/NEXTE_Sentry_Nav
3-D navigation and exploration implementation: https://github.com/66Lau/NEXTE_Sentry_Nav_3D
For a simulation environment: https://github.com/66Lau/sentry_sim
Environment:
- ROS Noetic
- Ubuntu 20.04
- Lidar: Mid360
This repository contains various modifications and adaptations for different modules. It is recommended to clone this repository directly. Below is the development workflow and process of this repository:
- Install Livox SDK2. The installation steps are detailed in the README. Note: Change the host IP to
192.168.1.50
. How to modify Ubuntu IP. The Lidar IP in this setup is192.168.1.180
. - Install Livox ROS Driver 2. Follow the steps in the README. Note: Before running, make sure to modify the host IP and Lidar IP in the configuration files.
- Configure Fast-LIO:
References:
sudo apt install libeigen3-dev
sudo apt install libpcl-dev
# Required for ROS2
sudo apt install ros-humble-pcl-ros
# Compile Fast-LIO
# Navigate to the 'src' directory of your workspace. Replace $A_ROS_DIR$ accordingly.
cd ~/$A_ROS_DIR$/src
git clone https://github.com/hku-mars/FAST_LIO.git
cd FAST_LIO
git submodule update --init
cd ../..
catkin_make
source devel/setup.bash
Note: If using MID360 (which requires livox_ros_driver2
instead of livox_ros_driver
), you need to modify CMakeLists.txt
in the Fast-LIO repository to change find_package(livox_ros_driver)
to find_package(livox_ros_driver2)
. Also update package.xml
and the corresponding .cpp
files.
# Install Sophus
git clone https://github.com/strasdat/Sophus.git
cd Sophus
git checkout a621ff
mkdir build
cd build
cmake ../ -DUSE_BASIC_LOGGING=ON
make
sudo make install
If you encounter errors, refer to the solution guide.
Error example:
/home/lau/Sophus/sophus/so2.cpp:32:26: error: lvalue required as left operand of assignment
unit_complex_.real() = 1.;
^~
/home/lau/Sophus/sophus/so2.cpp:33:26: error: lvalue required as left operand of assignment
Modify so2.cpp
at line 32:
SO2::SO2()
{
unit_complex_.real(1.);
unit_complex_.imag(0.);
}
After successfully installing Sophus, recompile Fast-LIO.
Finally, run:
# Navigate to the workspace containing livox_ros_driver2
cd ~/$A_ROS_DIR$
source devel/setup.bash
roslaunch livox_ros_driver2 msg_MID360.launch
Open another terminal and run:
# Navigate to the workspace containing Fast-LIO
cd ~/$A_ROS_DIR$
source devel/setup.bash
roslaunch fast_lio mapping_mid360.launch
After building the map, the robot can be localized using two methods:
- Method 1: Assume the initial position remains the same and use Fast-LIO’s odometry estimation for localization.
- Drawbacks:
- The robot must start from the same initial position each time, otherwise, errors are introduced.
- Odometry drift accumulates over time.
- Drawbacks:
- Method 2: Use the map for relocalization by matching the current Lidar point cloud with the prebuilt map. This method often requires manually setting the initial position estimate or utilizing additional robot sensors for rough initialization.
To avoid accumulated drift, Method 2 is recommended: FAST_LIO_LOCALIZATION
# Required packages, compatible with Python 3.8
sudo apt install ros-$ROS_DISTRO-ros-numpy
pip install numpy==1.21
pip install open3d
The original repository FAST_LIO_LOCALIZATION was implemented in Python 2, but this repository replaces it with Python 3.
-
global_localization.py
- Change interpreter to
#!/usr/bin/python3
- Replace
import thread
withimport _thread
for Python 3 compatibility - Update Open3D API:
o3d.registration
→o3d.pipelines.registration
- Modify
FOV = 6.28
on line 222 to match the actual Lidar range (for MID360:2*pi
rad) - Update
FOV_FAR = 30
to match the actual max range of the Lidar
- Change interpreter to
-
localization_MID360.launch
- Use
fastlio_mapping
withmid360.launch
from Fast-LIO2 - Adjust TF tree matching in line 28:
args="$(arg map) 5 _frame_id:=map cloud_pcd:=map" />
- Change
map
argument to the actual saved prior map path
- Use
Usage:
roslaunch livox_ros_driver2 msg_MID360.launch
roslaunch fast_lio_localization localization_MID360.launch
# Publish initial pose (or use RViz to manually set it)
rosrun fast_lio_localization publish_initial_pose.py 0 0 0 0 0 0
Why Convert?
Since move_base
relies on 2D grid maps for path planning, while Fast-LIO outputs 3D PCD maps, we need to convert PCD into a 2D grid map.
Conversion Methods:
- Offline PCD to Grid Map:
- Use pcd_package (Reference: Convert PCD to Grid Map)
- Use
octomap_server
to generate a 2D occupancy grid from a 3D point cloud (Reference: Generate 2D Grid Map)
- Real-time 2D Grid Map Construction:
- Directly generate a 2D grid map while constructing the 3D point cloud
This repository includes both methods, with Method 2 being the default.
Setup:
sudo apt install ros-noetic-map-server
sudo apt-get install ros-noetic-octomap-ros
sudo apt-get install ros-noetic-octomap-msgs
sudo apt-get install ros-noetic-octomap-server
sudo apt-get install ros-noetic-octomap-rviz-plugins
sudo apt-get install ros-noetic-move-base
Method 1:
roslaunch pcd2pgm run.launch
Method 2:
Using octomap_server_node
, Pointcloud2Map.launch
in FAST_LIO
builds a 2D grid map in real-time.
If you want to save the generated maps:
- The 3D point cloud map (PCD) will be automatically saved in
fast_lio/PCD
after runningsentry_build.launch
. - To save the 2D grid map, run:
# Save the PGM map file
rosrun map_server map_saver map:=/<Map Topic> -f PATH_TO_YOUR_FILE/mymap
# Example:
rosrun map_server map_saver map:=/projected_map -f /home/rm/ws_sentry/src/FAST_LIO/PCD/scans
In the move_base
navigation framework, the local cost map requires real-time 2D point cloud data as input. FAST_LIO outputs a 3D point cloud (/pointclouds2
), whereas move_base
requires a 2D LaserScan (/Laserscan
). Therefore, /pointclouds2
needs to be converted to /Laserscan
.
Based on pointcloud_to_laserscan.
Related blog post: pointcloud_to_laserscan_blog
Launch file: PointsCloud2toLaserscan.launch
Input: body
frame - The robot’s pose in the 3D point cloud coordinate system.
Output: body_2d
frame - The robot’s pose in the 2D grid map coordinate system.
Since fast_lio_localization
outputs the body
frame in the 3D point cloud coordinate system, while move_base
requires a map
frame in the 2D grid map coordinate system, a transformation is necessary.
The transformation depends on the Lidar installation. If the MID360 is mounted upright or slightly tilted but facing downward, set:
body_2d
position(x, y, 0)
, keepingx, y
synchronized withbody
body_2d
orientation(0,0,z,w)
, retaining only the yaw angle
For MID360 mounted upside-down (facing upward), modify the TF transformation accordingly.
Relevant code: \sentry_nav\src\Trans_TF_2d.cpp
TF tutorial: tf/Tutorials
This repository utilizes the open-source move_base
framework for path planning and obstacle avoidance.
/Laserscans
: 2D point cloud data in the robot's coordinate frame./tf
: The following frames must be included in the TF tree:/map
: 2D grid map coordinate frame (namedmap
in this repository)./odom
: Odometry frame (namedcamera_init
in this repository)./base_link
: Robot's coordinate frame (namedbody_2d
in this repository).- Tip: To check if the TF tree is correct, open
rqt
and use the TF tree plugin.
/map
: This is not a coordinate frame but the grid map information published bymap_server
.- In this repository,
map_server
is launched withinsentry_localize.launch
infast_lio_localization
.
- In this repository,
move_base_simple/goal
: The target position for the robot, which can be set using the red arrow inrviz
./odom
: Odometry information.- In this repository,
sentry_localize.launch
automatically starts Fast-LIO to publish odometry information.
- In this repository,
/cmd_vel
: Publishes velocity commands for robot movement.- Tip: If using ROS for the first time, monitor this topic carefully as it controls the robot's movement in terms of linear and angular velocity. Use
rqt
waveforms to verify correctness.
- Tip: If using ROS for the first time, monitor this topic carefully as it controls the robot's movement in terms of linear and angular velocity. Use
- Global and local paths.
- Cost map (obstacle avoidance cost grid).
For more details, refer to the official documentation:
- move_base Wiki
- dwa_local_planner Wiki
- Autolabor ROS Tutorials (Navigation Implementation 04 - Path Planning)
Relevant parameters and configurations are in the Sentry_Nav
package.
-
Build the map
roslaunch livox_ros_driver2 msg_MID360.launch
roslaunch fast_lio_localization sentry_build_map.launch
- Run the following command to save the grid map (the 3D point cloud PCD is automatically saved to the same path after execution):
rosrun map_server map_saver map:=/projected_map -f /home/rm/ws_sentry/src/sentry_slam/FAST_LIO/PCD/scans
-
Navigation
- Verify the 2D map, especially
scans.yaml
, and ensure thatorigin [x,y,yaw]
does not containnan
. If necessary, modify it to0
. roslaunch livox_ros_driver2 msg_MID360.launch
roslaunch fast_lio_localization sentry_localize.launch
- Publish an estimated initial position using
rviz
or:rosrun fast_lio_localization publish_initial_pose.py 0 0 0 0 0 0
roslaunch sentry_nav sentry_movebase.launch
- Set a navigation goal in
rviz
.
Tip: Use
rqt
to check/cmd_vel
. In ROS:- The red axis represents
x
. - The green axis represents
y
. - The blue axis represents
z
. - A positive angular velocity indicates counterclockwise rotation, while a negative value indicates clockwise rotation.
- Verify the 2D map, especially
- Why the robot's speed cannot reach the upper limit
The navigation layer and the underlying control layer use serial port communication
After navigation starts, the system will generate a path and cmd_vel topic to control the movement of the robot.
This repo uses a virtual serial port to send data related to the lower computer. ros serial communication
Set serial port permissions
sudo usermod -aG dialout $USER
# USRE is your username
# eg:
sudo usermod -aG dialout lau
rosrun sentry_serial sentry_send <serial port path>
#eg:
rosrun sentry_serial sentry_send /dev/ttyACM0
#default serial /dev/ttyACM0
The final command to use this navigation system:
- build the map
roslaunch livox_ros_driver2 msg_MID360.launch
roslaunch fast_lio_localization sentry_build_map.launch
rosrun map_server map_saver map:=/projected_map -f /home/rm/ws_sentry/src/sentry_slam/FAST_LIO/PCD/scans
- navigation(relocalization)
roslaunch livox_ros_driver2 msg_MID360.launch
roslaunch fast_lio_localization sentry_localize.launch
# use rviz publish initial guess position or `rosrun fast_lio_localization publish_initial_pose.py 0 0 0 0 0 0`
roslaunch sentry_nav sentry_movebase.launch
# use rviz publisn destination
roslaunch sentry_serial sentry_serial.launch
3.navigation(odometry localization)
roslaunch livox_ros_driver2 msg_MID360.launch
roslaunch fast_lio_localization sentry_localize_odom.launch
# use rviz publish initial guess position or `rosrun fast_lio_localization publish_initial_pose.py 0 0 0 0 0 0`
roslaunch sentry_nav sentry_movebase.launch
# use rviz publisn destination
roslaunch sentry_serial sentry_serial.launch
If an error occurs when running directly, pay attention to the error message, etc. Most of them are path problems
Here is a little explanation of the tf tree
- map->camera_init: tf conversion is published by relocation icp. If the odometer is used directly for positioning, it is statically published by static_transform_publisher.
- cmera_init->robot_foot_init: statically published by static_transform_publisher, which is the conversion from mid360 to the robot foot. Robot_foot_init means the initial position of the robot foot
- camera_init->body: published by the odometer information of fast_lio, which is the initial position of the radar and the relationship to the current position of the radar
- body->body_foot: the main function is to convert the radar position to the robot foot, which is also statically published
- map->body_2d: published by Trans_body_2d.cpp, the main function is to project the body onto the 2dmap
The above content is the initial introduction to building robot navigation. Thanks to the good decoupling between different ROS function packages, the slam part, obstacle avoidance part, and path planning part can be modified and optimized independently in the future. For subsequent optimization or modification, you can refer to the following content:
Change the local planner to dwa, and make cmd_vel output the y direction velocity of the omnidirectional mobile robot instead of using the default yaw
Because the output of move_base/cmd_vel has a sudden change in speed and the control frequency is not high, the robot movement will be stuck. In order to smooth the movement of the robot, we use the velocity_smoother_ema
package (based on the ema algorithm) to smooth the output speed. You can also useyocs_velocity_smoother
.
git clone https://github.com/seifEddy/velocity_smoother_ema.git
launch file of velocity_smoother_ema的 has been added to sentry_movebase.launch file,and serial part subscribe the sommthed command/smooth_cmd_cel
When using fast_lio to build a 3D point cloud map, the point cloud data is compressed to a 2D map using octomap. The constructed map can ensure that the robot posture in the 3D point cloud can be fully mapped to the 2D grid map
2023-12-21 Update:
Due to changes in the mechanical structure design, the robot's radar installation position has been changed to inverted, and most of the changes are in the branch invert_lidar.