Skip to content
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

Adding Seeking #2160

Merged
merged 25 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5183dcc
Fixed heuristics for seeking
sanatd33 Jan 17, 2024
03d7fa9
Removed log statement
sanatd33 Jan 17, 2024
8a868b6
Added comments to offense.cpp
sanatd33 Jan 22, 2024
85ecac3
Remove testing code
sanatd33 Jan 22, 2024
1cc87d9
Fix Code Style On seeking-test (#2161)
github-actions[bot] Jan 22, 2024
545322f
Created Role Interface for Seeking
sanatd33 Jan 24, 2024
502f403
Merge branch 'ros2' into seeking-test
sanatd33 Jan 24, 2024
580b39d
Fix Code Style On seeking-test (#2167)
github-actions[bot] Jan 24, 2024
41df6ad
Fixed warning messages
sanatd33 Jan 29, 2024
c3a91f6
Fixed heuristics for seeking
sanatd33 Jan 17, 2024
412990d
Removed log statement
sanatd33 Jan 17, 2024
bd0f241
Added comments to offense.cpp
sanatd33 Jan 22, 2024
fedf92c
Remove testing code
sanatd33 Jan 22, 2024
6bf581e
Fix Code Style On seeking-test (#2161)
github-actions[bot] Jan 22, 2024
ccc56fc
Created Role Interface for Seeking
sanatd33 Jan 24, 2024
7d8bebe
Fixed on_actionResetField_triggered() method (#2157)
jvogt23 Jan 23, 2024
26c7f7b
added play state to plan request (#2151)
petergarud Jan 23, 2024
a7cc97b
Fixed merge conflict
sanatd33 Jan 29, 2024
78096f2
Merge branch 'seeking-test' of https://github.com/RoboJackets/robocup…
sanatd33 Jan 29, 2024
e3be43a
Merge branch 'ros2' into seeking-test
sanatd33 Jan 29, 2024
ae1a663
Fix Code Style On seeking-test (#2175)
github-actions[bot] Jan 29, 2024
d727969
Removed previous include
sanatd33 Jan 29, 2024
8d7e5f6
Resolved Warnings
sanatd33 Jan 29, 2024
40e3662
Fix Code Style On seeking-test (#2181)
github-actions[bot] Jan 29, 2024
007f0a1
Resolved conversion from float to double
sanatd33 Jan 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions soccer/src/soccer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ set(ROBOCUP_LIB_SRC
strategy/agent/position/offense.cpp
strategy/agent/position/defense.cpp
strategy/agent/position/waller.cpp
strategy/agent/position/seeking.cpp
strategy/agent/position/goal_kicker.cpp
strategy/agent/position/penalty_player.cpp
)
Expand Down
17 changes: 15 additions & 2 deletions soccer/src/soccer/strategy/agent/position/offense.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
return state_to_task(intent);
}

Offense::State Offense::update_state() {

Check warning on line 17 in soccer/src/soccer/strategy/agent/position/offense.cpp

View workflow job for this annotation

GitHub Actions / build-and-test

function 'update_state' has cognitive complexity of 37 (threshold 25)
State next_state = current_state_;
// handle transitions between current state
WorldState* world_state = this->last_world_state_;
Expand All @@ -30,7 +30,7 @@

if (current_state_ == IDLING) {
// send_scorer_request();
next_state = AWAITING_SEND_PASS;
next_state = SEEKING;
} else if (current_state_ == SEARCHING) {
if (scorer_) {
next_state = STEALING;
Expand Down Expand Up @@ -58,7 +58,7 @@
}
} else if (current_state_ == RECEIVING) {
// transition to idling if we are close enough to the ball
if (distance_to_ball < ball_receive_distance_) {
if (distance_to_ball < 2 * ball_receive_distance_) {
next_state = IDLING;
}
} else if (current_state_ == STEALING) {
Expand All @@ -81,6 +81,12 @@
if (distance_to_ball < ball_lost_distance_) {
Position::broadcast_direct_pass_request();
}
} else if (current_state_ == SEEKING) {
// if the ball comes close to it while it's trying to seek, it should no longer be trying to
// seek
if (distance_to_ball < ball_receive_distance_) {
// next_state = RECEIVING;
}
}

return next_state;
Expand Down Expand Up @@ -181,6 +187,13 @@
auto empty_motion_cmd = planning::MotionCommand{};
intent.motion_command = empty_motion_cmd;
return intent;
} else if (current_state_ == SEEKING) {
// Only get a new target position if we have reached our target
if (check_is_done() ||
last_world_state_->get_robot(true, robot_id_).velocity.linear().mag() <= 0.01) {
Seeking seeker{robot_id_};
return seeker.get_task(intent, last_world_state_, this->field_dimensions_);
}
}

// should be impossible to reach, but this is an EmptyMotionCommand
Expand Down
5 changes: 3 additions & 2 deletions soccer/src/soccer/strategy/agent/position/offense.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <chrono>
#include <cmath>

#include <rclcpp/rclcpp.hpp>
Expand All @@ -13,6 +14,7 @@
#include "rj_common/time.hpp"
#include "rj_geometry/geometry_conversions.hpp"
#include "rj_geometry/point.hpp"
#include "seeking.hpp"

namespace strategy {

Expand Down Expand Up @@ -50,6 +52,7 @@ class Offense : public Position {
FACING, // turning to face the ball
SCORER, // overrides everything and will attempt to steal the bal and shoot it
AWAITING_SEND_PASS, // is waiting to send a pass to someone else
SEEKING, // is trying to get open
};

State update_state();
Expand All @@ -62,8 +65,6 @@ class Offense : public Position {
bool scorer_ = false;
bool last_scorer_ = false;

communication::PassResponse receive_pass_request(communication::PassRequest pass_request);

/**
* @brief Send request to the other robots to see if this robot should be the scorer
*
Expand Down
190 changes: 190 additions & 0 deletions soccer/src/soccer/strategy/agent/position/seeking.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#include "seeking.hpp"

namespace strategy {

Seeking::Seeking(int robot_id) { robot_id_ = robot_id; }

std::optional<RobotIntent> Seeking::get_task(RobotIntent intent, const WorldState* last_world_state,
FieldDimensions field_dimensions) {
// Determine target position for seeking
rj_geometry::Point current_loc = last_world_state->get_robot(true, robot_id_).pose.position();

target_pt = get_open_point(last_world_state, current_loc, field_dimensions);

planning::PathTargetFaceOption face_option = planning::FaceBall{};
bool ignore_ball = false;
planning::LinearMotionInstant goal{target_pt, rj_geometry::Point{0.0, 0.0}};
intent.motion_command = planning::MotionCommand{"path_target", goal, face_option, ignore_ball};

return intent;
}

rj_geometry::Point Seeking::get_open_point(const WorldState* world_state,
rj_geometry::Point current_loc,
FieldDimensions field_dimensions) {
return Seeking::calculate_open_point(3.0, .2, current_loc, world_state, field_dimensions);

Check warning on line 25 in soccer/src/soccer/strategy/agent/position/seeking.cpp

View workflow job for this annotation

GitHub Actions / build-and-test

parameter 'field_dimensions' is passed by value and only copied once; consider moving it to avoid unnecessary copies
}

rj_geometry::Point Seeking::calculate_open_point(double current_prec, double min_prec,
rj_geometry::Point current_point,
const WorldState* world_state,
FieldDimensions field_dimensions) {

Check warning on line 31 in soccer/src/soccer/strategy/agent/position/seeking.cpp

View workflow job for this annotation

GitHub Actions / build-and-test

the parameter 'field_dimensions' is copied for each invocation but only used as a const reference; consider making it a const reference
while (current_prec > min_prec) {
rj_geometry::Point ball_pos = world_state->ball.position;
rj_geometry::Point min = current_point;
double min_val = eval_point(ball_pos, current_point, world_state);
double curr_val{};
// Points in a current_prec radius of the current point, at 45 degree intervals
std::vector<rj_geometry::Point> check_points{
correct_point(current_point + rj_geometry::Point{current_prec, 0}, field_dimensions),
correct_point(current_point + rj_geometry::Point{-current_prec, 0}, field_dimensions),
correct_point(current_point + rj_geometry::Point{0, current_prec}, field_dimensions),
correct_point(current_point + rj_geometry::Point{0, -current_prec}, field_dimensions),
correct_point(
current_point + rj_geometry::Point{current_prec * 0.707, current_prec * 0.707},
field_dimensions),
correct_point(
current_point + rj_geometry::Point{current_prec * 0.707, -current_prec * 0.707},
field_dimensions),
correct_point(
current_point + rj_geometry::Point{-current_prec * 0.707, current_prec * 0.707},
field_dimensions),
correct_point(
current_point + rj_geometry::Point{-current_prec * 0.707, -current_prec * 0.707},
field_dimensions)};

// Finds the best point out of the ones checked
for (auto point : check_points) {
curr_val = eval_point(ball_pos, point, world_state);
if (curr_val < min_val) {
min_val = curr_val;
min = point;
}
}
current_prec *= 0.5;
current_point = min;
}
return current_point;
}

rj_geometry::Point Seeking::correct_point(rj_geometry::Point p, FieldDimensions field_dimensions) {

Check warning on line 70 in soccer/src/soccer/strategy/agent/position/seeking.cpp

View workflow job for this annotation

GitHub Actions / build-and-test

method 'correct_point' can be made const

Check warning on line 70 in soccer/src/soccer/strategy/agent/position/seeking.cpp

View workflow job for this annotation

GitHub Actions / build-and-test

the parameter 'field_dimensions' is copied for each invocation but only used as a const reference; consider making it a const reference
double BORDER_BUFFER = .2;

Check warning on line 71 in soccer/src/soccer/strategy/agent/position/seeking.cpp

View workflow job for this annotation

GitHub Actions / build-and-test

invalid case style for variable 'BORDER_BUFFER'
double x = p.x();
double y = p.y();

// X Border
if (p.x() > field_dimensions.field_x_right_coord() - BORDER_BUFFER) {
x = field_dimensions.field_x_right_coord() - BORDER_BUFFER;
} else if (p.x() < field_dimensions.field_x_left_coord() + BORDER_BUFFER) {
x = field_dimensions.field_x_left_coord() + BORDER_BUFFER;
}

// Y Border
if (p.y() > field_dimensions.their_goal_loc().y() - BORDER_BUFFER) {
y = field_dimensions.their_goal_loc().y() - BORDER_BUFFER;
} else if (p.y() < field_dimensions.our_goal_loc().y() + BORDER_BUFFER) {
y = field_dimensions.our_goal_loc().y() + BORDER_BUFFER;
}

// Goalie Boxes
if ((y < 1.2 || y > 7.8) && fabs(x) < 1.2) {
if (y > 4.5) {
y = 8.0 - BORDER_BUFFER;
} else {
y = 1.0 + BORDER_BUFFER;
}

if (x > .5) {
x = 1.0 + BORDER_BUFFER;
} else {
x = -1.0 - BORDER_BUFFER;
}
}

// Assigns robots to horizontal thirds
if (robot_id_ == 1) {
// Assign left
if (x > field_dimensions.field_x_left_coord() + field_dimensions.width() / 2) {
x = field_dimensions.field_x_left_coord() + field_dimensions.width() / 2 -
BORDER_BUFFER;
}
} else if (robot_id_ == 2) {
// Assign right
if (x < field_dimensions.field_x_right_coord() - field_dimensions.width() / 2) {
x = field_dimensions.field_x_right_coord() - field_dimensions.width() / 2 +
BORDER_BUFFER;
}
} else {
// Assign middle
if (x < field_dimensions.field_x_left_coord() + field_dimensions.width() / 3) {
x = field_dimensions.field_x_left_coord() + field_dimensions.width() / 3 +
BORDER_BUFFER;
} else if (x > field_dimensions.field_x_right_coord() - field_dimensions.width() / 3) {
x = field_dimensions.field_x_right_coord() - field_dimensions.width() / 3 -
BORDER_BUFFER;
}
}

return rj_geometry::Point(x, y);
}

double Seeking::eval_point(rj_geometry::Point ball_pos, rj_geometry::Point current_point,

Check warning on line 131 in soccer/src/soccer/strategy/agent/position/seeking.cpp

View workflow job for this annotation

GitHub Actions / build-and-test

method 'eval_point' can be made static
const WorldState* world_state) {
// Determines 'how good' a point is
// A higher value is a worse point

// Does not go into the goalie boxes
rj_geometry::Rect goal_box{rj_geometry::Point{1, 8}, rj_geometry::Point{-1, 9}};
if (goal_box.contains_point(current_point)) {
return 10000000;
}

// Line of Sight Heuristic
double max = 0;
double curr_dp;

Check warning on line 144 in soccer/src/soccer/strategy/agent/position/seeking.cpp

View workflow job for this annotation

GitHub Actions / build-and-test

variable 'curr_dp' is not initialized
for (auto robot : world_state->their_robots) {
curr_dp = (current_point).norm().dot((robot.pose.position() - ball_pos).norm());
curr_dp *= curr_dp;
if (curr_dp > max) {
max = curr_dp;
}
}

// Whether the path from ball to the point is blocked
// Same logic in passing to check if target is open
rj_geometry::Segment pass_path{ball_pos, current_point};
double min_robot_dist = 10000;
float min_path_dist = 10000;
for (auto bot : world_state->their_robots) {
rj_geometry::Point opp_pos = bot.pose.position();
min_robot_dist = std::min(min_robot_dist, current_point.dist_to(opp_pos));
min_path_dist = std::min(min_path_dist, pass_path.dist_to(opp_pos));
}

for (auto bot : world_state->our_robots) {
rj_geometry::Point ally_pos = bot.pose.position();
min_robot_dist = std::min(min_robot_dist, current_point.dist_to(ally_pos));
min_path_dist = std::min(min_path_dist, pass_path.dist_to(ally_pos));
}

min_path_dist = 0.1 / min_path_dist;
min_robot_dist = 0.1 / min_robot_dist;

// More Line of Sight Heuristics
for (auto robot : world_state->our_robots) {
curr_dp = (current_point - ball_pos).norm().dot((robot.pose.position() - ball_pos).norm());
curr_dp *= curr_dp;
if (curr_dp > max) {
max = curr_dp;
}
}

// Additional heuristics for calculating optimal point
double ball_proximity_loss = (current_point - ball_pos).mag() * .002;
double goal_distance_loss = (9.0 - current_point.y()) * .008;

// Final evaluation
return max + ball_proximity_loss + goal_distance_loss + min_path_dist + min_robot_dist;
}

} // namespace strategy
101 changes: 101 additions & 0 deletions soccer/src/soccer/strategy/agent/position/seeking.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#pragma once

#include <cmath>

#include <rclcpp/rclcpp.hpp>
#include <rclcpp_action/rclcpp_action.hpp>
#include <spdlog/spdlog.h>

#include <rj_msgs/action/robot_move.hpp>

#include "planning/instant.hpp"
#include "position.hpp"
#include "rj_common/field_dimensions.hpp"
#include "rj_common/time.hpp"
#include "rj_constants/constants.hpp"
#include "rj_geometry/geometry_conversions.hpp"
#include "rj_geometry/point.hpp"
#include "role_interface.hpp"

namespace strategy {

/*
* The Seeking role provides the implementation for a offensive robot that
* is trying to get open, so that they can receive a pass
*/
class Seeking : public RoleInterface {

Check warning on line 26 in soccer/src/soccer/strategy/agent/position/seeking.hpp

View workflow job for this annotation

GitHub Actions / build-and-test

class 'Seeking' defines a default destructor but does not define a copy constructor, a copy assignment operator, a move constructor or a move assignment operator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call this Seeker

public:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see the GH action warning: explicitly =default the other four required ctors/operators see "rule of five" section here https://en.cppreference.com/w/cpp/language/rule_of_three or ask me for more info

Seeking(int robot_id);
~Seeking() = default;

/**
* @brief Returns a seeker behavior which aims to get open
*
* @param intent The RobotIntent to add the movement to
* @param world_state The current WorldState
* @param field_dimensions The dimensions of the field
*
* @return [RobotIntent with next target point for the robot]
*/
std::optional<RobotIntent> get_task(RobotIntent intent, const WorldState* world_state,
FieldDimensions field_dimensions) override;

private:
// The seeker's id
int robot_id_;
// The taret point to move to
rj_geometry::Point target_pt{0.0, 0.0};

Check warning on line 47 in soccer/src/soccer/strategy/agent/position/seeking.hpp

View workflow job for this annotation

GitHub Actions / build-and-test

invalid case style for private member 'target_pt'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

target_pt_


/**
* @brief Returns the point which is most 'open'
*
* @param world_state The current WorldState
* @param current_position The current position of the seeker
* @param field_dimensions The dimensions of the field
*
* @return rj_geometry::Point The target point
*/
rj_geometry::Point get_open_point(const WorldState* world_state,
rj_geometry::Point current_position,
FieldDimensions field_dimensions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FieldDimensions field_dimensions);
FieldDimensions field_dimensions) const;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
FieldDimensions field_dimensions);
const FieldDimensions& field_dimensions);


/**
* @brief Calculates which point is the best by iteratively searching around the robot
*
* @param current_prec A double that represents how far away to look from the robot
* @param min_prec A double that represents the minimum distance to look from the robot
* @param current_point The robot's current position
* @param world_state The current WorldState
* @param field_dimensions The dimensions of the field
*
* @return rj_geometry::Point The best point found
*/
rj_geometry::Point calculate_open_point(double current_prec, double min_prec,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same changes as before

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also for both of these member fns make them static if they don't use any members

rj_geometry::Point current_point,
const WorldState* world_state,
FieldDimensions field_dimensions);

/**
* @brief Corrects the point to be within the field
*
* @param point The point to correct
* @param field_dimensions The dimensions of the field
*
* @return rj_geometry::Point The corrected point
*/
rj_geometry::Point correct_point(rj_geometry::Point point, FieldDimensions field_dimensions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as last two


/**
* @brief Calculates how 'good' a target point is
*
* @param ball_pos The current position of the ball
* @param current_point The point that is being evaluated
* @param world_state The current world state
*
* @return double The evaluation of that target point
*/
double eval_point(rj_geometry::Point ball_pos, rj_geometry::Point current_point,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

const WorldState* world_state);
};

} // namespace strategy
Loading