-
Notifications
You must be signed in to change notification settings - Fork 127
Add Pass Feature Collection class #3599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 15 commits
4aec288
b56ac67
d608e1e
2b49ed5
71aa658
2f04b8c
d8a1260
cc09931
a8b9e87
a628e95
7abcebd
f0eab71
97a4cb2
c02533c
0977e58
18e48e2
5b13624
13c9f39
6bfab39
d4746f8
eb93fc3
4ecfeba
8a2bab6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -144,6 +144,26 @@ double calculateInterceptRisk(const Team& enemy_team, const Pass& pass, | |
| return *std::max_element(enemy_intercept_risks.begin(), enemy_intercept_risks.end()); | ||
| } | ||
|
|
||
| double getEnemyTimeToInterceptPoint(const Robot& enemy_robot, const Pass& pass, | ||
| const Point& interception_point) | ||
| { | ||
| Vector enemy_interception_vector = interception_point - enemy_robot.position(); | ||
| // Take into account the enemy robot's radius for minimum min_interception_distance | ||
| // required to travel to intercept the pass. | ||
| double min_interception_distance = | ||
| std::max(0.0, enemy_interception_vector.length() - ROBOT_MAX_RADIUS_METERS); | ||
|
|
||
| const double ENEMY_ROBOT_INTERCEPTION_SPEED_METERS_PER_SECOND = 0.5; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How was this speed determined & if the intention was that this value should be tuned, we should add a TODO here to track. Otherwise, we should move this constant elsewhere.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it was used in the old cost function code, i can move it to a constants file |
||
| double signed_1d_enemy_vel = | ||
| enemy_robot.velocity().dot(enemy_interception_vector.normalize()); | ||
|
|
||
| return getTimeToTravelDistance( | ||
| min_interception_distance, ENEMY_ROBOT_MAX_SPEED_METERS_PER_SECOND, | ||
| ENEMY_ROBOT_MAX_ACCELERATION_METERS_PER_SECOND_SQUARED, | ||
| signed_1d_enemy_vel, ENEMY_ROBOT_INTERCEPTION_SPEED_METERS_PER_SECOND) | ||
| .toSeconds(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Caller should perform conversion. As a wrapper around |
||
| } | ||
|
|
||
| double calculateInterceptRisk(const Robot& enemy_robot, const Pass& pass, | ||
| const TbotsProto::PassingConfig& passing_config) | ||
| { | ||
|
|
@@ -157,22 +177,10 @@ double calculateInterceptRisk(const Robot& enemy_robot, const Pass& pass, | |
| // point on the pass before the ball | ||
| Point closest_interception_point = closestPoint( | ||
| enemy_robot.position(), Segment(pass.passerPoint(), pass.receiverPoint())); | ||
| Vector enemy_interception_vector = | ||
| closest_interception_point - enemy_robot.position(); | ||
| // Take into account the enemy robot's radius for minimum min_interception_distance | ||
| // required to travel to intercept the pass. | ||
| double min_interception_distance = | ||
| std::max(0.0, enemy_interception_vector.length() - ROBOT_MAX_RADIUS_METERS); | ||
|
|
||
| const double ENEMY_ROBOT_INTERCEPTION_SPEED_METERS_PER_SECOND = 0.5; | ||
| double signed_1d_enemy_vel = | ||
| enemy_robot.velocity().dot(enemy_interception_vector.normalize()); | ||
| double enemy_robot_time_to_interception_point_sec = | ||
| getTimeToTravelDistance( | ||
| min_interception_distance, ENEMY_ROBOT_MAX_SPEED_METERS_PER_SECOND, | ||
| ENEMY_ROBOT_MAX_ACCELERATION_METERS_PER_SECOND_SQUARED, signed_1d_enemy_vel, | ||
| ENEMY_ROBOT_INTERCEPTION_SPEED_METERS_PER_SECOND) | ||
| .toSeconds(); | ||
| getEnemyTimeToInterceptPoint(enemy_robot, pass, closest_interception_point); | ||
|
|
||
| // Scale the time to interception point by the enemy robot's interception capability | ||
| Duration enemy_robot_time_to_interception_point = | ||
| Duration::fromSeconds(enemy_robot_time_to_interception_point_sec * | ||
|
|
@@ -195,6 +203,53 @@ double calculateInterceptRisk(const Robot& enemy_robot, const Pass& pass, | |
| 0.0, 1.0); | ||
| } | ||
|
|
||
| const Robot* getClosestReceiverToPass(const Team& friendly_team, const Pass& pass) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any reason we are using raw pointers here? e.g.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
| { | ||
| if (friendly_team.getAllRobots().empty()) | ||
| return nullptr; | ||
|
|
||
| const Robot* best_receiver = nullptr; | ||
| double curr_best_distance = std::numeric_limits<double>::max(); | ||
|
|
||
| for (const Robot& robot : friendly_team.getAllRobots()) | ||
| { | ||
| double distance = (robot.position() - pass.receiverPoint()).length(); | ||
| if (distance < curr_best_distance) | ||
| { | ||
| best_receiver = &robot; | ||
| curr_best_distance = distance; | ||
| } | ||
| } | ||
|
|
||
| return best_receiver; | ||
| } | ||
|
|
||
| Duration getBallTravelTime(const Pass& pass, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ideally we should return pointers for these helpers. Since this file seems to contains a lot of stray functions, we should wrap these in namespaces while we are working on this.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wdym by pointers? we seem to have functions that return a |
||
| const TbotsProto::PassingConfig& passing_config) | ||
| { | ||
| return Duration::fromSeconds((pass.receiverPoint() - pass.passerPoint()).length() / | ||
| pass.speed()) + | ||
| Duration::fromSeconds(passing_config.pass_delay_sec()); | ||
| } | ||
|
|
||
| Timestamp getEarliestReceiveTime(const Robot* best_receiver, const Pass& pass, | ||
| const TbotsProto::PassingConfig& passing_config) | ||
| { | ||
| Duration min_robot_travel_time = | ||
| best_receiver->getTimeToPosition(pass.receiverPoint()); | ||
| Timestamp earliest_time_to_receive_point = | ||
| best_receiver->timestamp() + min_robot_travel_time; | ||
|
|
||
| return earliest_time_to_receive_point; | ||
| } | ||
|
|
||
| Timestamp getEarliestTimeToAngle(const Robot* best_receiver, const Pass& pass) | ||
| { | ||
| Angle receive_angle = (pass.passerPoint() - best_receiver->position()).orientation(); | ||
| Duration time_to_receive_angle = best_receiver->getTimeToOrientation(receive_angle); | ||
| return best_receiver->timestamp() + time_to_receive_angle; | ||
| } | ||
|
|
||
| double ratePassFriendlyCapability(const Team& friendly_team, const Pass& pass, | ||
| const TbotsProto::PassingConfig& passing_config) | ||
| { | ||
|
|
@@ -211,37 +266,20 @@ double ratePassFriendlyCapability(const Team& friendly_team, const Pass& pass, | |
| } | ||
|
|
||
| // Get the robot that is closest to where the pass would be received | ||
| Robot best_receiver = friendly_team.getAllRobots()[0]; | ||
| for (const Robot& robot : friendly_team.getAllRobots()) | ||
| { | ||
| double distance = (robot.position() - pass.receiverPoint()).length(); | ||
| double curr_best_distance = | ||
| (best_receiver.position() - pass.receiverPoint()).length(); | ||
| if (distance < curr_best_distance) | ||
| { | ||
| best_receiver = robot; | ||
| } | ||
| } | ||
| const Robot* best_receiver = getClosestReceiverToPass(friendly_team, pass); | ||
|
|
||
| Duration ball_travel_time = getBallTravelTime(pass, passing_config); | ||
| Timestamp receive_time = best_receiver->timestamp() + ball_travel_time; | ||
|
|
||
| // Figure out what time the robot would have to receive the ball at | ||
| // and how long it would take our robot to get there | ||
| // TODO (#2988): We should generate a more realistic ball trajectory | ||
| Duration ball_travel_time = | ||
| Duration::fromSeconds((pass.receiverPoint() - pass.passerPoint()).length() / | ||
| pass.speed()) + | ||
| Duration::fromSeconds(passing_config.pass_delay_sec()); | ||
| Timestamp receive_time = best_receiver.timestamp() + ball_travel_time; | ||
|
|
||
| // Figure out how long it would take our robot to get there | ||
| Duration min_robot_travel_time = | ||
| best_receiver.getTimeToPosition(pass.receiverPoint()); | ||
| Timestamp earliest_time_to_receive_point = | ||
| best_receiver.timestamp() + min_robot_travel_time; | ||
| const Timestamp earliest_time_to_receive_point = | ||
| getEarliestReceiveTime(best_receiver, pass, passing_config); | ||
|
|
||
| // Figure out what angle the robot would have to be at to receive the ball | ||
| Angle receive_angle = (pass.passerPoint() - best_receiver.position()).orientation(); | ||
| Duration time_to_receive_angle = best_receiver.getTimeToOrientation(receive_angle); | ||
| Timestamp earliest_time_to_receive_angle = | ||
| best_receiver.timestamp() + time_to_receive_angle; | ||
| const Timestamp earliest_time_to_receive_angle = | ||
| getEarliestTimeToAngle(best_receiver, pass); | ||
|
|
||
| // Figure out if rotation or moving will take us longer | ||
| Timestamp latest_time_to_receiver_state = | ||
|
|
@@ -259,30 +297,36 @@ double ratePassFriendlyCapability(const Team& friendly_team, const Pass& pass, | |
| sigmoid_width); | ||
| } | ||
|
|
||
| double getStaticPositionQuality(const Field& field, const Point& position, | ||
| const TbotsProto::PassingConfig& passing_config) | ||
| Rectangle getReducedField(const Field& field, TbotsProto::PassingConfig passing_config) | ||
| { | ||
| // This constant is used to determine how steep the sigmoid slopes below are | ||
| static const double sig_width = 0.1; | ||
|
|
||
| // The offset from the sides of the field for the center of the sigmoid functions | ||
| double x_offset = passing_config.static_field_position_quality_x_offset(); | ||
| double y_offset = passing_config.static_field_position_quality_y_offset(); | ||
| double friendly_goal_weight = | ||
| passing_config.static_field_position_quality_friendly_goal_distance_weight(); | ||
|
|
||
| // Make a slightly smaller field, and positive weight values in this reduced field | ||
| double half_field_length = field.xLength() / 2; | ||
| double half_field_width = field.yLength() / 2; | ||
| Rectangle reduced_size_field( | ||
| Point(-half_field_length + x_offset, -half_field_width + y_offset), | ||
| Point(half_field_length - x_offset, half_field_width - y_offset)); | ||
| return reduced_size_field; | ||
| } | ||
|
|
||
| double getStaticPositionQuality(const Field& field, const Point& position, | ||
| const TbotsProto::PassingConfig& passing_config) | ||
| { | ||
| // This constant is used to determine how steep the sigmoid slopes below are | ||
| static const double sig_width = 0.1; | ||
|
|
||
| // Make a slightly smaller field, and positive weight values in this reduced field | ||
| const auto reduced_size_field = getReducedField(field, passing_config); | ||
| double on_field_quality = rectangleSigmoid(reduced_size_field, position, sig_width); | ||
|
|
||
| // Add a negative weight for positions closer to our goal | ||
| Vector vec_to_friendly_goal = Vector(field.friendlyGoalCenter().x() - position.x(), | ||
| field.friendlyGoalCenter().y() - position.y()); | ||
| double distance_to_friendly_goal = vec_to_friendly_goal.length(); | ||
| double friendly_goal_weight = | ||
| passing_config.static_field_position_quality_friendly_goal_distance_weight(); | ||
| double near_friendly_goal_quality = | ||
| (1 - | ||
| std::exp(-friendly_goal_weight * (std::pow(5, -2 + distance_to_friendly_goal)))); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -117,6 +117,19 @@ double ratePassNotTooClose(const Pass& pass, | |
| double calculateInterceptRisk(const Team& enemy_team, const Pass& pass, | ||
| const TbotsProto::PassingConfig& passing_config); | ||
|
|
||
| /** | ||
| * Calculates the time taken by an enemy to get to a specific intercept point | ||
| * | ||
| * @param enemy_robot The robot that might intercept our pass | ||
| * @param pass The pass we want to get the intercept probability for | ||
| * @param interception_point The point on the pass's path that the enemy is trying to | ||
| * intercept the ball at | ||
| * @return A value in seconds, which is the time taken by the enemy to get to the | ||
| * interception point | ||
| */ | ||
| double getEnemyTimeToInterceptPoint(const Robot& enemy_robot, const Pass& pass, | ||
| const Point& interception_point); | ||
|
|
||
| /** | ||
| * Calculates the likelihood that the given pass will be intercepted by a given robot | ||
| * | ||
|
|
@@ -131,6 +144,15 @@ double calculateInterceptRisk(const Team& enemy_team, const Pass& pass, | |
| double calculateInterceptRisk(const Robot& enemy_robot, const Pass& pass, | ||
| const TbotsProto::PassingConfig& passing_config); | ||
|
|
||
| Duration getBallTravelTime(const Pass& pass, | ||
| const TbotsProto::PassingConfig& passing_config); | ||
|
|
||
| const Robot* getClosestReceiverToPass(const Team& friendly_team, const Pass& pass); | ||
|
|
||
| Timestamp getEarliestReceiveTime(const Robot* best_receiver, const Pass& pass, | ||
| const TbotsProto::PassingConfig& passing_config); | ||
|
|
||
| Timestamp getEarliestTimeToAngle(const Robot* best_receiver, const Pass& pass); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comments |
||
|
|
||
| /** | ||
| * Calculate the probability of a friendly robot receiving the given pass | ||
|
|
@@ -149,6 +171,8 @@ double calculateInterceptRisk(const Robot& enemy_robot, const Pass& pass, | |
| double ratePassFriendlyCapability(const Team& friendly_team, const Pass& pass, | ||
| const TbotsProto::PassingConfig& passing_config); | ||
|
|
||
| Rectangle getReducedField(const Field& field, TbotsProto::PassingConfig passing_config); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comments |
||
|
|
||
| /** | ||
| * Calculates the static position quality for a given position on a given field | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
passunusedThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this function is a bit too specific, does it have to be only for the "enemy robot"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the constants used (such as
ENEMY_ROBOT_MAX_SPEED_METERS_PER_SECOND) seem enemy specific. i'm not against changing them but maybe not as part of this PR