Skip to content

Commit a5719b4

Browse files
authored
Account for measurement delay in localization (#650)
2 parents c88ae76 + ab6daa4 commit a5719b4

File tree

12 files changed

+138
-198
lines changed

12 files changed

+138
-198
lines changed

bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/ball_kick_area.py

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ def perform(self, reevaluate=False):
2525
ball_position = self.blackboard.world_model.get_ball_position_uv()
2626

2727
self.publish_debug_data("ball_position", {"u": ball_position[0], "v": ball_position[1]})
28+
self.publish_debug_data(
29+
"smoothing_close", f"{self.no_near_decisions} ({self.no_near_decisions / self.smoothing * 10}%)"
30+
)
2831

2932
# Check if the ball is in the enter area
3033
if 0 <= ball_position[0] <= self.kick_x_enter and 0 <= abs(ball_position[1]) <= self.kick_y_enter:

bitbots_behavior/bitbots_body_behavior/config/body_behavior.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ body_behavior:
146146
dribble_ball_distance_threshold: 0.5
147147
dribble_kick_angle: 0.6
148148

149-
kick_decision_smoothing: 5.0
149+
kick_decision_smoothing: 1.0
150150

151151
##################
152152
# costmap params #

bitbots_navigation/bitbots_localization/config/config.yaml

-8
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,11 @@ bitbots_localization:
33
misc:
44
init_mode: 0
55
percentage_best_particles: 100
6-
min_motion_linear: 0.0
7-
min_motion_angular: 0.0
86
max_motion_linear: 0.5
97
max_motion_angular: 3.14
10-
filter_only_with_motion: false
118
ros:
129
line_pointcloud_topic: 'line_mask_relative_pc'
1310
goal_topic: 'goals_simulated'
14-
fieldboundary_topic: 'field_boundary_relative'
1511
particle_publishing_topic: 'pose_particles'
1612
debug_visualization: true
1713
particle_filter:
@@ -46,10 +42,6 @@ bitbots_localization:
4642
goal:
4743
factor: 0.0
4844
out_of_field_score: 0.0
49-
field_boundary:
50-
factor: 0.0
51-
out_of_field_score: 0.0
5245
confidences:
5346
line_element: 0.01
5447
goal_element: 0.0
55-
field_boundary_element: 0.0

bitbots_navigation/bitbots_localization/include/bitbots_localization/ObservationModel.hpp

+13-16
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,15 @@
66
#define BITBOTS_LOCALIZATION_OBSERVATIONMODEL_H
77

88
#include <particle_filter/ParticleFilter.h>
9+
#include <tf2_ros/buffer.h>
910

1011
#include <bitbots_localization/RobotState.hpp>
1112
#include <bitbots_localization/map.hpp>
1213
#include <bitbots_localization/tools.hpp>
1314
#include <sensor_msgs/msg/point_cloud2.hpp>
1415
#include <sensor_msgs/point_cloud2_iterator.hpp>
15-
#include <soccer_vision_3d_msgs/msg/field_boundary.hpp>
1616
#include <soccer_vision_3d_msgs/msg/goalpost.hpp>
1717
#include <soccer_vision_3d_msgs/msg/goalpost_array.hpp>
18-
#include <soccer_vision_3d_msgs/msg/marking_array.hpp>
19-
#include <soccer_vision_3d_msgs/msg/marking_intersection.hpp>
2018

2119
#include "localization_parameters.hpp"
2220

@@ -31,8 +29,7 @@ class RobotPoseObservationModel : public particle_filter::ObservationModel<Robot
3129
* empty
3230
*/
3331
RobotPoseObservationModel(std::shared_ptr<Map> map_lines, std::shared_ptr<Map> map_goals,
34-
std::shared_ptr<Map> map_field_boundary, const bitbots_localization::Params &config,
35-
const FieldDimensions &field_dimensions);
32+
const bitbots_localization::Params &config, const FieldDimensions &field_dimensions);
3633

3734
/**
3835
*
@@ -45,36 +42,36 @@ class RobotPoseObservationModel : public particle_filter::ObservationModel<Robot
4542

4643
void set_measurement_goalposts(sv3dm::msg::GoalpostArray measurement);
4744

48-
void set_measurement_field_boundary(sv3dm::msg::FieldBoundary measurement);
45+
const std::vector<std::pair<double, double>> get_measurement_lines() const;
4946

50-
void set_measurement_markings(sv3dm::msg::MarkingArray measurement);
51-
52-
std::vector<std::pair<double, double>> get_measurement_lines() const;
53-
54-
std::vector<std::pair<double, double>> get_measurement_goals() const;
55-
56-
std::vector<std::pair<double, double>> get_measurement_field_boundary() const;
47+
const std::vector<std::pair<double, double>> get_measurement_goals() const;
5748

5849
double get_min_weight() const override;
5950

6051
void clear_measurement();
6152

6253
bool measurements_available() override;
6354

55+
void set_movement_since_line_measurement(const tf2::Transform movement);
56+
void set_movement_since_goal_measurement(const tf2::Transform movement);
57+
6458
private:
6559
double calculate_weight_for_class(const RobotState &state,
6660
const std::vector<std::pair<double, double>> &last_measurement,
67-
std::shared_ptr<Map> map, double element_weight) const;
61+
std::shared_ptr<Map> map, double element_weight,
62+
const tf2::Transform &movement_since_measurement) const;
6863

6964
// Measurements
7065
std::vector<std::pair<double, double>> last_measurement_lines_;
7166
std::vector<std::pair<double, double>> last_measurement_goal_;
72-
std::vector<std::pair<double, double>> last_measurement_field_boundary_;
67+
68+
// Movement since last measurement
69+
tf2::Transform movement_since_line_measurement_ = tf2::Transform::getIdentity();
70+
tf2::Transform movement_since_goal_measurement_ = tf2::Transform::getIdentity();
7371

7472
// Reference to the maps for the different classes
7573
std::shared_ptr<Map> map_lines_;
7674
std::shared_ptr<Map> map_goals_;
77-
std::shared_ptr<Map> map_field_boundary_;
7875

7976
// Parameters
8077
bitbots_localization::Params config_;

bitbots_navigation/bitbots_localization/include/bitbots_localization/RobotState.hpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#include <particle_filter/ParticleFilter.h>
99
#include <tf2/LinearMath/Quaternion.h>
10+
#include <tf2/LinearMath/Transform.h>
11+
#include <tf2/utils.h>
1012

1113
#include <Eigen/Core>
1214
#include <bitbots_localization/tools.hpp>
@@ -25,10 +27,17 @@ class RobotState {
2527
/**
2628
* @param x Position of the robot.
2729
* @param y Position of the robot.
28-
* @param T Orientaion of the robot in radians.
30+
* @param T Orientation of the robot in radians.
2931
*/
3032
RobotState(double x, double y, double T);
3133

34+
/**
35+
* @brief Constructor for a robot state based on a tf2::Transform.
36+
*
37+
* @param transform Transform of the robots base_footprint in the map frame.
38+
*/
39+
explicit RobotState(tf2::Transform transform);
40+
3241
RobotState operator*(float factor) const;
3342

3443
RobotState &operator+=(const RobotState &other);
@@ -63,6 +72,8 @@ class RobotState {
6372
visualization_msgs::msg::Marker renderMarker(std::string n_space, std::string frame, rclcpp::Duration lifetime,
6473
std_msgs::msg::ColorRGBA color, rclcpp::Time stamp) const;
6574

75+
tf2::Transform getTransform() const;
76+
6677
private:
6778
double m_XPos;
6879
double m_YPos;

bitbots_navigation/bitbots_localization/include/bitbots_localization/localization.hpp

+4-20
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
#include <rclcpp/rclcpp.hpp>
4848
#include <sensor_msgs/msg/camera_info.hpp>
4949
#include <sensor_msgs/msg/point_cloud2.hpp>
50-
#include <soccer_vision_3d_msgs/msg/field_boundary.hpp>
5150
#include <soccer_vision_3d_msgs/msg/goalpost_array.hpp>
5251
#include <std_msgs/msg/color_rgba.hpp>
5352
#include <std_srvs/srv/trigger.hpp>
@@ -110,12 +109,6 @@ class Localization {
110109
*/
111110
void GoalPostsCallback(const sv3dm::msg::GoalpostArray &msg); // TODO
112111

113-
/**
114-
* Callback for the relative field boundary measurements
115-
* @param msg Message containing the field boundary points.
116-
*/
117-
void FieldboundaryCallback(const sv3dm::msg::FieldBoundary &msg);
118-
119112
/**
120113
* Resets the state distribution of the state space
121114
* @param distribution The type of the distribution
@@ -158,17 +151,13 @@ class Localization {
158151
// Declare subscribers
159152
rclcpp::Subscription<sm::msg::PointCloud2>::SharedPtr line_point_cloud_subscriber_;
160153
rclcpp::Subscription<sv3dm::msg::GoalpostArray>::SharedPtr goal_subscriber_;
161-
rclcpp::Subscription<sv3dm::msg::FieldBoundary>::SharedPtr fieldboundary_subscriber_;
162-
163154
rclcpp::Subscription<gm::msg::PoseWithCovarianceStamped>::SharedPtr rviz_initial_pose_subscriber_;
164155

165156
// Declare publishers
166157
rclcpp::Publisher<gm::msg::PoseWithCovarianceStamped>::SharedPtr pose_with_covariance_publisher_;
167158
rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr pose_particles_publisher_;
168-
rclcpp::Publisher<visualization_msgs::msg::Marker>::SharedPtr lines_publisher_;
169159
rclcpp::Publisher<visualization_msgs::msg::Marker>::SharedPtr line_ratings_publisher_;
170160
rclcpp::Publisher<visualization_msgs::msg::Marker>::SharedPtr goal_ratings_publisher_;
171-
rclcpp::Publisher<visualization_msgs::msg::Marker>::SharedPtr fieldboundary_ratings_publisher_;
172161
rclcpp::Publisher<nav_msgs::msg::OccupancyGrid>::SharedPtr field_publisher_;
173162

174163
// Declare services
@@ -179,8 +168,8 @@ class Localization {
179168
rclcpp::TimerBase::SharedPtr publishing_timer_;
180169

181170
// Declare tf2 objects
182-
std::unique_ptr<tf2_ros::Buffer> tfBuffer;
183-
std::shared_ptr<tf2_ros::TransformListener> tfListener;
171+
std::shared_ptr<tf2_ros::Buffer> tf_buffer_;
172+
std::shared_ptr<tf2_ros::TransformListener> tf_listener_;
184173
std::shared_ptr<tf2_ros::TransformBroadcaster> br;
185174

186175
// Declare particle filter components
@@ -201,7 +190,6 @@ class Localization {
201190
// Declare input message buffers
202191
sm::msg::PointCloud2 line_pointcloud_relative_;
203192
sv3dm::msg::GoalpostArray goal_posts_relative_;
204-
sv3dm::msg::FieldBoundary fieldboundary_relative_;
205193

206194
// Declare time stamps
207195
rclcpp::Time last_stamp_lines = rclcpp::Time(0);
@@ -219,16 +207,12 @@ class Localization {
219207
// Keep track of the odometry transform in the last step
220208
geometry_msgs::msg::TransformStamped previousOdomTransform_;
221209

222-
// Flag that checks if the robot is moving
223-
bool robot_moved = false;
224-
225210
// Keep track of the number of filter steps
226211
int timer_callback_count_ = 0;
227212

228213
// Maps for the different measurement classes
229214
std::shared_ptr<Map> lines_;
230215
std::shared_ptr<Map> goals_;
231-
std::shared_ptr<Map> field_boundary_;
232216

233217
// RNG that is used for the different sampling steps
234218
particle_filter::CRandomNumberGenerator random_number_generator_;
@@ -271,8 +255,8 @@ class Localization {
271255
* @param map map for this class
272256
* @param publisher ros publisher for the type visualization_msgs::msg::Marker
273257
*/
274-
void publish_debug_rating(std::vector<std::pair<double, double>> measurements, double scale, const char name[24],
275-
std::shared_ptr<Map> map,
258+
void publish_debug_rating(const std::vector<std::pair<double, double>> &measurements, double scale,
259+
const char name[24], std::shared_ptr<Map> map,
276260
rclcpp::Publisher<visualization_msgs::msg::Marker>::SharedPtr &publisher);
277261

278262
/**

bitbots_navigation/bitbots_localization/include/bitbots_localization/map.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ class Map {
4545

4646
double get_occupancy(double x, double y);
4747

48-
std::pair<double, double> observationRelative(std::pair<double, double> observation, double stateX, double stateY,
49-
double stateT);
48+
std::pair<double, double> getObservationCoordinatesInMapFrame(std::pair<double, double> observation, double stateX,
49+
double stateY, double stateT);
5050

5151
nav_msgs::msg::OccupancyGrid get_map_msg(std::string frame_id, int threshold = -1);
5252

bitbots_navigation/bitbots_localization/src/ObservationModel.cpp

+23-30
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,25 @@
77
namespace bitbots_localization {
88

99
RobotPoseObservationModel::RobotPoseObservationModel(std::shared_ptr<Map> map_lines, std::shared_ptr<Map> map_goals,
10-
std::shared_ptr<Map> map_field_boundary,
1110
const bitbots_localization::Params &config,
1211
const FieldDimensions &field_dimensions)
1312
: particle_filter::ObservationModel<RobotState>(),
1413
map_lines_(map_lines),
1514
map_goals_(map_goals),
16-
map_field_boundary_(map_field_boundary),
1715
config_(config),
1816
field_dimensions_(field_dimensions) {
1917
particle_filter::ObservationModel<RobotState>::accumulate_weights_ = true;
2018
}
2119

2220
double RobotPoseObservationModel::calculate_weight_for_class(
2321
const RobotState &state, const std::vector<std::pair<double, double>> &last_measurement, std::shared_ptr<Map> map,
24-
double element_weight) const {
22+
double element_weight, const tf2::Transform &movement_since_measurement) const {
2523
double particle_weight_for_class;
2624
if (!last_measurement.empty()) {
27-
std::vector<double> ratings = map->Map::provideRating(state, last_measurement);
25+
// Subtract (reverse) the movement from our state to get the hypothetical state at the time of the measurement
26+
const RobotState state_at_measurement(state.getTransform() * movement_since_measurement.inverse());
27+
// Get the ratings for for all points in the measurement based on the map
28+
const std::vector<double> ratings = map->Map::provideRating(state_at_measurement, last_measurement);
2829
// Take the average of the ratings (functional)
2930
particle_weight_for_class = std::pow(std::accumulate(ratings.begin(), ratings.end(), 0.0) / ratings.size(), 2);
3031
} else {
@@ -34,22 +35,19 @@ double RobotPoseObservationModel::calculate_weight_for_class(
3435
}
3536

3637
double RobotPoseObservationModel::measure(const RobotState &state) const {
37-
double particle_weight_lines = calculate_weight_for_class(state, last_measurement_lines_, map_lines_,
38-
config_.particle_filter.confidences.line_element);
39-
double particle_weight_goal = calculate_weight_for_class(state, last_measurement_goal_, map_goals_,
40-
config_.particle_filter.confidences.goal_element);
41-
double particle_weight_field_boundary =
42-
calculate_weight_for_class(state, last_measurement_field_boundary_, map_field_boundary_,
43-
config_.particle_filter.confidences.field_boundary_element);
38+
double particle_weight_lines =
39+
calculate_weight_for_class(state, last_measurement_lines_, map_lines_,
40+
config_.particle_filter.confidences.line_element, movement_since_line_measurement_);
41+
double particle_weight_goal =
42+
calculate_weight_for_class(state, last_measurement_goal_, map_goals_,
43+
config_.particle_filter.confidences.goal_element, movement_since_goal_measurement_);
4444

4545
// Get relevant config values
4646
auto scoring_config = config_.particle_filter.scoring;
4747

4848
// Calculate weight for the particle
4949
double weight = (((1 - scoring_config.lines.factor) + scoring_config.lines.factor * particle_weight_lines) *
50-
((1 - scoring_config.goal.factor) + scoring_config.goal.factor * particle_weight_goal) *
51-
((1 - scoring_config.field_boundary.factor) +
52-
scoring_config.field_boundary.factor * particle_weight_field_boundary));
50+
((1 - scoring_config.goal.factor) + scoring_config.goal.factor * particle_weight_goal));
5351

5452
if (weight < config_.particle_filter.weighting.min_weight) {
5553
weight = config_.particle_filter.weighting.min_weight;
@@ -68,6 +66,7 @@ double RobotPoseObservationModel::measure(const RobotState &state) const {
6866
}
6967

7068
void RobotPoseObservationModel::set_measurement_lines_pc(sm::msg::PointCloud2 measurement) {
69+
// convert to polar
7170
for (sm::PointCloud2ConstIterator<float> iter_xyz(measurement, "x"); iter_xyz != iter_xyz.end(); ++iter_xyz) {
7271
std::pair<double, double> linePolar = cartesianToPolar(iter_xyz[0], iter_xyz[1]);
7372
last_measurement_lines_.push_back(linePolar);
@@ -82,39 +81,33 @@ void RobotPoseObservationModel::set_measurement_goalposts(sv3dm::msg::GoalpostAr
8281
}
8382
}
8483

85-
void RobotPoseObservationModel::set_measurement_field_boundary(sv3dm::msg::FieldBoundary measurement) {
86-
// convert to polar
87-
for (gm::msg::Point &point : measurement.points) {
88-
std::pair<double, double> fieldBoundaryPointPolar = cartesianToPolar(point.x, point.y);
89-
last_measurement_field_boundary_.push_back(fieldBoundaryPointPolar);
90-
}
91-
}
92-
93-
std::vector<std::pair<double, double>> RobotPoseObservationModel::get_measurement_lines() const {
84+
const std::vector<std::pair<double, double>> RobotPoseObservationModel::get_measurement_lines() const {
9485
return last_measurement_lines_;
9586
}
9687

97-
std::vector<std::pair<double, double>> RobotPoseObservationModel::get_measurement_goals() const {
88+
const std::vector<std::pair<double, double>> RobotPoseObservationModel::get_measurement_goals() const {
9889
return last_measurement_goal_;
9990
}
10091

101-
std::vector<std::pair<double, double>> RobotPoseObservationModel::get_measurement_field_boundary() const {
102-
return last_measurement_field_boundary_;
103-
}
104-
10592
double RobotPoseObservationModel::get_min_weight() const { return config_.particle_filter.weighting.min_weight; }
10693

10794
void RobotPoseObservationModel::clear_measurement() {
10895
last_measurement_lines_.clear();
10996
last_measurement_goal_.clear();
110-
last_measurement_field_boundary_.clear();
11197
}
11298

11399
bool RobotPoseObservationModel::measurements_available() {
114100
bool available = false;
115101
available |= !last_measurement_lines_.empty();
116102
available |= !last_measurement_goal_.empty();
117-
available |= !last_measurement_field_boundary_.empty();
118103
return available;
119104
}
105+
106+
void RobotPoseObservationModel::set_movement_since_line_measurement(const tf2::Transform movement) {
107+
movement_since_line_measurement_ = movement;
108+
}
109+
110+
void RobotPoseObservationModel::set_movement_since_goal_measurement(const tf2::Transform movement) {
111+
movement_since_goal_measurement_ = movement;
112+
}
120113
} // namespace bitbots_localization

0 commit comments

Comments
 (0)