15     measurement_noise_model,
 
   23     """Generates ground truth and simulated measurements for SLAM. 
   26         num_landmarks: Number of landmarks to generate. 
   27         world_size: Size of the square world environment. 
   28         robot_radius: Radius of the robot's circular path. 
   29         robot_angular_vel: Angular velocity of the robot (rad/step). 
   30         num_steps: Number of simulation steps. 
   31         dt: Time step duration. 
   32         odometry_noise_model: GTSAM noise model for odometry. 
   33         measurement_noise_model: GTSAM noise model for bearing-range. 
   34         max_sensor_range: Maximum range of the bearing-range sensor. 
   35         X: GTSAM symbol shorthand function for poses. 
   36         L: GTSAM symbol shorthand function for landmarks. 
   37         odom_seed: Random seed for odometry noise. 
   38         meas_seed: Random seed for measurement noise. 
   39         landmark_seed: Random seed for landmark placement. 
   43             - landmarks_gt_dict (dict): L(i) -> gtsam.Point2 ground truth. 
   44             - poses_gt (list): List of gtsam.Pose2 ground truth poses. 
   45             - odometry_measurements (list): List of noisy gtsam.Pose2 odometry. 
   46             - measurements_sim (list): List of lists, measurements_sim[k] contains 
   47                                        tuples (L(lm_id), bearing, range) for step k. 
   48             - landmarks_gt_array (np.array): 2xN numpy array of landmark positions. 
   50     np.random.seed(landmark_seed)
 
   51     odometry_noise_sampler = 
gtsam.Sampler(odometry_noise_model, odom_seed)
 
   52     measurement_noise_sampler = 
gtsam.Sampler(measurement_noise_model, meas_seed)
 
   55     landmarks_gt_array = (np.random.rand(2, num_landmarks) - 0.5) * world_size
 
   62     current_pose_gt = 
gtsam.Pose2(robot_radius, 0, np.pi / 2)  
 
   63     poses_gt.append(current_pose_gt)
 
   65     for _ 
in range(num_steps):
 
   66         delta_theta = robot_angular_vel * dt
 
   67         arc_length = robot_angular_vel * robot_radius * dt
 
   68         motion_command = 
gtsam.Pose2(arc_length, 0, delta_theta)
 
   69         current_pose_gt = current_pose_gt.compose(motion_command)
 
   70         poses_gt.append(current_pose_gt)
 
   73     odometry_measurements = []
 
   74     for k 
in range(num_steps):
 
   76         pose_k1 = poses_gt[k + 1]
 
   77         true_odom = pose_k.between(pose_k1)
 
   80         odom_noise_vec = odometry_noise_sampler.sample()
 
   81         noisy_odom = true_odom.compose(
 
   82             gtsam.Pose2(odom_noise_vec[0], odom_noise_vec[1], odom_noise_vec[2])
 
   84         odometry_measurements.append(noisy_odom)
 
   87     measurements_sim = [[] 
for _ 
in range(num_steps + 1)]
 
   88     for k 
in range(num_steps + 1):
 
   89         robot_pose = poses_gt[k]
 
   90         for lm_id 
in range(num_landmarks):
 
   91             lm_gt_pt = landmarks_gt_dict[
L(lm_id)]
 
   93                 measurement_factor = gtsam.BearingRangeFactor2D(
 
   96                     robot_pose.bearing(lm_gt_pt),
 
   97                     robot_pose.range(lm_gt_pt),
 
   98                     measurement_noise_model,
 
  100                 true_range = measurement_factor.measured().
range()
 
  101                 true_bearing = measurement_factor.measured().bearing()
 
  105                     true_range <= max_sensor_range
 
  106                     and abs(true_bearing.theta()) < np.pi / 2
 
  109                     noise_vec = measurement_noise_sampler.sample()
 
  110                     noisy_bearing = true_bearing.retract(
 
  111                         np.array([noise_vec[0]])
 
  113                     noisy_range = true_range + noise_vec[1]
 
  116                         measurements_sim[k].append(
 
  117                             (
L(lm_id), noisy_bearing, noisy_range)
 
  119             except Exception 
as e:
 
  124     print(f
"Simulation Generated: {num_landmarks} landmarks.")
 
  126         f
"Simulation Generated: {num_steps + 1} ground truth poses and {num_steps} odometry measurements." 
  128     num_meas_total = sum(
len(m_list) 
for m_list 
in measurements_sim)
 
  129     print(f
"Simulation Generated: {num_meas_total} bearing-range measurements.")
 
  134         odometry_measurements,