Пример #1
0
    def __init__(self):
        stats_top = rospy.get_param('~pf_stats_top', 'stats')
        self.stats_sub = rospy.Subscriber(stats_top, numpy_msg(Floats),
                                          self.stat_cb)
        self.path_img = rospy.get_param('~background_img_path',
                                        'default_real_mean_depth.png')
        self.map_frame = rospy.get_param('~map_frame', 'map')
        self.odom_frame = rospy.get_param('~odom_frame', 'odom')
        self.survey_name = rospy.get_param('~survey_name', 'survey')

        # Real mbes pings subscriber
        mbes_pings_top = rospy.get_param("~mbes_pings_topic", 'mbes_pings')

        # PF ping subscriber
        pf_pings_top = rospy.get_param("~particle_sim_mbes_topic",
                                       'pf_mbes_pings')

        self.real_pings_sub = message_filters.Subscriber(
            mbes_pings_top, PointCloud2)
        self.pf_pings_sub = message_filters.Subscriber(pf_pings_top,
                                                       PointCloud2)
        self.ts = message_filters.ApproximateTimeSynchronizer(
            [self.real_pings_sub, self.pf_pings_sub],
            20,
            slop=20.0,
            allow_headerless=False)

        self.ts.registerCallback(self.ping_cb)
        self.pings_vec = np.zeros((1, 6))

        self.filter_cnt = 1
        self.datagram_size = 17
        self.filt_vec = np.zeros((self.datagram_size, 1))
        self.img = plt.imread(self.path_img)

        # Map to odom transform to plot AUV pose on top of image
        tfBuffer = tf2_ros.Buffer()
        tf2_ros.TransformListener(tfBuffer)
        try:
            rospy.loginfo("Waiting for transforms")
            m2o_tf = tfBuffer.lookup_transform(self.map_frame, self.odom_frame,
                                               rospy.Time(0),
                                               rospy.Duration(35))
            self.m2o_mat = matrix_from_tf(m2o_tf)
            rospy.loginfo("Transforms locked - stats node")
        except:
            rospy.logerr("Stats node: Could not lookup transforms")

        # When the survey is finished, save the data to disk
        finished_top = rospy.get_param("~survey_finished_top",
                                       '/survey_finished')
        self.synch_pub = rospy.Subscriber(finished_top, Bool, self.synch_cb)
        self.survey_finished = False

        self.cov_traces = [0.]

        rospy.spin()
Пример #2
0
    def update(self, meas_mbes, odom):
        # Compute AUV MBES ping ranges
        particle_tf = Transform()
        particle_tf.translation = odom.pose.pose.position
        particle_tf.rotation = odom.pose.pose.orientation
        tf_mat = matrix_from_tf(particle_tf)
        m2auv = np.matmul(self.m2o_mat, np.matmul(tf_mat, self.base2mbes_mat))
        # this will not work in simulation ***
        mbes_meas_ranges = self.ping2ranges(meas_mbes)

        self.pf_mbes_pub.publish(meas_mbes)
        # Measurement update of each particle
        for i in range(0, self.pc, 8):
            for j in range(i, i + 8):
                if j < self.pc:
                    mbes_goal = self.particles[j].get_mbes_goal()
                    #print(mbes_goal)
                    self.ac_mbes[j].send_goal(mbes_goal)
                else:
                    break
            for j in range(i, i + 8):
                if j < self.pc:
                    if self.ac_mbes[j].wait_for_result(rospy.Duration(0.03)):
                        mbes_res = self.ac_mbes[j].get_result()
                        got_result = True
                    else:
                        mbes_res = None
                        got_result = False
                    self.particles[j].meas_update(mbes_res, mbes_meas_ranges,
                                                  got_result)
                else:
                    break

        weights = []
        for i in range(self.pc):
            weights.append(self.particles[i].w)

        self.miss_meas = weights.count(1.e-50)

        weights_array = np.asarray(weights)
        # Add small non-zero value to avoid hitting zero
        weights_array += 1.e-30

        return weights_array
Пример #3
0
    def update(self, meas_mbes, odom):
        # Compute AUV MBES ping ranges
        particle_tf = Transform()
        particle_tf.translation = odom.pose.pose.position
        particle_tf.rotation = odom.pose.pose.orientation
        tf_mat = matrix_from_tf(particle_tf)
        m2auv = np.matmul(self.m2o_mat, np.matmul(tf_mat, self.base2mbes_mat))
        mbes_meas_ranges = pcloud2ranges(meas_mbes, m2auv)

        # Measurement update of each particle
        weights = []
        for i in range(self.pc):
            self.particles[i].meas_update(mbes_meas_ranges)
            weights.append(self.particles[i].w)

        weights_array = np.asarray(weights)
        # Add small non-zero value to avoid hitting zero
        weights_array += 1.e-30

        return weights_array
Пример #4
0
    def __init__(self):
        # Read necessary parameters
        self.pc = rospy.get_param('~particle_count', 10)  # Particle Count
        map_frame = rospy.get_param('~map_frame', 'map')  # map frame_id
        odom_frame = rospy.get_param('~odom_frame', 'odom')
        meas_model_as = rospy.get_param('~mbes_as',
                                        '/mbes_sim_server')  # map frame_id
        mbes_pc_top = rospy.get_param("~particle_sim_mbes_topic", '/sim_mbes')
        beams_num = rospy.get_param("~num_beams_sim", 20)
        self.beams_real = rospy.get_param("~n_beams_mbes", 512)

        # Initialize tf listener
        tfBuffer = tf2_ros.Buffer()
        tf2_ros.TransformListener(tfBuffer)
        try:
            rospy.loginfo("Waiting for transforms")
            mbes_tf = tfBuffer.lookup_transform('hugin/base_link',
                                                'hugin/mbes_link',
                                                rospy.Time(0),
                                                rospy.Duration(20))
            self.base2mbes_mat = matrix_from_tf(mbes_tf)

            m2o_tf = tfBuffer.lookup_transform(map_frame, odom_frame,
                                               rospy.Time(0),
                                               rospy.Duration(20))
            self.m2o_mat = matrix_from_tf(m2o_tf)

            rospy.loginfo("Transforms locked - pf node")
        except:
            rospy.loginfo(
                "ERROR: Could not lookup transform from base_link to mbes_link"
            )

        # Read covariance values
        meas_cov = float(rospy.get_param('~measurement_covariance', 0.01))
        cov_string = rospy.get_param('~motion_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        motion_cov = list(map(float, cov_list))

        cov_string = rospy.get_param('~init_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        init_cov = list(map(float, cov_list))

        cov_string = rospy.get_param('~resampling_noise_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        self.res_noise_cov = list(map(float, cov_list))

        # Initialize list of particles
        self.particles = np.empty(self.pc, dtype=object)

        for i in range(self.pc):
            self.particles[i] = Particle(beams_num,
                                         self.pc,
                                         i,
                                         self.base2mbes_mat,
                                         self.m2o_mat,
                                         init_cov=init_cov,
                                         meas_cov=meas_cov,
                                         process_cov=motion_cov,
                                         map_frame=map_frame,
                                         odom_frame=odom_frame,
                                         meas_as=meas_model_as,
                                         pc_mbes_top=mbes_pc_top)

        #Initialize an ac per particle for the mbes updates
        self.ac_mbes = np.empty(self.pc, dtype=object)
        self.nr_of_callbacks = 0

        for i in range(self.pc):
            self.ac_mbes[i] = actionlib.SimpleActionClient(
                meas_model_as, MbesSimAction)
            self.ac_mbes[i].wait_for_server()

        self.time = None
        self.old_time = None
        self.pred_odom = None
        self.latest_mbes = PointCloud2()
        self.prev_mbes = PointCloud2()
        self.poses = PoseArray()
        self.poses.header.frame_id = odom_frame
        self.avg_pose = PoseWithCovarianceStamped()
        self.avg_pose.header.frame_id = odom_frame

        # Initialize particle poses publisher
        pose_array_top = rospy.get_param("~particle_poses_topic",
                                         '/particle_poses')
        self.pf_pub = rospy.Publisher(pose_array_top, PoseArray, queue_size=10)

        # Initialize average of poses publisher
        avg_pose_top = rospy.get_param("~average_pose_topic", '/average_pose')
        self.avg_pub = rospy.Publisher(avg_pose_top,
                                       PoseWithCovarianceStamped,
                                       queue_size=10)

        # Establish subscription to mbes pings message
        mbes_pings_top = rospy.get_param("~mbes_pings_topic", 'mbes_pings')
        rospy.Subscriber(mbes_pings_top, PointCloud2, self.mbes_callback)

        # Establish subscription to odometry message (intentionally last)
        odom_top = rospy.get_param("~odometry_topic", 'odom')
        rospy.Subscriber(odom_top, Odometry, self.odom_callback)

        # Expected meas of PF outcome at every time step
        pf_mbes_top = rospy.get_param("~average_mbes_topic", '/avg_mbes')
        self.pf_mbes_pub = rospy.Publisher(pf_mbes_top,
                                           PointCloud2,
                                           queue_size=1)

        self.stats = rospy.Publisher('/pf/n_eff', Float32, queue_size=10)
        rospy.loginfo("Particle filter class successfully created")

        self.update_rviz()
        rospy.spin()
Пример #5
0
    def __init__(self):
        # Read necessary parameters
        self.pc = rospy.get_param('~particle_count', 10)  # Particle Count
        self.map_frame = rospy.get_param('~map_frame', 'map')  # map frame_id
        self.mbes_frame = rospy.get_param('~mbes_link',
                                          'mbes_link')  # mbes frame_id
        odom_frame = rospy.get_param('~odom_frame', 'odom')
        meas_model_as = rospy.get_param('~mbes_as',
                                        '/mbes_sim_server')  # map frame_id
        self.beams_num = rospy.get_param("~num_beams_sim", 20)
        self.beams_real = rospy.get_param("~n_beams_mbes", 512)
        self.mbes_angle = rospy.get_param("~mbes_open_angle",
                                          np.pi / 180. * 60.)

        # Initialize tf listener
        tfBuffer = tf2_ros.Buffer()
        tf2_ros.TransformListener(tfBuffer)

        # Read covariance values
        meas_std = float(rospy.get_param('~measurement_std', 0.01))
        cov_string = rospy.get_param('~motion_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        motion_cov = list(map(float, cov_list))

        cov_string = rospy.get_param('~init_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        init_cov = list(map(float, cov_list))

        cov_string = rospy.get_param('~resampling_noise_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        self.res_noise_cov = list(map(float, cov_list))

        # Global variables
        self.pred_odom = None
        self.n_eff_filt = 0.
        self.n_eff_mask = [self.pc] * 3
        self.latest_mbes = PointCloud2()
        self.prev_mbes = PointCloud2()
        self.poses = PoseArray()
        self.poses.header.frame_id = odom_frame
        self.avg_pose = PoseWithCovarianceStamped()
        self.avg_pose.header.frame_id = odom_frame

        # Initialize particle poses publisher
        pose_array_top = rospy.get_param("~particle_poses_topic",
                                         '/particle_poses')
        self.pf_pub = rospy.Publisher(pose_array_top, PoseArray, queue_size=10)

        # Initialize average of poses publisher
        avg_pose_top = rospy.get_param("~average_pose_topic", '/average_pose')
        self.avg_pub = rospy.Publisher(avg_pose_top,
                                       PoseWithCovarianceStamped,
                                       queue_size=10)

        # Expected meas of PF outcome at every time step
        pf_mbes_top = rospy.get_param("~average_mbes_topic", '/avg_mbes')
        self.pf_mbes_pub = rospy.Publisher(pf_mbes_top,
                                           PointCloud2,
                                           queue_size=1)

        stats_top = rospy.get_param('~pf_stats_top', 'stats')
        self.stats = rospy.Publisher(stats_top,
                                     numpy_msg(Floats),
                                     queue_size=10)

        mbes_pc_top = rospy.get_param("~particle_sim_mbes_topic", '/sim_mbes')
        self.pcloud_pub = rospy.Publisher(mbes_pc_top,
                                          PointCloud2,
                                          queue_size=10)

        # Load mesh
        svp_path = rospy.get_param('~sound_velocity_prof')
        mesh_path = rospy.get_param('~mesh_path')

        if svp_path.split('.')[1] != 'cereal':
            sound_speeds = csv_data.csv_asvp_sound_speed.parse_file(svp_path)
        else:
            sound_speeds = csv_data.csv_asvp_sound_speed.read_data(svp_path)

        data = np.load(mesh_path)
        V, F, bounds = data['V'], data['F'], data['bounds']
        print("Mesh loaded")

        # Create draper
        self.draper = base_draper.BaseDraper(V, F, bounds, sound_speeds)
        self.draper.set_ray_tracing_enabled(False)
        data = None
        V = None
        F = None
        bounds = None
        sound_speeds = None
        print("draper created")
        print("Size of draper: ", sys.getsizeof(self.draper))

        # Load GP
        gp_path = rospy.get_param("~gp_path", 'gp.path')
        self.gp = gp.SVGP.load(1000, gp_path)
        print("Size of GP: ", sys.getsizeof(self.gp))

        # Action server for MBES pings sim (necessary to be able to use UFO maps as well)
        sim_mbes_as = rospy.get_param('~mbes_sim_as', '/mbes_sim_server')
        self.as_ping = actionlib.SimpleActionServer('/mbes_sim_server',
                                                    MbesSimAction,
                                                    execute_cb=self.mbes_as_cb,
                                                    auto_start=True)

        # Subscription to real mbes pings
        mbes_pings_top = rospy.get_param("~mbes_pings_topic", 'mbes_pings')
        rospy.Subscriber(mbes_pings_top, PointCloud2, self.mbes_real_cb)

        # Establish subscription to odometry message (intentionally last)
        odom_top = rospy.get_param("~odometry_topic", 'odom')
        rospy.Subscriber(odom_top, Odometry, self.odom_callback)

        # Create expected MBES beams directions
        angle_step = self.mbes_angle / self.beams_num
        self.beams_dir = []
        for i in range(0, self.beams_num):
            roll_step = rotation_matrix(-self.mbes_angle / 2. + angle_step * i,
                                        (1, 0, 0))[0:3, 0:3]
            rot = roll_step[:, 2]
            self.beams_dir.append(rot / np.linalg.norm(rot))

        # Shift for fast ray tracing in 2D
        beams = np.asarray(self.beams_dir)
        n_beams = len(self.beams_dir)
        self.beams_dir_2d = np.concatenate(
            (beams[:, 0].reshape(n_beams, 1), np.roll(
                beams[:, 1:3], 1, axis=1).reshape(n_beams, 2)),
            axis=1)

        self.beams_dir_2d = np.array([1, -1, 1]) * self.beams_dir_2d

        # Start to play survey data. Necessary to keep the PF and auv_2_ros in synch
        synch_top = rospy.get_param("~synch_topic", '/pf_synch')
        self.synch_pub = rospy.Publisher(synch_top, Bool, queue_size=10)
        msg = Bool()
        msg.data = True

        # Transforms from auv_2_ros
        try:
            rospy.loginfo("Waiting for transforms")
            mbes_tf = tfBuffer.lookup_transform('hugin/base_link',
                                                'hugin/mbes_link',
                                                rospy.Time(0),
                                                rospy.Duration(35))
            self.base2mbes_mat = matrix_from_tf(mbes_tf)

            m2o_tf = tfBuffer.lookup_transform(self.map_frame, odom_frame,
                                               rospy.Time(0),
                                               rospy.Duration(35))
            self.m2o_mat = matrix_from_tf(m2o_tf)

            rospy.loginfo("Transforms locked - pf node")
        except:
            rospy.loginfo(
                "ERROR: Could not lookup transform from base_link to mbes_link"
            )

        # Initialize list of particles
        self.particles = np.empty(self.pc, dtype=object)
        for i in range(self.pc):
            self.particles[i] = Particle(self.beams_num,
                                         self.pc,
                                         i,
                                         self.base2mbes_mat,
                                         self.m2o_mat,
                                         init_cov=init_cov,
                                         meas_std=meas_std,
                                         process_cov=motion_cov)

        # PF filter created. Start auv_2_ros survey playing
        rospy.loginfo("Particle filter class successfully created")
        self.synch_pub.publish(msg)

        finished_top = rospy.get_param("~survey_finished_top",
                                       '/survey_finished')
        self.finished_sub = rospy.Subscriber(finished_top, Bool, self.synch_cb)
        self.survey_finished = False

        # Start timing now
        self.time = rospy.Time.now().to_sec()
        self.old_time = rospy.Time.now().to_sec()

        # Create particle to compute DR
        self.dr_particle = Particle(self.beams_num,
                                    self.pc,
                                    self.pc + 1,
                                    self.base2mbes_mat,
                                    self.m2o_mat,
                                    init_cov=[0.] * 6,
                                    meas_std=meas_std,
                                    process_cov=motion_cov)

        rospy.spin()
Пример #6
0
    def __init__(self):
        # Read necessary parameters
        param = rospy.search_param("particle_count")
        self.pc = rospy.get_param(param)  # Particle Count
        param = rospy.search_param("map_frame")
        map_frame = rospy.get_param(param)  # map frame_id

        # Initialize connection to MbesSim action server
        self.ac_mbes = actionlib.SimpleActionClient('/mbes_sim_server',
                                                    MbesSimAction)
        rospy.loginfo("Waiting for MbesSim action server")
        self.ac_mbes.wait_for_server()
        rospy.loginfo("Connected MbesSim action server")

        # Initialize tf listener
        tfBuffer = tf2_ros.Buffer()
        tf2_ros.TransformListener(tfBuffer)
        try:
            rospy.loginfo("Waiting for transform from base_link to mbes_link")
            mbes_tf = tfBuffer.lookup_transform('hugin/mbes_link',
                                                'hugin/base_link',
                                                rospy.Time.now(),
                                                rospy.Duration(10))
            mbes_matrix = matrix_from_tf(mbes_tf)
            rospy.loginfo(
                "Transform locked from base_link to mbes_link - pf node")
        except:
            rospy.loginfo(
                "ERROR: Could not lookup transform from base_link to mbes_link"
            )

        # Read covariance values
        param = rospy.search_param("measurement_covariance")
        meas_cov = float(rospy.get_param(param))
        param = rospy.search_param("motion_covariance")
        cov_string = rospy.get_param(param)
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        predict_cov = list(map(float, cov_list))  # [xv_cov, yv_cov, yaw_v_cov]

        # Initialize list of particles
        self.particles = []
        for i in range(self.pc):  # index starts from 0
            self.particles.append(
                Particle(i,
                         mbes_matrix,
                         meas_cov=meas_cov,
                         process_cov=predict_cov,
                         map_frame=map_frame))

        # Initialize class/callback variables
        self.time = None
        self.old_time = None
        self.pred_odom = None
        self.mbes_true_pc = None
        self.poses = PoseArray()
        self.poses.header.frame_id = map_frame
        self.avg_pose = PoseWithCovarianceStamped()
        self.avg_pose.header.frame_id = map_frame

        # Initialize particle poses publisher
        param = rospy.search_param("particle_poses_topic")
        pose_array_top = rospy.get_param(param)
        self.pf_pub = rospy.Publisher(pose_array_top, PoseArray, queue_size=10)
        # Initialize average of poses publisher
        param = rospy.search_param("average_pose_topic")
        avg_pose_top = rospy.get_param(param)
        self.avg_pub = rospy.Publisher(avg_pose_top,
                                       PoseWithCovarianceStamped,
                                       queue_size=10)
        # Initialize sim_mbes pointcloud publisher
        param = rospy.search_param("particle_sim_mbes_topic")
        mbes_pc_top = rospy.get_param(param)
        self.pcloud_pub = rospy.Publisher(mbes_pc_top,
                                          PointCloud2,
                                          queue_size=10)

        # Establish subscription to mbes pings message
        param = rospy.search_param("mbes_pings_topic")
        mbes_pings_top = rospy.get_param(param)
        rospy.Subscriber(mbes_pings_top, PointCloud2, self._mbes_callback)
        # Establish subscription to odometry message (intentionally last)
        param = rospy.search_param("odometry_topic")
        odom_top = rospy.get_param(param)
        rospy.Subscriber(odom_top, Odometry, self.odom_callback)
        rospy.sleep(0.5)
Пример #7
0
    def __init__(self):
        # Read necessary parameters
        self.pc = rospy.get_param('~particle_count', 10)  # Particle Count
        self.map_frame = rospy.get_param('~map_frame', 'map')  # map frame_id
        self.mbes_frame = rospy.get_param('~mbes_link',
                                          'mbes_link')  # mbes frame_id
        odom_frame = rospy.get_param('~odom_frame', 'odom')
        meas_model_as = rospy.get_param('~mbes_as',
                                        '/mbes_sim_server')  # map frame_id
        self.beams_num = rospy.get_param("~num_beams_sim", 20)
        self.beams_real = rospy.get_param("~n_beams_mbes", 512)
        self.mbes_angle = rospy.get_param("~mbes_open_angle",
                                          np.pi / 180. * 60.)

        # Initialize tf listener
        tfBuffer = tf2_ros.Buffer()
        tf2_ros.TransformListener(tfBuffer)
        try:
            rospy.loginfo("Waiting for transforms")
            mbes_tf = tfBuffer.lookup_transform('hugin/base_link',
                                                'hugin/mbes_link',
                                                rospy.Time(0),
                                                rospy.Duration(20))
            self.base2mbes_mat = matrix_from_tf(mbes_tf)

            m2o_tf = tfBuffer.lookup_transform(self.map_frame, odom_frame,
                                               rospy.Time(0),
                                               rospy.Duration(20))
            self.m2o_mat = matrix_from_tf(m2o_tf)

            rospy.loginfo("Transforms locked - pf node")
        except:
            rospy.loginfo(
                "ERROR: Could not lookup transform from base_link to mbes_link"
            )

        # Read covariance values
        meas_cov = float(rospy.get_param('~measurement_covariance', 0.01))
        cov_string = rospy.get_param('~motion_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        motion_cov = list(map(float, cov_list))

        cov_string = rospy.get_param('~init_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        init_cov = list(map(float, cov_list))

        cov_string = rospy.get_param('~resampling_noise_covariance')
        cov_string = cov_string.replace('[', '')
        cov_string = cov_string.replace(']', '')
        cov_list = list(cov_string.split(", "))
        self.res_noise_cov = list(map(float, cov_list))

        # Initialize list of particles
        self.particles = np.empty(self.pc, dtype=object)

        for i in range(self.pc):
            self.particles[i] = Particle(self.beams_num,
                                         self.pc,
                                         i,
                                         self.base2mbes_mat,
                                         self.m2o_mat,
                                         init_cov=init_cov,
                                         meas_cov=meas_cov,
                                         process_cov=motion_cov)

        self.time = None
        self.old_time = None
        self.pred_odom = None
        self.latest_mbes = PointCloud2()
        self.prev_mbes = PointCloud2()
        self.poses = PoseArray()
        self.poses.header.frame_id = odom_frame
        self.avg_pose = PoseWithCovarianceStamped()
        self.avg_pose.header.frame_id = odom_frame

        # Initialize particle poses publisher
        pose_array_top = rospy.get_param("~particle_poses_topic",
                                         '/particle_poses')
        self.pf_pub = rospy.Publisher(pose_array_top, PoseArray, queue_size=10)

        # Initialize average of poses publisher
        avg_pose_top = rospy.get_param("~average_pose_topic", '/average_pose')
        self.avg_pub = rospy.Publisher(avg_pose_top,
                                       PoseWithCovarianceStamped,
                                       queue_size=10)

        # Establish subscription to odometry message (intentionally last)
        odom_top = rospy.get_param("~odometry_topic", 'odom')
        rospy.Subscriber(odom_top, Odometry, self.odom_callback)

        # Expected meas of PF outcome at every time step
        pf_mbes_top = rospy.get_param("~average_mbes_topic", '/avg_mbes')
        self.pf_mbes_pub = rospy.Publisher(pf_mbes_top,
                                           PointCloud2,
                                           queue_size=1)

        self.stats = rospy.Publisher('/pf/n_eff', Float32, queue_size=10)
        rospy.loginfo("Particle filter class successfully created")

        mbes_pc_top = rospy.get_param("~particle_sim_mbes_topic", '/sim_mbes')
        self.pcloud_pub = rospy.Publisher(mbes_pc_top,
                                          PointCloud2,
                                          queue_size=10)

        # Load mesh
        print("Loading data")
        svp_path = rospy.get_param('~sound_velocity_prof')
        mesh_path = rospy.get_param('~mesh_path')
        sound_speeds = csv_data.csv_asvp_sound_speed.parse_file(svp_path)
        data = np.load(mesh_path)
        V, F, bounds = data['V'], data['F'], data['bounds']
        print("Mesh loaded")

        # Create draper
        self.draper = base_draper.BaseDraper(V, F, bounds, sound_speeds)
        self.draper.set_ray_tracing_enabled(False)
        print("draper created")

        # Action server for MBES pings sim (necessary to be able to use UFO maps as well)
        self.as_ping = actionlib.SimpleActionServer('/mbes_sim_server',
                                                    MbesSimAction,
                                                    execute_cb=self.mbes_as_cb)

        # Subscription to real mbes pings
        mbes_pings_top = rospy.get_param("~mbes_pings_topic", 'mbes_pings')
        rospy.Subscriber(mbes_pings_top, PointCloud2, self.mbes_real_cb)

        # Create expected MBES beams directions
        angle_step = self.mbes_angle / self.beams_num
        self.beams_dir = []
        for i in range(0, self.beams_num):
            roll_step = rotation_matrix(-self.mbes_angle / 2. + angle_step * i,
                                        (1, 0, 0))[0:3, 0:3]
            rot = roll_step[:, 2]
            self.beams_dir.append(rot / np.linalg.norm(rot))

        self.update_rviz()
        rospy.spin()