Skip to content

Commit

Permalink
[Docs] Add in Doxygen docs generator
Browse files Browse the repository at this point in the history
  • Loading branch information
sahil-kale committed Dec 31, 2023
1 parent 1d3f6b8 commit 709ce5e
Show file tree
Hide file tree
Showing 14 changed files with 2,907 additions and 84 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/docment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Generate Documentation

on:
pull_request:
branches: [ main ]

jobs:
generate-documentation:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: sudo apt install doxygen python3
- run: python3 scripts/generate_documentation.py
- uses: actions/upload-artifact@v3
with:
name: html-output
path: html/
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,6 @@ cppcheckbuild/
# Bazel files
bazel-*

.vscode/
.vscode/

docs_html/
2,658 changes: 2,658 additions & 0 deletions Doxyfile

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion control_loop/bldc/brushless_control_loop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ void BrushlessControlLoop::update_rotor_position_estimator(
do {
estimator_inputs.time = current_time_us;

bridge_.read_bemf(estimator_inputs.phase_voltage);
bridge_.read_phase_voltage(estimator_inputs.phase_voltage);
bridge_.read_current(estimator_inputs.phase_current);

// Get the commutation step
Expand Down
14 changes: 7 additions & 7 deletions control_loop/bldc/rotor_estimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ app_hal_status_E BldcSensorlessRotorSectorSensor::get_electrical_angle(float& an
app_hal_status_E ret = APP_HAL_OK;
do {
// Get the bemf voltage
hwbridge::Bridge3Phase::phase_voltage_t bemf_voltage;
ret = bridge_.read_bemf(bemf_voltage);
hwbridge::Bridge3Phase::phase_voltage_t phase_voltage;
ret = bridge_.read_phase_voltage(phase_voltage);
const utime_t current_time = clock_.get_time_us();

if (ret != APP_HAL_OK) {
Expand All @@ -31,7 +31,7 @@ app_hal_status_E BldcSensorlessRotorSectorSensor::get_electrical_angle(float& an
control_loop::Bldc6Step::determine_commutation_step_from_theta(estimated_electrical_angle_);

// Check if a zero crossing has occurred
const bool zero_crossing = zero_crossing_detected(bemf_voltage, step);
const bool zero_crossing = zero_crossing_detected(phase_voltage, step);

// If we detect a zero crossing, then we should store the time of the zero crossing
// NOTE: time_of_last_zero_crossing_ is only set to zero when the rotor position estimator is reset
Expand Down Expand Up @@ -67,21 +67,21 @@ app_hal_status_E BldcSensorlessRotorSectorSensor::get_electrical_angle(float& an
}

bool BldcSensorlessRotorSectorSensor::zero_crossing_detected(
const hwbridge::Bridge3Phase::phase_voltage_t& bemf_voltage,
const hwbridge::Bridge3Phase::phase_voltage_t& phase_voltage,
control_loop::Bldc6Step::commutation_step_t current_commutation_step) {
float phase_sum = 0.0f;
control_loop::Bldc6Step::CommutationSignal zero_crossing_signal = control_loop::Bldc6Step::CommutationSignal::Z_RISING;
float undriven_phase_voltage = 0.0f;

const float bemf_voltages[hwbridge::Bridge3Phase::NUM_PHASES] = {bemf_voltage.u, bemf_voltage.v, bemf_voltage.w};
const float phase_voltages[hwbridge::Bridge3Phase::NUM_PHASES] = {phase_voltage.u, phase_voltage.v, phase_voltage.w};

for (uint8_t i = 0; i < hwbridge::Bridge3Phase::NUM_PHASES; i++) {
if ((current_commutation_step.signals[i] != control_loop::Bldc6Step::CommutationSignal::Z_FALLING) &&
(current_commutation_step.signals[i] != control_loop::Bldc6Step::CommutationSignal::Z_RISING)) {
phase_sum += bemf_voltages[i];
phase_sum += phase_voltages[i];
} else {
zero_crossing_signal = current_commutation_step.signals[i];
undriven_phase_voltage = bemf_voltages[i];
undriven_phase_voltage = phase_voltages[i];
}
}

Expand Down
6 changes: 3 additions & 3 deletions control_loop/bldc/rotor_estimator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ class ElectricalRotorPosEstimator {
class EstimatorInputs {
public:
utime_t time = 0;
hwbridge::Bridge3Phase::phase_voltage_t phase_voltage = {0.0f, 0.0f, 0.0f};
hwbridge::Bridge3Phase::phase_voltage_t phase_voltage;
control_loop::Bldc6Step::commutation_step_t current_commutation_step = {
control_loop::Bldc6Step::CommutationSignal::Z_FALLING, control_loop::Bldc6Step::CommutationSignal::HIGH,
control_loop::Bldc6Step::CommutationSignal::LOW};

hwbridge::Bridge3Phase::phase_current_t phase_current = {0.0f, 0.0f, 0.0f};
hwbridge::Bridge3Phase::phase_current_t phase_current;
float V_alpha = 0.0f;
float V_beta = 0.0f;
float phase_resistance = 0.0f;
Expand Down Expand Up @@ -91,7 +91,7 @@ class BldcSensorlessRotorSectorSensor : public BldcRotorSectorSensor {
app_hal_status_E get_electrical_angle(float& angle) override;

protected:
bool zero_crossing_detected(const hwbridge::Bridge3Phase::phase_voltage_t& bemf_voltage,
bool zero_crossing_detected(const hwbridge::Bridge3Phase::phase_voltage_t& phase_voltage,
control_loop::Bldc6Step::commutation_step_t current_commutation_step);
hwbridge::Bridge3Phase& bridge_;
float estimated_electrical_angle_ = 0.0f;
Expand Down
9 changes: 7 additions & 2 deletions hal/hal_clock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

namespace basilisk_hal {

// Create a clock class that can be used to get the current time in microseconds via singleton pattern
/**
* @brief Abstract class for a clock that keeps track of the time since boot
* @note This class should provide a way to get the current time in microseconds
*/
class HAL_CLOCK {
public:
HAL_CLOCK() = default;
Expand Down Expand Up @@ -39,7 +42,9 @@ class HAL_CLOCK {
*/
static float get_dt_s(utime_t t1, utime_t t2) { return static_cast<float>(get_dt_us(t1, t2)) / kMicrosecondsPerSecond; }

// Add a constant for the number of microseconds in a second
/**
* @brief Number of microseconds per second
*/
static constexpr float kMicrosecondsPerSecond = 1000000.0f;
};

Expand Down
125 changes: 95 additions & 30 deletions hwbridge/3phase/bridge_3phase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,54 +5,119 @@

namespace hwbridge {

// Define a generic 3-phase bridge class

/**
* @brief Abstract class for a 3-phase bridge that can be used to control a 3-phase inverter
* @note This class is intended to be used as an interface for a 3-phase bridge with a complementary PWM output and a fast ADC
* system for current sensing
*/
class Bridge3Phase {
public:
Bridge3Phase() = default;
virtual ~Bridge3Phase() = default;

typedef struct phase_command {
/**
* @brief Phase command typedef to hold the duty cycle and invert low side flag
*/
class phase_command_t {
public:
/**
* @brief Duty cycle for the high side PWM channel assuming complementary PWM
* @note The duty cycle is between 0.0f and 1.0f, where 0.5 is 50% duty cycle and represents 0V (assumes complementary
* pwm)
*/
float duty_cycle_high_side;
/**
* @brief Invert the low side PWM channel
* @note The invert low side flag is used to invert the low side PWM channel (if complementary PWM is used)
* @note Note that the invert low side flag, if set to false, is used to High-Z the bridge output. Caution should be used
* in allowing an abstracted bridge to allow a non-inverted output to be commanded to a duty cycle that is not 0.0f
*/
bool invert_low_side;
} phase_command_t;

// Define a struct to return the PHASE (not backemf) voltage
typedef struct phase_voltage {
float u;
float v;
float w;
} phase_voltage_t;

// Define a struct to return the current
typedef struct phase_current {
float u;
float v;
float w;
} phase_current_t;

class phase_params {
};

/**
* @brief Phase voltage readings in Volts
*/
class phase_voltage_t {
public:
float resistance;
float inductance;
/**
* @brief Phase U voltage
*/
float u = 0.0f;

/**
* @brief Phase V voltage
*/
float v = 0.0f;

/**
* @brief Phase W voltage
*/
float w = 0.0f;
};

/**
* @brief Phase current readings in Amps
*/
class phase_current_t {
public:
/**
* @brief Phase U current
*/
float u = 0.0f;
/**
* @brief Phase V current
*/
float v = 0.0f;
/**
* @brief Phase W current
*/
float w = 0.0f;
};

/**
* @brief Initialize the 3-phase bridge
* @return app_hal_status_E The status of the operation
*/
virtual app_hal_status_E init() = 0;

// Define a virtual function to set the individual phases' duty cycles and enable/disable the phase
/**
* @brief Set the phase voltages
* @param u The phase U voltage
* @param v The phase V voltage
* @param w The phase W voltage
* @return app_hal_status_E The status of the operation
*/
virtual app_hal_status_E set_phase(const phase_command_t& u, const phase_command_t& v, const phase_command_t& w) = 0;

// Define a virtual function to get the back emf voltage
virtual app_hal_status_E read_bemf(phase_voltage_t& bemf_voltage) = 0;

// Define a virtual function to get the current
/**
* @brief Read the phase voltages from the bridge
* @param phase_voltage The phase voltages in volts
* @return app_hal_status_E The status of the operation
*/
virtual app_hal_status_E read_phase_voltage(phase_voltage_t& phase_voltage) = 0;

/**
* @brief Read the phase currents from the bridge
* @param current The phase currents in amps
* @return app_hal_status_E The status of the operation
* @note this function can be called from a high frequency control loop and should be implemented as efficiently as possible
* or employ some other system to pre-trigger a current reading that can then be read from a buffer
*/
virtual app_hal_status_E read_current(phase_current_t& current) = 0;

// Define a virtual function to get the bus voltage
/**
* @brief Read the bus voltage from the bridge
* @param bus_voltage The bus voltage in volts
* @return app_hal_status_E The status of the operation
* @note this function can be called from a high frequency control loop and should be implemented in a way that does not
* block for a long time
*/
virtual app_hal_status_E read_bus_voltage(float& bus_voltage) = 0;

virtual app_hal_status_E read_phase_params(phase_params& params) = 0;

/**
* @brief Number of phases in the bridge
*/
static constexpr uint8_t NUM_PHASES = 3;
};

Expand Down
32 changes: 29 additions & 3 deletions hwbridge/h_bridge/bridge_hbridge.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,46 @@

namespace hwbridge {

// Define a generic h-bridge class
/**
* @brief Abstract class for an H bridge that can be used to control a motor
* @note This class assumes the A -> B side is a positive voltage across the H bridge
* @note See the `HBridgeInput` class for more information on the input to the H bridge
*/
class HBridge {
public:
HBridge() = default;
virtual ~HBridge() = default;

/**
* @brief HBridge input class to hold the input to the HBridge
* @note This class only modulates the high side of the H bridge. The low side is assumed to be controlled by a GPIO to reduce
* complexity.
*/
class HBridgeInput {
public:
/**
* Duty cycle for the high side of the A phase PWM
*/
float duty_cycle_a_h;
/**
* @brief The state of the low side A phase GPIO
*/
bool low_side_a_gpio_state;
/**
* @brief Duty cycle for the high side of the B phase PWM
*/
float duty_cycle_b_h;
/**
* @brief The state of the low side B phase GPIO
*/
bool low_side_b_gpio_state;

// Overload the == operator
/**
* @brief Equality operator
* @param other The other HBridgeInput to compare to
* @return True if the HBridgeInputs are equal, false otherwise
* @note This is used to determine if the HBridgeInput has changed and needs to be updated or for unit testing
*/
bool operator==(const HBridgeInput& other) const {
const bool low_side_gpios_equal =
(low_side_a_gpio_state == other.low_side_a_gpio_state) && (low_side_b_gpio_state == other.low_side_b_gpio_state);
Expand All @@ -33,7 +59,7 @@ class HBridge {

/**
* @brief Run the HBridge at a given speed
* @param speed The speed to run the HBridge at
* @param input The input to the HBridge
* @return app_hal_status_E The status of the operation
*/
virtual app_hal_status_E run(HBridgeInput input) = 0;
Expand Down
10 changes: 10 additions & 0 deletions scripts/generate_documentation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import subprocess

# First, remove the html directory
subprocess.call(["rm", "-r", "docs_html"])

# Then, generate the documentation
ret = subprocess.call(["doxygen", "Doxyfile"])
if ret != 0:
print("doxygen failed")
exit(ret)
2 changes: 1 addition & 1 deletion scripts/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

set -euxo pipefail

sudo apt install -y git clang-format clang-tidy build-essential gdb
sudo apt install -y git clang-format clang-tidy build-essential gdb doxygen

git submodule update --init --recursive

Expand Down
3 changes: 1 addition & 2 deletions test/mocks/mock_bridge_3phase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@ class MOCK_BRIDGE_3PHASE : public Bridge3Phase {
MOCK_METHOD(app_hal_status_E, set_phase, (const phase_command_t& u, const phase_command_t& v, const phase_command_t& w),
(override));
MOCK_METHOD(app_hal_status_E, init, (), (override));
MOCK_METHOD(app_hal_status_E, read_bemf, (phase_voltage_t & bemf_voltage), (override));
MOCK_METHOD(app_hal_status_E, read_phase_voltage, (phase_voltage_t & phase_voltage), (override));
MOCK_METHOD(app_hal_status_E, read_current, (phase_current_t & current), (override));
MOCK_METHOD(app_hal_status_E, read_bus_voltage, (float& voltage), (override));
MOCK_METHOD(app_hal_status_E, read_phase_params, (phase_params & params), (override));
};

} // namespace hwbridge
Expand Down
Loading

0 comments on commit 709ce5e

Please sign in to comment.