Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7057257
doctest header
roccoagain Feb 27, 2026
24b21b1
Working tests and make target
roccoagain Feb 28, 2026
25461a3
Switched to PlatformIO and Unity to test on the Teensy4.1 rather than…
roccoagain Feb 28, 2026
2b92cb5
Suppress pio command print in makefile
roccoagain Feb 28, 2026
96b6d9e
Add DUSB_SERIAL to build flags so the teensy can auto-reboot during t…
roccoagain Feb 28, 2026
c800e0b
Example sensor test
roccoagain Feb 28, 2026
f84a630
PIDFilters tests - only done for derivative and wrap around might do …
leBronzo1 Mar 4, 2026
0b036b8
PIDFilters tests - only done for derivative and wrap around might do …
leBronzo1 Mar 4, 2026
6452b86
test_cntrls and test_fltrs - minor fix in filters and just did the se…
leBronzo1 Mar 4, 2026
3260fa2
tests
leBronzo1 Mar 25, 2026
1a82935
yo
leBronzo1 Mar 25, 2026
ba7594d
changes to pid tests and new vector tests after refactor more to come…
leBronzo1 Mar 29, 2026
2f4f7dd
sensors and filters done
leBronzo1 Apr 1, 2026
d2e1352
sensors and filters done
leBronzo1 Apr 1, 2026
498a0c1
Sensors, Utils, and Filters done just cntrls to go
leBronzo1 Apr 1, 2026
c71ad23
merge + some tests added
leBronzo1 Apr 6, 2026
47c5b9d
Bugs fixed and ready for test
leBronzo1 Apr 6, 2026
9d68342
removed include in controls tests
roccoagain Apr 8, 2026
1a38aae
shit dont work
leBronzo1 Apr 11, 2026
2a7794d
Sensors tests done with Gerald
leBronzo1 Apr 11, 2026
d85e6d4
Complete just need to test
leBronzo1 Apr 11, 2026
25987b5
merge
leBronzo1 Apr 11, 2026
073642d
makefile temp
leBronzo1 Apr 11, 2026
de43690
senors still errors
leBronzo1 Apr 12, 2026
e4874c9
I dont even know
leBronzo1 Apr 12, 2026
18a9ef2
all done
leBronzo1 Apr 12, 2026
bee91c5
add Doxygen comments to MotorVelocities struct
leBronzo1 Apr 12, 2026
f4d0563
Convert identation to tabs and remove comments inside of targets that…
roccoagain Aug 17, 2026
60e473e
Keep build artifacts in the build directory
roccoagain Aug 17, 2026
d079d12
Organize the phonies
roccoagain Aug 17, 2026
34364e2
Remove unused Arduino path detection
roccoagain Aug 17, 2026
3477a87
Separate elf, hex, map, and dump targets
roccoagain Aug 17, 2026
2d0c341
Organize flags
roccoagain Aug 17, 2026
50ee7c6
Remove bugged automatic paralellism
roccoagain Aug 17, 2026
cf78629
Clean up Makefile comments and formatting
roccoagain Aug 17, 2026
624c96e
Organize flags and centralize feature/debug defines
roccoagain Aug 17, 2026
7582d27
Improve prints while building
roccoagain Aug 17, 2026
8095b33
Fix includes in src
roccoagain Aug 17, 2026
1dbebe6
Fix library inc dirs
roccoagain Aug 17, 2026
fe00610
Decouple clangd generation from normal builds
roccoagain Aug 17, 2026
6a89b59
Separate elf, hex, and dump targets
roccoagain Aug 18, 2026
f9ee6a3
Rewrite git_info.h only when contents change
roccoagain Aug 18, 2026
9389e4a
Cache the git_scraper binary in build/
roccoagain Aug 18, 2026
ad8839f
Build in parallel and make dump generation opt-in
roccoagain Aug 18, 2026
9a470f3
Use -g2 instead of -g3 for debug info
roccoagain Aug 18, 2026
0b0d1b3
Make per-object disassembly opt-in via DUMP_OBJS
roccoagain Aug 18, 2026
5651030
Strip trailing slashes from LIBRARY_INC_DIRS
roccoagain Aug 18, 2026
ec3a1b5
Document the clean/build workflow at the top of the Makefile
roccoagain Aug 19, 2026
5e5ec4f
Merge conflicts and platform ini issue fixed
leBronzo1 Aug 21, 2026
34c41df
Merge remote-tracking branch 'origin/main' into feature-unit-testing
leBronzo1 Aug 21, 2026
d84653f
Remove PlatformIO test environment
leBronzo1 Aug 26, 2026
373b9ad
Merge remote-tracking branch 'origin/makefile-build-system' into feat…
leBronzo1 Aug 26, 2026
06edac7
unit testing with unity completed
leBronzo1 Aug 26, 2026
fcb75c2
updated readme documentation
leBronzo1 Aug 26, 2026
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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ compile_commands.json
# Ignore any tools/ directory artifacts
tools/*.txt
tools/*.out
tools/git_scraper
tools/custom_monitor
tools/compiler
tools/tools
Expand Down
318 changes: 165 additions & 153 deletions Makefile

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ There are a few other nice helper functions within the makefile. This will list
make help
```

To run tests:
```bash
make test
```


## Contributing
`main` is the production branch, which is required to be in an always working state.
Expand Down
2 changes: 1 addition & 1 deletion src/comms/config_data/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "comms/data/comms_data.hpp" // for CommsData, TypeLabel, to_string
#include "comms/config_data/motor.hpp" // for Motor
#include "state.hpp" // for StateName
#include "safety.hpp" // for assert_or_safety_mode
#include "utils/safety.hpp" // for assert_or_safety_mode

/// These values are arbitrary limits for the size of the arrays in the Controller struct.
// They should be large enough to accommodate any reasonable number of motors, states, or sub controllers per controller configuration.
Expand Down
2 changes: 1 addition & 1 deletion src/comms/config_data/estimator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include "state.hpp" // for StateName
#include "motor.hpp" // for MotorName
#include "sensor.hpp" // for SensorName
#include "safety.hpp" // for assert_or_safety_mode
#include "utils/safety.hpp" // for assert_or_safety_mode

/// These values are arbitrary limits for the size of the arrays in the Estimator struct.
// They should be large enough to accommodate any reasonable number of states, motors, or sensors used by an estimator configuration.
Expand Down
2 changes: 1 addition & 1 deletion src/comms/data/hive_data.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "hive_data.hpp"
#include "comms_data.hpp"
#include "config_data/sensor.hpp"
#include "comms/config_data/sensor.hpp"

#include "comms/comms_layer.hpp" // for CommsLayer

Expand Down
2 changes: 1 addition & 1 deletion src/comms/data/packet_payload.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "packet_payload.hpp"
#include "safety.hpp"
#include "utils/safety.hpp"

#include <algorithm> // for min
#include "comms/comms_layer.hpp" // for CommsLayer
Expand Down
2 changes: 1 addition & 1 deletion src/comms/data/sendable.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include <type_traits> // for is_base_of, is_copy_constructible
#include "comms_layer.hpp" // for CommsLayer
#include "comms/comms_layer.hpp" // for CommsLayer

namespace Comms {

Expand Down
6 changes: 1 addition & 5 deletions src/comms/ethernet_comms.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ namespace qn = qindesign::network;
#include "utils/timing.hpp" // for Timer
#include "comms/ethernet_packet.hpp" // for EthernetPacket

// DEBUG define for displaying all comms errors/status updates
// This is very noisy on start up
// #define COMMS_DEBUG

namespace Comms {

/// @brief Ethernet Communications. This handles all comms between the Jetson and the Teensy via Ethernet
Expand Down Expand Up @@ -105,4 +101,4 @@ class EthernetComms {
Timer m_regulation_timer;
};

} // namespace Comms
} // namespace Comms
77 changes: 36 additions & 41 deletions src/controls/controller.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "controller.hpp"
#include "motor.hpp"
#include "sensors/can/motor.hpp"
#include "sensors/RefSystem.hpp"
#include <cmath>

namespace {
/// @brief Unwrap a potentially wrapped error value to maintain continuity across wrap boundaries.
Expand Down Expand Up @@ -179,22 +180,21 @@ void XDriveController::step(RobotStateMap& reference_map, RobotStateMap& estimat
outputp[2] = pidp[2].filter(dt, false, false);
outputv[2] = pidv[2].filter(dt, false, false);
output[2] = (outputp[2] + outputv[2]) * controller_config.gear_ratios.chassis_rad_to_motor_rad;
float chassis_heading = estimate_map[Cfg::StateName::ChassisHeading].get_position();

// Convert to motor velocities
motor_velocity[1] = output[0] * cos(chassis_heading) + output[1] * sin(chassis_heading) + output[2];
motor_velocity[2] = output[0] * sin(chassis_heading) - output[1] * cos(chassis_heading) + output[2];
motor_velocity[3] = -output[0] * cos(chassis_heading) - output[1] * sin(chassis_heading) + output[2];
motor_velocity[0] = -output[0] * sin(chassis_heading) + output[1] * cos(chassis_heading) + output[2];
float chassis_heading = estimate_map[Cfg::StateName::ChassisHeading].get_position();
MotorVelocities mv = xdrive_mix(output[0], output[1], output[2], chassis_heading);
// position mode uses [1,2,3,0] index order
motor_velocity[1] = mv.v[0];
motor_velocity[2] = mv.v[1];
motor_velocity[3] = mv.v[2];
motor_velocity[0] = mv.v[3];

// Power limiting
float power_buffer = ref.ref_data.robot_power_heat.buffer_energy;
float power_limit_ratio = 1.0;
float power_buffer_limit_thresh = power_buffer_controller.gains.power_buffer_threshold;
float power_buffer_critical_thresh = power_buffer_controller.gains.power_buffer_critical_threshold;
if (power_buffer < power_buffer_limit_thresh) {
power_limit_ratio = constrain(((power_buffer - power_buffer_critical_thresh) / power_buffer_limit_thresh), 0.0, 1.0);
}
float power_limit_ratio = compute_power_limit_ratio(
ref.ref_data.robot_power_heat.buffer_energy,
power_buffer_controller.gains.power_buffer_threshold,
power_buffer_controller.gains.power_buffer_critical_threshold
);

float motor_outputs[4];

Expand Down Expand Up @@ -248,8 +248,7 @@ void XDriveController::step(RobotStateMap& reference_map, RobotStateMap& estimat
outputp[2] = pidp[2].filter(dt, false, false);
outputv[2] = pidv[2].filter(dt, false, false);
output[2] = (outputp[2] + outputv[2]) * controller_config.gear_ratios.chassis_rad_to_motor_rad;
// Serial.printf("chassis heading output: %f, chassis x output: %f, chassis y output: %f chassis angle:%f\n", output[2], output[0], output[1], estimate[2][0]);
// Adjust for chassis heading so control is field relative

float chassis_heading = estimate_map[Cfg::StateName::ChassisHeading].get_position();

// Convert to motor velocities
Expand All @@ -258,13 +257,11 @@ void XDriveController::step(RobotStateMap& reference_map, RobotStateMap& estimat
motor_velocity[3] = -output[0] * cos(chassis_heading) - output[1] * sin(chassis_heading) + output[2];
motor_velocity[0] = -output[0] * sin(chassis_heading) + output[1] * cos(chassis_heading) + output[2];
// Power limiting
float power_buffer = ref.ref_data.robot_power_heat.buffer_energy;
float power_limit_ratio = 1.0;
float power_buffer_limit_thresh = power_buffer_controller.gains.power_buffer_threshold;
float power_buffer_critical_thresh = power_buffer_controller.gains.power_buffer_critical_threshold;
if (power_buffer < power_buffer_limit_thresh) {
power_limit_ratio = constrain(((power_buffer - power_buffer_critical_thresh) / power_buffer_limit_thresh), 0.0, 1.0);
}
float power_limit_ratio = compute_power_limit_ratio(
ref.ref_data.robot_power_heat.buffer_energy,
power_buffer_controller.gains.power_buffer_threshold,
power_buffer_controller.gains.power_buffer_critical_threshold
);

float motor_outputs[4];

Expand Down Expand Up @@ -313,11 +310,10 @@ void YawController::step(RobotStateMap& reference_map, RobotStateMap& estimate_m
pidv.setpoint = reference_map[yaw_angle_state].get_velocity();
pidv.measurement = estimate_map[yaw_angle_state].get_velocity();

output += pidp.filter(dt, true, true); // position wraps
output += pidv.filter(dt, true, false); // no wrap for velocity

output = constrain(output, -1.0, 1.0);
output += pidp.filter(dt, true, true);
output += pidv.filter(dt, true, false);

output = clamp1(output);

float motor_outputs[2];

Expand Down Expand Up @@ -352,13 +348,12 @@ void PitchController::step(RobotStateMap& reference_map, RobotStateMap& estimate
pidp.setpoint = reference_map[pitch_angle_state].get_position();
pidp.measurement = estimate_map[pitch_angle_state].get_position();


pidv.setpoint = reference_map[pitch_angle_state].get_velocity();
pidv.measurement = estimate_map[pitch_angle_state].get_velocity();

output += pidp.filter(dt, true, false); // position wraps
output += pidv.filter(dt, true, false); // no wrap for velocity
output = constrain(output, -1.0, 1.0);
output += pidp.filter(dt, true, false);
output += pidv.filter(dt, true, false);
output = clamp1(output);

float motor_outputs[2];

Expand Down Expand Up @@ -404,7 +399,7 @@ void FlywheelController::step(RobotStateMap& reference_map, RobotStateMap& estim

pid_low.setpoint = target_motor_velocity * flywheel_directions[i];
pid_low.measurement = flywheel_motors[i]->get_state().speed;

flywheel_motors[i]->write_motor_torque(pid_low.filter(dt, true, false));
}
}
Expand All @@ -428,14 +423,14 @@ void FeederController::step(RobotStateMap& reference_map, RobotStateMap& estimat
pidv.ki = full_state_velocity_controller.gains.i;
pidv.kd = full_state_velocity_controller.gains.d;
pidv.kf = full_state_velocity_controller.gains.f;

pidp.setpoint = reference_map[feeder_position_state].get_position();
pidp.measurement = estimate_map[feeder_position_state].get_position();

float outputp = pidp.filter(dt, true, true);
float output = outputp * controller_config.gear_ratios.feeder_direction;

feeder_motor->write_motor_torque(output);
feeder_motor->write_motor_torque(output);
}

void FeederController::handleControllerError(const char* controller_name, const char* state_name, const State& reference_state, const State& estimate_state, float error) {
Expand Down Expand Up @@ -494,9 +489,9 @@ void LowerFeederController::step(RobotStateMap& reference_map, RobotStateMap& es
// Serial.printf("upper feeder shot, time: %f \n", (micros() - target_increase_time) / 1000.0);
timer_active = false;
}

upper_feeder_reference_state = upper_feeder_reference_governor.step_reference_map(upper_target);

upper_pidp.setpoint = upper_feeder_reference_state[upper_feeder_position_state].get_position();
upper_pidp.measurement = upper_pos;

Expand All @@ -508,7 +503,7 @@ void LowerFeederController::step(RobotStateMap& reference_map, RobotStateMap& es

lower_pidv.setpoint = reference_map[upper_feeder_position_state].get_velocity();
lower_pidv.measurement = estimate_map[lower_feeder_position_state].get_velocity();

float upper_outputp = upper_pidp.filter(dt, true, true);
float upper_outputv = upper_pidv.filter(dt, true, false);
float upper_output = (upper_outputp + upper_outputv) * controller_config.gear_ratios.upper_feeder_direction;
Expand All @@ -518,13 +513,13 @@ void LowerFeederController::step(RobotStateMap& reference_map, RobotStateMap& es
float lower_outputv = lower_pidv.filter(dt, true, false);
float lower_output = (lower_outputp + lower_outputv) * controller_config.gear_ratios.lower_feeder_direction;
lower_output = constrain(lower_output, -1.0, 1.0);

// Serial.printf("Feeder Velocity Setpoint: %f, Measurement: %f, output: %f\n", lower_pidv.setpoint, lower_pidv.measurement, output);
// Serial.printf("lower feeder reference position: %f, reference velocity: %f, estimate position: %f, estimate velocity: %f\n",
// Serial.printf("lower feeder reference position: %f, reference velocity: %f, estimate position: %f, estimate velocity: %f\n",
// reference_map[lower_feeder_position_state].get_position(), reference_map[lower_feeder_position_state].get_velocity(),
// estimate_map[lower_feeder_position_state].get_position(), estimate_map[lower_feeder_position_state].get_velocity());
upper_feeder_motor->write_motor_torque(upper_output);
upper_feeder_motor->write_motor_torque(upper_output);

near_feeder_motor->write_motor_torque(lower_output);
far_feeder_motor->write_motor_torque(-lower_output);
}
}
7 changes: 4 additions & 3 deletions src/controls/controller.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#pragma once

#include "controller_math.hpp"
#include "estimator.hpp"
#include "filters/pid_filter.hpp"
#include "motor.hpp"
#include "safety.hpp"
#include "sensors/can/motor.hpp"
#include "utils/safety.hpp"
#include "utils/timing.hpp"
#include "sensors/can/can_manager.hpp"
#include "robot_state_map.hpp"
Expand Down Expand Up @@ -573,4 +574,4 @@ struct LowerFeederController : public Controller {
lower_pidv.sumError = 0.0;
lower_feeder_error_monitor = ErrorMonitor{};
}
};
};
26 changes: 26 additions & 0 deletions src/controls/controller_math.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "controller_math.hpp"

#include <algorithm>
#include <cmath>

float compute_power_limit_ratio(float buffer, float limit_thresh, float critical_thresh) {
if (buffer >= limit_thresh) {
return 1.0f;
}
return std::clamp((buffer - critical_thresh) / limit_thresh, 0.0f, 1.0f);
}

MotorVelocities xdrive_mix(float x, float y, float rot, float heading) {
const float cosine = std::cos(heading);
const float sine = std::sin(heading);
return {{
x * cosine + y * sine + rot,
x * sine - y * cosine + rot,
-x * cosine - y * sine + rot,
-x * sine + y * cosine + rot,
}};
}

float clamp1(float value) {
return std::clamp(value, -1.0f, 1.0f);
}
11 changes: 11 additions & 0 deletions src/controls/controller_math.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

/// @brief Holds the normalized velocity outputs for all four motors of an X-drive chassis.
struct MotorVelocities {
/// @brief Normalized velocity for each motor, indexed 0-3.
float v[4];
};

float compute_power_limit_ratio(float buffer, float limit_thresh, float critical_thresh);
MotorVelocities xdrive_mix(float x, float y, float rot, float heading);
float clamp1(float value);
2 changes: 1 addition & 1 deletion src/controls/estimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include <limits>

#include "estimator.hpp"
#include "ICM20649.hpp"
#include "sensors/ICM20649.hpp"
#include "utils/vector_math.hpp"
#include "utils/wrapping.hpp"
#include "sensors/RefSystem.hpp"
Expand Down
4 changes: 2 additions & 2 deletions src/controls/estimator.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#pragma once

#include "estimator.hpp"
#include "comms/config_data/estimator.hpp"
#include "robot_state_map.hpp"
#include "safety.hpp"
#include "utils/safety.hpp"
#include "sensors/can/can_manager.hpp"
#include "state.hpp"
#include "utils/timing.hpp"
Expand Down
10 changes: 5 additions & 5 deletions src/hello_robot.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
#include <Arduino.h>
#include <optional>

#include "can_manager.hpp"
#include "sensors/can/can_manager.hpp"
#include "comms/comms_layer.hpp"
#include "controls/reference_governor.hpp"
#include "controls/state.hpp"
#include "git_info.h"

#include "robot_state_map.hpp"
#include "safety.hpp"
#include "controls/robot_state_map.hpp"
#include "utils/safety.hpp"
#include "sensors/buff_encoder.hpp"
#include "state.hpp"
#include "comms/config_data/state.hpp"
#include "utils/boot_splash.hpp"
#include "utils/profiler.hpp"

Expand All @@ -25,7 +25,7 @@
#include "sensors/StereoCamTrigger.hpp"
#include "utils/profiler.hpp"

#include "sensor_manager.hpp"
#include "sensors/sensor_manager.hpp"
#include <TeensyDebug.h>
#include <wiring.h>

Expand Down
2 changes: 1 addition & 1 deletion src/sensors/ICM20649.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "ICM20649.hpp"
#include "safety.hpp"
#include "utils/safety.hpp"
#include "comms/data/sendable.hpp"

// initialize ICM
Expand Down
3 changes: 0 additions & 3 deletions src/sensors/RefSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
#include "comms/data/sendable.hpp"
RefSystem ref; // Global instance

// Uncomment to enable debug prints
// #define REF_SYSTEM_DEBUG

uint8_t generateCRC8(const uint8_t *data, uint32_t len) {
uint8_t CRC8 = 0xFF;
while (len-- > 0) {
Expand Down
2 changes: 1 addition & 1 deletion src/sensors/StereoCamTrigger.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include "StereoCamTrigger.hpp"
#include "comms/data/sendable.hpp"
#include "transmitter_utils.hpp"
#include "sensors/transmitter/transmitter_utils.hpp"
#include <core_pins.h>

std::unique_ptr<RobotStateMap>* StereoCamTrigger::estimated_state_map_interrupt_safe = nullptr;
Expand Down
2 changes: 1 addition & 1 deletion src/sensors/StereoCamTrigger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <avr/interrupt.h>
#include "sensors/sensor.hpp"
#include "comms/data/stereo_cam_trigger_data.hpp"
#include "robot_state_map.hpp"
#include "controls/robot_state_map.hpp"
#include <memory>


Expand Down
Loading
Loading