diff --git a/docs/getting-started.md b/docs/getting-started.md index a55602907c..e289356dde 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -5,35 +5,30 @@ - [Table of Contents](#table-of-contents) -- [Software Setup](#software-setup) - - [Introduction](#introduction) - - [Installation and Setup](#installation-and-setup) - - [Operating systems](#operating-systems) - - [Getting the Code](#getting-the-code) - - [Installing Software Dependencies](#installing-software-dependencies) - - [Installing an IDE](#installing-an-ide) - - [Installing an IDE: CLion](#installing-an-ide-clion) - - [Getting your Student License](#getting-your-student-license) - - [Installing CLion](#installing-clion) - - [Installing an IDE: VS Code](#installing-an-ide-vs-code) - - [Editing with Vim or NeoVim](#editing-with-vim-or-neovim) - - [Building and Running the Code](#building-and-running-the-code) - - [Building from the command line](#building-from-the-command-line) - - [Building from the command line using the fuzzy finder](#building-from-the-command-line-using-the-fuzzy-finder) - - [Building with CLion](#building-with-clion) - - [Building with VS Code](#building-with-vs-code) - - [Running our AI, Simulator, SimulatedTests or Robot Diagnostics](#running-our-ai-simulator-simulatedtests-or-robot-diagnostics) - - [Debugging](#debugging) - - [Debugging with CLion](#debugging-with-clion) - - [Debugging from the Command Line](#debugging-from-the-command-line) - - [Profiling](#profiling) - - [Callgrind](#callgrind) - - [Tracy](#tracy) - - [Building for the robot](#building-for-the-robot) - - [Deploying Robot Software to the robot](#deploying-robot-software-to-the-robot) - - [Testing Robot Software locally](#testing-robot-software-locally) - - [Setting up Virtual Robocup 2021](#setting-up-virtual-robocup-2021) - - [Setting up the SSL Simulation Environment](#setting-up-the-ssl-simulation-environment) + - [Installing Software Dependencies](#installing-software-dependencies) + - [Installing an IDE](#installing-an-ide) + - [Installing an IDE: CLion](#installing-an-ide-clion) + - [Getting your Student License](#getting-your-student-license) + - [Installing CLion](#installing-clion) + - [Installing an IDE: VS Code](#installing-an-ide-vs-code) + - [Editing with Vim or NeoVim](#editing-with-vim-or-neovim) +- [Building and Running the Code](#building-and-running-the-code) + - [Building from the command line](#building-from-the-command-line) + - [Building from the command line using the fuzzy finder](#building-from-the-command-line-using-the-fuzzy-finder) + - [Building with CLion](#building-with-clion) + - [Building with VS Code](#building-with-vs-code) + - [Running our AI, Simulator, SimulatedTests or Robot Diagnostics](#running-our-ai-simulator-simulatedtests-or-robot-diagnostics) +- [Debugging](#debugging) + - [Debugging with CLion](#debugging-with-clion) + - [Debugging from the Command Line](#debugging-from-the-command-line) +- [Profiling](#profiling) + - [Callgrind](#callgrind) + - [Tracy](#tracy) +- [Building for the robot](#building-for-the-robot) +- [Deploying Robot Software to the robot](#deploying-robot-software-to-the-robot) +- [Testing Robot Software locally](#testing-robot-software-locally) +- [Setting up Virtual Robocup 2021](#setting-up-virtual-robocup-2021) + - [Setting up the SSL Simulation Environment](#setting-up-the-ssl-simulation-environment) - [Workflow](#workflow) - [Issue and Project Tracking](#issue-and-project-tracking) - [Issues](#issues) @@ -49,53 +44,6 @@ - [Testing](#testing) - -# Software Setup - -## Introduction - -These instructions assume that you have the following accounts setup: -- [GitHub](https://github.com/login) -- [Discord](https://discord.com). Please contact a Thunderbots lead to receive the invite link. - -These instructions assume you have a basic understanding of Linux and the command line. There are many great tutorials online, such as [LinuxCommand](http://linuxcommand.org/). The most important things you'll need to know are how to move around the filesystem and how to run programs or scripts. - -## Installation and Setup - -### Operating systems - -We currently only support Linux, specifically Ubuntu. - -If you have a X86_64 machine, we support Ubuntu 22.04 LTS and Ubuntu 24.04 LTS. - -If you have a ARM64 (also known as AARCH64) machine, we support Ubuntu 24.04 LTS. - -You are welcome to use a different version or distribution of Linux, but may need to make some tweaks in order for things to work. - -You can use Ubuntu 22.04 LTS or Ubuntu 24.04 LTS inside Windows through Windows Subsystem for Linux, by following [this guide](./getting-started-wsl.md). **Running and developing Thunderbots on Windows is experimental and not officially supported.** - -### Getting the Code - -1. Open a new terminal -2. Install git by running `sudo apt-get install git` -3. Go to the [software repository](https://github.com/UBC-Thunderbots/Software) -4. Click the `Fork` button in the top-right to fork the repository ([click here to learn about Forks](https://help.github.com/en/articles/fork-a-repo)) - 1. Click on your user when prompted - 2. You should be automatically redirected to your new fork -5. Clone your fork of the repository. As GitHub is forcing users to stop using usernames and passwords for authorization, we will be using the SSH link. - - To clone using SSH: - - 1. If not setup prior, you will need to add an SSH key to your GitHub account. Instructions can be found [here](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent). For each computer you contribute to GitHub with, you will need an additional SSH Key pair linked to your account. - 2. After you have successfully set up a SSH key for your device and added it to GitHub, you can clone the repository using the following command: - 1. e.g. `git clone git@github.com:/Software.git` - 2. You can find this link under the green `Code` button on the main page of your fork on GitHub, under the SSH tab. (This should now be available after adding your SSH key to GitHub successfully.) - - Alternatively, you can clone using HTTPS. You'll need to either use a credential helper (Git Credential Manager, GitHub CLI, etc.) or a personal access token ([details here](https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls)). -6. Set up your git remotes ([what is a remote and how does it work?](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes)) - 1. You should have a remote named `origin` that points to your fork of the repository. Git will have set this up automatically when you cloned your fork in the previous step. - 2. You will need to add a second remote, named `upstream`, that points to our main Software repository, which is where you created your fork from. (**Note:** This is _not_ your fork) - 1. Open a terminal and navigate to the folder you cloned (your fork): `cd path/to/the/repository/Software` 2. Navigate to our main Software repository in your browser and copy the url from the green `Code` button. Copy the SSH url if you originally cloned with SSH, or use the HTTPS url if you previously cloned with HTTPS 3. From your terminal, add the new remote by running `git remote add upstream ` (without the angle brackets) 1. e.g. `git remote add upstream git@github.com:UBC-Thunderbots/Software.git` diff --git a/docs/useful-robot-commands.md b/docs/useful-robot-commands.md index 1ede1bcd24..b5096017c1 100644 --- a/docs/useful-robot-commands.md +++ b/docs/useful-robot-commands.md @@ -5,10 +5,6 @@ - [Table of Contents](#table-of-contents) -- [Common Debugging Steps](#common-debugging-steps) -- [Off Robot Commands](#off-robot-commands) - - [Wifi Disclaimer](#wifi-disclaimer) - - [Miscellaneous Ansible Tasks & Options](#miscellaneous-ansible-tasks--options) - [Flashing the robot's compute module](#flashing-the-robots-compute-module) - [Flashing the powerboard](#flashing-the-powerboard) - [Setting up the embedded host](#setting-up-the-embedded-host) @@ -24,28 +20,6 @@ - [Redis](#redis) - -# Common Debugging Steps -```mermaid ---- -title: Robot Debugging Steps ---- -flowchart TD - ssh("Can you SSH into the robot? - `ssh robot@192.168.0.20RobotID` (for Nanos) OR `ssh robot@192.168.5.20RobotID` (for Pis) OR `ssh robot@robot_name.local` - e.g. `ssh robot@192.168.0.203` (for Nanos) or `ssh robot@192.168.5.203` (for Pis) or `ssh robot@robert.local` - for a robot called robert with robot id 3") - ssh ---> |Yes| tloop_status - ssh --> |No - Second Try| monitor("Connect Jetson or Pi to an external monitor and check wifi connection or SSH using an ethernet cable") - ssh --> |No - First Try| restart(Restart robot) - restart --> ssh - - diagnostics("`Run Diagnostics while connected to '**tbots**' wifi`") --> robot_view - robot_view(Robot is shown as connected in 'Robot View' widget?) --> |Yes| check_motors(All motors move?) - style diagnostics stroke:#f66,stroke-width:2px,stroke-dasharray: 5 5 - - check_motors -->|Yes| field_test(Running AI?) - field_test -->|No| done(Done) style done stroke:#30fa02,stroke-width:2px,stroke-dasharray: 5 5 field_test -->|Yes| field_test_moves(Does robot move during field test?) field_test_moves --> |No| check_shell("`Check that the correct shell is placed on the robot`") diff --git a/src/software/ai/hl/stp/play/offense/offense_play_test.py b/src/software/ai/hl/stp/play/offense/offense_play_test.py index 3bc0668499..b865ebe2c2 100644 --- a/src/software/ai/hl/stp/play/offense/offense_play_test.py +++ b/src/software/ai/hl/stp/play/offense/offense_play_test.py @@ -1,5 +1,7 @@ import software.python_bindings as tbots_cpp from proto.play_pb2 import Play, PlayName + +from software.simulated_tests.excessive_dribbling import NeverExcessivelyDribbles from software.simulated_tests.friendly_team_scored import * from software.simulated_tests.ball_enters_region import * from software.simulated_tests.friendly_has_ball_possession import * @@ -76,7 +78,8 @@ def setup(start_point): # Always Validation inv_always_validation_sequence_set = [ - [BallAlwaysStaysInRegion(regions=[field.fieldBoundary()])] + [BallAlwaysStaysInRegion(regions=[field.fieldBoundary()])], + [NeverExcessivelyDribbles()], ] ag_always_validation_sequence_set = [[FriendlyAlwaysHasBallPossession()]] diff --git a/src/software/ai/hl/stp/tactic/dribble/BUILD b/src/software/ai/hl/stp/tactic/dribble/BUILD index 3c5565efb3..67199a889f 100644 --- a/src/software/ai/hl/stp/tactic/dribble/BUILD +++ b/src/software/ai/hl/stp/tactic/dribble/BUILD @@ -1,3 +1,5 @@ +load("@simulated_tests_deps//:requirements.bzl", "requirement") + package(default_visibility = ["//visibility:public"]) cc_library( @@ -60,3 +62,20 @@ cc_test( "//software/world", ], ) + +py_test( + name = "excessive_dribble_test", + srcs = [ + "excessive_dribble_test.py", + ], + # TODO (#2619) Remove tag to run in parallel + tags = [ + "exclusive", + ], + deps = [ + "//software:conftest", + "//software/simulated_tests:speed_threshold_helpers", + "//software/simulated_tests:validation", + requirement("pytest"), + ], +) diff --git a/src/software/ai/hl/stp/tactic/dribble/excessive_dribble_test.py b/src/software/ai/hl/stp/tactic/dribble/excessive_dribble_test.py new file mode 100644 index 0000000000..6589e322d9 --- /dev/null +++ b/src/software/ai/hl/stp/tactic/dribble/excessive_dribble_test.py @@ -0,0 +1,134 @@ +import pytest + +import software.python_bindings as tbots_cpp +from software.simulated_tests.excessive_dribbling import ( + NeverExcessivelyDribbles, + EventuallyStartsExcessivelyDribbling, +) +from proto.message_translation.tbots_protobuf import ( + WorldState, + AssignedTacticPlayControlParams, + DribbleTactic, +) +from software.simulated_tests.simulated_test_fixture import ( + pytest_main, +) +from proto.message_translation.tbots_protobuf import create_world_state + + +@pytest.mark.parametrize( + "initial_location,dribble_destination,final_dribble_orientation, should_excessively_dribble", + [ + # Tests Should not excessively dribble + # Dribble Destination for the ball < 1.0 from its starting position + (tbots_cpp.Point(0.5, 0), tbots_cpp.Point(1.02, 0), tbots_cpp.Angle(), False), + # Dribble Testing diagonally + ( + tbots_cpp.Point(0.25, 0.25), + tbots_cpp.Point(0.80, 0.50), + tbots_cpp.Angle.fromRadians(50), + False, + ), + # Boundary Testing, because of the autoref implementation (initial of position Bot to final of Ball), + # a conservative max dribble distance (0.95 m) is used + # Test vertical dribbling + (tbots_cpp.Point(0.01, 0), tbots_cpp.Point(0.96, 0), tbots_cpp.Angle(), False), + # Test horizontal dribbling + (tbots_cpp.Point(1, 1.5), tbots_cpp.Point(1.95, 1.5), tbots_cpp.Angle(), False), + # Test bot and ball in same position + (tbots_cpp.Point(0, 1), tbots_cpp.Point(0.95, 1), tbots_cpp.Angle(), False), + # Tests Should excessively dribble + # Dribble Destination for the ball > 1.0 from its starting position + (tbots_cpp.Point(0, 2), tbots_cpp.Point(0, 0.5), tbots_cpp.Angle(), True), + # Dribble Testing diagonally + ( + tbots_cpp.Point(0.1, 1.1), + tbots_cpp.Point(1.1, 0.1), + tbots_cpp.Angle.fromRadians(50), + True, + ), + # Boundary Testing, due to the conservative implementation a dribble distance of 1 m should fail + # Test Vertical Dribbling + (tbots_cpp.Point(0, 1), tbots_cpp.Point(0, 2), tbots_cpp.Angle(), True), + # Test Horizontal Dribbling + (tbots_cpp.Point(1, 2), tbots_cpp.Point(0, 2), tbots_cpp.Angle(), True), + # Test Diagonal Dribbling + (tbots_cpp.Point(0, 1), tbots_cpp.Point(0.6, 1.8), tbots_cpp.Angle(), True), + # Test robot and ball at same position (affects dribbling orientation and therefore perceived dribble distance) + (tbots_cpp.Point(0, 0), tbots_cpp.Point(0, 1), tbots_cpp.Angle(), True), + ( + tbots_cpp.Point(0.0, 0.01), + tbots_cpp.Point(0.81, 0.61), + tbots_cpp.Angle(), + True, + ), + ( + tbots_cpp.Point(0.01, 0.00), + tbots_cpp.Point(0.81, 0.61), + tbots_cpp.Angle(), + True, + ), + ], +) +def test_excessive_dribbling( + initial_location, + dribble_destination, + final_dribble_orientation, + should_excessively_dribble, + simulated_test_runner, +): + if should_excessively_dribble: + blue_robot_locations = [tbots_cpp.Point(0, 0.0)] + + # Always and Eventually validation sets for excessive dribbling + always_validation_sequence_set = [[]] + eventually_validation_sequence_set = [[EventuallyStartsExcessivelyDribbling()]] + else: + blue_robot_locations = [tbots_cpp.Point(0, 1)] + + # Always and Eventually validation sets for not excessive dribbling + always_validation_sequence_set = [[NeverExcessivelyDribbles()]] + eventually_validation_sequence_set = [[]] + + simulated_test_runner.simulator_proto_unix_io.send_proto( + WorldState, + create_world_state( + [], + blue_robot_locations=blue_robot_locations, + ball_location=initial_location, + ball_velocity=tbots_cpp.Vector(0, 0), + ), + ) + + # Setup Tactic + params = AssignedTacticPlayControlParams() + params.assigned_tactics[0].dribble.CopyFrom( + DribbleTactic( + dribble_destination=tbots_cpp.createPointProto(dribble_destination), + final_dribble_orientation=tbots_cpp.createAngleProto( + final_dribble_orientation + ), + allow_excessive_dribbling=True, + ) + ) + + simulated_test_runner.blue_full_system_proto_unix_io.send_proto( + AssignedTacticPlayControlParams, params + ) + + # Setup no tactics on the enemy side + params = AssignedTacticPlayControlParams() + simulated_test_runner.yellow_full_system_proto_unix_io.send_proto( + AssignedTacticPlayControlParams, params + ) + + simulated_test_runner.run_test( + inv_eventually_validation_sequence_set=eventually_validation_sequence_set, + inv_always_validation_sequence_set=always_validation_sequence_set, + ag_eventually_validation_sequence_set=eventually_validation_sequence_set, + ag_always_validation_sequence_set=always_validation_sequence_set, + ) + + +if __name__ == "__main__": + pytest_main(__file__) diff --git a/src/software/simulated_tests/excessive_dribbling.py b/src/software/simulated_tests/excessive_dribbling.py index d310ba1346..01c58e9516 100644 --- a/src/software/simulated_tests/excessive_dribbling.py +++ b/src/software/simulated_tests/excessive_dribbling.py @@ -1,5 +1,6 @@ import software.python_bindings as tbots_cpp -from proto.import_all_protos import * +from proto.import_all_protos import ValidationStatus, ValidationGeometry +from software.thunderscope.constants import DribblingConstants from software.simulated_tests.validation import ( Validation, @@ -12,39 +13,46 @@ class ExcessivelyDribbling(Validation): """Checks if any friendly robot is excessively dribbling the ball, i.e. for over 1m.""" - def __init__(self): - self.continous_dribbling_start_point = None - @override - def get_validation_status(self, world) -> ValidationStatus: + def get_validation_status( + self, + world, + ) -> ValidationStatus: """Checks if any friendly robot is excessively dribbling the ball, i.e. for over 1m. :param world: The world msg to validate + estimate of max dribble distance (effective dribble distance is length - error margin) :return: FAILING when the robot is excessively dribbling PASSING when the robot is not excessively dribbling """ - ball_position = tbots_cpp.createPoint(world.ball.current_state.global_position) - for robot in world.friendly_team.team_robots: - if not tbots_cpp.Robot(robot).isNearDribbler(ball_position, 0.01): - # if ball is not near dribbler then de-activate this validation - self.continous_dribbling_start_point = None - elif ( - ball_position - (self.continous_dribbling_start_point or ball_position) - ).length() > 1.0: + # Use world calculation of dribbling distance, which uses implementation + # of initial position of bot to final position of BALL + + if ( + world.HasField("dribble_displacement") + and world.dribble_displacement is not None + ): + dribble_disp = world.dribble_displacement + dist = tbots_cpp.createSegment(dribble_disp).length() + if dist > ( + DribblingConstants.MAX_DRIBBLING_DISTANCE + - DribblingConstants.DRIBBLING_ERROR_MARGIN + ): return ValidationStatus.FAILING - elif self.continous_dribbling_start_point is None: - # ball is in dribbler, but previously wasn't in dribbler, so set continuous dribbling start point - self.continous_dribbling_start_point = ball_position + return ValidationStatus.PASSING @override def get_validation_geometry(self, world) -> ValidationGeometry: """(override) Shows the max allowed dribbling circle""" - return create_validation_geometry( - [tbots_cpp.Circle(self.continous_dribbling_start_point, 1.0)] - if self.continous_dribbling_start_point is not None - else [] - ) + if world.HasField("dribble_displacement"): + dribbling_start_point = tbots_cpp.createSegment( + world.dribble_displacement + ).getStart() + return create_validation_geometry( + [tbots_cpp.Circle(dribbling_start_point, 1.0)] + ) + return create_validation_geometry([]) @override def __repr__(self): diff --git a/src/software/thunderscope/constants.py b/src/software/thunderscope/constants.py index 3422727e97..4ba2612e56 100644 --- a/src/software/thunderscope/constants.py +++ b/src/software/thunderscope/constants.py @@ -379,6 +379,13 @@ class ProtoPlayerFlags(Enum): UNCAUGHT_EXCEPTION_FLAG = 1 << 0 +class DribblingConstants: + """Constants to be used to check whether the robot has dribbled beyond competition regulations""" + + MAX_DRIBBLING_DISTANCE = 1.0 + DRIBBLING_ERROR_MARGIN = 0.06 + + class LogLevels(StrEnum): """Log levels for FullSystem to indicate minimum logged level"""