Skip to content

Commit

Permalink
Merge branch 'master' into Elevation-data
Browse files Browse the repository at this point in the history
  • Loading branch information
PatrickRung committed Mar 4, 2025
2 parents 9646c3e + f06734c commit aec74da
Show file tree
Hide file tree
Showing 12 changed files with 302 additions and 9 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ distribution installed (Ubuntu recommended). Either should work fine. Whichever

**Mac users:** We do not make any effort to support Mac systems. You *may* be able to get things working, but if you try you'll be on your own. It's **highly recommended** for Mac users to use a Linux VM.

> ⚠️ For Mac users, we recommend running a Ubuntu virtual machine via [UTM](https://mac.getutm.app/). After installing the app, set up your VM using [UTM's Ubuntu image](https://mac.getutm.app/gallery/ubuntu-20-04). Please note that UTM only supports the latest version of Ubuntu (22.04). Since the codebase is based on an older version of Ubuntu, there may be package errors that you need to manually resolve. For the sake of convenience, we also recommend SSHing into UTM via VSCode's Remote SSH feature. [More info can be found here](https://arteen.linux.ucla.edu/ssh-into-utm-vm.html).
**From here on out, the installation instructions will assume you are using Ubuntu 20.04 LTS**. Windows users should run commands in either their Linux VM or their WSL
terminal. For Linux users, we'll assume you're running Ubuntu; users of another
distribution may need to change some instructions (e.g. package managers) depending on
Expand Down Expand Up @@ -77,6 +79,15 @@ cd build
cmake ../src
```

## Formatting the code with clang-format

Run clang-format on every edited file. **Github will block your merge if you try to merge code that has not been clang-format'ed correctly!!!**

```
clang-format -i /path/to/file/<FILENAME>/
```
For more information about clang-format, [please see the documentation](https://clang.llvm.org/docs/ClangFormatStyleOptions.html).

## Compile the code

To build all of our executables (requires having all optional dependencies installed, e.g. OpenCV and URG), run
Expand Down
4 changes: 3 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -339,12 +339,14 @@ if(WITH_TESTS)
../tests/util/MathTest.cpp
../tests/util/TimeTest.cpp
../tests/util/SchedulerTest.cpp
../tests/util/RandomTest.cpp
../tests/util/JsonTest.cpp
../tests/util/ThreadingTest.cpp
# Protocol/teleop tests
../tests/kinematics/DiffWristKinematicsTest.cpp)

target_link_libraries(tests
${rover_libs}
stub_world_interface
${OpenCV_LIBS})
include(CTest)
include(Catch)
Expand Down
4 changes: 2 additions & 2 deletions src/Rover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ void parseCommandLine(int argc, char** argv) {
const auto now = std::chrono::system_clock::now();
const std::time_t t_c = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&t_c), "%Y%m%d_%H%M%S.log");
ss << "logs/" << std::put_time(std::localtime(&t_c), "%Y%m%d_%H%M%S.log");
std::string logFileName = ss.str();
loguru::add_file("latest.log", loguru::Truncate, loguru::Verbosity_INFO);
loguru::add_file("logs/latest.log", loguru::Truncate, loguru::Verbosity_INFO);
loguru::add_file(logFileName.c_str(), loguru::Append, loguru::Verbosity_INFO);

program.parse_args(argc, argv);
Expand Down
4 changes: 3 additions & 1 deletion src/TunePID.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ const std::map<motorid_t, std::string> motorNameMap = {
{motorid_t::wristDiffRight, "wristDiffRight"},
{motorid_t::wristDiffLeft, "wristDiffLeft"},
{motorid_t::hand, "hand"},
{motorid_t::activeSuspension, "activeSuspension"}};
{motorid_t::activeSuspension, "activeSuspension"},
{motorid_t::drillActuator, "drillActuator"},
{motorid_t::drillMotor, "drillMotor"}};

const std::map<std::string, motorid_t> nameToMotorMap = reverseMap(motorNameMap);

Expand Down
4 changes: 4 additions & 0 deletions src/gps/dummy/dummy_gps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ using robot::types::DataPoint;
DataPoint<navtypes::gpscoords_t> readGPSCoords() {
return {};
}

DataPoint<double> readIMUHeading() {
return {};
}
4 changes: 3 additions & 1 deletion src/world_interface/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ enum class motorid_t {
wristDiffRight,
wristDiffLeft,
hand,
activeSuspension
activeSuspension,
drillActuator,
drillMotor
};

/** @brief the mounted peripheral on the robot. */
Expand Down
12 changes: 9 additions & 3 deletions src/world_interface/real_world_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ constexpr auto motorSerialIDMap = frozen::make_unordered_map<motorid_t, can::dev
{motorid_t::wristDiffLeft, DEVICE_SERIAL_MOTOR_WRIST_DIFF_LEFT},
{motorid_t::wristDiffRight, DEVICE_SERIAL_MOTOR_WRIST_DIFF_RIGHT},
{motorid_t::hand, DEVICE_SERIAL_MOTOR_HAND},
{motorid_t::activeSuspension, DEVICE_SERIAL_LINEAR_ACTUATOR}});
{motorid_t::activeSuspension, DEVICE_SERIAL_LINEAR_ACTUATOR},
{motorid_t::drillActuator, DEVICE_SERIAL_DRILL_ARM_MOTOR},
{motorid_t::drillMotor, DEVICE_SERIAL_DRILL_MOTOR}});

/** @brief A mapping of PID controlled motors to their pid coefficients. */
constexpr auto motorPIDMap = frozen::make_unordered_map<motorid_t, pidcoef_t>(
Expand Down Expand Up @@ -132,7 +134,9 @@ constexpr auto positive_pwm_scales =
{motorid_t::rearLeftSwerve, 1.0},
{motorid_t::rearRightSwerve, 1.0},
{motorid_t::hand, -0.75},
{motorid_t::activeSuspension, -0.5}});
{motorid_t::activeSuspension, -0.5},
{motorid_t::drillActuator, -0.5},
{motorid_t::drillMotor, 1.0}});
/**
* @brief A mapping of motorids to power scale factors when commanded with negative power.
* Negative values mean that the motor is inverted.
Expand All @@ -153,6 +157,8 @@ constexpr auto negative_pwm_scales =
{motorid_t::rearLeftSwerve, 1.0},
{motorid_t::rearRightSwerve, 1.0},
{motorid_t::hand, -0.75},
{motorid_t::activeSuspension, -0.5}});
{motorid_t::activeSuspension, -0.5},
{motorid_t::drillActuator, -0.5},
{motorid_t::drillMotor, 1.0}});

} // namespace robot
3 changes: 2 additions & 1 deletion src/world_interface/simulator_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ const std::map<motorid_t, std::string> motorNameMap = {
{motorid_t::wristDiffLeft, "wristDiffLeft"},
{motorid_t::wristDiffRight, "wristDiffRight"},
{motorid_t::hand, "hand"},
{motorid_t::activeSuspension, "activeSuspension"}};
{motorid_t::activeSuspension, "activeSuspension"},
{motorid_t::drillActuator, "drillActuator"}};

std::optional<std::reference_wrapper<net::websocket::SingleClientWSServer>> wsServer;

Expand Down
78 changes: 78 additions & 0 deletions tests/util/CoreTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,84 @@

using namespace util;

TEST_CASE("Test almostEqual", "[util][core]") {
SECTION("Numbers are approximately equal") {
REQUIRE(almostEqual(1.000000001, 1.000000002));
REQUIRE(almostEqual(1.0, 1.0, 1e-5));
}

SECTION("Numbers are not approximately equal") {
REQUIRE_FALSE(almostEqual(1.0, 1.1));
REQUIRE_FALSE(almostEqual(1.0, 1.0 + 1e-5, 1e-6));
}
}

TEST_CASE("Test Key Set", "[util][core]") {
SECTION("Extracting keys from a given map") {
std::unordered_map<std::string, int> inputtedMap = {
{"key1", 1}, {"key2", 2}, {"key3", 3}};

auto keys = keySet(inputtedMap);

std::unordered_set<std::string> expectedSet = {"key1", "key2", "key3"};

REQUIRE(keys == expectedSet);
}

SECTION("Empty map results in empty set") {
std::unordered_map<std::string, int> emptyMap;
auto keys = keySet(emptyMap);
REQUIRE(keys.empty());
}
}

TEST_CASE("Test To String", "[util][core]") {
SECTION("Convert integers to strings") {
REQUIRE(to_string(69) == "69");
REQUIRE(to_string(-1) == "-1");
}

SECTION("Convert floats to strings") {
REQUIRE(to_string(3.14).substr(0, 4) == "3.14");
REQUIRE(to_string(1e-6) == "0.000001");
}

SECTION("Convert booleans to strings") {
REQUIRE(to_string(true) == "true");
REQUIRE(to_string(false) == "false");
}
}

TEST_CASE("Test Freeze String", "[util][core]") {
SECTION("Converting std::string to frozen::string") {
std::string stdString = "Test";
auto frozenString = freezeStr(stdString);
REQUIRE(frozenString == frozen::string("Test"));
}

SECTION("Converting empty std::string results in empty frozen::string") {
std::string stdString;
auto frozenString = freezeStr(stdString);
REQUIRE(frozenString == frozen::string(""));
}
}

TEST_CASE("Test Pair To Tuple", "[util][core]") {
SECTION("Converting pair of integers to tuple") {
std::pair<int, int> pair = {0, 1};
auto tuple = pairToTuple(pair);
REQUIRE(std::get<0>(tuple) == 0);
REQUIRE(std::get<1>(tuple) == 1);
}

SECTION("Converting mixed pair of string and integer to tuple") {
std::pair<std::string, int> pair = {"key0", 0};
auto tuple = pairToTuple(pair);
REQUIRE(std::get<0>(tuple) == "key0");
REQUIRE(std::get<1>(tuple) == 0);
}
}

TEST_CASE("Test RAIIHelper", "[util][core]") {
SECTION("Test RAIIHelper executes") {
bool called = false;
Expand Down
65 changes: 65 additions & 0 deletions tests/util/JsonTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "../../src/utils/json.h"

#include <catch2/catch.hpp>

using namespace util;

TEST_CASE("Test Has Key", "[util][json]") {
json j = {{"name", "huskyRobos"}, {"location", "University of Washington"}};

REQUIRE(hasKey(j, "name")); // has key of 'name'
REQUIRE_FALSE(hasKey(j, "numLosses")); // doesn't have key of 'numLosses'
}

TEST_CASE("Test Validate Key (Given Individual Types)", "[util][json]") {
json j = {{"name", "huskyRobos"}, {"age", 11}, {"cool", true}};
REQUIRE(validateKey(j, "name", val_t::string)); // has key of 'name' that is a string
REQUIRE_FALSE(
validateKey(j, "age", val_t::string)); // doesn't have key of 'age' that is a string
REQUIRE(validateKey(j, "cool", val_t::boolean)); // has key of 'cool' that is a boolean
}

TEST_CASE("Test Validate Key (Given Set of Types)", "[util][json]") {
json j = {{"name", "huskyRobos"}, {"age", 11}, {"cool", true}};

std::unordered_set<val_t> keyTypesAllowed = {val_t::string, val_t::number_integer};

REQUIRE(validateKey(
j, "name", keyTypesAllowed)); // has key of 'name' that is a type of the allowed types
REQUIRE(validateKey(
j, "age", keyTypesAllowed)); // has key of 'age' that is a type of the allowed types
REQUIRE_FALSE(validateKey(
j, "cool",
keyTypesAllowed)); // doesn't have key of 'cool' that is a type of the allowed types
}

TEST_CASE("Test Validate One Of", "[util][json]") {
json j = {{"status", "active"}, {"subTeams", "software"}};

std::unordered_set<std::string> statusValueTypesAllowed = {"active", "inactive"};
std::unordered_set<std::string> subTeamValueTypesAllowed = {"software", "electrical",
"mechanical"};

REQUIRE(validateOneOf(j, "status",
statusValueTypesAllowed)); // value of 'status' is a string in set of
// statusValueTypesAllowed
REQUIRE_FALSE(validateOneOf(
j, "status", {"pending", "closed"})); // value of 'status' is a string but not in set
// of statusValueTypesAllowed
REQUIRE(validateOneOf(j, "subTeams",
subTeamValueTypesAllowed)); // value of 'subTeams' is a string in set
// of subTeamValueTypesAllowed
}

TEST_CASE("Test Validate Range", "[util][json]") {
json j = {
{"winLossRatio", 0.8375},
{"avgGPA", 3.6},
};

REQUIRE(validateRange(j, "winLossRatio", 0.0,
1.0)); // 'winLossRatio' is in range from 0.0 to 1.0
REQUIRE(validateRange(j, "avgGPA", 0.0, 4.0)); // 'avgGPA' is in range from 0.0 to 4.0
REQUIRE_FALSE(
validateRange(j, "avgGPA", 0.0, 2.0)); // 'avgGPA' isnt in range of 0.0 to 2.0
}
21 changes: 21 additions & 0 deletions tests/util/RandomTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "../../src/utils/random.h"

#include <catch2/catch.hpp>

using namespace util;

TEST_CASE("Test Standard Normal Distribution w/ different thread_ids", "[util][random]") {
double sample0 = stdn(0);
double sample1 = stdn(1);

// samples should be different
REQUIRE(sample0 != sample1);
}

TEST_CASE("Test Get Normal Seed", "[util][random]") {
double seed1 = getNormalSeed();
double seed2 = getNormalSeed();

// seeds should be the same
REQUIRE(seed1 == seed2);
}
Loading

0 comments on commit aec74da

Please sign in to comment.