Skip to content

Commit 9e998b2

Browse files
authored
Merge branch 'UBC-Thunderbots:master' into fmt-githook
2 parents 9a654e5 + 85838af commit 9e998b2

211 files changed

Lines changed: 2005 additions & 1855 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

environment_setup/ubuntu22_requirements.txt

Lines changed: 0 additions & 14 deletions
This file was deleted.

environment_setup/ubuntu24_requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ ruff==0.5.5
99
pyqt-toast-notification==1.3.2
1010
md-toc==9.0.0
1111
grpcio-tools==1.71.0
12+
typer==0.21.0

src/cli/cli_params.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
from typer import Option
2+
from enum import Enum
3+
from typing import Annotated
4+
5+
from cli.multi_option import MultiOption
6+
7+
8+
class ActionArgument(str, Enum):
9+
build = "build"
10+
test = "test"
11+
run = "run"
12+
13+
14+
class DebugBinary(str, Enum):
15+
sim = "sim"
16+
blue = "blue"
17+
yellow = "yellow"
18+
19+
20+
class Platform(str, Enum):
21+
PI = "PI"
22+
NANO = "NANO"
23+
LIMITED = "LIMITED"
24+
25+
26+
PrintCommandOption: type[bool] = Annotated[
27+
bool, Option("-p", "--print_command", help="Print the generated Bazel command")
28+
]
29+
30+
NoOptimizedBuildOption: type[bool] = Annotated[
31+
bool,
32+
Option(
33+
"-no", "--no_optimized_build", help="Compile binaries without -O3 optimizations"
34+
),
35+
]
36+
37+
DebugBuildOption: type[bool] = Annotated[
38+
bool,
39+
Option(
40+
"-d",
41+
"--debug",
42+
help="Compile binaries with debug symbols",
43+
),
44+
]
45+
46+
SelectDebugBinariesOption = Annotated[
47+
list[DebugBinary] | None,
48+
MultiOption(
49+
"-ds",
50+
"--select_debug_binaries",
51+
help="Select all binaries which are running separately in debug mode",
52+
),
53+
]
54+
55+
FlashRobotsOption = Annotated[
56+
list[int] | None,
57+
MultiOption(
58+
"-f",
59+
"--flash_robots",
60+
help="A list of space separated integers representing the robot IDs "
61+
"that should be flashed by the deploy_robot_software Ansible playbook",
62+
),
63+
]
64+
65+
SSHPasswordOption = Annotated[
66+
str,
67+
Option(
68+
"-pwd", "--pwd", help="Password used by Ansible when SSHing into the robots"
69+
),
70+
]
71+
72+
InteractiveModeOption = Annotated[
73+
bool,
74+
Option(
75+
"-i",
76+
"--interactive",
77+
help="Enables interactive searching for bazel targets",
78+
),
79+
]
80+
81+
TracyOption = Annotated[
82+
bool, Option("--tracy", help="Run the binary with the TRACY_ENABLE macro defined")
83+
]
84+
85+
PlatformOption = Annotated[
86+
Platform, Option("-pl", "--platform", help="The platform to build Thunderloop for")
87+
]
88+
89+
EnableThunderscopeOption = Annotated[bool, Option("-t", "--enable_thunderscope")]
90+
EnableVisualizerOption = Annotated[bool, Option("-v", "--enable_visualizer")]
91+
StopAIOnStartOption = Annotated[bool, Option("-t", "--stop_ai_on_start")]

src/cli/multi_option.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
from typing import Any
2+
import click
3+
import typer
4+
import typer.core
5+
import typer.main
6+
from typer.models import OptionInfo
7+
8+
9+
# ======= Patch to support nargs functionality in typer =======
10+
# nargs usage is considered bad practice in typer and many CLIs,
11+
# but since we likely want to be able to parse many optional args at once, this patch allows us to do so.
12+
# See https://github.com/fastapi/typer/issues/110
13+
# ==============================================================
14+
15+
16+
class OptionEatAll(typer.core.TyperOption):
17+
"""Click option that consumes arguments until next option flag."""
18+
19+
def __init__(self, *args: Any, **kwargs: Any) -> None:
20+
kwargs["multiple"] = True
21+
kwargs["is_flag"] = False
22+
super().__init__(*args, **kwargs)
23+
self._previous_parser_process = None
24+
self._eat_all_parser = None
25+
26+
def add_to_parser(self, parser: Any, ctx: click.Context) -> Any:
27+
def parser_process(value: str, state: Any) -> None:
28+
values = [value]
29+
done = False
30+
while state.rargs and not done:
31+
for prefix in self._eat_all_parser.prefixes:
32+
if state.rargs[0].startswith(prefix):
33+
done = True
34+
break
35+
if not done:
36+
values.append(state.rargs.pop(0))
37+
for val in values:
38+
self._previous_parser_process(val, state)
39+
40+
retval = super().add_to_parser(parser, ctx)
41+
for name in self.opts:
42+
our_parser = parser._long_opt.get(name) or parser._short_opt.get(name)
43+
if our_parser:
44+
self._eat_all_parser = our_parser
45+
self._previous_parser_process = our_parser.process
46+
our_parser.process = parser_process
47+
break
48+
return retval
49+
50+
51+
class MultiOptionInfo(OptionInfo):
52+
"""Marker for multi-argument options."""
53+
54+
is_multi_option: bool = True
55+
56+
def __init__(self, option_info: OptionInfo) -> None:
57+
super().__init__(**option_info.__dict__)
58+
59+
60+
def MultiOption(
61+
default: Any = ..., *param_decls: str, **kwargs: Any
62+
) -> MultiOptionInfo:
63+
"""Create option that accepts multiple values."""
64+
return MultiOptionInfo(typer.Option(default, *param_decls, **kwargs))
65+
66+
67+
# Monkey-patch to detect MultiOptionInfo and use OptionEatAll
68+
_original_get_click_param = typer.main.get_click_param
69+
70+
71+
def _patched_get_click_param(param: typer.models.ParamMeta):
72+
click_param, converter = _original_get_click_param(param)
73+
if isinstance(param.default, MultiOptionInfo):
74+
option_eat_all = object.__new__(OptionEatAll)
75+
option_eat_all.__dict__.update(click_param.__dict__)
76+
option_eat_all._previous_parser_process = None
77+
option_eat_all._eat_all_parser = None
78+
return (option_eat_all, converter)
79+
return (click_param, converter)
80+
81+
82+
typer.main.get_click_param = _patched_get_click_param

src/proto/message_translation/power_frame_msg.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ TbotsProto_PowerPulseControl inline createNanoPbPowerPulseControl(
142142
kick_constant = std::min(kick_constant, MAX_KICK_CONSTANT);
143143
kick_coeff = std::min(kick_coeff, MAX_KICK_COEFFICIENT);
144144

145+
nanopb_control.has_chicker = true;
146+
145147
switch (power_control.chicker().chicker_command_case())
146148
{
147149
case TbotsProto::PowerControl::ChickerControl::kKickSpeedMPerS:
@@ -229,17 +231,17 @@ TbotsProto_PowerPulseControl inline createNanoPbPowerPulseControl(
229231
switch (chicker_command)
230232
{
231233
case ChickerCommandMode::CHIP:
232-
control.chicker.which_chicker_command =
234+
chicker.which_chicker_command =
233235
TbotsProto_PowerPulseControl_ChickerControl_chip_pulse_width_tag;
234236
chicker.chicker_command.chip_pulse_width = chip_pulse_width;
235237
break;
236238
case ChickerCommandMode::KICK:
237-
control.chicker.which_chicker_command =
239+
chicker.which_chicker_command =
238240
TbotsProto_PowerPulseControl_ChickerControl_kick_pulse_width_tag;
239241
chicker.chicker_command.kick_pulse_width = kick_pulse_width;
240242
break;
241243
case ChickerCommandMode::AUTOCHIPORKICK:
242-
control.chicker.which_chicker_command =
244+
chicker.which_chicker_command =
243245
TbotsProto_PowerPulseControl_ChickerControl_auto_chip_or_kick_tag;
244246
switch (auto_chip_or_kick)
245247
{
@@ -263,6 +265,7 @@ TbotsProto_PowerPulseControl inline createNanoPbPowerPulseControl(
263265
break;
264266
}
265267

268+
control.has_chicker = true;
266269
control.chicker = chicker;
267270
control.geneva_slot = geneva_slot;
268271

src/shared/uart_framing/uart_framing_test.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,8 @@ class UartFramingTest : public ::testing::Test
100100
}
101101

102102
TbotsProto_PowerPulseControl test_message;
103-
// TODO: Previously from online calculator, but this value may be incorrect since the
104-
// bazel 8 migration
105-
const uint16_t TEST_MESSAGE_CRC = 34041;
103+
104+
const uint16_t TEST_MESSAGE_CRC = 60410;
106105
};
107106

108107
bool operator==(const TbotsProto_PowerPulseControl& lhs,
@@ -149,5 +148,9 @@ TEST_F(UartFramingTest, marshalling_test)
149148
EXPECT_EQ(test_frame_unmarshalled.length, TbotsProto_PowerPulseControl_size);
150149
EXPECT_EQ(test_frame_unmarshalled.crc, TEST_MESSAGE_CRC);
151150
EXPECT_EQ(test_frame_unmarshalled.power_msg.power_control, test_message);
151+
EXPECT_EQ(test_frame_unmarshalled.power_msg.power_control.chicker.chicker_command
152+
.auto_chip_or_kick.auto_chip_or_kick.autochip_pulse_width,
153+
test_message.chicker.chicker_command.auto_chip_or_kick.auto_chip_or_kick
154+
.autochip_pulse_width);
152155
EXPECT_TRUE(verifyLengthAndCrc(test_frame_unmarshalled));
153156
}

src/software/ai/ai.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
#include "software/tracy/tracy_constants.h"
88

99

10-
Ai::Ai(const TbotsProto::AiConfig& ai_config)
11-
: ai_config_(ai_config),
12-
fsm(std::make_unique<FSM<PlaySelectionFSM>>(PlaySelectionFSM{ai_config})),
10+
Ai::Ai(std::shared_ptr<const TbotsProto::AiConfig> ai_config_ptr)
11+
: ai_config_ptr(ai_config_ptr),
12+
fsm(std::make_unique<FSM<PlaySelectionFSM>>(PlaySelectionFSM{ai_config_ptr})),
1313
override_play(nullptr),
14-
current_play(std::make_unique<HaltPlay>(ai_config)),
14+
current_play(std::make_unique<HaltPlay>(ai_config_ptr)),
1515
ai_config_changed(false)
1616
{
17-
auto current_override = ai_config_.ai_control_config().override_ai_play();
17+
auto current_override = ai_config_ptr->ai_control_config().override_ai_play();
1818
if (current_override != TbotsProto::PlayName::UseAiSelection)
1919
{
2020
// Override to new play if we're not running Ai Selection
@@ -32,12 +32,11 @@ void Ai::overridePlay(std::unique_ptr<Play> play)
3232
void Ai::overridePlayFromProto(TbotsProto::Play play_proto)
3333
{
3434
current_override_play_proto = play_proto;
35-
overridePlay(std::move(createPlay(play_proto, ai_config_)));
35+
overridePlay(std::move(createPlay(play_proto, ai_config_ptr)));
3636
}
3737

38-
void Ai::updateAiConfig(TbotsProto::AiConfig& ai_config)
38+
void Ai::updateAiConfig()
3939
{
40-
ai_config_ = std::move(ai_config);
4140
ai_config_changed = true;
4241
}
4342

@@ -47,9 +46,9 @@ void Ai::checkAiConfig()
4746
{
4847
ai_config_changed = false;
4948

50-
fsm = std::make_unique<FSM<PlaySelectionFSM>>(PlaySelectionFSM{ai_config_});
49+
fsm = std::make_unique<FSM<PlaySelectionFSM>>(PlaySelectionFSM{ai_config_ptr});
5150

52-
auto current_override = ai_config_.ai_control_config().override_ai_play();
51+
auto current_override = ai_config_ptr->ai_control_config().override_ai_play();
5352
if (current_override != TbotsProto::PlayName::UseAiSelection)
5453
{
5554
// Override to new play if we're not running Ai Selection
@@ -73,7 +72,7 @@ std::unique_ptr<TbotsProto::PrimitiveSet> Ai::getPrimitives(const WorldPtr& worl
7372

7473
fsm->process_event(PlaySelectionFSM::Update([this](std::unique_ptr<Play> play)
7574
{ current_play = std::move(play); },
76-
world_ptr->gameState(), ai_config_));
75+
world_ptr->gameState(), *ai_config_ptr));
7776

7877
std::unique_ptr<TbotsProto::PrimitiveSet> primitive_set;
7978
if (static_cast<bool>(override_play))

src/software/ai/ai.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ class Ai final
1818

1919
/**
2020
* Create an AI with given configurations
21-
* @param ai_config_ The AI configuration
21+
* @param ai_config_ptr shared pointer to the ai configuration
2222
*/
23-
explicit Ai(const TbotsProto::AiConfig& ai_config);
23+
explicit Ai(std::shared_ptr<const TbotsProto::AiConfig> ai_config_ptr);
2424

2525
/**
2626
* Overrides the play
@@ -60,12 +60,12 @@ class Ai final
6060
*
6161
* @param ai_config The new AiConfig proto
6262
*/
63-
void updateAiConfig(TbotsProto::AiConfig& ai_config);
63+
void updateAiConfig();
6464

6565
private:
6666
void checkAiConfig();
6767

68-
TbotsProto::AiConfig ai_config_;
68+
std::shared_ptr<const TbotsProto::AiConfig> ai_config_ptr;
6969
std::unique_ptr<FSM<PlaySelectionFSM>> fsm;
7070
std::unique_ptr<Play> override_play;
7171
std::unique_ptr<Play> current_play;

src/software/ai/hl/stp/play/BUILD

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ cc_library(
8686
srcs = ["play.cpp"],
8787
hdrs = [
8888
"play.h",
89-
"play_fsm.h",
89+
"play_base.hpp",
90+
"play_fsm.hpp",
9091
],
9192
deps = [
9293
"//software/ai/hl/stp/tactic",

src/software/ai/hl/stp/play/assigned_tactics_play.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
#include "software/logger/logger.h"
77
#include "software/util/generic_factory/generic_factory.h"
88

9-
AssignedTacticsPlay::AssignedTacticsPlay(TbotsProto::AiConfig config)
10-
: Play(config, false),
9+
AssignedTacticsPlay::AssignedTacticsPlay(
10+
std::shared_ptr<const TbotsProto::AiConfig> ai_config_ptr)
11+
: Play(ai_config_ptr, false),
1112
assigned_tactics(),
1213
override_motion_constraints(),
13-
obstacle_factory(config.robot_navigation_obstacle_config())
14+
obstacle_factory(ai_config_ptr->robot_navigation_obstacle_config())
1415
{
1516
}
1617

@@ -89,5 +90,6 @@ std::unique_ptr<TbotsProto::PrimitiveSet> AssignedTacticsPlay::get(
8990
void AssignedTacticsPlay::updateTactics(const PlayUpdate &play_update) {}
9091

9192
// Register this play in the genericFactory
92-
static TGenericFactory<std::string, Play, AssignedTacticsPlay, TbotsProto::AiConfig>
93+
static TGenericFactory<std::string, Play, AssignedTacticsPlay,
94+
std::shared_ptr<const TbotsProto::AiConfig>>
9395
factory;

0 commit comments

Comments
 (0)