Skip to content

Commit e945885

Browse files
authored
Shift Click can Now Move Robot (UBC-Thunderbots#3411)
1 parent 3eef72e commit e945885

6 files changed

Lines changed: 138 additions & 2 deletions

File tree

src/software/python_bindings.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,16 @@ PYBIND11_MODULE(python_bindings, m)
348348
.def("angularVelocity", &Robot::angularVelocity)
349349
.def("isNearDribbler", &Robot::isNearDribbler, py::arg("test_point"),
350350
py::arg("TOLERANCE") = BALL_TO_FRONT_OF_ROBOT_DISTANCE_WHEN_DRIBBLING)
351-
.def("dribblerArea", &Robot::dribblerArea);
351+
.def("dribblerArea", &Robot::dribblerArea)
352+
.def("id", &Robot::id);
352353

353354
py::class_<Team>(m, "Team")
355+
.def(py::init<TbotsProto::Team>())
354356
.def(py::init<const std::vector<Robot>&>())
355357
.def("assignGoalie", &Team::assignGoalie)
356-
.def("getAllRobots", &Team::getAllRobots);
358+
.def("getAllRobots", &Team::getAllRobots)
359+
.def("getNearestRobot",
360+
py::overload_cast<const Point&>(&Team::getNearestRobot, py::const_));
357361

358362
py::class_<Timestamp>(m, "Timestamp").def(py::init<>());
359363

src/software/thunderscope/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ py_library(
8888
"//software/thunderscope/gl/layers:gl_cost_vis_layer",
8989
"//software/thunderscope/gl/layers:gl_debug_shapes_layer",
9090
"//software/thunderscope/gl/layers:gl_max_dribble_layer",
91+
"//software/thunderscope/gl/layers:gl_movement_field_test_layer",
9192
"//software/thunderscope/gl/layers:gl_obstacle_layer",
9293
"//software/thunderscope/gl/layers:gl_passing_layer",
9394
"//software/thunderscope/gl/layers:gl_path_layer",

src/software/thunderscope/constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ class EstopMode(IntEnum):
183183
<b><code>Ctrl + R:</code></b> Remove the current layout file and reset the layout<br><br>
184184
Layout file (on save) is located at {SAVED_LAYOUT_PATH}<br>
185185
186+
<h3>GL Field Movement Test Layer</h3>
187+
<b><code>Shift+Alt+Control+Click</code></b> Select the robot that is going to be moved<br>
188+
<b><code>Shift+Alt+Click</code></b>Move the selected robot to the clicked point<br>
189+
186190
"""
187191
)
188192

src/software/thunderscope/gl/layers/BUILD

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,18 @@ py_library(
158158
],
159159
)
160160

161+
py_library(
162+
name = "gl_movement_field_test_layer",
163+
srcs = ["gl_movement_field_test_layer.py"],
164+
deps = [
165+
":gl_layer",
166+
"//software/thunderscope:proto_unix_io",
167+
"//software/thunderscope:util",
168+
"//software/thunderscope/gl/graphics:gl_polygon",
169+
requirement("pyqtgraph"),
170+
],
171+
)
172+
161173
py_library(
162174
name = "gl_max_dribble_layer",
163175
srcs = ["gl_max_dribble_layer.py"],
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import math
2+
from pyqtgraph.Qt.QtCore import Qt
3+
from software.thunderscope.gl.helpers.extended_gl_view_widget import MouseInSceneEvent
4+
from proto.import_all_protos import *
5+
from software.thunderscope.gl.layers.gl_world_layer import tbots_cpp
6+
from software.thunderscope.proto_unix_io import ProtoUnixIO
7+
from software.logger.logger import create_logger
8+
from software.thunderscope.gl.layers.gl_layer import GLLayer
9+
from software.thunderscope.thread_safe_buffer import ThreadSafeBuffer
10+
11+
logger = create_logger(__name__)
12+
13+
14+
class GLMovementFieldTestLayer(GLLayer):
15+
def __init__(
16+
self, name: str, fullsystem_io: ProtoUnixIO, buffer_size: int = 5
17+
) -> None:
18+
"""Initialize the GLMovementFieldTestLayer
19+
20+
:param name: The displayed name of the layer
21+
:param buffer_size: The buffer size we have
22+
:param fullsystem_io: The fullsystem protounix io
23+
"""
24+
super().__init__(name)
25+
26+
self.world_buffer: ThreadSafeBuffer = ThreadSafeBuffer(buffer_size, World)
27+
self.fullsystem_io: ProtoUnixIO = fullsystem_io
28+
self.selected_robot_id = 0
29+
self.cached_team: tbots_cpp.Team = None
30+
self.is_selected = False
31+
32+
def select_closest_robot(self, point):
33+
"""Find the closest robot to a point
34+
35+
:param point: the reference point to find the closest robot
36+
"""
37+
if not self.cached_team:
38+
logger.warning("No vision data received")
39+
return
40+
41+
closest_robot = self.cached_team.getNearestRobot(
42+
tbots_cpp.Point(point.x(), point.y())
43+
)
44+
if closest_robot is None:
45+
logger.warning(
46+
"No robots found. Are you sure there is friendly robot on field?"
47+
)
48+
return
49+
50+
self.selected_robot_id = closest_robot.id()
51+
self.is_selected = True
52+
53+
def mouse_in_scene_pressed(self, event: MouseInSceneEvent) -> None:
54+
"""Move to the point clicked.
55+
If Shift+Alt+Control is pressed, clicking selects a robot based on the closest point in scene.
56+
If Shift+Alt is pressed, clicking moves a robot to the point in scene.
57+
58+
:param event: The event
59+
"""
60+
if not self.visible():
61+
return
62+
63+
if not event.mouse_event.modifiers() & Qt.KeyboardModifier.AltModifier:
64+
return
65+
66+
point = event.point_in_scene
67+
if event.mouse_event.modifiers() & Qt.KeyboardModifier.ControlModifier:
68+
# Shift+Alt+Control is pressed
69+
self.select_closest_robot(point)
70+
else:
71+
# Shift+Alt is pressed
72+
self.move_to_point(point)
73+
74+
def move_to_point(self, point):
75+
"""Move to a point
76+
77+
:param point: the point we are commanding the robot to move to
78+
"""
79+
# whether the selected_robot_index would cause index out of range issues
80+
if not self.is_selected:
81+
logger.warning("No robot selected to be moved")
82+
return
83+
84+
robot_id = self.selected_robot_id
85+
86+
point = Point(x_meters=point.x(), y_meters=point.y())
87+
move_tactic = MoveTactic(
88+
destination=point,
89+
dribbler_mode=DribblerMode.OFF,
90+
final_orientation=Angle(radians=-math.pi / 2),
91+
ball_collision_type=BallCollisionType.AVOID,
92+
auto_chip_or_kick=AutoChipOrKick(autokick_speed_m_per_s=0.0),
93+
max_allowed_speed_mode=MaxAllowedSpeedMode.PHYSICAL_LIMIT,
94+
obstacle_avoidance_mode=ObstacleAvoidanceMode.SAFE,
95+
)
96+
97+
assign_tactic = AssignedTacticPlayControlParams()
98+
assign_tactic.assigned_tactics[robot_id].move.CopyFrom(move_tactic)
99+
100+
self.fullsystem_io.send_proto(AssignedTacticPlayControlParams, assign_tactic)
101+
102+
def refresh_graphics(self):
103+
"""Updating the world cache"""
104+
world = self.world_buffer.get(block=False, return_cached=False)
105+
106+
if world is None:
107+
return
108+
109+
self.cached_team = tbots_cpp.Team(world.friendly_team)

src/software/thunderscope/widget_setup_functions.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
gl_tactic_layer,
2828
gl_cost_vis_layer,
2929
gl_trail_layer,
30+
gl_movement_field_test_layer,
3031
gl_max_dribble_layer,
3132
gl_referee_info_layer,
3233
)
@@ -122,6 +123,9 @@ def setup_gl_widget(
122123
visualization_buffer_size,
123124
)
124125
)
126+
field_movement_layer = gl_movement_field_test_layer.GLMovementFieldTestLayer(
127+
"Field Movement Layer", full_system_proto_unix_io
128+
)
125129
simulator_layer = gl_simulator_layer.GLSimulatorLayer(
126130
"Simulator", friendly_colour_yellow, visualization_buffer_size
127131
)
@@ -145,6 +149,7 @@ def setup_gl_widget(
145149
gl_widget.add_layer(validation_layer)
146150
gl_widget.add_layer(trail_layer, False)
147151
gl_widget.add_layer(debug_shapes_layer, True)
152+
gl_widget.add_layer(field_movement_layer, False)
148153
gl_widget.add_layer(max_dribble_layer, True)
149154
gl_widget.add_layer(referee_layer)
150155

@@ -180,6 +185,7 @@ def setup_gl_widget(
180185
for arg in [
181186
(World, world_layer.world_buffer),
182187
(World, cost_vis_layer.world_buffer),
188+
(World, field_movement_layer.world_buffer),
183189
(World, max_dribble_layer.world_buffer),
184190
(RobotStatus, world_layer.robot_status_buffer),
185191
(Referee, world_layer.referee_buffer),

0 commit comments

Comments
 (0)