diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index af270ac..8161242 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -47,14 +47,16 @@ jobs: ament_flake8 --config ament_flake8.ini \ movensys_navigation_description/launch \ movensys_navigation_nav2_config/launch \ - movensys_navigation_nav2_config/movensys_navigation_nav2_config + movensys_navigation_nav2_config/movensys_navigation_nav2_config \ + movensys_navigation_perception/launch - name: ament_xmllint (package.xml) run: | source /opt/ros/${{ matrix.ros_distro }}/setup.bash ament_xmllint \ movensys_navigation_description/package.xml \ - movensys_navigation_nav2_config/package.xml + movensys_navigation_nav2_config/package.xml \ + movensys_navigation_perception/package.xml - name: cppcheck (warnings only, never fails) run: | diff --git a/.github/workflows/movensys-navigation.yml b/.github/workflows/movensys-navigation.yml index 83624ea..6295bfd 100644 --- a/.github/workflows/movensys-navigation.yml +++ b/.github/workflows/movensys-navigation.yml @@ -25,8 +25,6 @@ jobs: - name: Setup ROS ${{ matrix.ros_distro }} uses: ros-tooling/setup-ros@v0.7 - with: - required-ros-distributions: ${{ matrix.ros_distro }} - name: Setup workspace run: | @@ -36,14 +34,20 @@ jobs: - name: Install dependencies run: | sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + ros-${{ matrix.ros_distro }}-ros-base # GH ubuntu-22.04 runners pin LLVM's libunwind, blocking the stock # libunwind-dev that libgoogle-glog-dev (via slam-toolbox) needs. sudo apt-get install -y libunwind-dev sudo rosdep init || true rosdep update cd ~/movensys_ws + # This job only compiles (BUILD_TESTING=OFF), so runtime deps such as + # navigation2, ros_gz_sim and rviz2 are not needed. rosdep install --from-paths src --ignore-src -y \ - --rosdistro ${{ matrix.ros_distro }} + --rosdistro ${{ matrix.ros_distro }} \ + -t buildtool -t build -t buildtool_export -t build_export \ + --skip-keys isaac_ros_visual_slam - name: Build run: | diff --git a/.github/workflows/test-nav2.yml b/.github/workflows/test-nav2.yml index e427429..4f3c4e3 100644 --- a/.github/workflows/test-nav2.yml +++ b/.github/workflows/test-nav2.yml @@ -27,8 +27,6 @@ jobs: - name: Setup ROS ${{ matrix.ros_distro }} uses: ros-tooling/setup-ros@v0.7 - with: - required-ros-distributions: ${{ matrix.ros_distro }} - name: Setup workspace run: | @@ -38,6 +36,8 @@ jobs: - name: Install dependencies run: | sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + ros-${{ matrix.ros_distro }}-ros-base # GH ubuntu-22.04 runners pin LLVM's libunwind, blocking the stock # libunwind-dev that libgoogle-glog-dev (via slam-toolbox) needs. sudo apt-get install -y libunwind-dev @@ -45,7 +45,9 @@ jobs: rosdep update cd ~/movensys_ws rosdep install --from-paths src --ignore-src -y \ - --rosdistro ${{ matrix.ros_distro }} + --rosdistro ${{ matrix.ros_distro }} \ + -t buildtool -t build -t buildtool_export -t build_export -t test \ + --skip-keys isaac_ros_visual_slam - name: Build run: | diff --git a/.github/workflows/test-perception.yml b/.github/workflows/test-perception.yml index 286848a..057d2b2 100644 --- a/.github/workflows/test-perception.yml +++ b/.github/workflows/test-perception.yml @@ -25,8 +25,6 @@ jobs: - name: Setup ROS ${{ matrix.ros_distro }} uses: ros-tooling/setup-ros@v0.7 - with: - required-ros-distributions: ${{ matrix.ros_distro }} - name: Setup workspace run: | @@ -36,6 +34,8 @@ jobs: - name: Install dependencies run: | sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + ros-${{ matrix.ros_distro }}-ros-base # GH ubuntu-22.04 runners pin LLVM's libunwind, blocking the stock # libunwind-dev that libgoogle-glog-dev (via slam-toolbox) needs. sudo apt-get install -y libunwind-dev @@ -43,7 +43,9 @@ jobs: rosdep update cd ~/movensys_ws rosdep install --from-paths src/movensys-navigation/movensys_navigation_perception \ - --ignore-src -y --rosdistro ${{ matrix.ros_distro }} + --ignore-src -y --rosdistro ${{ matrix.ros_distro }} \ + -t buildtool -t build -t buildtool_export -t build_export -t test \ + --skip-keys isaac_ros_visual_slam - name: Build run: | diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 60008f7..d6cb79b 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -45,7 +45,9 @@ jobs: rosdep update cd ~/movensys_ws rosdep install --from-paths src --ignore-src -y \ - --rosdistro ${{ matrix.ros_distro }} + --rosdistro ${{ matrix.ros_distro }} \ + -t buildtool -t build -t buildtool_export -t build_export -t test \ + --skip-keys isaac_ros_visual_slam - name: colcon build run: | @@ -54,6 +56,7 @@ jobs: colcon build --symlink-install \ --packages-select \ movensys_navigation_description \ + movensys_navigation_perception \ movensys_navigation_nav2_config - name: colcon test @@ -63,6 +66,7 @@ jobs: source install/setup.bash colcon test --packages-select \ movensys_navigation_description \ + movensys_navigation_perception \ movensys_navigation_nav2_config \ --event-handlers console_cohesion+ colcon test-result --verbose diff --git a/doc/3a_manual_simulation.md b/doc/3a_manual_simulation.md index daa97f1..855c382 100644 --- a/doc/3a_manual_simulation.md +++ b/doc/3a_manual_simulation.md @@ -25,9 +25,9 @@ nros ros2 launch movensys_navigation_nav2_config sim_bridge.launch.py use_sim_ti ### Step 3: Run EKF + RSP ``` -nros ros2 launch movensys_navigation_nav2_config base.launch.py use_sim_time:=true +nros ros2 launch movensys_navigation_nav2_config base.launch.py use_sim_time:=true ``` -add `rsp:=false` if use gazebo (step 1b). +add `rsp:=false` if use gazebo (step 1b) and add `use_cuvslam:=true` for use cuvslam. diff --git a/doc/3b_manual_hil.md b/doc/3b_manual_hil.md index 96a3083..1a333ae 100644 --- a/doc/3b_manual_hil.md +++ b/doc/3b_manual_hil.md @@ -23,7 +23,7 @@ set `use_sim_time:=true` ``` nros ros2 launch movensys_navigation_nav2_config base.launch.py use_sim_time:=true ``` -add `rsp:=false` if use gazebo (step 1b) or ros2_control. +add `rsp:=false` if use gazebo (step 1b) or ros2_control add `use_cuvslam:=true` for use cuvslam. diff --git a/doc/3c_manual_real.md b/doc/3c_manual_real.md index 7a13c66..2a3fa83 100644 --- a/doc/3c_manual_real.md +++ b/doc/3c_manual_real.md @@ -12,7 +12,7 @@ check `~/workspaces/movensys_ws/src/wmx-r2/doc/launch__navigat ``` nros ros2 launch movensys_navigation_nav2_config base.launch.py ``` -add `rsp:=false` if use ros2_control. +add `rsp:=false` if use ros2_control add `use_cuvslam:=true` for use cuvslam. diff --git a/doc/4a_mapping_simulation.md b/doc/4a_mapping_simulation.md index 744a44f..53fbd94 100644 --- a/doc/4a_mapping_simulation.md +++ b/doc/4a_mapping_simulation.md @@ -25,9 +25,9 @@ nros ros2 launch movensys_navigation_nav2_config sim_bridge.launch.py use_sim_ti ### Step 3: Mapping ``` -nros ros2 launch movensys_navigation_nav2_config mapping.launch.py use_sim_time:=true +nros ros2 launch movensys_navigation_nav2_config mapping.launch.py use_sim_time:=true ``` -add `rsp:=false` if use gazebo (step 1b) +add `rsp:=false` if use gazebo (step 1b) add `use_cuvslam:=true` for use cuvslam diff --git a/doc/4b_mapping_hil.md b/doc/4b_mapping_hil.md index 28b146d..1dc0880 100644 --- a/doc/4b_mapping_hil.md +++ b/doc/4b_mapping_hil.md @@ -25,7 +25,7 @@ set `use_sim_time:=true` ``` nros ros2 launch movensys_navigation_nav2_config mapping.launch.py use_sim_time:=true ``` -add `rsp:=false` if use gazebo (step 1b) or ros2_control. +add `rsp:=false` if use gazebo (step 1b) or ros2_control add `use_cuvslam:=true` for use cuvslam. diff --git a/doc/4c_mapping_real.md b/doc/4c_mapping_real.md index 8d60d10..bc42462 100644 --- a/doc/4c_mapping_real.md +++ b/doc/4c_mapping_real.md @@ -17,7 +17,7 @@ check `~/workspaces/movensys_ws/src/wmx-r2/doc/launch__navigat ``` nros ros2 launch movensys_navigation_nav2_config mapping.launch.py ``` -add `rsp:=false` if use ros2_control. +add `rsp:=false` if use ros2_control add `use_cuvslam:=true` for use cuvslam. diff --git a/doc/5a_navigation_simulation.md b/doc/5a_navigation_simulation.md index 3280992..93a4794 100644 --- a/doc/5a_navigation_simulation.md +++ b/doc/5a_navigation_simulation.md @@ -26,7 +26,7 @@ nros ros2 launch movensys_navigation_nav2_config sim_bridge.launch.py use_sim_ti ``` nros ros2 launch movensys_navigation_nav2_config navigation.launch.py use_sim_time:=true ``` -add `rsp:=false` if use gazebo (step 1b). +add `rsp:=false` if use gazebo (step 1b) add `use_cuvslam:=true` for use cuvslam. diff --git a/doc/5b_navigation_hil.md b/doc/5b_navigation_hil.md index 068b895..5f5ec12 100644 --- a/doc/5b_navigation_hil.md +++ b/doc/5b_navigation_hil.md @@ -21,7 +21,7 @@ set `use_sim_time:=true` ``` nros ros2 launch movensys_navigation_nav2_config navigation.launch.py use_sim_time:=true ``` -add `rsp:=false` if use gazebo (step 1b) or ros2_control. +add `rsp:=false` if use gazebo (step 1b) or ros2_control add `use_cuvslam:=true` for use cuvslam. diff --git a/doc/5c_navigation_real.md b/doc/5c_navigation_real.md index 62938c3..176803c 100644 --- a/doc/5c_navigation_real.md +++ b/doc/5c_navigation_real.md @@ -12,7 +12,7 @@ check `~/workspaces/movensys_ws/src/wmx-r2/doc/launch__navigat ``` nros ros2 launch movensys_navigation_nav2_config navigation.launch.py ``` -add `rsp:=false` if use ros2_control. +add `rsp:=false` if use ros2_control add `use_cuvslam:=true` for use cuvslam. ### Step 3: Set initial pose diff --git a/docker/isaac-ros_3.2.Dockerfile b/docker/isaac-ros_3.2.Dockerfile index 592fe49..0ee59c7 100644 --- a/docker/isaac-ros_3.2.Dockerfile +++ b/docker/isaac-ros_3.2.Dockerfile @@ -26,6 +26,7 @@ RUN apt-get update && \ ros-humble-rmw-cyclonedds-cpp \ ros-humble-tf-transformations \ ros-humble-isaac-ros-nvblox \ + ros-humble-isaac-ros-visual-slam \ ros-humble-isaac-ros-examples \ ros-humble-isaac-ros-realsense \ ros-humble-isaac-ros-ess \ diff --git a/docker/isaac-ros_4.1.Dockerfile b/docker/isaac-ros_4.1.Dockerfile index 9e81278..50b931d 100644 --- a/docker/isaac-ros_4.1.Dockerfile +++ b/docker/isaac-ros_4.1.Dockerfile @@ -36,6 +36,7 @@ RUN apt-get update && \ RUN apt-get update && \ apt-get install -y \ ros-jazzy-isaac-ros-nvblox \ + ros-jazzy-isaac-ros-visual-slam \ ros-jazzy-robot-localization \ ros-jazzy-slam-toolbox \ ros-jazzy-navigation2 \ diff --git a/movensys_navigation_description/launch/gazebo_navigation_simulation.launch.py b/movensys_navigation_description/launch/gazebo_navigation_simulation.launch.py index effea18..f2430ee 100644 --- a/movensys_navigation_description/launch/gazebo_navigation_simulation.launch.py +++ b/movensys_navigation_description/launch/gazebo_navigation_simulation.launch.py @@ -19,6 +19,9 @@ def generate_launch_description(): clock_msg = {'humble': 'ignition.msgs.Clock', 'jazzy': 'gz.msgs.Clock'}[ros_distro] imu_msg = {'humble': 'ignition.msgs.IMU', 'jazzy': 'gz.msgs.IMU'}[ros_distro] lidar_msg = {'humble': 'ignition.msgs.LaserScan', 'jazzy': 'gz.msgs.LaserScan'}[ros_distro] + image_msg = {'humble': 'ignition.msgs.Image', 'jazzy': 'gz.msgs.Image'}[ros_distro] + camera_info_msg = {'humble': 'ignition.msgs.CameraInfo', + 'jazzy': 'gz.msgs.CameraInfo'}[ros_distro] world_file = {'humble': 'arena_ign.world', 'jazzy': 'arena_gz.world'}[ros_distro] @@ -69,6 +72,14 @@ def generate_launch_description(): f'/imu@sensor_msgs/msg/Imu[{imu_msg}', f'/lidar_front_left_scan@sensor_msgs/msg/LaserScan[{lidar_msg}', f'/lidar_rear_right_scan@sensor_msgs/msg/LaserScan[{lidar_msg}', + f'/image_front_infra1/rgb@sensor_msgs/msg/Image[{image_msg}', + f'/image_front_infra1/rgb/camera_info@sensor_msgs/msg/CameraInfo[{camera_info_msg}', + f'/image_front_infra2/rgb@sensor_msgs/msg/Image[{image_msg}', + f'/image_front_infra2/rgb/camera_info@sensor_msgs/msg/CameraInfo[{camera_info_msg}', + ], + remappings=[ + ('/image_front_infra1/rgb/camera_info', '/image_front_infra1/camera_info'), + ('/image_front_infra2/rgb/camera_info', '/image_front_infra2/camera_info'), ], output='screen' ) diff --git a/movensys_navigation_description/urdf/diffbot/movensys_navigation.urdf b/movensys_navigation_description/urdf/diffbot/movensys_navigation.urdf index 0989fe8..cfc5e3f 100644 --- a/movensys_navigation_description/urdf/diffbot/movensys_navigation.urdf +++ b/movensys_navigation_description/urdf/diffbot/movensys_navigation.urdf @@ -111,6 +111,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/movensys_navigation_description/urdf/diffbot/perception.gazebo b/movensys_navigation_description/urdf/diffbot/perception.gazebo index e6c8637..09d2959 100644 --- a/movensys_navigation_description/urdf/diffbot/perception.gazebo +++ b/movensys_navigation_description/urdf/diffbot/perception.gazebo @@ -85,6 +85,51 @@ + + + + 0 0 0 0 0 0 + true + false + 30 + /image_front_infra1/rgb + camera_front_infra1_optical_frame + + 1.518 + + 640 + 360 + L8 + + + 0.1 + 30.0 + + + + + + 0 -0.095 0 0 0 0 + true + false + 30 + /image_front_infra2/rgb + camera_front_infra2_optical_frame + + 1.518 + + 640 + 360 + L8 + + + 0.1 + 30.0 + + + + + diff --git a/movensys_navigation_description/urdf/diffbot/perception.xacro b/movensys_navigation_description/urdf/diffbot/perception.xacro index eee0933..d9a56df 100644 --- a/movensys_navigation_description/urdf/diffbot/perception.xacro +++ b/movensys_navigation_description/urdf/diffbot/perception.xacro @@ -134,4 +134,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/movensys_navigation_nav2_config/config/diffbot/ekf_cuvslam.yaml b/movensys_navigation_nav2_config/config/diffbot/ekf_cuvslam.yaml new file mode 100644 index 0000000..41a97c9 --- /dev/null +++ b/movensys_navigation_nav2_config/config/diffbot/ekf_cuvslam.yaml @@ -0,0 +1,118 @@ +### ekf config file (with cuVSLAM visual-inertial odometry fused in) ### +# Same as ekf.yaml, plus odom1 = /visual_slam/tracking/odometry from Isaac ROS +# Visual SLAM (cuVSLAM). Selected by base.launch.py when use_cuvslam:=true. +# +# Sources fused here: +# odom0 (/odom_enc) -> wheel encoder twist (vx, vyaw) +# odom1 (/visual_slam/tracking/odometry)-> visual-inertial odometry (x, y, yaw) +# imu0 (/imu) -> wheeltec N100 IMU yaw + yaw rate +ekf_filter_node: + ros__parameters: + frequency: 50.0 + sensor_timeout: 0.1 + two_d_mode: true + transform_time_offset: 0.0 + transform_timeout: 0.0 + print_diagnostics: true + debug: false + debug_out_file: odometry_debug.txt + permit_corrected_publication: false + publish_acceleration: false + publish_tf: true + map_frame: map # Defaults to "map" if unspecified + odom_frame: odom # Defaults to "odom" if unspecified + base_link_frame: base_link # Defaults to "base_link" if unspecified + world_frame: odom # Defaults to the value of odom_frame if unspecified + + #The order of the values is + #x, y, z, + #roll, pitch, yaw, + #vx, vy, vz, + #vroll, vpitch, vyaw, + #ax, ay, az. + + odom0: /odom_enc + odom0_config: [false, false, false, + false, false, false, + true, true, false, + false, false, true, + false, false, false] + odom0_queue_size: 2 + odom0_nodelay: false + odom0_differential: false + odom0_relative: false + odom0_pose_rejection_threshold: 50.0 + odom0_twist_rejection_threshold: 10.0 + + # cuVSLAM visual-inertial odometry. Fused as a differential pose source so + # that its (drift-free over short horizons) relative motion complements the + # wheel encoder without fighting it over absolute position. two_d_mode keeps + # z/roll/pitch flat, so only x, y and yaw are pulled from it. + odom1: /visual_slam/tracking/odometry + odom1_config: [true, true, false, + false, false, true, + false, false, false, + false, false, false, + false, false, false] + odom1_queue_size: 10 + odom1_nodelay: true + odom1_differential: true + odom1_relative: false + odom1_pose_rejection_threshold: 5.0 + odom1_twist_rejection_threshold: 5.0 + + imu0: /imu + imu0_config: [false, false, false, + false, false, true, + false, false, false, + false, false, true, + false, false, false] + imu0_nodelay: false + imu0_differential: false + imu0_relative: true + imu0_queue_size: 5 + imu0_pose_rejection_threshold: 1.57 # Note the difference in parameter names + imu0_twist_rejection_threshold: 1.57 # + imu0_linear_acceleration_rejection_threshold: 5.0 # + imu0_remove_gravitational_acceleration: false + + use_control: true + stamped_control: true + control_timeout: 0.2 + control_config: [true, false, false, false, false, true] + acceleration_limits: [1.3, 0.0, 0.0, 0.0, 0.0, 3.4] + deceleration_limits: [1.3, 0.0, 0.0, 0.0, 0.0, 4.5] + acceleration_gains: [0.8, 0.0, 0.0, 0.0, 0.0, 0.9] + deceleration_gains: [1.0, 0.0, 0.0, 0.0, 0.0, 1.0] + + process_noise_covariance: [0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.06, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.03, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.06, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.025, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.025, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.04, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.01, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.015] + + initial_estimate_covariance: [1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1e-9] diff --git a/movensys_navigation_nav2_config/launch/__pycache__/base.launch.cpython-312.pyc b/movensys_navigation_nav2_config/launch/__pycache__/base.launch.cpython-312.pyc deleted file mode 100644 index f5d6c0f..0000000 Binary files a/movensys_navigation_nav2_config/launch/__pycache__/base.launch.cpython-312.pyc and /dev/null differ diff --git a/movensys_navigation_nav2_config/launch/base.launch.py b/movensys_navigation_nav2_config/launch/base.launch.py index bc07cb0..5061d4a 100644 --- a/movensys_navigation_nav2_config/launch/base.launch.py +++ b/movensys_navigation_nav2_config/launch/base.launch.py @@ -19,10 +19,13 @@ def generate_launch_description(): xacro_file = os.path.join(description_share, 'urdf', navigation_model, 'movensys_navigation.xacro') - ekf_config_file = os.path.join(nav2_config_share, 'config', navigation_model, 'ekf.yaml') + config_dir = os.path.join(nav2_config_share, 'config', navigation_model) + ekf_config_file = os.path.join(config_dir, 'ekf.yaml') + ekf_cuvslam_config_file = os.path.join(config_dir, 'ekf_cuvslam.yaml') rviz_config = os.path.join(nav2_config_share, 'rviz', 'navigation.rviz') use_sim_time = ParameterValue(LaunchConfiguration('use_sim_time'), value_type=bool) + use_cuvslam = LaunchConfiguration('use_cuvslam') robot_state_publisher = Node( package='robot_state_publisher', executable='robot_state_publisher', @@ -30,15 +33,33 @@ def generate_launch_description(): condition=IfCondition(LaunchConfiguration('rsp')), parameters=[{ 'use_sim_time': use_sim_time, - 'robot_description': Command(['xacro ', xacro_file, ' robot_name:=amr']), + 'robot_description': Command([ + 'xacro ', xacro_file, ' robot_name:=amr', + ' urdf_camera_optical_tf:=', LaunchConfiguration('use_sim_time'), + ]), }]) start_robot_localization = Node( package='robot_localization', executable='ekf_node', name='ekf_filter_node', output='screen', + condition=UnlessCondition(use_cuvslam), parameters=[ekf_config_file, {'use_sim_time': use_sim_time}], remappings=[('odometry/filtered', 'odom'), ('cmd_vel', 'cmd_vel_safe')]) + start_robot_localization_cuvslam = Node( + package='robot_localization', executable='ekf_node', + name='ekf_filter_node', output='screen', + condition=IfCondition(use_cuvslam), + parameters=[ekf_cuvslam_config_file, {'use_sim_time': use_sim_time}], + remappings=[('odometry/filtered', 'odom'), ('cmd_vel', 'cmd_vel_safe')]) + + # cuVSLAM (Isaac ROS Visual SLAM) + RealSense driver. + start_visual_slam = IncludeLaunchDescription( + PythonLaunchDescriptionSource( + os.path.join(perception_share, 'launch', 'cuvslam.launch.py')), + condition=IfCondition(use_cuvslam), + launch_arguments={'use_sim_time': LaunchConfiguration('use_sim_time')}.items()) + rviz = Node( package='rviz2', executable='rviz2', name='rviz2', arguments=['-d', rviz_config], @@ -64,8 +85,17 @@ def generate_launch_description(): description='Publish /robot_description here. Set false when a backend ' 'launch (Gazebo sim or wmx_r2_control) already publishes it.', ), + DeclareLaunchArgument( + 'use_cuvslam', + default_value='false', + description='Fuse Isaac ROS Visual SLAM (cuVSLAM) into the EKF. When true, ' + 'the EKF uses ekf_cuvslam.yaml and the RealSense + cuVSLAM stack ' + 'is launched (requires an isaac-ros_* image).', + ), robot_state_publisher, start_robot_localization, + start_robot_localization_cuvslam, + start_visual_slam, rviz, start_perception, ]) diff --git a/movensys_navigation_nav2_config/launch/mapping.launch.py b/movensys_navigation_nav2_config/launch/mapping.launch.py index cdc8e2c..e7bde92 100644 --- a/movensys_navigation_nav2_config/launch/mapping.launch.py +++ b/movensys_navigation_nav2_config/launch/mapping.launch.py @@ -21,6 +21,7 @@ def generate_launch_description(): launch_arguments={ 'use_sim_time': use_sim_time, 'rsp': LaunchConfiguration('rsp'), + 'use_cuvslam': LaunchConfiguration('use_cuvslam'), }.items()) start_slam_toolbox = IncludeLaunchDescription( @@ -43,6 +44,10 @@ def generate_launch_description(): description='Publish /robot_description via base.launch.py. Set false when a ' 'backend launch (Gazebo sim or wmx_r2_control) already publishes it.', ), + DeclareLaunchArgument( + 'use_cuvslam', default_value='false', + description='Fuse Isaac ROS Visual SLAM (cuVSLAM) into the EKF (see base.launch.py).', + ), start_base, start_slam_toolbox, ]) diff --git a/movensys_navigation_nav2_config/launch/navigation.launch.py b/movensys_navigation_nav2_config/launch/navigation.launch.py index 7e602d8..259efae 100644 --- a/movensys_navigation_nav2_config/launch/navigation.launch.py +++ b/movensys_navigation_nav2_config/launch/navigation.launch.py @@ -45,6 +45,7 @@ def generate_launch_description(): launch_arguments={ 'use_sim_time': LaunchConfiguration('use_sim_time'), 'rsp': LaunchConfiguration('rsp'), + 'use_cuvslam': LaunchConfiguration('use_cuvslam'), }.items()) # --- localization (map_server + amcl) --- @@ -110,6 +111,9 @@ def generate_launch_description(): 'rsp', default_value='true', description='Publish /robot_description via base.launch.py. Set false when a ' 'backend launch (Gazebo sim or wmx_r2_control) already publishes it.'), + DeclareLaunchArgument( + 'use_cuvslam', default_value='false', + description='Fuse Isaac ROS Visual SLAM (cuVSLAM) into the EKF (see base.launch.py).'), start_base, map_server, amcl, diff --git a/movensys_navigation_nav2_config/package.xml b/movensys_navigation_nav2_config/package.xml index 702aa96..2d8552f 100644 --- a/movensys_navigation_nav2_config/package.xml +++ b/movensys_navigation_nav2_config/package.xml @@ -11,8 +11,9 @@ urdf xacro - ros_gz_sim - ros2_control + + ros_gz_sim + ros2_control rclcpp sensor_msgs @@ -35,6 +36,8 @@ slam_toolbox + movensys_navigation_perception + navigation2 nav2_bringup diff --git a/movensys_navigation_perception/CMakeLists.txt b/movensys_navigation_perception/CMakeLists.txt index e1a0d8b..3e8c2cb 100644 --- a/movensys_navigation_perception/CMakeLists.txt +++ b/movensys_navigation_perception/CMakeLists.txt @@ -26,6 +26,7 @@ if(BUILD_TESTING) endif() install(DIRECTORY + config launch DESTINATION share/${PROJECT_NAME} ) diff --git a/movensys_navigation_perception/config/diffbot/cuvslam.yaml b/movensys_navigation_perception/config/diffbot/cuvslam.yaml new file mode 100644 index 0000000..80ea08b --- /dev/null +++ b/movensys_navigation_perception/config/diffbot/cuvslam.yaml @@ -0,0 +1,56 @@ +### Isaac ROS Visual SLAM (cuVSLAM) config ### +# Stereo-inertial visual odometry from a RealSense D455 (infra1/infra2 + IMU). +# The node publishes /visual_slam/tracking/odometry, which the EKF fuses as an +# extra odometry source (see ekf_cuvslam.yaml). TF publishing is disabled here +# because robot_localization's EKF owns the odom -> base_link transform. +visual_slam_node: + ros__parameters: + # --- frames --- + # base_frame chains to the camera optical frames via: + # base_link -> camera_front_link (URDF/robot_state_publisher) + # camera_front_link -> camera_front_*_optical_frame (realsense2_camera) + base_frame: base_link + odom_frame: odom + map_frame: map + # One D455 = two imagers. Order must match the image_N remaps in + # cuvslam.launch.py: image_0 -> infra1 (left), image_1 -> infra2 (right). + # These names come from the driver's node name (camera_front); the driver + # fixes the suffixes, so infra1/infra2 rather than left/right. + camera_optical_frames: [camera_front_infra1_optical_frame, + camera_front_infra2_optical_frame] + + imu_frame: camera_front_gyro_optical_frame + + # --- cameras --- + num_cameras: 2 + # RealSense infra streams are already rectified/undistorted. + rectified_images: true + enable_image_denoising: false + image_jitter_threshold_ms: 34.0 + + # --- inertial fusion (D455 IMU) --- + enable_imu_fusion: false + # Noise characteristics for the BMI055 (Isaac ROS reference values). + gyro_noise_density: 0.000244 + gyro_random_walk: 0.000019393 + accel_noise_density: 0.001862 + accel_random_walk: 0.003 + calibration_frequency: 200.0 + + # --- odometry vs. full SLAM --- + # false = pure visual(-inertial) odometry (VO), the mode used to feed the + # EKF. Set true to enable landmark mapping + loop closure if you + # later want cuVSLAM to also correct map -> odom drift. + enable_localization_n_mapping: false + + # --- TF ownership --- + # The EKF publishes odom -> base_link, so keep both off here. + publish_odom_to_base_tf: false + publish_map_to_odom_tf: false + invert_odom_to_base_tf: false + + # --- visualization (off by default; enable for debugging in RViz) --- + enable_slam_visualization: false + enable_landmarks_view: false + enable_observations_view: false + verbosity: 0 diff --git a/movensys_navigation_perception/config/diffbot/realsense_front.yaml b/movensys_navigation_perception/config/diffbot/realsense_front.yaml new file mode 100644 index 0000000..aa8f7f5 --- /dev/null +++ b/movensys_navigation_perception/config/diffbot/realsense_front.yaml @@ -0,0 +1,30 @@ +/**: + ros__parameters: + device_type: '' + serial_no: '333422302722' + usb_port_id: '' + + enable_infra1: true + enable_infra2: true + enable_color: false + enable_depth: false + + depth_module: + emitter_enabled: 0 + profile: '640x360x90' + + enable_gyro: true + enable_accel: true + gyro_fps: 200 + accel_fps: 200 + unite_imu_method: 2 + + enable_sync: true + + camera_resolution: + width: 640 + height: 480 + camera_name: 'camera_front' + focal_length: + f_x: 380.0 + f_y: 380.0 diff --git a/movensys_navigation_perception/launch/__pycache__/diffbot_perception.launch.cpython-312.pyc b/movensys_navigation_perception/launch/__pycache__/diffbot_perception.launch.cpython-312.pyc deleted file mode 100644 index 1c49f56..0000000 Binary files a/movensys_navigation_perception/launch/__pycache__/diffbot_perception.launch.cpython-312.pyc and /dev/null differ diff --git a/movensys_navigation_perception/launch/cuvslam.launch.py b/movensys_navigation_perception/launch/cuvslam.launch.py new file mode 100644 index 0000000..66d42fd --- /dev/null +++ b/movensys_navigation_perception/launch/cuvslam.launch.py @@ -0,0 +1,48 @@ +import os + +from ament_index_python.packages import get_package_share_directory +from launch import LaunchDescription +from launch.actions import DeclareLaunchArgument +from launch.substitutions import LaunchConfiguration +from launch_ros.actions import ComposableNodeContainer +from launch_ros.descriptions import ComposableNode + + +def generate_launch_description(): + navigation_model = os.environ.get('NAVIGATION_MODEL', 'diffbot') + perception_share = get_package_share_directory('movensys_navigation_perception') + vslam_params = os.path.join( + perception_share, 'config', navigation_model, 'cuvslam.yaml') + + use_sim_time = LaunchConfiguration('use_sim_time') + + visual_slam_node = ComposableNode( + name='visual_slam_node', + package='isaac_ros_visual_slam', + plugin='nvidia::isaac_ros::visual_slam::VisualSlamNode', + parameters=[vslam_params, {'use_sim_time': use_sim_time}], + remappings=[ + ('visual_slam/image_0', '/image_front_infra1/rgb'), + ('visual_slam/camera_info_0', '/image_front_infra1/camera_info'), + ('visual_slam/image_1', '/image_front_infra2/rgb'), + ('visual_slam/camera_info_1', '/image_front_infra2/camera_info'), + ], + ) + + visual_slam_container = ComposableNodeContainer( + name='visual_slam_container', + namespace='', + package='rclcpp_components', + executable='component_container_mt', + composable_node_descriptions=[visual_slam_node], + output='screen', + ) + + return LaunchDescription([ + DeclareLaunchArgument( + 'use_sim_time', + default_value='false', + description='Use simulation (Gazebo/Isaac) clock if true', + ), + visual_slam_container, + ]) diff --git a/movensys_navigation_perception/launch/diffbot_perception.launch.py b/movensys_navigation_perception/launch/diffbot_perception.launch.py index 93288b4..f0d7840 100644 --- a/movensys_navigation_perception/launch/diffbot_perception.launch.py +++ b/movensys_navigation_perception/launch/diffbot_perception.launch.py @@ -1,10 +1,32 @@ import math +import os +from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): + pkg_share = get_package_share_directory('movensys_navigation_perception') + navigation_model = os.environ.get('NAVIGATION_MODEL', 'diffbot') + realsense_config = os.path.join(pkg_share, 'config', navigation_model, + 'realsense_front.yaml') + + camera_front_node = Node( + package='realsense2_camera', + executable='realsense2_camera_node', + name='realsense2_camera', + namespace='camera_front', + parameters=[realsense_config], + output='screen', + remappings=[ + ('realsense2_camera/infra1/image_rect_raw', '/image_front_infra1/rgb'), + ('realsense2_camera/infra1/camera_info', '/image_front_infra1/camera_info'), + ('realsense2_camera/infra2/image_rect_raw', '/image_front_infra2/rgb'), + ('realsense2_camera/infra2/camera_info', '/image_front_infra2/camera_info'), + ], + ) + lidar_front_left_node = Node( package='sick_safetyscanners2', executable='sick_safetyscanners2_node', @@ -12,25 +34,25 @@ def generate_launch_description(): output='screen', emulate_tty=True, parameters=[ - {"frame_id": "scan", - "sensor_ip": "192.168.29.11", - "host_ip": "192.168.29.44", - "interface_ip": "0.0.0.0", - "host_udp_port": 0, - "channel": 0, - "channel_enabled": True, - "skip": 0, - "angle_start": math.radians(-130), - "angle_end": math.radians(130), - "time_offset": 0.0, - "general_system_state": True, - "derived_settings": True, - "measurement_data": True, - "intrusion_data": True, - "application_io_data": True, - "use_persistent_config": False, - "min_intensities": 0.0, - "max_distance": 30} + {'frame_id': 'scan', + 'sensor_ip': '192.168.29.11', + 'host_ip': '192.168.29.44', + 'interface_ip': '0.0.0.0', + 'host_udp_port': 0, + 'channel': 0, + 'channel_enabled': True, + 'skip': 0, + 'angle_start': math.radians(-130), + 'angle_end': math.radians(130), + 'time_offset': 0.0, + 'general_system_state': True, + 'derived_settings': True, + 'measurement_data': True, + 'intrusion_data': True, + 'application_io_data': True, + 'use_persistent_config': False, + 'min_intensities': 0.0, + 'max_distance': 30} ], ) @@ -41,25 +63,25 @@ def generate_launch_description(): output='screen', emulate_tty=True, parameters=[ - {"frame_id": "scan", - "sensor_ip": "192.168.29.12", - "host_ip": "192.168.29.44", - "interface_ip": "0.0.0.0", - "host_udp_port": 0, - "channel": 0, - "channel_enabled": True, - "skip": 0, - "angle_start": math.radians(-130), - "angle_end": math.radians(130), - "time_offset": 0.0, - "general_system_state": True, - "derived_settings": True, - "measurement_data": True, - "intrusion_data": True, - "application_io_data": True, - "use_persistent_config": False, - "min_intensities": 0.0, - "max_distance": 30} + {'frame_id': 'scan', + 'sensor_ip': '192.168.29.12', + 'host_ip': '192.168.29.44', + 'interface_ip': '0.0.0.0', + 'host_udp_port': 0, + 'channel': 0, + 'channel_enabled': True, + 'skip': 0, + 'angle_start': math.radians(-130), + 'angle_end': math.radians(130), + 'time_offset': 0.0, + 'general_system_state': True, + 'derived_settings': True, + 'measurement_data': True, + 'intrusion_data': True, + 'application_io_data': True, + 'use_persistent_config': False, + 'min_intensities': 0.0, + 'max_distance': 30} ], ) @@ -69,10 +91,10 @@ def generate_launch_description(): name='imu_node', output='screen', parameters=[ - {"serial_port": "/dev/ttyACM0", - "serial_baud": 921600} + {'serial_port': '/dev/ttyACM0', + 'serial_baud': 921600} ], ) return LaunchDescription( - [lidar_front_left_node, lidar_rear_right_node, imu_node]) + [camera_front_node, lidar_front_left_node, lidar_rear_right_node, imu_node]) diff --git a/movensys_navigation_perception/package.xml b/movensys_navigation_perception/package.xml index 170963d..75b2f56 100644 --- a/movensys_navigation_perception/package.xml +++ b/movensys_navigation_perception/package.xml @@ -11,7 +11,11 @@ ament_cmake ros2launch - + + isaac_ros_visual_slam + realsense2_camera + rclcpp_components + ament_lint_auto ament_lint_common