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

Add feature to bind to specific network interfaces via Thunderscope #3235

Open
wants to merge 63 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
229d183
init
itsarune May 23, 2024
236ddc7
wip
itsarune May 27, 2024
8a457b2
wip
itsarune May 27, 2024
a925f7c
mayhaps it works
itsarune May 30, 2024
6254966
wip
itsarune Jun 3, 2024
7bee165
wip
itsarune Jun 4, 2024
dfe793f
wip
itsarune Jun 5, 2024
ee9fdf2
wip
itsarune Jun 6, 2024
8d02281
debugging
itsarune Jun 8, 2024
b83c152
should clean this up
itsarune Jun 8, 2024
50ba57c
wip
itsarune Jun 12, 2024
def143a
various thunderscope improvements
itsarune Jun 13, 2024
e70630c
add some unit tests
itsarune Jun 14, 2024
db86590
wip
itsarune Jun 15, 2024
e5f7547
wip
itsarune Jun 17, 2024
059aa3f
wip
itsarune Jun 19, 2024
c19d303
wip
itsarune Jun 19, 2024
ab5a988
wip & cleanup
itsarune Jun 20, 2024
84bf1c3
Merge branch 'master' of github.com:UBC-Thunderbots/Software into net…
itsarune Jun 22, 2024
1d36ec8
wip
itsarune Jun 22, 2024
84d9ae4
cleanup
itsarune Jun 26, 2024
80e353d
revert unintentional change
itsarune Jun 26, 2024
22eb8a8
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jun 26, 2024
2649a4a
bug fix and update getting_started guide
itsarune Jun 28, 2024
a7cadce
Merge branch 'master' of github.com:UBC-Thunderbots/Software into net…
itsarune Jun 28, 2024
835e54f
Merge branch 'network-manager' of github.com:itsarune/Software into n…
itsarune Jun 28, 2024
4022588
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jun 28, 2024
64ad3d4
formatting + fix CI
itsarune Jun 29, 2024
1052f58
Merge branch 'network-manager' of github.com:itsarune/Software into n…
itsarune Jun 29, 2024
5c0fcb4
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jun 29, 2024
ff1e6bc
address PR comments
itsarune Jul 10, 2024
6673c61
Merge branch 'master' of github.com:UBC-Thunderbots/Software into net…
itsarune Jul 10, 2024
e039654
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jul 10, 2024
ebadd3e
finish up addressing comments
itsarune Jul 11, 2024
2ef6145
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jul 11, 2024
1ab3aa5
update getting started
itsarune Jul 11, 2024
0a28827
Merge branch 'network-manager' of github.com:itsarune/Software into n…
itsarune Jul 11, 2024
47f3fa5
further improve docs
itsarune Jul 11, 2024
286d956
doc cleanup
itsarune Jul 11, 2024
438951c
simplify getting_started more
itsarune Jul 11, 2024
1feeb21
remove unnecessary socket closing
itsarune Jul 11, 2024
7fa3752
cleanup edge case handling of robot_communication binding
itsarune Jul 11, 2024
4123cf4
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Jul 11, 2024
326fa63
cleanup edge cases
itsarune Jul 11, 2024
bf1472f
Merge branch 'network-manager' of github.com:itsarune/Software into n…
itsarune Jul 11, 2024
8c358a1
formatting
itsarune Jul 11, 2024
5678e3c
cleanup logic
itsarune Jul 11, 2024
78c2504
simplify logic for selecting interface
itsarune Jul 11, 2024
13db8e6
further simplify selection logic
itsarune Jul 11, 2024
78a7203
remove redundant caching
itsarune Jul 11, 2024
e16126f
delete duplicated code
itsarune Jul 11, 2024
869bf00
Merge branch 'master' of github.com:UBC-Thunderbots/Software into net…
itsarune Jul 16, 2024
159c68b
Merge branch 'master' of github.com:UBC-Thunderbots/Software into net…
itsarune Sep 1, 2024
3219b97
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Sep 1, 2024
89fc6b9
address PR comments
itsarune Sep 3, 2024
7fcec12
update documentation for getLocalIp
itsarune Sep 3, 2024
52a21f0
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Sep 3, 2024
bd9e6fe
Merge branch 'master' of github.com:UBC-Thunderbots/Software into net…
itsarune Oct 18, 2024
80a49ef
maybe fix ci
itsarune Oct 19, 2024
4cea2d7
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Oct 19, 2024
369e050
Merge branch 'master' of github.com:UBC-Thunderbots/Software into net…
itsarune Oct 30, 2024
8284a3b
Merge branch 'master' of github.com:UBC-Thunderbots/Software into net…
itsarune Nov 16, 2024
bfe0f11
[pre-commit.ci lite] apply automatic fixes
pre-commit-ci-lite[bot] Nov 16, 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
20 changes: 13 additions & 7 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -230,13 +230,11 @@ Now that you're setup, if you can run it on the command line, you can run it in

- If we want to run it with real robots:
- Open your terminal, `cd` into `Software/src` and run `ifconfig`.
- Pick the network interface you would like to use:
1. If you are running things locally, you can pick any interface that is not `lo`
2. If you would like to communicate with robots on the network, make sure to select the interface that is connected to the same network as the robots.
- Pick the network interface you would like to use. If you would like to communicate with robots on the network, make sure to select the interface that is connected to the same network as the robots.
- For example, on a sample machine, the output may look like this:

```
enp0s5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
wlp3s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
...
[omitted]
...
Expand All @@ -247,22 +245,30 @@ Now that you're setup, if you can run it on the command line, you can run it in
...
```

- An appropriate interface we could choose is `enp0s5`
- An appropriate interface we could choose is `wlp3s0`
- Hint: If you are using a wired connection, the interface will likely start with `e-`. If you are using a WiFi connection, the interface will likely start with `w-`.
- If we are running the AI as "blue": `./tbots.py run thunderscope_main --interface=[interface_here] --run_blue`
- If we are running the AI as "yellow": `./tbots.py run thunderscope_main --interface=[interface_here] --run_yellow`
- `[interface_here]` corresponds to the `ifconfig` interfaces seen in the previous step
- For instance, a call to run the AI as blue on wifi could be: `./tbots.py run thunderscope_main --interface=enp0s5 --run_blue`
- For instance, a call to run the AI as blue on WiFi could be: `./tbots.py run thunderscope_main --interface=wlp3s0 --run_blue`. This will start Thunderscope and set up communication with robots over the wifi interface. It will also listen for referee and vision messages on the same interface.
- **Note: You do not need to include the `--interface=[interface_here]` argument!** You can run Thunderscope without it and use the dynamic configuration widget to set the interfaces for communication to send and receive robot, vision and referee messages.
- If you choose to include `--interface=[interface_here]` argument, Thunderscope will listen for and send robot messages on this port as well as receive vision and referee messages.
- Using the dynamic configuration widget is recommended at Robocup. To reduce latencies, it is recommended to connect the robot router to the AI computer via ethernet and use a separate ethernet connection to receive vision and referee messages. In this configuration, Thunderscope will need to bind to two different interfaces, each likely starting with a "e-".
- If you have specified `--run_blue` or `--run_yellow`, navigate to the "Parameters" widget. In "ai_config" > "ai_control_config" > "network_config", you can set the appropriate interface using the dropdowns for robot, vision and referee message communication.
- This command will set up robot communication and the Unix full system binary context manager. The Unix full system context manager hooks up our AI, Backend and SensorFusion
2. Run AI along with Robot Diagnostics:
- The Mechanical and Electrical sub-teams use Robot Diagnostics to test specific parts of the Robot.
- If we want to run with one AI and Diagnostics
- `./tbots.py run thunderscope_main [--run_blue | --run_yellow] --run_diagnostics` will start Thunderscope
- `./tbots.py run thunderscope_main [--run_blue | --run_yellow] --run_diagnostics --interface=[interface_here]` will start Thunderscope
- `[--run_blue | --run_yellow]` indicate which FullSystem to run
- `--run_diagnostics` indicates if diagnostics should be loaded as well
- Initially, the robots are all connected to the AI and only receive input from it
- To change the input source for the robot, use the drop-down menu of that robot to change it between None, AI, and Manual
- None means the robots are receiving no commands
- More info about Manual control below
- `--interface=[interface_here]` corresponds to the `ifconfig` interfaces seen in the previous step
- For instance, a call to run the AI as blue on WiFi could be: `./tbots.py run thunderscope_main --interface=wlp3s0 --run_blue --run_diagnostics`
- The `--interface` flag is optional. If you do not include it, you can set the interface in the dynamic configuration widget. See above for how to set the interface in the dynamic configuration widget.
3. Run only Diagnostics
- To run just Diagnostics
- `./tbots.py run thunderscope --run_diagnostics --interface <network_interface>`
Expand Down
15 changes: 15 additions & 0 deletions src/proto/parameters.proto
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ message AiControlConfig

// Override the existing play with the Play enum provided
required PlayName override_ai_play = 2 [default = UseAiSelection];

// Interfaces for various network listeners
required NetworkConfig network_config = 3;
}

message AiParameterConfig
Expand Down Expand Up @@ -618,6 +621,18 @@ message PossessionTrackerConfig
];
}

message NetworkConfig
{
// The robot communication interface
required string robot_communication_interface = 1 [default = "lo"];

// The referee interface
required string referee_interface = 2 [default = "lo"];

// The vision interface
required string vision_interface = 3 [default = "lo"];
}

message CreaseDefenderConfig
{
// The additional buffer length for each side of the goal
Expand Down
19 changes: 15 additions & 4 deletions src/software/embedded/services/network/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,27 @@

NetworkService::NetworkService(const std::string& ip_address,
unsigned short primitive_listener_port,
unsigned short robot_status_sender_port, bool multicast)
unsigned short robot_status_sender_port,
const std::string& interface, bool multicast)
: primitive_tracker(ProtoTracker("primitive set"))
{
std::optional<std::string> error;
sender = std::make_unique<ThreadedProtoUdpSender<TbotsProto::RobotStatus>>(
ip_address, robot_status_sender_port, multicast);
ip_address, robot_status_sender_port, interface, multicast, error);
if (error)
{
LOG(FATAL) << *error;
}

udp_listener_primitive_set =
std::make_unique<ThreadedProtoUdpListener<TbotsProto::PrimitiveSet>>(
ip_address, primitive_listener_port,
boost::bind(&NetworkService::primitiveSetCallback, this, _1), multicast);
ip_address, primitive_listener_port, interface,
boost::bind(&NetworkService::primitiveSetCallback, this, _1), multicast,
error);
if (error)
{
LOG(FATAL) << *error;
}

radio_listener_primitive_set =
std::make_unique<ThreadedProtoRadioListener<TbotsProto::PrimitiveSet>>(
Expand Down
4 changes: 3 additions & 1 deletion src/software/embedded/services/network/network.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ class NetworkService
* @param ip_address The IP Address the service should connect to
* @param primitive_listener_port The port to listen for primitive protos
* @param robot_status_sender_port The port to send robot status
* @param interface the interface to listen and send on
* @param multicast If true, then the provided IP address is a multicast address and
* we should join the group
*/
NetworkService(const std::string& ip_address, unsigned short primitive_listener_port,
unsigned short robot_status_sender_port, bool multicast);
unsigned short robot_status_sender_port, const std::string& interface,
bool multicast);

/**
* When the network service is polled, it sends the robot_status and returns
Expand Down
22 changes: 14 additions & 8 deletions src/software/embedded/thunderloop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,10 @@ extern "C"
crash_msg.set_exit_signal(g3::signalToStr(signal_num));
*(crash_msg.mutable_status()) = *robot_status;

std::optional<std::string> error;
auto sender = std::make_unique<ThreadedProtoUdpSender<TbotsProto::RobotCrash>>(
std::string(ROBOT_MULTICAST_CHANNELS.at(channel_id)) + "%" +
network_interface,
ROBOT_CRASH_PORT, true);
std::string(ROBOT_MULTICAST_CHANNELS.at(channel_id)), ROBOT_CRASH_PORT,
network_interface, true, error);
sender->sendProto(crash_msg);
std::cerr << "Broadcasting robot crash msg";

Expand Down Expand Up @@ -110,8 +110,8 @@ Thunderloop::Thunderloop(const RobotConstants_t& robot_constants, bool enable_lo
<< "THUNDERLOOP: Network Logger initialized! Next initializing Network Service";

network_service_ = std::make_unique<NetworkService>(
std::string(ROBOT_MULTICAST_CHANNELS.at(channel_id_)) + "%" + network_interface_,
PRIMITIVE_PORT, ROBOT_STATUS_PORT, true);
std::string(ROBOT_MULTICAST_CHANNELS.at(channel_id_)), PRIMITIVE_PORT,
ROBOT_STATUS_PORT, network_interface, true);
LOG(INFO)
<< "THUNDERLOOP: Network Service initialized! Next initializing Power Service";

Expand Down Expand Up @@ -478,9 +478,15 @@ void Thunderloop::updateErrorCodes()

void Thunderloop::waitForNetworkUp()
{
ThreadedUdpSender network_test(
std::string(ROBOT_MULTICAST_CHANNELS.at(channel_id_)) + "%" + network_interface_,
NETWORK_COMM_TEST_PORT, true);
std::optional<std::string> error;
ThreadedUdpSender network_test(std::string(ROBOT_MULTICAST_CHANNELS.at(channel_id_)),
NETWORK_COMM_TEST_PORT, network_interface_, true,
error);
if (error.has_value())
{
LOG(FATAL) << "Thunderloop cannot connect to the network. Error: "
<< error.value();
}

// Send an empty packet on the specific network interface to
// ensure wifi is connected. Keeps trying until successful
Expand Down
10 changes: 8 additions & 2 deletions src/software/logger/network_sink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@ NetworkSink::NetworkSink(unsigned int channel, const std::string& interface, int
bool enable_log_merging)
: robot_id(robot_id), log_merger(LogMerger(enable_log_merging))
{
std::optional<std::string> error;
log_output.reset(new ThreadedProtoUdpSender<TbotsProto::RobotLog>(
std::string(ROBOT_MULTICAST_CHANNELS.at(channel)) + "%" + interface,
ROBOT_LOGS_PORT, true));
std::string(ROBOT_MULTICAST_CHANNELS.at(channel)), ROBOT_LOGS_PORT, interface,
true, error));
if (error)
{
std::cerr << error.value() << std::endl;
std::terminate();
}
}

void NetworkSink::sendToNetwork(g3::LogMessageMover log_entry)
Expand Down
11 changes: 8 additions & 3 deletions src/software/logger/plotjuggler_sink.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@

#include "software/logger/plotjuggler_sink.h"

#include <google/protobuf/util/json_util.h>

#include "shared/constants.h"

PlotJugglerSink::PlotJugglerSink()
: udp_sender(PLOTJUGGLER_GUI_DEFAULT_HOST, PLOTJUGGLER_GUI_DEFAULT_PORT, false)
PlotJugglerSink::PlotJugglerSink(const std::string& interface)
: udp_sender(PLOTJUGGLER_GUI_DEFAULT_HOST, PLOTJUGGLER_GUI_DEFAULT_PORT, interface,
false, error)
{
if (error.has_value())
{
std::cerr << "Error setting up UDP sender for PlotJugglerSink: " << error.value();
std::terminate();
}
}

void PlotJugglerSink::sendToPlotJuggler(g3::LogMessageMover log_entry)
Expand Down
7 changes: 6 additions & 1 deletion src/software/logger/plotjuggler_sink.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ class PlotJugglerSink
public:
/**
* Creates a PlotJugglerSink that sends udp packets to the PlotJuggler server
*
* @param interface The interface to send Plotjuggler UDP packets on
*/
PlotJugglerSink();
PlotJugglerSink(const std::string& interface = "lo");

~PlotJugglerSink() = default;

Expand All @@ -30,6 +32,9 @@ class PlotJugglerSink
void sendToPlotJuggler(g3::LogMessageMover log_entry);

private:
// Any error that occurs during the creation of the UDP sender will be stored here
std::optional<std::string> error;

ThreadedUdpSender udp_sender;
};

Expand Down
9 changes: 7 additions & 2 deletions src/software/network_log_listener_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,14 @@ int main(int argc, char **argv)
logFromNetworking(log);
};

std::optional<std::string> error;
auto log_input = std::make_unique<ThreadedProtoUdpListener<TbotsProto::RobotLog>>(
std::string(ROBOT_MULTICAST_CHANNELS.at(args.channel)) + "%" + args.interface,
ROBOT_LOGS_PORT, robot_log_callback, true);
std::string(ROBOT_MULTICAST_CHANNELS.at(args.channel)), ROBOT_LOGS_PORT,
args.interface, robot_log_callback, true, error);
if (error)
{
LOG(FATAL) << *error;
}


LOG(INFO) << "Network logger listening on channel "
Expand Down
52 changes: 52 additions & 0 deletions src/software/networking/udp/BUILD
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
package(default_visibility = ["//visibility:public"])

cc_library(
name = "network_utils",
srcs = [
"network_utils.cpp",
],
hdrs = [
"network_utils.h",
],
)

cc_test(
name = "network_utils_test",
srcs = [
"network_utils_test.cpp",
],
deps = [
":network_utils",
"//shared/test_util:tbots_gtest_main",
],
)

cc_library(
name = "proto_udp_listener",
hdrs = [
"proto_udp_listener.hpp",
],
visibility = ["//visibility:private"],
deps = [
":network_utils",
"//software/logger",
"//software/util/typename",
],
Expand All @@ -22,6 +44,7 @@ cc_library(
],
visibility = ["//visibility:private"],
deps = [
":network_utils",
"@boost//:asio",
],
)
Expand All @@ -37,6 +60,17 @@ cc_library(
],
)

cc_test(
name = "threaded_proto_udp_listener_test",
srcs = [
"threaded_proto_udp_listener_test.cpp",
],
deps = [
":threaded_proto_udp_listener",
"//shared/test_util:tbots_gtest_main",
],
)

cc_library(
name = "threaded_proto_udp_sender",
hdrs = [
Expand All @@ -47,6 +81,17 @@ cc_library(
],
)

cc_test(
name = "threaded_proto_udp_sender_test",
srcs = [
"threaded_proto_udp_sender_test.cpp",
],
deps = [
":threaded_proto_udp_sender",
"//shared/test_util:tbots_gtest_main",
],
)

cc_library(
name = "threaded_udp_sender",
srcs = [
Expand All @@ -59,3 +104,10 @@ cc_library(
":udp_sender",
],
)

cc_library(
name = "udp_network_factory",
hdrs = [
"udp_network_factory.hpp",
],
)
42 changes: 42 additions & 0 deletions src/software/networking/udp/network_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "software/networking/udp/network_utils.h"

#include <arpa/inet.h>

std::optional<std::string> getLocalIp(const std::string& interface, bool ipv4)
{
struct ifaddrs* ifAddrStruct = nullptr;
struct ifaddrs* ifa = nullptr;

getifaddrs(&ifAddrStruct);

for (ifa = ifAddrStruct; ifa != nullptr; ifa = ifa->ifa_next)
{
if (ifa->ifa_name == interface)
{
if (ipv4 && ifa->ifa_addr->sa_family == AF_INET)
{
char addressBuffer[INET_ADDRSTRLEN];
struct sockaddr_in* sa = (struct sockaddr_in*)ifa->ifa_addr;
inet_ntop(AF_INET, &sa->sin_addr, addressBuffer, INET_ADDRSTRLEN);
freeifaddrs(ifAddrStruct);
return addressBuffer;
}
else if (!ipv4 && ifa->ifa_addr->sa_family == AF_INET6)
{
char addressBuffer[INET6_ADDRSTRLEN];
struct sockaddr_in6* sa = (struct sockaddr_in6*)ifa->ifa_addr;
inet_ntop(AF_INET6, &sa->sin6_addr, addressBuffer, INET6_ADDRSTRLEN);
freeifaddrs(ifAddrStruct);
return addressBuffer;
}
}
}

return std::nullopt;
}

bool isIpv6(const std::string& ip_address)
{
struct sockaddr_in6 sa;
return inet_pton(AF_INET6, ip_address.c_str(), &(sa.sin6_addr)) != 0;
}
Loading
Loading