rpng / open_vins

An open source platform for visual-inertial navigation research.
https://docs.openvins.com
GNU General Public License v3.0
2.21k stars 653 forks source link

Failed to initialize: D455+Jetson Orin on a drone #373

Closed mzahana closed 1 year ago

mzahana commented 1 year ago

Hi @goldbattle

I have the following setup

The above is mounted on a drone

estimator_config.yaml

%YAML:1.0 # need to specify the file type at the top!

verbosity: "INFO" # ALL, DEBUG, INFO, WARNING, ERROR, SILENT

use_fej: true # if first-estimate Jacobians should be used (enable for good consistency)
integration: "rk4" # discrete, rk4, analytical (if rk4 or analytical used then analytical covariance propagation is used)
use_stereo: true # if we have more than 1 camera, if we should try to track stereo constraints between pairs
max_cameras: 2 # how many cameras we have 1 = mono, 2 = stereo, >2 = binocular (all mono tracking)

calib_cam_extrinsics: true # if the transform between camera and IMU should be optimized R_ItoC, p_CinI
calib_cam_intrinsics: true # if camera intrinsics should be optimized (focal, center, distortion)
calib_cam_timeoffset: true # if timeoffset between camera and IMU should be optimized
calib_imu_intrinsics: false # if imu intrinsics should be calibrated (rotation and skew-scale matrix)
calib_imu_g_sensitivity: false # if gyroscope gravity sensitivity (Tg) should be calibrated

max_clones: 11 # how many clones in the sliding window
max_slam: 50 # number of features in our state vector
max_slam_in_update: 25 # update can be split into sequential updates of batches, how many in a batch
max_msckf_in_update: 40 # how many MSCKF features to use in the update
dt_slam_delay: 1 # delay before initializing (helps with stability from bad initialization...)

gravity_mag: 9.81 # magnitude of gravity in this location

feat_rep_msckf: "GLOBAL_3D"
feat_rep_slam: "ANCHORED_MSCKF_INVERSE_DEPTH"
feat_rep_aruco: "ANCHORED_MSCKF_INVERSE_DEPTH"

# zero velocity update parameters we can use
# we support either IMU-based or disparity detection.
try_zupt: false
zupt_chi2_multipler: 0 # set to 0 for only disp-based
zupt_max_velocity: 0.1
zupt_noise_multiplier: 10
zupt_max_disparity: 0.5 # set to 0 for only imu-based
zupt_only_at_beginning: false

# ==================================================================
# ==================================================================

init_window_time: 5.0 # how many seconds to collect initialization information
init_imu_thresh: 1.5 # threshold for variance of the accelerometer to detect a "jerk" in motion
init_max_disparity: 10.0 # max disparity to consider the platform stationary (dependent on resolution)
init_max_features: 50 # how many features to track during initialization (saves on computation)

init_dyn_use: false # if dynamic initialization should be used
init_dyn_mle_opt_calib: false # if we should optimize calibration during intialization (not recommended)
init_dyn_mle_max_iter: 50 # how many iterations the MLE refinement should use (zero to skip the MLE)
init_dyn_mle_max_time: 0.05 # how many seconds the MLE should be completed in
init_dyn_mle_max_threads: 6 # how many threads the MLE should use
init_dyn_num_pose: 6 # number of poses to use within our window time (evenly spaced)
init_dyn_min_deg: 10.0 # orientation change needed to try to init

init_dyn_inflation_ori: 10 # what to inflate the recovered q_GtoI covariance by
init_dyn_inflation_vel: 100 # what to inflate the recovered v_IinG covariance by
init_dyn_inflation_bg: 10 # what to inflate the recovered bias_g covariance by
init_dyn_inflation_ba: 100 # what to inflate the recovered bias_a covariance by
init_dyn_min_rec_cond: 1e-12 # reciprocal condition number thresh for info inversion

init_dyn_bias_g: [ 0.0, 0.0, 0.0 ] # initial gyroscope bias guess
init_dyn_bias_a: [ 0.0, 0.0, 0.0 ] # initial accelerometer bias guess

# ==================================================================
# ==================================================================

record_timing_information: false # if we want to record timing information of the method
record_timing_filepath: "/tmp/traj_timing.txt" # https://docs.openvins.com/eval-timing.html#eval-ov-timing-flame

# if we want to save the simulation state and its diagional covariance
# use this with rosrun ov_eval error_simulation
save_total_state: false
filepath_est: "/tmp/ov_estimate.txt"
filepath_std: "/tmp/ov_estimate_std.txt"
filepath_gt: "/tmp/ov_groundtruth.txt"

# ==================================================================
# ==================================================================

# our front-end feature tracking parameters
# we have a KLT and descriptor based (KLT is better implemented...)
use_klt: true # if true we will use KLT, otherwise use a ORB descriptor + robust matching
num_pts: 200 # number of points (per camera) we will extract and try to track
fast_threshold: 30 # threshold for fast extraction (warning: lower threshs can be expensive)
grid_x: 5 # extraction sub-grid count for horizontal direction (uniform tracking)
grid_y: 5 # extraction sub-grid count for vertical direction (uniform tracking)
min_px_dist: 15 # distance between features (features near each other provide less information)
knn_ratio: 0.70 # descriptor knn threshold for the top two descriptor matches
track_frequency: 31.0 # frequency we will perform feature tracking at (in frames per second / hertz)
downsample_cameras: false # will downsample image in half if true
num_opencv_threads: 4 # -1: auto, 0-1: serial, >1: number of threads
histogram_method: "HISTOGRAM" # NONE, HISTOGRAM, CLAHE

# aruco tag tracker for the system
# DICT_6X6_1000 from https://chev.me/arucogen/
use_aruco: false
num_aruco: 1024
downsize_aruco: true

# ==================================================================
# ==================================================================

# camera noises and chi-squared threshold multipliers
up_msckf_sigma_px: 1
up_msckf_chi2_multipler: 1
up_slam_sigma_px: 1
up_slam_chi2_multipler: 1
up_aruco_sigma_px: 1
up_aruco_chi2_multipler: 1

# masks for our images
use_mask: false

# imu and camera spacial-temporal
# imu config should also have the correct noise values
relative_config_imu: "kalibr_imu_chain.yaml"
relative_config_imucam: "kalibr_imucam_chain.yaml"

kalibr_imu_chain.yaml

%YAML:1.0

imu0:
  T_i_b:
    - [1.0, 0.0, 0.0, 0.0]
    - [0.0, 1.0, 0.0, 0.0]
    - [0.0, 0.0, 1.0, 0.0]
    - [0.0, 0.0, 0.0, 1.0]
  # Values from allan plots
  # https://github.com/rpng/ar_table_dataset
  #accelerometer_noise_density: 0.0010382453726199955
  #accelerometer_random_walk: 4.132785219723178e-05
  #gyroscope_noise_density: 0.00010272083263292572
  #gyroscope_random_walk: 1.1106223553679963e-06
  # Inflated values (to account for unmodelled effects)
  # density x5
  # walk x10
  #Accelerometer
  accelerometer_noise_density: 0.018325460766195713 
  accelerometer_random_walk: 0.0031526548679969497 
  #Gyroscope
  gyroscope_noise_density: 0.005658445654838128
  gyroscope_random_walk: 4.9244827968800026e-04 
  rostopic: /camera/imu
  time_offset: 0.0
  update_rate: 200
  # three different modes supported:
  # "calibrated" (same as "kalibr"), "kalibr", "rpng"
  model: "kalibr"
  # how to get from Kalibr imu.yaml result file:
  #   - Tw is imu0:gyroscopes:M:
  #   - R_IMUtoGYRO: is imu0:gyroscopes:M:
  #   - Ta is imu0:accelerometers:M:
  #   - R_IMUtoACC not used by Kalibr
  #   - Tg is imu0:gyroscopes:A:
  Tw:
    - [ 1.0, 0.0, 0.0 ]
    - [ 0.0, 1.0, 0.0 ]
    - [ 0.0, 0.0, 1.0 ]
  R_IMUtoGYRO:
    - [ 1.0, 0.0, 0.0 ]
    - [ 0.0, 1.0, 0.0 ]
    - [ 0.0, 0.0, 1.0 ]
  Ta:
    - [ 1.0, 0.0, 0.0 ]
    - [ 0.0, 1.0, 0.0 ]
    - [ 0.0, 0.0, 1.0 ]
  R_IMUtoACC:
    - [ 1.0, 0.0, 0.0 ]
    - [ 0.0, 1.0, 0.0 ]
    - [ 0.0, 0.0, 1.0 ]
  Tg:
    - [ 0.0, 0.0, 0.0 ]
    - [ 0.0, 0.0, 0.0 ]
    - [ 0.0, 0.0, 0.0 ]

kalibr_imucam_chain.yaml

%YAML:1.0

cam0:
  T_cam_imu:
    - [0.9999942992129773, -0.0006837030318090254, 0.003306673813320594, 0.01734357246126995]
    - [0.0006819183997666188, 0.9999996212593953, 0.000540803438387852, -0.008519633421954392]
    - [-0.003307042309899398, -0.0005385454736672996, 0.9999943867042107, -0.018723905687986195]
    - [0.0, 0.0, 0.0, 1.0]
  cam_overlaps: [1]
  camera_model: pinhole
  distortion_coeffs: [0.0019712980218442736, -0.0011090942743057983, -0.0006211171700097682, -0.0034327653409294196]
  distortion_model: radtan
  intrinsics: [320.17488748238287, 320.0283628174116, 314.0668795454674, 180.36893447271257]
  resolution: [640, 360]
  rostopic: /camera/infra1/image_rect_raw
  timeshift_cam_imu: 0.004639958649183853

cam1:
  T_cam_imu:
    - [0.9999855287596171, -0.0003605813977934117, 0.00536770457504073, -0.07667191595392714]
    - [0.000365189906339375, 0.9999995655732808, -0.0008576068926449692, -0.008542662389807396]
    - [-0.005367393006074334, 0.0008595547135404881, 0.9999852260198713, -0.017739927010989854]
    - [0.0, 0.0, 0.0, 1.0]
  T_cn_cnm1:
    - [0.9999978238338454, 0.00032423014342537217, 0.0020608741811117422, -0.09397410073693341]
    - [-0.00032135073657469737, 0.9999989720658036, -0.0013973550168239824, -4.36282992379309e-05]
    - [-0.002061325127286215, 0.0013966897125111987, 0.99999690009348, 0.0010315706607051294]
    - [0.0, 0.0, 0.0, 1.0]
  cam_overlaps: [0]
  camera_model: pinhole
  distortion_coeffs: [0.00415520544025779, -0.003951065114859482, -0.00042589527047545586, -0.00442085250772721]
  distortion_model: radtan
  intrinsics: [319.69438067702725, 320.1948319604044, 313.46161305104766, 180.7178241492703]
  resolution: [640, 360]
  rostopic: /camera/infra2/image_rect_raw
  timeshift_cam_imu: 0.005012709485041032

# cam0:
#   T_cam_imu:
#     - [0.9999654398038452, 0.007342326779113337, -0.003899927610975742, -0.027534314618518095]
#     - [-0.0073452195116216765, 0.9999727585590525, -0.0007279355223411334, -0.0030587146933711722]
#     - [0.0038944766308488753, 0.0007565561891287445, 0.9999921303062861, -0.023605118842939803]
#     - [0.0, 0.0, 0.0, 1.0]
#   cam_overlaps: []
#   camera_model: pinhole
#   distortion_coeffs: [-0.045761895748285604, 0.03423951132164367, -0.00040139057556727315, 0.000431371425853453]
#   distortion_model: radtan
#   intrinsics: [416.85223429743274, 414.92069080087543, 421.02459311003213, 237.76180565241077]
#   resolution: [848, 480]
#   rostopic: /d455/color/image_raw
#   timeshift_cam_imu: 0.002524377913673846

When I run the estimator, I get the following about

[INFO] [launch]: All log files can be found below /home/admin/.ros/log/2023-08-22-06-15-37-880685-orin-nx-173717
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [run_subscribe_msckf-1]: process started with pid [173719]
[run_subscribe_msckf-1] overriding node verbosity with value from ROS!
[run_subscribe_msckf-1] Setting printing level to: INFO
[run_subscribe_msckf-1] overriding node max_cameras with value from ROS!
[run_subscribe_msckf-1] overriding node max_cameras with value from ROS!
[run_subscribe_msckf-1] overriding node use_stereo with value from ROS!
[run_subscribe_msckf-1] parameter T_imu_cam not found, trying T_cam_imu instead (will return T_imu_cam still)!
[run_subscribe_msckf-1] parameter T_imu_cam not found, trying T_cam_imu instead (will return T_imu_cam still)!
[run_subscribe_msckf-1] overriding node use_stereo with value from ROS!
[run_subscribe_msckf-1] parameter T_imu_cam not found, trying T_cam_imu instead (will return T_imu_cam still)!
[run_subscribe_msckf-1] parameter T_imu_cam not found, trying T_cam_imu instead (will return T_imu_cam still)!
[run_subscribe_msckf-1] subscribing to IMU: /camera/imu
[run_subscribe_msckf-1] subscribing to cam (stereo): /camera/infra1/image_rect_raw
[run_subscribe_msckf-1] subscribing to cam (stereo): /camera/infra2/image_rect_raw
[run_subscribe_msckf-1] [TIME]: 0.0109 seconds total (91.8 hz, 3.45 ms behind)
[run_subscribe_msckf-1] [TIME]: 0.0079 seconds total (126.0 hz, 3.11 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 0,0 < 15
[run_subscribe_msckf-1] [TIME]: 0.0069 seconds total (144.2 hz, 3.27 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 0,0 < 15
[run_subscribe_msckf-1] [TIME]: 0.0062 seconds total (160.3 hz, 1.53 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 57,0 < 15
[run_subscribe_msckf-1] [TIME]: 0.0156 seconds total (64.3 hz, 2.94 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 0,0 < 15
[run_subscribe_msckf-1] [TIME]: 0.0059 seconds total (168.1 hz, 2.76 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 0,56 < 15
[run_subscribe_msckf-1] [TIME]: 0.0102 seconds total (98.3 hz, 3.04 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 0,56 < 15
[run_subscribe_msckf-1] [TIME]: 0.0216 seconds total (46.2 hz, 2.77 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 0,56 < 15
[run_subscribe_msckf-1] [TIME]: 0.0275 seconds total (36.4 hz, 3.09 ms behind)
[run_subscribe_msckf-1] [TIME]: 0.0044 seconds total (226.6 hz, 3.25 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 0,56 < 15
[run_subscribe_msckf-1] [TIME]: 0.0062 seconds total (160.0 hz, 3.97 ms behind)
[run_subscribe_msckf-1] [init]: not enough feats to compute disp: 0,56 < 15
[run_subscribe_msckf-1] [TIME]: 0.0038 seconds total (265.6 hz, 3.32 ms behind)
[run_subscribe_msckf-1] [init]: disparity is 0.215,0.254 (10.00 thresh)
[run_subscribe_msckf-1] [init]: failed static init: no accel jerk detected

The drone is initially static for a couple of seconds, then I move it briefly.

I don't see the a frame moving in rviz.

What could be the issue? Do I have to move the drone immediately, or after a specific amount of time?

goldbattle commented 1 year ago

I recommend directly trying the d455 config: https://github.com/rpng/open_vins/tree/master/config/rs_d455

The init_window_time shouldn't be more than 2 seconds, and you would just need to tune the init_imu_thresh to detect your device pickup if needed. This above config should work out of the box so first try this / compare your configuration to it.

mzahana commented 1 year ago

Thank you very much @goldbattle . I will try it and report the result.

Could you please elaborate more on init_imu_thresh parameter ? How is it used ? Thanks.

goldbattle commented 1 year ago

You can see that we compute the accelerometer standard deviations. If this is large then we expect the platform to have changed its acceleration or rotation. We have two windows. The first window we want to be static, and the second to have this high variance in acceleration (e.g. it was picked up). We use the first window to recover the direction of gravity to initialize the system. This is the logic for static initialization. https://github.com/rpng/open_vins/blob/master/ov_init/src/static/StaticInitializer.cpp#L84-L98

init_imu_thresh will depend on how noisy the IMU is. For example if you have a MAV with motors this will cause noise and thus will require this threshold to be increased to prevent the case that turning the motors on to introduce large acceleration noise from the vibrations. It also depends on how noisy the IMU is.

In general this shouldn't be too hard to tune, but seems there are quite a few issues about how to do this. I recommend recording a bag of picking up the sensor, and then based on this tune the parameter such that when it is picked up (inspect the camera feed) the system detects it as moving. You want this window to be short (between 1-1.5 seconds) so you have good responsiveness.

Hope this helps.

Userpc1010 commented 1 year ago

@mzahana If you run open vins successfully, could you make a short demo of how tracking works on the drone?

mzahana commented 1 year ago

Thanks @goldbattle for your feedback. I am doing some experiments and will share some feedback soon.

@Userpc1010 I think it can work pretty well, depending on your environment, camera-imu setup, calibration, and compute power. I am still doing some testing.

mzahana commented 1 year ago

I was finally able to run ov_msckf successfully on a quadcopter. In my setup, I use D455 connected to a Jetson Orin NX. I have a docker container with ROS 2 humble in which the entire software runs (Realsense ros2 node+ open_vins). The D455 is damped to reduce the effect of vibrations during flight.

Now, the estimator is working fine.

Here are my config files.

estimator_config.yaml

%YAML:1.0 # need to specify the file type at the top!

verbosity: "INFO" # ALL, DEBUG, INFO, WARNING, ERROR, SILENT

use_fej: true # if first-estimate Jacobians should be used (enable for good consistency)
integration: "rk4" # discrete, rk4, analytical (if rk4 or analytical used then analytical covariance propagation is used)
use_stereo: true # if we have more than 1 camera, if we should try to track stereo constraints between pairs
max_cameras: 1 # how many cameras we have 1 = mono, 2 = stereo, >2 = binocular (all mono tracking)

calib_cam_extrinsics: true # if the transform between camera and IMU should be optimized R_ItoC, p_CinI
calib_cam_intrinsics: true # if camera intrinsics should be optimized (focal, center, distortion)
calib_cam_timeoffset: true # if timeoffset between camera and IMU should be optimized
calib_imu_intrinsics: false # if imu intrinsics should be calibrated (rotation and skew-scale matrix)
calib_imu_g_sensitivity: false # if gyroscope gravity sensitivity (Tg) should be calibrated

max_clones: 11 # how many clones in the sliding window
max_slam: 50 # number of features in our state vector
max_slam_in_update: 25 # update can be split into sequential updates of batches, how many in a batch
max_msckf_in_update: 40 # how many MSCKF features to use in the update
dt_slam_delay: 1 # delay before initializing (helps with stability from bad initialization...)

gravity_mag: 9.81 # magnitude of gravity in this location

feat_rep_msckf: "GLOBAL_3D"
feat_rep_slam: "ANCHORED_MSCKF_INVERSE_DEPTH"
feat_rep_aruco: "ANCHORED_MSCKF_INVERSE_DEPTH"

# zero velocity update parameters we can use
# we support either IMU-based or disparity detection.
try_zupt: true
zupt_chi2_multipler: 0 # set to 0 for only disp-based
zupt_max_velocity: 0.1
zupt_noise_multiplier: 10
zupt_max_disparity: 0.5 # set to 0 for only imu-based
zupt_only_at_beginning: false

# ==================================================================
# ==================================================================

init_window_time: 2.0 # how many seconds to collect initialization information
init_imu_thresh: 2.5 # threshold for variance of the accelerometer to detect a "jerk" in motion
init_max_disparity: 10.0 # max disparity to consider the platform stationary (dependent on resolution)
init_max_features: 50 # how many features to track during initialization (saves on computation)

init_dyn_use: false # if dynamic initialization should be used
init_dyn_mle_opt_calib: false # if we should optimize calibration during intialization (not recommended)
init_dyn_mle_max_iter: 50 # how many iterations the MLE refinement should use (zero to skip the MLE)
init_dyn_mle_max_time: 0.05 # how many seconds the MLE should be completed in
init_dyn_mle_max_threads: 6 # how many threads the MLE should use
init_dyn_num_pose: 6 # number of poses to use within our window time (evenly spaced)
init_dyn_min_deg: 10.0 # orientation change needed to try to init

init_dyn_inflation_ori: 10 # what to inflate the recovered q_GtoI covariance by
init_dyn_inflation_vel: 100 # what to inflate the recovered v_IinG covariance by
init_dyn_inflation_bg: 10 # what to inflate the recovered bias_g covariance by
init_dyn_inflation_ba: 100 # what to inflate the recovered bias_a covariance by
init_dyn_min_rec_cond: 1e-12 # reciprocal condition number thresh for info inversion

init_dyn_bias_g: [ 0.0, 0.0, 0.0 ] # initial gyroscope bias guess
init_dyn_bias_a: [ 0.0, 0.0, 0.0 ] # initial accelerometer bias guess

# ==================================================================
# ==================================================================

record_timing_information: false # if we want to record timing information of the method
record_timing_filepath: "/tmp/traj_timing.txt" # https://docs.openvins.com/eval-timing.html#eval-ov-timing-flame

# if we want to save the simulation state and its diagional covariance
# use this with rosrun ov_eval error_simulation
save_total_state: false
filepath_est: "/tmp/ov_estimate.txt"
filepath_std: "/tmp/ov_estimate_std.txt"
filepath_gt: "/tmp/ov_groundtruth.txt"

# ==================================================================
# ==================================================================

# our front-end feature tracking parameters
# we have a KLT and descriptor based (KLT is better implemented...)
use_klt: true # if true we will use KLT, otherwise use a ORB descriptor + robust matching
num_pts: 200 # number of points (per camera) we will extract and try to track
fast_threshold: 30 # threshold for fast extraction (warning: lower threshs can be expensive)
grid_x: 5 # extraction sub-grid count for horizontal direction (uniform tracking)
grid_y: 5 # extraction sub-grid count for vertical direction (uniform tracking)
min_px_dist: 15 # distance between features (features near each other provide less information)
knn_ratio: 0.70 # descriptor knn threshold for the top two descriptor matches
track_frequency: 31.0 # frequency we will perform feature tracking at (in frames per second / hertz)
downsample_cameras: false # will downsample image in half if true
num_opencv_threads: 4 # -1: auto, 0-1: serial, >1: number of threads
histogram_method: "HISTOGRAM" # NONE, HISTOGRAM, CLAHE

# aruco tag tracker for the system
# DICT_6X6_1000 from https://chev.me/arucogen/
use_aruco: false
num_aruco: 1024
downsize_aruco: true

# ==================================================================
# ==================================================================

# camera noises and chi-squared threshold multipliers
up_msckf_sigma_px: 1
up_msckf_chi2_multipler: 1
up_slam_sigma_px: 1
up_slam_chi2_multipler: 1
up_aruco_sigma_px: 1
up_aruco_chi2_multipler: 1

# masks for our images
use_mask: false

# imu and camera spacial-temporal
# imu config should also have the correct noise values
relative_config_imu: "kalibr_imu_chain.yaml"
relative_config_imucam: "kalibr_imucam_chain.yaml"

Note that I set try_zupt: true. The default value is false

I also used Kalibr to calibrate the camera and imu. I used allan_ros2 to compute the statistics of the D455 imu.

Now there is a little issue. I can observe a drift of about 20-30 cm form the origin (marked on the ground) after flying around and going back to origin. Is this normal? How to tune the ov_msckf such that I minimuze this drift?

Thank you.

Userpc1010 commented 1 year ago

What about using the calibration from the EEPROM of the camera itself. The depth camera was calibrated at the factory, is the intel calibration procedure more accurate? Also, if you are using a camera on a drone, it is probably better to select the stereo mode for greater tracking stability during fast movements, in which case calibration is not needed at all, because the images of the stereo camera are read already undistortions and the coefficients should be equal to 0.

mzahana commented 1 year ago

@Userpc1010 I didn't use the camera params that are in the EEPROM, so I can't tell the difference. For the question related to the stability of stereo setup, I will leave it to @goldbattle to answer.

Userpc1010 commented 1 year ago

@mzahana I launched the camera with your settings, everything seems to be in order and the camera works a stable in stereo. Also I didn't have stable tracking without try_zupt: true in mono or stereo maybe this should be added by default to rs_d455 @goldbattle ? Screenshot from 2023-09-05 23-19-44

mzahana commented 1 year ago

@Userpc1010 what was your configuration in mono mode that worked well for you?

Userpc1010 commented 1 year ago

To test mono I used the following configuration:

estimator_config.yaml:

%YAML:1.0 # need to specify the file type at the top!

verbosity: "INFO" # ALL, DEBUG, INFO, WARNING, ERROR, SILENT

use_fej: true # if first-estimate Jacobians should be used (enable for good consistency)
integration: "rk4" # discrete, rk4, analytical (if rk4 or analytical used then analytical covariance propagation is used)
use_stereo: false # if we have more than 1 camera, if we should try to track stereo constraints between pairs
max_cameras: 1 # how many cameras we have 1 = mono, 2 = stereo, >2 = binocular (all mono tracking)

calib_cam_extrinsics: true # if the transform between camera and IMU should be optimized R_ItoC, p_CinI
calib_cam_intrinsics: true # if camera intrinsics should be optimized (focal, center, distortion)
calib_cam_timeoffset: true # if timeoffset between camera and IMU should be optimized
calib_imu_intrinsics: false # if imu intrinsics should be calibrated (rotation and skew-scale matrix)
calib_imu_g_sensitivity: false # if gyroscope gravity sensitivity (Tg) should be calibrated

max_clones: 11 # how many clones in the sliding window
max_slam: 50 # number of features in our state vector
max_slam_in_update: 25 # update can be split into sequential updates of batches, how many in a batch
max_msckf_in_update: 40 # how many MSCKF features to use in the update
dt_slam_delay: 1 # delay before initializing (helps with stability from bad initialization...)

gravity_mag: 9.81 # magnitude of gravity in this location

feat_rep_msckf: "GLOBAL_3D"
feat_rep_slam: "ANCHORED_MSCKF_INVERSE_DEPTH"
feat_rep_aruco: "ANCHORED_MSCKF_INVERSE_DEPTH"

# zero velocity update parameters we can use
# we support either IMU-based or disparity detection.
try_zupt: true
zupt_chi2_multipler: 0 # set to 0 for only disp-based
zupt_max_velocity: 0.1
zupt_noise_multiplier: 10
zupt_max_disparity: 0.5 # set to 0 for only imu-based
zupt_only_at_beginning: false

# ==================================================================
# ==================================================================

init_window_time: 2.0 # how many seconds to collect initialization information
init_imu_thresh: 1.5 # threshold for variance of the accelerometer to detect a "jerk" in motion
init_max_disparity: 10.0 # max disparity to consider the platform stationary (dependent on resolution)
init_max_features: 50 # how many features to track during initialization (saves on computation)

init_dyn_use: false # if dynamic initialization should be used
init_dyn_mle_opt_calib: false # if we should optimize calibration during intialization (not recommended)
init_dyn_mle_max_iter: 50 # how many iterations the MLE refinement should use (zero to skip the MLE)
init_dyn_mle_max_time: 0.05 # how many seconds the MLE should be completed in
init_dyn_mle_max_threads: 6 # how many threads the MLE should use
init_dyn_num_pose: 6 # number of poses to use within our window time (evenly spaced)
init_dyn_min_deg: 10.0 # orientation change needed to try to init

init_dyn_inflation_ori: 10 # what to inflate the recovered q_GtoI covariance by
init_dyn_inflation_vel: 100 # what to inflate the recovered v_IinG covariance by
init_dyn_inflation_bg: 10 # what to inflate the recovered bias_g covariance by
init_dyn_inflation_ba: 100 # what to inflate the recovered bias_a covariance by
init_dyn_min_rec_cond: 1e-12 # reciprocal condition number thresh for info inversion

init_dyn_bias_g: [ 0.0, 0.0, 0.0 ] # initial gyroscope bias guess
init_dyn_bias_a: [ 0.0, 0.0, 0.0 ] # initial accelerometer bias guess

# ==================================================================
# ==================================================================

record_timing_information: false # if we want to record timing information of the method
record_timing_filepath: "/tmp/traj_timing.txt" # https://docs.openvins.com/eval-timing.html#eval-ov-timing-flame

# if we want to save the simulation state and its diagional covariance
# use this with rosrun ov_eval error_simulation
save_total_state: false
filepath_est: "/tmp/ov_estimate.txt"
filepath_std: "/tmp/ov_estimate_std.txt"
filepath_gt: "/tmp/ov_groundtruth.txt"

# ==================================================================
# ==================================================================

# our front-end feature tracking parameters
# we have a KLT and descriptor based (KLT is better implemented...)
use_klt: true # if true we will use KLT, otherwise use a ORB descriptor + robust matching
num_pts: 200 # number of points (per camera) we will extract and try to track
fast_threshold: 30 # threshold for fast extraction (warning: lower threshs can be expensive)
grid_x: 5 # extraction sub-grid count for horizontal direction (uniform tracking)
grid_y: 5 # extraction sub-grid count for vertical direction (uniform tracking)
min_px_dist: 15 # distance between features (features near each other provide less information)
knn_ratio: 0.70 # descriptor knn threshold for the top two descriptor matches
track_frequency: 31.0 # frequency we will perform feature tracking at (in frames per second / hertz)
downsample_cameras: false # will downsample image in half if true
num_opencv_threads: 4 # -1: auto, 0-1: serial, >1: number of threads
histogram_method: "HISTOGRAM" # NONE, HISTOGRAM, CLAHE

# aruco tag tracker for the system
# DICT_6X6_1000 from https://chev.me/arucogen/
use_aruco: false
num_aruco: 1024
downsize_aruco: true

# ==================================================================
# ==================================================================

# camera noises and chi-squared threshold multipliers
up_msckf_sigma_px: 1
up_msckf_chi2_multipler: 1
up_slam_sigma_px: 1
up_slam_chi2_multipler: 1
up_aruco_sigma_px: 1
up_aruco_chi2_multipler: 1

# masks for our images
use_mask: false

# imu and camera spacial-temporal
# imu config should also have the correct noise values
relative_config_imu: "kalibr_imu_chain.yaml"
relative_config_imucam: "kalibr_imucam_chain.yaml"

kalibr_imucam_chain.yaml:

%YAML:1.0

#cam0:
#  T_cam_imu:
#    - [0.9999942992129773, -0.0006837030318090254, 0.003306673813320594, 0.01734357246126995]
#    - [0.0006819183997666188, 0.9999996212593953, 0.000540803438387852, -0.008519633421954392]
#    - [-0.003307042309899398, -0.0005385454736672996, 0.9999943867042107, -0.018723905687986195]
#    - [0.0, 0.0, 0.0, 1.0]
#  cam_overlaps: [1]
#  camera_model: pinhole
#  distortion_coeffs: [0.0, 0.0, 0.0, 0.0]
#  distortion_model: radtan
#  intrinsics: [320.17488748238287, 320.0283628174116, 314.0668795454674, 180.36893447271257]
#  resolution: [848, 480]
#  rostopic: /d455/infra1/image_rect_raw
#  timeshift_cam_imu: 0.004639958649183853

#cam1:
#  T_cam_imu:
#    - [0.9999855287596171, -0.0003605813977934117, 0.00536770457504073, -0.07667191595392714]
#    - [0.000365189906339375, 0.9999995655732808, -0.0008576068926449692, -0.008542662389807396]
#    - [-0.005367393006074334, 0.0008595547135404881, 0.9999852260198713, -0.017739927010989854]
#    - [0.0, 0.0, 0.0, 1.0]
#  T_cn_cnm1:
#    - [0.9999978238338454, 0.00032423014342537217, 0.0020608741811117422, -0.09397410073693341]
#    - [-0.00032135073657469737, 0.9999989720658036, -0.0013973550168239824, -4.36282992379309e-05]
#    - [-0.002061325127286215, 0.0013966897125111987, 0.99999690009348, 0.0010315706607051294]
#    - [0.0, 0.0, 0.0, 1.0]
#  cam_overlaps: [0]
#  camera_model: pinhole
#  distortion_coeffs: [0.0, 0.0, 0.0, 0.0]
#  distortion_model: radtan
#  intrinsics: [319.69438067702725, 320.1948319604044, 313.46161305104766, 180.7178241492703]
#  resolution: [848, 480]
#  rostopic: /d455/infra2/image_rect_raw
#  timeshift_cam_imu: 0.005012709485041032

cam0:
 T_cam_imu:
   - [0.9999654398038452, 0.007342326779113337, -0.003899927610975742, -0.027534314618518095]
   - [-0.0073452195116216765, 0.9999727585590525, -0.0007279355223411334, -0.0030587146933711722]
   - [0.0038944766308488753, 0.0007565561891287445, 0.9999921303062861, -0.023605118842939803]
   - [0.0, 0.0, 0.0, 1.0]
 cam_overlaps: []
 camera_model: pinhole
 distortion_coeffs: [-0.045761895748285604, 0.03423951132164367, -0.00040139057556727315, 0.000431371425853453]
 distortion_model: radtan
 intrinsics: [416.85223429743274, 414.92069080087543, 421.02459311003213, 237.76180565241077]
 resolution: [848, 480]
 rostopic: /d455/color/image_raw
 timeshift_cam_imu: 0.002524377913673846

launch_d455.example:

<?xml version="1.0" encoding="UTF-8"?>
<launch>
  <arg name="serial_no"           default="215122253909"/>
  <arg name="json_file_path"      default=""/>
  <arg name="camera"              default="d455"/>
  <arg name="tf_prefix"           default="$(arg camera)"/>
  <arg name="external_manager"    default="false"/>
  <arg name="manager"             default="realsense2_camera_manager"/>
  <arg name="respawn"             default="true"/>

  <arg name="fisheye_width"       default="640"/>
  <arg name="fisheye_height"      default="480"/>
  <arg name="enable_fisheye"      default="false"/>

  <arg name="depth_width"         default="848"/>
  <arg name="depth_height"        default="480"/>
  <arg name="enable_depth"        default="false"/>

  <arg name="infra_width"        default="848"/>
  <arg name="infra_height"       default="480"/>
  <arg name="enable_infra1"       default="true"/>
  <arg name="enable_infra2"       default="true"/>

  <arg name="color_width"         default="848"/>
  <arg name="color_height"        default="480"/>
  <arg name="enable_color"        default="true"/>

  <arg name="fisheye_fps"         default="30"/>
  <arg name="depth_fps"           default="30"/>
  <arg name="infra_fps"           default="30"/>
  <arg name="color_fps"           default="30"/>
  <arg name="gyro_fps"            default="200"/>
  <arg name="accel_fps"           default="200"/>
  <arg name="enable_gyro"         default="true"/>
  <arg name="enable_accel"        default="true"/>

  <arg name="enable_pointcloud"         default="false"/>
  <arg name="pointcloud_texture_stream" default="RS2_STREAM_COLOR"/>
  <arg name="pointcloud_texture_index"  default="0"/>

  <arg name="enable_sync"               default="false"/>
  <arg name="align_depth"               default="true"/>

  <arg name="filters"                   default="pointcloud"/>
  <arg name="clip_distance"             default="-2"/>
  <arg name="linear_accel_cov"          default="0.01"/>
  <arg name="initial_reset"             default="false"/>
  <arg name="reconnect_timeout"         default="6.0"/>
  <arg name="unite_imu_method"          default="linear_interpolation"/>
  <arg name="topic_odom_in"             default="odom_in"/>
  <arg name="calib_odom_file"           default=""/>
  <arg name="publish_odom_tf"           default="true"/>
  <arg name="allow_no_texture_points"   default="false"/>

  <group ns="$(arg camera)">
    <include file="$(find realsense2_camera)/launch/includes/nodelet.launch.xml">
      <arg name="tf_prefix"                value="$(arg tf_prefix)"/>
      <arg name="external_manager"         value="$(arg external_manager)"/>
      <arg name="manager"                  value="$(arg manager)"/>
      <arg name="serial_no"                value="$(arg serial_no)"/>
      <arg name="json_file_path"           value="$(arg json_file_path)"/>
      <arg name="respawn"                  value="$(arg respawn)"/>

      <arg name="enable_pointcloud"        value="$(arg enable_pointcloud)"/>
      <arg name="pointcloud_texture_stream" value="$(arg pointcloud_texture_stream)"/>
      <arg name="pointcloud_texture_index"  value="$(arg pointcloud_texture_index)"/>
      <arg name="enable_sync"              value="$(arg enable_sync)"/>
      <arg name="align_depth"              value="$(arg align_depth)"/>

      <arg name="fisheye_width"            value="$(arg fisheye_width)"/>
      <arg name="fisheye_height"           value="$(arg fisheye_height)"/>
      <arg name="enable_fisheye"           value="$(arg enable_fisheye)"/>

      <arg name="depth_width"              value="$(arg depth_width)"/>
      <arg name="depth_height"             value="$(arg depth_height)"/>
      <arg name="enable_depth"             value="$(arg enable_depth)"/>

      <arg name="color_width"              value="$(arg color_width)"/>
      <arg name="color_height"             value="$(arg color_height)"/>
      <arg name="enable_color"             value="$(arg enable_color)"/>

      <arg name="infra_width"              value="$(arg infra_width)"/>
      <arg name="infra_height"             value="$(arg infra_height)"/>
      <arg name="enable_infra1"            value="$(arg enable_infra1)"/>
      <arg name="enable_infra2"            value="$(arg enable_infra2)"/>

      <arg name="fisheye_fps"              value="$(arg fisheye_fps)"/>
      <arg name="depth_fps"                value="$(arg depth_fps)"/>
      <arg name="infra_fps"                value="$(arg infra_fps)"/>
      <arg name="color_fps"                value="$(arg color_fps)"/>
      <arg name="gyro_fps"                 value="$(arg gyro_fps)"/>
      <arg name="accel_fps"                value="$(arg accel_fps)"/>
      <arg name="enable_gyro"              value="$(arg enable_gyro)"/>
      <arg name="enable_accel"             value="$(arg enable_accel)"/>

      <arg name="filters"                  value="$(arg filters)"/>
      <arg name="clip_distance"            value="$(arg clip_distance)"/>
      <arg name="linear_accel_cov"         value="$(arg linear_accel_cov)"/>
      <arg name="initial_reset"            value="$(arg initial_reset)"/>
      <arg name="reconnect_timeout"        value="$(arg reconnect_timeout)"/>
      <arg name="unite_imu_method"         value="$(arg unite_imu_method)"/>
      <arg name="topic_odom_in"            value="$(arg topic_odom_in)"/>
      <arg name="calib_odom_file"          value="$(arg calib_odom_file)"/>
      <arg name="publish_odom_tf"          value="$(arg publish_odom_tf)"/>
      <arg name="allow_no_texture_points"  value="$(arg allow_no_texture_points)"/>
    </include>
  </group>

</launch>

subscribe.launch:

<launch>

    <!-- what config we are going to run (should match folder name) -->
    <arg name="verbosity"   default="INFO" /> <!-- ALL, DEBUG, INFO, WARNING, ERROR, SILENT -->
    <arg name="config"      default="rs_d455" /> <!-- euroc_mav, tum_vi, rpng_aruco -->
    <arg name="config_path" default="$(find ov_msckf)/../config/$(arg config)/estimator_config.yaml" />

    <!-- mono or stereo and what ros bag to play -->
    <arg name="max_cameras" default="1" />
    <arg name="use_stereo"  default="false" />
    <arg name="bag_start"   default="0" /> <!-- v1-2: 0, mh1: 40, mh2: 35, mh3: 17.5, mh4-5: 15 -->
    <arg name="bag_rate"    default="1" />
    <arg name="dataset"     default="V1_01_easy" /> <!-- V1_01_easy, V1_02_medium, V2_02_medium -->
    <arg name="dobag"       default="false" /> <!-- if we should play back the bag -->
    <arg name="bag"         default="/media/patrick/RPNG\ FLASH\ 3/$(arg config)/$(arg dataset).bag" />
<!--    <arg name="bag"         default="/home/patrick/datasets/$(arg config)/$(arg dataset).bag" />-->
<!--    <arg name="bag"         default="/datasets/$(arg config)/$(arg dataset).bag" />-->

    <!-- saving trajectory path and timing information -->
    <arg name="dosave"      default="false" />
    <arg name="dotime"      default="false" />
    <arg name="path_est"    default="/tmp/traj_estimate.txt" />
    <arg name="path_time"   default="/tmp/traj_timing.txt" />

    <!-- if we should viz the groundtruth -->
    <arg name="dolivetraj"  default="false" />
    <arg name="path_gt"     default="$(find ov_data)/$(arg config)/$(arg dataset).txt" />

    <!-- MASTER NODE! -->
<!--    <node name="ov_msckf" pkg="ov_msckf" type="run_subscribe_msckf" output="screen" clear_params="true" required="true" launch-prefix="gdb -ex run &#45;&#45;args">-->
    <node name="ov_msckf" pkg="ov_msckf" type="run_subscribe_msckf" output="screen" clear_params="true" required="true">

        <!-- master configuration object -->
        <param name="verbosity"              type="string" value="$(arg verbosity)" />
        <param name="config_path"            type="string" value="$(arg config_path)" />

        <!-- world/filter parameters -->
        <param name="use_stereo"             type="bool"   value="$(arg use_stereo)" />
        <param name="max_cameras"            type="int"    value="$(arg max_cameras)" />

        <!-- timing statistics recording -->
        <param name="record_timing_information"   type="bool"   value="$(arg dotime)" />
        <param name="record_timing_filepath"      type="string" value="$(arg path_time)" />

    </node>

    <!-- play the dataset -->
    <group if="$(arg dobag)">
        <node pkg="rosbag" type="play" name="rosbag" args="-d 1 -r $(arg bag_rate) -s $(arg bag_start) $(arg bag)" required="true"/>
    </group>

    <!-- record the trajectory if enabled -->
    <group if="$(arg dosave)">
        <node name="recorder_estimate" pkg="ov_eval" type="pose_to_file" output="screen" required="true">
            <param name="topic"      type="str" value="/ov_msckf/poseimu" />
            <param name="topic_type" type="str" value="PoseWithCovarianceStamped" />
            <param name="output"     type="str" value="$(arg path_est)" />
        </node>
    </group>

    <!-- path viz of aligned gt -->
    <group if="$(arg dolivetraj)">
        <node name="live_align_trajectory" pkg="ov_eval" type="live_align_trajectory" output="log" clear_params="true">
            <param name="alignment_type" type="str" value="posyaw" />
            <param name="path_gt"        type="str" value="$(arg path_gt)" />
        </node>
    </group>

</launch>

Screenshot from 2023-09-13 11-01-37

I conducted a test on a car, stereo mode and got a result similar to some other frameworks (1 2 3 4) that I tested before, but despite this, OpenVins is quite sophisticated and many problems have been solved here, such as resistance to rapid rotations and motion blur, imu init, which is necessary for drones.

mzahana commented 1 year ago

Thanks @Userpc1010 for the reply. You mentioned that you conducted a test on a car in stereo mode. Did you test in mono mode?

Userpc1010 commented 1 year ago

@mzahana No, I didn't test mono on the machine, I did a mono test to make sure it was less stable and chose stereo. The stereo mode has better calibration and more accurately determines the image scale, I believe mono cannot surpass stereo.

goldbattle commented 1 year ago

To both of you, could you post a bag and config file so I can take a look? @Userpc1010 could you open a new issue with the bag and configs for your driving dataset as I am interested in seeing what the problem there is. I don't think there should be a large problem filming from inside the car, but have you tried collecting a dataset with the sensor outside the vehicle?

Userpc1010 commented 1 year ago

@goldbattle Here I published everything I have. Unfortunately I don't have a tripod to mount the camera outside the car.

goldbattle commented 1 year ago

For now I don't want to enable the zvupt as default true since this can cause trouble for users just using the device handheld. Feel free to reopen if there is some problem with the current code.