diff --git a/src/motion_lib/include/motion_lib/vel_process_model/kinematic_bicycle.hpp b/cone_viz/cone_viz/__init__.py
old mode 100755
new mode 100644
similarity index 100%
rename from src/motion_lib/include/motion_lib/vel_process_model/kinematic_bicycle.hpp
rename to cone_viz/cone_viz/__init__.py
diff --git a/cone_viz/cone_viz/cone_marker_publisher.py b/cone_viz/cone_viz/cone_marker_publisher.py
new file mode 100644
index 000000000..ab5f182ad
--- /dev/null
+++ b/cone_viz/cone_viz/cone_marker_publisher.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+import math
+import rclpy
+from rclpy.node import Node
+
+from visualization_msgs.msg import Marker, MarkerArray
+from custom_interfaces.msg import PerceptionOutput, Pose
+
+
+class ConeMarkerPublisher(Node):
+ def __init__(self):
+ super().__init__("cone_marker_publisher")
+
+ self.vehicle_x = 0.0
+ self.vehicle_y = 0.0
+ self.vehicle_theta = 0.0
+ self.have_pose = False
+
+ # Store all global cones seen so far
+ self.global_cones = []
+
+ self.create_subscription(
+ PerceptionOutput, "/perception/cones", self.cones_callback, 10
+ )
+
+ self.create_subscription(
+ Pose, "/state_estimation/vehicle_pose", self.pose_callback, 10
+ )
+
+ self.marker_pub = self.create_publisher(
+ MarkerArray, "/visualization/cones_markers", 10
+ )
+
+ def pose_callback(self, msg: Pose):
+ self.vehicle_x = msg.x
+ self.vehicle_y = msg.y
+ self.vehicle_theta = msg.theta
+ self.have_pose = True
+
+ def cones_callback(self, msg: PerceptionOutput):
+ if not self.have_pose:
+ return
+
+ cos_t = math.cos(self.vehicle_theta)
+ sin_t = math.sin(self.vehicle_theta)
+
+ # Transform new cones to global frame and store them
+ for cone in msg.cone_array:
+ lx = cone.x
+ ly = cone.y
+
+ gx = self.vehicle_x + cos_t * lx - sin_t * ly
+ gy = self.vehicle_y + sin_t * lx + cos_t * ly
+
+ self.global_cones.append((gx, gy))
+
+ # Build the map markers with ALL cones observed so far
+ marker_array = MarkerArray()
+ marker_id = 0
+
+ for gx, gy in self.global_cones:
+ marker = Marker()
+ marker.header.frame_id = "map"
+ marker.header.stamp = self.get_clock().now().to_msg()
+ marker.id = marker_id
+ marker.type = Marker.SPHERE
+
+ marker.pose.position.x = gx
+ marker.pose.position.y = gy
+ marker.pose.position.z = 0.0
+
+ marker.scale.x = 0.25
+ marker.scale.y = 0.25
+ marker.scale.z = 0.25
+
+ marker.color.r = 0.0
+ marker.color.g = 0.5
+ marker.color.b = 1.0
+ marker.color.a = 1.0
+
+ # Make markers persistent
+ marker.lifetime.sec = 0
+ marker.lifetime.nanosec = 0
+
+ marker_array.markers.append(marker)
+ marker_id += 1
+
+ self.marker_pub.publish(marker_array)
+
+
+def main(args=None):
+ rclpy.init(args=args)
+ node = ConeMarkerPublisher()
+ rclpy.spin(node)
+ node.destroy_node()
+ rclpy.shutdown()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/cone_viz/package.xml b/cone_viz/package.xml
new file mode 100644
index 000000000..8638187d1
--- /dev/null
+++ b/cone_viz/package.xml
@@ -0,0 +1,23 @@
+
+
+
+ cone_viz
+ 0.0.0
+ TODO: Package description
+ filipelopes
+ TODO: License declaration
+
+ rclpy
+ visualization_msgs
+ custom_interfaces
+ std_msgs
+
+ ament_copyright
+ ament_flake8
+ ament_pep257
+ python3-pytest
+
+
+ ament_python
+
+
diff --git a/cone_viz/resource/cone_viz b/cone_viz/resource/cone_viz
new file mode 100644
index 000000000..e69de29bb
diff --git a/cone_viz/setup.cfg b/cone_viz/setup.cfg
new file mode 100644
index 000000000..5ffe35e22
--- /dev/null
+++ b/cone_viz/setup.cfg
@@ -0,0 +1,4 @@
+[develop]
+script_dir=$base/lib/cone_viz
+[install]
+install_scripts=$base/lib/cone_viz
diff --git a/cone_viz/setup.py b/cone_viz/setup.py
new file mode 100644
index 000000000..6c3e84d38
--- /dev/null
+++ b/cone_viz/setup.py
@@ -0,0 +1,20 @@
+from setuptools import setup
+
+package_name = "cone_viz"
+
+setup(
+ name=package_name,
+ version="0.0.0",
+ packages=[package_name],
+ install_requires=["setuptools"],
+ zip_safe=True,
+ maintainer="Your Name",
+ maintainer_email="you@example.com",
+ description="Visualize cones from perception and vehicle pose",
+ license="Apache-2.0",
+ entry_points={
+ "console_scripts": [
+ "cone_marker_publisher = cone_viz.cone_marker_publisher:main",
+ ],
+ },
+)
diff --git a/cone_viz/test/test_copyright.py b/cone_viz/test/test_copyright.py
new file mode 100644
index 000000000..97a39196e
--- /dev/null
+++ b/cone_viz/test/test_copyright.py
@@ -0,0 +1,25 @@
+# Copyright 2015 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ament_copyright.main import main
+import pytest
+
+
+# Remove the `skip` decorator once the source file(s) have a copyright header
+@pytest.mark.skip(reason='No copyright header has been placed in the generated source file.')
+@pytest.mark.copyright
+@pytest.mark.linter
+def test_copyright():
+ rc = main(argv=['.', 'test'])
+ assert rc == 0, 'Found errors'
diff --git a/cone_viz/test/test_flake8.py b/cone_viz/test/test_flake8.py
new file mode 100644
index 000000000..27ee1078f
--- /dev/null
+++ b/cone_viz/test/test_flake8.py
@@ -0,0 +1,25 @@
+# Copyright 2017 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ament_flake8.main import main_with_errors
+import pytest
+
+
+@pytest.mark.flake8
+@pytest.mark.linter
+def test_flake8():
+ rc, errors = main_with_errors(argv=[])
+ assert rc == 0, \
+ 'Found %d code style errors / warnings:\n' % len(errors) + \
+ '\n'.join(errors)
diff --git a/cone_viz/test/test_pep257.py b/cone_viz/test/test_pep257.py
new file mode 100644
index 000000000..b234a3840
--- /dev/null
+++ b/cone_viz/test/test_pep257.py
@@ -0,0 +1,23 @@
+# Copyright 2015 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from ament_pep257.main import main
+import pytest
+
+
+@pytest.mark.linter
+@pytest.mark.pep257
+def test_pep257():
+ rc = main(argv=['.', 'test'])
+ assert rc == 0, 'Found code style errors / warnings'
diff --git a/config/car/vehicle.yaml b/config/car/vehicle.yaml
index bfce6a685..ff44b1141 100644
--- a/config/car/vehicle.yaml
+++ b/config/car/vehicle.yaml
@@ -3,6 +3,7 @@ car:
wheel_base: 1.53
track_width: 1.2
dist_cg_2_rear_axis: 0.804
+ rear_axis_to_camera: 0.79
gear_ratio: 3.67
cog_height: 0.5
lift_coefficient: -0.86
diff --git a/config/control/vehicle.yaml b/config/control/vehicle.yaml
index 7e7d76344..5029166ac 100644
--- a/config/control/vehicle.yaml
+++ b/config/control/vehicle.yaml
@@ -2,7 +2,7 @@ control:
control_solver: "decoupled" # Options: "decoupled"
lateral_controller: "pure_pursuit" # Options: "pure_pursuit"
longitudinal_controller: "pid" # Options: "pid"
- pure_pursuit_lookahead_gain: 1.5
+ pure_pursuit_lookahead_gain: 1.2
pure_pursuit_lookahead_minimum: 3.0 # Acceleration: 6.0 , Skidpad: 4.0 , Autocross: 4.0 , Trackdrive: 4.0
pure_pursuit_lpf_alpha: 1 # Smoothing factor for the low-pass filter (0 = max smoothing, 1 = no smoothing)
pure_pursuit_lpf_initial_value: 0.0
diff --git a/config/perception/vehicle.yaml b/config/perception/vehicle.yaml
index 9eb2839f5..174d9d3dc 100644
--- a/config/perception/vehicle.yaml
+++ b/config/perception/vehicle.yaml
@@ -8,7 +8,7 @@ perception:
#FOV trimming
apply_rotation: false
- rotation: 90.0
+ rotation: 2.736
apply_fov_trimming: false
fov: 180.0
min_range: 2.5
diff --git a/config/planning/vehicle.yaml b/config/planning/vehicle.yaml
index 31e4ba0b0..e7476fe1e 100644
--- a/config/planning/vehicle.yaml
+++ b/config/planning/vehicle.yaml
@@ -30,7 +30,7 @@ planning:
smoothing_spline_precision: 10
smoothing_use_path_smoothing: false
#---------------------- Velocity Planning (vp_) -----------------------
- vp_minimum_velocity: 3.0
+ vp_minimum_velocity: 2.0
vp_braking_acceleration: -1.5
vp_normal_acceleration: 0.9
vp_use_velocity_planning: true
diff --git a/config/slam/pacsim.yaml b/config/slam/pacsim.yaml
index 04cc7c051..b2b141dcd 100644
--- a/config/slam/pacsim.yaml
+++ b/config/slam/pacsim.yaml
@@ -1,91 +1,54 @@
slam:
- motion_model_name: "constant_velocity_turnrate" # "constant_velocity" or "constant_velocity_turnrate" or ... -> name of the motion model
+ motion_model_name: "constant_velocity_turnrate" # "constant_velocity" or "constant_velocity_turnrate" or "constant_acceleration_turnrate" or ... -> name of the motion model
+ pose_updater_name: "difference_based_ready" # "base_pose_updater" or "difference_based_ready" -> name of the pose updater object, responsible for keeping pose estimate
landmark_filter_name: "consecutive_count" # "consecutive_count" or other names of filters of perception data
+ lidar_odometry_topic: "-" # "/fast_limo/state" or "/kiss/odometry" or "" -> topic for pose from lidar odometry
+ receive_lidar_odometry: false # Whether to use lidar odometry topic or not
data_association_model_name: "nearest_neighbor" # "maximum_likelihood_md" or "maximum_likelihood_nll" or "nearest_neighbor" or... -> name of the data association model
- data_association_limit_distance: 30 # maximum distance to consider a cone for data association
- data_association_gate: 1.23 # Maximum allowed Malahanobis distance (or euclidean distance for nearest neighbor) between an observation and matched landmark
+ data_association_limit_distance: 70 # maximum distance to consider a cone for data association
+ data_association_gate: 0.9 # Maximum allowed Malahanobis distance (or euclidean distance for nearest neighbor) between an observation and matched landmark
new_landmark_confidence_gate: 0.6 # Minimum confidence to consider an observation as a new landmark in data asociation
- observation_x_noise: 0.01 # sigma of the noise for cone positions in x
- observation_y_noise: 0.01 # sigma of the noise for cone positions in y
- velocity_x_noise: 0.2 # sigma of the noise for the velocity in x
- velocity_y_noise: 0.2 # sigma of the noise for the velocity in y
- angular_velocity_noise: 0.1 # sigma of the noise for the angular velocity
- pose_x_initial_noise: 0.1 # sigma of the noise for the initial pose in x
- pose_y_initial_noise: 0.1 # sigma of the noise for the initial pose in y
- pose_theta_initial_noise: 0.1 # sigma of the noise for the initial pose in yaw
- using_preloaded_map: true # Use preloaded map for SLAM, if true, the map will be loaded from the file only for skidpad and acceleration
+ observation_x_noise: 0.02 # sigma of the noise for cone positions in x (range in Graph SLAM)
+ observation_y_noise: 0.001 # sigma of the noise for cone positions in y (bearing in Graph SLAM)
+ velocity_x_noise: 0.1 # variance of the noise for the velocity in x
+ velocity_y_noise: 0.8 # variance of the noise for the velocity in y
+ imu_acceleration_x_noise: 0.005 # variance of the noise for the acceleration in x from IMU
+ angular_velocity_noise: 0.01 # variance of the noise for the angular velocity
+ pose_x_initial_noise: 0.001 # sigma of the noise for the initial pose in x
+ pose_y_initial_noise: 0.001 # sigma of the noise for the initial pose in y
+ pose_theta_initial_noise: 0.001 # sigma of the noise for the initial pose in yaw
+ preloaded_map_noise: 0.001 # sigma of the noise for preloaded map landmarks used for skidpad and acceleration
+ using_preloaded_map: false # Use preloaded map for SLAM, if true, the map will be loaded from the file only for skidpad and acceleration
slam_solver_name: "graph_slam" # "graph_slam" or "ekf_slam" or ... -> name of the slam solver
- minimum_observation_count: 1 # Minimum number of times a new landmark must be observed to be added to the map
- minimum_frequency_of_detections: 5 # Minimum frequency of detections to consider a landmark as valid
- slam_min_pose_difference: 0.3 # Minimum distance between poses to consider adding to factor graph
- slam_optimization_mode: "sync" # "sync" or "async" or ... -> name of the optimization mode, in which sync is at every factor added, async is at every time step
+ slam_optimization_mode: "async" # "sync" or "sync-parallel" or "async" or ... -> name of the optimization mode, in which sync is at every factor added, async is at every time step and sync-parallel is sync but callbacks execute in parallel
+ slam_optimization_in_poses: false # If true, the optimization will be done also when poses are added, not only when observations are added
slam_optimization_type: "sliding_window_levenberg" # "normal_levenberg" or "isam2" or "sliding_window_levenberg" or ... -> name of the optimization type
- preloaded_map_noise: 0.001 # sigma of the noise for preloaded map landmarks used for skidpad and acceleration
+
+ # Timestamp Synchronization Dependency
+ synchronized_timestamps: true # Whether motion and observation data are synchronized timestamps or not
+ max_pose_history_updater: 30 # Maximum number of past poses to keep for pose updater for observation delay compensation
+ max_pose_history_graph: 10 # Maximum number of past graphed poses to keep for observation delay compensation
+
+ # Only for pose_updater_name: "difference_based_ready"
+ slam_min_pose_difference: 0.3 # Minimum distance between poses to consider adding to factor graph
# Only for slam_optimization_mode: "async"
- slam_optimization_period: 0.2 # Time between optimization steps in seconds, 0.0 means optimization every time observations are added
+ slam_optimization_period: 0.05 # Time between optimization steps in seconds, 0.0 means optimization every time observations are added
# Only for slam_optimization_type: "isam2"
- slam_isam2_relinearize_threshold: 0.005 # Threshold for relinearizing the graph in isam2
- slam_isam2_relinearize_skip: 1 # Number of steps to skip before relinearizing the graph in isam2
- slam_isam2_factorization: "QR" # QR" or "CHOLESKY" -> Factorization method for isam2
+ slam_isam2_relinearize_threshold: 0.1 # Threshold for relinearizing the graph in isam2
+ slam_isam2_relinearize_skip: 5 # Number of steps to skip before relinearizing the graph in isam2
+ slam_isam2_factorization: "QR" # "QR" or "CHOLESKY" -> Factorization method for isam2
# Only for slam_optimization_type: "sliding_window_levenberg"
- sliding_window_size: 80 # Number of poses to keep in the sliding window
-
-## FSG23 AutoX Track complete working - Best ever
-# slam:
-# motion_model_name: "constant_velocity_turnrate" # "constant_velocity" or "constant_velocity_turnrate" or ... -> name of the motion model
-# data_association_model_name: "nearest_neighbor" # "maximum_likelihood_md" or "maximum_likelihood_nll" or "nearest_neighbor" or... -> name of the data association model
-# data_association_limit_distance: 30 # maximum distance to consider a cone for data association
-# data_association_gate: 1.23 # Maximum allowed Malahanobis distance (or euclidean distance for nearest neighbor) between an observation and matched landmark
-# new_landmark_confidence_gate: 0.6 # Minimum confidence to consider an observation as a new landmark in data asociation
-# observation_x_noise: 0.01 # sigma of the noise for cone positions in x
-# observation_y_noise: 0.01 # sigma of the noise for cone positions in y
-# velocity_x_noise: 0.2 # sigma of the noise for the velocity in x
-# velocity_y_noise: 0.2 # sigma of the noise for the velocity in y
-# angular_velocity_noise: 0.3 # sigma of the noise for the angular velocity
-# slam_solver_name: "graph_slam" # "graph_slam" or "ekf_slam" or ... -> name of the slam solver
-# slam_min_pose_difference: 0.3 # Minimum distance between poses to consider adding to factor graph
-# slam_optimization_mode: "sync" # "sync" or "async" or ... -> name of the optimization mode, in which sync is at every factor added, async is at every time step
-# slam_optimization_type: "sliding_window_levenberg" # "normal_levenberg" or "isam2" or "sliding_window_levenberg" or ... -> name of the optimization type
+ sliding_window_size: 50 # Number of poses to keep in the sliding window
-# # Only for slam_optimization_mode: "async"
-# slam_optimization_period: 0.2 # Time between optimization steps in seconds, 0.0 means optimization every time observations are added
-
-# # Only for slam_optimization_type: "isam2"
-# slam_isam2_relinearize_threshold: 0.005 # Threshold for relinearizing the graph in isam2
-# slam_isam2_relinearize_skip: 1 # Number of steps to skip before relinearizing the graph in isam2
-# slam_isam2_factorization: "QR" # QR" or "CHOLESKY" -> Factorization method for isam2
-
-# # Only for slam_optimization_type: "sliding_window_levenberg"
-# sliding_window_size: 80 # Number of poses to keep in the sliding window
-
-
-## FSE23 Track complete working - Best ever
-# slam:
- # motion_model_name: "constant_velocity_turnrate" # "constant_velocity" or "constant_velocity_turnrate" or ... -> name of the motion model
- # data_association_model_name: "nearest_neighbor" # "maximum_likelihood_md" or "maximum_likelihood_nll" or "nearest_neighbor" or... -> name of the data association model
- # data_association_limit_distance: 20 # maximum distance to consider a cone for data association
- # data_association_gate: 1.23 # Maximum allowed Malahanobis distance (or euclidean distance for nearest neighbor) between an observation and matched landmark
- # new_landmark_confidence_gate: 0.6 # Minimum confidence to consider an observation as a new landmark in data asociation
- # observation_x_noise: 0.01 # sigma of the noise for cone positions in x
- # observation_y_noise: 0.01 # sigma of the noise for cone positions in y
- # velocity_x_noise: 0.2 # sigma of the noise for the velocity in x
- # velocity_y_noise: 0.2 # sigma of the noise for the velocity in y
- # angular_velocity_noise: 0.2 # sigma of the noise for the angular velocity
- # slam_solver_name: "graph_slam" # "graph_slam" or "ekf_slam" or ... -> name of the slam solver
- # slam_min_pose_difference: 0.3 # Minimum distance between poses to consider adding to factor graph
- # slam_optimization_mode: "sync" # "sync" or "async" or ... -> name of the optimization mode, in which sync is at every factor added, async is at every time step
- # slam_optimization_type: "sliding_window_levenberg" # "normal_levenberg" or "isam2" or "sliding_window_levenberg" or ... -> name of the optimization type
-
- # # Only for slam_optimization_mode: "async"
- # slam_optimization_period: 0.2 # Time between optimization steps in seconds, 0.0 means optimization every time observations are added
-
- # # Only for slam_optimization_type: "isam2"
- # slam_isam2_relinearize_threshold: 0.005 # Threshold for relinearizing the graph in isam2
- # slam_isam2_relinearize_skip: 1 # Number of steps to skip before relinearizing the graph in isam2
- # slam_isam2_factorization: "QR" # QR" or "CHOLESKY" -> Factorization method for isam2
+ # Perception data filters
+ minimum_observation_count: 3 # Minimum number of times a new landmark must be observed to be added to the map
+ minimum_frequency_of_detections: 5 # Minimum frequency of detections to consider a landmark as valid
- # # Only for slam_optimization_type: "sliding_window_levenberg"
- # sliding_window_size: 40 # Number of poses to keep in the sliding window
+ # Loop closure paramteters
+ threshold_dist: 4.0 # Distance around origin to trigger loop closure
+ first_x_cones: 10 # consider a loop if you see any of these first X cones
+ border_width: 5 # distance to givve to start searching for loop closure again
+ minimum_confidence: 3 # minimum number of observations to confirm loop closure
\ No newline at end of file
diff --git a/config/slam/vehicle.yaml b/config/slam/vehicle.yaml
index 6ca95458a..744a71176 100644
--- a/config/slam/vehicle.yaml
+++ b/config/slam/vehicle.yaml
@@ -1,34 +1,54 @@
slam:
- motion_model_name: "constant_velocity" # "constant_velocity" or "constant_velocity_turnrate" or ... -> name of the motion model
+ motion_model_name: "constant_velocity_turnrate" # "constant_velocity" or "constant_velocity_turnrate" or "constant_acceleration_turnrate" or ... -> name of the motion model
+ pose_updater_name: "difference_based_ready" # "base_pose_updater" or "difference_based_ready" -> name of the pose updater object, responsible for keeping pose estimate
landmark_filter_name: "consecutive_count" # "consecutive_count" or other names of filters of perception data
+ lidar_odometry_topic: "-" # "/fast_limo/state" or "/kiss/odometry" or "" -> topic for pose from lidar odometry
+ receive_lidar_odometry: false # Whether to use lidar odometry topic or not
data_association_model_name: "nearest_neighbor" # "maximum_likelihood_md" or "maximum_likelihood_nll" or "nearest_neighbor" or... -> name of the data association model
- data_association_limit_distance: 70 # maximum distance to consider a cone for data association
- data_association_gate: 1.5 # Maximum allowed Malahanobis distance (or euclidean distance for nearest neighbor) between an observation and matched landmark
- new_landmark_confidence_gate: 0.6 # Minimum confidence to consider an observation as a new landmark in data asociation
- observation_x_noise: 0.03 # sigma of the noise for cone positions in x
- observation_y_noise: 0.03 # sigma of the noise for cone positions in y
- velocity_x_noise: 0.03 # sigma of the noise for the velocity in x
- velocity_y_noise: 0.03 # sigma of the noise for the velocity in y
- angular_velocity_noise: 0.05 # sigma of the noise for the angular velocitys
- pose_x_initial_noise: 0.1 # sigma of the noise for the initial pose in x
- pose_y_initial_noise: 0.1 # sigma of the noise for the initial pose in y
- pose_theta_initial_noise: 0.1 # sigma of the noise for the initial pose in yaw
- using_preloaded_map: false # Use preloaded map for SLAM, if true, the map will be loaded from the file, only for skidpad and acceleration
+ data_association_limit_distance: 40 # maximum distance to consider a cone for data association
+ data_association_gate: 1.2 # Maximum allowed Malahanobis distance (or euclidean distance for nearest neighbor) between an observation and matched landmark
+ new_landmark_confidence_gate: 0.0 # Minimum confidence to consider an observation as a new landmark in data asociation
+ observation_x_noise: 0.02 # sigma of the noise for cone positions in x (range in Graph SLAM)
+ observation_y_noise: 0.001 # sigma of the noise for cone positions in y (bearing in Graph SLAM)
+ velocity_x_noise: 0.1 # variance of the noise for the velocity in x
+ velocity_y_noise: 0.8 # variance of the noise for the velocity in y
+ imu_acceleration_x_noise: 0.005 # variance of the noise for the acceleration in x from IMU
+ angular_velocity_noise: 0.01 # variance of the noise for the angular velocity
+ pose_x_initial_noise: 0.001 # sigma of the noise for the initial pose in x
+ pose_y_initial_noise: 0.001 # sigma of the noise for the initial pose in y
+ pose_theta_initial_noise: 0.001 # sigma of the noise for the initial pose in yaw
+ preloaded_map_noise: 0.001 # sigma of the noise for preloaded map landmarks used for skidpad and acceleration
+ using_preloaded_map: false # Use preloaded map for SLAM, if true, the map will be loaded from the file only for skidpad and acceleration
slam_solver_name: "graph_slam" # "graph_slam" or "ekf_slam" or ... -> name of the slam solver
- minimum_observation_count: 3 # Minimum number of times a new landmark must be observed to be added to the map
- minimum_frequency_of_detections: 5 # Minimum frequency of the detections of a landmark to add it to the map
- slam_min_pose_difference: 0.1 # Minimum distance between poses to consider adding to factor graph
- slam_optimization_mode: "sync" # "sync" or "async" or ... -> name of the optimization mode, in which sync is at every factor added, async is at every time step
- slam_optimization_type: "sliding_window_levenberg" # "normal_levenberg" or "isam2" or "sliding_window_levenberg" or ... -> name of the optimization type
- preloaded_map_noise: 0.0 # sigma of the noise for preloaded map landmarks used for skidpad and acceleration
+ slam_optimization_mode: "async" # "sync" or "sync-parallel" or "async" or ... -> name of the optimization mode, in which sync is at every factor added, async is at every time step and sync-parallel is sync but callbacks execute in parallel
+ slam_optimization_in_poses: false # If true, the optimization will be done also when poses are added, not only when observations are added
+ slam_optimization_type: "isam2" # "normal_levenberg" or "isam2" or "sliding_window_levenberg" or ... -> name of the optimization type
+
+ # Timestamp Synchronization Dependency
+ synchronized_timestamps: false # Whether motion and observation data are synchronized timestamps or not
+ max_pose_history_updater: 30 # Maximum number of past poses to keep for pose updater buffer for observation delay compensation
+ max_pose_history_graph: 7 # Maximum number of past graphed poses to keep in instance buffer for observation delay compensation
+
+ # Only for pose_updater_name: "difference_based_ready"
+ slam_min_pose_difference: 0.15 # Minimum distance between poses to consider adding to factor graph
# Only for slam_optimization_mode: "async"
- slam_optimization_period: 0.2 # Time between optimization steps in seconds, 0.0 means optimization every time observations are added
+ slam_optimization_period: 0.25 # Time between optimization steps in seconds, 0.0 means optimization every time observations are added
# Only for slam_optimization_type: "isam2"
- slam_isam2_relinearize_threshold: 0.005 # Threshold for relinearizing the graph in isam2
- slam_isam2_relinearize_skip: 1 # Number of steps to skip before relinearizing the graph in isam2
- slam_isam2_factorization: "QR" # QR" or "CHOLESKY" -> Factorization method for isam2
-
+ slam_isam2_relinearize_threshold: 0.1 # Threshold for relinearizing the graph in isam2
+ slam_isam2_relinearize_skip: 5 # Number of steps to skip before relinearizing the graph in isam2
+ slam_isam2_factorization: "QR" # "QR" or "CHOLESKY" -> Factorization method for isam2
+
# Only for slam_optimization_type: "sliding_window_levenberg"
- sliding_window_size: 100 # Number of poses to keep in the sliding window
+ sliding_window_size: 50 # Number of poses to keep in the sliding window
+
+ # Perception data filters
+ minimum_observation_count: 3 # Minimum number of times a new landmark must be observed to be added to the map
+ minimum_frequency_of_detections: 5 # Minimum frequency of detections to consider a landmark as valid
+
+ # Loop closure paramteters
+ threshold_dist: 4.0 # Distance around origin to trigger loop closure
+ first_x_cones: 10 # consider a loop if you see any of these first X cones
+ border_width: 5 # distance to give to start searching for loop closure again
+ minimum_confidence: 3 # minimum number of observations to confirm loop closure
\ No newline at end of file
diff --git a/kill_nodes.sh b/kill_nodes.sh
index 309048447..d8c811d47 100755
--- a/kill_nodes.sh
+++ b/kill_nodes.sh
@@ -1,6 +1,11 @@
# Keywords to match against running ROS 2 processes
NODE_PATTERNS=(
- "inspection"
+ "perception_adapter"
+ "slam"
+ "velocity_estimation"
+ "planning_adapter"
+ "control_adapter"
+ "ros_can"
)
diff --git a/src/common_lib/include/common_lib/car_parameters/car_parameters.hpp b/src/common_lib/include/common_lib/car_parameters/car_parameters.hpp
index 000d1d133..659ae273f 100644
--- a/src/common_lib/include/common_lib/car_parameters/car_parameters.hpp
+++ b/src/common_lib/include/common_lib/car_parameters/car_parameters.hpp
@@ -8,13 +8,14 @@
#include "aero_parameters.hpp"
#include "common_lib/config_load/config_load.hpp"
#include "steering_motor_parameters.hpp"
-#include "tire_parameters.hpp"
#include "steering_parameters.hpp"
+#include "tire_parameters.hpp"
namespace common_lib::car_parameters {
struct CarParameters {
double wheel_diameter = 0.406;
double wheelbase = 1.530;
+ double rear_axis_to_camera = 0.79;
double track_width = 1.2;
double dist_cg_2_rear_axis = 0.804;
double gear_ratio = 4;
@@ -28,8 +29,8 @@ struct CarParameters {
common_lib::car_parameters::SteeringMotorParameters steering_motor_parameters;
common_lib::car_parameters::SteeringParameters steering_parameters;
CarParameters();
- CarParameters(double wheel_diameter, double wheelbase, double track_width,
- double dist_cg_2_rear_axis, double gear_ratio);
+ CarParameters(double wheel_diameter, double wheelbase, double rear_axis_to_camera,
+ double track_width, double dist_cg_2_rear_axis, double gear_ratio);
};
} // namespace common_lib::car_parameters
\ No newline at end of file
diff --git a/src/common_lib/include/common_lib/sensor_data/imu.hpp b/src/common_lib/include/common_lib/sensor_data/imu.hpp
index 084435dcd..abdd775e3 100644
--- a/src/common_lib/include/common_lib/sensor_data/imu.hpp
+++ b/src/common_lib/include/common_lib/sensor_data/imu.hpp
@@ -5,14 +5,18 @@
namespace common_lib::sensor_data {
struct ImuData {
- float rotational_velocity;
- float acceleration_x;
- float acceleration_y;
+ double rotational_velocity;
+ double acceleration_x;
+ double acceleration_y;
+ double rotational_velocity_noise;
+ double acceleration_x_noise;
+ double acceleration_y_noise;
rclcpp::Time timestamp_ = rclcpp::Time(0); //< Time of sensor data collection
ImuData() = default;
- ImuData(float rotational_velocity, float acceleration_x, float acceleration_y,
- rclcpp::Time timestamp = rclcpp::Time(0));
+ ImuData(double rotational_velocity, double acceleration_x, double acceleration_y,
+ rclcpp::Time timestamp = rclcpp::Time(0), double rotational_velocity_noise = 0.0,
+ double acceleration_x_noise = 0.0, double acceleration_y_noise = 0.0);
};
} // namespace common_lib::sensor_data
\ No newline at end of file
diff --git a/src/common_lib/include/common_lib/structures/circular_buffer.hpp b/src/common_lib/include/common_lib/structures/circular_buffer.hpp
new file mode 100644
index 000000000..2d196fec9
--- /dev/null
+++ b/src/common_lib/include/common_lib/structures/circular_buffer.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include
+#include
+#include
+
+template
+class CircularBuffer {
+public:
+ explicit CircularBuffer(size_t capacity = 0)
+ : capacity_(capacity), head_(0), size_(0), buffer_(capacity) {}
+
+ void set_capacity(size_t capacity) {
+ capacity_ = capacity;
+ buffer_.resize(capacity);
+ clear();
+ }
+
+ void clear() {
+ head_ = 0;
+ size_ = 0;
+ }
+
+ inline size_t size() const { return size_; }
+ inline size_t capacity() const { return capacity_; }
+ inline bool empty() const { return size_ == 0; }
+ inline bool full() const { return size_ == capacity_; }
+
+ /** Add item into circular buffer */
+ void push(const T& item) {
+ if (capacity_ == 0) return;
+
+ buffer_[head_] = item;
+ head_ = (head_ + 1) % capacity_;
+
+ if (size_ < capacity_) size_++;
+ }
+
+ /** Access the most recent item */
+ const T& latest() const {
+ if (size_ == 0) throw std::out_of_range("CircularBuffer::latest - buffer empty");
+
+ size_t index = (head_ + capacity_ - 1) % capacity_;
+ return buffer_[index];
+ }
+
+ /** Access i-th element from the end (0 = latest, 1 = previous, ...) */
+ const T& from_end(size_t i) const {
+ if (i >= size_) throw std::out_of_range("CircularBuffer::from_end - index too large");
+
+ size_t index = (head_ + capacity_ - 1 - i) % capacity_;
+ return buffer_[index];
+ }
+
+ /** Iterate raw access */
+ const T& operator[](size_t index) const {
+ if (index >= size_) throw std::out_of_range("CircularBuffer::operator[] - index too large");
+
+ size_t real_index = (head_ + capacity_ - size_ + index) % capacity_;
+ return buffer_[real_index];
+ }
+
+private:
+ size_t capacity_;
+ size_t head_;
+ size_t size_;
+ std::vector buffer_;
+};
diff --git a/src/common_lib/src/car_parameters/car_parameters.cpp b/src/common_lib/src/car_parameters/car_parameters.cpp
index 2a4a3f267..88cf518dd 100644
--- a/src/common_lib/src/car_parameters/car_parameters.cpp
+++ b/src/common_lib/src/car_parameters/car_parameters.cpp
@@ -1,11 +1,13 @@
#include "common_lib/car_parameters/car_parameters.hpp"
common_lib::car_parameters::CarParameters::CarParameters(double wheel_diameter, double wheelbase,
+ double rear_axis_to_camera,
double track_width,
double dist_cg_2_rear_axis,
double gear_ratio)
: wheel_diameter(wheel_diameter),
wheelbase(wheelbase),
+ rear_axis_to_camera(rear_axis_to_camera),
track_width(track_width),
dist_cg_2_rear_axis(dist_cg_2_rear_axis),
gear_ratio(gear_ratio) {}
@@ -24,5 +26,6 @@ common_lib::car_parameters::CarParameters::CarParameters() {
this->wheelbase = car_config["car"]["wheel_base"].as();
this->track_width = car_config["car"]["track_width"].as();
this->dist_cg_2_rear_axis = car_config["car"]["dist_cg_2_rear_axis"].as();
+ this->rear_axis_to_camera = car_config["car"]["rear_axis_to_camera"].as();
this->gear_ratio = car_config["car"]["gear_ratio"].as();
}
\ No newline at end of file
diff --git a/src/common_lib/src/sensor_data/imu.cpp b/src/common_lib/src/sensor_data/imu.cpp
index af6f38df8..c6153a9c5 100644
--- a/src/common_lib/src/sensor_data/imu.cpp
+++ b/src/common_lib/src/sensor_data/imu.cpp
@@ -2,11 +2,15 @@
namespace common_lib::sensor_data {
-ImuData::ImuData(float rotational_velocity, float acceleration_x, float acceleration_y,
- rclcpp::Time timestamp)
+ImuData::ImuData(double rotational_velocity, double acceleration_x, double acceleration_y,
+ rclcpp::Time timestamp, double rotational_velocity_noise,
+ double acceleration_x_noise, double acceleration_y_noise)
: rotational_velocity(rotational_velocity),
acceleration_x(acceleration_x),
acceleration_y(acceleration_y),
+ rotational_velocity_noise(rotational_velocity_noise),
+ acceleration_x_noise(acceleration_x_noise),
+ acceleration_y_noise(acceleration_y_noise),
timestamp_(timestamp) {}
} // namespace common_lib::sensor_data
\ No newline at end of file
diff --git a/src/motion_lib/CMakeLists.txt b/src/motion_lib/CMakeLists.txt
index 655cd1845..0487a61f4 100644
--- a/src/motion_lib/CMakeLists.txt
+++ b/src/motion_lib/CMakeLists.txt
@@ -28,6 +28,8 @@ set(IMPLEMENTATION_FILES
src/v2p_models/constant_velocity_model.cpp
src/v2p_models/base_v2p_motion_model.cpp
src/v2p_models/constant_velocity_turnrate_model.cpp
+ src/v2p_models/constant_acceleration_turnrate_model.cpp
+ src/v2p_models/odometry_model.cpp
src/aero_model/default_aero_model.cpp
src/tire_model/pacejka_combined_slip.cpp
src/steering_model/parallel_front_steering.cpp
@@ -67,6 +69,7 @@ if(BUILD_TESTING)
test/main.cpp
test/v2p_models/constant_velocity_model_test.cpp
test/v2p_models/constant_velocity_turnrate_model_test.cpp
+ test/v2p_models/constant_acceleration_turnrate_model_test.cpp
test/vel_process_model/particle_model_test.cpp
)
diff --git a/src/motion_lib/include/motion_lib/car_parameters.hpp b/src/motion_lib/include/motion_lib/car_parameters.hpp
new file mode 100644
index 000000000..9589f4a6a
--- /dev/null
+++ b/src/motion_lib/include/motion_lib/car_parameters.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+constexpr double WHEEL_DIAMETER = 0.5;
+constexpr double WHEELBASE = 1.530;
+constexpr double REAR_AXIS_TO_CAMERA = 0.79;
+constexpr double AXIS_LENGTH = 1.2;
+constexpr double DIST_CG_2_REAR_AXIS = 0.9822932352409;
\ No newline at end of file
diff --git a/src/motion_lib/include/motion_lib/s2v_model/bicycle_model.hpp b/src/motion_lib/include/motion_lib/s2v_model/bicycle_model.hpp
new file mode 100644
index 000000000..ef52e3694
--- /dev/null
+++ b/src/motion_lib/include/motion_lib/s2v_model/bicycle_model.hpp
@@ -0,0 +1,64 @@
+#pragma once
+
+#include
+#include
+#include
+
+#include "common_lib/maths/transformations.hpp"
+#include "motion_lib/s2v_model/s2v_model.hpp"
+
+class BicycleModel : public S2VModel {
+ common_lib::car_parameters::CarParameters car_parameters_;
+
+public:
+ BicycleModel(common_lib::car_parameters::CarParameters car_parameters)
+ : car_parameters_(car_parameters) {}
+ /**
+ * @brief assumes a bicycle model and a set of parameters about the vehicle to calculate the
+ * velocities of the center of mass given the velocities of the wheels
+ *
+ * @param rl_rpm rear left wheel velocity in rpm
+ * @param fl_rpm front left wheel velocity in rpm
+ * @param rr_rpm rear right wheel velocity in rpm
+ * @param fr_rpm front right wheel velocity in rpm
+ * @param steering_angle steering angle in radians
+ * @return std::pair translational and rotational velocities of the center of mass
+ * in m/s and rad/s respectively
+ */
+ std::pair wheels_velocities_to_cg(double rl_rpm, [[maybe_unused]] double fl_rpm,
+ double rr_rpm, [[maybe_unused]] double fr_rpm,
+ double steering_angle) override;
+
+ /**
+ * @brief Calculates the position of the rear axis given the position of the center of mass, the
+ * the orientation and the distance between the center of mass and the rear axis
+ *
+ * @param cg position of the center of mass in meters
+ * @param orientation orientation of the vehicle relative to the world frame in radians
+ * @param dist_cg_2_rear_axis disntance between the center of mass and the rear axis in meters
+ * @return common_lib::structures::Position
+ */
+ common_lib::structures::Position rear_axis_position(const common_lib::structures::Position& cg,
+ double orientation,
+ double dist_cg_2_rear_axis) override;
+ /**
+ * @brief Assumes a bicycle model and a set of parameters about the vehicle to calculate the
+ * velocities of the wheels given the velocities of the center of mass
+ *
+ * @param cg_velocities vector of velocities on the Center of Gravity {velocity_x, velocity_y,
+ * rotational_velocity} in m/s and rad/s respectively
+ * @return Eigen::VectorXd rpms of the wheels, the steering angle, and motor rpms {fl_rpm, fr_rpm,
+ * rl_rpm, rr_rpm, steering_angle, motor_rpm}
+ */
+ Eigen::VectorXd cg_velocity_to_wheels(const Eigen::Vector3d& cg_velocities) override;
+
+ /**
+ * @brief Calculates the jacobian of the function cg_velocity_to_wheels with respect to the center
+ * of mass velocities
+ *
+ * @param cg_velocities vector of velocities on the Center of Gravity {velocity_x, velocity_y,
+ * rotational_velocity} in m/s and rad/s respectively
+ * @return Eigen::MatrixXd jacobian matrix of dimension 6x3
+ */
+ Eigen::MatrixXd jacobian_cg_velocity_to_wheels(const Eigen::Vector3d& cg_velocities) override;
+};
\ No newline at end of file
diff --git a/src/motion_lib/include/motion_lib/s2v_model/map.hpp b/src/motion_lib/include/motion_lib/s2v_model/map.hpp
new file mode 100644
index 000000000..52aa2fc22
--- /dev/null
+++ b/src/motion_lib/include/motion_lib/s2v_model/map.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include