Robot Substitution#3429
Conversation
|
|
||
| // move to middle of court and to positive y boundary and stop | ||
| auto_sub_tactic->updateControlParams( | ||
| Point(0, world_ptr->field().totalYLength() / 2), Angle::zero(), |
There was a problem hiding this comment.
we need to be able to control which boundary to go to. Ideally, via dynamic params
| TbotsProto::MaxAllowedSpeedMode::PHYSICAL_LIMIT, | ||
| TbotsProto::ObstacleAvoidanceMode::SAFE); | ||
|
|
||
| for (auto robot : injured_robots) |
There was a problem hiding this comment.
we need to limit the number of robots that will simultaneously substitute (ideally a max number set via dynamic params)
| asst)); | ||
| } | ||
|
|
||
| TEST_F(TacticAssignmentTest, test_assigning_stop_tactics_to_unassigned_non_goalie_robots) |
There was a problem hiding this comment.
can you add this test file to the BUILD
|
|
||
| virtual ~SensorFusion() = default; | ||
|
|
||
| const static int BREAK_BEAM_TOLERANCE = 2; |
There was a problem hiding this comment.
please suffix units to all constants
| TEST_F(SensorFusionTest, test_detect_front_right_motor_fault) | ||
| { | ||
| std::vector<TbotsProto::RobotStatus> robot_status_msgs; | ||
| auto robot_msg = std::make_unique<TbotsProto::RobotStatus>(); | ||
| robot_msg->set_robot_id(1); | ||
| robot_msg->add_error_code(TbotsProto::ErrorCode::NO_ERROR); | ||
| robot_msg->mutable_motor_status()->mutable_front_right()->add_motor_faults( | ||
| TbotsProto::MotorFault::DRIVER_OVERTEMPERATURE); | ||
| robot_status_msgs.push_back(*robot_msg); | ||
|
|
||
| auto robot_msg2 = std::make_unique<TbotsProto::RobotStatus>(); | ||
| robot_msg2->add_error_code(TbotsProto::ErrorCode::NO_ERROR); | ||
| robot_msg2->set_robot_id(2); | ||
| robot_status_msgs.push_back(*robot_msg2); | ||
|
|
||
| SensorProto sensor_msg; | ||
|
|
||
| auto ssl_wrapper_packet = | ||
| createSSLWrapperPacket(std::move(geom_data), initDetectionFrame()); | ||
| // set vision msg so that world is valid | ||
| *(sensor_msg.mutable_ssl_vision_msg()) = *ssl_wrapper_packet; | ||
|
|
||
| sensor_fusion.processSensorProto(sensor_msg); | ||
|
|
||
| sensor_fusion.detectInjuredRobots(robot_status_msgs); | ||
|
|
||
| std::vector<Robot> injured_robots = | ||
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 1); | ||
|
|
||
| if (injured_robots.size() == 1) | ||
| { | ||
| EXPECT_EQ(injured_robots[0].id(), 1); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(SensorFusionTest, test_detect_front_left_motor_fault) | ||
| { | ||
| std::vector<TbotsProto::RobotStatus> robot_status_msgs; | ||
| auto robot_msg = std::make_unique<TbotsProto::RobotStatus>(); | ||
| robot_msg->set_robot_id(1); | ||
| robot_msg->add_error_code(TbotsProto::ErrorCode::NO_ERROR); | ||
| robot_msg->mutable_motor_status()->mutable_front_left()->add_motor_faults( | ||
| TbotsProto::MotorFault::DRIVER_OVERTEMPERATURE_PREWARNING); | ||
| robot_status_msgs.push_back(*robot_msg); | ||
|
|
||
| auto robot_msg2 = std::make_unique<TbotsProto::RobotStatus>(); | ||
| robot_msg2->add_error_code(TbotsProto::ErrorCode::NO_ERROR); | ||
| robot_msg2->set_robot_id(2); | ||
| robot_status_msgs.push_back(*robot_msg2); | ||
|
|
||
| SensorProto sensor_msg; | ||
|
|
||
| auto ssl_wrapper_packet = | ||
| createSSLWrapperPacket(std::move(geom_data), initDetectionFrame()); | ||
| // set vision msg so that world is valid | ||
| *(sensor_msg.mutable_ssl_vision_msg()) = *ssl_wrapper_packet; | ||
|
|
||
| sensor_fusion.processSensorProto(sensor_msg); | ||
|
|
||
| sensor_fusion.detectInjuredRobots(robot_status_msgs); | ||
|
|
||
| std::vector<Robot> injured_robots = | ||
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 1); | ||
|
|
||
| if (injured_robots.size() == 1) | ||
| { | ||
| EXPECT_EQ(injured_robots[0].id(), 1); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(SensorFusionTest, test_detect_back_right_motor_fault) | ||
| { | ||
| std::vector<TbotsProto::RobotStatus> robot_status_msgs; | ||
| auto robot_msg = std::make_unique<TbotsProto::RobotStatus>(); | ||
| robot_msg->set_robot_id(1); | ||
| robot_msg->add_error_code(TbotsProto::ErrorCode::NO_ERROR); | ||
| robot_msg->mutable_motor_status()->mutable_front_right()->add_motor_faults( | ||
| TbotsProto::MotorFault::DRIVER_OVERTEMPERATURE); | ||
| robot_status_msgs.push_back(*robot_msg); | ||
|
|
||
| auto robot_msg2 = std::make_unique<TbotsProto::RobotStatus>(); | ||
| robot_msg2->add_error_code(TbotsProto::ErrorCode::NO_ERROR); | ||
| robot_msg2->set_robot_id(2); | ||
| robot_msg2->mutable_motor_status()->mutable_back_right()->add_motor_faults( | ||
| TbotsProto::MotorFault::DRIVER_OVERTEMPERATURE); | ||
| robot_status_msgs.push_back(*robot_msg2); | ||
|
|
||
| SensorProto sensor_msg; | ||
|
|
||
| auto ssl_wrapper_packet = | ||
| createSSLWrapperPacket(std::move(geom_data), initDetectionFrame()); | ||
| // set vision msg so that world is valid | ||
| *(sensor_msg.mutable_ssl_vision_msg()) = *ssl_wrapper_packet; | ||
|
|
||
| sensor_fusion.processSensorProto(sensor_msg); | ||
|
|
||
| sensor_fusion.detectInjuredRobots(robot_status_msgs); | ||
|
|
||
| std::vector<Robot> injured_robots = | ||
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 2); | ||
|
|
||
| if (injured_robots.size() == 2) | ||
| { | ||
| EXPECT_EQ(injured_robots[0].id(), 1); | ||
| EXPECT_EQ(injured_robots[1].id(), 2); | ||
| } | ||
| } | ||
|
|
||
| TEST_F(SensorFusionTest, test_detect_back_left_motor_fault) | ||
| { | ||
| std::vector<TbotsProto::RobotStatus> robot_status_msgs; | ||
| auto robot_msg = std::make_unique<TbotsProto::RobotStatus>(); | ||
| robot_msg->set_robot_id(1); | ||
| robot_msg->add_error_code(TbotsProto::ErrorCode::NO_ERROR); | ||
| robot_msg->mutable_motor_status()->mutable_front_left()->add_motor_faults( | ||
| TbotsProto::MotorFault::DRIVER_OVERTEMPERATURE_PREWARNING); | ||
| robot_status_msgs.push_back(*robot_msg); | ||
|
|
||
| auto robot_msg2 = std::make_unique<TbotsProto::RobotStatus>(); | ||
| robot_msg2->add_error_code(TbotsProto::ErrorCode::NO_ERROR); | ||
| robot_msg2->set_robot_id(2); | ||
| robot_msg2->mutable_motor_status()->mutable_back_left()->add_motor_faults( | ||
| TbotsProto::MotorFault::DRIVER_OVERTEMPERATURE_PREWARNING); | ||
| robot_status_msgs.push_back(*robot_msg2); | ||
|
|
||
| SensorProto sensor_msg; | ||
|
|
||
| auto ssl_wrapper_packet = | ||
| createSSLWrapperPacket(std::move(geom_data), initDetectionFrame()); | ||
| // set vision msg so that world is valid | ||
| *(sensor_msg.mutable_ssl_vision_msg()) = *ssl_wrapper_packet; | ||
|
|
||
| sensor_fusion.processSensorProto(sensor_msg); | ||
|
|
||
| sensor_fusion.detectInjuredRobots(robot_status_msgs); | ||
|
|
||
| std::vector<Robot> injured_robots = | ||
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 2); | ||
|
|
||
| if (injured_robots.size() == 2) | ||
| { | ||
| EXPECT_EQ(injured_robots[0].id(), 1); | ||
| EXPECT_EQ(injured_robots[1].id(), 2); | ||
| } | ||
| } |
There was a problem hiding this comment.
these tests are all very similar. consider making this into a parametrized test (TEST_P)
example:
| dribble_displacement = std::nullopt; | ||
| } | ||
|
|
||
| // This detects injured robots, but isn't called anywhere? |
There was a problem hiding this comment.
looks like you can call this function in:
|
This PR is stale because it has been open for 30 days with no activity. Remove stale label or comment or this will be closed in 5 days. |
|
This PR was closed because it has been stalled for 5 days with no activity. |
fc6997b to
f2b8a13
Compare
| if (injured_robots.size() > 0) | ||
| { | ||
| std::map<RobotId, TrajectoryPath> robot_trajectories = {}; | ||
| unsigned int num_injured = (unsigned int)injured_robots.size(); |
There was a problem hiding this comment.
don't use C-style casts. static_cast<unsigned int>(injured_robots.size())
| void SensorFusion::detectInjuredRobots( | ||
| const std::vector<TbotsProto::RobotStatus> &robot_status_msgs) | ||
| { | ||
| /* potential improvement: add short circuit logic when an error is detected */ |
| RobotId robot_id = robot_status_msg.robot_id(); | ||
| bool has_error = false; | ||
|
|
||
| // Note: each check is not continuing when the robot is identified as injured |
There was a problem hiding this comment.
| // Note: each check is not continuing when the robot is identified as injured | |
| // Note: check stops once a robot has been identified as injured |
| drive_unit_msgs.push_back(motor_status_msgs.front_left()); | ||
| drive_unit_msgs.push_back(motor_status_msgs.front_right()); | ||
| drive_unit_msgs.push_back(motor_status_msgs.back_left()); | ||
| drive_unit_msgs.push_back(motor_status_msgs.back_right()); |
There was a problem hiding this comment.
you can also add the dribbler as well
| virtual ~SensorFusion() = default; | ||
|
|
||
| const static int BREAK_BEAM_TOLERANCE = 2; | ||
| void detectInjuredRobots( |
There was a problem hiding this comment.
also this function can be private
|
|
||
| std::vector<Robot> injured_robots = | ||
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 1); |
There was a problem hiding this comment.
kinda pedantic but if you use ASSERT_EQ here, then below you can remove the if because the assertion will stop execution at this point if it fails
|
|
||
| std::vector<Robot> injured_robots = | ||
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 2); |
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 1); | ||
|
|
||
| if (injured_robots.size() == 1) |
|
|
||
| std::vector<Robot> injured_robots = | ||
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 1); |
| sensor_fusion.getWorld().value().friendlyTeam().getInjuredRobots(); | ||
| EXPECT_EQ(injured_robots.size(), 1); | ||
|
|
||
| if (injured_robots.size() == 1) |
itsarune
left a comment
There was a problem hiding this comment.
great work with the tests! left some comments
It turns out that the code taken previously doesn't really work after running the test case. I will work on this in a few days. |
| std::vector<RobotSubstituionParam> substitution_robot_params | ||
| = trySubstituteInjuredRobots(world_ptr); | ||
| // applying robot substitution result | ||
| num_tactics -= static_cast<unsigned int>(substitution_robot_params.size()); |
There was a problem hiding this comment.
prone to underflow:
num_tactics = std::max(0, static_cast<int>(num_tactics) - substitution_robot_params.size());
| std::vector<Play::RobotSubstituionParam> Play::trySubstituteInjuredRobots(const WorldPtr& world_ptr){ | ||
| // Don't do anything if there aren't any injured robots | ||
| const std::vector<Robot>& injured_robots = world_ptr->friendlyTeam().getInjuredRobots(); | ||
| if(injured_robots.size() == 0) |
There was a problem hiding this comment.
using explicit { } is a part of our code style guide:
Software/docs/code-style-guide.md
Line 307 in bd3317f
|
|
||
| // move to middle of court and to positive y boundary and stop | ||
| double y_coordinate = world_ptr->field().totalYLength() / 2.0; | ||
| if(!ai_config.robot_substitution_config().substitute_at_positive_y()) |
There was a problem hiding this comment.
using explicit { } is a part of our code style guide:
Software/docs/code-style-guide.md
Line 307 in bd3317f
|
|
||
| private: | ||
| // For the implementation of `trySubstituteInjuredRobots` | ||
| struct RobotSubstituionParam{ |
There was a problem hiding this comment.
| struct RobotSubstituionParam{ | |
| struct RobotSubstitutionParam{ |
| * Remove the substituted robot from robots | ||
| * | ||
| * @param world_ptr: the current world_ptr with the robot | ||
| * @param robots substituted robots are removed from this list. There is side effect |
| virtual void updateTactics(const PlayUpdate& play_update); | ||
|
|
||
| private: | ||
| // For the implementation of `trySubstituteInjuredRobots` |
There was a problem hiding this comment.
| // For the implementation of `trySubstituteInjuredRobots` | |
| /** | |
| * RobotSubstitutionParam contains the replacement tactics for robot substitutions. |
| EXPECT_EQ(expected_pos, injured_robot_pos); | ||
| } | ||
|
|
||
| /** |
There was a problem hiding this comment.
you should also check that we don't exceed the limit we've set in the maximum_robot_substitution_count()
|
|
||
| // substitution tactic is just a move tactic to a decided location | ||
| std::shared_ptr<MoveTactic> auto_sub_tactic = std::make_shared<MoveTactic>(); | ||
|
|
There was a problem hiding this comment.
Robot Substitution rules
We should also check that the ball is > 0.5m away from the robot substitution location before committing to the substitution
| @@ -0,0 +1,71 @@ | |||
|
|
|||
| TEST_F(TacticAssignmentTest, test_assigning_stop_tactics_to_unassigned_non_goalie_robots) | |||
There was a problem hiding this comment.
why did you make a new test file and not just put it here: https://github.com/UBC-Thunderbots/Software/blob/master/src/software/ai/hl/stp/stp_tactic_assignment_test.cpp
|
@Mr-Anyone What the status of this issue? If it is not currently in progress, could you create an issue, note your progress then link this PR? That way I can assign this issue to someone/prune this ticket |
I just took a look at this PR, and it seems that if you call Nobodies calls tbh, it may be easier to redo this PR than to build from it (I think you can do it more elegantly than this). Feel free to assign it to people. I took most of the code from #3091 . |
|
@Andrewyx @williamckha btw, feel free to take over #3455 if you think it is urgent or just want to assign it for someone to do. |
Description
Robot substitution
Testing Done
TBD, maybe need a field potentially!
Length Justification and Key Files to Review
N/A
Review Checklist
.hfile) should have a javadoc style comment at the start of them. For examples, see the functions defined inthunderbots/software/geom. Similarly, all classes should have an associated Javadoc comment explaining the purpose of the class.TODO(or similar) statements should either be completed or associated with a github issueTaken mostly from @jameschuang2002 in his pr.