This repository provides a ROS2 package that estimates stereo visual inertial odometry using the Isaac Elbrus GPU-accelerated library. It takes in a time synced pair of stereo images (grayscale) along with respective camera intrinsics to publish the current pose of the camera relative to its start pose.
Elbrus is based on two core technologies: Visual Odometry (VO) and Simultaneous Localization and Mapping (SLAM).
Visual Odometry is a method for estimating a camera position relative to its start position. This method has an iterative nature. At each iteration it considers two consequential input frames (stereo pairs). On both frames, it finds a set of keypoints. Matching keypoints in these two sets gives the ability to estimate the transition and relative rotation of the camera between frames.
Simultaneous Localization and Mapping is a method built on top of the VO predictions. It aims to improve the quality of VO estimations by leveraging the knowledge of previously seen parts of a trajectory. It detects if the current scene was seen in the past (i.e. a loop in camera movement) and runs an additional optimization procedure to tune previously obtained poses.
Along with visual data Elbrus can optionally use Inertial Measurement Unit (IMU) measurements. It automatically switches to IMU when VO is unable to estimate a pose–for example, when there is dark lighting or long solid surfaces in front of a camera.
Elbrus delivers real-time tracking performance: more than 60 FPS for VGA resolution. For the KITTI benchmark, the algorithm achieves a drift of ~1% in localization and an orientation error of 0.003 degrees per meter of motion.
Elbrus allows for robust tracking in various environments and with different use cases: indoor, outdoor, aerial, HMD, automotive, and robotics.
This has been tested on ROS2 (Foxy) and should build and run on x86_64 and aarch64 (Jetson).
This Isaac ROS package is designed and tested to be compatible with ROS2 Foxy on Jetson hardware.
- AGX Xavier or Xavier NX
- JetPack 4.6
- CUDA 10.2+ supported discrete GPU
- Ubuntu 18.04+
Note: For best performance on Jetson, ensure that power settings are configured appropriately (Power Management for Jetson).
Precompiled ROS2 Foxy packages are not available for JetPack 4.6 (based on Ubuntu 18.04 Bionic). You can either manually compile ROS2 Foxy and required dependent packages from source or use the Isaac ROS development Docker image from Isaac ROS Common.
You must first install the Nvidia Container Toolkit to make use of the Docker container development/runtime environment.
Configure nvidia-container-runtime
as the default runtime for Docker by editing /etc/docker/daemon.json
to include the following:
"runtimes": {
"nvidia": {
"path": "nvidia-container-runtime",
"runtimeArgs": []
}
},
"default-runtime": "nvidia"
and then restarting Docker: sudo systemctl daemon-reload && sudo systemctl restart docker
Run the following script in isaac_ros_common
to build the image and launch the container:
$ scripts/run_dev.sh <optional path>
You can either provide an optional path to mirror in your host ROS workspace with Isaac ROS packages, which will be made available in the container as /workspaces/isaac_ros-dev
, or you can setup a new workspace in the container.
Note: isaac_ros_common
is used for running tests and/or creating a development container.
Elbrus provides the user with two possible modes: visual odometry with SLAM (rectified transform) or pure visual odometry (smooth transform).
Using rectified transform (enable_rectified_pose = true
) is more beneficial in cases when the camera path is frequently encircled or entangled. Though rectified transform increases computational resource demands for VO, it usually reduces the final position drift dramatically.
On the other hand, using pure VO (smooth tranform) may be useful on relatively short and straight camera trails. This choice will reduce compute usage and increase working speed without causing essential pose drift.
This section describes the coordinate frames that are involved in the VisualOdomertyNode
. The frames discussed below are oriented as follows:
left_camera_frame
: The frame associated with left eye of the stereo camera. Note that this is not the same as optical frame.right_camera_frame
: The frame associated with right eye of the stereo camera. Note that this is not the same as optical frame.imu_frame
: The frame associated with the IMU sensor (if available).fixed_frame
: The fixed frame that aligns with the start pose of the stereo camera. The tracked poses are published in the tf tree with respect to this frame.current_smooth_frame
: The moving frame that tracks the current smooth pose of the stereo camera. The poses in this frame represent a smooth continous motion. Note that the frame can drift over time.current_rectified_frame
: The moving frame that tracks the current rectified pose of the stereo camera. The poses in this frame represent an accurate position and orientation. Note that the frame can have sudden jumps.
- Create a ROS2 workspace if one is not already prepared:
mkdir -p your_ws/src
Note: The workspace can have any name; these steps use the nameyour_ws
. - Clone this package repository to
your_ws/src/isaac_ros_visual_odometry
. Check that you have Git LFS installed before cloning to pull down all large files.
sudo apt-get install git-lfs
cd your_ws/src && git clone https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_visual_odometry
- Build and source the workspace:
cd your_ws && colcon build --symlink-install && source install/setup.bash
- (Optional) Run tests to verify complete and correct installation:
colcon test
This repository comes with pre-configured launch files for a real camera and a simulator.
Note: You will need to calibrate the intrinsics of your camera if you want the node to determine the 3D pose of your camera. See here for more details.
-
Start
isaac_ros_visual_odometry
using the launch files:
ros2 launch isaac_ros_visual_odometry isaac_ros_visual_odometry_realsense.launch.py
-
To connect the RealSense camera default tf tree to the
current_smooth_frame
(default value is base_link_smooth), run the following command:
ros2 run tf2_ros static_transform_publisher 0 0 0 0 0 0 1 base_link_smooth camera_link
-
In a separate terminal, spin up RViz to see the tracking of the camera:
rviz2
-
Add the tf tree in the Displays panel of the RViz.
-
Set the Fixed frame in the Global Options to the name provided in the
fixed_frame
variable.
-
Try moving your camera, and you should see something like this:
-
If you prefer to observe the Visual Odometry output in a text mode, on a separate terminal echo the contents of the
/visual_odometry/tf_stamped
topic with the following command:
ros2 topic echo /visual_odometry/tf_stamped
- Before launching the
isaac_ros_visual_odometry
node, set up a Isaac Sim ROS2 bridge as described here. - After that, follow this link to open up the ROS Stereo example.
- Note: The default stereo offset for the right camera from Isaac Sim is zero. Change the x value to
-175.92
and keep the y value to0.0
.
- Press Play to start publishing the data from Isaac SIM.
- In a seprate terminal, start
isaac_ros_visual_odometry
using the launch files:
ros2 launch isaac_ros_visual_odometry isaac_ros_visual_odometry_isaac_sim.launch.py
- In a separate terminal, send the signal to rotate the robot in the sim as follows:
ros2 topic pub /cmd_vel geometry_msgs/Twist '{linear: {x: 0.0, y: 0.0, z: 0.0}, angular: {x: 0.0,y: 0.0,z: 0.05}}'
- In a separate terminal, spin up the RViz to see the tracking of the robot:
rviz2
- Add the tf tree in the Displays RViz panel.
- Set the Fixed frame in the Global Options to the name provided in the
fixed_frame
variable.
- You should see something like this:
- If you prefer to observe the Visual Odometry output in a text mode, on a separate terminal, echo the contents of the
/visual_odometry/tf_stamped
topic with the following command:
ros2 topic echo /visual_odometry/tf_stamped
Component | Topics Subscribed | Topics Published | Parameters |
---|---|---|---|
VisualOdometryNode |
/stereo_camera/left/image : The image from the left eye of the stereo camera in grayscale /stereo_camera/left/camera_info : CameraInfo from the left eye of the stereo camera /stereo_camera/right/image : The image from the right eye of the stereo camera in grayscale /stereo_camera/right/camera_info : CameraInfo from the right eye of the stereo camera visual_odometry/imu : Sensor data from IMU(optional). |
/visual_odometry/tf_stamped : A consolidated message that provies information about the tracked poses. It consists of two poses: smooth_transform is calculated from pure visual odometry; rectified_transform is calculated with SLAM enabled. It also gives the states of both poses. See more details below. |
enable_rectified_pose : If enabled, rectified_transform will be populated in the message. It is enabled by default.denoise_input_images : If enabled, input images are denoised. It can be enabled when images are noisy because of low-light conditions. It is disabled by default. rectified_images : Flag to mark if the images coming in the subscribed topics are rectified or raw. It is enabled by default. enable_imu : If enabled, IMU data is used. It is disabled by default. enable_debug_mode : If enabled, a debug dump(image frames, timestamps, and camera info) is saved on to the disk at the path indicated by debug_dump_path . It is disabled by default debug_dump_path : The path to the directory to store the debug dump data. The default value is /tmp/elbrus . gravitational_force : The initial gravity vector defined in the odom frame. If the IMU sensor is not parallel to the floor, update all the axes with appropriate values. The default value is {0.0, 0, -9.8} . left_camera_frame : The name of the left camera frame. The default value is left_cam . right_camera_frame : The name of the right camera frame. The default value is right_cam . imu_frame : The name of the imu frame. The default value is imu . fixed_frame : The name of the frame where odomerty or poses are tracked. This is a fixed frame. The default value is odom . current_smooth_frame : The name of the frame where smooth_transform is published. This is a moving frame. The default value is base_link_smooth. current_rectified_frame : The name of the frame where rectified_transform is published. This is a moving frame. The default value is base_link_rectified . |
# The frame id in the header is used as the reference frame of both the transforms below.
std_msgs/Header header
# The frame id of the child frame to which the transforms point.
string child_frame_id
# Translation and rotation in 3-dimensions of child_frame_id from header.frame_id.
# rectified_tranform represents the most accurate position and orientation.
# It shall be consumed if robust tracking is needed. Note: It can result in sudden jumps.
geometry_msgs/Transform rectified_transform
# smooth_transform represents the position and orientation which corresponds to a smooth continous motion.
# It shall be consumed if using as another signal for e.g. in case of sensor fusion.
# Note: It might drift over time
geometry_msgs/Transform smooth_transform
# Pure visual odometry return code:
# 0 - Unknown state
# 1 - Success
# 2 - Failed
# 3 - Success but invalidated by IMU
uint8 vo_state
# Integrator status:
# 0 - Unknown state
# 1 - Static
# 2 - Inertial
# 3 - IMU
uint8 integrator_state
- If RViz is not showing the poses, check the Fixed Frame value.
- If you are seeing
Tracker is lost.
messages frequently, it could be caused by the following issues:- Fast motion causing the motion blur in the frames.
- Low-lighting conditions
- The wrong
camerainfo
is being published
- For better performance:
- Increase the capture framerate from the camera to yield a better tracking result.
- If input images are noisy, you can use the
denoise_input_images
flag in the node.
Date | Changes |
---|---|
2021-10-20 | Initial release |